0

I've been generating cellular automaton with the following Python code. I'm trying to find reversible second-order automata for the second phase of the project but am having trouble understanding the core concept.

Would I map the time steps of the neighborhoods to a new neighborhood or at the cellular level like with forward evolution?

import itertools
from enum import Enum

import matplotlib.pyplot as plt


class BoundaryConfig(Enum):
    ZERO = 0,
    CYCLIC = 1


class NeighborhoodBiasing(Enum):
    LHS = 0,
    RHS = 1


class RuleOfInteraction(Enum):
    # Mapping of binary numbers to neighborhood state
    NEIGHBORHOOD_SET = "neighborhood_set"


class NeighborhoodBias(Enum):
    LHS = 0
    RHS = 1


class GatewayKey():
    def __init__(self, cells, neighborhood_sites):
        self.interaction = RuleOfInteraction.NEIGHBORHOOD_SET
        self.neighborhood_sites = neighborhood_sites
        self.neighborhood_states = [seq for seq in itertools.product([0, 1], repeat=self.neighborhood_sites)]
        self.num_states = len(self.neighborhood_states)
        # TODO: Accomodate higher dimensionality, see self.dimensionality
        self.total_cells = len(cells)
        self.initial_config = cells
        self.boundary_config = BoundaryConfig.ZERO
        self.neighbohood_bias = NeighborhoodBias.RHS


class CA:
    def __init__(self, total_cells, neighborhood_sites):
        # Create initial state all true with midway point off
        self.state = [1] * total_cells
        self.state[total_cells // 2] = 0
        # Snapshot initial config
        self.config = GatewayKey(self.state, neighborhood_sites)

    # TODO: Higher dimensionality
    def get_neighbor_sites(self, cell: int) -> []:
        """
        Get neighborhood sites (neighbors + cell itself) with biasing for left hand side
        on even numbers, or shifting and grabbing the rightmost
        :param cell:
        :return:
        """
        distance = self.config.neighborhood_sites // 2
        lhs = cell - distance
        rhs = cell + distance
        neighborhood = []
        if self.config.neighborhood_sites % 2:
            if self.config.neighbohood_bias == NeighborhoodBias.LHS:
                lhs -= 1
            else:
                rhs += 1
        if self.config.boundary_config == BoundaryConfig.CYCLIC:
            if lhs < 0:
                neighborhood += self.state[lhs:] + self.state[:rhs]
            elif rhs > self.config.total_cells:
                rhs = -(self.config.total_cells - rhs)
                neighborhood += self.state[lhs:] + self.state[:rhs]
            else:
                neighborhood += self.state[lhs:rhs]
        elif self.config.boundary_config == BoundaryConfig.ZERO:
            if lhs < 0:
                neighborhood += ([0] * abs(lhs)) + self.state[:rhs]
            elif rhs > self.config.total_cells:
                rhs = -(self.config.total_cells - rhs)
                neighborhood += self.state[lhs:] + ([0] * rhs)
            else:
                neighborhood += self.state[lhs:rhs]
        print("Neighborhood:", neighborhood)
        return neighborhood

    def rule_of_interaction(self, cell, rule) -> int:
        """
        Interaction with a single cell in the automaton state
        :param cell: index of cell in state
        :param rule: bit-mapping rule to apply
        :return: new cell state
        """
        print("Rule: ", rule)
        print("Cell: ", cell)
        neighbors = self.get_neighbor_sites(cell)
        if self.config.interaction == RuleOfInteraction.NEIGHBORHOOD_SET:
            neighbors_tuple = tuple(neighbors)
            bit_offset = self.config.neighborhood_states.index(neighbors_tuple)
            new_cell_state = (rule >> bit_offset) & 1
            return new_cell_state
        else:
            raise NotImplementedError


if __name__ == "__main__":
    GRID_SIZE = 31
    EPOCHS = 15
    NEIGHBORHOOD_SITES = 4

    ca = CA(GRID_SIZE, NEIGHBORHOOD_SITES)

    print(ca.config.neighborhood_states)
    print(ca.config.num_states)

    for rule in range(2 ** ca.config.num_states):
        state_history = [ca.config.initial_config]
        state_transitions = []
        ca.state = ca.config.initial_config
        for epoch in range(EPOCHS):
            # capture previous state
            new_state = ca.state.copy()
            for cell in range(GRID_SIZE):
                new_state[cell] = ca.rule_of_interaction(cell, rule)
            ca.state = new_state
            state_history.append(ca.state)
        print(state_history)
        # If wanting to save JPEGs
        plt.imsave('img/{}.png'.format(rule), state_history)

  • I'd like to help, but I can't really understand what you're asking in your second paragraph. Clearly there's a mutual terminology barrier of some kind here. I'd also like to suggest that, if you're looking for help in "understanding the core concept", your question might be better suited for [cs.se] rather than for Stack Overflow. – Ilmari Karonen Dec 08 '21 at 00:30
  • Whichever site you ask it on, though, dumping a pile of code into your question with no explanation of what you want it to do and how it's not doing what you want isn't very useful. There are some tips in the [help center](/help/how-to-ask) on how to ask a good question that you might want to take a look at. – Ilmari Karonen Dec 08 '21 at 00:33

0 Answers0