def test_generate_func_node(self): # SYMBOLIC REGRESSION TREES for i in range(100): node = self.generator.generate_func_node() self.assertEquals(node.node_type, NodeType.FUNCTION) # CLASSIFICATION TREES self.config["tree_generation"]["tree_type"] = "CLASSIFICATION_TREE" self.config["function_nodes"] = [ { "type": "CLASS_FUNCTION", "name": "GREATER_THAN", "arity": 2, "data_range": { "lower_bound": 0.0, "upper_bound": 10.0, "decimal_places": 1 } } ] self.config["class_attributes"] = [ "attrubte_1", "attrubte_2", "attrubte_3" ] generator = TreeGenerator(self.config) for i in range(100): node = generator.generate_func_node() class_attribute = node.class_attribute self.assertEquals(node.node_type, NodeType.CLASS_FUNCTION) self.assertTrue(class_attribute in self.config["class_attributes"])
def test_generate_func_node(self): # SYMBOLIC REGRESSION TREES for i in range(100): node = self.generator.generate_func_node() self.assertEquals(node.node_type, NodeType.FUNCTION) # CLASSIFICATION TREES self.config["tree_generation"]["tree_type"] = "CLASSIFICATION_TREE" self.config["function_nodes"] = [{ "type": "CLASS_FUNCTION", "name": "GREATER_THAN", "arity": 2, "data_range": { "lower_bound": 0.0, "upper_bound": 10.0, "decimal_places": 1 } }] self.config["class_attributes"] = [ "attrubte_1", "attrubte_2", "attrubte_3" ] generator = TreeGenerator(self.config) for i in range(100): node = generator.generate_func_node() class_attribute = node.class_attribute self.assertEquals(node.node_type, NodeType.CLASS_FUNCTION) self.assertTrue(class_attribute in self.config["class_attributes"])
def evaluate_trees(): results = [] response = {} # parse incomming data if request.data is not None: incomming = json.loads(request.data) config = incomming["config"] individuals = incomming["individuals"] # convert dict to trees parser = TreeGenerator(config) for individual in list(individuals): tree = parser.generate_tree_from_dict(individual) individuals.append(tree) individuals.remove(individual) evaluate(individuals, functions, config, results) # jsonify results response["results"] = [] for individual in results: result = { "id": individual.tree_id, "score": individual.score, } response["results"].append(result) else: response = {"status": PlayNodeStatus.ERROR} return jsonify(response)
def __init__(self, config, **kwargs): self.config = config self.recorder = kwargs.get("recorder", None) self.generator = TreeGenerator(self.config) # mutation stats self.method = None self.index = None self.mutation_probability = None self.random_probability = None self.mutated = False self.before_mutation = None self.after_mutation = None
def test_greedy_over_selection(self): print "GREEDY-OVER SELECTION" # create population of size 1000 self.config["max_population"] = 1000 generator = TreeGenerator(self.config) population = generator.init() # greedy over selection old_pop_size = self.print_population("OLD", population) self.selection.greedy_over_selection(population) new_pop_size = self.print_population("NEW", population) self.assertEquals(old_pop_size, new_pop_size)
def setUp(self): self.config = { "max_population" : 10, "tree_generation" : { "method" : "FULL_METHOD", "initial_max_depth" : 3 }, "selection" : { "method" : "ROULETTE_SELECTION" }, "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.selection = Selection(self.config) self.population = self.generator.init() # give population random scores for inidividual in self.population.individuals: inidividual.score = random.triangular(1, 100)
def setUp(self): self.config = { "max_population": 50, "tree_generation": { "method": "FULL_METHOD", "initial_max_depth": 4 }, "evaluator": { "use_cache": True }, "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}, ], "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)
def setUp(self): self.config = { "max_population": 50, "tree_generation": { "method": "FULL_METHOD", "initial_max_depth": 4 }, "evaluator": { "use_cache": True }, "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}, ], "input_variables": [ {"type": "INPUT", "name": "x"} ], "data_file": "tests/data/sine.dat", "response_variables": [{"name": "y"}] } config.load_data(self.config) self.functions = { "ADD": "+", "SUB": "-", "MUL": "*", "DIV": "/", "POW": "**", "SIN": "math.sin", "COS": "math.cos", "RAD": "math.radians", "LN": "math.ln", "LOG": "math.log" } self.generator = TreeGenerator(self.config)
def setUp(self): self.config = { "max_population": 10, "tree_generation": { "tree_type": "SYMBOLIC_REGRESSION", "method": "RAMPED_HALF_AND_HALF_METHOD", "initial_max_depth": 3 }, "function_nodes": [ {"type": "FUNCTION", "arity": 2, "name": "ADD"}, {"type": "FUNCTION", "arity": 2, "name": "SUB"}, {"type": "FUNCTION", "arity": 2, "name": "MUL"}, {"type": "FUNCTION", "arity": 2, "name": "DIV"}, {"type": "FUNCTION", "arity": 1, "name": "COS"}, {"type": "FUNCTION", "arity": 1, "name": "SIN"} ], "terminal_nodes": [ {"type": "CONSTANT", "value": 1.0}, {"type": "INPUT", "name": "x"}, {"type": "INPUT", "name": "y"}, { "type": "RANDOM_CONSTANT", "data_range": { "upper_bound": 10.0, "lower_bound": -10.0, "decimal_places": 1 } } ], "input_variables": [ {"name": "x"}, {"name": "y"} ] } self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.parser = TreeParser()
def setUp(self): self.config = { "max_population": 5, "tree_generation": { "tree_type": "CLASSIFICATION_TREE", "method": "FULL_METHOD", "initial_max_depth": 2 }, "evaluator": { "use_cache": True }, "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, "data_range": { "lower_bound": 0.0, "upper_bound": 10.0, "decimal_places": 0, } }], "terminal_nodes": [ { "type": "RANDOM_CONSTANT", "name": "species", "range": [1.0, 2.0, 3.0] }, ], "input_variables": [{ "name": "sepal_length" }, { "name": "sepal_width" }, { "name": "petal_length" }, { "name": "petal_width" }], "class_attributes": ["sepal_length", "sepal_width", "petal_length", "petal_width"], "data_file": "tests/data/iris.dat", "response_variables": [{ "name": "species" }] } config.load_data(self.config) self.functions = GPFunctionRegistry("CLASSIFICATION") self.generator = TreeGenerator(self.config) self.population = self.generator.init()
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
class TreeMutation(object): def __init__(self, config, **kwargs): self.config = config self.recorder = kwargs.get("recorder", None) self.generator = TreeGenerator(self.config) # mutation stats self.method = None self.index = None self.mutation_probability = None self.random_probability = None self.mutated = False self.before_mutation = None self.after_mutation = None def generate_new_node(self, details): if details is None: return None elif details["type"] == NodeType.FUNCTION: return Node( NodeType.FUNCTION, name=details["name"], arity=details["arity"], branches=[] ) elif details["type"] == NodeType.CLASS_FUNCTION: return Node( NodeType.CLASS_FUNCTION, name=details["name"], arity=details["arity"], branches=[] ) elif details["type"] == NodeType.INPUT: return Node( NodeType.INPUT, name=details["name"] ) elif details["type"] == NodeType.CONSTANT: return Node( NodeType.CONSTANT, name=details.get("name", None), value=details["value"] ) elif details["type"] == NodeType.RANDOM_CONSTANT: resolved_details = self.generator.resolve_random_constant(details) return Node( NodeType.CONSTANT, name=resolved_details.get("name", None), value=resolved_details["value"] ) def mutate_new_node_details(self, old_node): # determine what kind of old_node it is node_pool = [] if old_node.is_function() or old_node.is_class_function(): tmp = list(self.config["function_nodes"]) tmp = [n for n in tmp if n["arity"] == old_node.arity] node_pool.extend(tmp) elif old_node.is_terminal(): node_pool.extend(self.config["terminal_nodes"]) # check the node and return retry = 0 retry_limit = 100 while True: if retry == retry_limit: return None else: retry += 1 n_details = sample(node_pool, 1)[0] if n_details["type"] == NodeType.RANDOM_CONSTANT: n_details = self.generator.resolve_random_constant(n_details) elif n_details["type"] == NodeType.CLASS_FUNCTION: n_details = self.generator.resolve_class_function(n_details) new_node = self.generate_new_node(n_details) if old_node.equals(new_node) is False: return n_details def point_mutation(self, tree, mutation_index=None): # mutate node self.index = randint(0, len(tree.program) - 1) node = tree.program[self.index] new_node = self.mutate_new_node_details(node) if new_node is None: return elif node.is_function(): node.name = new_node["name"] elif node.is_terminal(): node.node_type = new_node.get("type") node.name = new_node.get("name", None) node.value = new_node.get("value", None) tree.update() self.mutated = True def hoist_mutation(self, tree, mutation_index=None): # new indivdiaul generated from subtree node = None if mutation_index is None: self.index = randint(0, len(tree.program) - 2) node = tree.program[self.index] else: self.index = mutation_index node = tree.program[mutation_index] tree.root = node tree.update() self.mutated = True def subtree_mutation(self, tree, mutation_index=None): # subtree exchanged against external random subtree node = None if mutation_index is None: self.index = randint(0, len(tree.program) - 1) node = tree.program[self.index] else: self.index = mutation_index node = tree.program[mutation_index] self.generator.max_depth = randint(1, 3) sub_tree = self.generator.generate_tree() if node is not tree.root: tree.replace_node(node, sub_tree.root) else: tree.root = sub_tree.root tree.update() self.mutated = True def shrink_mutation(self, tree, mutation_index=None): # replace subtree with terminal if len(tree.func_nodes): node = None if mutation_index is None: self.index = randint(0, len(tree.func_nodes) - 1) node = tree.func_nodes[self.index] while node is tree.root: self.index = randint(0, len(tree.func_nodes) - 1) node = tree.func_nodes[self.index] else: self.index = mutation_index node = tree.program[mutation_index] candidate_nodes = tree.term_nodes candidate_nodes.extend(tree.input_nodes) new_node_detail = sample(candidate_nodes, 1)[0] node_details = self.mutate_new_node_details(new_node_detail) new_node = self.generate_new_node(node_details) if new_node: tree.replace_node(node, new_node) tree.update() self.mutated = True def expansion_mutation(self, tree, mutation_index=None): # terminal exchanged against external random subtree node = None if mutation_index is None: prob = random() if tree.size == 1: return elif prob > 0.5 and len(tree.term_nodes) > 0: self.index = randint(0, len(tree.term_nodes) - 1) node = tree.term_nodes[self.index] elif prob < 0.5 and len(tree.input_nodes) > 0: self.index = randint(0, len(tree.input_nodes) - 1) node = tree.input_nodes[self.index] elif len(tree.term_nodes) > 0: self.index = randint(0, len(tree.term_nodes) - 1) node = tree.term_nodes[self.index] elif len(tree.input_nodes) > 0: self.index = randint(0, len(tree.input_nodes) - 1) node = tree.input_nodes[self.index] else: self.index = mutation_index node = tree.program[mutation_index] sub_tree = self.generator.generate_tree() tree.replace_node(node, sub_tree.root) tree.update() self.mutated = True def mutate(self, tree): mutation_methods = { "POINT_MUTATION": self.point_mutation, "HOIST_MUTATION": self.hoist_mutation, "SUBTREE_MUTATION": self.subtree_mutation, "SHRINK_MUTATION": self.shrink_mutation, "EXPAND_MUTATION": self.expansion_mutation } self.method = sample(self.config["mutation"]["methods"], 1)[0] self.index = None self.mutation_probability = self.config["mutation"]["probability"] self.random_probability = random() self.mutated = False self.before_mutation = None self.after_mutation = None # record before mutation self.before_mutation = tree.to_dict()["program"] # mutate if self.mutation_probability >= self.random_probability: mutation_func = mutation_methods[self.method] mutation_func(tree) # record after mutation self.after_mutation = tree.to_dict()["program"] # record if self.recorder is not None: self.recorder.record(RecordType.MUTATION, self) def to_dict(self): self_dict = { "method": self.method, "mutation_index": self.index, "mutation_probability": self.mutation_probability, "random_probability": self.random_probability, "mutated": self.mutated, "before_mutation": self.before_mutation, "after_mutation": self.after_mutation } return self_dict
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 setUp(self): self.config = { "max_population": 5, "tree_generation": { "tree_type": "CLASSIFICATION_TREE", "method": "FULL_METHOD", "initial_max_depth": 2 }, "evaluator": { "use_cache": True }, "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, "data_range": { "lower_bound": 0.0, "upper_bound": 10.0, "decimal_places": 0, } } ], "terminal_nodes": [ { "type": "RANDOM_CONSTANT", "name": "species", "range": [ 1.0, 2.0, 3.0 ] }, ], "input_variables": [ {"name": "sepal_length"}, {"name": "sepal_width"}, {"name": "petal_length"}, {"name": "petal_width"} ], "class_attributes": [ "sepal_length", "sepal_width", "petal_length", "petal_width" ], "data_file": "tests/data/iris.dat", "response_variables": [{"name": "species"}] } config.load_data(self.config) self.functions = GPFunctionRegistry("CLASSIFICATION") self.generator = TreeGenerator(self.config) self.population = self.generator.init()
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)
class TreeGeneratorTests(unittest.TestCase): def setUp(self): self.config = { "max_population": 10, "tree_generation": { "tree_type": "SYMBOLIC_REGRESSION", "method": "RAMPED_HALF_AND_HALF_METHOD", "initial_max_depth": 3 }, "function_nodes": [{ "type": "FUNCTION", "arity": 2, "name": "ADD" }, { "type": "FUNCTION", "arity": 2, "name": "SUB" }, { "type": "FUNCTION", "arity": 2, "name": "MUL" }, { "type": "FUNCTION", "arity": 2, "name": "DIV" }, { "type": "FUNCTION", "arity": 1, "name": "COS" }, { "type": "FUNCTION", "arity": 1, "name": "SIN" }], "terminal_nodes": [{ "type": "CONSTANT", "value": 1.0 }, { "type": "INPUT", "name": "x" }, { "type": "INPUT", "name": "y" }, { "type": "RANDOM_CONSTANT", "data_range": { "upper_bound": 10.0, "lower_bound": -10.0, "decimal_places": 1 } }], "input_variables": [{ "name": "x" }, { "name": "y" }] } self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.parser = TreeParser() def tearDown(self): del self.config del self.generator del self.parser def test_generate_func_node(self): # SYMBOLIC REGRESSION TREES for i in range(100): node = self.generator.generate_func_node() self.assertEquals(node.node_type, NodeType.FUNCTION) # CLASSIFICATION TREES self.config["tree_generation"]["tree_type"] = "CLASSIFICATION_TREE" self.config["function_nodes"] = [{ "type": "CLASS_FUNCTION", "name": "GREATER_THAN", "arity": 2, "data_range": { "lower_bound": 0.0, "upper_bound": 10.0, "decimal_places": 1 } }] self.config["class_attributes"] = [ "attrubte_1", "attrubte_2", "attrubte_3" ] generator = TreeGenerator(self.config) for i in range(100): node = generator.generate_func_node() class_attribute = node.class_attribute self.assertEquals(node.node_type, NodeType.CLASS_FUNCTION) self.assertTrue(class_attribute in self.config["class_attributes"]) def test_resolve_random_constant(self): upper_bound = 10.0 lower_bound = -10.0 decimal_places = 0 for i in range(100): n_details = { "type": "RANDOM_CONSTANT", "data_range": { "lower_bound": lower_bound, "upper_bound": upper_bound, "decimal_places": decimal_places } } new_n_details = self.generator.resolve_random_constant(n_details) node_type = new_n_details["type"] node_value = new_n_details["value"] self.assertEquals(node_type, "CONSTANT") self.assertTrue(upper_bound >= node_value) self.assertTrue(lower_bound <= node_value) self.assertEquals(node_value, int(node_value)) upper_bound = 100.0 lower_bound = -100.0 decimal_places = 1 for i in range(100): n_details = { "type": "RANDOM_CONSTANT", "data_range": { "lower_bound": lower_bound, "upper_bound": upper_bound, "decimal_places": decimal_places } } new_n_details = self.generator.resolve_random_constant(n_details) node_type = new_n_details["type"] node_value = new_n_details["value"] self.assertEquals(node_type, "CONSTANT") self.assertTrue(upper_bound >= node_value) self.assertTrue(lower_bound <= node_value) node_value = decimal.Decimal(str(node_value)) node_decimal_places = abs(node_value.as_tuple().exponent) self.assertEquals(decimal_places, node_decimal_places) def test_generate_term_node(self): for i in range(100): node = self.generator.generate_term_node() self.assertTrue(node.node_type == NodeType.CONSTANT or NodeType.INPUT) def test_full_method(self): tests = 1 for i in xrange(tests): tree = self.generator.full_method() # asserts init_max = self.config["tree_generation"]["initial_max_depth"] self.assertEquals(tree.depth, init_max) self.assertTrue(tree.size > init_max) def test_grow_method(self): tests = 1000 for i in xrange(tests): tree = self.generator.grow_method() # asserts init_max = self.config["tree_generation"]["initial_max_depth"] self.assertEquals(tree.depth, init_max) self.assertTrue(tree.size > init_max) def test_generate_tree_from_dict(self): population = self.generator.init() tree = population.individuals[0] tree_dict = self.parser.tree_to_dict(tree, tree.root) tree_generated = self.generator.generate_tree_from_dict(tree_dict) program_str = "" for i in tree.program: if i.name is not None: program_str += i.name else: program_str += str(i.value) generated_str = "" for i in tree_generated.program: if i.name is not None: generated_str += i.name else: generated_str += str(i.value) self.assertEquals(program_str, generated_str) def test_init(self): population = self.generator.init() self.assertEquals(len(population.individuals), 10)
class TreeMutation(object): def __init__(self, config, **kwargs): self.config = config self.recorder = kwargs.get("recorder", None) self.generator = TreeGenerator(self.config) # mutation stats self.method = None self.index = None self.mutation_probability = None self.random_probability = None self.mutated = False self.before_mutation = None self.after_mutation = None def generate_new_node(self, details): if details is None: return None elif details["type"] == NodeType.FUNCTION: return Node(NodeType.FUNCTION, name=details["name"], arity=details["arity"], branches=[]) elif details["type"] == NodeType.CLASS_FUNCTION: return Node(NodeType.CLASS_FUNCTION, name=details["name"], arity=details["arity"], branches=[]) elif details["type"] == NodeType.INPUT: return Node(NodeType.INPUT, name=details["name"]) elif details["type"] == NodeType.CONSTANT: return Node(NodeType.CONSTANT, name=details.get("name", None), value=details["value"]) elif details["type"] == NodeType.RANDOM_CONSTANT: resolved_details = self.generator.resolve_random_constant(details) return Node(NodeType.CONSTANT, name=resolved_details.get("name", None), value=resolved_details["value"]) def mutate_new_node_details(self, old_node): # determine what kind of old_node it is node_pool = [] if old_node.is_function() or old_node.is_class_function(): tmp = list(self.config["function_nodes"]) tmp = [n for n in tmp if n["arity"] == old_node.arity] node_pool.extend(tmp) elif old_node.is_terminal(): node_pool.extend(self.config["terminal_nodes"]) # check the node and return retry = 0 retry_limit = 100 while True: if retry == retry_limit: return None else: retry += 1 n_details = sample(node_pool, 1)[0] if n_details["type"] == NodeType.RANDOM_CONSTANT: n_details = self.generator.resolve_random_constant(n_details) elif n_details["type"] == NodeType.CLASS_FUNCTION: n_details = self.generator.resolve_class_function(n_details) new_node = self.generate_new_node(n_details) if old_node.equals(new_node) is False: return n_details def point_mutation(self, tree, mutation_index=None): # mutate node self.index = randint(0, len(tree.program) - 1) node = tree.program[self.index] new_node = self.mutate_new_node_details(node) if new_node is None: return elif node.is_function(): node.name = new_node["name"] elif node.is_terminal(): node.node_type = new_node.get("type") node.name = new_node.get("name", None) node.value = new_node.get("value", None) tree.update() self.mutated = True def hoist_mutation(self, tree, mutation_index=None): # new indivdiaul generated from subtree node = None if mutation_index is None: self.index = randint(0, len(tree.program) - 2) node = tree.program[self.index] else: self.index = mutation_index node = tree.program[mutation_index] tree.root = node tree.update() self.mutated = True def subtree_mutation(self, tree, mutation_index=None): # subtree exchanged against external random subtree node = None if mutation_index is None: self.index = randint(0, len(tree.program) - 1) node = tree.program[self.index] else: self.index = mutation_index node = tree.program[mutation_index] self.generator.max_depth = randint(1, 3) sub_tree = self.generator.generate_tree() if node is not tree.root: tree.replace_node(node, sub_tree.root) else: tree.root = sub_tree.root tree.update() self.mutated = True def shrink_mutation(self, tree, mutation_index=None): # replace subtree with terminal if len(tree.func_nodes): node = None if mutation_index is None: self.index = randint(0, len(tree.func_nodes) - 1) node = tree.func_nodes[self.index] while node is tree.root: self.index = randint(0, len(tree.func_nodes) - 1) node = tree.func_nodes[self.index] else: self.index = mutation_index node = tree.program[mutation_index] candidate_nodes = tree.term_nodes candidate_nodes.extend(tree.input_nodes) new_node_detail = sample(candidate_nodes, 1)[0] node_details = self.mutate_new_node_details(new_node_detail) new_node = self.generate_new_node(node_details) if new_node: tree.replace_node(node, new_node) tree.update() self.mutated = True def expansion_mutation(self, tree, mutation_index=None): # terminal exchanged against external random subtree node = None if mutation_index is None: prob = random() if tree.size == 1: return elif prob > 0.5 and len(tree.term_nodes) > 0: self.index = randint(0, len(tree.term_nodes) - 1) node = tree.term_nodes[self.index] elif prob < 0.5 and len(tree.input_nodes) > 0: self.index = randint(0, len(tree.input_nodes) - 1) node = tree.input_nodes[self.index] elif len(tree.term_nodes) > 0: self.index = randint(0, len(tree.term_nodes) - 1) node = tree.term_nodes[self.index] elif len(tree.input_nodes) > 0: self.index = randint(0, len(tree.input_nodes) - 1) node = tree.input_nodes[self.index] else: self.index = mutation_index node = tree.program[mutation_index] sub_tree = self.generator.generate_tree() tree.replace_node(node, sub_tree.root) tree.update() self.mutated = True def mutate(self, tree): mutation_methods = { "POINT_MUTATION": self.point_mutation, "HOIST_MUTATION": self.hoist_mutation, "SUBTREE_MUTATION": self.subtree_mutation, "SHRINK_MUTATION": self.shrink_mutation, "EXPAND_MUTATION": self.expansion_mutation } self.method = sample(self.config["mutation"]["methods"], 1)[0] self.index = None self.mutation_probability = self.config["mutation"]["probability"] self.random_probability = random() self.mutated = False self.before_mutation = None self.after_mutation = None # record before mutation self.before_mutation = tree.to_dict()["program"] # mutate if self.mutation_probability >= self.random_probability: mutation_func = mutation_methods[self.method] mutation_func(tree) # record after mutation self.after_mutation = tree.to_dict()["program"] # record if self.recorder is not None: self.recorder.record(RecordType.MUTATION, self) def to_dict(self): self_dict = { "method": self.method, "mutation_index": self.index, "mutation_probability": self.mutation_probability, "random_probability": self.random_probability, "mutated": self.mutated, "before_mutation": self.before_mutation, "after_mutation": self.after_mutation } return self_dict
class PlayTests(unittest.TestCase): 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 tearDown(self): del self.config del self.generator del self.selection del self.crossover del self.mutation def test_reproduce(self): tests = 1 for i in range(tests): population = self.generator.init() res = [] evaluate(population.individuals, self.functions, self.config, res) population.individuals = res # print "POPULATION" # for i in population.individuals: # print i, i.score # print "\n" self.selection.select(population) # print "SELECTION" # for i in population.individuals: # print i, i.score # print "\n" # reproduce play_details = play.play_details(population=population, selection=self.selection, crossover=self.crossover, mutation=self.mutation, evaluate=None, config=self.config) play.play_ga_reproduce(play_details) # print "REPRODUCE" # for i in population.individuals: # print i, i.score # assert max_pop = self.config["max_population"] self.assertEquals(len(population.individuals), max_pop) self.assertTrue(population.config is self.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)
class SelectionTests(unittest.TestCase): def setUp(self): self.config = { "max_population" : 10, "tree_generation" : { "method" : "FULL_METHOD", "initial_max_depth" : 3 }, "selection" : { "method" : "ROULETTE_SELECTION" }, "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.selection = Selection(self.config) self.population = self.generator.init() # give population random scores for inidividual in self.population.individuals: inidividual.score = random.triangular(1, 100) def print_population(self, phase, population): print "{0}[{1}]:".format(phase, len(population.individuals)) for individual in population.individuals: print individual, individual.score print '\n\n' return len(population.individuals) def test_normalize_scores(self): self.selection._normalize_scores(self.population) total_sum = 0 for individual in self.population.individuals: total_sum += individual.score self.assertEquals(round(total_sum, 2), 1.0) def test_roulette_selection(self): print "ROULETTE SELECTION" old_pop_size = len(self.population.individuals) self.selection.roulette_wheel_selection(self.population) new_pop_size = len(self.population.individuals) # assert # check for object uniqueness individual_ids = [] for i in self.population.individuals: self.assertFalse(id(i) in individual_ids) individual_ids.append(id(i)) self.assertEquals(new_pop_size, old_pop_size) def test_tournament_selection(self): print "TOURNAMENT SELECTION" # tournament selection old_pop_size = self.print_population("OLD", self.population) self.selection.tournament_selection(self.population) new_pop_size = self.print_population("NEW", self.population) # assert # check for object uniqueness individual_ids = [] for i in self.population.individuals: self.assertFalse(id(i) in individual_ids) individual_ids.append(id(i)) self.assertEqual(old_pop_size, new_pop_size) def test_elitest_selection(self): print "ELITEST SELECTION" # elitest selection old_pop_size = self.print_population("OLD", self.population) self.selection.elitest_selection(self.population) new_pop_size = self.print_population("NEW", self.population) self.assertEquals(old_pop_size, new_pop_size) def test_greedy_over_selection(self): print "GREEDY-OVER SELECTION" # create population of size 1000 self.config["max_population"] = 1000 generator = TreeGenerator(self.config) population = generator.init() # greedy over selection old_pop_size = self.print_population("OLD", population) self.selection.greedy_over_selection(population) new_pop_size = self.print_population("NEW", population) self.assertEquals(old_pop_size, new_pop_size) def test_select(self): old_pop_size = len(self.population.individuals) self.selection.select(self.population) new_pop_size = len(self.population.individuals) # assert # check for object uniqueness individual_ids = [] for i in self.population.individuals: self.assertFalse(id(i) in individual_ids) individual_ids.append(id(i)) self.assertEquals(old_pop_size, new_pop_size)
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 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 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
def setUp(self): self.config = { "max_population": 50, "tree_generation": { "method": "FULL_METHOD", "initial_max_depth": 4 }, "evaluator": { "use_cache": True }, "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 }, ], "input_variables": [{ "type": "INPUT", "name": "x" }], "data_file": "tests/data/sine.dat", "response_variables": [{ "name": "y" }] } config.load_data(self.config) self.functions = { "ADD": "+", "SUB": "-", "MUL": "*", "DIV": "/", "POW": "**", "SIN": "math.sin", "COS": "math.cos", "RAD": "math.radians", "LN": "math.ln", "LOG": "math.log" } self.generator = TreeGenerator(self.config)
def setUp(self): self.config = { "max_population": 10, "tree_generation": { "tree_type": "SYMBOLIC_REGRESSION", "method": "RAMPED_HALF_AND_HALF_METHOD", "initial_max_depth": 3 }, "function_nodes": [{ "type": "FUNCTION", "arity": 2, "name": "ADD" }, { "type": "FUNCTION", "arity": 2, "name": "SUB" }, { "type": "FUNCTION", "arity": 2, "name": "MUL" }, { "type": "FUNCTION", "arity": 2, "name": "DIV" }, { "type": "FUNCTION", "arity": 1, "name": "COS" }, { "type": "FUNCTION", "arity": 1, "name": "SIN" }], "terminal_nodes": [{ "type": "CONSTANT", "value": 1.0 }, { "type": "INPUT", "name": "x" }, { "type": "INPUT", "name": "y" }, { "type": "RANDOM_CONSTANT", "data_range": { "upper_bound": 10.0, "lower_bound": -10.0, "decimal_places": 1 } }], "input_variables": [{ "name": "x" }, { "name": "y" }] } self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.parser = TreeParser()
class TreeEvaluatorTests(unittest.TestCase): def setUp(self): self.config = { "max_population": 50, "tree_generation": { "method": "FULL_METHOD", "initial_max_depth": 4 }, "evaluator": { "use_cache": True }, "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}, ], "input_variables": [ {"type": "INPUT", "name": "x"} ], "data_file": "tests/data/sine.dat", "response_variables": [{"name": "y"}] } config.load_data(self.config) self.functions = { "ADD": "+", "SUB": "-", "MUL": "*", "DIV": "/", "POW": "**", "SIN": "math.sin", "COS": "math.cos", "RAD": "math.radians", "LN": "math.ln", "LOG": "math.log" } self.generator = TreeGenerator(self.config) def tearDown(self): del self.config del self.generator 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_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_evaluate(self): population = self.generator.init() results = [] start_time = time.time() evaluator.evaluate( population.individuals, self.functions, self.config, results ) end_time = time.time() print("GP run took: %2.2fsecs\n" % (end_time - start_time)) population.individuals = results # assert for individual in population.individuals: self.assertTrue(individual.score is not None) self.assertTrue(individual.score > 0)
class ClassifierEvaluationTests(unittest.TestCase): def setUp(self): self.config = { "max_population": 5, "tree_generation": { "tree_type": "CLASSIFICATION_TREE", "method": "FULL_METHOD", "initial_max_depth": 2 }, "evaluator": { "use_cache": True }, "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, "data_range": { "lower_bound": 0.0, "upper_bound": 10.0, "decimal_places": 0, } } ], "terminal_nodes": [ { "type": "RANDOM_CONSTANT", "name": "species", "range": [ 1.0, 2.0, 3.0 ] }, ], "input_variables": [ {"name": "sepal_length"}, {"name": "sepal_width"}, {"name": "petal_length"}, {"name": "petal_width"} ], "class_attributes": [ "sepal_length", "sepal_width", "petal_length", "petal_width" ], "data_file": "tests/data/iris.dat", "response_variables": [{"name": "species"}] } config.load_data(self.config) self.functions = GPFunctionRegistry("CLASSIFICATION") self.generator = TreeGenerator(self.config) self.population = self.generator.init() def test_evaluate_tree(self): for i in range(100): tree = self.generator.generate_tree() score, output = evaluate_tree(tree, self.functions, self.config) # self.assertTrue(score < 1.0) self.assertEquals(len(output), self.config["data"]["rows"]) def test_evaluate(self): results = [] evaluate(self.population.individuals, self.functions, self.config, results) self.assertTrue(len(results), len(self.population.individuals))
"petal_length", "petal_width" ], "data_file": "data/iris.dat", "input_variables": [ {"name": "sepal_length"}, {"name": "sepal_width"}, {"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,
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 = { "max_population": 10, "tree_generation": { "method": "FULL_METHOD", "initial_max_depth": 3 }, "selection": { "method": "ROULETTE_SELECTION" }, "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.selection = Selection(self.config) self.population = self.generator.init() # give population random scores for inidividual in self.population.individuals: inidividual.score = random.triangular(1, 100)
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 ClassifierEvaluationTests(unittest.TestCase): def setUp(self): self.config = { "max_population": 5, "tree_generation": { "tree_type": "CLASSIFICATION_TREE", "method": "FULL_METHOD", "initial_max_depth": 2 }, "evaluator": { "use_cache": True }, "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, "data_range": { "lower_bound": 0.0, "upper_bound": 10.0, "decimal_places": 0, } }], "terminal_nodes": [ { "type": "RANDOM_CONSTANT", "name": "species", "range": [1.0, 2.0, 3.0] }, ], "input_variables": [{ "name": "sepal_length" }, { "name": "sepal_width" }, { "name": "petal_length" }, { "name": "petal_width" }], "class_attributes": ["sepal_length", "sepal_width", "petal_length", "petal_width"], "data_file": "tests/data/iris.dat", "response_variables": [{ "name": "species" }] } config.load_data(self.config) self.functions = GPFunctionRegistry("CLASSIFICATION") self.generator = TreeGenerator(self.config) self.population = self.generator.init() def test_evaluate_tree(self): for i in range(100): tree = self.generator.generate_tree() score, output = evaluate_tree(tree, self.functions, self.config) # self.assertTrue(score < 1.0) self.assertEquals(len(output), self.config["data"]["rows"]) def test_evaluate(self): results = [] evaluate(self.population.individuals, self.functions, self.config, results) self.assertTrue(len(results), len(self.population.individuals))
class PlayTests(unittest.TestCase): 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 tearDown(self): del self.config del self.generator del self.selection del self.crossover del self.mutation def test_reproduce(self): tests = 1 for i in range(tests): population = self.generator.init() res = [] evaluate(population.individuals, self.functions, self.config, res) population.individuals = res # print "POPULATION" # for i in population.individuals: # print i, i.score # print "\n" self.selection.select(population) # print "SELECTION" # for i in population.individuals: # print i, i.score # print "\n" # reproduce play_details = play.play_details( population=population, selection=self.selection, crossover=self.crossover, mutation=self.mutation, evaluate=None, config=self.config ) play.play_ga_reproduce(play_details) # print "REPRODUCE" # for i in population.individuals: # print i, i.score # assert max_pop = self.config["max_population"] self.assertEquals(len(population.individuals), max_pop) self.assertTrue(population.config is self.config)
class TreeEvaluatorTests(unittest.TestCase): def setUp(self): self.config = { "max_population": 50, "tree_generation": { "method": "FULL_METHOD", "initial_max_depth": 4 }, "evaluator": { "use_cache": True }, "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 }, ], "input_variables": [{ "type": "INPUT", "name": "x" }], "data_file": "tests/data/sine.dat", "response_variables": [{ "name": "y" }] } config.load_data(self.config) self.functions = { "ADD": "+", "SUB": "-", "MUL": "*", "DIV": "/", "POW": "**", "SIN": "math.sin", "COS": "math.cos", "RAD": "math.radians", "LN": "math.ln", "LOG": "math.log" } self.generator = TreeGenerator(self.config) def tearDown(self): del self.config del self.generator 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_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_evaluate(self): population = self.generator.init() results = [] start_time = time.time() evaluator.evaluate(population.individuals, self.functions, self.config, results) end_time = time.time() print("GP run took: %2.2fsecs\n" % (end_time - start_time)) population.individuals = results # assert for individual in population.individuals: self.assertTrue(individual.score is not None) self.assertTrue(individual.score > 0)
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 TreeGeneratorTests(unittest.TestCase): def setUp(self): self.config = { "max_population": 10, "tree_generation": { "tree_type": "SYMBOLIC_REGRESSION", "method": "RAMPED_HALF_AND_HALF_METHOD", "initial_max_depth": 3 }, "function_nodes": [ {"type": "FUNCTION", "arity": 2, "name": "ADD"}, {"type": "FUNCTION", "arity": 2, "name": "SUB"}, {"type": "FUNCTION", "arity": 2, "name": "MUL"}, {"type": "FUNCTION", "arity": 2, "name": "DIV"}, {"type": "FUNCTION", "arity": 1, "name": "COS"}, {"type": "FUNCTION", "arity": 1, "name": "SIN"} ], "terminal_nodes": [ {"type": "CONSTANT", "value": 1.0}, {"type": "INPUT", "name": "x"}, {"type": "INPUT", "name": "y"}, { "type": "RANDOM_CONSTANT", "data_range": { "upper_bound": 10.0, "lower_bound": -10.0, "decimal_places": 1 } } ], "input_variables": [ {"name": "x"}, {"name": "y"} ] } self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION") self.generator = TreeGenerator(self.config) self.parser = TreeParser() def tearDown(self): del self.config del self.generator del self.parser def test_generate_func_node(self): # SYMBOLIC REGRESSION TREES for i in range(100): node = self.generator.generate_func_node() self.assertEquals(node.node_type, NodeType.FUNCTION) # CLASSIFICATION TREES self.config["tree_generation"]["tree_type"] = "CLASSIFICATION_TREE" self.config["function_nodes"] = [ { "type": "CLASS_FUNCTION", "name": "GREATER_THAN", "arity": 2, "data_range": { "lower_bound": 0.0, "upper_bound": 10.0, "decimal_places": 1 } } ] self.config["class_attributes"] = [ "attrubte_1", "attrubte_2", "attrubte_3" ] generator = TreeGenerator(self.config) for i in range(100): node = generator.generate_func_node() class_attribute = node.class_attribute self.assertEquals(node.node_type, NodeType.CLASS_FUNCTION) self.assertTrue(class_attribute in self.config["class_attributes"]) def test_resolve_random_constant(self): upper_bound = 10.0 lower_bound = -10.0 decimal_places = 0 for i in range(100): n_details = { "type": "RANDOM_CONSTANT", "data_range": { "lower_bound": lower_bound, "upper_bound": upper_bound, "decimal_places": decimal_places } } new_n_details = self.generator.resolve_random_constant(n_details) node_type = new_n_details["type"] node_value = new_n_details["value"] self.assertEquals(node_type, "CONSTANT") self.assertTrue(upper_bound >= node_value) self.assertTrue(lower_bound <= node_value) self.assertEquals(node_value, int(node_value)) upper_bound = 100.0 lower_bound = -100.0 decimal_places = 1 for i in range(100): n_details = { "type": "RANDOM_CONSTANT", "data_range": { "lower_bound": lower_bound, "upper_bound": upper_bound, "decimal_places": decimal_places } } new_n_details = self.generator.resolve_random_constant(n_details) node_type = new_n_details["type"] node_value = new_n_details["value"] self.assertEquals(node_type, "CONSTANT") self.assertTrue(upper_bound >= node_value) self.assertTrue(lower_bound <= node_value) node_value = decimal.Decimal(str(node_value)) node_decimal_places = abs(node_value.as_tuple().exponent) self.assertEquals(decimal_places, node_decimal_places) def test_generate_term_node(self): for i in range(100): node = self.generator.generate_term_node() self.assertTrue( node.node_type == NodeType.CONSTANT or NodeType.INPUT ) def test_full_method(self): tests = 1 for i in xrange(tests): tree = self.generator.full_method() # asserts init_max = self.config["tree_generation"]["initial_max_depth"] self.assertEquals(tree.depth, init_max) self.assertTrue(tree.size > init_max) def test_grow_method(self): tests = 1000 for i in xrange(tests): tree = self.generator.grow_method() # asserts init_max = self.config["tree_generation"]["initial_max_depth"] self.assertEquals(tree.depth, init_max) self.assertTrue(tree.size > init_max) def test_generate_tree_from_dict(self): population = self.generator.init() tree = population.individuals[0] tree_dict = self.parser.tree_to_dict(tree, tree.root) tree_generated = self.generator.generate_tree_from_dict(tree_dict) program_str = "" for i in tree.program: if i.name is not None: program_str += i.name else: program_str += str(i.value) generated_str = "" for i in tree_generated.program: if i.name is not None: generated_str += i.name else: generated_str += str(i.value) self.assertEquals(program_str, generated_str) def test_init(self): population = self.generator.init() self.assertEquals(len(population.individuals), 10)
"value": 10.0 }, ], "input_variables": [{ "type": "INPUT", "name": "var1" }], "response_variables": [{ "name": "answer" }], "data_file": "arabas_et_al-f1.dat" } config["max_population"] = 100000 load_data(config, data_dir) generator = TreeGenerator(config) population = generator.init() results = [] # TREE EVALUTOR 1 start_time = time.time() tree_eval_1.evaluate(copy.deepcopy(population.individuals), GPFunctionRegistry("SYMBOLIC_REGRESSION"), config, results) end_time = time.time() time_taken = end_time - start_time print "Evaluator 1 took:", str(round(time_taken, 2)) + "s" # TREE EVALUTOR 2 # functions = { # "ADD": "+",
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 SelectionTests(unittest.TestCase): def setUp(self): self.config = { "max_population": 10, "tree_generation": { "method": "FULL_METHOD", "initial_max_depth": 3 }, "selection": { "method": "ROULETTE_SELECTION" }, "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.selection = Selection(self.config) self.population = self.generator.init() # give population random scores for inidividual in self.population.individuals: inidividual.score = random.triangular(1, 100) def print_population(self, phase, population): print "{0}[{1}]:".format(phase, len(population.individuals)) for individual in population.individuals: print individual, individual.score print '\n\n' return len(population.individuals) def test_normalize_scores(self): self.selection._normalize_scores(self.population) total_sum = 0 for individual in self.population.individuals: total_sum += individual.score self.assertEquals(round(total_sum, 2), 1.0) def test_roulette_selection(self): print "ROULETTE SELECTION" old_pop_size = len(self.population.individuals) self.selection.roulette_wheel_selection(self.population) new_pop_size = len(self.population.individuals) # assert # check for object uniqueness individual_ids = [] for i in self.population.individuals: self.assertFalse(id(i) in individual_ids) individual_ids.append(id(i)) self.assertEquals(new_pop_size, old_pop_size) def test_tournament_selection(self): print "TOURNAMENT SELECTION" # tournament selection old_pop_size = self.print_population("OLD", self.population) self.selection.tournament_selection(self.population) new_pop_size = self.print_population("NEW", self.population) # assert # check for object uniqueness individual_ids = [] for i in self.population.individuals: self.assertFalse(id(i) in individual_ids) individual_ids.append(id(i)) self.assertEqual(old_pop_size, new_pop_size) def test_elitest_selection(self): print "ELITEST SELECTION" # elitest selection old_pop_size = self.print_population("OLD", self.population) self.selection.elitest_selection(self.population) new_pop_size = self.print_population("NEW", self.population) self.assertEquals(old_pop_size, new_pop_size) def test_greedy_over_selection(self): print "GREEDY-OVER SELECTION" # create population of size 1000 self.config["max_population"] = 1000 generator = TreeGenerator(self.config) population = generator.init() # greedy over selection old_pop_size = self.print_population("OLD", population) self.selection.greedy_over_selection(population) new_pop_size = self.print_population("NEW", population) self.assertEquals(old_pop_size, new_pop_size) def test_select(self): old_pop_size = len(self.population.individuals) self.selection.select(self.population) new_pop_size = len(self.population.individuals) # assert # check for object uniqueness individual_ids = [] for i in self.population.individuals: self.assertFalse(id(i) in individual_ids) individual_ids.append(id(i)) self.assertEquals(old_pop_size, new_pop_size)
def test_evaluate(self): random.seed(10) # solution = { # "results": # [ # {"score": 15726642.002161335}, # {"score": 359.25843589015597}, # {"score": 92155571.22132382}, # {"score": 26186.46142920347}, # {"score": 15649304.847552022}, # {"score": 188.86069156360125}, # {"score": 23439.33097274221}, # ] # } # setup config = { "max_population" : 10, "max_generation" : 5, "tree_generation" : { "method" : "GROW_METHOD", "initial_max_depth" : 3 }, "evaluator": { "use_cache" : True }, "selection" : { "method" : "TOURNAMENT_SELECTION", "tournament_size": 5 }, "crossover" : { "method" : "POINT_CROSSOVER", "probability" : 0.8 }, "mutation" : { "methods": [ "POINT_MUTATION", "HOIST_MUTATION", "SUBTREE_MUTATION", "SHRINK_MUTATION", "EXPAND_MUTATION" ], "probability" : 0.9 }, "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": "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} ], "data_file" : "tests/data/sine.dat", "input_variables" : [{"type": "INPUT", "name": "x"}], "response_variables" : [{"name": "y"}] } parser = TreeParser() population = TreeGenerator(config).init() # create a dictionary of trees data = {"config": config, "individuals": []} for individual in population.individuals: tree_json = parser.tree_to_dict(individual, individual.root) data["individuals"].append(tree_json) # make sure population size is equals to number of trees population_size = len(population.individuals) individuals = len(data["individuals"]) self.assertEquals(population_size, individuals) # evaluating individuals data = json.dumps(data) host = "localhost" port = 8080 req_type = "POST" path = "evaluate" response = self.transmit(host, port, req_type, path, data) response = json.loads(response) print response
class TreeEvaluatorTests(unittest.TestCase): def setUp(self): self.config = { "max_population": 50, "tree_generation": { "method": "FULL_METHOD", "initial_max_depth": 4 }, "evaluator": { "use_cache": True }, "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}, ], "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) def tearDown(self): del self.config del self.generator # 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_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 # result = evaluator.eval_tree(tree, self.functions, self.config) # self.assertEquals(round(result, 7), 0.5000001) def test_evaluate(self): population = self.generator.init() results = [] start_time = time.time() evaluator.evaluate( population.individuals, self.functions, self.config, results ) end_time = time.time() print("GP run took: %2.2fsecs\n" % (end_time - start_time)) population.individuals = results # assert for individual in population.individuals: self.assertTrue(individual.score is not None) self.assertTrue(individual.score > 0)
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