For a given graph, construct shortest path tree- Python - python-3.x

Problem scale- I am taking OSM Road network of a city (6000 nodes and 50000 edges.)
Input - The graph is read as a netwrokx Digraph. (weighted)
For a given node r, I want to construct shortest path tree. Is there a standard Networkx function or library which can do so ? If not, How can I do this efficiently ? ( as opposed to running Dijkstra for all r-v pair)
Input in any form is highly valued!

This function returns the shortest path, from any node to every node reachable
Here's an example of its output:
For the following (very simple) graph:
G = nx.path_graph(5)
the single_source_shortest_path function:
path_1 = nx.single_source_shortest_path(G, 1)
returns:
{1: [1], 0: [1, 0], 2: [1, 2], 3: [1, 2, 3], 4: [1, 2, 3, 4]}
Where the shortest path from node 1 to any target T is returned by path_1[T].
There is also a networkX built-in solution to run Dijkstra for every node pair(docs):
shortest_paths = dict(nx.all_pairs_dijkstra_path(G))
shortest_paths[1]
# returns {1: [1], 0: [1, 0], 2: [1, 2], 3: [1, 2, 3], 4: [1, 2, 3, 4]}

Related

subset of a multilist- recursive solution

I need to implement a function to find all subsets of a multiset (I.E an element can appear twice)- but I can not use loops or any modules, only recursion.
My idea was to initialize an empty list and use it to save the results into.
For the first step, we put the original list inside, and then we run the recursive function on the same list after popping the first element. and we run it again on the same function without the second element, and so on.
This was my attempt:
def element_pop(inputlist:list,idx:int)->list: # returns a list without arr[idx]
temp=inputlist.copy()
temp.pop(idx)
return temp
def allsubsets(inputlist:list,resultlist:list)->list:#recurse through the first given list and in the end put all subsets of all sizes inside
idx=len(inputlist)-1
resultlist.append(inputlist)
if(idx>0):
temp=element_pop(inputlist,idx)
idx-=1
return allsubsets(temp,resultlist)
return resultlist
However,these are the results I get:
list= [1, 2, 3]
F(List)= [[1, 2, 3], [1, 2], [1]]
But what I expect to get is:
f(list)= [[1, 2, 3], [1, 2], [1, 3], [2, 3], [1], [2], [3]]
I'm uncertain as to how to iterate through the list in the recursive step, and what promises me I wont get multiple [1]s or [2]s in the final stage?
I also tried breaking the problem down to finding all subsets of size(1,2,3..len(list)) but it hasn't lead me to anything either.
Note: the same element can appear multiple times, for example:
list= [1, 2, 3, 1]
f(list)= [[1], [2], [3], [1], [1, 2], [1, 3], [1, 1], [1, 2, 3], [1, 2, 1], [1, 3, 1], [2, 3, 1], [1, 2, 3, 1]]

Deleting an item from a list which is a value in a given dictionary

myDict={0:[1,2,3,4],1:[0,2],2:[0,1],3:[0,4],4:[0,3]}
Hi, being new to the concept of dictionaries I am unable to figure out how to delete an item from the list of any key value pair. Lets say I am on myDict[0], my concern is how do I delete lets say the values 1 and 2 of 0:[1,2,3,4] list. Thank you!
myDict = {0: [1, 2, 3, 4], 1: [0, 2], 2: [0, 1], 3: [0, 4], 4: [0, 3]}
myDict[0] = [3, 4] # Whatever here
'''
You can treat myDict[0] as a normal list
'''
myDict[0].remove(3) # Same as list.remove(), because myDict[0] is just a list
print(myDict[0])
print(myDict[0][0])# Printing the 0th value in the list, which is myDict[0]
myDict = {0: [1, 2, 3, 4], 1: [0, 2], 2: [0, 1], 3: [0, 4], 4: [0, 3]}
myDict[0].remove(myDict[0][0])
myDict[0].remove(myDict[0][1])
print(myDict)

Creating networkx graph using Delaunay Triangulation

