Substitute count_alive_neighbors function by sum

This commit is contained in:
timofej 2023-08-17 12:21:45 +02:00
parent 34794ffb7a
commit 7c488d2892
3 changed files with 123 additions and 17 deletions

View File

@ -18,4 +18,4 @@ limitations under the License.
from .neighborhood import Neighborhood, MooreNeighborhood, RadialNeighborhood, VonNeumannNeighborhood, \ from .neighborhood import Neighborhood, MooreNeighborhood, RadialNeighborhood, VonNeumannNeighborhood, \
HexagonalNeighborhood, EdgeRule HexagonalNeighborhood, EdgeRule
from .automaton import Neuropercolation, NeuropercolationCoupled from .automaton import Neuropercolation, NeuropercolationCoupled
from .display import Simulate2Layers from .display import Simulate2Layers, Simulate4Layers

View File

@ -123,7 +123,7 @@ class Neuropercolation(CellularAutomatonCreator, abc.ABC):
for coord, old, new in zip(this_state.keys(), this_state.values(), next_state.values()): for coord, old, new in zip(this_state.keys(), this_state.values(), next_state.values()):
coord_c = tuple([*coord[:2],int(1-coord[2])]) coord_c = tuple([*coord[:2],int(1-coord[2])])
old_c = this_state[coord_c] old_c = this_state[coord_c]
new_state = evolution_rule(old.state.copy(), old_c.state.copy(), [n.state for n in old.neighbors], coord[2], coord_c[2]) #inverse the inhibitory layer's action new_state = evolution_rule(old.state.copy(), old_c.state.copy(), [n.state[0] for n in old.neighbors], coord[2], coord_c[2]) #inverse the inhibitory layer's action
evolve_cell(old, new, new_state) evolve_cell(old, new, new_state)
@ -136,9 +136,9 @@ class Neuropercolation(CellularAutomatonCreator, abc.ABC):
def evolve_rule(self, last_cell_state, link_last_state, neighbors_last_states, cell_lay, link_cell_lay): def evolve_rule(self, last_cell_state, link_last_state, neighbors_last_states, cell_lay, link_cell_lay):
new_cell_state = last_cell_state new_cell_state = last_cell_state
if link_cell_lay==0: if link_cell_lay==0:
alive_neighbours = self.__count_alive_neighbours(neighbors_last_states)+link_last_state[0] # adjust for excitatory link cells alive_neighbours = sum(neighbors_last_states)+link_last_state[0] # adjust for excitatory link cells
else: else:
alive_neighbours = self.__count_alive_neighbours(neighbors_last_states)+(1-link_last_state[0]) # adjust for inhibitory link cells alive_neighbours = sum(neighbors_last_states)+(1-link_last_state[0]) # adjust for inhibitory link cells
CASE = (random.random()>=self.epsilon) CASE = (random.random()>=self.epsilon)
if alive_neighbours > 2: if alive_neighbours > 2:
@ -153,14 +153,6 @@ class Neuropercolation(CellularAutomatonCreator, abc.ABC):
new_cell_state = ALIVE new_cell_state = ALIVE
return new_cell_state return new_cell_state
@staticmethod
def __count_alive_neighbours(neighbours):
alive_neighbors = []
for n in neighbours:
if n == ALIVE:
alive_neighbors.append(1)
return len(alive_neighbors)
class NeuropercolationCoupled(CellularAutomatonCreator, abc.ABC): class NeuropercolationCoupled(CellularAutomatonCreator, abc.ABC):
def __init__(self, dim, eps, coupling=[], *args, **kwargs): def __init__(self, dim, eps, coupling=[], *args, **kwargs):
@ -206,11 +198,11 @@ class NeuropercolationCoupled(CellularAutomatonCreator, abc.ABC):
if coord[:2] in self.coupling: if coord[:2] in self.coupling:
coord_c = tuple([*coord[:2],coord[2],int(1-coord[3])]) coord_c = tuple([*coord[:2],coord[2],int(1-coord[3])])
old_c = this_state[coord_c] old_c = this_state[coord_c]
new_state = evolution_rule(old.state.copy(), old_c.state.copy(), [n.state for n in old.neighbors], 0) new_state = evolution_rule(old.state.copy(), old_c.state.copy(), [n.state[0] for n in old.neighbors], 0)
else: else:
coord_c = tuple([*coord[:2],int(1-coord[2]),coord[3]]) coord_c = tuple([*coord[:2],int(1-coord[2]),coord[3]])
old_c = this_state[coord_c] old_c = this_state[coord_c]
new_state = evolution_rule(old.state.copy(), old_c.state.copy(), [n.state for n in old.neighbors], coord_c[2]) #inverse the inhibitory layer's action new_state = evolution_rule(old.state.copy(), old_c.state.copy(), [n.state[0] for n in old.neighbors], coord_c[2]) #inverse the inhibitory layer's action
evolve_cell(old, new, new_state) evolve_cell(old, new, new_state)
@ -223,9 +215,9 @@ class NeuropercolationCoupled(CellularAutomatonCreator, abc.ABC):
def evolve_rule(self, last_cell_state, link_last_state, neighbors_last_states, other_layer): def evolve_rule(self, last_cell_state, link_last_state, neighbors_last_states, other_layer):
new_cell_state = last_cell_state new_cell_state = last_cell_state
if other_layer==0: if other_layer==0:
alive_neighbours = self.__count_alive_neighbours(neighbors_last_states)+link_last_state[0] # adjust for excitatory link cells alive_neighbours = sum(neighbors_last_states)+link_last_state[0] # adjust for excitatory link cells
else: else:
alive_neighbours = self.__count_alive_neighbours(neighbors_last_states)+(1-link_last_state[0]) # adjust for inhibitory link cells alive_neighbours = sum(neighbors_last_states)+(1-link_last_state[0]) # adjust for inhibitory link cells
CASE = (random.random()>=self.epsilon) CASE = (random.random()>=self.epsilon)
if alive_neighbours > 2: if alive_neighbours > 2:

