def etb_textbook(self, row, node, textbook_level):
     """
     ETB Textbook level report
     :param row: textbook information
     :param node: root node of textbook
     :param textbook_level: list of required details about textbooks
     :return: textbook_level
     """
     result = {
         'Textbook ID':
         row['identifier'],
         'Medium':
         row['medium'],
         'Grade':
         row['grade'],
         'Subject':
         row['subject'],
         'Textbook Name':
         row['name'],
         'Textbook Status':
         row['status'],
         'Created On':
         '/'.join(row['createdOn'].split('T')[0].split('-')[::-1]),
         'Last Updated On':
         '/'.join(row['lastUpdatedOn'].split('T')[0].split('-')[::-1]),
         'channel':
         row['createdFor'][0],
         'grade_sort':
         self.grade_sort(row['gradeLevel']),
         'Total content linked':
         node.leafNodesCount,
         'Total QR codes linked to content':
         len(
             findall(node,
                     filter_=lambda node_: node_.leafNodesCount > 0 and
                     node_.dialcode != '')),
         'Total number of QR codes with no linked content':
         len(
             findall(node,
                     filter_=lambda node_: node_.leafNodesCount == 0 and
                     node_.dialcode != '')),
         'Total number of leaf nodes':
         len(findall(node, filter_=lambda node_: node_.is_leaf)),
         'Number of leaf nodes with no content':
         len(
             findall(node,
                     filter_=lambda node_: node_.is_leaf and node_.
                     leafNodesCount == 0)),
         'With QR codes':
         'With QR Code' if
         len(findall(node, filter_=lambda node_: node_.dialcode != '')) > 0
         else 'Without QR Code'
     }
     textbook_level.append(result)
 def dce_textbook(self, row, node, textbook_level):
     """
     generate DCE Textbook level report
     :param row: textbook information
     :param node: textbook tree structure
     :param textbook_level: list of details about the textbook
     :return: textbook_level
     """
     result = {
         'Textbook ID':
         row['identifier'],
         'Medium':
         row['medium'],
         'Grade':
         row['grade'],
         'Subject':
         row['subject'],
         'Textbook Name':
         row['name'],
         'Created On':
         '/'.join(row['createdOn'].split('T')[0].split('-')[::-1]),
         'Last Updated On':
         '/'.join(row['lastUpdatedOn'].split('T')[0].split('-')[::-1]),
         'channel':
         row['createdFor'][0],
         'grade_sort':
         self.grade_sort(row['gradeLevel']),
         'Total number of QR codes':
         len(findall(node, filter_=lambda node_: node_.dialcode != '')),
         'Number of QR codes with atleast 1 linked content':
         len(
             findall(node,
                     filter_=lambda node_: node_.leafNodesCount > 0 and
                     node_.dialcode != '')),
         'Number of QR codes with no linked content':
         len(
             findall(node,
                     filter_=lambda node_: node_.leafNodesCount == 0 and
                     node_.dialcode != '')),
         'Term 1 QR Codes with no linked content':
         len(
             findall(node,
                     filter_=lambda node_: node_.leafNodesCount == 0 and
                     node_.dialcode != '' and node_.term == 'T1')),
         'Term 2 QR Codes with no linked content':
         len(
             findall(node,
                     filter_=lambda node_: node_.leafNodesCount == 0 and
                     node_.dialcode != '' and node_.term == 'T2'))
     }
     textbook_level.append(result)
def add_account_to_dict(parent_name, child_name):
    global NODE_TREE
    p = findall(NODE_TREE, filter_=lambda node: node.name in (parent_name, ))
    if p:
        Node(child_name, parent=p[0])
    else:
        Node(parent_name, parent=NODE_TREE)
Beispiel #4
0
    def explorationPolicy(self, coords):
        state = self.GridWorld.coord2state[coords[0], coords[1]]
        Q = self.V[:, state] + self.C[0, state, :].reshape(
            (1, self.actions.n_prim + self.actions.n_opt))
        # Chech whether or not the options can be called from current state
        optList = findall(
            self.actions,
            lambda node: node.type == 'option' and node.actionID >= 0)

        for opt in optList:
            if not opt.option.initSet[coords[0], coords[1]]:
                Q[0, opt.actionID] = -1

        # adm_actionSet = np.hstack((np.zeros((1,self.actions.n_prim)),np.ones((1,self.actions.n_opt))))
        # for actionID in self.GridWorld.state_actions[state]:
        # 	adm_actionSet[0,actionID] = 1

        for actionID in range(self.actions.n_prim):
            if actionID not in self.GridWorld.state_actions[state]:
                Q[0, actionID] = -1

        greedyActionID = np.argmax(Q + 0.00000005 *
                                   np.random.rand(Q.shape[0], Q.shape[1]))
        actionID = greedyActionID
        failed = np.random.rand(1) < self.explorationRate()
        if failed or np.isnan(greedyActionID):
            actionID = np.random.choice(self.GridWorld.state_actions[state])

        self.Q = Q
        return actionID
