MODULE HACKSQRT; % Routines for manipulation of sqrt expressions.
% Author: James H. Davenport.
FLUID '(NESTEDSQRTS THISPLACE);
EXPORTS SQRTSINTREE,SQRTSINSQ,SQRTSINSQL,SQRTSINSF,SQRTSIGN;
EXPORTS DEGREENEST,SORTSQRTS;
IMPORTS MKVECT,INTERR,GETV,DEPENDSP,UNION;
SYMBOLIC PROCEDURE SQRTSINTREE(U,VAR,SLIST);
% Adds to slist all the sqrts in the prefix-type tree u.
IF ATOM U
THEN SLIST
ELSE IF CAR U EQ '!*SQ
THEN UNION(SLIST,SQRTSINSQ(CADR U,VAR))
ELSE IF CAR U EQ 'SQRT
THEN IF DEPENDSP(ARGOF U,VAR)
THEN <<
SLIST:=SQRTSINTREE(ARGOF U,VAR,SLIST);
% nested square roots
IF MEMBER(U,SLIST)
THEN SLIST
ELSE U.SLIST >>
ELSE SLIST
ELSE SQRTSINTREE(CAR U,VAR,SQRTSINTREE(CDR U,VAR,SLIST));
SYMBOLIC PROCEDURE SQRTSINSQ(U,VAR);
% Returns list of all sqrts in sq.
SQRTSINSF(DENR U,SQRTSINSF(NUMR U,NIL,VAR),VAR);
SYMBOLIC PROCEDURE SQRTSINSQL(U,VAR);
% Returns list of all sqrts in sq list.
IF NULL U
THEN NIL
ELSE SQRTSINSF(DENR CAR U,
SQRTSINSF(NUMR CAR U,SQRTSINSQL(CDR U,VAR),VAR),VAR);
SYMBOLIC PROCEDURE SQRTSINSF(U,SLIST,VAR);
% Adds to slist all the sqrts in sf.
IF DOMAINP U OR NULL U
THEN SLIST
ELSE <<
IF EQCAR(MVAR U,'SQRT) AND
DEPENDSP(ARGOF MVAR U,VAR) AND
NOT MEMBER(MVAR U,SLIST)
THEN BEGIN
SCALAR SLIST2;
SLIST2:=SQRTSINTREE(ARGOF MVAR U,VAR,NIL);
IF SLIST2
THEN <<
NESTEDSQRTS:=T;
SLIST:=UNION(SLIST2,SLIST) >>;
SLIST:=(MVAR U).SLIST
END;
SQRTSINSF(LC U,SQRTSINSF(RED U,SLIST,VAR),VAR) >>;
SYMBOLIC PROCEDURE EASYSQRTSIGN(SLIST,THINGS);
% This procedure builds a list of all substitutions for all possible
% combinations of square roots in list.
IF NULL SLIST
THEN THINGS
ELSE EASYSQRTSIGN(CDR SLIST,
NCONC(MAPCONS(THINGS,(CAR SLIST).(CAR SLIST)),
MAPCONS(THINGS,
LIST(CAR SLIST,'MINUS,CAR SLIST))));
SYMBOLIC PROCEDURE HARDSQRTSIGN(SLIST,THINGS);
% This procedure fulfils the same role for nested sqrts
% ***assumption: the simpler sqrts come further up the list.
IF NULL SLIST
THEN THINGS
ELSE BEGIN
SCALAR THISPLACE,ANSWERS,POS,NEG;
THISPLACE:=CAR SLIST;
ANSWERS:= for each u in THINGS collect SUBLIS(U,THISPLACE) . U;
POS := for each u in ANSWERS collect (THISPLACE . CAR U) . CDR U;
% pos is sqrt(f) -> sqrt(innersubst f)
NEG := for each u in ANSWERS
collect {THISPLACE,'MINUS,CAR U} . CDR U;
% neg is sqrt(f) -> -sqrt(innersubst f)
RETURN HARDSQRTSIGN(CDR SLIST,NCONC(POS,NEG))
END;
SYMBOLIC PROCEDURE DEGREENEST(PF,VAR);
% Returns the maximum degree of nesting of var
% inside sqrts in the prefix form pf.
IF ATOM PF
THEN 0
ELSE IF CAR PF EQ 'SQRT
THEN IF DEPENDSP(CADR PF,VAR)
THEN IADD1 DEGREENEST(CADR PF,VAR)
ELSE 0
ELSE IF CAR PF EQ 'EXPT
THEN IF DEPENDSP(CADR PF,VAR)
THEN IF EQCAR(CADDR PF,'QUOTIENT)
THEN IADD1 DEGREENEST(CADR PF,VAR)
ELSE DEGREENEST(CADR PF,VAR)
ELSE 0
ELSE DEGREENESTL(CDR PF,VAR);
SYMBOLIC PROCEDURE DEGREENESTL(U,VAR);
%Returns max degreenest from list of pfs u.
IF NULL U
THEN 0
ELSE MAX(DEGREENEST(CAR U,VAR),
DEGREENESTL(CDR U,VAR));
SYMBOLIC PROCEDURE SORTSQRTS(U,VAR);
% Sorts list of sqrts into order required by hardsqrtsign
% (and many other parts of the package).
BEGIN
SCALAR I,V;
V:=MKVECT(10); %should be good enough!
WHILE U DO <<
I:=DEGREENEST(CAR U,VAR);
IF I IEQUAL 0
THEN INTERR "Non-dependent sqrt found";
IF I > 10
THEN INTERR
"Degree of nesting exceeds 10 (recompile with 10 increased)";
PUTV(V,I,(CAR U).GETV(V,I));
U:=CDR U >>;
U:=GETV(V,10);
FOR I :=9 STEP -1 UNTIL 1 DO
U:=NCONC(GETV(V,I),U);
RETURN U
END;
SYMBOLIC PROCEDURE SQRTSIGN(SQRTS,X);
IF NESTEDSQRTS THEN HARDSQRTSIGN(SORTSQRTS(SQRTS,X),LIST NIL)
ELSE EASYSQRTSIGN(SQRTS,LIST NIL);
ENDMODULE;
END;