From 6839a7e06c731b2629a2846e4e0d512d985d99f5 Mon Sep 17 00:00:00 2001 From: Alessandro Mauri Date: Tue, 23 Sep 2025 23:30:11 +0200 Subject: [PATCH] documentation of mtree --- lib/ugui.c3l/src/mtree.c3 | 169 +++++++++++++++++++++++++------------- 1 file changed, 114 insertions(+), 55 deletions(-) diff --git a/lib/ugui.c3l/src/mtree.c3 b/lib/ugui.c3l/src/mtree.c3 index ee4ba38..22d4cc8 100644 --- a/lib/ugui.c3l/src/mtree.c3 +++ b/lib/ugui.c3l/src/mtree.c3 @@ -1,5 +1,64 @@ module mtree{Type}; +/* ================================================================================================ + * MTree, Bitmap-based tree + * ================================================================================================ + * + * Overview + * -------- + * The MTree is a bitmap-based tree structure composed of three core elements: + * - Element Vector: Stores user data. + * - Reference Node Vector: Manages node relationships. + * - Bitmap: Marks used indices. + * + * The name "MTree" originates from "Matrix Tree," where the vector is divided into + * sectors of power-of-two sizes. Each node's bitmap marks the positions of its + * children within the same sector. + * + * If a parent and its children are in different sectors, a new node is created. + * The parent's "next" field points to this new node, forming a chain that must + * be traversed during iteration. + * + * + * Example (sector size = 8) + * ------------------------- + * + * _________________________________ + * |__ __ _______________________ | + * | | | | _ | + * | v v vv |v + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * refs_vec:| 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|15|16|... + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * \__________ __________/ \__________ __________/ \__ + * V V + * sector 0 sector 1 + * + * + * Node Relationships: + * ------------------- + * - Root (Element 0) has three direct children: 1, 2, and 10. + * - Node 10 is in a different sector than the root, so root.next points to Node 11. + * - Node 11 has Node 10 as a direct child and Node 0 (root) as its parent. + * + * Bitmap Representation: + * --------------------- + * + * root = { + * .parent = -1; // Root has no parent + * .next = 11; // Points to Node 11 + * .children = 0b00000110; // [0|1|1|0|0|0|0|0] (Children: 1, 2) + * } + * + * node11 = { + * .parent = 0; // Parent is root (Node 0) + * .next = -1; // Last in the chain + * .children = 0b00000100; // [0|0|1|0|0|0|0|0] (Child: 10) + * } + * + * ================================================================================================ + */ + import std::core::mem; import std::core::mem::allocator; import std::io; @@ -12,9 +71,9 @@ const BITS = Bitmap.sizeof*8; alias IdxList = List{int}; -// more: if positive it contains the index of the next node that contains the children information -struct Node { - int more; +// next: if positive it contains the index of the next node that contains the children information +struct RefNode { + int next; int parent; Bitmap children; } @@ -23,9 +82,9 @@ struct MTree { usz elements; Allocator allocator; IdxList queue; - Bitmap[] used; - Type[] elem_mat; // element matrix - Node[] refs_mat; // relationship matrix + Bitmap[] used; + Type[] elem_vec; // element vector + RefNode[] refs_vec; // relationship vector } @@ -38,11 +97,11 @@ fn void MTree.init(&tree, usz size, Allocator allocator = mem) tree.allocator = allocator; tree.queue.init(tree.allocator, size); tree.used = allocator::new_array(tree.allocator, Bitmap, size/BITS); - tree.elem_mat = allocator::new_array(tree.allocator, Type, size); - tree.refs_mat = allocator::new_array(tree.allocator, Node, size); - - foreach (&r: tree.refs_mat) { - r.more = -1; + tree.elem_vec = allocator::new_array(tree.allocator, Type, size); + tree.refs_vec = allocator::new_array(tree.allocator, RefNode, size); + + foreach (&r: tree.refs_vec) { + r.next = -1; } } @@ -52,8 +111,8 @@ fn void MTree.free(&tree) tree.elements = 0; tree.queue.free(); (void)allocator::free(tree.allocator, tree.used); - (void)allocator::free(tree.allocator, tree.elem_mat); - (void)allocator::free(tree.allocator, tree.refs_mat); + (void)allocator::free(tree.allocator, tree.elem_vec); + (void)allocator::free(tree.allocator, tree.refs_vec); } @@ -69,7 +128,7 @@ fn int MTree.get_free_spot(&tree) } <* @require idx >= 0 *> -fn void MTree.set_used(&tree, int idx) +macro void MTree.set_used(&tree, int idx) { int r = idx % BITS; int q = idx / BITS; @@ -77,7 +136,7 @@ fn void MTree.set_used(&tree, int idx) } <* @require idx >= 0 *> -fn void MTree.unset_used(&tree, int idx) +macro void MTree.unset_used(&tree, int idx) { int r = idx % BITS; int q = idx / BITS; @@ -85,7 +144,7 @@ fn void MTree.unset_used(&tree, int idx) } <* @require idx >= 0 *> -fn bool MTree.is_used(&tree, int idx) +macro bool MTree.is_used(&tree, int idx) { int r = idx % BITS; int q = idx / BITS; @@ -93,12 +152,12 @@ fn bool MTree.is_used(&tree, int idx) } -// get the last node in the "more" chain +// get the last node in the "next" chain <* @require tree.is_used(parent) == true *> fn int MTree.last_node(&tree, int parent) { - while(tree.refs_mat[parent].more >= 0) { - parent = tree.refs_mat[parent].more; + while(tree.refs_vec[parent].next >= 0) { + parent = tree.refs_vec[parent].next; } return parent; } @@ -111,48 +170,48 @@ fn int MTree.add(&tree, int parent, Type t) int subtree = idx / BITS; tree.set_used(idx); - tree.elem_mat[idx] = t; - tree.refs_mat[idx] = (Node){ + tree.elem_vec[idx] = t; + tree.refs_vec[idx] = (RefNode){ .parent = parent, - .more = -1, + .next = -1, }; - + tree.elements++; // root element, has no parent if (tree.elements == 1) { - tree.refs_mat[idx].parent = -1; + tree.refs_vec[idx].parent = -1; return idx; } - + // if the parent already has a node in the same subtree as the child then update that node's // children bitmap bool done; - for (int p = parent; p >= 0; p = tree.refs_mat[p].more) { + for (int p = parent; p >= 0; p = tree.refs_vec[p].next) { int ps = p/BITS; if (ps == subtree) { - tree.refs_mat[p].children |= (1l << (idx%BITS)); + tree.refs_vec[p].children |= (1l << (idx%BITS)); done = true; break; } } // on fail we need to create another parent node if (!done) { - int new_more = tree.get_free_spot(); + int new_next = tree.get_free_spot(); // if the new node does not land in the same subtree as the child we cannot do // anything since the references are immutable - if (new_more/BITS != subtree) { + if (new_next/BITS != subtree) { unreachable("cannot allocate new child for parent"); } - tree.set_used(new_more); + tree.set_used(new_next); tree.elements++; - // update the "more" chain + // update the "next" chain int last_link = tree.last_node(parent); - tree.refs_mat[last_link].more = new_more; - tree.refs_mat[new_more].more = -1; - tree.refs_mat[new_more].children |= (long)(1 << (idx%BITS)); - tree.refs_mat[new_more].parent = last_link; - // FIXME: the elem_mat is not updated, do we need to? + tree.refs_vec[last_link].next = new_next; + tree.refs_vec[new_next].next = -1; + tree.refs_vec[new_next].children |= (long)(1 << (idx%BITS)); + tree.refs_vec[new_next].parent = last_link; + // FIXME: the elem_vec is not updated, do we need to? } return idx; @@ -165,15 +224,15 @@ fn int MTree.children_it(&tree, int parent, int n) { int tot_children; int child; - for (int p = parent; p >= 0; p = tree.refs_mat[p].more) { - int cn = (int)tree.refs_mat[p].children.popcount(); + for (int p = parent; p >= 0; p = tree.refs_vec[p].next) { + int cn = (int)tree.refs_vec[p].children.popcount(); tot_children += cn; // we are in the right subtree if (tot_children > n) { child = (p/BITS) * BITS; // start at the parent's subtree index int j = cn - (tot_children - n); // we need the j-th children of this node - Bitmap u = tree.refs_mat[p].children; + Bitmap u = tree.refs_vec[p].children; child += j; // add the children number do { @@ -191,8 +250,8 @@ fn int MTree.children_it(&tree, int parent, int n) fn int MTree.children_num(&tree, int parent) { int n; - for (int p = parent; p >= 0; p = tree.refs_mat[p].more) { - n += (int)tree.refs_mat[p].children.popcount(); + for (int p = parent; p >= 0; p = tree.refs_vec[p].next) { + n += (int)tree.refs_vec[p].children.popcount(); } return n; } @@ -215,7 +274,7 @@ fn int MTree.level_order_it(&tree, int parent, int i) tree.queue.clear(); tree.queue.push(parent); } - + if (tree.queue.len() == 0) return -1; int p = tree.queue.pop_first()!!; @@ -232,11 +291,11 @@ fn void MTree.prune(&tree, int parent) for (int i = 0; (c = tree.children_it(parent, i)) >= 0; i++) { tree.prune(c); // prune the subtree - // delete all children including their more chain + // delete all children including their next chain for (int p = c; p >= 0;) { - int next = tree.refs_mat[p].more; + int next = tree.refs_vec[p].next; tree.unset_used(p); - tree.refs_mat[p] = {.more = -1}; + tree.refs_vec[p] = {.next = -1}; p = next; } @@ -244,40 +303,40 @@ fn void MTree.prune(&tree, int parent) // finally delete the parent for (int p = parent; p >= 0;) { - int next = tree.refs_mat[p].more; + int next = tree.refs_vec[p].next; tree.unset_used(p); tree.elements--; - tree.refs_mat[p] = {.more = -1}; + tree.refs_vec[p] = {.next = -1}; p = next; } } <* @require tree.is_used(ref) *> -fn Type MTree.get(&tree, int ref) => tree.elem_mat[ref]; +fn Type MTree.get(&tree, int ref) => tree.elem_vec[ref]; <* @require tree.is_used(ref) *> -fn Type MTree.parentof(&tree, int ref) => tree.refs_mat[ref].parent; +fn Type MTree.parentof(&tree, int ref) => tree.refs_vec[ref].parent; fn void MTree.nuke(&tree) { foreach (idx, &b: tree.used) { *b = 0; - tree.refs_mat[idx] = {.more = -1}; + tree.refs_vec[idx] = {.next = -1}; } tree.elements = 0; } -macro bool MTree.is_root(&t, int i) => t.refs_mat[i].parent == -1; +macro bool MTree.is_root(&t, int i) => t.refs_vec[i].parent == -1; fn void MTree.print(&tree) { - foreach (idx, c: tree.elem_mat) { + foreach (idx, c: tree.elem_vec) { if (tree.is_used((int)idx)) { - io::printfn("[%d](%s) parent:%d more:%d children:%b", - idx, c, tree.refs_mat[idx].parent, tree.refs_mat[idx].more, - tree.refs_mat[idx].children + io::printfn("[%d](%s) parent:%d next:%d children:%b", + idx, c, tree.refs_vec[idx].parent, tree.refs_vec[idx].next, + tree.refs_vec[idx].children ); } }