Search code examples
optimizationmaple

Maple: Compiling function that substitutes numbers into expression


I have a complex Maple expression which is in this form:

expr := Sum(f(x, t, n), n=1...N);

To numerically evaluate this in Maple for any x and t, I might write

result := (x_, t_) -> value(subs(x=x_, t=t_, N=1000, expr));
result(0.5, 2.0); # some number

However, especially for large N, this computation is very expensive. How can I speed up result(x, t)?

I have tried using Compiler:-Compile, but the functions subs and value have no analogue in C code, so this fails. (Compiler:-Compile(result); gives an error message: Warning, the function names {subs, value} are not recognized in the target language.)

How can I transform result so that it may be compiled and evaluated faster, without having to manually rewrite the Sum as for-loop inside a procedure? I can’t reimplement it from scratch because expr is generated symbolically and I don’t want to lose generality.

Thank you.


Solution

  • By wrapping the actual call of procedure result below within a call to evalf we instruct Maple to try its evalf/Sum technique of numeric summation convergence acceleration (via Levin-u transformation). This is quick in the case that the trailing terms' contribution is estimated as dropping off quick "enough".

    restart;
    
    # for an example
    f := (x,t,n)->sin((x-t)/n*Pi):
    
    expr := Sum(f(x, t, n), n=1...N):
    
    result1 := unapply( expr, [x,t,N] ):
    
    evalf(result1( 2.0, 0.1, 10000 ));
                          46.91622734
    

    The procedure result2 below uses add instead of sum. Your original approach of applying the value command to the inert Sum would produce an active sum call, which -- on every invocation, and for each set of passed arguments -- would likely end up causing slow and unnecessary, unsuccessful attempts at symbolic summation before falling back to merely adding up the terms numerically.

    By simply replacing the inert Sum with the much more appropriate add command we can bypass all such repeated, failing, and wasted attempts at symbolic summation and go straight to the job of numerically adding up all the terms.

    result2 := unapply( subs(Sum=add,expr), [x::float,t::float,N::integer] ):
    
    result2( 2.0, 0.1, 10000 );
                          46.91622733
    

    If the expression expr is evalhf'able then (since add is too) we can instead do the numerical adding of all the terms under Maple's faster double-precision floating-point evaluation mechanism.

    evalhf(result1( 2.0, 0.1, 10000 ));
                      46.9162273272279222