or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

array-conversion.mdindex.mdtree-analysis.mdtree-construction.mdtree-iterators.mdtree-modification.mdtree-navigation.mdtree-traversal.md

tree-analysis.mddocs/

0

# Tree Analysis

1

2

Index calculation, counting, and position comparison operations for tree structure analysis.

3

4

## Capabilities

5

6

### Index Calculation

7

8

Find the index position of an object among its siblings.

9

10

```javascript { .api }

11

/**

12

* Find the index of the given object (number of preceding siblings)

13

* Time Complexity: O(n) where n is the number of preceding siblings, O(1) amortized if tree not modified

14

* @param {Object} child - Child object to find index of

15

* @returns {number} The number of preceding siblings, or -1 if the object has no parent

16

*/

17

index(child: Object): number;

18

```

19

20

### Children Count

21

22

Calculate the number of children an object has.

23

24

```javascript { .api }

25

/**

26

* Calculate the number of children

27

* Time Complexity: O(n) where n is the number of children, O(1) amortized if tree not modified

28

* @param {Object} parent - Parent object

29

* @returns {number} Number of children

30

*/

31

childrenCount(parent: Object): number;

32

```

33

34

### Position Comparison

35

36

Compare the relative positions of two objects in the tree.

37

38

```javascript { .api }

39

/**

40

* Compare the position of an object relative to another object

41

* Time Complexity: O(n + m + o) where n,m are ancestor counts, o is common ancestor children

42

* @param {Object} left - Left object (reference/context object)

43

* @param {Object} right - Right object (other object)

44

* @returns {number} Bitmask indicating relationship between objects

45

*/

46

compareTreePosition(left: Object, right: Object): number;

47

```

48

49

## Position Comparison Constants

50

51

The `compareTreePosition` method returns a bitmask with these possible values:

52

53

```javascript { .api }

54

// Access via SymbolTree.TreePosition

55

const TreePosition = {

56

DISCONNECTED: 1, // Objects are in different trees

57

PRECEDING: 2, // Left object precedes right object in tree order

58

FOLLOWING: 4, // Left object follows right object in tree order

59

CONTAINS: 8, // Left object contains right object (left is ancestor of right)

60

CONTAINED_BY: 16 // Left object is contained by right object (right is ancestor of left)

61

};

62

```

63

64

## Usage Examples

65

66

### Basic Index Operations

67

68

```javascript

69

const SymbolTree = require("symbol-tree");

70

const tree = new SymbolTree();

71

72

// Build a tree structure

73

const parent = { name: "parent" };

74

const child1 = { name: "child1" };

75

const child2 = { name: "child2" };

76

const child3 = { name: "child3" };

77

78

tree.appendChild(parent, child1);

79

tree.appendChild(parent, child2);

80

tree.appendChild(parent, child3);

81

82

// Get indices

83

console.log(tree.index(child1)); // 0 (first child)

84

console.log(tree.index(child2)); // 1 (second child)

85

console.log(tree.index(child3)); // 2 (third child)

86

87

// Object with no parent

88

const orphan = { name: "orphan" };

89

console.log(tree.index(orphan)); // -1

90

91

// Count children

92

console.log(tree.childrenCount(parent)); // 3

93

console.log(tree.childrenCount(child1)); // 0 (no children)

94

```

95

96

### Position Comparison Examples

97

98

```javascript

99

// Build a more complex tree:

100

// root

101

// / \

102

// A D

103

// / \ \

104

// B C E

105

const root = { name: "root" };

106

const nodeA = { name: "A" };

107

const nodeB = { name: "B" };

108

const nodeC = { name: "C" };

109

const nodeD = { name: "D" };

110

const nodeE = { name: "E" };

111

112

tree.appendChild(root, nodeA);

113

tree.appendChild(root, nodeD);

114

tree.appendChild(nodeA, nodeB);

115

tree.appendChild(nodeA, nodeC);

116

tree.appendChild(nodeD, nodeE);

117

118

// Compare positions

119

const { TreePosition } = SymbolTree;

120

121

// A contains B (A is ancestor of B)

122

const aToBRelation = tree.compareTreePosition(nodeA, nodeB);

123

console.log(aToBRelation === TreePosition.CONTAINS); // true

124

125

// B is contained by A (B is descendant of A)

126

const bToARelation = tree.compareTreePosition(nodeB, nodeA);

127

console.log(bToARelation === TreePosition.CONTAINED_BY); // true

128

129

// B precedes C (B comes before C in tree order)

130

const bToCRelation = tree.compareTreePosition(nodeB, nodeC);

131

console.log(bToCRelation === TreePosition.PRECEDING); // true

132

133

// C follows B (C comes after B in tree order)

134

const cToBRelation = tree.compareTreePosition(nodeC, nodeB);

135

console.log(cToBRelation === TreePosition.FOLLOWING); // true

136

137

// A precedes D (A comes before D in tree order)

138

const aToDRelation = tree.compareTreePosition(nodeA, nodeD);

139

console.log(aToDRelation === TreePosition.PRECEDING); // true

140

```

