def test_mutate_new_node_details(self):
        # MUTATE NEW FUNCTION NODE DETAILS
        for i in range(100):
            func_node = Node(NodeType.FUNCTION,
                             name="ADD",
                             arity=2,
                             branches=[])
            node_details = self.mutation.mutate_new_node_details(func_node)
            self.assertNotEquals(node_details["name"], func_node.name)
            self.assertEquals(node_details["arity"], func_node.arity)
            self.assertEquals(node_details["type"], func_node.node_type)

        # MUTATE NEW TERMINAL NODE DETAILS
        for i in range(100):
            term_node = Node(NodeType.CONSTANT, value=1.0)
            node_details = self.mutation.mutate_new_node_details(term_node)
            if node_details["type"] == NodeType.CONSTANT:
                self.assertNotEqual(node_details["value"], term_node.value)

            elif node_details["type"] == NodeType.INPUT:
                self.assertNotEqual(node_details["name"], term_node.name)

        # MUTATE NEW CLASS FUNCTION NODE DETAILS
        self.config["function_nodes"] = [{
            "type": "CLASS_FUNCTION",
            "name": "GREATER_THAN",
            "arity": 2,
            "data_range": {
                "lower_bound": 0.0,
                "upper_bound": 10.0,
                "decimal_places": 0,
            }
        }, {
            "type": "CLASS_FUNCTION",
            "name": "LESS_THAN",
            "arity": 2,
            "data_range": {
                "lower_bound": 0.0,
                "upper_bound": 10.0,
                "decimal_places": 0,
            }
        }, {
            "type": "CLASS_FUNCTION",
            "name": "EQUALS",
            "arity": 2,
            "decimal_precision": 2
        }]
        mutation = TreeMutation(self.config)

        for i in range(100):
            class_func_node = Node(NodeType.CLASS_FUNCTION,
                                   name="GREATER_THAN",
                                   arity=2)
            node_details = mutation.mutate_new_node_details(class_func_node)
            self.assertNotEquals(node_details["name"], class_func_node.name)
            self.assertEquals(node_details["arity"], class_func_node.arity)
            self.assertEquals(node_details["type"], class_func_node.node_type)
    def setUp(self):
        self.config = {
            "tree_generation": {
                "method": "GROW_METHOD",
                "initial_max_depth": 4
            },
            "mutation": {
                "methods": [
                    "POINT_MUTATION", "HOIST_MUTATION", "SUBTREE_MUTATION",
                    "SHRINK_MUTATION", "EXPAND_MUTATION"
                ],
                "probability":
                1.0
            },
            "function_nodes": [{
                "type": "FUNCTION",
                "name": "ADD",
                "arity": 2
            }, {
                "type": "FUNCTION",
                "name": "SUB",
                "arity": 2
            }, {
                "type": "FUNCTION",
                "name": "MUL",
                "arity": 2
            }, {
                "type": "FUNCTION",
                "name": "DIV",
                "arity": 2
            }, {
                "type": "FUNCTION",
                "name": "COS",
                "arity": 1
            }, {
                "type": "FUNCTION",
                "name": "SIN",
                "arity": 1
            }, {
                "type": "FUNCTION",
                "name": "RAD",
                "arity": 1
            }],
            "terminal_nodes": [{
                "type": "CONSTANT",
                "value": 1.0
            }, {
                "type": "CONSTANT",
                "value": 2.0
            }, {
                "type": "INPUT",
                "name": "x"
            }],
            "input_variables": [{
                "type": "INPUT",
                "name": "x"
            }]
        }
        self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION")
        self.generator = TreeGenerator(self.config)

        self.parser = TreeParser()
        self.mutation = TreeMutation(self.config)

        # create nodes
        left_node = Node(NodeType.CONSTANT, value=1.0)
        right_node = Node(NodeType.INPUT, name="x")

        cos_func = Node(NodeType.FUNCTION,
                        name="COS",
                        arity=1,
                        branches=[left_node])

        sin_func = Node(NodeType.FUNCTION,
                        name="SIN",
                        arity=1,
                        branches=[right_node])

        add_func = Node(NodeType.FUNCTION,
                        name="ADD",
                        arity=2,
                        branches=[cos_func, sin_func])

        # create tree
        self.tree = Tree()
        self.tree.root = add_func
        self.tree.update_program()
        self.tree.update_func_nodes()
        self.tree.update_term_nodes()
