示例#1
0
 def create_full_tree(depth):
     if depth == 0:
         terminal = Terminal.random_terminal()
         node = Node("terminal", terminal)
         return Tree(node)
     else:
         function = Function.random_function()
         root_node = Node("function", function)
         result = Tree(root_node)
         for i in range(2):  #function.arity()
             result.add_child(Initializer.create_full_tree(depth - 1))
         return result
示例#2
0
 def create_full_tree(depth):
     if depth == 0:
         terminal = Terminal.random_terminal()
         node = Node("terminal", terminal)
         return Tree(node)
     else:
         function = Function.random_function()
         root_node = Node("function", function)
         result = Tree(root_node)
         for i in range(2):  #function.arity()
             result.add_child(Initializer.create_full_tree(depth - 1))
         return result
示例#3
0
    def read_tree(self, line):
        parents = list(map(int, line.split()))
        #print("parents:", parents, "# parents:", len(parents))
        trees = dict()
        root = None
        for i in range(1, len(parents) + 1):
            #print("i:", i, "; trees' keys:", trees.keys(), "; parents[i-1]:", parents[i-1])

            # if we haven't processed it, and its listed parent is actually sensical (has a parent)
            if i - 1 not in trees.keys() and parents[i - 1] != -1:
                idx = i
                prev = None
                #print("\tin if; idx = i = ", i)

                # follows parent links, starting with index i
                while True:
                    #print("\t\tin while loops")
                    parent = parents[idx - 1]
                    #print("\t\t\tparent:", parent)
                    if parent == -1:
                        #print("*** parent is -1!")
                        break
                    tree = Tree()
                    #print("\t\t\tprev:", prev)
                    if prev is not None:
                        #print("\t\t\tprev isn't None, so adding it as a children to Tree")
                        tree.add_child(prev)
                    
                    trees[idx - 1] = tree
                    tree.idx = idx - 1
                    #print("\t\t\ttrees:", trees)
                    #print("\t\t\ttree = ", tree, "idx:", tree.idx)
                    if parent - 1 in trees.keys(): # simply checks if we should point its parent to the current node
                        #print("\t\t\t\tparent -1 is in trees!")
                        trees[parent - 1].add_child(tree)
                        break
                    elif parent == 0: # make it the root
                        #print("\t\t\t\tparent = 0")
                        root = tree
                        break
                    else:
                        #print("\t\t\t\tset prev to be = tree; idx = parent", idx, "=", parent)
                        prev = tree
                        idx = parent
        #print("# trees:", len(trees.keys()))

        #all_nodes = []
        #self.dfs(root, all_nodes)
        #print("all_nodes:", len(all_nodes))
        #exit()
        return root
示例#4
0
文件: sort.py 项目: bukss/tree_sort
def tree_sort(l: List(int)) -> List(int):
    """
    A python implementation of tree sort
    Tree sort constructs a binary search tree where each left branch is less
    than the parent, and each right branch is greater than the parent. When 
    the tree is traversed in inorder the nodes are in ascending order
    """

    tree = Tree()
    [tree.add_child(n) for n in l]
    return tree.collate()
示例#5
0
def rec(x,y,attrNameList,attrs,parent_examples,class_values):
    node = Tree()
    is_pure,first_item = is_pure_set(y)
    if(x.__len__()==0):
        class_amount = list()
        for y_value in class_values:
            class_amount.append((y_value,get_sum_y_value(parent_examples, y_value)))
        return Tree(max(class_amount,key=itemgetter(1)),class_amount)
    elif(is_pure):
        return Tree(first_item + " " + str(y.__len__()),[(first_item,y.__len__())])
    elif(attrNameList.__len__()==0):
        class_amount = list()
        for y_value in class_values:
            class_amount.append((y_value, get_sum_y_value(y, y_value)))
        return Tree(max(class_amount, key=itemgetter(1)),class_amount)
    else:
        best_gain,best_gain_index = find_best_gain_index(x,y,attrs,attrNameList,class_values)
        node.name = attrNameList[best_gain_index]
        adsf = list()
        for class_value in class_values:
            adsf.append((class_value,y.count(class_value)))
        node.values = adsf
        tmp_attrs = attrs.copy()
        x_values = tmp_attrs.pop(attrNameList[best_gain_index])
        for value in x_values:
            '''
            höger eller vänster
            '''
            dx = x.copy()
            dy = y.copy()
            ddx, ddy = update_data_set(dx, dy, best_gain_index, value)
            tmp_attrNameList = attrNameList[:]
            tmp_attrNameList[best_gain_index] = None
            node.add_child(rec(ddx,ddy,tmp_attrNameList,tmp_attrs,dy,class_values))
            # best_gain, best_gain_index = find_best_gain_index(ddx, ddy, tmp_attrs, tmp_attrNameList, class_values)
            # if best_gain == 1 or best_gain == 0:
            #     return Tree('leaf')
            # if best_gain_index > -1:
            #     node.add_child(rec(ddx, ddy,tmp_attrNameList,tmp_attrs,dx,class_values))
    return node