141

142

### Understanding Tree Order

143

144

Tree order is depth-first: root, A, B, C, D, E

145

146

```javascript

147

// Verify tree order using position comparison

148

function isInTreeOrder(node1, node2) {

149

const relation = tree.compareTreePosition(node1, node2);

150

return (relation & TreePosition.PRECEDING) !== 0;

151

}

152

153

console.log(isInTreeOrder(root, nodeA)); // true

154

console.log(isInTreeOrder(nodeA, nodeB)); // true

155

console.log(isInTreeOrder(nodeB, nodeC)); // true

156

console.log(isInTreeOrder(nodeC, nodeD)); // true

157

console.log(isInTreeOrder(nodeD, nodeE)); // true

158

159

// Reverse should be false

160

console.log(isInTreeOrder(nodeE, nodeD)); // false

161

```

162

163

### Disconnected Objects

164

165

```javascript

166

// Create separate tree

167

const otherRoot = { name: "otherRoot" };

168

const otherChild = { name: "otherChild" };

169

tree.appendChild(otherRoot, otherChild);

170

171

// Compare objects from different trees

172

const disconnectedRelation = tree.compareTreePosition(nodeA, otherChild);

173

console.log(disconnectedRelation === TreePosition.DISCONNECTED); // true

174

175

// Note: DISCONNECTED never occurs with other bits

176

console.log(disconnectedRelation & TreePosition.PRECEDING); // 0

177

console.log(disconnectedRelation & TreePosition.FOLLOWING); // 0

178

```

179

180

### Practical Analysis Functions

181

182

```javascript

183

// Find position of child among siblings

184

function getChildPosition(parent, targetChild) {

185

const index = tree.index(targetChild);

186

const total = tree.childrenCount(parent);

187

188

return {

189

index: index,

190

total: total,

191

isFirst: index === 0,

192

isLast: index === total - 1,

193

isEmpty: total === 0

194

};

195

}

196

197

const position = getChildPosition(parent, child2);

198

console.log(position);

199

// { index: 1, total: 3, isFirst: false, isLast: false, isEmpty: false }

200

201

// Analyze tree structure

202

function analyzeNode(node) {

203

const parent = tree.parent(node);

204

const childCount = tree.childrenCount(node);

205

const index = parent ? tree.index(node) : -1;

206

207

return {

208

hasParent: parent !== null,

209

hasChildren: childCount > 0,

210

childCount: childCount,

211

siblingIndex: index,

212

isRoot: parent === null,

213

isLeaf: childCount === 0

214

};

215

}

216

217

console.log(analyzeNode(root));

218

// { hasParent: false, hasChildren: true, childCount: 2, siblingIndex: -1, isRoot: true, isLeaf: false }

219

220

console.log(analyzeNode(nodeB));

221

// { hasParent: true, hasChildren: false, childCount: 0, siblingIndex: 0, isRoot: false, isLeaf: true }

222

```

223

224

### Sorting and Ordering

225

226