class TreeMutatorTests(unittest.TestCase):
    def setUp(self):
        self.config = {
            "tree_generation": {
                "method": "GROW_METHOD",
                "initial_max_depth": 4
            },
            "mutation": {
                "methods": [
                    "POINT_MUTATION", "HOIST_MUTATION", "SUBTREE_MUTATION",
                    "SHRINK_MUTATION", "EXPAND_MUTATION"
                ],
                "probability":
                1.0
            },
            "function_nodes": [{
                "type": "FUNCTION",
                "name": "ADD",
                "arity": 2
            }, {
                "type": "FUNCTION",
                "name": "SUB",
                "arity": 2
            }, {
                "type": "FUNCTION",
                "name": "MUL",
                "arity": 2
            }, {
                "type": "FUNCTION",
                "name": "DIV",
                "arity": 2
            }, {
                "type": "FUNCTION",
                "name": "COS",
                "arity": 1
            }, {
                "type": "FUNCTION",
                "name": "SIN",
                "arity": 1
            }, {
                "type": "FUNCTION",
                "name": "RAD",
                "arity": 1
            }],
            "terminal_nodes": [{
                "type": "CONSTANT",
                "value": 1.0
            }, {
                "type": "CONSTANT",
                "value": 2.0
            }, {
                "type": "INPUT",
                "name": "x"
            }],
            "input_variables": [{
                "type": "INPUT",
                "name": "x"
            }]
        }
        self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION")
        self.generator = TreeGenerator(self.config)

        self.parser = TreeParser()
        self.mutation = TreeMutation(self.config)

        # create nodes
        left_node = Node(NodeType.CONSTANT, value=1.0)
        right_node = Node(NodeType.INPUT, name="x")

        cos_func = Node(NodeType.FUNCTION,
                        name="COS",
                        arity=1,
                        branches=[left_node])

        sin_func = Node(NodeType.FUNCTION,
                        name="SIN",
                        arity=1,
                        branches=[right_node])

        add_func = Node(NodeType.FUNCTION,
                        name="ADD",
                        arity=2,
                        branches=[cos_func, sin_func])

        # create tree
        self.tree = Tree()
        self.tree.root = add_func
        self.tree.update_program()
        self.tree.update_func_nodes()
        self.tree.update_term_nodes()

    def tearDown(self):
        del self.config
        del self.generator
        del self.parser

    def build_tree_str(self, tree):
        tree_str = ""

        for node in tree.program:
            if hasattr(node, "name") and node.name is not None:
                tree_str += "node:{0} addr:{1}\n".format(node.name, id(node))
            else:
                tree_str += "node:{0} addr:{1}\n".format(node.value, id(node))

        return tree_str

    def tree_equals(self, tree_1_str, tree_2_str):
        if tree_1_str == tree_2_str:
            return True
        else:
            return False

    def mutated(self, tree, mutation_func, mutation_index=None):
        tree_before = self.build_tree_str(self.tree)
        mutation_func(tree, mutation_index)
        tree_after = self.build_tree_str(self.tree)

        print("Before Mutation")
        print(tree_before)

        print("\nAfter Mutation")
        print(tree_after)

        self.assertTrue(self.tree_equals(tree_before, tree_before))
        self.assertTrue(self.tree_equals(tree_after, tree_after))
        self.assertFalse(self.tree_equals(tree_before, tree_after))

    def test_mutate_new_node_details(self):
        # MUTATE NEW FUNCTION NODE DETAILS
        for i in range(100):
            func_node = Node(NodeType.FUNCTION,
                             name="ADD",
                             arity=2,
                             branches=[])
            node_details = self.mutation.mutate_new_node_details(func_node)
            self.assertNotEquals(node_details["name"], func_node.name)
            self.assertEquals(node_details["arity"], func_node.arity)
            self.assertEquals(node_details["type"], func_node.node_type)

        # MUTATE NEW TERMINAL NODE DETAILS
        for i in range(100):
            term_node = Node(NodeType.CONSTANT, value=1.0)
            node_details = self.mutation.mutate_new_node_details(term_node)
            if node_details["type"] == NodeType.CONSTANT:
                self.assertNotEqual(node_details["value"], term_node.value)

            elif node_details["type"] == NodeType.INPUT:
                self.assertNotEqual(node_details["name"], term_node.name)

        # MUTATE NEW CLASS FUNCTION NODE DETAILS
        self.config["function_nodes"] = [{
            "type": "CLASS_FUNCTION",
            "name": "GREATER_THAN",
            "arity": 2,
            "data_range": {
                "lower_bound": 0.0,
                "upper_bound": 10.0,
                "decimal_places": 0,
            }
        }, {
            "type": "CLASS_FUNCTION",
            "name": "LESS_THAN",
            "arity": 2,
            "data_range": {
                "lower_bound": 0.0,
                "upper_bound": 10.0,
                "decimal_places": 0,
            }
        }, {
            "type": "CLASS_FUNCTION",
            "name": "EQUALS",
            "arity": 2,
            "decimal_precision": 2
        }]
        mutation = TreeMutation(self.config)

        for i in range(100):
            class_func_node = Node(NodeType.CLASS_FUNCTION,
                                   name="GREATER_THAN",
                                   arity=2)
            node_details = mutation.mutate_new_node_details(class_func_node)
            self.assertNotEquals(node_details["name"], class_func_node.name)
            self.assertEquals(node_details["arity"], class_func_node.arity)
            self.assertEquals(node_details["type"], class_func_node.node_type)

    def test_point_mutation(self):
        print "---------- POINT MUATION! ----------"
        self.mutated(self.tree, self.mutation.point_mutation)

    def test_hoist_mutation(self):
        print "---------- HOIST MUATION! ----------"
        self.mutated(self.tree, self.mutation.hoist_mutation, 3)

    def test_SUBTREE_MUTATION(self):
        print "---------- SUBTREE MUATION! ----------"
        self.mutated(self.tree, self.mutation.subtree_mutation, 3)

    def test_shrink_mutation(self):
        print "---------- SHRINK MUATION! ----------"
        self.mutated(self.tree, self.mutation.shrink_mutation, 3)

    def test_expansion_mutation(self):
        print "---------- EXPANSION MUATION! ----------"
        self.mutated(self.tree, self.mutation.expansion_mutation, 3)

    def test_mutate(self):
        print "MUTATE!"
        tree_before = self.build_tree_str(self.tree)
        self.mutation.mutate(self.tree)
        tree_after = self.build_tree_str(self.tree)

        print "----->", self.mutation.method
        print("Before Mutation")
        print(tree_before)

        print("\nAfter Mutation")
        print(tree_after)

        self.assertTrue(self.tree_equals(tree_before, tree_before))
        self.assertTrue(self.tree_equals(tree_after, tree_after))
        self.assertFalse(self.tree_equals(tree_before, tree_after))
Beispiel #4
0
                "name": "petal_length"
            }, {
                "name": "petal_width"
            }],
            "response_variables": [{
                "name": "species"
            }]
        }
        load_data(config, script_path)
        functions = GPFunctionRegistry("CLASSIFICATION")
        generator = TreeGenerator(config)

        # genetic operators
        selection = Selection(config)
        crossover = TreeCrossover(config)
        mutation = TreeMutation(config)

        # run symbolic regression
        population = generator.init()

        start_time = time.time()
        details = play.play_details(
            population=population,
            evaluate=evaluate,
            functions=functions,
            selection=selection,
            crossover=crossover,
            mutation=mutation,
            print_func=print_func,
            stop_func=default_stop_func,
            config=config,
Beispiel #5
0
    def setUp(self):
        self.config = {
            "max_population":
            10,
            "tree_generation": {
                "method": "FULL_METHOD",
                "initial_max_depth": 4
            },
            "evaluator": {
                "use_cache": True
            },
            "selection": {
                "method": "TOURNAMENT_SELECTION",
                "tournament_size": 2
            },
            "crossover": {
                "method": "POINT_CROSSOVER",
                "probability": 0.6
            },
            "mutation": {
                "methods": ["POINT_MUTATION"],
                "probability": 0.8
            },
            "function_nodes": [{
                "type": "FUNCTION",
                "name": "ADD",
                "arity": 2
            }, {
                "type": "FUNCTION",
                "name": "SUB",
                "arity": 2
            }],
            "terminal_nodes": [
                {
                    "type": "CONSTANT",
                    "value": 1.0
                },
            ],
            "input_variables": [{
                "type": "INPUT",
                "name": "x"
            }],
            "data_file":
            "tests/data/sine.dat",
            "response_variables": [{
                "name": "y"
            }],
            "recorder": {
                "store_file": "json_store_test.json",
                "compress": True
            }
        }
        config.load_data(self.config)

        self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION")
        self.generator = TreeGenerator(self.config)

        self.json_store = JSONStore(self.config)
        self.json_store.setup_store()

        self.population = self.generator.init()
        results = []
        cache = {}
        evaluate(self.population.individuals, self.functions, self.config,
                 results, cache, self.json_store)
        self.population.sort_individuals()

        self.selection = Selection(self.config, recorder=self.json_store)
        self.crossover = TreeCrossover(self.config, recorder=self.json_store)
        self.mutation = TreeMutation(self.config, recorder=self.json_store)
            "MUL": "*",
            "DIV": "/",
            "POW": "**",
            "SIN": "math.sin",
            "COS": "math.cos",
            "RAD": "math.radians",
            "LN": "math.ln",
            "EXP": "math.exp",
            "LOG": "math.log"
        }
        generator = TreeGenerator(config)

        # genetic operators
        selection = Selection(config, recorder=json_store)
        crossover = TreeCrossover(config, recorder=json_store)
        mutation = TreeMutation(config, recorder=json_store)

        # run symbolic regression
        population = generator.init()

        start_time = time.time()
        details = play.play_details(population=population,
                                    evaluate=evaluate,
                                    functions=functions,
                                    selection=selection,
                                    crossover=crossover,
                                    mutation=mutation,
                                    print_func=print_func,
                                    plot_func=plot_func,
                                    stop_func=default_stop_func,
                                    config=config,
Beispiel #7
0
    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)
Beispiel #8
0
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)
Beispiel #9
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()
Beispiel #10
0
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)
Beispiel #11
0
class TreeMutatorTests(unittest.TestCase):
    def setUp(self):
        self.config = {
            "tree_generation": {
                "method": "GROW_METHOD",
                "initial_max_depth": 4
            },

            "mutation": {
                "methods": [
                    "POINT_MUTATION",
                    "HOIST_MUTATION",
                    "SUBTREE_MUTATION",
                    "SHRINK_MUTATION",
                    "EXPAND_MUTATION"
                ],
                "probability": 1.0
            },

            "function_nodes": [
                {"type": "FUNCTION", "name": "ADD", "arity": 2},
                {"type": "FUNCTION", "name": "SUB", "arity": 2},
                {"type": "FUNCTION", "name": "MUL", "arity": 2},
                {"type": "FUNCTION", "name": "DIV", "arity": 2},
                {"type": "FUNCTION", "name": "COS", "arity": 1},
                {"type": "FUNCTION", "name": "SIN", "arity": 1},
                {"type": "FUNCTION", "name": "RAD", "arity": 1}
            ],

            "terminal_nodes": [
                {"type": "CONSTANT", "value": 1.0},
                {"type": "CONSTANT", "value": 2.0},
                {"type": "INPUT", "name": "x"}
            ],

            "input_variables": [
                {"type": "INPUT", "name": "x"}
            ]

        }
        self.functions = GPFunctionRegistry("SYMBOLIC_REGRESSION")
        self.generator = TreeGenerator(self.config)

        self.parser = TreeParser()
        self.mutation = TreeMutation(self.config)

        # create nodes
        left_node = Node(NodeType.CONSTANT, value=1.0)
        right_node = Node(NodeType.INPUT, name="x")

        cos_func = Node(
            NodeType.FUNCTION,
            name="COS",
            arity=1,
            branches=[left_node]
        )

        sin_func = Node(
            NodeType.FUNCTION,
            name="SIN",
            arity=1,
            branches=[right_node]
        )

        add_func = Node(
            NodeType.FUNCTION,
            name="ADD",
            arity=2,
            branches=[cos_func, sin_func]
        )

        # create tree
        self.tree = Tree()
        self.tree.root = add_func
        self.tree.update_program()
        self.tree.update_func_nodes()
        self.tree.update_term_nodes()

    def tearDown(self):
        del self.config
        del self.generator
        del self.parser

    def build_tree_str(self, tree):
        tree_str = ""

        for node in tree.program:
            if hasattr(node, "name") and node.name is not None:
                tree_str += "node:{0} addr:{1}\n".format(node.name, id(node))
            else:
                tree_str += "node:{0} addr:{1}\n".format(node.value, id(node))

        return tree_str

    def tree_equals(self, tree_1_str, tree_2_str):
        if tree_1_str == tree_2_str:
            return True
        else:
            return False

    def mutated(self, tree, mutation_func, mutation_index=None):
        tree_before = self.build_tree_str(self.tree)
        mutation_func(tree, mutation_index)
        tree_after = self.build_tree_str(self.tree)

        print("Before Mutation")
        print(tree_before)

        print("\nAfter Mutation")
        print(tree_after)

        self.assertTrue(self.tree_equals(tree_before, tree_before))
        self.assertTrue(self.tree_equals(tree_after, tree_after))
        self.assertFalse(self.tree_equals(tree_before, tree_after))

    def test_mutate_new_node_details(self):
        # MUTATE NEW FUNCTION NODE DETAILS
        for i in range(100):
            func_node = Node(
                NodeType.FUNCTION,
                name="ADD",
                arity=2,
                branches=[]
            )
            node_details = self.mutation.mutate_new_node_details(func_node)
            self.assertNotEquals(node_details["name"], func_node.name)
            self.assertEquals(node_details["arity"], func_node.arity)
            self.assertEquals(node_details["type"], func_node.node_type)

        # MUTATE NEW TERMINAL NODE DETAILS
        for i in range(100):
            term_node = Node(
                NodeType.CONSTANT,
                value=1.0
            )
            node_details = self.mutation.mutate_new_node_details(term_node)
            if node_details["type"] == NodeType.CONSTANT:
                self.assertNotEqual(node_details["value"], term_node.value)

            elif node_details["type"] == NodeType.INPUT:
                self.assertNotEqual(node_details["name"], term_node.name)

        # MUTATE NEW CLASS FUNCTION NODE DETAILS
        self.config["function_nodes"] = [
            {
                "type": "CLASS_FUNCTION",
                "name": "GREATER_THAN",
                "arity": 2,

                "data_range": {
                    "lower_bound": 0.0,
                    "upper_bound": 10.0,
                    "decimal_places": 0,
                }
            },
            {
                "type": "CLASS_FUNCTION",
                "name": "LESS_THAN",
                "arity": 2,

                "data_range": {
                    "lower_bound": 0.0,
                    "upper_bound": 10.0,
                    "decimal_places": 0,
                }
            },
            {
                "type": "CLASS_FUNCTION",
                "name": "EQUALS",
                "arity": 2,
                "decimal_precision": 2
            }
        ]
        mutation = TreeMutation(self.config)

        for i in range(100):
            class_func_node = Node(
                NodeType.CLASS_FUNCTION,
                name="GREATER_THAN",
                arity=2
            )
            node_details = mutation.mutate_new_node_details(class_func_node)
            self.assertNotEquals(node_details["name"], class_func_node.name)
            self.assertEquals(node_details["arity"], class_func_node.arity)
            self.assertEquals(node_details["type"], class_func_node.node_type)

    def test_point_mutation(self):
        print "---------- POINT MUATION! ----------"
        self.mutated(self.tree, self.mutation.point_mutation)

    def test_hoist_mutation(self):
        print "---------- HOIST MUATION! ----------"
        self.mutated(self.tree, self.mutation.hoist_mutation, 3)

    def test_SUBTREE_MUTATION(self):
        print "---------- SUBTREE MUATION! ----------"
        self.mutated(self.tree, self.mutation.subtree_mutation, 3)

    def test_shrink_mutation(self):
        print "---------- SHRINK MUATION! ----------"
        self.mutated(self.tree, self.mutation.shrink_mutation, 3)

    def test_expansion_mutation(self):
        print "---------- EXPANSION MUATION! ----------"
        self.mutated(self.tree, self.mutation.expansion_mutation, 3)

    def test_mutate(self):
        print "MUTATE!"
        tree_before = self.build_tree_str(self.tree)
        self.mutation.mutate(self.tree)
        tree_after = self.build_tree_str(self.tree)

        print "----->", self.mutation.method
        print("Before Mutation")
        print(tree_before)

        print("\nAfter Mutation")
        print(tree_after)

        self.assertTrue(self.tree_equals(tree_before, tree_before))
        self.assertTrue(self.tree_equals(tree_after, tree_after))
        self.assertFalse(self.tree_equals(tree_before, tree_after))
