Add Simulate1Layer
This commit is contained in:
parent
47d22e59ac
commit
7d5f579a34
@ -17,5 +17,5 @@ limitations under the License.
|
||||
|
||||
from .neighborhood import Neighborhood, MooreNeighborhood, RadialNeighborhood, VonNeumannNeighborhood, \
|
||||
HexagonalNeighborhood, EdgeRule
|
||||
from .automaton import Neuropercolation, NeuropercolationCoupled
|
||||
from .display import Simulate2Layers, Simulate4Layers
|
||||
from .automaton import Neurolattice, Neuropercolation, NeuropercolationCoupled
|
||||
from .display import Simulate1Layer, Simulate2Layers, Simulate4Layers
|
||||
|
@ -79,6 +79,74 @@ class CellularAutomatonCreator(abc.ABC):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class Neurolattice(CellularAutomatonCreator, abc.ABC):
|
||||
""" Cellular automaton with the evolution rules of conways game of life """
|
||||
|
||||
def __init__(self, dim, eps, *args, **kwargs):
|
||||
super().__init__(dimension=[dim, dim],
|
||||
neighborhood=VonNeumannNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS))
|
||||
self._evolution_step = 0
|
||||
self.epsilon = eps
|
||||
|
||||
def init_cell_state(self, coord): # pylint: disable=no-self-use
|
||||
return DEAD
|
||||
|
||||
def get_cells(self):
|
||||
return self._current_state
|
||||
|
||||
def set_cells(self, cells):
|
||||
""" Sets the cell states both as current and next states """
|
||||
for (coordinate, c_cell), n_cell in zip(self._current_state.items(), self._next_state.values()):
|
||||
new_cell_state = cells[coordinate].state
|
||||
c_cell.state = new_cell_state
|
||||
n_cell.state = new_cell_state
|
||||
|
||||
cells = property(get_cells, set_cells)
|
||||
|
||||
def get_evolution_step(self):
|
||||
return self._evolution_step
|
||||
|
||||
evolution_step = property(get_evolution_step)
|
||||
|
||||
def evolve(self, times=1):
|
||||
""" Evolve all cells x times.
|
||||
:param times: The number of evolution steps processed with one call of this method.
|
||||
"""
|
||||
for _ in itertools.repeat(None, times):
|
||||
self.__evolve_cells(self._current_state, self._next_state)
|
||||
self._current_state, self._next_state = self._next_state, self._current_state
|
||||
self._evolution_step += 1
|
||||
|
||||
def __evolve_cells(self, this_state, next_state):
|
||||
evolve_cell = self.__evolve_cell
|
||||
evolution_rule = self.evolve_rule
|
||||
for coord, old, new in zip(this_state.keys(), this_state.values(), next_state.values()):
|
||||
new_state = evolution_rule(old.state.copy(), [n.state[0] for n in old.neighbors])
|
||||
evolve_cell(old, new, new_state)
|
||||
|
||||
def __evolve_cell(self, old, cell, new_state):
|
||||
changed = new_state != old.state
|
||||
cell.state = new_state
|
||||
cell.is_dirty |= changed
|
||||
old.is_dirty |= changed
|
||||
|
||||
def evolve_rule(self, last_cell_state, neighbors_last_states):
|
||||
new_cell_state = last_cell_state
|
||||
alive_neighbours = sum(neighbors_last_states)+last_cell_state[0]
|
||||
|
||||
CASE = (random.random()>=self.epsilon)
|
||||
if alive_neighbours > 2:
|
||||
if CASE:
|
||||
new_cell_state = ALIVE
|
||||
else:
|
||||
new_cell_state = DEAD
|
||||
else:
|
||||
if CASE:
|
||||
new_cell_state = DEAD
|
||||
else:
|
||||
new_cell_state = ALIVE
|
||||
return new_cell_state
|
||||
|
||||
class Neuropercolation(CellularAutomatonCreator, abc.ABC):
|
||||
""" Cellular automaton with the evolution rules of conways game of life """
|
||||
|
||||
|
@ -18,14 +18,13 @@ limitations under the License.
|
||||
|
||||
import os
|
||||
import json
|
||||
import pbjson
|
||||
import time
|
||||
import operator
|
||||
import collections
|
||||
import contextlib
|
||||
from typing import Sequence
|
||||
|
||||
from . import Neuropercolation, NeuropercolationCoupled
|
||||
from . import Neurolattice, Neuropercolation, NeuropercolationCoupled
|
||||
|
||||
_Rect = collections.namedtuple(typename="Rect",
|
||||
field_names=["left", "top", "width", "height"])
|
||||
@ -66,6 +65,130 @@ class PygameEngine:
|
||||
return True
|
||||
|
||||
|
||||
class Simulate1Layer:
|
||||
def __init__(self,
|
||||
dim,
|
||||
eps,
|
||||
res=4,
|
||||
draw='pygame',
|
||||
path='/cloud/Public/_data/neuropercolation/test/',
|
||||
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 = Neurolattice(dim,eps)
|
||||
self.__cell_size = [res,res]
|
||||
self.__dimension = dim
|
||||
self.__epsilon = eps
|
||||
self.__gridside = dim*res
|
||||
self.__rect = _Rect(left=0, top=30, width=dim*res, height=dim*res)
|
||||
self.__draw_engine = PygameEngine((self.__rect.width,self.__rect.height+self.__rect.top)) if draw == 'pygame' else draw
|
||||
self.__state_to_color = self._get_cell_color if state_to_color_cb is None else state_to_color_cb
|
||||
self.__path = path
|
||||
self.__state_list = []
|
||||
|
||||
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
|
||||
"""
|
||||
self._append_state()
|
||||
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)
|
||||
self._append_state()
|
||||
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,
|
||||
runlendig=len(str(last_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')
|
||||
self._save_state_list()
|
||||
|
||||
def _append_state(self):
|
||||
automaton_state = [[0 for n in range(self.__dimension)] for m in range(self.__dimension)]
|
||||
for coord, cell in self._cellular_automaton._current_state.items():
|
||||
x,y = coord
|
||||
automaton_state[y][x] = int(cell.state[0])
|
||||
|
||||
automaton_state = [''.join(str(cells) for cells in rows) for rows in automaton_state]
|
||||
automaton_state = '.'.join(str(rows) for rows in automaton_state)
|
||||
self.__state_list.append(automaton_state)
|
||||
|
||||
def _save_state_list(self):
|
||||
if not os.path.exists(self.__path):
|
||||
os.makedirs(self.__path)
|
||||
|
||||
with open(self.__path+f"eps={round(self.__epsilon,3):.3f}_states.txt", 'w', encoding='utf-8') as f:
|
||||
json.dump(self.__state_list, f, indent=1)
|
||||
|
||||
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 _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)
|
||||
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.mul,
|
||||
self.__cell_size,
|
||||
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, runlendig):
|
||||
self.__draw_engine.fill_surface_with_color(((0, 0), (self.__rect.width, 30)))
|
||||
self.__draw_engine.write_text((0, 5), f'Step: {evolution_step:>{runlendig}} FPS: {int(1/(evolve_duration+draw_duration))}')
|
||||
|
||||
def _is_not_user_terminated(self):
|
||||
return self.__draw_engine.is_active()
|
||||
|
||||
class Simulate2Layers:
|
||||
def __init__(self,
|
||||
dim,
|
||||
|
Loading…
Reference in New Issue
Block a user