コード例 #1
0
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
コード例 #2
0
    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'))
コード例 #3
0
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)
コード例 #4
0
    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'))
コード例 #5
0
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)
コード例 #6
0
ファイル: logic_tools.py プロジェクト: TobiasSimon/GarlicSim
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)
コード例 #7
0
ファイル: tests.py プロジェクト: ofri/GarlicSim
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
    
    
    
コード例 #8
0
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
コード例 #9
0
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
        
    
    
    
コード例 #10
0
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)
コード例 #11
0
ファイル: test_endable.py プロジェクト: TobiasSimon/GarlicSim
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. #####################
    
    
    
コード例 #12
0
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)