5.2 Calling symbolic routines from algebraic mode

REDUCE offers various ways to use symbolic routines in algebraic mode such that they appear on the algebraic level as genuine parts of REDUCE. These mainly differ in their strategy of evaluating parameters (and results).

5.2.1 Common protocol

Some general protocol rules apply for REDUCE symbolic mode routines:

5.2.2 Symbolic operator

The simplest way to link a symbolic procedure to algebraic mode is the symbolic operator declaration. In that case the routine can be called by its proper name in algebraic mode with REDUCE first evaluating its parameters to fully simplified algebraic forms. Upon return the result should also be an algebraic form (or NIL). Example:

   symbolic procedure my_plus(a,b);  
     begin scalar r;  
        print a; print b;  
        r := reval{’plus,a,b};  
        print r;  
        return r;  
     end;  
   symbolic operator my_plus;

This routine receives two algebraic expressions and computes their sum by calling the algebraic evaluator. The calls the the LISP function print have been inserted here and in the following examples to show you the forms passed to the routine.

5.2.3 Polyfn

If the symbolic routine is specialized for computations with pure polynomials it can be declared polyfn. REDUCE will evaluate the arguments for such a routine to standard forms and expects that the result also will have that form. Example:

   symbolic procedure poly_plus(a,b);  
     begin scalar r;  
        print a; print b;  
        r := addf(a,b);  
        print r;  
        return r;  
     end;  
   put(’poly_plus,’polyfn,’poly_plus);

This routine also adds its arguments but it is specialized for polynomials. If called with a non-polynomial form an error message will be generated. In the put statement the first argument is the algebraic operator name and the third one is the name of the associated evaluator function. These may differ.

5.2.4 Psopfn

The most general type of function is that of a psopfn. REDUCE will not evaluate the parameters for such a routine, instead it passes the unevaluated list of parameters to the function. The routine has to evaluate its parameters itself (of course using the services of reval and friends). So a psopfn can handle variable numbers of parameters. The result must be an algebraic expression or nil. Example:

   symbolic procedure multi_plus0 u;  
     begin scalar r;  
        r:=0;  
        for each x in u do  
        <<x:=reval x; print x;  
          r:=reval{’plus,r,x}  
        >>;  
        print r;  
        return r;  
     end;  
 
   put(’multi_plus,’psopfn,’multi_plus0);

This routine can be called with an arbitrary number of parameters; it will evaluate them one after the other, add them by calling reval and return the sum as result. Note that the name used in algebraic mode is multi_plus which is different from the name of the symbolic routine doing the work. This is necessary because otherwise the argument count check of REDUCE would complain as soon as the routine is called with more than one argument.

In the next example a psopfn implements an operator with a fixed number of arguments; it expects two numbers as arguments and performs an extensive checking as any such routine should do; again the name of the routine and the algebraic mode operator are different:

   symbolic procedure bin_plus0 u;  
    begin scalar p1,p2,r;  
     if length u neq 2 then rederr "illegal number of arguments";  
     p1:=reval car u; p2:=reval cadr u;  
     if not numberp p1 then typerr(p1,"number");  
     if not numberp p2 then typerr(p2,"number");  
     r:=p1+p2;  
     return r;  
   end;  
 
   put(’bin_plus,’psopfn,’bin_plus0);

The functions typerr and rederr are explained in the section error management.

5.2.5 Simpfn

When you declare a new algebraic operator and want to assign a special evaluation mode for it which cannot be written in algebraic mode (e.g. as a rule set) you can create a simplifier which has the task to convert each operator expression to a standard quotient. A simplifier function is linked to the operator by the property simpfn and has one argument which is the unevaluated parameter list of the operator expression. It will be called every time the operator appears in an expression. It must return a standard quotient. Example:

   algebraic operator op_plus;  
 
   symbolic procedure simp_op_plus u;  
     begin scalar r;  
        r:=simp 0;  
        for each x in u do  
        <<x:=simp x; print x;  
          r:=addsq(r,x)  
        >>;  
        return print r;  
     end;  
 
   put(’op_plus,’simpfn,’simp_op_plus);

In many cases the simpfn is the method of choice as it is best integrated into the REDUCE evaluation process: its results can immediately be used for subsequent calculations while algebraic form results need to be converted to standard quotients before combining them with other formulae.

Note that a simpfn which cannot simplify its argument must nevertheless return a standard quotient, then with the unevaluable form as kernel. E.g. a function for supporting the algebraic evaluation of the operator “<”:

   algebraic operator <;  
 
   symbolic procedure simp_lessp u;  
     begin scalar a1,a2,d;  
        a1:=simp car u; a2:=simp cadr u;  
        d:=subtrsq(a1,a2);  
        if domainp denr d and domainp numr d then  
          return if !:minusp numr d then simp 1 else simp 0;  
        return mksq({’lessp,prepsq a1,prepsq a2},1);  
     end;  
 
   put(’lessp,’simpfn,’simp_lessp);

Here all comparisons with numeric items are reduced to zero or one because of the equivalence of zero and “false” in algebraic mode, while in all other cases the non-evaluable expression is returned mapped by the function mksq which converts an algebraic expression into a standard quotient, ensuring the identity of composite kernels (see the section standard forms) .