If statment with an array of numbers - python-2.7

I have an array of numbers
x = np.arange(-5., 5., .001)
and an equation that is
y=somefunction(x*r)
When absolute value of x is less than .1, I want to let r=5, otherwise r=0. Then, I should get len(x) many values of y.
This is what I've tried:
if abs(x) < .1 :
r=5
else:
r=0

Try this it will work. Instead of using if-else use vectorization method. This method is faster than if-else. My suggestion is that always try to use vectorization methods for the speedy process instead of using if-else,for-loops,etc.
x = np.arange(-5., 5., .001)
print(x)
output: array([-5. , -4.999, -4.998, ..., 4.997, 4.998, 4.999])
x[abs(x)< .1]=5
x[abs(x)> .1]=0
Again you can print values of x variable and you will see the change.
Hopefully, this will help you. Good Luck!

Related

Summation under a given assumption (returning piecewise function)

I am looking to evaluate the sum an infinite geometric series in SymPy, and want to use the fact that I know the sum has to converge. (Similar to this post: How to Sum with conditions on Sympy?)
My code:
import sympy as sp
from sympy import oo
from sympy.assumptions import assuming, Q
from sympy.assumptions.assume import global_assumptions
x,k = sp.symbols('x k')
#global_assumptions.add(Q.is_true(sp.Abs(x)<1))
with assuming(Q.is_true(sp.Abs(x)<1)):
y = sp.Sum(x**k,(k,0,oo)).doit()
print y
The result is:
Piecewise((1/(-x + 1), Abs(x) < 1), (Sum(x**k, (k, 0, oo)), True))
So it seems the assumption that abs(x)<1 is not taken into account.
Using the global_assumptions (commented out here) does not give the desired result.
Concretely, how do I evaluate the sum such that the result would be 1/(1-x)?
At present, the assumptions made by the assumptions module are not used by the rest of SymPy modules, which makes them less useful than one might hope.
You can sort of fake it by using .subs like this:
y = sp.Sum(x**k, (k,0,oo)).doit().subs(sp.Abs(x) < 1, True)
which returns 1/(-x + 1).
I think this is the best one can do at present. Because this is just a literal substitution of True for a condition, rather than a logical inference, it won't work when the assumption doesn't exactly match a condition in Piecewise:
y = sp.Sum(x**k, (k,0,oo)).doit().subs(sp.Abs(x) < 1/2, True) # alas :(

Sympy: Using "assumptions" to evaluate Piecewise, specifically for IndexedBase

I am trying to evaluate a certain expression under consideration of assumption. Specifically my problem is related to indexedBase objects.
See the following code:
from sympy import *
init_printing(use_latex="mathjax")
ntot = symbols("n_tot", integer = True)
i = Idx("i",(1,ntot))
k = Idx("k", (1,ntot))
j = Idx("j",(1,ntot))
x = IndexedBase("x")
As an example let's take the derivative of two summations over x[i].
expr = Sum(Sum(x[i],(i,1,ntot)),(k,1,ntot)).diff(x[j])
(NOTE: this is not possible in the current SymPy version 1.0, it is possible with the development version and will be available in future SymPy stable versions.)
I want to evaluate the expression and get a piecewise answer:
print(expr.doit())
OUTPUT: n_tot*Piecewise((1, And(1 <= j, j <= n_tot)), (0, True))
So my problem is, how can I tell sympy that I know for certain that j is between 1 and ntot. So that my result is 1:
I tried the following but with no luck:
with assuming(j==2):
expr=Sum(Sum(x[i],(i,1,ntot)),(k,1,ntot)).diff(x[j]).doit()
Assumptions on inequalities are a sorely missed feature in SymPy.
Technically the Idx object was created to allow a symbol to contain a definition range, so as to put limits on indexed symbols. Your j already has this information:
In [28]: j.upper
Out[28]: n_tot
In [29]: j.lower
Out[29]: 1
Unfortunately, the inequality class is not meant to handle Idx objects, so its range gets disregared.
You could actually try:
In [32]: simplify(expr.doit()).args[0][0]
Out[32]: n_tot
This manually extracts the first term of the Piecewise expression.
Obviously, the current algorithm needs improvement, it should already tell to Sum that j is within the correct range in order to give 1 as a result.

