undoing one form of symbolic root

acer's picture

In this previous post, an example is shown that demonstrates the potential problems that can arise following symbolic conversions such as from sqrt(x^2)  to x^(1/2).

Here x is an unknown symbol. The difficulties include the fact that, while `sqrt` can be smart about simplifying numeric values (eg. integers, rationals) the `^` operator has no such opportunity. Once the conversion from `sqrt` or `root` to `^` has been made there is no usual subsequent opportunity for complete simplification of powers, even when evaluation is done at a numeric value.

In short, eval( x^(1/2), x=4 ) will result in 4^(1/2) and not have the opportunity to simplify to the result of 2, which would be more convenient.

In the previous post, an expression 'q' was shown for which evaluation at a numeric point produced a fractional result whose numerator was zero but whose denominator was a "veiled zero". As was shown, Maple's current behaviour is that zero divided by veiled-zero immediately brings about a result of zero, with no opportunity to detect the exception. The result of zero, for that example, is incorrect.

If, on the other hand,  some smarter resolution of certain `^` terms could instead be done, then a veiled-zero in the denominator might be resolved as being a detectable zero. The final result would be the (much more satisfactory) detection of a division by zero -- a numeric exception event.

Below, I show an experiment toward working around that behaviour. It works by examining the input for one-over-integer powers, when evaluation is to be done at a numeric value. Just prior to actual evaluation, such `^` instances are replaced by effective calls to `root` or `sqrt`.

Note the I have to temporarily redefine `eval` in order to do this. That is seriously changing Maple, because `eval` is used in many hidden and important places. Basically, if `eval` is changed badly then key bits of Maple won't work. Of course, my changes only affect the single Maple session, and are not permanent.

> # The original problematic example
> q := (6*((1/3)*A-1/9))/(36*A-116+12*sqrt(12*A^3-3*A^2-54*A+93))^(1/3);
                                   6 (A/3 - 1/9)
            q := --------------------------------------------------
                                       3      2             1/2 1/3
                 (36 A - 116 + 12 (12 A  - 3 A  - 54 A + 93)   )
 
>
   
> eval(q, A = 1/3); # :(
                                       0
 

> `eval/F` := proc()
>   if nargs=2 and type(1/op(2,args[1]),integer) then
>       root(eval(op(1,args[1]),args[2]),1/(op(2,args[1])));
>   else
>     `^`(eval(op(1,args[1]),args[2]),op(2,args[1]));
>   end if;
> end proc:
>
> unprotect(eval): # living on the edge
> origeval := eval(eval):
>
> eval := proc(x)
> local b, dx, nx;
>   if nargs=0 then
>       error "invalid input: eval expects 1 or 2 arguments, but received 0";
>   elif nargs=1 then Z(x);
>   elif nargs=2 and type(args[2],symbol=numeric) then
>       nx := Z(subsindets(numer(x),`^`,t->'F'(op(t))),args[2..-1]);
>       dx := Z(subsindets(denom(x),`^`,t->'F'(op(t))),args[2..-1]);
>       nx/dx;
>   else
>       Z(args[1],args[2]);
>   end if;
> end proc:
>
> eval:=subs(Z=origeval(origeval),origeval(eval)):
> protect(eval);


> eval(q, A = 1/3); # :)
Error, (in eval) numeric exception: division by zero
>
> f:=(a-2)/(a-8^(1/3));
                                       a - 2
                                f := ----------
                                          (1/3)
                                     a - 8
 
> eval(f,a=2);
Error, (in eval) numeric exception: division by zero
>
>
> ee := (34-sqrt(A^2))^(1/3);
                                         2 1/2 (1/3)
                           ee := (34 - (A )   )
 
> eval(ee,A=7); # want result to be 3
                                       3
 
# some sanity checks
> eval(ee);
                                      2 1/2 (1/3)
                              (34 - (A )   )
 
> eval(ee,A=y*p);
                                     2  2 1/2 (1/3)
                             (34 - (y  p )   )
 
> eval('''ee''',1);
                                     ''ee''
 
> eval(ee,[A=7]); # weakness
                                       1/2 (1/3)
                               (34 - 49   )
 
> eval(A^(11/2),A=4); # weakness
                                         1/2
                                   1024 4
                                                                                
>
# Now revert.
> unprotect(eval);
> eval:=origeval(origeval):
> protect(eval);

Improvements to the (initial, simplistic) methodology would be welcome. This is also expected to be measurably slower than usual `eval`.

acer

}