Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Analog of Maple "unapply" or Mathematica "Function" in Maxima

Tags:

maxima

In Wolfram Mathematica we can define an operator acting on a function (i.e. function that returns function) e.g. as for the operator of multiplication by the first argument acting on a functions of two arguments in the example below

X[f_] = Function[{x, y}, x*f[x, y]]

Then we can apply this operators to any function with any 2 arguments

In[2]:= X[g][z, t]

Out[2]= z g[z, t]

There is a similar construction in Maple

X:=proc(f) option operator; local x,y;

unapply(x*f(x,y),x,y)

end;

with the similar mode of application

> X(g)(z,t);

  z g(z, t)

In Maxima I tried this

X(f):=lambda([x,y],x*f(x,y));

but when trying to apply it I get

(%i5) X(g)(z,t)

(%o5) z*f(z,t)

so, it looks like f is not recognized as an argument of function X when I used lambda.

Is there any way to solve this problem?

In case of Maple and Mathematica this type of operators helps a lot to manipulate with linear differential operators

like image 204
Truffaldino Avatar asked Sep 14 '25 20:09

Truffaldino


1 Answers

Maxima lambda doesn't evaluate any of the expressions inside the body of it, so f is not evaluated (to g). That's the behavior you are seeing. The motivation for it that I can see is that the lambda body might contain expressions which don't have the expected effect until some variables have values, e.g. length, for ..., print, etc.

You can get the expected behavior by substituting into the body. Here are two ways to do that. The first uses the function subst which I think is maybe the most obvious.

(%i1) X(f):= subst ('f = f, lambda([x,y],x*f(x,y)));
(%o1)   X(f) := subst('f = f, lambda([x, y], x f(x, y)))
(%i2) X(g);
(%o2)               lambda([x, y], x g(x, y))
(%i3) X(g)(z, t);
(%o3)                       z g(z, t)

The second uses the function buildq which is effectively a substitution function which quotes (does not evaluate) the expression into which something is substituted.

(%i4) X(f) := buildq ([f], lambda ([x, y], x*f(x, y)));
(%o4)    X(f) := buildq([f], lambda([x, y], x f(x, y)))
(%i5) X(g);
(%o5)               lambda([x, y], x g(x, y))
(%i6) X(g)(z, t);
(%o6)                       z g(z, t)

Finally, if you are interested in creating lambda expressions using evaluated expressions more often, you could create your own kind of lambda for that. I'll call it evlambda here.

(%i11) evlambda (a, b) := apply (lambda, [a, b]);
(%o11)         evlambda(a, b) := apply(lambda, [a, b])
(%i12) X(f) := evlambda ([x, y], x*f(x, y));
(%o12)           X(f) := evlambda([x, y], x f(x, y))
(%i13) X(g);
(%o13)                lambda([x, y], x g(x, y))
(%i14) X(g)(z, t);
(%o14)                        z g(z, t)

The key here is that evlambda is defined as an ordinary function, so its arguments are evaluated. So by the time lambda is applied, b has been evaluated so it contains g.

Note that this evlambda won't do anything useful with length, for ..., and print, which is to be expected.

(%i15) foo : evlambda ([l], 1 + length(l));
length: argument cannot be a symbol; found l
 -- an error. To debug this try: debugmode(true);
(%i16) bar : evlambda ([n], for i thru n do print (i));
Unable to evaluate predicate 1 > n
 -- an error. To debug this try: debugmode(true);
(%i17) baz : evlambda ([x], print (x));
x
(%o17)                    lambda([x], x)
(%i18) baz(5);
(%o18)                           5     

The last one, with print, evaluates print when baz is defined (so x is the output), but then not again when baz(5) is evaluated -- this behavior is to be expected since evlambda evaluates its arguments.

like image 82
Robert Dodier Avatar answered Sep 17 '25 19:09

Robert Dodier