K-shortest path algorithm for python 3 - python-3.x

I have tried an available K-shortest path algorithm. But it gives an error and i cannot figure out what it is. I want to find two shortest paths between two network nodes.
It gives an error saying that int type is not iterable and i do not know how to solve it.
import sys
#sys.modules[__name__].__dict__.clear()
import simpy
import random
import math
#import run_parameters
from heapq import heappush, heappop
from itertools import count
import networkx as nx
import matplotlib.pyplot as plt
"""
A NetworkX based implementation of Yen's algorithm for computing K-shortest paths.
Yen's algorithm computes single-source K-shortest loopless paths for a
graph with non-negative edge cost. For more details, see:
http://networkx.github.io
http://en.m.wikipedia.org/wiki/Yen%27s_algorithm
"""
__author__ = 'Guilherme Maia <guilhermemm#gmail.com>'
__all__ = ['k_shortest_paths']
from heapq import heappush, heappop
from itertools import count
import networkx as nx
def k_shortest_paths(G, source, target, k=2, weight='weight'):
"""Returns the k-shortest paths from source to target in a weighted graph G.
Parameters
----------
G : NetworkX graph
source : node
Starting node
target : node
Ending node
`
k : integer, optional (default=1)
The number of shortest paths to find
weight: string, optional (default='weight')
Edge data key corresponding to the edge weight
Returns
-------
lengths, paths : lists
Returns a tuple with two lists.
The first list stores the length of each k-shortest path.
The second list stores each k-shortest path.
Raises
------
NetworkXNoPath
If no path exists between source and target.
Examples
--------
>>> G=nx.complete_graph(5)
>>> print(k_shortest_paths(G, 0, 4, 4))
([1, 2, 2, 2], [[0, 4], [0, 1, 4], [0, 2, 4], [0, 3, 4]])
Notes
------
Edge weight attributes must be numerical and non-negative.
Distances are calculated as sums of weighted edges traversed.
"""
if source == target:
return ([0], [[source]])
length, path = nx.single_source_dijkstra(G, source, target, weight=weight)
if target not in length:
raise nx.NetworkXNoPath("node %s not reachable from %s" % (source, target))
lengths = [length[target]]
paths = [path[target]]
c = count()
B = []
G_original = G.copy()
for i in range(1, k):
for j in range(len(paths[-1]) - 1):
spur_node = paths[-1][j]
root_path = paths[-1][:j + 1]
edges_removed = []
for c_path in paths:
if len(c_path) > j and root_path == c_path[:j + 1]:
u = c_path[j]
v = c_path[j + 1]
if G.has_edge(u, v):
edge_attr = G.edge[u][v]
G.remove_edge(u, v)
edges_removed.append((u, v, edge_attr))
for n in range(len(root_path) - 1):
node = root_path[n]
# out-edges
for u, v, edge_attr in G.edges_iter(node, data=True):
G.remove_edge(u, v)
edges_removed.append((u, v, edge_attr))
if G.is_directed():
# in-edges
for u, v, edge_attr in G.in_edges_iter(node, data=True):
G.remove_edge(u, v)
edges_removed.append((u, v, edge_attr))
spur_path_length, spur_path = nx.single_source_dijkstra(G, spur_node, target, weight=weight)
if target in spur_path and spur_path[target]:
total_path = root_path[:-1] + spur_path[target]
total_path_length = get_path_length(G_original, root_path, weight) + spur_path_length[target]
heappush(B, (total_path_length, next(c), total_path))
for e in edges_removed:
u, v, edge_attr = e
G.add_edge(u, v, edge_attr)
if B:
(l, _, p) = heappop(B)
lengths.append(l)
paths.append(p)
else:
break
return (lengths, paths)
def get_path_length(G, path, weight='weight'):
length = 0
if len(path) > 1:
for i in range(len(path) - 1):
u = path[i]
v = path[i + 1]
length += G.edge[u][v].get(weight, 1)
return length
G=nx.complete_graph(5)
print(k_shortest_paths(G, 0, 4, 4))
Why it gives this error? In some cases it works for k=1, but when i increase k to 2, the error comes.

Related

How to appending 1 value to array A to match the dimensions of array B?