示例#6
0
def test_tree():

    # initialize tree
    tree = Tree("Apple")
    assert tree.preorder_traversal(tree.root) == 'Apple, '

    # test add_child, pre-order and post-order traversal
    tree.add_child('Apple', 'Pear', tree.root)
    assert tree.preorder_traversal(tree.root) == 'Apple, Pear, '
    assert tree.postorder_traversal(tree.root) == 'Pear, Apple, '
    tree.add_child('Apple', 'Orange', tree.root)
    tree.add_child('Apple', 'Grape', tree.root)
    tree.add_child('Orange', 'Mango', tree.root)
    tree.add_child('Orange', 'Peach', tree.root)
    tree.add_child('Grape', 'Watermelon', tree.root)
    assert tree.preorder_traversal(
        tree.root) == 'Apple, Pear, Orange, Mango, Peach, Grape, Watermelon, '
    assert tree.postorder_traversal(
        tree.root) == 'Pear, Mango, Peach, Orange, Watermelon, Grape, Apple, '

    # test has
    assert tree.has('Apple', tree.root)
    assert tree.has('Pear', tree.root)
    assert tree.has('Orange', tree.root)
    assert tree.has('Grape', tree.root)
    assert tree.has('Mango', tree.root)
    assert tree.has('Watermelon', tree.root)
    assert not tree.has('Pineapple', tree.root)
    assert not tree.has('Plum', tree.root)
    assert not tree.has('Kiwi', tree.root)

    # test is_empty
    assert not tree.is_empty(tree.root)
    assert tree.is_empty(None)

    # test nuke
    tree.nuke()
    assert tree.is_empty(tree.root)
示例#7
0
 def read_tree(self, line):
     # print("line:",line)
     # 3 3 5 5 11 5 6 9 6 11 0 11
     # parents = list(map(int, line.split()))
     parents = line
     trees = dict()
     root = None
     # 1 - 13
     for i in range(1, len(parents) + 1):
         if i - 1 not in trees.keys() and parents[i - 1] != -1:
             idx = i  # 1  2  7  8
             prev = None
             while True:
                 parent = parents[
                     idx - 1]  # parent = 3  5  11  0 --- 3 5  11 -- 6  9
                 if parent == -1:
                     break
                 tree = Tree()  # 实例化
                 if prev is not None:
                     tree.add_child(
                         prev
                     )  # null  5这棵树的孩子结点的3   11这棵树的孩子结点为5  0这棵树的孩子结点为11  5这棵树的孩子结点为3  11这棵树的孩子结点为5
                 trees[
                     idx -
                     1] = tree  # trees[0]为空Tree()  trees[5]为 5这棵树   trees[4]为 11这棵树  trees[10]为 0这棵树  trees[1]为 3这棵树 trees[2]为 5这棵树 trees[6]为 6这棵树 trees[7]为 9这棵树
                 # tree.idx为树的编号
                 tree.idx = idx - 1  # 0  2  4  10  1  2  -- 6  7
                 if parent - 1 in trees.keys():
                     trees[parent - 1].add_child(tree)
                     break
                 elif parent == 0:
                     root = tree  # 0这棵树是root
                     break
                 else:
                     prev = tree  # prev为 Tree()  tree.idx = 0  prev= 5这棵树   prev= 11这棵树  prev= 0这棵树 prev= 3这棵树   5这棵树  9
                     idx = parent  # idx = 3   5  11  0   3  5
     return root
示例#8
0
文件: tests.py 项目: bukss/tree_sort
def init_tree() -> Tree:
    """
    Generates a tree that looks like
                    6
                   / \
                  5   8
                 /\   /\
                2    7  9 
               /\       /\
              1  3       10
                 /\
                   4      
    """
    tree = Tree()
    children = [6, 8, 9, 5, 2, 1, 3, 7, 10, 4]
    [tree.add_child(child) for child in children]
    return tree
示例#9
0
class PN:
    def __init__(self,
                 name,
                 root,
                 evaluate,
                 result,
                 get_pn_dpn,
                 max_nodes,
                 delete_subtrees=False,
                 immediateEvaluation=True):
        self.pn_tree = Tree()
        self.name = name
        self.evaluate = evaluate
        self.result = result
        self.get_pn_dpn = get_pn_dpn
        self.max_nodes = max_nodes
        self.delete_subtrees = delete_subtrees
        self.immediateEvaluation = immediateEvaluation

        self.root = root
        self.pn_tree.set_root(self.root)
        self.eval_count = 0
        self.terminated = False

    def terminate(self):
        self.terminated = True

    def evaluate_node(self, node):
        self.evaluate(node)
        self.eval_count += 1

    def reset(self, node):
        self.eval_count = 0
        self.root = node
        self.pn_tree.clear()
        self.pn_tree.set_root(self.root)

    def set_second_level(self, evaluate):
        pass

    def set_evaluate(self, evaluate):
        self.evaluate = evaluate

    def set_limit(self, max_nodes):
        self.max_nodes = max_nodes

    def get_size(self):
        return self.pn_tree.node_count

    def get_node_count(self):
        return self.pn_tree.node_count + self.pn_tree.deleted_count

    def perform_search(self):
        if self.immediateEvaluation:
            self.evaluate_node(self.root)
        self.set_pn_dpn(self.root)
        current_node = self.root
        while self.root.pn != 0 and self.root.dpn != 0 and self.pn_tree.node_count <= self.max_nodes and not self.terminated:
            most_proving = self.select_most_proving_node(current_node)
            if not self.immediateEvaluation:
                self.evaluate_node(most_proving)
                self.set_pn_dpn(most_proving)
            self.expand_node(most_proving)
            current_node = self.update_ancestors(most_proving)
        return self.result(self)

    # Calculating proof and disproof numbers
    def set_pn_dpn(self, node):
        # Internal Node
        if node.expanded:
            # AND Node
            # PN = sum of children PN; DPN = minimum of children DPN
            if node.node_type == "AND":
                node.pn = sum(c.pn for c in node.children)
                node.dpn = min(c.dpn for c in node.children)
            # OR Node
            # PN = minimum of children PN; DPN = sum of children DPN
            else:
                node.pn = min(c.pn for c in node.children)
                node.dpn = sum(c.dpn for c in node.children)
        # Leaf node
        else:
            evaluation = node.value
            # Lost
            if evaluation == FALSE:
                node.pn = float("inf")
                node.dpn = 0
            # Won
            elif evaluation == TRUE:
                node.pn = 0
                node.dpn = float("inf")
            # Unknown
            elif evaluation == UNKNOWN:
                node.pn, node.dpn = self.get_pn_dpn(node)

    def select_most_proving_node(self, node):
        while node.expanded:
            # Lowest DPN
            if node.node_type == "AND":
                vals = [c.dpn for c in node.children]
            # Lowest PN
            else:
                vals = [c.pn for c in node.children]
            node = node.children[vals.index(min(vals))]
        return node

    def expand_node(self, node):
        if node.pn == 0 or node.dpn == 0: return
        # Check whether evaluation added children to node
        if node.expanded: return
        # generate all children
        child_type = "AND" if node.node_type == "OR" else "OR"
        for a in node.state.allowed_actions():
            new_state = node.state.perform_action(a)
            # Node(Type,State,Parent,Action)
            child_node = Node(node_type=child_type,
                              state=new_state,
                              parent=node,
                              depth=node.depth + 1,
                              action=a)
            self.add_child(child_node, node)

            if self.immediateEvaluation:
                self.evaluate_node(child_node)
            self.set_pn_dpn(child_node)
            if child_node.pn == 0 and node.node_type == "OR": break  # won
            if child_node.dpn == 0 and node.node_type == "AND": break  # lost
        node.expanded = True

    def update_ancestors(self, node):
        while True:
            old_pn = node.pn
            old_dpn = node.dpn
            # Check in case of delayed evaluation
            if old_pn == 0 or old_dpn == 0:
                if node == self.root:
                    return self.root
                node = node.parent
                continue
            self.set_pn_dpn(node)
            # No change on the path
            if node.pn == old_pn and node.dpn == old_dpn:
                return node
            # delete disproved subtrees
            if self.delete_subtrees and (node.pn == 0 or node.dpn == 0):
                self.delete_subtree(node)

            if node == self.root:
                return self.root
            node = node.parent
        return node

    def delete_subtree(self, node):
        self.pn_tree.delete_subtree(node)

    def add_child(self, child_node, node):
        self.pn_tree.add_child(child_node, node)