Beispiel #5
0
    def test_recommend(self):
        # create fake wins and plays
        self.update_nodes(nodes=list(PreOrderIter(self.tree.root)), n_plays=100, n_wins=1)

        # backpropagate good attributes to node where same player than root has to play
        node_name = '0_3_4'
        node = findall(self.tree.root, filter_=lambda n: node_name == n.name)[0]
        self.tree.backpropagate(node, n_plays=1000, n_wins=999, n_ties=0)

        # corresponding level1 name
        node_to_recommend_name = '_'.join(node_name.split('_')[:2])
        node_to_recommend = findall(self.tree.root, filter_=lambda n: node_to_recommend_name == n.name)[0]

        # move corresponding to node
        recommended_move = self.tree.recommended_play()
        self.assertEqual(node_to_recommend.game.last_play, recommended_move)
Beispiel #6
0
 def find(self, fn, level=None) -> Tuple:
     """
     >>> f.find(fn=lambda node: node.dependency_relation in ("obj"))
     :param fn:
     :return:
     """
     return findall(self, filter_=fn, maxlevel=level)
Beispiel #7
0
 def rels_by_order(self, *args, level=2) -> Optional['AnalNode']:
     for a in args:
         rs = findall(self,
                      filter_=lambda n: n.dependency_relation == a,
                      maxlevel=level)
         if rs:
             return rs[0]
def addChildren(node):
    '''
	Given a node (where node.name is a base URL), scrape all 
	links from the page at that URL and add the unique links 
	as children.
	'''
    page = getPage(node.name)

    if page == None:
        # Can happen if we try to access a non-existent URL
        return

    for link in page.iterlinks():
        # Get URL of the HTML link element
        l = urlparse(link[2])
        if l.netloc.startswith("www."):
            # TODO: see note in main() about www.
            netloc = l.netloc[4:]
        else:
            netloc = l.netloc

        # If the link is not to the same base URL and not already in the
        #	children of the tree, add it to the tree.
        # TODO: Maybe instead of skipping duplicates we can count the number
        #	of times a link appears on a page, and weight certain nodes as
        #	"more important" than others.
        if netloc != '' and netloc != node.name:
            find = search.findall(node, filter_=lambda n: n.name == netloc)
            if find == ():
                # Setting the parent here automatically updates the tree!
                Node(netloc, parent=node)
Beispiel #9
0
    def run(self, dispatcher, tracker, domain):
        func = tracker.get_slot('function')
        if (func != None):
            result_list = search.findall(self.ITSM_tree, lambda node:
                                         (func) in node.id)
            length = len(result_list)
            temp = ""
            if (length > 1):
                for x in range(0, length):
                    result = result_list[x]
                    temp += str(x + 1) + ". " + result.id + ": "
                    temp += result.url
                    if (x != length - 1):
                        temp += "\n"
                response = """Are you looking for...\n{}""".format(temp)
            elif (length == 1):
                url = result_list[0].url
                title = result_list[0].id
                response = """I think you are looking for this!\n{}\n{}""".format(
                    title, url)

            else:
                temp = search.find(self.ITSM_tree, lambda node:
                                   ("homepage") == node.id)
                url = temp.url
                response = "Sorry! Content related to '{}' is not found! Please checkout our homepage {}".format(
                    func, url)
        else:
            response = "Sorry! I don't understand what you are asking.. Please try asking in other ways!"
            # print(response)

        dispatcher.utter_message(response)
        return [SlotSet('function', None)]
