Sindbad~EG File Manager
/* automode solving of a single (linear or nonlinear) inequality for MathXpert */
/*
M. Beeson
Original date 7.7.91
2.19.99 last modified
3.2.00 modified solve_ineq
5.6.13 include stdef.h
6.4.13 added code to use mulineq to deal with u/2^(n/2) < v/2^n by multiplying both sides
added code to use polylessexp
modified autoineq not to use explicitdomain on TESTCONVERGENCE
6.5.13 modified autoineq to use mulineq when one side has a positive denominator and the other is a product or atom
added code to use logrtbound
6.10.13 modified control of polylessexp and ratlogbound to only use them in topic _comparison_test,
not in problemtype TESTCONVERGENCE. It probably doesn't matter as inequalities come up only that topic
under TESTCONVERGENCE.
1.9.25 modified pre_ineq in conditions for mul_equation, adding || FRACTION(right)
*/
#include <assert.h>
#include <string.h>
#include <stddef.h>
#include "globals.h"
#include "checkarg.h" /* for operator typedef */
#include "ops.h" /* for prototypes of operators */
#include "trig.h"
#include "calc.h" /* polyvalop */
#include "probtype.h"
#include "eqn.h"
#include "graphstr.h" /* mpdoc.h needs it */
#include "display.h"
#include "mpdoc.h" /* automode.h needs it */
#include "automode.h"
#include "prover.h" /* noccurs */
#include "symbols.h"
#include "autosimp.h" /* get_pathlength, get_path */
#include "eqn.h" /* econstant */
#include "algaux.h" /* contains_monomially */
#include "cflags.h" /* set_factorflag */
#include "autoeqn.h" /* inhibit_transfer, stop_alltoleft */
#include "pvalaux.h" /* obviously_positive */
#include "deval.h" /* seminumerical */
#include "domain.h" /* contains_defined_variables */
#include "polynoms.h" /* ispolyin */
#include "logineq.h"
#include "tdefn.h"
static unsigned short contains_sqrt3(term a);
static int one_nonconstant_term(term t);
/*__________________________________________________________________*/
void pre_ineq(term t, actualop *o, int *nops)
/* Generate a list of operators to be tried in pre_ops when
solving inequalities. Called by pre_ops.
Put the operators to be used in o[0], o[1],... and return
the number of operators in *nops. t is an equation.
*/
{ int i=0;
int problemtype = get_problemtype();
int pathlength = get_pathlength();
int currenttopic = get_currenttopic();
unsigned short const *path = get_path();
unsigned short f = FUNCTOR(t);
term x = get_eigenvariable();
if(solved(t,x))
{ *nops = 0;
return;
}
int strictflag; /* 1 for < or >, 0 for LE or GE */
term left,right;
if(f == '<' || f == LE)
{ left = ARG(0,t);
right = ARG(1,t);
}
else if(f == '>' || f == GE)
{ left = ARG(1,t);
right = ARG(0,t);
}
else
{ *nops = i; /* assert(0); only inequalities get to this function */
return;
}
if(f == '<' || f == '>')
strictflag = 1;
else
strictflag = 0;
o[i] = arithmetic; ++i; /* reduce e.g. 0 > 1 to false */
if(FUNCTOR(left) == '^' &&
FUNCTOR(right) == '^' &&
ISINTEGER(ARG(0,left)) &&
ISINTEGER(ARG(0,right))
)
{ o[i] = writeintegeraspower; ++i;
}
if(currenttopic == _comparison_test && ispolyin(left,x) && FUNCTOR(right) == '^' && contains(ARG(1,right),FUNCTOR(x))
&& !ONE(left) // this prevents it from messing up a problem in comparison test
)
{ o[i] = polylessexp; ++i;
}
if(currenttopic == _comparison_test && logpoly(left,x) && algebraic(right,x))
{ o[i] = logratbound; ++i;
}
if(FUNCTOR(left) == '^' && FUNCTOR(right) == '^' &&
(FUNCTOR(ARG(0,left)) == '^' || FUNCTOR(ARG(0,right)) == '^')
)
/* pre-empt introducelninexponent */
{ o[i] = powertopower; ++i; /* example: 2^(6x) = (2^6)^(x^2) */
}
if(strictflag && FUNCTOR(left) == ABSFUNCTOR)
{ if(ZERO(right))
{ o[i] = f == '<' ? absineqfalse : absineqfalseg; ++i;
}
else
{ o[i] = f == '<' ? abslessthanneg : absgreaterthanneg; ++i;
}
}
if(strictflag && FUNCTOR(right) == ABSFUNCTOR)
{ o[i] = f == '<' ? absineqtrue3 : absineqtrue3g; ++i;
}
if(!strictflag && FUNCTOR(right) == ABSFUNCTOR)
{ if(ZERO(left))
{ o[i] = f == LE ? absineqtrue : absineqtrueg; ++i;
}
else
{ o[i] = f == LE ? absineqtrue2 : absineqtrue2g; ++i;
}
}
if(!strictflag && FUNCTOR(left) == ABSFUNCTOR)
{ o[i] = f == LE ? absleneg : absgeneg; ++i;
/* abs(u) <= -c is false if c > 0 */
o[i] = f == LE ? absleneg2 : absgeneg2; ++i;
/* abs(u) <= -c iff u = 0, after inferring c >= 0 and assuming c = 0 */
}
if(problemtype == INDUCTION)
{ o[i] = arithmetic; ++i;
o[i] = selectinductionvariable; ++i;
o[i] = useinductionhyp; ++i;
}
else if(SOLVETYPE(problemtype) || problemtype == TESTCONVERGENCE)
{ if(!ZERO(right) && !ZERO(left))
{ set_factorflag(0); /* turn off factoring till right side is zero */
o[i] = factoroneside; ++i;
/* example: x^2 + 2x + 1 < c^2 => (x+1)^2 < c^2. Note that
after that you have to transfer and factor again, you can't
just take the square root in general. To see this consider this
example: x^4 + 2x^2 + 1 < 1/4. You get the wrong answer by
factoring and taking the square root without abs, and if you leave
abs in you get something intractable.
*/
}
else
{ set_factorflag(0x111); /* turn it back on */
if(
( ZERO(left) && !is_linear_in(right,x)) ||
( ZERO(right) && !is_linear_in(left,x))
)
{ o[i] = strictflag ? droppositive1 : droppositive2; ++i;
}
}
o[i] = cancelterm; ++i; /* cancel additive term on both sides */
if(pathlength >= 2 && path[pathlength-2] != AND)
{ /* don't work on one term of an interval_as_and */
o[i] = fractionalsubstitution; ++i;
o[i] = gcdsubstitution; ++i;
}
if(status(polyvalop) >= KNOWN)
{ o[i] = polyvalop; ++i;
}
if(contains_sqrt3(t) == SQRT && !ZERO(left) && !ZERO(right))
/* example: u = sqrt u; just go ahead and square,
or at least try (perhaps the side conditions won't be inferred).
Don't do: u-sqrt u = 0; -sqrt u = -u; sqrt u = u; u=u^2
the sqrt must be nonconstant and not deeply nested. */
{ o[i] = f == '<' ? powerineq11: powerineq21 ; ++i;
/* square the inequality sqrt(u) < v */
if(FUNCTOR(ARG(1,t)) == SQRT && f == '<')
{ o[i] = sqsqrtineq1; ++i;
}
if(FUNCTOR(ARG(0,t)) == SQRT && f == '>')
{ o[i] = sqsqrtineq1rev; ++i;
}
if(FUNCTOR(ARG(1,t)) == SQRT && f == LE)
{ o[i] = sqsqrtineq2; ++i;
}
if(FUNCTOR(ARG(0,t)) == SQRT && f == GE)
{ o[i] = sqsqrtineq2rev; ++i;
}
o[i] = f == '<' ? squareineq1 :
f == '>' ? squareineq1g :
f == LE ? squareineq2 :
squareineq2g; ++i;
o[i] = f == '<' ? squareineq3 :
f == '>' ? squareineq3g:
f == LE ? squareineq4:
squareineq4g; ++i;
o[i] = f == '<' ? powerineq12:
f == '>' ? powerineq12g:
f == LE ? powerineq22:
powerineq22g; ++i;
}
if(contains_sqrt3(t) == ROOT && !ZERO(left) && !ZERO(right) &&
(contains_monomially(left,ROOT) || contains_monomially(right,ROOT))
)
{ if(FUNCTOR(ARG(1,t)) == ROOT && f == '<')
{ o[i] = powerrootineq1; ++i;
}
if(FUNCTOR(ARG(0,t)) == ROOT && f == '>')
{ o[i] = powerrootineq1rev; ++i;
}
if(FUNCTOR(ARG(1,t)) == ROOT && f == LE)
{ o[i] = powerrootineq2; ++i;
}
if(FUNCTOR(ARG(0,t)) == ROOT && f == GE)
{ o[i] = powerrootineq2rev; ++i;
}
o[i] = f == '<' ? powerineq14odd:
f == '>' ? powerineq14oddg:
f == LE ? powerineq24odd:
powerineq24oddg; ++i;
o[i] = f == '<' ? powerineq14even:
f == '>' ? powerineq14eveng:
f == LE ? powerineq24even:
powerineq24eveng; ++i;
o[i] = f == '<' ? powerineq13:
f == '>' ? powerineq13g:
f == LE ? powerineq23:
powerineq23g; ++i;
o[i] = f == '<' ? powerineq15:
f == '>' ? powerineq15g:
f == LE ? powerineq25:
powerineq25g; ++i;
}
o[i] = crossmultiply; ++i; /* don't require args to be
fractions because of
(a/b)^n = (c/d)^m */
/* Given u/(f(x))^2 < 0 we want to multiply by (f(x))^2
immediately, before factoring f(x). If we used obviously_nonnegative
instead of obviously_positive in the next lines, it would work on
x/sqrt(x^2-1) etc. to multiply by the sqrt. This throws
the work into the prover behind the scenes, so we really
should make the polynomial under the square root be
factored first.
*/
if(
(ZERO(right) || FUNCTOR(right) == '*' || ATOMIC(right) || FRACTION(right))
&& FRACTION(left) && !infer(positive(ARG(1,left)))
)
{ o[i] = mulineq; ++i;
}
if(
(ZERO(left) || FUNCTOR(right) == '*' || ATOMIC(right) || FRACTION(left))
&& FRACTION(right) && !infer(positive(ARG(1,right)))
)
{ o[i] = mulineq; ++i;
}
if(problemtype == TESTCONVERGENCE)
{ o[i] = divineq; ++i; // it selects a good arg in certain cases, and otherwise fails
}
/* Next add or subtract terms if required */
if(!inhibit_transfer(t))
{ o[i] = strictflag ? transferstrictineq : transferineq; ++i;
}
if(f == '=' && problemtype != LINEAR_EQUATION)
{ o[i] = spliteqn; ++i; /* ab=0 iff or(a=0,b=0) */
}
/* example (x-7)/sqrt(f(x)) < 0, mulineq will not choose sqrt(f(x))
but f(x) sqrt(f(x)), so you will not lose the exclusion of the
codomain of f(x).
*/
}
*nops = i;
}
/*__________________________________________________________________*/
void solve_ineq(term t, int initiali, actualop *o, int *nops)
/* called by post_ops for solving inequalities */
/* t is an equation or inequality. The selected operator (or operators) is
returned in o[initiali] and if needed subsequent values of initiali;
nops is returned as one more than the last index used (i.e., it is the
final dimension of the array o.)
*/
{ int i = initiali;
unsigned ineqsymbol = FUNCTOR(t);
term left,right,u,v,x;
unsigned f,g,h;
int sflag; /* set to 0 for GE or >, to 1 for LE or < */
int pathlength = get_pathlength();
unsigned short const *path = get_path();
if(ineqsymbol == NE)
{ *nops = i;
return; /* This isn't supposed to happen, but if through oversight
it does, the solution will just stop. No need to crash
by hitting the next assertion. */
}
assert(ineqsymbol == '<' || ineqsymbol == LE || ineqsymbol == GE || ineqsymbol == '>');
/* In order to handle all four inequality symbols we set 'sflag' to zero
for GE or '>' and reverse the left and right sides. Then when we
determine which operators to throw in, we check flag again and throw
in the correct version, for example flag ? absge : absle
*/
x = get_eigenvariable();
if(contains(t,FUNCTOR(x)) && solved(t,x))
goto solved; /* we may still need to use explicitdomain ('use assumptions') */
if(ineqsymbol == GE || ineqsymbol == '>')
{ sflag = 0;
left = ARG(1,t);
right = ARG(0,t);
if(ineqsymbol == GE)
ineqsymbol = LE;
else
ineqsymbol = '<';
}
else
{ sflag = 1;
left = ARG(0,t);
right = ARG(1,t);
}
assert(ineqsymbol == '<' || ineqsymbol == LE);
g = FUNCTOR(left);
h = FUNCTOR(right);
if(seminumerical(t))
{ o[i] = numericalineq; ++i;
*nops = i;
return;
}
if(g==ABSFUNCTOR)
{ if(seminumerical(right))
{ o[i] = absineqfalse; ++i;
}
if(!ATOMIC(ARG(0,left)))
{ f = FUNCTOR(ARG(0,left));
switch(f)
{ case SIN:
o[i] = abssinineq; ++i;
break;
case COS:
o[i] = abscosineq; ++i;
break;
case ATAN:
o[i] = absarctanineq; ++i;
break;
}
}
if(ineqsymbol == '<' && !constant(right) && !block_squareeqn2(t))
{ o[i] = sflag ? squareineq1: squareineq1g; ++i;
o[i] = sflag ? squareineq3: squareineq3g; ++i;
}
else if(ineqsymbol == LE && !constant(right) && !block_squareeqn2(t))
{ o[i] = sflag ? squareineq2: squareineq2g; ++i;
o[i] = sflag ? squareineq4: squareineq4g; ++i;
}
}
if(h==ABSFUNCTOR && ZERO(left))
{ o[i] = absineqtrue; i++;
o[i] = (ineqsymbol == '<' ? (sflag ? lessthanabs :greaterthanabs) : (sflag ? leabs : geabs)); ++i;
*nops = i;
return;
}
if(g==ABSFUNCTOR &&
(
( is_linear_in(ARG(0,left), x)) ||
/* e.g. abs(x+3) < 5 but don't break up abs sin x < 1/2 */
(FUNCTOR(ARG(0,left)) == '+' && one_nonconstant_term(ARG(0,left)))
/* abs(x^2-1) must be broken up */
)
)
{ o[i] = (ineqsymbol == '<' ? (sflag ? abslessthan : absgreaterthan) : (sflag ? absle : absge)); ++i;
*nops = i;
return; /* certain to work */
}
if(h==ABSFUNCTOR && (!ATOMIC(left) || !econstant(right)))
{ o[i] = (ineqsymbol == '<' ? (sflag ? lessthanabs :greaterthanabs) : (sflag ? leabs : geabs));
++i;
*nops = i;
return; /* certain to work */
}
/* Now for the reciprocal operators */
if(g == '/' &&
econstant(right) &&
econstant(ARG(0,left)) &&
!obviously_nonnegative(ARG(1,left))
/* if the denom is positive it's better just to multiply by it.
Example: 1/abs(x) > 3
*/
)
{ if(obviously_positive(right))
/* The following operators will use 'infer' but automode only tries them
in obvious cases, to avoid long fruitless attempted inferences */
{ o[i] = ineqsymbol == '<' ? (sflag ? recipineq11 : recipineq11g) : (sflag ? recipineq12 : recipineq12g);
++i;
}
if(obviously_positive(tnegate(right)))
{ o[i] = ineqsymbol == '<' ? (sflag ? recipineq31 : recipineq31g) : (sflag ? recipineq32 : recipineq32g);
++i;
}
}
if(h == '/' &&
econstant(left) &&
econstant(ARG(0,right)) &&
!obviously_nonnegative(ARG(1,right))
/* if the denom is positive it's better just to multiply by it.
Example: 3 < 1/abs(x)
*/
)
{ if(obviously_positive(left))
{ o[i] = ineqsymbol == '<' ?
(sflag ? recipineq21 : recipineq21g) :
(sflag ? recipineq22 : recipineq22g);
++i;
}
if(obviously_positive(tnegate(left)))
{ o[i] = ineqsymbol == '<' ?
(sflag ? recipineq41 : recipineq41g) :
(sflag ? recipineq42 : recipineq42g);
++i;
}
}
if(g == '/' && h == '/' &&
(
( econstant(ARG(0,left)) && FUNCTOR(ARG(1,left)) == SQRT) ||
( econstant(ARG(0,right)) && FUNCTOR(ARG(1,right)) == SQRT)
)
)
{ if(ineqsymbol == '<' && !constant(right) && !block_squareeqn2(t))
{ o[i] = sflag ? squareineq1: squareineq1g; ++i;
o[i] = sflag ? squareineq3: squareineq3g; ++i;
}
else if(ineqsymbol == LE && !constant(right) && !block_squareeqn2(t))
{ o[i] = sflag ? squareineq2: squareineq2g; ++i;
o[i] = sflag ? squareineq4: squareineq4g; ++i;
}
}
if(g == '/' && h == '/')
{ term u = ARG(1,left);
term v = ARG(1,right);
if(FUNCTOR(u) == '^' && FUNCTOR(v) == '^' && equals(ARG(0,u),ARG(0,v)))
{ o[i] = mulineq; ++i;
}
}
if(g==SIN)
{ o[i] = sinineq; ++i;
}
else if(g == COS)
{ o[i] = coslowerbound; ++i;
}
else if(g == ATAN)
{ o[i] = arctanineq; ++i;
}
else if(h == TAN)
{ o[i] = tanineq; ++i;
}
if(g=='+' && ZERO(right) && FUNCTOR(ARG(0,left))=='-' &&
!(pathlength >= 3 && path[pathlength-3] == AND)
/* changesigns is called on interval_as_and terms in preops */
)
{ o[i] = ineqsymbol == '<' ? changesigns1 : changesigns2; ++i;
*nops = i;
return; /* certain to work */
}
if(g == '+' && ARITY(left) == 2)
{ u = ARG(0,left);
v = ARG(1,left);
if(FUNCTOR(u) == '*' && ARITY(u) == 2 && POSNUMBER(ARG(0,u)))
u = ARG(1,u);
if(FUNCTOR(v) == '*' && ARITY(v) == 2 && POSNUMBER(ARG(0,v)))
v = ARG(1,v);
if(
(FUNCTOR(u) == ABSFUNCTOR && FUNCTOR(v) == ABSFUNCTOR && !contains(right,ABSFUNCTOR)) ||
(FUNCTOR(u) == SQRT && FUNCTOR(v) == SQRT && !contains(right,SQRT)) ||
(FUNCTOR(u) == '^' && ONEHALF(ARG(1,u)) && FUNCTOR(v) == '^' && ONEHALF(ARG(1,v)))
)
{ o[i] = ineqsymbol == '<' ?
(sflag ? squareineq1: squareineq1g) :
(sflag ? squareineq2: squareineq2g); ++i;
/* Examples: abs(x) + abs(x-3) <= 4 */
/* sqrt x + sqrt(x-3) <= 4 */
/* x^(1/2) + (x-3)^(1/2) <= 4 */
/* Squaring the sum will reduce two absolute values to one.
It is then isolated and squared again to eliminate abs entirely.
*/
}
}
if(ZERO(left) && FUNCTOR(right) == '/' && ineqsymbol == '<' &&
!econstant(ARG(1,right)) &&
!( pathlength >= 3 && path[pathlength-3] == AND)
/* don't use these on one side of an interval_as_and term */
)
{ o[i] = sflag ? posnum1 : posnum1g; ++i;
o[i] = sflag ? mulineqsqrt1 : mulineqsqrt1g; ++i;
/* 0 < u/sqrt v => 0 < uv */
o[i] = sflag ? mulineqbysquare1: mulineqbysquare1g; ++i;
}
if(ZERO(left) && FUNCTOR(right) == '/' && ineqsymbol == LE &&
!econstant(ARG(1,right)) &&
!(pathlength >= 3 && path[pathlength-3] == AND)
/* don't use these on one side of an interval_as_and term */
)
{ o[i] = sflag ? posnum2: posnum2g; ++i;
o[i] = sflag ? mulineqsqrt3: mulineqsqrt3g; ++i;
/* 0 <= u/sqrt v => 0 <= uv */
o[i] = sflag ? mulineqbysquare3: mulineqbysquare3g; ++i;
}
if(ZERO(right) && FUNCTOR(left) == '/' && ineqsymbol == '<' &&
!( pathlength >= 3 && path[pathlength-3] == AND)
/* don't use these on one side of an interval_as_and term */
)
{ o[i] = sflag ? mulineqsqrt2: mulineqsqrt2g; ++i;
/* u/sqrt v < 0 => uv < 0 */
o[i] = sflag ? mulineqbysquare2: mulineqbysquare2g; ++i;
}
if(ZERO(right) && FUNCTOR(left) == '/' && ineqsymbol == LE &&
!(pathlength >= 3 && path[pathlength-3] != AND)
/* don't use these on one side of an interval_as_and term */
)
{ o[i] = sflag ? mulineqsqrt4: mulineqsqrt4g; ++i;
/* u/sqrt v <= 0 => uv <= 0 */
o[i] = sflag ? mulineqbysquare4: mulineqbysquare4g; ++i;
}
if( g =='+' || h == '+' ||
(SIGNEDFRACTION(left) && contains(left,FUNCTOR(x))) ||
(SIGNEDFRACTION(right) && contains(right,FUNCTOR(x)))
)
/* eliminate fractions if denoms have known sign;
but not, e.g., in x^2 < 1/4 */
{
o[i] = mulineq; ++i;
}
if(FRACTION(left) && FUNCTOR(ARG(0,left)) == ABSFUNCTOR)
{ o[i] = mulineq; ++i; /* example: abs(2x+1)/2 < 5x */
o[i] = mulineqsq; ++i; /* example: abs(2x+1)/(3x) < 5x */
}
if(FRACTION(right) && FUNCTOR(ARG(0,right)) == ABSFUNCTOR)
{ o[i] = mulineq; ++i;
o[i] = mulineqsq; ++i;
}
if(g == '*' || h == '*') /* divide by constant factor */
{ if(ZERO(right) && ineqsymbol == '<')
{ o[i] = sflag ? normalizelinear1: normalizelinear1g; ++i;
o[i] = sflag ? intervalsneg1: intervalsneg1g; ++i;
}
else if(ZERO(right) && ineqsymbol == LE)
{ o[i] = sflag ? normalizelinear2: normalizelinear2g; ++i;
o[i] = sflag ? intervalsneg2: intervalsneg2g; ++i;
}
else if(ZERO(left) && ineqsymbol == '<')
{ o[i] = sflag ? normalizelinear1: normalizelinear1g; ++i;
o[i] = sflag ? intervalspos1: intervalspos1g; ++i;
}
else if(ZERO(left) && ineqsymbol == LE)
{ o[i] = sflag ? normalizelinear2: normalizelinear2g; ++i;
o[i] = sflag ? intervalspos2: intervalspos2g; ++i;
}
if(contains_sqrt3(t))
{ o[i] = mulineq; ++i; /* example, (1/4)(x-3) < 2, multiply by 4 */
}
o[i] = divineq; ++i;
}
if(g == SQRT)
{ o[i] = ineqsymbol == '<' ?
(sflag ? powerineq11: powerineq11g):
(sflag ? powerineq21: powerineq21g); ++i;
*nops = i;
return;
}
if(g == ROOT)
{ o[i] = ineqsymbol == '<' ?
(sflag ? powerineq14odd: powerineq14oddg):
(sflag ? powerineq24odd: powerineq24oddg); ++i;
o[i] = ineqsymbol == '<' ?
(sflag ? powerineq14even: powerineq14eveng):
(sflag ? powerineq24even: powerineq24eveng); ++i;
*nops = i;
return;
}
if(g == '-' && econstant(right) && !econstant(left) &&
/* work on -x < 3, but not on -3 < x */
!(pathlength >= 3 && path[pathlength-3] == AND)
/* changesigns is called on interval_as_and terms in preops */
)
{ o[i] = ineqsymbol == '<' ?
(sflag ? changesigns1: changesigns1g):
(sflag ? changesigns2: changesigns2g); ++i;
}
if(h == '-' && !econstant(right) && econstant(left) && /* work on 3 < -x, but not on x < - 3 */
!(pathlength >= 3 && path[pathlength-3] == AND)
/* changesigns is called on interval_as_and terms in preops */
)
{ o[i] = ineqsymbol == '<' ?
(sflag ? changesigns1: changesignsandsense3):
(sflag ? changesigns2: changesignsandsense4); ++i;
/* -x > 3 becomes x < - 3 rather than -3 > x;
note that in this case '-x' is 'right', not 'left',
because args of > were switched at the top of the function. */
}
if(g == '-' && contains_sqrt(left) && !contains_sqrt(right) &&
!(!econstant(right) && econstant(left)) && /* stop loop with above conditions */
!(pathlength >= 3 && path[pathlength-3] == AND)
/* changesigns is called on interval_as_and terms in preops */
)
{ o[i] = ineqsymbol == '<' ?
(sflag ? changesigns1: changesigns1g):
(sflag ? changesigns2: changesigns2g); ++i;
}
if(h == '-' && contains_sqrt(right) && !contains_sqrt(left) &&
!(!econstant(left) && econstant(right)) && /* stop loop with above conditions */
!(pathlength >= 3 && path[pathlength-3] == AND)
/* changesigns is called on interval_as_and terms in preops */
)
{ o[i] = ineqsymbol == '<' ?
(sflag ? changesigns1: changesigns1g):
(sflag ? changesigns2: changesigns2g); ++i;
}
/* This is the time to recognize a
polynomial inequality and bring it to the form f(x) < 0.
However, on an inequality like x < sqrt(x^2+1), we don't want
to put everything on the left.
*/
if(!econstant(left) && !contains_sqrt3(left) &&
/* don't use alltoleft if the result will have two summands containing a sqrt
or root, because this will loop with autotransfer */
!(contains_sqrt(right) && FUNCTOR(right) == '+' && contains_sqrt(left)) &&
/* If there's a sum on the right, you can go ahead and transfer it,
and later isolate one root. */
!stop_alltoleft(t)
)
{ o[i] = alltoleft; ++i;
}
/* the condition prevents looping: 0 < f(x); -f(x) < 0; 0 < f(x)... */
/* changesigns will work if we have 0 < -f(x); otherwise just leave
everything on the right. */
/* since factor is on while solving equations, any polynomial that can
be factored will be factored now. Then split_ineq will reduce the problem.
So if we get past here with a polynomial, it can't be factored by Mathpert.
quadraticformula has been applied in autosum, don't repeat it here
*/
o[i] = completethesquare; ++i;
if(g == LN && econstant(right))
{ o[i] = ineqsymbol == '<' ? expineq1 : expineq2;
*nops = i;
return;
}
if(h == LN && econstant(left))
{ o[i] = ineqsymbol == '<' ? expineq1 : expineq2;
*nops = i;
return;
}
if(g == LOG && econstant(right))
{ o[i] = ineqsymbol == '<' ? expineq1 : expineq2;
*nops = i;
return;
}
if(h == LN && econstant(left))
{ o[i] = ineqsymbol == '<' ? expineq1 : expineq2;
*nops = i;
return;
}
if(g == '^')
{ if(isinteger(ARG(1,left)) && iseven(ARG(1,left)) && econstant(right))
{ o[i] = ineqsymbol == '<' ?
(sflag ? sqrtineq14: sqrtineq14g):
(sflag ? sqrtineq24: sqrtineq24g); ++i;
if(equals(ARG(1,left),two))
{ o[i] = ineqsymbol == '<' ?
(sflag ? squarefalse1 : squarefalse1g):
(sflag ? squarefalse2 : squarefalse2g); ++i;
}
else
{ o[i] = ineqsymbol == '<' ?
(sflag ? evenpowerineq3: evenpowerineq3g):
(sflag ? evenpowerineq4: evenpowerineq4g); ++i;
}
*nops = i;
return;
}
if(equals(ARG(0,left),eulere) && econstant(right))
{ o[i] = ineqsymbol == '<' ? lnineq1 : lnineq2;
++i;
*nops = i;
return;
}
if(equals(ARG(0,left),ten) && econstant(right))
{ o[i] = ineqsymbol == '<' ? logineq1 : logineq2;
++i;
*nops = i;
return;
}
if(FUNCTOR(ARG(1,left))=='/') /* fractional exponent */
{ o[i] = ineqsymbol == '<' ?
(sflag ? powerineq16: powerineq16g):
(sflag ? powerineq26: powerineq26g); ++i;
*nops = i;
return;
}
if(econstant(ARG(1,left)) && econstant(right))
{ o[i] = ineqsymbol == '<' ?
(sflag ? oddrootineq: oddrootineqg):
(sflag ? oddrootineq2: oddrootineq2g); ++i;
o[i] = ineqsymbol == '<' ?
(sflag ? rootineq13: rootineq13g):
(sflag ? rootineq23: rootineq23g); ++i;
o[i] = ineqsymbol == '<' ?
(sflag ? evenpowerineq3: evenpowerineq3g):
(sflag ? evenpowerineq4: evenpowerineq4g); ++i;
*nops = i;
return;
}
}
if(h == '^')
{
if(isinteger(ARG(1,right)) && iseven(ARG(1,right)) && econstant(left))
{ o[i] = ineqsymbol == '<' ?
(sflag ? sqrtineq15: sqrtineq15g):
(sflag ? sqrtineq25: sqrtineq25g); ++i;
if(equals(ARG(1,right),two))
{ o[i] = ineqsymbol == '<' ?
(sflag ? squaretrue1: squaretrue1g):
(sflag ? squaretrue2: squaretrue2g); ++i;
}
else
{ o[i] = ineqsymbol == '<' ?
(sflag ? evenpowerineq1: evenpowerineq1g):
(sflag ? evenpowerineq2: evenpowerineq2g); ++i;
}
*nops = i;
return;
}
if(equals(ARG(0,right),eulere) && econstant(left))
{ o[i] = (ineqsymbol == '<' ? lnineq1 : lnineq2);
++i;
*nops = i;
return;
}
if(equals(ARG(0,right),ten) && econstant(left))
{ o[i] = (ineqsymbol == '<' ? logineq1 : logineq2);
++i;
*nops = i;
return;
}
if(FUNCTOR(ARG(1,right))=='/') /* fractional exponent */
{ o[i] = ineqsymbol == '<' ?
(sflag ? powerineq16: powerineq16g):
(sflag ? powerineq26: powerineq26g); ++i;
*nops = i;
return;
}
if(econstant(ARG(1,right)) && econstant(left))
{ o[i] = ineqsymbol == '<' ?
(sflag ? oddrootineq: oddrootineqg):
(sflag ? oddrootineq2: oddrootineq2g); ++i;
o[i] = ineqsymbol == '<' ?
(sflag ? rootineq15: rootineq15g):
(sflag ? rootineq25: rootineq25g); ++i;
o[i] = ineqsymbol == '<' ?
(sflag ? evenpowerineq1: evenpowerineq1g):
(sflag ? evenpowerineq2: evenpowerineq2g); ++i;
*nops = i;
return;
}
}
if(g == LN)
{ o[i] = ineqsymbol == '<' ?
( sflag ? lnleftineq1: lnleftineq1g):
( sflag ? lnleftineq2: lnleftineq2g); ++i;
}
if(g == LOG)
{ o[i] = ineqsymbol == '<' ?
( sflag ? logleftineq1: logleftineq1g):
( sflag ? logleftineq2: logleftineq2g); ++i;
}
if(g == LOGB)
{ o[i] = ineqsymbol == '<' ?
( sflag ? powerineq17: powerineq17g):
( sflag ? powerineq27: powerineq27g); ++i;
}
if(h == LN)
{ o[i] = ineqsymbol == '<' ?
( sflag ? lnrightineq1: lnrightineq1g):
( sflag ? lnrightineq2: lnrightineq2g); ++i;
}
if(g == LOG)
{ o[i] = ineqsymbol == '<' ?
( sflag ? logrightineq1: logrightineq1g):
( sflag ? logrightineq2: logrightineq2g); ++i;
}
if(g == LOGB)
{ o[i] = ineqsymbol == '<' ?
( sflag ? powerineq17: powerineq17g):
( sflag ? powerineq27: powerineq27g); ++i;
}
if(get_problemtype() == IMPLICIT_DIFF || noccurs(get_eigenvariable(),t) > 1)
{ /* if possible, simplify the problem by making a good substitution */
o[i] = makesubstitution; ++i;
}
/* Next come the isolation operators, now that the variable is on one side.
Observe that muleqn and diveqn work in auto mode to isolate / and * ,
and change_signs works to isolate - .
*/
if(econstant(left))
{
if(h==SQRT && ineqsymbol == '<')
{ o[i] = sflag ? powerineq12: powerineq12g; ++i;
*nops = i;
return;
}
if(h==SQRT && ineqsymbol == LE)
{ o[i] = sflag ? powerineq22: powerineq22g; ++i;
*nops = i;
return;
}
if(h==ROOT && ineqsymbol == '<')
{ o[i] = sflag ? powerineq15: powerineq15g; ++i;
*nops = i;
return;
}
if(h==ROOT && ineqsymbol == LE)
{ o[i] = sflag ? powerineq25: powerineq25g; ++i;
*nops = i;
return;
}
}
solved:
if(pathlength <= 3 &&
/* pathlength <= 3 means apply it only to top-level inequalities, not
to inequalities that may have been generated by previous calls to
explicitdomain.
*/
get_problemtype() != TESTCONVERGENCE && /* Since we only care about asymptotic behavior in that case */
!(pathlength >=3 && path[pathlength-3] == AND) &&
/* explicitdomain will be applied directly to an interval_as_and. */
solved(t,get_eigenvariable()) &&
!contains_defined_variables(t) /* wait till definitions have been unwound */
)
{ o[i] = explicitdomain; ++i;
}
*nops = i;
return;
}
/*___________________________________________________________________*/
static unsigned short contains_sqrt3(term a)
/* return ABSFUNCTOR or SQRT or ROOT if a contains an ABSFUNCTOR or SQRT or ROOT
term as a factor or as a factor of num or denom. Similar to
contains_sqrt2 in eqn.c but does not allow minus signs.
*/
{ unsigned short n,f;
unsigned short ans;
int i;
f = FUNCTOR(a);
if(INEQUALITY(f))
{ i = contains_sqrt3(ARG(0,a));
if(i)
return (unsigned short) i;
return contains_sqrt3(ARG(1,a));
}
if(f==SQRT || f == ABSFUNCTOR || f == ROOT)
{ if(contains(a, FUNCTOR(get_eigenvariable())))
return f;
else
return 0;
}
n = ARITY(a);
if(f == '/')
{ for(i=0;i<n;i++)
{ ans = contains_sqrt3(ARG(i,a));
if(ans)
return ans;
}
}
if(f != '*')
return 0;
for(i=0;i<n;i++)
{ f = FUNCTOR(ARG(i,a));
if((f == SQRT || f == ABSFUNCTOR || f==ROOT) &&
contains(ARG(i,a),FUNCTOR(get_eigenvariable()))
)
return f;
}
return 0;
}
/*_____________________________________________________________________*/
static int one_nonconstant_term(term t)
/* t is a sum. Return 1 if it has exactly one nonconstant summand */
{ unsigned short n = ARITY(t);
int i;
int count=0;
if(FUNCTOR(t) != '+')
return 0;
for(i=0;i<n;i++)
{ if(!econstant(ARG(i,t)))
++count;
}
return count == 1 ? 1 : 0;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists