diff --git a/src/topupopt/data/gis/identify.py b/src/topupopt/data/gis/identify.py index ee69c61d8427c477abf506bcc9722be0ba729c06..bc42c18021e13835c00dcb20da17971434081389 100644 --- a/src/topupopt/data/gis/identify.py +++ b/src/topupopt/data/gis/identify.py @@ -1090,7 +1090,7 @@ def is_path_straight( def find_simplifiable_paths( network: nx.MultiDiGraph, - excluded_nodes: list, + protected_nodes: list, ignore_self_loops: bool = False, consider_reversed_edges: bool = False, include_both_directions: bool = False, @@ -1106,7 +1106,7 @@ def find_simplifiable_paths( ---------- network : nx.MultiDiGraph The object describing the graph. - excluded_nodes : list + protected_nodes : list A list of keys for nodes that cannot be in any straight path. ignore_self_loops : bool, optional If True, paths including self-loops can still be straight. If False, @@ -1139,7 +1139,7 @@ def find_simplifiable_paths( node_key for node_key in network.nodes() # the node cannot be among those excluded - if node_key not in excluded_nodes + if node_key not in protected_nodes # the node has to be linked to two other nodes other than itself if len(set(neighbours(network, node_key, ignore_self_loops=True))) == 2 # exclude nodes with self-loops if desired: diff --git a/src/topupopt/data/gis/modify.py b/src/topupopt/data/gis/modify.py index a00087bf4d0138969b95628b134740765e85ccdc..a0e28eda8b5a8b760baa1f00434064e0f19f9843 100644 --- a/src/topupopt/data/gis/modify.py +++ b/src/topupopt/data/gis/modify.py @@ -276,7 +276,9 @@ def transform_roundabouts_into_crossroads( def remove_dead_ends( - network: nx.MultiDiGraph, keepers: tuple = None, max_iterations: int = 1 + network: nx.MultiDiGraph, + protected_nodes: list = None, + max_iterations: int = 1 ) -> list: """ Removes dead ends (non-cyclical branches) from a directed graph. @@ -288,7 +290,7 @@ def remove_dead_ends( ---------- network : nx.MultiDiGraph The object describing the directed graph. - keepers : tuple, optional + protected_nodes : list, optional A list of keys for the nodes that are not to be considered for removal. The default is None, which means all nodes are under consideration. max_iterations : int, optional @@ -301,8 +303,8 @@ def remove_dead_ends( """ - if type(keepers) == type(None): - keepers = [] + if type(protected_nodes) == type(None): + protected_nodes = [] # while true nodes_removed = [] @@ -313,7 +315,7 @@ def remove_dead_ends( target_nodes = [ node_key for node_key in network.nodes() - if node_key not in keepers + if node_key not in protected_nodes # if it has at most one neighbour other than itself if len(set(gis_iden.neighbours(network, node_key, ignore_self_loops=True))) <= 1 @@ -505,20 +507,30 @@ def replace_path(network: nx.MultiDiGraph, path: list) -> tuple: def remove_longer_parallel_edges( - network: nx.MultiDiGraph, ignore_edge_directions: bool = False + network: nx.MultiDiGraph, + distance_key: str = osm.KEY_OSMNX_LENGTH, + ignore_edge_directions: bool = True, + protected_edges: list = None ) -> list: """ Removes longer parallel edges from the network. - - Parallel edges are those connecting the same nodes in the same direction. If - there are parallel edges between any given pair of nodes, the longer ones - will be removed. If desired, edge directions can be ignored. In that case, - only the shortest edge between the same pair of nodes will be retained. + + Parallel edges refer to multiple edges connecting the same nodes. If there + are parallel edges between any given pair of nodes, only the shortest one + will be retained. If desired, edge directions can be ignored. By default, + edge directions are taken into account when selecting parallel edges. Parameters ---------- network : nx.MultiDiGraph The object describing the graph. + distance_key : str, optional + The key used to obtain distances. The default is osm.KEY_OSMNX_LENGTH. + ignore_edge_directions : bool, optional + If True, edge directions are ignored. The default is True. + protected_edges : list, optional + A list of edges that should be retained. The default is None, which + means all edges are elligible. Returns ------- @@ -526,7 +538,9 @@ def remove_longer_parallel_edges( A list of the edges removed. """ - + if type(protected_edges) == type(None): + # default: empty list + protected_edges = [] edges_removed = [] for node_one in network.nodes(): for node_two in network.nodes(): @@ -545,15 +559,22 @@ def remove_longer_parallel_edges( # if none exist, skip if len(list_edges) == 0: continue - # otherwise, sort them by distance (lower distances first) + # otherwise, sort them by distance (shorter distances first) + # note: protected edges are considered in the sorting too sorted_edges = sorted( - (network.edges[edge_key][osm.KEY_OSMNX_LENGTH], edge_key) + (network.edges[edge_key][distance_key], edge_key) for edge_key in list_edges ) + # edges to be removed (drop protected edges here) + edges_for_removal = tuple( + edge_tuple[1] + for edge_tuple in sorted_edges[1:] + if edge_tuple[1] not in protected_edges + ) # remove all but the shortest edge - network.remove_edges_from(edge_tuple[1] for edge_tuple in sorted_edges[1:]) + network.remove_edges_from(edges_for_removal) # update the list of edges removed - edges_removed.extend(edge_tuple[1] for edge_tuple in sorted_edges[1:]) + edges_removed.extend(edges_for_removal) # return statement return edges_removed diff --git a/src/topupopt/data/gis/utils.py b/src/topupopt/data/gis/utils.py index 2ac442f3b434ec4485ac767e2ae68a7f06b3bf87..39fafe63f55f27d35f79a84ce2abfd9333c0756e 100644 --- a/src/topupopt/data/gis/utils.py +++ b/src/topupopt/data/gis/utils.py @@ -740,9 +740,10 @@ def get_directed( def simplify_network( network: MultiDiGraph, - protected_nodes: list, + protected_nodes: list = None, + protected_edges: list = None, dead_end_probing_depth: int = 5, - remove_opposite_parallel_edges: bool = True, + ignore_edge_directions: bool = True, update_street_count_per_node: bool = True, transform_roundabouts: bool = False, max_number_iterations: int = 5, @@ -756,13 +757,15 @@ def simplify_network( network : MultiDiGraph The object describing the network. protected_nodes : list - A list with the keys for the nodes that must be preserved. + The keys for the nodes that must be preserved. + protected_edges : list + The keys for the edges that must be preserved. dead_end_probing_depth : int, optional The maximum number of nodes a dead end can have to be detectable. The default is 5. - remove_opposite_parallel_edges : bool, optional - If True, longer parallel edges in opposite directions are also removed. - The default is True. + ignore_edge_directions : bool, optional + If True, direction is ignored in the search for parallel edges and + simplifiable paths. The default is True. update_street_count_per_node : bool, optional If True, updates the street count on each node. The default is True. transform_roundabouts : bool, optional @@ -778,23 +781,38 @@ def simplify_network( """ + if type(protected_nodes) == type(None): + protected_nodes = [] + if type(protected_edges) == type(None): + protected_edges = [] + else: + # if there are protected edges, then the nodes involved in those edges + # must also be preserved, otherwise they can be removed too + protected_nodes.extend( + # set(aaa for aa in a for aaa in aa[0:-1]) + set(nn for nnn in protected_edges for nn in nnn[0:-1]) + ) iteration_counter = 0 while iteration_counter < max_number_iterations: - # remove self loops (tends to create straight paths and dead ends) + # remove self loops (can create straight paths and dead ends) looping_node_keys = gis_mod.remove_self_loops(network) # remove longer parallel edges (can create dead ends and straight paths) edge_keys = gis_mod.remove_longer_parallel_edges( - network, ignore_edge_directions=remove_opposite_parallel_edges + network, + ignore_edge_directions=ignore_edge_directions, + protected_edges=protected_edges, ) - # remove dead ends (tends to create straight paths) + # remove dead ends (can create straight paths) node_keys = gis_mod.remove_dead_ends( - network, protected_nodes, max_iterations=dead_end_probing_depth + network, + protected_nodes=protected_nodes, + max_iterations=dead_end_probing_depth ) - # join segments (can create self-loops) + # join segments (can create self-loops and parallel edges) paths = gis_iden.find_simplifiable_paths( network, - protected_nodes, - consider_reversed_edges=True) + protected_nodes=protected_nodes, + consider_reversed_edges=ignore_edge_directions) for path in paths: gis_mod.replace_path(network, path) # update iteration counter diff --git a/tests/test_esipp_problem.py b/tests/test_esipp_problem.py index 288e5c1ff43236e7d19e9cb87575130c02ddcbf6..6ec6d625f2bbe16dd14c555197b2d621b727a457 100644 --- a/tests/test_esipp_problem.py +++ b/tests/test_esipp_problem.py @@ -29,7 +29,7 @@ class TestESIPPProblem: def build_solve_ipp( self, - # solver: str = "glpk", + solver: str = None, solver_options: dict = None, use_sos_arcs: bool = False, arc_sos_weight_key: str = (InfrastructurePlanningProblem.SOS1_ARC_WEIGHTS_NONE), @@ -55,6 +55,8 @@ class TestESIPPProblem: assessment_weights: dict = None, simplify_problem: bool = False, ): + if type(solver) == type(None): + solver = self.solver if type(assessment_weights) != dict: assessment_weights = {} # default @@ -226,7 +228,7 @@ class TestESIPPProblem: # optimise ipp.optimise( - solver_name=self.solver, + solver_name=solver, solver_options=solver_options, output_options={}, print_solver_output=print_solver_output, @@ -6173,7 +6175,7 @@ class TestESIPPProblem: ]: # TODO: make this work with GLPK and SCIP ipp = self.build_solve_ipp( - # solver='cbc', # does not work with GLPK nor SCIP + solver='cbc', # does not work with GLPK nor SCIP solver_options={}, perform_analysis=False, plot_results=False, # True, @@ -7602,7 +7604,7 @@ class TestESIPPProblem: # no sos, regular time intervals ipp = self.build_solve_ipp( - # solver='cbc', # TODO: make this work with other solvers + solver='cbc', # TODO: make this work with other solvers solver_options={}, plot_results=False, # True, print_solver_output=False, @@ -7677,6 +7679,8 @@ class TestESIPPProblem: # ************************************************************************* # ************************************************************************* + # TODO: this test is failing + def test_directed_arc_static_downstream_new(self): # time @@ -7744,7 +7748,7 @@ class TestESIPPProblem: # no sos, regular time intervals ipp = self.build_solve_ipp( - # solver=solver, + # solver='cbc', solver_options={}, plot_results=False, # True, print_solver_output=False, @@ -7877,7 +7881,7 @@ class TestESIPPProblem: # no sos, regular time intervals ipp = self.build_solve_ipp( - # solver='cbc', # TODO: make this work with other solvers + solver='cbc', # TODO: make this work with other solvers solver_options={}, plot_results=False, # True, print_solver_output=False, diff --git a/tests/test_gis_identify.py b/tests/test_gis_identify.py index cb960a9fa4e6377d140f6f2bd7725dee6dbd9cf7..9eef616d0d27d2dcb993ba370002286719448a6e 100644 --- a/tests/test_gis_identify.py +++ b/tests/test_gis_identify.py @@ -28,7 +28,7 @@ class TestGisIdentify: self, network: nx.MultiDiGraph, path: list, - excluded_nodes: list, + protected_nodes: list, consider_reversed_edges: bool, ignore_self_loops: bool, ): @@ -48,7 +48,7 @@ class TestGisIdentify: assert path[0] == path[-1] and path[0] == node # cycle: make sure # no excluded nodes in the intermediate positions - for node in excluded_nodes: + for node in protected_nodes: assert node not in path[1:-1] # intermediate nodes can only have two neighbours for node_key in path[1:-1]: @@ -119,7 +119,7 @@ class TestGisIdentify: # paths paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes=[], + protected_nodes=[], consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -128,7 +128,7 @@ class TestGisIdentify: self.straight_path_validator( network, path, - excluded_nodes=[], + protected_nodes=[], consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -142,7 +142,7 @@ class TestGisIdentify: # paths paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes=[], + protected_nodes=[], consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -151,7 +151,7 @@ class TestGisIdentify: self.straight_path_validator( network, path, - excluded_nodes=[], + protected_nodes=[], consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -165,7 +165,7 @@ class TestGisIdentify: # paths paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes=[], + protected_nodes=[], consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -174,7 +174,7 @@ class TestGisIdentify: self.straight_path_validator( network, path, - excluded_nodes=[], + protected_nodes=[], consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -188,7 +188,7 @@ class TestGisIdentify: # paths paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes=[], + protected_nodes=[], consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -197,7 +197,7 @@ class TestGisIdentify: self.straight_path_validator( network, path, - excluded_nodes=[], + protected_nodes=[], consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -223,7 +223,7 @@ class TestGisIdentify: # no reversed edges, no self loops, no excluded nodes consider_reversed_edges = False ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] # test path validator with non-path error_raised = False @@ -231,7 +231,7 @@ class TestGisIdentify: assert not self.straight_path_validator( network, [1, 1, 1], - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -241,7 +241,7 @@ class TestGisIdentify: straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -255,11 +255,11 @@ class TestGisIdentify: # no reversed edges, no self loops, no excluded nodes consider_reversed_edges = False ignore_self_loops = True - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -276,11 +276,11 @@ class TestGisIdentify: # no reversed edges, no self loops, no excluded nodes consider_reversed_edges = True ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -297,11 +297,11 @@ class TestGisIdentify: # no reversed edges, no self loops, no excluded nodes consider_reversed_edges = True ignore_self_loops = True - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -343,11 +343,11 @@ class TestGisIdentify: # no reversed edges, no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -359,11 +359,11 @@ class TestGisIdentify: # no reversed edges, allow self loops, no excluded nodes ignore_self_loops = True - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -375,11 +375,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the middle node ignore_self_loops = False - excluded_nodes = [1] + protected_nodes = [1] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -391,11 +391,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the start node ignore_self_loops = False - excluded_nodes = [0] + protected_nodes = [0] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -407,11 +407,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the end node ignore_self_loops = False - excluded_nodes = [2] + protected_nodes = [2] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -429,11 +429,11 @@ class TestGisIdentify: # allow reversed edges, allow self loops, no excluded nodes ignore_self_loops = True - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -445,11 +445,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -461,11 +461,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the middle node ignore_self_loops = False - excluded_nodes = [1] + protected_nodes = [1] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -477,11 +477,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the start node ignore_self_loops = False - excluded_nodes = [0] + protected_nodes = [0] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -493,11 +493,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the end node ignore_self_loops = False - excluded_nodes = [2] + protected_nodes = [2] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -529,11 +529,11 @@ class TestGisIdentify: # no reversed edges, no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -545,11 +545,11 @@ class TestGisIdentify: # no reversed edges, allow self loops, no excluded nodes ignore_self_loops = True - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -561,11 +561,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the middle node ignore_self_loops = False - excluded_nodes = [1] + protected_nodes = [1] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -577,11 +577,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the start node ignore_self_loops = False - excluded_nodes = [0] + protected_nodes = [0] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -593,11 +593,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the end node ignore_self_loops = False - excluded_nodes = [2] + protected_nodes = [2] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -615,11 +615,11 @@ class TestGisIdentify: # allow reversed edges, allow self loops, no excluded nodes ignore_self_loops = True - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -631,11 +631,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -647,11 +647,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the middle node ignore_self_loops = False - excluded_nodes = [1] + protected_nodes = [1] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -663,11 +663,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the start node ignore_self_loops = False - excluded_nodes = [0] + protected_nodes = [0] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -679,11 +679,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the end node ignore_self_loops = False - excluded_nodes = [2] + protected_nodes = [2] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -715,11 +715,11 @@ class TestGisIdentify: # no reversed edges, no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -730,7 +730,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -740,11 +740,11 @@ class TestGisIdentify: # no reversed edges, allow self loops, no excluded nodes ignore_self_loops = True - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -755,7 +755,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -765,11 +765,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the middle node ignore_self_loops = False - excluded_nodes = [1] + protected_nodes = [1] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -781,11 +781,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the start node ignore_self_loops = False - excluded_nodes = [0] + protected_nodes = [0] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -796,7 +796,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -806,11 +806,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the end node ignore_self_loops = False - excluded_nodes = [2] + protected_nodes = [2] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -821,7 +821,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -837,11 +837,11 @@ class TestGisIdentify: # allow reversed edges, allow self loops, no excluded nodes ignore_self_loops = True - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -852,7 +852,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -862,11 +862,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -877,7 +877,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -887,11 +887,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the middle node ignore_self_loops = False - excluded_nodes = [1] + protected_nodes = [1] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -903,11 +903,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the start node ignore_self_loops = False - excluded_nodes = [0] + protected_nodes = [0] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -918,7 +918,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -928,11 +928,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the end node ignore_self_loops = False - excluded_nodes = [2] + protected_nodes = [2] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -943,7 +943,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -973,11 +973,11 @@ class TestGisIdentify: # no reversed edges, no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -988,7 +988,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -998,11 +998,11 @@ class TestGisIdentify: # no reversed edges, allow self loops, no excluded nodes ignore_self_loops = True - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1013,7 +1013,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1023,11 +1023,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the middle node ignore_self_loops = False - excluded_nodes = [1] + protected_nodes = [1] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1039,11 +1039,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the start node ignore_self_loops = False - excluded_nodes = [0] + protected_nodes = [0] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1054,7 +1054,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1064,11 +1064,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the end node ignore_self_loops = False - excluded_nodes = [2] + protected_nodes = [2] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1079,7 +1079,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1095,11 +1095,11 @@ class TestGisIdentify: # allow reversed edges, allow self loops, no excluded nodes ignore_self_loops = True - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1110,7 +1110,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1120,11 +1120,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1135,7 +1135,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1145,11 +1145,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the middle node ignore_self_loops = False - excluded_nodes = [1] + protected_nodes = [1] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1161,11 +1161,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the start node ignore_self_loops = False - excluded_nodes = [0] + protected_nodes = [0] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1176,7 +1176,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1186,11 +1186,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the end node ignore_self_loops = False - excluded_nodes = [2] + protected_nodes = [2] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1201,7 +1201,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1231,11 +1231,11 @@ class TestGisIdentify: # no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1246,7 +1246,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1256,11 +1256,11 @@ class TestGisIdentify: # allow self loops, no excluded nodes ignore_self_loops = True - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1271,7 +1271,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1281,11 +1281,11 @@ class TestGisIdentify: # no self loops, excluded the "middle" node ignore_self_loops = False - excluded_nodes = [1] + protected_nodes = [1] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1296,7 +1296,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1306,11 +1306,11 @@ class TestGisIdentify: # no self loops, excluded the start node ignore_self_loops = False - excluded_nodes = [0] + protected_nodes = [0] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1321,7 +1321,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1331,11 +1331,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the end node ignore_self_loops = False - excluded_nodes = [2] + protected_nodes = [2] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1346,7 +1346,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1362,11 +1362,11 @@ class TestGisIdentify: # allow reversed edges, allow self loops, no excluded nodes ignore_self_loops = True - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1377,7 +1377,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1387,11 +1387,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1402,7 +1402,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1412,11 +1412,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the middle node ignore_self_loops = False - excluded_nodes = [1] + protected_nodes = [1] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1427,7 +1427,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1437,11 +1437,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the start node ignore_self_loops = False - excluded_nodes = [0] + protected_nodes = [0] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1452,7 +1452,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1462,11 +1462,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the end node ignore_self_loops = False - excluded_nodes = [2] + protected_nodes = [2] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1477,7 +1477,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1507,11 +1507,11 @@ class TestGisIdentify: # no reversed edges, no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1523,11 +1523,11 @@ class TestGisIdentify: # no reversed edges, allow self loops, no excluded nodes ignore_self_loops = True - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1539,11 +1539,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the middle node ignore_self_loops = False - excluded_nodes = [1] + protected_nodes = [1] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1555,11 +1555,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the start node ignore_self_loops = False - excluded_nodes = [0] + protected_nodes = [0] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1571,11 +1571,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the end node ignore_self_loops = False - excluded_nodes = [2] + protected_nodes = [2] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1593,11 +1593,11 @@ class TestGisIdentify: # allow reversed edges, allow self loops, no excluded nodes ignore_self_loops = True - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1608,7 +1608,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1618,11 +1618,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1633,7 +1633,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1643,11 +1643,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the middle node ignore_self_loops = False - excluded_nodes = [1] + protected_nodes = [1] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1659,11 +1659,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the start node ignore_self_loops = False - excluded_nodes = [0] + protected_nodes = [0] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1674,7 +1674,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1684,11 +1684,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the end node ignore_self_loops = False - excluded_nodes = [2] + protected_nodes = [2] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1699,7 +1699,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1729,11 +1729,11 @@ class TestGisIdentify: # no reversed edges, no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1745,11 +1745,11 @@ class TestGisIdentify: # no reversed edges, allow self loops, no excluded nodes ignore_self_loops = True - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1761,11 +1761,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the middle node ignore_self_loops = False - excluded_nodes = [1] + protected_nodes = [1] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1777,11 +1777,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the start node ignore_self_loops = False - excluded_nodes = [0] + protected_nodes = [0] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1793,11 +1793,11 @@ class TestGisIdentify: # do not allow reversed edges, no self loops, excluded the end node ignore_self_loops = False - excluded_nodes = [2] + protected_nodes = [2] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1815,11 +1815,11 @@ class TestGisIdentify: # allow reversed edges, allow self loops, no excluded nodes ignore_self_loops = True - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1830,7 +1830,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1840,11 +1840,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1855,7 +1855,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1865,11 +1865,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the middle node ignore_self_loops = False - excluded_nodes = [1] + protected_nodes = [1] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1881,11 +1881,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the start node ignore_self_loops = False - excluded_nodes = [0] + protected_nodes = [0] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1896,7 +1896,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1906,11 +1906,11 @@ class TestGisIdentify: # allow reversed edges, no self loops, excluded the end node ignore_self_loops = False - excluded_nodes = [2] + protected_nodes = [2] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1921,7 +1921,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1951,11 +1951,11 @@ class TestGisIdentify: # no reversed edges, no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1966,7 +1966,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1982,11 +1982,11 @@ class TestGisIdentify: # no reversed edges, no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -1997,7 +1997,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -2007,11 +2007,11 @@ class TestGisIdentify: # no reversed edges, no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, include_both_directions=True, @@ -2023,7 +2023,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -2053,11 +2053,11 @@ class TestGisIdentify: # no reversed edges, no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -2068,7 +2068,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -2084,11 +2084,11 @@ class TestGisIdentify: # no reversed edges, no self loops, no excluded nodes ignore_self_loops = False - excluded_nodes = [] + protected_nodes = [] straight_paths = gis_iden.find_simplifiable_paths( network, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) @@ -2104,7 +2104,7 @@ class TestGisIdentify: self.straight_path_validator( network, straight_path, - excluded_nodes, + protected_nodes, consider_reversed_edges=consider_reversed_edges, ignore_self_loops=ignore_self_loops, ) diff --git a/tests/test_gis_modify.py b/tests/test_gis_modify.py index aab6fa64e7dbddbe92fb879a415317250574f659..c46a8c1dac1c7aaa703645713a2d0849b56660d6 100644 --- a/tests/test_gis_modify.py +++ b/tests/test_gis_modify.py @@ -160,7 +160,7 @@ class TestGisModify: # find paths paths = gis_iden.find_simplifiable_paths( _net, - excluded_nodes=[], + protected_nodes=[], ignore_self_loops=ignore_self_loops, consider_reversed_edges=consider_reversed_edges, ) @@ -882,7 +882,7 @@ class TestGisModify: ) initial_number_edges = network.number_of_edges() true_edges_removed = [(0, 1, 1), (1, 2, 1), (2, 0, 1)] - edges_removed = gis_mod.remove_longer_parallel_edges(network) + edges_removed = gis_mod.remove_longer_parallel_edges(network, ignore_edge_directions=False) assert len(edges_removed) == len(true_edges_removed) for edge_key in edges_removed: assert edge_key in true_edges_removed @@ -903,7 +903,7 @@ class TestGisModify: ) initial_number_edges = network.number_of_edges() true_edges_removed = [(0, 1, 1), (0, 1, 2), (0, 1, 3)] - edges_removed = gis_mod.remove_longer_parallel_edges(network) + edges_removed = gis_mod.remove_longer_parallel_edges(network, ignore_edge_directions=False) assert len(edges_removed) == len(true_edges_removed) for edge_key in edges_removed: assert edge_key in true_edges_removed @@ -928,7 +928,7 @@ class TestGisModify: ) initial_number_edges = network.number_of_edges() true_edges_removed = [(0, 1, 1), (1, 2, 1), (2, 0, 1)] - edges_removed = gis_mod.remove_longer_parallel_edges(network) + edges_removed = gis_mod.remove_longer_parallel_edges(network, ignore_edge_directions=False) assert len(edges_removed) == len(true_edges_removed) for edge_key in edges_removed: assert edge_key in true_edges_removed @@ -961,7 +961,44 @@ class TestGisModify: (2, 1, 0), (0, 2, 0), ] - edges_removed = gis_mod.remove_longer_parallel_edges(network, True) + edges_removed = gis_mod.remove_longer_parallel_edges(network, ignore_edge_directions=True) + assert len(edges_removed) == len(true_edges_removed) + for edge_key in edges_removed: + assert edge_key in true_edges_removed + assert network.number_of_edges() == initial_number_edges - len(edges_removed) + + # example using protected edges + + network = nx.MultiDiGraph() + network.add_edges_from( + [ + (0, 1, 0, {"length": 3}), + (1, 2, 0, {"length": 4}), + (2, 0, 0, {"length": 5}), + # additional edges + (0, 1, 1, {"length": 4}), + (1, 2, 1, {"length": 5}), + (2, 0, 1, {"length": 6}), + # oppposite edges + (1, 0, 0, {"length": 7}), + (2, 1, 0, {"length": 8}), + (0, 2, 0, {"length": 9}), + ] + ) + initial_number_edges = network.number_of_edges() + true_edges_removed = [ + (0, 1, 1), + (1, 2, 1), + #(2, 0, 1), # protected + (1, 0, 0), + (2, 1, 0), + (0, 2, 0), + ] + edges_removed = gis_mod.remove_longer_parallel_edges( + network, + ignore_edge_directions=True, + protected_edges=[(0, 1, 0), (2, 0, 1)] + ) assert len(edges_removed) == len(true_edges_removed) for edge_key in edges_removed: assert edge_key in true_edges_removed @@ -993,7 +1030,7 @@ class TestGisModify: ("b", "a", 0), (0, "b", 0), ] - edges_removed = gis_mod.remove_longer_parallel_edges(network, True) + edges_removed = gis_mod.remove_longer_parallel_edges(network, ignore_edge_directions=True) assert len(edges_removed) == len(true_edges_removed) for edge_key in edges_removed: assert edge_key in true_edges_removed @@ -1115,7 +1152,7 @@ class TestGisModify: ) nodes_removed = gis_mod.remove_dead_ends( - network, keepers=[4, 8], max_iterations=2 + network, protected_nodes=[4, 8], max_iterations=2 ) true_nodes_removed = [3, 6, 7] @@ -1184,7 +1221,7 @@ class TestGisModify: max_iterations = 5 nodes_removed = gis_mod.remove_dead_ends( - _net, keepers=keeper_dead_end_nodes, max_iterations=max_iterations + _net, protected_nodes=keeper_dead_end_nodes, max_iterations=max_iterations ) # the nodes removed cannot include keeper nodes for node_key in nodes_removed: diff --git a/tests/test_gis_utils.py b/tests/test_gis_utils.py index ffd77d739b30e05c7d8e8e31d3b627899455e434..41e6509d02dc58c3ae03dc69f722b33b76570282 100644 --- a/tests/test_gis_utils.py +++ b/tests/test_gis_utils.py @@ -2399,17 +2399,127 @@ class TestGisUtils: _osm.KEY_OSMNX_ONEWAY: False, }, ), + + (23,28,0,{ + _osm.KEY_OSMNX_OSMID: 34, + _osm.KEY_OSMNX_LENGTH: random.random(), + _osm.KEY_OSMNX_REVERSED: False, + _osm.KEY_OSMNX_ONEWAY: False, + }, + ), + + (28,29,0,{ + _osm.KEY_OSMNX_OSMID: 35, + _osm.KEY_OSMNX_LENGTH: 0.1, + _osm.KEY_OSMNX_REVERSED: False, + _osm.KEY_OSMNX_ONEWAY: False, + }, + ), + + (29,32,0,{ + _osm.KEY_OSMNX_OSMID: 36, + _osm.KEY_OSMNX_LENGTH: 0.1+0.1, + _osm.KEY_OSMNX_REVERSED: False, + _osm.KEY_OSMNX_ONEWAY: False, + }, + ), + + (28,30,0,{ + _osm.KEY_OSMNX_OSMID: 37, + _osm.KEY_OSMNX_LENGTH: 0.1, + _osm.KEY_OSMNX_REVERSED: False, + _osm.KEY_OSMNX_ONEWAY: False, + }, + ), + + (30,32,0,{ + _osm.KEY_OSMNX_OSMID: 38, + _osm.KEY_OSMNX_LENGTH: 0.1+0.2, + _osm.KEY_OSMNX_REVERSED: False, + _osm.KEY_OSMNX_ONEWAY: False, + }, + ), + + (32,31,0,{ + _osm.KEY_OSMNX_OSMID: 39, + _osm.KEY_OSMNX_LENGTH: 0.1, + _osm.KEY_OSMNX_REVERSED: False, + _osm.KEY_OSMNX_ONEWAY: False, + }, + ), + + (31,28,0,{ + _osm.KEY_OSMNX_OSMID: 40, + _osm.KEY_OSMNX_LENGTH: 0.1+0.3, + _osm.KEY_OSMNX_REVERSED: False, + _osm.KEY_OSMNX_ONEWAY: False, + }, + ), + # branch for protected edge (33,34) + + (23,33,0,{ + _osm.KEY_OSMNX_OSMID: 41, + _osm.KEY_OSMNX_LENGTH: random.random(), + _osm.KEY_OSMNX_REVERSED: False, + _osm.KEY_OSMNX_ONEWAY: False, + }, + ), + + (33,34,0,{ + _osm.KEY_OSMNX_OSMID: 42, + _osm.KEY_OSMNX_LENGTH: random.random(), + _osm.KEY_OSMNX_REVERSED: False, + _osm.KEY_OSMNX_ONEWAY: False, + }, + ), + + (34,35,0,{ + _osm.KEY_OSMNX_OSMID: 43, + _osm.KEY_OSMNX_LENGTH: random.random(), + _osm.KEY_OSMNX_REVERSED: False, + _osm.KEY_OSMNX_ONEWAY: False, + }, + ), + + # branch for protected edge (36,37) + (23,36,0,{ + _osm.KEY_OSMNX_OSMID: 44, + _osm.KEY_OSMNX_LENGTH: random.random(), + _osm.KEY_OSMNX_REVERSED: False, + _osm.KEY_OSMNX_ONEWAY: False, + }, + ), + + (36,37,0,{ + _osm.KEY_OSMNX_OSMID: 45, + _osm.KEY_OSMNX_LENGTH: random.random(), + _osm.KEY_OSMNX_REVERSED: False, + _osm.KEY_OSMNX_ONEWAY: False, + }, + ), + + (37,38,0,{ + _osm.KEY_OSMNX_OSMID: 46, + _osm.KEY_OSMNX_LENGTH: random.random(), + _osm.KEY_OSMNX_REVERSED: False, + _osm.KEY_OSMNX_ONEWAY: False, + }, + ), ]) # add node data for i, node_key in enumerate(network.nodes()): network.nodes[node_key][_osm.KEY_OSMNX_X] = i+random.random() network.nodes[node_key][_osm.KEY_OSMNX_Y] = i+1+random.random() # define the keepers - protected_nodes = [1, 2, 5, 8, 13, 16, 19, 4, 18, 22, 23, 24, 25, 26] + protected_nodes = [1, 2, 5, 8, 13, 16, 19, 4, 18, 22, 23, 24, 25, 26, 32, 35] # identify the original nodes node_keys = tuple(network.nodes()) # try simplifying it - gis_utils.simplify_network(network, protected_nodes) + gis_utils.simplify_network( + network, + protected_nodes=protected_nodes, + protected_edges=[(33,34,0),(36,37,0)] + ) # protected nodes must still exist for node_key in protected_nodes: assert network.has_node(node_key) @@ -2463,8 +2573,30 @@ class TestGisUtils: # node 21 should not exist assert not network.has_node(21) - # node 27 should exist + # nodes 27, 33, 34 and 35 should exist assert network.has_node(27) + assert network.has_node(33) + assert network.has_node(34) + assert network.has_node(35) + # there should be an edge between 33 and 34 + assert network.has_edge(33, 34) or network.has_edge(34, 33) + # there should be an edge between 34 and 35 + assert network.has_edge(34, 35) or network.has_edge(35, 34) + + # nodes 28, 29, 30, and 31 should not exist + assert not network.has_node(28) + assert not network.has_node(29) + assert not network.has_node(30) + assert not network.has_node(31) + # there should be an edge between 23 and 32 + assert network.has_edge(23, 32) or network.has_edge(32, 23) + + # nodes 36 and 37 should exist, node 38 should not + assert network.has_node(36) + assert network.has_node(37) + assert not network.has_node(38) + # the edge (36,37) should exist + assert network.has_edge(36, 37) or network.has_edge(37, 36) # ************************************************************************* # ************************************************************************* @@ -2486,7 +2618,7 @@ class TestGisUtils: for i in range(number_nodes_protected) ] # try simplifying it - gis_utils.simplify_network(network, protected_nodes) + gis_utils.simplify_network(network, protected_nodes=protected_nodes) # protected nodes must still exist for node_key in protected_nodes: assert network.has_node(node_key) @@ -2507,8 +2639,9 @@ class TestGisUtils: continue # all other nodes cannot be dead ends assert len(tuple(gis_iden.neighbours(network, node_key))) >= 1 - - # TODO: verify that the graph did not change in any meaningful way + + # ************************************************************************* + # ************************************************************************* # *****************************************************************************