Piecewise functions.

Hi all, this is probably an already discussed problem, but I've not been able to find a solution even after googling a lot. I've a piecewise defined function: / | f1(x) if x <= a f(x) = | | f2(x) if x > a \ where f1 and f2 are not defined outside the above range. How can I define such a function in Python in order to apply (map) it to an array ranging from values smaller to values bigger than a? Thanks, Andrea.

On Thu, 22 Sep 2005, Andrea Riciputi apparently wrote:
this is probably an already discussed problem, but I've not been able to find a solution even after googling a lot.
I've a piecewise defined function:
/ | f1(x) if x <= a f(x) = | | f2(x) if x > a \
where f1 and f2 are not defined outside the above range. How can I define such a function in Python in order to apply (map) it to an array ranging from values smaller to values bigger than a?
I suspect I do not understand your question. But perhaps you want this: def f(x): return x<=a and f1(x) or f2(x) fwiw, Alan

I've already tried something like this, but it doesn't work since f1 and f2 return not valid values outside the range over they are defined. Perhaps an example could clarify; suppose that f1(x) = 1./ sqrt(1 - x**2) for x <= 1, and f2(x) = 1./sqrt(x**2 - 1) for x > 1. Your suggestion, as the other I've tried, fails with a "OverflowError: math range error". Any helps? Andrea. On Sep 22, 2005, at 9:33 PM, Alan G Isaac wrote:
On Thu, 22 Sep 2005, Andrea Riciputi apparently wrote:
this is probably an already discussed problem, but I've not been able to find a solution even after googling a lot.
I've a piecewise defined function:
/ | f1(x) if x <= a f(x) = | | f2(x) if x > a \
where f1 and f2 are not defined outside the above range. How can I define such a function in Python in order to apply (map) it to an array ranging from values smaller to values bigger than a?
I suspect I do not understand your question. But perhaps you want this:
def f(x): return x<=a and f1(x) or f2(x)
fwiw, Alan
------------------------------------------------------- SF.Net email is sponsored by: Tame your development challenges with Apache's Geronimo App Server. Download it for free - -and be entered to win a 42" plasma tv or your very own Sony(tm)PSP. Click here to play: http://sourceforge.net/ geronimo.php _______________________________________________ Numpy-discussion mailing list Numpy-discussion@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/numpy-discussion

On Thu, 22 Sep 2005, Andrea Riciputi apparently wrote:
I've already tried something like this, but it doesn't work since f1 and f2 return not valid values outside the range over they are defined. Perhaps an example could clarify; suppose that f1(x) = 1./ sqrt(1 - x**2) for x <= 1, and f2(x) = 1./sqrt(x**2 - 1) for x > 1.
Your suggestion, as the other I've tried, fails with a "OverflowError: math range error".
If you do it as I suggested, they should not I believe be evaluated outside of their range. So your function must be generating an overflow error within this range.
import math import random def f1(x): return math.sqrt(1-x**2) ... def f2(x): return 1./math.sqrt(x**2-1) ... def f(x): return x<=1 and f1(x) or f2(x) ... d = [random.uniform(0,2) for i in range(20)] fd = [f(x) for x in d]
Works fine. Cheers, Alan Isaac

Andrea Riciputi wrote:
On Sep 22, 2005, at 9:33 PM, Alan G Isaac wrote:
def f(x): return x<=a and f1(x) or f2(x)
I've already tried something like this, but it doesn't work
I wish people would stop suggesting the 'a and b or c' trick, because it DOESN'T WORK except in special circumstances (i.e. when you can be sure that b is never false). What you want is: def f(x): if x <= a: return f1(x) else: return f2(x) -- Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg.ewing@canterbury.ac.nz +--------------------------------------+

On Sep 23, 2005, at 5:23 AM, Greg Ewing wrote:
I wish people would stop suggesting the 'a and b or c' trick, because it DOESN'T WORK except in special circumstances (i.e. when you can be sure that b is never false).
What you want is:
def f(x): if x <= a: return f1(x) else: return f2(x)
It doesn't work either. As I've already explained x is an array containing values both above and below a! What I really need is a way to prevent f1 and f2 from acting on those values of the 'x' array for which the functions are not defined. Any other hints? Andrea.

On Fri, 23 Sep 2005, Andrea Riciputi apparently wrote:
What I really need is a way to prevent f1 and f2 from acting on those values of the 'x' array for which the functions are not defined.
The example I posted works with an array, which I called d. If you must feed the array to the function, just move the list comprehension inside of f. Of course, you may find list comprehension too slow for your application. Alan Isaac

On Thu, 22 Sep 2005 17:44:59 +0200 Andrea Riciputi <ariciputi@pito.com> wrote:
Hi all, this is probably an already discussed problem, but I've not been able to find a solution even after googling a lot.
I've a piecewise defined function:
/ | f1(x) if x <= a f(x) = | | f2(x) if x > a \
where f1 and f2 are not defined outside the above range. How can I define such a function in Python in order to apply (map) it to an array ranging from values smaller to values bigger than a?
This does maybe what you want: from scipy import * def f(x): """Approximative implementation of: -1/(x-pi) for x < pi 1/(x-pi) for x > pi """ result = zeros(len(x), x.typecode()) i = argmin(abs(x-pi)) # you may have to tweak i here, because it may be off by 1 result[:i+1] = -1/(x[:i+1]-pi) result[i+1:] = 1/(x[i+1:]-pi) return result x = arange(0, 10, 1, Float) print f(x) print abs(1/(x-pi)) Gerard

Here is a slightly different solution, that is easier to my eyes and that can handle arguments in arbitrary order. It requires numarray (as it uses array indexing). If I understand well it should work woth the new scipy-core (Numeric3), but I haven't it compiled here. Obs: Probably f2 implementation is faster than f1. Best, Paulo ---- from numarray import * def f1(x): """Implementation of: -1/(x-pi) for x < pi 1/(x-pi) for x > pi """ result = zeros(len(x), x.typecode()) # First solution, probably slower, but clear. result[x < pi] = -1/(x[x < pi]-pi) result[x > pi] = 1/(x[x > pi]-pi) return result def f2(x): """Second Iplementation of: -1/(x-pi) for x < pi 1/(x-pi) for x > pi """ result = zeros(len(x), x.typecode()) # Second solution, probably faster as where returns only # the correct indexes. small = where(x < pi) big = where(x > pi) result[small] = -1/(x[small]-pi) result[big] = 1/(x[big]-pi) return result x = arange(0, 10, 1, Float) print f1(x) print f2(x) print abs(1/(x-pi)) # It uses the default value for pi. api = array([pi]) print f1(api) print f2(api)

On Sep 23, 2005, at 1:24 PM, Paulo J. S. Silva wrote:
Here is a slightly different solution, that is easier to my eyes and that can handle arguments in arbitrary order.
It requires numarray (as it uses array indexing). If I understand well
[snip]
Thanks, it is exactly what I'm looking for. Unfortunately, I'm using Numeric, and I won't switch to numarray only for these feature; small arrays are too frequent in my applications. Anyway the method proposed by Gerard Vermeulen works too (thanks a lot Gerard!), and I'll stay with it, at least until Numeric3 won't be ready for the root-mean-square users. ;-) Cheers, Andrea.

Andrea Riciputi wrote:
Hi all, this is probably an already discussed problem, but I've not been able to find a solution even after googling a lot.
I've a piecewise defined function:
/ | f1(x) if x <= a f(x) = | | f2(x) if x > a \
where f1 and f2 are not defined outside the above range. How can I define such a function in Python in order to apply (map) it to an array ranging from values smaller to values bigger than a?
This is not a trivial problem in current versions of Numeric. What are you using, Numeric, numarray? In new scipy core (which replaces Numeric) and, I think, in numarray, you could say gta = x>a lea = x<=a y = x.copy() y[gta] = f2(x[gta]) y[lea] = f1(x[lea]) I've also just written a piecewise function for the new scipy core so you could write y = piecewise(x, x<=a, [f1,f2]) -Travis Oliphant

On Sep 26, 2005, at 7:43 PM, Travis Oliphant wrote:
This is not a trivial problem in current versions of Numeric.
What are you using, Numeric, numarray?
In new scipy core (which replaces Numeric) and, I think, in numarray, you could say
gta = x>a lea = x<=a y = x.copy() y[gta] = f2(x[gta]) y[lea] = f1(x[lea])
I've also just written a piecewise function for the new scipy core so you could write
y = piecewise(x, x<=a, [f1,f2])
-Travis Oliphant
Yes I'm using Numeric, and in the short to middle term I'll stay with it. Anyway I'm aware of the effort you are spending in putting together a Numeric replacement, and I'll look forward for a stable release of it. In the meanwhile I'll use the tricks already suggested here. Thanks again for your effort, Andrea.
participants (6)
-
Alan G Isaac
-
Andrea Riciputi
-
Gerard Vermeulen
-
Greg Ewing
-
Paulo J. S. Silva
-
Travis Oliphant