View File

@ -113,6 +113,7 @@ class Simulate2Layers:
self.__draw_engine._pygame.quit() self.__draw_engine._pygame.quit()
except: except:
print('Failed to quit pygame') print('Failed to quit pygame')
def _sleep_to_keep_rate(self, time_taken, evolutions_per_second): # pragma: no cover def _sleep_to_keep_rate(self, time_taken, evolutions_per_second): # pragma: no cover
if evolutions_per_second > 0: if evolutions_per_second > 0:
rest_time = 1.0 / evolutions_per_second - time_taken rest_time = 1.0 / evolutions_per_second - time_taken
@ -173,3 +174,116 @@ class Simulate2Layers:
def _is_not_user_terminated(self): def _is_not_user_terminated(self):
return self.__draw_engine.is_active() return self.__draw_engine.is_active()
class Simulate4Layers:
def __init__(self,
cellular_automaton: NeuropercolationCoupled,
window_size=(1000, 800),
stretch_cells=False,
draw_engine=None,
state_to_color_cb=None,
*args, **kwargs):
"""
Creates a window to render a 2D CellularAutomaton.
:param cellular_automaton: The automaton to display and evolve
:param window_size: The Window size (default: 1000 x 800)
:param stretch_cells: Stretches cells to fit into window size. (default: false)
Activating it can result in black lines throughout the automaton.
:param draw_engine: The draw_engine (default: pygame)
:param state_to_color_cb: A callback to define the draw color of CA states (default: red for states != 0)
"""
super().__init__(*args, **kwargs)
self._cellular_automaton = cellular_automaton
self.__rect = _Rect(left=0, top=30, width=window_size[0], height=window_size[1])
self.__calculate_cell_display_size(stretch_cells)
self.__draw_engine = PygameEngine(window_size, self.__rect.top) if draw_engine is None else draw_engine
self.__state_to_color = self._get_cell_color if state_to_color_cb is None else state_to_color_cb
def run(self,
evolutions_per_second=0,
evolutions_per_draw=1,
last_evolution_step=0,):
"""
Evolves and draws the CellularAutomaton
:param evolutions_per_second: 0 = as fast as possible | > 0 to slow down the CellularAutomaton
:param evolutions_per_draw: Amount of evolutions done before screen gets redrawn.
:param last_evolution_step: 0 = infinite | > 0 evolution step at which this method will stop
Warning: is blocking until finished
"""
with contextlib.suppress(KeyboardInterrupt):
while self._is_not_user_terminated() and self._not_at_the_end(last_evolution_step):
time_ca_start = time.time()
self._cellular_automaton.evolve(evolutions_per_draw)
time_ca_end = time.time()
self._redraw_dirty_cells()
time_ds_end = time.time()
self.print_process_info(evolve_duration=(time_ca_end - time_ca_start),
draw_duration=(time_ds_end - time_ca_end),
evolution_step=self._cellular_automaton.evolution_step)
self._sleep_to_keep_rate(time.time() - time_ca_start, evolutions_per_second)
try:
self.__draw_engine._pygame.quit()
except:
print('Failed to quit pygame')
def _sleep_to_keep_rate(self, time_taken, evolutions_per_second): # pragma: no cover
if evolutions_per_second > 0:
rest_time = 1.0 / evolutions_per_second - time_taken
if rest_time > 0:
time.sleep(rest_time)
def _not_at_the_end(self, last_evolution_step):
return (self._cellular_automaton.evolution_step < last_evolution_step or last_evolution_step <= 0)
def __calculate_cell_display_size(self, stretch_cells): # pragma: no cover
grid_dimension = self._cellular_automaton.dimension
if stretch_cells:
self.__cell_size = [(self.__rect.width) / (grid_dimension[0]*2),
(self.__rect.height) / (grid_dimension[1]*2)]
else:
self.__cell_size = [int((self.__rect.width) / (grid_dimension[0]*2)),
int((self.__rect.height) / (grid_dimension[1]*2))]
def _redraw_dirty_cells(self):
self.__draw_engine.update_rectangles(list(self.__redraw_dirty_cells()))
def __redraw_dirty_cells(self):
for coordinate, cell in self._cellular_automaton.cells.items():
if cell.is_dirty:
yield self.__redraw_cell(cell, coordinate)
def __redraw_cell(self, cell, coordinate):
cell_color = self.__state_to_color(cell.state)
if coordinate[2]==1:
cell_color = cell_color[::-1]
cell_pos = self.__calculate_cell_position_in_the_grid(coordinate)
surface_pos = self.__calculate_cell_position_on_screen(cell_pos)
cell.is_dirty = False
return self.__draw_cell_surface(surface_pos, cell_color)
def _get_cell_color(self, current_state: Sequence) -> Sequence:
""" Returns the color of the cell depending on its current state """
return 255 if current_state[0] else 0, 0, 0
def __calculate_cell_position_in_the_grid(self, coord):
return list(map(operator.add,
map(operator.mul,
self.__cell_size,
coord[:2]),
[(self.__rect.width/2)*(coord[3]),
(self.__rect.height/2)*(coord[2])]))
def __calculate_cell_position_on_screen(self, cell_pos):
return [self.__rect.left + cell_pos[0], self.__rect.top + cell_pos[1]]
def __draw_cell_surface(self, surface_pos, cell_color):
return self.__draw_engine.fill_surface_with_color((surface_pos, self.__cell_size), cell_color)
def print_process_info(self, evolve_duration, draw_duration, evolution_step):
self.__draw_engine.fill_surface_with_color(((0, 0), (self.__rect.width, 30)))
self.__draw_engine.write_text((10, 5), "CA: " + "{0:.4f}".format(evolve_duration) + "s")
self.__draw_engine.write_text((310, 5), "Display: " + "{0:.4f}".format(draw_duration) + "s")
self.__draw_engine.write_text((660, 5), "Step: " + str(evolution_step))
def _is_not_user_terminated(self):
return self.__draw_engine.is_active()