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 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))
"name": "petal_length" }, { "name": "petal_width" }], "response_variables": [{ "name": "species" }] } load_data(config, script_path) functions = GPFunctionRegistry("CLASSIFICATION") generator = TreeGenerator(config) # genetic operators selection = Selection(config) crossover = TreeCrossover(config) mutation = TreeMutation(config) # run symbolic regression population = generator.init() start_time = time.time() details = play.play_details( population=population, evaluate=evaluate, functions=functions, selection=selection, crossover=crossover, mutation=mutation, print_func=print_func, stop_func=default_stop_func, config=config,
def setUp(self): self.config = { "max_population": 10, "tree_generation": { "method": "FULL_METHOD", "initial_max_depth": 4 }, "evaluator": { "use_cache": True }, "selection": { "method": "TOURNAMENT_SELECTION", "tournament_size": 2 }, "crossover": { "method": "POINT_CROSSOVER", "probability": 0.6 }, "mutation": { "methods": ["POINT_MUTATION"], "probability": 0.8 }, "function_nodes": [{ "type": "FUNCTION", "name": "ADD", "arity": 2 }, { "type": "FUNCTION", "name": "SUB", "arity": 2 }], "terminal_nodes": [ { "type": "CONSTANT", "value": 1.0 }, ], "input_variables": [{ "type": "INPUT", "name": "x" }], "data_file": "tests/data/sine.dat", "response_variables": [{ "name": "y" }], "recorder": { "store_file": "json_store_test.json", "compress": True } } config.load_data(self.config) self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.json_store = JSONStore(self.config) self.json_store.setup_store() self.population = self.generator.init() results = [] cache = {} evaluate(self.population.individuals, self.functions, self.config, results, cache, self.json_store) self.population.sort_individuals() self.selection = Selection(self.config, recorder=self.json_store) self.crossover = TreeCrossover(self.config, recorder=self.json_store) self.mutation = TreeMutation(self.config, recorder=self.json_store)
"MUL": "*", "DIV": "/", "POW": "**", "SIN": "math.sin", "COS": "math.cos", "RAD": "math.radians", "LN": "math.ln", "EXP": "math.exp", "LOG": "math.log" } generator = TreeGenerator(config) # genetic operators selection = Selection(config, recorder=json_store) crossover = TreeCrossover(config, recorder=json_store) mutation = TreeMutation(config, recorder=json_store) # run symbolic regression population = generator.init() start_time = time.time() details = play.play_details(population=population, evaluate=evaluate, functions=functions, selection=selection, crossover=crossover, mutation=mutation, print_func=print_func, plot_func=plot_func, stop_func=default_stop_func, config=config,
def setUp(self): self.config = { "max_population" : 10, "tree_generation" : { "method" : "FULL_METHOD", "initial_max_depth" : 4 }, "evaluator" : { "use_cache": True }, "selection" : { "method" : "TOURNAMENT_SELECTION", "tournament_size": 2 }, "crossover" : { "method" : "POINT_CROSSOVER", "probability" : 0.6 }, "mutation" : { "methods": ["POINT_MUTATION"], "probability" : 0.8 }, "function_nodes" : [ {"type": "FUNCTION", "name": "ADD", "arity": 2}, {"type": "FUNCTION", "name": "SUB", "arity": 2} ], "terminal_nodes" : [ {"type": "CONSTANT", "value": 1.0}, ], "input_variables" : [ {"type": "INPUT", "name": "x"} ], "data_file" : "tests/data/sine.dat", "response_variables" : [{"name": "y"}], "recorder" : { "store_file": "json_store_test.json", "compress": True } } config.load_data(self.config) self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.json_store = JSONStore(self.config) self.json_store.setup_store() self.population = self.generator.init() results = [] cache = {} evaluate( self.population.individuals, self.functions, self.config, results, cache, self.json_store ) self.population.sort_individuals() self.selection = Selection(self.config, recorder=self.json_store) self.crossover = TreeCrossover(self.config, recorder=self.json_store) self.mutation = TreeMutation(self.config, recorder=self.json_store)
class JSONStoreTests(unittest.TestCase): def setUp(self): self.config = { "max_population": 10, "tree_generation": { "method": "FULL_METHOD", "initial_max_depth": 4 }, "evaluator": { "use_cache": True }, "selection": { "method": "TOURNAMENT_SELECTION", "tournament_size": 2 }, "crossover": { "method": "POINT_CROSSOVER", "probability": 0.6 }, "mutation": { "methods": ["POINT_MUTATION"], "probability": 0.8 }, "function_nodes": [{ "type": "FUNCTION", "name": "ADD", "arity": 2 }, { "type": "FUNCTION", "name": "SUB", "arity": 2 }], "terminal_nodes": [ { "type": "CONSTANT", "value": 1.0 }, ], "input_variables": [{ "type": "INPUT", "name": "x" }], "data_file": "tests/data/sine.dat", "response_variables": [{ "name": "y" }], "recorder": { "store_file": "json_store_test.json", "compress": True } } config.load_data(self.config) self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.json_store = JSONStore(self.config) self.json_store.setup_store() self.population = self.generator.init() results = [] cache = {} evaluate(self.population.individuals, self.functions, self.config, results, cache, self.json_store) self.population.sort_individuals() self.selection = Selection(self.config, recorder=self.json_store) self.crossover = TreeCrossover(self.config, recorder=self.json_store) self.mutation = TreeMutation(self.config, recorder=self.json_store) def tearDown(self): self.json_store.delete_store() del self.config del self.functions del self.generator del self.population del self.json_store def test_setup_store(self): # assert file_exists = os.path.exists(self.config["recorder"]["store_file"]) self.assertEquals(file_exists, True) def test_purge_store(self): # write something to store file self.json_store.store_file.write("Hello World\n") self.json_store.store_file.close() # purge store file self.json_store.purge_store() # assert store_file = open(self.config["recorder"]["store_file"], "r").read() self.assertEquals(len(store_file), 0) def test_delete_store(self): # delete store self.json_store.delete_store() # assert file_exists = os.path.exists(self.config["recorder"]["store_file"]) self.assertEquals(file_exists, False) def test_record_population(self): self.json_store.record_population(self.population) record = self.json_store.generation_record self.assertNotEquals(record, {}) self.assertEquals(record["population"]["generation"], 0) def test_record_selection(self): # record selection self.selection.select(self.population) # assert record = self.json_store.generation_record # import pprint # pprint.pprint(record) self.assertNotEquals(record, {}) self.assertEquals(record["selection"]["selected"], 10) def test_record_crossover(self): # record crossover tree_1 = self.population.individuals[0] tree_2 = self.population.individuals[1] self.crossover.crossover(tree_1, tree_2) # assert record = self.json_store.generation_record self.assertNotEquals(record, {}) def test_record_mutation(self): # record mutation tree = self.population.individuals[0] self.mutation.mutate(tree) # assert record = self.json_store.generation_record # pprint.pprint(record) self.assertNotEquals(record, {}) def test_record_evaulation(self): # record evaluation results = [] evaluate(self.population.individuals, self.functions, self.config, results, recorder=self.json_store) # assert record = self.json_store.generation_record # import pprint # pprint.pprint(record) self.assertEquals(record["evaluation"]["cache_size"], 10) self.assertEquals(record["evaluation"]["match_cached"], 0) def test_record_to_file(self): # write record to file and close self.json_store.record_population(self.population) self.json_store.record_to_file() self.json_store.store_file.close() # open up the file and restore json to dict store_file = open(self.config["recorder"]["store_file"], "r").read() data = json.loads(store_file) # assert tests self.assertNotEquals(data, {}) self.assertEquals(data["population"]["generation"], 0) def test_summarize_store(self): # write record to file and close self.json_store.setup_store() self.json_store.record_population(self.population) for i in range(5): tree_1 = self.population.individuals[0] tree_2 = self.population.individuals[1] self.crossover.crossover(tree_1, tree_2) for i in range(10): tree = self.population.individuals[0] self.mutation.mutate(tree) self.json_store.record_to_file() self.json_store.store_file.close() # summarize self.json_store.summarize_store() # assert store_file = open(self.config["recorder"]["store_file"], "r") line = json.loads(store_file.read()) store_file.close() self.assertIsNotNone(line) def test_finalize(self): # write record to file and close self.json_store.setup_store() self.json_store.record_population(self.population) self.json_store.record_to_file() self.json_store.store_file.close() # zip the store file self.json_store.finalize() # assert store_fp = self.config["recorder"]["store_file"] store_fp = list(os.path.splitext(store_fp)) # split ext store_fp[1] = ".zip" # change ext to zip store_fp = "".join(store_fp) file_exists = os.path.exists(store_fp) self.assertEquals(file_exists, True)
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 JSONStoreTests(unittest.TestCase): def setUp(self): self.config = { "max_population" : 10, "tree_generation" : { "method" : "FULL_METHOD", "initial_max_depth" : 4 }, "evaluator" : { "use_cache": True }, "selection" : { "method" : "TOURNAMENT_SELECTION", "tournament_size": 2 }, "crossover" : { "method" : "POINT_CROSSOVER", "probability" : 0.6 }, "mutation" : { "methods": ["POINT_MUTATION"], "probability" : 0.8 }, "function_nodes" : [ {"type": "FUNCTION", "name": "ADD", "arity": 2}, {"type": "FUNCTION", "name": "SUB", "arity": 2} ], "terminal_nodes" : [ {"type": "CONSTANT", "value": 1.0}, ], "input_variables" : [ {"type": "INPUT", "name": "x"} ], "data_file" : "tests/data/sine.dat", "response_variables" : [{"name": "y"}], "recorder" : { "store_file": "json_store_test.json", "compress": True } } config.load_data(self.config) self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.json_store = JSONStore(self.config) self.json_store.setup_store() self.population = self.generator.init() results = [] cache = {} evaluate( self.population.individuals, self.functions, self.config, results, cache, self.json_store ) self.population.sort_individuals() self.selection = Selection(self.config, recorder=self.json_store) self.crossover = TreeCrossover(self.config, recorder=self.json_store) self.mutation = TreeMutation(self.config, recorder=self.json_store) def tearDown(self): self.json_store.delete_store() del self.config del self.functions del self.generator del self.population del self.json_store def test_setup_store(self): # assert file_exists = os.path.exists(self.config["recorder"]["store_file"]) self.assertEquals(file_exists, True) def test_purge_store(self): # write something to store file self.json_store.store_file.write("Hello World\n") self.json_store.store_file.close() # purge store file self.json_store.purge_store() # assert store_file = open(self.config["recorder"]["store_file"], "r").read() self.assertEquals(len(store_file), 0) def test_delete_store(self): # delete store self.json_store.delete_store() # assert file_exists = os.path.exists(self.config["recorder"]["store_file"]) self.assertEquals(file_exists, False) def test_record_population(self): self.json_store.record_population(self.population) record = self.json_store.generation_record self.assertNotEquals(record, {}) self.assertEquals(record["population"]["generation"], 0) def test_record_selection(self): # record selection self.selection.select(self.population) # assert record = self.json_store.generation_record # import pprint # pprint.pprint(record) self.assertNotEquals(record, {}) self.assertEquals(record["selection"]["selected"], 10) def test_record_crossover(self): # record crossover tree_1 = self.population.individuals[0] tree_2 = self.population.individuals[1] self.crossover.crossover(tree_1, tree_2) # assert record = self.json_store.generation_record self.assertNotEquals(record, {}) def test_record_mutation(self): # record mutation tree = self.population.individuals[0] self.mutation.mutate(tree) # assert record = self.json_store.generation_record # pprint.pprint(record) self.assertNotEquals(record, {}) def test_record_evaulation(self): # record evaluation results = [] evaluate( self.population.individuals, self.functions, self.config, results, recorder=self.json_store ) # assert record = self.json_store.generation_record # import pprint # pprint.pprint(record) self.assertEquals(record["evaluation"]["cache_size"], 10) self.assertEquals(record["evaluation"]["match_cached"], 0) def test_record_to_file(self): # write record to file and close self.json_store.record_population(self.population) self.json_store.record_to_file() self.json_store.store_file.close() # open up the file and restore json to dict store_file = open(self.config["recorder"]["store_file"], "r").read() data = json.loads(store_file) # assert tests self.assertNotEquals(data, {}) self.assertEquals(data["population"]["generation"], 0) def test_summarize_store(self): # write record to file and close self.json_store.setup_store() self.json_store.record_population(self.population) for i in range(5): tree_1 = self.population.individuals[0] tree_2 = self.population.individuals[1] self.crossover.crossover(tree_1, tree_2) for i in range(10): tree = self.population.individuals[0] self.mutation.mutate(tree) self.json_store.record_to_file() self.json_store.store_file.close() # summarize self.json_store.summarize_store() # assert store_file = open(self.config["recorder"]["store_file"], "r") line = json.loads(store_file.read()) store_file.close() self.assertIsNotNone(line) def test_finalize(self): # write record to file and close self.json_store.setup_store() self.json_store.record_population(self.population) self.json_store.record_to_file() self.json_store.store_file.close() # zip the store file self.json_store.finalize() # assert store_fp = self.config["recorder"]["store_file"] store_fp = list(os.path.splitext(store_fp)) # split ext store_fp[1] = ".zip" # change ext to zip store_fp = "".join(store_fp) file_exists = os.path.exists(store_fp) self.assertEquals(file_exists, True)
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_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 gp_benchmark_loop(config): try: # setup random.seed(config["random_seed"]) # VERY IMPORTANT! load_data(config, config["call_path"]) json_store = JSONStore(config) # functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") generator = TreeGenerator(config) # genetic operators selection = Selection(config, recorder=json_store) crossover = TreeCrossover(config, recorder=json_store) mutation = TreeMutation(config, recorder=json_store) # setup the initial random population population = generator.init() # create play details details = play.play_details( population=population, functions=config["functions"], evaluate=evaluate, selection=selection, crossover=crossover, mutation=mutation, editor=edit_trees, stop_func=default_stop_func, # print_func=print_func, config=config, recorder=json_store) # run symbolic regression start_time = time.time() play.play(details) end_time = time.time() time_taken = end_time - start_time # print msg print("DONE -> pop: {0} cross: {1} mut: {2} seed: {3} [{4}s]".format( config["max_population"], config["crossover"]["probability"], config["mutation"]["probability"], config["random_seed"], round(time_taken, 2))) # log on completion if config.get("log_path", False): config.pop("data") msg = { "timestamp": time.mktime(datetime.now().timetuple()), "status": "DONE", "config": config, "runtime": time_taken, "best_score": population.find_best_individuals()[0].score, "best": str(population.find_best_individuals()[0]) } log_path = os.path.expandvars(config["log_path"]) log_file = open(log_path, "a+") log_file.write(json.dumps(msg) + "\n") log_file.close() except Exception as err_msg: import traceback traceback.print_exc() # log exception if config.get("log_path", False): msg = { "timestamp": time.mktime(datetime.now().timetuple()), "status": "ERROR", "config": config, "error": err_msg } log_path = os.path.expandvars(config["log_path"]) log_file = open(log_path, "a+") log_file.write(json.dumps(msg) + "\n") log_file.close() raise # raise the exception return config
def setUp(self): random.seed(0) self.config = { "max_population": 20, "max_generation": 5, "tree_generation": { "method": "GROW_METHOD", "initial_max_depth": 4 }, "evaluator": { "use_cache": True }, "selection": { "method": "TOURNAMENT_SELECTION", "tournament_size": 2 }, "crossover": { "method": "POINT_CROSSOVER", "probability": 0.8 }, "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": "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" }], "data_file": "tests/data/sine.dat", "response_variables": [{ "name": "y" }] } config.load_data(self.config) self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.selection = Selection(self.config, recorder=None) self.crossover = TreeCrossover(self.config, recorder=None) self.mutation = TreeMutation(self.config, recorder=None)
def gp_predict(train_data, test_data, train_cat, xx, yy): # setup config = { "max_population": 800, "max_generation": 30, "stale_limit": 10, "tree_generation": { "tree_type": "CLASSIFICATION_TREE", "method": "RAMPED_HALF_AND_HALF_METHOD", "depth_ranges": [{ "size": 1, "percentage": 1.0 }] }, "evaluator": { "use_cache": True }, "selection": { "method": "TOURNAMENT_SELECTION", "tournament_size": 100 }, "crossover": { "method": "POINT_CROSSOVER", "probability": 0.8 }, "mutation": { "methods": ["SUBTREE_MUTATION"], "probability": 0.8 }, "function_nodes": [{ "type": "CLASS_FUNCTION", "name": "GREATER_THAN", "arity": 2, "data_range": { "lower_bound": -1.0, "upper_bound": 1.0, "decimal_places": 2, } }, { "type": "CLASS_FUNCTION", "name": "LESS_THAN", "arity": 2, "data_range": { "lower_bound": -1.0, "upper_bound": 1.0, "decimal_places": 2, } }, { "type": "CLASS_FUNCTION", "name": "EQUALS", "arity": 2, "data_range": { "lower_bound": -1.0, "upper_bound": 1.0, "decimal_places": 2 } }], "terminal_nodes": [ { "type": "RANDOM_CONSTANT", "name": "category", "range": [0.0, 1.0] }, ], "class_attributes": ["x", "y"], "input_variables": [{ "name": "x" }, { "name": "y" }], "response_variables": [{ "name": "category" }] } # load data config["data"] = {} config["data"]["rows"] = len(train_data) config["data"]["x"] = [] config["data"]["y"] = [] config["data"]["category"] = train_cat for row in train_data: config["data"]["x"].append(row[0]) config["data"]["y"].append(row[1]) functions = GPFunctionRegistry("CLASSIFICATION") generator = TreeGenerator(config) # genetic operators selection = Selection(config) crossover = TreeCrossover(config) mutation = TreeMutation(config) # run symbolic regression population = generator.init() details = play.play_details( population=population, evaluate=evaluate, functions=functions, selection=selection, crossover=crossover, mutation=mutation, print_func=print_func, stop_func=default_stop_func, config=config, editor=edit_trees, ) play.play(details) best_tree = population.best_individuals[0] # gp_plot_dt(best_tree, True) # load test data config["data"] = {} config["data"]["rows"] = len(test_data) config["data"]["x"] = [] config["data"]["y"] = [] for row in test_data: config["data"]["x"].append(row[0]) config["data"]["y"].append(row[1]) # predict predicted = gp_eval.predict_tree(best_tree, functions, config) # load test data config["data"] = {} config["data"]["rows"] = xx.shape[0] * xx.shape[1] config["data"]["x"] = np.reshape(xx, xx.shape[0] * xx.shape[1]) config["data"]["y"] = np.reshape(yy, yy.shape[0] * yy.shape[1]) contour = gp_eval.predict_tree(best_tree, functions, config) contour = np.array(contour) contour = contour.reshape(xx.shape) return predicted, contour