numpy array to list conversion issue - python

For some reason, evalRow(list(array([0, 1, 0, 0, 0]))) and evalRow([0, 1, 0, 0, 0]) give different results. However if I use magicConvert (here to debug this) instead of list to go from numpy array to list it works as expected:
def magicConvert(a):
ss = str(list(a))[1:-1]
return map(int, ss.split(","))
# You don't actually need to read these functions, just here to reproduce the error:
from itertools import *
def evalRow(r):
grouped = map(
lambda (v, l): (v, len(tuple(l))),
groupby(chain([2], r, [2])))
result = 0
for player in (1, -1):
for (pre, mid, post) in allTuples(grouped, 3):
if mid[0] == player:
result += player * streakScore(mid[1], (pre[0] == 0) + (post[0] == 0))
return result
def streakScore(size, blanks):
return 0 if blanks == 0 else (
100 ** (size - 1) * (1 if blanks == 1 else 10))
def allTuples(l, size):
return map(lambda i: l[i : i + size], xrange(len(l) - size + 1))

The difference in the behaviour is due to the fact that doing list(some_array) returns a list of numpy.int64, while, doing the conversion via the string representation (or equivalently using the tolist() method) returns a list of python's ints:
In [21]: import numpy as np
In [22]: ar = np.array([1,2,3])
In [23]: list(ar)
Out[23]: [1, 2, 3]
In [24]: type(list(ar)[0])
Out[24]: numpy.int64
In [25]: type(ar.tolist()[0])
Out[25]: builtins.int
I believe the culprit is the 100 ** (size - 1) part of your code:
In [26]: 100 ** (np.int64(50) - 1)
Out[26]: 0
In [27]: 100 ** (50 - 1)
Out[27]: 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
In [28]: type(100 ** (np.int64(50) - 1))
Out[28]: numpy.int64
What you see is the int64 overflowing, hence the result of the exponentiation are essentially "random", while python's ints have unlimited range and give the correct result.
To summary:
If you want to convert between numpy and python data types use the proper methods, in this case array.tolist()
Remember that numpys data types have limited range, hence you should check for overflows and expect strange results in other situations. If you do not use the proper methods for conversion you might end up using numpy data types when you didn't expect (as in this case).
Never assume it's a bug in python/numpy/a very widely used library. The chances to find a bug in such trivial cases in such well-tested and widely used softwares is really small. If the program gives unexpected results, 99.999% of the times it's because you are doing something wrong. So, before blaming on others try to check step by step what your program is doing.

I tested it and it gave me differnet results. Don't ask me why, maybe a bug?
Anyway always use the tolist() function to convert a numpy array to a list.
evalRow(array([0, 1, 0, 0, 0]).tolist()) == evalRow([0, 1, 0, 0, 0])
#output: True

Related

How to find negative imaginary parts of values in an array then turning them to positive?

I have a function a=x*V where x assumes thousands of values as x = arange(1,1000,0.1) and V is a combination of other constants. These make a always complex (has nonzero real and imaginary parts). However, because a depends on other values, the imag(a) can be negative for some x's.
For what I am doing, however, I need imag(a) to be always positive, so I need to take the negative values and turn them into positive.
I have tried doing
if imag(a)<0:
imag(a) = -1*imag(a)
That didn't seem to work because it gives me the error: SyntaxError: Can't assign to function call. I thought it was because it's an array so I tried any() and all(), but that didn't work either.
I'm out of options now.
IIUC:
In [35]: a = np.array([1+1j, 2-2j, 3+3j, 4-4j])
In [36]: a.imag *= np.where(a.imag < 0, -1, 1)
In [37]: a
Out[37]: array([ 1.+1.j, 2.+2.j, 3.+3.j, 4.+4.j])
You can't redefine a function that way. It would be like saying
sqrt(x) = 2*sqrt(x)
What you can do is reassign the value of a (not imag(a)).
if imag(a) < 0
a = a - 2*imag(a)*j
For example, if a = 3 - 5j, then it would give you
3 - 5j - 2(-5)j = 3 + 5j
It appears to be faster than doing subtraction. For a full function:
import numpy as np
def imag_abs(x):
mask = x.imag < 0
x[mask] = np.conj(x[mask])
return x

Why NumPy is casting objects to floats?

I'm trying to store intervals (with its specific arithmetic) in NumPy arrays. If I use my own Interval class, it works, but my class is very poor and my Python knowledge limited.
I know pyInterval and it's very complete. It covers my problems. The only thing which is not working is storing pyInterval objects in NumPy arrays.
class Interval(object):
def __init__(self, lower, upper = None):
if upper is None:
self.upper = self.lower = lower
elif lower <= upper:
self.lower = lower
self.upper = upper
else:
raise ValueError(f"Lower is bigger than upper! {lower},{upper}")
def __repr__(self):
return "Interval " + str((self.lower,self.upper))
def __mul__(self,another):
values = (self.lower * another.lower,
self.upper * another.upper,
self.lower * another.upper,
self.upper * another.lower)
return Interval(min(values), max(values))
import numpy as np
from interval import interval
i = np.array([Interval(2,3), Interval(-3,6)], dtype=object) # My class
ix = np.array([interval([2,3]), interval([-3,6])], dtype=object) # pyInterval
These are the results
In [30]: i
Out[30]: array([Interval (2, 3), Interval (-3, 6)], dtype=object)
In [31]: ix
Out[31]:
array([[[2.0, 3.0]],
[[-3.0, 6.0]]], dtype=object)
The intervals from pyInterval has been casted as list of list of floats. It doesn't be a problem if them preserves interval arithmetics...
In [33]: i[0] * i[1]
Out[33]: Interval (-9, 18)
In [34]: ix[0] * ix[1]
Out[34]: array([[-6.0, 18.0]], dtype=object)
Out[33] is the wished output. The output using pyInterval is incorrect. Obviously using raw pyInterval it works like a charm
In [35]: interval([2,3]) * interval([-3,6])
Out[35]: interval([-9.0, 18.0])
Here is the pyInterval source code. I don't understand why using this object NumPy doesn't work as I expect.
To be fair, it is really hard for the numpy.ndarray constructor to infer what kind of data should go into it. It receives objects which resemble lists of tuples and makes do with it.
You can, however, help your constructor a bit by not having it guess the shape of your data:
a = interval([2,3])
b = interval([-3,6])
ll = [a,b]
ix = np.empty((len(ll),), dtype=object)
ix[:] = [*ll]
ix[0]*ix[1] #interval([-9.0, 18.0])
NumPy sees each interval as an array of two numbers, and it does elementwise multiplication which you don't want. Try this:
interval.__mul__(ix[0], ix[1])
That is a direct invocation of the function you want to call. It should give you the answer you need, even if it is not very pretty. To turn it into something that works on whole arrays, you can do this:
itvmul = np.vectorize(interval.__mul__)
That will allow you to do elementwise multiplication of arrays of intervals: https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.vectorize.html

Symbolic conditional sum

Is there a way to calculate, or at least state properly, a symbolic sum which iterates over a sequence conditionally?
For example, if a(n) is a sequence (of reals) and c(n) is a "condition" (boolean function defined on the integers), then I wish to compute, or at least state, the sum over all a(n)'s for which c(n).
Formally, I'd like to do something like this:
n = Symbol('n', integer=True, positive=True)
a = 1 / n**2
c = Eq(n%3, 1)
## s = Sum(a, (n, 0, oo), condition=c)
So s should be the following sum:
1/1 + 1/16 + 1/49 + 1/100 + 1/169 + ...
Of course, in this case I can define s manually, but I wonder whether I can do it automatically somehow.
Edit:
By manually I mean
Sum(1/(3*n+1)**2, (n, 0, oo))
This can be evaluated (and it is about 1.12173301393634).
An attempt I've made (which failed) is as follows:
Sum(Eq(n%3, 1) * (1/n**2), (n, 0, oo))
Trying to evaluate this using .evalf() resulted
AttributeError: 'BooleanFalse' object has no attribute '_eval_evalf'
Edit (2):
Here's another attempt, which yields a wrong result:
p = Piecewise((1/(n**2), Eq(n%3, 1)), (0, True))
Sum(p, (n, 0, oo)).evalf()
## returns 1.00000000000000
Either I've done something wrong, or this is a sympy bug.
Using a Piecewise is definitely the correct way to do this. The wrong result is a bug in SymPy, which you should report at https://github.com/sympy/sympy/issues/new. Your second method won't work because in SymPy booleans are not implicitly integers (True and False are not 1 and 0).
Or avoid piecewise by defining your function as 1/(3*n+1)**2
>>> Sum((3*n + 1)**(-2), (n, 0, oo))
Sum((3*n + 1)**(-2), (n, 0, oo))
>>> print filldedent(_.doit())
exp(-4*I*pi/3)*polylog(2, exp_polar(4*I*pi/3))/3 + pi**2/18 +
exp(-2*I*pi/3)*polylog(2, exp_polar(2*I*pi/3))/3
>>> Sum((3*n + 1)**(-2), (n, 0, oo)).n()
1.12173301393634
You can see that the remapping works by using Symbol-trickery. e.g. the 1st 6 terms:
>>> Add(*[(1/n).subs(n,Symbol(str((3*i+1)**2))) for i in range(5)])
1/49 + 1/169 + 1/16 + 1/100 + 1/1
If it's a linear sequence then you could use Integal's transform method to do the transformation for you:
>>> i=Integral(1/x**2,(x,1,oo))
>>> i.transform(x,3*x - 2)
Integral(3/(3*x - 2)**2, (x, 1, oo))
>>> (Sum(*_.args)/3).n(3) # divide by 3 to handle renorm
1.12

