From 7e6287e60695435ae60d06ea1f22e5cfc48139b3 Mon Sep 17 00:00:00 2001 From: Josh Date: Wed, 16 Oct 2024 17:19:49 -0400 Subject: [PATCH 1/9] create seprate set of functions to address new insert node protocol --- src/social_norms_trees/atomic_mutations.py | 152 +++++++++++++++++++-- 1 file changed, 138 insertions(+), 14 deletions(-) diff --git a/src/social_norms_trees/atomic_mutations.py b/src/social_norms_trees/atomic_mutations.py index 311c091..1e32e2f 100644 --- a/src/social_norms_trees/atomic_mutations.py +++ b/src/social_norms_trees/atomic_mutations.py @@ -4,6 +4,7 @@ import logging from types import GenericAlias from typing import Callable, List, Mapping, NamedTuple, Tuple, TypeVar, Union, Dict +from colorama import Fore, Back, Style import click import py_trees @@ -365,6 +366,10 @@ class NodeMappingRepresentation(NamedTuple): labels: List[str] representation: str +class InsertTypeMappingRepresentation(NamedTuple): + index_mapping: Dict + parent_child_mapping: Dict + tree_representation: str def prompt_identify( tree: TreeOrLibrary, @@ -387,6 +392,33 @@ def prompt_identify( return node +#we need two types of "prompt_identify" functions +#1 for the original style of displaying tree with numbers ordered on the left hand side +#1 for the new style, where number is embedded in tree (insert, move aka insert_type) +def insert_type_prompt_identify( + tree: TreeOrLibrary, + function: Callable[ + [TreeOrLibrary], Tuple[Mapping[str, BehaviorIdentifier], List[str], str] + ], + message: str = "Choose position to insert the node?", +) -> BehaviorIdentifier: + + index_mapping, parent_child_mapping, tree_representation = function(tree) + + #display tree + print(tree_representation) + + mapping = list(index_mapping.keys()) + key = click.prompt( + text=message, + type=click.Choice(mapping) + ) + + temp_parent = index_mapping[key] + child_list_index_1 = parent_child_mapping[temp_parent] + return temp_parent, child_list_index_1.index(key) + + def get_node_mapping(tree: BehaviorTree) -> NodeMappingRepresentation: """ Examples: @@ -507,6 +539,88 @@ def get_composite_mapping(tree: BehaviorTree, skip_label="_"): function=get_composite_mapping ) +class TreeInsertionState: + def __init__(self): + self.index_mapping = {} + self.parent_child_mapping = {} + self.tree_representation = "" + +def append_line(state, content, level): + """ + Appends a line representing an existing node to the tree representation string. + """ + state.tree_representation += Fore.LIGHTBLACK_EX + (' ' * level + content) + "\n" + +def append_insertion_point(state, content, level): + """ + Appends a line representing an insertion point to the tree representation string. + """ + state.tree_representation += Fore.WHITE + (' ' * level + content) + "\n" + +def create_insertion_point(state, parent_node, level): + """ + Create relevant insertion point(s) for a given parent node and updates the state with the new insertion index. + """ + insertion_index = str(len(state.index_mapping)) + append_insertion_point(state, f"--> {{{insertion_index}}}", level) + state.index_mapping[insertion_index] = parent_node + + if parent_node in state.parent_child_mapping: + state.parent_child_mapping[parent_node].append(insertion_index) + else: + state.parent_child_mapping[parent_node] = [insertion_index] + + +def build_tree_with_insertion_points(node, state, level=0): + """ + Recursively traverses the tree to construct a string representation with all possible insertion points, + while updating the state to reflect the current parent-node hierarchy and insertion mappings. + """ + + # Create an insertion point before this node, but only if its not the root level + if level != 0: + create_insertion_point(state, node.parent, level) + + + # Display the current node + append_line(state, f"[-] {node.name}", level) + + # Iterate through each child node + for child in node.children: + #For selector and sequence nodes + if isinstance(child, py_trees.composites.Composite): + # Recursive call on each child node + build_tree_with_insertion_points(child, state, level+1) + # Create additional insertion point after the last child of this composite node + if child == (node.children[-1]): + create_insertion_point(state, node, level + 1) + + else: + #For leaf nodes, create insertion point before the leaf node first + create_insertion_point(state, node, level + 1) + #display the leaf node + append_line(state, f"--> {child.name}", level + 1) + #Create additional insertion point after the last leaf node + if child == (node.children[-1]): + create_insertion_point(state, node, level + 1) + + return state + + +def get_insert_mapping(tree: BehaviorTree): + """ + """ + + state = TreeInsertionState() + build_tree_with_insertion_points(tree, state) + + return InsertTypeMappingRepresentation(state.index_mapping, state.parent_child_mapping, state.tree_representation) + + +test_prompt_identify_index = partial( + insert_type_prompt_identify, + function=get_insert_mapping +) def get_child_index_mapping(tree: BehaviorTree, skip_label="_"): """ @@ -568,7 +682,7 @@ def get_child_index_mapping(tree: BehaviorTree, skip_label="_"): def get_position_mapping(tree): """ - + For insert and move node actions [-] S0 --> {1} @@ -582,8 +696,20 @@ def get_position_mapping(tree): --> Failure --> {6} --> {7} + + For exchange and remove node actions + {0} [-] Sequence0 + {1} [-] Sequence1 + {2} --> Dummy1 + {3} --> Dummy2 + {4} --> Dummy2 + {5} [o] Sequence2 + {6} --> Failure + {7} --> Dummy3 + + Both will follow color scheme """ pass @@ -662,9 +788,10 @@ def prompt_get_mutate_arguments(annotation: GenericAlias, tree, library): return node elif annotation_ == str(CompositeIndex): _logger.debug("in CompositeIndex") - composite_node = prompt_identify_composite( - tree, message="Which parent?") - index = prompt_identify_child_index(composite_node) + #instead of getting parent node, then children index, we simply ask for one index. + #from one index, we determine the values "composite_node" and "index" + #and return + composite_node, index = test_prompt_identify_index(tree) return composite_node, index elif annotation_ == str(NewNode): _logger.debug("in NewNode") @@ -699,29 +826,26 @@ def end_experiment(*args, **kwargs): def load_experiment(): """Placeholder function for loading a tree and library (should come from a file).""" tree = py_trees.composites.Sequence( - "S0", + "Sequence0", False, children=[ - py_trees.behaviours.Dummy("A"), py_trees.composites.Sequence( - "S1", + "Sequence1", memory=False, children=[ - py_trees.behaviours.Dummy("B"), - py_trees.behaviours.Dummy("C"), - py_trees.behaviours.Dummy("D"), + py_trees.behaviours.Dummy("Dummy1"), + py_trees.behaviours.Dummy("Dummy2"), ], ), + py_trees.behaviours.Dummy("Dummy2"), py_trees.composites.Selector( - "S2", + "Sequence2", memory=False, children=[ - py_trees.behaviours.Dummy("E"), - py_trees.behaviours.Dummy("F"), py_trees.behaviours.Failure(), + py_trees.behaviours.Dummy("Dummy3"), ], ), - py_trees.behaviours.Success(), ], ) library = [py_trees.behaviours.Success(), py_trees.behaviours.Failure()] From aaac95b6feabfab7b199e05de5b1e6b31c9ec881 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 17 Oct 2024 08:26:54 -0400 Subject: [PATCH 2/9] small changes, add color to label_tree_lines --- src/social_norms_trees/atomic_mutations.py | 102 +++++++++++---------- 1 file changed, 52 insertions(+), 50 deletions(-) diff --git a/src/social_norms_trees/atomic_mutations.py b/src/social_norms_trees/atomic_mutations.py index 1e32e2f..a810f2d 100644 --- a/src/social_norms_trees/atomic_mutations.py +++ b/src/social_norms_trees/atomic_mutations.py @@ -344,7 +344,8 @@ def label_tree_lines( # Make the line. If `t` is missing, # then we don't want a trailing space # so we strip that away - f"{i}: {t}".rstrip() + #TODO: update color + f"{Fore.WHITE}{{{i}}}: {t}{Style.RESET_ALL}".rstrip() for i, t in zip(padded_labels, tree_representation_lines) ] @@ -394,7 +395,7 @@ def prompt_identify( #we need two types of "prompt_identify" functions #1 for the original style of displaying tree with numbers ordered on the left hand side -#1 for the new style, where number is embedded in tree (insert, move aka insert_type) +#1 for the new style, where number is embedded in tree (insert or move aka insert_type) def insert_type_prompt_identify( tree: TreeOrLibrary, function: Callable[ @@ -445,6 +446,7 @@ def get_node_mapping(tree: BehaviorTree) -> NodeMappingRepresentation: 1: --> Dummy """ + #TODO: should we remove index 0 for root node? mapping = {str(i): n for i, n in enumerate_nodes(tree)} labels = list(mapping.keys()) representation = label_tree_lines(tree=tree, labels=labels) @@ -549,13 +551,13 @@ def append_line(state, content, level): """ Appends a line representing an existing node to the tree representation string. """ - state.tree_representation += Fore.LIGHTBLACK_EX + (' ' * level + content) + "\n" + state.tree_representation += Fore.LIGHTBLACK_EX + (' ' * level + content) + "\n" def append_insertion_point(state, content, level): """ Appends a line representing an insertion point to the tree representation string. """ - state.tree_representation += Fore.WHITE + (' ' * level + content) + "\n" + state.tree_representation += Fore.WHITE + (' ' * level + content) + "\n" def create_insertion_point(state, parent_node, level): """ @@ -617,66 +619,66 @@ def get_insert_mapping(tree: BehaviorTree): return InsertTypeMappingRepresentation(state.index_mapping, state.parent_child_mapping, state.tree_representation) -test_prompt_identify_index = partial( +prompt_identify_insertion_index = partial( insert_type_prompt_identify, function=get_insert_mapping ) -def get_child_index_mapping(tree: BehaviorTree, skip_label="_"): - """ - Examples: - >>> a = get_child_index_mapping(py_trees.behaviours.Dummy()) - >>> a.mapping - {'0': 0} +# def get_child_index_mapping(tree: BehaviorTree, skip_label="_"): +# """ +# Examples: +# >>> a = get_child_index_mapping(py_trees.behaviours.Dummy()) +# >>> a.mapping +# {'0': 0} - >>> a.labels - ['0'] +# >>> a.labels +# ['0'] - >>> print(a.representation) - _: --> Dummy - 0: +# >>> print(a.representation) +# _: --> Dummy +# 0: - >>> b = get_child_index_mapping(py_trees.composites.Sequence("", False, children=[py_trees.behaviours.Dummy()])) - >>> b.mapping # doctest: +NORMALIZE_WHITESPACE - {'0': 0, '1': 1} +# >>> b = get_child_index_mapping(py_trees.composites.Sequence("", False, children=[py_trees.behaviours.Dummy()])) +# >>> b.mapping # doctest: +NORMALIZE_WHITESPACE +# {'0': 0, '1': 1} - >>> b.labels - ['0', '1'] +# >>> b.labels +# ['0', '1'] - >>> print(b.representation) - _: [-] - 0: --> Dummy - 1: - """ - mapping = {} - display_labels, allowed_labels = [], [] +# >>> print(b.representation) +# _: [-] +# 0: --> Dummy +# 1: +# """ +# mapping = {} +# display_labels, allowed_labels = [], [] - for node in iterate_nodes(tree): - if node in tree.children: - index = tree.children.index(node) - label = str(index) - mapping[label] = index - allowed_labels.append(label) - display_labels.append(label) - else: - display_labels.append(skip_label) +# for node in iterate_nodes(tree): +# if node in tree.children: +# index = tree.children.index(node) +# label = str(index) +# mapping[label] = index +# allowed_labels.append(label) +# display_labels.append(label) +# else: +# display_labels.append(skip_label) - # Add the "after all the elements" label - post_list_index = len(tree.children) - post_list_label = str(post_list_index) - allowed_labels.append(post_list_label) - display_labels.append(post_list_label) - mapping[post_list_label] = post_list_index +# # Add the "after all the elements" label +# post_list_index = len(tree.children) +# post_list_label = str(post_list_index) +# allowed_labels.append(post_list_label) +# display_labels.append(post_list_label) +# mapping[post_list_label] = post_list_index - representation = label_tree_lines(tree=tree, labels=display_labels) +# representation = label_tree_lines(tree=tree, labels=display_labels) - return NodeMappingRepresentation(mapping, allowed_labels, representation) +# return NodeMappingRepresentation(mapping, allowed_labels, representation) -prompt_identify_child_index = partial( - prompt_identify, - function=get_child_index_mapping -) +# prompt_identify_child_index = partial( +# prompt_identify, +# function=get_child_index_mapping +# ) def get_position_mapping(tree): @@ -791,7 +793,7 @@ def prompt_get_mutate_arguments(annotation: GenericAlias, tree, library): #instead of getting parent node, then children index, we simply ask for one index. #from one index, we determine the values "composite_node" and "index" #and return - composite_node, index = test_prompt_identify_index(tree) + composite_node, index = prompt_identify_insertion_index(tree) return composite_node, index elif annotation_ == str(NewNode): _logger.debug("in NewNode") From 944c227146ec6482fef3d9650c763f0e51f288d2 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 17 Oct 2024 11:08:58 -0400 Subject: [PATCH 3/9] update text display --- src/social_norms_trees/atomic_mutations.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/social_norms_trees/atomic_mutations.py b/src/social_norms_trees/atomic_mutations.py index a810f2d..52a00f1 100644 --- a/src/social_norms_trees/atomic_mutations.py +++ b/src/social_norms_trees/atomic_mutations.py @@ -406,12 +406,12 @@ def insert_type_prompt_identify( index_mapping, parent_child_mapping, tree_representation = function(tree) - #display tree - print(tree_representation) + #add tree to text display + text = f"{tree_representation}\n{message}" mapping = list(index_mapping.keys()) key = click.prompt( - text=message, + text=text, type=click.Choice(mapping) ) From f85133f053eee29bd2c5622ecbc48adcdba3af9c Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 25 Oct 2024 15:36:52 -0400 Subject: [PATCH 4/9] clean up code --- src/social_norms_trees/atomic_mutations.py | 206 ++++++++++----------- 1 file changed, 99 insertions(+), 107 deletions(-) diff --git a/src/social_norms_trees/atomic_mutations.py b/src/social_norms_trees/atomic_mutations.py index 52a00f1..2d97e4d 100644 --- a/src/social_norms_trees/atomic_mutations.py +++ b/src/social_norms_trees/atomic_mutations.py @@ -367,11 +367,6 @@ class NodeMappingRepresentation(NamedTuple): labels: List[str] representation: str -class InsertTypeMappingRepresentation(NamedTuple): - index_mapping: Dict - parent_child_mapping: Dict - tree_representation: str - def prompt_identify( tree: TreeOrLibrary, function: Callable[ @@ -389,36 +384,8 @@ def prompt_identify( text = f"{message}" key = click.prompt(text=text, type=click.Choice(labels)) - node = mapping[key] - return node - - -#we need two types of "prompt_identify" functions -#1 for the original style of displaying tree with numbers ordered on the left hand side -#1 for the new style, where number is embedded in tree (insert or move aka insert_type) -def insert_type_prompt_identify( - tree: TreeOrLibrary, - function: Callable[ - [TreeOrLibrary], Tuple[Mapping[str, BehaviorIdentifier], List[str], str] - ], - message: str = "Choose position to insert the node?", -) -> BehaviorIdentifier: - - index_mapping, parent_child_mapping, tree_representation = function(tree) - - #add tree to text display - text = f"{tree_representation}\n{message}" - - mapping = list(index_mapping.keys()) - key = click.prompt( - text=text, - type=click.Choice(mapping) - ) - - temp_parent = index_mapping[key] - child_list_index_1 = parent_child_mapping[temp_parent] - return temp_parent, child_list_index_1.index(key) - + value = mapping[key] + return value def get_node_mapping(tree: BehaviorTree) -> NodeMappingRepresentation: """ @@ -547,24 +514,26 @@ def __init__(self): self.parent_child_mapping = {} self.tree_representation = "" -def append_line(state, content, level): +def _append_line(state, content, level): """ Appends a line representing an existing node to the tree representation string. """ - state.tree_representation += Fore.LIGHTBLACK_EX + (' ' * level + content) + "\n" + # state.tree_representation += Fore.LIGHTBLACK_EX + (' ' * level + content) + "\n" + state.tree_representation += (' ' * level + content) + "\n" -def append_insertion_point(state, content, level): +def _append_insertion_point(state, content, level): """ Appends a line representing an insertion point to the tree representation string. """ - state.tree_representation += Fore.WHITE + (' ' * level + content) + "\n" + # state.tree_representation += Fore.WHITE + (' ' * level + content) + "\n" + state.tree_representation += (' ' * level + content) + "\n" -def create_insertion_point(state, parent_node, level): +def _create_insertion_point(state, parent_node, level): """ Create relevant insertion point(s) for a given parent node and updates the state with the new insertion index. """ insertion_index = str(len(state.index_mapping)) - append_insertion_point(state, f"--> {{{insertion_index}}}", level) + _append_insertion_point(state, f"--> {{{insertion_index}}}", level) state.index_mapping[insertion_index] = parent_node if parent_node in state.parent_child_mapping: @@ -573,38 +542,59 @@ def create_insertion_point(state, parent_node, level): state.parent_child_mapping[parent_node] = [insertion_index] -def build_tree_with_insertion_points(node, state, level=0): +def _build_tree_with_insertion_points(node, state, level=0): """ Recursively traverses the tree to construct a string representation with all possible insertion points, while updating the state to reflect the current parent-node hierarchy and insertion mappings. + + Examples: + + >>> tree = py_trees.composites.Sequence("S0", memory = False, children = []) + >>> state = TreeInsertionState() + >>> res = _build_tree_with_insertion_points(tree, state) + >>> print(res.tree_representation) + [-] S0 + --> {0} + + + >>> tree2 = py_trees.composites.Sequence("S0", memory = False, children = [ + ... py_trees.behaviours.Dummy()]) + >>> state2 = TreeInsertionState() + >>> res2 = _build_tree_with_insertion_points(tree2, state2) + >>> print(res2.tree_representation) + [-] S0 + --> {0} + --> Dummy + --> {1} + """ # Create an insertion point before this node, but only if its not the root level if level != 0: - create_insertion_point(state, node.parent, level) + _create_insertion_point(state, node.parent, level) # Display the current node - append_line(state, f"[-] {node.name}", level) + _append_line(state, f"[-] {node.name}", level) # Iterate through each child node for child in node.children: #For selector and sequence nodes if isinstance(child, py_trees.composites.Composite): # Recursive call on each child node - build_tree_with_insertion_points(child, state, level+1) + _build_tree_with_insertion_points(child, state, level+1) # Create additional insertion point after the last child of this composite node if child == (node.children[-1]): - create_insertion_point(state, node, level + 1) + _create_insertion_point(state, node, level + 1) else: #For leaf nodes, create insertion point before the leaf node first - create_insertion_point(state, node, level + 1) + _create_insertion_point(state, node, level + 1) #display the leaf node - append_line(state, f"--> {child.name}", level + 1) + _append_line(state, f"--> {child.name}", level + 1) #Create additional insertion point after the last leaf node if child == (node.children[-1]): - create_insertion_point(state, node, level + 1) + _create_insertion_point(state, node, level + 1) return state @@ -614,71 +604,73 @@ def get_insert_mapping(tree: BehaviorTree): """ state = TreeInsertionState() - build_tree_with_insertion_points(tree, state) + _build_tree_with_insertion_points(tree, state) + mapping = {label: (state.index_mapping[label], state.parent_child_mapping[state.index_mapping[label]].index(label)) for label in state.index_mapping.keys()} + labels = state.index_mapping.keys() - return InsertTypeMappingRepresentation(state.index_mapping, state.parent_child_mapping, state.tree_representation) + return NodeMappingRepresentation(mapping, labels, state.tree_representation) prompt_identify_insertion_index = partial( - insert_type_prompt_identify, + prompt_identify, function=get_insert_mapping ) -# def get_child_index_mapping(tree: BehaviorTree, skip_label="_"): -# """ -# Examples: -# >>> a = get_child_index_mapping(py_trees.behaviours.Dummy()) -# >>> a.mapping -# {'0': 0} - -# >>> a.labels -# ['0'] - -# >>> print(a.representation) -# _: --> Dummy -# 0: - -# >>> b = get_child_index_mapping(py_trees.composites.Sequence("", False, children=[py_trees.behaviours.Dummy()])) -# >>> b.mapping # doctest: +NORMALIZE_WHITESPACE -# {'0': 0, '1': 1} - -# >>> b.labels -# ['0', '1'] - -# >>> print(b.representation) -# _: [-] -# 0: --> Dummy -# 1: -# """ -# mapping = {} -# display_labels, allowed_labels = [], [] - -# for node in iterate_nodes(tree): -# if node in tree.children: -# index = tree.children.index(node) -# label = str(index) -# mapping[label] = index -# allowed_labels.append(label) -# display_labels.append(label) -# else: -# display_labels.append(skip_label) - -# # Add the "after all the elements" label -# post_list_index = len(tree.children) -# post_list_label = str(post_list_index) -# allowed_labels.append(post_list_label) -# display_labels.append(post_list_label) -# mapping[post_list_label] = post_list_index - -# representation = label_tree_lines(tree=tree, labels=display_labels) - -# return NodeMappingRepresentation(mapping, allowed_labels, representation) - - -# prompt_identify_child_index = partial( -# prompt_identify, -# function=get_child_index_mapping -# ) +def get_child_index_mapping(tree: BehaviorTree, skip_label="_"): + """ + Examples: + >>> a = get_child_index_mapping(py_trees.behaviours.Dummy()) + >>> a.mapping + {'0': 0} + + >>> a.labels + ['0'] + + >>> print(a.representation) + _: --> Dummy + 0: + + >>> b = get_child_index_mapping(py_trees.composites.Sequence("", False, children=[py_trees.behaviours.Dummy()])) + >>> b.mapping # doctest: +NORMALIZE_WHITESPACE + {'0': 0, '1': 1} + + >>> b.labels + ['0', '1'] + + >>> print(b.representation) + _: [-] + 0: --> Dummy + 1: + """ + mapping = {} + display_labels, allowed_labels = [], [] + + for node in iterate_nodes(tree): + if node in tree.children: + index = tree.children.index(node) + label = str(index) + mapping[label] = index + allowed_labels.append(label) + display_labels.append(label) + else: + display_labels.append(skip_label) + + # Add the "after all the elements" label + post_list_index = len(tree.children) + post_list_label = str(post_list_index) + allowed_labels.append(post_list_label) + display_labels.append(post_list_label) + mapping[post_list_label] = post_list_index + + representation = label_tree_lines(tree=tree, labels=display_labels) + + return NodeMappingRepresentation(mapping, allowed_labels, representation) + + +prompt_identify_child_index = partial( + prompt_identify, + function=get_child_index_mapping +) def get_position_mapping(tree): From baab9106d6635e40ff47f20dc63523a0d37a1566 Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 25 Oct 2024 16:19:54 -0400 Subject: [PATCH 5/9] fix edge case for new insertion function --- src/social_norms_trees/atomic_mutations.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/social_norms_trees/atomic_mutations.py b/src/social_norms_trees/atomic_mutations.py index 2d97e4d..86f273b 100644 --- a/src/social_norms_trees/atomic_mutations.py +++ b/src/social_norms_trees/atomic_mutations.py @@ -567,6 +567,18 @@ def _build_tree_with_insertion_points(node, state, level=0): --> Dummy --> {1} + + >>> tree3 = py_trees.composites.Sequence("S0", memory = False, children = [ + ... py_trees.composites.Sequence("S1", memory = False, children = [])]) + >>> state3 = TreeInsertionState() + >>> res3 = _build_tree_with_insertion_points(tree3, state3) + >>> print(res3.tree_representation) + [-] S0 + --> {0} + [-] S1 + --> {1} + --> {2} + """ # Create an insertion point before this node, but only if its not the root level @@ -577,6 +589,10 @@ def _build_tree_with_insertion_points(node, state, level=0): # Display the current node _append_line(state, f"[-] {node.name}", level) + #edge case, if sequence node exists but there are no children defined, set child node as potential insertion point + if not node.children: + _create_insertion_point(state, node, level+1) + # Iterate through each child node for child in node.children: #For selector and sequence nodes @@ -596,11 +612,14 @@ def _build_tree_with_insertion_points(node, state, level=0): if child == (node.children[-1]): _create_insertion_point(state, node, level + 1) + return state def get_insert_mapping(tree: BehaviorTree): """ + Examples: + >>> """ state = TreeInsertionState() From 28063be51d4cf1437b709424c81399e0d9e5e7ed Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 25 Oct 2024 17:46:10 -0400 Subject: [PATCH 6/9] add testcases --- src/social_norms_trees/atomic_mutations.py | 36 +++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/social_norms_trees/atomic_mutations.py b/src/social_norms_trees/atomic_mutations.py index 86f273b..e0eddfb 100644 --- a/src/social_norms_trees/atomic_mutations.py +++ b/src/social_norms_trees/atomic_mutations.py @@ -619,7 +619,41 @@ def _build_tree_with_insertion_points(node, state, level=0): def get_insert_mapping(tree: BehaviorTree): """ Examples: - >>> + + >>> child_node_1 = py_trees.behaviours.Dummy() + >>> sequence_node_1 = py_trees.composites.Sequence("S1", False, children=[]) + >>> root_node_1 = py_trees.composites.Sequence("S0", False, children=[child_node_1, sequence_node_1]) + + >>> a = get_insert_mapping(root_node_1) + + >>> list(a.labels) + ['0', '1', '2', '3'] + + >>> a.mapping["0"][0] == root_node_1 + True + >>> a.mapping["2"][0] == sequence_node_1 + True + >>> a.mapping["3"][0] == root_node_1 + True + + >>> a.mapping["0"][1] == 0 + True + >>> a.mapping["1"][1] == 1 + True + >>> a.mapping["2"][1] == 0 + True + >>> a.mapping["3"][1] == 2 + True + + >>> print(a.representation) + [-] S0 + --> {0} + --> Dummy + --> {1} + [-] S1 + --> {2} + --> {3} + """ state = TreeInsertionState() From 65e95f64cb92642196bcb8a56c91b5f6a8139209 Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 25 Oct 2024 17:51:01 -0400 Subject: [PATCH 7/9] add comments for more clarity --- src/social_norms_trees/atomic_mutations.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/social_norms_trees/atomic_mutations.py b/src/social_norms_trees/atomic_mutations.py index e0eddfb..4d93c91 100644 --- a/src/social_norms_trees/atomic_mutations.py +++ b/src/social_norms_trees/atomic_mutations.py @@ -658,7 +658,17 @@ def get_insert_mapping(tree: BehaviorTree): state = TreeInsertionState() _build_tree_with_insertion_points(tree, state) - mapping = {label: (state.index_mapping[label], state.parent_child_mapping[state.index_mapping[label]].index(label)) for label in state.index_mapping.keys()} + #create mapping where each label maps to a tuple: + #first element is the parent node reference for the current label index + #second element is the index of the label in its parent's child list in parent_child_mapping + mapping = { + label: ( + state.index_mapping[label], #parent node reference + state.parent_child_mapping[state.index_mapping[label]].index(label) #position in parent's child list + ) + for label in state.index_mapping.keys() + } + labels = state.index_mapping.keys() return NodeMappingRepresentation(mapping, labels, state.tree_representation) From e1abe0317ce604704d79e0a6c010e9dee4044aec Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 28 Oct 2024 12:28:44 -0400 Subject: [PATCH 8/9] fix testing --- src/social_norms_trees/atomic_mutations.py | 99 +++++++++++----------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/src/social_norms_trees/atomic_mutations.py b/src/social_norms_trees/atomic_mutations.py index f4d80b6..9a08cad 100644 --- a/src/social_norms_trees/atomic_mutations.py +++ b/src/social_norms_trees/atomic_mutations.py @@ -309,7 +309,7 @@ def label_tree_lines( """Label the lines of a tree. Examples: >>> print(label_tree_lines(py_trees.behaviours.Dummy(), labels=["0"])) - 0: --> Dummy + {0}: --> Dummy >>> tree = py_trees.composites.Sequence( ... "S1", ... False, @@ -318,20 +318,20 @@ def label_tree_lines( ... py_trees.behaviours.Dummy()] ... ) >>> print(label_tree_lines(tree, labels=["A", "B", "C"])) - A: [-] S1 - B: --> Dummy - C: --> Dummy + {A}: [-] S1 + {B}: --> Dummy + {C}: --> Dummy >>> print(label_tree_lines(tree, labels=["AAA", "BB", "C"])) - AAA: [-] S1 - BB: --> Dummy - C: --> Dummy + {AAA}: [-] S1 + { BB}: --> Dummy + { C}: --> Dummy If there are more labels than lines, then those are shown too: >>> print(label_tree_lines(tree, labels=["AAA", "BB", "C", "O"])) - AAA: [-] S1 - BB: --> Dummy - C: --> Dummy - O: + {AAA}: [-] S1 + { BB}: --> Dummy + { C}: --> Dummy + { O}: """ max_len = max([len(s) for s in labels]) padded_labels = [s.rjust(max_len) for s in labels] @@ -343,7 +343,8 @@ def label_tree_lines( # then we don't want a trailing space # so we strip that away #TODO: update color - f"{Fore.WHITE}{{{i}}}: {t}{Style.RESET_ALL}".rstrip() + # f"{Fore.WHITE}{{{i}}}: {t}{Style.RESET_ALL}".rstrip() + f"{{{i}}}: {t}".rstrip() for i, t in zip(padded_labels, tree_representation_lines) ] @@ -376,6 +377,8 @@ def prompt_identify( mapping, labels, representation = function(tree) + print("ha!") + # print(representation) if display_nodes: text = f"{representation}\n{message}" else: @@ -396,8 +399,8 @@ def get_node_mapping(tree: BehaviorTree) -> NodeMappingRepresentation: ['0'] >>> print(a.representation) - 0: --> Dummy - + {0}: --> Dummy + >>> b = get_node_mapping(py_trees.composites.Sequence("", False, children=[py_trees.behaviours.Dummy()])) >>> b.mapping # doctest: +NORMALIZE_WHITESPACE {'0': , @@ -407,8 +410,8 @@ def get_node_mapping(tree: BehaviorTree) -> NodeMappingRepresentation: ['0', '1'] >>> print(b.representation) - 0: [-] - 1: --> Dummy + {0}: [-] + {1}: --> Dummy """ #TODO: should we remove index 0 for root node? @@ -468,7 +471,7 @@ def get_composite_mapping(tree: BehaviorTree, skip_label="_"): [] >>> print(a.representation) - _: --> Dummy + {_}: --> Dummy >>> b = get_composite_mapping(py_trees.composites.Sequence("", False, children=[py_trees.behaviours.Dummy()])) >>> b.mapping # doctest: +NORMALIZE_WHITESPACE @@ -478,8 +481,8 @@ def get_composite_mapping(tree: BehaviorTree, skip_label="_"): ['0'] >>> print(b.representation) - 0: [-] - _: --> Dummy + {0}: [-] + {_}: --> Dummy """ mapping = {} display_labels, allowed_labels = [], [] @@ -681,9 +684,8 @@ def get_child_index_mapping(tree: BehaviorTree, skip_label="_"): ['0'] >>> print(a.representation) - _: --> Dummy - 0: - + {_}: --> Dummy + {0}: >>> b = get_child_index_mapping(py_trees.composites.Sequence("", False, children=[py_trees.behaviours.Dummy()])) >>> b.mapping # doctest: +NORMALIZE_WHITESPACE {'0': 0, '1': 1} @@ -692,9 +694,9 @@ def get_child_index_mapping(tree: BehaviorTree, skip_label="_"): ['0', '1'] >>> print(b.representation) - _: [-] - 0: --> Dummy - 1: + {_}: [-] + {0}: --> Dummy + {1}: """ mapping = {} display_labels, allowed_labels = [], [] @@ -873,29 +875,30 @@ def end_experiment(): def load_experiment(): """Placeholder function for loading a tree and library (should come from a file).""" - tree = py_trees.composites.Sequence( - "Sequence0", - False, - children=[ - py_trees.composites.Sequence( - "Sequence1", - memory=False, - children=[ - py_trees.behaviours.Dummy("Dummy1"), - py_trees.behaviours.Dummy("Dummy2"), - ], - ), - py_trees.behaviours.Dummy("Dummy2"), - py_trees.composites.Selector( - "Sequence2", - memory=False, - children=[ - py_trees.behaviours.Failure(), - py_trees.behaviours.Dummy("Dummy3"), - ], - ), - ], - ) + # tree = py_trees.composites.Sequence( + # "Sequence0", + # False, + # children=[ + # py_trees.composites.Sequence( + # "Sequence1", + # memory=False, + # children=[ + # py_trees.behaviours.Dummy("Dummy1"), + # py_trees.behaviours.Dummy("Dummy2"), + # ], + # ), + # py_trees.behaviours.Dummy("Dummy2"), + # py_trees.composites.Selector( + # "Sequence2", + # memory=False, + # children=[ + # py_trees.behaviours.Failure(), + # py_trees.behaviours.Dummy("Dummy3"), + # ], + # ), + # ], + # ) + tree = py_trees.behaviours.Dummy() library = [py_trees.behaviours.Success(), py_trees.behaviours.Failure()] return tree, library From 8c31b0a44880a41b63b302a0bdfcce0bf3050384 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 4 Nov 2024 13:05:34 -0500 Subject: [PATCH 9/9] comment out font color library --- src/social_norms_trees/atomic_mutations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/social_norms_trees/atomic_mutations.py b/src/social_norms_trees/atomic_mutations.py index 9a08cad..226d115 100644 --- a/src/social_norms_trees/atomic_mutations.py +++ b/src/social_norms_trees/atomic_mutations.py @@ -4,7 +4,7 @@ import logging from types import GenericAlias from typing import Callable, List, Mapping, NamedTuple, Tuple, TypeVar, Union, Dict -from colorama import Fore, Back, Style +# from colorama import Fore, Back, Style import click import py_trees