How can I create a piecewise inline function in MATLAB?
Asked Answered
D

4

7

I have a function in MATLAB which takes another function as an argument. I would like to somehow define a piecewise inline function that can be passed in. Is this somehow possible in MATLAB?

Edit: The function I would like to represent is:

f(x) = { 1.0,  0.0 <= x <= 0.5,
         -1.0, 0.5 < x <= 1.0

where 0.0 <= x <= 1.0
Dardani answered 28/4, 2009 at 3:5 Comment(0)
T
12

You really have defined a piecewise function with three break points, i.e., at [0, 0.5, 1]. However, you have not defined the value of the function outside of the breaks. (By the way, I've used the term "break" here, because we are really defining a simple form of spline, a piecewise constant spline. I might also have used the term knot, another common word in the world of splines.)

If you absolutely know that you will never evaluate the function outside of [0,1], then there is no problem. So then just define a piecewise function with ONE break point, at x = 0.5. The simple way to define a piecewise constant function like yours is to use a logical operator. Thus the test (x > 0.5) returns a constant, either 0 or 1. By scaling and translating that result, it is easy to generate a function that does what you wish.

constfun = @(x) (x > 0.5)*2 - 1;

An inline function does a similar thing, but inline functions are VERY slow compared to an anonymous function. I would strongly recommend use of the anonymous form. As a test, try this:

infun = inline('(x > 0.5)*2 - 1','x');
x = 0:.001:1;

tic,y = constfun(x);toc
Elapsed time is 0.002192 seconds.

tic,y = infun(x);toc
Elapsed time is 0.136311 seconds.

Yes, the inline function took wildly more time to execute than did the anonymous form.

A problem with the simple piecewise constant form I've used here is it is difficult to expand to when you have more break points. For example, suppose you wished to define a function that took on three different values depending on what interval the point fell in? While this can be done too with creative use of tests, carefully shifting and scaling them, it can get nasty. For example, how might one define the piecewise function that returns

-1 when x < 0,
2 when 0 <= x < 1,
1 when 1 <= x

One solution is to use a unit Heaviside function. So first, define a basic unit Heaviside function.

H = @(x) (x >= 0);

Our piecewise function is now derived from H(x).

P = @(x) -1 + H(x)*3 + H(x-1)*(-1);

See that there are three pieces to P(x). The first term is what happens for x below the first break point. Then we add in a piece that takes effect above zero. Finally, the third piece adds in another offset in above x == 1. It is easily enough plotted.

ezplot(P,[-3,3])

More sophisticated splines are easily generated from this beginning. Se that I've called this construct a spline again. Really, this is where we might be leading. In fact, this is where this leads. A spline is a piecewise function, carefully tied together at a list of knots or break points. Splines in particular often have specified orders of continuity, so for example, a cubic spline will be twice differentiable (C2) across the breaks. There are also piecewise cubic functions that are only C1 functions. My point in all of this is I've described a simple beginning point to form any piecewise function. It works quite well for polynomial splines, although there may be a wee bit of mathematics required to choose the coefficients of these functions.

Another way to create this function is as an explicit piecewise polynomial. In MATLAB, we have the little known function mkpp. Try this out...

pp = mkpp([0 .5 1],[1;-1]);

Had you the splines toolbox, then fnplt will plot this directly for you. Assuming that you don't have that TB, do this:

ppfun = @(x) ppval(pp,x);
ezplot(ppfun,[0 1])

Looking back at the mkpp call, it is rather simple after all. The first argument is the list of break points in the curve (as a ROW vector). The second argument is a COLUMN vector, with the piecewise constant values the curve will take on in these two defined intervals between the breaks.

Several years ago I posted another option, piecewise_eval. It can be downloaded from the MATLAB Central file exchange. This is a function that will allow a user to specify a piecewise function purely as a list of break points, along with functional pieces between those breaks. Thus, for a function with a single break at x = 0.5, we would do this:

fun = @(x) piecewise_eval(x,0.5,{1,-1});

See that the third argument provides the value used in each segment, although those pieces need not be purely constant functions. If you wish the function to return perhaps a NaN outside of the interval of interest, this too is easily accomplished.

fun = @(x) piecewise_eval(x,[0 0.5 1],{NaN,1,-1,NaN});

My point in all of this rather lengthy excursion is to understand what a piecewise function is, and several ways to build one in MATLAB.

Touzle answered 28/4, 2009 at 11:13 Comment(1)
Thank you! I do have some experience with interpolation and piecewise polynomials. I didn't know there was a function for making them in Matlab (I'm pretty new to it.), nor had I thought of my piecewise function as a spine with polynomials of degree zero. Thanks for all of this! I should point out that your anonymous function flip flops the values posted in my example, but I understand the logic nonetheless. Thanks!Dardani
M
5

Unfortunately, MATLAB doesn't have a ternary operator which would make this sort of thing easier, but to expand slightly on gnovice's approach, you could create an anonymous function like so:

fh = @(x) ( 2 .* ( x <= 0.5 ) - 1 )

In general, anonymous functions are more powerful than inline function objects, and allow you to create closures etc.

Madelina answered 28/4, 2009 at 6:43 Comment(0)
D
4

If you really want to make an inline function (as opposed to an anonymous function), then the following would probably be the simplest way:

f = inline('2.*(x <= 0.5)-1');

However, as pointed out in the other answers, anonymous functions are more commonly used and are more efficient:

f = @(x) (2.*(x <= 0.5)-1);
Discern answered 28/4, 2009 at 3:59 Comment(0)
R
2

I just had to solve that problem, and I think the easiest thing to do is use anonymous functions. Say that you have a piecewise function:

when x<0    : x^2 + 3x
when 0<=x<=4: e^x
when x>4    : log(x)

I'd first define logical masks for each piecewise region:

PIECE1 = @(x) x<0
PIECE2 = @(x) x>=0 & x<=4
PIECE3 = @(x) x>4

Then I'd put them all together:

f = @(x) PIECE1(x).*(x.^2+3*x) + PIECE2(x).*exp(x) + PIECE3(x).*log(x)

x = -10:.1:10
figure;
plot(x,f(x))
Romina answered 6/11, 2013 at 15:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.