The program I have here is simulating the velocity of a falling object.
The velocity is calculated by subtracting the y position from time_1 and time_2.
The problem that I have is that the dimensions of array v and array t don't match. Instead of shortening array t I would like to add 0 at the beginning of the v array. So that the graph will show v = 0 at t= 0. Yes, I know it is a small interval and that it does not really matter. But I want to know it for educational purpose.
I'm wondering if i can write the line v = (y[1:] - y[:-1])/0.1 in a from where i keep the dimension.
The ideal thing that would happen is that the array y will be substracted with an array y[:-1] and that this subtraction will happen at the end of the y array so the result will be an array of dimension 101 with a 0 as start value.
I would like to know your thoughts about this.
import matplotlib.pyplot as plt
t = linspace(0,10,101)
g = 9.80665
y = 0.5*g*t*t
v = (y[1:] - y[:-1])/0.1
plt.plot(t,v)
plt.show()
is there a function where i can add a certain value to the beginning of an array? np.append will add it to the end.
Maybe you could just pre-define the length of the result at the beginning and then fill up the values:
import numpy as np
dt = .1
g = 9.80665
t_end = 10
t = np.arange(0,t_end+dt,dt)
y = 0.5*g*t*t
v = np.zeros(t.shape[0])
v[1:] = (y[1:] - y[:-1])/dt
if you simply looking for the append at index function it would be this one:
np.insert([1,2,3,4,5,6], 2, 100)
>> array([ 1, 2, 100, 3, 4, 5, 6])
another possible solution to this would be to use np.append but inverse your order :
import numpy as np
v = np.random.rand(10)
value = 42 # value to append at the beginning of v
value_arr = np.array([value]) # dimensions should be adjust for multidimensional array
v = np.append(arr = value_arr, values = v, axis=0)
and the possible variants following the same idea, using np.concatenate or np.hstack ...
regarding your second question in comments, one solution may be :
t = np.arange(6)
condlist = [t <= 2, t >= 4]
choicelist = [1, 1]
t = np.select(condlist, choicelist, default=t)

Using theano.scan within PyMC3 gives TypeError: slice indices must be integers or None or have an __index__ method

I would like to to use theano.scan within pymc3. I run into problems when I add more than two variables as sequences. Here is a simple example:
import numpy as np
import pymc3 as pm
import theano
import theano.tensor as T
a = np.ones(5)
b = np.ones(5)
basic_model = pm.Model()
with basic_model:
a_plus_b, _ = theano.scan(fn=lambda a, b: a + b, sequences=[a, b])
results in the following error:
Traceback (most recent call last):
File "StackOverflowExample.py", line 23, in <module>
sequences=[a, b])
File "\Anaconda3\lib\site-packages\theano\scan_module\scan.py", line 586, in scan
scan_seqs = [seq[:actual_n_steps] for seq in scan_seqs]
File "\Anaconda3\lib\site-packages\theano\scan_module\scan.py", line 586, in <listcomp>
scan_seqs = [seq[:actual_n_steps] for seq in scan_seqs]
TypeError: slice indices must be integers or None or have an __index__ method
However, when I run the same theano.scan outside a pymc model block, everything works fine:
a = T.vector('a')
b = T.vector('b')
a_plus_b, update = theano.scan(fn=lambda a, b: a + b, sequences=[a, b])
a_plus_b_function = theano.function(inputs=[a, b], outputs=a_plus_b, updates=update)
a = np.ones(5)
b = np.ones(5)
print(a_plus_b_function(a, b))
prints [2. 2. 2. 2. 2.], like it should.
In addition, the problem seems to be specific to adding more than one sequences. Everything works just fine when there is one variable in sequences and one in non-sequences. The following code works:
a = np.ones(5)
c = 2
basic_model = pm.Model()
with basic_model:
a_plus_c, _ = theano.scan(fn=lambda a, c: a + c, sequences=[a], non_sequences=[c])
a_plus_c_print = T.printing.Print('a_plus_c')(a_plus_c)
prints a_plus_c __str__ = [ 3. 3. 3. 3. 3.], as expected.
Note: I can't just use a + b instead of theano.scan because my actual function is more complex. I actually want to have something like this:
rewards = np.array([1, 1, 1, 1]) # reward (1) or no reward (0)
choices = np.array([1, 0, 1, 0]) # action left (1) or right (0)
Q_old = 0 # initial Q-value
alpha = 0.1 # learning rate
def update_Q(reward, choice, Q_old, alpha):
return Q_old + choice * alpha * (reward - Q_old)
Q_left, _ = theano.scan(fn=update_Q,
sequences=[rewards, choices],
outputs_info=[Q_old],
non_sequences=[alpha])
Turns out it was a simple mistake! Everything is working as soon as I define a and b as tensor variables. Adding those two lines did the job:
a = T.as_tensor_variable(np.ones(5))
b = T.as_tensor_variable(np.ones(5))

