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)