added single and multi core deviation

This commit is contained in:
Richard Feistenauer 2019-02-10 11:54:42 +01:00
parent 3e3af78ccd
commit 726cc6394f
4 changed files with 61 additions and 30 deletions

View File

@ -43,8 +43,8 @@ if __name__ == "__main__":
random.seed(1000) random.seed(1000)
# best single is 400/400 with 0,2 ca speed and 0,09 redraw / multi is 300/300 with 0.083 # best single is 400/400 with 0,2 ca speed and 0,09 redraw / multi is 300/300 with 0.083
neighborhood = MooreNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS) neighborhood = MooreNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS)
ca = make_cellular_automaton(dimension=[100, 100], neighborhood=neighborhood, rule=TestRule(), state_class=MyState) ca = make_cellular_automaton(dimension=[400, 400], neighborhood=neighborhood, rule=TestRule(), state_class=MyState)
ca_processor = CellularAutomatonProcessor(process_count=4, cellular_automaton=ca) ca_processor = CellularAutomatonProcessor(process_count=1, cellular_automaton=ca)
ca_window = PyGameFor2D(window_size=[1000, 800], cellular_automaton=ca) ca_window = PyGameFor2D(window_size=[1000, 800], cellular_automaton=ca)
ca_window.main_loop(cellular_automaton_processor=ca_processor, ca_iterations_per_draw=10) ca_window.main_loop(cellular_automaton_processor=ca_processor, ca_iterations_per_draw=1)

Binary file not shown.

View File

@ -3,31 +3,30 @@ from ctypes import c_float, c_bool
class CellState: class CellState:
_state_save_slot_count = 2
""" """
This is the base class for all cell states. This is the base class for all cell states.
When using the cellular automaton display, inherit this class and implement get_state_draw_color. When using the cellular automaton display, inherit this class and implement get_state_draw_color.
""" """
_state_save_slot_count = 2
def __init__(self, initial_state=(0., ), draw_first_state=True): def __init__(self, initial_state=(0., ), draw_first_state=True):
self._state_slots = [RawArray(c_float, initial_state) for i in range(self.__class__._state_save_slot_count)] self._state_slots = [list(initial_state) for i in range(self.__class__._state_save_slot_count)]
self._active = [RawValue(c_bool, False) for i in range(self.__class__._state_save_slot_count)] self._active = [False for i in range(self.__class__._state_save_slot_count)]
self._active[0].value = True self._active[0] = True
if draw_first_state: self._dirty = draw_first_state
self._dirty = RawValue(c_bool, True)
else:
self._dirty = RawValue(c_bool, False)
def is_active(self, iteration): def is_active(self, iteration):
return self._active[self.__calculate_slot(iteration)] return self._active[self._calculate_slot(iteration)]
def set_active_for_next_iteration(self, iteration): def set_active_for_next_iteration(self, iteration):
self._active[self.__calculate_slot(iteration + 1)].value = True self._active[self._calculate_slot(iteration + 1)] = True
def is_set_for_redraw(self): def is_set_for_redraw(self):
return self._dirty.value return self._dirty
def was_redrawn(self): def was_redrawn(self):
self._dirty.value = False self._dirty = False
def get_state_of_last_iteration(self, current_iteration_index): def get_state_of_last_iteration(self, current_iteration_index):
return self.get_state_of_iteration(current_iteration_index - 1) return self.get_state_of_iteration(current_iteration_index - 1)
@ -37,7 +36,7 @@ class CellState:
:param iteration: Uses the iteration index, to differ between concurrent states. :param iteration: Uses the iteration index, to differ between concurrent states.
:return The state for this iteration. :return The state for this iteration.
""" """
return self._state_slots[self.__calculate_slot(iteration)] return self._state_slots[self._calculate_slot(iteration)]
def set_state_of_iteration(self, new_state, iteration): def set_state_of_iteration(self, new_state, iteration):
""" Will set the new state for the iteration modulo number of saved states. """ Will set the new state for the iteration modulo number of saved states.
@ -45,25 +44,50 @@ class CellState:
:param iteration: Uses the iteration index, to differ between concurrent states. :param iteration: Uses the iteration index, to differ between concurrent states.
:return True if state has changed. :return True if state has changed.
""" """
changed = self._change_state(new_state, iteration)
self._dirty |= changed
self._active[self._calculate_slot(iteration)] = False
return changed
def _change_state(self, new_state, iteration):
current_state = self.get_state_of_iteration(iteration) current_state = self.get_state_of_iteration(iteration)
changed = False changed = False
for i in range(len(current_state)): for i, ns in enumerate(new_state):
try: try:
if current_state[i] != new_state[i]: if current_state[i] != ns:
changed = True changed = True
current_state[i] = new_state[i] current_state[i] = ns
except IndexError: except IndexError:
raise IndexError("New State length or type is invalid!") raise IndexError("New State length or type is invalid!")
self._dirty.value |= changed
self._active[self.__calculate_slot(iteration)].value = False
return changed return changed
def get_state_draw_color(self, iteration): def get_state_draw_color(self, iteration):
raise NotImplementedError raise NotImplementedError
@classmethod @classmethod
def __calculate_slot(cls, iteration): def _calculate_slot(cls, iteration):
return iteration % cls._state_save_slot_count return iteration % cls._state_save_slot_count
class SynchronousCellState(CellState):
def __init__(self, initial_state=(0., ), draw_first_state=True):
super().__init__(initial_state, draw_first_state)
self._state_slots = [RawArray(c_float, initial_state) for i in range(self.__class__._state_save_slot_count)]
self._active = [RawValue(c_bool, False) for i in range(self.__class__._state_save_slot_count)]
self._active[0].value = True
self._dirty = RawValue(c_bool, draw_first_state)
def set_active_for_next_iteration(self, iteration):
self._active[self._calculate_slot(iteration + 1)].value = True
def is_set_for_redraw(self):
return self._dirty.value
def was_redrawn(self):
self._dirty.value = False
def set_state_of_iteration(self, new_state, iteration):
changed = self._change_state(new_state, iteration)
self._dirty.value |= changed
self._active[self._calculate_slot(iteration)].value = False
return changed

View File

@ -17,11 +17,18 @@ class CellularAutomatonProcessor:
self.ca = cellular_automaton self.ca = cellular_automaton
cells = {i: (c.state, c.neighbours) for i, c in enumerate(self.ca.cells)} cells = {i: (c.state, c.neighbours) for i, c in enumerate(self.ca.cells)}
self.evolve_range = range(len(self.ca.cells)) self.evolve_range = range(len(self.ca.cells))
self._evolve_method = lambda x, y: None
if process_count > 1:
self.pool = multiprocessing.Pool(processes=process_count, self.pool = multiprocessing.Pool(processes=process_count,
initializer=_init_process, initializer=_init_process,
initargs=(cells, initargs=(cells,
self.ca.evolution_rule, self.ca.evolution_rule,
self.ca.evolution_iteration_index)) self.ca.evolution_iteration_index))
self._evolve_method = self.pool.map
else:
_init_process(cells, self.ca.evolution_rule, self.ca.evolution_iteration_index)
self._evolve_method = lambda x, y: list(map(x, y))
for cell in self.ca.cells: for cell in self.ca.cells:
del cell.neighbours del cell.neighbours
@ -31,7 +38,7 @@ class CellularAutomatonProcessor:
def evolve(self): def evolve(self):
self.ca.evolution_iteration_index.value += 1 self.ca.evolution_iteration_index.value += 1
self.pool.map(_process_routine, self.evolve_range) self._evolve_method(_process_routine, self.evolve_range)
global_cells = None global_cells = None