Sindbad~EG File Manager
/* M. Beeson, for Mathpert
supercancel(), cancellation including cancelling sqrts and roots.
Original date 5.25.93
last modified 1.29.98
5.5.13 added include "pvalaux.h"
9.25.14 removed unused static function rs_check1
*/
#include <assert.h>
#include "globals.h"
#include "cancel.h"
#include "pvalaux.h" // restore_roots
/*_______________________________________________________________*/
static int sc_aux(term a, term *ans)
/* if a is a root, sqrt, or product, replace all roots and sqrts
by fractional powers, distributing the powers across products that
were inside the roots or sqrts. Return 0 if something is done,
1 otherwise. In any case *ans is equal to a */
{ unsigned short f = FUNCTOR(a);
unsigned short n;
term arg,exp,temp;
unsigned short i,j,k,count;
int err,flag;
term onehalf = make_fraction(one,two);
if(f == SQRT && FUNCTOR(ARG(0,a)) != '*')
{ *ans = make_power(ARG(0,a),onehalf);
return 0;
}
if(f == SQRT) /* and the arg is a product */
{ arg = ARG(0,a);
n = ARITY(arg);
*ans = make_term('*',n);
for(i=0;i<n;i++)
{ ARGREP(*ans,i,make_power(ARG(i,arg),onehalf));
}
return 0;
}
if(f == ROOT && FUNCTOR(ARG(1,a)) != '*')
{ *ans = make_power(ARG(1,a),make_fraction(one,ARG(0,a)));
return 0;
}
if(f == ROOT) /* and the arg is a product */
{ arg = ARG(1,a);
n = ARITY(arg);
exp = make_fraction(one,ARG(0,a));
*ans = make_term('*',n);
for(i=0;i<n;i++)
{ ARGREP(*ans,i,make_power(ARG(i,arg),exp));
}
return 0;
}
if(f != '*' || !contains_sqrt(a))
{ *ans = a;
return 1;
}
/* Now a is a product */
/* count the arity of the answer */
n = ARITY(a);
count = 0;
for(i=0;i<n;i++)
{ arg = ARG(i,a);
if(FUNCTOR(arg) == SQRT && FUNCTOR(ARG(0,arg)) == '*')
count += ARITY(ARG(0,arg));
else if(FUNCTOR(arg) == ROOT && FUNCTOR(ARG(1,arg)) == '*')
count += ARITY(ARG(1,arg));
else if(FUNCTOR(arg) == '*')
count += ARITY(arg);
else
++count;
}
*ans = make_term('*',count);
k=0;
flag = 1;
for(i=0;i<n;i++)
{ arg = ARG(i,a);
err = sc_aux(arg,&temp);
if(!err)
flag = 0;
if(FUNCTOR(temp) != '*')
{ ARGREP(*ans,k,temp);
++k;
}
else
{ for(j=0;j<ARITY(temp);j++)
{ ARGREP(*ans,k,ARG(j,temp));
++k;
}
}
}
assert(k==count);
return flag;
}
/*_______________________________________________________________*/
void restore_roots(term t, term *ans)
/* change subterms of t which are fractional exponents
to root or sqrt terms */
{ unsigned short i,n;
term exp;
if(ATOMIC(t))
{ *ans = t;
return;
}
if(FUNCTOR(t) == '^' && FRACTION(ARG(1,t)))
{ exp = ARG(1,t);
if(equals(ARG(1,exp),two))
*ans=make_power(sqrt1(ARG(0,t)),ARG(0,exp));
else
*ans=make_power(make_root(ARG(1,exp),ARG(0,t)),ARG(0,exp));
return;
}
n = ARITY(t);
*ans = make_term(FUNCTOR(t),n);
for(i=0;i<n;i++)
restore_roots(ARG(i,t),ARGPTR(*ans) + i);
}
/*_______________________________________________________________*/
int supercancel(term a,term b, term *cancelled, term *ans)
/* like cancel, but also cancels square roots and roots, so
it will do x/\sqrt x = \sqrt x, and x^2/\sqrt x = x\sqrt x, and \sqrt (xy)/\sqrt x = \sqrt y, and so on.
Like cancel, it is supposed to return *cancelled and *ans in fresh space.
This function can change the domain because sc_aux distributes powers
across products and restore_roots doesn't put them back, so we can
change sqrt(ab) in the fraction to sqrt(a) sqrt(b).
*/
{ int err;
term aa,bb,q,t;
sc_aux(a,&aa); /* contains many pointers to onehalf maybe so better
not be destroying results of sc_aux.
But no problem: cancel makes fresh space below */
sc_aux(b,&bb);
err = cancel(aa,bb,&q,&t); /* fresh space */
if(err)
return 1;
restore_roots(q,cancelled);
restore_roots(t,ans);
return 0;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists