Package: lazytree
Lazy TreeTable of ContentsInstallationUsageInstallationIf you just need to uselazytree, you can just run:$ pip install lazytreeFor developers, note that this project uses thepoetrypython package/dependency
management tool. Please familarize yourself with it and then
run:$ poetry installUsageALazyTreeis a triple,(root, child_map, view)whereroot : Aand a child map,child_map, which mapsato a (finite) list of
childrenchild_map : A -> List[A]define the tree's structure andview : A -> Bdefines what the tree represents. The default view is
the identity map,lambda x: x.This structure is useful for modeling infinite (or really large) trees
where only a finite number of nodes need to be accessed. For example,
the following Binary tree represents the recursive subdivision of the
interval [0, 1].fromlazytreeimportLazyTreedefsplit(itvl):lo,hi=itvlmid=lo+(hi-lo)/2return(lo,mid),(mid,hi)tree=LazyTree(root=(0,1),# Initial Itvlchild_map=split# Itvl -> [Itvl])Conceptually aLazyTreeobject can be thought of as containing the pieces of data.Therootof the tree.The data represented by theroot, accessed via theviewmethod.The child subtrees - computed usingchild_mapand accessed through the.childrenattribute.For example, in our interval example, each node corresponds to an interval of(0, 1)and has two child subtrees.# View the current root.asserttree.view()==tree.rootsubtrees=tree.childrenassertlen(subtrees)==2Often, for each node in a tree, one is interested in computing a particular function. This can be done using themapandviewmethods. For example, belowmapeach interval in the tree to it's size. This results in a newLazyTreeobject.tree2=tree.map(lambdaitvl:itvl[1]-itvl[0])# Change view to itvl size.asserttree2.view()==1# Access the root's subtreessubtrees=tree2.childrenassertlen(subtrees)==2assertsubtrees[0].root==(0,0.5)assertsubtrees[0].view()==0.5Travesals of aLazyTreeobject are also implemented. For example,# Breadth First Search through tree.## Note: calls .view() before returning.itvls=tree.bfs()# returns a generator.sizes=tree2.bfs()# returns a generator.assertnext(itvls)==(0,1)assertnext(sizes)==1assertnext(itvls)==(0,0.5)assertnext(sizes)==0.5assertnext(itvls)==(0.5,1)assertnext(sizes)==0.5# Cost guided traversal.## Note: Smaller means higher priority.sizes=tree2.cost_guided_refinement(cost=lambdax:x)assertnext(sizes)==1# (0, 1)assertnext(sizes)==0.5# (0, 0.5)assertnext(sizes)==0.25# (0, 0.25)# Iterative Deepening Depth First Traversalsizes=tree2.iddfs(max_depth=3)# returns a generator.assertlist(sizes)==[1,0.5,0.5,0.25,0.25,0.25,0.25,0.125,0.125,0.125,0.125,0.125,0.125,0.125,0.125]# Note, you can reset the current view.tree3=tree2.with_identity_view()asserttree3.view()==tree.view()Finally, one can "prune" away subtrees by labeling them as leaf nodes using theprunemethod. If you are sure that the resulting tree is finite (either due to pruning or the providedchild_map) then one can compute the leaves of the tree.# Prune subtrees with a root of size less than 0.1.tree4=tree2.prune(isleaf=lambdas:s<0.2)sizes=tree.bfs()assertall(s>0.001forsinsizes)# Note that sizes is now finite.# Compute leafs of tree. Careful! Could be infinite!assertall(s==0.125forsintree4.leaves())assertlen(list(tree4.leaves()))==8