You can use sympy's lambdify function to generate the numpy piecewise function. This is a simpler example but shows the general idea:

In [15]: from sympy import symbols, Piecewise                                                                                               

In [16]: x, a = symbols('x, a')                                                                                                   

In [17]: expr = Piecewise((x, x>a), (0, True))                                                                                    

In [18]: expr                                                                                                                     
Out[18]: 
⎧x  for a < x
⎨            
⎩0  otherwise

In [19]: from sympy import lambdify                                                                                               

In [20]: fun = lambdify((x, a), expr)                                                                                             

In [21]: fun([1, 3], [4, 2])                                                                                                      
Out[21]: array([0., 3.])

In [22]: import inspect                                                                                                           

In [23]: print(inspect.getsource(fun))                                                                                            
def _lambdifygenerated(x, a):
    return (select([less(a, x),True], [x,0], default=nan))
Answer from Oscar Benjamin on Stack Overflow
🌐
NumPy
numpy.org › doc › stable › reference › generated › numpy.piecewise.html
numpy.piecewise — NumPy v2.4 Manual
>>> np.piecewise(x, [x < 0, x >= 0], [lambda x: -x, lambda x: x]) array([2.5, 1.5, 0.5, 0.5, 1.5, 2.5]) Apply the same function to a scalar value.
🌐
NumPy
numpy.org › devdocs › reference › generated › numpy.piecewise.html
numpy.piecewise — NumPy v2.5.dev0 Manual
Define the signum function, which is -1 for x < 0 and +1 for x >= 0. >>> x = np.linspace(-2.5, 2.5, 6) >>> np.piecewise(x, [x < 0, x >= 0], [-1, 1]) array([-1., -1., -1., 1., 1., 1.])
🌐
NumPy
numpy.org › doc › 2.1 › reference › generated › numpy.piecewise.html
numpy.piecewise — NumPy v2.1 Manual
>>> np.piecewise(x, [x < 0, x >= 0], [lambda x: -x, lambda x: x]) array([2.5, 1.5, 0.5, 0.5, 1.5, 2.5]) Apply the same function to a scalar value.
🌐
Medium
medium.com › @amit25173 › understanding-numpy-piecewise-with-examples-53b4fc9b8dcf
Understanding numpy.piecewise with Examples | by Amit Yadav | Medium
February 8, 2025 - You’ve probably written if-elif-else conditions in Python before, right? Something like this: def custom_function(x): if x < 3: return x**2 else: return 3*x + 1 · Now, imagine you have a NumPy array and need to apply different functions based on conditions. Writing a loop would be slow and ugly. That’s where numpy.piecewise comes in.
🌐
w3resource
w3resource.com › numpy › functional-programming › piecewise.php
NumPy Functional programming: piecewise() function - w3resource
Apply the same function to a scalar value. >>> import numpy as np >>> x = np.linspace(-3.5, 3.5, 5) >>> y = -6 >>> np.piecewise(y, [y < 0, y >= 0], [lambda x: -x, lambda x: x]) Output: array(6) Python - NumPy Code Editor: Previous: frompyfunc() function Next: NumPy Home  ·
🌐
Python Pool
pythonpool.com › home › blog › all about numpy piecewise function
All about Numpy Piecewise Function - Python Pool
June 8, 2021 - Python's Numpy piecewise function is used to define sub functions for different intervals depending on the input value given to the function.
🌐
Sketchy thoughts
sfalsharif.wordpress.com › 2009 › 12 › 18 › piecwise-function-definitions-in-numpy
Piecewise function definitions in NumPy | Sketchy thoughts
March 28, 2010 - The basic format of the piecewise statement, ignoring optional arguments, is numpy.piecewise(x, condlist, funclist) , where x is a NumPy ndarray, condlist is the list of boolean arrays upon which the piecwise function defenition depends, and funclist is a list of functions corresponding to each of the boolean conditons.
🌐
NumPy
numpy.org › doc › 1.23 › reference › generated › numpy.piecewise.html
numpy.piecewise — NumPy v1.23 Manual
Define the sigma function, which is -1 for x < 0 and +1 for x >= 0. >>> x = np.linspace(-2.5, 2.5, 6) >>> np.piecewise(x, [x < 0, x >= 0], [-1, 1]) array([-1., -1., -1., 1., 1., 1.])
🌐
NumPy
numpy.org › doc › 2.2 › reference › generated › numpy.piecewise.html
numpy.piecewise — NumPy v2.2 Manual
>>> np.piecewise(x, [x < 0, x >= 0], [lambda x: -x, lambda x: x]) array([2.5, 1.5, 0.5, 0.5, 1.5, 2.5]) Apply the same function to a scalar value.
Find elsewhere
Top answer
1 of 2
1

