0

Starting from the following Maxima code taken from here

/* piecewise function definition */
itvs: [[x<0],[x>=0,x<1], [x>=1]]; /* intervals */
pfun:  [ a,    x^2+b,      c*x  ]; /* local functions */

/* piecewise function constructor */
f:0$
for i: 1 thru 3 do f:f+charfun(apply("and",itvs[i]))*pfun[i]$
f;

/* differentiation of piecewise function */
gradef(charfun(dummy),0)$
diff(f,x);

I'd like to make a function able to take 2 arguments like itvsand pfun and return a piecewise function like f, but I was not able to do it because of errors due to evaluation of symbols. For example in the following try I get the error "incorrect syntax: itvs is not an infix operator":

define(pfc(itvs,pfun),(
    f:0,
    for i: 1 thru length(itvs) do f:f+charfun("and" itvs[i])*pfun[i],
    f
));

How can I define such a function? The documentation I found is very concise and could not help me, is there some less known documentation about this subject?

EDIT

An alternative format of input argument, maybe simpler and more flexible, could be:

/* piecewise function definition */
pfd: [
    [a,     x<0],
    [x^2+b, x>=0 and x<1],
    [c*x,   x>=1]
]; 

Writing a function constructor with this argument might be simpler.

FOLLOW UP

If you don't actually need a piecewise function since a piecewise expression is enough (as -- I discovered later -- in my case), writing a piecewise expression constructor (using the alternative format of input argument) becomes straightforward:

/* pec=piecewise expression constructor */
/* argument is an array of [expression,interval] couples */
pec(x) := sum(x[i][1]*charfun(x[i][2]), i,1,length(x));

f: pec( [[(1+x)/2, x>=-1 and x<1],[3, x<-1 or x>=1]] )

(f)   3*charfun(x<-1 or x>=1)+((x+1)*charfun(x>=-1 and x<1))/2
Community
  • 1
  • 1
mmj
  • 5,514
  • 2
  • 44
  • 51

2 Answers2

2

Couple of things. (1) Instead of charfun("and" itvs[i]) you want charfun(apply("and", itvs[i])). (2) Instead of pfc(itvs,pfun) you want pfc(x). Also (3) probably you want to make f a local variable.

I think this might work:

define(pfc(x), block([f:0],
    for i: 1 thru length(itvs)
        do f:f+charfun(apply("and", itvs[i]))*pfun[i],
    f));
Robert Dodier
  • 16,905
  • 2
  • 31
  • 48
  • This works, but not in the sense I wanted. Infact I'd like such function to be a constructor, in the sense that the piecewise (mathematic) function returned should be "defined" by the arguments I pass to `pfc` function. Each time I pass different arguments a different piecewise (mathematic) function should be returned. – mmj Mar 01 '16 at 23:39
  • @mmj OK. I'll put a separate answer to address that. – Robert Dodier Mar 02 '16 at 06:26
2

OP indicates that they want pfc to construct a piecewise function. Here is an attempt:

pfc (itvs, pfun) := block ([body],
    body : sum (charfun (apply ("and", itvs[i]))*pfun[i], i, 1, length(itvs)),
    buildq ([body], lambda ([x], body)));

Now pfc takes intervals and expressions and constructs an unnamed function of one argument. It's assumed the argument is named x; I guess if one wanted to make this a little more complicated, one could specify a different variable as an argument for pfc and make it another variable for buildq, e.g. buildq([body, var], lambda([var], body).

Robert Dodier
  • 16,905
  • 2
  • 31
  • 48
  • It works, thanks! Changing the format of argument (as in my question EDIT) `pfc` becomes even simpler: `pfc (x) := buildq ([body:sum( x[i][1]*charfun(x[i][2]), i, 1, length(x))], lambda ([x], body));`. You might want to add this simpler version to your answer to give it more visibility. – mmj Mar 02 '16 at 11:36