3.20.2. DZ


Lush contains a mechanism called ``DZ'' which allows to define very efficient numerical functions. This mechanism is based on a small stack machine, and on a DZ compiler. The DZ module is a remnant from an early attempt at compiling SN numerical to make it run faster. It was eventually superseded by the DH function (i.e functions compiled to C), but was kept around.

New DZ functions are easily defined with the functions dz , dz-compile and zlambda . They return an object from of class DZ which can be executed like a 'de' but which can only contain and return numerical expressions. Except for the overhead associated to small DZ functions, typical DZ functions execute 15 to 20 time faster than their DE equivalent.

Two important restrictions are enforced in dz function declaration:



3.20.2.0. Predefined DZs


A couple of useful DZ functions are predefined.



3.20.2.0.0. (sgn n)
[DZ]


Returns +1 if n is equal or greater than 0 , -1 otherwise.
? (sgn -2)
= -1

? (sgn 1.2)
= 1



3.20.2.0.1. (abs n)
[DZ]


Returns the absolute value of n .
? (abs 123.3)
= 123.3

? (abs -23.3)
= 23.3



3.20.2.0.2. (int n)
[DZ]


Returns the integral part of n .
? (int -4.5)
= -5

? (int 4.5)
= 4



3.20.2.0.3. (sqrt n)
[DZ]


Returns the square root of n
? (sqrt 15)
= 3.873



3.20.2.0.4. (0-x-1 n)
[DZ]


This function implements a piecewise saturated linear function. It returns 0 if n is smaller than -1. It returns 1 if n is larger than +1. It returns n if n is in the -1 to +1 range.
? (0-x-1 -2)
= -1

? (0-x-1 0.7)
= 0.7

? (0-x-1 1.3)
= 1



3.20.2.0.5. (0-1-0 n)
[DZ]


This function implements the indicator function of the -1 to +1 range. It returns 1 if n is in the -1 to +1 range. It returns 0 otherwise.
? (0-1-0 -2)
= 0

? (0-1-0 0.7)
= 1



3.20.2.0.6. (sin n)
[DZ]


Returns the sine of n radians.
? (sin (/ 3.1415 3))
= 0.866



3.20.2.0.7. (cos n)
[DZ]


Returns the cosine of n radians.
? (cos (/ 3.1415 3))
= 0.5



3.20.2.0.8. (tan n)
[DZ]


Returns the tangent of n radians.
? (tan (/ 3.1415 3))
= 1.7319



3.20.2.0.9. (atan n)
[DZ]


Returns the arc tangent of n , in radians.
? (* 4 (atan 1))
= 3.1416



3.20.2.0.10. (exp n)
[DZ]


Returns the exponential of n .
? (exp 1)
= 2.7183



3.20.2.0.11. (exp-1 n)
[DZ]


Returns the exponential of n minus 1. This function gives an accurate value of exp(n)-1 even for small values of n .
? (exp-1 0.5)
= 0.6487



3.20.2.0.12. (log n)
[DZ]


Returns the natural logarithm of n .
? (log 2)
= 0.6931



3.20.2.0.13. (log1+ n)
[DZ]


Returns the natural logarithm of n plus 1. This function gives an accurate value of log(1+n) even for small values of n .
? (log1+ 1)
= 0.6931



3.20.2.0.14. (sinh n)
[DZ]


Returns the hyperbolic sine of n .
? (sinh 1)
= 1.1752



3.20.2.0.15. (cosh n)
[DZ]


Returns the hyperbolic cosine of n .
? (cosh 1)
= 1.5431



3.20.2.0.16. (tanh n)
[DZ]


See: (qtanh n )
Returns the hyperbolic tangent of n .
? (tanh 1)
= 0.7616



3.20.2.0.17. (qtanh n)
[DZ]


See: (tanh n )
Returns a rational approximation of the hyperbolic tangent of n . This function is orders of magnitude faster than tanh . Its acuracy however is quite low (about 0.00001.)
? (qtanh 1)
= 0.7616



3.20.2.0.18. (qdtanh n)
[DZ]