You can use sympy's lambdify function to generate the numpy piecewise function. This is a simpler example but shows the general idea:

In [15]: from sympy import symbols, Piecewise                                                                                               

In [16]: x, a = symbols('x, a')                                                                                                   

In [17]: expr = Piecewise((x, x>a), (0, True))                                                                                    

In [18]: expr                                                                                                                     
Out[18]: 
⎧x  for a < x
⎨            
⎩0  otherwise

In [19]: from sympy import lambdify                                                                                               

In [20]: fun = lambdify((x, a), expr)                                                                                             

In [21]: fun([1, 3], [4, 2])                                                                                                      
Out[21]: array([0., 3.])

In [22]: import inspect                                                                                                           

In [23]: print(inspect.getsource(fun))                                                                                            
def _lambdifygenerated(x, a):
    return (select([less(a, x),True], [x,0], default=nan))
2 of 2
1

Sorry about the length of this answer, but I think you need to see the full debugging process. I had to look at the tracebacks and test small pieces of your code to identify the exact problem. I've seen a lot of the numpy ambiguity error, but not this sympy relational error.

===

Lets look at the whole traceback, not just one line of it. At the very least we need to identify which line of your code is producing the problem.

In [4]: expr = np.piecewise((0, x-a <=  -2*h), ((1/6)*(2*h+(x-a))**3, -2*h<=x-a<
   ...: =-h), (2*h**3/3-0.5*(x-a)**2*(2*h+(x-a)), -h<= x-a<= 0), (2*(h**3/3)-0.5
   ...: *(x-a)**2*(2*h+(x-a)), 0<=x-a<=2*h), ((1/6)*(2*h-(x-a))**3, h<=x-a<=2*h)
   ...: , (0, x-a<=2*h))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-893bb4b36321> in <module>
----> 1 expr = np.piecewise((0, x-a <=  -2*h), ((1/6)*(2*h+(x-a))**3, -2*h<=x-a<=-h), (2*h**3/3-0.5*(x-a)**2*(2*h+(x-a)), -h<= x-a<= 0), (2*(h**3/3)-0.5*(x-a)**2*(2*h+(x-a)), 0<=x-a<=2*h), ((1/6)*(2*h-(x-a))**3, h<=x-a<=2*h), (0, x-a<=2*h))

/usr/local/lib/python3.8/dist-packages/sympy/core/relational.py in __nonzero__(self)
    382 
    383     def __nonzero__(self):
--> 384         raise TypeError("cannot determine truth value of Relational")
    385 
    386     __bool__ = __nonzero__

TypeError: cannot determine truth value of Relational

While np.piecewise is a numpy function, because x is a sympy.Symbol, the equations are sympy expressions. numpy and sympy are not well integrated. Somethings work, many others don't.

Did you try a small expression? Good programming practice is to start with small pieces, making sure those work first.

Let's try something smaller:

In [8]: expr = np.piecewise((0, x-a <=  -2*h),
   ...:  ((1/6)*(2*h+(x-a))**3, -2*h<=x-a<=-h))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-37ff62e49efb> in <module>
      1 expr = np.piecewise((0, x-a <=  -2*h),
----> 2  ((1/6)*(2*h+(x-a))**3, -2*h<=x-a<=-h))

/usr/local/lib/python3.8/dist-packages/sympy/core/relational.py in __nonzero__(self)
    382 
    383     def __nonzero__(self):
--> 384         raise TypeError("cannot determine truth value of Relational")
    385 
    386     __bool__ = __nonzero__

TypeError: cannot determine truth value of Relational

and smaller pieces:

In [10]: (0, x-a <=  -2*h)
Out[10]: (0, x + 1 ≤ -1.0)

In [11]: ((1/6)*(2*h+(x-a))**3, -2*h<=x-a<=-h)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-11-7bd9f95d077d> in <module>
----> 1 ((1/6)*(2*h+(x-a))**3, -2*h<=x-a<=-h)

/usr/local/lib/python3.8/dist-packages/sympy/core/relational.py in __nonzero__(self)
    382 
    383     def __nonzero__(self):
--> 384         raise TypeError("cannot determine truth value of Relational")
    385 
    386     __bool__ = __nonzero__

TypeError: cannot determine truth value of Relational

In [12]: (1/6)*(2*h+(x-a))**3
Out[12]: 
                            3
1.33333333333333⋅(0.5⋅x + 1) 

But:

In [13]: -2*h<=x-a<=-h
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-13-5ffb419cd443> in <module>
----> 1 -2*h<=x-a<=-h

/usr/local/lib/python3.8/dist-packages/sympy/core/relational.py in __nonzero__(self)
    382 
    383     def __nonzero__(self):
--> 384         raise TypeError("cannot determine truth value of Relational")
    385 
    386     __bool__ = __nonzero__

TypeError: cannot determine truth value of Relational

Simplify further:

In [14]: 0 < x < 3
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-14-59ba4ce00627> in <module>
----> 1 0 < x < 3

/usr/local/lib/python3.8/dist-packages/sympy/core/relational.py in __nonzero__(self)
    382 
    383     def __nonzero__(self):
--> 384         raise TypeError("cannot determine truth value of Relational")
    385 
    386     __bool__ = __nonzero__

TypeError: cannot determine truth value of Relational

While a < b < c is allowed for regular Python variables and scalars, it does not work for numpy arrays, and evidently doesn't work for sympy variables either.

So the immediate problem has nothing to do with numpy. You are using invalid sympy expressions!

===

Your basis function reveals an aspect of the same problem. Again we need to look at the FULL traceback, and then test portions to identify the exact problem expression.

In [16]: basis(x, -1,0.5,0)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-16-b328f95b3c79> in <module>
----> 1 basis(x, -1,0.5,0)

<ipython-input-15-c6436540e3f3> in basis(x, a, b, h)
      1 def basis(x,a,b, h):
----> 2     if x <= a-2*h:
      3         return 0;
      4     elif (x<=a-h) or (x >=2*h):
      5         return (1/6)*(2*h+(x-a))**3

/usr/local/lib/python3.8/dist-packages/sympy/core/relational.py in __nonzero__(self)
    382 
    383     def __nonzero__(self):
--> 384         raise TypeError("cannot determine truth value of Relational")
    385 
    386     __bool__ = __nonzero__

TypeError: cannot determine truth value of Relational

This expression is a sympy relational:

In [17]: x <= -1
Out[17]: x ≤ -1

But we can't use such a relational in a Python if statement.

In [18]: if x <= -1: pass
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-18-b56148a48367> in <module>
----> 1 if x <= -1: pass

/usr/local/lib/python3.8/dist-packages/sympy/core/relational.py in __nonzero__(self)
    382 
    383     def __nonzero__(self):
--> 384         raise TypeError("cannot determine truth value of Relational")
    385 
    386     __bool__ = __nonzero__

TypeError: cannot determine truth value of Relational

Python if is simple True/False switch; its argument must evaluate to one or the other. The error is telling us that a sympy.Relational does not work. 0 < x < 1 is variation on that basic Python if (it tests 0<x and x<1 and performs a and).

A variation on this that we often see in numpy (and pandas) is:

In [20]: 0 < np.array([0,1,2])
Out[20]: array([False,  True,  True])

In [21]: 0 < np.array([0,1,2])<1
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-21-bc1039cec1fc> in <module>
----> 1 0 < np.array([0,1,2])<1

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

The numpy expression has multiple True/False values, and can't be used im a Python expression that requires a simple True/False.

edit

Correctly expanding the two sided tests:

In [23]: expr = np.piecewise((0, x-a <=  -2*h),
    ...:  ((1/6)*(2*h+(x-a))**3, (-2*h<=x-a)&(x-a<=-h)),
    ...:  (2*h**3/3-0.5*(x-a)**2*(2*h+(x-a)), (-h<= x-a)&(x-a<= 0)),
    ...:  (2*(h**3/3)-0.5*(x-a)**2*(2*h+(x-a)), (0<=x-a)&(x-a<=2*h)),
    ...:  ((1/6)*(2*h-(x-a))**3, (h<=x-a)&(x-a<=2*h)), (0, x-a<=2*h))

In [24]: expr
Out[24]: 
array([-0.5*(x + 1)**2*(x + 2.0) + 0.0833333333333333,
       -0.5*(x + 1)**2*(x + 2.0) + 0.0833333333333333], dtype=object)

In [26]: p = lambdify((x,), expr)

x is the only sympy symbol in expr.

Looking at the resulting function:

In [27]: print(p.__doc__)
Created with lambdify. Signature:

func(x)

Expression:

[-0.5*(x + 1)**2*(x + 2.0) + 0.0833333333333333  -0.5*(x + 1)**2*(x + 2.0)...

Source code:

def _lambdifygenerated(x):
    return ([-0.5*(x + 1)**2*(x + 2.0) + 0.0833333333333333, -0.5*(x + 1)**2*(x + 2.0) + 0.0833333333333333])
🌐
Datagawker
datagawker.com › home › plotting piecewise functions in python and matplotlib the elegant way
Plotting Piecewise Functions in Python and Matplotlib the Elegant Way - Data Gawker
January 8, 2024 - Regardless of the number of segments (i.e. pieces of functions), we would want to prepare the data on the y-axis in one series (Numpy array) rather than as several different series on the same plot. There are a couple of ways to accomplish this. A simple way of implementing a piecewise function would be to write a Python function with conditional statements inside, and then use Numpy’s vectorize() function to apply the function to a Numpy array.
🌐
ProgramCreek
programcreek.com › python › example › 102171 › numpy.piecewise
Python Examples of numpy.piecewise
GCP: ratings from https://cloud.google.com/compute/docs/disks/performance#ssd-pd-performance AWS: to achieve good performance on EBS, one needs to use an EBS-optimized VM instance, and the smallest VM instance that can be EBS optimized is *.large VM types (e.g., c4.large), those comes with 2 cores. ratings from http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSOptimized.html """ if self._provider == GCP: value = self._iops self._cpu_count = int( numpy.piecewise([value], [[value <= 15000], [ (value > 15000) & (value <= 25000) ], [value > 25000]], [lambda x: 1, lambda x: 16, lambda x: 32])) elif self._provider == AWS: self._cpu_count = 2
🌐
Reddit
reddit.com › r/learnpython › how to do piecewise functions in python?
r/learnpython on Reddit: How to do piecewise functions in python?
December 11, 2015 -

Hi guys,

I'm using numpy and plotly to graph piecewise functions. I previously used matlab. I need help to essentially translate matlab piecewise functions into something I can use in python. Here's what I had in matlab:

Constant1 = 5;
Constant2 = 10;

Formula1 = @(x,y) x*Constant1;
Formula2 = @(x,y) x*Constant2;

MainFormula = @(x,y) [Formula1(x,y)*(y<=5) + Formula2(x,y)*(y>5)];

So what this would essentially do is make 'MainFormula' equal to 'Formula1' for all values of y less than or equal to 5, and it would make 'MainFormula' equal to 'Formula2' for all values of y greater than 5.

I would really appreciate any help with this.

Thanks

Top answer
1 of 2
2
def pwise (x): if x < 0: result='less than' elif x==0: result = 'equal' ... #more elif followed by else return result
2 of 2
1
The direct translation would be this: constant1 = 5 constant2 = 10 formula1 = lambda x: x*constant1 formula2 = lambda x: x*constant2 main_formula = lambda x, y: formula1(x)*(y <= 5) + formula2(x)*(y > 5) Note that I am using python style conventions. All of your variable names could be used as-is, but for style reasons lowercase variable names separated by _ are usually used. Same with the spaces I added in x,y, y<=5, and y>5, they aren't required, just recommended for readability reasons. These style recommendations are found in pep8 , and can be checked automatically by a program of the same name. Further, you could do, for example lambda x, y: x*constant1, it doesn't hurt anything, but it is unnecessary and I think it makes the code less clear. However, assuming you are using numpy arrays (which you should be), it would be easier to do this: def formula(x, y, const1=5, const2=10, sep=5): x1 = x.copy() x1[y <= sep] *= const1 x1[y > sep] *= const2 return x You can then use formula in the exact same way as MainFormula. It will default to using 5 for the first constant and 10 for the second, and 5 for the value of y to use to differentiate the two, but you can change that by passing different values to the function, such as formula(x, y, sep=200), or formula(x, y, 50, 100). If you don't care about losing your original x, you can simplify this further: def formula(x, y, const1=5, const2=10, sep=5): x[y <= sep] *= const1 x[y > sep] *= const2 In this case, whatever array you pass to formula as x will be changed in-place, so nothing is returned. This will be considerably faster than any of the previous approaches when dealing with large datasets. You could even simplify this further by doing the y calculation in the function call if you wanted: def formula(x, isy, const1=5, const2=10): x[isy] *= const1 x[~isy] *= const2 And then call it like this: formula(x, y<=5) The final approach you could do is to handle x separately: def formula(isy, const1=5, const2=10): return isy*const1 + ~isy*const2 or: lambda isy: isy*constant1 + ~isy*constant2 And then call it like this: x1 = x*isy(y <=5)
🌐
NumPy
numpy.org › doc › 2.0 › reference › generated › numpy.piecewise.html
numpy.piecewise — NumPy v2.0 Manual
>>> np.piecewise(x, [x < 0, x >= 0], [lambda x: -x, lambda x: x]) array([2.5, 1.5, 0.5, 0.5, 1.5, 2.5]) Apply the same function to a scalar value.
🌐
SciPy
docs.scipy.org › doc › › numpy-1.8.1 › reference › generated › numpy.piecewise.html
numpy.piecewise — NumPy v1.8 Manual
Define the sigma function, which is -1 for x < 0 and +1 for x >= 0. >>> x = np.linspace(-2.5, 2.5, 6) >>> np.piecewise(x, [x < 0, x >= 0], [-1, 1]) array([-1., -1., -1., 1., 1., 1.])
🌐
University of Texas at Austin
het.as.utexas.edu › HET › Software › Numpy › reference › generated › numpy.piecewise.html
numpy.piecewise — NumPy v1.9 Manual
Define the sigma function, which is -1 for x < 0 and +1 for x >= 0. >>> x = np.linspace(-2.5, 2.5, 6) >>> np.piecewise(x, [x < 0, x >= 0], [-1, 1]) array([-1., -1., -1., 1., 1., 1.])
🌐
Mabouali
mabouali.com › 2024 › 02 › 04 › piecewise-linear-functions-part-i
Piecewise-Linear Functions: Part I – Moe’s Homepage
But we already see that things are not always that easy. So, another way of implementing this function is: import numpy as np def my_piecewise_function(x): if x < 0: return -x else: return x
Top answer
1 of 1
12

In general, numpy arrays are very good at doing sensible things when you just write the code as if they were just numbers. Chaining comparisons is one of the rare exceptions. The error you're seeing is essentially this (obfuscated a bit by piecewise internals and ipython error formatting):

>>> a = np.array([1, 2, 3])
>>> 1.5 < a
array([False,  True,  True], dtype=bool)
>>> 
>>> 1.5 < a < 2.5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> 
>>> (1.5 < a) & (a < 2.5)
array([False,  True, False], dtype=bool)
>>> 

You can alternatively use np.logical_and, but bitwise & (not and) works just fine here.

As far as plotting is concerned, numpy itself doesn't do any. Here's an example with matplotlib:

>>> import numpy as np
>>> def piecew(x):
...   conds = [x < 0, (x > 0) & (x < 1), (x > 1) & (x < 2), x > 2]
...   funcs = [lambda x: x+1, lambda x: 1, 
...            lambda x: -x + 2., lambda x: (x-2)**2]
...   return np.piecewise(x, conds, funcs)
>>>
>>> import matplotlib.pyplot as plt
>>> xx = np.linspace(-0.5, 3.1, 100)
>>> plt.plot(xx, piecew(xx))
>>> plt.show() # or plt.savefig('foo.eps')

Notice that piecewise is a capricious beast. In particular, it needs its x argument to be an array, and won't even try converting it if it isn't (in numpy parlance: x needs to be an ndarray, not an array_like):

>>> piecew(2.1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in piecew
  File "/home/br/.local/lib/python2.7/site-packages/numpy/lib/function_base.py", line 690, in piecewise
    "function list and condition list must be the same")
ValueError: function list and condition list must be the same
>>> 
>>> piecew(np.asarray([2.1]))
array([ 0.01])
🌐
GitHub
github.com › numpy › numpy › pull › 5187
Enhance piecewise to allow functions to have arbitrary number of input arguments by pbrod · Pull Request #5187 · numpy/numpy
Made piecewise function simpler and more general. The new piecewise function allows functions of the type f(x0, x1,.. ,xn) i.e. to have arbitrary number of input arguments that are evaluated condit...
Author   numpy