added multi processing, extremly slow though

This commit is contained in:
Richard Feistenauer 2019-01-06 11:21:46 +01:00
parent ac2a6216b3
commit a8d17f6fe9
4 changed files with 164 additions and 37 deletions

View File

@ -2,7 +2,7 @@
import random import random
from cellular_automaton.cellular_automaton import CellularAutomaton, CellularAutomatonEvolver from cellular_automaton.cellular_automaton import CellularAutomaton, CellularAutomatonProcessor
from cellular_automaton.ca_rule import Rule from cellular_automaton.ca_rule import Rule
from cellular_automaton.ca_neighborhood import MooreNeighborhood, EdgeRule from cellular_automaton.ca_neighborhood import MooreNeighborhood, EdgeRule
from cellular_automaton.ca_display import PyGameFor2D from cellular_automaton.ca_display import PyGameFor2D
@ -12,22 +12,32 @@ from cellular_automaton.ca_grid import Grid
class TestRule(Rule): class TestRule(Rule):
def evolve_cell(self, cell, iteration_index): def evolve_cell(self, cell, iteration_index):
active = False
neighbors = cell.neighbours
if cell.state is None: if cell.state is None:
rand = random.randrange(0, 101, 1) return self._init_state(cell)
if rand <= 99: else:
cell.state = MyStatus(0) return self._evolve_state(cell, iteration_index)
else:
cell.state = MyStatus(1) @staticmethod
cell.is_set_for_redraw = True def _evolve_state(cell, iteration_index):
active = True try:
elif len(neighbors) == 8: left_neighbour_state = cell.neighbours[0].state.get_status_of_iteration(iteration_index - 1)
left_neighbour_state = neighbors[0].state.get_status_of_iteration(iteration_index - 1)
active = cell.state.set_status_of_iteration(left_neighbour_state, iteration_index) active = cell.state.set_status_of_iteration(left_neighbour_state, iteration_index)
if active: if active:
cell.is_set_for_redraw = True cell.is_set_for_redraw = True
return active return active
except IndexError:
return False
@staticmethod
def _init_state(cell):
rand = random.randrange(0, 101, 1)
if rand <= 99:
cell.state = MyStatus(0)
return False
else:
cell.state = MyStatus(1)
cell.is_set_for_redraw = True
return True
class MyStatus(CellState): class MyStatus(CellState):
@ -44,8 +54,10 @@ class MyStatus(CellState):
if __name__ == "__main__": if __name__ == "__main__":
random.seed(1000) random.seed(1000)
rule = TestRule() rule = TestRule()
ca = CellularAutomaton(Grid([400, 400], MooreNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS)), grid = Grid(dimension=[400, 400],
rule) neighborhood=MooreNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS))
ca_evolver = CellularAutomatonEvolver(2) ca = CellularAutomaton(grid, rule)
ca_window = PyGameFor2D([1000, 800], ca, ca_evolver, 5) ca_window = PyGameFor2D(window_size=[1000, 800], cellular_automaton=ca)
ca_window.main_loop() ca_processor = CellularAutomatonProcessor(process_count=8)
ca_window.main_loop(cellular_automaton_processor=ca_processor,
ca_iterations_per_draw=5)

View File

@ -30,3 +30,6 @@ class CellState:
def get_state_draw_color(self, iteration): def get_state_draw_color(self, iteration):
raise NotImplementedError raise NotImplementedError
def __str__(self):
return str(self._state_slots)

View File

