Sindbad~EG File Manager
/* inequality operators;
but addeqn1, subeqn1, switchsides1,changesigns1 (for strict inequalities)
and addeqn2, subeqn2 etc. (for non-strict ineqs) are in eqn.c;
M. Beeson
Original date: 7.5.91
Last modified 2.27.98
modified oddrootineq_aux inserting strcat(reason, " ");
7.15.05 added set_noassumptions and get_noassumptions to control
whether select_ineq_divarg makes assumptions. This is called from safe_solve to
ensure that, e.g., on the AGM inequality it doesn't assume 0 < b. Only inequalities
are affected by this change.
1.20.06 corrected return value of nl_aux2 after check fails.
*/
#define ALGEBRA_DLL
#include <string.h>
#include <math.h>
#include "globals.h"
#include <assert.h>
#include "ops.h"
#include "operator.h"
#include "probtype.h"
#include "algaux.h"
#include "order.h"
#include "polynoms.h"
#include "eqn.h"
#include "factor.h"
#include "complex.h" /* rootofunity */
#include "mstring.h"
#include "solvelin.h"
#include "prover.h"
#include "symbols.h"
#include "cancel.h" /* naive_lcm */
#include "errbuf.h"
#include "deval.h"
#include "pvalaux.h" /* iseven, obviously_positive */
#include "simpprod.h" /* square */
#include "boole.h"
#include "deriv.h" /* derivative */
#include "autosimp.h" /* set_pathtail, SetShowStepOperation */
#include "advfact.h" /* nthroot_aux */
static int select_ineq_divarg(term, term *);
static int rootineq_aux(term, term, term *, char *);
static int p14even_aux(term ineq, term arg, term *next, char *reason);
/*______________________________________________________________*/
static int meq_aux(term arg, term *ans)
/* arg has come from muleqn_aux
if arg is positive, make *ans= arg;
if negative, make *ans = -arg;
if arg is constant, assume it's positive and make *ans = arg;
if arg isn't constant and isn't a product, and isn't positive, square it;
if arg is a product, treat it factor-by-factor recursively.
Return 0 for success, 1 when calling operator must fail.
*/
{ int i,err;
unsigned short n;
if(econstant(arg))
{ err = check(lessthan(zero,arg));
if(err)
{ *ans = strongnegate(arg); /* new value is positive */
err = check(positive(*ans));
if(err)
return 1;
return 0;
}
*ans = arg;
return 0;
}
/* So now arg wasn't constant; for example in solving (x+3)/x < 2, arg is x */
if(FUNCTOR(arg) != '*')
{ /* since arg is already in the denom, or is a SQRT in the num,
it can't be zero, so it's enough to infer that it's nonnegative;
we don't have to infer that it's positive. */
if(FUNCTOR(arg) == SQRT)
{ *ans = arg;
return 0; /* without calling infer */
}
err = infer(le(zero,arg));
if(err)
*ans = square(arg); /* this is definitely positive */
else
*ans = arg;
return 0;
}
/* Now we have to do it factor by factor, squaring some if needed */
n = ARITY(arg);
*ans = make_term('*',n);
for(i=0;i<n;i++)
{ err = meq_aux(ARG(i,arg),ARGPTR(*ans) + i);
if(err)
return 1;
}
return 0;
}
/*________________________________________________________________*/
MEXPORT_ALGEBRA int mulineq(term ineq, term arg, term *next, char *reason)
/* multiply both sides by ?
*/
{ term temp,x,u,v;
int err;
int sign = 1;
unsigned short f = FUNCTOR(ineq);
unsigned short g;
if(!INEQUALITY(f))
return 1;
if(FUNCTOR(arg) != ILLEGAL) /* we're in menu mode */
{ /* check that the sign of arg can be determined */
if(f == '<' || f == '>')
{ x = get_eigenvariable();
if(obviously_positive(arg))
{ sign = 1;
err = 0;
}
else if(obviously_negative(arg))
{ sign = -1;
err = 0;
}
if(!contains(arg,FUNCTOR(x)))
{ err = infer(lessthan(zero,arg));
if(err)
{ err = infer(lessthan(arg,zero));
if(err)
{ errbuf(0, english(1575));
/* Cannot determine the sign of the expression you chose. */
return 1;
}
sign = -1;
}
}
else
{ err = infer(le(zero,arg));
if(err)
{ err = infer(le(arg,zero));
if(err)
{ errbuf(0, english(1575));
/* Cannot determine the sign of the expression you chose. */
return 1;
}
sign = -1;
}
/* And now worry about the possibility that arg is zero */
err = infer(nonzero(arg));
if(err)
{ /* It still is OK if you can verify that at the zeroes
of arg, the old inequality is already false. */
subst(zero,arg,ineq,&u);
v = lpt(u);
err = equals(v,false) ? 0 : 1;
if(err)
{ errbuf(0, english(1732));
errbuf(1, english(1733));
errbuf(2, english(1734));
/* Cannot verify that the chosen expression is nonzero.
If it has zeroes that are not zeroes of the inequality, the
solution set would change. Therefore this multiplication is illegal. */
return 1;
}
}
}
}
else if (f == LE || f == GE)
{ if(obviously_nonnegative(arg))
{ sign = 1;
err = 0;
}
else if(NEGATIVE(arg) && obviously_nonnegative(ARG(0,arg)))
{ sign = -1;
err = 0;
}
else if(obviously_negative(arg))
{ sign = -1;
err = 0;
}
else
{ err = infer(le(zero,arg));
if(!err)
sign = 1;
else
{ err = infer(le(arg,zero));
if(err)
{ errbuf(0, english(1575));
/* Cannot determine the sign of the expression you chose. */
return 1;
}
sign = -1;
}
}
}
else
{ err = infer(nonzero(arg));
sign = 0;
}
if(err)
{ errbuf(0, english(1575));
/* Cannot determine the sign of the expression you chose. */
return 1;
}
if(sign >= 0)
return muleqn_aux(ineq,arg,next,reason);
else
{ err = muleqn_aux(ineq,arg,&temp,reason);
if(err)
return 1;
switch(f)
{ case '<' :
g = '>';
break;
case LE:
g = GE;
break;
case '>':
g = '<';
break;
case GE:
g = LE;
break;
default:
assert(0);
}
*next = make_term(g,2);
ARGREP(*next,0,ARG(0,temp));
ARGREP(*next,1,ARG(1,temp));
return 0;
}
}
/* So now we're in auto mode */
err = select_mularg(ineq,&arg);
if(err)
return 1;
err = meq_aux(arg,&temp);
if(err)
return 1;
return muleqn_aux(ineq,temp,next,reason);
}
/*________________________________________________________________*/
MEXPORT_ALGEBRA int mulineqsq(term ineq, term arg, term *next, char *reason)
/* multiply both sides by ?^2
*/
{ unsigned short f = FUNCTOR(ineq);
term u,v;
if(!INEQUALITY(f))
return 1;
if(FUNCTOR(arg) == ILLEGAL)
return 1; /* not used in auto mode */
muleqn_aux(ineq,square(arg),&u,reason);
if(f == '<' || f == '>' || !infer(nonzero(arg)))
{ *next = u;
return 0;
}
/* but if it's <=, we must make it a strict ineq and throw in
the possibility that the num is zero. */
if(f == LE)
SETFUNCTOR(u,'<',2);
else if(f == GE)
SETFUNCTOR(u,'>',2);
copy(ineq,&v);
SETFUNCTOR(v,'=',2);
*next = or(u,v);
return 0;
}
/*________________________________________________________________*/
MEXPORT_ALGEBRA int divineq(term ineq, term arg, term *next, char *reason)
/* divide both sides by ?
*/
{ unsigned short f = FUNCTOR(ineq);
int err;
if(!INEQUALITY(f))
return 1;
if(FUNCTOR(arg) == ILLEGAL)
{ err = select_ineq_divarg(ineq,&arg);
if(err)
return 1;
}
if(FUNCTOR(arg) != ILLEGAL)
return diveqn_aux(ineq,arg,next,reason);
/* diveqn_aux reverses the sense of the inequality if arg is negative */
return 1;
}
/*_______________________________________________________________*/
static char *reasonstrict[6] =
{ "$u^2 < v => |u| < �v$",
"$0�u<v^2 => �u < |v|$",
"$0 � u < v => �u < �v$", /* sqrtineq */
"$u < v => ��u < ��v$ ", /* (if n is odd) will be added by strcat */
"$u^2� < v => |u| < ^2��v$",
"$0�u<v^2� => ^2��u < |v|$"
};
static char *reasonle[6] =
{ "$u^2 � v => |u| � �v$",
"$0�u�v^2 => �u � |v|$",
"$0 � u � v => �u � �v$", /* sqrtineq */
"$u � v => ��u � ��v$", /* (if n is odd) will be added by strcat */
"$u^2� � v => |u| � ^2��v$",
"$0�u�v^2� => ^2��u � |v|$"
};
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sqrtineq11(term ineq, term arg, term *next, char *reason)
/* u^2 < v => |u| < �v */
{ term left;
unsigned short f = FUNCTOR(ineq);
if(!INEQUALITY(f))
return 1;
left = f == '<' ? ARG(0,ineq) : ARG(1,ineq);
if(!ATOMIC(left) && FUNCTOR(left) == '^')
return rootineq_aux(ineq,two,next,reason);
/* override automatic selection of arg */
return 1;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sqrtineq12(term ineq, term arg, term *next, char *reason)
/* 0 � u < v^2 => �u < |v| */
{ term right;
unsigned short f = FUNCTOR(ineq);
if(!INEQUALITY(f))
return 1;
right = f == '<' ? ARG(1,ineq) : ARG(0,ineq);
if(!ATOMIC(right) && FUNCTOR(right) == '^')
return rootineq_aux(ineq,two,next,reason); /* override automatic selection of arg */
return 1;
}
/*__________________________________________________________________*/
/* used only in menu mode */
MEXPORT_ALGEBRA int sqrtineq13(term ineq, term arg, term *next, char *reason)
/* 0 � u < v => �u < �v */
{ unsigned short f = FUNCTOR(ineq);
if(!INEQUALITY(f))
return 1;
return rootineq_aux(ineq,two,next,reason); /* override automatic selection of arg */
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sqrtineq21(term ineq, term arg, term *next, char *reason)
/* u^2 � v => |u| � �v */
{ term left;
unsigned short f = FUNCTOR(ineq);
if(f != LE && f != GE)
return 1;
left = f == LE ? ARG(0,ineq) : ARG(1,ineq);
if(!ATOMIC(left) && FUNCTOR(left) == '^')
return rootineq_aux(ineq,two,next,reason); /* override automatic selection of arg */
return 1;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int sqrtineq22(term ineq, term arg, term *next, char *reason)
/* 0 � u � v^2 => �u � |v| */
{ term right;
unsigned short f = FUNCTOR(ineq);
if(!INEQUALITY(f))
return 1;
right = f == LE ? ARG(1,ineq) : ARG(0,ineq);
if(!ATOMIC(right) && FUNCTOR(right) == '^')
return rootineq_aux(ineq,two,next,reason); /* override automatic selection of arg */
return 1;
}
/*__________________________________________________________________*/
/* used only in menu mode */
MEXPORT_ALGEBRA int sqrtineq23(term ineq, term arg, term *next, char *reason)
/* 0 � u � v => �u � �v */
{ unsigned short f = FUNCTOR(ineq);
if(f != LE && f != GE)
return 1;
return rootineq_aux(ineq,two,next,reason); /* override automatic selection of arg */
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int rootineq11(term ineq, term arg, term *next, char *reason)
/* u^2� < v => |u| < ^2��v */
{ term left;
unsigned short f = FUNCTOR(ineq);
if(!INEQUALITY(f))
return 1;
left = f == '<' ? ARG(0,ineq) : ARG(1,ineq);
if(FUNCTOR(left) == '^')
return rootineq_aux(ineq,arg,next,reason);
return 1;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int rootineq12(term ineq, term arg, term *next, char *reason)
/* 0 � u < v^2� => ^2��u < |v| */
{ term right;
unsigned short f = FUNCTOR(ineq);
if(!INEQUALITY(f))
return 1;
right = f== '<' ? ARG(1,ineq) : ARG(0,ineq);
if(FUNCTOR(right) == '^')
return rootineq_aux(ineq,arg,next,reason);
return 1;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int rootineq21(term ineq, term arg, term *next, char *reason)
/* u^2� � v => |u| � ^2��v */
{ term left;
unsigned short f = FUNCTOR(ineq);
if(!INEQUALITY(f))
return 1;
left = f== LE ? ARG(0,ineq) : ARG(1,ineq);
if(FUNCTOR(left) == '^')
return rootineq_aux(ineq,arg,next,reason);
return 1;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int rootineq22(term ineq, term arg, term *next, char *reason)
/* 0 � u � v^2� => ^2��u � |v| */
{ term right;
unsigned short f = FUNCTOR(ineq);
if(f != LE && f != GE)
return 1;
right = f == LE ? ARG(1,ineq) : ARG(0,ineq);
if(FUNCTOR(right) == '^')
return rootineq_aux(ineq,arg,next,reason);
return 1;
}
/*__________________________________________________________________*/
static int oddrootineq_aux(term ineq, term arg, term *next, char *reason)
/* workhorse of oddrootineq and oddrootineq2 */
{ int err,err2;
term left,right,newleft,newright;
unsigned short f = FUNCTOR(ineq);
if(!INEQUALITY(f))
return 1;
left = ARG(0,ineq);
right = ARG(1,ineq);
if(FUNCTOR(arg)==ILLEGAL) /* this can be so even in menu mode */
{ if(FUNCTOR(left) == '^' && !econstant(left))
{ arg = ARG(1,left);
if(get_mathmode() == AUTOMODE && !econstant(arg))
/* e.g. don't take x-th root of x^x */
{ errbuf(0, english(394));
/* Exponent must be constant for this to work. */
return 1;
}
}
else if(FUNCTOR(right) == '^' && !econstant(right))
arg = ARG(1,right);
else
{ errbuf(0, english(468));
/* This operator only works if there's an */
errbuf(1, english(469));
/* exponent on one side of the inequality. */
return 1;
}
}
err = infer(odd(arg));
if(err)
{ errbuf(0, english(470));
/* One side of the inequality must be */
errbuf(1, english(471));
/* an odd power for this to work. */
return 1;
}
err = nthroot_aux(left,arg,&newleft);
err2 = nthroot_aux(right,arg,&newright);
if(err2)
newright = make_root(arg,right);
/* sometimes nthroot_aux returns a ROOT term but we
don't fail in that case. */
if(err)
newleft = make_root(arg,left);
*next = make_term(f,2);
ARGREP(*next,0,newleft);
ARGREP(*next,1,newright);
HIGHLIGHT(*next);
strcpy(reason, (f=='<' ? reasonstrict[3] : reasonle[3]));
strcat(reason," ");
strcat(reason, english(2192)); /* (if n is odd) */
return 0;
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int oddrootineq(term ineq, term arg, term *next, char *reason)
{ unsigned short f = FUNCTOR(ineq);
if(!INEQUALITY(f))
return 1;
return oddrootineq_aux(ineq,arg,next,reason); /* override automatic selection of arg */
}
/*__________________________________________________________________*/
MEXPORT_ALGEBRA int oddrootineq2(term ineq, term arg, term *next, char *reason)
{ unsigned short f = FUNCTOR(ineq);
if(!INEQUALITY(f))
return 1;
return oddrootineq_aux(ineq,arg,next,reason); /* override automatic selection of arg */
}
/*__________________________________________________________________*/
static int rootineq_aux(term ineq, term arg, term *next, char *reason)
/* the workhorse of rootineq and sqrtineq etc. */
{ term left,right,newleft,newright;
int err,err2,err3;
long m;
unsigned short f = FUNCTOR(ineq); /* some inequality sign */
if(f == GE || f == '>') /* reduce to LE or '<' */
{ term temp,temp2;
invert(ineq,&temp);
err = rootineq_aux(temp,arg,&temp2, reason);
if(err)
{ RELEASE(temp);
return 1;
}
invert(temp2,next);
RELEASE(temp);
RELEASE(temp2);
return 0;
}
left = ARG(0,ineq);
right = ARG(1,ineq);
if(get_complex())
{ errbuf(0, english(472));
/* You can't take roots of inequalities */
errbuf(1, english(473));
/* with complex numbers turned on. */
return 1;
}
if(get_mathmode() == AUTOMODE)
{ if(!( (collected(left) && econstant(right)) ||
(collected(right) && econstant(left))
)
)
return 1;
}
if(FUNCTOR(arg)==ILLEGAL) /* this can be so even in menu mode */
{ if(FUNCTOR(left) == '^' && !econstant(left))
{ arg = ARG(1,left);
if(get_mathmode() == AUTOMODE && !econstant(arg))
/* e.g. don't take x-th root of x^x */
{ errbuf(0, english(474));
/* Exponent must be constant for this to work. */
return 1;
}
}
else if(FUNCTOR(right) == '^' && !econstant(right))
arg = ARG(1,right);
else
{ errbuf(0, english(468));
/* This operator only works if there's an */
errbuf(1, english(469));
/* exponent on one side of the inequality. */
return 1;
}
}
if(ISINTEGER(arg))
{ m = INTDATA(arg);
if(m==1)
return 1;
}
else /* arg isn't an integer (might still be a bignum) */
{ err = infer(and(type(arg,INTEGER),lessthan(zero,arg)));
if(err)
return 1;
m = -1; /* just so it isn't 2 */
}
err = (m==2 ? sqrt_aux(left,&newleft) : nthroot_aux(left,arg,&newleft));
err2 = (m==2 ? sqrt_aux(right,&newright) : nthroot_aux(right,arg,&newright));
if(err2)
newright = (m==2 ? make_sqrt(right) : make_root(arg,right));
else if(FUNCTOR(newright) == ROOT)
err2 = 1; /* sometimes nthroot_aux returns a ROOT term */
if(err)
newleft = (m==2 ? make_sqrt(left) : make_root(arg,left));
if(get_mathmode() != AUTOMODE)
err3 = infer(odd(arg)); /* if so this is easy */
else
err3 = 1; /* if arg were odd, we wouldn't be here in auto mode */
if(!err3)
{ *next = make_term(f,2);
ARGREP(*next,0,newleft);
ARGREP(*next,1,newright);
HIGHLIGHT(*next);
strcpy(reason, (f=='<' ? reasonstrict[3] : reasonle[3]));
strcat(reason, english(2192)); /* (if n is odd) */
return 0;
}
err3 = infer(le(zero,left));
if(err3)
{ errbuf(0, english(475));
/* This only works if the exponent is odd, */
errbuf(1, english(476));
/* or both sides of the inequality are � 0. */
return 1;
}
*next = make_term(f,2);
if(FUNCTOR(newleft) != SQRT &&
! (FUNCTOR(newleft) == ROOT && !infer(even(ARG(0,newleft))))
)
{ err3 = infer(le(zero,newleft));
if(err3)
newleft = abs1(newleft);
}
if(FUNCTOR(newright) != SQRT &&
! (FUNCTOR(newright) == ROOT && !infer(even(ARG(0,newright))))
)
{ err3 = infer(le(zero,newright));
if(err3)
newright = abs1(newright);
}
ARGREP(*next,0,newleft);
ARGREP(*next,1,newright);
HIGHLIGHT(*next);
if(FUNCTOR(newright)==ABS && m==2)
strcpy(reason, (f=='<' ? reasonstrict[1] : reasonle[1]));
else if(FUNCTOR(newleft) == ABS && m==2)
strcpy(reason, (f=='<' ? reasonstrict[0] : reasonle[0]));
else if(m==2)
strcpy(reason, (f=='<' ? reasonstrict[2] : reasonle[2]));
else if(err2 || FUNCTOR(newleft) == ABS)
strcpy(reason, (f=='<' ? reasonstrict[4] : reasonle[4]));
else
strcpy(reason, (f=='<' ? reasonstrict[5] : reasonle[5]));
return 0;
}
/*_____________________________________________________________________*/
void invert(term ineq, term *ans)
/* change '<' to '>' and GE to LE in inequalities or Boolean combinations thereof */
{ unsigned short f = FUNCTOR(ineq);
unsigned short n = ARITY(ineq);
int i;
if(ATOMIC(ineq))
{ *ans = ineq;
return;
}
switch(f)
{ case '<' : *ans = make_term('>',2);
ARGREP(*ans,0,ARG(1,ineq));
ARGREP(*ans,1,ARG(0,ineq));
return;
case LE : *ans = make_term(LE, 2);
ARGREP(*ans,0,ARG(1,ineq));
ARGREP(*ans,1,ARG(0,ineq));
return;
case '>' : *ans = lessthan(ARG(1,ineq),ARG(0,ineq));
return;
case GE : *ans = le(ARG(1,ineq),ARG(0,ineq));
return;
case AND : *ans = make_term(AND,n); break;
case OR : *ans = make_term(OR,n); break;
default : *ans = ineq; return;
}
for(i=0;i<n;i++)
invert(ARG(i,ineq),ARGPTR(*ans) + i);
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int mulineqbysquare1(term ineq, term arg, term *next, char *reason)
/* 0 < u/v => 0 < uv */
{ unsigned short f = FUNCTOR(ineq);
term denom;
if(f != '<' && f != '>')
return 1;
if(!ZERO(ARG(f == '<' ? 0 : 1,ineq)))
return 1;
if(!FRACTION(ARG(f == '<' ? 1: 0,ineq)))
return 1;
denom = ARG(1,ARG(f == '<' ? 1 : 0,ineq));
muleqn_aux(ineq, square(denom),next,reason);
SetShowStepArg(denom); /* muleqn_aux set it wrongly to square(denom) */
SetShowStepOperation(mulineqsq);
HIGHLIGHT(*next);
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int mulineqbysquare2(term ineq, term arg, term *next, char *reason)
/* u/v < 0 => uv < 0 */
{ unsigned short f = FUNCTOR(ineq);
term denom;
if(f != '<' && f != '>')
return 1;
if(!ZERO(ARG(f == '<' ? 1 : 0,ineq)))
return 1;
if(!FRACTION(ARG(f == '<' ? 0 : 1, ineq)))
return 1;
denom = ARG(1, ARG(f == '<' ? 0 : 1, ineq));
muleqn_aux(ineq, square(denom),next,reason);
SetShowStepArg(denom); /* muleqn_aux set it wrongly to square(denom) */
SetShowStepOperation(mulineqsq);
HIGHLIGHT(*next);
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int mulineqbysquare3(term ineq, term arg, term *next, char *reason)
/* 0 � u/v => 0 < uv or u = 0 */
{ unsigned short f = FUNCTOR(ineq);
term num, denom,temp;
int err;
if(f != LE && f != GE)
return 1;
if(!ZERO(ARG(f == LE ? 0 : 1,ineq)))
return 1;
if(!FRACTION(ARG(f == LE ? 1: 0,ineq)))
return 1;
denom = ARG(1,ARG(f == LE ? 1 : 0,ineq));
num = ARG(0,ARG(f == LE ? 1 : 0, ineq));
muleqn_aux(ineq, square(denom),&temp,reason);
SetShowStepArg(denom); /* muleqn_aux set it wrongly to square(denom) */
SetShowStepOperation(mulineqsq);
SETFUNCTOR(temp,(unsigned short)(f == LE ? '<' : '>'), 2);
err = infer(nonzero(num));
if(err)
{ *next = or(temp,equation(num,zero));
strcpy(reason, english(2190));
/* $0�u/v$ => 0<uv or u=0 */
}
else
*next = temp;
HIGHLIGHT(*next);
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int mulineqbysquare4(term ineq, term arg, term *next, char *reason)
/* u/v � 0 => uv < 0 or u = 0 */
{ unsigned short f = FUNCTOR(ineq);
term num, denom,temp;
int err;
if(f != LE && f != GE)
return 1;
if(!ZERO(ARG(f == LE ? 1 : 0,ineq)))
return 1;
if(!FRACTION(ARG(f == LE ? 0: 1,ineq)))
return 1;
denom = ARG(1,ARG(f == LE ? 0 : 1,ineq));
num = ARG(0,ARG(f == LE ? 0 : 1, ineq));
muleqn_aux(ineq, square(denom),&temp,reason);
SetShowStepArg(denom); /* muleqn_aux set it wrongly to square(denom) */
SetShowStepOperation(mulineqsq);
SETFUNCTOR(temp,(unsigned short)(f == LE ? '<' : '>'), 2);
err = infer(nonzero(num));
if(err)
{ *next = or(temp,equation(num,zero));
strcpy(reason, english(2191));
/* $u/v�0$ => uv<0 or u=0 */
}
else
*next = temp;
HIGHLIGHT(*next);
return 0;
}
/*______________________________________________________ */
/* �u < v => u < v^2 */
MEXPORT_ALGEBRA int powerineq11(term ineq, term arg, term *next, char *reason)
{ term left,right;
int err;
if(FUNCTOR(ineq) != '<' && FUNCTOR(ineq) != '>')
return 1;
left = FUNCTOR(ineq) == '<' ? ARG(0,ineq) : ARG(1,ineq);
right = FUNCTOR(ineq) == '<' ? ARG(1,ineq) : ARG(0,ineq);
if(FUNCTOR(left) != SQRT)
return 1;
err = check(le(zero,right));
if(err)
{ errbuf(0, english(1549)); /* Right side must be non-negative */
return 1;
}
*next = make_term(FUNCTOR(ineq),2);
ARGREP(*next, (FUNCTOR(ineq) == '<' ? 0 : 1), ARG(0,left));
ARGREP(*next,(FUNCTOR(ineq) == '<' ? 1 : 0), square(right));
HIGHLIGHT(*next);
strcpy(reason,"$�u < v => u < v^2$");
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerineq21(term ineq, term arg, term *next, char *reason)
/* �u � v => u � v^2 */
{ term left,right;
int err;
if(FUNCTOR(ineq) != LE && FUNCTOR(ineq) != GE)
return 1;
left = FUNCTOR(ineq) == LE ? ARG(0,ineq) : ARG(1,ineq);
right = FUNCTOR(ineq) == LE ? ARG(1,ineq) : ARG(0,ineq);
if(FUNCTOR(left) != SQRT)
return 1;
err = check(le(zero,right));
if(err)
{ errbuf(0, english(1549)); /* Right side must be non-negative */
return 1;
}
*next = make_term(FUNCTOR(ineq),2);
ARGREP(*next, (FUNCTOR(ineq) == LE ? 0 : 1), ARG(0,left));
ARGREP(*next,(FUNCTOR(ineq) == LE ? 1 : 0), square(right));
HIGHLIGHT(*next);
strcpy(reason,"$�u � v => u � v^2$");
return 0;
}
/*______________________________________________________ */
static int p12_aux(term ineq,term *next,char *reason)
/* used in next two operators */
{ int err;
term left,right;
int side = (FUNCTOR(ineq) == '<' || FUNCTOR(ineq) == LE);
left = side ? ARG(0,ineq) : ARG(1,ineq);
right = side ? ARG(1,ineq) : ARG(0,ineq);
if(FUNCTOR(right) != SQRT)
return 1;
err = econstant(left) ? check(le(zero,left)) : infer(le(zero,left));
if(err)
{ errbuf(0, english(477));
/* Left side is negative, so that won't work. */
return 1;
}
err = econstant(right)? check(le(zero,right)) : infer(le(zero,right));
if(err)
{ errbuf(0,english(1549)); /* Right side must be nonnegative. */
return 1;
}
*next = make_term(FUNCTOR(ineq),2);
ARGREP(*next,(side ? 0 : 1), square(left));
ARGREP(*next,(side ? 1 : 0),ARG(0,right));
HIGHLIGHT(*next);
if(FUNCTOR(ineq) == '<' || FUNCTOR(ineq) == '>')
strcpy(reason,"$0� u < �v => u^2 < v$");
else
strcpy(reason,"$0� u � �v => u^2 � v$");
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerineq12(term ineq, term arg, term *next, char *reason)
/* 0 � u < �v => u^2 < |v| */
{ if(FUNCTOR(ineq) != '<' && FUNCTOR(ineq) != '>')
return 1;
return p12_aux(ineq,next,reason);
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerineq22(term ineq, term arg, term *next, char *reason)
/* 0 � u � �v => u^2 � |v| */
{ if(FUNCTOR(ineq) != LE && FUNCTOR(ineq) != GE)
return 1;
return p12_aux(ineq,next,reason);
}
/*______________________________________________________ */
static term distribpower(term t, term n)
/* return t�, using (ab)� = a�b� and (��u)� = u */
{ term ans,u,v;
int i;
unsigned short m;
if(FUNCTOR(t)== ROOT && equals(ARG(0,t),n))
return ARG(1,t);
if(FUNCTOR(t) == SQRT && equals(n,two))
return ARG(0,t);
if(FUNCTOR(t) == SQRT)
{ polyval(make_fraction(n,two),&u);
return make_power(ARG(0,t),u);
}
if(FUNCTOR(t) != '*')
return make_power(t,n);
m = ARITY(t);
ans = make_term('*',m);
for(i=0;i<m;i++)
{ u = ARG(i,t);
if(FUNCTOR(u)==ROOT && equals(ARG(0,u),n))
ARGREP(ans,i,ARG(1,u));
else if(FUNCTOR(u) == SQRT)
{ polyval(make_fraction(n,two),&v);
ARGREP(ans,i,make_power(ARG(0,u),v));
}
else
ARGREP(ans,i,make_power(u,n));
}
return ans;
}
/*___________________________________________________________________*/
static int p14_aux(term ineq, term *next, char *reason)
/* used in next two operators */
/* ��u < v => u < v� and the same with LE instead of < */
/* if n is odd, this is fine. If n is even, it's only valid if
u >= 0; this will be true because the left side is defined.
Nevertheless the operator checks it, because of course we
may be doing limits where undefined expressions are allowed.
*/
{ term left, right, n, u;
int err;
int side = (FUNCTOR(ineq) == '<' || FUNCTOR(ineq) == LE);
left = side ? ARG(0,ineq) : ARG(1,ineq);
if(FUNCTOR(left) != ROOT)
return 1;
n = ARG(0,left); /* index of the root */
u = ARG(1,left);
right = side ? ARG(1,ineq) : ARG(0,ineq);
*next = make_term(FUNCTOR(ineq),2);
err = infer(odd(n));
if(err)
{ err = infer(le(zero,u));
if(err)
{ errbuf(0, english(1309));
/* Cannot verify the condition, n odd or u nonnegative. */
return 1;
}
}
ARGREP(*next, (side ? 0 : 1), ARG(1,left));
ARGREP(*next, (side ? 1 : 0), make_power(right,n));
HIGHLIGHT(*next);
if(FUNCTOR(ineq) == '<' || FUNCTOR(ineq) == '>')
strcpy(reason, english(482));
/* ��u < v => u < v� */
else
strcpy(reason, english(483));
/* ��u � v => u � v� */
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerineq14odd(term ineq, term arg, term *next, char *reason)
/* ��u < v => u < v� */
{ if(FUNCTOR(ineq) != '<' && FUNCTOR(ineq) != '>')
return 1;
return p14_aux(ineq,next,reason);
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerineq14even(term ineq, term arg, term *next, char *reason)
/* ^2��u < v iff 0 � u < v^2� */
{ if(FUNCTOR(ineq) != '<' && FUNCTOR(ineq) != '>')
return 1;
return p14even_aux(ineq,arg,next,reason);
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerineq24even(term ineq, term arg, term *next, char *reason)
/* ^2��u < v iff 0 � u < v^2� */
{ if(FUNCTOR(ineq) != LE && FUNCTOR(ineq) != GE)
return 1;
return p14even_aux(ineq,arg,next,reason);
}
/*______________________________________________________ */
static int p14even_aux(term ineq, term arg, term *next, char *reason)
/* ^2��u < v iff 0 � u < v^2�, or the same with LE */
/* ineq must have functor <, >, LE, or GE */
{ term left, right, n, u, w,temp;
int err;
unsigned short f = FUNCTOR(ineq);
int side = (f == '<' || f == LE);
left = side ? ARG(0,ineq) : ARG(1,ineq);
if(FUNCTOR(left) != ROOT)
return 1;
if(!iseven(ARG(0,left)))
{ errbuf(0, english(875)); /* Index of root must be even */
return 1;
}
n = ARG(0,left); /* index of the root */
u = ARG(1,left);
right = side ? ARG(1,ineq) : ARG(0,ineq);
*next = make_term(FUNCTOR(ineq),2);
err = infer(le(zero,u));
if(!err)
{ *next = make_term(FUNCTOR(ineq),2);
ARGREP(*next, (side ? 0 : 1), ARG(1,left));
ARGREP(*next, (side ? 1 : 0), make_power(right,n));
HIGHLIGHT(*next);
switch(f)
{ case '<' :
strcpy(reason, english(1608));
/* ^2��u<v iff u<v^2� (u>0) */
return 0;
case '>':
strcpy(reason, english(1609));
/* v>^2��u iff v^2�>u (u>0) */
return 0;
case LE:
strcpy(reason, english(1610));
/* ^2��u�v iff u�v^2� (u>0) */
return 0;
case GE:
strcpy(reason, english(1611));
/* v�^2��u iff v^2��u (u>0) */
return 0;
default:
assert(0);
}
}
copy(ARG(1,left),&temp); /* Avoid DAGs */
if(f == LE || f == GE)
w = le(ARG(1,left),make_power(right,n));
else
w = lessthan(ARG(1,left),make_power(right,n));
*next = and(le(zero,temp),w);
HIGHLIGHT(*next);
switch(f)
{ case '<':
strcpy(reason, english(1612)); /* ^2��u<v iff 0�u<v^2� */
return 0;
case '>':
strcpy(reason, english(1613)); /* v>^2��u iff 0�u<v^2� */
return 0;
case LE:
strcpy(reason, english(1614)); /* ^2��u�v iff 0�u�v^2� */
return 0;
case GE:
strcpy(reason, english(1615)); /* v�^2��u iff 0�u�v^2� */
return 0;
}
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerineq24odd(term ineq, term arg, term *next, char *reason)
/* ��u � v => u � v� */
{ if(FUNCTOR(ineq) != LE && FUNCTOR(ineq) != GE)
return 1;
return p14_aux(ineq,next,reason);
}
/*______________________________________________________ */
static int p13_aux(term ineq, term *next, char *reason)
/* used in next two operators */
/* 0 � a��u < v => a�u < v� and the same with LE */
{ term left, right, n;
int i;
unsigned short m;
term u;
int side = (FUNCTOR(ineq) == '<' || FUNCTOR(ineq) == LE);
left = side ? ARG(0,ineq) : ARG(1,ineq);
right = side ? ARG(1,ineq) : ARG(0,ineq);
if(FUNCTOR(left) == ROOT)
return p14_aux(ineq,next,reason);
if(FUNCTOR(left) != '*')
return 1;
m = ARITY(left);
for(i=0;i<m;i++)
{ u = ARG(i,left);
if(FUNCTOR(u) == ROOT)
break;
}
if(i==m)
return 1;
n = ARG(0,u); /* index of the root */
*next = make_term(FUNCTOR(ineq),2);
ARGREP(*next, (side ? 0 : 1), distribpower(left,n));
ARGREP(*next, (side ? 1 : 0), distribpower(right,n));
HIGHLIGHT(*next);
if(FUNCTOR(ineq) == '<' || FUNCTOR(ineq) == '>')
strcpy(reason, "$0�a(��u)<v => a�u<v�$");
else
strcpy(reason, "$0�a(��u)�v => a�u�v�$");
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerineq13(term ineq, term arg, term *next, char *reason)
/* 0 � a��u < v => a�u < v� */
{ if(FUNCTOR(ineq) != '<' && FUNCTOR(ineq) != '>')
return 1;
return p13_aux(ineq,next,reason);
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerineq23(term ineq, term arg, term *next, char *reason)
/* 0 � a��u � v => u � v� */
{ if(FUNCTOR(ineq) != LE && FUNCTOR(ineq) != GE)
return 1;
return p13_aux(ineq,next,reason);
}
/*______________________________________________________ */
static int squareineq_aux(term ineq, term *next, char *reason)
/* used in next two operators */
/* returns 1 if left side can't be proved nonnegative,
returns 2 if right side can't be checked nonnegative after
left side is proved nonnegative.
*/
{ term left, right;
int err;
unsigned short f = FUNCTOR(ineq);
int side = (f == '<' || f == LE);
left = side ? ARG(0,ineq) : ARG(1,ineq);
right = side ? ARG(1,ineq) : ARG(0,ineq);
*next = make_term(FUNCTOR(ineq),2);
err = infer(le(zero,left));
if(err)
{ errbuf(0, english(side ? 1559: 1578));
/* Left side must be nonnegative */
return 1;
}
/* check(le(zero,right)) is no longer good enough, now that check
refuses to make assumptions involving the eigenvariable */
err = infer(le(zero,right));
if(err)
{ err = infer(lessthan(right,zero));
if(!err)
{ errbuf(0, english(side ? 1576 : 1577));
/* Right side is negative */
return 2;
}
assume(le(zero,right));
commentbuf(0, english(2226));
/* !Assuming the previous right side is nonnegative. */
}
ARGREP(*next, (side ? 0 : 1), distribpower(left,two));
ARGREP(*next, (side ? 1 : 0), distribpower(right,two));
HIGHLIGHT(*next);
strcpy(reason, english(1553)); /* square both sides */
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int squareineq1(term ineq, term arg, term *next, char *reason)
/* u < v iff u^2 < v^2 provided u >= 0 can be inferred and
then v >= 0 can be checked. Some assumptions may be made during
this checking. Will this be legit? We must have
u < v iff (u^2 < v^2 && v >= 0)
which we do have if u >= 0 is inferred. Note then that is
is LEGAL AND NECESSARY to allow check to make assumptions that
depend on the eigenvariable here.
Example: abs(x) < x. We can infer abs(x) >= 0 so we
can square if we assume x >= 0. We get abs(x)^2 < x^2 which
simplifies to false, the correct answer. Explicitdomain does
not bring back the assumptions since they are combined by &&
with the current line, so if it's false that's the end.
*/
{ int err;
if(FUNCTOR(ineq) != '<' && FUNCTOR(ineq) != '>')
return 1;
err = squareineq_aux(ineq,next,reason);
if(err)
return 1;
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int squareineq2(term ineq, term arg, term *next, char *reason)
/* 0 � u � v => u^2 � v^2 */
{ int err;
if(FUNCTOR(ineq) != LE && FUNCTOR(ineq) != GE)
return 1;
err = squareineq_aux(ineq,next,reason);
if(err)
return 1;
return 0;
}
/*______________________________________________________ */
static int squareineq_extra(int strictflag, term ineq, term *next, char *reason)
/* used in next two operators */
{ term left,right,u;
int err;
unsigned short f = FUNCTOR(ineq);
int side = (f == '<' || f == LE);
left = side ? ARG(0,ineq) : ARG(1,ineq);
right = side ? ARG(1,ineq) : ARG(0,ineq);
err = squareineq_aux(ineq,next,reason);
if(!err)
return 0; /* No need for the second disjunct */
if(err == 1)
{ /* left can't be inferred nonnegative. */
err = infer(le(zero,right));
if(err)
{ errbuf(0,english(1549));
/* Right side must be (non-negative)*/
return 1;
}
}
if(err == 2)
{ /* Right side was proved negative */
errbuf(0, english(1549)); /* Right side must be (non-negative)*/
return 1;
}
u = make_term(FUNCTOR(ineq),2);
ARGREP(u, (side ? 0 : 1), distribpower(left,two));
ARGREP(u, (side ? 1 : 0), distribpower(right,two));
*next = or(u,strictflag ? lessthan(left,zero) : le(left,zero));
/* u < v is equivalent to u^2 < v^2 or u < 0 when we only know v >= 0 */
HIGHLIGHT(*next);
strcpy(reason, english(1553)); /* square both sides */
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int squareineq3(term ineq, term arg, term *next, char *reason)
/* u < v becomes u^2 < v^2 or u < 0 provided 0 <= v */
{ int err;
if(FUNCTOR(ineq) != '<' && FUNCTOR(ineq) != '>')
return 1;
err = squareineq_extra(1,ineq,next,reason);
if(err)
return 1;
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int squareineq4(term ineq, term arg, term *next, char *reason)
/* u <= v becomes u^2 <= v^2 or u <= 0 provided 0 <= v*/
{ int err;
if(FUNCTOR(ineq) != LE && FUNCTOR(ineq) != GE)
return 1;
err = squareineq_extra(0,ineq,next,reason);
if(err)
return 1;
return 0;
}
/*______________________________________________________ */
static int p15_aux(term ineq,term *next,char *reason)
/* used in next two operators */
{ int err;
term left,right,n;
int side = (FUNCTOR(ineq) == '<' || FUNCTOR(ineq) == LE);
left = side ? ARG(0,ineq) : ARG(1,ineq);
right = side ? ARG(1,ineq) : ARG(0,ineq);
if(FUNCTOR(right) != ROOT)
return 1;
n = ARG(0,right);
err = econstant(left) ? check(le(zero,left)) : infer(le(zero,left));
if(err)
{ errbuf(0, english(477));
/* Left side is negative, so that won't work. */
return 1;
}
*next = make_term(FUNCTOR(ineq),2);
ARGREP(*next,(side ? 0 : 1), make_power(left,n));
ARGREP(*next,(side ? 1 : 0), ARG(1,right));
HIGHLIGHT(*next);
if(FUNCTOR(ineq) == '<' || FUNCTOR(ineq) == '>')
strcpy(reason,"$0� u< ��v => u� < v$");
else
strcpy(reason,"$0� u� ��v => u� � v$");
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerineq15(term ineq, term arg, term *next, char *reason)
/* 0 � u < ��v => u� < v */
{ if(FUNCTOR(ineq)!= '<' && FUNCTOR(ineq) != '>')
return 1;
return p15_aux(ineq,next,reason);
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerineq25(term ineq, term arg, term *next, char *reason)
/* 0 � u � ��v => u� � v */
{ if(FUNCTOR(ineq)!= LE && FUNCTOR(ineq) != GE)
return 1;
return p15_aux(ineq,next,reason);
}
/*______________________________________________________ */
static int select_power( term left, term right, term *arg)
/* if one of left or right is a fractional power a/n or an n-th root,
return n in *arg and return 0. If both are fraction powers
return the lcm of the denoms in *arg, and return 0.
If neither is a fractional
power return 1.
*/
{ term n,m;
if(FUNCTOR(right) == '^' && FRACTION(ARG(1,right)))
m = ARG(1,ARG(1,right));
else if(FUNCTOR(right) == ROOT)
m = ARG(0,right);
else if(FUNCTOR(right) == SQRT)
m = two;
else
m = zero;
if(FUNCTOR(left) == '^' && FRACTION(ARG(1,left)))
n = ARG(1,ARG(1,left));
else if(FUNCTOR(left) == ROOT)
n = ARG(0,left);
else if(FUNCTOR(left) == SQRT)
n = two;
else
n = zero;
if(ZERO(m) && ZERO(n))
return 1;
if(ZERO(m))
{ *arg = n;
return 0;
}
if(ZERO(n))
{ *arg = m;
return 0;
}
naive_lcm(n,m,arg);
return 0;
}
/*______________________________________________________ */
static int p16_aux(term ineq,term arg,term *next,char *reason)
/* used in next two operators */
/* condition on arg has already been checked by check_arg */
{ term left,right;
int side = (FUNCTOR(ineq) == '<' || FUNCTOR(ineq) == LE);
int err;
left = side ? ARG(0,ineq) : ARG(1,ineq);
right = side ? ARG(1,ineq) : ARG(0,ineq);
*next = make_term(FUNCTOR(ineq),2);
if(FUNCTOR(arg) == ILLEGAL)
{ err = select_power(left,right,&arg);
if(err)
return 1;
}
ARGREP(*next,(side ? 0 : 1), make_power(left,arg));
ARGREP(*next,(side ? 1 : 0), make_power(right,arg));
HIGHLIGHT(*next);
if(FUNCTOR(ineq) == '<' || FUNCTOR(ineq) == '>')
strcpy(reason, english(484));
/* u < v => u� < v� (n odd, n>0) */
else
strcpy(reason, english(485));
/* u � v => u� � v� (n odd, n�0) */
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerineq16(term ineq, term arg, term *next, char *reason)
/* u < v => u� < v� (n odd, n>0) */
/* takes an arg */
{ if(FUNCTOR(ineq) != '<' && FUNCTOR(ineq) != '>')
return 1;
return p16_aux(ineq,arg,next,reason);
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerineq26(term ineq, term arg, term *next, char *reason)
/* u � v => u� � v� (n odd, n�0) */
/* takes an arg in menu mode; in auto mode, the arg is supplied
by autoineq, so in either case, it should have an arg; however it
can also be called by ssolve, in which case it arg is ILLEGAL,
so it has to cope with that.
*/
{ if(FUNCTOR(ineq) != LE && FUNCTOR(ineq) != GE)
return 1;
return p16_aux(ineq,arg,next,reason);
}
/*______________________________________________________ */
static int p17_aux(term ineq,term arg,term *next,char *reason)
/* used in next two operators */
/* condition on arg has already been checked by check_arg */
{ term left,right;
int err;
int side = (FUNCTOR(ineq) == '<' || FUNCTOR(ineq) == LE);
left = side ? ARG(0,ineq) : ARG(1,ineq);
right = side ? ARG(1,ineq) : ARG(0,ineq);
if(FUNCTOR(arg) == ILLEGAL)
{ err = select_power(left,right,&arg);
if(err)
return 1;
}
err = infer(le(zero,left));
if(err)
{ errbuf(0, english(508));
/* Can't verify sides of inequality are nonnegative */
return 1;
}
*next = make_term(FUNCTOR(ineq),2);
ARGREP(*next,(side ? 0 : 1), make_power(left,arg));
ARGREP(*next,(side ? 1 : 0), make_power(right,arg));
HIGHLIGHT(*next);
if(FUNCTOR(ineq) == '<' || FUNCTOR(ineq) == '>')
strcpy(reason, english(509));
/* 0 � u < v => u� < v� (n>0) */
else
strcpy(reason, english(510));
/* 0 � u � v => u� � v� (n>0) */
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerineq17(term ineq, term arg, term *next, char *reason)
/* 0 � u < v => u� < v� */
/* takes an arg in menu mode; in auto mode, the arg is supplied
by autoineq, so in either case, it should have an arg */
{ if(FUNCTOR(ineq) != '<' && FUNCTOR(ineq) != '>')
return 1;
return p17_aux(ineq,arg,next,reason);
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerineq27(term ineq, term arg, term *next, char *reason)
/* 0 � u � v => u� � v� 0*/
/* takes an arg in menu mode; in auto mode, the arg is supplied
by autoineq, so in either case, it should have an arg */
{ if(FUNCTOR(ineq) != LE && FUNCTOR(ineq) != GE)
return 1;
return p17_aux(ineq,arg,next,reason);
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int solvelinearineq(term ineq, term arg, term *next, char *reason)
/* solve linear inequality in one step, strict or not */
{ term x;
int err = derivative_subterm(ineq,&x);
if(err) /* solve for dy/dx if it occurs, else for the eigenvariable */
x = get_eigenvariable();
solve_linear_ineq_for(ineq,x,next);
HIGHLIGHT(*next);
strcpy(reason, english(486)); /* solve linear ineq */
return 0;
}
/*__________________________________________________________________*/
static int nl_aux2(term t, term *next)
/* t is of the form ax�b with a != 1 (or else return 0),
or an integral power of an expression of that form .
If t is of this form
then determine the sign of a, if possible.
Return value:
-1 if a is negative;
-2: sign of a not determinable but a has functor '-'
-3 a was -1;
1 if a is positive
2 if sign of a is not determinable (and functor isn't '-').
0 failure
Return x � b/c in *next if sign of a is
determinable and c(x�b/c) if not, where either c = a or a= -c. */
{ term x,temp,a;
long degree;
unsigned short n = ARITY(t);
int i,count,err,sign,signa = 0;
x = get_eigenvariable();
if(FUNCTOR(t) == '^' && FUNCTOR(ARG(0,t)) == '+')
{ err = infer(type(ARG(1,t),INTEGER));
if(err)
return 0; /* failure */
sign = nl_aux2(ARG(0,t),&temp);
if(sign == 0)
return 0;
if(sign ==1)
*next = make_power(temp,ARG(1,t));
else
*next = product(make_power(minusone,ARG(1,t)),make_power(temp,ARG(1,t)));
return 1; /* because the sign is incorporated */
}
if(ATOMIC(t) || FUNCTOR(t) != '+')
return 0;
count = collected(t); /* number of occurrences of x */
if(count != 1)
return 0; /* failure */
for(i=0;i<n;i++)
{ if(contains(ARG(i,t),FUNCTOR(x)))
break;
}
assert(i<n); /* because collected(t)==1 */
err = monomial_form(ARG(i,t),x,°ree,&a);
if(err)
return 0;
if(equals(a,one))
return 0;
if(equals(a,minusone))
{ *next = strongnegate(t);
return -3;
}
if(degree != 1)
return 0;
/* a must be nonzero */
if(ZERO(a))
{ errbuf(0, english(1310));
/* Zero denominator would be created */
return 1;
}
if(!OBJECT(a))
{ err = check(nonzero(a));
if(err)
{ errbuf(0, english(1310));
return 0; /* failure */
}
}
/* Now determine the sign of a if possible */
if(OBJECT(a))
signa = 1;
else if(NEGATIVE(a) && OBJECT(ARG(0,a)))
signa = -1;
else if(infer(lessthan(a,zero))==0)
signa = -1;
else if(infer(lessthan(zero,a))==0)
signa = 1;
if(signa)
{ *next = make_term('+',n);
for(i=0;i<n;i++)
{ polyval(signedfraction(ARG(i,t),a),&temp);
ARGREP(*next,i,temp);
}
additive_sortargs(*next);
PROTECT(*next);
return signa;
}
/* so now we can't find out the sign of a */
*next = make_term('+',n);
for(i=0;i<n;i++)
{ polyval(signedfraction(ARG(i,t),a),&temp);
ARGREP(*next,i,temp);
}
PROTECT(*next);
return NEGATIVE(a) ? -2 : 2;
}
/*__________________________________________________________________*/
static int nl_aux(term t, term *next, int *flag)
/* t should be a linear function of the eigenvariable, or a product
containing some linear factors. Change ax�b to x�b/a in such factors,
adjusting for the sign of a. Return 0 for success, 1 for failure.
The case a =1 is considered a failure */
/* *flag is a product of numbers, one for each factor of t, as follows:
1 or -1 means (x�b/a) was put in *next
2 or -2 means a(x�b/a) was put in *next
if (*flag < 0) means we need to throw in a - sign along with *next
-3 means a= -1
*/
{ term temp,u;
unsigned short n,k;
int i,tempsign,sign;
int err=1;
*flag = 1;
if(FUNCTOR(t) == '*')
{ n = ARITY(t);
k=0;
sign = 1;
u = make_term('*',(unsigned short)(3*n));
/* can't be sure how much space we really need but this is enough */
for(i=0;i<n;i++)
{ tempsign = nl_aux2(ARG(i,t),&temp); /* -1,-2 or 1,2 for success, 0 for failure */
if(tempsign == 0)
{ ARGREP(u,k,ARG(i,t));
++k;
}
else
{ err = 0;
sign *= tempsign;
if(FUNCTOR(temp)=='*')
{ assert(ARITY(temp)<=3);
/* it can be 3 in a case like (-ax + 2)^3 where we
get back (-1)^3 * a * (x - 2/a) */
ARGREP(u,k,ARG(0,temp));
HIGHLIGHT(ARG(k,u));
++k;
ARGREP(u,k,ARG(1,temp));
HIGHLIGHT(ARG(k,u));
++k;
if(ARITY(temp)==3)
{ ARGREP(u,k,ARG(2,temp));
++k;
}
}
else
{ ARGREP(u,k,temp);
HIGHLIGHT(ARG(k,u));
++k;
}
}
}
SETFUNCTOR(u,'*',k);
if(sign > 0)
*next = u;
else
{ tneg(u,next);
HIGHLIGHT(*next);
}
*flag = sign;
return err;
}
if(FUNCTOR(t) != '+')
return 1;
sign = nl_aux2(t,&temp);
if(sign == 0)
return 1;
if(sign > 0)
*next = temp;
else
tneg(temp,next);
HIGHLIGHT(*next);
*flag = sign;
return 0;
}
/*__________________________________________________________*/
MEXPORT_ALGEBRA int normalizelinear1(term t, term arg, term *next, char *reason)
/* ax � b < 0 iff x � b/a < 0 */
/* This operator is applied in auto mode to a product on one side of an
inequality whose other side is zero. However in menu mode it might also
be applied when one side is a single linear factor, so in that case
it must apply to the whole inequality, as it must check that the other
side is zero. */
{ unsigned short f = FUNCTOR(t);
term left,right;
int err;
int flag;
if(f == '<' || f == '>')
{ left = ARG(0,t);
right = ARG(1,t);
if(ZERO(left))
{ *next = make_term(f,2);
ARGREP(*next,0,zero);
err = nl_aux(right,ARGPTR(*next) + 1,&flag);
if(err)
return 1;
}
else if(ZERO(right))
{ *next = make_term(f,2);
ARGREP(*next,1,zero);
err = nl_aux(left,ARGPTR(*next),&flag);
if(err)
return 1;
}
else
return 1;
}
else if(f == '*')
{ err = nl_aux(t,next,&flag);
if(err)
return 1;
}
if(flag % 3 == 0)
strcpy(reason, "-x+b = -(x-b)");
else if (flag&1) /* flag is odd, so no factor returned flag = �2 */
strcpy(reason, "$ax�b<0 iff (x�b/a)<0$");
else
strcpy(reason, "$ax�b<0 iff a(x�b/a)<0$");
return 0;
}
/*__________________________________________________________*/
MEXPORT_ALGEBRA int normalizelinear2(term t, term arg, term *next, char *reason)
/* ax � b � 0 iff a(x � b/a) � 0 */
/* It drops the a if it is positive, and replaces it by a minus sign
if it's negative */
/* This operator is applied in auto mode to a product on one side of an
inequality whose other side is zero. However in menu mode it might also
be applied when one side is a single linear factor, so in that case
it must apply to the whole inequality, as it must check that the other
side is zero. */
{ unsigned short f = FUNCTOR(t);
int err,flag;
term left,right;
if(f == LE || f == GE)
{ left = ARG(0,t);
right = ARG(1,t);
if(ZERO(left))
{ *next = make_term(f,2);
ARGREP(*next,0,zero);
err = nl_aux(ARG(1,t),ARGPTR(*next) + 1,&flag);
if(err)
return 1;
}
else if(ZERO(right))
{ *next = make_term(f,2);
ARGREP(*next,1,zero);
err = nl_aux(ARG(0,t),ARGPTR(*next),&flag);
if(err)
return 1;
}
else
return 1;
}
else if(f == '*')
{ err = nl_aux(t,next,&flag);
if(err)
return 1;
}
if(flag % 3 == 0)
strcpy(reason, "-x+b = -(x-b)");
else if (flag&1) /* flag is odd, so no factor returned flag = �2 */
strcpy(reason, "$ax�b�0$ iff $(x�b/a)�0$");
else
strcpy(reason, "$ax�b�0$ iff $a(x�b/a)�0$");
return 0;
}
/*__________________________________________________________________*/
static int noassumptions = 0;
MEXPORT_ALGEBRA void set_noassumptions(int n)
/* This is used to turn off assumption-making in select_ineq_divarg
when it's called from ssolve, reduce_ineq, lpt.
*/
{ noassumptions = n;
}
MEXPORT_ALGEBRA int get_noassumptions(void)
{ return noassumptions;
}
/*____________________________________________________________________*/
int select_ineq_divarg(term eqn, term *arg)
/* called from automode. Select POSITIVE arg to be used by diveqn. Divide by
constant factors of a product on the left, but only when the right
side is already constant. solve_ineq has already checked (in automode)
that one side is econstant. Interchange roles of 'right' and 'left'
side when eigenvariable is only on the right.
If factors are encountered with signs that can't be determined,
it assumes they are positive. It doesn't try to check they aren't zero
since they already occur in a denominator.
*/
{ term left,right,c,u;
unsigned short n,k;
int err;
unsigned short symbol = FUNCTOR(eqn);
int i;
if(symbol != '<' && symbol != LE && symbol != GE && symbol != '>')
return 1;
left = ARG(0,eqn);
right = ARG(1,eqn);
if(econstant(left) && !econstant(right))
{ left = ARG(1,eqn);
right = ARG(0,eqn);
}
if(ATOMIC(left) || FUNCTOR(left) != '*')
return 1;
n = ARITY(left);
c= make_term('*',n);
k=0; /* mark place in c */
for(i=0;i<n;i++)
{ u = ARG(i,left);
if(econstant(u))
{ if(FUNCTOR(u)== '-')
u = ARG(0,u);
err = infer(lessthan(zero,u));
if(!err)
{ ARGREP(c,k,u);
++k;
}
else
{ err = infer(lessthan(u,zero));
if(!err)
{ ARGREP(c,k,strongnegate(u));
++k;
}
else if(noassumptions)
return 1; // when called from safe_solve, reduce_ineq, lpt.
else
{ assume(lessthan(zero,u));
ARGREP(c,k,u);
++k;
}
}
}
}
if(k==0)
{ RELEASE(c);
return 1;
}
if(k==1)
{ *arg = ARG(0,c);
RELEASE(c);
return 0;
}
SETFUNCTOR(c,'*',k);
*arg = c;
return 0;
}
/*______________________________________________________________________*/
MEXPORT_ALGEBRA int numericalineq(term t, term arg, term *next, char *reason)
/* evaluate numerical inequality */
{ unsigned short f = FUNCTOR(t);
double a,b;
term test;
if(!INEQUALITY(f))
return 1;
if(!seminumerical(t))
return 1;
deval(ARG(0,t),&a);
if(a == BADVAL)
return 1;
deval(ARG(1,t),&b);
if(b == BADVAL)
return 1;
if(fabs(b-a) < VERYSMALL)
{ /* Let's see if we can ensure that the difference really is zero.
It looks silly to display a warning about roundoff error when
the input is 0 < 0. */
polyval(sum(ARG(1,t),tnegate(ARG(0,t))),&test);
if(!ZERO(test))
/* No, can't prove it. Maybe roundoff error is involved. */
{ commentbuf(0,english(1847));
commentbuf(1,english(1848));
commentbuf(2,english(1849));
/* The difference is very small, and possibly roundoff errors may
have entered in, so the correctness of the calculation
cannot be guaranteed. */
}
}
switch(f)
{ case '<' :
*next = a < b ? true : false;
break;
case '>':
*next = a > b ? true : false;
break;
case NE:
*next = a != b ? true : false;
break;
case LE:
*next = a <= b ? true : false;
break;
case GE:
*next = a >= b ? true : false;
break;
}
strcpy(reason, english(1530)); /* evaluate numerically */
return 0;
}
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int evenpowerineq1(term t, term arg, term *next, char *reason)
/* a < x^2� is true if a < 0 */
{ int err;
term left,right;
unsigned short f = FUNCTOR(t);
if(f != '<' && f != '>')
return 1;
if(f == '<')
{ left = ARG(0,t);
right = ARG(1,t);
}
else
{ left = ARG(1,t);
right = ARG(0,t);
}
if(FUNCTOR(right) != '^')
return 1;
if(!iseven(ARG(1,right)))
return 1;
err = infer(lessthan(left,zero));
if(err)
return 1;
*next = true;
HIGHLIGHT(*next);
strcpy(reason,english(1533)); /* a < x^2� is true if a < 0 */
return 0;
}
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int squaretrue1(term t, term arg, term *next, char *reason)
/* a < x^2 is true if a < 0 */
{ return evenpowerineq1(t,arg,next,reason);
}
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int evenpowerineq2(term t, term arg, term *next, char *reason)
/* a � x^2� is true if a � 0 */
{ int err;
term left,right;
unsigned short f = FUNCTOR(t);
if(f != LE && f != GE)
return 1;
if(f == LE)
{ left = ARG(0,t);
right = ARG(1,t);
}
else
{ left = ARG(1,t);
right = ARG(0,t);
}
if(FUNCTOR(right) != '^')
return 1;
if(!iseven(ARG(1,right)))
return 1;
err = infer(le(left,zero));
if(err)
return 1;
*next = true;
HIGHLIGHT(*next);
strcpy(reason,english(1534)); /* a � x^2� is true if a � 0 */
return 0;
}
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int squaretrue2(term t, term arg, term *next, char *reason)
/* a � x^2 is true if a � 0 */
{ return evenpowerineq2(t,arg,next,reason);
}
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int evenpowerineq3(term t, term arg, term *next, char *reason)
/* x^2� < a is false if a � 0 */
{ int err;
term left,right;
unsigned short f = FUNCTOR(t);
if(f != '<' && f != '>')
return 1;
if(f == '<')
{ left = ARG(0,t);
right = ARG(1,t);
}
else
{ left = ARG(1,t);
right = ARG(0,t);
}
if(FUNCTOR(left) != '^')
return 1;
if(!iseven(ARG(1,left)))
return 1;
err = infer(le(right,zero));
if(err)
return 1;
*next = false;
HIGHLIGHT(*next);
strcpy(reason, english(1535)); /* x^2� < a is false if a � 0 */
return 0;
}
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int squarefalse1(term t, term arg, term *next, char *reason)
/* x^2 < a is false if a � 0 */
{ return evenpowerineq3(t,arg,next,reason);
}
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int evenpowerineq4(term t, term arg, term *next, char *reason)
/* x^2� � a is false if a < 0 */
{ int err;
term left,right;
unsigned short f = FUNCTOR(t);
if(f != LE && f != GE)
return 1;
if(f == LE)
{ left = ARG(0,t);
right = ARG(1,t);
}
else
{ left = ARG(1,t);
right = ARG(0,t);
}
if(FUNCTOR(left) != '^')
return 1;
if(!iseven(ARG(1,left)))
return 1;
err = infer(lessthan(right,zero));
if(err)
return 1;
*next = false;
HIGHLIGHT(*next);
strcpy(reason,english(1536)); /* x^2� � a is false if a < 0 */
return 0;
}
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int squarefalse2(term t, term arg, term *next, char *reason)
/* x^2 � a is false if a < 0 */
{ return evenpowerineq4(t,arg,next,reason);
}
/*________________________________________________________________________*/
MEXPORT_ALGEBRA int factoroneside(term t, term arg, term *next, char *reason)
/* t must be an equation or inequality with one constant side.
The other side, after possibly removing a constant factor,
must be a sum. Try to factor it as a power of a sum.
What is in the sum must be a monotone function of the eigenvariable
or it is fruitless to do this anyway, because you are going to
get -c < f(x) < c, so unless f is monotone
(and has explicit inverse) you can't do much.
This operator is used in automode only.
*/
{ term left,right,p,q,c,s,u,x;
int swapflag,err,i,flag=0;
unsigned short f = FUNCTOR(t);
unsigned short n;
unsigned short path[32];
unsigned short path2[32];
actualop op;
if(!INEQUALITY(f))
return 1;
if(econstant(ARG(1,t)))
{ left = ARG(1,t);
right = ARG(0,t);
swapflag = 1;
}
else if(econstant(ARG(0,t)))
{ left = ARG(0,t);
right = ARG(1,t);
swapflag = 0;
}
else
return 1;
if(FUNCTOR(right) == '*')
/* ratpart2(right,&c,&s); The use of ratpart loses the path information
we need to make ShowStep work */
{ n = ARITY(right);
for(i=0;i<n;i++)
{ if(!econstant(ARG(i,right)))
{ if(flag)
return 1;
flag = i+1;
}
}
if(!flag)
return 1;
s = ARG(flag-1,right);
if(FUNCTOR(s) != '+')
return 1;
if(n == 2)
c = ARG(0,right);
else
{ c = make_term('*',(unsigned short)(n-1));
for(i=0;i<n-1;i++)
ARGREP(c,i,ARG((unsigned short)(i<flag-1? i :i+1),right));
}
}
else
{ c = one;
s = right;
}
if(FUNCTOR(s) != '+')
return 1;
if(ARITY(s) != 3)
return 1;
err = factorsquareofdif(s,arg,&q,reason);
if(err)
{ err = factorsquareofsum(s,arg,&q,reason);
if(err)
return 1;
op = factorsquareofsum;
}
else
op = factorsquareofdif;
path2[0] = f;
path2[1] =(unsigned short)(swapflag ? 1 : 2);
if(FUNCTOR(right) == '*')
{ path2[2] = '*';
path2[3] =(unsigned short) flag;
path2[4] = 0;
}
else
path2[2] = 0;
pathncopy(path,29,get_pathtail());
pathcat(path,path2);
p = NEGATIVE(q) ? ARG(0,q) : q;
assert(FUNCTOR(p) == '^');
x = get_eigenvariable();
if(is_linear_in(ARG(0,p),x))
err = 0;
else
{ u = derivative(ARG(0,p),x);
err = obviously_positive(u) ? 0 : 1;
if(err)
err = obviously_positive(tnegate(u));
}
if(err)
return 1; /* can't do anything with the result so don't bother */
*next = make_term(f,2);
ARGREP(*next, swapflag ? 1 : 0, left);
ARGREP(*next, swapflag ? 0 : 1, ONE(c) ? q : product(c,q));
set_pathtail(path);
SetShowStepOperation(op);
return 0;
}
/*_____________________________________________________________*/
MEXPORT_ALGEBRA int combineintervals(term t, term arg, term *next, char *reason)
/* if t is an OR of intervals, and the union of some pair of
these intervals is an interval, succeed, returning the union in
*next. Return 0 for success, 1 for failure. There are several
possibilities as intervals can be of the forms a < x,
a<x<b, x < a, etc with LE instead of < in one or both positions.
It only works if the necessary values min(a,b) etc can be computed
because a and b are numbers.
If more generally t is a Boolean combination of inequalities,
TarskiBoole is called, which reduces t to a DNF, a disjunction of
conjunctions of inequalities; but the conjunctions don't have to
be intervals if the input inequalities were not. FINISH THIS.
*/
{ int err;
if(FUNCTOR(t) != OR)
return 1;
err = union_intervals(t,next);
if(err)
return 1;
HIGHLIGHT(*next);
strcpy(reason,english(1546)); /* combine intervals */
return 0;
}
/*______________________________________________________________*/
MEXPORT_ALGEBRA int lessthantole(term t, term arg, term *next, char *reason)
/* or( u < v, u=v) becomes u <= v */
/* or( a < u < v, u = v) becomes a < u <= v */
/* or( u < v < b, u = v) becomes u <= v < b */
{ unsigned short n;
int i,j,k;
term u,v,w,p,q,r;
if(FUNCTOR(t) != OR)
return 1;
n = ARITY(t);
for(i=0;i<n;i++)
{ p = ARG(i,t);
if(FUNCTOR(p) == '<' ||
(FUNCTOR(p) == AND && interval_as_and(p))
)
{ for(j=0;j<n;j++)
{ if(j==i)
continue;
q = ARG(j,t);
if(FUNCTOR(q) == '=')
{ if(FUNCTOR(p) == '<')
{ u = ARG(0,p);
v = ARG(1,p);
if(
(equals(u,ARG(0,q)) && equals(v,ARG(1,q))) ||
(equals(u,ARG(1,q)) && equals(v,ARG(0,q)))
)
{ r = le(u,v);
goto success;
}
}
else /* p is an interval_as_and */
{ u = ARG(0,ARG(0,p));
v = ARG(1,ARG(0,p));
w = ARG(1,ARG(1,p));
if(FUNCTOR(ARG(0,p)) == '<' &&
(
(equals(u,ARG(0,q)) && equals(v,ARG(1,q))) ||
(equals(u,ARG(1,q)) && equals(v,ARG(0,q)))
)
)
{ r = make_term(AND,2);
ARGREP(r,0,le(u,v));
copy(ARG(1,p),ARGPTR(r)+1);
goto success;
}
if(FUNCTOR(ARG(1,p)) == '<' &&
(
(equals(v,ARG(0,q)) && equals(w,ARG(1,q))) ||
(equals(v,ARG(1,q)) && equals(w,ARG(0,q)))
)
)
{ r = make_term(AND,2);
ARGREP(r,1,le(v,w));
copy(ARG(0,p),ARGPTR(r));
goto success;
}
}
}
}
}
}
return 1;
success:
HIGHLIGHT(r);
strcpy(reason, english(0));
/* u<v or u=v iff u�v */
if(n==2)
{ *next = r;
return 0;
}
*next = make_term(OR,(unsigned short)(n-1));
if(j < i)
{ k = j; /* swap i and j so i < j */
j = i;
i = k;
}
for(k=0;k<n-1;k++)
ARGREP(*next,k,k<i ? ARG(k,t) : k==i ? r : k<j ? ARG(k,t) : ARG(k+1,t));
return 0;
}
/*______________________________________________________________*/
MEXPORT_ALGEBRA int greaterthantoge(term t, term arg, term *next, char *reason)
/* or( u > v, u=v) becomes u >= v */
{ unsigned short n;
int i,j,k;
term u,v,p,q,r;
if(FUNCTOR(t) != OR)
return 1;
n = ARITY(t);
for(i=0;i<n;i++)
{ p = ARG(i,t);
if(FUNCTOR(p) == '>')
{ for(j=0;j<n;j++)
{ if(j==i)
continue;
q = ARG(j,t);
if(FUNCTOR(q) == '=')
{ u = ARG(0,p);
v = ARG(1,p);
if(
(equals(u,ARG(0,q)) && equals(v,ARG(1,q))) ||
(equals(u,ARG(1,q)) && equals(v,ARG(0,q)))
)
{ r = ge(u,v);
goto success;
}
}
}
}
}
return 1;
success:
HIGHLIGHT(r);
strcpy(reason, english(1603));
/* u>v or u=v iff u�v */
if(n==2)
{ *next = r;
return 0;
}
*next = make_term(OR,(unsigned short)(n-1));
if(j < i)
{ k = j; /* swap i and j so i < j */
j = i;
i = k;
}
for(k=0;k<n-1;k++)
ARGREP(*next,k,k<i ? ARG(k,t) : k==i ? r : k<j ? ARG(k,t) : ARG(k+1,t));
return 0;
}
/*_______________________________________________________________*/
MEXPORT_ALGEBRA int changesignsandsense1(term t, term arg, term *next, char *reason)
/* -u < -v becomes u > v */
{ term temp;
int err;
unsigned short f = FUNCTOR(t);
if(f != '<')
return 1;
err = changesigns(t,arg,&temp,reason);
if(err || FUNCTOR(temp) != f)
return 1;
*next = f == '<' ? greaterthan(ARG(1,temp),ARG(0,temp)) :
lessthan(ARG(1,temp),ARG(0,temp));
strcpy(reason, english( f == '<' ? 1604 : 1605));
/* -u < -v iff u > v */
/* -u > -v iff u < v */
HIGHLIGHT(*next);
return 0;
}
/*_______________________________________________________________*/
MEXPORT_ALGEBRA int changesignsandsense3(term t, term arg, term *next, char *reason)
/* -u > -v becomes u < v */
{ term temp;
int err;
unsigned short f = FUNCTOR(t);
if(f != '>')
return 1;
err = changesigns(t,arg,&temp,reason);
if(err || FUNCTOR(temp) != f)
return 1;
*next = f == '<' ? greaterthan(ARG(1,temp),ARG(0,temp)) :
lessthan(ARG(1,temp),ARG(0,temp));
strcpy(reason, english( f == '<' ? 1604 : 1605));
/* -u < -v iff u > v */
/* -u > -v iff u < v */
HIGHLIGHT(*next);
return 0;
}
/*_______________________________________________________________*/
MEXPORT_ALGEBRA int changesignsandsense2(term t, term arg, term *next, char *reason)
/* -u � -v becomes u � v */
{ term temp;
int err;
unsigned short f = FUNCTOR(t);
if(f != LE && f != GE)
return 1;
err = changesigns(t,arg,&temp,reason);
if(err || FUNCTOR(temp) != f)
return 1;
*next = f == LE ? ge(ARG(1,temp),ARG(0,temp)) :
le(ARG(1,temp),ARG(0,temp));
strcpy(reason, english( f == LE ? 1606 : 1607));
/* -u � -v iff u � v */
/* -u � -v iff u � v */
HIGHLIGHT(*next);
return 0;
}
/*_______________________________________________________________*/
MEXPORT_ALGEBRA int changesignsandsense4(term t, term arg, term *next, char *reason)
/* -u � -v becomes u � v */
{ term temp;
int err;
unsigned short f = FUNCTOR(t);
if(f != GE)
return 1;
err = changesigns(t,arg,&temp,reason);
if(err || FUNCTOR(temp) != f)
return 1;
*next = f == LE ? ge(ARG(1,temp),ARG(0,temp)) :
le(ARG(1,temp),ARG(0,temp));
strcpy(reason, english( f == LE ? 1606 : 1607));
/* -u � -v iff u � v */
/* -u � -v iff u � v */
HIGHLIGHT(*next);
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int sqsqrtineq1(term ineq, term arg, term *next, char *reason)
/* a < �u iff 0 � u provided a < 0 */
{ unsigned short f = FUNCTOR(ineq);
term a,u;
if(f != '<')
return 1;
if(FUNCTOR(ARG(1,ineq)) != SQRT)
return 1;
a = ARG(0,ineq);
u = ARG(0,ARG(1,ineq));
if(!obviously_negative(a))
return 1;
*next = le(zero,u);
HIGHLIGHT(*next);
strcpy(reason, english(1972));
/* a<�u iff 0�u provided a < 0 */
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int sqsqrtineq1rev(term ineq, term arg, term *next, char *reason)
/* �u > a iff u � 0 provided a < 0 */
{ unsigned short f = FUNCTOR(ineq);
term a,u;
if(f != '>')
return 1;
if(FUNCTOR(ARG(0,ineq)) != SQRT)
return 1;
a = ARG(1,ineq);
u = ARG(0,ARG(0,ineq));
if(!obviously_negative(a))
return 1;
*next = ge(u,zero);
HIGHLIGHT(*next);
strcpy(reason, english(1974));
/* �u > a iff u � 0 provided a < 0 */
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int sqsqrtineq2(term ineq, term arg, term *next, char *reason)
/* a � �u iff 0 � u provided a � 0 */
{ unsigned short f = FUNCTOR(ineq);
term a,u;
if(f != LE)
return 1;
if(FUNCTOR(ARG(1,ineq)) != SQRT)
return 1;
a = ARG(0,ineq);
u = ARG(0,ARG(1,ineq));
if(!obviously_nonnegative(strongnegate(a)))
return 1;
*next = le(zero,u);
HIGHLIGHT(*next);
strcpy(reason, english(1973));
/* a � �u iff 0�u provided a � 0 */
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int sqsqrtineq2rev(term ineq, term arg, term *next, char *reason)
/* �u � a iff u � 0 provided a � 0 */
{ unsigned short f = FUNCTOR(ineq);
term a,u;
if(f != GE)
return 1;
if(FUNCTOR(ARG(0,ineq)) != SQRT)
return 1;
a = ARG(1,ineq);
u = ARG(0,ARG(0,ineq));
if(!obviously_nonnegative(strongnegate(a)))
return 1;
*next = ge(u,zero);
HIGHLIGHT(*next);
strcpy(reason, english(1975));
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerrootineq1(term ineq, term arg, term *next, char *reason)
/* a < ^2��u iff 0 � u provided a < 0 */
{ unsigned short f = FUNCTOR(ineq);
term a,u;
if(f != '<')
return 1;
if(FUNCTOR(ARG(1,ineq)) != ROOT)
return 1;
if(!iseven(ARG(0,ARG(1,ineq))))
return 1;
a = ARG(0,ineq);
u = ARG(1,ARG(1,ineq));
if(!obviously_negative(a))
return 1;
*next = le(zero,u);
HIGHLIGHT(*next);
strcpy(reason, english(1976));
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerrootineq1rev(term ineq, term arg, term *next, char *reason)
/* ^2��u > a iff u � 0 provided a < 0 */
{ unsigned short f = FUNCTOR(ineq);
term a,u;
if(f != '>')
return 1;
if(FUNCTOR(ARG(0,ineq)) != ROOT)
return 1;
if(!iseven(ARG(0,ARG(0,ineq))))
return 1;
a = ARG(1,ineq);
u = ARG(1,ARG(0,ineq));
if(!obviously_negative(a))
return 1;
*next = ge(u,zero);
HIGHLIGHT(*next);
strcpy(reason, english(1978));
/* �u>-a iff u � 0 provided a>0 */
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerrootineq2(term ineq, term arg, term *next, char *reason)
/* a � ^2��u iff 0 � u provided a � 0 */
{ unsigned short f = FUNCTOR(ineq);
term a,u;
if(f != LE)
return 1;
if(FUNCTOR(ARG(1,ineq)) != ROOT)
return 1;
if(!iseven(ARG(0,ARG(1,ineq))))
return 1;
a = ARG(0,ineq);
u = ARG(1,ARG(1,ineq));
if(!obviously_nonnegative(strongnegate(a)))
return 1;
*next = le(zero,u);
HIGHLIGHT(*next);
strcpy(reason, english(1977));
/* -a�u iff 0�u provided a�0 */
return 0;
}
/*______________________________________________________ */
MEXPORT_ALGEBRA int powerrootineq2rev(term ineq, term arg, term *next, char *reason)
/* ^2��u � a iff u � 0 provided a � 0 */
{ unsigned short f = FUNCTOR(ineq);
term a,u;
if(f != GE)
return 1;
if(FUNCTOR(ARG(0,ineq)) != ROOT)
return 1;
if(!iseven(ARG(0,ARG(0,ineq))))
return 1;
a = ARG(1,ineq);
u = ARG(1,ARG(0,ineq));
if(!obviously_nonnegative(strongnegate(a)))
return 1;
*next = ge(u,zero);
HIGHLIGHT(*next);
strcpy(reason, english(1979));
return 0;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists