documentation of mtree
This commit is contained in:
parent
7f8b5196a5
commit
6839a7e06c
@ -1,5 +1,64 @@
|
|||||||
module mtree{Type};
|
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;
|
||||||
import std::core::mem::allocator;
|
import std::core::mem::allocator;
|
||||||
import std::io;
|
import std::io;
|
||||||
@ -12,9 +71,9 @@ const BITS = Bitmap.sizeof*8;
|
|||||||
|
|
||||||
alias IdxList = List{int};
|
alias IdxList = List{int};
|
||||||
|
|
||||||
// more: if positive it contains the index of the next node that contains the children information
|
// next: if positive it contains the index of the next node that contains the children information
|
||||||
struct Node {
|
struct RefNode {
|
||||||
int more;
|
int next;
|
||||||
int parent;
|
int parent;
|
||||||
Bitmap children;
|
Bitmap children;
|
||||||
}
|
}
|
||||||
@ -23,9 +82,9 @@ struct MTree {
|
|||||||
usz elements;
|
usz elements;
|
||||||
Allocator allocator;
|
Allocator allocator;
|
||||||
IdxList queue;
|
IdxList queue;
|
||||||
Bitmap[] used;
|
Bitmap[] used;
|
||||||
Type[] elem_mat; // element matrix
|
Type[] elem_vec; // element vector
|
||||||
Node[] refs_mat; // relationship matrix
|
RefNode[] refs_vec; // relationship vector
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -38,11 +97,11 @@ fn void MTree.init(&tree, usz size, Allocator allocator = mem)
|
|||||||
tree.allocator = allocator;
|
tree.allocator = allocator;
|
||||||
tree.queue.init(tree.allocator, size);
|
tree.queue.init(tree.allocator, size);
|
||||||
tree.used = allocator::new_array(tree.allocator, Bitmap, size/BITS);
|
tree.used = allocator::new_array(tree.allocator, Bitmap, size/BITS);
|
||||||
tree.elem_mat = allocator::new_array(tree.allocator, Type, size);
|
tree.elem_vec = allocator::new_array(tree.allocator, Type, size);
|
||||||
tree.refs_mat = allocator::new_array(tree.allocator, Node, size);
|
tree.refs_vec = allocator::new_array(tree.allocator, RefNode, size);
|
||||||
|
|
||||||
foreach (&r: tree.refs_mat) {
|
foreach (&r: tree.refs_vec) {
|
||||||
r.more = -1;
|
r.next = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,8 +111,8 @@ fn void MTree.free(&tree)
|
|||||||
tree.elements = 0;
|
tree.elements = 0;
|
||||||
tree.queue.free();
|
tree.queue.free();
|
||||||
(void)allocator::free(tree.allocator, tree.used);
|
(void)allocator::free(tree.allocator, tree.used);
|
||||||
(void)allocator::free(tree.allocator, tree.elem_mat);
|
(void)allocator::free(tree.allocator, tree.elem_vec);
|
||||||
(void)allocator::free(tree.allocator, tree.refs_mat);
|
(void)allocator::free(tree.allocator, tree.refs_vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -69,7 +128,7 @@ fn int MTree.get_free_spot(&tree)
|
|||||||
}
|
}
|
||||||
|
|
||||||
<* @require idx >= 0 *>
|
<* @require idx >= 0 *>
|
||||||
fn void MTree.set_used(&tree, int idx)
|
macro void MTree.set_used(&tree, int idx)
|
||||||
{
|
{
|
||||||
int r = idx % BITS;
|
int r = idx % BITS;
|
||||||
int q = idx / BITS;
|
int q = idx / BITS;
|
||||||
@ -77,7 +136,7 @@ fn void MTree.set_used(&tree, int idx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
<* @require idx >= 0 *>
|
<* @require idx >= 0 *>
|
||||||
fn void MTree.unset_used(&tree, int idx)
|
macro void MTree.unset_used(&tree, int idx)
|
||||||
{
|
{
|
||||||
int r = idx % BITS;
|
int r = idx % BITS;
|
||||||
int q = idx / BITS;
|
int q = idx / BITS;
|
||||||
@ -85,7 +144,7 @@ fn void MTree.unset_used(&tree, int idx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
<* @require idx >= 0 *>
|
<* @require idx >= 0 *>
|
||||||
fn bool MTree.is_used(&tree, int idx)
|
macro bool MTree.is_used(&tree, int idx)
|
||||||
{
|
{
|
||||||
int r = idx % BITS;
|
int r = idx % BITS;
|
||||||
int q = 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 *>
|
<* @require tree.is_used(parent) == true *>
|
||||||
fn int MTree.last_node(&tree, int parent)
|
fn int MTree.last_node(&tree, int parent)
|
||||||
{
|
{
|
||||||
while(tree.refs_mat[parent].more >= 0) {
|
while(tree.refs_vec[parent].next >= 0) {
|
||||||
parent = tree.refs_mat[parent].more;
|
parent = tree.refs_vec[parent].next;
|
||||||
}
|
}
|
||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
@ -111,48 +170,48 @@ fn int MTree.add(&tree, int parent, Type t)
|
|||||||
int subtree = idx / BITS;
|
int subtree = idx / BITS;
|
||||||
|
|
||||||
tree.set_used(idx);
|
tree.set_used(idx);
|
||||||
tree.elem_mat[idx] = t;
|
tree.elem_vec[idx] = t;
|
||||||
tree.refs_mat[idx] = (Node){
|
tree.refs_vec[idx] = (RefNode){
|
||||||
.parent = parent,
|
.parent = parent,
|
||||||
.more = -1,
|
.next = -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
tree.elements++;
|
tree.elements++;
|
||||||
// root element, has no parent
|
// root element, has no parent
|
||||||
if (tree.elements == 1) {
|
if (tree.elements == 1) {
|
||||||
tree.refs_mat[idx].parent = -1;
|
tree.refs_vec[idx].parent = -1;
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// if the parent already has a node in the same subtree as the child then update that node's
|
// if the parent already has a node in the same subtree as the child then update that node's
|
||||||
// children bitmap
|
// children bitmap
|
||||||
bool done;
|
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;
|
int ps = p/BITS;
|
||||||
if (ps == subtree) {
|
if (ps == subtree) {
|
||||||
tree.refs_mat[p].children |= (1l << (idx%BITS));
|
tree.refs_vec[p].children |= (1l << (idx%BITS));
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// on fail we need to create another parent node
|
// on fail we need to create another parent node
|
||||||
if (!done) {
|
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
|
// if the new node does not land in the same subtree as the child we cannot do
|
||||||
// anything since the references are immutable
|
// anything since the references are immutable
|
||||||
if (new_more/BITS != subtree) {
|
if (new_next/BITS != subtree) {
|
||||||
unreachable("cannot allocate new child for parent");
|
unreachable("cannot allocate new child for parent");
|
||||||
}
|
}
|
||||||
tree.set_used(new_more);
|
tree.set_used(new_next);
|
||||||
tree.elements++;
|
tree.elements++;
|
||||||
// update the "more" chain
|
// update the "next" chain
|
||||||
int last_link = tree.last_node(parent);
|
int last_link = tree.last_node(parent);
|
||||||
tree.refs_mat[last_link].more = new_more;
|
tree.refs_vec[last_link].next = new_next;
|
||||||
tree.refs_mat[new_more].more = -1;
|
tree.refs_vec[new_next].next = -1;
|
||||||
tree.refs_mat[new_more].children |= (long)(1 << (idx%BITS));
|
tree.refs_vec[new_next].children |= (long)(1 << (idx%BITS));
|
||||||
tree.refs_mat[new_more].parent = last_link;
|
tree.refs_vec[new_next].parent = last_link;
|
||||||
// FIXME: the elem_mat is not updated, do we need to?
|
// FIXME: the elem_vec is not updated, do we need to?
|
||||||
}
|
}
|
||||||
|
|
||||||
return idx;
|
return idx;
|
||||||
@ -165,15 +224,15 @@ fn int MTree.children_it(&tree, int parent, int n)
|
|||||||
{
|
{
|
||||||
int tot_children;
|
int tot_children;
|
||||||
int child;
|
int child;
|
||||||
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 cn = (int)tree.refs_mat[p].children.popcount();
|
int cn = (int)tree.refs_vec[p].children.popcount();
|
||||||
tot_children += cn;
|
tot_children += cn;
|
||||||
|
|
||||||
// we are in the right subtree
|
// we are in the right subtree
|
||||||
if (tot_children > n) {
|
if (tot_children > n) {
|
||||||
child = (p/BITS) * BITS; // start at the parent's subtree index
|
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
|
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
|
child += j; // add the children number
|
||||||
do {
|
do {
|
||||||
@ -191,8 +250,8 @@ fn int MTree.children_it(&tree, int parent, int n)
|
|||||||
fn int MTree.children_num(&tree, int parent)
|
fn int MTree.children_num(&tree, int parent)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
for (int p = parent; p >= 0; p = tree.refs_mat[p].more) {
|
for (int p = parent; p >= 0; p = tree.refs_vec[p].next) {
|
||||||
n += (int)tree.refs_mat[p].children.popcount();
|
n += (int)tree.refs_vec[p].children.popcount();
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@ -215,7 +274,7 @@ fn int MTree.level_order_it(&tree, int parent, int i)
|
|||||||
tree.queue.clear();
|
tree.queue.clear();
|
||||||
tree.queue.push(parent);
|
tree.queue.push(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tree.queue.len() == 0) return -1;
|
if (tree.queue.len() == 0) return -1;
|
||||||
|
|
||||||
int p = tree.queue.pop_first()!!;
|
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++) {
|
for (int i = 0; (c = tree.children_it(parent, i)) >= 0; i++) {
|
||||||
tree.prune(c); // prune the subtree
|
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;) {
|
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.unset_used(p);
|
||||||
tree.refs_mat[p] = {.more = -1};
|
tree.refs_vec[p] = {.next = -1};
|
||||||
p = next;
|
p = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,40 +303,40 @@ fn void MTree.prune(&tree, int parent)
|
|||||||
|
|
||||||
// finally delete the parent
|
// finally delete the parent
|
||||||
for (int p = parent; p >= 0;) {
|
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.unset_used(p);
|
||||||
tree.elements--;
|
tree.elements--;
|
||||||
tree.refs_mat[p] = {.more = -1};
|
tree.refs_vec[p] = {.next = -1};
|
||||||
p = next;
|
p = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<* @require tree.is_used(ref) *>
|
<* @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) *>
|
<* @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)
|
fn void MTree.nuke(&tree)
|
||||||
{
|
{
|
||||||
foreach (idx, &b: tree.used) {
|
foreach (idx, &b: tree.used) {
|
||||||
*b = 0;
|
*b = 0;
|
||||||
tree.refs_mat[idx] = {.more = -1};
|
tree.refs_vec[idx] = {.next = -1};
|
||||||
}
|
}
|
||||||
tree.elements = 0;
|
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)
|
fn void MTree.print(&tree)
|
||||||
{
|
{
|
||||||
foreach (idx, c: tree.elem_mat) {
|
foreach (idx, c: tree.elem_vec) {
|
||||||
if (tree.is_used((int)idx)) {
|
if (tree.is_used((int)idx)) {
|
||||||
io::printfn("[%d](%s) parent:%d more:%d children:%b",
|
io::printfn("[%d](%s) parent:%d next:%d children:%b",
|
||||||
idx, c, tree.refs_mat[idx].parent, tree.refs_mat[idx].more,
|
idx, c, tree.refs_vec[idx].parent, tree.refs_vec[idx].next,
|
||||||
tree.refs_mat[idx].children
|
tree.refs_vec[idx].children
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user