Iterators

Iterators allow to traverse the tree.

Depth First

The DepthFirstIterator traverses the tree in a depth first manner. If no node is specified the tree is traversed from the root node.

m = meshsphere(1.0, 0.1)
tree = TwoNTree(vertices(m), 0.1)
println(collect(H2Trees.DepthFirstIterator(tree)))
[373, 391, 372, 392, 16, 55, 388, 15, 385, 57, 56, 14, 393, 61, 60, 390, 108, 107, 62, 395, 109, 19, 18, 17, 409, 394, 382, 59, 415, 58, 5, 4, 357, 358, 360, 403, 356, 364, 362, 363, 412, 368, 369, 361, 406, 400, 383, 106, 105, 3, 104, 401, 103, 376, 371, 370, 389, 26, 102, 404, 25, 24, 2, 208, 188, 187, 186, 139, 65, 66, 64, 68, 185, 67, 184, 183, 63, 125, 178, 9, 74, 8, 73, 205, 72, 190, 206, 189, 7, 153, 148, 177, 149, 147, 150, 146, 215, 181, 176, 145, 179, 182, 180, 71, 210, 70, 204, 138, 142, 211, 143, 137, 69, 140, 131, 198, 199, 130, 160, 152, 151, 133, 144, 132, 129, 6, 203, 128, 127, 209, 202, 201, 200, 124, 207, 126, 123, 122, 169, 168, 212, 214, 167, 134, 36, 193, 173, 196, 35, 195, 163, 174, 162, 158, 159, 157, 156, 161, 213, 216, 155, 154, 34, 166, 165, 164, 197, 33, 32, 31, 30, 172, 175, 29, 28, 171, 170, 194, 39, 38, 41, 42, 141, 192, 40, 191, 136, 135, 37, 27, 98, 398, 97, 407, 100, 101, 378, 99, 377, 367, 366, 96, 355, 354, 353, 359, 414, 352, 384, 410, 95, 408, 397, 94, 413, 411, 365, 405, 351, 375, 350, 379, 374, 349, 48, 47, 46, 54, 53, 347, 399, 52, 381, 402, 380, 348, 51, 50, 49, 45, 386, 44, 93, 387, 92, 396, 91, 13, 43, 12, 11, 10, 438, 90, 89, 494, 88, 491, 87, 86, 495, 434, 433, 85, 425, 492, 424, 503, 458, 457, 476, 477, 420, 505, 419, 418, 429, 493, 502, 498, 428, 456, 470, 455, 453, 454, 469, 452, 475, 483, 84, 417, 487, 83, 448, 449, 488, 447, 446, 445, 82, 471, 444, 443, 440, 78, 79, 499, 77, 497, 81, 80, 76, 75, 253, 316, 252, 307, 262, 320, 260, 259, 251, 304, 250, 249, 340, 264, 322, 230, 229, 246, 302, 245, 267, 266, 265, 228, 269, 274, 309, 282, 317, 268, 344, 289, 345, 343, 291, 290, 284, 283, 341, 292, 318, 237, 342, 236, 299, 240, 305, 313, 227, 226, 225, 254, 233, 303, 296, 232, 273, 293, 272, 312, 311, 331, 315, 314, 231, 224, 334, 239, 238, 330, 329, 328, 327, 223, 324, 308, 222, 221, 346, 333, 332, 248, 306, 247, 243, 261, 335, 325, 336, 242, 279, 280, 281, 339, 288, 278, 277, 276, 275, 285, 287, 286, 271, 270, 241, 298, 338, 297, 337, 235, 234, 323, 244, 263, 220, 219, 218, 295, 326, 294, 257, 310, 258, 319, 256, 301, 321, 300, 255, 217, 416, 121, 23, 439, 22, 442, 489, 441, 496, 120, 119, 21, 118, 508, 478, 490, 500, 117, 473, 468, 472, 465, 466, 467, 464, 482, 461, 463, 474, 460, 459, 507, 509, 437, 501, 481, 436, 116, 112, 113, 485, 435, 111, 115, 510, 114, 480, 479, 431, 484, 430, 110, 427, 506, 426, 504, 423, 432, 486, 422, 451, 462, 450, 421, 20, 1]

