I have the following code that is generating a random number of tuples in order to create a connected undirect weighted graph.
for i in xrange(0,10):
for j in xrange(0, (int)(10*random.random())):
b = (int)(10*random.random())
j = [(i,b)]
print(j)
When I run this code I am able to randomly generate random vertices (x,y), however I am running into an issue in that my b variable has the possibility of repeating twice. For example I may get (6,3) followed by (6,3) which when I add weights would ruin the graphs I'm trying to create. Also I am sometimes running into issues where I might get (2,4) and then later get (4,2) which again ruins the graphs that I'm trying to create.
Does anyone know how I can keep vertices from repeating?
Use random.sample
>>> lst1 = random.sample(range(20), 10)
>>> lst2 = random.sample(range(20), 10)
>>> zip(lst1, lst2)
[(19, 5), (5, 11), (9, 19), (0, 9), (4, 6), (12, 0), (7, 12), (16, 1), (10, 7), (15, 16)]
You can change the list generated by range(20) to suit your set of vertices.
Don't generate a new vertex inside the for loop, since it may generate the same one again. (don't pick randomly off of the random.sample lists) Just generate them once and zip them together.
Since you want to remove duplicates of type (x, y) and (y, x). You can do something like the following. (or the simple in method works too)
>>> r = [(19, 5), (5, 11), (5, 19)]
>>> from itertools import groupby
>>> m = map(set, r)
>>> m
[set([19, 5]), set([11, 5]), set([19, 5])]
>>> sorted(m, key=lambda x: sum(x))
[set([11, 5]), set([19, 5]), set([19, 5])]
>>> [tuple(k) for k, v in groupby(sorted(m, key = lambda x: sum(x)))]
[(11, 5), (19, 5)]
Related
I have some Python code that I would like to run in Matlab. Suppose you have two lists of the same length:
x = [0, 2, 2, 5, 8, 10]
y = [0,2, 4, 7, 3, 3]
P = np.copy(y)
P.sort()
P = np.unique(P, axis=0) # P = [0 2 3 4 7] Takes the list y, sorts it and removes repeated elements
s = list(zip(x,y)) #match list x with y: s = [(0, 0), (2, 2), (2, 4), (5, 7), (8, 3), (10, 3)]
for y_1,y_2 in zip(P,P[1:]): # runs over (0, 2), (2, 3), (3, 4), (4, 7)
for v_1,v_2 in zip(s, s[1:]):
-- process --
Where in this case:
list(zip(s, s[1:])) = [((0, 0), (2, 2)), ((2, 2), (2, 4)), ((2, 4), (5, 7)), ((5, 7), (8, 3)), ((8, 3), (10, 3))]
I would like to translate this in Matlab but I don't know how to replicate the zip function. Any ideas on how I can do this?
MATLAB doesn’t have a zip, but you can accomplish the same thing in various ways. I think that the simplest translation of
for y_1,y_2 in zip(P,P[1:]):
...
is
for ii = 1:numel(P)-1
y_1 = P(ii);
y_2 = P(ii+1);
...
And in general, iterating over zip(x,y) is accomplished by iterating over indices 1:numel(x), then using the loop index to index into the arrays x and y.
Here's an implementation of Python's zip function in Matlab.
function out = zip(varargin)
% Emulate Python's zip() function.
%
% Don't actually use this! It will be slow. Matlab code works differently.
args = varargin;
nArgs = numel(args);
n = numel(args{1});
out = cell(1, n);
for i = 1:n
blah = cell(1, nArgs);
for j = 1:nArgs
if iscell(args{j})
blah(j) = args{j}(i);
else
blah{j} = args{j}(i);
end
end
out{i} = blah;
end
end
But don't use it; the performance will be lousy. In Matlab, you want to keep things in parallel primitive arrays instead, and use vectorized operations on those. Or, if you have to, iterate over array indexes.
The problem is to create a function to check if a linear combination of certain items of that list add up to a certain sum. The result would be a list with tuples(which are the same length of the list).
For example: given list: [3,7,10], sum= 60
result: [(0, 0, 6), (1, 1, 5), (2, 2, 4), (3, 3, 3), (4, 4, 2), (5, 5, 1), (6, 6, 0), (10, 0, 3), (11, 1, 2), (12, 2, 1), (13, 3, 0), (20, 0, 0)]
The problem is that the length of the list variates. I tried solving it with a bunch of if-statements and than using for loops, but there must be a more effective way to do it.
Here is some of the code I used.
def get_index(l, s):
res = []
if len(l)==3:
for i in range(s+1):
for j in range(s+1):
for k in range(s+1):
if l[0]*i + l[1]*j + l[2]*k==s:
res.append((i,j,k))
return res
Thanks already!!
Note:
It worked if I did changed the ranges to (s//l[i]+1).
I feel like there is a better way to do it, but here is a brute-forth approach with arrays:
A = np.array([3,7,10])
b = np.array([60])
from itertools import product
combin = [np.arange(i) for i in (b//A)+1]
d = np.stack(list(product(*combin)))
[tuple(i) for i in d[d#A==b]]
or equivalently without itertools:
d = np.rollaxis(np.indices((b//A)+1),0,4).reshape(-1,3)
[tuple(i) for i in d[d#A==b]]
output:
[(0, 0, 6), (1, 1, 5), (2, 2, 4), (3, 3, 3), (4, 4, 2), (5, 5, 1), (6, 6, 0), (10, 0, 3), (11, 1, 2), (12, 2, 1), (13, 3, 0), (20, 0, 0)]
comparison:
##Ehsan's solution 1
def m1(b):
combin = [np.arange(i) for i in (b//A)+1]
d = np.stack(list(product(*combin)))
return [tuple(i) for i in d[d#A==b]]
##Ehsan's solution 2
def m2(b):
d = np.rollaxis(np.indices((b//A)+1), 0, 4).reshape(-1,3)
return [tuple(i) for i in d[d#A==b]]
##mathfux solution
def m3(b):
A, B, C = range(0, b+1, 3), range(0, b+1, 7), range(0, b+1, 10)
triplets = list(product(A, B, C)) #all triplets
suitable_triplets = list(filter(lambda x: sum(x)==b, triplets)) #triplets that adds up to 60
return [(a//3, b//7, c//10) for a, b, c in suitable_triplets]
performance:
in_ = [np.array([n]) for n in [10,100,1000]]
which makes m2 the fastest among them.
This becomes a completely mathematical problem. You need to find all non-negative solution triplets for linear diophantine equation 3a+7b+10c=60.
The main idea of finding solutions for this equation can be illustrated using generating functions (polynomials). Let us take three such polynomials:
A=1+x^3+x^6+x^9+...+x^60
B=1+x^7+x^14+x^21+...+x^56
C=1+x^10+x^20+x^30+...+x^60
If you multiply them, you see that each term x^n can be expressed as a product of x^a, x^b and x^c, every of these terms are taken from A, B and C respectively.
Brute-force approach. You need to define multiplication of these polynomials that keeps track of terms that were multiplied, just like this:
[0, 3, 6] * [0, 7, 14] * [0, 10] = [(0,0,0), (0,0,10), (0,7,0), (0,7,10), (3,0,0), (3,0,10), (3,7,0), (3,7,10), (6,0,0), (6,0,10), (6,7,0), (6,7,10)]
Lists don't have * operator in Python but, fortunately, you can use itertools.product method instead. This is a complete sulution:
from itertools import product
A, B, C = range(0, 61, 3), range(0, 61, 7), range(0, 61, 10)
triplets = list(product(A, B, C)) # all triplets
suitable_triplets = list(filter(lambda x: sum(x)==60, triplets)) #triplets that adds up to 60
print([[a//3, b//7, c//10] for a, b, c in suitable_triplets])
Vectorised brut-force. This is based on previous script, replacing all the loops with numpy actions:
import numpy as np
l = np.array([3,7,10])
s = 60
unknowns = [range(0, s+1, n) for n in l]
triplets = np.stack(np.meshgrid(*unknowns), axis=-1).reshape(-1, len(unknowns))
suitable_triplets = triplets[np.sum(triplets, axis=1) == s]
solutions = suitable_triplets//l
Mathematical approach. In general, solving linear diophantine equations is hard. Look through this SO answer. It says that sympy is able to find a parametrised solution only but it can't identify domain:
import sympy as sp
from sympy.solvers.diophantine.diophantine import diop_solve
x,y,z = sp.symbols('x y z')
solution = diop_solve(3*x + 7*y + 10*z-60)
And the output of solution is (t_0, t_0 + 10*t_1 + 180, -t_0 - 7*t_1 - 120).
Optimised solution is possible using Sage but you are required to download Linux Operating System in this case :D
For image analysis i loaded up a float image with scipy imread.
Next, i had scipys argrelmax search for local maxima in axis 0 and 1 and stored the results as arrays of tuples.
data = msc.imread(prediction1, 'F')
datarelmax_0 = almax(data, axis = 0)
datarelmax_1 = almax(data, axis = 1)
how can i create a numpy array from both lists which contains only the tuples that are in both list?
Edit:
argrelmax creates a tuple with two arrays:
datarelmax_0 = ([1,2,3,4,5],[6,7,8,9,10])
datarelmax_1 = ([11,2,13,14,5], [11,7,13,14,10])
in want to create a numpy array that looks like:
result_ar[(2,7),(5,10)]
How about this "naive" way?
import numpy as np
result = np.array([x for x in datarelmax_0 if x in datarelmax_1])
Pretty simple. Maybe there's a better/faster/fancier way by using some numpy methods but this should work for now.
EDIT:
To answer your edited question, you can do this:
result = [x for x in zip(datarelmax_0[0], datarelmax_0[1]) if x in zip(datarelmax_1[0], datarelmax_1[1])]
This gives you
result = [(2, 7), (5, 10)]
If you convert it to a numpy array by using
result = np.array(result)
it looks like this:
result = array([[ 2, 7],
[ 5, 10]])
In case you are interested in what zip does:
>>> zip(datarelmax_0[0], datarelmax_0[1])
[(1, 6), (2, 7), (3, 8), (4, 9), (5, 10)]
>>> zip(datarelmax_1[0], datarelmax_1[1])
[(11, 11), (2, 7), (13, 13), (14, 14), (5, 10)]
I have a list of (x,y) values that are in a list like [(x,y),(x,y),(x,y)....]. I feel like there is a solution in matplotlib, but I couldn't quite get there because of my formatting. I would like to plot it as a histogram or line plot. Any help is appreciated.
You can quite easily convert a list of (x, y) tuples into a list of two tuples of x- and y- coordinates using the * ('splat') operator (see also this SO question):
>>> zip(*[(0, 0), (1, 1), (2, 4), (3, 9)])
[(0, 1, 2, 3), (0, 1, 4, 9)]
And then, you can use the * operator again to unpack those arguments into plt.plot
>>> plt.plot(*zip(*[(0, 0), (1, 1), (2, 4), (3, 9)]))
or even plt.bar
>>> plt.bar(*zip(*[(0, 0), (1, 1), (2, 4), (3, 9)]))
Perhaps you could try something like this (also see):
import numpy as np:
xs=[]; ys=[]
for x,y in xy_list:
xs.append(x)
ys.append(y)
xs=np.asarray(xs)
ys=np.asarray(ys)
plot(xs,ys,'ro')
Maybe not the most elegant solution, but it should work. Cheers, Trond
I am new to python and don't know the best way to do this.
I have a list of tuples which represent points and another list which represents offsets. I need a set of all the combinations that this forms.
Here's some code:
offsets = [( 0, 0),( 0,-1),( 0, 1),( 1, 0),(-1, 0)]
points = [( 1, 5),( 3, 3),( 8, 7)]
So my set of combined points should be
[( 1, 5),( 1, 4),( 1, 6),( 2, 5),( 0, 5),
( 3, 3),( 3, 2),( 3, 4),( 4, 3),( 2, 3),
( 8, 7),( 8, 6),( 8, 8),( 9, 7),( 7, 7)]
I'm not able to use NumPy or any other libraries.
result = [(x+dx, y+dy) for x,y in points for dx,dy in offsets]
For more, see list comprehensions.
Pretty simple:
>>> rslt = []
>>> for x, y in points:
... for dx, dy in offsets:
... rslt.append( (x+dx, y+dy) )
...
>>> rslt
[(1, 5), (1, 4), (1, 6), (2, 5), (0, 5), (3, 3), (3, 2), (3, 4), (4, 3), (2, 3), (8, 7), (8, 6), (8, 8), (9, 7), (7, 7)]
Cycle through the points and the offsets, then build new tuples of adding the offsets to the points.
Personally, I like Alok's answer. However, for fans of itertools, the itertools-based equivalent (in Python 2.6 and later) is:
import itertools as it
ps = [(x+dx, y+dy) for (x, y), (dx, dy) in it.product(points, offsets)]
However, in this case the itertools solution is not faster than the simple one (it's actually a tad slower because it needs to unpack each x, y repeatedly for every offset, while Alok's simple approach unpacks each x, y but once). Still, itertools.product is an excellent alternative to nested loops in other cases, so, it's worth knowing about it!-)
If you don't care about duplicates in the result:
result = []
for ox, oy in offsets:
for px, py in points:
result.append((px + ox, py + oy))
If you do care about duplicates in the result:
result = set()
for ox, oy in offsets:
for px, py in points:
result.add((px + ox, py + oy))