Beispiel #12
0
    def test_mutate_new_node_details(self):
        # MUTATE NEW FUNCTION NODE DETAILS
        for i in range(100):
            func_node = Node(
                NodeType.FUNCTION,
                name="ADD",
                arity=2,
                branches=[]
            )
            node_details = self.mutation.mutate_new_node_details(func_node)
            self.assertNotEquals(node_details["name"], func_node.name)
            self.assertEquals(node_details["arity"], func_node.arity)
            self.assertEquals(node_details["type"], func_node.node_type)

        # MUTATE NEW TERMINAL NODE DETAILS
        for i in range(100):
            term_node = Node(
                NodeType.CONSTANT,
                value=1.0
            )
            node_details = self.mutation.mutate_new_node_details(term_node)
            if node_details["type"] == NodeType.CONSTANT:
                self.assertNotEqual(node_details["value"], term_node.value)

            elif node_details["type"] == NodeType.INPUT:
                self.assertNotEqual(node_details["name"], term_node.name)

        # MUTATE NEW CLASS FUNCTION NODE DETAILS
        self.config["function_nodes"] = [
            {
                "type": "CLASS_FUNCTION",
                "name": "GREATER_THAN",
                "arity": 2,

                "data_range": {
                    "lower_bound": 0.0,
                    "upper_bound": 10.0,
                    "decimal_places": 0,
                }
            },
            {
                "type": "CLASS_FUNCTION",
                "name": "LESS_THAN",
                "arity": 2,

                "data_range": {
                    "lower_bound": 0.0,
                    "upper_bound": 10.0,
                    "decimal_places": 0,
                }
            },
            {
                "type": "CLASS_FUNCTION",
                "name": "EQUALS",
                "arity": 2,
                "decimal_precision": 2
            }
        ]
        mutation = TreeMutation(self.config)

        for i in range(100):
            class_func_node = Node(
                NodeType.CLASS_FUNCTION,
                name="GREATER_THAN",
                arity=2
            )
            node_details = mutation.mutate_new_node_details(class_func_node)
            self.assertNotEquals(node_details["name"], class_func_node.name)
            self.assertEquals(node_details["arity"], class_func_node.arity)
            self.assertEquals(node_details["type"], class_func_node.node_type)
