or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdnode-operations.mdtree-analysis.mdtree-io.mdtree-manipulation.mdtree-traversal.mdvisualization.md

tree-traversal.mddocs/

0

# Tree Traversal

1

2

TreeSwift provides comprehensive tree traversal methods implemented as memory-efficient generators. All traversal methods support filtering by node type (leaves, internal nodes, or both) and provide flexible iteration patterns for different algorithmic needs.

3

4

## Capabilities

5

6

### Preorder Traversal

7

8

Visits nodes in preorder: current node first, then recursively visit children. Useful for top-down tree processing and copying operations.

9

10

```python { .api }

11

def traverse_preorder(self, leaves: bool = True, internal: bool = True) -> Generator[Node, None, None]:

12

"""

13

Perform preorder traversal starting at this node.

14

15

Parameters:

16

- leaves (bool): Include leaf nodes in traversal

17

- internal (bool): Include internal nodes in traversal

18

19

Yields:

20

- Node: Nodes in preorder sequence

21

"""

22

```

23

24

Usage examples:

25

26

```python

27

import treeswift

28

29

tree = treeswift.read_tree_newick("((A,B),(C,D));")

30

31

# Traverse all nodes in preorder

32

for node in tree.traverse_preorder():

33

print(f"Node: {node.get_label()}, is_leaf: {node.is_leaf()}")

34

35

# Traverse only leaves

36

for leaf in tree.traverse_preorder(internal=False):

37

print(f"Leaf: {leaf.get_label()}")

38

39

# Traverse only internal nodes

40

for internal_node in tree.traverse_preorder(leaves=False):

41

print(f"Internal node with {internal_node.num_children()} children")

42

```

43

44

### Postorder Traversal

45

46

Visits children first, then the current node. Essential for bottom-up computations like calculating subtree statistics.

47

48

```python { .api }

49

def traverse_postorder(self, leaves: bool = True, internal: bool = True) -> Generator[Node, None, None]:

50

"""

51

Perform postorder traversal starting at this node.

52

53

Parameters:

54

- leaves (bool): Include leaf nodes in traversal

55

- internal (bool): Include internal nodes in traversal

56

57

Yields:

58

- Node: Nodes in postorder sequence

59

"""

60

```

61

62

Usage examples:

63

64

```python

65

import treeswift

66

67

tree = treeswift.read_tree_newick("((A:0.1,B:0.2):0.5,(C:0.3,D:0.4):0.6):0.0;")

68

69

# Calculate subtree sums in postorder

70

subtree_sums = {}

71

for node in tree.traverse_postorder():

72

if node.is_leaf():

73

subtree_sums[node] = node.get_edge_length() or 0

74

else:

75

subtree_sums[node] = sum(subtree_sums[child] for child in node.children)

76

if node.get_edge_length():

77

subtree_sums[node] += node.get_edge_length()

78

79

print(f"Total tree length: {subtree_sums[tree.root]}")

80

```

81

82

### Level-order Traversal

83

84

Visits nodes level by level (breadth-first), useful for level-based algorithms and visualization.

85

86

```python { .api }

87

def traverse_levelorder(self, leaves: bool = True, internal: bool = True) -> Generator[Node, None, None]:

88

"""

89

Perform level-order (breadth-first) traversal starting at this node.

90

91

Parameters:

92

- leaves (bool): Include leaf nodes in traversal

93

- internal (bool): Include internal nodes in traversal

94

95

Yields:

96

- Node: Nodes in level-order sequence

97

"""

98

```

99

100

Usage examples:

101

102

```python

103

import treeswift

104

105

tree = treeswift.read_tree_newick("(((A,B),C),((D,E),F));")

106

107

# Print tree structure level by level

108

current_level = 0

109

nodes_at_level = []

110

111

for node in tree.traverse_levelorder():

112

# Calculate node depth

113

depth = 0

114

curr = node

115

while curr.parent is not None:

116

depth += 1

117

curr = curr.parent

118

119

if depth > current_level:

120

if nodes_at_level:

121

print(f"Level {current_level}: {[n.get_label() or 'internal' for n in nodes_at_level]}")

122

current_level = depth

123

nodes_at_level = []

124

125

nodes_at_level.append(node)

126

127

if nodes_at_level:

128

print(f"Level {current_level}: {[n.get_label() or 'internal' for n in nodes_at_level]}")

129

```

130

131

### Inorder Traversal

132

133

For binary trees, visits left subtree, current node, then right subtree. Raises error for non-binary trees.

134

135

```python { .api }

136

def traverse_inorder(self, leaves: bool = True, internal: bool = True) -> Generator[Node, None, None]:

137

"""

138

Perform inorder traversal starting at this node (binary trees only).

139

140

Parameters:

141

- leaves (bool): Include leaf nodes in traversal

142

- internal (bool): Include internal nodes in traversal

143

144

Yields:

145

- Node: Nodes in inorder sequence

146

147

Raises:

148

- RuntimeError: If tree contains non-binary nodes

149

"""

150

```

151

152

