简体   繁体   中英

how to add float typed weights to an retworkx digraph

In my pursuit after a fast graph library for python, I stumbled upon retworkx , and I'm trying to achieve the same (desired) result I've achieved using networkx .

In my networkx code, I instantiate a digraph object with an array of weighted edges, activate it's built-in shortest_path (dijkstra-based), and receive that path. I do so by using the following code:

graph = nx.DiGraph()
in_out_weight_triplets = np.concatenate((in_node_indices, out_node_indices,
                                         np.abs(weights_matrix)), axis=1)
graph.add_weighted_edges_from(in_out_weight_triplets)
shortest_path = nx.algorithms.shortest_path(graph, source=n_nodes, target=n_nodes + 1,
                                            weight='weight')

when trying to reproduce the same shortest path using retworkx:

graph = rx.PyDiGraph(multigraph=False)
in_out_weight_triplets = np.concatenate((in_node_indices.astype(int), 
                                         out_node_indices.astype(int),
                                         np.abs(weights_matrix)), axis=1)
unique_nodes = np.unique([in_node_indices.astype(int), out_node_indices.astype(int)])
graph.add_nodes_from(unique_nodes)
graph.extend_from_weighted_edge_list(list(map(tuple, in_out_weight_triplets)))
shortest_path = rx.digraph_dijkstra_shortest_paths(graph, source=n_nodes,
                                                   target=n_nodes + 1)

but for using a triplet with float weights I get the error:

 "C:\Users\tomer.d\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py", line 3437, in run_code exec(code_obj, self.user_global_ns, self.user_ns) File "<ipython-input-23-752a42ce79d7>", line 1, in <module> graph.extend_from_weighted_edge_list(list(map(tuple, in_out_weight_triplets))) TypeError: argument 'edge_list': 'numpy.float64' object cannot be interpreted as an integer ```

and when i try the workaround of multiplying the weights by factor of 10^4 and casting them to ints:

np.concatenate((in_node_indices.astype(int), out_node_indices.astype(int),
               (np.abs(weights_matrix) * 10000).astype(int), axis=1)

so that I supposedly won't lose the weight subtleties - no errors are being raised, but the output of the shortest path is different than the one I get when using networkx.

I'm aware of the fact that the weights aren't necessarily the issue here, but they are currently my main suspect.

any other advice would be thankfully accepted.

Without knowing what in_node_indices , out_node_indices and weights_matrix contain in the code snippets it's hard to provide an exact working example for your use case. But, I can take a guess based on the error message. I think the issue you're hitting here is likely because you're trying to use the values in in_node_indices and out_node_indices as retworkx indices but there isn't a 1:1 mapping necessarily. The retworkx index for a node is assigned when the node is added and is the returned value. So if you do something like graph.add_node(3) , the return from that will not necessarily be 3 it will be the node index assigned to that instance of 3 when it's added as a node in the graph. If you ran graph.add_nodes_from([3, 3]) you'd get two different indices returned. This is different from networkx which treats the data payloads as a lookup key in the graph (so graph.add_node(3) adds a node 3 to the graph which you look up by 3 , but then you can only have a single node with the payload 3 ). You can refer to the documentation on retworkx for networkx users for more details here: https://qiskit.org/documentation/retworkx/networkx.html

So when you call add_nodes_from() you need to map the value at a position in the input array to the returned index from the method at the same position to identify that node in the graph. I think if you do something like:

import retworkx as rx
graph = rx.PyDiGraph(multigraph=False)
unique_indices = np.unique([in_node_indices, out_node_indices])
rx_indices = graph.add_nodes_from(unique_indices)
index_map = dict(zip(unique_indices, rx_indices))
in_out_weight_triplets = np.concatenate((in_node_indices, out_node_indices,
                                         np.abs(weights_matrix)), axis=1)
graph.add_nodes_from([(index_map[in], index_map[out], weight) for in, out, weight in in_out_weight_triplets])

I haven't tested the above snippet (so there might be typos or other issues with it) because I don't know what the contents of in_node_indices , out_node_indices , and weight_matrix are. But it should give you an a better idea of what I described above.

That being said I do wonder if weight_matrix is an adjacency matrix , if it is then it's probably easier to just do:

import retworkx

graph = retworkx.PyDiGraph.from_adjacency_matrix(weight_matrix)

this is also typically faster (assuming you already have the matrix) because it uses the numpy C api and avoids the type conversion going between python and rust and all the pre-processing steps.

There was also an issue opened similar to this in the retworkx issue tracker recently: https://github.com/Qiskit/retworkx/issues/546 . My response there contains more details on the internals of retworkx.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM