Sindbad~EG File Manager
/* invert_ineq, which solves some inequalities in which the unknown occurs
only once. Domain needs this for interval_form, used in calculating
domains of definite integrals. */
/* M. Beeson
6.9.92 file created
1.29.98 last modified
*/
#include <assert.h>
#include <math.h>
#include "globals.h"
#include "prover.h"
#include "eqn.h"
#include "algaux.h"
#include "invineq.h"
#include "pvalaux.h" /* twoparts */
/*_________________________________________________________________*/
int invert_ineq(term u,term c,term x,term *ans,unsigned short *g)
/* solves some one-to-one inequalities (u<c or u<=c) assuming complex is off;
including linear equations, equations involving SQRT and ROOT and
trig and argtrig functions. The unknown x must occur only once and only
on the left side, i.e. in u. The variable g is used to pass IN the
inequality sign between u and c (which can be <, >, LE, or GE, but not NE)
and again to pass OUT the sign of the solved inequality x *g *ans.
returns 0 if x *g *ans solves u *g c for x;
returns -1 if equation is impossible, e.g. sin x = 2;
returns 1 if it can't figure it out, or an error condition arises,
such as a non-one-to-one function.
Example: if u is tan x; then *ans = arctan c
This function just applies inverse functions WITHOUT checking that
the resulting terms are defined. The calling function should then
check that *ans is defined.
*/
{ term a,v,denom,num,temp,power;
unsigned short f;
int err,sign;
unsigned short originalg = *g; /* restore it before failing */
start: /* label used for tail recursion */
sign = 0;
if(contains(c,FUNCTOR(x))) /* x must appear only on the left */
{ *g = originalg;
return 1;
}
if(equals(u,x)) /* already solved */
{ *ans = c;
return 0;
}
if(ATOMIC(u))
{ *g = originalg;
return 1; /* should never get such a call */
}
f = FUNCTOR(u);
v = ARG(0,u);
if(f=='/' && ZERO(c)) /* a/b < 0 iff ab < 0 etc */
{ denom = ARG(1,u);
polyval(signedproduct(v,denom),&temp);
err = invert_ineq(temp,zero,x,ans,g);
if(err)
return err;
if(*g == LE || *g == GE)
/* careful: 1/x \le 0 isn't equivalent to x\le 0,
and a/b \le 0 isn't equivalent to a/b < 0 either */
{ err = infer(ne(zero,v));
if(!err)
{ *g = SWITCH(*g);
return 0;
}
err = infer(ne(zero,denom));
if(!err)
return 0; /* without changing *g */
*g = originalg;
return 1; /* if can't determine that either num or denom is
nonzero, it's too hard. */
}
}
if(f=='/' && !contains(ARG(1,u),FUNCTOR(x)))
{ denom = ARG(1,u);
err = infer(lessthan(zero, denom));
if(err)
{ err = infer(lessthan(denom,zero));
if(err)
{ *g = originalg;
return 1; /* can't determine sign of denom */
}
*g = SWITCH(*g);
}
polyval(signedproduct(denom,c),&temp);
u = v;
c = temp;
goto start;
}
if(f=='/' && !contains(v,FUNCTOR(x)))
{ denom = ARG(1,u);
err = infer(lessthan(zero, denom));
if(err)
{ err = infer(lessthan(denom,zero));
if(err)
{ *g = originalg;
return 1; /* can't determine sign of denom */
}
*g = SWITCH(*g);
}
polyval(signedfraction(v,c),&temp);
u = denom;
c = temp;
goto start;
}
if(f=='*')
{ twoparts(u,x,&a,&v);
if(ONE(a))
return 1; /* u is a product of two or more terms containing x */
if((OBJECT(a) || RATIONALP(a)) && !ISZERO(a))
/* don't call infer in this simple case */
err = 0;
else
err = infer(lessthan(zero, a));
if(err)
{ err = infer(lessthan(a,zero));
if(err)
return 1; /* can't determine sign of denom */
*g = SWITCH(*g);
}
polyval(signedfraction(c,a),&temp);
u = v;
c = temp;
goto start;
}
if(f=='+')
{ unsigned short i, n = ARITY(u);
int count=0,marker = 0; // marker is initialized just to silence a warning
term s;
if(n==2) /* common case */
{ for(i=0;i<2;i++)
{ if(!contains(ARG(i,u),FUNCTOR(x)))
{ polyval(sum(c,tnegate(ARG(i,u))),&temp);
return invert_ineq(ARG(i ? 0 : 1,u),temp,x,ans,g);
}
}
return 1;
}
assert(n > 2);
for(i=0;i<n;i++)
{ s = ARG(i,u);
if(contains(s,FUNCTOR(x)))
{ if(count)
{ *g = originalg;
return 1; /* more than one term with x in it */
}
else
{ ++count;
marker = i;
}
}
}
if(!count)
{ *g = originalg;
return 1;
}
temp = make_term('+',(unsigned short)(n-1));
/* put all the terms except the one with index marker in temp */
for(i=0;i<n;i++)
{ if(i<marker)
ARGREP(temp,i,ARG(i,u));
else if (i> marker)
ARGREP(temp,i-1,ARG(i,u));
}
polyval(sum(c,tnegate(temp)),&a);
u = ARG(marker,u);
c = a;
goto start;
}
if(f=='^' && !contains(v,FUNCTOR(x)))
{ if(equals(v,eulere))
return invert_ineq(ARG(1,u),ln1(c),x,ans,g);
err = infer(lessthan(zero,v));
if(err)
{ *g = originalg;
return 1; /* negative base too hard */
}
u = ARG(1,u);
c = make_fraction(ln1(c),ln1(v));
goto start;
}
if(f=='^' && INTEGERP(ARG(1,u)) && ISODD(ARG(1,u)) && !contains(c,FUNCTOR(x)))
/* x^3 = -1 for example */
{ if(NEGATIVE(c))
{ c = ARG(0,c);
sign = -1;
}
else
sign = 1;
if(FUNCTOR(c) == '^')
{ polyval(product(ARG(1,c),reciprocal(ARG(1,u))),&temp);
temp = make_power(ARG(0,c),temp);
}
else
temp = make_power(c,reciprocal(ARG(1,u)));
u = v;
c = sign == -1 ? tnegate(temp) : temp;
goto start;
}
if(f=='^' && !contains(ARG(1,u),FUNCTOR(x)))
{ /* lambda(x,x^n) is one-one only if n is an odd integer,
or a rational with an odd denom and odd num */
power = ARG(1,u);
err = infer(le(zero,v));
if(!err) /* then need not worry about whether power is odd or not */
{ /* but we still need to know if power >0 or < 0 */
err = infer(lessthan(zero,power));
if(err)
{ err = infer(lessthan(power,zero));
if(err)
return 1;
*g = SWITCH(*g);
}
if(!infer(le(zero,c)) || !infer(odd(power)))
{ polyval(make_power(c,reciprocal(power)),&temp);
u = v;
c = temp;
goto start;
}
/* c < 0 and power is even */
*g = originalg;
return 1;
}
if(FRACTION(power))
{ num = ARG(0,power);
denom = ARG(1,power);
if(!INTEGERP(num))
{ err = infer(type(num,INTEGER));
if(err)
{ *g = originalg;
return 1;
}
}
if(!INTEGERP(denom))
{ err = infer(type(denom,INTEGER));
if(err)
{ *g = originalg;
return 1;
}
}
err = infer(odd(denom));
if(err)
{ *g = originalg;
return 1;
}
err = infer(odd(num));
if(err)
{ *g = originalg;
return 1;
}
}
else if(!INTEGERP(power))
{ err = infer(type(power,INTEGER));
if(err)
{ *g = originalg;
return 1;
}
err = infer(odd(power));
if(err)
{ *g = originalg;
return 1;
}
}
err = infer(even(power));
if(!err)
/* function isn't one-one, so can't invert unless v has one sign */
{ err= infer(le(zero,v)); /* then it would still be ok */
if(err)
{ err = infer(le(v,zero));
if(err)
{ *g = originalg;
return 1;
}
else
sign = -1;
}
else
sign = 1;
}
else
{ err = infer(odd(power));
if(err)
{ *g = originalg;
return 1; /* can't tell if power is even or odd */
}
}
if(!infer(le(zero,c)) || !infer(odd(power)))
{ polyval(make_power(c,reciprocal(power)),&temp);
if(sign == -1)
{ *g = SWITCH(*g);
temp = tnegate(temp);
}
u = v;
c = temp;
goto start;
}
*g = originalg;
return 1;
}
if(f==ROOT)
{ if(contains(v,FUNCTOR(x)))
return 1;
u = ARG(1,u);
c = make_power(c,ARG(0,u));
goto start;
}
if(ARITY(u) != 1)
return 1;
if(f == FUNCTOR(c))
{ u = v;
c = ARG(0,c);
goto start;
}
u = v;
switch(f)
{ case '-' :
c = tnegate(c);
if(*g != '=' && *g != NE)
*g = SWITCH(*g);
break;
case TAN :
c = atan1(c);
break;
case SQRT:
c = make_power(c,two);
break;
case LN :
c = make_power(eulere,c);
break;
case SINH:
c = asinh1(c);
break;
case ASINH:
c = sinh1(c);
break;
case ATAN :
c = tan1(c);
break;
case COT :
c = atan1(reciprocal(c));
break;
case ACOT :
c = cot1(c);
break;
case TANH:
c = atanh1(c);
break;
case ATANH:
c = tanh1(c);
break;
default:
return 1; /* nothing more to try */
}
goto start; /* tail recursion */
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists