lantunes / cellpylib

A library for working with Cellular Automata, for Python.
https://cellpylib.org
Apache License 2.0
228 stars 32 forks source link

Add a typecheck in the binary_rule method allowing a binary array as … #4

Closed swifmaneum closed 3 years ago

swifmaneum commented 3 years ago

…rule; Adding an additional parameter powers_of_two to the binary_rule method allowing faster computation

lantunes commented 3 years ago

Here are a few test cases we can add (to test_cellpylib.py):

def test_binary_rule(self):
    rule_number = 6667021275756174439087127638698866559
    radius = 3
    timesteps = 12
    init = np.array([[1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1]])

    actual = cpl.evolve(init, timesteps=timesteps,
                        apply_rule=lambda n, c, t: cpl.binary_rule(n, rule_number), r=radius)

    expected = np.array([[1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1],
                         [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1],
                         [1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1],
                         [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0],
                         [0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1],
                         [1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0],
                         [0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1],
                         [1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0],
                         [0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1],
                         [1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                         [1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                         [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])
    np.testing.assert_equal(expected.tolist(), actual.tolist())

def test_binary_rule_powers_of_two_nks(self):
    rule_number = 30
    radius = 1
    size = 149
    timesteps = 149

    expected = cpl.evolve(cpl.init_simple(size=size), timesteps=timesteps,
                          apply_rule=lambda n, c, t: cpl.binary_rule(n, rule_number, scheme="nks"), r=radius)

    powers_of_two = 2 ** np.arange(radius * 2 + 1)[::-1]
    rule = list(map(int, bin(rule_number)[2:]))
    rule_bin_array = np.pad(rule, ((2 ** (radius * 2 + 1)) - len(rule), 0), 'constant').tolist()
    actual = cpl.evolve(cpl.init_simple(size=size), timesteps=timesteps,
                        apply_rule=lambda n, c, t: cpl.binary_rule(n, rule_bin_array, scheme="nks", powers_of_two=powers_of_two),
                        r=radius)

    np.testing.assert_equal(expected.tolist(), actual.tolist())

def test_binary_rule_powers_of_two_default(self):
    rule_number = 6667021275756174439087127638698866559
    radius = 3
    timesteps = 49
    init = np.array([[1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0,
            1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1]])

    expected = cpl.evolve(init, timesteps=timesteps,
                          apply_rule=lambda n, c, t: cpl.binary_rule(n, rule_number), r=radius)

    powers_of_two = 2 ** np.arange(radius * 2 + 1)[::-1]
    rule = list(map(int, bin(rule_number)[2:]))
    rule_bin_array = np.pad(rule, ((2 ** (radius * 2 + 1)) - len(rule), 0), 'constant')
    actual = cpl.evolve(init, timesteps=timesteps,
                        apply_rule=lambda n, c, t: cpl.binary_rule(n, rule_bin_array, powers_of_two=powers_of_two),
                        r=radius)

    np.testing.assert_equal(expected.tolist(), actual.tolist())

I also changed your implementation of binary_rule locally, on line 98, before running the tests above:

if isinstance(rule, (list, np.ndarray)):
    assert len(rule) == n
    rule_bin_array = rule
swifmaneum commented 3 years ago

I added your suggestions. Right now there's only the assert len(rule) == n for checking that the rule array is sized correctly but I agree that we could add a check and pad the rule array if necessary. I also added an additional assert ensuring that powers_of_two has the right size.

lantunes commented 3 years ago

I added your suggestions. Right now there's only the assert len(rule) == n for checking that the rule array is sized correctly but I agree that we could add a check and pad the rule array if necessary. I also added an additional assert ensuring that powers_of_two has the right size.

Sounds good, thank you for contributing this!

lantunes commented 3 years ago

closes #3