Returns a rational approximation of the derivative of the hyperbolic tangent of n . The accuracy of this function is quite low (about 0.00001), but its computation time is very small.
? (qdtanh 1)
= 0.42



3.20.2.0.19. (qstdsigmoid n)
[DZ]


See: (qtanh n )
Returns the value of standard sigmoid at point n , computed with a rational approximation to the hyperbolic tangent. The standard sigmoid is defined as



3.20.2.0.20. (qdstdsigmoid n)
[DZ]


See: (qdtanh n )
Returns the value of the derivative of standard sigmoid at point n , computed with a rational approximation to the hyperbolic tangent. The standard sigmoid is defined as



3.20.2.0.21. (qexpmx n)
[DZ]


Returns a rational approximation of the exponential of minus the absolute value of n . The accuracy of this function is quite low (about 0.00001), but its computation time may be smaller on certain computers.
? (qexpmx 1)
= 0.3679



3.20.2.0.22. (qdexpmx n)
[DZ]


Returns a rational approximation of the derivative of the exponential of minus the absolute value of n . The accuracy of this function is quite low (about 0.00001), but its computation time may be smaller on certain computers.
? (qdexpmx 1)
= 0.3679



3.20.2.0.23. (qexpmx2 n)
[DZ]


Returns a rational approximation of the exponential of minus the square of n . The accuracy of this function is quite low (about 0.00001), but its computation time may be smaller on certain computers.
? (qexpmx 1)
= 0.3679



3.20.2.0.24. (qdexpmx2 n)
[DZ]


Returns a rational approximation of the exponential of minus the square of n . The accuracy of this function is quite low (about 0.00001), but its computation time may be smaller on certain computers.
? (qdexpmx 1)
= 0.3679



3.20.2.1. Compiling DZ


The following functions are useful to define DZ functions.



3.20.2.1.0. (dz name args . body)
[DM]


Create a new function which evaluate its argument and which is similar to a de except that it works only on numerical expression and is much faster. Sets the symbol name to this function.

args is the argument list, made of symbol names.

body is the function itself. Each list in body will be evaluated when the function is called. The result of the last evaluation will be returned by the function call.

Example:

? (dz fact (n)
     (let ((res 1)) 
       (for (i 2 n) 
           (setq res (* i res))) 
        res))
= fact
? (fact 5)
= 120
?



3.20.2.1.1. (zlambda args . body)
[DF]


Returns a function which evaluates its argument and is similiar to a de except that it works only on numerical expression, and is much faster than a de .

args is the argument list, made of symbol names.

body is the function itself. Each list in body will be evaluated when the function is called. The result of the last evaluation will be returned by the function call.

Example:

? ((zlambda (x)
     (* x x) ) (+ 4 5))
 [dz.lsh] (autoload)
= 81



3.20.2.1.2. (dz-compile de-function)
[DE]


Returns a function which evaluates its argument and is similiar to a DE except that it works only on numerical expression, and is much faster than a DE.

de-function is the de function to be compiled.



3.20.2.1.3. (dz-load n program)
[DX]


This function returns a new DZ which takes n arguments.

The list program describes which instruction will be executed by the stack machine. Each element in this list can be a label declarations or a stack machine instruction.

Caution must be exercised when you are programming this machine: An incorrect program may hang SN3. Usually DZ programs are composed by the DZ compiler, which is assumed correct.



3.20.2.1.4. (dz-spline index)
[DX]


See: (dz-dspline index )
Generates a DZ function that computes a cubic spline interpolations of a set of n points specified by the n by 2 matrix index . Argument index thus must be a n by 2 index. Its first column contains the abscissa, its second column contains the ordinates of the points.

The function dz-spline may be used for generating the derivative of this cubic spline interpolation.



3.20.2.1.5. (dz-dspline index)
[DX]


See: (dz-spline index )
Generates a DZ function that computes the derivative of a cubic spline interpolations of a set of n points specified by the n by 2 matrix index . Argument index thus must be a n by 2 index. Its first column contains the abscissa, its second column contains the ordinates of the points.

The function dz-spline may be used for generating the cubic spline itself.



3.20.2.1.6. (dz-def dz)
[DX]