Usage examples:

153

154

```python

155

import treeswift

156

157

# Binary tree

158

tree = treeswift.read_tree_newick("((A,B),(C,D));")

159

160

try:

161

for node in tree.traverse_inorder():

162

print(f"Node: {node.get_label() or 'internal'}")

163

except RuntimeError as e:

164

print(f"Error: {e}")

165

166

# This will raise an error (non-binary)

167

try:

168

tree = treeswift.read_tree_newick("(A,B,C);")

169

for node in tree.traverse_inorder():

170

print(node)

171

except RuntimeError as e:

172

print(f"Cannot perform inorder on non-binary tree: {e}")

173

```

174

175

### Root Distance Order Traversal

176

177

Visits nodes ordered by their distance from the root, either ascending or descending.

178

179

```python { .api }

180

def traverse_rootdistorder(self, ascending: bool = True, leaves: bool = True, internal: bool = True) -> Generator[tuple[float, Node], None, None]:

181

"""

182

Traverse nodes ordered by distance from root.

183

184

Parameters:

185

- ascending (bool): True for ascending distance order, False for descending

186

- leaves (bool): Include leaf nodes in traversal

187

- internal (bool): Include internal nodes in traversal

188

189

Yields:

190

- tuple[float, Node]: (distance_from_root, node) pairs in distance order

191

"""

192

```

193

194

Usage examples:

195

196

```python

197

import treeswift

198

199

tree = treeswift.read_tree_newick("((A:0.1,B:0.2):0.3,(C:0.4,D:0.5):0.6):0.0;")

200

201

# Nodes by increasing distance from root

202

print("Nodes by distance from root (ascending):")

203

for distance, node in tree.traverse_rootdistorder(ascending=True):

204

label = node.get_label() or "internal"

205

print(f" {distance:.1f}: {label}")

206

207

# Nodes by decreasing distance from root (leaves first)

208

print("\nNodes by distance from root (descending):")

209

for distance, node in tree.traverse_rootdistorder(ascending=False):

210

label = node.get_label() or "internal"

211

print(f" {distance:.1f}: {label}")

212

213

# Only leaves by distance

214

print("\nLeaves by distance from root:")

215

for distance, node in tree.traverse_rootdistorder(internal=False):

216

print(f" {distance:.1f}: {node.get_label()}")

217

```

218

219

### Specialized Traversal Methods

220

221

Convenience methods for specific node types.

222

223

```python { .api }

224

def traverse_leaves(self) -> Generator[Node, None, None]:

225

"""Traverse only leaf nodes (convenience method)."""

226

227

def traverse_internal(self) -> Generator[Node, None, None]:

228

"""Traverse only internal nodes (convenience method)."""

229

```

230

231

Usage examples:

232

233

```python

234

import treeswift

235

236

tree = treeswift.read_tree_newick("((A,B),(C,D));")

237

238

# Get all leaf labels

239

leaf_labels = [node.get_label() for node in tree.traverse_leaves()]

240

print(f"Leaves: {leaf_labels}")

241

242

# Count internal nodes

243

internal_count = sum(1 for node in tree.traverse_internal())

244

print(f"Internal nodes: {internal_count}")

245

```

246

247

### Node-level Traversal Methods

248

249

Individual nodes also support traversal methods for subtree operations.

250

251

```python { .api }

252

# Node class methods

253

def traverse_preorder(self, leaves: bool = True, internal: bool = True) -> Generator[Node, None, None]:

254

"""Preorder traversal starting from this node."""

255

256

def traverse_postorder(self, leaves: bool = True, internal: bool = True) -> Generator[Node, None, None]:

257

"""Postorder traversal starting from this node."""

258

259

def traverse_levelorder(self, leaves: bool = True, internal: bool = True) -> Generator[Node, None, None]:

260

"""Level-order traversal starting from this node."""

261

262

def traverse_ancestors(self, include_self: bool = True) -> Generator[Node, None, None]:

263

"""Traverse ancestors of this node toward root."""

264

265

def traverse_bfs(self, include_self: bool = True) -> Generator[tuple[Node, float], None, None]:

266

"""Breadth-first search yielding (node, distance) pairs."""

267

```

268

269

Usage examples:

270

271

```python

272

import treeswift

273

274

tree = treeswift.read_tree_newick("(((A,B),C),((D,E),F));")

275

276

# Find a specific leaf and traverse its ancestors

277

for node in tree.traverse_leaves():

278

if node.get_label() == "A":

279

print("Ancestors of A:")

280

for ancestor in node.traverse_ancestors():

281

label = ancestor.get_label() or f"internal({ancestor.num_children()} children)"

282

print(f" {label}")

283

break

284

285

# BFS from a specific internal node

286

internal_nodes = list(tree.traverse_internal())

287

if internal_nodes:

288

start_node = internal_nodes[0]

289

print(f"\nBFS from internal node:")

290

for node, distance in start_node.traverse_bfs():

291

label = node.get_label() or "internal"

292

print(f" Distance {distance}: {label}")

293

```