I have a Delaunay Triangulation (DT) (scipy) as follows:
# Take first 50 rows with 3 attributes to create a DT-
d = data.loc[:50, ['aid', 'x', 'y']].values
dt = Delaunay(points = d)
# List of triangles in the DT-
dt.simplices
'''
array([[1, 3, 4, 0],
[1, 2, 3, 0],
[1, 2, 3, 4]], dtype=int32)
'''
Now, I want to create a graph using 'networkx' package and add the nodes and edges found using DT from above.
# Create an empty graph with no nodes and no edges.
G = nx.Graph()
The code I have come up with to add the unique nodes from DT simplices into 'G' is-
# Python3 list to contain nodes
nodes = []
for simplex in data_time_delaunay[1].simplices.tolist():
for nde in simplex:
if nde in nodes:
continue
else:
nodes.append(nde)
nodes
# [1, 3, 4, 0, 2]
# Add nodes to graph-
G.add_nodes_from(nodes)
How do I add edges to 'G' using 'dt.simplices'? For example, the first triangle is [1, 3, 4, 0] and is between the nodes/vertices 1, 3, 4 and 0. How do I figure out which nodes are attached to each other and then add them as edges to 'G'?
Also, is there a better way to add nodes to 'G'?
I am using Python 3.8.
Thanks!
You could add the rows in the array as paths. A path just constitutes a sequence of edges, so the path 1,2,3 translates to the edge list (1,2),(2,3).
So iterate over the rows and use nx.add_path:
simplices = np.array([[1, 3, 4, 0],
[1, 2, 3, 0],
[1, 2, 3, 4]])
G = nx.Graph()
for path in simplices:
nx.add_path(G, path)
nx.draw(G, with_labels=True, node_size=500, node_color='lightgreen')

Flipping bits in nested lists

I have a project wherein I have to use bit-flip mutation of genetic algorithm.
The code I have so far looks like this:
def mutation(pop, mr):
for i in range(len(pop)):
if (random.random() < mr):
if (pop[i] == 1):
pop[i] = 0
else:
pop[i] = 1
else:
pop[i] = pop[i]
return pop
mut = mutation(populations, 0.3)
print(mut)
For example, I have the following (depending on my project, populations can look like populations_1 or populations_2):
populations_1 = [[1, 0], [1, 1], [0, 1], [1, 0]]
populations_2 = [[1], [1], [0], [1]]
What I am doing is assigning random generated numbers to elements in populations and check if it is less than mutation rate. If it is, then bit-flip mutation will happen, if not, it will remain as it is. For the case of populations_1, if populations_1 index 2 is less than mutation rate, then it should become [1, 0]. For populations_2 index 3, it should become [0] if it is less than mutation rate. This is the objective of the mutation function.
Can anyone help me with turning the code I have so far to adapt situations like in populations_1? I think the code I have so far only works for populations_2.
Any help/suggestion/readings would be very much appreciated! Thanks!
You can use list comprehensions to do what you want. The values in pop are updated only if r<mr. To update them, you can iterate over each element (a) in list pop[i], and if a == 0 it becomes 1, otherwise 0. See the code below:
def mutation(pop, mr):
for i in range(len(pop)):
r = random.random()
print(r) # you can remove this line, it is only for testing
if r < mr:
pop[i] = [1 if a == 0 else 0 for a in pop[i]]
return pop
Test 1:
populations_1 = [[1, 0], [1, 1], [0, 1], [1, 0], [0,0]]
mut = mutation(populations_1, 0.3)
print(mut)
#random number for each iteration
0.3952226177233832
0.11290933711515283
0.08131952363738537
0.8489702326753509
0.9598842135077205
#output:
[[1, 0], [0, 0], [1, 0], [1, 0], [0, 0]]
Test 2:
populations_2 = [[1], [1], [0], [1]]
mut = mutation(populations_2, 0.3)
print(mut)
0.3846024893833684
0.7680389523799874
0.19371896835988422
0.008814288533701364
[[1], [1], [1], [0]]

return the total number of neighbors by using pysal's weights object

I construct a weights object:
import pysal as ps
neighbors = {0: [3, 1], 1: [0, 2, 2], 2: [1, 2], 3: [0, 1, 1]}
weights = {0: [1, 1], 1: [1, 1, 1], 2: [1, 1], 3: [1, 1, 1]}
w = ps.W(neighbors, weights)
Weights object in pysal has a neighbors attribute like the following:
w.neighbors
It will returns a dict: {0: [3, 1], 1: [0, 2, 2], 2: [1, 2], 3: [0, 1, 1]}.
I've checked pysal's api and find lots of methods and attribute to return something about the number of neighbors but not the total number of all neighbors.
For the above w, I want it to return something like: {0: 2, 1: 3, 2: 2, 3: 3}. Instead of looping over the dict like:
n_nbrs = dict()
for key, value in w.neighbors.items():
n_nbrs[key] = len(value)
Is there any easy way to achieve this?
You can use w.cardinalities. It will return exactly what are you looking for - {0: 2, 1: 3, 2: 2, 3: 3}.
PySAL is currently changing its structure, so the weights module is now part of libpysal package and its documentation is explaining it, unlike the one you are referring to.

Resources