def gp_benchmark_loop(config):
    try:
        # setup
        random.seed(config["random_seed"])  # VERY IMPORTANT!
        load_data(config, config["call_path"])
        json_store = JSONStore(config)
        # functions = GPFunctionRegistry("SYMBOLIC_REGRESSION")
        generator = TreeGenerator(config)

        # genetic operators
        selection = Selection(config, recorder=json_store)
        crossover = TreeCrossover(config, recorder=json_store)
        mutation = TreeMutation(config, recorder=json_store)

        # setup the initial random population
        population = generator.init()

        # create play details
        details = play.play_details(
            population=population,
            functions=config["functions"],
            evaluate=evaluate,
            selection=selection,
            crossover=crossover,
            mutation=mutation,
            editor=edit_trees,
            stop_func=default_stop_func,
            # print_func=print_func,
            config=config,
            recorder=json_store)

        # run symbolic regression
        start_time = time.time()
        play.play(details)
        end_time = time.time()
        time_taken = end_time - start_time

        # print msg
        print("DONE -> pop: {0} cross: {1} mut: {2} seed: {3} [{4}s]".format(
            config["max_population"], config["crossover"]["probability"],
            config["mutation"]["probability"], config["random_seed"],
            round(time_taken, 2)))

        # log on completion
        if config.get("log_path", False):
            config.pop("data")
            msg = {
                "timestamp": time.mktime(datetime.now().timetuple()),
                "status": "DONE",
                "config": config,
                "runtime": time_taken,
                "best_score": population.find_best_individuals()[0].score,
                "best": str(population.find_best_individuals()[0])
            }
            log_path = os.path.expandvars(config["log_path"])
            log_file = open(log_path, "a+")
            log_file.write(json.dumps(msg) + "\n")
            log_file.close()

    except Exception as err_msg:
        import traceback
        traceback.print_exc()

        # log exception
        if config.get("log_path", False):
            msg = {
                "timestamp": time.mktime(datetime.now().timetuple()),
                "status": "ERROR",
                "config": config,
                "error": err_msg
            }
            log_path = os.path.expandvars(config["log_path"])
            log_file = open(log_path, "a+")
            log_file.write(json.dumps(msg) + "\n")
            log_file.close()

        raise  # raise the exception

    return config
Beispiel #14
0
    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)
Beispiel #15
0
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