Related
I am relatively new to python, but I have an issue that I just cannot understand.
I am trying to implement multiprocessing on piece of code that computes the mandelbrot fractal. My problem is that, it seemingly works and doesn't work at random, and I don't understand why.
I have narrowed the problem down to specifically the .get() function that i am running to get data from the "ApplyResult" multiprocessing objects. It seems that this function will time out and run forever or until it is terminated. Occasionally the code will run once or twice, and then stop working, which suggests to me some kind of ports that are being used and not released, but everything I try to add to the code to fix this doesn't seem to help.
I have tried removing the "if name = main" part, which seemingly makes no difference, I have tried other functions I could find in the multiprocessing documentation to release the ports, including,.join() .kill(), .terminate(), as well as trying without the close altogether.
The relevant part of my code looks like this
import numpy as np
import multiprocessing as mp
import os
I = 100
T = 2
N = 100
C_rerow = np.reshape(np.linspace(-2, 1, N), (1, N))
C_imrow = np.reshape(np.linspace(1.5, -1.5, N), (N, 1))
C = C_rerow + C_imrow*1j
def mandel(C_row):
Mandelbrot = np.ones_like(np.absolute(C_row))
Z_old = np.zeros_like(C[:,0])
for i in range(I):
Z_new = Z_old**2 + C_row
Z_old = Z_new
Bool = (np.absolute(Z_new) > T) & (Mandelbrot == 1)
Mandelbrot[Bool] = i/I
return Mandelbrot
def MultiP(C, I, T):
pool = mp.Pool(processes=os.cpu_count() - 1)
Mc = []
for j in range(N):
C_row = C[j,:]
test = pool.apply_async(mandel, (C_row,))
Mc.append(test)
pool.close()
return Mc
if __name__ == '__main__':
Mc = MultiP(C, I, T)
Mc = [Mc[i].get(timeout = 5) for i in range(len(Mc))]
Another strange issue that I can't understand is, that if I rename the output of MultiP to something different than what the function returns, (eg rename Mc = MultiP() to MC = MultiP(), then the returned values just will not be saved. I've never seen anything like that happen with functions before, and I'm not sure if the problems are related, but I thought I would mention it.
Any input would be appreciated.
This is a bit long for a comment and perhaps not quite an answer. The bottom line is that I could not reproduce your error, but I did have a few remarks.
Code that create new processes needs to be conditionally executed by the test if __name__ == '__main__': on those platforms that use the operating system spawn rather than fork method of creating new processes. In such cases, the new process does not inherit a copy of the main process's address space as it was when the sub-process was created but instead starts execution from the top of the program re-executing everything it finds at global scope. If it weren't for the if __name__ == '__main__': test, it would recursively attempt to create even more sub-processes in an endless loop. Consequently, it's a good practice not to have complex calculations done at the global scope that do not really need to be there for they will be re-executed by every sub-process in your multiprocessing pool. It is better to move those calculations to within the if __name__ == '__main__': block. If the worker functions that you will be calling need to access those values you can either pass then as function arguments (this can be costly if these are large pieces of data) or initialized once each sub-process's address space with a global variable, as is done below.
I also tried to re-create the problem you cited in renaming the return value from MultiP from Mc to MC but had no problems. I also corrected your indentation errors.
When you execute the sequence pool.close() followed by pool.join(), you will block until all submitted tasks complete. So if you have submitted asynchronous tasks with apply_async and do not need to get any return values from the returned AsyncResult instances created, you can use close and join to be sure the tasks have finished executing. If you are using method get on the returned AsyncResult instances, you are also guaranteed that the tasks have completed (or timed out in your case), in which case there is really no need to be issuing close and join. By the way, just because you get a TimeoutError exception when you call get signifying that the task has timed out, it is still actually running. Presumably you do not want to wait for timed out tasks to complete. You should therefore call pool.terminate() to kill any running tasks (this is implicitly called at the termination of a with Pool() as poll: block.
Note the comments I have added.
Rhetorical questions for you (they don't need to be answered, but should be thought about):
You have global variables C, I, T, N. Function MultiP accepts C, I and T as arguments ignoring the global variables but accesses global variable N. mandel accesses everything it needs as global variables. Isn't this inconsistent?
MultiP contains the logic to repeatedly call mandel. It could be doing this with or without multiprocessing. With multiprocessing it could be using apply_async or the potentially more efficient map method (if all the arguments were put into a list and if you used a suitable chunksize argument, which turned out to be greater than 1). Yet you return back to its caller not the final results but rather a list of AsyncResult instances. This means that the caller is dependent on the implementation details of MulitiP. Since the caller is immediately "getting" the results anyway, wouldn't it be wiser just to have MultiP "get" and return the results and reduce the coupling between caller and callee?
import numpy as np
import multiprocessing as mp
import os
N = 100
I = 100
T = 2
def init_pool(c):
global C
C = c
def mandel(C_row):
Mandelbrot = np.ones_like(np.absolute(C_row))
Z_old = np.zeros_like(C[:,0])
for i in range(I):
Z_new = Z_old**2 + C_row
Z_old = Z_new
Bool = (np.absolute(Z_new) > T) & (Mandelbrot == 1)
Mandelbrot[Bool] = i/I
return Mandelbrot
def MultiP(C, I, T):
# initialize each sub-process's global C variable:
pool = mp.Pool(processes=os.cpu_count() - 1, initializer=init_pool, initargs=(C,))
Mc = []
for j in range(N):
C_row = C[j,:]
test = pool.apply_async(mandel, (C_row,))
Mc.append(test)
# previous 5 statements can be replaced with:
# Mc = [pool.apply_async(mandel, (C[j,:],)) for j in range(N)]
#pool.close() # not required
return Mc
if __name__ == '__main__':
# moved here so the calculations are done once:
C_rerow = np.reshape(np.linspace(-2, 1, N), (1, N))
C_imrow = np.reshape(np.linspace(1.5, -1.5, N), (N, 1))
C = C_rerow + C_imrow*1j
MC = MultiP(C, I, T)
# The following can throw a TimeoutError exception:
MC = [MC[i].get(timeout = 5) for i in range(len(MC))]
print(MC)
Prints:
test.py:17: RuntimeWarning: overflow encountered in square
Z_new = Z_old**2 + C_row
test.py:17: RuntimeWarning: invalid value encountered in square
Z_new = Z_old**2 + C_row
test.py:17: RuntimeWarning: overflow encountered in square
Z_new = Z_old**2 + C_row
test.py:17: RuntimeWarning: invalid value encountered in square
Z_new = Z_old**2 + C_row
test.py:17: RuntimeWarning: overflow encountered in square
Z_new = Z_old**2 + C_row
test.py:17: RuntimeWarning: overflow encountered in square
Z_new = Z_old**2 + C_row
test.py:17: RuntimeWarning: invalid value encountered in square
Z_new = Z_old**2 + C_row
test.py:17: RuntimeWarning: overflow encountered in square
Z_new = Z_old**2 + C_row
test.py:17: RuntimeWarning: invalid value encountered in square
Z_new = Z_old**2 + C_row
test.py:17: RuntimeWarning: overflow encountered in square
Z_new = Z_old**2 + C_row
test.py:17: RuntimeWarning: invalid value encountered in square
Z_new = Z_old**2 + C_row
test.py:17: RuntimeWarning: overflow encountered in square
Z_new = Z_old**2 + C_row
test.py:19: RuntimeWarning: overflow encountered in absolute
Bool = (np.absolute(Z_new) > T) & (Mandelbrot == 1)
test.py:17: RuntimeWarning: invalid value encountered in square
Z_new = Z_old**2 + C_row
test.py:17: RuntimeWarning: invalid value encountered in square
Z_new = Z_old**2 + C_row
test.py:19: RuntimeWarning: overflow encountered in absolute
Bool = (np.absolute(Z_new) > T) & (Mandelbrot == 1)
[array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
etc.
I bet I am doing something very simple wrong. I want to start with an empty 2D numpy array and append arrays to it (with dimensions 1 row by 4 columns).
open_cost_mat_train = np.matrix([])
for i in xrange(10):
open_cost_mat = np.array([i,0,0,0])
open_cost_mat_train = np.vstack([open_cost_mat_train,open_cost_mat])
my error trace is:
File "/Users/me/anaconda/lib/python2.7/site-packages/numpy/core/shape_base.py", line 230, in vstack
return _nx.concatenate([atleast_2d(_m) for _m in tup], 0)
ValueError: all the input array dimensions except for the concatenation axis must match exactly
What am I doing wrong? I have tried append, concatenate, defining the empty 2D array as [[]], as [], array([]) and many others.
You need to reshape your original matrix so that the number of columns match the appended arrays:
open_cost_mat_train = np.matrix([]).reshape((0,4))
After which, it gives:
open_cost_mat_train
# matrix([[ 0., 0., 0., 0.],
# [ 1., 0., 0., 0.],
# [ 2., 0., 0., 0.],
# [ 3., 0., 0., 0.],
# [ 4., 0., 0., 0.],
# [ 5., 0., 0., 0.],
# [ 6., 0., 0., 0.],
# [ 7., 0., 0., 0.],
# [ 8., 0., 0., 0.],
# [ 9., 0., 0., 0.]])
If open_cost_mat_train is large I would encourage you to replace the for loop by a vectorized algorithm. I will use the following funtions to show how efficiency is improved by vectorizing loops:
def fvstack():
import numpy as np
np.random.seed(100)
ocmt = np.matrix([]).reshape((0, 4))
for i in xrange(10):
x = np.random.random()
ocm = np.array([x, x + 1, 10*x, x/10])
ocmt = np.vstack([ocmt, ocm])
return ocmt
def fshape():
import numpy as np
from numpy.matlib import empty
np.random.seed(100)
ocmt = empty((10, 4))
for i in xrange(ocmt.shape[0]):
ocmt[i, 0] = np.random.random()
ocmt[:, 1] = ocmt[:, 0] + 1
ocmt[:, 2] = 10*ocmt[:, 0]
ocmt[:, 3] = ocmt[:, 0]/10
return ocmt
I've assumed that the values that populate the first column of ocmt (shorthand for open_cost_mat_train) are obtained from a for loop, and the remaining columns are a function of the first column, as stated in your comments to my original answer. As real costs data are not available, in the forthcoming example the values in the first column are random numbers, and the second, third and fourth columns are the functions x + 1, 10*x and x/10, respectively, where x is the corresponding value in the first column.
In [594]: fvstack()
Out[594]:
matrix([[ 5.43404942e-01, 1.54340494e+00, 5.43404942e+00, 5.43404942e-02],
[ 2.78369385e-01, 1.27836939e+00, 2.78369385e+00, 2.78369385e-02],
[ 4.24517591e-01, 1.42451759e+00, 4.24517591e+00, 4.24517591e-02],
[ 8.44776132e-01, 1.84477613e+00, 8.44776132e+00, 8.44776132e-02],
[ 4.71885619e-03, 1.00471886e+00, 4.71885619e-02, 4.71885619e-04],
[ 1.21569121e-01, 1.12156912e+00, 1.21569121e+00, 1.21569121e-02],
[ 6.70749085e-01, 1.67074908e+00, 6.70749085e+00, 6.70749085e-02],
[ 8.25852755e-01, 1.82585276e+00, 8.25852755e+00, 8.25852755e-02],
[ 1.36706590e-01, 1.13670659e+00, 1.36706590e+00, 1.36706590e-02],
[ 5.75093329e-01, 1.57509333e+00, 5.75093329e+00, 5.75093329e-02]])
In [595]: np.allclose(fvstack(), fshape())
Out[595]: True
In order for the calls to fvstack() and fshape() produce the same results, the random number generator is initialized in both functions through np.random.seed(100). Notice that the equality test has been performed using numpy.allclose instead of fvstack() == fshape() to avoid the round off errors associated to floating point artihmetic.
As for efficiency, the following interactive session shows that initializing ocmt with its final shape is significantly faster than repeatedly stacking rows:
In [596]: import timeit
In [597]: timeit.timeit('fvstack()', setup="from __main__ import fvstack", number=10000)
Out[597]: 1.4884241055042366
In [598]: timeit.timeit('fshape()', setup="from __main__ import fshape", number=10000)
Out[598]: 0.8819408006311278
I was wondering if there is any function in numpy to determine whether a matrix is Unitary?
This is the function I wrote but it is not working. I would be thankful if you guys can find an error in my function and/or tell me another way to find out if a given matrix is unitary.
def is_unitary(matrix: np.ndarray) -> bool:
unitary = True
n = matrix.size
error = np.linalg.norm(np.eye(n) - matrix.dot( matrix.transpose().conjugate()))
if not(error < np.finfo(matrix.dtype).eps * 10.0 *n):
unitary = False
return unitary
Let's take an obviously unitary array:
>>> a = 0.7
>>> b = (1-a**2)**0.5
>>> m = np.array([[a,b],[-b,a]])
>>> m.dot(m.conj().T)
array([[ 1., 0.],
[ 0., 1.]])
and try your function on it:
>>> is_unitary(m)
Traceback (most recent call last):
File "<ipython-input-28-8dc9ddb462bc>", line 1, in <module>
is_unitary(m)
File "<ipython-input-20-3758c2016b67>", line 5, in is_unitary
error = np.linalg.norm(np.eye(n) - matrix.dot( matrix.transpose().conjugate()))
ValueError: operands could not be broadcast together with shapes (4,4) (2,2)
which happens because
>>> m.size
4
>>> np.eye(m.size)
array([[ 1., 0., 0., 0.],
[ 0., 1., 0., 0.],
[ 0., 0., 1., 0.],
[ 0., 0., 0., 1.]])
If we replace n = matrix.size with len(m) or m.shape[0] or something, we get
>>> is_unitary(m)
True
I might just use
>>> np.allclose(np.eye(len(m)), m.dot(m.T.conj()))
True
where allclose has rtol and atol parameters.
If you are using NumPy's matrix class, there is a property for the Hermitian conjugate, so:
def is_unitary(m):
return np.allclose(np.eye(m.shape[0]), m.H * m)
e.g.
In [79]: P = np.matrix([[0,-1j],[1j,0]])
In [80]: is_unitary(P)
Out[80]: True
I am trying to combine cvxopt (an optimization solver) and PyMC (a sampler) to solve convex stochastic optimization problems.
For reference, installing both packages with pip is straightforward:
pip install cvxopt
pip install pymc
Both packages work independently perfectly well. Here is an example of how to solve an LP problem with cvxopt:
# Testing that cvxopt works
from cvxopt import matrix, solvers
# Example from http://cvxopt.org/userguide/coneprog.html#linear-programming
c = matrix([-4., -5.])
G = matrix([[2., 1., -1., 0.], [1., 2., 0., -1.]])
h = matrix([3., 3., 0., 0.])
sol = solvers.lp(c, G, h)
# The solution sol['x'] is correct: (1,1)
However, when I try using it with PyMC (e.g. by putting a distribution on one of the coefficients), PyMC gives an error:
import pymc as pm
import cvxopt
c1 = pm.Normal('c1', mu=-4, tau=.5**-2)
#pm.deterministic
def my_lp_solver(c1=c1):
c = matrix([c1, -5.])
G = matrix([[2., 1., -1., 0.], [1., 2., 0., -1.]])
h = matrix([3., 3., 0., 0.])
sol = solvers.lp(c, G, h)
solution = np.array(sol['x'],dtype=float).flatten()
return solution
m = pm.MCMC(dict(c1=c1, x=x))
m.sample(20000, 10000, 10)
I get the following PyMC error:
<ipython-input-21-5ce2909be733> in x(c1)
14 #pm.deterministic
15 def x(c1=c1):
---> 16 c = matrix([c1, -5.])
17 G = matrix([[2., 1., -1., 0.], [1., 2., 0., -1.]])
18 h = matrix([3., 3., 0., 0.])
TypeError: invalid type in list
Why? Is there any way to make cvxoptplay nicely with PyMC?
Background:
In case anyone wonders, PyMC allows you to sample from any function of your choice. In this particular case, the function from which we sample is one that maps an LP problem to a solution. We are sampling from this function because our LP problem contains stochastic coefficients, so one cannot just apply an LP solver off-the-shelf.
More specifically in this case, a single PyMC output sample is simply a solution to the LP problem. As parameters of the LP problem vary (according to distributions of your choice), the output samples from PyMC would be different, and the hope is to get a posterior distribution.
The solution above is inspired by this answer, the only difference is that I am hoping to use a true general solver (in this case cvxopt)
The type of c1 generated with pm.Normal is numpy array, you just need to strip it out and convert it to float(c1), then it works finely:
>>> #pm.deterministic
... def my_lp_solver(c1=c1):
... c = matrix([float(c1), -5.])
... G = matrix([[2., 1., -1., 0.], [1., 2., 0., -1.]])
... h = matrix([3., 3., 0., 0.])
... sol = solvers.lp(c, G, h)
... solution = np.array(sol['x'],dtype=float).flatten()
... return solution
...
pcost dcost gap pres dres k/t
0: -8.1223e+00 -1.8293e+01 4e+00 0e+00 7e-01 1e+00
1: -8.8301e+00 -9.4605e+00 2e-01 1e-16 4e-02 3e-02
2: -9.0229e+00 -9.0297e+00 2e-03 2e-16 5e-04 4e-04
3: -9.0248e+00 -9.0248e+00 2e-05 3e-16 5e-06 4e-06
4: -9.0248e+00 -9.0248e+00 2e-07 2e-16 5e-08 4e-08
Optimal solution found.
I am very new to Python (in the past I used Mathematica, Maple, or Matlab scripts). I am very impressed how NumPy can evaluate functions over arrays but having problems trying to implement it in several dimensions. My question is very simple (please don't laugh): is there a more elegant and efficient way to evaluate some function f (which is defined over R^2) without using loops?
import numpy
M=numpy.zeros((10,10))
for i in range(0,10):
for j in range(0,10):
M[i,j]=f(i,j)
return M
The goal when coding with numpy is to implement your computation on the whole array, as much as possible. So if your function is, for example, f(x,y) = x**2 +2*y and you want to apply it to all integer pairs x,y in [0,10]x[0,10], do:
x,y = np.mgrid[0:10, 0:10]
fxy = x**2 + 2*y
If you don't find a way to express your function in such a way, then:
Ask how to do it (and state explicitly the function definition)
use numpy.vectorize
Same example using vectorize:
def f(x,y): return x**2 + 2*y
x,y = np.mgrid[0:10, 0:10]
fxy = np.vectorize(f)(x.ravel(),y.ravel()).reshape(x.shape)
Note that in practice I only use vectorize similarly to python map when the content of the arrays are not numbers. A typical example is to compute the length of all list in an array of lists:
# construct a sample list of lists
list_of_lists = np.array([range(i) for i in range(1000)])
print np.vectorize(len)(list_of_lists)
# [0,1 ... 998,999]
Yes, many numpy functions operate on N-dimensional arrays. Take this example:
>>> M = numpy.zeros((3,3))
>>> M[0][0] = 1
>>> M[2][2] = 1
>>> M
array([[ 1., 0., 0.],
[ 0., 0., 0.],
[ 0., 0., 1.]])
>>> M > 0.5
array([[ True, False, False],
[False, False, False],
[False, False, True]], dtype=bool)
>>> numpy.sum(M)
2.0
Note the difference between numpy.sum, which operates on N-dimensional arrays, and sum, which only goes 1 level deep:
>>> sum(M)
array([ 1., 0., 1.])
So if you build your function f() out of operations that work on n-dimensional arrays, then f() itself will work on n-dimensional arrays.
You can also use numpy multi-dimension slicing, like below. You just provide slices for each dimension:
arr = np.zeros((5,5)) # 5 rows, 5 columns
# update only first column
arr[:,0] = 1
# update only last row ... same as arr[-1] = 1
arr[-1,:] = 1
# update center
arr[1:-1, 1:-1] = 1
print arr
output:
array([[ 1., 0., 0., 0., 0.],
[ 1., 1., 1., 1., 0.],
[ 1., 1., 1., 1., 0.],
[ 1., 1., 1., 1., 0.],
[ 1., 1., 1., 1., 1.]])
A pure python answer, not depending upon numpy tools, is to make the Cartesian Product of two sequences:
from itertools import product
for i, j in product(range(0, 10), range(0, 10)):
M[i,j]=f(i,j)
Edit: Actually, I should have read the question properly. This still uses loops, just one less loop.