derivatives of generalized Lambert



On 29/09/2011 10:14 PM, Barton Willis wrote:
> I was thinking about the options for the derivative of the generalized Lambert function with respect to
> the first argument. Possibilities:
>
>   (1) signal an error,
>   (2) return an 'at' nounform,
>   (3) give the function a silly name and hope that nobody asks for the derivative of that function.
>
> Scheme (1) is honest and pretty easy to do with a simplifying error. One not so nice thing about this
> method is that internally Maxima doesn't expect diff to signal an error, so things such as
> integrate(generalized_lambert_w(k,x),k) signals an error about the derivative of the
> generalized Lambert, instead of returning an integrate nounform. Code for scheme 1:
>
> ;;; A derivative of the generalized Lambert function with respect to the first argument signals an error.
> ;;; To do this, we need a simplifying error function:
>
> (defun simp-serror (x y z) "A simplifying error function."
>    (declare (ignore y))
>    (merror (simpcheck (second x) z)))
>
> (setf (get 'serror 'operators) #'simp-serror)
>
> ;;; Derivative of generalized_lambert_w. This code is adapted from specfun.lisp
>
> (defprop %generalized_lambert_w
>    ((k x)
>     ((serror) "Maxima doesn't know the derivative of generalized_lambert_w with respect to the first argument.")
>     ((mtimes)
>      ((mexpt) $%e ((mtimes) -1 ((%generalized_lambert_w) k x)))
>      ((mexpt) ((mplus) 1 ((%generalized_lambert_w) k x)) -1)))
>    grad)
>
> Scheme (2) is a bit weird, but maybe it's not wrong:
>
> (defprop %generalized_lambert_w
>    ((k x)
>      ((mprog)
>       ((mlist) ((msetq) kk (($gensym))) ((msetq) xx (($gensym))))
>       ((%at) ((%derivative) ((%generalized_lambert_w) kk xx) kk 1)
>        ((mlist) ((mequal) kk k) ((mequal) xx x))))
>      ((mtimes)
>       ((mexpt) $%e ((mtimes) -1 ((%generalized_lambert_w) k x)))
>       ((mexpt) ((mplus) 1 ((%generalized_lambert_w) k x)) -1)))
>    grad)
>
> (%i13) diff(%,k);
> (%o13) block([kk:gensym(),xx:gensym()],at('diff(generalized_lambert_w(kk,xx),kk,1),[kk=k,xx=x]))
>
> (%i14) ev(%,at);
> (%o14) at('diff(generalized_lambert_w(g34265,g34266),g34265,1),[g34265=k,g34266=x])
>
> (%i15) ev(%,diff);
> (%o15) at(block([kk:gensym(),xx:gensym()],at('diff(generalized_lambert_w(kk,xx),kk,1),[kk=g34265,xx=g34266])),[g34265=k,g34266=x])
>
> Scheme (3) isn't a serious option (name the function abracadabra, maybe).
For integrals, you can return a value of nil and this is converted to a 
noun form.  The code for this is in function integrallookups in 
sin.lisp. Examples of usage for the first arg of Bessel functions are in 
bessel.lisp.

I think the same happens for derivatives.  Certainly  
%inverse_jacobi_nc  and %inverse_jacobi_nd in ellipt.lisp are coded that 
way.

(defprop %inverse_jacobi_nc
     ((x m)
      ;; Whittaker and Watson, example in 22.122
      ;; inverse_jacobi_nc(u,m) = 
integrate(1/sqrt(t^2-1)/sqrt((1-m)*t^2+m), t, 1, u)
      ;; -> 1/sqrt(x^2-1)/sqrt((1-m)*x^2+m)
      ((mtimes)
       ((mexpt) ((mplus) -1 ((mexpt) x 2)) ((rat) -1 2))
       ((mexpt)
        ((mplus) m
     ((mtimes) -1 ((mplus) -1 m) ((mexpt) x 2)))
        ((rat) -1 2)))
      ;; wrt m
;     ((%derivative) ((%inverse_jacobi_nc) x m) m 1)
      nil)
   grad)