示例#10
0
文件: tests.py 项目: bukss/tree_sort
 def test(self):
     tree = Tree()
     tree.add_child(5)
     assert (tree.tree[5]["left"] is None)
     assert (tree.tree[5]["right"] is None)
示例#11
0
文件: tests.py 项目: bukss/tree_sort
 def test(self):
     tree = Tree()
     tree.add_child(5)
     tree.add_child(3)
     assert (tree.tree[5]["left"] == 3)
示例#12
0
    def GenerateAST(self, ins):
        self._statement_num += 1
        AST = Tree()
        try:
            l.info("[insn] op  %s" % (ins.opname))
            AST.op=ins.op
            AST.opname = ins.opname

            if ins.op == idaapi.cit_block:
                self.dump_block(ins.ea, ins.cblock, AST)
            elif ins.op == idaapi.cit_expr:
                AST.add_child(self.dump_expr(ins.cexpr))

            elif ins.op == idaapi.cit_if:
                l.info("[if]"+spliter)
                cif = ins.details
                cexpr = cif.expr
                ithen = cif.ithen
                ielse = cif.ielse

                AST.add_child(self.dump_expr(cexpr))
                if ithen:
                    AST.add_child(self.GenerateAST(ithen))
                if ielse:
                    AST.add_child(self.GenerateAST(ielse))

            elif ins.op == idaapi.cit_while:
                cwhile = ins.details
                self.dump_while(cwhile,AST)

            elif ins.op == idaapi.cit_return:
                creturn = ins.details
                AST.add_child( self.dump_return(creturn) )

            elif ins.op == idaapi.cit_for:
                l.info( '[for]'+spliter)
                cfor = ins.details
                AST.add_child(self.dump_expr(cfor.init))
                AST.add_child(self.dump_expr(cfor.step))
                AST.add_child(self.dump_expr(cfor.expr))
                AST.add_child(self.GenerateAST(cfor.body))
            elif ins.op == idaapi.cit_switch:
                l.info('[switch]'+spliter)
                cswitch = ins.details
                cexpr = cswitch.expr
                ccases = cswitch.cases #Switch cases: values and instructions.
                cnumber = cswitch.mvnf #Maximal switch value and number format.
                AST.add_child(self.dump_expr(cexpr))
                self.dump_ccases(ccases, AST)
            elif ins.op == idaapi.cit_do:
                l.info('[do]'+spliter)
                cdo = ins.details
                cbody = cdo.body
                cwhile = cdo.expr
                AST.add_child(self.GenerateAST(cbody))
                AST.add_child(self.dump_expr(cwhile))
            elif ins.op == idaapi.cit_break or ins.op == idaapi.cit_continue:
                pass
            elif ins.op == idaapi.cit_goto:
                pass
            else:
                l.warning('[error] not handled op type %s' % ins.opname)

        except:
            l.warning("[E] exception here ! ")

        return AST