Python Matrix Multiplication - Append into empty list

How do I generate random matrices and get them multiplied in an efficient way.
This is what I've done:
`mat1 = []
for i in range(0, order):
num1 = random.sample(range(1,10), order)
print(num1)
mat1.append(num1)
print()
print("Result of Matrix Multiplication.")
for p in range(len(mat1)):
for q in range(len(mat2[0])):
for r in range(len(mat2)):
res_matrix[p][q] += mat1[p][r] * mat2[r][q]
for res in res_matrix:
print(res)`
You can use list comprehension to generate res_matrix using
res_matrix = [[0 for i in range(order)] for j in range(order)]
Also, have you heard of numpy? It does this kind of computations (and many more) in an easy and very fast way. This is what your code would become with numpy
import numpy as np
print("Generate 1st Matrix")
mat1 = np.random.randint(1, 10, size=(order, order))
print(mat1)
print("Generate 2nd Matrix")
mat2 = np.random.randint(1, 10, size=(order, order))
print(mat2)
res_matrix = mat1.dot(mat2)
print("Result of Matrix Multiplication.")
print(res_matrix)

How can I compare two lists of numpy vectors?

I have two lists of numpy vectors and wish to determine whether they represent approximately the same points (but possibly in a different order).
I've found methods such as numpy.testing.assert_allclose but it doesn't allow for possibly different orders. I have also found unittest.TestCase.assertCountEqual but that doesn't work with numpy arrays!
What is my best approach?
import unittest
import numpy as np
first = [np.array([20, 40]), np.array([20, 60])]
second = [np.array([19.8, 59.7]), np.array([20.1, 40.5])]
np.testing.assert_all_close(first, second, atol=2) # Fails because the orders are different
unittest.TestCase.assertCountEqual(None, first, second) # Fails because numpy comparisons evaluate element-wise; and because it doesn't allow a tolerance
A nice list iteration approach
In [1047]: res = []
In [1048]: for i in first:
...: for j in second:
...: diff = np.abs(i-j)
...: if np.all(diff<2):
...: res.append((i,j))
In [1049]: res
Out[1049]:
[(array([20, 40]), array([ 20.1, 40.5])),
(array([20, 60]), array([ 19.8, 59.7]))]
Length of res is the number of matches.
Or as list comprehension:
def match(i,j):
diff = np.abs(i-j)
return np.all(diff<2)
In [1051]: [(i,j) for i in first for j in second if match(i,j)]
Out[1051]:
[(array([20, 40]), array([ 20.1, 40.5])),
(array([20, 60]), array([ 19.8, 59.7]))]
or with the existing array test:
[(i,j) for i in first for j in second if np.allclose(i,j, atol=2)]
Here you are :)
( idea based on
Euclidean distance between points in two different Numpy arrays, not within )
import numpy as np
import scipy.spatial
first = [np.array([20 , 60 ]), np.array([ 20, 40])]
second = [np.array([19.8, 59.7]), np.array([20.1, 40.5])]
def pointsProximityCheck(firstListOfPoints, secondListOfPoints, distanceTolerance):
pointIndex = 0
maxDistance = 0
lstIndices = []
for item in scipy.spatial.distance.cdist( firstListOfPoints, secondListOfPoints ):
currMinDist = min(item)
if currMinDist > maxDistance:
maxDistance = currMinDist
if currMinDist < distanceTolerance :
pass
else:
lstIndices.append(pointIndex)
# print("point with pointIndex [", pointIndex, "] in the first list outside of Tolerance")
pointIndex+=1
return (maxDistance, lstIndices)
maxDistance, lstIndicesOfPointsOutOfTolerance = pointsProximityCheck(first, second, distanceTolerance=0.5)
print("maxDistance:", maxDistance, "indicesOfOutOfTolerancePoints", lstIndicesOfPointsOutOfTolerance )
gives on output with distanceTolerance=0.5 :
maxDistance: 0.509901951359 indicesOfOutOfTolerancePoints [1]
but possibly in a different order
This is the key requirement. This problem can be treat as a classic problem in graph theory - finding perfect matching in unweighted bipartite graph. Hungarian Algorithm is a classic algo to solve this problem.
Here I implemented one.
import numpy as np
def is_matched(first, second):
checked = np.empty((len(first),), dtype=bool)
first_matching = [-1] * len(first)
second_matching = [-1] * len(second)
def find(i):
for j, point in enumerate(second):
if np.allclose(first[i], point, atol=2):
if not checked[j]:
checked[j] = True
if second_matching[j] == -1 or find(second_matching[j]):
second_matching[j] = i
first_matching[i] = j
return True
def get_max_matching():
count = 0
for i in range(len(first)):
if first_matching[i] == -1:
checked.fill(False)
if find(i):
count += 1
return count
return len(first) == len(second) and get_max_matching() == len(first)
first = [np.array([20, 40]), np.array([20, 60])]
second = [np.array([19.8, 59.7]), np.array([20.1, 40.5])]
print(is_matched(first, second))
# True
first = [np.array([20, 40]), np.array([20, 60])]
second = [np.array([19.8, 59.7]), np.array([20.1, 43.5])]
print(is_matched(first, second))
# False