Beispiel #10
0
    def update_nodes(self, n_plays, n_wins, n_ties=0, nodes=None, node_names=None, include_ancestors=False):
        # get selection as nodes
        selected_nodes = []
        if node_names is not None and nodes is None:
            for node_name in node_names:
                for node in findall(self.tree.root, filter_=lambda n: node_name == n.name):
                    selected_nodes.append(node)
        elif node_names is None and nodes is not None:
            selected_nodes = nodes
        else:
            raise ValueError('One of node_names and nodes arguments must be None')

        # get ancestors if needed
        nodes_to_update = []
        if include_ancestors:
            for node in selected_nodes:
                for ancestor in node.ancestors:
                    nodes_to_update.append(ancestor)
                nodes_to_update.append(node)
        else:
            for node in selected_nodes:
                nodes_to_update.append(node)

        # update corresponding nodes
        for node in nodes_to_update:
            node.n_plays = n_plays
            node.n_wins = n_wins
            node.n_ties = n_ties
Beispiel #11
0
def get_childs(query_term="radiological finding"):
    tree = None
    s = {}
    path = root + '/Rx-thorax-automatic-captioning/' + filetree
    stream = open(path, "r")
    docs = yaml.load_all(stream, Loader=yaml.FullLoader)
    print("Starting to search " + query_term + " in the following trees:")
    for doc in docs:
        tree_root = DictImporter().import_(doc)
        print("\t" + tree_root.label)
        r = search.findall(tree_root, lambda node: node.label == query_term)
        if r:
            tree = RenderTree(r[0])
            for pre, _, node in tree:
                CUI = None
                try:
                    CUI = node.concept
                    m = re.search('\((\w+)\)', CUI)
                    if m:
                        CUI = m.group(0).strip('(').strip(')')
                        cui.add(CUI)
                except:
                    pass
                s[node.label] = CUI
    if tree:

        t = str(tree.by_attr(lambda n: n.label + '\n'))

        st.sidebar.markdown("## Tree of child terms")
        st.sidebar.markdown(t)

    return s, t
Beispiel #12
0
 def filter_tree(self, parent):
     for child in parent.children:
         if search.findall(child, filter_=lambda node: not self.is_included(node)):
             child.parent = None
         if self.is_excluded(child):
             child.parent = None
         self.filter_tree(child)
Beispiel #13
0
def show_branching(tree):
    row, col = vim.current.window.cursor
    print(
        str(
            search.findall(tree[0],
                           filter_=lambda node: node.start_line <= row and node
                           .end_line >= row)[-1]).split("'")[1].replace(
                               " ", ""))
Beispiel #14
0
def findCommonParent(a,b):
   commonParent = a
   while True:
      res = findall(commonParent, filter_=lambda node: node.name == b.name)
      if (commonParent.parent == None):
         return None
      elif (res):
         return commonParent
      commonParent = commonParent.parent
Beispiel #15
0
    def __init__(self, players, wins_needed=2):
        """
        This method initializes the Tourney Class. We will create the upper and
        lower brackets as well as the players in the tounrey. Raises an 
        exception if the number of players is not a power of 2.

        Arguments:
            :param self: This object
            :param players: A list of strings of names of players
            :param wins_needed: Number of wins needed to win a match. Default=2

        Raises:
            Exception: The number of players is not a power of 2
        """
        self.players = []
        self.matches = []
        self.wins_needed = wins_needed
        num_players = len(players)

        # Make sure we are a power of 2
        if (num_players is not 0 and num_players & (num_players - 1) is 0):
            self.stages = int(log2(num_players))

            print('Making a bracket with {} Stages'.format(self.stages))

            # Recursively make the trees
            self.upper_bracket = self.make_upper_tree(
                self.stages,
                Node('Stage{}'.format(self.stages + 1),
                     contestant='Upper Champ',
                     player=None))
            if (self.stages is 1):
                self.lower_bracket = Node('Stage{}'.format(self.stages - 1),
                                          contestant='Lower Champ',
                                          player=None)
            else:
                self.lower_bracket = self.make_lower_tree(
                    self.stages - 1,
                    Node('Stage{}-Major'.format(self.stages),
                         contestant='Lower Champ',
                         player=None))

            # Now populate the upper bracket to start
            shuffle(players)
            groups = zip(
                findall(self.upper_bracket,
                        filter_=lambda node: node.name in ('Stage1')), players)
            for node, player in groups:
                node.contestant = player
                new_player = Player(player)
                self.players.append(new_player)
                node.player = new_player

            # We are now done! Print the brackets
            self.print_brackets()
        else:
            raise Exception('{} is not a power of 2'.format(num_players))
 def add_account_to_dict(self, parent_name, child_name):
     #import ipdb; ipdb.set_trace()
     global NODE_TREE
     p = findall(NODE_TREE,
                 filter_=lambda node: node.name in (parent_name, ))
     if p:
         Node(child_name, parent=p[0])
     else:
         Node(parent_name, parent=NODE_TREE)
