% File ALGEBRA.ARI  (c)		09/16/80	The Soft Warehouse %


PROPERTY PRTMATH, +, FUNCTION (LEX1,
  % Local: %  EX1),
  PRTPAREN (LPAR),
  PRTMATH (POP(LEX1), 0, GET ('LBP, LOP1)),
  LOOP
    PRTSPACE (),
    BLOCK
      WHEN NEGCOEF (EX1:POP(LEX1)),
        PRINT ('-),
        EX1: -EX1 EXIT,
      PRINT (LOP1),
    ENDBLOCK,
    PRTSPACE (),
    WHEN ATOM (LEX1) EXIT,
    PRTMATH (EX1, GET ('RBP, LOP1), GET ('LBP, LOP1)),
  ENDLOOP,
  PRTMATH (EX1, GET ('RBP, LOP1), 0),
  PRTPAREN (RPAR),
ENDFUN $

FUNCTION SQUARE (EX1,
  % Local: %  LEX1, LEX2, LEX3),
  WHEN SUM (EX1),
    LEX1: REVERSE (REST(EX1)),
    LOOP
      LEX2: MERGESUM ((EX1:POP(LEX1))^2, LEX2),
      WHEN ATOM (LEX3:LEX1), MKSUM (LEX2) EXIT,
      EX1: 2*EX1,
      LOOP
	LEX2: MERGESUM (EX1*POP(LEX3), LEX2),
        WHEN ATOM (LEX3) EXIT,
      ENDLOOP,
    ENDLOOP EXIT,
  EX1*EX1,
ENDFUN $



NUMNUM: 6 $

PUSH ('NUMNUM, FLAGS) $

FUNCTION NUMNUM (EX1),
  WHEN INTEGER (EX1), MULTIPLE (NUMNUM, 2) EXIT,
  WHEN SUM (EX1), MULTIPLE (NUMNUM, 5) EXIT,
  MULTIPLE (NUMNUM, 3),
ENDFUN $

DENNUM: 6 $

PUSH ('DENNUM, FLAGS) $

FUNCTION DENNUM (EX1),
  WHEN INTEGER (EX1), MULTIPLE (DENNUM, 2) EXIT,
  WHEN SUM (EX1), MULTIPLE (DENNUM, 5) EXIT,
  MULTIPLE (DENNUM, 3),
ENDFUN $

FUNCTION DISTRIB (EX1, LEX1,
  % Local: %  NUMNUM, DENNUM, LEX2),
  LOOP
    LEX2: MERGESUM (EX1*POP(LEX1), LEX2),
    WHEN ATOM (LEX1), LEX2 EXIT,
  ENDLOOP,
ENDFUN $

PROPERTY *, +, FUNCTION (EX1, LEX4,
  % Local: %  LEX1, LEX2, LEX3),
  WHEN POSITIVE (NUMNUM) OR POSITIVE (DENNUM),
    WHEN PRODUCT (EX1),
      LEX1: REST (EX1),
      LOOP
        EX1: POP(LEX1),
        BLOCK
          WHEN DENOM (EX1),
            WHEN POSITIVE (DENNUM) AND DENNUM (EX1^-1),
              PUSH (EX1, LEX2) EXIT,
            PUSH (EX1, LEX3) EXIT,
          WHEN POSITIVE (NUMNUM) AND NUMNUM (EX1),
            PUSH (EX1, LEX2) EXIT,
          PUSH (EX1, LEX3),
        ENDBLOCK,
        WHEN ATOM (LEX1) EXIT,
      ENDLOOP,
      MERGEFACT (MKSUM (DISTRIB (MKPROD (REVERSE(LEX2)), LEX4,
	NUMNUM, DENNUM)),  REVERSE (LEX3)) EXIT,
    WHEN DENOM (EX1),
      WHEN POSITIVE (DENNUM) AND DENNUM (EX1^-1),
        MKSUM (DISTRIB (EX1, LEX4, NUMNUM, DENNUM)) EXIT,
      EXIT,
    WHEN POSITIVE (NUMNUM) AND NUMNUM (EX1),
      MKSUM (DISTRIB (EX1, LEX4, NUMNUM, DENNUM)) EXIT,
  EXIT,
ENDFUN $


DENDEN: 6 $

PUSH ('DENDEN, FLAGS) $

FUNCTION DENDEN (EX1),
  WHEN INTEGER (EX1), MULTIPLE (DENDEN, 2) EXIT,
  WHEN SUM (EX1), MULTIPLE (DENDEN, 5) EXIT,
  MULTIPLE (DENDEN, 3),
ENDFUN $

NUMDEN: 0 $

PUSH ('NUMDEN, FLAGS) $

FUNCTION NUMDEN (EX1),
  WHEN INTEGER (EX1), MULTIPLE (NUMDEN, 2) EXIT,
  WHEN SUM (EX1), MULTIPLE (NUMDEN, 5) EXIT,
  MULTIPLE (NUMDEN, 3),
ENDFUN $

PROPERTY *, ^, FUNCTION (EX1, EX2, EX3,
  % Local: %  LEX1, LEX2, LEX3),
  WHEN NEGATIVE(BASEXP) AND BASEXP(EX2) AND BASE(EX1) = EX2,
    EX2 ^ (EXPON(EX1) + EX3) EXIT,
  WHEN NEGATIVE(EXPBAS) AND EXPBAS(EX3) AND EXPON(EX1) = EX3,
    (BASE(EX1) * EX2) ^ EX3 EXIT,
  WHEN EX3 EQ -1,
    WHEN INTEGER (EX2),
      WHEN INTEGER (EX1),
	EX3: GCD (EX1, EX2),
	WHEN EX3 EQ 1, FALSE EXIT,
	EX1: QUOTIENT (EX1, EX3),
	EX2: QUOTIENT (EX2, EX3),
	WHEN EX2 EQ 1, EX1 EXIT,
	EX2: LIST ('^, EX2, -1),
	WHEN EX1 EQ 1, EX2 EXIT,
	LIST ('*, EX1, EX2) EXIT,
      WHEN RECIP (EX1),
	LIST ('^, TIMES (EX2, SECOND(EX1)), -1) EXIT EXIT,
    WHEN SUM (EX2),
      WHEN POSITIVE (DENDEN) OR POSITIVE (NUMDEN),
        EX2: REST (EX2),
        WHEN PRODUCT (EX1),
          LEX1: REST (EX1),
          LOOP
            EX1: POP(LEX1),
            BLOCK
              WHEN DENOM (EX1),
                EX3: EX1^-1,
                WHEN POSITIVE (DENDEN) AND DENDEN (EX3),
                  LEX2: ADJOIN (EX3, LEX2) EXIT,
                LEX3: ADJOIN (EX1, LEX3) EXIT,
              WHEN POSITIVE (NUMDEN) AND NUMDEN (EX1),
                LEX2: ADJOIN (EX1^-1, LEX2) EXIT,
              LEX3: ADJOIN (EX1, LEX3),
            ENDBLOCK,
            WHEN ATOM (LEX1) EXIT,
          ENDLOOP,
          MERGEFACT (LIST ('^, MKSUM (
	    DISTRIB (MKPROD(REVERSE(LEX2)), EX2, DENDEN, NUMDEN)),
              -1),  REVERSE (LEX3)) EXIT,
        WHEN DENOM (EX1),
          EX3: EX1^-1,
          WHEN POSITIVE (DENDEN) AND DENDEN (EX3),
            LIST ('^, MKSUM (DISTRIB (EX3, EX2, DENDEN, NUMDEN)), -1)
	      EXIT,
          EXIT,
        WHEN POSITIVE (NUMDEN) AND NUMDEN (EX1),
          LIST ('^, MKSUM (
	    DISTRIB (EX1^-1, EX2, DENDEN, NUMDEN)), -1) EXIT,
      EXIT,
    EXIT,
  EXIT,
ENDFUN $


EXPBAS: 30 $

PUSH ('EXPBAS, FLAGS) $

FUNCTION EXPBAS (EX1),
  WHEN NUMBER (EX1), MULTIPLE (EXPBAS, 2) EXIT,
  WHEN SUM (EX1), MULTIPLE (EXPBAS, 5) EXIT,
  MULTIPLE (EXPBAS, 3),
ENDFUN $

PROPERTY BASE, *, FUNCTION (EX1, EX2, EX3),
  WHEN POSITIVE (EXPBAS) AND EXPBAS (EX1),
    EX2^EX1 * EX3^EX1 EXIT,
ENDFUN $


BASEXP: -30 $

PUSH ('BASEXP, FLAGS) $

FUNCTION BASEXP (EX1),
  WHEN NUMBER (EX1), MULTIPLE (BASEXP, 2) EXIT,
  WHEN PRODUCT (EX1), MULTIPLE (BASEXP, 5) EXIT,
  MULTIPLE (BASEXP, 3),
ENDFUN $

PROPERTY EXPON, +, FUNCTION (EX1, EX2, EX3),
  WHEN POSITIVE (BASEXP) AND BASEXP (EX1),
    EX1^EX2 * EX1^EX3 EXIT,
ENDFUN $


PWREXPD: 0 $

PUSH ('PWREXPD, FLAGS) $

PROPERTY BASE, +, FUNCTION (EX1, EX2, EX3,
  % Local: %  NUMNUM, DENNUM),
  WHEN INTEGER (EX1),
    BLOCK
      WHEN SUM (EX3),
        EX2: ADJOIN ('+, ADJOIN (EX2, REST(EX3))) EXIT,
      EX2: LIST ('+, EX2, EX3),
    ENDBLOCK,
    WHEN EX1 EQ -1,
      WHEN NEGATIVE (DENDEN) OR NEGATIVE (NUMDEN),
        NUMNUM: DENDEN,
        DENNUM: NUMDEN,
        EX2: EVAL (EX2),
        WHEN SUM (EX2), FALSE EXIT,
        EX2^-1 EXIT EXIT,
    WHEN POSITIVE (PWREXPD),
      NUMNUM: 30,
      DENNUM: 30,
      WHEN POSITIVE (EX1),
        WHEN MULTIPLE (PWREXPD, 2), EXPT (EX2, EX1) EXIT,
        EXIT,
      WHEN MULTIPLE (PWREXPD, 3), EXPT (EX2, -EX1) ^ -1 EXIT,
    EXIT,
  EXIT,
ENDFUN $


FUNCTION EXPAND (EX1,
  % Local: %  PWREXPD, NUMNUM, DENDEN, DENNUM, NUMDEN, BASEXP, EXPBAS),
  PWREXPD: 6,
  NUMNUM: DENDEN: DENNUM: BASEXP: EXPBAS: 30,
  NUMDEN: 0,
  EVAL (EX1),
ENDFUN $


%**** optional content factorization & common denominator pkg. ****%


FUNCTION CONTENT (LEX1, LEX2),
  WHEN ATOM (LEX1),
    WHEN ATOM (LEX2), FALSE EXIT,
    WHEN DENOM (FIRST(LEX2)) AND
      NEGATIVE (DENNUM) AND DENNUM (FIRST(LEX2)^-1),
        ADJOIN (POP(LEX2), CONTENT (FALSE, LEX2)) EXIT,
    CONTENT (FALSE, REST(LEX2)) EXIT,
  CONTENT1 (BASE(FIRST(LEX1)), LEX1, LEX2),
ENDFUN $

FUNCTION CONTENT1 (EX1, LEX1, LEX2,
  % Local: %  EX2),
  WHEN ATOM (LEX2), CONTENT (LEX2, LEX1) EXIT,
  EX2: BASE (FIRST(LEX2)),
  WHEN EX1 = EX2,
    EX1: MIN (EXPON(POP(LEX1)), EXPON(POP(LEX2))),
    WHEN FIRST(EX1) EQ 'MIN, CONTENT (LEX1, LEX2) EXIT,
    EX2: EX2^EX1,
    WHEN DENOM (EX2),
      WHEN NEGATIVE (DENNUM) AND DENNUM (EX2^-1),
        ADJOIN (EX2, CONTENT (LEX1, LEX2)) EXIT,
      CONTENT (LEX1, LEX2) EXIT,
    WHEN NEGATIVE (NUMNUM) AND NUMNUM (EX2),
      ADJOIN (EX2, CONTENT (LEX1, LEX2)) EXIT,
    CONTENT (LEX1, LEX2) EXIT,
  WHEN ORDERED (EX1, EX2),
    EX1: POP(LEX1),
    WHEN DENOM (EX1) AND NEGATIVE (DENNUM) AND DENNUM (EX1^-1),
      ADJOIN (EX1, CONTENT1 (EX2, LEX2, LEX1)) EXIT,
    CONTENT1 (EX2, LEX2, LEX1) EXIT,
  EX2: POP(LEX2),
  WHEN DENOM (EX2) AND NEGATIVE (DENNUM) AND DENNUM (EX2^-1),
    ADJOIN (EX2, CONTENT1 (EX1, LEX1, LEX2)) EXIT,
  CONTENT1 (EX1, LEX1, LEX2),
ENDFUN $

FUNCTION CANCEL (LEX1, LEX2),
  WHEN ATOM (LEX1), LEX2 EXIT,
  CANCEL1 (BASE(FIRST(LEX1)), LEX1, LEX2),
ENDFUN $

FUNCTION CANCEL1 (EX1, LEX1, LEX2,
  % Local: %  EX2),
  WHEN ATOM (LEX2),
    ADJOIN (EX1^-EXPON(POP(LEX1)), CANCEL (LEX1, LEX2))  EXIT,
  WHEN EX1 = (EX2:BASE(FIRST(LEX2))),
    WHEN ZERO (EX1: EXPD(EXPON (POP(LEX2)) - EXPON (POP(LEX1)))),
      CANCEL (LEX1, LEX2) EXIT,
    ADJOIN (EX2^EX1, CANCEL (LEX1, LEX2)) EXIT,
  WHEN ORDERED (EX1, EX2),
    ADJOIN (EX1^-EXPON(POP(LEX1)), CANCEL (LEX1, LEX2)) EXIT,
  ADJOIN (POP(LEX2), CANCEL1 (EX1, LEX1, LEX2)),
ENDFUN $

FUNCTION FACTOR (LEX1, LEX2,
  % Local: %  LEX3, LEX4, EX1),
  EX1: 1,
  LEX3: LEX1,
  LEX4: LEX2,
  BLOCK
    WHEN INTEGER (FIRST(LEX1)),
      WHEN INTEGER (FIRST(LEX2)),
        BLOCK
          WHEN NEGATIVE (NUMNUM) AND NUMNUM (FIRST(LEX1)),
            EX1: GCD (FIRST(LEX1), FIRST(LEX2)),
	    WHEN NEGATIVE (FIRST (LEX1))  AND  NEGATIVE (FIRST (LEX2)),
	      EX1: MINUS(EX1)  EXIT EXIT,
        ENDBLOCK,
        LEX1: REST (LEX1),
        LEX2: REST (LEX2) EXIT,
      LEX1: REST (LEX1) EXIT,
    WHEN INTEGER (FIRST(LEX2)),  LEX2: REST (LEX2) EXIT,
  ENDBLOCK,
  BLOCK
    WHEN RECIP (FIRST(LEX1)),
      WHEN RECIP (FIRST(LEX2)),
        BLOCK
          WHEN NEGATIVE (DENNUM) AND DENNUM (SECOND(FIRST(LEX1))),
            EX1: EX1 *
              LCM (SECOND(FIRST(LEX1)), SECOND(FIRST(LEX2)))^-1  EXIT,
        ENDBLOCK,
        LEX1: REST (LEX1),
        LEX2: REST (LEX2)  EXIT,
      BLOCK
        WHEN NEGATIVE (DENNUM) AND DENNUM (SECOND(FIRST(LEX1))),
          EX1: EX1 * FIRST(LEX1)  EXIT,
      ENDBLOCK,
      LEX1: REST (LEX1)  EXIT,
    WHEN RECIP (FIRST(LEX2)),
      BLOCK
        WHEN NEGATIVE (DENNUM) AND DENNUM (SECOND(FIRST(LEX2))),
          EX1: EX1 * FIRST(LEX2)  EXIT,
      ENDBLOCK,
      LEX2: REST (LEX2)  EXIT,
  ENDBLOCK,
  LEX1: CONTENT (LEX1, LEX2),
  WHEN EX1 EQ 1 AND ATOM (LEX1), FALSE EXIT,
  MKPROD (MERGEPROD (EX1,
    MERGEPROD (PRODLEX (ADJOIN (EX1^-1, CANCEL(LEX1,LEX3)))  +
      PRODLEX (ADJOIN (EX1^-1, CANCEL(LEX1,LEX4))), LEX1))),
ENDFUN $

PROPERTY +, *, FUNCTION (EX1, LEX1),
  WHEN NEGATIVE (NUMNUM) OR NEGATIVE (DENNUM),
    WHEN EX1 EQ 1,  FACTOR(LEX1)  EXIT,
    WHEN PRODUCT(EX1),  FACTOR (LEX1, REST(EX1))  EXIT,
    FACTOR (LEX1, LIST(EX1)) EXIT,
ENDFUN $

PROPERTY +, ^, FUNCTION (EX1, EX2, EX3),
  WHEN NEGATIVE (NUMNUM) OR NEGATIVE (DENNUM),
    EX2: LIST ('^, EX2, EX3),
    WHEN EX1 EQ 1,  FACTOR (LIST(EX2))  EXIT,
    WHEN PRODUCT (EX1),  FACTOR (LIST(EX2), REST(EX1))  EXIT,
    FACTOR (LIST(EX2), LIST(EX1)) EXIT,
ENDFUN $


FUNCTION EXPD (EX1,
  % Local: %  PWREXPD, NUMNUM, DENDEN, DENNUM, NUMDEN, BASEXP, EXPBAS),
  PWREXPD: 6,
  NUMNUM: DENDEN: EXPBAS: 30,
  DENNUM: BASEXP: -30,
  NUMDEN: 0,
  EVAL (EX1),
ENDFUN $

FUNCTION FCTR (EX1,
  % Local: %  PWREXPD, NUMNUM, DENDEN, DENNUM, NUMDEN, BASEXP, EXPBAS),
  NUMNUM: DENDEN: -6,
  PWREXPD: NUMDEN: 0,
  DENNUM: BASEXP: -30,
  EXPBAS: 30,
  EVAL (EX1),
ENDFUN $


%****************** optional flags package ***************************%

FUNCTION FLAGS (
    % Local: % LEX1, EX1),
  EX1: LINELENGTH()-18,
  LEX1: FLAGS,
  NEWLINE (),
  LOOP
    WHEN ATOM (LEX1) EXIT,
    BLOCK
      WHEN GREATER (SPACES(), EX1),
	NEWLINE () EXIT,
    ENDBLOCK,
    PRINT (FIRST(LEX1)),
    PRINT (" = "),
    PRINT (EVAL(POP(LEX1))),
    SPACES (18 - MOD(SPACES(),18)),
  ENDLOOP,
  NEWLINE (),
  "",
ENDFUN $

RDS () $