@ -2,7 +2,7 @@ import pygame
import time import time
import operator import operator
from cellular_automaton.cellular_automaton import CellularAutomaton, CellularAutomatonEvolver from cellular_automaton.cellular_automaton import CellularAutomaton, CellularAutomatonProcessor
class _DisplayInfo: class _DisplayInfo:
@ -33,22 +33,16 @@ class DisplayFor2D:
class PyGameFor2D: class PyGameFor2D:
def __init__(self, def __init__(self, window_size: list, cellular_automaton: CellularAutomaton):
windows_size: list, self._window_size = window_size
cellular_automaton: CellularAutomaton,
cellular_automaton_evolver: CellularAutomatonEvolver,
ca_iterations_per_draw):
self._window_size = windows_size
self._cellular_automaton = cellular_automaton self._cellular_automaton = cellular_automaton
self._cellular_automaton_evolver = cellular_automaton_evolver
self._ca_steps_per_draw = ca_iterations_per_draw
pygame.init() pygame.init()
pygame.display.set_caption("Cellular Automaton") pygame.display.set_caption("Cellular Automaton")
self._screen = pygame.display.set_mode(self._window_size) self._screen = pygame.display.set_mode(self._window_size)
self._font = pygame.font.SysFont("monospace", 15) self._font = pygame.font.SysFont("monospace", 15)
self.ca_display = DisplayFor2D([0, 30, windows_size[0], windows_size[1]-30], cellular_automaton, self._screen) self.ca_display = DisplayFor2D([0, 30, window_size[0], window_size[1] - 30], cellular_automaton, self._screen)
def _print_process_duration(self, time_ca_end, time_ca_start, time_ds_end): def _print_process_duration(self, time_ca_end, time_ca_start, time_ds_end):
self._screen.fill([0, 0, 0], ((0, 0), (self._window_size[0], 30))) self._screen.fill([0, 0, 0], ((0, 0), (self._window_size[0], 30)))
@ -60,12 +54,12 @@ class PyGameFor2D:
update_rect = self._screen.blit(label, pos) update_rect = self._screen.blit(label, pos)
pygame.display.update(update_rect) pygame.display.update(update_rect)
def main_loop(self): def main_loop(self, cellular_automaton_processor: CellularAutomatonProcessor, ca_iterations_per_draw):
running = True running = True
while running: while running:
time_ca_start = time.time() time_ca_start = time.time()
self._cellular_automaton_evolver.evolve_x_times(self._cellular_automaton, self._ca_steps_per_draw) cellular_automaton_processor.evolve_x_times(self._cellular_automaton, ca_iterations_per_draw)
time_ca_end = time.time() time_ca_end = time.time()
self.ca_display._redraw_cellular_automaton() self.ca_display._redraw_cellular_automaton()
time_ds_end = time.time() time_ds_end = time.time()

View File

