def find_clear_place_on_circle(circle_points, circle_size=1): ''' Find the point on a circle that's the farthest away from other points. Given an interval `(0, circle_size)` and a bunch of points in it, find a place for a new point that is as far away from the other points as possible. (Since this is a circle, there's wraparound, e.g. the end of the interval connects to the start.) ''' # Before starting, taking care of two edge cases: if not circle_points: # Edge case: No points at all return circle_size / 2 if len(circle_points) == 1: # Edge case: Only one point return (circle_points[0] + circle_size / 2) % circle_size sorted_circle_points = sorted(circle_points) last_point = sorted_circle_points[-1] if last_point >= circle_size: raise Exception("One of the points (%s) is bigger than the circle " "size %s." % (last_point, circle_size)) clear_space = {} for first_point, second_point in cute_iter_tools.consecutive_pairs( sorted_circle_points, wrap_around=True ): clear_space[first_point] = second_point - first_point # That's the only one that might be negative, so we ensure it's positive: clear_space[last_point] %= circle_size maximum_clear_space = max(clear_space.itervalues()) winners = [key for (key, value) in clear_space.iteritems() if value == maximum_clear_space] winner = winners[0] result = (winner + (maximum_clear_space / 2)) % circle_size return result
def _get_higher_path(self, node, reverse=False): ''' Get a higher path than this one. "Higher" means that in some point in the past the other path goes through a child node with a higher index number (in `children`) than this path. This method will return the lowest path that is just above this path. ''' my_iter = __builtin__.reversed if reverse else iter wanted_clock = node.state.clock for (kid, parent) in cute_iter_tools.consecutive_pairs(reversed(self)): if len(parent.children) == 1: continue my_index = parent.children.index(kid) if reverse: if my_index > 0: kids_to_try = parent.children[:my_index] break if not reverse: if my_index < len(parent.children) -1: kids_to_try = parent.children[my_index+1:] break else: raise PathLookupError('This path is the %s one.' % \ ('lowest' if reverse else 'highest')) for node in my_iter(kids_to_try): paths = node.all_possible_paths() # todo: make reversed argument for path in my_iter(paths): assert isinstance(path, Path) if path[-1].state.clock >= wanted_clock: return path raise PathLookupError('''This path is the %s one which extends enough \ in the future to the clock of the specified node.''' % \ ('lowest' if reverse else 'highest'))
def all_equal(iterable, exhaustive=False): ''' Return whether all elements in the iterable are equal to each other. If `exhaustive` is set to False, it's assumed that the equality relation is transitive, therefore not every member is tested against every other member. So in a list of size n, n-1 equality checks will be made. If `exhaustive` is set to True, every member will be checked against every other member. So in a list of size n, (n*(n-1))/2 equality checks will be made. ''' if exhaustive is True: pairs = cute_iter_tools.orderless_combinations(iterable, 2) else: # exhaustive is False pairs = cute_iter_tools.consecutive_pairs(iterable) return all(a==b for (a, b) in pairs)
def _get_higher_path(self, node, _reverse=False): ''' Get a higher path than this one. "Higher" means that in some point in the past the other path goes through a child node with a higher index number (in `children`) than this path. This method will return the lowest path that is just above this path. ''' my_iter = __builtin__.reversed if _reverse else iter wanted_clock = node.state.clock for (kid, parent) in cute_iter_tools.consecutive_pairs(reversed(self)): if len(parent.children) == 1: continue my_index = parent.children.index(kid) if _reverse: if my_index > 0: kids_to_try = parent.children[:my_index] break if not _reverse: if my_index < len(parent.children) - 1: kids_to_try = parent.children[my_index + 1:] break else: raise PathLookupError('This path is the %s one.' % \ ('lowest' if _reverse else 'highest')) for node in my_iter(kids_to_try): paths = node.all_possible_paths() # todo: make reversed argument for path in my_iter(paths): assert isinstance(path, Path) if path[-1].state.clock >= wanted_clock: return path raise PathLookupError('This path is the %s one which extends enough ' 'in the future to the clock of the specified ' 'node.' % ('lowest' if _reverse else 'highest'))
def all_equal(iterable, exhaustive=False): ''' Return whether all elements in the iterable are equal to each other. If `exhaustive` is set to `False`, it's assumed that the equality relation is transitive, therefore not every member is tested against every other member. So in a list of size `n`, `n-1` equality checks will be made. If `exhaustive` is set to `True`, every member will be checked against every other member. So in a list of size `n`, `(n*(n-1))/2` equality checks will be made. ''' # todo: Maybe I should simply check if `len(set(iterable)) == 1`? Will not # work for unhashables. if exhaustive is True: pairs = sequence_tools.combinations(list(iterable), 2) else: # exhaustive is False pairs = cute_iter_tools.consecutive_pairs(iterable) return all(a == b for (a, b) in pairs)
def all_equal(iterable, exhaustive=False): ''' Return whether all elements in the iterable are equal to each other. If `exhaustive` is set to `False`, it's assumed that the equality relation is transitive, therefore not every member is tested against every other member. So in a list of size `n`, `n-1` equality checks will be made. If `exhaustive` is set to `True`, every member will be checked against every other member. So in a list of size `n`, `(n*(n-1))/2` equality checks will be made. ''' # todo: Maybe I should simply check if `len(set(iterable)) == 1`? Will not # work for unhashables. if exhaustive is True: pairs = sequence_tools.combinations(list(iterable), 2) else: # exhaustive is False pairs = cute_iter_tools.consecutive_pairs(iterable) return all(a==b for (a, b) in pairs)
def simpack_check(simpack, cruncher): state = simpack.State.create_messy_root() if \ simpack.State.create_messy_root else \ simpack.State.create_root() new_state = garlicsim.simulate(state, 5) result = garlicsim.list_simulate(state, 5) my_simpack_grokker = garlicsim.misc.SimpackGrokker(simpack) empty_step_profile = garlicsim.misc.StepProfile() assert len(result) == 6 for item in result: assert isinstance(item, garlicsim.data_structures.State) if hasattr(simpack, 'State'): # Later make mandatory assert isinstance(item, simpack.State) if _is_deterministic(simpack): assert result[-1] == new_state for old, new in cute_iter_tools.consecutive_pairs(result): assert new == my_simpack_grokker.step(old, empty_step_profile) project = garlicsim.Project(simpack) project.crunching_manager.Cruncher = cruncher root = project.root_this_state(state) project.begin_crunching(root, 20) total_nodes_added = 0 while project.crunching_manager.jobs: time.sleep(0.1) total_nodes_added += project.sync_crunchers() x = total_nodes_added 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 if _is_deterministic(simpack): assert my_path[5].state == new_state assert len(my_path) == x + 1 node_1 = my_path[-3] node_2 = project.simulate(node_1, 5) assert len(project.tree.nodes) == x + 6 assert len(project.tree.roots) == 1 assert len(project.tree.all_possible_paths()) == 2 node_3 = my_path.next_node(node_1) project.begin_crunching(node_3, 5) total_nodes_added = 0 while project.crunching_manager.jobs: time.sleep(0.1) total_nodes_added += project.sync_crunchers() y = total_nodes_added assert len(project.tree.nodes) == x + y + 6 paths = project.tree.all_possible_paths() assert len(paths) == 3 assert set(len(p) for p in paths) == set([x + 1, x + 4, x + y]) 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 + 6 + total_nodes_added assert len(project.tree.all_possible_paths()) == 3 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 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 plain_root = project.create_root() assert len(project.tree.roots) == 2 assert len(project.tree.all_possible_paths()) == 4
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 simpack_check(simpack, cruncher): my_simpack_grokker = garlicsim.misc.SimpackGrokker(simpack) state = simpack.State.create_messy_root() if \ simpack.State.create_messy_root else \ simpack.State.create_root() new_state = garlicsim.simulate(state, 5) result = garlicsim.list_simulate(state, 5) iter_result = garlicsim.iter_simulate(state, 5) 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) == 6 if _is_deterministic(simpack): assert iter_result_in_list == result empty_step_profile = garlicsim.misc.StepProfile() assert len(result) == 6 for item in result: assert isinstance(item, garlicsim.data_structures.State) if hasattr(simpack, 'State'): # Later make mandatory assert isinstance(item, simpack.State) if _is_deterministic(simpack): assert result[-1] == new_state for old, new in cute_iter_tools.consecutive_pairs(result): assert new == my_simpack_grokker.step(old, empty_step_profile) project = garlicsim.Project(simpack) project.crunching_manager.Cruncher = cruncher assert project.tree.lock._ReadWriteLock__writer is None root = project.root_this_state(state) project.begin_crunching(root, 20) total_nodes_added = 0 while project.crunching_manager.jobs: time.sleep(0.1) total_nodes_added += project.sync_crunchers() x = total_nodes_added 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 if _is_deterministic(simpack): assert my_path[5].state == new_state assert len(my_path) == x + 1 node_1 = my_path[-3] node_2 = project.simulate(node_1, 5) assert len(project.tree.nodes) == x + 6 assert len(project.tree.roots) == 1 assert len(project.tree.all_possible_paths()) == 2 node_3 = my_path.next_node(node_1) project.begin_crunching(node_3, 5) total_nodes_added = 0 while project.crunching_manager.jobs: time.sleep(0.1) total_nodes_added += project.sync_crunchers() y = total_nodes_added assert len(project.tree.nodes) == x + y + 6 paths = project.tree.all_possible_paths() assert len(paths) == 3 assert set(len(p) for p in paths) == set([x + 1, x + 4, x + y]) 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 + 6 + 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 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 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(node_1, 10) assert project.tree.lock._ReadWriteLock__writer is None new_node = iterator.next() assert new_node is node_1 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 node_1 assert new_node.parent is node_1 assert len(project.tree.nodes) == number_of_nodes + 1 bunch_of_new_nodes = tuple(iterator) for parent_node, kid_node in cute_iter_tools.consecutive_pairs(bunch_of_new_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 + 10
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)
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 # # ### Finished testing end creation in middle of block. #####################
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)