Python - lambda in list comprehension gives wrong result

I got a numpy.ndarray of electromagnetic samples as complex numbers, where the format is as follows:
ex1:
[[ 8.23133235e-15, -1.59200901e-15, -4.39818917e-13, 7.68089585e-13]
[ 6.98151957e-15, -1.20306059e-15, 9.83923013e-13, 1.64838108e-11]
[ 8.41053742e-15, -1.77702007e-15, -5.98961364e-13, 8.97436205e-13]
[ 7.08443026e-15, -1.25262430e-15, 1.11415868e-12, 1.69346186e-11]]
where rows make up real and imaginary part alternately:
[[z1Ex.real, z1Ey.real, z1Hx.real, z1Hy.real],
[z1Ex.imag, z1Ey.imag, z1Hx.imag, z1Hy.imag],
[z2Ex.real, z2Ey.real, z2Hx.real, z2Hy.real],
[z2Ex.imag, z2Ey.imag, z2Hx.imag, z2Hy.imag],
...etc.]
What I want is to create a new array which expresses the data in magnitude and phase, but keep the same format (i.e. replace real rows with magnitude rows and imaginary with phase rows).
I managed to put up list comprehensions for both calculations (which I´m fairly proud of, being an 2-week amateur, so please be gentle;)). The result for magnitude is what I´d expect, but the phase is terribly off and I don´t have any idea why...
My approach:
Slice the original array in real and imag sub-arrays:
import numpy, cmath
real = ex1[::2] #numpy.ndarray
imag = ex1[1::2] #numpy.ndarray
Define lambdas outside of list comprehension:
magcalc = lambda z, y: abs(complex(z, y))
phasecalc = lambda z,y: cmath.phase(complex(z, y))
Define list comprehension to do math on sub-arrays:
real[:] = np.array([[magcalc(z,y) for z, y in zip(real[x],imag[x])] for x in xrange(len(real))])
imag[:] = np.array([[phasecalc(z,y) for z, y in zip(real[x],imag[x])] for x in xrange(len(imag))])
Check results in original array:
print ex1[:4]
If I do that, the phase result for the first Ex sample is 0.574 rad. If I check the phase manually (i.e. cmath.phase(complex(z1Ex.real,z1Ex.imag))), then I get 0.703 rad. I would accept if there was smth wrong in my list comprehensions, but the magnitude results are completely correct, so I doubt that that´s it.
Where am I doing it wrong? I really tried to find out for 2 days straight now, no luck... Also, I can´t think of another way to achieve what I want.
Please help... (Using Python 2.7)
Thanks
Nils
Oh jeez.. Now I saw the problem, can´t believe how dense I am... Credit goes to John, for making me re-think variable assignments.
In imag[:] = np.array([[phasecalc(z,y) for z, y in zip(real[x],imag[x])] for x in xrange(len(imag))]), I refer to real[], as if it was still populated with real values. But I changed real[] the line before to contain magnitude... So, just changing the variable names for the list comprehensions will do it:
Define list comprehension to do math on sub-arrays:
realcopy[:] = np.array([[magcalc(z,y) for z, y in zip(real[x],imag[x])] for x in xrange(len(real))])
imagcopy[:] = np.array([[phasecalc(z,y) for z, y in zip(real[x],imag[x])] for x in xrange(len(imag))])
And then re-assign to original mag, phase arrays:
Check original results
real[:] = realcopy
imag[:] = imagcopy
print ex1[:4]
Sorry for the waste of time and bytes...
Cheers
Nils

Calculating the value of arctan(x) in C++

I have to calculate the value of arctan(x) . I have calculated the value of this by evaluating the following series :
Arctan (x) = x – x^3/3 + x^5/5 – x^7/7 + x^9/9 - …
But the following code can not calculate the actual value. For example, calculate_angle(1) returns 38.34 . Why?
const double DEGREES_PER_RADIAN = 57.296;
double calculate_angle(double x)
{
int power=5,count=3;
double term,result,prev_res;
prev_res = x;
result= x-pow(x,3)/3;
while(abs(result-prev_res)<1e-10)
{
term = pow(x,power)/power;
if(count%2==0)
term = term*(-1);
prev_res=result;
result=result+term;
++count;
power+=2;
// if(count=99)
// break;
}
return result*DEGREES_PER_RADIAN;
}
EDIT: I found the culprit. You forgot to include stdlib.h, where the function abs resides. You must have ignored the warning about abs being implicitly declared. I checked that removing the include yields the result 38.19 and including it yields the result ~45.
The compiler is not required to stop compilation when an undeclared function is being used (in this case abs). Instead, it is allowed to make assumptions on how the function is declared (in this case, wrong one.)
Besides, like other posters already stated, your use of abs is inappropriate as it returns an int, not a double or float. The condition in the while should be >1e-100 not <1e-100. The 1e-100 is also too small.
--
You forgot to increase count and power after calculating the first two summands:
prev_res = x;
result= x-pow(x,3)/3;
count = 4; <<<<<<
power = 5; <<<<<<
while(abs(result-prev_res)<1e-100)
{
term = pow(x,power)/power;
if(count%2==1)
term = term*(-1);
Also I consider your use of the count variable counterintuitive: it is intialized with 3 like if it denotes the last used power; but then, loop iterations increase it by 1 instead of 2 and you decide the sign by count%2 == 1 as opposed to power%4 == 3
The series converges to tan^{-1} x, but not very fast. Consider the series when x=1:
1 - 1/3 + 1/5 - 1/7 + 1/9 - ...
What is the error when truncating at the 1/9 term? It's around 1/9. To get 10^{-100} accuracy, you would need to have 10^{100} terms. The universe would end before you'd get that. And, catastrophic round-off error and truncation error would make the answer utterly unreliable. You only have 14 digits to play with for doubles.
Look at reference works like Abramowitz and Stegun [AMS 55] or the new NIST Digital Library of Mathematical Functions at http://dlmf.nist.gov to see how these are done in practice. Often, one uses Padé approximants instead of Taylor series. Even when you stick with Taylor series, you often use Chebyshev approximation to cut down on the total error.
I also recommend Numerical Methods that [Usually] Work, by Forman Acton. Or the Numerical Recipes in ... series.
Your sign is the wrong way around after the first two terms. It should be:
if(count%2==0)
term = term*(-1);
Your comparison is the wrong way around in the while condition. Also, you're expecting an unrealistically high level of precision. I would suggest something more like this:
while(fabs(result-prev_res)>1e-8)
Finally, you'll get a more accurate result with a better value for DEGREES_PER_RADIAN. Why not something like this:
const double DEGREES_PER_RADIAN = 180/M_PI;

python and weierstrass function

based on this function. I'm trying to create two empty arrays (one for x and other for y), which later I will use to plot in python. But before anything this is what I have so far...
import math
x1=-2.0
x2=2.0
arr1 = []
arr2 = []
i=0
n=10
delta=(x2-x1)/n
for i in range (0,n+1):
x=x1+delta*i
arr1.append(x)
print arr1
# I have not called the w function yet
the code above creates a list of 10 numbers for now to keep it simple. Then it will send the elements of the array to the function below and compute the equation with certain numbers(infinite loop).
#This function will create the array list for y
import math
def w(x, limit):# the limit here to compare when the number is really small
suma = 0.0
sumb = 0.0
m=1
x=0
suma=suma+((1/(math.pow(2,m))*(math.sin(math.pow(2,m)*x)))
sumb=suma+((1/(math.pow(2,m+1))*(math.sin(math.pow(2,m+1)*x))) # I'm having a
#syntax error
#here
x+=0
if (abs (suma-sumb)<limit):
break:
else m+=1:
if (m<20):
break:
I will appreciate any help with my syntax errors or any suggestion. I just hope I was clear enough.
Thanks ahead of time
The syntax error is actually on the previous line, where the parenthesis are not balanced. You need an extra ) at the end of that line (and at the one you indicated as giving an error too btw).
There are also a few other issues
suma is set to zero, so suma = suma + ... is the same as suma = ..., but I'm guessing you still need to add while loop before this line.
On the line indicated, you have sumb = suma +, which is probably a copy/paste mistake.
The code block starting at x+=0 is indented by only 3 spaces instead of 4. This is probably not the case in your actual code, but if it is, Python will complain about that too.
else m+=1: should be else: m+=1 (colon directly after else, not at the end of the line.
break: should just be break (without to colon).