module tpsmisc;
% Miscellaneous Support Functions added August 1993
% Author: Alan Barnes <barnesa@cs.aston.ac.uk>.

fluid '(gensym!-list);

% build a new copy of a power-series structure with no shared elements

symbolic procedure ps!:copy(ps);
begin scalar gensym!-list, new;
  new := ps!:copy1 ps;
  if gensym!-list then fix!-up!-links(ps,new);
  return new;
end;

symbolic procedure ps!:copy1 ps;
  if ps!:atom ps or car ps neq '!:ps!: then ps
  else begin scalar new, old, newexp;
     old := cdr ps;
     if idp old then <<
       new :=  gensym();
       gensym!-list := (eval old . new) . gensym!-list;
       return car ps . new >>;
     new := mkvect 7;
     for i := 0:7 do putv(new, i, getv(old, i));
     old := ps!:expression ps;
     new := car ps . new;
     if listp old then <<
       newexp := rator old . foreach arg in rands old collect
                                                       ps!:copy1 arg;
       ps!:set!-expression(new, newexp);
       if rator old = 'psgen then <<
          % terms are shared power series so need to be copied
          newexp := ps!:replace(rand1 old, rand1 newexp, ps!:terms ps);
          ps!:set!-terms(new, newexp)
       >>
     >>;
     return new;
   end;

symbolic procedure ps!:replace(p,q,terms);
   foreach term in terms collect (car term . ps!:copy2(cdr term,p,q));

symbolic procedure ps!:copy2(ps, p, q);
% copy series ps. If structure p is shared in ps,
% then q is shared in the copy
% this rigmarole avoids recomputation of terms of base series in PSGEN

  if ps!:atom ps or car ps neq '!:ps!: then ps
  else if ps = p then q
  else 
   begin scalar new, old, newexp;
     old := cdr ps;     % this is always a vector (I hope!!)
     new := mkvect 7;
     for i := 0:7 do putv(new, i, getv(old, i));
     old := ps!:expression ps;
     new := car ps . new;
     if listp old then <<
       newexp := rator old . foreach arg in rands old collect 
                                    ps!:copy2(arg,p,q);
       ps!:set!-expression(new, newexp);
     >>;
     return new;
   end;


symbolic procedure fix!-up!-links(p,q);
    if ps!:atom p or car p neq '!:ps!: then nil
    else 
      begin scalar x, args1, args2;
        if (x :=assoc(cdr p,gensym!-list)) then set(cdr x, cdr q);
        if not idp cdr p then <<
          x := ps!:expression p;
          if listp x then <<
             args1 := cdr x;
	     args2 := cdr ps!:expression q;
             while args1 do <<
               fix!-up!-links(car args1, car args2);
               args1 :=cdr args1; args2 := cdr args2
             >>
          >>
        >>;
      end;

put('pscopy,'simpfn,'simppscopy);

symbolic procedure simppscopy u;
  << u:=prepsqxx simp!* carx(u,'pscopy);
     if ps!:p u then simp!* ps!:copy u
     else typerr(u,"power series:  simppscopy")
  >>;          

endmodule; 

end;
