From 480800c9a468acad7e52eb9d92cbb9facdfd5cf2 Mon Sep 17 00:00:00 2001 From: Lionel GUEZ <guez@lmd.ens.fr> Date: Thu, 14 Sep 2023 20:56:27 +0200 Subject: [PATCH] Rewrite using new algorithm The old algorithm did not give correct results on tests `Greece_trajectories`, `Test_order_edges` and `Traj_component`. We abandon the idea of processing edges in date order. Instead, we now process vertices in topological order. --- Trajectories/trajectories.py | 173 ++++++++++++----------------------- 1 file changed, 61 insertions(+), 112 deletions(-) diff --git a/Trajectories/trajectories.py b/Trajectories/trajectories.py index 7742cf5c..b734f6c7 100755 --- a/Trajectories/trajectories.py +++ b/Trajectories/trajectories.py @@ -13,81 +13,48 @@ instantaneous eddies in each trajectory are in ascending order. """ import graph_tool +from graph_tool import topology import json import sys -import numpy as np -import report_graph - -def assign_traj_edge(source, target, traj_prop, ind_traj, g, traj_segm, - expanded_traj): - """Assign trajectories to the source and target of a given edge. This - means updating ind_traj, traj_prop, traj_segm and expanded_traj. - - """ - - if traj_prop[source] == - 1 and traj_prop[target] == - 1: - ind_traj += 1 - traj_prop[source] = ind_traj - traj_prop[target] = ind_traj - segments = [int(g.vertex_properties.name[source]), - int(g.vertex_properties.name[target])] - traj_segm.append(segments) - inst_eddies = list(g.vertex_properties.inst_eddies[source]) \ - + list(g.vertex_properties.inst_eddies[target]) - expanded_traj.append(inst_eddies) - elif traj_prop[source] == - 1: - # assert traj_prop[target] != - 1 - # target is already in a trajectory. Can we extend the - # trajectory of target backward? - in_neighbors = g.get_in_neighbors(target, [traj_prop]) - - if np.any(in_neighbors[:, 1] == traj_prop[target]): - # target already has a direct predecessor in its - # trajectory so we create a new trajectory for source. - ind_traj += 1 - traj_prop[source] = ind_traj - segments = [int(g.vertex_properties.name[source])] - traj_segm.append(segments) - inst_eddies = list(g.vertex_properties.inst_eddies[source]) - expanded_traj.append(inst_eddies) - else: - traj_prop[source] = traj_prop[target] - segment = int(g.vertex_properties.name[source]) - traj_segm[traj_prop[source]].insert(0, segment) - inst_eddies = list(g.vertex_properties.inst_eddies[source]) - expanded_traj[traj_prop[source]] = inst_eddies \ - + expanded_traj[traj_prop[source]] - elif traj_prop[target] == - 1: - # assert traj_prop[source] != - 1 - # source is already in a trajectory. Can we extend the - # trajectory of source forward? - out_neighbors = g.get_out_neighbors(source, [traj_prop]) - - if np.any(out_neighbors[:, 1] == traj_prop[source]): - # source already has a direct successor in its trajectory - # so we create a new trajectory for target. - ind_traj += 1 - traj_prop[target] = ind_traj - segments = [int(g.vertex_properties.name[target])] - traj_segm.append(segments) - inst_eddies = list(g.vertex_properties.inst_eddies[target]) - expanded_traj.append(inst_eddies) - else: - traj_prop[target] = traj_prop[source] - segment = int(g.vertex_properties.name[target]) - traj_segm[traj_prop[target]].append(segment) - inst_eddies = list(g.vertex_properties.inst_eddies[target]) - expanded_traj[traj_prop[target]].extend(inst_eddies) +def new_traj(ind_traj, traj_prop, n, g, traj_segm, expanded_traj): + """Assign new trajectory to node index or vertex descriptor n.""" + + ind_traj += 1 + traj_prop[n] = ind_traj + segments = [int(g.vertex_properties.name[n])] + traj_segm.append(segments) + inst_eddies = list(g.vertex_properties.inst_eddies[n]) + expanded_traj.append(inst_eddies) return ind_traj if len(sys.argv) != 2: sys.exit("Required argument: input-graph") g = graph_tool.load_graph(sys.argv[1]) -traj_prop = g.new_vertex_property('int', val = - 1) -# Trajectory index to which a segment belongs. - 1 means the segment -# does not belong yet to any trajectory. The trajectory index is also -# the index in lists traj_segm and expanded_traj. +if "cost_function" in g.edge_properties: + closest_succ = g.new_vertex_property('int') + # Index of the closest direct successor of a node: tail of the + # out-edge with smallest cost. - 1 means there is no successor. + + # Set closest_succ for all nodes: + for n in g.iter_vertices(): + all_cost = g.get_out_edges(n, + eprops = [g.edge_properties.cost_function]) + # numpy array with dtype float64 + + if all_cost.size == 0: + # n has no successor + closest_succ[n] = - 1 + else: + i_min = all_cost[:, 2].argmin() + closest_succ[n] = all_cost[i_min, 1] +else: + # This happens if there are only isolated segments. + print("No cost values in the input file.") + +traj_prop = g.new_vertex_property('int') +# Trajectory index to which a segment belongs. The trajectory index is +# also the index in lists traj_segm and expanded_traj. ind_traj = - 1 # initialize index of trajectory traj_segm = [] # an element of traj_segm is a trajectory, represented @@ -95,53 +62,35 @@ traj_segm = [] # an element of traj_segm is a trajectory, represented expanded_traj = [] # an element of expanded_traj is a trajectory, # represented by a list of instantaneous eddies -if "cost_function" in g.edge_properties: - # Build my_subgraphs, a dictionary of nodes at each date: - - my_subgraphs = {} - - for v in g.vertices(): - date_index = report_graph.node_to_date_eddy(int(g.vp.name[v]), - g.gp.e_overestim, - only_date = True) - - if date_index in my_subgraphs: - my_subgraphs[date_index].append(int(v)) +for n in topology.topological_sort(g): + if g.vertex(n).in_degree() >= 1: + # Find the index of the closest direct predecessor of a node: + # head of the in-edge with smallest cost. + + all_cost = g.get_in_edges(n, eprops = [g.edge_properties.cost_function]) + # numpy array with dtype float64 + + i_min = all_cost[:, 2].argmin() + closest_pred = all_cost[i_min, 0] + + if closest_succ[closest_pred] == n: + # Assign to n the trajectory of closest_pred. This means + # updating ind_traj, traj_prop, traj_segm and + # expanded_traj. closest_pred is already in a trajectory, + # traj_prop[closest_pred]] is defined. We extend the + # trajectory of closest_pred forward. + traj_prop[n] = traj_prop[closest_pred] + segment = int(g.vertex_properties.name[n]) + traj_segm[traj_prop[n]].append(segment) + inst_eddies = list(g.vertex_properties.inst_eddies[n]) + expanded_traj[traj_prop[n]].extend(inst_eddies) else: - my_subgraphs[date_index] = [int(v)] - - for date_index in sorted(my_subgraphs): - # Consider all outgoing edges at a given date: - - edges = [] - all_cost = [] - - for n in my_subgraphs[date_index]: - for source, target, cost \ - in g.iter_out_edges(n, [g.edge_properties.cost_function]): - edges.append([n, target]) - all_cost.append(cost) - - # Array of indices that sort on cost: - ind_cost = np.argsort(all_cost) - - # Loop over edges in ascending order of cost: - for i in ind_cost: - ind_traj = assign_traj_edge(*edges[i], traj_prop, ind_traj, g, - traj_segm, expanded_traj) -else: - # This happens if there are only isolated segments. - print("No cost values in the input file.") + ind_traj = new_traj(ind_traj, traj_prop, n, g, traj_segm, + expanded_traj) + else: + ind_traj = new_traj(ind_traj, traj_prop, n, g, traj_segm, expanded_traj) -# Create trajectories for isolated segments: -for v in g.vertices(): - if traj_prop[v] == - 1: - ind_traj += 1 - traj_prop[v] = ind_traj - segments = [int(g.vertex_properties.name[v])] - traj_segm.append(segments) - inst_eddies = list(g.vertex_properties.inst_eddies[v]) - expanded_traj.append(inst_eddies) + # traj_prop[n] is defined print("Number of trajectories: ", len(traj_segm)) -- GitLab