alias for 2nd deriv (25.4.00)

Matthias Kawski

This probably is something old – but I can’t find any help. Is there a way to define aliases for second derivatives? I tried all sorts of variations, of the following...

> restart;                          working w/ MAPLE V r.5 
> alias(wt=diff(w(t),t)): 
> diff(w(t),t); 
                                I, wt 
                                  wt 
 
> alias(utt=diff(u(t),t,t)): 
> diff(u(t),t,t); 
                                2 
                               d 
                               --- u(t) 
                                 2 
                               dt

I can work around this in simple examples as the above, but where I really need it is in some huge formulas involving derivatives of Christoffel symbols (working with my own programs, similar to the tensor-package functionality).

Thus, simple workarounds like using

      map(q->subs(diff(f(x,y,y),x,y,y)=fxyy,q),mylist);

are rather impractical.

Kayll Lake (26.4.00)

This feature is available in GRTensorII via ”autoAlias”.

Please see

http://grtensor.phy.queensu.ca/

Nathan Sokalski (26.4.00)

I believe there is a way to make an alias for the 2nd derivative. The following is an example I made. Hopefully you don’t mind using D instead of diff.

> alias(second=(D@@2)); 
                           I, second 
> f:=x->x^4; 
                          f := x -> x^4 
> second(f)(x); 
                               12x^2

I didn’t really test this with any other functions, but I expect it would work the same as D (other than the fact that it’s the 2nd derivative). And in case you can’t figure it out yourself, second is just the variable name I chose. You could also modify this alias to do the 3rd, 4th, 1000th, or whatever derivative by changing it to alias(second=(D@@3)); , alias(second=(D@@4)); , alias(second=(D@@1000));.

Edgardo S. Cheb-Terrab (26.4.00)

I don’t know how to change the behavior of Maple’s ’alias’ command, but I know how to somehow solve your problem.