Beispiel #17
0
    def test_select_level3(self):
        # create fake wins and plays
        self.update_nodes(nodes=list(PreOrderIter(self.tree.root)), n_plays=1000, n_wins=2)

        # give best attributes to ancestors of one node
        node_name = '0_3_4_1'
        node = findall(self.tree.root, filter_=lambda n: n.name == node_name)[0]
        self.update_nodes(node_names=[node_name], include_ancestors=True, n_plays=50, n_wins=45)

        selected_node = self.tree.select()   # to update scores
        self.assertEqual(node.parent.name, selected_node.name)   # because node is not fully expanded
 def all_leaf_node_need_eva(self, current_node, depth):
     current_street = current_node.round_state.current_street
     if current_street + depth > Const.Street.RIVER + 1:
         return None
     else:
         return search.findall(
             current_node,
             filter_=lambda node:
             (node.round_state.current_street == current_street + depth
              ) and node.history_cell != None,
             maxlevel=depth * 7)
Beispiel #19
0
 def set_scope(self):
     functions = findall_by_attr(self.root, "cabecalho")
     for function in functions:
         scope = function.child(name="ID").child().name
         var_declarations = findall(function,
                                    filter_=lambda node: node.name in
                                    ("var", "id"))
         for var in var_declarations:
             var.scope = scope
             for child in var.children:
                 child.scope = scope
Beispiel #20
0
    def _nms(self, boxes: np.ndarray, class_names: List[str]):
        if len(class_names) == 0:
            return []

        # For object class, get the height of its corresponding node in the hierarchy tree.
        # Less height => finer-grained class name => higher score.
        heights = np.array([
            findall(self._hierarchy,
                    lambda node: node.LabelName.lower() in c)[0].height
            for c in class_names
        ])
        # Get a sorting of the heights in ascending order, i.e. higher scores first.
        score_order = heights.argsort()

        # Compute areas for calculating intersection over union. Add 1 to avoid division by zero
        # for zero area (padding/dummy) boxes.
        x1, y1, x2, y2 = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
        areas = (x2 - x1 + 1) * (y2 - y1 + 1)

        # Fill "keep_boxes" with indices of boxes to keep, move from left to right in
        # ``score_order``, keep current box index (score_order[0]) and suppress (discard) other
        # indices of boxes having lower IoU threshold with current box from ``score_order``.
        # list. Note the order is a sorting of indices according to scores.
        keep_box_indices = []

        while score_order.size > 0:
            # Keep the index of box under consideration.
            current_index = score_order[0]
            keep_box_indices.append(current_index)

            # For the box we just decided to keep (score_order[0]), compute its IoU with other
            # boxes (score_order[1:]).
            xx1 = np.maximum(x1[score_order[0]], x1[score_order[1:]])
            yy1 = np.maximum(y1[score_order[0]], y1[score_order[1:]])
            xx2 = np.minimum(x2[score_order[0]], x2[score_order[1:]])
            yy2 = np.minimum(y2[score_order[0]], y2[score_order[1:]])

            intersection = np.maximum(0.0, xx2 - xx1 + 1) * np.maximum(
                0.0, yy2 - yy1 + 1)
            union = areas[score_order[0]] + areas[
                score_order[1:]] - intersection

            # Perform NMS for IoU >= 0.85. Check score, boxes corresponding to object
            # classes with smaller/equal height in hierarchy cannot be suppressed.
            keep_condition = np.logical_or(
                heights[score_order[1:]] >= heights[score_order[0]],
                intersection / union <= self._nms_threshold,
            )

            # Only keep the boxes under consideration for next iteration.
            score_order = score_order[1:]
            score_order = score_order[np.where(keep_condition)[0]]

        return keep_box_indices
Beispiel #21
0
    def uses_macros(self) -> bool:
        """Indicates if this XML document contains any <expand> element.

        Returns:
            bool: True if the tool contains at least one <expand> elements.
        """
        try:
            found = findall(self.root, filter_=lambda node: node.name == "expand", mincount=1)
            return len(found) > 0
        except BaseException:
            return False
