def test_cached_history_function(): def changes(history_browser): ''' Return how many cells changed between most recent state and its parent. ''' changes.called_flag = True try: state = history_browser[-1] last_state = history_browser[-2] except IndexError: return None board, last_board = state.board, last_state.board board_size = len(board._Board__list) counter = 0 for i in xrange(board_size): if board._Board__list[i] != last_board._Board__list[i]: counter += 1 return counter cached_changes = caching.history_cache(changes) cute_testing.assert_polite_wrapper(cached_changes, changes, same_signature=False) s = life.State.create_messy_root(5, 5) p = garlicsim.Project(life) r = p.root_this_state(s) leaf = p.simulate(r, 10) path = leaf.make_containing_path() result_1 = [cached_changes(node) for node in list(path)[0:5]] assert changes.called_flag is True changes.called_flag = False result_2 = [cached_changes(node) for node in list(path)[0:5]] assert changes.called_flag is False assert result_1 == result_2 result_1 = [cached_changes(node) for node in list(path)] assert changes.called_flag is True changes.called_flag = False result_2 = [cached_changes(node) for node in list(path)] assert changes.called_flag is False assert result_1 == result_2
def test_project(self): project = garlicsim.Project(lightbulb) root = project.root_this_state(self.state) project.begin_crunching(root, 4) print project.sync_crunchers() print project.sync_crunchers() print project.tree (path, ) = project.tree.all_possible_paths() print path
def check(simpack, cruncher_type): my_simpack_grokker = garlicsim.misc.SimpackGrokker(simpack) assert my_simpack_grokker is garlicsim.misc.SimpackGrokker(simpack) # Ensuring caching works. assert garlicsim.misc.simpack_grokker.step_type.StepType.get_step_type( my_simpack_grokker.default_step_function ) == simpack._test_settings.DEFAULT_STEP_FUNCTION_TYPE step_profile = my_simpack_grokker.build_step_profile() deterministic = \ my_simpack_grokker.settings.DETERMINISM_FUNCTION(step_profile) state = simpack.State.create_root() project = garlicsim.Project(simpack) project.crunching_manager.cruncher_type = cruncher_type assert project.tree.lock._ReadWriteLock__writer is None root = project.root_this_state(state) def run_sync_crunchers_until_we_get_at_least_one_node(): while not project.sync_crunchers(): time.sleep(0.1) ### Test changing clock target on the fly: ################################ # # huge_number = 10**20 different_huge_number = huge_number + 1 assert different_huge_number - huge_number == 1 job = project.begin_crunching(root, huge_number) run_sync_crunchers_until_we_get_at_least_one_node() (cruncher, ) = project.crunching_manager.crunchers.values() ## An interlude to test `__repr__` methods: ############################### step_profile_description = repr(job.crunching_profile.step_profile) assert step_profile_description == \ 'StepProfile(%s)' % simpack._test_settings.DEFAULT_STEP_FUNCTION short_step_profile_description = \ job.crunching_profile.step_profile.__repr__(short_form=True) assert short_step_profile_description == \ '%s(<state>)' % address_tools.describe( simpack._test_settings.DEFAULT_STEP_FUNCTION, shorten=True, root=simpack, ) crunching_profile_description = repr(job.crunching_profile) assert crunching_profile_description == \ 'CrunchingProfile(clock_target=%d, step_profile=%s)' % \ (huge_number, short_step_profile_description) job_description = repr(job) assert job_description == 'Job(node=%s, crunching_profile=%s)' % \ (repr(job.node), crunching_profile_description) crunching_manager_description = repr(project.crunching_manager) assert re.match( ('^<.*?CrunchingManager currently employing 1 crunchers to ' 'handle 1 jobs at .*?>$'), crunching_manager_description) project_description = repr(project) assert re.match( '<.*?Project containing .*? nodes and employing 1 crunchers at .*?>', project_description) # Assert the job cruncher is not unequal to itself: assert not job.crunching_profile.__ne__(job.crunching_profile) ## Finished interlude to test `__repr__` methods. ######################### job.crunching_profile.raise_clock_target(different_huge_number) # Letting our crunching manager update our cruncher about the new clock # target: project.sync_crunchers() assert not job.is_done() (same_cruncher, ) = project.crunching_manager.crunchers.values() # todo: On slow machines cruncher doesn't get created fast enough for the # above assert to work. Probably make some function that waits for it. assert same_cruncher is cruncher # Deleting jobs so the cruncher will stop: del project.crunching_manager.jobs[:] project.sync_crunchers() assert not project.crunching_manager.jobs assert not project.crunching_manager.crunchers # # ### Finish testing changing clock target on the fly. ###################### ### Test changing step profile on the fly: ################################ # # # For simpacks providing more than one step function, we'll test changing # between them. This will exercise the crunching manager's policy of # switching crunchers immediately when the step profile for a job gets # changed. if simpack._test_settings.N_STEP_FUNCTIONS >= 2: default_step_function, alternate_step_function = \ my_simpack_grokker.all_step_functions[:2] job = project.begin_crunching(root, infinity) assert job.crunching_profile.step_profile.step_function == \ default_step_function run_sync_crunchers_until_we_get_at_least_one_node() (cruncher, ) = project.crunching_manager.crunchers.values() alternate_step_profile = \ garlicsim.misc.StepProfile(alternate_step_function) job.crunching_profile.step_profile = alternate_step_profile # Letting our crunching manager get a new cruncher for our new step # profile: project.sync_crunchers() (new_cruncher, ) = project.crunching_manager.crunchers.values() assert new_cruncher is not cruncher last_node_with_default_step_profile = job.node assert not last_node_with_default_step_profile.children # It's a leaf assert last_node_with_default_step_profile.\ step_profile.step_function == default_step_function # Another `sync_crunchers`: run_sync_crunchers_until_we_get_at_least_one_node() # And now we have some new nodes with the alternate step profile. (first_node_with_alternate_step_profile,) = \ last_node_with_default_step_profile.children path = last_node_with_default_step_profile.make_containing_path() nodes_with_alternate_step_profile = list( path.__iter__(head=first_node_with_alternate_step_profile)) for node in nodes_with_alternate_step_profile: assert node.step_profile == alternate_step_profile # Deleting jobs so the cruncher will stop: del project.crunching_manager.jobs[:] project.sync_crunchers() assert not project.crunching_manager.jobs assert not project.crunching_manager.crunchers # # ### Finished testing changing step profile on the fly. #################### ### Testing cruncher type switching: ###################################### # # job_1 = project.begin_crunching(root, clock_buffer=infinity) job_2 = project.begin_crunching(root, clock_buffer=infinity) assert len(project.crunching_manager.crunchers) == 0 assert project.sync_crunchers() == 0 assert len(project.crunching_manager.crunchers) == 2 (cruncher_1, cruncher_2) = project.crunching_manager.crunchers.values() assert type(cruncher_1) is cruncher_type assert type(cruncher_2) is cruncher_type time.sleep(0.2) # Letting the crunchers start working project.crunching_manager.cruncher_type = MustachedThreadCruncher project.sync_crunchers() assert len(project.crunching_manager.crunchers) == 2 (cruncher_1, cruncher_2) = project.crunching_manager.crunchers.values() assert type(cruncher_1) is MustachedThreadCruncher assert type(cruncher_2) is MustachedThreadCruncher project.crunching_manager.cruncher_type = cruncher_type project.sync_crunchers() assert len(project.crunching_manager.crunchers) == 2 (cruncher_1, cruncher_2) = project.crunching_manager.crunchers.values() assert type(cruncher_1) is cruncher_type assert type(cruncher_2) is cruncher_type # Deleting jobs so the crunchers will stop: del project.crunching_manager.jobs[:] project.sync_crunchers() assert not project.crunching_manager.jobs assert not project.crunching_manager.crunchers
def check(simpack, cruncher_type): assert simpack._test_settings.ENDABLE is True assert simpack._test_settings.CONSTANT_CLOCK_INTERVAL == 1 my_simpack_grokker = garlicsim.misc.SimpackGrokker(simpack) assert my_simpack_grokker is garlicsim.misc.SimpackGrokker(simpack) # Ensuring caching works. assert garlicsim.misc.simpack_grokker.step_type.StepType.get_step_type( my_simpack_grokker.default_step_function ) == simpack._test_settings.DEFAULT_STEP_FUNCTION_TYPE step_profile = my_simpack_grokker.build_step_profile() deterministic = \ my_simpack_grokker.settings.DETERMINISM_FUNCTION(step_profile) state = simpack.State.create_root() ### Running for short periods synchronically so it doesn't end: ########### # # # Whether we run the simulation for one, two, three, or four iterations, # the simulation doesn't end. prev_state = state for i in [1, 2, 3, 4]: new_state = garlicsim.simulate(state, i) assert new_state.clock >= getattr(prev_state, 'clock', 0) prev_state = new_state result = garlicsim.list_simulate(state, 4) for item in result: assert isinstance(item, garlicsim.data_structures.State) assert isinstance(item, simpack.State) assert isinstance(result, list) assert len(result) == 5 iter_result = garlicsim.iter_simulate(state, 4) assert not hasattr(iter_result, '__getitem__') assert hasattr(iter_result, '__iter__') iter_result_in_list = list(iter_result) del iter_result assert len(iter_result_in_list) == len(result) == 5 # # ### Done running for short periods synchronically so it doesn't end. ###### ### Now, let's run it for longer periods synchronically to make it end: ### # # for i in [5, 6, 7]: new_state = garlicsim.simulate(state, i) assert new_state.clock == 4 result = garlicsim.list_simulate(state, 7) assert isinstance(result, list) assert len(result) == 5 iter_result = garlicsim.iter_simulate(state, 7) assert not hasattr(iter_result, '__getitem__') assert hasattr(iter_result, '__iter__') iter_result_in_list = list(iter_result) del iter_result assert len(iter_result_in_list) == len(result) == 5 # # ### Done running for longer periods synchronically to make it end. ######## ### Setting up a project to run asynchronous tests: project = garlicsim.Project(simpack) project.crunching_manager.cruncher_type = cruncher_type assert project.tree.lock._ReadWriteLock__writer is None root = project.root_this_state(state) def get_all_ends(): return [ member for member in project.tree.iterate_tree_members() if isinstance(member, garlicsim.data_structures.End) ] assert len(get_all_ends()) == 0 ### Running for short periods asynchronically so it doesn't end: ########## # # project.begin_crunching(root, 4) total_nodes_added = 0 while project.crunching_manager.jobs: time.sleep(0.1) total_nodes_added += project.sync_crunchers() assert total_nodes_added == 4 assert len(project.tree.nodes) == 5 assert len(project.tree.roots) == 1 paths = project.tree.all_possible_paths() assert len(paths) == 1 (my_path, ) = paths assert len(my_path) == 5 node_1 = my_path[1] assert node_1.state.clock == 1 node_2 = project.simulate(node_1, 3) assert len(project.tree.nodes) == 8 assert len(project.tree.roots) == 1 assert len(project.tree.all_possible_paths()) == 2 assert len(get_all_ends()) == 0 # # ### Done running for short periods asynchronically so it doesn't end. ##### ### Now, let's run it for longer periods asynchronically to make it end: ## # # node_3 = my_path.next_node(node_1) assert node_3.state.clock == 2 project.begin_crunching(node_3, 3) total_nodes_added = 0 while project.crunching_manager.jobs: time.sleep(0.1) total_nodes_added += project.sync_crunchers() assert total_nodes_added == 2 # Would have been 3 without the end! assert len(get_all_ends()) == 1 # So now `node_3`'s newer path has an end: ended_path = node_3.all_possible_paths()[1] isinstance(ended_path, garlicsim.data_structures.Path) (end, ) = ended_path.get_ends_of_last_node() # (Asserting there's one end.) assert isinstance(end, garlicsim.data_structures.End) assert len(project.tree.nodes) == 10 paths = project.tree.all_possible_paths() assert len(paths) == 3 assert [len(p) for p in paths] == [5, 5, 5] # Ensuring buffer on `ended_path` from `node_3` won't cause a new job to be # created since we have a path to an existing end: project.ensure_buffer_on_path(node_3, ended_path, 10) project.ensure_buffer_on_path(node_3, ended_path, 1000) project.ensure_buffer_on_path(node_3, ended_path, infinity) total_nodes_added = 0 assert not project.crunching_manager.jobs assert len(project.tree.nodes) == 10 # These `ensure_buffer_on_path` calls shouldn't have added any ends: assert len(get_all_ends()) == 1 # But `node_3` has the older path coming out of it which goes all the way to # clock 4 but doesn't terminate in an `End`: other_path = node_3.all_possible_paths()[0] assert other_path.get_ends_of_last_node() == [] # And when we `ensure_buffer` from `node_3`, it will ensure a buffer on that # path also, and cause an `End` to be created there: project.ensure_buffer(node_3, 1000) total_nodes_added = 0 while project.crunching_manager.jobs: time.sleep(0.1) total_nodes_added += project.sync_crunchers() assert len(project.tree.nodes) == 10 assert len(get_all_ends()) == 2 plain_root = project.create_root() assert len(project.tree.roots) == 2 assert len(project.tree.all_possible_paths()) == 4 assert len(project.tree.nodes) == 11 iterator = project.iter_simulate(node_1, 10) new_node = iterator.next() assert new_node is node_1 assert len(project.tree.nodes) == 11 assert project.tree.lock._ReadWriteLock__writer is None new_node = iterator.next() assert new_node is not node_1 assert new_node.parent is node_1 assert len(project.tree.nodes) == 12 bunch_of_new_nodes = tuple(iterator) consecutive_pairs = cute_iter_tools.consecutive_pairs(bunch_of_new_nodes) for parent_node, kid_node in consecutive_pairs: assert project.tree.lock._ReadWriteLock__writer is None assert isinstance(parent_node, garlicsim.data_structures.Node) assert isinstance(kid_node, garlicsim.data_structures.Node) assert parent_node.children == [kid_node] assert kid_node.parent is parent_node assert len(project.tree.nodes) == 14 assert len(get_all_ends()) == 3 tree_members_iterator = \ project.tree.iterate_tree_members(include_blockful_nodes=False) assert tree_members_iterator.__iter__() is tree_members_iterator tree_members = list(tree_members_iterator) for tree_member in tree_members: if isinstance(tree_member, garlicsim.data_structures.Node): assert tree_member.block is None tree_members_iterator_including_blockful_nodes = \ project.tree.iterate_tree_members() assert tree_members_iterator_including_blockful_nodes.__iter__() is \ tree_members_iterator_including_blockful_nodes tree_members_including_blockful_nodes = \ list(tree_members_iterator_including_blockful_nodes) blockful_nodes = \ [member for member in tree_members_including_blockful_nodes if member not in tree_members] assert len(blockful_nodes) >= 1 for blockful_node in blockful_nodes: assert isinstance(blockful_node, garlicsim.data_structures.Node) assert isinstance(blockful_node.block, garlicsim.data_structures.Block) assert blockful_node.block is blockful_node.soft_get_block() assert set(tree_members).\ issubset(set(tree_members_including_blockful_nodes)) tree_step_profiles = project.tree.get_step_profiles() assert isinstance(tree_step_profiles, OrderedSet) assert tree_step_profiles == [step_profile] ends = [ member for member in tree_members if isinstance(member, garlicsim.data_structures.End) ] assert len(ends) == 3 for end in ends: assert end in tree_members_including_blockful_nodes ### Testing `Project.simulate`: ########################################### # # project.simulate(root, 4) assert len(get_all_ends()) == 3 project.simulate(root, 5) assert len(get_all_ends()) == 4 # # ### Finished testing `Project.simulate`. ################################## ### Testing end creation in middle of block: ############################## # # my_non_ending_step = non_ending_history_step if \ my_simpack_grokker.history_dependent else non_ending_inplace_step nodes_in_tree = len(project.tree.nodes) nodes = list(project.iter_simulate(root, 8, my_non_ending_step)) assert len(project.tree.nodes) == nodes_in_tree + 8 middle_node = nodes[-4] assert middle_node.state.clock == 5 assert nodes[1].block == middle_node.block == nodes[-1].block assert len(middle_node.block) == 8 project.begin_crunching(middle_node, infinity, step_profile) total_nodes_added = 0 assert project.crunching_manager.jobs while project.crunching_manager.jobs: time.sleep(0.1) total_nodes_added += project.sync_crunchers() assert total_nodes_added == 0 assert len(middle_node.ends) == 1 assert middle_node.block is not nodes[-1].block assert len(middle_node.block) == 5 assert len(nodes[-1].block) == 3
def __init_general(self, simpack, frame, project=None): '''General initialization.''' self.frame = frame '''The frame that this gui project lives in.''' assert isinstance(self.frame, garlicsim_wx.Frame) if isinstance(simpack, garlicsim.misc.SimpackGrokker): simpack_grokker = simpack simpack = simpack_grokker.simpack else: simpack_grokker = garlicsim.misc.SimpackGrokker(simpack) self.simpack = simpack '''The simpack used for this gui project.''' self.simpack_grokker = simpack_grokker '''The simpack grokker used for this gui project.''' self.simpack_wx_grokker = garlicsim_wx.misc.SimpackWxGrokker(simpack) '''The simpack_wx used for this gui project.''' self.project = project or garlicsim.Project(simpack_grokker) '''The project encapsulated in this gui project.''' assert isinstance(self.project, garlicsim.Project) ### If it's a new project, use `ProcessCruncher` if available: ######## # # if (not project): # Note this is the project given as an argument if (crunchers.ProcessCruncher in simpack_grokker.available_cruncher_types): self.project.crunching_manager.cruncher_type = \ crunchers.ProcessCruncher # # ####################################################################### self.path = None '''The active path.''' self.active_node = None '''The node that is currently displayed onscreen.''' self.is_playing = False '''Says whether the simulation is currently playing.''' self.infinity_job = None ''' The job of the playing leaf, which should be crunched to infinity. ''' self.default_buffer = 100 ''' The default clock buffer to crunch from an active node. For the user it is called "Autocrunch". ''' self._default_buffer_before_cancellation = None ''' The value of the default buffer before buffering was cancelled. When buffering will be enabled again, it will be set to this value. ''' self.timer_for_playing = thread_timer.ThreadTimer(self.frame) '''Contains the timer object used when playing the simulation.''' self.frame.Bind(thread_timer.EVT_THREAD_TIMER, self.__play_next, self.timer_for_playing) self.defacto_playing_speed = 4 '''The playing speed that we are actually playing in.''' self.official_playing_speed = 4 ''' The playing speed that we're "officially" playing in. The defacto playing speed may deviate from this. ''' self.standard_playing_speed = 4 '''The reference playing speed. This speed is considered "normal".''' self.last_tracked_real_time = None ''' The last tracked time point (real time, not simulation), for playback. ''' self.pseudoclock = 0 ''' The current pseudoclock. The pseudoclock is *something like* the clock of the current active node. But not exactly. We're letting the pseudoclock slide more smoothly from one node to its neighbor, instead of jumping. This is in order to make some things smoother in the program. This is also why it's called "pseudo". ''' self.default_step_profile = garlicsim.misc.StepProfile( self.simpack_grokker.default_step_function) '''The step profile that will be used be default.''' self.step_profiles = EmittingOrderedSet( emitter=None, items=(self.default_step_profile, )) '''An ordered set of step profiles that the user may use.''' self.step_profiles_to_hues = EmittingWeakKeyDefaultDict( emitter=None, default_factory=StepProfileHueDefaultFactory(self), ) '''Mapping from step profile to hue that represents it in GUI.''' self._tracked_step_profile = None self._temp_shell_history = None self._temp_shell_command_history = None self._job_and_node_of_recent_fork_by_crunching = None ### Setting up namespace: ############################################# # # self.namespace = { '__name__': '__garlicsim_shell__', # This will become `.__module__` of classes and functions. 'f': frame, 'frame': frame, 'gp': self, 'gui_project': self, 'p': self.project, 'project': self.project, 't': self.project.tree, 'tree': self.project.tree, 'gs': garlicsim, 'garlicsim': garlicsim, 'gs_wx': garlicsim_wx, 'garlicsim_wx': garlicsim_wx, 'wx': wx, 'simpack': self.simpack, self.simpack.__name__.rsplit('.', 1)[-1]: self.simpack, } '''Namespace that will be used in shell and other places.''' garlicsim_lib = import_tools.import_if_exists('garlicsim_lib', silent_fail=True) if garlicsim_lib: self.namespace.update({ 'gs_lib': garlicsim_lib, 'garlicsim_lib': garlicsim_lib, }) # # ### Finished setting up namespace. #################################### self.__init_emitters() self.__init_menu_enablings() self.emitter_system.top_emitter.emit()
def check(simpack, cruncher_type): my_simpack_grokker = garlicsim.misc.SimpackGrokker(simpack) assert my_simpack_grokker is garlicsim.misc.SimpackGrokker(simpack) # Ensuring caching works. assert not simpack._test_settings.ENDABLE assert garlicsim.misc.simpack_grokker.step_type.StepType.get_step_type( my_simpack_grokker.default_step_function ) == simpack._test_settings.DEFAULT_STEP_FUNCTION_TYPE step_profile = my_simpack_grokker.build_step_profile() deterministic = \ my_simpack_grokker.settings.DETERMINISM_FUNCTION(step_profile) state = simpack.State.create_root() prev_state = state for i in [1, 2, 3, 4]: new_state = garlicsim.simulate(state, i) assert new_state.clock >= getattr(prev_state, 'clock', 0) prev_state = new_state result = garlicsim.list_simulate(state, 4) for item in result: assert isinstance(item, garlicsim.data_structures.State) assert isinstance(item, simpack.State) assert isinstance(result, list) assert len(result) == 5 iter_result = garlicsim.iter_simulate(state, 4) assert not hasattr(iter_result, '__getitem__') assert hasattr(iter_result, '__iter__') iter_result_in_list = list(iter_result) del iter_result assert len(iter_result_in_list) == len(result) == 5 ### Setting up a project to run asynchronous tests: project = garlicsim.Project(simpack) project.crunching_manager.cruncher_type = cruncher_type assert project.tree.lock._ReadWriteLock__writer is None root = project.root_this_state(state) project.begin_crunching(root, 4) total_nodes_added = 0 while project.crunching_manager.jobs: time.sleep(0.1) total_nodes_added += project.sync_crunchers() assert total_nodes_added == 4 assert len(project.tree.nodes) == 5 assert len(project.tree.roots) == 1 paths = project.tree.all_possible_paths() assert len(paths) == 1 (my_path, ) = paths assert len(my_path) == 5 node_1 = my_path[1] assert node_1.state.clock == 1 node_2 = project.simulate(node_1, 3) assert len(project.tree.nodes) == 8 assert len(project.tree.roots) == 1 assert len(project.tree.all_possible_paths()) == 2 block_1, block_2 = [node.block for node in node_1.children] assert isinstance(block_1, garlicsim.data_structures.Block) assert isinstance(block_2, garlicsim.data_structures.Block) assert block_1.soft_get_block() is block_1 assert block_2.soft_get_block() is block_2 assert block_1.is_overlapping(block_1) assert block_2.is_overlapping(block_2) assert not block_1.is_overlapping(block_2) assert not block_2.is_overlapping(block_1) block_path_1 = block_1.make_containing_path() block_path_2 = block_2.make_containing_path() assert block_path_1 == block_path_1 assert block_path_1 != block_path_2 assert (block_1[0] in block_path_1) and (block_1[-1] in block_path_1) assert (block_2[0] in block_path_2) and (block_2[-1] in block_path_2) assert block_1.get_root() is block_2.get_root() tree_members_iterator = \ project.tree.iterate_tree_members(include_blockful_nodes=False) assert tree_members_iterator.__iter__() is tree_members_iterator tree_members = list(tree_members_iterator) assert (block_1 in tree_members) and (block_2 in tree_members) for tree_member in tree_members: if isinstance(tree_member, garlicsim.data_structures.Node): assert tree_member.block is None tree_members_iterator_including_blockful_nodes = \ project.tree.iterate_tree_members(include_blockful_nodes=True) assert tree_members_iterator_including_blockful_nodes.__iter__() is \ tree_members_iterator_including_blockful_nodes tree_members_including_blockful_nodes = \ list(tree_members_iterator_including_blockful_nodes) blockful_nodes = \ [member for member in tree_members_including_blockful_nodes if member not in tree_members] for blockful_node in blockful_nodes: assert isinstance(blockful_node, garlicsim.data_structures.Node) assert isinstance(blockful_node.block, garlicsim.data_structures.Block) assert blockful_node.block is blockful_node.soft_get_block() assert set(tree_members).\ issubset(set(tree_members_including_blockful_nodes)) tree_step_profiles = project.tree.get_step_profiles() assert isinstance(tree_step_profiles, OrderedSet) assert tree_step_profiles == [step_profile]
def test_node_selection_and_range(): '''Test `node_selection` and `node_range`.''' root_state = life.State.create_root(2, 2) project = garlicsim.Project(life) tree = project.tree root = project.root_this_state(root_state) leaf1 = project.simulate(root, 10) temp_path = root.make_containing_path() middle_node = temp_path[5] leaf2 = project.simulate(middle_node, 10) # Now we have a tree with a fork in it, in `middle_node` path1 = leaf1.make_containing_path() # creating only after leaf2 path2 = leaf2.make_containing_path() range1 = ds.NodeRange(root, leaf1) assert path1 == range1.make_path() range2 = ds.NodeRange(root, leaf2) assert path2 == range2.make_path() ns1 = ds.NodeSelection([range1, range2]) ns2 = ns1.copy() assert ns1 == ns2 ns2.compact() assert ns1 == ns2 range1blocky = ds.NodeRange(root, leaf1.block) range2blocky = ds.NodeRange(root, leaf2.block) ns3 = ds.NodeSelection([range1blocky, range2blocky]) ns4 = ns3.copy() ns4.compact() logic_tools.all_equal((ns1, ns2, ns3, ns4), exhaustive=True) all_ranges = sum((ns.ranges for ns in (ns1, ns2, ns3, ns4)), []) for range in all_ranges: assert range == range.clone_with_blocks_dissolved() assert len(tree.nodes) == 21 ##################### alt_tree, alt_ns1 = copy.deepcopy((tree, ns1)) alt_tree.delete_node_selection(alt_ns1) assert len(alt_tree.nodes) == 0 assert len(alt_tree.roots) == 0 ##################### assert len(tree.nodes) == 21 middle_node_grandparent = middle_node.parent.parent middle_node_grandchild_1 = path1.next_node(path1.next_node(middle_node)) middle_node_grandchild_2 = path2.next_node(path2.next_node(middle_node)) assert middle_node_grandchild_1 is not middle_node_grandchild_2 small_range_1 = ds.NodeRange(middle_node_grandparent, middle_node_grandchild_1) small_range_2 = ds.NodeRange(middle_node_grandparent, middle_node_grandchild_2) assert small_range_1 != small_range_2 small_ns = ds.NodeSelection((small_range_1, small_range_2)) ##################### alt_tree, alt_small_range_1 = copy.deepcopy((tree, small_range_1)) alt_tree.delete_node_range(alt_small_range_1) assert len(alt_tree.roots) == 3 assert len(alt_tree.nodes) == 16 ##################### ##################### alt_tree, alt_small_range_2 = copy.deepcopy((tree, small_range_2)) alt_tree.delete_node_range(alt_small_range_2) assert len(alt_tree.roots) == 3 assert len(alt_tree.nodes) == 16 ##################### ##################### alt_tree, alt_small_ns = copy.deepcopy((tree, small_ns)) alt_tree.delete_node_selection(alt_small_ns) assert len(alt_tree.roots) == 3 assert len(alt_tree.nodes) == 14 ##################### assert len(tree.nodes) == 21
def test(): '''Test tutorial-1.''' life_board_pattern = re.compile('^(([ #]{45}\n){24})([ #]{45})$') import garlicsim from garlicsim_lib.simpacks import life state = life.State.create_messy_root() assert life_board_pattern.match(repr(state)) assert repr(type(state)) == \ "<class 'garlicsim_lib.simpacks.life.state.State'>" new_state = garlicsim.simulate(state) assert life_board_pattern.match(repr(new_state)) new_state = garlicsim.simulate(state, 20) assert life_board_pattern.match(repr(new_state)) result = garlicsim.list_simulate(state, 20) assert repr(type(result)) == "<type 'list'>" assert len(result) == 21 assert life_board_pattern.match(repr(result[0])) assert result[0] == state assert life_board_pattern.match(repr(result[-1])) assert life_board_pattern.match(repr(result[7])) repr(garlicsim.iter_simulate(state, 5)) # Not testing cause of pypy et al. assert (list(garlicsim.iter_simulate(state, 5)) == \ garlicsim.list_simulate(state, 5)) project = garlicsim.Project(life) state = life.State.create_diehard() assert life_board_pattern.match(repr(state)) assert repr(state).count('#') == 7 root = project.root_this_state(state) assert repr(root) == \ ('<garlicsim.data_structures.Node with clock 0, ' 'root, leaf, touched, blockless, at %s>' % hex(id(root))) project.begin_crunching(root, 50) _result = project.sync_crunchers() assert repr(_result) == '<0 nodes were added to the tree>' (cruncher, ) = project.crunching_manager.crunchers.values() while cruncher.is_alive(): time.sleep(0.1) _result = project.sync_crunchers() assert repr(_result) == '<50 nodes were added to the tree>' assert repr( project.tree) == ('<garlicsim.data_structures.Tree with 1 roots, ' '51 nodes and 1 possible paths at %s>' % hex(id(project.tree))) (path, ) = project.tree.all_possible_paths() assert repr(path) == ('<garlicsim.data_structures.Path of length 51 ' 'at %s>' % hex(id(path))) assert repr(path[-1]) == ( '<garlicsim.data_structures.Node with clock 50, leaf, untouched, ' 'blockful, crunched with life.State.step_generator(<state>), at ' '%s>' % hex(id(path[-1]))) _state = path[-1].state assert repr(_state).count('#') == 24 assert life_board_pattern.match(repr(_state)) node = path[27] assert repr(node.state).count('#') == 20 assert life_board_pattern.match(repr(node.state)) new_node = project.fork_to_edit(node) new_node.state.board.set(28, 13, True) assert repr(new_node.state).count('#') == 21 assert life_board_pattern.match(repr(new_node.state)) new_node.finalize() assert repr( project.tree) == ('<garlicsim.data_structures.Tree with 1 roots, ' '52 nodes and 2 possible paths at %s>' % hex(id(project.tree))) project.ensure_buffer(root, 50) _result = project.sync_crunchers() assert repr(_result) == '<0 nodes were added to the tree>' (cruncher, ) = project.crunching_manager.crunchers.values() while cruncher.is_alive(): time.sleep(0.1) _result = project.sync_crunchers() assert repr(_result) == '<23 nodes were added to the tree>' new_path = new_node.make_containing_path() assert repr(new_path[-1].state).count('#') == 49 assert life_board_pattern.match(repr(new_path[-1].state))
def check(simpack, cruncher_type): ''' Run checks on a simpack that uses inplace step functions. ''' my_simpack_grokker = garlicsim.misc.SimpackGrokker(simpack) assert simpack._test_settings.DEFAULT_STEP_FUNCTION_TYPE in \ [garlicsim.misc.simpack_grokker.step_types.InplaceStep, garlicsim.misc.simpack_grokker.step_types.InplaceStepGenerator] assert garlicsim.misc.simpack_grokker.step_type.StepType.get_step_type( my_simpack_grokker.default_step_function ) == simpack._test_settings.DEFAULT_STEP_FUNCTION_TYPE assert simpack._test_settings.CONSTANT_CLOCK_INTERVAL == 1 step_profile = my_simpack_grokker.build_step_profile() state = simpack.State.create_root() assert state.clock == 0 with StateDeepcopyCounter() as state_deepcopy_counter: state_1 = garlicsim.simulate(state) assert state.clock == 0 assert state_1.clock == 1 assert state_1 is not state assert state_1.list is not state.list assert state_1.cross_process_persistent is state.cross_process_persistent n_state_deepcopy_operations = state_deepcopy_counter.call_count assert 1 <= n_state_deepcopy_operations <= 2 with StateDeepcopyCounter() as state_deepcopy_counter: state_2 = garlicsim.simulate(state, 2) assert state.clock == 0 assert state_1.clock == 1 assert state_2.clock == 2 assert state_2 is not state assert state_2.list is not state.list assert state_2.cross_process_persistent is state.cross_process_persistent assert n_state_deepcopy_operations == state_deepcopy_counter.call_count with StateDeepcopyCounter() as state_deepcopy_counter: state_10 = garlicsim.simulate(state, 10) assert state.clock == 0 assert state_1.clock == 1 assert state_2.clock == 2 assert state_10.clock == 10 assert state_10 is not state assert state_10 is not state_2 assert state_10.list is not state.list assert state_10.list is not state_2.list assert state_10.cross_process_persistent is state.cross_process_persistent assert n_state_deepcopy_operations == state_deepcopy_counter.call_count ########################################################################### # # with StateDeepcopyCounter() as state_deepcopy_counter: garlicsim.list_simulate(state, 3) n_state_deepcopy_operations_for_3_in_list = \ state_deepcopy_counter.call_count with StateDeepcopyCounter() as state_deepcopy_counter: garlicsim.list_simulate(state, 4) n_state_deepcopy_operations_for_4_in_list = \ state_deepcopy_counter.call_count assert n_state_deepcopy_operations_for_4_in_list > \ n_state_deepcopy_operations_for_3_in_list # # ########################################################################### prev_state = state for i in [1, 2, 3, 4]: new_state = garlicsim.simulate(state, i) assert new_state.clock >= getattr(prev_state, 'clock', 0) assert new_state is not prev_state assert new_state.list is not prev_state.list assert new_state.cross_process_persistent is \ prev_state.cross_process_persistent prev_state = new_state result = garlicsim.list_simulate(state, 4) for item in result: assert isinstance(item, garlicsim.data_structures.State) assert isinstance(item, simpack.State) assert isinstance(result, list) assert len(result) == 5 iter_result = garlicsim.iter_simulate(state, 4) assert not hasattr(iter_result, '__getitem__') assert hasattr(iter_result, '__iter__') iter_result_in_list = list(iter_result) del iter_result assert len(iter_result_in_list) == len(result) == 5 ### Setting up a project to run asynchronous tests: project = garlicsim.Project(simpack) project.crunching_manager.cruncher_type = cruncher_type assert project.tree.lock._ReadWriteLock__writer is None root = project.root_this_state(state) project.begin_crunching(root, 4) total_nodes_added = 0 while project.crunching_manager.jobs: time.sleep(0.1) total_nodes_added += project.sync_crunchers() assert total_nodes_added == 4 assert len(project.tree.nodes) == 5 assert len(project.tree.roots) == 1 paths = project.tree.all_possible_paths() assert len(paths) == 1 (my_path, ) = paths assert len(my_path) == 5 node_1 = my_path[1] assert node_1.state.clock == 1 node_2 = project.simulate(node_1, 3) assert len(project.tree.nodes) == 8 assert len(project.tree.roots) == 1 assert len(project.tree.all_possible_paths()) == 2 block_1, block_2 = [node.block for node in node_1.children] assert isinstance(block_1, garlicsim.data_structures.Block) assert isinstance(block_2, garlicsim.data_structures.Block) assert block_1.soft_get_block() is block_1 assert block_2.soft_get_block() is block_2 assert block_1.is_overlapping(block_1) assert block_2.is_overlapping(block_2) assert not block_1.is_overlapping(block_2) assert not block_2.is_overlapping(block_1) block_path_1 = block_1.make_containing_path() block_path_2 = block_2.make_containing_path() assert block_path_1 == block_path_1 assert block_path_1 != block_path_2 assert (block_1[0] in block_path_1) and (block_1[-1] in block_path_1) assert (block_2[0] in block_path_2) and (block_2[-1] in block_path_2) assert block_1.get_root() is block_2.get_root() tree_members_iterator = \ project.tree.iterate_tree_members(include_blockful_nodes=False) assert tree_members_iterator.__iter__() is tree_members_iterator tree_members = list(tree_members_iterator) assert (block_1 in tree_members) and (block_2 in tree_members) for tree_member in tree_members: if isinstance(tree_member, garlicsim.data_structures.Node): assert tree_member.block is None tree_members_iterator_including_blockful_nodes = \ project.tree.iterate_tree_members(include_blockful_nodes=True) assert tree_members_iterator_including_blockful_nodes.__iter__() is \ tree_members_iterator_including_blockful_nodes tree_members_including_blockful_nodes = \ list(tree_members_iterator_including_blockful_nodes) blockful_nodes = \ [member for member in tree_members_including_blockful_nodes if member not in tree_members] for blockful_node in blockful_nodes: assert isinstance(blockful_node, garlicsim.data_structures.Node) assert isinstance(blockful_node.block, garlicsim.data_structures.Block) assert blockful_node.block is blockful_node.soft_get_block() assert set(tree_members).\ issubset(set(tree_members_including_blockful_nodes)) tree_step_profiles = project.tree.get_step_profiles() assert isinstance(tree_step_profiles, OrderedSet) assert tree_step_profiles == [step_profile]
def check(simpack, cruncher_type): my_simpack_grokker = garlicsim.misc.SimpackGrokker(simpack) assert my_simpack_grokker is garlicsim.misc.SimpackGrokker(simpack) # Ensuring caching works. empty_step_profile = garlicsim.misc.StepProfile( my_simpack_grokker.default_step_function) state = simpack.State.create_messy_root() if \ simpack.State.create_messy_root else \ simpack.State.create_root() new_state = garlicsim.simulate(state, 3) result = garlicsim.list_simulate(state, 3) for item in result: assert isinstance(item, garlicsim.data_structures.State) assert isinstance(item, simpack.State) assert isinstance(result, list) assert len(result) == 4 if _is_deterministic(simpack): for old, new in cute_iter_tools.consecutive_pairs(result): assert new == my_simpack_grokker.step(old, empty_step_profile) iter_result = garlicsim.iter_simulate(state, 3) assert not hasattr(iter_result, '__getitem__') assert hasattr(iter_result, '__iter__') iter_result_in_list = list(iter_result) del iter_result assert len(iter_result_in_list) == len(result) == 4 if _is_deterministic(simpack): assert iter_result_in_list == result assert iter_result_in_list[-1] == new_state == result[-1] project = garlicsim.Project(simpack) # Ensure that `Project.__init__` can take simpack grokker: alterante_project = garlicsim.Project(my_simpack_grokker) project.simpack is alterante_project.simpack project.simpack_grokker is alterante_project.simpack_grokker project.crunching_manager.cruncher_type = cruncher_type assert project.tree.lock._ReadWriteLock__writer is None root = project.root_this_state(state) project.begin_crunching(root, 4) total_nodes_added = 0 while project.crunching_manager.jobs: time.sleep(0.1) total_nodes_added += project.sync_crunchers() x = total_nodes_added if x < 4: # For simpacks with long time intervals, we make sure at least 4 nodes # were created. path = root.make_containing_path() leaf = path[-1] project.simulate(leaf, math_tools.round_to_int(4 - x, up=True)) x += path.__len__(head=path.next_node(leaf)) assert len(project.tree.nodes) == x + 1 assert len(project.tree.roots) == 1 paths = project.tree.all_possible_paths() assert len(paths) == 1 (my_path, ) = paths assert len(my_path) == x + 1 node_1 = my_path[1] node_2 = project.simulate(node_1, 3) assert len(project.tree.nodes) == x + 1 + 3 assert len(project.tree.roots) == 1 assert len(project.tree.all_possible_paths()) == 2 ### Testing project pickling and unpickling: ############################## # # pickled_project = pickle.dumps(project, protocol=2) unpickled_project = cPickle.loads(pickled_project) path_pairs = itertools.izip(project.tree.all_possible_paths(), unpickled_project.tree.all_possible_paths()) if simpack.State.__eq__ != garlicsim.data_structures.State.__eq__: for path_of_original, path_of_duplicate in path_pairs: state_pairs = itertools.izip(path_of_original.states(), path_of_duplicate.states()) for state_of_original, state_of_duplicate in state_pairs: assert state_of_original == state_of_duplicate # # ### Finished testing project pickling and unpickling. ##################### node_3 = my_path.next_node(node_1) project.begin_crunching(node_3, 3) total_nodes_added = 0 while project.crunching_manager.jobs: time.sleep(0.1) total_nodes_added += project.sync_crunchers() y = total_nodes_added if y < 3: # For simpacks with long time intervals, we make sure at least 3 nodes # were created. path = node_3.children[1].make_containing_path() leaf = path[-1] project.simulate(leaf, math_tools.round_to_int(3 - y, up=True)) y += path.__len__(head=path.next_node(leaf)) assert len(project.tree.nodes) == x + y + 4 paths = project.tree.all_possible_paths() assert len(paths) == 3 assert [len(p) for p in paths] == [x + 1, 3 + y, 5] for (_path_1, _path_2) in cute_iter_tools.consecutive_pairs(paths): assert _path_1._get_higher_path(node=root) == _path_2 for _path in paths: assert _path.copy() == _path project.ensure_buffer(node_3, 3) total_nodes_added = 0 while project.crunching_manager.jobs: time.sleep(0.1) total_nodes_added += project.sync_crunchers() assert len(project.tree.nodes) == x + y + 4 + total_nodes_added assert len(project.tree.all_possible_paths()) == 3 assert project.tree.lock._ReadWriteLock__writer is None two_paths = node_3.all_possible_paths() assert len(two_paths) == 2 (path_1, path_2) = two_paths get_clock_buffer = lambda path: (path[-1].state.clock - node_3.state.clock) (clock_buffer_1, clock_buffer_2) = [get_clock_buffer(p) for p in two_paths] project.ensure_buffer_on_path(node_3, path_1, get_clock_buffer(path_1) * 1.2) total_nodes_added = 0 while project.crunching_manager.jobs: time.sleep(0.1) total_nodes_added += project.sync_crunchers() (old_clock_buffer_1, old_clock_buffer_2) = (clock_buffer_1, clock_buffer_2) (clock_buffer_1, clock_buffer_2) = [get_clock_buffer(p) for p in two_paths] assert clock_buffer_1 / old_clock_buffer_1 >= 1.2 - FUZZ assert clock_buffer_2 == old_clock_buffer_2 project.ensure_buffer_on_path(node_3, path_2, get_clock_buffer(path_2) * 1.3) total_nodes_added = 0 while project.crunching_manager.jobs: time.sleep(0.1) total_nodes_added += project.sync_crunchers() (old_clock_buffer_1, old_clock_buffer_2) = (clock_buffer_1, clock_buffer_2) (clock_buffer_1, clock_buffer_2) = [get_clock_buffer(p) for p in two_paths] assert clock_buffer_1 == old_clock_buffer_1 assert clock_buffer_2 / old_clock_buffer_2 >= 1.3 - FUZZ plain_root = project.create_root() assert len(project.tree.roots) == 2 assert len(project.tree.all_possible_paths()) == 4 assert project.tree.lock._ReadWriteLock__writer is None number_of_nodes = len(project.tree.nodes) iterator = project.iter_simulate(plain_root, 5) assert project.tree.lock._ReadWriteLock__writer is None new_node = iterator.next() assert new_node is plain_root assert len(project.tree.nodes) == number_of_nodes assert project.tree.lock._ReadWriteLock__writer is None new_node = iterator.next() assert new_node is not plain_root assert new_node.parent is plain_root assert len(project.tree.nodes) == number_of_nodes + 1 bunch_of_new_nodes = tuple(iterator) consecutive_nodes = cute_iter_tools.consecutive_pairs(bunch_of_new_nodes) for parent_node, kid_node in consecutive_nodes: assert project.tree.lock._ReadWriteLock__writer is None assert isinstance(parent_node, garlicsim.data_structures.Node) assert isinstance(kid_node, garlicsim.data_structures.Node) assert parent_node.children == [kid_node] assert kid_node.parent is parent_node assert len(project.tree.nodes) == number_of_nodes + 5 (alternate_path, ) = plain_root.all_possible_paths() assert isinstance(alternate_path, garlicsim.data_structures.Path) assert alternate_path == plain_root.make_containing_path() assert len(alternate_path) == 6 all_except_root = list(alternate_path)[1:] ((_key, _value), ) = plain_root.get_all_leaves().items() assert _key is alternate_path[-1] assert _value['nodes_distance'] == 5 assert 'clock_distance' in _value # Can't know the value of that. block = all_except_root[0].block assert isinstance(block, garlicsim.data_structures.Block) for node in all_except_root: assert isinstance(node, garlicsim.data_structures.Node) assert node.block is node.soft_get_block() is block nose.tools.assert_raises(garlicsim.data_structures.NodeError, node.finalize) assert node.get_root() is plain_root assert node.get_ancestor(generations=0) is node assert node.get_ancestor(generations=infinity, round=True) is \ plain_root nose.tools.assert_raises( garlicsim.data_structures.node.NodeLookupError, lambda: node.get_ancestor(generations=infinity, round=False)) nose.tools.assert_raises( garlicsim.data_structures.node.NodeLookupError, lambda: node.get_ancestor(generations=100, round=False)) if node.is_last_on_block(): assert block[-1] is node assert node.get_ancestor(generations=2, round=False) is \ block[-3] assert node.get_ancestor(generations=1, round=True) is \ block[-2] is node.parent if node.is_first_on_block(): assert block[0] is node assert set(all_except_root) == set(block) second_on_block = block[1] second_to_last_on_block = block[-2] assert second_to_last_on_block.state.clock > second_on_block.state.clock assert list( alternate_path.iterate_blockwise( second_on_block, second_to_last_on_block)) == list(block[1:-1]) assert list( alternate_path.iterate_blockwise_reversed( second_on_block, second_to_last_on_block)) == list(block[-2:0:-1]) ### Testing path methods: ################################################# # # empty_path = garlicsim.data_structures.Path(project.tree) assert len(empty_path) == 0 assert list(empty_path) == [] assert list(reversed(empty_path)) == [] assert list(empty_path.iterate_blockwise()) == [] assert list(empty_path.iterate_blockwise_reversed()) == [] for (path, other_path) in [(path_1, path_2), (path_2, path_1)]: assert isinstance(path, garlicsim.data_structures.Path) assert path[-1] is path.get_last_node() node_list = list(path) reversed_node_list = list(reversed(path)) assert node_list == list(reversed(reversed_node_list)) assert list(path.iterate_blockwise()) == \ list(reversed(list(path.iterate_blockwise_reversed(tail=path[-1])))) stranger_node = other_path[-1] assert stranger_node not in path nose.tools.assert_raises( garlicsim.data_structures.path.TailNotReached, lambda: list(path.__iter__(tail=stranger_node))) # # ### Finished testing path methods. ######################################## if simpack.State.create_messy_root is not None: messy_root = project.create_messy_root() assert len(project.tree.roots) == 3 assert messy_root is project.tree.roots[-1] assert isinstance(messy_root.state, simpack.State)