added multi processing, extremly slow though
This commit is contained in:
parent
ac2a6216b3
commit
a8d17f6fe9
@ -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:
|
|
||||||
cell.state = MyStatus(0)
|
|
||||||
else:
|
else:
|
||||||
cell.state = MyStatus(1)
|
return self._evolve_state(cell, iteration_index)
|
||||||
cell.is_set_for_redraw = True
|
|
||||||
active = True
|
@staticmethod
|
||||||
elif len(neighbors) == 8:
|
def _evolve_state(cell, iteration_index):
|
||||||
left_neighbour_state = neighbors[0].state.get_status_of_iteration(iteration_index - 1)
|
try:
|
||||||
|
left_neighbour_state = cell.neighbours[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)
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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__()
|
||||||
|
Loading…
Reference in New Issue
Block a user