First, concerning the display on the screen, in the PDEtools package distributed with Maple 6 (if you use Maple 5 or 4 you could download the versions ODEtools + PDEtools available on the web at http://lie.uwaterloo.ca/PDEtools.htm), there is a command called ’declare’, which is used to declare ”functionality” and change the display of derivatives. For example:

> with(PDEtools):

Now declare u as a function of t, and ’t’ as the ”prime derivative”:

    > declare( u(t), prime=t); 
 
      derivatives with respect to:, t, 
      of functions of one variable will now be displayed with ' 
 
                   u(t), will now be displayed as, u

Let’s see the effect:

    > diff(u(t),t,t) + u(t); 
 
                               u'' + u 
    > lprint(%); 
    diff(diff(u(t),t),t)+u(t)

So:

* you still input diff(u(t),t,t); 
 
* you 'see' derivatives displayed with a prime and u(t) as u 
 
* the output however is really diff(u(t),t,t)

and hence your input and output hasn’t changed but you read things in the screen with ease, as when you write formulas with your hand. For instance, compare this enhanced display for

    > diff(y(t),`$`(t,2))*diff(y(t),t)*y(t)*f(t)-2*diff(y(t),t)^3*t^6 
    > +2*diff(y(t),t)^2*y(t)*diff(g(t),t)+y(t)^5; 
 
                                3  6       2         5 
               y'' y' y f - 2 y'  t  + 2 y'  y g' + y

with its standard output on the screen:

 
      / 2      \ 
      |d       | /d      \               /d      \3  6 
      |--- y(t)| |-- y(t)| y(t) f(t) - 2 |-- y(t)|  t 
      |  2     | \dt     /               \dt     / 
      \dt      / 
 
                 /d      \2      /d      \       5 
             + 2 |-- y(t)|  y(t) |-- g(t)| + y(t) 
                 \dt     /       \dt     /

..after seeing the enhanced one, the redundancy in above is close to intolerable for me.

This ’declare’ command is potentially more helpful with partial derivatives of many-variable functions(for instance derivatives of Christoffel symbols), since it presents the derivatives as ”indexed”, which is what we use to do by hand. For instance:

> macro( G = Gamma(x,y,z) , df = diff);  # macros to simplify input 
> declare(G); 
 
            Gamma(x, y, z), will now be displayed as, Gamma 
 
> df(G,x) + df(G,y)*G; 
 
                      Gamma[x] + Gamma[y] Gamma

Finally, concerning not what you receive as output but what you type as input, if you download this PDEtools and ODEtools libraries from the web address on top, there is also a new command called 'diff_table' which could facilitate your life too, and used in conjunction with ’declare’ give the whole functionality you seem to be looking for. For example, let’s assign to ’T’ the 'diff_table' of Gamma(x,y,z):

    > with(ODEtools): 
 
    > T := diff_table( Gamma(x,y,z) ):

and now try

 
    > T[];       # derivative of "order zero" 
 
                                Gamma

The display above shows just ”Gamma” because of the ’declare’ statement, but what it is behind what you see is actually

    > lprint(%); 
    Gamma(x,y,z)

The thing is that now you enter *any* partial derivative as an indexed object, you receive *the full standard Maple diff expression* and you see the thing with *compact display* on the screen:

    > T[x]; 
                               Gamma[x] 
 
    > lprint(%); 
    diff(Gamma(x,y,z),x) 
 
    > T[x,x,y,y,z]; 
 
                         Gamma[x, x, y, y, z] 
 
    > lprint(%); 
    diff(diff(diff(diff(diff(Gamma(x,y,z),x),x),y),y),z) 
 
    > T[x,y]*T[z] - T[y,z]*T[x] - T[z,x]*T[y]; 
 
      Gamma[x, y] Gamma[z] - Gamma[y, z] Gamma[x] - Gamma[x, z] Gamma[y]

and so on. This 'diff_table' command also frees you of having to state an alias for each partial derivative you want to use and avoids potential collisions between your aliases and other Maple routines.

Hope this combination of ’declare’ and 'diff_table' helps. I use these commands all the time during interactive work and got so used with them that I can’t even imagine going back to the standard Maple input/output.

Roberto Sussman (1.5.00)

I think that the solution to aliasing derivatives provided by Edgardo Chen-Terrab is too cumbersome. Here is an alternative.

I did a small procedure ”difalias” that completely solves this problem. It aliases derivatives as subindices.

I work in General Relativity and I need to manipulate large tensor components full of partial derivatives. I find it very useful to be able to declare all functions and their dependencies (as in REDUCE) and not to have to carry them along.

Kayll Lake implemented the difalias procedure into grtensor but I do not like the way they did it: derivatives are aliased by functions are not !!

Then, from R5 onward (including R6) there is a display bug preventing aliasing of second (or higher) order derivatives. This bug carries on in grtensor implementation of difalias.

Joe Riel showed me how to correct this display bug: you need to erase the ‘print/diff‘ library. He also wrote the code in terms of permutations of indices and up to arbitrary order of derivatives (difalias goes only up to 3rd order derivatives).

If you use R3 or R4 you can download difalias (the code and binaries) from my maple website

http://www.nuclecu.unam.mx/~unamaple/difalias_.html

If you are using R5 or R6 you can generate your own .m file by running the code below:

I hope it works !!

########## code follows ############# 
##################################################### 
###The difalias procedure for R5 
###Roberto A Sussman, December 1994 
###Revised July 1999 (to correct aliasing bug in R5). 
##################################################### 
###Usage: 
###for S=S(t) type difalias(t,S) 
###for S=S(t,x,y,z) type difalias([t,x,y,z], S) 
###for S,U,V depending on t type difalias(t, [S,U,V]) 
###for S,U,V depending on t,x,y,z type difalias([t,x,y,z], ###[S,U,V]) 
##################################################### 
### Works up to 3rd order derivatives 
#################################################################### 
###If used in R5, the instruction `print/diff` := NULL: erases 
###the `print/diff` library and unaliased derivatives look like 
###nested derivatives. 
###If used with R3 or R4, omit all reference to `print/diff` 
###See http://www.nuclecu.unam.mx/~unamaple/difalias_.html 
#################################################################### 
 
  difalias := 
 
  proc(vars,funs) 
  local i,j,k,l,nvar,nfun; 
  ##the following instruction is only necessary in R5 and R6 
  global `print/diff`; 
  option `Copyright (c) 1994 by Roberto A Sussman. All rights reserved.`; 
  ##the following instruction is only necessary in R5 and R6 
  `print/diff` := NULL: 
      if type(vars,name) and type(funs,name) 
       then 
         RETURN(alias(funs = funs(vars),seq( 
         funs[vars $ i] = diff(funs(vars),vars $ i),i = 1 .. 3))) 
       elif type(vars,name) and type(funs,list) 
        then 
         RETURN(alias(seq(funs[i] = funs[i](vars),i = 1 .. nops(funs)),seq(seq( 
 
         funs[i][vars $ j] = diff(funs[i](vars),vars $ j), 
         i = 1 .. nops(funs)),j = 1 .. 3))) 
       elif type(vars,list) and type(funs,name) 
        then 
         RETURN(alias( 
         seq(funs = funs(op(vars)),i = 1 .. nops(vars)), 
         seq(funs[vars[i]] = diff(funs(op(vars)),vars[i]), 
         i = 1 .. nops(vars)),seq(seq( 
         funs[vars[i],vars[j]] =        diff(funs(op(vars)),vars[i],vars[j]), 
 
         i = 1 .. nops(vars)),j = 1 .. nops(vars)), 
         seq(seq(seq(funs[vars[i],vars[j],vars[k]] = 
         diff(funs(op(vars)),vars[i],vars[j],vars[k]), 
         i = 1 .. nops(vars)),j = 1 .. nops(vars)), 
         k=1..nops(vars)) )) 
       elif type(vars,list) and type(funs,list) 
        then 
         RETURN(alias(seq(seq( 
         funs[k] = funs[k](op(vars)),i = 1 .. nops(vars)), 
         k = 1 .. nops(funs)),seq(seq( 
         funs[k][vars[i]] = diff(funs[k](op(vars)),vars[i]), 
         i = 1 .. nops(vars)),k = 1 .. nops(funs)),seq(seq( 
         seq(funs[k][vars[i],vars[j]] = 
         diff(funs[k](op(vars)),vars[i],vars[j]), 
         i = 1 .. nops(vars)),j = 1 .. nops(vars)), 
         k = 1 .. nops(funs)), seq(seq(seq( 
         seq(funs[k][vars[i],vars[j], vars[l]] = 
         diff(funs[k](op(vars)),vars[i],vars[j], vars[l]), 
         i = 1 .. nops(vars)),j = 1 .. nops(vars)), 
         k = 1 .. nops(funs)),l=1..nops(vars) ))) 
       else 
         RETURN('difalias'(vars,funs)) 
       fi; 
  end;

Denis Pollney (8.5.00)

Roberto Sussman ¡sussky@mail.giga.com¿ wrote:

— I did a small procedure ”difalias” that completely ...

The GRTensor ‘autoAlias()’ function is quite different from difalias() in a number of respects. It operates on an expression and automatically picks out terms which involve a derivative and applies an alias to these terms.

These derivatives can be of any order. The user does not have to specify the functions to be aliased or the independent variables. Thus

  > autoAlias ( diff(p(x,y),x,y,y,y) + diff(q(r,t),r) + q(r,t) ); 
 
     p[x,y,y,y] + q[r] + q

In general, I’m not a big fan of aliasing for the standard reason: you invite a lot of confusion by, for example, aliasing something like f(r) by f. If you later refer to f(r) again, Maple thinks you are talking about f(r)(r), though it is not always apparent that this is what is happening from the output.

There is also a GRTensor-specific reason for not wanting to alias the function itself. Consider, for example, the Riemann tensor ‘R’ for some metric for which one of the components happens to be given by the function R(t). Once ‘R(t)’ has been aliased to ‘R’, you can not distinguish between it and the R which you would like to use for the tensor name.

The GRTensor autoAlias() only shies away from aliasing the function itself when such an ambiguity might exist, ie. when the alias corresponds to an existing GRTensor-defined tensor. In the above example, q(r,t) was aliased.

< Then, from R5 onward (including R6) there is a display bug ...

autoAlias() also makes use of Joe Riel’s ‘print/diff‘ trick for R5 (though in a somewhat different way than is done in difalias()) and can handle any number of derivatives.

For anyone interested, I’ve attached the most recent source code below. There’s not too much GRTensor-dependent stuff there, so you should be able to read it into Maple and it should work for you (try the example above, for instance). Apologies for the lack of documentation and general state of the code, it’s somewhat less than self-explanatory, I know.

# /*@@ 
#   @file   autoAlias.mpl 
#   @date   9 Feb 1999 
#   @author Denis Pollney 
#   @desc 
#           Alias functions so that their derivatives appear as 
#           subscripts. Based on an idea by Roberto Sussman and 
#           modified by Peter Musgrave for GRTensorII. Rewritten 
#           for MapleV.5 by Denis Pollney based on a suggestion 
#           by Joe Riel [MUG]. 
#   @enddesc 
#   @hist 
#            9 Feb 1999 Rewritten from scratch. Fixes problems with R5 
#                       use of alias by modifying `print/diff` [dp] 
#           27 Jul 1999 Added check for whether the aliased function 
#                       also corresponds to a grtensor object, in which 
#                       case it is not aliased [dp] 
#   @endhist 
# @@*/ 
#============================================================================== 
grG_usedNameSet := {}: 
 
autoAlias := proc (expr) 
global dlist_, grG_usedNameSet: 
local a, fn, f, x, df, aset, warnedSet: 
 
  aset := {alias()}: 
  dlist_ := NULL: 
 
  # the following sets the global dlist_ variable: 
  eval (subs(diff = `autoAlias/dlist`, expr)): 
 
  warnedSet := {}: 
 
  for a in {dlist_} do 
 
    fn := op(1,a): 
    f := `autoAlias/extractname` (fn): 
    x := `autoAlias/extractvars` (fn), op(op(2,a)): 
 
    if not member (op(0,f)[x], aset) then 
      aset := {alias (eval (op(0,f)[x] = subs (diff=''diff'',`$`=''`$`'', 
        readlib (`print/diff`)(f, x))))}: 
    fi: 
 
    if not member (op(0,f), aset) then 
 
      if not member (op(0,f), grG_usedNameSet) then 
 
         aset := {alias (op(0,f) = f)}: 
 
      else 
 
        if not member (op(0,f), warnedSet) then 
 
           printf (`Warning: %a corresponds to a previously defined GRTensor object -- 
                   to avoid ambiguities, only its derivatives have been aliased.\n`, op(0,f)): 
           warnedSet := warnedSet union {op(0,f)}: 
 
         fi: 
      fi: 
    fi: 
 
  od: 
 
  dlist_ := 'dlist_': 
  expr; 
end: 
 
 
`autoAlias/dlist` := proc (expr, d) 
global dlist_: 
 
  dlist_ := dlist_, [expr,{d}]: 
 
  RETURN (diff(expr, d)): 
end: 
 
 
`autoAlias/diff` := proc (expr, diffby) 
local varSeq, f, df, fname: 
 
  varSeq := diffby: 
 
  if type (expr, {function,procedure}) then 
 
    f := expr: 
 
    while type (f,{function,procedure}) and op (0,f) = ''diff'' do 
      varSeq := op (2,f), varSeq: 
      f := op (1,f): 
    od: 
 
    fname := `autoAlias/extractname` (f): 
 
    print (expr, {varSeq}, {diffby}); 
 
    df := subs (diff=''diff''`$`=''`$`'', 
      readlib (`print/diff`)(f,diffby)): 
    alias (fname[varSeq] = subs (diff=''diff''`$`=''`$`'', 
      readlib (`print/diff`)(f,diffby))): 
    RETURN (fname[varSeq]): 
 
  fi: 
 
  RETURN (diff(fname,diffby)): 
end: 
 
 
`autoAlias/extractname` := proc (f) 
 
  if op(0,f)=diff then 
    RETURN (`autoAlias/extractname` (op(1,f))): 
  fi: 
 
  RETURN (f): 
end: 
 
 
`autoAlias/extractvars` := proc (f) 
local a, v: 
 
  if op(0,f)='diff' then 
 
    v := NULL: 
 
    for a from 2 to nops(f) do 
      v := v, op(a,f): 
    od: 
 
    RETURN (`autoAlias/extractvars`(op(1,f)), v): 
 
  else 
 
    RETURN(NULL): 
 
  fi: 
end:

Ray Vickson ((15.5.00)

An *excellent* source is the book by Heck. I don’t have it with me now, but its (somewhat misleading) title is ”Introduction to Maple”. He does things similar to what you want in some very complex examples.