示例#13
0
    def dump_expr(self, cexpr):
        '''
        l.info the expression
        :return: AST with two nodes op and oprand : op Types.NODETYPE.OPTYPE, oprand : list[]
        '''
        # l.info "dumping expression %x" % (cexpr.ea)

        #操作数
        oprand =[] # a list of Tree()
        l.info("[expr] op %s" % cexpr.opname)

        if cexpr.op == idaapi.cot_call:
            # oprand = args
            # get the function call arguments
            self._get_callee(cexpr.ea)
            l.info('[call]'+spliter)
            args = cexpr.a
            for arg in args:
                oprand.append(self.dump_expr(arg))
        elif cexpr.op == idaapi.cot_idx:
            l.info('[idx]'+spliter)
            oprand.append(self.dump_expr(cexpr.x))
            oprand.append(self.dump_expr(cexpr.y))

        elif cexpr.op == idaapi.cot_memptr:
            l.info('[memptr]'+spliter)
            #TODO
            AST=Tree()
            AST.op = idaapi.cot_num #consider the mem size pointed by memptr
            AST.value = cexpr.ptrsize
            AST.opname = "value"
            oprand.append(AST)
            # oprand.append(cexpr.m) # cexpr.m : member offset
            # oprand.append(cexpr.ptrsize)
        elif cexpr.op == idaapi.cot_memref:

            l.info('[memref]'+spliter)
            # oprand.append(cexpr.m)

        elif cexpr.op == idaapi.cot_num:
            l.info ('[num]' + str(cexpr.n._value))
            AST = Tree()
            AST.op = idaapi.cot_num  # consider the mem size pointed by memptr
            AST.value = cexpr.n._value
            AST.opname = "value"
            oprand.append(AST)

        elif cexpr.op == idaapi.cot_var:
            # var : cexpr.v
            l.info ('[var]' + str(cexpr.v.idx))
            # oprand.append(cexpr.v.idx) # which var (index for var)
            # TODO handle array type
        elif cexpr.op == idaapi.cot_str:
            # string constant
            l.info( '[str]' + cexpr.string)
            AST =Tree()
            AST.opname = "string"
            AST.op = cexpr.op
            AST.value = cexpr.string
            oprand.append(AST)

        elif cexpr.op == idaapi.cot_obj:
            l.info ('[cot_obj]' + hex(cexpr.obj_ea))
            # oprand.append(cexpr.obj_ea)
            # Many strings are defined as 'obj'
            # I wonder if 'obj' still points to other types of data?
            # notice that the address of 'obj' is not in .text segment
            if get_segm_name(getseg(cexpr.obj_ea)) not in ['.text']:
                AST = Tree()
                AST.opname = "string"
                AST.op = cexpr.op
                AST.value = GetString(cexpr.obj_ea)
                oprand.append(AST)

        elif cexpr.op <= idaapi.cot_fdiv and cexpr.op >= idaapi.cot_comma:
            #All binocular operators
            oprand.append(self.dump_expr(cexpr.x))
            oprand.append(self.dump_expr(cexpr.y))

        elif cexpr.op >= idaapi.cot_fneg and cexpr.op <= idaapi.cot_call:
            # All unary operators
            l.info( '[single]' + spliter)
            oprand.append(self.dump_expr(cexpr.x))
        else:
            l.warning ('[error] %s not handled ' % cexpr.opname)
        AST = Tree()
        AST.opname=cexpr.opname
        AST.op=cexpr.op
        for tree in oprand:
            AST.add_child(tree)
        return AST
示例#14
0
from Tree import Tree
from bfs import bfs

tree1 = Tree(3)
tree2 = Tree(9)
tree3 = Tree(20)
tree4 = Tree(15)
tree5 = Tree(7)

tree1.add_child(tree2)
tree1.add_child(tree3)
tree3.add_child(tree4)
tree3.add_child(tree5)

goal_queue = bfs(tree1)

print(goal_queue)
示例#15
0
文件: tests.py 项目: bukss/tree_sort
 def test(self):
     tree = Tree()
     tree.add_child(5)
     tree.add_child(6)
     assert (tree.tree[5]["right"] == 6)
