formula-manipulation.a68

     
   1  COMMENT
   2  
   3  @section Synopsis
   4  
   5  Symbolic computing in Algol 68.
   6  
   7  Based on example 11.10 in the Revised Report on Algol 68.
   8  
   9  COMMENT
  10  
  11  PR quiet PR
  12  
  13  # Data structure #
  14  
  15  MODE FORM =  UNION (REF CONST, REF VAR, REF DYAD, REF MONAD),
  16       DYAD =  STRUCT (FORM lhs, INT op, FORM rhs),
  17       MONAD = STRUCT (INT op, FORM rhs),
  18       VAR =   STRUCT (STRING name, REF CONST value),
  19       CONST = STRUCT (NUM value),
  20       NUM =   LONG LONG REAL;
  21  
  22  # Access ops #
  23  
  24  OP VALUE = (REF CONST c) REF NUM: value OF c,
  25     VALUE = (REF VAR v) REF CONST: value OF v,
  26     NAME =  (REF VAR v) REF STRING: name OF v,
  27     LHS =   (REF DYAD t) REF FORM: lhs OF t,
  28     RHS =   (REF DYAD t) REF FORM: rhs OF t,
  29     RHS =   (REF MONAD t) REF FORM: rhs OF t,
  30     OPER =  (REF DYAD t) REF INT: op OF t,
  31     OPER =  (REF MONAD t) REF INT: op OF t,
  32     NUMER = (FORM f) NUM: CASE f
  33                           IN (REF CONST c): (c :/=: NIL | VALUE (c))
  34                           ESAC;
  35  
  36  # Generate objects #
  37  
  38  PROC new num =   (NUM v) REF NUM: HEAP NUM := v;
  39  PROC new dyad =  (FORM u, INT op, FORM v) REF DYAD:  NEW DYAD := (u, op, v);
  40  PROC new monad = (INT op, FORM v) REF MONAD: NEW MONAD := (op, v); 
  41  PROC new var =   (STRING name, REF CONST value) REF VAR: NEW VAR := (name, value);
  42  PROC new const = (NUM x) REF CONST: (NEW CONST c; VALUE c := x; c); 
  43  
  44  PROC zero =  REF CONST: new const (0), 
  45       one =   REF CONST: new const (1),
  46       two =   REF CONST: new const (2);
  47  
  48  PROC half = FORM: one / two;
  49  
  50  # Basic routines and ops #
  51  
  52  INT plus = 1, minus = 2, times = 3, over = 4, up = 5;
  53  
  54  PROC const = (FORM f) BOOL:
  55       CASE f
  56       IN (REF CONST u): u :/=: NIL
  57       OUT FALSE
  58       ESAC;
  59  
  60  OP DUP = (FORM f) FORM:
  61     CASE f
  62     IN (REF CONST u): new const (VALUE u),
  63        (REF VAR u):   new var (NAME u, VALUE u),
  64        (REF DYAD u):  new dyad (DUP LHS u, OPER u, DUP RHS u),
  65        (REF MONAD u): new monad (OPER u, DUP RHS u)
  66     ESAC;
  67  
  68  OP = = (FORM f, g) BOOL:
  69     CASE f
  70     IN (REF CONST u): CASE g
  71                       IN (REF CONST v): IF (u :=: NIL) OR (v :=: NIL)
  72                                         THEN FALSE
  73                                         ELSE VALUE u = VALUE v
  74                                         FI 
  75                       OUT FALSE 
  76                       ESAC, 
  77        (REF VAR u):   (g | (REF VAR v): NAME u = NAME v | FALSE), 
  78        (REF DYAD u):  (g | (REF DYAD v): OPER u = OPER v AND LHS u = LHS v AND RHS u = RHS v | FALSE),
  79        (REF MONAD u): (g | (REF MONAD v): OPER u = OPER v AND RHS u = RHS v | FALSE)
  80     OUT FALSE
  81     ESAC;
  82  
  83  OP /= = (FORM f, g) BOOL: NOT (f = g);
  84  
  85  # Pretty print NUM. #
  86  
  87  OP PRETTY = (NUM z) STRING:
  88     IF ABS (z - ROUND z) < 10 * long long small real
  89     THEN whole (z, 0)
  90     ELIF ABS (z) >= 0.1 THEF ABS (z) <= 10
  91     THEN STRING buf; 
  92          FOR digits TO real width
  93          WHILE puts (buf, fixed (z, 0, digits));
  94                NUM y;
  95                gets (buf, y);
  96                z /= y
  97          DO ~ OD;
  98          buf
  99     ELSE STRING buf, INT expw = 4; 
 100          FOR digits TO real width
 101          WHILE puts (buf, float (z, 4 + digits + expw, digits, expw));
 102                NUM y;
 103                gets (buf, y);
 104                z /= y
 105          DO ~ OD;
 106          buf
 107     FI;
 108  
 109  # Basic math. Indulge yourself adding more heuristics. #
 110  
 111  OP + = (FORM f) FORM: SIMPL f;
 112  
 113  OP - = (FORM f) FORM: 
 114     (FORM s = SIMPL f; s = zero | s | new monad (minus, s));
 115  
 116  OP + = (FORM f, g) FORM: 
 117     IF FORM s = SIMPL f, t = SIMPL g;
 118        s = zero
 119     THEN t
 120     ELIF t = zero
 121     THEN s
 122     ELIF s = t
 123     THEN new const (2) * s
 124     ELIF const (s) THEF const (t)
 125     THEN new const (NUMER (s) + NUMER (t))
 126     ELSE new dyad (s, plus, t)
 127     FI;
 128  
 129  OP - = (FORM f, g) FORM: 
 130     IF FORM s = SIMPL f, t = SIMPL g;
 131        s = zero
 132     THEN new monad (minus, t)
 133     ELIF t = zero
 134     THEN s
 135     ELIF s = t
 136     THEN zero
 137     ELIF const (s) THEF const (t)
 138     THEN new const (NUMER (s) - NUMER (t))
 139     ELSE new dyad (s, minus, t)
 140     FI;
 141  
 142  OP * = (FORM f, g) FORM:
 143     IF FORM s = SIMPL f, t = SIMPL g;
 144        s = zero OR t = zero
 145     THEN zero
 146     ELIF s = one
 147     THEN t
 148     ELIF t = one
 149     THEN s
 150     ELIF const (s) THEF const (t)
 151     THEN new const (NUMER (s) * NUMER (t))
 152     ELSE new dyad (s, times, t)
 153     FI;
 154  
 155  OP / = (FORM f, g) FORM:
 156     IF FORM s = SIMPL f, t = SIMPL g;
 157        t = zero
 158     THEN REF CONST (NIL)
 159     ELIF s = zero
 160     THEN zero
 161     ELIF t = one
 162     THEN s
 163     ELIF const (s) THEF const (t)
 164     THEN new const (NUMER (s) / NUMER (t))
 165     ELSE new dyad (s, over, t)
 166     FI;
 167  
 168  OP ^ = (FORM f, g) FORM:
 169     IF FORM s = SIMPL f, t = SIMPL g;
 170        t = zero
 171     THEN one
 172     ELIF t = one
 173     THEN s
 174     ELIF const (s) THEF const (t)
 175     THEN new const (NUMER (s) ** NUMER (t))
 176     ELSE new dyad (s, up, t)
 177     FI;
 178  
 179  OP SIMPL = (FORM f) FORM:
 180     CASE f
 181     IN (REF CONST u): u,
 182        (REF VAR u): (VALUE u :=: NIL | u | VALUE u),
 183        (REF MONAD u):
 184           CASE OPER u
 185           IN SIMPL RHS u,
 186              -SIMPL RHS u
 187           ESAC,
 188        (REF DYAD u):
 189           CASE OPER u
 190           IN SIMPL LHS u + SIMPL RHS u,
 191              SIMPL LHS u - SIMPL RHS u,
 192              SIMPL LHS u * SIMPL RHS u,
 193              SIMPL LHS u / SIMPL RHS u,
 194              SIMPL LHS u ^ SIMPL RHS u
 195           ESAC
 196     OUT f
 197     ESAC;
 198  
 199  OP EVAL = (FORM f) FORM:
 200     # Simplify as much as rules allow #
 201     BEGIN FORM u := DUP f, v;
 202           DO v := DUP u;
 203              u := SIMPL u
 204              UNTIL u = v
 205           OD;
 206           u
 207     END;
 208  
 209  # Applications of above definitions: derivative. #
 210  
 211  PROC deriv = (FORM f, # with respect to # REF VAR x) FORM:
 212       CASE f
 213       IN (REF CONST): zero,
 214          (REF VAR v): (v = x | one | zero),
 215          (REF MONAD u):
 216             CASE FORM s = RHS u;
 217                  OPER u
 218             IN + deriv (s, x),
 219                - deriv (s, x)
 220             ESAC,
 221          (REF DYAD u):
 222             CASE FORM s = LHS u, t = RHS u;
 223                  FORM deriv s = deriv (s, x), deriv t = deriv (t, x);
 224                  OPER u
 225             IN deriv s + deriv t,
 226                deriv s - deriv t,
 227                s * deriv t + deriv s * t,
 228                (deriv s - u * deriv t) / t,
 229                # (t | (REF CONST c): t * s ^ new const (VALUE c - 1) * deriv s) #
 230                t * s ^ (t - one) * deriv s
 231             ESAC
 232       ESAC;
 233  
 234  # A tiny demonstration #
 235  
 236  PROC write = (FORM f) VOID:
 237       CASE f
 238       IN (REF CONST c): print ((c :=: NIL | "(empty)" | PRETTY VALUE c)),
 239          (REF VAR v): print (NAME v),
 240          (REF MONAD u):  
 241             BEGIN
 242                print (("(", (OPER u | "+", "-")));
 243                write (RHS u);
 244                print (")")
 245             END,
 246          (REF DYAD u):
 247             BEGIN
 248                print ("(");
 249                write (LHS u);
 250                print ((OPER u | " + ", " - ", " * ", " / ", " ^ "));
 251                write (RHS u);
 252                print (")")
 253             END
 254       ESAC;
 255  
 256  PROC demo = (FORM f, REF VAR z) VOID:
 257       BEGIN write (f);
 258             print (" => ");
 259             write (EVAL f);
 260             IF z :/=: NIL
 261             THEN print ("; d/d");
 262                  write (z);
 263                  print (" = ");
 264                  write (EVAL deriv (EVAL f, z))
 265             FI;
 266             newline (standout)
 267       END;
 268  
 269  REF VAR pi var = new var ("pi", new const (qpi)), 
 270          x = new var ("x", NIL), 
 271          y = new var ("y", NIL);
 272  
 273  demo (zero - y, y);
 274  demo (x ^ half, x);
 275  demo (x ^ y, x);
 276  demo (pi var + pi var, NIL);
 277  demo (new const (2) ^ new const (3) + one, NIL)