Beispiel #22
0
    def test_backpropagate1(self):
        # select a node from which backpropagation start
        node_name = '0_3_4_1'
        node = findall(self.tree.root, filter_=lambda n: n.name == node_name)[0]
        total_plays_before = sum([n.n_plays for n in PreOrderIter(self.tree.root)])

        # perform backpropagation
        self.tree.backpropagate(node, n_plays=100, n_wins=10, n_ties=0)
        total_plays_after = sum([n.n_plays for n in PreOrderIter(self.tree.root)])
        total_wins_after = sum([n.n_wins for n in PreOrderIter(self.tree.root)])

        self.assertEquals(total_plays_after-total_plays_before, 4*100)
        self.assertGreater(total_wins_after, 1)
def find_nodes_by_name_pattern(name_pattern):
    node_ids = []
    
    nodes = search.findall(root,filter_=lambda node: name_pattern in node.name)
    if len(nodes) ==0:
        pdb.set_trace()
    for node in nodes:
            node_ids.append(node.id)
            descendants = node.descendants
            for descendant in descendants:
                node_ids.append(descendant.id)
    node_ids = set(node_ids)
    node_ids = [i for i in node_ids]
    return node_ids
    def declare_action(self, hole_card, current_node, depth, opp_model,
                       round_state, cut_off_nodes, prob_win):
        #compute evaluation for cutoff nodes
        for node in cut_off_nodes:
            if node.name[len(node.name) - 1] != "f":
                #all variable here
                our_prob_win = prob_win
                opp_pro_win = node.history_cell.most_prob_range()

                our_number_raise_at_street = 2 - node.parent.round_state.player_state.no_turn_raise[
                    0]
                opp_number_raise_at_street = 2 - node.parent.round_state.player_state.no_turn_raise[
                    1]

                opp_model = opp_model

                current_pot_value = node.round_state.pot

                feat_vector = [
                    our_prob_win, opp_pro_win, our_number_raise_at_street,
                    opp_number_raise_at_street, opp_model, current_pot_value
                ]
                feat_vector = numpy.array(feat_vector).flatten()

                node.eva = self.eval_fn(feat_vector)

        self.push_eva(current_node, cut_off_nodes, opp_model)

        child_list = list(
            search.findall(current_node,
                           filter_=lambda child: child.parent == current_node,
                           maxlevel=2))
        max_eva = max(child.eva for child in child_list)

        #to deal with equal evaluation, currently break tie arbitrary by randomize
        action_list = list()
        for child in child_list:
            if child.eva == max_eva:
                action_list.append(child)

        action_node = action_list[rand.randint(1, 999) % len(action_list)]

        action = self.action_mapping(action_node.name[len(action_node.name) -
                                                      1])
        if action == "fold":
            action == "call"

        return action
    def push_eva(self, current_node, node_list, opp_model):
        if len(node_list) == 1:
            return

        parent_list = list()
        for node in node_list:
            if node.parent != current_node:
                parent_list.append(node.parent)

        #consider unique parent only
        parent_list = list(set(parent_list))
        for parent in parent_list:
            #find all child of a parent, max 3
            child_list = list(
                search.findall(parent,
                               filter_=lambda child: child.parent == parent,
                               maxlevel=2))
            for child in child_list:
                if child.history_cell != None:
                    child_with_history_cell = child

            #parent is player node
            if parent.round_state.player_state.player_no == 0:
                parent.eva = max(child.eva for child in child_list)

            #parent is opp node
            elif parent.round_state.player_state.player_no == 1:
                #cannot raise
                parent.eva = 0
                if len(list(child_list)) == 2:
                    pr_opp_action = child_with_history_cell.history_cell.pr_EHS_range_call_only(
                        opp_model)
                    for child in child_list:
                        if child.name[len(child.name) - 1] == "f":
                            parent.eva += child.eva * pr_opp_action[0]
                        else:
                            parent.eva += child.eva * pr_opp_action[1]
                else:
                    pr_opp_action = child_with_history_cell.history_cell.pr_EHS_range(
                        opp_model)
                    for child in child_list:
                        if child.name[len(child.name) - 1] == "f":
                            parent.eva += child.eva * pr_opp_action[0]
                        elif child.name[len(child.name) - 1] == "r":
                            parent.eva += child.eva * pr_opp_action[2]
                        else:
                            parent.eva += child.eva * pr_opp_action[1]
        self.push_eva(current_node, parent_list, opp_model)
