2

although I know there's various questions looking for solutions to this error message, I've yet to find an answer that helps me solve my code to get the comparison working, I have the code

def f(x,d,h,L):
    ans=0.
    if ((0.<=x) & (x<d)):
        ans=h*(x/d)
    elif ((d<=x) & (x<=L)):
        ans=((L-x)/(L-d))
    return ans

x=np.linspace(0,10,1000)
h=5*10**(-3)
d=16*10**(-2)
L=64.52*10**(-2)
func=f(x,d,h,L)

But when I try running it I get an error pointing to the if line with the error code in the title, I've tried the proposed solutions given in similar questions such as using np.logical_and or and instead of & but all three yield the same error, please help me out

2
  • x is an array. Do you want f to do one thing if any/all of x fall in one range, and a different if they don't? Or do you want it to do one thing with the x values that fall in one range, and a different thing for the other x values? In other words does the if test apply to the whole of x or to the individual elements? Commented Jun 30, 2015 at 0:03
  • Another way to put my question - does the function work correctly if you pass the elements of x to it individually? Commented Jun 30, 2015 at 1:14

6 Answers 6

5

Use numpy.where. Optionally, use exponential notation for floating point numbers.

import numpy as np

def f(x, d, h, L):
    return np.where(x < d, h*(x/d), (L - x)/(L - d))

x = np.linspace(0,10,1000)
h = 5e-3
d = 16e-2
L = 64.52e-2

func = f(x, d, h, L)
Sign up to request clarification or add additional context in comments.

Comments

4

You're focusing on the conjunction of the clauses, but it's the clauses themselves. You probably want here something like:

if numpy.all(0 <= x) and numpy.all(x < d):
    ...

See the docs for numpy.all.

3 Comments

A possible alternative is numpy.all((0 <= x) & (x < d)):, but for readability reasons, I would not recommend that.
@Evert Thanks, though I actually think that the version in the answer benefits from short circuiting, while this doesn't, no?
Given x and the other parameters these all tests return False, meaning the f just returns 0..
1

I was able to solve my problem by defining x as an array an creating a cycle for evaluating every x individually, not sure if it's the most efficient way of doing it but I'm only working with 1000 iterations so it works well, here's what I did:

def f(a,d,h,L):
ans2=[]
for i in range(1000):
    if (0.<=a[i]) & (a[i]<d):
        ans=x[i]*(h/d)
        ans2.append(ans)
    elif ((d<=a[i]) & (a[i]<=L)):
        ans=h*((L-a[i])/(L-d))
        ans2.append(ans)
return ans2
L=64.52*10**(-2)
x=np.linspace(0,L,1000)
h=5*10**(-3)
d=16*10**(-2)
plot.plot(x,f(x,d,h,L))

Hope it solves somebody else's problem as well, and if it can be optimized to have be faster, I'd love to learn how.

Comments

0

The error is related to the fact that an array contains more than value. For instance a < 0 where a = 1 has a definitive truth value (false). However, what if a is an array. eg [-1, 0, 1], some elements are less than zero and some are greater than or equal to zero. So what what should the truth value be? To be able to create a truth value you have to specify if you want all the values to be less than zero, or for at least one value to be less than zero (any value).

Since mathematical operators on numpy arrays return arrays themselves we can call all or any on those arrays to see if all or at least one value is truthful. You would rewrite your if statement as:

if (0 <= x).all() and (x < d).all():
    ...
# alternatively
if 0 <= x.min() and x.max() < d:
    ...

Comments

0

Others have answered assuming that you want to apply one calculation or other depending on whether all/any values of x meet the respective conditions. I'll make a different assumption - that you want to apply f to each element of x individually.

Applied element by element I get:

In [226]: x=np.linspace(0,1,20)

In [227]: [f(z,d,h,L) for z in x]
Out[227]: 
[0.0,
 0.0016447368421052631,
 0.0032894736842105261,
 0.0049342105263157892,
 0.89586497157981526,
 0.78739098364212268,
 0.6789169957044302,
 0.57044300776673762,
 0.46196901982904509,
 0.35349503189135251,
 0.24502104395365998,
 0.13654705601596731,
 0.028073068078274897,
 0.0,
 0.0,
 0.0,
 0.0,
 0.0,
 0.0,
 0.0]

The vectorized equivalent:

In [238]: I = (0<=x) & (x<d)
In [239]: J=(d<=x) & (x<=L)

In [240]: out=np.zeros_like(x)
In [241]: out[I]=h*(x[I]/d)
In [242]: out[J]=(L-x[J])/(L-d)

In [243]: out
Out[243]: 
array([ 0.        ,  0.00164474,  0.00328947,  0.00493421,  0.89586497,
        0.78739098,  0.678917  ,  0.57044301,  0.46196902,  0.35349503,
        0.24502104,  0.13654706,  0.02807307,  0.        ,  0.        ,
        0.        ,  0.        ,  0.        ,  0.        ,  0.        ])

I'll let you package that as a function.


With the parameters as given (including the full x), np.all(I) and np.all(J) both are False, meaning f would return 0.0 if applied to x as a whole.


def f(x, d, h, L):
   I = (0<=x) & (x<d)
   J=(d<=x) & (x<=L)
   out=np.zeros_like(x)
   out[I]=h*(x[I]/d)
   out[J]=(L-x[J])/(L-d)
   return out

2 Comments

Hi. your answer is more like what I'm looking for, however, how can I make this into a function of x? I'm trying to make an x vs. y plot which should look like a triangle with the left side steeper than the right one, height h, distance from zero to L and d is the distance along x to the point where y=h
I added the function version.
0
def f(x,d,h,L):
    ans=0.
    if ((0.<=x) & (x<d)):
        ans=h*(x/d)
    elif ((d<=x) & (x<=L)):
        ans=((L-x)/(L-d))
    return ans

#A ajouter
f_vec = numpy.vectorize(f)
#et c'est tout^^

x=np.linspace(0,10,1000)
h=5*10**(-3)
d=16*10**(-2)
L=64.52*10**(-2)
func=f_vec(x,d,h,L) #ici il faut tout de même ajouter _vec

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.