Beispiel #1
0
    def setUp(self):
        self.config = {
            "cartesian": {
                "rows": 4,
                "columns": 3,
                "levels_back": 1,

                "num_inputs": 4,
                "num_outputs": 1
            },

            "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}
            ],

            "data_file": "tests/data/sine.dat",

            "response_variables" : [{"name": "y"}],

            "input_variables": [
                {"type": "INPUT", "name": "a"},
                {"type": "INPUT", "name": "b"},
                {"type": "INPUT", "name": "c"},
                {"type": "INPUT", "name": "d"}
            ]
        }
        self.generator = CartesianGenerator(self.config)
Beispiel #2
0
    def test_calculate_column_level(self):
        self.config["cartesian"]["num_inputs"] = 2
        generator = CartesianGenerator(self.config)

        self.assertEquals(generator.calculate_column_level(2), 0)
        self.assertEquals(generator.calculate_column_level(5), 0)

        self.assertEquals(generator.calculate_column_level(6), 1)
        self.assertEquals(generator.calculate_column_level(9), 1)

        self.assertEquals(generator.calculate_column_level(10), 2)
        self.assertEquals(generator.calculate_column_level(13), 2)

        self.assertRaises(
            RuntimeError,
            self.generator.calculate_column_level,
            0
        )
        self.assertRaises(
            RuntimeError,
            self.generator.calculate_column_level,
            1
        )
        self.assertRaises(
            RuntimeError,
            self.generator.calculate_column_level,
            -1
        )
        self.assertRaises(
            RuntimeError,
            self.generator.calculate_column_level,
            14
        )
Beispiel #3
0
    def __init__(self, config, **kwargs):
        self.config = config
        self.record_config = config.get("recorder", None)
        self.recorder = kwargs.get("recorder", None)
        self.generator = CartesianGenerator(config)

        # mutation stats
        self.method = None
        self.mutation_probability = None
        self.random_probability = None
        self.mutated = False
        self.before_mutation = None
        self.after_mutation = None
Beispiel #4
0
    def __init__(self, config, **kwargs):
        self.config = config
        self.record_config = config.get("recorder", None)
        self.recorder = kwargs.get("recorder", None)
        self.generator = CartesianGenerator(config)

        # mutation stats
        self.method = None
        self.mutation_probability = None
        self.random_probability = None
        self.mutated = False
        self.before_mutation = None
        self.after_mutation = None
Beispiel #5
0
class CartesianGeneratorTests(unittest.TestCase):
    def setUp(self):
        self.config = {
            "cartesian": {
                "rows": 4,
                "columns": 3,
                "levels_back": 1,

                "num_inputs": 4,
                "num_outputs": 1
            },

            "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}
            ],

            "data_file": "tests/data/sine.dat",

            "response_variables" : [{"name": "y"}],

            "input_variables": [
                {"type": "INPUT", "name": "a"},
                {"type": "INPUT", "name": "b"},
                {"type": "INPUT", "name": "c"},
                {"type": "INPUT", "name": "d"}
            ]
        }
        self.generator = CartesianGenerator(self.config)

    def test_build_address_grid(self):
        result = self.generator.build_address_grid()
        self.assertEquals(
            result,
            [
                [0, 1, 2, 3],
                [4, 5, 6, 7],
                [8, 9, 10, 11],
                [12, 13, 14, 15]
            ]
        )

        self.config["cartesian"]["num_inputs"] = 2
        result = self.generator.build_address_grid()
        self.assertEquals(
            result,
            [
                [0, 1],
                [2, 3, 4, 5],
                [6, 7, 8, 9],
                [10, 11, 12, 13]
            ]
        )

    def test_calculate_column_level(self):
        self.config["cartesian"]["num_inputs"] = 2
        generator = CartesianGenerator(self.config)

        self.assertEquals(generator.calculate_column_level(2), 0)
        self.assertEquals(generator.calculate_column_level(5), 0)

        self.assertEquals(generator.calculate_column_level(6), 1)
        self.assertEquals(generator.calculate_column_level(9), 1)

        self.assertEquals(generator.calculate_column_level(10), 2)
        self.assertEquals(generator.calculate_column_level(13), 2)

        self.assertRaises(
            RuntimeError,
            self.generator.calculate_column_level,
            0
        )
        self.assertRaises(
            RuntimeError,
            self.generator.calculate_column_level,
            1
        )
        self.assertRaises(
            RuntimeError,
            self.generator.calculate_column_level,
            -1
        )
        self.assertRaises(
            RuntimeError,
            self.generator.calculate_column_level,
            14
        )

    def test_get_valid_addresses(self):
        result = self.generator.get_valid_addresses(0)
        self.assertEquals(range(4), result)

        result = self.generator.get_valid_addresses(1)
        self.assertEquals(range(8), result)

        result = self.generator.get_valid_addresses(2)
        self.assertEquals(
            [4, 5, 6, 7, 8, 9, 10, 11],
            result
        )

        self.assertRaises(
            RuntimeError,
            self.generator.get_valid_addresses,
            -1
        )
        self.assertRaises(
            RuntimeError,
            self.generator.get_valid_addresses,
            3
        )

    def test_gen_random_conn_gene(self):
        for i in range(100):
            result = self.generator.gen_random_conn_gene(4)
            self.assertTrue(result >= 0, result <= 3)

    def test_gen_random_func_gene(self):
        num_funcs = len(self.config["function_nodes"])
        for i in range(100):
            result = self.generator.gen_random_func_gene()
            self.assertTrue(result >= 0, result <= num_funcs - 1)

    def test_gen_random_func_node(self):
        for i in range(100):
            node_addr = 7
            func_node = self.generator.gen_random_func_node(node_addr)
            func_index = func_node[0]
            func_conns = func_node[1:]

            # asserts
            # check number of connections
            arity = self.config["function_nodes"][func_index]["arity"]
            self.assertEquals(arity, len(func_node[1:]))

            # check what connections points to
            rows = self.config["cartesian"]["rows"]
            columns = self.config["cartesian"]["columns"]
            max_addr = (rows * columns) - 1
            for conn in func_conns:
                self.assertTrue(conn >= 0 and conn <= max_addr)

    def test_gen_random_output_node(self):
        num_inputs = self.config["cartesian"]["num_inputs"]
        rows = self.config["cartesian"]["rows"]
        columns = self.config["cartesian"]["columns"]
        num_funcs = (rows * columns)
        max_addr = (num_funcs + num_inputs) - 1

        for i in range(100):
            res = self.generator.gen_random_output_node()

            # asserts
            self.assertTrue(res >= 0 and res <= max_addr)

    def test_prep_input_nodes(self):
        input_nodes = self.generator.prep_input_nodes()
        self.assertEquals(input_nodes, ["a", "b", "c", "d"])

    def test_generate_new_cartesian(self):
        cartesian = self.generator.generate_new_cartesian()
        cart_dict = cartesian.to_dict()

        # import pprint
        # pprint.pprint(cartesian.to_dict())

        # asserts
        rows = self.config["cartesian"]["rows"]
        columns = self.config["cartesian"]["columns"]
        levels_back = self.config["cartesian"]["levels_back"]
        num_inputs = self.config["cartesian"]["num_inputs"]

        # assert graph config
        self.assertEquals(cartesian.rows, rows)
        self.assertEquals(cartesian.columns, columns)
        self.assertEquals(cartesian.levels_back, levels_back)

        # assert graph elements
        num_func_nodes = rows * columns
        self.assertEquals(len(cartesian.func_nodes), num_func_nodes)
        self.assertEquals(cart_dict["func_nodes_len"], num_func_nodes)

        self.assertEquals(len(cartesian.input_nodes), num_inputs)
        self.assertEquals(cart_dict["input_nodes_len"], num_inputs)

        num_output_nodes = self.config["cartesian"]["num_outputs"]
        self.assertEquals(len(cartesian.output_nodes), num_output_nodes)
        self.assertEquals(cart_dict["output_nodes_len"], num_output_nodes)
        config["data"]["1.0"] = [1.0 for j in range(rows)]

        # import pprint
        # pprint.pprint(config)

        json_store = JSONStore(config)
        functions = [
            funcs.add_function,
            funcs.sub_function,
            funcs.mul_function,
            funcs.div_function,
            funcs.sin_function,
            funcs.cos_function,
            funcs.rad_function
        ]
        generator = CartesianGenerator(config)

        # genetic operators
        selection = Selection(config, recorder=json_store)
        mutation = CartesianMutation(config)

        # run symbolic regression
        population = generator.init()

        start_time = time.time()
        details = play.play_details(
            population=population,
            evaluate=evaluate,
            functions=functions,
            selection=selection,
            mutation=mutation,
Beispiel #7
0
class CartesianMutation(object):
    def __init__(self, config, **kwargs):
        self.config = config
        self.record_config = config.get("recorder", None)
        self.recorder = kwargs.get("recorder", None)
        self.generator = CartesianGenerator(config)

        # mutation stats
        self.method = None
        self.mutation_probability = None
        self.random_probability = None
        self.mutated = False
        self.before_mutation = None
        self.after_mutation = None

    def mutate_new_func_gene(self, old_gene):
        retry = 0
        retry_limit = 10
        new_gene = old_gene

        while new_gene == old_gene and retry < retry_limit:
            new_gene = self.generator.gen_random_func_gene()
            retry += 1

        if new_gene == old_gene:
            err = "Error! Failed to mutate new function gene!"
            raise RuntimeError(err)
        else:
            return new_gene

    def mutate_new_conn_gene(self, old_gene, node_addr):
        retry = 0
        retry_limit = 20
        new_gene = old_gene

        while new_gene == old_gene and retry < retry_limit:
            new_gene = self.generator.gen_random_conn_gene(node_addr)
            retry += 1

        if new_gene == old_gene:
            err = "Error! Failed to mutate new function gene!"
            raise RuntimeError(err)
        else:
            return new_gene

    def mutate_function_node(self, node_addr, cartesian):
        # pick random function gene
        node = cartesian.graph()[node_addr]
        gene_index = randint(0, len(node) - 1)
        new_gene = None

        # mutate function gene
        if gene_index == 0:
            old_gene = node[gene_index]
            new_gene = self.mutate_new_func_gene(old_gene)

            old_arity = self.config["function_nodes"][old_gene]["arity"]
            new_arity = self.config["function_nodes"][new_gene]["arity"]

            if old_arity < new_arity:
                for i in range(old_arity - new_arity):
                    conn_gene = self.generator.gen_random_conn_gene(node_addr)
                    cartesian.graph()[node_addr].append(conn_gene)
            else:
                for i in range(new_arity - old_arity):
                    cartesian.graph()[node_addr].pop()

        # mutate connection gene
        else:
            old_gene = node[gene_index]
            new_gene = self.mutate_new_conn_gene(old_gene, node_addr)

        # return
        cartesian.graph()[node_addr][gene_index] = new_gene
        return gene_index

    def mutate_output_node(self, node_index, cartesian):
        retry = 0
        retry_limit = 20
        old_node_addr = cartesian.output_nodes[node_index]
        new_node_addr = old_node_addr

        # pick random input node or func node
        while new_node_addr == old_node_addr and retry < retry_limit:
            new_node_addr = randint(0, len(cartesian.graph()) - 1)
            retry += 1

        # mutate output node
        cartesian.output_nodes[node_index] = new_node_addr

        if retry == retry_limit:
            return None
        else:
            return new_node_addr

    def point_mutation(self, cartesian):
        result = None
        num_inputs = self.config["cartesian"]["num_inputs"]
        num_outputs = self.config["cartesian"]["num_outputs"]
        num_funcs = len(cartesian.func_nodes)
        max_addr = num_inputs + num_funcs + num_outputs - 1

        # chose random node
        node_addr = randint(num_inputs, max_addr)

        # mutate function node
        if node_addr < num_inputs + num_funcs:
            # convert index to node_addr in cartesian graph and mutate
            gene_index = self.mutate_function_node(node_addr, cartesian)
            result = {
                "mutated_node": "FUNC_NODE",
                "node_addr": node_addr,
                "gene_index": gene_index
            }

        # mutate output node
        else:
            # convert index to output node index and mutate
            node_index = node_addr - num_inputs - num_funcs
            new_addr = self.mutate_output_node(node_index, cartesian)
            result = {
                "mutated_node": "OUTPUT_NODE",
                "output_node": node_index,
                "new_addr": new_addr
            }

        # check result
        if result is None:
            self.mutated = False
        else:
            self.mutated = True
            self.index = result

    def mutate(self, cartesian):
        mutation_methods = {
            "POINT_MUTATION": self.point_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 = copy.deepcopy(cartesian.program())

        # mutate
        if self.mutation_probability >= self.random_probability:
            mutation_func = mutation_methods[self.method]
            mutation_func(cartesian)

        # record after mutation
        self.after_mutation = copy.deepcopy(cartesian.program())

        # record
        if self.recorder is not None:
            self.recorder.record(RecordType.MUTATION, self)

    def to_dict(self):
        self_dict = {
            "method": self.method,
            "mutation_probability": self.mutation_probability,
            "random_probability": self.random_probability,
            "mutated": self.mutated,
            "index": self.index,
            "before_mutation": self.before_mutation,
            "after_mutation": self.after_mutation
        }

        return self_dict
Beispiel #8
0
        # add constants
        rows = len(config["data"]["y"])
        # for i in range(11):
        #     config["data"][str(i) + ".0"] = [float(i) for j in range(rows)]
        config["data"]["1.0"] = [1.0 for j in range(rows)]

        # import pprint
        # pprint.pprint(config)

        json_store = JSONStore(config)
        functions = [
            funcs.add_function, funcs.sub_function, funcs.mul_function,
            funcs.div_function, funcs.sin_function, funcs.cos_function,
            funcs.rad_function
        ]
        generator = CartesianGenerator(config)

        # genetic operators
        selection = Selection(config, recorder=json_store)
        mutation = CartesianMutation(config)

        # run symbolic regression
        population = generator.init()

        start_time = time.time()
        details = play.play_details(population=population,
                                    evaluate=evaluate,
                                    functions=functions,
                                    selection=selection,
                                    mutation=mutation,
                                    print_func=print_func,
Beispiel #9
0
class CartesianMutation(object):
    def __init__(self, config, **kwargs):
        self.config = config
        self.record_config = config.get("recorder", None)
        self.recorder = kwargs.get("recorder", None)
        self.generator = CartesianGenerator(config)

        # mutation stats
        self.method = None
        self.mutation_probability = None
        self.random_probability = None
        self.mutated = False
        self.before_mutation = None
        self.after_mutation = None

    def mutate_new_func_gene(self, old_gene):
        retry = 0
        retry_limit = 10
        new_gene = old_gene

        while new_gene == old_gene and retry < retry_limit:
            new_gene = self.generator.gen_random_func_gene()
            retry += 1

        if new_gene == old_gene:
            err = "Error! Failed to mutate new function gene!"
            raise RuntimeError(err)
        else:
            return new_gene

    def mutate_new_conn_gene(self, old_gene, node_addr):
        retry = 0
        retry_limit = 20
        new_gene = old_gene

        while new_gene == old_gene and retry < retry_limit:
            new_gene = self.generator.gen_random_conn_gene(node_addr)
            retry += 1

        if new_gene == old_gene:
            err = "Error! Failed to mutate new function gene!"
            raise RuntimeError(err)
        else:
            return new_gene

    def mutate_function_node(self, node_addr, cartesian):
        # pick random function gene
        node = cartesian.graph()[node_addr]
        gene_index = randint(0, len(node) - 1)
        new_gene = None

        # mutate function gene
        if gene_index == 0:
            old_gene = node[gene_index]
            new_gene = self.mutate_new_func_gene(old_gene)

            old_arity = self.config["function_nodes"][old_gene]["arity"]
            new_arity = self.config["function_nodes"][new_gene]["arity"]

            if old_arity < new_arity:
                for i in range(old_arity - new_arity):
                    conn_gene = self.generator.gen_random_conn_gene(node_addr)
                    cartesian.graph()[node_addr].append(conn_gene)
            else:
                for i in range(new_arity - old_arity):
                    cartesian.graph()[node_addr].pop()

        # mutate connection gene
        else:
            old_gene = node[gene_index]
            new_gene = self.mutate_new_conn_gene(old_gene, node_addr)

        # return
        cartesian.graph()[node_addr][gene_index] = new_gene
        return gene_index

    def mutate_output_node(self, node_index, cartesian):
        retry = 0
        retry_limit = 20
        old_node_addr = cartesian.output_nodes[node_index]
        new_node_addr = old_node_addr

        # pick random input node or func node
        while new_node_addr == old_node_addr and retry < retry_limit:
            new_node_addr = randint(0, len(cartesian.graph()) - 1)
            retry += 1

        # mutate output node
        cartesian.output_nodes[node_index] = new_node_addr

        if retry == retry_limit:
            return None
        else:
            return new_node_addr

    def point_mutation(self, cartesian):
        result = None
        num_inputs = self.config["cartesian"]["num_inputs"]
        num_outputs = self.config["cartesian"]["num_outputs"]
        num_funcs = len(cartesian.func_nodes)
        max_addr = num_inputs + num_funcs + num_outputs - 1

        # chose random node
        node_addr = randint(num_inputs, max_addr)

        # mutate function node
        if node_addr < num_inputs + num_funcs:
            # convert index to node_addr in cartesian graph and mutate
            gene_index = self.mutate_function_node(node_addr, cartesian)
            result = {
                "mutated_node": "FUNC_NODE",
                "node_addr": node_addr,
                "gene_index": gene_index
            }

        # mutate output node
        else:
            # convert index to output node index and mutate
            node_index = node_addr - num_inputs - num_funcs
            new_addr = self.mutate_output_node(node_index, cartesian)
            result = {
                "mutated_node": "OUTPUT_NODE",
                "output_node": node_index,
                "new_addr": new_addr
            }

        # check result
        if result is None:
            self.mutated = False
        else:
            self.mutated = True
            self.index = result

    def mutate(self, cartesian):
        mutation_methods = {"POINT_MUTATION": self.point_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 = copy.deepcopy(cartesian.program())

        # mutate
        if self.mutation_probability >= self.random_probability:
            mutation_func = mutation_methods[self.method]
            mutation_func(cartesian)

        # record after mutation
        self.after_mutation = copy.deepcopy(cartesian.program())

        # record
        if self.recorder is not None:
            self.recorder.record(RecordType.MUTATION, self)

    def to_dict(self):
        self_dict = {
            "method": self.method,
            "mutation_probability": self.mutation_probability,
            "random_probability": self.random_probability,
            "mutated": self.mutated,
            "index": self.index,
            "before_mutation": self.before_mutation,
            "after_mutation": self.after_mutation
        }

        return self_dict