```javascript

227

// Sort nodes by tree order

228

function sortByTreeOrder(nodes) {

229

return nodes.slice().sort((a, b) => {

230

const relation = tree.compareTreePosition(a, b);

231

232

if (relation & TreePosition.PRECEDING) return -1;

233

if (relation & TreePosition.FOLLOWING) return 1;

234

if (relation & TreePosition.CONTAINS) return -1;

235

if (relation & TreePosition.CONTAINED_BY) return 1;

236

if (relation & TreePosition.DISCONNECTED) {

237

// For disconnected nodes, fall back to name comparison

238

return a.name.localeCompare(b.name);

239

}

240

return 0; // Same node

241

});

242

}

243

244

const shuffledNodes = [nodeE, nodeB, root, nodeD, nodeA, nodeC];

245

const sortedNodes = sortByTreeOrder(shuffledNodes);

246

console.log(sortedNodes.map(n => n.name));

247

// ["root", "A", "B", "C", "D", "E"] (tree order)

248

249

// Find common ancestor

250

function findCommonAncestor(node1, node2) {

251

const ancestors1 = [...tree.ancestorsIterator(node1)];

252

const ancestors2 = [...tree.ancestorsIterator(node2)];

253

254

// Find first common ancestor

255

for (const ancestor1 of ancestors1) {

256

for (const ancestor2 of ancestors2) {

257

if (ancestor1 === ancestor2) {

258

return ancestor1;

259

}

260

}

261

}

262

263

return null; // No common ancestor (disconnected)

264

}

265

266

console.log(findCommonAncestor(nodeB, nodeC).name); // "A"

267

console.log(findCommonAncestor(nodeB, nodeE).name); // "root"

268

```

269

270

### Performance Monitoring

271

272

```javascript

273

// Monitor index calculation performance

274

function measureIndexPerformance(parent, iterations = 1000) {

275

const children = tree.childrenToArray(parent);

276

if (children.length === 0) return;

277

278

const startTime = performance.now();

279

280

for (let i = 0; i < iterations; i++) {

281

// Access index of random child

282

const randomChild = children[Math.floor(Math.random() * children.length)];

283

tree.index(randomChild);

284

}

285

286

const endTime = performance.now();

287

const avgTime = (endTime - startTime) / iterations;

288

289

console.log(`Average index lookup time: ${avgTime.toFixed(3)}ms`);

290

return avgTime;

291

}

292

293

// Create large tree for testing

294

const largeParent = { name: "largeParent" };

295

for (let i = 0; i < 1000; i++) {

296

tree.appendChild(largeParent, { name: `child${i}` });

297

}

298

299

measureIndexPerformance(largeParent);

300

```

301

302

### DOM-Style Position Analysis

303

304

```javascript

305

// Simulate DOM position methods

306

function contains(container, contained) {

307

if (container === contained) return true;

308

309

const relation = tree.compareTreePosition(container, contained);

310

return (relation & TreePosition.CONTAINS) !== 0;

311

}

312

313

function isBefore(node1, node2) {

314

const relation = tree.compareTreePosition(node1, node2);

315

return (relation & TreePosition.PRECEDING) !== 0;

316

}

317

318

function isAfter(node1, node2) {

319

const relation = tree.compareTreePosition(node1, node2);

320

return (relation & TreePosition.FOLLOWING) !== 0;

321

}

322

323

// Usage

324

console.log(contains(nodeA, nodeB)); // true (A contains B)

325

console.log(contains(nodeB, nodeA)); // false (B doesn't contain A)

326

console.log(isBefore(nodeA, nodeD)); // true (A comes before D)

327

console.log(isAfter(nodeD, nodeA)); // true (D comes after A)

328

329

// Find insertion point for ordered insertion

330

function findInsertionPoint(parent, newNode, compareFn) {

331

const children = tree.childrenToArray(parent);

332

333

for (let i = 0; i < children.length; i++) {

334

if (compareFn(newNode, children[i]) < 0) {

335

return children[i]; // Insert before this child

336

}

337

}

338

339

return null; // Insert at end

340

}

341

342

// Usage: insert in alphabetical order

343

const newChild = { name: "BB" };

344

const insertBefore = findInsertionPoint(nodeA, newChild,

345

(a, b) => a.name.localeCompare(b.name)

346

);

347

348

if (insertBefore) {

349

tree.insertBefore(insertBefore, newChild);

350

} else {

351

tree.appendChild(nodeA, newChild);

352

}

353

354

// Verify order

355

console.log(tree.childrenToArray(nodeA).map(c => c.name));

356

// ["B", "BB", "C"] (alphabetical order maintained)

357

```