Python: Venn diagram: how to show the diagram contents?

I have the working code below.
from matplotlib import pyplot as plt
import numpy as np
from matplotlib_venn import venn3, venn3_circles
Gastric_tumor_promoters = set(['DPEP1', 'CDC42BPA', 'GNG4', 'RAPGEFL1', 'MYH7B', 'SLC13A3', 'PHACTR3', 'SMPX', 'NELL2', 'PNMAL1', 'KRT23', 'PCP4', 'LOX', 'CDC42BPA'])
Ovarian_tumor_promoters = set(['ABLIM1','CDC42BPA','VSNL1','LOX','PCP4','SLC13A3'])
Gastric_tumor_suppressors = set(['PLCB4', 'VSNL1', 'TOX3', 'VAV3'])
#Ovarian_tumor_suppressors = set(['VAV3', 'FREM2', 'MYH7B', 'RAPGEFL1', 'SMPX', 'TOX3'])
venn3([Gastric_tumor_promoters,Ovarian_tumor_promoters, Gastric_tumor_suppressors], ('GCPromoters', 'OCPromoters', 'GCSuppressors'))
venn3([Gastric_tumor_promoters,Ovarian_tumor_promoters, Gastric_tumor_suppressors], ('GCPromoters', 'OCPromoters', 'GCSuppressors'))
plt.show()
How can I show the contents of each of the set in these 3 circles? With the color alpha being 0.6. Circles must be bigger to accommodate all the symbols.
I'm not sure there is a simple way to do this automatically for any possible combination of sets. If you're ready to do some manual tuning in your particular example, start with something like that:
A = set(['DPEP1', 'CDC42BPA', 'GNG4', 'RAPGEFL1', 'MYH7B', 'SLC13A3', 'PHACTR3', 'SMPX', 'NELL2', 'PNMAL1', 'KRT23', 'PCP4', 'LOX', 'CDC42BPA'])
B = set(['ABLIM1','CDC42BPA','VSNL1','LOX','PCP4','SLC13A3'])
C = set(['PLCB4', 'VSNL1', 'TOX3', 'VAV3'])
v = venn3([A,B,C], ('GCPromoters', 'OCPromoters', 'GCSuppressors'))
v.get_label_by_id('100').set_text('\n'.join(A-B-C))
v.get_label_by_id('110').set_text('\n'.join(A&B-C))
v.get_label_by_id('011').set_text('\n'.join(B&C-A))
v.get_label_by_id('001').set_text('\n'.join(C-A-B))
v.get_label_by_id('010').set_text('')
plt.annotate(',\n'.join(B-A-C), xy=v.get_label_by_id('010').get_position() +
np.array([0, 0.2]), xytext=(-20,40), ha='center',
textcoords='offset points',
bbox=dict(boxstyle='round,pad=0.5', fc='gray', alpha=0.1),
arrowprops=dict(arrowstyle='->',
connectionstyle='arc',color='gray'))
Note that methods like v.get_label_by_id('001') return the matplotlib Text objects, and you are free to configure them to your liking (e.g. you can change font size by calling set_fontsize(8), etc).
Here is an example which automates the whole thing. It creates a temporary dictionary which contains the id's needed by venn as keys and the intersections of all participating sets for this very id.
If you don't want the labels sorted remove the sorted() call in the second last line.
import math
from matplotlib import pyplot as plt
from matplotlib_venn import venn2, venn3
import numpy as np
# Convert number to indices into binary
# e.g. 5 -> '101' > [2, 0]
def bits2indices(b):
l = []
if b == 0:
return l
for i in reversed(range(0, int(math.log(b, 2)) + 1)):
if b & (1 << i):
l.append(i)
return l
# Make dictionary containing venn id's and set intersections
# e.g. d = {'100': {'c', 'b', 'a'}, '010': {'c', 'd', 'e'}, ... }
def set2dict(s):
d = {}
for i in range(1, 2**len(s)):
# Make venn id strings
key = bin(i)[2:].zfill(len(s))
key = key[::-1]
ind = bits2indices(i)
# Get the participating sets for this id
participating_sets = [s[x] for x in ind]
# Get the intersections of those sets
inter = set.intersection(*participating_sets)
d[key] = inter
return d
# Define some sets
a = set(['a', 'b', 'c'])
b = set(['c', 'd', 'e'])
c = set(['e', 'f', 'a'])
s = [a, b, c]
# Create dictionary from sets
d = set2dict(s)
# Plot it
h = venn3(s, ('A', 'B', 'C'))
for k, v in d.items():
l = h.get_label_by_id(k)
if l:
l.set_text('\n'.join(sorted(v)))
plt.show()
/edit
I'm sorry I just figured out that the above code does not remove duplicate labels and is therefor wrong. The number of elements shown by venn and the number of labels was different. Here is a new version which removes wrong duplicates from other intersections. I guess there is a smarter and more functional way to do that instead of iterating over all intersections twice...
import math, itertools
from matplotlib import pyplot as plt
from matplotlib_venn import venn2, venn3
import numpy as np
# Generate list index for itertools combinations
def gen_index(n):
x = -1
while True:
while True:
x = x + 1
if bin(x).count('1') == n:
break
yield x
# Generate all combinations of intersections
def make_intersections(sets):
l = [None] * 2**len(sets)
for i in range(1, len(sets) + 1):
ind = gen_index(i)
for subset in itertools.combinations(sets, i):
inter = set.intersection(*subset)
l[next(ind)] = inter
return l
# Get weird reversed binary string id for venn
def number2venn_id(x, n_fill):
id = bin(x)[2:].zfill(n_fill)
id = id[::-1]
return id
# Iterate over all combinations and remove duplicates from intersections with
# more sets
def sets2dict(sets):
l = make_intersections(sets)
d = {}
for i in range(1, len(l)):
d[number2venn_id(i, len(sets))] = l[i]
for j in range(1, len(l)):
if bin(j).count('1') < bin(i).count('1'):
l[j] = l[j] - l[i]
d[number2venn_id(j, len(sets))] = l[j] - l[i]
return d
# Define some sets
a = set(['a', 'b', 'c', 'f'])
b = set(['c', 'd', 'e'])
c = set(['e', 'f', 'a'])
sets = [a, b, c]
d = sets2dict(sets)
# Plot it
h = venn3(sets, ('A', 'B', 'C'))
for k, v in d.items():
l = h.get_label_by_id(k)
if l:
l.set_fontsize(12)
l.set_text('\n'.join(sorted(v)))
# Original for comparison
f = plt.figure(2)
venn3(sets, ('A', 'B', 'C'))
plt.show()
Thanks for the automation, #Vinci! I wonder if you (or somebody else) has written a version that rearranges the content so that the elements stay within the bubble(s) in a random fashion instead of a long list? ... bonus track: re-dimensioning the bubbles if the elements do not fit? ;)

Resources