Parents Upward

The ParentUpwardsIterator is an iterator that iterates over all parent nodes of a given node in a tree until the root is reached. The last node is the node 0.

m = meshsphere(1.0, 0.1)
tree = TwoNTree(vertices(m), 0.1)
println(collect(H2Trees.ParentUpwardsIterator(tree, 373)))
[372, 14, 2, 1]

Children

The ChildIterator is an iterator over the children of a node in a tree.

m = meshsphere(1.0, 0.1)
tree = TwoNTree(vertices(m), 0.1)
println(collect(H2Trees.children(tree, H2Trees.root(tree))))
[2, 6, 27, 10, 75, 224, 217, 20]

Leaves

leaves returns an iterator over the leaf nodes in the tree, starting from the specified node. If no node is specified the tree is traversed from the root node.

m = meshsphere(1.0, 0.1)
tree = TwoNTree(vertices(m), 0.1)
println(collect(H2Trees.leaves(tree)))
[373, 391, 392, 16, 55, 388, 385, 57, 393, 61, 390, 108, 62, 395, 109, 19, 409, 394, 382, 59, 415, 5, 357, 358, 360, 403, 364, 362, 363, 412, 368, 369, 406, 400, 383, 106, 104, 401, 376, 371, 389, 26, 102, 404, 208, 188, 186, 139, 65, 66, 68, 185, 184, 125, 178, 9, 74, 73, 205, 190, 206, 153, 148, 177, 149, 150, 146, 215, 181, 176, 179, 182, 180, 71, 210, 204, 138, 142, 211, 143, 140, 131, 198, 199, 160, 152, 133, 144, 203, 128, 209, 202, 200, 124, 207, 126, 169, 168, 212, 214, 134, 36, 193, 173, 196, 195, 163, 174, 162, 158, 159, 156, 161, 213, 216, 155, 166, 165, 197, 33, 31, 30, 172, 175, 171, 194, 39, 41, 42, 141, 192, 191, 136, 98, 398, 407, 100, 101, 378, 377, 367, 355, 354, 353, 359, 414, 384, 410, 95, 408, 397, 413, 411, 365, 405, 351, 375, 379, 374, 349, 48, 54, 53, 347, 399, 381, 402, 348, 51, 45, 386, 93, 387, 396, 91, 13, 43, 438, 90, 89, 494, 491, 87, 495, 434, 425, 492, 503, 458, 476, 477, 420, 505, 429, 493, 502, 498, 456, 470, 455, 453, 454, 469, 475, 483, 84, 417, 487, 448, 449, 488, 447, 446, 471, 444, 440, 78, 79, 499, 497, 81, 253, 316, 307, 262, 320, 260, 251, 304, 340, 264, 322, 230, 246, 302, 267, 266, 269, 274, 309, 282, 317, 344, 289, 345, 343, 291, 290, 284, 341, 292, 318, 237, 342, 299, 240, 305, 313, 227, 254, 233, 303, 296, 273, 293, 312, 331, 315, 334, 239, 330, 329, 327, 223, 324, 308, 346, 333, 332, 248, 306, 243, 261, 335, 325, 336, 279, 280, 281, 339, 288, 278, 277, 275, 285, 287, 286, 271, 298, 338, 337, 235, 323, 244, 263, 220, 295, 326, 257, 310, 258, 319, 301, 321, 416, 121, 23, 439, 442, 489, 496, 120, 118, 508, 478, 490, 500, 473, 468, 472, 465, 466, 467, 482, 461, 463, 474, 460, 507, 509, 437, 501, 481, 112, 113, 485, 435, 115, 510, 480, 431, 484, 427, 506, 504, 423, 432, 486, 451, 462]

Level Iterator

LevelIterator return an iterator over the nodes at the specified level in the tree.

m = meshsphere(1.0, 0.1)
tree = TwoNTree(vertices(m), 0.1)
println(collect(H2Trees.LevelIterator(tree,2)))
[2, 6, 10, 20, 27, 75, 217, 224]