Beispiel #26
0
def save_location(tree, filename):
    row, col = vim.current.window.cursor

    # Get the name of the node that is in the current location
    location = str(
        search.findall(tree[0],
                       filter_=lambda node: node.start_line <= row and node.
                       end_line >= row)[-1]).split("'")[1].replace(" ", "")
    location_list = location.split('/')

    # Formate end of location for bookmark
    if '(' in location_list[-1] and location_list[-1] in NO_ATTRIBUTES:
        location_list[-1] = location_list[-1].split('(')[0]

    # Build the bookmark entry
    base_name = filename.split('/')[-1]
    library = base_name.split('.lib')[0]

    bookmark = ''
    for item in location_list:
        bookmark += item + '/'
    bookmark = bookmark.strip('/')
    bookmark += '",' + library
    bookmark += ',,,,ID'
    bookmark = '"' + bookmark

    # Check if bookmark csv already exists based on current Liberty file name
    # If it exists, append the new bookmark
    # If not, create a file with the proper header and bookmark
    bookmark_file_path = expanduser("~") + '/' + base_name + '_bookmark.csv'

    if os.path.isfile(bookmark_file_path):
        file_len = _get_file_len(bookmark_file_path)
        bookmark = bookmark.replace(",ID", ',' + str(file_len))
        with open(bookmark_file_path, 'a') as f:
            f.write(bookmark)
            f.write('\n')
    else:
        with open(bookmark_file_path, 'a+') as f:
            f.write('group_key_path,corner,indexes,origin_file,notes,id')
            f.write('\n')
            bookmark = bookmark.replace(',ID', ',1')
            f.write(bookmark)
            f.write('\n')

    # Notify user of saved location of bookmark
    print("Bookmarked saved in " + bookmark_file_path)
def absolute_urls_from_tree_service(root_node):
    paths = []
    for node in findall(root_node):
        path = DELIMITER.join([n.name for n in node.path
                               ]).strip(DELIMITER)  # .strip is ugly.
        paths.append(path)

    path_lengths = [len(p) for p in paths]
    max_path_indexes = max_points(path_lengths)

    urls = []

    for i in range(len(paths)):
        path = paths[i]
        if i in max_path_indexes:
            urls.append(path)

    return urls
Beispiel #28
0
	def update_threshold(self, child_node):
		neighbours_id = self.get_graph_neighbours(child_node)
		neighbours = search.findall(self, filter_=lambda node: node.node_id in neighbours_id, maxlevel=2)
		neighbours_W = np.array([node.w.squeeze() for node in neighbours])
		
		distances = np.sum( (child_node.w - neighbours_W)**2 , 1)
		
		if len(distances) > 1: average_distance = np.mean(distances)
		else: average_distance = distances[0]
		
		max_distance = np.max((self.T, average_distance))
		
		if max_distance == None: 
			print(1)
			
		child_node.set_T(max_distance)
		
		return neighbours
Beispiel #29
0
def build_tree(input_list, root):
    while input_list:
        print("Items left to process: " + str(len(input_list)))
        for i, item in enumerate(input_list):
            parent = item.split(')')[0]
            child = item.split(')')[1]  # is in orbit around

            if parent == 'COM':
                new_node = Node(child, parent=root)
                input_list.pop(i)

            else:
                results = search.findall(root,
                                         filter_=lambda node: node.name in
                                         (parent))
                if len(results) == 1:
                    new_node = Node(child, parent=results[0])
                    input_list.pop(i)
    return root
Beispiel #30
0
    def test_backpropagate2(self):
        # create fake wins and plays
        self.update_nodes(nodes=list(PreOrderIter(self.tree.root)), n_plays=0, n_wins=0)

        # select a node from which backpropagation start
        node_name = '0_3_6'
        node = findall(self.tree.root, filter_=lambda n: n.name == node_name)[0]
        self.tree.backpropagate(node, n_plays=20, n_wins=6, n_ties=0)

        # root node stats
        root_plays = self.tree.root.n_plays
        root_wins = self.tree.root.n_wins

        # level 1 nodes stats
        level1_nodes = list(LevelOrderGroupIter(self.tree.root))[1]
        level1_plays = sum([node.n_plays for node in level1_nodes])
        level1_wins = sum([node.n_wins for node in level1_nodes])

        self.assertEquals(root_plays, level1_plays)
        self.assertEquals(root_wins, level1_wins)