See: (dz-load n_1 n_2 program )
See: DZ opcodes.
This function returns the definition of the DZ function dz . This definition is a list (n . program) , where n is the number of arguments of the DZ, and program is a list of stack machine instructions.



3.20.2.1.7. (dz-trace boolean)
[DX]


It function sets or reset the trace mode for the stack machine In trace mode, each instruction is disassembled, and the stack is displayed after the execution of each instruction. This function is mostly useful for designing and debugging the DZ compiler.

This function does nothing if the trace mode has not been compiled. This is the usual setup, for efficiency reasons.



3.20.2.2. DZ opcodes


See: (dz-load n program )


A DZ program is a list which describes which instruction will be executed by the stack machine. Each element in this list can be a label declarations or a stack machine instruction.

A label declaration is a string. If this string is used as argument of a branch opcode, the branch will jump at the label location. If this string is used as argument of a subsequent stack relative opcode, this opcode will refer to the current top of the stack.

A stack machine instruction is a list composed of an opcode string and of its arguments. Opcodes fall into five broad categories:

Two other rules are enforced by the dz-load function:

The arguments of a DZ are pushed on the stack when the execution starts. The execution stops when the last opcode has been executed. The result must be the only element on the stack. The opcode "POP@" is handy for removing the arguments of the DZ.

It is forbidden to make loops whose iterations would add or remove elements to the stack. The size of the stack at each position of the program thus is determined statically.

Here are a brief description of the opcodes.

Opcode       Stack Before -> Stack After         Notes
 NOP                  * -> *
 STACK                * -> *            prints the stack.
 PRINT                * -> *            prints the top of the stack.
 ERROR                * ->              produces a run time error.
 POP                x * -> * 
 DUP                x * -> x x *
 PUSH# C              * -> C * 
 PUSH@ R     x a1..aR * -> aR x a1..aR *
 POP@ R      x a1..aR * -> x * 
 SET@ R      x a1..aR * -> a1..aR-1 x *
 MINUS              x * -> -x *
 INVERT             x * -> 1/x *
 ADD1               x * -> x+1 *
 SUB1               x * -> x-1 *
 MUL2               x * -> x*2 *
 DIV2               x * -> x/2 *
 RAND                 * -> r *          uniform random number in [0,1[
 GAUSS                * -> r *          gaussian random number (m=0,s=1)
 SPLINE N DATA      x * -> f(x) *       computes a spline interpolation
 DSPLINE N DATA     x * -> f'(x) *      computes its derivative
 
 ADD# C             x * -> x+C *
 ADD@ R      x a1..aR * -> x+aR a1..aR *
 ADD              x y * -> x+y *
 SUB# C             x * -> x-C *
 SUB@ R      x a1..aR * -> x-aR a1..aR *
 SUB              x y * -> y-x *
Idem for 
   MUL, DIV, MIN, MAX, 
   DIVI (integer division),
   MODI (remainder), 
   POWER (exponentiation)
 SGN                x * -> sgn(x) *
 ABS                x * -> abs(x) *
Idem for the following functions, equivalent to their
lowercase lisp counterpart:
   INT SQRT PIECE RECT
   SIN COS TAN ASIN ACOS ATAN 
   EXP EXPM1 LOG LOG1P TANH COSH SINH 
   QTANH QDTANH QSTDSIGMOID QDSTDSIGMOID 
   QEXPMX QDEXPMX QEXPMX2 QDEXPMX2
 BR L                 * -> *            inconditional relative branch
 BREQ L             x * -> *            branch if x==0
 BRNEQ L            x * -> *            branch if x!=0
 BRGT L             x * -> *            branch if x>0
 BRLT L             x * -> *            branch if x<0
 BRGEQ L            x * -> *            branch if x>=0
 BRLEQ L            x * -> *            branch if x<=0
The following opcodes are handy for programming <for> loops, where
<i> is the variable, <n> the limit and <s> the increment.
 BEGFOR L       i n s * -> i n s *      check and branch
                i n s * -> *            pop 3 if it does not branch
 ENDFOR L       i n s * -> i+s n s *    increment, check and branch
                i n s * -> *            pop 3 under if it does not branch