示例#16
0
文件: tests.py 项目: bukss/tree_sort
 def test(self):
     tree = Tree()
     tree.add_child(5)
     assert (tree.parent == 5)
示例#17
0
文件: tests.py 项目: bukss/tree_sort
 def test(self):
     tree = Tree()
     children = [5, 4, 6]
     [tree.add_child(child) for child in children]
     assert (tree.tree[5]["left"] == 4 and tree.tree[5]["right"] == 6)
示例#18
0
class TreeTest(unittest.TestCase):
    """docstring for TreeTest"""
    def setUp(self):
        self.tree = Tree(root=5)

    def test_tree_data(self):
        # print()
        # print("*** test_tree_data")
        # print(self.tree.data)
        self.assertEqual(self.tree.data, 5)
        # print("***end test_tree_data")
        # print()

    def test_tree_string_representation(self):
        # print(str(self.tree))
        self.assertEqual(str(self.tree), str(self.tree.data))

    def test_tree_children_exist(self):
        # print()
        # print("*** test test_tree_children_exist")
        self.tree.add_child(5, 4)
        self.tree.add_child(5, 7)
        self.tree.add_child(5, 9)
        # print(self.tree.children)
        self.assertTrue(len(self.tree.children) > 0)
        # print("***end test test_tree_children_exist")
        # print()

    def test_has_children(self):
        # print()
        # print("*** has_children")
        self.tree.add_child(5, 4)
        self.tree.add_child(5, 8)
        self.tree.add_child(6, 9)
        # print(self.tree.has_children())
        self.assertTrue(str(self.tree.children) == "[4, 8]")
        # print("***end has_children")
        # print()

    def test_find_proper_node(self):
        # print()
        # print("*** test_find_proper_node")
        # print(self.tree.has_children())
        self.assertFalse(self.tree.find_proper_node(9, 6))
        self.tree.add_child(5, 19)
        # print(self.tree.has_children())
        # print("***end test_find_proper_node")
        # print()

    def test_find_proper_node_when_children(self):
        # print()
        # print("*** test_find_proper_node_when_children")
        self.tree.add_child(5, 4)
        self.tree.add_child(5, 8)
        self.tree.add_child(5, 9)
        # add children to the children
        self.tree.add_child(8, 7)
        self.tree.add_child(8, 3)
        self.tree.add_child(8, 45)

        self.tree.add_child(9, 62)
        self.tree.add_child(9, 68)
        self.tree.add_child(9, 93)

        self.tree.add_child(4, 41)
        self.tree.add_child(4, 42)
        self.tree.add_child(4, 43)
        self.tree.add_child(4, 44)

        # print(self.tree.children[1].children)
        # print(self.tree.children[2].children)
        # print(self.tree.children[0].children)

        self.assertEqual(str(self.tree.children[1].children), "[7, 3, 45]")
        self.assertEqual(str(self.tree.children[2].children), "[62, 68, 93]")
        self.assertEqual(str(self.tree.children[0].children),
                         "[41, 42, 43, 44]")
        # print("***end test_find_proper_node_when_children")

    def test_find(self):
        # print()
        # print("*** test_find")
        self.tree.add_child(5, 4)
        self.tree.add_child(5, 8)
        self.tree.add_child(5, 9)
        # print(self.tree.find(5))
        self.assertEqual(self.tree.find(5), True)
        self.assertEqual(self.tree.find(6), False)

        self.tree.add_child(4, 41)
        self.tree.add_child(4, 42)
        self.tree.add_child(4, 43)
        self.tree.add_child(4, 44)

        self.tree.add_child(8, 82)
        self.tree.add_child(8, 87)
        self.tree.add_child(8, 83)

        self.tree.add_child(9, 92)
        self.tree.add_child(9, 98)
        self.tree.add_child(9, 93)

        # print(self.tree.find(4))
        # print(self.tree.find(8))
        # print(self.tree.find(9))
        # print(self.tree.find(41))
        # print(self.tree.find(42))
        # print(self.tree.find(43))
        # print(self.tree.find(44))
        # print(self.tree.find(82))
        # print(self.tree.find(87))
        # print(self.tree.find(83))
        # print(self.tree.find(92))
        # print(self.tree.find(98))
        # print(self.tree.find(93))
        self.assertEqual(self.tree.find(4), True)
        self.assertEqual(self.tree.find(8), True)
        self.assertEqual(self.tree.find(9), True)
        self.assertEqual(self.tree.find(41), True)
        self.assertEqual(self.tree.find(42), True)
        self.assertEqual(self.tree.find(43), True)
        self.assertEqual(self.tree.find(44), True)
        self.assertEqual(self.tree.find(82), True)
        self.assertEqual(self.tree.find(87), True)
        self.assertEqual(self.tree.find(83), True)
        self.assertEqual(self.tree.find(92), True)
        self.assertEqual(self.tree.find(98), True)
        self.assertEqual(self.tree.find(93), True)

        # print(self.tree.find(28))
        # print(self.tree.find(13))
        # print(self.tree.find(87))
        # print(self.tree.find(46))
        self.assertEqual(self.tree.find(28), False)
        self.assertEqual(self.tree.find(13), False)
        self.assertEqual(self.tree.find(87), True)
        self.assertEqual(self.tree.find(46), False)

        # print("***end test_find")
        # print()

    def test_height(self):
        # print()
        # print("*** test_height")
        # self.assertEqual(self.tree.height(), 1)

        # test when only root
        self.assertEqual(self.tree.height(), 1)

        # test when tree is with greater height than 1
        self.tree.add_child(5, 4)
        self.tree.add_child(5, 8)
        self.tree.add_child(5, 9)
        self.tree.add_child(4, 41)
        self.tree.add_child(4, 42)
        self.tree.add_child(4, 43)
        self.tree.add_child(4, 44)
        self.tree.add_child(44, 441)
        self.tree.add_child(44, 442)
        self.tree.add_child(44, 443)
        self.tree.add_child(443, "a")
        self.tree.add_child(443, "b")
        self.tree.add_child(443, "c")
        self.assertEqual(self.tree.height(), 5)

        self.tree.children = []

        # test after we have reset the tree's children to []
        self.assertEqual(self.tree.height(), 1)
        self.tree.add_child(5, 8)
        self.assertEqual(self.tree.height(), 2)
        self.tree.add_child(8, 14)
        self.assertEqual(self.tree.height(), 3)
        self.tree.add_child(14, 62)
        self.assertEqual(self.tree.height(), 4)

        # print("***end test_height")
        # print()

    def test_attr_count(self):
        self.tree.add_child(5, 4)
        self.tree.add_child(5, 8)
        self.tree.add_child(5, 9)
        self.tree.add_child(4, 41)
        self.tree.add_child(4, 42)
        self.tree.add_child(4, 43)
        self.tree.add_child(4, 44)
        self.tree.add_child(8, 82)
        self.tree.add_child(8, 87)
        self.tree.add_child(8, 83)
        self.tree.add_child(9, 92)
        self.tree.add_child(9, 98)
        self.tree.add_child(9, 93)

        self.assertEqual(self.tree.count_nodes(), 14)

    def test_tree_levels_method(self):
        # if only root
        self.assertEqual(self.tree.tree_levels(), [[5]])
        # add more nodes
        self.tree.add_child(5, 4)
        self.tree.add_child(5, 8)
        self.tree.add_child(5, 9)
        self.assertEqual(self.tree.tree_levels(), [[5], [4, 8, 9]])

        self.tree.add_child(4, 41)
        self.tree.add_child(4, 42)
        self.tree.add_child(4, 43)
        self.assertEqual(self.tree.tree_levels(),
                         [[5], [41, 42, 43], [4, 8, 9]])

        self.tree.add_child(8, 82)
        self.tree.add_child(8, 87)
        self.tree.add_child(8, 83)
        self.assertEqual(self.tree.tree_levels(),
                         [[5], [41, 42, 43], [82, 87, 83], [4, 8, 9]])

        self.tree.add_child(9, 92)
        self.tree.add_child(9, 97)
        self.tree.add_child(9, 93)
        self.assertEqual(
            self.tree.tree_levels(),
            [[5], [41, 42, 43], [82, 87, 83], [92, 97, 93], [4, 8, 9]])