def test_eval_tree(self): # create terminal nodes term_node = Node(NodeType.CONSTANT, value=100.0) input_node = Node(NodeType.INPUT, name="x") # create function nodes mul_func = Node( NodeType.FUNCTION, name="MUL", arity=2, branches=[input_node, term_node] ) rad_func = Node( NodeType.FUNCTION, name="RAD", arity=1, branches=[mul_func] ) sin_func = Node( NodeType.FUNCTION, name="SIN", arity=1, branches=[rad_func] ) # create tree tree = Tree() tree.root = sin_func tree.update() # evaluate tree score, output = evaluator.eval_tree(tree, self.functions, self.config) self.assertEquals(round(score, 7), 0.5000001)
def test_eval_tree(self): # create terminal nodes term_node = Node(NodeType.CONSTANT, value=100.0) input_node = Node(NodeType.INPUT, name="x") # create function nodes mul_func = Node(NodeType.FUNCTION, name="MUL", arity=2, branches=[input_node, term_node]) rad_func = Node(NodeType.FUNCTION, name="RAD", arity=1, branches=[mul_func]) sin_func = Node(NodeType.FUNCTION, name="SIN", arity=1, branches=[rad_func]) # create tree tree = Tree() tree.root = sin_func tree.update() # evaluate tree score, output = evaluator.eval_tree(tree, self.functions, self.config) self.assertEquals(round(score, 7), 0.5000001)
def test_generate_eq_function(self): # create terminal nodes term_node = Node(NodeType.CONSTANT, value=100.0) input_node = Node(NodeType.INPUT, name="x") # create function nodes mul_func = Node(NodeType.FUNCTION, name="MUL", arity=2, branches=[input_node, term_node]) rad_func = Node(NodeType.FUNCTION, name="RAD", arity=1, branches=[mul_func]) sin_func = Node(NodeType.FUNCTION, name="SIN", arity=1, branches=[rad_func]) # create tree tree = Tree() tree.root = sin_func tree.update() # generate equation function eq_func = evaluator.generate_eq_function(tree, self.functions, self.config) # assert self.assertIsNotNone(eq_func) self.assertEquals(round(eq_func(1), 4), 0.9848)
def test_generate_eq_function_multivars(self): # create terminal nodes term_node = Node(NodeType.INPUT, name="var2") input_node = Node(NodeType.INPUT, name="var1") # create function nodes div_func = Node( NodeType.FUNCTION, name="DIV", arity=2, branches=[input_node, term_node] ) # create tree tree = Tree() tree.root = div_func tree.update() # generate equation function config = { "input_variables": [ { "type": "INPUT", "name": "var1" }, { "type": "INPUT", "name": "var2" } ], "functions": { "ADD": "+", "SUB": "-", "MUL": "*", "DIV": "/", "POW": "**", "SIN": "math.sin", "COS": "math.cos", "RAD": "math.radians", "LN": "math.ln", "LOG": "math.log" } } eq_func = evaluator.generate_eq_function(tree, self.functions, config) # assert self.assertIsNotNone(eq_func) self.assertEquals(eq_func(1.0, 2.0), 0.5)
def test_edit_tree_inputs_and_terminals(self): # TEST INPUTS AND TERMINALS term_node_1 = Node(NodeType.CONSTANT, value=2.0) term_node_2 = Node(NodeType.INPUT, name="x") func_node = Node(NodeType.FUNCTION, name="ADD", arity=2, branches=[term_node_1, term_node_2]) print "BEFORE:", func_node tree = Tree() tree.root = func_node tree.depth = 3 editor.edit_tree(tree, tree.root, self.functions) print "AFTER:", func_node print
def generate_tree_from_dict(self, tree_dict): tree = Tree() stack = [] tree.tree_id = tree_dict["id"] for node_dict in tree_dict["program"]: node_type = node_dict["type"] node = None if node_type == NodeType.INPUT: node = Node( NodeType.INPUT, name=node_dict.get("name", None) ) tree.program.append(node) stack.append(node) elif node_type == NodeType.CONSTANT: node = Node( NodeType.CONSTANT, name=node_dict.get("name", None), value=node_dict.get("value", None) ) tree.program.append(node) stack.append(node) elif node_type == NodeType.FUNCTION: value_nodes = [] for i in xrange(node_dict["arity"]): value_nodes.append(stack.pop()) node = Node( NodeType.FUNCTION, name=node_dict["name"], arity=node_dict["arity"], branches=value_nodes ) tree.program.append(node) stack.append(node) if node_dict.get("root", False): tree.root = node return tree
def test_replace_node(self): # setup node_x = Node(NodeType.INPUT, name="x") node_y = Node(NodeType.INPUT, name="y") add_func = Node(NodeType.FUNCTION, name="ADD", arity=2, branches=[node_x, node_y]) # build tree tree = Tree() tree.root = add_func tree.update_program() # replace input node new_node = Node(NodeType.INPUT, name="z") before_replace = list(tree.program) tree.replace_node(node_x, new_node) after_replace = list(tree.program) # assert self.assertTrue(before_replace == before_replace) self.assertTrue(after_replace == after_replace) self.assertFalse(before_replace == after_replace) self.assertTrue(add_func.branches[0] is new_node)
def test_edit_tree_inputs_and_terminals(self): # TEST INPUTS AND TERMINALS term_node_1 = Node(NodeType.CONSTANT, value=2.0) term_node_2 = Node(NodeType.INPUT, name="x") func_node = Node( NodeType.FUNCTION, name="ADD", arity=2, branches=[term_node_1, term_node_2] ) print "BEFORE:", func_node tree = Tree() tree.root = func_node tree.depth = 3 editor.edit_tree(tree, tree.root, self.functions) print "AFTER:", func_node print
def test_edit_tree_zero_only(self): # TEST CONTAINS ZERO term_node_1 = Node(NodeType.CONSTANT, value=0.0) term_node_2 = Node(NodeType.CONSTANT, value=1.0) func_node = Node(NodeType.FUNCTION, name="ADD", arity=2, branches=[term_node_1, term_node_2]) print "BEFORE:", func_node tree = Tree() tree.root = func_node tree.depth = 3 editor.edit_tree(tree, tree.root, self.functions) print "AFTER:", func_node print self.assertEquals(func_node.value, 1.0)
def test_generate_eq_function_multivars(self): # create terminal nodes term_node = Node(NodeType.INPUT, name="var2") input_node = Node(NodeType.INPUT, name="var1") # create function nodes div_func = Node(NodeType.FUNCTION, name="DIV", arity=2, branches=[input_node, term_node]) # create tree tree = Tree() tree.root = div_func tree.update() # generate equation function config = { "input_variables": [{ "type": "INPUT", "name": "var1" }, { "type": "INPUT", "name": "var2" }], "functions": { "ADD": "+", "SUB": "-", "MUL": "*", "DIV": "/", "POW": "**", "SIN": "math.sin", "COS": "math.cos", "RAD": "math.radians", "LN": "math.ln", "LOG": "math.log" } } eq_func = evaluator.generate_eq_function(tree, self.functions, config) # assert self.assertIsNotNone(eq_func) self.assertEquals(eq_func(1.0, 2.0), 0.5)
def test_generate_eq_function(self): # create terminal nodes term_node = Node(NodeType.CONSTANT, value=100.0) input_node = Node(NodeType.INPUT, name="x") # create function nodes mul_func = Node( NodeType.FUNCTION, name="MUL", arity=2, branches=[input_node, term_node] ) rad_func = Node( NodeType.FUNCTION, name="RAD", arity=1, branches=[mul_func] ) sin_func = Node( NodeType.FUNCTION, name="SIN", arity=1, branches=[rad_func] ) # create tree tree = Tree() tree.root = sin_func tree.update() # generate equation function eq_func = evaluator.generate_eq_function( tree, self.functions, self.config ) # assert self.assertIsNotNone(eq_func) self.assertEquals(round(eq_func(1), 4), 0.9848)
def test_edit_tree_terminals_only(self): # TEST TERMINALS ONLY term_node_1 = Node(NodeType.CONSTANT, value=2.0) term_node_2 = Node(NodeType.CONSTANT, value=1.0) func_node = Node( NodeType.FUNCTION, name="ADD", arity=2, branches=[term_node_1, term_node_2] ) print "BEFORE:", func_node tree = Tree() tree.root = func_node tree.depth = 3 editor.edit_tree(tree, tree.root, self.functions) print "AFTER:", func_node print self.assertEquals(func_node.value, 3.0)
def test_edit_tree_prune(self): # TEST PRUNE term_node_1 = Node(NodeType.CONSTANT, value=0.0) term_node_2 = Node(NodeType.INPUT, name="x") func_node = Node(NodeType.FUNCTION, name="MUL", arity=2, branches=[term_node_1, term_node_2]) print "BEFORE:", func_node tree = Tree() tree.root = func_node tree.depth = 3 editor.edit_tree(tree, tree.root, self.functions) print "AFTER:", func_node print self.assertEquals(func_node.node_type, NodeType.CONSTANT) self.assertIsNone(func_node.name) self.assertEquals(func_node.value, 0)
def full_method(self): # initialize tree tree = Tree() tree.size = 1 tree.depth = self.max_depth tree.root = self.generate_func_node() tree.tree_type = self.gen_config.get("tree_type", None) # build tree via full method self.full_method_build_tree(tree, tree.root, 0) tree.update() return tree
def test_replace_node(self): # setup node_x = Node(NodeType.INPUT, name="x") node_y = Node(NodeType.INPUT, name="y") add_func = Node( NodeType.FUNCTION, name="ADD", arity=2, branches=[node_x, node_y] ) # build tree tree = Tree() tree.root = add_func tree.update_program() # replace input node new_node = Node(NodeType.INPUT, name="z") before_replace = list(tree.program) tree.replace_node(node_x, new_node) after_replace = list(tree.program) # assert self.assertTrue(before_replace == before_replace) self.assertTrue(after_replace == after_replace) self.assertFalse(before_replace == after_replace) self.assertTrue(add_func.branches[0] is new_node)
def test_edit_tree_prune(self): # TEST PRUNE term_node_1 = Node(NodeType.CONSTANT, value=0.0) term_node_2 = Node(NodeType.INPUT, name="x") func_node = Node( NodeType.FUNCTION, name="MUL", arity=2, branches=[term_node_1, term_node_2] ) print "BEFORE:", func_node tree = Tree() tree.root = func_node tree.depth = 3 editor.edit_tree(tree, tree.root, self.functions) print "AFTER:", func_node print self.assertEquals(func_node.node_type, NodeType.CONSTANT) self.assertIsNone(func_node.name) self.assertEquals(func_node.value, 0)
def setUp(self): self.config = { "max_population": 10, "tree_generation": { "method": "FULL_METHOD", "initial_max_depth": 4 }, "function_nodes": [ {"type": "FUNCTION", "name": "ADD", "arity": 2}, {"type": "FUNCTION", "name": "SUB", "arity": 2}, {"type": "FUNCTION", "name": "MUL", "arity": 2}, {"type": "FUNCTION", "name": "DIV", "arity": 2}, {"type": "FUNCTION", "name": "COS", "arity": 1}, {"type": "FUNCTION", "name": "SIN", "arity": 1} ], "terminal_nodes": [ {"type": "CONSTANT", "value": 1.0}, {"type": "INPUT", "name": "x"}, {"type": "INPUT", "name": "y"}, {"type": "INPUT", "name": "z"} ], "input_variables": [ {"name": "x"}, {"name": "y"}, {"name": "z"} ] } self.t_parser = TreeParser() self.tree = Tree() node_x = Node(NodeType.INPUT, name="x") node_y = Node(NodeType.INPUT, name="y") node_z = Node(NodeType.INPUT, name="z") self.tree.input_nodes.append(node_x) self.tree.input_nodes.append(node_y) self.tree.input_nodes.append(node_z)
class TreeCrossoverTests(unittest.TestCase): def setUp(self): self.config = { "tree_generation": { "initial_max_depth": 4 }, "crossover": { "method": "POINT_CROSSOVER", "probability": 1.0 }, "function_nodes": [{ "type": "FUNCTION", "name": "ADD", "arity": 2 }, { "type": "FUNCTION", "name": "SUB", "arity": 2 }, { "type": "FUNCTION", "name": "MUL", "arity": 2 }, { "type": "FUNCTION", "name": "DIV", "arity": 2 }, { "type": "FUNCTION", "name": "COS", "arity": 1 }, { "type": "FUNCTION", "name": "SIN", "arity": 1 }, { "type": "FUNCTION", "name": "RAD", "arity": 1 }], "terminal_nodes": [{ "type": "CONSTANT", "value": 1.0 }, { "type": "CONSTANT", "value": 2.0 }, { "type": "CONSTANT", "value": 2.0 }, { "type": "CONSTANT", "value": 3.0 }, { "type": "CONSTANT", "value": 4.0 }, { "type": "CONSTANT", "value": 5.0 }, { "type": "CONSTANT", "value": 6.0 }, { "type": "CONSTANT", "value": 7.0 }, { "type": "CONSTANT", "value": 8.0 }, { "type": "CONSTANT", "value": 9.0 }, { "type": "CONSTANT", "value": 10.0 }], "input_variables": [{ "type": "INPUT", "name": "x" }] } self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.crossover = TreeCrossover(self.config) self.parser = TreeParser() # create nodes left_node_1 = Node(NodeType.INPUT, name="x") right_node_1 = Node(NodeType.CONSTANT, value=2.0) node = Node(NodeType.CONSTANT, value=2.0) left_node_2 = Node(NodeType.CONSTANT, value=3.0) right_node_2 = Node(NodeType.CONSTANT, value=4.0) cos_func_1 = Node(NodeType.FUNCTION, name="ADD", arity=2, branches=[left_node_1, right_node_1]) sin_func_1 = Node(NodeType.FUNCTION, name="SIN", arity=1, branches=[node]) cos_func_2 = Node(NodeType.FUNCTION, name="COS", arity=1, branches=[left_node_2]) sin_func_2 = Node(NodeType.FUNCTION, name="SIN", arity=1, branches=[right_node_2]) add_func = Node(NodeType.FUNCTION, name="ADD", arity=2, branches=[cos_func_1, sin_func_1]) sub_func = Node(NodeType.FUNCTION, name="SUB", arity=2, branches=[sin_func_2, cos_func_2]) # create tree_1 self.tree_1 = Tree() self.tree_1.root = add_func self.tree_1.update() print self.tree_1 # create tree_2 self.tree_2 = Tree() self.tree_2.root = sub_func self.tree_2.update() def tearDown(self): del self.config del self.generator del self.parser def build_tree_str(self, tree): tree_str = "" for node in tree.program: if hasattr(node, "name") and node.name is not None: tree_str += "node:{0} addr:{1}\n".format(node.name, id(node)) else: tree_str += "node:{0} addr:{1}\n".format(node.value, id(node)) return tree_str def tree_equals(self, tree_1_str, tree_2_str): if tree_1_str == tree_2_str: return True else: return False def test_point_crossover(self): # record before crossover tree_1_before = self.build_tree_str(self.tree_1) tree_2_before = self.build_tree_str(self.tree_2) # point crossover self.crossover.point_crossover(self.tree_1, self.tree_2) # record after crossover tree_1_after = self.build_tree_str(self.tree_1) tree_2_after = self.build_tree_str(self.tree_2) print("Before Crossover") print("\nTree 1") print(tree_1_before) print("\nTree 2") print(tree_2_before) print("\nAfter Crossover") print("\nTree 1") print(tree_1_after) print("\nTree 2") print(tree_2_after) # asserts self.assertTrue(self.tree_equals(tree_1_before, tree_1_before)) self.assertTrue(self.tree_equals(tree_2_before, tree_2_before)) self.assertTrue(self.tree_equals(tree_1_after, tree_1_after)) self.assertTrue(self.tree_equals(tree_2_after, tree_2_after)) self.assertFalse(self.tree_equals(tree_1_before, tree_1_after)) self.assertFalse(self.tree_equals(tree_2_before, tree_2_after)) def test_common_region_point_crossover(self): # record before crossover tree_1_before = self.build_tree_str(self.tree_1) tree_2_before = self.build_tree_str(self.tree_2) # point crossover self.crossover.common_region_point_crossover(self.tree_1, self.tree_2) # record after crossover tree_1_after = self.build_tree_str(self.tree_1) tree_2_after = self.build_tree_str(self.tree_2) print("Before Crossover") print("\nTree 1") print(tree_1_before) print("\nTree 2") print(tree_2_before) print("\nAfter Crossover") print("\nTree 1") print(tree_1_after) print("\nTree 2") print(tree_2_after) def test_crossover(self): # record before crossover tree_1_before = self.build_tree_str(self.tree_1) tree_2_before = self.build_tree_str(self.tree_2) # point crossover self.crossover.crossover(self.tree_1, self.tree_2) # record after crossover tree_1_after = self.build_tree_str(self.tree_1) tree_2_after = self.build_tree_str(self.tree_2) print("Before Crossover") print("\nTree 1!") print(tree_1_before) print("\nTree 2!") print(tree_2_before) print("\nAfter Crossover") print("\nTree 1!") print(tree_1_after) print("\nTree 2!") print(tree_2_after) # asserts self.assertTrue(self.tree_equals(tree_1_before, tree_1_before)) self.assertTrue(self.tree_equals(tree_2_before, tree_2_before)) self.assertTrue(self.tree_equals(tree_1_after, tree_1_after)) self.assertTrue(self.tree_equals(tree_2_after, tree_2_after)) self.assertFalse(self.tree_equals(tree_1_before, tree_1_after)) self.assertFalse(self.tree_equals(tree_2_before, tree_2_after))
def setUp(self): self.config = { "tree_generation": { "initial_max_depth": 4 }, "crossover": { "method": "POINT_CROSSOVER", "probability": 1.0 }, "function_nodes": [{ "type": "FUNCTION", "name": "ADD", "arity": 2 }, { "type": "FUNCTION", "name": "SUB", "arity": 2 }, { "type": "FUNCTION", "name": "MUL", "arity": 2 }, { "type": "FUNCTION", "name": "DIV", "arity": 2 }, { "type": "FUNCTION", "name": "COS", "arity": 1 }, { "type": "FUNCTION", "name": "SIN", "arity": 1 }, { "type": "FUNCTION", "name": "RAD", "arity": 1 }], "terminal_nodes": [{ "type": "CONSTANT", "value": 1.0 }, { "type": "CONSTANT", "value": 2.0 }, { "type": "CONSTANT", "value": 2.0 }, { "type": "CONSTANT", "value": 3.0 }, { "type": "CONSTANT", "value": 4.0 }, { "type": "CONSTANT", "value": 5.0 }, { "type": "CONSTANT", "value": 6.0 }, { "type": "CONSTANT", "value": 7.0 }, { "type": "CONSTANT", "value": 8.0 }, { "type": "CONSTANT", "value": 9.0 }, { "type": "CONSTANT", "value": 10.0 }], "input_variables": [{ "type": "INPUT", "name": "x" }] } self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.crossover = TreeCrossover(self.config) self.parser = TreeParser() # create nodes left_node_1 = Node(NodeType.INPUT, name="x") right_node_1 = Node(NodeType.CONSTANT, value=2.0) node = Node(NodeType.CONSTANT, value=2.0) left_node_2 = Node(NodeType.CONSTANT, value=3.0) right_node_2 = Node(NodeType.CONSTANT, value=4.0) cos_func_1 = Node(NodeType.FUNCTION, name="ADD", arity=2, branches=[left_node_1, right_node_1]) sin_func_1 = Node(NodeType.FUNCTION, name="SIN", arity=1, branches=[node]) cos_func_2 = Node(NodeType.FUNCTION, name="COS", arity=1, branches=[left_node_2]) sin_func_2 = Node(NodeType.FUNCTION, name="SIN", arity=1, branches=[right_node_2]) add_func = Node(NodeType.FUNCTION, name="ADD", arity=2, branches=[cos_func_1, sin_func_1]) sub_func = Node(NodeType.FUNCTION, name="SUB", arity=2, branches=[sin_func_2, cos_func_2]) # create tree_1 self.tree_1 = Tree() self.tree_1.root = add_func self.tree_1.update() print self.tree_1 # create tree_2 self.tree_2 = Tree() self.tree_2.root = sub_func self.tree_2.update()
def setUp(self): self.config = { "max_population": 10, "tree_generation": { "method": "FULL_METHOD", "initial_max_depth": 4 }, "function_nodes": [{ "type": "FUNCTION", "name": "ADD", "arity": 2 }, { "type": "FUNCTION", "name": "SUB", "arity": 2 }, { "type": "FUNCTION", "name": "MUL", "arity": 2 }, { "type": "FUNCTION", "name": "DIV", "arity": 2 }, { "type": "FUNCTION", "name": "COS", "arity": 1 }, { "type": "FUNCTION", "name": "SIN", "arity": 1 }], "terminal_nodes": [{ "type": "CONSTANT", "value": 1.0 }, { "type": "INPUT", "name": "x" }, { "type": "INPUT", "name": "y" }, { "type": "INPUT", "name": "z" }], "input_variables": [{ "name": "x" }, { "name": "y" }, { "name": "z" }] } self.t_parser = TreeParser() self.tree = Tree() node_x = Node(NodeType.INPUT, name="x") node_y = Node(NodeType.INPUT, name="y") node_z = Node(NodeType.INPUT, name="z") self.tree.input_nodes.append(node_x) self.tree.input_nodes.append(node_y) self.tree.input_nodes.append(node_z)
class TreeTests(unittest.TestCase): def setUp(self): self.config = { "max_population": 10, "tree_generation": { "method": "FULL_METHOD", "initial_max_depth": 4 }, "function_nodes": [{ "type": "FUNCTION", "name": "ADD", "arity": 2 }, { "type": "FUNCTION", "name": "SUB", "arity": 2 }, { "type": "FUNCTION", "name": "MUL", "arity": 2 }, { "type": "FUNCTION", "name": "DIV", "arity": 2 }, { "type": "FUNCTION", "name": "COS", "arity": 1 }, { "type": "FUNCTION", "name": "SIN", "arity": 1 }], "terminal_nodes": [{ "type": "CONSTANT", "value": 1.0 }, { "type": "INPUT", "name": "x" }, { "type": "INPUT", "name": "y" }, { "type": "INPUT", "name": "z" }], "input_variables": [{ "name": "x" }, { "name": "y" }, { "name": "z" }] } self.t_parser = TreeParser() self.tree = Tree() node_x = Node(NodeType.INPUT, name="x") node_y = Node(NodeType.INPUT, name="y") node_z = Node(NodeType.INPUT, name="z") self.tree.input_nodes.append(node_x) self.tree.input_nodes.append(node_y) self.tree.input_nodes.append(node_z) def test_valid(self): # assert valid res = self.tree.valid(self.config["input_variables"]) self.assertTrue(res) # assert fail valid self.tree.input_nodes.pop() res = self.tree.valid(self.config["input_variables"]) self.assertFalse(res) def test_get_linked_node(self): # setup del self.tree.input_nodes[:] left_node = Node(NodeType.INPUT, name="x") right_node = Node(NodeType.INPUT, name="y") add_func = Node(NodeType.FUNCTION, name="ADD", arity=2, branches=[left_node, right_node]) self.tree.root = add_func self.tree.program = self.t_parser.post_order_traverse(self.tree.root) # pass test linked_node = self.tree.get_linked_node(left_node) self.assertTrue(linked_node is add_func) linked_node = self.tree.get_linked_node(right_node) self.assertTrue(linked_node is add_func) # fail test random_node = Node(NodeType.INPUT, name="z") linked_node = self.tree.get_linked_node(random_node) self.assertFalse(linked_node is add_func) def test_replace_node(self): # setup node_x = Node(NodeType.INPUT, name="x") node_y = Node(NodeType.INPUT, name="y") add_func = Node(NodeType.FUNCTION, name="ADD", arity=2, branches=[node_x, node_y]) # build tree tree = Tree() tree.root = add_func tree.update_program() # replace input node new_node = Node(NodeType.INPUT, name="z") before_replace = list(tree.program) tree.replace_node(node_x, new_node) after_replace = list(tree.program) # assert self.assertTrue(before_replace == before_replace) self.assertTrue(after_replace == after_replace) self.assertFalse(before_replace == after_replace) self.assertTrue(add_func.branches[0] is new_node) def test_equal(self): # create nodes left_node_1 = Node(NodeType.CONSTANT, value=1.0) right_node_1 = Node(NodeType.CONSTANT, value=2.0) left_node_2 = Node(NodeType.CONSTANT, value=3.0) right_node_2 = Node(NodeType.CONSTANT, value=4.0) cos_func_1 = Node(NodeType.FUNCTION, name="COS", arity=1, branches=[left_node_1]) sin_func_1 = Node(NodeType.FUNCTION, name="SIN", arity=1, branches=[right_node_1]) cos_func_2 = Node(NodeType.FUNCTION, name="COS", arity=1, branches=[left_node_2]) sin_func_2 = Node(NodeType.FUNCTION, name="SIN", arity=1, branches=[right_node_2]) add_func = Node(NodeType.FUNCTION, name="ADD", arity=2, branches=[cos_func_1, sin_func_1]) sub_func = Node(NodeType.FUNCTION, name="SUB", arity=2, branches=[sin_func_2, cos_func_2]) # create tree_1 tree_1 = Tree() tree_1.root = add_func tree_1.update() # create tree_2 tree_2 = Tree() tree_2.root = sub_func tree_2.update() self.assertTrue(tree_1.equals(tree_1)) self.assertFalse(tree_1.equals(tree_2)) self.assertTrue(tree_2.equals(tree_2)) self.assertFalse(tree_2.equals(tree_1)) def test_str(self): # setup del self.tree.input_nodes[:] left_node = Node(NodeType.INPUT, name="x") right_node = Node(NodeType.INPUT, name="y") add_func = Node(NodeType.FUNCTION, name="ADD", arity=2, branches=[left_node, right_node]) self.tree.root = add_func self.tree.program = self.t_parser.post_order_traverse(self.tree.root) # assert self.assertEquals(str(self.tree), "(x ADD y)")
def setUp(self): random.seed(10) self.config = { "max_population": 10, "tree_generation": { "method": "FULL_METHOD", "initial_max_depth": 4 }, "function_nodes": [ {"type": "FUNCTION", "name": "ADD", "arity": 2}, {"type": "FUNCTION", "name": "SUB", "arity": 2}, {"type": "FUNCTION", "name": "MUL", "arity": 2}, {"type": "FUNCTION", "name": "DIV", "arity": 2}, {"type": "FUNCTION", "name": "COS", "arity": 1}, {"type": "FUNCTION", "name": "SIN", "arity": 1} ], "terminal_nodes": [ {"type": "CONSTANT", "value": 1.0}, {"type": "INPUT", "name": "x"}, {"type": "INPUT", "name": "y"}, {"type": "INPUT", "name": "z"} ], "input_variables": [ {"name": "x"}, {"name": "y"}, {"name": "z"} ] } self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.parser = TreeParser() # create nodes left_node = Node(NodeType.CONSTANT, value=1.0) right_node = Node(NodeType.CONSTANT, value=2.0) cos_func = Node( NodeType.FUNCTION, name="COS", arity=1, branches=[left_node] ) sin_func = Node( NodeType.FUNCTION, name="SIN", arity=1, branches=[right_node] ) add_func = Node( NodeType.FUNCTION, name="ADD", arity=2, branches=[cos_func, sin_func] ) # create tree self.tree = Tree() self.tree.root = add_func self.tree.update_program() self.tree.update_func_nodes() self.tree.update_term_nodes()
class TreeParserTests(unittest.TestCase): def setUp(self): random.seed(10) self.config = { "max_population": 10, "tree_generation": { "method": "FULL_METHOD", "initial_max_depth": 4 }, "function_nodes": [ {"type": "FUNCTION", "name": "ADD", "arity": 2}, {"type": "FUNCTION", "name": "SUB", "arity": 2}, {"type": "FUNCTION", "name": "MUL", "arity": 2}, {"type": "FUNCTION", "name": "DIV", "arity": 2}, {"type": "FUNCTION", "name": "COS", "arity": 1}, {"type": "FUNCTION", "name": "SIN", "arity": 1} ], "terminal_nodes": [ {"type": "CONSTANT", "value": 1.0}, {"type": "INPUT", "name": "x"}, {"type": "INPUT", "name": "y"}, {"type": "INPUT", "name": "z"} ], "input_variables": [ {"name": "x"}, {"name": "y"}, {"name": "z"} ] } self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.parser = TreeParser() # create nodes left_node = Node(NodeType.CONSTANT, value=1.0) right_node = Node(NodeType.CONSTANT, value=2.0) cos_func = Node( NodeType.FUNCTION, name="COS", arity=1, branches=[left_node] ) sin_func = Node( NodeType.FUNCTION, name="SIN", arity=1, branches=[right_node] ) add_func = Node( NodeType.FUNCTION, name="ADD", arity=2, branches=[cos_func, sin_func] ) # create tree self.tree = Tree() self.tree.root = add_func self.tree.update_program() self.tree.update_func_nodes() self.tree.update_term_nodes() def tearDown(self): del self.config del self.generator del self.parser def test_parse_tree(self): # self.parser.print_tree(tree.root) program = self.parser.parse_tree(self.tree, self.tree.root) for i in program: if i.name is not None: print i.name else: print i.value self.assertEquals(self.tree.size, 5) self.assertEquals(self.tree.depth, 2) self.assertEquals(len(self.tree.func_nodes), 2) self.assertEquals(len(self.tree.term_nodes), 2) self.assertEquals(len(self.tree.input_nodes), 0) def test_parse_equation(self): # self.parser.print_tree(tree.root) equation = self.parser.parse_equation(self.tree.root) self.assertEquals(equation, "((COS(1.0)) ADD (SIN(2.0)))") def test_tree_to_dict(self): solution = { 'program': [ {'type': 'CONSTANT', 'value': 1.0}, {'arity': 1, 'type': 'FUNCTION', 'name': 'COS'}, {'type': 'CONSTANT', 'value': 2.0}, {'arity': 1, 'type': 'FUNCTION', 'name': 'SIN'}, {'arity': 2, 'type': 'FUNCTION', 'root': True, 'name': 'ADD'} ] } results = self.parser.tree_to_dict(self.tree, self.tree.root) self.assertEquals(results["program"], solution["program"])
class TreeTests(unittest.TestCase): def setUp(self): self.config = { "max_population": 10, "tree_generation": { "method": "FULL_METHOD", "initial_max_depth": 4 }, "function_nodes": [ {"type": "FUNCTION", "name": "ADD", "arity": 2}, {"type": "FUNCTION", "name": "SUB", "arity": 2}, {"type": "FUNCTION", "name": "MUL", "arity": 2}, {"type": "FUNCTION", "name": "DIV", "arity": 2}, {"type": "FUNCTION", "name": "COS", "arity": 1}, {"type": "FUNCTION", "name": "SIN", "arity": 1} ], "terminal_nodes": [ {"type": "CONSTANT", "value": 1.0}, {"type": "INPUT", "name": "x"}, {"type": "INPUT", "name": "y"}, {"type": "INPUT", "name": "z"} ], "input_variables": [ {"name": "x"}, {"name": "y"}, {"name": "z"} ] } self.t_parser = TreeParser() self.tree = Tree() node_x = Node(NodeType.INPUT, name="x") node_y = Node(NodeType.INPUT, name="y") node_z = Node(NodeType.INPUT, name="z") self.tree.input_nodes.append(node_x) self.tree.input_nodes.append(node_y) self.tree.input_nodes.append(node_z) def test_valid(self): # assert valid res = self.tree.valid(self.config["input_variables"]) self.assertTrue(res) # assert fail valid self.tree.input_nodes.pop() res = self.tree.valid(self.config["input_variables"]) self.assertFalse(res) def test_get_linked_node(self): # setup del self.tree.input_nodes[:] left_node = Node(NodeType.INPUT, name="x") right_node = Node(NodeType.INPUT, name="y") add_func = Node( NodeType.FUNCTION, name="ADD", arity=2, branches=[left_node, right_node] ) self.tree.root = add_func self.tree.program = self.t_parser.post_order_traverse(self.tree.root) # pass test linked_node = self.tree.get_linked_node(left_node) self.assertTrue(linked_node is add_func) linked_node = self.tree.get_linked_node(right_node) self.assertTrue(linked_node is add_func) # fail test random_node = Node(NodeType.INPUT, name="z") linked_node = self.tree.get_linked_node(random_node) self.assertFalse(linked_node is add_func) def test_replace_node(self): # setup node_x = Node(NodeType.INPUT, name="x") node_y = Node(NodeType.INPUT, name="y") add_func = Node( NodeType.FUNCTION, name="ADD", arity=2, branches=[node_x, node_y] ) # build tree tree = Tree() tree.root = add_func tree.update_program() # replace input node new_node = Node(NodeType.INPUT, name="z") before_replace = list(tree.program) tree.replace_node(node_x, new_node) after_replace = list(tree.program) # assert self.assertTrue(before_replace == before_replace) self.assertTrue(after_replace == after_replace) self.assertFalse(before_replace == after_replace) self.assertTrue(add_func.branches[0] is new_node) def test_equal(self): # create nodes left_node_1 = Node(NodeType.CONSTANT, value=1.0) right_node_1 = Node(NodeType.CONSTANT, value=2.0) left_node_2 = Node(NodeType.CONSTANT, value=3.0) right_node_2 = Node(NodeType.CONSTANT, value=4.0) cos_func_1 = Node( NodeType.FUNCTION, name="COS", arity=1, branches=[left_node_1] ) sin_func_1 = Node( NodeType.FUNCTION, name="SIN", arity=1, branches=[right_node_1] ) cos_func_2 = Node( NodeType.FUNCTION, name="COS", arity=1, branches=[left_node_2] ) sin_func_2 = Node( NodeType.FUNCTION, name="SIN", arity=1, branches=[right_node_2] ) add_func = Node( NodeType.FUNCTION, name="ADD", arity=2, branches=[cos_func_1, sin_func_1] ) sub_func = Node( NodeType.FUNCTION, name="SUB", arity=2, branches=[sin_func_2, cos_func_2] ) # create tree_1 tree_1 = Tree() tree_1.root = add_func tree_1.update() # create tree_2 tree_2 = Tree() tree_2.root = sub_func tree_2.update() self.assertTrue(tree_1.equals(tree_1)) self.assertFalse(tree_1.equals(tree_2)) self.assertTrue(tree_2.equals(tree_2)) self.assertFalse(tree_2.equals(tree_1)) def test_str(self): # setup del self.tree.input_nodes[:] left_node = Node(NodeType.INPUT, name="x") right_node = Node(NodeType.INPUT, name="y") add_func = Node( NodeType.FUNCTION, name="ADD", arity=2, branches=[left_node, right_node] ) self.tree.root = add_func self.tree.program = self.t_parser.post_order_traverse(self.tree.root) # assert self.assertEquals(str(self.tree), "(x ADD y)")
def test_equal(self): # create nodes left_node_1 = Node(NodeType.CONSTANT, value=1.0) right_node_1 = Node(NodeType.CONSTANT, value=2.0) left_node_2 = Node(NodeType.CONSTANT, value=3.0) right_node_2 = Node(NodeType.CONSTANT, value=4.0) cos_func_1 = Node( NodeType.FUNCTION, name="COS", arity=1, branches=[left_node_1] ) sin_func_1 = Node( NodeType.FUNCTION, name="SIN", arity=1, branches=[right_node_1] ) cos_func_2 = Node( NodeType.FUNCTION, name="COS", arity=1, branches=[left_node_2] ) sin_func_2 = Node( NodeType.FUNCTION, name="SIN", arity=1, branches=[right_node_2] ) add_func = Node( NodeType.FUNCTION, name="ADD", arity=2, branches=[cos_func_1, sin_func_1] ) sub_func = Node( NodeType.FUNCTION, name="SUB", arity=2, branches=[sin_func_2, cos_func_2] ) # create tree_1 tree_1 = Tree() tree_1.root = add_func tree_1.update() # create tree_2 tree_2 = Tree() tree_2.root = sub_func tree_2.update() self.assertTrue(tree_1.equals(tree_1)) self.assertFalse(tree_1.equals(tree_2)) self.assertTrue(tree_2.equals(tree_2)) self.assertFalse(tree_2.equals(tree_1))
class TreeMutatorTests(unittest.TestCase): def setUp(self): self.config = { "tree_generation": { "method": "GROW_METHOD", "initial_max_depth": 4 }, "mutation": { "methods": [ "POINT_MUTATION", "HOIST_MUTATION", "SUBTREE_MUTATION", "SHRINK_MUTATION", "EXPAND_MUTATION" ], "probability": 1.0 }, "function_nodes": [{ "type": "FUNCTION", "name": "ADD", "arity": 2 }, { "type": "FUNCTION", "name": "SUB", "arity": 2 }, { "type": "FUNCTION", "name": "MUL", "arity": 2 }, { "type": "FUNCTION", "name": "DIV", "arity": 2 }, { "type": "FUNCTION", "name": "COS", "arity": 1 }, { "type": "FUNCTION", "name": "SIN", "arity": 1 }, { "type": "FUNCTION", "name": "RAD", "arity": 1 }], "terminal_nodes": [{ "type": "CONSTANT", "value": 1.0 }, { "type": "CONSTANT", "value": 2.0 }, { "type": "INPUT", "name": "x" }], "input_variables": [{ "type": "INPUT", "name": "x" }] } self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.parser = TreeParser() self.mutation = TreeMutation(self.config) # create nodes left_node = Node(NodeType.CONSTANT, value=1.0) right_node = Node(NodeType.INPUT, name="x") cos_func = Node(NodeType.FUNCTION, name="COS", arity=1, branches=[left_node]) sin_func = Node(NodeType.FUNCTION, name="SIN", arity=1, branches=[right_node]) add_func = Node(NodeType.FUNCTION, name="ADD", arity=2, branches=[cos_func, sin_func]) # create tree self.tree = Tree() self.tree.root = add_func self.tree.update_program() self.tree.update_func_nodes() self.tree.update_term_nodes() def tearDown(self): del self.config del self.generator del self.parser def build_tree_str(self, tree): tree_str = "" for node in tree.program: if hasattr(node, "name") and node.name is not None: tree_str += "node:{0} addr:{1}\n".format(node.name, id(node)) else: tree_str += "node:{0} addr:{1}\n".format(node.value, id(node)) return tree_str def tree_equals(self, tree_1_str, tree_2_str): if tree_1_str == tree_2_str: return True else: return False def mutated(self, tree, mutation_func, mutation_index=None): tree_before = self.build_tree_str(self.tree) mutation_func(tree, mutation_index) tree_after = self.build_tree_str(self.tree) print("Before Mutation") print(tree_before) print("\nAfter Mutation") print(tree_after) self.assertTrue(self.tree_equals(tree_before, tree_before)) self.assertTrue(self.tree_equals(tree_after, tree_after)) self.assertFalse(self.tree_equals(tree_before, tree_after)) def test_mutate_new_node_details(self): # MUTATE NEW FUNCTION NODE DETAILS for i in range(100): func_node = Node(NodeType.FUNCTION, name="ADD", arity=2, branches=[]) node_details = self.mutation.mutate_new_node_details(func_node) self.assertNotEquals(node_details["name"], func_node.name) self.assertEquals(node_details["arity"], func_node.arity) self.assertEquals(node_details["type"], func_node.node_type) # MUTATE NEW TERMINAL NODE DETAILS for i in range(100): term_node = Node(NodeType.CONSTANT, value=1.0) node_details = self.mutation.mutate_new_node_details(term_node) if node_details["type"] == NodeType.CONSTANT: self.assertNotEqual(node_details["value"], term_node.value) elif node_details["type"] == NodeType.INPUT: self.assertNotEqual(node_details["name"], term_node.name) # MUTATE NEW CLASS FUNCTION NODE DETAILS self.config["function_nodes"] = [{ "type": "CLASS_FUNCTION", "name": "GREATER_THAN", "arity": 2, "data_range": { "lower_bound": 0.0, "upper_bound": 10.0, "decimal_places": 0, } }, { "type": "CLASS_FUNCTION", "name": "LESS_THAN", "arity": 2, "data_range": { "lower_bound": 0.0, "upper_bound": 10.0, "decimal_places": 0, } }, { "type": "CLASS_FUNCTION", "name": "EQUALS", "arity": 2, "decimal_precision": 2 }] mutation = TreeMutation(self.config) for i in range(100): class_func_node = Node(NodeType.CLASS_FUNCTION, name="GREATER_THAN", arity=2) node_details = mutation.mutate_new_node_details(class_func_node) self.assertNotEquals(node_details["name"], class_func_node.name) self.assertEquals(node_details["arity"], class_func_node.arity) self.assertEquals(node_details["type"], class_func_node.node_type) def test_point_mutation(self): print "---------- POINT MUATION! ----------" self.mutated(self.tree, self.mutation.point_mutation) def test_hoist_mutation(self): print "---------- HOIST MUATION! ----------" self.mutated(self.tree, self.mutation.hoist_mutation, 3) def test_SUBTREE_MUTATION(self): print "---------- SUBTREE MUATION! ----------" self.mutated(self.tree, self.mutation.subtree_mutation, 3) def test_shrink_mutation(self): print "---------- SHRINK MUATION! ----------" self.mutated(self.tree, self.mutation.shrink_mutation, 3) def test_expansion_mutation(self): print "---------- EXPANSION MUATION! ----------" self.mutated(self.tree, self.mutation.expansion_mutation, 3) def test_mutate(self): print "MUTATE!" tree_before = self.build_tree_str(self.tree) self.mutation.mutate(self.tree) tree_after = self.build_tree_str(self.tree) print "----->", self.mutation.method print("Before Mutation") print(tree_before) print("\nAfter Mutation") print(tree_after) self.assertTrue(self.tree_equals(tree_before, tree_before)) self.assertTrue(self.tree_equals(tree_after, tree_after)) self.assertFalse(self.tree_equals(tree_before, tree_after))
def test_equal(self): # create nodes left_node_1 = Node(NodeType.CONSTANT, value=1.0) right_node_1 = Node(NodeType.CONSTANT, value=2.0) left_node_2 = Node(NodeType.CONSTANT, value=3.0) right_node_2 = Node(NodeType.CONSTANT, value=4.0) cos_func_1 = Node(NodeType.FUNCTION, name="COS", arity=1, branches=[left_node_1]) sin_func_1 = Node(NodeType.FUNCTION, name="SIN", arity=1, branches=[right_node_1]) cos_func_2 = Node(NodeType.FUNCTION, name="COS", arity=1, branches=[left_node_2]) sin_func_2 = Node(NodeType.FUNCTION, name="SIN", arity=1, branches=[right_node_2]) add_func = Node(NodeType.FUNCTION, name="ADD", arity=2, branches=[cos_func_1, sin_func_1]) sub_func = Node(NodeType.FUNCTION, name="SUB", arity=2, branches=[sin_func_2, cos_func_2]) # create tree_1 tree_1 = Tree() tree_1.root = add_func tree_1.update() # create tree_2 tree_2 = Tree() tree_2.root = sub_func tree_2.update() self.assertTrue(tree_1.equals(tree_1)) self.assertFalse(tree_1.equals(tree_2)) self.assertTrue(tree_2.equals(tree_2)) self.assertFalse(tree_2.equals(tree_1))
def setUp(self): self.config = { "tree_generation": { "initial_max_depth": 4 }, "crossover": { "method": "POINT_CROSSOVER", "probability": 1.0 }, "function_nodes": [ {"type": "FUNCTION", "name": "ADD", "arity": 2}, {"type": "FUNCTION", "name": "SUB", "arity": 2}, {"type": "FUNCTION", "name": "MUL", "arity": 2}, {"type": "FUNCTION", "name": "DIV", "arity": 2}, {"type": "FUNCTION", "name": "COS", "arity": 1}, {"type": "FUNCTION", "name": "SIN", "arity": 1}, {"type": "FUNCTION", "name": "RAD", "arity": 1} ], "terminal_nodes": [ {"type": "CONSTANT", "value": 1.0}, {"type": "CONSTANT", "value": 2.0}, {"type": "CONSTANT", "value": 2.0}, {"type": "CONSTANT", "value": 3.0}, {"type": "CONSTANT", "value": 4.0}, {"type": "CONSTANT", "value": 5.0}, {"type": "CONSTANT", "value": 6.0}, {"type": "CONSTANT", "value": 7.0}, {"type": "CONSTANT", "value": 8.0}, {"type": "CONSTANT", "value": 9.0}, {"type": "CONSTANT", "value": 10.0} ], "input_variables": [ {"type": "INPUT", "name": "x"} ] } self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.crossover = TreeCrossover(self.config) self.parser = TreeParser() # create nodes left_node_1 = Node(NodeType.INPUT, name="x") right_node_1 = Node(NodeType.CONSTANT, value=2.0) node = Node(NodeType.CONSTANT, value=2.0) left_node_2 = Node(NodeType.CONSTANT, value=3.0) right_node_2 = Node(NodeType.CONSTANT, value=4.0) cos_func_1 = Node( NodeType.FUNCTION, name="ADD", arity=2, branches=[left_node_1, right_node_1] ) sin_func_1 = Node( NodeType.FUNCTION, name="SIN", arity=1, branches=[node] ) cos_func_2 = Node( NodeType.FUNCTION, name="COS", arity=1, branches=[left_node_2] ) sin_func_2 = Node( NodeType.FUNCTION, name="SIN", arity=1, branches=[right_node_2] ) add_func = Node( NodeType.FUNCTION, name="ADD", arity=2, branches=[cos_func_1, sin_func_1] ) sub_func = Node( NodeType.FUNCTION, name="SUB", arity=2, branches=[sin_func_2, cos_func_2] ) # create tree_1 self.tree_1 = Tree() self.tree_1.root = add_func self.tree_1.update() print self.tree_1 # create tree_2 self.tree_2 = Tree() self.tree_2.root = sub_func self.tree_2.update()
class TreeCrossoverTests(unittest.TestCase): def setUp(self): self.config = { "tree_generation": { "initial_max_depth": 4 }, "crossover": { "method": "POINT_CROSSOVER", "probability": 1.0 }, "function_nodes": [ {"type": "FUNCTION", "name": "ADD", "arity": 2}, {"type": "FUNCTION", "name": "SUB", "arity": 2}, {"type": "FUNCTION", "name": "MUL", "arity": 2}, {"type": "FUNCTION", "name": "DIV", "arity": 2}, {"type": "FUNCTION", "name": "COS", "arity": 1}, {"type": "FUNCTION", "name": "SIN", "arity": 1}, {"type": "FUNCTION", "name": "RAD", "arity": 1} ], "terminal_nodes": [ {"type": "CONSTANT", "value": 1.0}, {"type": "CONSTANT", "value": 2.0}, {"type": "CONSTANT", "value": 2.0}, {"type": "CONSTANT", "value": 3.0}, {"type": "CONSTANT", "value": 4.0}, {"type": "CONSTANT", "value": 5.0}, {"type": "CONSTANT", "value": 6.0}, {"type": "CONSTANT", "value": 7.0}, {"type": "CONSTANT", "value": 8.0}, {"type": "CONSTANT", "value": 9.0}, {"type": "CONSTANT", "value": 10.0} ], "input_variables": [ {"type": "INPUT", "name": "x"} ] } self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.crossover = TreeCrossover(self.config) self.parser = TreeParser() # create nodes left_node_1 = Node(NodeType.INPUT, name="x") right_node_1 = Node(NodeType.CONSTANT, value=2.0) node = Node(NodeType.CONSTANT, value=2.0) left_node_2 = Node(NodeType.CONSTANT, value=3.0) right_node_2 = Node(NodeType.CONSTANT, value=4.0) cos_func_1 = Node( NodeType.FUNCTION, name="ADD", arity=2, branches=[left_node_1, right_node_1] ) sin_func_1 = Node( NodeType.FUNCTION, name="SIN", arity=1, branches=[node] ) cos_func_2 = Node( NodeType.FUNCTION, name="COS", arity=1, branches=[left_node_2] ) sin_func_2 = Node( NodeType.FUNCTION, name="SIN", arity=1, branches=[right_node_2] ) add_func = Node( NodeType.FUNCTION, name="ADD", arity=2, branches=[cos_func_1, sin_func_1] ) sub_func = Node( NodeType.FUNCTION, name="SUB", arity=2, branches=[sin_func_2, cos_func_2] ) # create tree_1 self.tree_1 = Tree() self.tree_1.root = add_func self.tree_1.update() print self.tree_1 # create tree_2 self.tree_2 = Tree() self.tree_2.root = sub_func self.tree_2.update() def tearDown(self): del self.config del self.generator del self.parser def build_tree_str(self, tree): tree_str = "" for node in tree.program: if hasattr(node, "name") and node.name is not None: tree_str += "node:{0} addr:{1}\n".format(node.name, id(node)) else: tree_str += "node:{0} addr:{1}\n".format(node.value, id(node)) return tree_str def tree_equals(self, tree_1_str, tree_2_str): if tree_1_str == tree_2_str: return True else: return False def test_point_crossover(self): # record before crossover tree_1_before = self.build_tree_str(self.tree_1) tree_2_before = self.build_tree_str(self.tree_2) # point crossover self.crossover.point_crossover(self.tree_1, self.tree_2) # record after crossover tree_1_after = self.build_tree_str(self.tree_1) tree_2_after = self.build_tree_str(self.tree_2) print("Before Crossover") print("\nTree 1") print(tree_1_before) print("\nTree 2") print(tree_2_before) print("\nAfter Crossover") print("\nTree 1") print(tree_1_after) print("\nTree 2") print(tree_2_after) # asserts self.assertTrue(self.tree_equals(tree_1_before, tree_1_before)) self.assertTrue(self.tree_equals(tree_2_before, tree_2_before)) self.assertTrue(self.tree_equals(tree_1_after, tree_1_after)) self.assertTrue(self.tree_equals(tree_2_after, tree_2_after)) self.assertFalse(self.tree_equals(tree_1_before, tree_1_after)) self.assertFalse(self.tree_equals(tree_2_before, tree_2_after)) def test_common_region_point_crossover(self): # record before crossover tree_1_before = self.build_tree_str(self.tree_1) tree_2_before = self.build_tree_str(self.tree_2) # point crossover self.crossover.common_region_point_crossover(self.tree_1, self.tree_2) # record after crossover tree_1_after = self.build_tree_str(self.tree_1) tree_2_after = self.build_tree_str(self.tree_2) print("Before Crossover") print("\nTree 1") print(tree_1_before) print("\nTree 2") print(tree_2_before) print("\nAfter Crossover") print("\nTree 1") print(tree_1_after) print("\nTree 2") print(tree_2_after) def test_crossover(self): # record before crossover tree_1_before = self.build_tree_str(self.tree_1) tree_2_before = self.build_tree_str(self.tree_2) # point crossover self.crossover.crossover(self.tree_1, self.tree_2) # record after crossover tree_1_after = self.build_tree_str(self.tree_1) tree_2_after = self.build_tree_str(self.tree_2) print("Before Crossover") print("\nTree 1!") print(tree_1_before) print("\nTree 2!") print(tree_2_before) print("\nAfter Crossover") print("\nTree 1!") print(tree_1_after) print("\nTree 2!") print(tree_2_after) # asserts self.assertTrue(self.tree_equals(tree_1_before, tree_1_before)) self.assertTrue(self.tree_equals(tree_2_before, tree_2_before)) self.assertTrue(self.tree_equals(tree_1_after, tree_1_after)) self.assertTrue(self.tree_equals(tree_2_after, tree_2_after)) self.assertFalse(self.tree_equals(tree_1_before, tree_1_after)) self.assertFalse(self.tree_equals(tree_2_before, tree_2_after))
def setUp(self): self.config = { "tree_generation": { "method": "GROW_METHOD", "initial_max_depth": 4 }, "mutation": { "methods": [ "POINT_MUTATION", "HOIST_MUTATION", "SUBTREE_MUTATION", "SHRINK_MUTATION", "EXPAND_MUTATION" ], "probability": 1.0 }, "function_nodes": [ {"type": "FUNCTION", "name": "ADD", "arity": 2}, {"type": "FUNCTION", "name": "SUB", "arity": 2}, {"type": "FUNCTION", "name": "MUL", "arity": 2}, {"type": "FUNCTION", "name": "DIV", "arity": 2}, {"type": "FUNCTION", "name": "COS", "arity": 1}, {"type": "FUNCTION", "name": "SIN", "arity": 1}, {"type": "FUNCTION", "name": "RAD", "arity": 1} ], "terminal_nodes": [ {"type": "CONSTANT", "value": 1.0}, {"type": "CONSTANT", "value": 2.0}, {"type": "INPUT", "name": "x"} ], "input_variables": [ {"type": "INPUT", "name": "x"} ] } self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.parser = TreeParser() self.mutation = TreeMutation(self.config) # create nodes left_node = Node(NodeType.CONSTANT, value=1.0) right_node = Node(NodeType.INPUT, name="x") cos_func = Node( NodeType.FUNCTION, name="COS", arity=1, branches=[left_node] ) sin_func = Node( NodeType.FUNCTION, name="SIN", arity=1, branches=[right_node] ) add_func = Node( NodeType.FUNCTION, name="ADD", arity=2, branches=[cos_func, sin_func] ) # create tree self.tree = Tree() self.tree.root = add_func self.tree.update_program() self.tree.update_func_nodes() self.tree.update_term_nodes()
def setUp(self): self.config = { "tree_generation": { "method": "GROW_METHOD", "initial_max_depth": 4 }, "mutation": { "methods": [ "POINT_MUTATION", "HOIST_MUTATION", "SUBTREE_MUTATION", "SHRINK_MUTATION", "EXPAND_MUTATION" ], "probability": 1.0 }, "function_nodes": [{ "type": "FUNCTION", "name": "ADD", "arity": 2 }, { "type": "FUNCTION", "name": "SUB", "arity": 2 }, { "type": "FUNCTION", "name": "MUL", "arity": 2 }, { "type": "FUNCTION", "name": "DIV", "arity": 2 }, { "type": "FUNCTION", "name": "COS", "arity": 1 }, { "type": "FUNCTION", "name": "SIN", "arity": 1 }, { "type": "FUNCTION", "name": "RAD", "arity": 1 }], "terminal_nodes": [{ "type": "CONSTANT", "value": 1.0 }, { "type": "CONSTANT", "value": 2.0 }, { "type": "INPUT", "name": "x" }], "input_variables": [{ "type": "INPUT", "name": "x" }] } self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.parser = TreeParser() self.mutation = TreeMutation(self.config) # create nodes left_node = Node(NodeType.CONSTANT, value=1.0) right_node = Node(NodeType.INPUT, name="x") cos_func = Node(NodeType.FUNCTION, name="COS", arity=1, branches=[left_node]) sin_func = Node(NodeType.FUNCTION, name="SIN", arity=1, branches=[right_node]) add_func = Node(NodeType.FUNCTION, name="ADD", arity=2, branches=[cos_func, sin_func]) # create tree self.tree = Tree() self.tree.root = add_func self.tree.update_program() self.tree.update_func_nodes() self.tree.update_term_nodes()
class TreeMutatorTests(unittest.TestCase): def setUp(self): self.config = { "tree_generation": { "method": "GROW_METHOD", "initial_max_depth": 4 }, "mutation": { "methods": [ "POINT_MUTATION", "HOIST_MUTATION", "SUBTREE_MUTATION", "SHRINK_MUTATION", "EXPAND_MUTATION" ], "probability": 1.0 }, "function_nodes": [ {"type": "FUNCTION", "name": "ADD", "arity": 2}, {"type": "FUNCTION", "name": "SUB", "arity": 2}, {"type": "FUNCTION", "name": "MUL", "arity": 2}, {"type": "FUNCTION", "name": "DIV", "arity": 2}, {"type": "FUNCTION", "name": "COS", "arity": 1}, {"type": "FUNCTION", "name": "SIN", "arity": 1}, {"type": "FUNCTION", "name": "RAD", "arity": 1} ], "terminal_nodes": [ {"type": "CONSTANT", "value": 1.0}, {"type": "CONSTANT", "value": 2.0}, {"type": "INPUT", "name": "x"} ], "input_variables": [ {"type": "INPUT", "name": "x"} ] } self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.parser = TreeParser() self.mutation = TreeMutation(self.config) # create nodes left_node = Node(NodeType.CONSTANT, value=1.0) right_node = Node(NodeType.INPUT, name="x") cos_func = Node( NodeType.FUNCTION, name="COS", arity=1, branches=[left_node] ) sin_func = Node( NodeType.FUNCTION, name="SIN", arity=1, branches=[right_node] ) add_func = Node( NodeType.FUNCTION, name="ADD", arity=2, branches=[cos_func, sin_func] ) # create tree self.tree = Tree() self.tree.root = add_func self.tree.update_program() self.tree.update_func_nodes() self.tree.update_term_nodes() def tearDown(self): del self.config del self.generator del self.parser def build_tree_str(self, tree): tree_str = "" for node in tree.program: if hasattr(node, "name") and node.name is not None: tree_str += "node:{0} addr:{1}\n".format(node.name, id(node)) else: tree_str += "node:{0} addr:{1}\n".format(node.value, id(node)) return tree_str def tree_equals(self, tree_1_str, tree_2_str): if tree_1_str == tree_2_str: return True else: return False def mutated(self, tree, mutation_func, mutation_index=None): tree_before = self.build_tree_str(self.tree) mutation_func(tree, mutation_index) tree_after = self.build_tree_str(self.tree) print("Before Mutation") print(tree_before) print("\nAfter Mutation") print(tree_after) self.assertTrue(self.tree_equals(tree_before, tree_before)) self.assertTrue(self.tree_equals(tree_after, tree_after)) self.assertFalse(self.tree_equals(tree_before, tree_after)) def test_mutate_new_node_details(self): # MUTATE NEW FUNCTION NODE DETAILS for i in range(100): func_node = Node( NodeType.FUNCTION, name="ADD", arity=2, branches=[] ) node_details = self.mutation.mutate_new_node_details(func_node) self.assertNotEquals(node_details["name"], func_node.name) self.assertEquals(node_details["arity"], func_node.arity) self.assertEquals(node_details["type"], func_node.node_type) # MUTATE NEW TERMINAL NODE DETAILS for i in range(100): term_node = Node( NodeType.CONSTANT, value=1.0 ) node_details = self.mutation.mutate_new_node_details(term_node) if node_details["type"] == NodeType.CONSTANT: self.assertNotEqual(node_details["value"], term_node.value) elif node_details["type"] == NodeType.INPUT: self.assertNotEqual(node_details["name"], term_node.name) # MUTATE NEW CLASS FUNCTION NODE DETAILS self.config["function_nodes"] = [ { "type": "CLASS_FUNCTION", "name": "GREATER_THAN", "arity": 2, "data_range": { "lower_bound": 0.0, "upper_bound": 10.0, "decimal_places": 0, } }, { "type": "CLASS_FUNCTION", "name": "LESS_THAN", "arity": 2, "data_range": { "lower_bound": 0.0, "upper_bound": 10.0, "decimal_places": 0, } }, { "type": "CLASS_FUNCTION", "name": "EQUALS", "arity": 2, "decimal_precision": 2 } ] mutation = TreeMutation(self.config) for i in range(100): class_func_node = Node( NodeType.CLASS_FUNCTION, name="GREATER_THAN", arity=2 ) node_details = mutation.mutate_new_node_details(class_func_node) self.assertNotEquals(node_details["name"], class_func_node.name) self.assertEquals(node_details["arity"], class_func_node.arity) self.assertEquals(node_details["type"], class_func_node.node_type) def test_point_mutation(self): print "---------- POINT MUATION! ----------" self.mutated(self.tree, self.mutation.point_mutation) def test_hoist_mutation(self): print "---------- HOIST MUATION! ----------" self.mutated(self.tree, self.mutation.hoist_mutation, 3) def test_SUBTREE_MUTATION(self): print "---------- SUBTREE MUATION! ----------" self.mutated(self.tree, self.mutation.subtree_mutation, 3) def test_shrink_mutation(self): print "---------- SHRINK MUATION! ----------" self.mutated(self.tree, self.mutation.shrink_mutation, 3) def test_expansion_mutation(self): print "---------- EXPANSION MUATION! ----------" self.mutated(self.tree, self.mutation.expansion_mutation, 3) def test_mutate(self): print "MUTATE!" tree_before = self.build_tree_str(self.tree) self.mutation.mutate(self.tree) tree_after = self.build_tree_str(self.tree) print "----->", self.mutation.method print("Before Mutation") print(tree_before) print("\nAfter Mutation") print(tree_after) self.assertTrue(self.tree_equals(tree_before, tree_before)) self.assertTrue(self.tree_equals(tree_after, tree_after)) self.assertFalse(self.tree_equals(tree_before, tree_after))