From 45d6550c881f9ceed55c2e87ba0b05aec8a9b666 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Tue, 15 Sep 2020 19:53:49 +0800 Subject: [PATCH 01/44] Update tree.py --- treelib/tree.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/treelib/tree.py b/treelib/tree.py index 6ee18c9..e2cfa3c 100644 --- a/treelib/tree.py +++ b/treelib/tree.py @@ -889,9 +889,8 @@ def subtree(self, nid, identifier=None): # define nodes parent/children in this tree # all pointers are the same as copied tree, except the root st[node_n].clone_pointers(self._identifier, st.identifier) - if node_n == nid: - # reset root parent for the new tree - st[node_n].set_predecessor(None, st.identifier) + # reset root parent for the new tree + st[nid].set_predecessor(None, st.identifier) return st def update_node(self, nid, **attrs): From 5024c90f38f4905f0fad75746fdb32066a9d5bb7 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Mon, 21 Jun 2021 09:28:46 +0800 Subject: [PATCH 02/44] Create random_tree.py --- examples/random_tree.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 examples/random_tree.py diff --git a/examples/random_tree.py b/examples/random_tree.py new file mode 100644 index 0000000..d1521e5 --- /dev/null +++ b/examples/random_tree.py @@ -0,0 +1,25 @@ +""" +Generate a tree randomly +""" + +import random +from treelib import Tree + +def _random(max_depth=5, min_width=1, max_width=2, offset=(0,)): + # just have fun + tree = Tree() + root = tree.create_node(identifier=offset) + if max_depth == 0: + return tree + elif max_depth ==1: + nb = random.randint(min_width, max_width) + for i in range(nb): + tree.create_node(identifier=offset+(i,), parent=offset) + else: + nb = random.randint(min_width, max_width) + for i in range(nb): + subtree = _random(max_depth=max_depth-1, max_width=max_width, offset=offset+(i,)) + tree.paste(offset, subtree) + return tree + +print(_random()) From 545a66d311c712dae461671859c4d7a8bf1a7d3a Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Mon, 21 Jun 2021 10:02:15 +0800 Subject: [PATCH 03/44] Update tree.py --- treelib/tree.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/treelib/tree.py b/treelib/tree.py index e2cfa3c..2b673a1 100644 --- a/treelib/tree.py +++ b/treelib/tree.py @@ -295,6 +295,12 @@ def all_nodes_itr(self): Added by William Rusnack """ return self._nodes.values() + + def iternodes(self): + """ + alias of `all_nodes_itr` but conform to the convention of Python. + """ + return self._nodes.values() def ancestor(self, nid, level=None): """ @@ -993,3 +999,25 @@ def to_graphviz(self, filename=None, shape='circle', graph='digraph'): print(f.getvalue()) f.close() + + + def map(self, key): + """Morphism of tree + + Work like the built-in `map` + + Arguments + key: function of a node + """ + tree = self._clone(with_tree=tree) + for a in tree.iternodes(): + key(a) + return tree + + def map_data(self, key): + """morphism of tree, but act on data of nodes. + """ + tree = self._clone(with_tree=tree) + for a in tree.iternodes(): + a.data = key(a.data) + return tree From 82d0614a043d3203025d56347014b5b9f5c74e91 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Mon, 21 Jun 2021 10:06:36 +0800 Subject: [PATCH 04/44] Update tree.py --- treelib/tree.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/treelib/tree.py b/treelib/tree.py index 2b673a1..9b55b05 100644 --- a/treelib/tree.py +++ b/treelib/tree.py @@ -1001,23 +1001,27 @@ def to_graphviz(self, filename=None, shape='circle', graph='digraph'): f.close() - def map(self, key): + def map(self, key, deep=True): """Morphism of tree Work like the built-in `map` Arguments - key: function of a node + key -- function of a node + deep -- please keep it true """ - tree = self._clone(with_tree=tree) + tree = self._clone(with_tree=tree, deep=deep) for a in tree.iternodes(): key(a) return tree - def map_data(self, key): + def map_data(self, key, deep=True): """morphism of tree, but act on data of nodes. + + Arguments + key -- pure function of node.data """ - tree = self._clone(with_tree=tree) + tree = self._clone(with_tree=tree, deep=deep) for a in tree.iternodes(): a.data = key(a.data) return tree From c33380f73f1595f7fbdc0140c62b1834dd6c49ad Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Mon, 21 Jun 2021 14:20:07 +0800 Subject: [PATCH 05/44] Update random_tree.py --- examples/random_tree.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/examples/random_tree.py b/examples/random_tree.py index d1521e5..38f9ccd 100644 --- a/examples/random_tree.py +++ b/examples/random_tree.py @@ -1,12 +1,7 @@ -""" -Generate a tree randomly -""" - import random from treelib import Tree def _random(max_depth=5, min_width=1, max_width=2, offset=(0,)): - # just have fun tree = Tree() root = tree.create_node(identifier=offset) if max_depth == 0: @@ -22,4 +17,16 @@ def _random(max_depth=5, min_width=1, max_width=2, offset=(0,)): tree.paste(offset, subtree) return tree -print(_random()) +def key(node): + node.tag = ''.join(map(str, node.identifier)) + +def _map(tree, key): + + tree = tree._clone(with_tree=True) + print(tree) + for a in tree.all_nodes_itr(): + key(a) + return tree + + +print(_map(_random(), key)) From 6f816bf4bd3a22d56f668e648ce5c4416d38f59d Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Fri, 29 Apr 2022 09:15:02 +0800 Subject: [PATCH 06/44] Update tree.py rewrite the `contains` method --- treelib/tree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/treelib/tree.py b/treelib/tree.py index 9b55b05..f1bcaf8 100644 --- a/treelib/tree.py +++ b/treelib/tree.py @@ -340,7 +340,7 @@ def children(self, nid): def contains(self, nid): """Check if the tree contains node of given id""" - return True if nid in self._nodes else False + return nid in self._nodes def create_node(self, tag=None, identifier=None, parent=None, data=None): """ From a91d105488f972c7bafdb59086dd920692f865d4 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Fri, 29 Apr 2022 21:40:11 +0800 Subject: [PATCH 07/44] Update tree.py define `apply` method for a tree --- treelib/tree.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/treelib/tree.py b/treelib/tree.py index f1bcaf8..ba0d52e 100644 --- a/treelib/tree.py +++ b/treelib/tree.py @@ -1001,7 +1001,7 @@ def to_graphviz(self, filename=None, shape='circle', graph='digraph'): f.close() - def map(self, key, deep=True): + def apply(self, key, deep=True): """Morphism of tree Work like the built-in `map` @@ -1015,7 +1015,7 @@ def map(self, key, deep=True): key(a) return tree - def map_data(self, key, deep=True): + def apply_data(self, key, deep=True): """morphism of tree, but act on data of nodes. Arguments From 5c7bbbde9dac7379e309a9624997388710ed9151 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Fri, 29 Apr 2022 21:42:45 +0800 Subject: [PATCH 08/44] Update random_tree.py --- examples/random_tree.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/random_tree.py b/examples/random_tree.py index 38f9ccd..3fe1580 100644 --- a/examples/random_tree.py +++ b/examples/random_tree.py @@ -17,10 +17,8 @@ def _random(max_depth=5, min_width=1, max_width=2, offset=(0,)): tree.paste(offset, subtree) return tree -def key(node): - node.tag = ''.join(map(str, node.identifier)) -def _map(tree, key): +def _map(func, tree): tree = tree._clone(with_tree=True) print(tree) @@ -29,4 +27,6 @@ def _map(tree, key): return tree -print(_map(_random(), key)) +def key(node): + node.tag = ''.join(map(str, node.identifier)) +print(_map(key, _random())) From ce6f8bdb4430ca80b3fd9fa317f0df9e6db078db Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Fri, 29 Apr 2022 22:28:51 +0800 Subject: [PATCH 09/44] Update tree.py --- treelib/tree.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/treelib/tree.py b/treelib/tree.py index 5fd5fde..c14a43e 100644 --- a/treelib/tree.py +++ b/treelib/tree.py @@ -1007,21 +1007,21 @@ def apply(self, key, deep=True): Work like the built-in `map` Arguments - key -- function of a node + key -- impure function of a node deep -- please keep it true """ tree = self._clone(with_tree=tree, deep=deep) - for a in tree.iternodes(): + for a in tree.all_nodes(): key(a) return tree def apply_data(self, key, deep=True): """morphism of tree, but act on data of nodes. + It calls the method `apply` Arguments key -- pure function of node.data """ - tree = self._clone(with_tree=tree, deep=deep) - for a in tree.iternodes(): + def _key(a): a.data = key(a.data) - return tree + return self.apply(_key, deep=deep) From f9b8f04f821c6e5b8fd2f3f54560685aab8ef235 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Fri, 28 Oct 2022 09:19:21 +0800 Subject: [PATCH 10/44] update --- examples/random_tree.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/random_tree.py b/examples/random_tree.py index 3fe1580..c5d8fdc 100644 --- a/examples/random_tree.py +++ b/examples/random_tree.py @@ -2,6 +2,7 @@ from treelib import Tree def _random(max_depth=5, min_width=1, max_width=2, offset=(0,)): + # generate a tree randomly tree = Tree() root = tree.create_node(identifier=offset) if max_depth == 0: @@ -19,14 +20,15 @@ def _random(max_depth=5, min_width=1, max_width=2, offset=(0,)): def _map(func, tree): - + # tree as a functor tree = tree._clone(with_tree=True) print(tree) for a in tree.all_nodes_itr(): key(a) return tree - def key(node): node.tag = ''.join(map(str, node.identifier)) print(_map(key, _random())) + +print(_random().apply(key)) From 5fbe23b261071d8290a5951747cb06aec4bbabff Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 14:03:12 +0800 Subject: [PATCH 11/44] Create cluster_tree Clustering Model Based on Decision Tree --- examples/cluster_tree | 94 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 examples/cluster_tree diff --git a/examples/cluster_tree b/examples/cluster_tree new file mode 100644 index 0000000..73cbfbb --- /dev/null +++ b/examples/cluster_tree @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 + +"""Clustering Model Based on Decision Tree +""" + +import numpy as np +import numpy.linalg as LA +from scipy.stats import entropy +from scipy.spatial.distance import cdist + +import pandas as pd + +from treelib import Node, Tree + +from sklearn.base import ClusterMixin, BaseEstimator +from sklearn.cluster import KMeans + + +class TreeCluster(BaseEstimator, ClusterMixin, Tree): + """Decision Tree for classification/cluster + + epsilon: the threshold of info gain or other select method + selection_method: the selection method + features_: the features of the input vars + classes_: the classes of output vars + """ + + def __init__(self, epsilon=0.6, features=None, classes=None, *args, **kwargs): + super().__init__(*args, **kwargs) + self.epsilon = epsilon + self.features_ = features + self.classes_ = classes + + def fit(self, X, Y=None, mean=None, level=(0,)): + """ + calc cond_proba, proba, priori_proba, features + then call fit_with_proba + + Arguments: + X {2D array|list|dataframe} -- input vars + + Returns: + TreeCluster + """ + + kmeans = KMeans(n_clusters=2) + + if mean is None: + mean = X.mean(axis=0) + self.add_node(Node(tag='-'.join(map(str, level)), identifier=level, data={'mean':mean})) + + if len(X)>2: + kmeans.fit(X) + y = kmeans.predict(X) + classes_ = np.unique(y) + means_ = kmeans.cluster_centers_ + + gain = 1 - kmeans.inertia_ / LA.norm(X - mean, 'fro')**2 + + if gain > self.epsilon: + for k, m in zip(classes_, means_): + t = TreeCluster(epsilon=self.epsilon) + t.fit(X[y==k], mean=m, level=level+(k,)) + self.paste(level, t) + + if level == (0,): + # get cluster centers from the data of the nodes + self.cluster_centers_ = [node.data['mean'] for node in self.all_nodes_itr() if node.is_leaf()] + self.classes_ = np.arange(len(self.cluster_centers_)) + + return self + + def predict_proba(self, X): + distances = np.exp(-cdist(X, self.cluster_centers_)) + return distances / distances.sum(axis=0)[None,:] + + def predict(self, X): + p = self.predict_proba(X) + return self.classes_[np.argmax(p, axis=1)] + + +if __name__ == '__main__': + + from sklearn import datasets + + iris = datasets.load_iris() + X_train, y_train = iris.data, iris.target + + tc = TreeCluster(epsilon=0.5) + tc.fit(X_train) + y_ = tc.predict(X_train) + + print(tc) + print(tc.cluster_centers_) From de4b6ed9f6d9c124783d7e6933da861269b0edfb Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 14:11:10 +0800 Subject: [PATCH 12/44] Update tree.py --- treelib/tree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/treelib/tree.py b/treelib/tree.py index f10b944..5c3da66 100644 --- a/treelib/tree.py +++ b/treelib/tree.py @@ -1143,7 +1143,7 @@ def apply(self, key, deep=True): key -- impure function of a node deep -- please keep it true """ - tree = self._clone(with_tree=tree, deep=deep) + tree = self._clone(with_tree=True, deep=deep) for a in tree.all_nodes(): key(a) return tree From fe921444fe05e47d22d1a93f556230c6da97196a Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 14:45:20 +0800 Subject: [PATCH 13/44] Update cluster_tree --- examples/cluster_tree | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/cluster_tree b/examples/cluster_tree index 73cbfbb..b9f2191 100644 --- a/examples/cluster_tree +++ b/examples/cluster_tree @@ -31,7 +31,7 @@ class TreeCluster(BaseEstimator, ClusterMixin, Tree): self.features_ = features self.classes_ = classes - def fit(self, X, Y=None, mean=None, level=(0,)): + def fit(self, X, Y=None, mean=None, level=()): """ calc cond_proba, proba, priori_proba, features then call fit_with_proba @@ -63,7 +63,7 @@ class TreeCluster(BaseEstimator, ClusterMixin, Tree): t.fit(X[y==k], mean=m, level=level+(k,)) self.paste(level, t) - if level == (0,): + if level == (): # get cluster centers from the data of the nodes self.cluster_centers_ = [node.data['mean'] for node in self.all_nodes_itr() if node.is_leaf()] self.classes_ = np.arange(len(self.cluster_centers_)) From d5a5f9baef4e4ecc114d27b8017084dfb8b83ee8 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 14:49:52 +0800 Subject: [PATCH 14/44] Update random_tree.py --- examples/random_tree.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/random_tree.py b/examples/random_tree.py index c5d8fdc..5db7c08 100644 --- a/examples/random_tree.py +++ b/examples/random_tree.py @@ -1,13 +1,13 @@ import random from treelib import Tree -def _random(max_depth=5, min_width=1, max_width=2, offset=(0,)): +def _random(max_depth=5, min_width=1, max_width=2, offset=()): # generate a tree randomly tree = Tree() root = tree.create_node(identifier=offset) if max_depth == 0: return tree - elif max_depth ==1: + elif max_depth == 1: nb = random.randint(min_width, max_width) for i in range(nb): tree.create_node(identifier=offset+(i,), parent=offset) @@ -27,8 +27,11 @@ def _map(func, tree): key(a) return tree + def key(node): node.tag = ''.join(map(str, node.identifier)) + + print(_map(key, _random())) print(_random().apply(key)) From ee1b1f695428efd6da11461a9434091713e16c7c Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 14:52:01 +0800 Subject: [PATCH 15/44] Update random_tree.py --- examples/random_tree.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/random_tree.py b/examples/random_tree.py index 5db7c08..85cc0c9 100644 --- a/examples/random_tree.py +++ b/examples/random_tree.py @@ -1,10 +1,11 @@ import random from treelib import Tree + def _random(max_depth=5, min_width=1, max_width=2, offset=()): # generate a tree randomly tree = Tree() - root = tree.create_node(identifier=offset) + tree.create_node(identifier=offset) if max_depth == 0: return tree elif max_depth == 1: From 1716b61c5efec00c9e814888967e8afa3cc9c132 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:07:00 +0800 Subject: [PATCH 16/44] Update tree.py --- treelib/tree.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/treelib/tree.py b/treelib/tree.py index 5c3da66..d0c5475 100644 --- a/treelib/tree.py +++ b/treelib/tree.py @@ -335,7 +335,7 @@ def all_nodes_itr(self): Added by William Rusnack """ return self._nodes.values() - + def iternodes(self): """ alias of `all_nodes_itr` but conform to the convention of Python. @@ -1136,9 +1136,8 @@ def to_graphviz( def apply(self, key, deep=True): """Morphism of tree - Work like the built-in `map` - + Arguments key -- impure function of a node deep -- please keep it true @@ -1147,11 +1146,11 @@ def apply(self, key, deep=True): for a in tree.all_nodes(): key(a) return tree - + def apply_data(self, key, deep=True): - """morphism of tree, but act on data of nodes. + """morphism of tree, but acts on data of nodes. It calls the method `apply` - + Arguments key -- pure function of node.data """ From 4fa9690d75ca8de08eaca5767b7897898054a032 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:08:40 +0800 Subject: [PATCH 17/44] Update tree.py --- treelib/tree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/treelib/tree.py b/treelib/tree.py index d0c5475..8b55c61 100644 --- a/treelib/tree.py +++ b/treelib/tree.py @@ -1137,7 +1137,7 @@ def to_graphviz( def apply(self, key, deep=True): """Morphism of tree Work like the built-in `map` - + Arguments key -- impure function of a node deep -- please keep it true From ad255c33538ce6f214b0514c0a12b507f585d084 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:12:07 +0800 Subject: [PATCH 18/44] Update tree.py --- treelib/tree.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/treelib/tree.py b/treelib/tree.py index 8b55c61..377fe7b 100644 --- a/treelib/tree.py +++ b/treelib/tree.py @@ -1154,8 +1154,10 @@ def apply_data(self, key, deep=True): Arguments key -- pure function of node.data """ + def _key(a): a.data = key(a.data) + return self.apply(_key, deep=deep) @classmethod From c8a9d5b2932f84227eca0f602c6aa023727105f1 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:22:08 +0800 Subject: [PATCH 19/44] Update random_tree.py --- examples/random_tree.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/random_tree.py b/examples/random_tree.py index 85cc0c9..7b66d8c 100644 --- a/examples/random_tree.py +++ b/examples/random_tree.py @@ -1,3 +1,4 @@ + import random from treelib import Tree @@ -11,7 +12,8 @@ def _random(max_depth=5, min_width=1, max_width=2, offset=()): elif max_depth == 1: nb = random.randint(min_width, max_width) for i in range(nb): - tree.create_node(identifier=offset+(i,), parent=offset) + identifier = offset + (i,) + tree.create_node(identifier=identifier, parent=offset) else: nb = random.randint(min_width, max_width) for i in range(nb): From dbbb10c8c60d5dec73f1faf1f8249a25bf794182 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:25:15 +0800 Subject: [PATCH 20/44] Update random_tree.py --- examples/random_tree.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/random_tree.py b/examples/random_tree.py index 7b66d8c..9115d35 100644 --- a/examples/random_tree.py +++ b/examples/random_tree.py @@ -1,3 +1,8 @@ +#!/usr/bin/env python3 + +""" +Generate a tree randomly; Test the `apply` method; +""" import random from treelib import Tree From 574fcee7b72121c392c0955f57add93db6124143 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:26:21 +0800 Subject: [PATCH 21/44] Update random_tree.py --- examples/random_tree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/random_tree.py b/examples/random_tree.py index 9115d35..78c95ed 100644 --- a/examples/random_tree.py +++ b/examples/random_tree.py @@ -22,7 +22,7 @@ def _random(max_depth=5, min_width=1, max_width=2, offset=()): else: nb = random.randint(min_width, max_width) for i in range(nb): - subtree = _random(max_depth=max_depth-1, max_width=max_width, offset=offset+(i,)) + subtree = _random(max_depth=max_depth-1, max_width=max_width, offset=offset + (i,)) tree.paste(offset, subtree) return tree From b53ac6f31df74275fbf0f34981459382d8c048c0 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:27:32 +0800 Subject: [PATCH 22/44] Update random_tree.py --- examples/random_tree.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/random_tree.py b/examples/random_tree.py index 78c95ed..f06b7b1 100644 --- a/examples/random_tree.py +++ b/examples/random_tree.py @@ -22,7 +22,8 @@ def _random(max_depth=5, min_width=1, max_width=2, offset=()): else: nb = random.randint(min_width, max_width) for i in range(nb): - subtree = _random(max_depth=max_depth-1, max_width=max_width, offset=offset + (i,)) + _offset = offset + (i,) + subtree = _random(max_depth=max_depth-1, max_width=max_width, offset=_offset) tree.paste(offset, subtree) return tree From 004cce6f1eb80943928333b7bef9283f56f43e9d Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:45:45 +0800 Subject: [PATCH 23/44] Update random_tree.py --- examples/random_tree.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/random_tree.py b/examples/random_tree.py index f06b7b1..d702b45 100644 --- a/examples/random_tree.py +++ b/examples/random_tree.py @@ -23,7 +23,8 @@ def _random(max_depth=5, min_width=1, max_width=2, offset=()): nb = random.randint(min_width, max_width) for i in range(nb): _offset = offset + (i,) - subtree = _random(max_depth=max_depth-1, max_width=max_width, offset=_offset) + max_depth -= 1 + subtree = _random(max_depth=max_depth, max_width=max_width, offset=_offset) tree.paste(offset, subtree) return tree From 734f46805ca7999a861b24120e438728c4919cdc Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 16:23:00 +0800 Subject: [PATCH 24/44] Update random_tree.py --- examples/random_tree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/random_tree.py b/examples/random_tree.py index d702b45..96827e8 100644 --- a/examples/random_tree.py +++ b/examples/random_tree.py @@ -39,7 +39,7 @@ def _map(func, tree): def key(node): - node.tag = ''.join(map(str, node.identifier)) + node.tag = "-".join(map(str, node.identifier)) print(_map(key, _random())) From 0b42017bcfef1f4794bf72f8774daa03e2a7d1c8 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 16:25:07 +0800 Subject: [PATCH 25/44] Update tree.py --- treelib/tree.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/treelib/tree.py b/treelib/tree.py index 377fe7b..a701ffe 100644 --- a/treelib/tree.py +++ b/treelib/tree.py @@ -521,6 +521,9 @@ def get_node(self, nid): return None return self._nodes[nid] + def get_root(self): + return self.get_node(self.root) + def is_branch(self, nid): """ Return the children (ID) list of nid. From 9665b3a596e3f3be73c848672beba769e7daff1e Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 18:45:31 +0800 Subject: [PATCH 26/44] Update tree.py --- treelib/tree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/treelib/tree.py b/treelib/tree.py index a701ffe..e18dc92 100644 --- a/treelib/tree.py +++ b/treelib/tree.py @@ -700,7 +700,7 @@ def paste(self, nid, new_tree, deep=False): for cid, node in iteritems(new_tree.nodes): if deep: - node = deepcopy(new_tree[node]) + node = deepcopy(node) self._nodes.update({cid: node}) node.clone_pointers(new_tree.identifier, self._identifier) From 4b27b7168e07d19f2380474df8a8d65100c89ca2 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 21:32:51 +0800 Subject: [PATCH 27/44] Create huffman_tree.py --- examples/huffman_tree.py | 102 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 examples/huffman_tree.py diff --git a/examples/huffman_tree.py b/examples/huffman_tree.py new file mode 100644 index 0000000..95df1c8 --- /dev/null +++ b/examples/huffman_tree.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python + + +"""Huffman coding +""" + +from copy import deepcopy + +from toolz import * +from treelib import * + +import numpy as np + + +def _get_symbols(tree): + a = tree.data['symbols'] if isinstance(tree, Node) else tree.get_node(tree.root).data['symbols'] + if isinstance(a, str): + return [a] + else: + return a + + +def _get_frequency(tree): + a = tree.data['frequency'] if isinstance(tree, Node) else tree.get_node(tree.root).data['frequency'] + if isinstance(a, str): + return [a] + else: + return a + + +def merge(trees, level=''): + """merge the trees to one tree by add a root + + Args: + trees (list): list of trees or nodes + level (tuple, optional): the prefix for identifier + + Returns: + Tree + """ + + data = list(concat(map(_get_symbols, trees))) + freq = sum(map(_get_frequency, trees)) + t = Tree() + root = Node(tag='', identifier=level, data={'symbols':data, 'frequency':freq, 'code':''}) + t.add_node(root) + t.root = level + root.tag = f"{root.data['code']}:{{{','.join(root.data['symbols'])}}}/{root.data['frequency']}" + for k, tree in enumerate(trees): + if isinstance(tree, Node): + tree.identifier = f'{k}' + tree.identifier + tree.data['code'] = f'{k}' + tree.data['code'] + tree.tag = f"{tree.data['code']}:{{{','.join(tree.data['symbols'])}}}/{tree.data['frequency']}" + t.add_node(tree, parent=level) + else: + for n in tree.all_nodes_itr(): + n.identifier = f'{k}' + n.identifier + n.data['code'] = f'{k}' + n.data['code'] + n.tag = f"{n.data['code']}:{{{','.join(n.data['symbols'])}}}/{n.data['frequency']}" + + nodes = {n.identifier:n for k, n in tree._nodes.items()} + tree._nodes = nodes + tree.root = f'{k}' + tree.root + for n in tree.all_nodes_itr(): + if n.is_root(): + n.set_successors([f'{k}' + l for l in n._successors[tree.identifier]], tree.identifier) + elif n.is_leaf(): + n.set_predecessor(f'{k}'+ n._predecessor[tree.identifier], tree.identifier) + else: + n.set_predecessor(f'{k}'+ n._predecessor[tree.identifier], tree.identifier) + n.set_successors([f'{k}' + l for l in n._successors[tree.identifier]], tree.identifier) + + t.paste(level, tree, deep=True) + return t + + +def huffman_tree(trees, level='', n_branches=2): + """Huffman coding + + Args: + trees (list): list of trees or nodes + level (tuple, optional): the prefix for identifier + set n_branches=2 by default + + Returns: + Tree: Huffman tree + """ + if len(trees) == 2: + return merge(trees, level=level) + else: + ks = np.argsort([_get_frequency(tree) for tree in trees])[:n_branches] + t = merge([trees[k] for k in ks], level=level) + t = huffman_tree([t]+[tree for i, tree in enumerate(trees) if i not in ks], level=level) + t.tag = 'root' + return t + + +d = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5} +nodes =[Node(identifier='', data={'symbols':s, 'frequency':f, 'code':''}) for s, f in d.items()] +t = huffman_tree(nodes) + +print(t) From 3532fd13cc2e7ef9d63b9681b048ad6f4908aa83 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 21:38:50 +0800 Subject: [PATCH 28/44] Update huffman_tree.py --- examples/huffman_tree.py | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/examples/huffman_tree.py b/examples/huffman_tree.py index 95df1c8..d867a08 100644 --- a/examples/huffman_tree.py +++ b/examples/huffman_tree.py @@ -4,16 +4,17 @@ """Huffman coding """ -from copy import deepcopy - -from toolz import * -from treelib import * +from toolz import concat +from treelib import Tree, Node import numpy as np def _get_symbols(tree): - a = tree.data['symbols'] if isinstance(tree, Node) else tree.get_node(tree.root).data['symbols'] + if isinstance(tree, Node): + a = tree.data['symbols'] + else: + a = tree.get_node(tree.root).data['symbols'] if isinstance(a, str): return [a] else: @@ -21,7 +22,11 @@ def _get_symbols(tree): def _get_frequency(tree): - a = tree.data['frequency'] if isinstance(tree, Node) else tree.get_node(tree.root).data['frequency'] + a = tree.data['frequency'] + if isinstance(tree, Node): + a = tree.data['frequency'] + else: + a = tree.get_node(tree.root).data['frequency'] if isinstance(a, str): return [a] else: @@ -30,7 +35,7 @@ def _get_frequency(tree): def merge(trees, level=''): """merge the trees to one tree by add a root - + Args: trees (list): list of trees or nodes level (tuple, optional): the prefix for identifier @@ -58,17 +63,17 @@ def merge(trees, level=''): n.data['code'] = f'{k}' + n.data['code'] n.tag = f"{n.data['code']}:{{{','.join(n.data['symbols'])}}}/{n.data['frequency']}" - nodes = {n.identifier:n for k, n in tree._nodes.items()} + nodes = {n.identifier: n for k, n in tree._nodes.items()} tree._nodes = nodes tree.root = f'{k}' + tree.root for n in tree.all_nodes_itr(): if n.is_root(): - n.set_successors([f'{k}' + l for l in n._successors[tree.identifier]], tree.identifier) + n.set_successors([f'{k}' + nid for nid in n._successors[tree.identifier]], tree.identifier) elif n.is_leaf(): n.set_predecessor(f'{k}'+ n._predecessor[tree.identifier], tree.identifier) else: n.set_predecessor(f'{k}'+ n._predecessor[tree.identifier], tree.identifier) - n.set_successors([f'{k}' + l for l in n._successors[tree.identifier]], tree.identifier) + n.set_successors([f'{k}' + nid for nid in n._successors[tree.identifier]], tree.identifier) t.paste(level, tree, deep=True) return t @@ -90,13 +95,13 @@ def huffman_tree(trees, level='', n_branches=2): else: ks = np.argsort([_get_frequency(tree) for tree in trees])[:n_branches] t = merge([trees[k] for k in ks], level=level) - t = huffman_tree([t]+[tree for i, tree in enumerate(trees) if i not in ks], level=level) + t = huffman_tree([t] + [tree for i, tree in enumerate(trees) if i not in ks], level=level) t.tag = 'root' return t -d = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5} -nodes =[Node(identifier='', data={'symbols':s, 'frequency':f, 'code':''}) for s, f in d.items()] +d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} +nodes =[Node(identifier='', data={'symbols': s, 'frequency': f, 'code': ''}) for s, f in d.items()] t = huffman_tree(nodes) print(t) From 31e4940dc50c58da841306d31fab0c09f2deadc6 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 21:41:47 +0800 Subject: [PATCH 29/44] Update huffman_tree.py --- examples/huffman_tree.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/examples/huffman_tree.py b/examples/huffman_tree.py index d867a08..1d237ee 100644 --- a/examples/huffman_tree.py +++ b/examples/huffman_tree.py @@ -11,6 +11,8 @@ def _get_symbols(tree): + """Get the symbols from the root of a tree or a node + """ if isinstance(tree, Node): a = tree.data['symbols'] else: @@ -22,7 +24,8 @@ def _get_symbols(tree): def _get_frequency(tree): - a = tree.data['frequency'] + """Get the frequency from the root of a tree or a node + """ if isinstance(tree, Node): a = tree.data['frequency'] else: @@ -39,7 +42,7 @@ def merge(trees, level=''): Args: trees (list): list of trees or nodes level (tuple, optional): the prefix for identifier - + Returns: Tree """ @@ -47,7 +50,7 @@ def merge(trees, level=''): data = list(concat(map(_get_symbols, trees))) freq = sum(map(_get_frequency, trees)) t = Tree() - root = Node(tag='', identifier=level, data={'symbols':data, 'frequency':freq, 'code':''}) + root = Node(tag='', identifier=level, data={'symbols': data, 'frequency': freq, 'code': ''}) t.add_node(root) t.root = level root.tag = f"{root.data['code']}:{{{','.join(root.data['symbols'])}}}/{root.data['frequency']}" @@ -70,9 +73,9 @@ def merge(trees, level=''): if n.is_root(): n.set_successors([f'{k}' + nid for nid in n._successors[tree.identifier]], tree.identifier) elif n.is_leaf(): - n.set_predecessor(f'{k}'+ n._predecessor[tree.identifier], tree.identifier) + n.set_predecessor(f'{k}' + n._predecessor[tree.identifier], tree.identifier) else: - n.set_predecessor(f'{k}'+ n._predecessor[tree.identifier], tree.identifier) + n.set_predecessor(f'{k}' + n._predecessor[tree.identifier], tree.identifier) n.set_successors([f'{k}' + nid for nid in n._successors[tree.identifier]], tree.identifier) t.paste(level, tree, deep=True) @@ -101,7 +104,7 @@ def huffman_tree(trees, level='', n_branches=2): d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} -nodes =[Node(identifier='', data={'symbols': s, 'frequency': f, 'code': ''}) for s, f in d.items()] +nodes = [Node(identifier='', data={'symbols': s, 'frequency': f, 'code': ''}) for s, f in d.items()] t = huffman_tree(nodes) print(t) From f4b60fe9bc7710a254e03bf800c49981dc183e9d Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 21:44:01 +0800 Subject: [PATCH 30/44] Update huffman_tree.py --- examples/huffman_tree.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/huffman_tree.py b/examples/huffman_tree.py index 1d237ee..a2c7962 100644 --- a/examples/huffman_tree.py +++ b/examples/huffman_tree.py @@ -11,7 +11,9 @@ def _get_symbols(tree): - """Get the symbols from the root of a tree or a node + """Get `symbols` from the root of a tree or a node + + tree: Tree or Node """ if isinstance(tree, Node): a = tree.data['symbols'] @@ -24,7 +26,9 @@ def _get_symbols(tree): def _get_frequency(tree): - """Get the frequency from the root of a tree or a node + """Get `frequency` from the root of a tree or a node + + tree: Tree or Node """ if isinstance(tree, Node): a = tree.data['frequency'] From 3f5c6832883acb01f513052b4f033d78dac4bb61 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 21:48:01 +0800 Subject: [PATCH 31/44] Update huffman_tree.py --- examples/huffman_tree.py | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/examples/huffman_tree.py b/examples/huffman_tree.py index a2c7962..d660477 100644 --- a/examples/huffman_tree.py +++ b/examples/huffman_tree.py @@ -16,9 +16,9 @@ def _get_symbols(tree): tree: Tree or Node """ if isinstance(tree, Node): - a = tree.data['symbols'] + a = tree.data["symbols"] else: - a = tree.get_node(tree.root).data['symbols'] + a = tree.get_node(tree.root).data["symbols"] if isinstance(a, str): return [a] else: @@ -31,9 +31,9 @@ def _get_frequency(tree): tree: Tree or Node """ if isinstance(tree, Node): - a = tree.data['frequency'] + a = tree.data["frequency"] else: - a = tree.get_node(tree.root).data['frequency'] + a = tree.get_node(tree.root).data["frequency"] if isinstance(a, str): return [a] else: @@ -54,33 +54,33 @@ def merge(trees, level=''): data = list(concat(map(_get_symbols, trees))) freq = sum(map(_get_frequency, trees)) t = Tree() - root = Node(tag='', identifier=level, data={'symbols': data, 'frequency': freq, 'code': ''}) + root = Node(tag="", identifier=level, data={"symbols": data, "frequency": freq, "code": ""}) t.add_node(root) t.root = level - root.tag = f"{root.data['code']}:{{{','.join(root.data['symbols'])}}}/{root.data['frequency']}" + root.tag = f"{root.data['code']}:{{{",".join(root.data['symbols'])}}}/{root.data['frequency']}" for k, tree in enumerate(trees): if isinstance(tree, Node): - tree.identifier = f'{k}' + tree.identifier - tree.data['code'] = f'{k}' + tree.data['code'] - tree.tag = f"{tree.data['code']}:{{{','.join(tree.data['symbols'])}}}/{tree.data['frequency']}" + tree.identifier = f"{k}" + tree.identifier + tree.data['code'] = f"{k}" + tree.data['code'] + tree.tag = f"{tree.data['code']}:{{{",".join(tree.data['symbols'])}}}/{tree.data['frequency']}" t.add_node(tree, parent=level) else: for n in tree.all_nodes_itr(): - n.identifier = f'{k}' + n.identifier - n.data['code'] = f'{k}' + n.data['code'] - n.tag = f"{n.data['code']}:{{{','.join(n.data['symbols'])}}}/{n.data['frequency']}" + n.identifier = f"{k}" + n.identifier + n.data['code'] = f"{k}" + n.data['code'] + n.tag = f"{n.data['code']}:{{{",".join(n.data['symbols'])}}}/{n.data['frequency']}" nodes = {n.identifier: n for k, n in tree._nodes.items()} tree._nodes = nodes - tree.root = f'{k}' + tree.root + tree.root = f"{k}" + tree.root for n in tree.all_nodes_itr(): if n.is_root(): - n.set_successors([f'{k}' + nid for nid in n._successors[tree.identifier]], tree.identifier) + n.set_successors([f"{k}" + nid for nid in n._successors[tree.identifier]], tree.identifier) elif n.is_leaf(): - n.set_predecessor(f'{k}' + n._predecessor[tree.identifier], tree.identifier) + n.set_predecessor(f"{k}" + n._predecessor[tree.identifier], tree.identifier) else: - n.set_predecessor(f'{k}' + n._predecessor[tree.identifier], tree.identifier) - n.set_successors([f'{k}' + nid for nid in n._successors[tree.identifier]], tree.identifier) + n.set_predecessor(f"{k}" + n._predecessor[tree.identifier], tree.identifier) + n.set_successors([f"{k}" + nid for nid in n._successors[tree.identifier]], tree.identifier) t.paste(level, tree, deep=True) return t @@ -103,12 +103,12 @@ def huffman_tree(trees, level='', n_branches=2): ks = np.argsort([_get_frequency(tree) for tree in trees])[:n_branches] t = merge([trees[k] for k in ks], level=level) t = huffman_tree([t] + [tree for i, tree in enumerate(trees) if i not in ks], level=level) - t.tag = 'root' + t.tag = "root" return t -d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} -nodes = [Node(identifier='', data={'symbols': s, 'frequency': f, 'code': ''}) for s, f in d.items()] +d = {"a": 1, "b": 2, "c": 3, "d": 4, "e": 5} +nodes = [Node(identifier="", data={"symbols": s, "frequency": f, "code": ""}) for s, f in d.items()] t = huffman_tree(nodes) print(t) From ed65d07d1dd71b504b3ec1189e11d3a0b9633b38 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 21:50:56 +0800 Subject: [PATCH 32/44] Update huffman_tree.py --- examples/huffman_tree.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/huffman_tree.py b/examples/huffman_tree.py index d660477..b111f5a 100644 --- a/examples/huffman_tree.py +++ b/examples/huffman_tree.py @@ -57,18 +57,18 @@ def merge(trees, level=''): root = Node(tag="", identifier=level, data={"symbols": data, "frequency": freq, "code": ""}) t.add_node(root) t.root = level - root.tag = f"{root.data['code']}:{{{",".join(root.data['symbols'])}}}/{root.data['frequency']}" + root.tag = f"{root.data['code']}:{{{','.join(root.data['symbols'])}}}/{root.data['frequency']}" for k, tree in enumerate(trees): if isinstance(tree, Node): tree.identifier = f"{k}" + tree.identifier tree.data['code'] = f"{k}" + tree.data['code'] - tree.tag = f"{tree.data['code']}:{{{",".join(tree.data['symbols'])}}}/{tree.data['frequency']}" + tree.tag = f"{tree.data['code']}:{{{','.join(tree.data['symbols'])}}}/{tree.data['frequency']}" t.add_node(tree, parent=level) else: for n in tree.all_nodes_itr(): n.identifier = f"{k}" + n.identifier n.data['code'] = f"{k}" + n.data['code'] - n.tag = f"{n.data['code']}:{{{",".join(n.data['symbols'])}}}/{n.data['frequency']}" + n.tag = f"{n.data['code']}:{{{','.join(n.data['symbols'])}}}/{n.data['frequency']}" nodes = {n.identifier: n for k, n in tree._nodes.items()} tree._nodes = nodes From 89917f87ca823dd6084f14a6ec700892a2a4eb9c Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 21:54:03 +0800 Subject: [PATCH 33/44] Update huffman_tree.py --- examples/huffman_tree.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/huffman_tree.py b/examples/huffman_tree.py index b111f5a..85d3ede 100644 --- a/examples/huffman_tree.py +++ b/examples/huffman_tree.py @@ -40,7 +40,7 @@ def _get_frequency(tree): return a -def merge(trees, level=''): +def merge(trees, level=""): """merge the trees to one tree by add a root Args: @@ -86,7 +86,7 @@ def merge(trees, level=''): return t -def huffman_tree(trees, level='', n_branches=2): +def huffman_tree(trees, level="", n_branches=2): """Huffman coding Args: From cb2829fc0cc72ccb42044f25cdc15be14e4636d9 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 22:00:22 +0800 Subject: [PATCH 34/44] Update huffman_tree.py --- examples/huffman_tree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/huffman_tree.py b/examples/huffman_tree.py index 85d3ede..a987584 100644 --- a/examples/huffman_tree.py +++ b/examples/huffman_tree.py @@ -54,7 +54,7 @@ def merge(trees, level=""): data = list(concat(map(_get_symbols, trees))) freq = sum(map(_get_frequency, trees)) t = Tree() - root = Node(tag="", identifier=level, data={"symbols": data, "frequency": freq, "code": ""}) + root = Node(identifier=level, data={"symbols": data, "frequency": freq, "code": ""}) t.add_node(root) t.root = level root.tag = f"{root.data['code']}:{{{','.join(root.data['symbols'])}}}/{root.data['frequency']}" From 4a82ee62c0880dc677be20c92765dbcdc6251012 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 22:03:02 +0800 Subject: [PATCH 35/44] Update huffman_tree.py --- examples/huffman_tree.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/huffman_tree.py b/examples/huffman_tree.py index a987584..4cf63e7 100644 --- a/examples/huffman_tree.py +++ b/examples/huffman_tree.py @@ -61,13 +61,13 @@ def merge(trees, level=""): for k, tree in enumerate(trees): if isinstance(tree, Node): tree.identifier = f"{k}" + tree.identifier - tree.data['code'] = f"{k}" + tree.data['code'] + tree.data["code"] = f"{k}" + tree.data["code"] tree.tag = f"{tree.data['code']}:{{{','.join(tree.data['symbols'])}}}/{tree.data['frequency']}" t.add_node(tree, parent=level) else: for n in tree.all_nodes_itr(): n.identifier = f"{k}" + n.identifier - n.data['code'] = f"{k}" + n.data['code'] + n.data["code"] = f"{k}" + n.data["code"] n.tag = f"{n.data['code']}:{{{','.join(n.data['symbols'])}}}/{n.data['frequency']}" nodes = {n.identifier: n for k, n in tree._nodes.items()} From baa4bb3344566a700ce32601627079e1af7a50c3 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 22:06:34 +0800 Subject: [PATCH 36/44] Update huffman_tree.py --- examples/huffman_tree.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/examples/huffman_tree.py b/examples/huffman_tree.py index 4cf63e7..a33d9b8 100644 --- a/examples/huffman_tree.py +++ b/examples/huffman_tree.py @@ -70,17 +70,16 @@ def merge(trees, level=""): n.data["code"] = f"{k}" + n.data["code"] n.tag = f"{n.data['code']}:{{{','.join(n.data['symbols'])}}}/{n.data['frequency']}" - nodes = {n.identifier: n for k, n in tree._nodes.items()} - tree._nodes = nodes + tree._nodes = {n.identifier: n for k, n in tree._nodes.items()} tree.root = f"{k}" + tree.root for n in tree.all_nodes_itr(): if n.is_root(): - n.set_successors([f"{k}" + nid for nid in n._successors[tree.identifier]], tree.identifier) + n.set_successors([f"{k}{nid}" for nid in n._successors[tree.identifier]], tree.identifier) elif n.is_leaf(): - n.set_predecessor(f"{k}" + n._predecessor[tree.identifier], tree.identifier) + n.set_predecessor(f"{k}{n._predecessor[tree.identifier]}", tree.identifier) else: - n.set_predecessor(f"{k}" + n._predecessor[tree.identifier], tree.identifier) - n.set_successors([f"{k}" + nid for nid in n._successors[tree.identifier]], tree.identifier) + n.set_predecessor(f"{k}{n._predecessor[tree.identifier]}", tree.identifier) + n.set_successors([f"{k}{nid}" for nid in n._successors[tree.identifier]], tree.identifier) t.paste(level, tree, deep=True) return t From 7395ba6ae242be9ff7b795c7b500a8db6d1fd7ef Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 22:09:06 +0800 Subject: [PATCH 37/44] Update huffman_tree.py --- examples/huffman_tree.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/huffman_tree.py b/examples/huffman_tree.py index a33d9b8..d32c8d1 100644 --- a/examples/huffman_tree.py +++ b/examples/huffman_tree.py @@ -71,15 +71,16 @@ def merge(trees, level=""): n.tag = f"{n.data['code']}:{{{','.join(n.data['symbols'])}}}/{n.data['frequency']}" tree._nodes = {n.identifier: n for k, n in tree._nodes.items()} - tree.root = f"{k}" + tree.root + tree.root = f"{k}{tree.root}" + tid = tree.identifier for n in tree.all_nodes_itr(): if n.is_root(): - n.set_successors([f"{k}{nid}" for nid in n._successors[tree.identifier]], tree.identifier) + n.set_successors([f"{k}{nid}" for nid in n._successors[tid]], tid) elif n.is_leaf(): - n.set_predecessor(f"{k}{n._predecessor[tree.identifier]}", tree.identifier) + n.set_predecessor(f"{k}{n._predecessor[tid]}", tid) else: - n.set_predecessor(f"{k}{n._predecessor[tree.identifier]}", tree.identifier) - n.set_successors([f"{k}{nid}" for nid in n._successors[tree.identifier]], tree.identifier) + n.set_predecessor(f"{k}{n._predecessor[tid]}", tid) + n.set_successors([f"{k}{nid}" for nid in n._successors[tid]], tid) t.paste(level, tree, deep=True) return t From dc6a0ee799b927db9f225ea93f9677fc0dbeadb1 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 22:14:09 +0800 Subject: [PATCH 38/44] Update huffman_tree.py --- examples/huffman_tree.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/huffman_tree.py b/examples/huffman_tree.py index d32c8d1..acf602b 100644 --- a/examples/huffman_tree.py +++ b/examples/huffman_tree.py @@ -57,7 +57,7 @@ def merge(trees, level=""): root = Node(identifier=level, data={"symbols": data, "frequency": freq, "code": ""}) t.add_node(root) t.root = level - root.tag = f"{root.data['code']}:{{{','.join(root.data['symbols'])}}}/{root.data['frequency']}" + root.tag = f"root:{{{','.join(root.data['symbols'])}}}/{root.data['frequency']}" for k, tree in enumerate(trees): if isinstance(tree, Node): tree.identifier = f"{k}" + tree.identifier @@ -102,8 +102,7 @@ def huffman_tree(trees, level="", n_branches=2): else: ks = np.argsort([_get_frequency(tree) for tree in trees])[:n_branches] t = merge([trees[k] for k in ks], level=level) - t = huffman_tree([t] + [tree for i, tree in enumerate(trees) if i not in ks], level=level) - t.tag = "root" + t = huffman_tree( [t] + [tree for k, tree in enumerate(trees) if k not in ks], level=level ) return t From 8e0743a590220c9e0c519a484e4ee49d3878fd1b Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 22:16:59 +0800 Subject: [PATCH 39/44] Update huffman_tree.py --- examples/huffman_tree.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/huffman_tree.py b/examples/huffman_tree.py index acf602b..4f2ff56 100644 --- a/examples/huffman_tree.py +++ b/examples/huffman_tree.py @@ -102,8 +102,8 @@ def huffman_tree(trees, level="", n_branches=2): else: ks = np.argsort([_get_frequency(tree) for tree in trees])[:n_branches] t = merge([trees[k] for k in ks], level=level) - t = huffman_tree( [t] + [tree for k, tree in enumerate(trees) if k not in ks], level=level ) - return t + trees = [t, *(tree for k, tree in enumerate(trees) if k not in ks)] + return huffman_tree(trees, level=level) d = {"a": 1, "b": 2, "c": 3, "d": 4, "e": 5} From efa63b0788af325036bdbb9e441ec083ac20c529 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 22:51:28 +0800 Subject: [PATCH 40/44] Update huffman_tree.py --- examples/huffman_tree.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/examples/huffman_tree.py b/examples/huffman_tree.py index 4f2ff56..85ff596 100644 --- a/examples/huffman_tree.py +++ b/examples/huffman_tree.py @@ -97,6 +97,8 @@ def huffman_tree(trees, level="", n_branches=2): Returns: Tree: Huffman tree """ + assert len(trees)>=2 + if len(trees) == 2: return merge(trees, level=level) else: @@ -106,8 +108,17 @@ def huffman_tree(trees, level="", n_branches=2): return huffman_tree(trees, level=level) +def make_node(s, f): + """Make `Node` object + + s: str + f: number + """ + return Node(identifier="", data={"symbols": s, "frequency": f, "code": ""}) + + d = {"a": 1, "b": 2, "c": 3, "d": 4, "e": 5} -nodes = [Node(identifier="", data={"symbols": s, "frequency": f, "code": ""}) for s, f in d.items()] +nodes = [make_node(s, f) for s, f in d.items()] +nodes = list(nodes) t = huffman_tree(nodes) - print(t) From 5787d5b1410d3ef956cb1ec795e83483152bab86 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 22:55:51 +0800 Subject: [PATCH 41/44] Update huffman_tree.py --- examples/huffman_tree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/huffman_tree.py b/examples/huffman_tree.py index 85ff596..687703c 100644 --- a/examples/huffman_tree.py +++ b/examples/huffman_tree.py @@ -97,7 +97,7 @@ def huffman_tree(trees, level="", n_branches=2): Returns: Tree: Huffman tree """ - assert len(trees)>=2 + assert len(trees) >= 2 if len(trees) == 2: return merge(trees, level=level) From 0580b0f2e8360ec3160a073adc0ff36eb098af2c Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Thu, 11 Apr 2024 22:59:31 +0800 Subject: [PATCH 42/44] Update huffman_tree.py --- examples/huffman_tree.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/huffman_tree.py b/examples/huffman_tree.py index 687703c..783e44c 100644 --- a/examples/huffman_tree.py +++ b/examples/huffman_tree.py @@ -57,18 +57,18 @@ def merge(trees, level=""): root = Node(identifier=level, data={"symbols": data, "frequency": freq, "code": ""}) t.add_node(root) t.root = level - root.tag = f"root:{{{','.join(root.data['symbols'])}}}/{root.data['frequency']}" + root.tag = f"root: {{{','.join(root.data['symbols'])}}}/{root.data['frequency']}" for k, tree in enumerate(trees): if isinstance(tree, Node): tree.identifier = f"{k}" + tree.identifier tree.data["code"] = f"{k}" + tree.data["code"] - tree.tag = f"{tree.data['code']}:{{{','.join(tree.data['symbols'])}}}/{tree.data['frequency']}" + tree.tag = f"{tree.data['code']}: {{{','.join(tree.data['symbols'])}}}/{tree.data['frequency']}" t.add_node(tree, parent=level) else: for n in tree.all_nodes_itr(): n.identifier = f"{k}" + n.identifier n.data["code"] = f"{k}" + n.data["code"] - n.tag = f"{n.data['code']}:{{{','.join(n.data['symbols'])}}}/{n.data['frequency']}" + n.tag = f"{n.data['code']}: {{{','.join(n.data['symbols'])}}}/{n.data['frequency']}" tree._nodes = {n.identifier: n for k, n in tree._nodes.items()} tree.root = f"{k}{tree.root}" From d6733b6aef0ddd44ebacc084b9b4e57bd1553b64 Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Sat, 13 Apr 2024 09:58:59 +0800 Subject: [PATCH 43/44] Update tree.py --- treelib/tree.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/treelib/tree.py b/treelib/tree.py index e18dc92..aadb62c 100644 --- a/treelib/tree.py +++ b/treelib/tree.py @@ -698,10 +698,12 @@ def paste(self, nid, new_tree, deep=False): if set_joint: raise ValueError("Duplicated nodes %s exists." % list(map(text, set_joint))) - for cid, node in iteritems(new_tree.nodes): - if deep: - node = deepcopy(node) - self._nodes.update({cid: node}) + if deep: + new_nodes = {cid: deepcopy(node) for cid, node in iteritems(new_tree.nodes)} + else: + new_nodes = new_tree.nodes + self._nodes.update(new_nodes) + for _, node in iteritems(new_nodes): node.clone_pointers(new_tree.identifier, self._identifier) self.__update_bpointer(new_tree.root, nid) From 49f8b346788b2befb17a1e43a09f2a6e3e04576b Mon Sep 17 00:00:00 2001 From: William Song <30965609+Freakwill@users.noreply.github.com> Date: Sat, 13 Apr 2024 10:19:41 +0800 Subject: [PATCH 44/44] Update node.py --- treelib/node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/treelib/node.py b/treelib/node.py index 958c734..067f30b 100644 --- a/treelib/node.py +++ b/treelib/node.py @@ -267,7 +267,7 @@ def tag(self): @tag.setter def tag(self, value): """Set the value of `_tag`.""" - self._tag = value if value is not None else None + self._tag = value def __repr__(self): name = self.__class__.__name__