Architecture

In this part, the generic architecture of tree value will be introduced. You can try to understand its core ideas by reading this page.

Like that in numpy and pytorch, tree value’s data layer and logic layer are separated with each other. The data layer is called Tree and the logic layer is called TreeValue. One or more tree values may be pointed to one tree, they share the same memory. In order to support the tree-to-tree operations (tree-to-value or value-to-value are special cases of tree-to-tree) ,func_treelize are provided to transform a common value-based function to a tree-based function.

The core architecture is like this:

../../_images/architecture.puml.svg

Tree

Tree class is the data layer of the TreeValue. The relation with Tree and TreeValue is similar to that of torch.Tensor and torch.Buffer. Actually, there can be multiple TreeValue nodes pointed at the same Tree node, they will share the same memory and when one the them are modified, the other TreeValue pointed at the same position will be effected all at a time.

Here is a example with the usage of the same memories.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
from treevalue import TreeValue

if __name__ == '__main__':
    t1 = TreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
    t2 = TreeValue(t1)  # use the same memory with t1

    print("Initial t1:")
    print(t1)
    print("Initial t2:")
    print(t2)
    print()

    t1.a, t1.x.c = 7, 5  # only t1 is updated in code
    print("Updated t1:")
    print(t1)
    print("Updated t2:")
    print(t2)
    print()

The output is like the following, you can see the memory address of t1 and t2 are the same, when t1 is updated, t2 will be changed together.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Initial t1:
<TreeValue 0x7fc6076d5370 keys: ['a', 'b', 'x']>
├── 'a' --> 1
├── 'b' --> 2
└── 'x' --> <TreeValue 0x7fc6073ff940 keys: ['c', 'd']>
    ├── 'c' --> 3
    └── 'd' --> 4

Initial t2:
<TreeValue 0x7fc6076d5370 keys: ['a', 'b', 'x']>
├── 'a' --> 1
├── 'b' --> 2
└── 'x' --> <TreeValue 0x7fc6073ff940 keys: ['c', 'd']>
    ├── 'c' --> 3
    └── 'd' --> 4


Updated t1:
<TreeValue 0x7fc6076d5370 keys: ['a', 'b', 'x']>
├── 'a' --> 7
├── 'b' --> 2
└── 'x' --> <TreeValue 0x7fc6073ff940 keys: ['c', 'd']>
    ├── 'c' --> 5
    └── 'd' --> 4

Updated t2:
<TreeValue 0x7fc6076d5370 keys: ['a', 'b', 'x']>
├── 'a' --> 7
├── 'b' --> 2
└── 'x' --> <TreeValue 0x7fc6073ff940 keys: ['c', 'd']>
    ├── 'c' --> 5
    └── 'd' --> 4

For contributor, you can get the tree instance inside of a TreeValue instance, by using get_property_data function, like the following code.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from treevalue import TreeValue
from treevalue.tree.tree.tree import get_data_property

if __name__ == '__main__':
    t1 = TreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
    tree = get_data_property(t1)  # tree is the data tree

    print('t1:')
    print(t1)

    print('tree:')
    print(tree)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
t1:
<TreeValue 0x7f7d1c485370 keys: ['a', 'b', 'x']>
├── 'a' --> 1
├── 'b' --> 2
└── 'x' --> <TreeValue 0x7f7d1c1bf940 keys: ['c', 'd']>
    ├── 'c' --> 3
    └── 'd' --> 4

tree:
<Tree 0x7f7d1c485370 keys: ['a', 'b', 'x']>
├── 'a' --> 1
├── 'b' --> 2
└── 'x' --> <Tree 0x7f7d1c1bf940 keys: ['c', 'd']>
    ├── 'c' --> 3
    └── 'd' --> 4

Not only the native Tree class is provided, TreeView class is also provided for processing the tree view cases. They have the same methods and interface (actually they are both inherited from BaseTree class), so they are compatible with each other. The class Tree and TreeView form the data layer of TreeValue.

TreeValue

The TreeValue is the logic layer, all the operations and calculations are performed on this layer.

There are 2 primitive TreeValue classes in this project, which are called TreeValue and FastTreeValue. In class TreeValue, only the least necessary features are implemented, while the common and frequently-used features are all implement in the FastTreeValue, which inherits from TreeValue.

When coding, if you need to define a kind of tree which has the common convenient features, just implement class FastTreeValue or use function general_tree_value is okay. But if you need to define your own operations from an empty template, just inherit the raw TreeValue class.

For further information of TreeValue, take a look at:

func_treelize

Function func_treelize is the core feature of this project, almost all the convenient calculations and operations are based on this function.

For further information of func_treelize, take a look at the following pages and their source code implements: