Sindbad~EG File Manager
/* reduce_ineq, simplify inequalities for Mathpert's theorem prover */
/* M. Beeson
1.29.91 Original date
6.4.99 modified
1.4.00 added code for 0 < ln u iff 1 < u, search for LN to find it
2.28.00 added a couple of lines to simple_bounds
2.28.00 corrected 'return 1' to 'return 0' at simple_bounds line 2161 and 2165
2.28.00 added more lines to simple_bounds so it can get sin(x) <= x when x >= 0.
12.16.10 added code around line 182 so ln(x) != 0 will reduce to x != 1
1.14.11 added code to one_sign to recognize x + sqrt(x^2 + 1) as having one sign
1.15.11 similarly for x-sqrt(x^2+1)
9.15.11 added calls to copy around lines 1590-1610
5.2.13 added code to reduce_ineq at line 1054 to catch |2k \pm 1| < 1 and return false.
1.6.15 moved declaration out of switch statement to quiet a warning
11.15.20 moved declaration to legal C position
8.8.24 replaced math.h with sincos.h
1.8.25 added code at line 273
*/
#include <assert.h>
#include <stdlib.h>
#include <math.h>
#include "globals.h"
#include "prover.h"
#include "probtype.h"
#include "algaux.h"
#include "cancel.h"
#include "order.h"
#include "eqn.h"
#include "simpprod.h"
#include "fraction.h"
#include "factor.h"
#include "solvelin.h"
#include "deval.h"
#include "evaltrig.h"
#include "trig.h" /* cancelfactorial2 */
#include "infsup.h"
#include "pvalaux.h" /* mvpolymult2 */
#include "reset.h" /* save_and_reset */
#include "ops.h" /* explicitdomain */
#include "ssolve.h" /* ssolve */
#include "nextline.h" /* strip_multiplicities */
#include "polynoms.h" /* makepoly */
#include "binders.h" /* get_binders */
#include "trigdom.h" /* hasroot */
#include "invineq.h" /* invert_ineq */
#include "fastdom.h" /* too_complicated */
#include "redineq.h"
static int cancel_identical(unsigned short, term, term, term *);
static int reduce_fractional_ineq(unsigned short, term, term, term *);
static int solve_it(term, term, unsigned short, term *);
static int one_sign(term);
static int easy_sign(term);
static int reduce_trigsum(term t, term *ans);
static int contains_binders(term t);
/*________________________________________________________________*/
int reduce_ineq(term t, term *ans)
/* one-step reduction of inequalities and '='.
return 0 for a successful reduction, 1 for failure.
In case it returns 1, *ans is returned as t, but
not in fresh space.
Returns 3 for low memory; if less than 24K heap is available
it fails immediately.
(This function includes all reductions to
be applied before conjoin, disjoin.)
*/
{ term a,b,u,v,temp,temp2,x,cancelled,trash,w;
unsigned short n,m,f,g,h,k;
int i,err;
int complex = get_complex();
double z;
long kk;
void *savenode;
int savenextdefn, saveeigen, nvariables;
unsigned long nbytes;
short savenextassumption;
termlist *binders;
f = FUNCTOR(t);
if(contains(t,ILLEGAL))
{ *ans = t;
return 1; // something has gone wrong before now, let's not make things worse.
}
assert(ARITY(t)==2);
assert (f == '<' || f == LE || f == NE || f == '=');
if(PRIME(t))
{ *ans = t;
return 1; /* already processed */
}
nbytes = mycoreleft();
if(nbytes < 24576)
{ *ans = t;
return 3;
}
savenode = heapmax();
int nvars = get_nvariables();
savenextdefn = get_nextdefn();
savenextassumption = get_nextassumption();
nvariables = get_nvariables();
saveeigen = get_eigenindex();
if(contains(t,SIN) || contains(t,COS) ||
contains(t,ATAN) || contains(t,ACOT)
)
{ err = simple_bounds(t,ans); /* can it be deduced from -1 <= sin t etc. */
if(!err)
return 0;
}
a = ARG(0,t);
b = ARG(1,t);
g = FUNCTOR(a);
h = FUNCTOR(b);
if(equals(b,infinity) && f == LE)
{ *ans = trueterm;
return 0;
}
if(equals(a,minusinfinity) && f == LE)
{ *ans = trueterm;
return 0;
}
if(equals(a,complexi) && seminumerical(b) && f != NE)
{ *ans = falseterm; /* refute i < 0 etc. */
return 0;
}
if(equals(b,complexi) && seminumerical(a) && f != NE)
{ *ans = falseterm; /* refute 0 < i etc. */
return 0;
}
if(ZERO(a) && f == LE && obviously_nonnegative(b))
{ *ans = trueterm;
return 0;
}
if(ZERO(a) && (f == '<' || f == NE) && obviously_positive(b))
{ *ans = trueterm;
return 0;
}
if(f == NE &&
(
(ZERO(a) && obviously_nonzero(b)) ||
(ZERO(b) && obviously_nonzero(a))
)
)
{ *ans = trueterm;
return 0; /* example, 1/c != 0 */
/* Even if c is undefined, e.g. 1/0 != 0 still reduces to true */
}
if(f == '=' &&
(
(ZERO(a) && obviously_nonzero(b)) ||
(ZERO(b) && obviously_nonzero(a))
)
)
{ *ans = falseterm;
return 0;
}
if(equals(b,infinity) && (f != '<' || !equals(a,infinity)))
{ *ans = domain(a);
return 0; /* example: 0 <= infinity */
}
if(equals(a,infinity)) /* infinity < c is false, even if c = infinity */
/* even infinity <= infinity is false */
{ *ans = falseterm;
return 0;
}
if(equals(b,minusinfinity))
{ *ans = falseterm;
return 0;
}
if(ATOMIC(a) && ATOMIC(b))
{ if(get_binders())
{ err = nonstandard(t,ans);
if(err)
*ans = t;
return err; /* this line allows inspecting ans in the debugger */
}
else
{ *ans = t;
return 1; /* can't be processed further */
}
}
if(equals(a,minusinfinity) && !equals(b,minusinfinity))
{ *ans = trueterm;
return 0;
}
err = cancel_identical(f,a,b,ans); /* identical terms on both sides? */
if(!err)
return 0;
if(ZERO(a) && (h == LN || h == LOG || h == LOGB))
/* 0 < ln u iff 1 < u */
{ *ans = make_term(f,2);
ARGREP(*ans,0,one);
ARGREP(*ans,1,ARG(h == LOGB ? 1 : 0,b));
return 0;
}
if(ZERO(b) && (g == LN || g == LOG || g == LOGB))
/* ln u < 0 iff u < 1 */
{ *ans = make_term(f,2);
ARGREP(*ans,1,one);
ARGREP(*ans,0,ARG(g == LOGB ? 1 : 0,a));
return 0;
}
if(ZERO(a) && h == SQRT)
{ switch(f)
{ case NE:
case '<':
*ans = lessthan(zero,ARG(0,b));
return 0;
case LE:
*ans = le(zero,ARG(0,b));
return 0;
case '=':
*ans = equation(ARG(0,b),zero);
return 0;
}
}
if(ZERO(b) && g == SQRT)
{ switch(f)
{ case NE:
*ans = lessthan(zero,ARG(0,a));
return 0;
case '<':
if(!get_complex())
*ans = falseterm;
else
*ans = lessthan(zero, im(ARG(0,a)));
return 0;
case LE:
if(!get_complex())
*ans = equation(ARG(0,a),zero);
else
*ans = le(zero,im(ARG(0,a)));
return 0;
case '=':
*ans = equation(ARG(0,a),zero);
return 0;
}
}
if(ZERO(a) && h == ROOT && iseven(ARG(0,b)))
{ switch(f)
{ case NE:
case '<':
*ans = lessthan(zero,ARG(1,b));
return 0;
case LE:
*ans = le(zero,ARG(1,b));
return 0;
case '=':
*ans = equation(ARG(1,b),zero);
return 0;
}
}
if(ZERO(b) && g == ROOT && iseven(ARG(0,a)))
{ switch(f)
{ case NE:
*ans = lessthan(zero,ARG(1,a));
return 0;
case '<':
if(!get_complex())
*ans = falseterm;
else
*ans = lessthan(zero, im(ARG(1,a)));
return 0;
case LE:
if(!get_complex())
*ans = equation(ARG(1,a),zero);
else
*ans = le(zero,im(ARG(1,a)));
return 0;
case '=':
*ans = equation(ARG(1,a),zero);
return 0;
}
}
if(ONE(b) && g == ABSFUNCTOR &&
FUNCTOR(ARG(0,a)) == '^' &&
iseven(ARG(1,ARG(0,a)))
)
{ *ans = make_term(f,2);
ARGREP(*ans,1,one);
ARGREP(*ans,0,abs1(ARG(0,ARG(0,a))));
return 0;
}
if(ZERO(a) && h == ROOT && isodd(ARG(0,b)))
{ *ans = make_term(f,2);
ARGREP(*ans,0,zero);
ARGREP(*ans,1,ARG(1,b));
return 0;
}
if(ZERO(b) && g == ROOT && iseven(ARG(0,a)))
{ *ans = make_term(f,2);
ARGREP(*ans,0,ARG(1,a));
ARGREP(*ans,2,zero);
return 0;
}
if(ZERO(a) && h =='^') /* 0 < u^v (or \le or != ) */
{ u = ARG(0,b);
v = ARG(1,b);
if(f == '=')
{ *ans = lpt(equation(zero,u));
if(contains(*ans, ILLEGAL))
{ *ans = t;
return 1;
}
return 0;
}
if(f == NE)
{ *ans = lpt(ne(u,zero));
if(contains(*ans, ILLEGAL))
{ *ans = t;
return 1;
}
return 0;
}
if(f == LE) /* and !complex */
{ if(OBJECT(u) || equals(u,eulere) || equals(u,pi_term))
{ *ans = get_polyvaldomainflag() ? domain(v) : trueterm;
return 0;
}
if(NEGATIVE(v))
return reduce_ineq(lessthan(zero,make_power(u,ARG(0,v))),ans);
if(INTEGERP(v)) /* far the most common case, speed it up */
{ *ans = ISODD(v) ? le(zero,u) : trueterm;
return 0;
}
if(RATIONALP(v)) /* speed this up too */
{ if(ISODD(ARG(0,v))) /* x^(1/2) or x^(1/3) */
{ if(ISODD(ARG(1,v)))
*ans = trueterm; /* x^(1/3) */
else
*ans = get_polyvaldomainflag() ? le(zero,v) : trueterm;
/* x^(1/2) for example */
}
else
*ans = trueterm;
return 0;
}
*ans = make_term(OR,4);
ARGREP(*ans,0,lessthan(zero,u));
ARGREP(*ans,1, and(equation(u,zero),ne(v,zero)));
ARGREP(*ans,2,even(v));
ARGREP(*ans,3,and(odd(denom1(v)),even(numerator1(v))));
return 0;
}
if(f == '<') /* and !complex */
{ if(OBJECT(u) || equals(u,eulere) || equals(u,pi_term))
{ *ans = trueterm;
return 0;
}
if(NEGATIVE(v))
v = ARG(0,v);
if(INTEGERP(v)) /* far the most common case, speed it up */
{ *ans = ISODD(v) ? lessthan(zero,u) : ne(zero,u);
return 0;
}
if(RATIONALP(v))
{ if(ISODD(ARG(0,v)))
{ if(ISODD(ARG(1,v)))
*ans = trueterm; /* x^(1/3) */
else /* x^(1/2) */
*ans = lessthan(zero,u) ;
}
else
*ans = get_polyvaldomainflag() ? ne(u,zero) : trueterm;
/* x^(2/5) for example */
return 0;
}
if(immediate(lessthan(zero,u)) == 1)
{ *ans = trueterm;
return 0; /* this helps when u is the index variable in a series */
}
if(OBJECT(v) && TYPE(v) == DOUBLE)
{ double z = DOUBLEDATA(v);
long kk;
if(nearint(z,&kk))
{ if(kk & 1)
{ *ans = lessthan(zero,u);
return 0;
}
*ans = ne(u,zero);
return 0;
}
*ans = lessthan(zero,u);
return 0;
}
*ans = and(ne(zero,u),
or3(lessthan(zero,u),
even(v),
and(odd(denom1(v)),even(numerator1(v)))
)
);
return 0;
}
}
if(h == MAXFUNCTOR && (f == LE || f == '<'))
{ /* x < max(u,v) => x < u or x < v */
u = make_term(f,2);
v = make_term(f,2);
ARGREP(u,0,a);
copy(a,ARGPTR(v)); /* not ARGREP(v,0,a), so as not to create a DAG */
ARGREP(u,1,ARG(0,b));
ARGREP(v,1,ARG(1,b));
*ans = or(u,v);
}
if(h == MINFUNCTOR && (f == LE || f == '<'))
{ /* x < min(u,v) => x < u and x < v */
u = make_term(f,2);
v = make_term(f,2);
ARGREP(u,0,a);
copy(a,ARGPTR(v)); /* not ARGREP(v,0,a), so as not to create a DAG */
ARGREP(u,1,ARG(0,b));
ARGREP(v,1,ARG(1,b));
*ans = and(u,v);
return 0;
}
if(ZERO(b) && g == '^') /* u^v < 0 (or LE, !=, = ) */
{ u = ARG(0,a);
v = ARG(1,a);
if(f == '=')
{ *ans = lpt(equation(zero,u));
if(equals(*ans,falseterm) || obviously_nonzero(v))
return 0;
if(!cancel(u,v,&cancelled,&trash) && obviously_nonzero(trash))
{ *ans = falseterm; /* x^x is never zero, also x^(2x) etc. */
return 0;
}
if(get_polyvaldomainflag())
{ *ans = and(*ans, ne(v,zero));
}
return 0;
}
if(f == NE)
{ if(NEGATIVE(v))
v = ARG(0,v);
if(complex || INTEGERP(v) || (RATIONALP(v) && ISODD(ARG(1,v))))
{ *ans = ne(u,zero);
return 0;
}
if(RATIONALP(v) && ISEVEN(ARG(1,v)))
{ *ans = lessthan(zero,u);
return 0;
}
if(obviously_positive(u)) /* this takes care of e^x != 0 */
{ *ans = trueterm;
return 0;
}
if(!constant(v))
/* neglect the possibility of a negative base and integer exponent or
rational exponent with odd denominator where u^v could be defined and
nonzero; this makes complicated expressions which makes it impossible
to analyze integrands. We simply assume that for variable exponents,
the definition u^v = e^v ln u is used. */
{ *ans = lessthan(zero,u);
return 0;
}
w = lpt(le(zero,u));
if(equals(w,trueterm))
{ /* example, analyzing integral(1/x^s,x,0,1), we get
here and want to return 0 < s for *ans instead of
a complicated expression as below. */
*ans = lessthan(zero,u);
return 0;
}
*ans = or3(
and(type(v,INTEGER),ne(u,zero)),
lessthan(zero,u),
and(ne(u,zero),odd(denom1(v)))
);
return 0;
}
if(f=='<')
{ if(OBJECT(u) || equals(u,eulere) || equals(u,pi_term))
{ *ans = falseterm;
return 0;
}
if(NEGATIVE(v))
v = ARG(0,v);
if(INTEGERP(v) && ISEVEN(v))
{ *ans = falseterm;
return 0;
}
if(INTEGERP(v)) /* && ISODD(v) */
{ *ans = lessthan(u,zero);
return 0;
}
if(RATIONALP(v) && ISODD(ARG(1,v)))
{ *ans = lessthan(u,zero);
return 0;
}
if(RATIONALP(v) && ISEVEN(ARG(1,v)))
{ *ans = falseterm;
return 0;
}
*ans = and(
lessthan(u,zero),
or(
odd(v),
and(odd(denom1(v)),odd(numerator1(v)))
)
);
return 0;
}
if(f==LE)
{ if(OBJECT(u) || equals(u,eulere) || equals(u,pi_term))
{ *ans = falseterm;
return 0;
}
*ans = or(
and(
le(u,zero),
or(
odd(v),
and(odd(denom1(v)),odd(numerator1(v)))
)
),
and(equation(u,zero), lessthan(zero,v))
);
return 0;
}
}
if(ZERO(a) && f == LE && h == '+')
{ /* a sum of absolute values is non-negative */
for(i=0;i<ARITY(b); i++)
{ if(FUNCTOR(ARG(i,b)) != ABSFUNCTOR)
break;
}
if(i==ARITY(b))
{ *ans = trueterm;
return 0;
}
}
if(ZERO(a) && h == '+' && ARITY(b) == 2 && isdifofsquares(b))
/* 0 < x^2-y^2 => y^2 < x^2 */
{ temp = make_term(f,2);
if(NEGATIVE(ARG(1,b)))
{ ARGREP(temp,0, ARG(0,ARG(1,b)));
ARGREP(temp,1, ARG(0,b));
reduce_ineq(temp,ans);
return 0;
}
else
{ ARGREP(temp,0, ARG(0,ARG(0,b)));
ARGREP(temp,1,ARG(1,b));
reduce_ineq(temp,ans);
return 0;
}
}
if(ZERO(b) && g == '+' && ARITY(a) == 2 && isdifofsquares(a))
/* x^2-y^2 < 0 => x^2 < y^2 */
{ temp = make_term(f,2);
if(NEGATIVE(ARG(1,a)))
{ ARGREP(temp,1, ARG(0,ARG(1,a)));
ARGREP(temp,0, ARG(0,a));
reduce_ineq(temp,ans);
return 0;
}
else
{ ARGREP(temp,1, ARG(0,ARG(0,a)));
ARGREP(temp,0,ARG(1,a));
reduce_ineq(temp,ans);
return 0;
}
}
if(ZERO(b) && FUNCTOR(a) == ABSFUNCTOR && (f == '=' || f == NE))
{ *ans = f == '=' ? equation(ARG(0,a),zero) : ne(ARG(0,a),zero);
return 0; /* abs(x) == 0 iff x == 0 */
}
if(ZERO(a) && FUNCTOR(b) == ABSFUNCTOR && (f == '=' || f == NE))
{ *ans = f == '=' ? equation(zero,ARG(0,b)) : ne(zero,ARG(0,b));
return 0;
}
if(ZERO(b) && ATOMIC(a)) /* a < 0 */
/* check whether a:NATNUM is an assumption */
{ int nextassumption = get_nextassumption();
u = type(a,NATNUM);
for(i=0;i<nextassumption;i++)
{ if (equals(get_assumption(i),u))
break;
}
if(i < nextassumption) /* a:natnum was found */
{ if(f == '<')
{ *ans = falseterm;
return 0;
}
if(f == LE)
{ *ans = equation(a,zero);
return 0;
}
if(f == NE)
{ *ans = lessthan(zero,a);
return 0;
}
}
}
if(ZERO(a) && ATOMIC(b) && f == LE)
/* check whether b:NATNUM is an assumption */
{ int nextassumption = get_nextassumption();
u = type(b,NATNUM);
for(i=0;i<nextassumption;i++)
{ if (equals(get_assumption(i),u))
break;
}
if(i<nextassumption) /* b:natnum was found */
{ *ans = trueterm;
return 0;
}
}
if(f == '=' && ZERO(a) && h == '*')
/* 0 = xy => xy = 0 */
{ u = equation(b,a);
reduce_ineq(u,ans);
return 0;
}
/* uv = 0 reduces to or(u=0,v=0), deleting obviously nonzero factors*/
/* uv != 0 reduces to and(u!=0,v!=0), deleting obviously nonzero factors */
if((f == '=' || f==NE) && ZERO(b) && g == '+' && contains(a,'^'))
{ /* use polyval to factor it , e.g. x^4 + 3x^2 */
int savefactorflag = get_polyvalfactorflag();
int savecomdenomflag = get_polyvalcomdenomflag();
int savegcdflag = get_polyvalgcdflag();
int savefactorflag2 = get_polyvalfactorflag2();
int savelogflag = get_polyvallogflag();
int savefunctionflag = get_polyvalfunctionflag();
set_polyvalfactorflag(1);
set_polyvalfunctionflag(1);
set_polyvallogflag(1);
set_polyvalfactorflag2(0x100);
set_polyvalcomdenomflag(1);
UNSET_ALREADY(a);
/* in case a was processed when factoring was off, it may still
have the ALREADY bit set. That may have happened long ago
so it's not enough to do this only when saveit is 0. */
err = polyval(a,&u);
set_polyvalfactorflag(savefactorflag);
set_polyvalcomdenomflag(savecomdenomflag);
set_polyvalgcdflag(savegcdflag);
set_polyvallogflag(savelogflag);
set_polyvalfunctionflag(savefunctionflag);
set_polyvalfactorflag2(savefactorflag2);
/* I observed an example in which polyval takes a sum of 6 terms
and re-orders the terms, and then on the recursive call reorders
them to the original order, causing a loop. Hopefully ordering
of terms is unique, but in order to be sure we don't make a
recursive call if only the order of terms has changed.
*/
if(err || eqtest(a,u))
destroy_term(u); /* and keep going */
else
{ v = make_term(f,2);
ARGREP(v,0,u);
ARGREP(v,1,zero);
reduce_ineq(v,ans);
return equals(t,*ans) ? 1 : 0;
}
}
if((f == NE || f == '=') && ZERO(b) && g == '+' && !complex)
{ /* catch a case like x^4 + x^2 + 1 which has no real roots */
if(one_sign(a))
{ *ans = (f==NE ? trueterm : falseterm);
return 0;
}
}
if((f==LE || f == '<') && ZERO(a) && h == '+' && !complex)
{ int sign = one_sign(b);
if(sign)
{ *ans = (sign > 0 ? trueterm : falseterm);
return 0;
}
}
if((f==LE || f == '<') && ZERO(b) && g == '+' && !complex)
{ int sign = one_sign(a);
if(sign)
{ *ans = (sign > 0 ? falseterm : trueterm);
return 0;
}
}
if((f == '=' || f==NE) && ZERO(b) && g == '*')
{ /* delete obviously nonzero factors and return an OR or AND */
k = 0;
n = ARITY(a);
temp = (f== '=' ? make_term(OR,n) : make_term(AND,n));
for(i=0;i<n;i++)
{ if(!obviously_nonzero(ARG(i,a)))
{ v = (f == '=' ? equation(ARG(i,a),zero) : ne(ARG(i,a),zero));
ARGREP(temp,k,v);
k++;
}
}
if(k==0)
{ *ans = (f == NE ? trueterm : falseterm);
RELEASE(temp);
return 0;
}
if(k==1)
{ *ans = ARG(0,temp);
RELEASE(temp);
return 0;
}
*ans = temp;
SETFUNCTOR(*ans,FUNCTOR(temp),k);
return 0; /* even if k==n, since we changed uv=0 to or(u=0,v=0) */
}
/* given 0 < uv, remove obviously positive or negative factors and
return a new inequality. Reduce_ineq does not take 0 < uv apart into
a Boolean combination of inequalities involving u and v separately. */
if((f == '<' || f== LE) &&
((ZERO(a) && h == '*') || (ZERO(b) && g == '*'))
)
{ int sign;
unsigned short kk=0;
term tt,uval;
if(ZERO(b))
{ b=a;
a= zero;
sign = -1; /* will cause reversal of inequality in the end*/
}
else
sign = 1; /* net sign of cancelled factors */
/* delete obviously one-signed factors and return an OR or AND */
k = 0;
n = ARITY(b);
temp = make_term('*',n);
/* accumulate the not-obviously-one-signed factors in temp */
if(f == '<')
tt = make_term(AND,n);
for(i=0;i<n;i++)
{ double zz;
term w = ARG(i,b);
if(seminumerical(w))
{ err = deval(w,&zz);
if(!err)
{ if(zz < 0.0)
sign = (sign > 0 ? -1 : 1);
continue;
}
}
u = f == '<' ? lessthan(zero,w) : le(zero,w);
v = f == '<' ? lessthan(w,zero) : le(w,zero);
uval = lpt(u);
if(immediate(uval)==1)
{ RELEASE(u);
RELEASE(v);
continue;
}
if(immediate(lpt(v))==1)
{ sign = (sign > 0 ? -1 : 1);
RELEASE(u);
RELEASE(v);
continue;
}
if(f == '<') /* example, 0 < x^2y^2 */
{ u = le(zero,w);
if(immediate(lpt(u)) == 1)
{ ARGREP(tt,kk,uval); /* in the example, uval is x != 0 */
++kk;
}
else
{ ARGREP(temp,k,w);
++k;
}
}
else /* f == LE and can't immediately determine sign of ARG(i,b)) */
{ ARGREP(temp,k,w);
++k;
}
RELEASE(u);
RELEASE(v);
}
SETFUNCTOR(tt,AND,kk); /* whether or not f == '<'; harmless anyway */
if(k==0) /* could determine the sign of every arg */
{ if(sign < 0)
{ *ans = falseterm;
RELEASE(temp);
if(f == '<')
RELEASE(tt);
return 0;
}
assert(sign > 0);
if(kk==0)
{ *ans = trueterm;
RELEASE(temp);
if(f == '<')
RELEASE(tt);
return 0;
}
*ans = tt;
return 0;
}
if(k==1)
{ *ans = make_term(f,2);
if(sign > 0)
{ ARGREP(*ans,0,zero);
ARGREP(*ans,1,ARG(0,temp));
}
else
{ ARGREP(*ans,0,ARG(0,temp));
ARGREP(*ans,1,zero);
}
if(kk)
{ SETFUNCTOR(tt,AND,(unsigned short)(kk+1));
ARGREP(tt,kk,*ans);
*ans = tt;
}
RELEASE(temp);
return 0;
}
*ans = make_term(f,2);
SETFUNCTOR(temp,FUNCTOR(temp),k);
if(sign > 0)
{ ARGREP(*ans,0,zero);
ARGREP(*ans,1,temp);
}
else
{ ARGREP(*ans,0,temp);
ARGREP(*ans,1,zero);
}
if(kk)
{ SETFUNCTOR(tt,AND,(unsigned short)(kk+1));
ARGREP(tt,kk,*ans);
*ans = tt;
}
/* Now check whether anything was actually changed: */
if(! equals(*ans,t))
return 0;
}
/* look for a common factor to cancel out from both sides */
if(!ZERO(a) && !ZERO(b) && !ONE(a) && !ONE(b) &&
!ISATOM(a) && !ISATOM(b) && /* don't cancel 1/3 from x = -1/3 */
!equals(a,minusone) && !equals(b,minusone)
)
{ term cancelled;
if(contains_sqrt(a) || contains_sqrt(b))
err = supercancel(a,b,&cancelled,&temp);
else
err = cancel(a,b,&cancelled,&temp);
if(!err) /* something cancelled */
{ if(FRACTION(temp))
SETFUNCTOR(temp,f,2); /* change it to an inequality */
else
{ temp2 = temp;
temp = make_term(f,2);
ARGREP(temp,0,temp2);
ARGREP(temp,1,one);
}
if( seminumerical(cancelled) &&
!deval(cancelled,&z) &&
fabs(z) > VERYSMALL
)
{ if(f == '=' || f == NE)
*ans = temp;
else if(z > 0.0)
*ans = temp;
else /*if z < 0.0 */
{ *ans = make_term(f,2);
ARGREP(*ans,0,ARG(1,temp));
ARGREP(*ans,1,ARG(0,temp));
}
return 0;
}
/* Now it was not a numerical term that cancelled */
if(f == '=')
{ *ans = or(temp,equation(cancelled,zero));
return 0;
}
if(f == NE)
{ *ans = and(ne(cancelled,zero),temp);
return 0;
}
temp2 = make_term(f,2);
ARGREP(temp2,0,ARG(1,temp));
ARGREP(temp2,1,ARG(0,temp));
if(f == '<')
{ *ans = or(
and(lessthan(zero,cancelled),temp),
and(lessthan(cancelled,zero),temp2)
);
}
else
{ *ans = or(
and(le(zero,cancelled),temp),
and(le(cancelled,zero),temp2)
);
}
return 0;
}
}
if(g == '-' && h == '-') /* -u < -v iff v < u */
{ u = ARG(0,a);
v = ARG(0,b);
*ans = make_term(f,2);
if(f == '=' || f == NE)
{ ARGREP(*ans,0,u);
ARGREP(*ans,1,v);
}
else
{ ARGREP(*ans,0,v);
ARGREP(*ans,1,u);
}
return 0;
}
if(g == ABSFUNCTOR && obviously_nonnegative(ARG(0,a)))
{ *ans = make_term(f,2);
ARGREP(*ans,0,ARG(0,a));
if(FUNCTOR(b) == ABSFUNCTOR && obviously_nonnegative(ARG(0,b)))
ARGREP(*ans,1,ARG(0,b));
else
ARGREP(*ans,1,b);
return 0;
}
if(h == ABSFUNCTOR && obviously_nonnegative(ARG(0,b)))
{ *ans = make_term(f,2);
ARGREP(*ans,0,a);
ARGREP(*ans,1,ARG(0,b));
return 0;
}
if(g == ABSFUNCTOR && FRACTION(ARG(0,a)) && obviously_positive(ARG(1,ARG(0,a))))
/* |c/2| < b iff |c| < 2b for example */
{ *ans = make_term(f,2);
ARGREP(*ans,0,abs1(ARG(0,ARG(0,a))));
ARGREP(*ans,1,product(ARG(1,ARG(0,a)),b));
return 0;
}
if(g == '/' || h == '/')
{ err = reduce_fractional_ineq(f,a,b,ans);
if(!err)
return 0;
}
if(g == '^' && h == '^' && equals(ARG(1,a),two) && equals(ARG(1,b),two))
/* u^2 f v^2 => ... */
{ term u2,u3,u4,v2;
u = ARG(0,a);
v = ARG(0,b);
switch(f)
{ case '=': /* u = v or u = -v */
*ans = or(equation(u,v),equation(u,tnegate(v)));
return 0;
case NE: /* u != v and u != -v */
*ans = and(ne(u,v),ne(u,tnegate(v)));
return 0;
case LE: /* 0 <= u <= v or v <= u <= 0 */
copy(u,&u2);
copy(u,&u3);
copy(u,&u4);
copy(v,&v2);
*ans = or(and(le(zero,u),le(u2,v)),and(le(v2,u3),le(u4,zero)));
return 0;
case '<': /* 0 <= u <= v or v <= u <= 0 */
copy(u,&u2);
copy(u,&u3);
copy(u,&u4);
copy(v,&v2);
*ans = or(and(le(zero,u),le(u2,v)),and(le(v2,u3),le(u4,zero)));
return 0;
}
}
if(g == VECTOR && (f == '=' || f == NE))
/* (p,q,0) is identified with (p,q) */
{ assert(h == VECTOR); /* else an ill-formed term has crept in! */
n = ARITY(a);
m = ARITY(b);
k = (unsigned short)(n < m ? m : n); /* max of m and n */
*ans = make_term((unsigned short)(f=='=' ? AND : OR), n);
for(i=0;i<k;i++)
{ u = make_term(f,2);
ARGREP(u,0,(i<n ? ARG(i,a): zero));
ARGREP(u,1,(i<m ? ARG(i,b): zero));
ARGREP(*ans,i,u);
}
return 0;
}
if(ZERO(b) && g == '+' && ARITY(a) == 2 &&
FUNCTOR(ARG(1,a))== '-' && FUNCTOR(ARG(0,ARG(1,a))) != '+'
)
{ *ans = make_term(f,2); /* change a-b < 0 to a < b etc. */
ARGREP(*ans,0,ARG(0,a));
ARGREP(*ans,1,ARG(0,ARG(1,a)));
return 0;
}
if(ZERO(a) && h == '+' && ARITY(b) == 2 &&
FUNCTOR(ARG(1,b))== '-' && FUNCTOR(ARG(0,ARG(1,b))) != '+'
)
{ *ans = make_term(f,2); /* change 0 < x-y to y < x etc. */
ARGREP(*ans,1,ARG(0,b));
ARGREP(*ans,0,ARG(0,ARG(1,b)));
return 0;
}
if(ZERO(b) && g == '+' && ARITY(a) == 2 &&
FUNCTOR(ARG(0,a))== '-' && FUNCTOR(ARG(0,ARG(0,a))) != '+'
)
{ *ans = make_term(f,2); /* change -y+x < 0 to x < y etc. */
ARGREP(*ans,0,ARG(1,a));
ARGREP(*ans,1,ARG(0,ARG(0,a)));
return 0;
}
if(ZERO(a) && h == '+' && ARITY(b) == 2 &&
FUNCTOR(ARG(0,b))== '-' && FUNCTOR(ARG(0,ARG(0,b))) != '+'
)
{ *ans = make_term(f,2); /* change 0 < -y+x to y < x etc. */
ARGREP(*ans,1,ARG(1,b));
ARGREP(*ans,0,ARG(0,ARG(0,b)));
return 0;
}
/* change a/b+c != 0 to a != -bc */
/* example, 1 + 1/sin x != 0 */
if( (f == NE || f == '=') &&
ZERO(b) && g == '+' &&
ARITY(a) == 2 && (FRACTION(ARG(0,a)) || FRACTION(ARG(1,a))) &&
!(FRACTION(ARG(0,a)) && FRACTION(ARG(1,a)))
)
{ term p,q,r,s;
*ans = make_term(f,2);
if(FRACTION(ARG(0,a)))
{ p = ARG(0,ARG(0,a));
r = ARG(1,ARG(0,a));
q = ARG(1,a);
}
else
{ p = ARG(0,ARG(1,a));
r = ARG(1,ARG(1,a));
q = ARG(0,a);
}
s = product(r,q);
if(constant(s))
{ ARGREP(*ans,0,p);
ARGREP(*ans,1,tnegate(s));
}
else
{ ARGREP(*ans,0,s);
ARGREP(*ans,1,tnegate(p));
}
return 0;
}
if(ZERO(a) && h == '+' && ARITY(b)==2 && FUNCTOR(ARG(1,b)) == '-')
{ *ans = make_term(f,2);
ARGREP(*ans,0,ARG(0,ARG(1,b)));
ARGREP(*ans,1,ARG(0,b));
return 0;
}
if(ZERO(a) && h == '+' && ARITY(b) == 3)
/* catch quadratics with negative discriminant and positive
quadratic term, these are positive */
{ term *atomlist,aa,bb,cc,xx,yy;
int natoms = atomsin(b,&atomlist);
double aval,bval,cval;
free2(atomlist);
if(natoms == 1 && isquadratic(b,&aa,&bb,&cc,&xx,&yy))
{ deval(aa,&aval);
deval(bb,&bval);
deval(cc,&cval);
if(fabs(aval) <= 1.0e150 && /* guard against overflow */
fabs(bval) <= 1.0e150 &&
fabs(cval) <= 1.0e150 &&
(bval*bval - 4.0 *aval *cval) < 0 /* negative discriminant */
)
{ *ans = aval > 0.0 ? trueterm : falseterm;
return 0;
}
}
}
binders = get_binders();
if(binders && (f=='<' || f == LE || f == NE))
{ err = nonstandard(t,ans);
if(!err) /* nonstandard tries to eliminate the nonstandard
variable, but there might not be one, or
it might not succeed. */
return 0;
if(get_lpt_binderflag() && (f == '<' || f == NE))
{ /* for definite integrals, if one side of the inequality is
zero and the other a polynomial, use coste-roy rather than
trying to factor. Coste-roy, in sturm.c, uses generalized
Sturm sequences. hasroot is in trigdom.c */
term left,right,x,q;
POLYnomial p;
double dleft, dright;
int nvars,nroots;
term *atomlist;
nvars = variablesin(t,&atomlist);
if(ONE(b) && FUNCTOR(a) == ABSFUNCTOR && f == '<')
{ /* example, |2k-1| < 1, impossible with k an integer */
term z = ARG(0,a);
term *atomlist3;
int m = variablesin(z,&atomlist3);
int i;
for(i=0;i<m;i++)
{ term u = atomlist3[i];
if(TYPE(u) == INTEGER)
{ // see if z is of the form pu \pm q with p, q integers
if(
equals(z,u) ||
( FUNCTOR(z) == '*' && INTEGERP(ARG(0,z)) && equals(ARG(1,z),u))
)
{ *ans = falseterm;
free2(atomlist3);
free2(atomlist);
return 0;
}
if(FUNCTOR(z) == '+' && ARITY(z) == 2)
{ term p = ARG(0,z);
term q = ARG(1,z);
if(INTEGERP(q) || (NEGATIVE(q) && INTEGERP(ARG(0,q))))
{ if(equals(p,u))
{ *ans = falseterm;
free2(atomlist3);
free2(atomlist);
return 0;
}
if(FUNCTOR(p) == '*' && INTEGERP(ARG(0,p)) && equals(ARG(1,p),u))
{ *ans = falseterm;
free2(atomlist3);
free2(atomlist);
return 0;
}
}
}
}
}
}
if(ZERO(a))
q = b;
else
q = a;
if(nvars == 1 && !binders_interval(&left,&x,&right) &&
equals(x,atomlist[0]) &&
!deval(left,&dleft) && !deval(right,&dright) && dleft < dright &&
dleft != BADVAL && dright != BADVAL &&
!makepoly(q,x,&p) && DEGREE(p) >= 2
)
{ /* it's a definite integral or sum */
free2(atomlist);
RELEASE(p);
nroots = hasroot(q,x,dleft,dright,1,1);
if(nroots > 0)
*ans = falseterm;
else if(nroots == 0) /* it has no root */
/* nroots < 0 signals an error */
{ if(f == NE)
*ans = trueterm;
else /* determine the sign of q on (left,right) */
{ double saveit = VALUE(x);
double z;
SETVALUE(x,0.5 *(dright+dleft));
deval(q,&z);
SETVALUE(x,saveit);
assert(z != 0);
if(z > 0.0)
*ans = ZERO(a) ? trueterm : falseterm;
else
*ans = ZERO(a) ? falseterm : trueterm;
}
}
return 0;
}
else
free2(atomlist);
}
}
switch(f)
{ case '<' :
if(ZERO(a) && ARITY(b)==1 && FUNCTOR(b) != IMAGPART && FUNCTOR(b) != REALPART)
{ if(FUNCTOR(b)=='-')
*ans = lessthan(ARG(0,b),zero);
else
*ans = posval(FUNCTOR(b),ARG(0,b));
return 0;
}
if(ZERO(b) && ARITY(a)==1 && FUNCTOR(a) != IMAGPART && FUNCTOR(a) != REALPART)
{ if(FUNCTOR(a)=='-')
*ans = lessthan(zero,ARG(0,a));
else
*ans = negval(FUNCTOR(a),ARG(0,a));
return 0;
}
break;
case LE:
if(ZERO(a) && ARITY(b)==1 && FUNCTOR(b) != IMAGPART && FUNCTOR(b) != REALPART)
{ if(FUNCTOR(b)== '-')
*ans = le(ARG(0,b),zero);
else
*ans = nonnegval(FUNCTOR(b),ARG(0,b));
return 0;
}
if(ZERO(b) && ARITY(a)==1 && FUNCTOR(a) != IMAGPART && FUNCTOR(a) != REALPART)
{ if(FUNCTOR(a)=='-')
*ans = le(zero,ARG(0,a));
else
*ans = nonposval(FUNCTOR(a),ARG(0,a));
return 0;
}
break;
case'=':
if(ATOMIC(a) && ATOMIC(b))
{ *ans = t;
SET_ALREADY(*ans);
return 0;
}
if(equals(a,b))
{ *ans = trueterm;
return 0;
}
if(ZERO(a))
{ *ans = equation(b,a); /* prefer x = 0 to 0 = x */
return 0;
}
if(ZERO(b) && ARITY(a)==1 && FUNCTOR(a) != IMAGPART && FUNCTOR(a) != REALPART)
{ if(FUNCTOR(a)=='-')
*ans = equation(ARG(0,a),zero);
else
*ans = zeroval(FUNCTOR(a),ARG(0,a));
return 0;
}
break;
case NE:
if(ZERO(a) && FUNCTOR(b) == '*')
{ *ans = ne(b,zero);
return 0;
}
if(ZERO(b) && FUNCTOR(a) == '*')
{ *ans = make_term(AND,ARITY(a));
k=0;
for(i=0;i<ARITY(a);i++)
{ u = ARG(i,a);
if(NEGATIVE(u))
u = ARG(0,u);
if(ZERO(u))
{ RELEASE(*ans);
*ans = falseterm;
return 0;
}
if(OBJECT(u))
continue;
u = lpt(ne(u,zero));
if(equals(u,falseterm))
{ *ans =falseterm;
return 0;
}
if(!equals(u,trueterm))
{ ARGREP(*ans,k,u);
++k;
}
}
if(k==0)
{ RELEASE(*ans);
*ans = trueterm;
return 0;
}
if(k==1)
{ temp = ARG(0,*ans);
RELEASE(*ans);
*ans = temp;
return 0;
}
SETFUNCTOR(*ans,AND,k);
return 0;
}
if(ZERO(a) && ARITY(b)==1 &&
FUNCTOR(b) != IMAGPART &&
FUNCTOR(b) != REALPART
)
{ unsigned short hh = FUNCTOR(b);
if(hh =='-')
{ *ans = ne(zero,ARG(0,b));
return 0;
}
else if(ATOMIC(ARG(0,b)))
{ *ans = nonzeroval(FUNCTOR(b),ARG(0,b));
if(immediate(*ans) == 1)
{ *ans = trueterm;
return 0;
}
else
return 0;
}
else if(!(hh==SIN || hh==COS || hh==TAN || h==COT) ||
!too_complicated(ARG(0,b))
)
{ *ans = nonzeroval(hh,ARG(0,b));
return 0;
}
}
if(ZERO(b) && ARITY(a)==1 &&
FUNCTOR(a) != IMAGPART &&
FUNCTOR(a) != REALPART
)
{ if(FUNCTOR(a)=='-')
{ *ans = ne(ARG(0,a),zero);
return 0;
}
else if(ATOMIC(ARG(0,a)))
{ *ans = nonzeroval(FUNCTOR(a),ARG(0,a));
if(immediate(*ans) == 1)
{ *ans = trueterm;
return 0;
}
else
{ SET_ALREADY(*ans);
return 0;
}
}
else
break;
}
if(FUNCTOR(a)==VECTOR)
{ assert(FUNCTOR(b)==VECTOR && ARITY(a)==ARITY(b));
*ans = make_term(OR,ARITY(a));
for(i=0;i<ARITY(a);i++)
ARGREP(*ans,i,ne(ARG(i,a),ARG(i,b)));
return 0;
}
break;
}
if((f == '<' || f == LE) && ZERO(a) && !ATOMIC(b) && ARITY(b) == 1)
{ term u = ARG(0,b);
double zz;
if(seminumerical(u))
{ err = deval(b,&zz);
if((!err && (zz > VERYSMALL && f == '<')) || ((zz > -VERYSMALL && f==LE)))
{ *ans = trueterm;
return 0;
}
}
if(contains(u,FUNCTOR(pi_term)) &&
(h==SIN || h==COS || h==TAN || h==COT || h==SEC || h==CSC)
)
{ term temp;
err = periodic(b,&temp);
if(!err)
{ if(seminumerical(temp))
{ err = deval(temp,&zz);
if((!err && (zz > VERYSMALL && f == '<')) || ((zz > -VERYSMALL && f==LE)))
{ *ans = trueterm;
return 0;
}
}
*ans = f==LE ? le(zero,temp) : lessthan(zero,temp);
return 0;
}
}
*ans = f== '<' ? posval(FUNCTOR(b),ARG(0,b)) :
nonnegval(FUNCTOR(b),ARG(0,b));
return 0;
}
if(f == NE && ZERO(a) && !ATOMIC(b) && ARITY(b) == 1)
/* e.g. tan(u) != 0 */
{ term u = ARG(0,b);
double zz;
if(seminumerical(u))
{ err = deval(b,&zz);
if(!err && fabs(zz) > VERYSMALL)
{ *ans = trueterm;
return 0;
}
}
if(contains(u,FUNCTOR(pi_term)) &&
(h==SIN || h==COS || h==TAN || h==COT || h==SEC || h==CSC)
)
{ term temp;
err = halfperiodic(b,&temp);
if(!err)
{ if(seminumerical(temp))
{ err = deval(temp,&zz);
if(!err && fabs(zz) > VERYSMALL)
{ *ans = trueterm;
return 0;
}
}
*ans = ne(zero,temp);
return 0;
}
}
*ans = nonzeroval(FUNCTOR(b),ARG(0,b));
return 0;
}
if(ZERO(a) && !ATOMIC(b) && FUNCTOR(b) == ROOT)
{ *ans = t; /* in case rootinfo fails */
return rootinfo(f,b,ans);
}
if(f==NE && ZERO(b) && !ATOMIC(a) && g == ROOT)
{ *ans = t;
return rootinfo(NE,a,ans);
}
if(ZERO(a) && !ATOMIC(b) && FUNCTOR(b) == LOGB)
{ *ans = make_term(f,2);
ARGREP(*ans,0,one);
ARGREP(*ans,1,ARG(1,b));
return 0;
}
x = get_eigenvariable();
if(contains_binders(t))
return 1; /* can't do anything further if it contains integrals, limits, etc. */
if(!solved(t,x))
{ err = solve_it(a,b,f,ans); /* If it contains only one occurrence
of the eigenvariable, or does not contain the eigenvariable
but has only one occurrence of some other variable. */
if(err && contains(t,FUNCTOR(x)))
{ term u = make_term(f,2);
ARGREP(u,0,a);
ARGREP(u,1,b);
temp_inhibit(explicitdomain);
stopcheck(); /* documented in prover.c */
err = ssolve(u,x,ans);
if(!err && contains(*ans,MULTIPLICITY))
*ans = strip_multiplicities(*ans);
startcheck();
temp_release(explicitdomain);
}
if(!err)
{ if(ATOMIC(*ans))
return 0; /* it could be true or false */
a = ARG(0,*ans);
b = ARG(1,*ans);
if(
(!ISATOM(a) || TYPE(a) != INTEGER || !seminumerical(b)) &&
(!ISATOM(b) || TYPE(b) != INTEGER || !seminumerical(a))
)
SETPRIME(*ans); /* don't process again; this stops a loop
3x = -1 => x = -1/3 => 3x = -1 by cancelling 1/3 */
return 0;
}
}
if( f == NE && /* catch n != 3/2, etc. */
ISATOM(a) &&
TYPE(a) == INTEGER &&
seminumerical(b)
)
{ err = deval(b,&z);
if(!err && !nearint(z,&kk))
{ *ans = trueterm;
return 0;
}
}
if( (f == LE || f == '<') && /* catch 3/2 < n, etc. */
ISATOM(b) &&
TYPE(b) == INTEGER &&
seminumerical(a)
)
{ err = deval(a,&z);
if(!err && !nearint(z,&kk))
{ long c;
if(z < 0.0)
c = - (long) (-z);
else
{ c = (long) z + 1;
if(c==0) /* overflow, z was the largest long */
{ *ans = t;
return 1; /* this will never happen in a million years */
}
}
*ans = le(make_int(c),b);
return 0;
}
}
if( (f == LE || f == '<') && /* catch n < 3/2, etc. */
ISATOM(a) &&
TYPE(a) == INTEGER &&
seminumerical(b)
)
{ err = deval(b,&z);
if(!err && !nearint(z,&kk))
{ long c;
if(z < 0.0)
{ c = (long) (-z) - 1;
if(c==0) /* overflow, z was the largest negative long */
{ *ans = t;
return 1; /* this will never happen in a million years */
}
c = -c;
}
else
c = (long) z;
*ans = le(a,make_int(c));
return 0;
}
}
err = reduce_trigsum(t,ans);
if(!err)
return 0;
/* the following code reduces, for example, 2(q+1)! < (q+2)! to 2 < q+2 */
if(
(FUNCTOR(a) == FACTORIAL ||
(FUNCTOR(a) == '*' && contains_at_toplevel(a,FACTORIAL))
) &&
(FUNCTOR(b) == FACTORIAL ||
(FUNCTOR(b) == '*' && contains_at_toplevel(b,FACTORIAL))
)
)
{ char buffer[DIMREASONBUFFER];
term temp;
err = cancelfactorial2(make_fraction(b,a),zero,&temp,buffer);
if(!err)
{ if(FRACTION(temp))
{ *ans = make_term(f,2);
ARGREP(*ans,0,ARG(1,temp));
ARGREP(*ans,1,ARG(0,temp));
return 0;
}
}
}
*ans = t;
/* Now we're going to fail */
reset_heap(savenode);
set_nvariables(nvars);
set_nextdefn(savenextdefn);
set_nvariables(nvariables);
set_eigenvariable(saveeigen);
set_nextassumption(savenextassumption);
return 1;
}
/*_____________________________________________________________________*/
static int cancel_identical(unsigned short f, term a, term b, term *ans)
/* cancel identical terms from both sides of inequality a f b if
possible; return 0 for success, 1 for failure. */
{ unsigned short m,n;
term u,v;
int i,j,k;
if(FUNCTOR(a) == '+' && FUNCTOR(b) != '+')
{ n = ARITY(a);
for(i=0;i<n;i++)
{ if(equals(ARG(i,a),b))
{ if(n==2)
u = ARG( (i==0 ? 1 : 0), a);
else
{ u = make_term('+',(unsigned short)(n-1));
for(j=0;j<i;j++)
ARGREP(u,j,ARG(j,a));
for(j=i;j<n-1;j++)
ARGREP(u,j,ARG(j+1,a));
}
*ans = make_term(f,2);
ARGREP(*ans,0,u);
ARGREP(*ans,1,zero);
return 0;
}
}
}
if(FUNCTOR(a) != '+' && FUNCTOR(b) == '+')
{ n = ARITY(b);
for(i=0;i<n;i++)
{ if (equals(ARG(i,b),a))
{ if(n==2)
u = ARG( (i==0 ? 1 : 0), b);
else
{ u = make_term('+',(unsigned short)(n-1));
for(j=0;j<i;j++)
ARGREP(u,j,ARG(j,b));
for(j=i;j<n-1;j++)
ARGREP(u,j,ARG(j+1,b));
}
*ans = make_term(f,2);
ARGREP(*ans,0,zero);
ARGREP(*ans,1,u);
return 0;
}
}
}
if(FUNCTOR(a) == '+' && FUNCTOR(b) == '+')
{ n = ARITY(a);
m = ARITY(b);
for(i=0;i<n;i++)
{ for(k=0;k<m;k++)
{ if(equals(ARG(i,a),ARG(k,b)))
{ if(n==2)
u = ARG( (i==0 ? 1 : 0), a);
else
{ u = make_term('+',(unsigned short)(n-1));
for(j=0;j<i;j++)
ARGREP(u,j,ARG(j,a));
for(j=i;j<n-1;j++)
ARGREP(u,j,ARG(j+1,a));
}
if(m==2)
v = ARG( (k==0 ? 1 : 0), b);
else
{ v = make_term('+',(unsigned short)(m-1));
for(j=0;j<k;j++)
ARGREP(v,j,ARG(j,b));
for(j=k;j<m-1;j++)
ARGREP(v,j,ARG(j+1,b));
}
*ans = make_term(f,2);
ARGREP(*ans,0,u);
ARGREP(*ans,1,v);
return 0;
}
}
}
}
if(equals(a,b))
{ if(f == '<')
{ *ans = falseterm;
return 0;
}
if(f == LE)
{ *ans = trueterm;
return 0;
}
if(f == NE)
{ *ans = falseterm;
return 0;
}
if(f == '=')
{ *ans = trueterm;
return 0;
}
}
return 1;
}
/*__________________________________________________________________*/
static int reduce_fractional_ineq(unsigned short f, term a, term b, term *ans)
/* reduce the inequality a f b and return the result in *ans */
/* Return 0 for success, 1 for failure */
/* f is <, LE, or NE or = */
{ term u,v,temp,temp2,whichvar,ans1,ans2;
int stoploop;
int err2;
if(f == '<' && ZERO(a) && FUNCTOR(b) == '/')
{ u = ARG(0,b);
v = ARG(1,b);
if(OBJECT(u))
*ans = lessthan(zero,v);
else if(OBJECT(v))
*ans = lessthan(zero,u);
else if(NEGATIVE(u) && OBJECT(ARG(0,u)))
*ans = lessthan(v,zero);
else if(NEGATIVE(v) && OBJECT(ARG(0,v)))
*ans = lessthan(u,zero);
else if(FUNCTOR(v) == '+' && FUNCTOR(u) == '+' &&
ARITY(u) == 2 && ARITY(v) == 2
)
/* 0 < (a+b)/(a-b) iff 0 < b(a-b) */
/* if one of a or b is constant this will avoid
introducing disjunctions */
{ term a = ARG(0,u);
term b = ARG(1,u);
term c = ARG(0,v);
term d = ARG(1,v);
if(equals(a,c))
{ if(NEGATIVE(b) && equals(ARG(0,b),d))
*ans = lessthan(zero,product(d,sum(a,b)));
else if(NEGATIVE(d) && equals(ARG(0,d),b))
*ans = lessthan(zero,product(b,sum(a,d)));
else
*ans = lessthan(zero, product(sum(a,d),sum(a,b)));
}
else if(equals(b,c))
{ /* switch the roles of a and b */
if(NEGATIVE(a) && equals(ARG(0,a),d))
*ans = lessthan(zero,product(d,sum(a,b)));
else if(NEGATIVE(d) && equals(ARG(0,d),a))
*ans = lessthan(zero,product(a,sum(b,d)));
else
*ans = lessthan(zero,product(sum(b,d),sum(a,b)));
}
else
{ term v2,u2;
copy(v,&v2); // don't create a term with duplicates in different subterms
copy(u,&u2);
*ans = or(
and(lessthan(zero,v),lessthan(zero,u)),
and(lessthan(v2,zero),lessthan(u2,zero))
);
}
}
else
{ term v2,u2;
copy(v,&v2); // don't create a term with duplicates in different subterms
copy(u,&u2);
*ans = or(
and(lessthan(zero,v),lessthan(zero,u)),
and(lessthan(v2,zero),lessthan(u2,zero))
);
}
return 0;
}
if(ONE(a) && FRACTION(b) && f == LE)
{ u = ARG(0,b);
v = ARG(1,b);
if(FUNCTOR(v) == '+' && FUNCTOR(u) == '+' &&
ARITY(u) == 2 && ARITY(v) == 2
)
/* 1 <= (a+b)/(a-b) iff 0 <= b(a-b) */
/* if one of a or b is constant this will avoid
introducing disjunctions */
{ term aa = ARG(0,u);
term bb = ARG(1,u);
term c = ARG(0,v);
term d = ARG(1,v);
if(equals(aa,c))
{ if(NEGATIVE(bb) && equals(ARG(0,bb),d))
*ans = le(zero,(OBJECT(d) ? sum(aa,bb) : product(d,sum(aa,bb))));
else if(NEGATIVE(d) && equals(ARG(0,d),bb))
*ans = le(zero,(OBJECT(bb) ? sum(aa,d) : product(bb,sum(aa,d))));
return 0;
}
}
}
if(f == LE && ZERO(a) && FUNCTOR(b) == '/')
{ u = ARG(0,b);
v = ARG(1,b);
if(OBJECT(u))
*ans = lessthan(zero,v);
else if(OBJECT(v))
*ans = le(zero,u);
else if(NEGATIVE(u) && OBJECT(ARG(0,u)))
*ans = lessthan(v,zero);
else if(NEGATIVE(v) && OBJECT(ARG(0,v)))
*ans = le(u,zero);
else
*ans = or(
and(lessthan(zero,v),le(zero,u)),
and(lessthan(v,zero),le(u,zero))
);
return 0;
}
if(f == '<' && ZERO(b) && FUNCTOR(a) == '/')
{ u = ARG(0,a);
v = ARG(1,a);
if(OBJECT(u))
*ans = lessthan(v,zero);
else if(OBJECT(v))
*ans = lessthan(u,zero);
else if(NEGATIVE(u) && OBJECT(ARG(0,u)))
*ans = lessthan(zero,v);
else if(NEGATIVE(v) && OBJECT(ARG(0,v)))
*ans = lessthan(zero,u);
else
*ans = or(
and(lessthan(zero,v),lessthan(u,zero)),
and(lessthan(v,zero),lessthan(zero,u))
);
return 0;
}
if(f == LE && ZERO(b) && FUNCTOR(a) == '/')
{ u = ARG(0,a);
v = ARG(1,a);
if(OBJECT(u))
*ans = lessthan(v,zero);
else if(OBJECT(v))
*ans = le(u,zero);
else if(NEGATIVE(u) && OBJECT(ARG(0,u)))
*ans = lessthan(zero,v);
else if(NEGATIVE(v) && OBJECT(ARG(0,v)))
*ans = le(zero,u);
else
*ans = or(
and(lessthan(zero,v),le(u,zero)),
and(lessthan(v,zero),le(zero,u))
);
return 0;
}
if((f == LE || f == '<') &&
OBJECT(a) &&
FRACTION(b) &&
OBJECT(ARG(0,b)) &&
!OBJECT(ARG(1,b))
)
/* a < u/v with a and u positive numbers */
/* example: 1 < 1/cos x => 0 < cos x < 1 */
{ u = ARG(0,b);
v = ARG(1,b);
temp = f == LE ? le(v,make_fraction(u,a)) : lessthan(v,make_fraction(u,a));
*ans = and(lessthan(zero,v), temp);
return 0;
}
if( f == NE && FUNCTOR(a) == '/' && ZERO(b))
{ u = ARG(0,a);
if(obviously_nonzero(u))
*ans = trueterm;
else
*ans = ne(u,zero);
/* regardless of the denom; the denom need not be defined */
return 0;
}
if( f == '=' && FUNCTOR(a) == '/' && ZERO(b))
{ u = ARG(0,a);
v = ARG(1,a);
if(OBJECT(u))
*ans = and(equation(u,zero),ne(v,zero));
else if(OBJECT(v))
*ans = equation(u,zero);
else if(NEGATIVE(u) && OBJECT(ARG(0,u)))
*ans = and(equation(ARG(0,u),zero),ne(v,zero));
else if(NEGATIVE(v) && OBJECT(ARG(0,v)))
*ans = equation(u,zero);
else
{ temp2 = domain(v);
if(equals(temp2,trueterm))
*ans = equation(u,zero);
else
*ans = and(temp2,equation(u,zero));
}
return 0;
}
if( f == NE && FUNCTOR(b) == '/' && ZERO(a))
{ u = ARG(0,b);
v = ARG(1,b);
if(OBJECT(u))
*ans = and(ne(u,zero),ne(v,zero));
else if(OBJECT(v))
*ans = ne(u,zero);
else if(NEGATIVE(u) && OBJECT(ARG(0,u)))
*ans = and(ne(u,zero),ne(v,zero));
else if(NEGATIVE(v) && OBJECT(ARG(0,v)))
*ans = ne(u,zero);
else
{ temp2 = domain(v);
if(equals(temp2,trueterm))
*ans = ne(u,zero);
else
*ans = and(temp2,ne(u,zero));
}
return 0;
}
if( f == '=' && FUNCTOR(b) == '/' && ZERO(a))
{ u = ARG(0,b);
v = ARG(1,b);
if(OBJECT(u))
*ans = and(equation(u,zero),ne(v,zero));
else if(OBJECT(v))
*ans = equation(u,zero);
else if(NEGATIVE(u) && OBJECT(ARG(0,u)))
*ans = and(equation(ARG(0,u),zero),ne(v,zero));
else if(NEGATIVE(v) && OBJECT(ARG(0,v)))
*ans = equation(u,zero);
else
*ans = and(domain(v),equation(u,zero));
return 0;
}
if( FUNCTOR(a) == '/' && FUNCTOR(b) == '/')
{ term p,q,p1,p2,q1,q2; /* u/p < v/q */
u = ARG(0,a);
p = ARG(1,a);
v = ARG(0,b);
q = ARG(1,b);
p1 = obviously_positive(p) ? trueterm : lessthan(zero,p);
if(equals(p,q)) /* comparing fractions with the same denominator */
/* u/p < v/p iff u<v and p > 0 */
{ temp = make_term(f,2);
ARGREP(temp,0,u);
ARGREP(temp,1,v);
if (f == '=' || f == NE || immediate(p1)==1) /* a common case, e.g. p = 2 */
{ *ans = temp;
return 0;
}
if(f == '=' || f == NE)
{ *ans = and(ne(p,zero),temp);
return 0;
}
p2 = obviously_negative(p) ? trueterm : lessthan(p,zero);
temp2 = make_term(f,2);
ARGREP(temp,0,v);
ARGREP(temp,1,u);
if(equals(p1,trueterm))
*ans = temp;
else if(equals(p2,trueterm))
*ans = temp2;
else
*ans = or(and(p1,temp),and(p2,temp2));
return 0;
}
/* comparing fractions with different denominators */
if(f == '=' || f == NE)
{ p2 = ne(p,zero);
q2 = ne(q,zero);
polyval(sum(product(q,u),tnegate(product(p,v))),&temp);
if(FUNCTOR(temp) == '+' && ARITY(temp) == 2 && NEGATIVE(ARG(1,temp)))
temp = f == '=' ? equation(ARG(0,temp),ARG(0,ARG(1,temp))) :
ne(ARG(0,temp),ARG(0,ARG(1,temp)));
else
temp = f == '=' ? equation(temp,zero) : ne(temp,zero);
*ans = and3(p2,q2,temp);
return 0;
}
p2 = obviously_negative(p) ? trueterm : lessthan(p,zero);
q1 = obviously_positive(q) ? trueterm : lessthan(zero,q);
q2 = obviously_negative(q) ? trueterm : lessthan(q,zero);
if(equals(p1,trueterm) && equals(q1,trueterm))
{ if(equals(u,v))
{ /* equal nums, positive denoms */
if(obviously_nonnegative(u))
{ *ans = make_term(f,2);
ARGREP(*ans,0,q);
ARGREP(*ans,1,p);
return 0;
}
if(obviously_nonnegative(strongnegate(u)))
{ *ans = make_term(f,2);
ARGREP(*ans,0,p);
ARGREP(*ans,1,q);
return 0;
}
temp = make_term(f,2);
ARGREP(temp,0,q);
ARGREP(temp,1,p);
temp2 = make_term(f,2);
ARGREP(temp,0,p);
ARGREP(temp,1,q);
*ans = or(and(le(zero,u),temp),and(le(u,zero),temp2));
return 0;
}
/* positive denoms, unequal nums. Cross-multiply */
*ans = make_term(f,2);
polyval(product(u,q),&temp);
polyval(product(v,p),&temp2);
ARGREP(*ans,0,temp);
ARGREP(*ans,1,temp2);
return 0;
}
else if(equals(p2,trueterm) && equals(q2,trueterm))
{ if(equals(u,v))
{ /* equal nums, negative denoms */
if(obviously_nonnegative(u))
{ *ans = make_term(f,2);
ARGREP(*ans,0,p);
ARGREP(*ans,1,q);
return 0;
}
if(obviously_nonnegative(strongnegate(u)))
{ *ans = make_term(f,2);
ARGREP(*ans,0,q);
ARGREP(*ans,1,p);
return 0;
}
temp = make_term(f,2);
ARGREP(temp,0,q);
ARGREP(temp,1,p);
temp2 = make_term(f,2);
ARGREP(temp,0,p);
ARGREP(temp,1,q);
*ans = or(and(le(zero,u),temp2),and(le(u,zero),temp));
return 0;
}
/* negative denoms, unequal nums. Cross-multiply */
*ans = make_term(f,2);
polyval(product(u,q),&temp);
polyval(product(v,p),&temp2);
ARGREP(*ans,0,temp2);
ARGREP(*ans,1,temp);
return 0;
}
else if(
(equals(p1,trueterm) && equals(q2,trueterm)) ||
(equals(p2,trueterm) && equals(q1,trueterm))
)
{ /* denoms have opposite signs. Cross-multiply and change the sense */
if(equals(u,v))
{ /* equal nums */
*ans = make_term(f,2);
ARGREP(*ans,0,p);
ARGREP(*ans,1,q);
return 0;
}
polyval(product(u,q),&temp);
polyval(product(v,p),&temp2);
*ans = make_term(f,2);
ARGREP(*ans,0,temp2);
ARGREP(*ans,1,temp);
return 0;
}
else /* can't determine the signs of the denoms */
{ polyval(product(u,q),&temp);
polyval(product(v,p),&temp2);
ans1 = make_term(f,2);
ARGREP(ans1,0,temp);
ARGREP(ans1,1,temp2);
ans2 = make_term(f,2);
copy(temp2,ARGPTR(ans2));
copy(temp,ARGPTR(ans2)+1); /* avoid creating a DAG */
*ans = or(
and(or(and(p1,q1),and(p2,q2)),ans1),
and(or(and(p1,q2),and(p2,q1)),ans2)
);
return 0;
}
}
temp = lessthan(a,b);
stoploop = get_whichvar(temp,&whichvar);
RELEASE(temp);
if( FUNCTOR(b) == '/' && FUNCTOR(a) != '/' /* a < u/v */
&& (stoploop || !already_solved(a,b,whichvar)) /* stop loops as on n < 1/2 */
)
{ term w;
u = ARG(0,b);
v = ARG(1,b);
temp = make_term(f,2);
if(
(FUNCTOR(a) == '+' && FUNCTOR(v) != '+') ||
(FUNCTOR(v) == '+' && FUNCTOR(a) != '+')
)
{ err2 = mvpolymult2(a,v,&w);
if(err2)
w = product(a,v);
}
else
w = product(a,v);
ARGREP(temp,0,w);
ARGREP(temp,1,u);
if(f == '=' || f == NE)
{ *ans = and(ne(v,zero),temp);
return 0;
}
temp2 = make_term(f,2);
ARGREP(temp2,0,u);
ARGREP(temp2,1,product(v,a));
*ans = or(and(lessthan(zero,v),temp),and(lessthan(v,zero),temp2));
return 0;
}
if( FUNCTOR(a) == '/' && FUNCTOR(b) != '/' && /* u/v < b */
(stoploop || !already_solved(a,b,whichvar))
)
{ term w;
u = ARG(0,a);
v = ARG(1,a);
temp = make_term(f,2);
if(
(FUNCTOR(b) == '+' && FUNCTOR(v) != '+') ||
(FUNCTOR(v)=='+' && FUNCTOR(b) != '+')
)
{ err2 = mvpolymult2(v,b,&w);
if(err2)
w = product(v,b);
}
else
w = product(v,b);
ARGREP(temp,1,w);
ARGREP(temp,0,u);
if(f == '=')
{ *ans = temp; /* no need to throw in v != 0 */
return 0;
}
if(f == NE)
{ *ans = and(temp,ne(v,zero));
return 0;
}
temp2 = make_term(f,2);
ARGREP(temp2,1,u);
ARGREP(temp2,0,w);
*ans = or(and(lessthan(zero,v),temp),and(lessthan(v,zero),temp2));
return 0;
}
return 1;
}
/*___________________________________________________________*/
int simple_bounds(term t, term *ans)
/* return 0 if t is an inequality (< or LE), or an interval_as_and
(example: -1 < sin x < 1) that can be deduced
from simple bounds on standard functions (in that case *ans = true);
If t is a strict inequality and the corresponding non-strict
inequality can be deduced (as in cos x < 1) but the bound is sharp,
then return the corresponding NE term (as cos x != 1).
return 1 for failure to simplify t. */
/* Also return 0, with *ans= falseterm, in case t can be
refuted based on simple bounds on standard functions, for example,
1 < sin x, or sin x < -1. */
{ term u,v,a,b;
unsigned short f = FUNCTOR(t);
unsigned short g,h;
int err;
double z;
if(f != '<' && f != LE && f != NE && f != AND)
return 1;
u = ARG(0,t);
v = ARG(1,t);
if(interval_as_and(t))
{ a = ARG(0,u);
b = ARG(1,v);
f = FUNCTOR(ARG(1,u));
g = FUNCTOR(ARG(0,t));
h = FUNCTOR(ARG(1,t));
if(f == COS || f == SIN)
{ if(equals(a,minusone) && ONE(b))
{ if(g == LE && h == LE)
{ *ans = trueterm;
return 0;
}
if(g == '<' && h == LE)
{ *ans = ne(ARG(1,u),minusone);
return 0;
}
if(g == LE && h == '<')
{ *ans = ne(ARG(1,u),one);
return 0;
}
if(g == '<' && h == '<')
{ if(f == SIN)
{ *ans = ne(cos1(ARG(0,ARG(1,u))),zero);
return 0; /* odd multiples of pi/2 */
}
if(f == COS)
{ *ans = ne(sin1(ARG(0,ARG(1,u))),zero);
return 0;
}
}
}
else if(ONE(b) && !infer(lessthan(a,minusone)))
{ if(h == '<')
{ *ans = trueterm;
return 0;
}
if(h == LE)
{ *ans = v;
return 0;
}
}
else if(equals(a,minusone) && !infer(lessthan(one,b)))
{ if(g == '<')
{ *ans = trueterm;
return 0;
}
if(g == LE)
{ *ans = u;
return 0;
}
}
else if(!infer(lessthan(one,b)) && !infer(lessthan(a,minusone)))
{ *ans = trueterm;
return 0;
}
}
return 1; /* added 1.4.00 */
}
if(f == AND)
return 1; /* not an interval_as_and */
if(f == NE)
{ /* catch for example sin x != 4 and return true */
if(get_complex())
return 1;
if(
(FUNCTOR(u) == SIN || FUNCTOR(u) == COS) &&
seminumerical(v)
)
{ deval(v,&z);
if(z == BADVAL)
{ if(OBJECT(v) && TYPE(v) == BIGNUM)
{ *ans = trueterm; /* very large number */
return 0;
}
return 1; /* unknown causes, e.g. reciprocal of
a large bignum would get here */
}
if(fabs(z) > 1.0)
{ *ans = trueterm; /* sin and cos bounded between -1 and 1 */
return 0;
}
}
return 1;
}
/* Now f is LE or < */
if(FRACTION(u) && FRACTION(v) && equals(ARG(1,u),ARG(1,v)) &&
obviously_positive(ARG(1,u))
)
/* example, sin^n(u)/2^n <= 1/2^n */
{ u = ARG(0,u);
v = ARG(0,v);
}
if(ZERO(u)) /* catch 0 <= 1+cos x etc */
{ err = inf(v,&u);
if(err)
return 1;
if(ZERO(u))
{ *ans = f == LE ? trueterm : ne(v,zero);
return 0;
}
err = infer(le(zero,u));
if(err)
return 1;
if(f == LE)
{ *ans = trueterm;
return 0;
}
/* Now f == '<' */
err = infer(lessthan(zero,u));
if(!err)
{ *ans = trueterm;
return 0;
}
*ans = ne(v,zero);
return 0;
}
if(constant(u) && !ATOMIC(v))
/* lower bounds */
{ g = FUNCTOR(v);
if(g == '^' && POSNUMBER(ARG(1,v)))
/* handle sin^k x >= -1 as well as sin x >= -1 */
{ v = ARG(0,v);
g = FUNCTOR(v);
}
if((g == SEC || g == CSC) && !infer(le(u,one)))
{ if(f == '<' || !infer(lessthan(u,minusone)))
{ *ans = trueterm;
return 0;
}
return 1;
}
if((g == COS || g == SIN) && !infer(le(u,minusone)))
{ if(f == LE || !infer(lessthan(u,minusone)))
{ *ans = trueterm;
return 0;
}
if(equals(u,minusone))
{ *ans = ne(v,u); /* -1 < sin x iff -1 != sin x; the latter is easier to solve */
return 0;
}
return 1;
}
if((g == COS || g == SIN) && !infer(le(one,u)))
{ if(ONE(u) && f == LE)
{ *ans = equation(v,u); /* 1 <= sin x iff sin x == 1 */
return 0;
}
if(f == '<' || !infer(lessthan(one,u)))
{ *ans = falseterm; /* refute 1 < cos x or 2 <= cos x */
return 0;
}
}
return 1;
/* -1 < cos a if a isn't an odd multiple of pi */
/* -1 < sin a if a+pi/2 isn't an even multiple of pi */
/* These are too hard to express and look too complicated
anyway, better to leave these inequalities alone. */
}
if(constant(v) && !ATOMIC(u))
/* upper bounds */
{ g = FUNCTOR(u);
if(g == '^' && POSNUMBER(ARG(1,u)))
/* handle sin^k x >= -1 as well as sin x >= -1 */
{ u = ARG(0,u);
g = FUNCTOR(u);
}
if(g != COS && g != SIN)
return 1;
if(ONE(v) && f == LE)
{ *ans = trueterm;
return 0;
}
if(ONE(v) && f == '<')
{ *ans = ne(v,one);
return 0;
}
err = infer(le(one,v));
if(err)
return 1;
if(f == LE)
{ *ans = trueterm; /* cos a \le 1 */
return 0;
}
err = infer(lessthan(one,v));
if(!err)
{ *ans = trueterm;
return 0;
}
return 1; /* give up, inequality too complicated */
}
if(FUNCTOR(u) == SIN && equals(v,ARG(0,u)) && obviously_nonnegative(v))
{ if(f == LE)
{ *ans = trueterm;
return 0;
}
if(obviously_positive(v))
{ *ans = trueterm;
return 0;
}
*ans = ne(v,zero);
return 0;
}
if(f == '<' && FUNCTOR(u) == SIN && equals(v,ARG(0,u)) && obviously_positive(v))
{ *ans = trueterm;
return 0;
}
return 1;
}
/*___________________________________________________________________*/
static int solve_it(term leftside, term rightside, unsigned short f, term *ans)
/* determine variable v: the eigenvariable if leftside or rightside
contains it, otherwise, the unique variable in leftside = rightside if there
is only one; else fail. Then if v occurs on only one side of the
equation, try to solve it using invert_ineq or other methods.
Return 0 for success, 1 for failure.
f is the functor of the 'equation', which can be NE or an inequality
as well as =.
If the equation is already solved, so that *ans would be the
original equation, that counts as failure.
Always return a solved inequality with functor < or LE, not > or GE.
But a solved equation can have the variable on either side.
*/
{ term v = get_eigenvariable();
int nvariables = get_nvariables();
term *varlist = get_varlist();
term temp;
int l,r,ll,rr,i,err,count=0;
l = contains(leftside,FUNCTOR(v));
r = contains(rightside,FUNCTOR(v));
if(l && r)
return 1;
if(!l && !r) /* look for a unique v */
{ for(i=0;i<nvariables;i++)
{ temp = varlist[i];
ll = contains(leftside,FUNCTOR(temp));
rr = contains(rightside,FUNCTOR(temp));
if(ll && rr)
return 1; /* some variable on both sides */
if(ll || rr)
{ ++count;
v = temp;
l = ll; /* record which side we found v on */
r = rr;
}
}
if(count != 1)
return 1; /* no variable, or two or more variables */
}
if(l)
{ if(equals(leftside,v))
return 1; /* already solved */
if(f == '=' || f == NE)
err = invert_eqn(leftside,rightside,v,&temp);
else
err = invert_ineq(leftside,rightside,v,&temp,&f);
if(err < 0 && f== '=') /* impossible equation */
{ *ans = falseterm;
return 0;
}
if(err < 0 && f== NE) /* impossible equation is valid NE*/
{ *ans = trueterm;
return 0;
}
if(!err)
{ *ans = make_term(f,2);
ARGREP(*ans,0,v);
ARGREP(*ans,1,temp);
goto success;
}
return 1;
}
else if(r)
{ if(equals(rightside,v))
return 1; /* already solved */
if(f == '=' || f == NE)
err = invert_eqn(rightside,leftside,v,&temp);
else
{ f = SWITCH(f);
err = invert_ineq(rightside,leftside,v,&temp,&f);
}
if(err < 0 && f== '=') /* impossible equation */
{ *ans = falseterm;
return 0;
}
if(err < 0 && f== NE) /* impossible equation is valid NE*/
{ *ans = trueterm;
return 0;
}
if(!err)
{ if(f == '>' || f == GE)
{ *ans = make_term(SWITCH(f),2);
ARGREP(*ans,1,v);
ARGREP(*ans,0,temp);
goto success;
}
*ans = make_term(f,2);
ARGREP(*ans,0,v);
ARGREP(*ans,1,temp);
goto success;
}
return 1;
}
assert(0); /* either l or r was nonzero */
success:
if(get_binders() == NULL)
SETPRIME(*ans);
else
{ term h,a,q;
err = get_infinitesimal(&h,&a,&q);
if(!err && !contains(*ans,FUNCTOR(h)))
SETPRIME(*ans);
}
if(FUNCTOR(*ans) == '>')
*ans = lessthan(ARG(1,*ans),ARG(0,*ans));
else if(FUNCTOR(*ans) == GE)
*ans = le(ARG(1,*ans),ARG(0,*ans));
return 0;
}
/*_________________________________________________________________________*/
static int one_sign(term a)
/* a is a sum. Return 1 if all the summands are nonnegative and at least
one positive number is among them.
Also a sum of the form x + sqrt(x^2 + positive) is positive.
Return -1 if all are nonpositive and at
least one negative number is among them.
Return 0 otherwise (can't prove the function is all of one sign this way)
For speed, and to avoid creating new variables by analyzing trig
functions, this function applies only limited tests for positivity to
the summands. */
{ int flag = 0;
int err,i,sign;
term u,v,p,q;
double z;
unsigned short n = ARITY(a);
if(n==2)
{ // check for the special case x + sqrt(x^2+positive)
if(FUNCTOR(ARG(0,a)) == SQRT || FUNCTOR(ARG(0,a)) == '^')
{ u = ARG(1,a);
v = ARG(0,a);
}
else
{ u = ARG(0,a);
v = ARG(1,a);
}
if(
(FUNCTOR(v) == SQRT && FUNCTOR(ARG(0,v)) == '+' && ARITY(ARG(0,v)) == 2) ||
(FUNCTOR(v) == '^' && equals(ARG(1,v),make_fraction(one,two)) && FUNCTOR(ARG(0,v)) == '+' && ARITY(ARG(0,v)) == 2)
)
{ p = ARG(0,ARG(0,v));
q = ARG(1,ARG(0,v));
if(FUNCTOR(p) == '^' && equals(ARG(1,p),two) && equals(ARG(0,p),u) && !infer(lessthan(zero,q)))
return 1;
if(FUNCTOR(q) == '^' && equals(ARG(1,q),two) && equals(ARG(0,q),u) && !infer(lessthan(zero,p)))
return 1;
}
}
if(n==2 && (NEGATIVE(ARG(1,a)) || NEGATIVE(ARG(0,a))))
{ // check for the special case x - sqrt(x^2+positive) (which is negative, so -1 will be returned)
if(NEGATIVE(ARG(1,a)))
{ v = ARG(0,ARG(1,a));
u = ARG(0,a);
}
else
{ u = ARG(0,ARG(0,a));
v = ARG(1,a);
}
if(
(FUNCTOR(v) == SQRT && FUNCTOR(ARG(0,v)) == '+' && ARITY(ARG(0,v)) == 2) ||
(FUNCTOR(v) == '^' && equals(ARG(1,v),make_fraction(one,two)) && FUNCTOR(ARG(0,v)) == '+' && ARITY(ARG(0,v)) == 2)
)
{ p = ARG(0,ARG(0,v));
q = ARG(1,ARG(0,v));
if(FUNCTOR(p) == '^' && equals(ARG(1,p),two) && equals(ARG(0,p),u) && !infer(lessthan(zero,q)))
return -1;
if(FUNCTOR(q) == '^' && equals(ARG(1,q),two) && equals(ARG(0,q),u) && !infer(lessthan(zero,p)))
return -1;
}
}
for(i=0;i<n;i++)
{ u = ARG(i,a);
if(OBJECT(u) && !ZERO(u))
{ if(flag < 0)
return 0; /* both neg and pos terms */
flag = 1;
}
else if(FUNCTOR(u)=='-' && OBJECT(ARG(0,u)))
{ if(flag > 0)
return 0;
flag = -1;
}
else if(seminumerical(u) && !deval(u,&z) && z != BADVAL)
{ /* example, u = sqrt(3) */
if(z > 0.0)
{ if(flag < 0)
return 1;
flag = 1;
}
else if(z < 0.0)
{ if(flag > 0)
return 1;
flag = -1;
}
}
}
if(flag==0)
return 0; /* no seminumerical term present, failure */
if(n == 2 && (contains(a,SIN) || contains(a,COS)))
/* catch sin x - 1 etc */
{ p = ARG(0,a);
q = ARG(1,a);
if(FUNCTOR(p) == COS || FUNCTOR(p) == SIN)
{ err = deval(q,&z);
if(!err)
{ if(z > 1.0)
return 1;
if(z < -1.0)
return -1;
}
}
else if(FUNCTOR(q) == COS || FUNCTOR(q) == SIN)
{ err = deval(p,&z);
if(!err)
{ if(z > 1.0)
return 1;
if(z < -1.0)
return -1;
}
}
}
for(i=0;i<n;i++)
{ u = ARG(i,a);
if(OBJECT(u) || (FUNCTOR(u)=='-' && OBJECT(ARG(0,u))))
continue;
sign = easy_sign(u); /* 1 or -1 if sign can be determined */
if(sign != flag)
return 0;
}
return flag;
}
/*____________________________________________________________________*/
static int easy_sign(term t)
/* return 1 if t is obviously nonnegative, -1 if obviously
negative, 0 if can't easily tell. */
{ unsigned short n;
int sign,sign2,i;
if(ISATOM(t))
{ if(equals(t,eulere) || equals(t,pi_term))
return 1;
return 0;
}
if(OBJECT(t))
return 1;
if(FUNCTOR(t) == '+')
return one_sign(t);
if(FUNCTOR(t) == SQRT)
return 1;
if(FUNCTOR(t) == ROOT && iseven(ARG(0,t)))
return 1;
if(NEGATIVE(t))
return -easy_sign(ARG(0,t));
if(FRACTION(t))
{ if(OBJECT(ARG(1,t)))
return easy_sign(ARG(0,t));
if(OBJECT(ARG(0,t)))
return easy_sign(ARG(1,t));
sign = easy_sign(ARG(0,t));
if(!sign)
return 0; /* failure */
sign2 = easy_sign(ARG(1,t));
if(!sign2)
return 0;
return sign * sign2;
}
if(FUNCTOR(t) == '^')
{ if(iseven(ARG(1,t)))
return 1;
return 0;
}
if(FUNCTOR(t) == '*')
{ n = ARITY(t);
sign = 1;
for(i=0;i<n;i++)
{ sign *= easy_sign(ARG(i,t));
if(!sign)
return 0;
}
return sign;
}
return 0;
}
/*___________________________________________________________________*/
int isdifofsquares(term t)
/* return 1 if t has the form a^2-b^2 or -a^2 + b^2,
or a^2-1 or -1 + a^2. Else return 0 */
{ term u,v;
if(FUNCTOR(t) != '+' || ARITY(t) != 2)
return 0;
u = ARG(0,t);
v = ARG(1,t);
if(NEGATIVE(u) && NEGATIVE(v))
return 0; /* just ONE of them must be negative */
if(NEGATIVE(u))
u = ARG(0,u);
else if(NEGATIVE(v))
v = ARG(0,v);
else
return 0;
if(ONE(u) && FUNCTOR(v) == '^' && equals(ARG(1,v),two))
return 1;
if(ONE(v) && FUNCTOR(u) == '!' && equals(ARG(1,u),two))
return 1;
if(FUNCTOR(u) != '^' || !equals(ARG(1,u),two))
return 0;
if(FUNCTOR(v) != '^' || !equals(ARG(1,v),two))
return 0;
return 1;
}
/*______________________________________________________________*/
static int reduce_trigsum(term t, term *ans)
/* reduce cos x <= 1 + sin x to cos x <= 0 or 0 <= sin x,
and reduce -1-sin x <= cos x to 0 <= sin x or 0 <= cos x,
and reduce cos x - sin x <= 1
and reduce -1 <= cos x + sin x
and similarly for strict inequalities. Put the answer in *ans.
Return 0 for success, 1 for failure; in case of failure,
*ans is garbage.
*/
{ term a,b,u,v,x;
unsigned short f,g,h;
f = FUNCTOR(t);
assert(ARITY(t)==2);
if(f != '<' && f != LE)
return 1;
if(PRIME(t))
return 1; /* already processed */
a = ARG(0,t);
b = ARG(1,t);
g = FUNCTOR(a);
h = FUNCTOR(b);
if(g == COS)
{ x = ARG(0,a);
if(h != '+' || ARITY(b) != 2)
return 1;
u = ARG(0,b);
v = ARG(1,b);
if(ONE(v))
{ v = u;
u = one;
}
if(ONE(u) && FUNCTOR(v) == SIN && equals(ARG(0,v),x))
{ /* cos x <= 1 + sin x */
*ans = f == LE ?
or(le(cos1(x),zero),le(zero,sin1(x))) :
or(lessthan(cos1(x),zero),lessthan(zero,sin1(x)));
return 0;
}
return 1;
}
if(h == COS)
{ x = ARG(0,b);
if(g != '+' || ARITY(a) != 2)
return 1;
u = ARG(0,a);
v = ARG(1,a);
if(!NEGATIVE(u))
return 1;
u = ARG(0,u);
if(!NEGATIVE(v))
return 1;
v = ARG(0,v);
if(ONE(v))
{ v = u;
u = one;
}
if(ONE(u) && FUNCTOR(v) == SIN && equals(ARG(0,v),x))
{ /* -1-sin x <= cos x */
*ans = f == LE ?
or(le(zero,cos1(x)),le(zero,sin1(x))) :
or(lessthan(zero,cos1(x)),lessthan(zero,sin1(x)));
return 0;
}
return 1;
}
if(ONE(b) && g == '+' && ARITY(a) == 2 && NEGATIVE(ARG(1,a)))
{ u = ARG(0,a);
v = ARG(1,ARG(1,a));
if(FUNCTOR(u) == COS && FUNCTOR(v) == SIN && equals(ARG(0,u),ARG(0,v)))
{ x = ARG(0,u);
*ans = f == LE ?
or(le(cos1(x),zero),le(zero,sin1(x))) :
or(lessthan(cos1(x),zero),lessthan(zero,sin1(x)));
return 0;
}
return 1;
}
if(equals(a,minusone) && FUNCTOR(b) == '+' && ARITY(b) == 2)
{ u = ARG(0,b);
v = ARG(1,b);
if(
(
(FUNCTOR(u) == COS && FUNCTOR(v) == SIN) ||
(FUNCTOR(v) == COS && FUNCTOR(u) == SIN)
) &&
equals(ARG(0,u),ARG(0,v))
)
{ x = ARG(0,u);
*ans = f == LE ?
or(le(zero,cos1(x)),le(zero,sin1(x))) :
or(lessthan(zero,cos1(x)),lessthan(zero,sin1(x)));
return 0;
}
return 1;
}
return 1;
}
/*__________________________________________________________________*/
static int contains_binders(term t)
/* return 1 if t contains a binding functor */
{ unsigned short n,f;
int i;
if(ATOMIC(t))
return 0;
f = FUNCTOR(t);
if(f == INTEGRAL || f == LIMIT || f == DIFF || f == LIMIT ||
f == SUM || f == PRODUCT
)
return 1;
n = ARITY(t);
for(i=0;i<n;i++)
{ if(contains_binders(ARG(i,t)))
return 1;
}
return 0;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists