Example #1
0
def test_reset_parameters_upon_creation_of_node(rng):
    class CustomParameter(cgp.Parameter):
        _initial_values = {"<p>": lambda: np.pi}

    genome_params = {
        "n_inputs": 1,
        "n_outputs": 1,
        "n_columns": 1,
        "n_rows": 1,
    }
    primitives = (CustomParameter, CustomParameter)
    genome = cgp.Genome(**genome_params, primitives=primitives)
    # f(x) = p
    genome.dna = [ID_INPUT_NODE, ID_NON_CODING_GENE, 0, 0, ID_OUTPUT_NODE, 1]
    genome._parameter_names_to_values["<p1>"] = 1.0

    f = cgp.CartesianGraph(genome).to_func()
    y = f(0.0)
    assert y == pytest.approx(1.0)

    # now mutate the genome, since there is only one other option for
    # the hidden node, a new CustomParameter node will be created;
    # creating this new node should reset the parameter to its initial
    # value; after mutation we recreate the correct graph connectivity
    # manually
    genome.mutate(1.0, rng)
    # f(x) = p
    genome.dna = [ID_INPUT_NODE, ID_NON_CODING_GENE, 0, 0, ID_OUTPUT_NODE, 1]

    f = cgp.CartesianGraph(genome).to_func()
    y = f(0.0)
    assert y == pytest.approx(np.pi)
Example #2
0
    def _objective(individual):

        if individual.fitness is not None:
            return individual

        def f0(x):
            return x[0] * (x[0] + x[0])

        def f1(x):
            return (x[0] * x[1]) - x[1]

        y0 = cgp.CartesianGraph(individual.genome[0]).to_func()
        y1 = cgp.CartesianGraph(individual.genome[1]).to_func()

        loss = 0
        for _ in range(100):

            x0 = np.random.uniform(size=1)
            x1 = np.random.uniform(size=2)

            loss += float((f0(x0) - y0(x0))**2)
            loss += float((f1(x1) - y1(x1))**2)
        individual.fitness = -loss

        return individual
Example #3
0
    def _objective(individual):

        if not individual.fitness_is_None():
            return individual

        rng = np.random.RandomState(rng_seed)

        def f0(x):
            return x[0] * (x[0] + x[0])

        def f1(x):
            return (x[0] * x[1]) - x[1]

        y0 = cgp.CartesianGraph(individual.genome[0]).to_func()
        y1 = cgp.CartesianGraph(individual.genome[1]).to_func()

        loss = 0
        for _ in range(100):

            x0 = rng.uniform(size=1)
            x1 = rng.uniform(size=2)

            loss += float((f0(x0) - y0(x0))**2)
            loss += float((f1(x1) - y1(x1[0], x1[1]))**2)
        individual.fitness = -loss

        return individual
def test_to_func_simple():
    primitives = (cgp.Add, )
    genome = cgp.Genome(2, 1, 1, 1, primitives)

    genome.dna = [
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        0,
        0,
        1,
        ID_OUTPUT_NODE,
        2,
        ID_NON_CODING_GENE,
    ]
    graph = cgp.CartesianGraph(genome)
    f = graph.to_func()

    x = [5.0, 2.0]
    y = f(*x)

    assert x[0] + x[1] == pytest.approx(y)

    primitives = (cgp.Sub, )
    genome = cgp.Genome(2, 1, 1, 1, primitives)

    genome.dna = [
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        0,
        0,
        1,
        ID_OUTPUT_NODE,
        2,
        ID_NON_CODING_GENE,
    ]
    graph = cgp.CartesianGraph(genome)
    f = graph.to_func()

    x = [5.0, 2.0]
    y = f(*x)

    assert x[0] - x[1] == pytest.approx(y)
def test_compile_torch_output_shape(genome, batch_size):
    torch = pytest.importorskip("torch")

    c = cgp.CartesianGraph(genome).to_torch()
    x = torch.Tensor(batch_size, 1).normal_()
    y = c(x)
    assert y.shape == (batch_size, genome._n_outputs)
Example #6
0
def test_multiple_parameters_per_node():

    p = 3.1415
    q = 2.7128

    class DoubleParameter(cgp.OperatorNode):
        _arity = 0
        _initial_values = {"<p>": lambda: p, "<q>": lambda: q}
        _def_output = "<p> + <q>"
        _def_numpy_output = "np.ones(len(x[0])) * (<p> + <q>)"
        _def_torch_output = "torch.ones(1).expand(x.shape[0]) * (<p> + <q>)"

    genome_params = {
        "n_inputs": 1,
        "n_outputs": 1,
        "n_columns": 1,
        "n_rows": 1,
    }
    primitives = (DoubleParameter, )
    genome = cgp.Genome(**genome_params, primitives=primitives)
    # f(x) = p + q
    genome.dna = [ID_INPUT_NODE, ID_NON_CODING_GENE, 0, 0, ID_OUTPUT_NODE, 1]
    f = cgp.CartesianGraph(genome).to_func()
    y = f(0.0)

    assert y == pytest.approx(p + q)
def test_allow_sympy_expr_with_infinities():
    pytest.importorskip("sympy")

    primitives = (cgp.Sub, cgp.Div)
    genome = cgp.Genome(1, 1, 2, 1, primitives, 1)

    # x[0] / (x[0] - x[0])
    genome.dna = [
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        0,
        0,
        0,
        1,
        0,
        1,
        ID_OUTPUT_NODE,
        2,
        ID_NON_CODING_GENE,
    ]
    graph = cgp.CartesianGraph(genome)

    expr = graph.to_sympy(simplify=True)
    # complex infinity should appear in expression
    assert "zoo" in str(expr)
def test_pretty_str():
    primitives = (cgp.Sub, cgp.Mul)
    genome = cgp.Genome(1, 1, 2, 1, primitives, 1)

    # x[0] ** 2
    genome.dna = [
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        0,
        0,
        0,
        1,
        0,
        0,
        ID_OUTPUT_NODE,
        2,
        ID_NON_CODING_GENE,
    ]
    graph = cgp.CartesianGraph(genome)

    pretty_str = graph.pretty_str()

    for node in graph.input_nodes:
        assert node.__class__.__name__ in pretty_str
    for node in graph.output_nodes:
        assert node.__class__.__name__ in pretty_str
    for node in graph.hidden_nodes:
        assert node.__class__.__name__ in pretty_str
def test_compile_two_columns():
    primitives = (cgp.Add, cgp.Sub)
    genome = cgp.Genome(2, 1, 2, 1, primitives, 1)

    genome.dna = [
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        0,
        0,
        1,
        1,
        0,
        2,
        ID_OUTPUT_NODE,
        3,
        ID_NON_CODING_GENE,
    ]
    graph = cgp.CartesianGraph(genome)
    f = graph.to_func()

    x = [5.0, 2.0]
    y = f(*x)

    assert x[0] - (x[0] + x[1]) == pytest.approx(y)
Example #10
0
def test_parameter_w_random_initial_value(rng_seed):
    np.random.seed(rng_seed)

    min_val = 0.5
    max_val = 1.5

    class CustomParameter(cgp.Parameter):
        _initial_values = {"<p>": lambda: np.random.uniform(min_val, max_val)}

    genome_params = {
        "n_inputs": 1,
        "n_outputs": 1,
        "n_columns": 1,
        "n_rows": 1,
    }
    primitives = (CustomParameter, )
    genome = cgp.Genome(**genome_params, primitives=primitives)
    # f(x) = c
    genome.dna = [ID_INPUT_NODE, ID_NON_CODING_GENE, 0, 0, ID_OUTPUT_NODE, 1]
    f = cgp.CartesianGraph(genome).to_func()
    y = f(0.0)

    assert min_val <= y
    assert y <= max_val
    assert y != pytest.approx(1.0)
Example #11
0
def test_mul():
    params = {"n_inputs": 2, "n_outputs": 1, "n_columns": 1, "n_rows": 1, "levels_back": 1}

    primitives = (cgp.Mul,)
    genome = cgp.Genome(
        params["n_inputs"],
        params["n_outputs"],
        params["n_columns"],
        params["n_rows"],
        params["levels_back"],
        primitives,
    )
    genome.dna = [
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        0,
        0,
        1,
        ID_OUTPUT_NODE,
        2,
        ID_NON_CODING_GENE,
    ]
    graph = cgp.CartesianGraph(genome)

    x = [5.0, 1.5]
    y = graph(x)

    assert x[0] * x[1] == pytest.approx(y[0])
Example #12
0
def test_constant_float():
    params = {"n_inputs": 2, "n_outputs": 1, "n_columns": 1, "n_rows": 1, "levels_back": 1}

    primitives = (cgp.ConstantFloat,)
    genome = cgp.Genome(
        params["n_inputs"],
        params["n_outputs"],
        params["n_columns"],
        params["n_rows"],
        params["levels_back"],
        primitives,
    )
    genome.dna = [
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        0,
        0,
        ID_OUTPUT_NODE,
        2,
    ]
    graph = cgp.CartesianGraph(genome)

    x = [None, None]
    y = graph(x)

    # by default the output value of the ConstantFloat node is 1.0
    assert 1.0 == pytest.approx(y[0])
def test_to_numpy():
    primitives = (cgp.Add, cgp.Mul, cgp.ConstantFloat)
    genome = cgp.Genome(1, 1, 2, 2, primitives, 1)
    # f(x) = x ** 2 + 1.
    genome.dna = [
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        2,
        0,
        0,
        1,
        0,
        0,
        0,
        1,
        2,
        0,
        0,
        1,
        ID_OUTPUT_NODE,
        3,
        ID_NON_CODING_GENE,
    ]
    graph = cgp.CartesianGraph(genome)
    f = graph.to_numpy()

    x = np.random.normal(size=100)
    y = f(x)
    y_target = x**2 + 1.0

    assert y == pytest.approx(y_target)
Example #14
0
def objective(individual, n_trials, simulate_func, exp_params, input_spikes,
              synapse_params):
    """Objective function of the evolution.

    Evaluates the fitness of a given individual in a number of trials
    and sets the fitness of the individual.

    Parameters
    ----------
    individual : cgp.IndividualMultiGenome
        Individual to be evaluated.
    n_trials : int
        Number of trials that the invidiual is evaluated on.
    simulate_func : Callable
        Function executing the NEST simulation.
    exp_params : dict
        Dictionary holding the experiment parameters.
    input_spikes : list
        List of input spikes for each trial. Each item is a list of
        numpy arrays defining the spikes of each input neurons.
    synapse_params : dict
        Dictionary holding the synapse parameters.

    Returns
    -------
    cgp.IndividualMultiGenome
        Individual with updated fitness.
    """

    if individual.fitness is not None:
        return individual

    graph = [cgp.CartesianGraph(genome) for genome in individual.genome]
    try:
        sympy_expr = [str(g.to_sympy(simplify=True)[0]) for g in graph]
    except cgp.InvalidSympyExpression:
        individual.fitness = -np.inf
        return individual

    @cgp.utils.disk_cache("cache.pkl")
    def inner_objective(exp_params, synapse_params, input_spikes, sympy_expr):
        SNR = []
        for i in range(n_trials):
            SNR.append(
                simulate_func(
                    sympy_expr,
                    exp_params=exp_params,
                    input_spikes=input_spikes[i],
                    synapse_params=synapse_params[i],
                ))
        fitness = np.min(SNR)
        return fitness

    # return the updated individual
    individual.fitness = inner_objective(exp_params, synapse_params,
                                         input_spikes, sympy_expr)
    return individual
def test_compile_numpy_output_shape(genome, batch_size):

    c = cgp.CartesianGraph(genome).to_numpy()
    x = np.random.normal(size=batch_size)
    y = c(x)

    if genome._n_outputs == 1:
        assert y.shape == (batch_size, )
    else:
        assert len(y) == genome._n_outputs
        assert y[0].shape == (batch_size, )
def test_constant_float():
    params = {
        "n_inputs": 2,
        "n_outputs": 1,
        "n_columns": 1,
        "n_rows": 1,
        "levels_back": 1
    }

    val = 1.678

    primitives = (cgp.node_factories.ConstantFloatFactory(val), )
    genome = cgp.Genome(
        params["n_inputs"],
        params["n_outputs"],
        params["n_columns"],
        params["n_rows"],
        params["levels_back"],
        primitives,
    )
    genome.dna = [
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        0,
        0,
        ID_OUTPUT_NODE,
        2,
    ]
    graph = cgp.CartesianGraph(genome)

    x = [None, None]
    y = graph(x)

    assert val == pytest.approx(y[0])

    # make sure different classes are created for multiple calls to the class
    # factory
    prim_0 = cgp.node_factories.ConstantFloatFactory(val)(0, [None])
    prim_1 = cgp.node_factories.ConstantFloatFactory(val)(0, [None])

    assert prim_0 is not prim_1

    prim_1._output = 2 * val

    assert val == pytest.approx(prim_0._output)
    assert 2 * val == pytest.approx(prim_1._output)
def test_compile_addsubmul():
    params = {
        "n_inputs": 2,
        "n_outputs": 1,
        "n_columns": 2,
        "n_rows": 2,
        "levels_back": 1
    }

    primitives = (cgp.Add, cgp.Sub, cgp.Mul)
    genome = cgp.Genome(
        params["n_inputs"],
        params["n_outputs"],
        params["n_columns"],
        params["n_rows"],
        primitives,
        params["levels_back"],
    )
    genome.dna = [
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        2,
        0,
        1,
        1,
        0,
        1,
        1,
        2,
        3,
        0,
        0,
        0,
        ID_OUTPUT_NODE,
        4,
        ID_NON_CODING_GENE,
    ]
    graph = cgp.CartesianGraph(genome)
    f = graph.to_func()

    x = [5.0, 2.0]
    y = f(*x)

    assert (x[0] * x[1]) - (x[0] - x[1]) == pytest.approx(y)
Example #18
0
def test_input_dim_python(rng):

    genome = cgp.Genome(2, 1, 1, 1, (cgp.ConstantFloat, ))
    genome.randomize(rng)
    f = cgp.CartesianGraph(genome).to_func()

    # fail for too short input
    with pytest.raises(ValueError):
        f(None)

    # fail for too long input
    with pytest.raises(ValueError):
        f(None, None, None)

    # do not fail for input with correct length
    f(None, None)
Example #19
0
def test_mutate_hidden_region(rng_seed):
    rng = np.random.RandomState(rng_seed)
    genome = cgp.Genome(1, 1, 3, 1, None, (cgp.Add, cgp.ConstantFloat))
    dna = [
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        1,
        0,
        0,
        1,
        0,
        0,
        0,
        0,
        2,
        ID_OUTPUT_NODE,
        3,
        ID_NON_CODING_GENE,
    ]
    genome.dna = list(dna)
    active_regions = cgp.CartesianGraph(genome).determine_active_regions()

    # mutating any gene in inactive region returns True
    genome.dna = list(dna)
    assert genome._mutate_hidden_region(3, active_regions, rng) is True
    genome.dna = list(dna)
    assert genome._mutate_hidden_region(4, active_regions, rng) is True
    genome.dna = list(dna)
    assert genome._mutate_hidden_region(5, active_regions, rng) is True

    # mutating function gene in active region returns False
    genome.dna = list(dna)
    assert genome._mutate_hidden_region(6, active_regions, rng) is False
    # mutating inactive genes in active region returns True
    genome.dna = list(dna)
    assert genome._mutate_hidden_region(7, active_regions, rng) is True
    genome.dna = list(dna)
    assert genome._mutate_hidden_region(8, active_regions, rng) is True

    # mutating any gene in active region without silent genes returns False
    genome.dna = list(dna)
    assert genome._mutate_hidden_region(9, active_regions, rng) is False
    genome.dna = list(dna)
    assert genome._mutate_hidden_region(10, active_regions, rng) is False
    genome.dna = list(dna)
    assert genome._mutate_hidden_region(11, active_regions, rng) is False
def test_direct_input_output():
    params = {"n_inputs": 1, "n_outputs": 1, "n_columns": 3, "n_rows": 3, "levels_back": 2}
    primitives = (cgp.Add, cgp.Sub)
    genome = cgp.Genome(
        params["n_inputs"],
        params["n_outputs"],
        params["n_columns"],
        params["n_rows"],
        params["levels_back"],
        primitives,
    )
    genome.randomize(np.random)

    genome[-2:] = [0, ID_NON_CODING_GENE]  # set inputs for output node to input node
    graph = cgp.CartesianGraph(genome)

    x = [2.14159]
    y = graph(x)

    assert x[0] == pytest.approx(y[0])
Example #21
0
def test_input_dim_numpy(rng):

    genome = cgp.Genome(2, 1, 1, 1, (cgp.ConstantFloat, ))
    genome.randomize(rng)
    f = cgp.CartesianGraph(genome).to_numpy()

    # # fail for missing batch dimension
    # with pytest.raises(ValueError):
    #     f(np.array([1.0]))

    # fail for too short input
    with pytest.raises(ValueError):
        f(np.array([1.0]))

    # fail for too long input
    with pytest.raises(ValueError):
        f(np.array([1.0]), np.array([1.0]), np.array([1.0]))

    # do not fail for input with correct shape
    f(np.array([1.0]), np.array([1.0]))
Example #22
0
def test_input_dim_torch(rng):
    torch = pytest.importorskip("torch")

    genome = cgp.Genome(2, 1, 1, 1, (cgp.ConstantFloat, ))
    genome.randomize(rng)
    f = cgp.CartesianGraph(genome).to_torch()

    # fail for missing batch dimension
    with pytest.raises(ValueError):
        f(torch.Tensor([1.0]))

    # fail for too short input
    with pytest.raises(ValueError):
        f(torch.Tensor([1.0]).reshape(-1, 1))

    # fail for too long input
    with pytest.raises(ValueError):
        f(torch.Tensor([1.0, 1.0, 1.0]).reshape(-1, 3))

    # do not fail for input with correct shape
    f(torch.Tensor([1.0, 1.0]).reshape(-1, 2))
def test_input_dim_numpy(rng_seed):
    rng = np.random.RandomState(rng_seed)

    genome = cgp.Genome(2, 1, 1, 1, 1, (cgp.ConstantFloat,))
    genome.randomize(rng)
    f = cgp.CartesianGraph(genome).to_numpy()

    # fail for missing batch dimension
    with pytest.raises(ValueError):
        f(np.array([1.0]))

    # fail for too short input
    with pytest.raises(ValueError):
        f(np.array([1.0]).reshape(-1, 1))

    # fail for too long input
    with pytest.raises(ValueError):
        f(np.array([1.0, 1.0, 1.0]).reshape(-1, 3))

    # do not fail for input with correct shape
    f(np.array([1.0, 1.0]).reshape(-1, 2))
def test_to_sympy():
    sympy = pytest.importorskip("sympy")

    primitives = (cgp.Add, cgp.ConstantFloat)
    genome = cgp.Genome(1, 1, 2, 2, primitives, 1)

    # f = x_0 + x_0 + 1.0
    genome.dna = [
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        1,
        2,
        0,
        0,
        1,
        ID_OUTPUT_NODE,
        3,
        ID_NON_CODING_GENE,
    ]
    graph = cgp.CartesianGraph(genome)

    y_0_target = sympy.sympify("x_0 + x_0 + 1.0", evaluate=False)
    y_0 = graph.to_sympy(simplify=False)
    assert y_0_target == y_0

    y_0_target = sympy.sympify("2 * x_0 + 1.0", evaluate=True)
    y_0 = graph.to_sympy()
    assert y_0_target == y_0

    for x in np.random.normal(size=100):
        assert y_0_target.subs("x_0", x).evalf() == pytest.approx(
            y_0.subs("x_0", x).evalf())
def test_allow_powers_of_x_0():
    pytest.importorskip("sympy")

    primitives = (cgp.Sub, cgp.Mul)
    genome = cgp.Genome(1, 1, 2, 1, primitives, 1)

    # x[0] ** 2
    genome.dna = [
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        0,
        0,
        0,
        1,
        0,
        0,
        ID_OUTPUT_NODE,
        2,
        ID_NON_CODING_GENE,
    ]
    graph = cgp.CartesianGraph(genome)
    graph.to_sympy(simplify=True)
def test_to_sympy():
    sympy = pytest.importorskip("sympy")

    primitives = (cgp.Add, cgp.ConstantFloat)
    genome = cgp.Genome(1, 1, 2, 2, 1, primitives)

    genome.dna = [
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        1,
        0,
        0,
        1,
        0,
        0,
        0,
        0,
        1,
        0,
        0,
        1,
        ID_OUTPUT_NODE,
        3,
        ID_NON_CODING_GENE,
    ]
    graph = cgp.CartesianGraph(genome)

    x_0_target, y_0_target = sympy.symbols("x_0_target y_0_target")
    y_0_target = x_0_target + 1.0

    y_0 = graph.to_sympy()[0]

    for x in np.random.normal(size=100):
        assert pytest.approx(
            y_0_target.subs("x_0_target", x).evalf() == y_0.subs("x_0", x).evalf()
        )
            "pc0": pc0,
            #"pc0_empirical": pc0_empirical
        })

    [history,
     champion] = evolution(data=data,
                           population_params=params['population_params'],
                           genome_params=params['genome_params'],
                           ea_params=params['ea_params'],
                           evolve_params=params['evolve_params'],
                           learning_rate=learning_rate,
                           alpha=alpha,
                           fitness_mode=fitness_mode)

    # evaluate weights of champion (not passed down for non-re-evaluated champion)
    champion_learning_rule = cgp.CartesianGraph(champion.genome).to_numpy()
    champion_fitness, champion_weights_per_dataset = calculate_fitness(
        individual=champion,
        data=data,
        learning_rate=learning_rate,
        alpha=alpha,
        mode=fitness_mode,
    )

    # evaluate hypothetical fitness of oja rule
    oja_fitness, oja_weights_per_dataset = calculate_fitness(
        individual=ind_oja_min,
        data=data,
        learning_rate=learning_rate,
        alpha=alpha,
        mode=fitness_mode)
Example #28
0
def test_genome_reordering_empirically(rng):
    # empirically test that reordering does not change the output function of a genome

    pytest.importorskip("sympy")

    genome_params = {
        "n_inputs":
        2,
        "n_outputs":
        1,
        "n_columns":
        14,
        "n_rows":
        1,
        "primitives":
        (cgp.Mul, cgp.Sub, cgp.Add, cgp.ConstantFloat, cgp.Parameter),
    }

    genome = cgp.Genome(**genome_params)

    # f(x_0, x_1) = x_0 ** 2 - x_1 + 1 + 0.5
    dna_fixed = [
        ID_INPUT_NODE,  # x_0 (address 0)
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        ID_INPUT_NODE,  # x_1 (address 1)
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        0,  # Mul ->  x_0^2 (address 2)
        0,  # x
        0,  # x
        1,  # Sub -> x_0^2 - x_1 (address 3)
        2,  # x^2
        1,  # y
        1,  # Sub ->  0 (address 4)
        0,  # x
        0,  # x
        3,  # const -> 1 (address 5)
        2,
        3,
        3,  # const -> 1 (address 6)
        0,
        0,
        4,  # param -> 0.9 (address 7)
        4,
        3,
        4,  # param -> 0.4 (address 8)
        7,
        2,
        2,  # Add -> x_0^2 - x_1 + 1 (address 9)
        3,  # x_0^2 - x_1
        5,  # 1
        1,  # Sub -> x_0^2 - x_1 + 1 - 0.9 (address 10)
        9,  # x_0^2 - x_1 + 1
        7,  # 0.9
        2,  # Add -> x_0^2 - x_1 + 1 - 0.9 + 0.4 (address 11)
        10,  # x_0^2 - x_1 + 1 - 0.9
        8,  # 0.4
        3,  # const (address 12)
        0,
        1,
        3,  # const (address 13)
        0,
        1,
        3,  # const (address 14)
        0,
        1,
        3,  # const (address 15)
        0,
        1,
        ID_OUTPUT_NODE,
        11,
        ID_NON_CODING_GENE,
    ]

    genome.dna = dna_fixed
    genome._parameter_names_to_values["<p7>"] = 0.9
    genome._parameter_names_to_values["<p8>"] = 0.4

    sympy_expression = cgp.CartesianGraph(genome).to_sympy()
    n_reorderings = 100
    for _ in range(n_reorderings):
        genome.reorder(rng)
        new_graph = cgp.CartesianGraph(genome)
        sympy_expression_after_reorder = new_graph.to_sympy()
        assert sympy_expression_after_reorder == sympy_expression
def test_repr(rng, genome_params):
    genome = cgp.Genome(**genome_params)
    genome.randomize(rng)
    # Assert that the CartesianGraph.__repr__ doesn't raise an error
    str(cgp.CartesianGraph(genome))
def test_pretty_str_with_unequal_inputs_rows_outputs():
    primitives = (cgp.Add, )

    # less rows than inputs/outputs
    genome = cgp.Genome(1, 1, 1, 2, primitives)
    # f(x) = x[0] + x[0]
    genome.dna = [
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        0,
        0,
        0,
        0,
        0,
        0,
        ID_OUTPUT_NODE,
        1,
        ID_NON_CODING_GENE,
    ]
    graph = cgp.CartesianGraph(genome)

    expected_pretty_str = """
00 * InputNode          \t01 * Add (00,00)        \t03 * OutputNode (01)    \t
                        \t02   Add                \t                        \t
"""
    assert graph.pretty_str() == expected_pretty_str

    # more rows than inputs/outputs
    genome = cgp.Genome(3, 3, 1, 2, primitives)
    # f(x) = [x[0] + x[1], x[0] + x[1], x[1] + x[2]]
    genome.dna = [
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        ID_INPUT_NODE,
        ID_NON_CODING_GENE,
        ID_NON_CODING_GENE,
        0,
        0,
        1,
        0,
        1,
        2,
        ID_OUTPUT_NODE,
        3,
        ID_NON_CODING_GENE,
        ID_OUTPUT_NODE,
        3,
        ID_NON_CODING_GENE,
        ID_OUTPUT_NODE,
        4,
        ID_NON_CODING_GENE,
    ]
    graph = cgp.CartesianGraph(genome)

    expected_pretty_str = """
00 * InputNode          \t03 * Add (00,01)        \t05 * OutputNode (03)    \t
01 * InputNode          \t04 * Add (01,02)        \t06 * OutputNode (03)    \t
02 * InputNode          \t                        \t07 * OutputNode (04)    \t
"""
    assert graph.pretty_str() == expected_pretty_str