@ -1,5 +1,9 @@
from cellular_automaton.ca_grid import Grid from cellular_automaton.ca_grid import Grid
from cellular_automaton.ca_rule import Rule from cellular_automaton.ca_rule import Rule
from cellular_automaton.ca_cell_state import CellState
from multiprocessing import Process, Pipe, Array, Value
import multiprocessing
class CellularAutomaton: class CellularAutomaton:
@ -9,14 +13,22 @@ class CellularAutomaton:
self.evolution_iteration_index = 0 self.evolution_iteration_index = 0
class CellularAutomatonEvolver: class _EvolutionProcess:
def __init__(self, process: Process, pipe: Pipe):
self.process = process
self.pipe = pipe
self.cell = None
class CellularAutomatonProcessor:
def __init__(self, process_count: int = 1): def __init__(self, process_count: int = 1):
self.__processes = process_count self._processes = list(_create_processes(process_count))
self.__cellular_automaton = None self.__cellular_automaton = None
def evolve_x_times(self, cellular_automaton: CellularAutomaton, evolution_steps: int): def evolve_x_times(self, cellular_automaton: CellularAutomaton, evolution_steps: int):
""" Evolve all cells for x time steps. """ Evolve all cells for x time steps.
:param evolution_steps: the count of evolutions done. :param cellular_automaton: The cellular automaton to evolve.
:param evolution_steps: The count of evolutions done.
:return: True if all cells are inactive :return: True if all cells are inactive
""" """
for evo in range(evolution_steps): for evo in range(evolution_steps):
@ -27,10 +39,12 @@ class CellularAutomatonEvolver:
def evolve(self, cellular_automaton: CellularAutomaton): def evolve(self, cellular_automaton: CellularAutomaton):
""" Evolves all active cells for one time step. """ Evolves all active cells for one time step.
:param cellular_automaton: The cellular automaton to evolve.
:return: True if all cells are inactive. :return: True if all cells are inactive.
""" """
self.__cellular_automaton = cellular_automaton self.__cellular_automaton = cellular_automaton
if self._is_evolution_finished(): if self._is_evolution_finished():
print("finished")
return True return True
else: else:
cellular_automaton.evolution_iteration_index += 1 cellular_automaton.evolution_iteration_index += 1
@ -44,11 +58,115 @@ class CellularAutomatonEvolver:
active_cells = self.__cellular_automaton.grid.get_active_cells() active_cells = self.__cellular_automaton.grid.get_active_cells()
self.__cellular_automaton.grid.clear_active_cells() self.__cellular_automaton.grid.clear_active_cells()
self._evolve_cells(active_cells.values()) self._evolve_cells(active_cells.values())
print(len(self.__cellular_automaton.grid.get_active_cells()))
def _evolve_cells(self, cells: list): def _evolve_cells(self, cells):
cellular_automaton = self.__cellular_automaton cellular_automaton = self.__cellular_automaton
for cell in cells: processes = self._processes
active = cellular_automaton.evolution_rule.evolve_cell(cell, cellular_automaton.evolution_iteration_index) process_count = len(processes)
for i, cell in enumerate(cells):
evolution_process = processes[i % process_count]
if evolution_process.cell:
response = evolution_process.pipe.recv()
evolved_cell = evolution_process.cell
evolved_cell.state = response[0]
evolved_cell.is_set_for_redraw |= response[1]
if evolved_cell.is_set_for_redraw:
cellular_automaton.grid.set_cells_active([evolved_cell] + evolved_cell.neighbours)
evolution_process.cell = None
if active: cell_info = self.read_cell_info(cell, cellular_automaton.evolution_iteration_index)
evolution_process.pipe.send(cell_info)
evolution_process.cell = cell
for evolution_process in processes:
response = evolution_process.pipe.recv()
cell = evolution_process.cell
cell.state = response[0]
cell.is_set_for_redraw |= response[1]
if cell.is_set_for_redraw:
cellular_automaton.grid.set_cells_active([cell] + cell.neighbours) cellular_automaton.grid.set_cells_active([cell] + cell.neighbours)
evolution_process.cell = None
# if cellular_automaton.evolution_rule.evolve_cell(cell.state, cellular_automaton.evolution_iteration_index):
# cellular_automaton.grid.set_cells_active([cell] + cell.neighbours)
@staticmethod
def read_cell_info(cell, iteration):
coordinate = cell.coordinate
return [coordinate, cell.state, [n.state for n in cell.neighbours], iteration]
# if cell.state is not None:
# cell_state = cell.state.get_status_of_iteration(iteration - 1)
# else:
# cell_state = None
#
# neighbor_states = []
# for neighbor in cell.neighbours:
# if neighbor.state is not None:
# neighbor_state = neighbor.state.get_status_of_iteration(iteration - 1)
# else:
# neighbor_state = None
# neighbor_states.append(neighbor_state)
#
# return [coordinate, cell_state, neighbor_states]
def _create_processes(count):
for i in range(count):
parent_pipe_connection, child_pipe_connection = Pipe()
p = Process(target=process_routine, args=(child_pipe_connection, ))
p.start()
yield _EvolutionProcess(p, parent_pipe_connection)
def process_routine(pipe_conn: Pipe):
while True:
info = pipe_conn.recv()
pipe_conn.send(evolve_cell(*info))
def evolve_cell(coordinate, cell_state, neighbor_states, index):
if cell_state is None:
return _init_state()
else:
new_state = _evolve_state(cell_state, neighbor_states, index)
if new_state is None:
print(",".join([str(x) for x in neighbor_states]))
return [cell_state, False]
else:
changed = cell_state.set_status_of_iteration(new_state, index)
return [cell_state, changed]
def _evolve_state(cell_state, neighbor_states, index):
try:
left_neighbour_state = neighbor_states[0].get_status_of_iteration(index - 1)
return left_neighbour_state
except (IndexError, AttributeError):
return None
import random
def _init_state():
rand = random.randrange(0, 101, 1)
if rand <= 99:
return [MyStatus(0), False]
else:
return [MyStatus(1), True]
class MyStatus(CellState):
def __init__(self, initial_state):
super().__init__(initial_state)
def get_state_draw_color(self, iteration):
red = 0
if self._state_slots[iteration % 2][0]:
red = 255
return [red, 0, 0]
def __str__(self):
return super().__str__()