Manual fft not giving me same results as fft

import numpy as np
import matplotlib.pyplot as pp
curve = np.genfromtxt('C:\Users\latel\Desktop\kool\Neuro\prax2\data\curve.csv',dtype = 'float', delimiter = ',')
curve_abs2 = np.empty_like(curve)
z = 1j
N = len(curve)
for i in range(0,N-1):
curve_abs2[i] =0
for k in range(0,N-1):
curve_abs2[i] += (curve[i]*np.exp((-1)*z*(np.pi)*i*((k-1)/N)))
for i in range(0,N):
curve_abs2[i] = abs(curve_abs2[i])/(2*len(curve_abs2))
#curve_abs = (np.abs(np.fft.fft(curve)))
#pp.plot(curve_abs)
pp.plot(curve_abs2)
pp.show()
The code behind # gives me 3 values. But this is just ... different
Wrong ^^ this code: http://www.upload.ee/image/3922681/Ex5problem.png
Correct using numpy.fft.fft(): http://www.upload.ee/image/3922682/Ex5numpyformulas.png
There are several problems:
You are assigning complex values to the elements of curve_abs2, so it should be declared to be complex, e.g. curve_abs2 = np.empty_like(curve, dtype=np.complex128). (And I would recommend using the name, say, curve_fft instead of curve_abs2.)
In python, range(low, high) gives the sequence [low, low + 1, ..., high - 2, high - 1], so instead of range(0, N - 1), you must use range(0, N) (which can be simplified to range(N), if you want).
You are missing a factor of 2 in your formula. You could fix this by using z = 2j.
In the expression that is being summed in the inner loop, you are indexing curve as curve[i], but this should be curve[k].
Also in that expression, you don't need to subtract 1 from k, because the k loop ranges from 0 to N - 1.
Because k and N are integers and you are using Python 2.7, the division in the expression (k-1)/N will be integer division, and you'll get 0 for all k. To fix this and the previous problem, you can change that term to k / float(N).
If you fix those issues, when the first double loop finishes, the array curve_abs2 (now a complex array) should match the result of np.fft.fft(curve). It won't be exactly the same, but the differences should be very small.
You could eliminate that double loop altogether using numpy vectorized calculations, but that is a topic for another question.

can't multiply sequence by non-int of type 'list'

def evalPolynomial(coeffs,x):
return sum([n for n in coeffs] * [x**(m-1)for m in range(len(coeffs),0,-1)])
TypeError: can't multiply sequence by non-int of type 'list'
Not sure what's causing the error? When I print each of the statements separately, they each give me a list, but when I try to multiply them it doesn't work.
Python list s can only be multiplied by an integer, in which case the elements of the list are repeated:
>>> [1,2,3] * 3
[1, 2, 3, 1, 2, 3, 1, 2, 3]
If you want vectorial operations use numpy.ndarray instead:
>>> import numpy as np
>>> ar = np.array([1,2,3])
>>> ar * 3
array([3, 6, 9])
In particular there is a numpy function for convolution(i.e. polynomial multiplication):
>>> a = np.array([1,2,3]) # 1 + 2x + 3x^2
>>> b = np.array([4,5,6]) # 4 + 5x + 6x^2
>>> np.convolve(a, b) # (1 + 2x + 3x^2) * (4 + 5x + 6x^2)
array([ 4, 13, 28, 27, 18]) # 4 + 13x + 28x^2 + 27x^3 + 18x^4
If you want to evaluate a polynomial there is the numpy.polyval function which does this.
Keep in mind that using numpy limits the size of the integers, so you might obtain wrong results if the coefficients are so big that they overflow.
The expression [n for n in coeffs] is a list, of integers.
Lists do support multiplication by an integer, but this means "make a list that
is n copies of the starting list"; this is not what you want in this mathematical context.
I would recommend that you look at the numpy (or scipy which is largely a superset of numpy) package to help with this. It has a function polyval for evaluating exactly what you want, and also provides a class based representation polynomial. In general, for doing numeric computation in Python, you should look at these packages.
But if you want to roll your own, you'll need to do the math inside of the list comprehension,
one way to do it is:
return sum( [ n*x**(i-1) for (n,i) in zip( coeffs, xrange(len(coeffs),0,-1)) ] )
You are trying to multiple two lists together. This is not a valid operation in python.
If you want to multiply each corresponding element in the two lists you can use something like this:
def evalPolynomial(coeffs,x):
return sum(x * y for x, y in zip(coeffs, (x**(m-1)for m in range(len(coeffs),0,-1))))

Categories

Resources