Same Level Nodes

[SameLevelIterator] returns an iterator over the nodes at the same level as node in the tree.

m = meshsphere(1.0, 0.1)
tree = TwoNTree(vertices(m), 0.1)
println(collect(H2Trees.SameLevelIterator(tree,3)))
[3, 7, 11, 14, 17, 21, 24, 28, 34, 37, 46, 49, 63, 69, 76, 82, 85, 96, 110, 116, 122, 129, 218, 221, 225, 228, 231, 241, 249, 255, 418, 421]

Near- and Far Nodes

The NearNodeIterator returns, in the Galerkin case, an iterator over the nodes in the tree that are at the same level as the specified node and are near to node. Two nodes are near if the function isnear(tree, nodea, nodeb) evaluates to true.

m = meshsphere(1.0, 0.1)
tree = TwoNTree(vertices(m), 0.1)
println("node 4 is at level ", H2Trees.level(tree, 4))
println("nodes near to node 4: ", collect(H2Trees.NearNodeIterator(tree, 4)))
node 4 is at level 4
nodes near to node 4: [4, 58, 105, 137, 352, 356, 361, 436]

In the Petrov-Galerkin case the NearNodeIterator returns an iterator over the nodes in the testtree that are at the same level as the specified node in the trialtree and are near to node. Two nodes are near if the function isnear(testtree, trialtree, testnode, trialnode) evaluates to true.

mx = meshsphere(1.0, 0.1)
my = meshsphere(2.0, 0.1)

testtree = TwoNTree(vertices(mx), 0.1)
trialtree = TwoNTree(vertices(my), 0.1)
println("trial node 4 is at level ", H2Trees.level(trialtree, 4))
println("nodes near to trial node 4: ", collect(H2Trees.NearNodeIterator(testtree, trialtree, 4)))
trial node 4 is at level 4
nodes near to trial node 4: [4, 15, 18, 25, 47, 50, 52, 56, 58, 60, 64, 67, 70, 94, 97, 99, 103, 105, 107, 111, 114, 117, 123, 127, 130, 132, 137, 145, 147, 151, 154, 167, 183, 187, 201, 242, 247, 256, 294, 300, 350, 352, 356, 361, 366, 370, 372, 380, 419, 422, 424, 426, 428, 430, 436, 445, 450, 457, 459, 464, 479]

The FarNodeIterator is defined accordingly.

Well Separated Nodes

The WellSeparatedIterator is used to identify which translations should occur and which should not. This determination is based on the concept of well-separated nodes.

Note

Two nodes are considered well-separated if their parents are near each other and the nodes themselves are far apart. This assumes that child clusters are completely inside their parent clusters.

The WellSeparatedIterator can be configured using either an isnear or an iswellseparated function.

The following example demonstrates the usage of the WellSeparatedIterator in the Galerkin-case

m = meshsphere(1.0, 0.1)
tree = KMeansTree(vertices(m), 4; minvalues=60)

# Using the WellSeparatedIterator with the default isnear() function
println("First iterator\t", collect(H2Trees.WellSeparatedIterator(tree, 3)))

# Creating a functor without specifying a tree first
functor = H2Trees.WellSeparatedIterator()
iterator = functor(tree)
println("Second iterator\t", collect(iterator(tree, 3)))

# Specifying a custom iswellseparated criterion
functor = H2Trees.WellSeparatedIterator(; iswellseparated=(tree) -> (tree, nodea, nodeb) -> iseven(nodea))
iterator = functor(tree)
println("Third iterator\t", collect(iterator(tree, 3)))

# Specifying a custom isnear criterion
functor = H2Trees.WellSeparatedIterator(; isnear=(tree) -> (tree, nodea, nodeb) -> iseven(nodea))
iterator = functor(tree)
println("Fourth iterator\t", collect(iterator(tree, 3)))
First iterator	[39, 50]
Second iterator	[39, 50]
Third iterator	[8, 18, 24, 34, 50, 60, 66, 76]
Fourth iterator	[3, 13, 45, 55]

When defining the isnear or iswellseparated criterion, it is necessary to provide a function that takes a tree as input and returns another function. This returned function is then used to evaluate the criterion.

At first glance, this may seem like an unnecessary layer of indirection. However, it actually provides a significant advantage: it enables precomputations that can be performed only once, when the criterion function is first created, rather than every time the iterator is called.

By allowing the initial function to perform any necessary precomputations and store the results, the returned function can then simply use these precomputed values to evaluate the criterion. This can significantly improve performance, especially when working with large trees or complex criteria.

For the Petrov-Galerkin case, we assume that translations occur from the trialtree to the testtree. This scenario can be demonstrated with the following example

mx = meshsphere(1.0, 0.1)
my = meshsphere(2.0, 0.1)

tree = TwoNTree(vertices(mx), vertices(my), 0.1)

# Using the WellSeparatedIterator with the default isnear() function
println("First iterator\t", collect(H2Trees.WellSeparatedIterator(tree, 4)))

# Creating a functor without specifying a tree first
functor = H2Trees.WellSeparatedIterator()
iterator = functor(tree)
println("Second iterator\t", collect(iterator(H2Trees.testtree(tree), H2Trees.trialtree(tree), 4)))

# Specifying a custom iswellseparated criterion
functor = H2Trees.WellSeparatedIterator(;
    iswellseparated=(tree) -> (testtree, trialtree, testnode, trialnode) -> iseven(testnode)
)
iterator = functor(tree)
println("Third iterator\t", collect(iterator(H2Trees.testtree(tree), H2Trees.trialtree(tree), 4)))

# Specifying a custom isnear criterion
functor = H2Trees.WellSeparatedIterator(;
    isnear=(tree) -> (testtree, trialtree, testnode, trialnode) -> iseven(testnode)
)
iterator = functor(tree)
println("Fourth iterator\t", collect(iterator(H2Trees.testtree(tree), H2Trees.trialtree(tree), 4)))
First iterator	[7, 11, 21, 28, 37, 76, 85, 218, 221, 228, 231, 249]
Second iterator	[7, 11, 21, 28, 37, 76, 85, 218, 221, 228, 231, 249]
Third iterator	[14, 24, 28, 34, 46, 76, 82, 96, 110, 116, 122, 218, 228, 418]
Fourth iterator	[3, 7, 11, 17, 21, 49, 63, 69, 129, 225, 231, 249, 421]

In general, it is more efficient to use functors instead of functions in this context.

Translating Nodes

The TranslatingNodesIterator is a wrapper for the WellSeparatedIterator.

Filtering Nodes

NodeFilterIterator returns an iterator over nodes at the same level as trialnode in trialtree, for which the function filter(testtree, trialtree, testnode, trialnode) return true. In the case of a tree with the trait isBlockTree, it is assumed that trialnode is belonging to the trialtree. For the Galerkin case, we have

m = meshsphere(1.0, 0.1)
tree = TwoNTree(vertices(m), 0.1)
println(collect(H2Trees.NodeFilterIterator(tree, 3, (tree, nodea, nodeb)-> iseven(nodea))))
[14, 24, 28, 34, 46, 76, 82, 96, 110, 116, 122, 218, 228, 418]

and for the Petrov-Galerkin case

mx = meshsphere(1.0, 0.1)
my = meshsphere(2.0, 0.1)

tree = TwoNTree(vertices(mx), vertices(my), 0.1)
testtree = H2Trees.testtree(tree)
trialtree = H2Trees.trialtree(tree)
println(collect(H2Trees.NodeFilterIterator(tree, 3, (testree, trialtree, testnode, trialnode)-> iseven(testnode))))
[2, 6, 10, 20, 224]

and

mx = meshsphere(1.0, 0.1)
my = meshsphere(2.0, 0.1)

tree = TwoNTree(vertices(mx), vertices(my), 0.1)
testtree = H2Trees.testtree(tree)
trialtree = H2Trees.trialtree(tree)
println(collect(H2Trees.NodeFilterIterator(testtree, trialtree, 3, (testree, trialtree, testnode, trialnode)-> iseven(testnode))))
[2, 6, 10, 20, 224]