Sindbad~EG File Manager
/* M. Beeson, for Mathpert */
/* Functions to build the SelectOperator menu, specifically
for adding operations to solve inequalities and equations.
*/
/*
1.29.95 Original date
11.12.98 last modified
*/
#define AUTOMODE_DLL
#include <math.h> /* abs */
#include <string.h> /* memset */
#include <assert.h>
#include "globals.h"
#include "graphstr.h"
#include "display.h"
#include "display1.h" /* needed by lterm.h */
#include "document.h"
#include "tdefn.h"
#include "checkarg.h"
#include "ops.h"
#include "trig.h"
#include "calc.h"
#include "bigrect.h"
#include "lterm.h"
#include "selectop.h"
#include "automode.h"
#include "cflags.h"
#include "exec.h" /* erasecolors, finish_exec */
#include "probtype.h"
#include "ops.h"
#include "trig.h"
#include "calc.h"
#include "pvalaux.h" /* content_factor */
/* rawcollectpowers */
/* contains_at_toplevel */
#include "order.h" /* additive_sortargs, common_variables */
#include "prover.h" /* NOTDEFINED */
#include "cancel.h" /* cancel */
#include "mplimits.h" /* LIMITAND */
#include "match.h" /* matchstring */
#include "polynoms.h" /* ispolyin */
#include "sigma.h" /* freevars */
#include "dowith.h" /* dowith */
#include "factor.h" /* numerical_poly */
#include "eqn.h" /* econstant */
#include "solvelin.h" /* is_linear_in */
#include "intsub.h" /* readpending */
#include "exponent.h" /* possible_int */
#include "deval.h"
#include "optable.h" /* access_optable */
#include "docdata.h" /* history */
#include "chkinput.h" /* mathematical */
#include "pda.h" /* seminumerical2 */
#include "relrates.h" /* used */
#include "domain.h" /* contains_defined_variables */
#include "autosub.h"
#include "autosimp.h" /* contains_calc */
static int showsub(term t);
static int nonconstant_powers(term t);
static int show_explicitdomain(term t);
static int powersof10(term);
static int higher_powers(term);
static int two_terms(POLYnomial p);
static int contains_powerof(term t, term x);
/*__________________________________________________________________*/
void select_inequality_ops(term t, actualop *o, int *nops)
/* Fill pre-allocated array o with the operators that
could be applied to t. Return the dimension of the
array in *nops.
*/
{ term u,v,x,context;
term xx,yy,a,b,c;
unsigned short f = FUNCTOR(t);
unsigned short g,h;
char buffer[DIMREASONBUFFER];
int i=0;
int count,sflag;
term left,right,w;
if(!INEQUALITY(f))
{ *nops = 0;
return;
}
left = ARG(0,t);
right = ARG(1,t);
x = get_eigenvariable();
if(solved(t,get_eigenvariable()) &&
!contains_defined_variables(t) &&
get_nextassumption() > 0
)
{ o[i] = explicitdomain; ++i;
}
if(
(numerical(left) || select_arith_aux(left)) &&
(numerical(right) || select_arith_aux(right))
)
{ o[i] = arithmetic; ++i;
}
if(econstant(left) && FUNCTOR(right) == '+' && ARITY(right) == 3 &&
isquadratic(right,&xx,&yy,&a,&b,&c)
)
{ o[i] = completethesquare; ++i;
}
if(econstant(right) && FUNCTOR(left) == '+' && ARITY(left) == 3 &&
isquadratic(left,&xx,&yy,&a,&b,&c)
)
{ o[i] = completethesquare; ++i;
}
/* on 1 < x^2-x, we need completethesquare; isquadratic fails on
arity 2 so we use a different check below. */
if(econstant(left) && FUNCTOR(right) == '+' && ARITY(right) == 2 &&
mvpoly(right) && !makepoly(right,x,&w) &&
(ARITY(w) == 3 || two_terms(w))
/* two_terms catches a polynomial like 6x^6 + x^3 */
)
{ o[i] = completethesquare; ++i;
}
if(econstant(right) && FUNCTOR(left) == '+' && ARITY(left) == 2 &&
mvpoly(left) && !makepoly(left,x,&w) &&
(ARITY(w) == 3 || two_terms(w))
)
{ o[i] = completethesquare; ++i;
}
switch(f)
{ case '>': /* fall through */
case '<':
if(showsub(t))
{ o[i] = makesubstitution; ++i;
}
if(f == '>')
{ u = ARG(1,t);
v = ARG(0,t);
g = FUNCTOR(u);
h = FUNCTOR(v);
o[i] = reversegreaterthan; ++i;
sflag = 0;
}
else
{ v = ARG(1,t);
u = ARG(0,t);
g = FUNCTOR(u);
h = FUNCTOR(v);
o[i] = reverselessthan; ++i;
sflag = 1;
}
if(seminumerical(t))
{ o[i] = numericalineq; ++i;
count = 0;
}
else if(!iscomplex(t) && !get_complex())
/* get_complex is necessary so that sqrt(-1) can't be
selected when it's a complex-number topic */
{ o[i] = evalatpoint; ++i;
count = 1;
}
context = history(get_activeline());
if(FUNCTOR(v) == SQRT && obviously_negative(u))
{ o[i] = f == '<' ? sqsqrtineq1 : sqsqrtineq1rev; ++i;
}
if(FUNCTOR(v) == ROOT && iseven(ARG(0,v)) &&
obviously_negative(u)
)
{ o[i] = f == '<' ? powerrootineq1 : powerrootineq1rev; ++i;
}
if(contains(t,SQRT) || contains(t,ABS))
{ o[i] = sflag ? squareineq1 : squareineq1g; ++i;
o[i] = sflag ? squareineq3 : squareineq3g; ++i;
}
if(ZERO(u))
{ if(!is_linear_in(v,x))
{ o[i] = droppositive1 ; ++i;
}
if(h == '/')
{ o[i] = sflag ? mulineqbysquare1 : mulineqbysquare1g; ++i;
/* 0 < u/v => 0 < uv */
if(contains_sqrt(ARG(1,v)) == SQRT)
{ o[i] = sflag ? mulineqsqrt1 : mulineqsqrt1g; ++i;
/* 0 < u/sqrt v => 0 < uv */
}
}
if(h == '*')
{ if(sflag)
{ if(!normalizelinear1(t,zero,&w,buffer))
{ o[i] = normalizelinear1; ++i;
}
}
else
{ if(!normalizelinear1g(t,zero,&w,buffer))
{ o[i] = normalizelinear1g; ++i;
}
}
o[i] = sflag ? intervalspos1 : intervalspos1g; ++i; /* 0<(x-a)(x-b)=>x<a or b<x (if a<b) */
}
}
if(ZERO(v))
{ if(!is_linear_in(u,x))
{ o[i] = droppositive1; ++i;
}
if(g == ABS)
{ o[i] = absineqfalse; ++i; /* abs(u) < 0 is false */
}
if(g == '/')
{ o[i] = sflag ? mulineqbysquare2 : mulineqbysquare2g; ++i;
/* u/v < 0 => uv < 0 */
if(contains_sqrt(ARG(1,u)) == SQRT)
{ o[i] = sflag ? mulineqsqrt2 : mulineqsqrt2g; ++i;
/* u/sqrt v < 0 => uv < 0 */
}
}
if(g == '+' && count && is_linear_in(u,x))
{ o[i] = sflag ? normalizelinear1 : normalizelinear1g; ++i; /* ax � b < 0 iff a(x�b/a) < 0 */
}
if(g == '*')
{ if(sflag)
{ if(!normalizelinear1(t,zero,&w,buffer))
{ o[i] = normalizelinear1; ++i;
}
}
else
{ if(!normalizelinear1g(t,zero,&w,buffer))
{ o[i] = normalizelinear1g; ++i;
}
}
o[i] = sflag ? intervalsneg1 : intervalsneg1g; ++i; /* (x-a)(x-b)<0 => a<x<b (if a<b) */
}
}
switch(g)
{ case ABS:
o[i] = f == '<' ? abslessthan : absgreaterthan; ++i; /* |u|< v iff -v < u < v */
if(FUNCTOR(ARG(0,u)) == SIN)
{ o[i] = abssinineq; ++i; /* |sin u| � 1 */
}
if(FUNCTOR(ARG(0,u)) == COS)
{ o[i] = abscosineq; ++i; /* |cos u| � 1 */
}
if(FUNCTOR(ARG(0,u)) == ATAN)
{ o[i] = absarctanineq; ++i; /* |arctan u| � �/2 */
}
if(!infer(le(v,zero)))
{ o[i] = f == '<' ? abslessthanneg : absgreaterthanneg; ++i;
/* abs(u) < -c is false when c >= 0 */
/* -c > abs(u) is flase when c >= 0 */
}
break;
case SIN:
o[i] = sinineq; ++i; /* sin u � u if u�0 */
break;
case ATAN:
o[i] = arctanineq; ++i; /* arctan u � u if u�0 */
break;
case SQRT:
o[i] = powerineq11; ++i; /* �u < v => u < v^2 */
break;
case ROOT:
if(isodd(ARG(0,u)))
{ o[i] = sflag ? powerineq14odd :powerineq14oddg; ++i;
}
else
{ o[i] = sflag ? powerineq14even : powerineq14eveng; ++i;
/* ��u < v => u < v */
}
break;
case '^':
if(isinteger(ARG(1,u)) && iseven(ARG(1,u)))
{ o[i] = sflag ? sqrtineq11 : sqrtineq11g; ++i;
/* u^2 < v => |u| < �v */
o[i] = sflag ? sqrtineq14 : sqrtineq14g; ++i;
/* u^2 < a => -a < u < a */
}
if(INTEGERP(ARG(1,u)) && iseven(ARG(1,u)))
{ if(ZERO(v) ||
(NEGATIVE(v) && OBJECT(ARG(0,v)))
)
{ if(isinteger(ARG(1,u)) && iseven(ARG(1,u)))
{ o[i] = sflag ? squarefalse1: squarefalse1g; ++i;
}
else
{ o[i] = sflag ? evenpowerineq3 : evenpowerineq3g; ++i;
}
}
}
else if(!(INTEGERP(ARG(1,u)) && ISODD(ARG(1,u))))
{ o[i] = sflag ? rootineq11 : rootineq11g; ++i;
/* u^2� < v => |u| < ^2��v */
o[i] = sflag ? rootineq13 : rootineq13g; ++i;
/* u^2� < a iff -^2��a < u < ^2��a */
}
break;
case '/':
count = contains_sqrt(u);
if(count == ROOT)
{ o[i] = sflag ? powerineq13 : powerineq13g; ++i;
/* 0 � a(��u) < v => a�u < v� */
}
/* Now for the reciprocal inequaltiies */
if(econstant(v) &&
econstant(ARG(0,u)) &&
obviously_positive(ARG(0,u))
)
{ if(obviously_positive(v))
{ o[i] = sflag ? recipineq11 : recipineq11g; ++i;
/* 1/x < a iff x < 0 or 1/a < x provided a > 0 */
}
else if(obviously_positive(strongnegate(v)))
{ o[i] = sflag ? recipineq31 : recipineq31g; ++i;
/* 1/x < -a iff -1/a < x < 0 < x provided a > 0 */
}
}
break;
case '-': /* fall through */
case '*':
count = contains_sqrt(u);
if(count == ROOT)
{ o[i] = sflag ? powerineq13 : powerineq13g; ++i;
/* 0 � a(��u) < v => a�u < v� */
}
break;
}
if( (g == '^' &&
!(INTEGERP(ARG(1,u)) && ISEVEN(ARG(1,u)))) || (h == '^' && !(INTEGERP(ARG(1,v)) && ISEVEN(ARG(1,v))))\
)
{ o[i] = sflag ? oddrootineq : oddrootineqg; ++i;
}
o[i] = addeqn1; ++i;
o[i] = subeqn1; ++i;
o[i] = changesigns1; ++i; /* -u < -v iff v < u */
o[i] = sflag ? changesignsandsense1 : changesignsandsense3; ++i;
/* change -u < -v to u > v */
o[i] = mulineq; ++i; /* multiply both sides */
o[i] = divineq; ++i; /* divide both sides */
o[i] = sflag ? sqrtineq13 : sqrtineq13g; ++i;
/* 0 � u < v => �u < �v */
o[i] = sflag ? powerineq16 : powerineq16g; ++i;
/* u < v => u� < v� (n odd, n>0) */
o[i] = sflag ? powerineq17: powerineq17g; ++i;
/* 0 � u < v => u� < v� (n > 0) */
switch(h)
{ case '^':
if(isinteger(ARG(1,v)) && iseven(ARG(1,v)))
{ o[i] = sflag ? sqrtineq12 : sqrtineq12g; ++i;
/* 0 � u < v^2 => �u < |v| */
o[i] = sflag ? sqrtineq15 : sqrtineq15g; ++i;
/* a < u^2 => u < -�a or �a < u */
}
if(isinteger(ARG(1,v)) && iseven(ARG(1,v)))
{ if(NEGATIVE(u) && OBJECT(ARG(0,u)))
{ if(isinteger(ARG(1,v)) && iseven(ARG(1,v)))
{ o[i] = sflag ? squaretrue1 : squaretrue1g; ++i;
}
else
{ o[i] = sflag ? evenpowerineq1 : evenpowerineq1g; ++i;
}
}
}
if( !(INTEGERP(ARG(1,v)) && isodd(ARG(1,v))))
{ o[i] = sflag ? rootineq12 : rootineq12g; ++i;
/* 0 � u < v^2� => ^2��u < |v| */
o[i] = sflag ? rootineq15 : rootineq15g; ++i;
/* a < u^2� iff v < -^2��a or ^2��a < u */
}
break;
case '/':
/* Now for the reciprocal inequaltiies */
if(econstant(u) &&
econstant(ARG(0,v)) &&
obviously_positive(ARG(0,v))
)
{ if(obviously_positive(u))
{ o[i] = sflag ? recipineq21 : recipineq21g; ++i;
/* a < 1/x iff 0 < x < 1/a < x provided a > 0 */
}
else if(obviously_positive(strongnegate(u)))
{ o[i] = sflag ? recipineq41 : recipineq41g; ++i;
/* -a < 1/x iff x < -1/a or 0 < x provided a > 0 */
}
}
break;
case SQRT:
o[i] = sflag ? powerineq12 : powerineq12g; ++i;
/* 0 � u < �v => u^2 < v */
break;
case ROOT:
o[i] = sflag ? powerineq15 : powerineq15g; ++i;
/* 0 � u < ��v => u� < |v| */
break;
case TAN:
o[i] = tanineq; ++i; /* u <= tan u if 0<= u pi/2 */
break;
case COS:
o[i] = coslowerbound; ++i; /* 1 - u^2/2 � cos u */
break;
case ABS:
o[i] = f == '<' ? lessthanabs: greaterthanabs; ++i; /* u < abs(v) if v < -u or u < v */
if(!infer(lessthan(zero,u)))
{ o[i] = f == '<' ? absineqtrue3 : absineqtrue3g; ++i;
/* -c < abs(u) is true if c > 0 */
/* abs(u) > -c is true if c > 0 */
}
break;
}
if(get_nextdefn() > 0 && contains_defined_variables(t))
{ o[i] = unwinddefinition; ++i;
}
if(nonconstant_powers(t))
{ o[i] = lnineq1; ++i;
if(g == '^' && h == '^' && equals(ARG(0,u),ARG(0,v)) && !equals(ARG(0,u),eulere) && !equals(ARG(0,u),ten))
{ o[i] = expineq1; ++i;
}
if(powersof10(t))
{ o[i] = logineq1; ++i;
}
}
if(show_explicitdomain(t))
{ o[i] = explicitdomain; ++i;
}
break;
case GE:
/* fall through */
case LE:
if(f == GE)
{ u = ARG(1,t);
v = ARG(0,t);
g = FUNCTOR(u);
h = FUNCTOR(v);
o[i] = reversege; ++i;
sflag = 0;
}
else
{ v = ARG(1,t);
h = FUNCTOR(v);
u = ARG(0,t);
g = FUNCTOR(u);
o[i] = reversele; ++i;
sflag = 1;
}
if(seminumerical(t))
{ o[i] = numericalineq; ++i;
count = 0;
}
else
count = 1;
o[i] = evalatpoint; ++i;
context = history(get_activeline());
if(FUNCTOR(v) == SQRT && obviously_negative(u))
{ o[i] = f == '<' ? sqsqrtineq2 : sqsqrtineq2rev; ++i;
}
if(FUNCTOR(v) == ROOT && iseven(ARG(0,v)) &&
obviously_negative(u)
)
{ o[i] = f == '<' ? powerrootineq2 : powerrootineq2rev; ++i;
}
if(contains(t,SQRT) || contains(t,ABS))
{ o[i] = sflag ? squareineq2 : squareineq2g; ++i;
o[i] = sflag ? squareineq4 : squareineq4g; ++i;
}
if(ZERO(u))
{ if(!is_linear_in(v,x))
{ o[i] = droppositive2 ; ++i;
}
if(h == '/')
{ o[i] = sflag ? mulineqbysquare3 : mulineqbysquare3g; ++i;
/* 0 <= u/v => 0 < uv or u = 0 */
if(contains_sqrt(v) == SQRT)
{ o[i] = sflag ? mulineqsqrt3 : mulineqsqrt3g; ++i;
/* 0 <= u/sqrt v => 0 <= uv */
}
}
if(h == '*')
{ if(sflag)
{ if(!normalizelinear2(t,zero,&w,buffer))
{ o[i] = normalizelinear2; ++i;
}
}
else
{ if(!normalizelinear2g(t,zero,&w,buffer))
{ o[i] = normalizelinear2g; ++i;
}
}
o[i] = sflag ? intervalspos2 : intervalspos2g; ++i;
/* 0�(x-a)(x-b)=>x�a or b�x (if a<b) */
}
if(h == ABS)
{ o[i] = sflag ? absineqtrue : absineqtrueg; ++i; /* |u| � 0 is true */
}
}
if(ZERO(v))
{ if(!is_linear_in(u,x))
{ o[i] = droppositive2; ++i;
}
if(g == '/')
{ o[i] = sflag ? mulineqbysquare4 : mulineqbysquare4g; ++i;
/* u/v <= 0 => uv < 0 or u = 0 */
if(contains_sqrt(u) == SQRT)
{ o[i] = sflag ? mulineqsqrt4 : mulineqsqrt4g; ++i;
/* u/sqrt v <= 0 => uv <= 0 */
}
}
if(g == '+' && count && is_linear_in(u,x))
{ o[i] = sflag ? normalizelinear2 : normalizelinear2g; ++i;
/* ax � b � 0 iff a(x�b/a) � 0 */
}
if(g == '*')
{ if(sflag)
{ if(!normalizelinear2(t,zero,&w,buffer))
{ o[i] = normalizelinear2; ++i;
}
}
else
{ if(!normalizelinear2g(t,zero,&w,buffer))
{ o[i] = normalizelinear2g; ++i;
}
}
o[i] = sflag ? intervalsneg2 : intervalsneg2g; ++i;
/* (x-a)(x-b)�0 => a�x�b (if a<b) */
}
if(g == ABS && sflag == 0)
{ o[i] = absineqfalseg; ++i; /* 0 > abs(u) is false */
}
}
switch(g)
{ case ABS:
o[i] = f == LE ? absle: absge; ++i; /* |u| � v iff -v � u � v */
if(FUNCTOR(ARG(0,u)) == SIN)
{ o[i] = abssinineq; ++i; /* |sin u| � 1 */
}
if(FUNCTOR(ARG(0,u)) == COS)
{ o[i] = abscosineq; ++i; /* |cos u| � 1 */
}
if(FUNCTOR(ARG(0,u)) == ATAN)
{ o[i] = absarctanineq; ++i; /* |arctan u| � �/2 */
}
if(!infer(lessthan(v,zero)))
{ o[i] = f == LE ? absleneg : absgeneg; ++i;
/* abs(u) <= -c is false (c > 0) */
/* -c >= abs(u) is false (c > 0 */
}
if(!infer(le(v,zero)) && infer(lessthan(v,zero)))
/* v is nonpositive but not provably negative */
/* example: abs(x^3-x) <= -x^2 */
{ o[i] = f == LE ? absleneg2 : absgeneg2; ++i;
}
break;
case SIN:
o[i] = sinineq; ++i; /* sin u � u if u�0 */
break;
case ATAN:
o[i] = arctanineq; ++i; /* arctan u � u if u�0 */
break;
case SQRT:
o[i] = powerineq21; ++i; /* �u � v => u � v^2 */
break;
case ROOT:
if(isodd(ARG(0,u)))
{ o[i] = sflag ? powerineq24odd : powerineq24oddg; ++i;
/* ��u � v => u � v */
}
else
{ o[i] = sflag ? powerineq24even : powerineq24eveng; ++i;
}
break;
case '^':
if(isinteger(ARG(1,u)) && iseven(ARG(1,u)))
{ o[i] = sflag ? sqrtineq21 : sqrtineq21g; ++i;
/* u^2 � v => |u| � �v */
o[i] = sflag ? sqrtineq24 : sqrtineq24g; ++i;
/* u^2 � a => -a � u � a */
}
if(INTEGERP(ARG(1,u)) && iseven(ARG(1,u)))
{ if(NEGATIVE(v) && OBJECT(ARG(0,v)))
{ if(isinteger(ARG(1,u)) && iseven(ARG(1,u)))
{ o[i] = sflag ? squarefalse2 : squarefalse2g; ++i;
}
else
{ o[i] = sflag ? evenpowerineq4 : evenpowerineq4g; ++i;
}
}
}
else if(!(INTEGERP(ARG(1,u)) && ISODD(ARG(1,u))))
{ o[i] = sflag ? rootineq21 : rootineq21g; ++i;
/* u^2� � v => |u| � ^2��v */
o[i] = sflag ? rootineq23 : rootineq23g; ++i;
/* u^2� � a iff -^2��a � u � ^2��a */
}
break;
case '/':
count = contains_sqrt(u);
if(count == ROOT)
{ o[i] = sflag ? powerineq23 : powerineq23g; ++i;
/* 0 � a(��u) � v => a�u � v� */
}
/* Now for the reciprocal inequaltiies */
if(econstant(v) &&
econstant(ARG(0,u)) &&
obviously_positive(ARG(0,u))
)
{ if(obviously_positive(v))
{ o[i] = sflag ? recipineq12 : recipineq12g; ++i;
/* 1/x <= a iff x < 0 or 1/a <= x provided a > 0 */
}
else if(obviously_positive(strongnegate(v)))
{ o[i] = sflag ? recipineq32 : recipineq32g; ++i;
/* 1/x <= -a iff -1/a <= x < 0 provided a > 0 */
}
}
break;
case '-': /* fall through */
case '*':
count = contains_sqrt(u);
if(count == ROOT)
{ o[i] = sflag ? powerineq23 : powerineq23g; ++i;
/* 0 � a(��u) � v => a�u � v� */
}
break;
}
if( (g == '^' && !(INTEGERP(ARG(1,u)) && ISEVEN(ARG(1,u)))) || (h == '^' && !(INTEGERP(ARG(1,v)) && ISEVEN(ARG(1,v)))))
{ o[i] = sflag ? oddrootineq2 : oddrootineq2g; ++i;
}
o[i] = addeqn2; ++i;
o[i] = subeqn1; ++i;
o[i] = changesigns2; ++i; /* -u � -v iff v � u */
o[i] = sflag ? changesignsandsense2 : changesignsandsense4; ++i;
/* change -u � -v to u � v */
o[i] = mulineq; ++i; /* multiply both sides by ? */
o[i] = divineq; ++i; /* divide both sides by ? */
o[i] = sflag ? sqrtineq23 : sqrtineq23g; ++i;
/* 0 � u � v => �u � �v */
o[i] = sflag ? powerineq26 : powerineq26g; ++i;
/* u � v => u� � v� (n odd, n>0) */
o[i] = sflag ? powerineq27 : powerineq27g; ++i;
/* 0 � u � v => u� � v� (n > 0) */
o[i] = alltoleft; ++i;
switch(h)
{ case '^':
if(isinteger(ARG(1,v)) && iseven(ARG(1,v)))
{ o[i] = sflag ? sqrtineq22 : sqrtineq22g; ++i;
/* 0 � u � v^2 => �u � |v| */
o[i] = sflag ? sqrtineq25 : sqrtineq25g; ++i;
/* a � u^2 => u � -�a or �a � u */
}
if(INTEGERP(ARG(1,v)) && iseven(ARG(1,v)))
{ if(ZERO(u) ||
(NEGATIVE(u) && OBJECT(ARG(0,u)))
)
{ if(isinteger(ARG(1,v)) && iseven(ARG(1,v)))
{ o[i] = sflag ? squaretrue2: squaretrue2g; ++i;
}
else
{ o[i] = sflag ? evenpowerineq2 : evenpowerineq2g; ++i;
}
}
}
if( !(INTEGERP(ARG(1,v)) && ISODD(ARG(1,v))))
{ o[i] = sflag ? rootineq22 : rootineq22g; ++i;
/* 0 � u � v^2� => ^2��u � |v| */
o[i] = sflag ? rootineq25 : rootineq25g; ++i;
/* a � u^2� iff u � -^2��a or ^2��a � u */
}
break;
case '/':
/* Now for the reciprocal inequaltiies */
if(econstant(u) &&
econstant(ARG(0,v)) &&
obviously_positive(ARG(0,v))
)
{ if(obviously_positive(u))
{ o[i] = sflag ? recipineq22 : recipineq22g; ++i;
/* a <= 1/x iff 0 < x <= 1/a provided a > 0 */
}
else if(obviously_positive(strongnegate(u)))
{ o[i] = sflag ? recipineq42 : recipineq42g; ++i;
/* -a <= 1/x iff x <= -1/a or 0 < x provided a > 0 */
}
}
case SQRT:
o[i] = sflag ? powerineq22 : powerineq22g; ++i;
/* 0 � u � �v => u^2 � v */
break;
case ROOT:
o[i] = sflag ? powerineq25 : powerineq25g; ++i;
/* 0 � u � ��v => u� � |v| */
break;
case TAN:
o[i] = tanineq; ++i; /* tan u � u if u�0 */
break;
case COS:
o[i] = coslowerbound; ++i; /* 1 - u^2/2 � cos u */
break;
case ABS:
o[i] = f == LE ? leabs : geabs; ++i; /* u <= abs(v) if v <= -u or u <= v */
if(!infer(le(zero,u)))
{ o[i] = f == LE ? absineqtrue2 : absineqtrue2g; ++i;
/* -c <= abs(u) is true if c >= 0 */
/* abs(u) >= -c is true if c >= 0 */
}
break;
}
if(get_nextdefn() > 0)
{ o[i] = unwinddefinition; ++i;
}
if(nonconstant_powers(t))
{ o[i] = lnineq2; ++i;
if(g == '^' && h == '^' && equals(ARG(0,u),ARG(0,v)) && !equals(ARG(0,u),eulere) && !equals(ARG(0,u),ten))
{ o[i] = expineq2; ++i;
}
if(powersof10(t))
{ o[i] = logineq2; ++i;
}
}
if(show_explicitdomain(t))
{ o[i] = explicitdomain; ++i;
}
break;
}
if(status(polyvalop) > LEARNING && !polyval(t,&w))
{ o[i] = polyvalop; ++i;
}
*nops = i;
}
/*__________________________________________________________________*/
void select_equation_ops(term t, actualop *o, int *nops)
/* Fill pre-allocated array o with the operators that
could be applied to t. Return the dimension of the
array in *nops. t is presumed to be an equation.
*/
{ term u,v,w,c,x,xx,yy,a,b,cc,context,temp,dummy;
char buffer[DIMREASONBUFFER];
unsigned short g,h;
int i=0;
int err;
int problemtype = get_problemtype();
int currenttopic = get_currenttopic();
if(FUNCTOR(t) != '=')
assert(0);
u = ARG(0,t);
v = ARG(1,t);
x = get_eigenvariable();
if(
(numerical(u) || select_arith_aux(u)) &&
(numerical(v) || select_arith_aux(v))
)
{ o[i] = arithmetic; ++i;
if(!rejecteqn(t,zero,&w,buffer))
{ o[i] = rejecteqn; ++i;
*nops = i;
return;
}
}
g = FUNCTOR(u);
h = FUNCTOR(v);
if(showsub(t))
{ o[i] = makesubstitution; ++i;
}
if(problemtype == MINMAX && get_nvariables() > 1 &&
contains_existentials(t)
)
{ o[i] = eliminateparameter; ++i;
}
if(FUNCTOR(ARG(0,t)) == VECTOR && FUNCTOR(ARG(1,t)) == VECTOR)
{ if(!impossibleeqns(t,zero,&w,buffer))
{ o[i] = impossibleeqns; ++i;
}
o[i] = dropzerorow; ++i;
o[i] = convertmatrixeqn; ++i;
}
if(currenttopic == _cramers_rule)
{ o[i] = cramersrule; ++i;
}
if(contains(t,MATRIX) &&
( currenttopic == _eqns_in_matrix_form ||
currenttopic == _gauss_jordan
)
)
{ o[i] = addrows; ++i;
o[i] = subrows; ++i;
o[i] = addmulrows; ++i;
o[i] = submulrows; ++i;
o[i] = swaprows; ++i;
SETFUNCTOR(dummy,ILLEGAL,0);
if(!dropduplicaterow(t,dummy,&w,buffer))
{ o[i] = dropduplicaterow; ++i;
}
if(!impossibleeqns(t,dummy,&w,buffer))
{ o[i] = impossibleeqns; ++i;
}
*nops = i; /* don't show dividebymatrix on _gauss_jordan */
return;
}
if(contains(t,MATRIX))
{ if(FUNCTOR(ARG(0,t)) == '*' &&
FUNCTOR(ARG(0,ARG(0,t))) == MATRIX
)
{ o[i] = dividebymatrix; ++i;
}
*nops = i; /* None of the following operators are
for matrix equations */
return;
}
if(FUNCTOR(ARG(0,t)) == VECTOR && FUNCTOR(ARG(1,t)) == VECTOR)
{ *nops = i;
return;
}
if(g == h && SOLVETYPE(problemtype) && equals(u,v))
{ o[i] = trueeqn; ++i;
}
if(obviously_nonnegative(u) &&
obviously_nonnegative(strongnegate(v))
&& !ZERO(u) && !ZERO(v)
)
{ o[i] = pseudosquare; ++i;
}
if(obviously_nonnegative(v) && obviously_nonnegative(strongnegate(u)))
{ o[i] = pseudosquare; ++i;
}
if(ZERO(u))
{ u = v;
v = zero;
g = FUNCTOR(u);
h = FUNCTOR(v);
}
if(problemtype == SOLVE_EQUATION &&
ISATOM(ARG(0,t)) &&
readpending(&temp) == 0
)
{ o[i] = showcallingcubic; ++i;
}
if(status(intsub) == LEARNING)
{ if(ISATOM(ARG(0,t)) && !contains(t,DIFF) &&
!contains(ARG(1,t),FUNCTOR(ARG(0,t))) &&
problemtype == INTEGRATION &&
readpending(&temp) == 0
)
/* Integrating by substitution the LEARNING way */
{ o[i] = difsubstitution; ++i;
*nops = i;
return;
}
if(contains(ARG(0,t),DIFF) && !contains(ARG(1,t),DIFF) &&
problemtype == INTEGRATION &&
readpending(&temp) == 0
)
{ o[i] = showcallingproblem; ++i;
}
*nops = i;
return; /* you have to compute du/dx first */
}
if((contains(t,DIFF) || contains(t,PR)) &&
currenttopic != _logarithmic_differentiation
)
{ if(!SOLVETYPE(problemtype))
{ o[i] = difeqn; ++i;
*nops = i;
return; /* don't show equation-solving operations */
}
}
if(problemtype != LINEAR_EQUATION && problemtype != LINEAR_EQUATIONS)
{ err = cancel(v,u,&c,&w); /* only show spliteqn2 if it works */
if(!err)
{ o[i] = cancelfactor; ++i;
if(!seminumerical(c))
{ o[i] = spliteqn2; ++i; /* if ab = ac then a=0 or b=c */
}
}
if(problemtype != IMPLICIT_DIFF &&
problemtype != RELATED_RATES &&
problemtype != MINMAX
)
{ o[i] = evalatpoint; ++i;
if(!contains_calc(t) && !solved(t,get_eigenvariable()))
{ o[i] = solvenumerically; ++i;
}
}
}
context = history(get_activeline());
if(FUNCTOR(context) == AND)
{ if(get_selected_equation())
{ o[i] = showalleqns; ++i;
}
}
switch(g)
{ case ABS:
o[i] = abseqn; ++i; /* |u|=c iff u=c or u = -c */
if(equals(ARG(0,u),v))
{ o[i] = abseqntoineq1; ++i;
}
/* the next rule is for abs(p) = -p; it will
work when v+ARG(0,u) simplifies to zero,
and there are lots of ways that can happen,
so let's just run the operation. */
err = abseqntoineq2(t,zero,&w,buffer);
if(!err)
{ o[i] = abseqntoineq2; ++i;
}
if(!infer(le(v,zero)))
{ o[i] = abseqnneg; ++i;
}
break;
case '*':
if(h == '*' && status(cancelfactor) >= LEARNING)
/* cancel common factor on both sides; don't
show it unless it works */
{ err = cancelfactor(t,zero,&w,buffer);
if(!err)
{ o[i] = cancelfactor; ++i;
}
}
break;
case '/':
if(FUNCTOR(ARG(0,u)) == ABS && equals(ARG(1,u),ARG(0,ARG(0,u))))
{ o[i] = abseqn2; ++i; /* |u|/u=c iff c=�1 */
}
break;
case SIN:
o[i] = solvesin; ++i; /* sin u=c iff u= (-1)�arcsin c+n� */
o[i] = solvesin2; ++i; /* sin u=c iff u = arcsin c + 2n� or u = -arcsin c + (2n+1)� */
o[i] = rejectimpossiblesin; ++i; /* reject sin u = c if |c|>1 */
if(ZERO(v))
{ o[i] = solvesin0; ++i; /* sin u = 0 iff u = n� */
}
if(ONE(v))
{ o[i] = solvesin90; ++i; /* sin u = 1 iff u = �/2+2n� */
}
if(equals(v,minusone))
{ o[i] = solvesin270; ++i; /* sin u = -1 iff u = 3�/2+2n� */
}
if(FRACTION(v) && equals(ARG(1,v),two))
{ if(ONE(ARG(0,v)))
{ o[i] = solvesin30; ++i; /* sin(u)=1/2 iff u=�/6 or 5�/6+2n� */
}
if(FUNCTOR(ARG(0,v)) == SQRT && equals(ARG(0,ARG(0,v)),three))
{ o[i] = solvesin60; ++i; /* sin(u)=�3/2 iff u=�/3 or 2�/3+2n� */
}
}
if(NEGATIVE(v) && FRACTION(ARG(0,v)) && equals(ARG(1,ARG(0,v)),two))
{ if(ONE(ARG(0,ARG(0,v))))
{ o[i] = solvesin330; ++i; /* sin(u)=-1/2 iff u=-�/6 or -5�/6+2n� */
}
if(FUNCTOR(ARG(0,ARG(0,v))) == SQRT && equals(ARG(0,ARG(0,ARG(0,v))),three))
{ o[i] = solvesin300; ++i; /* sin(u)=-�3/2 iff u=-�/3 or -2�/3+2n� */
}
}
if(FRACTION(v) && ONE(ARG(0,v)) &&
FUNCTOR(ARG(1,v)) == SQRT &&
equals(ARG(0,ARG(1,v)),two)
)
{ o[i] = solvesin45; ++i; /* sin u = 1/�2 if u=�/4 or 3�/4 + 2n� */
}
if(NEGATIVE(v) && FRACTION(ARG(0,v)) &&
ONE(ARG(0,ARG(0,v))) &&
FUNCTOR(ARG(1,ARG(0,v))) == SQRT &&
equals(ARG(0,ARG(1,ARG(0,v))),two)
)
{ o[i] = solvesin315; ++i; /* sin u=-1/�2 if u=5�/4 or 7�/4 + 2n� */
}
break;
case COS:
o[i] = solvecos; ++i; /* cos u=c iff u=�arccos c+2n� */
o[i] = rejectimpossiblecos; ++i; /* reject cos u = c if |c|>1 */
if(ZERO(v))
{ o[i] = solvecos90; ++i; /* sin u = 1 iff u = �/2+2n� */
}
if(ONE(v))
{ o[i] = solvecos0; ++i; /* cos u = 1 iff u = 2n� */
}
if(equals(v,minusone))
{ o[i] = solvecos180; ++i; /* cos u = -1 iff u = (2n+1)� */
}
if(FRACTION(v) && equals(ARG(1,v),two))
{ if(ONE(ARG(0,v)))
{ o[i] = solvecos60; ++i; /* cos(u)=1/2 iff u=��/3+2n� */
}
if(FUNCTOR(ARG(0,v)) == SQRT && equals(ARG(0,ARG(0,v)),three))
{ o[i] = solvecos30; ++i; /* cos(u)=�3/2 iff u=��/6 + 2n� */
}
}
if(NEGATIVE(v) && FRACTION(ARG(0,v)) && equals(ARG(1,ARG(0,v)),two))
{ if(ONE(ARG(0,ARG(0,v))))
{ o[i] = solvecos120; ++i; /* cos(u)=-1/2 iff u=� 2�/3+2n� */
}
if(FUNCTOR(ARG(0,ARG(0,v))) == SQRT && equals(ARG(0,ARG(0,ARG(0,v))),three))
{ o[i] = solvecos150; ++i; /* cos(u)=-�3/2 iff u=�5�/6 + 2n� */
}
}
if(FRACTION(v) && ONE(ARG(0,v)) &&
FUNCTOR(ARG(1,v)) == SQRT &&
equals(ARG(0,ARG(1,v)),two)
)
{ o[i] = solvecos45; ++i; /* cos u = 1/�2 if u=�/4 or 7�/4 + 2n� */
}
if(NEGATIVE(v) && FRACTION(ARG(0,v)) &&
ONE(ARG(0,ARG(0,v))) &&
FUNCTOR(ARG(1,ARG(0,v))) == SQRT &&
equals(ARG(0,ARG(1,ARG(0,v))),two)
)
{ o[i] = solvecos135; ++i; /* cos u=-1/�2 if u=3�/4 or 5�/4 + 2n� */
}
break;
case COT:
if(ZERO(v))
{ o[i] = solvecot90; ++i; /* cot u = 0 iff cos u = 0 */
/* Then cot can't be converted to 1/tan */
}
break;
case TAN:
o[i] = solvetan; ++i; /* tan u=c iff u=arctan c+n� (c not � i) */
if(ZERO(v))
{ o[i] = solvetan0; ++i; /* tan u = 0 iff sin u = 0 */
}
if(FRACTION(v) && ONE(ARG(0,v)) &&
FUNCTOR(ARG(1,v)) == SQRT &&
equals(ARG(0,ARG(1,v)),three)
)
{ o[i] = solvetan30; ++i; /* tan(u)=1/�3 iff u = �/6 + n� */
}
if(h == SQRT && equals(ARG(0,v),three))
{ o[i] = solvetan60; ++i; /* tan(u)=�3 iff u = �/3 + n� */
}
if(NEGATIVE(v) && FUNCTOR(ARG(0,v)) == SQRT && equals(ARG(0,ARG(0,v)),three))
{ o[i] = solvetan120; ++i; /* tan(u)=-�3 iff u = 2�/3 + n� */
}
if(NEGATIVE(v) && FRACTION(ARG(0,v)) &&
ONE(ARG(0,ARG(0,v))) &&
equals(ARG(0,ARG(1,ARG(0,v))),three)
)
{ o[i] = solvetan330; ++i; /* tan(u)=-1/�3 iff u = -�/6 + n� */
}
if(ONE(v))
{ o[i] = solvetan45; ++i; /* tan u = 1 if u= �/4 or 5�/4 + 2n� */
}
if(equals(v,minusone))
{ o[i] = solvetan135; ++i; /* tan u = -1 if u=3�/4 or 7�/4 + 2n� */
}
break;
}
o[i] = switchsides; ++i;
o[i] = changesigns; ++i;
o[i] = addeqn; ++i;
o[i] = subeqn; ++i;
o[i] = muleqn; ++i;
o[i] = diveqn; ++i;
if(problemtype != LINEAR_EQUATIONS && problemtype != LINEAR_EQUATION)
{ o[i] = squareeqn; ++i;
}
if(!get_complex() && ZERO(v) && g == '+' && ARITY(u) == 3)
{ o[i] = negativediscriminant; ++i;
}
if(contains(t,ROOT) ||
contains_fractional_exponents(t) ||
(FUNCTOR(u) == '^' && !INTEGERP(ARG(1,u))) ||
(FUNCTOR(v) == '^' && !INTEGERP(ARG(1,v)))
)
/* otherwise why clutter up the menu with an irrelevant operation?
especially for the beginning algebra student */
{ o[i] = powereqn; ++i;
}
o[i] = alltoleft; ++i;
if(problemtype != LINEAR_EQUATION && ZERO(v) && FUNCTOR(u) == '*')
{ o[i] = spliteqn; ++i;
}
if(FRACTION(u) || FRACTION(v))
{ o[i] = crossmultiply; ++i;
}
if(ZERO(v) && FUNCTOR(u) == '+' && ARITY(u) > 3 && !long_quadratic(u,x,&a,&b,&c))
/* example: x^2 -2x + 4 + e^2 = 0; these arise from log equations. */
{ o[i] = quadraticformula; ++i;
}
if(ZERO(v) && FUNCTOR(u) == '+' && ARITY(u) == 3 &&
isquadratic(u,&xx,&yy,&a,&b,&cc)
)
{ o[i] = quadraticformula; ++i;
o[i] = completethesquare; ++i;
}
else if(currenttopic == _complete_the_square)
{ o[i] = completethesquare; ++i;
}
else if(FUNCTOR(u) == '+' && ARITY(u) == 2 && numerical(v))
{ term w = make_term('+',3);
ARGREP(w,0,ARG(0,u));
ARGREP(w,1,ARG(1,u));
ARGREP(w,2,tnegate(v));
if(isquadratic(w,&xx,&yy,&a,&b,&cc))
{ o[i] = completethesquare; ++i;
}
RELEASE(w);
}
/* What are the conditions for sqrteqn? Theoretically you
can apply it to ANY equation, but it will just clutter up
the screen in many cases where it couldn't possibly be relevant.
But, in principle it should be shown where legally applicable.
However, if either side is a nonconstant sum, it's not going to
help much! Of course, the sum might factor to a square...*/
if(!(g == '+' && !econstant(u)) && !(h == '+' && !econstant(v)) &&
problemtype != LINEAR_EQUATIONS && problemtype != LINEAR_EQUATION
)
{ o[i] = sqrteqn; ++i;
if(higher_powers(t)) /* powers other than 2 */
{ o[i]= rooteqn; ++i;
if(get_complex())
{ o[i] = demoivre; ++i;
}
}
}
if(!ALGEBRA_TOPIC(currenttopic) &&
(!ispolyin(u,x) || !ispolyin(v,x))
)
{ o[i] = functioneqn; ++i;
}
if(get_nextdefn() > 0)
{ o[i] = unwinddefinition; ++i;
}
if(solved(t,x) &&
problemtype != LINEAR_EQUATIONS &&
problemtype != LINEAR_EQUATION &&
problemtype != MINMAX
)
{ o[i] = checkroot; ++i;
if(contains(t,PI_ATOM))
{ term *atomlist;
int nvars = integer_parameters(t,&atomlist);
free2(atomlist);
if(nvars)
{ o[i] = periodicform; ++i;
}
}
}
if( problemtype != LINEAR_EQUATIONS && problemtype != LINEAR_EQUATION &&
rejecteqn(t,zero,&w,buffer)==0
)
{ o[i] = rejecteqn; ++i;
}
if(ZERO(v) && !makepoly(u,x,&w) && DEGREE(w) == 3)
{ /* a cubic */
if(!ZERO(ARG(2,w)))
{ o[i] = eliminatequadraticterm; ++i;
}
else if(!ZERO(ARG(1,w))) /* don't show these on x^3 - 8 = 0 */
{ o[i] = computediscriminant; ++i;
o[i] = viete; ++i;
o[i] = get_complex ? cardan : realcardan ; ++i;
o[i] = cardan2; ++i;
}
}
/* Again, in theory you could always raise any equation to
an arbitrary power, but you don't want to do it unless
one side is a logarithm. */
if(g == LN || h == LN)
{ o[i] = powereqn3; ++i;
o[i] = powereqn2; ++i;
}
if(g == LOG || h == LOG)
{ o[i] = powereqn4; ++i;
o[i] = powereqn2; ++i;
}
if(g == LOGB || h == LOGB)
{ o[i] = powereqn5; ++i;
o[i] = powereqn2; ++i;
}
if(nonconstant_powers(t))
{ o[i] = lneqn; ++i;
if(g == '^' && h == '^' && equals(ARG(0,u),ARG(0,v)))
{ o[i] = logbeqn; ++i;
}
else if (g == '^' && INTEGERP(v) && !logbeqn(t,zero,&w,buffer))
{ o[i] = logbeqn; ++i;
}
else if (h == '^' && INTEGERP(u) && !logbeqn(t,zero,&w,buffer))
{ o[i] = logbeqn; ++i;
}
if(powersof10(t))
{ o[i] = logeqn; ++i;
}
}
if(status(solvelinear) > LEARNING &&
!contains_powerof(t,x) &&
!solvelinear(t,zero,&w,buffer) /* only show it if it will work */
)
{ o[i] = solvelinear; ++i;
}
if(status(ssolveop) > LEARNING &&
(!contains_calc(t) || problemtype == RELATED_RATES)
)
{ o[i] = ssolveop; ++i;
}
if(status(polyvalop) > LEARNING && !polyval(t,&w))
{ o[i] = polyvalop; ++i;
}
if(get_complex() && !explicitparams(t,zero,&w,buffer))
{ o[i] = explicitparams; ++i;
}
*nops = i;
return;
}
/*___________________________________________________________________*/
static int showsub(term t)
/* t is an equation or inequality. Return 1 if the Term Selection
Menu should show "make a substitution (u = ? )" so they can type in a
substitution. Return 0 if not. */
{ short savenextassumption = get_nextassumption();
char buffer[DIMREASONBUFFER];
int saveit = get_nvariables();
int savenextdefn = get_nextdefn();
int saveeigen = get_eigenindex();
term sub,ans;
int err = autosub(t,&sub,&ans);
/* this tries gcdsubstitution, but not fractionalsubstitution */
if(err)
err = fractionalsubstitution(t,zero,&ans,buffer);
set_eigenvariable(saveeigen);
set_nvariables(saveit);
set_nextdefn(savenextdefn);
set_nextassumption(savenextassumption);
return !err;
}
/*__________________________________________________________________*/
static int nonconstant_powers(term t)
/* Return 1 if t contains a power in which the exponent is not
numerical */
{ unsigned short n;
int k;
if(ATOMIC(t))
return 0;
if(FUNCTOR(t) == '^')
{ if(!numerical(ARG(1,t)))
return 1;
return nonconstant_powers(ARG(0,t));
}
n = ARITY(t);
for(k=0;k<n;k++)
{ if(nonconstant_powers(ARG(k,t)))
return 1;
}
return 0;
}
/*_____________________________________________________________________*/
static int show_explicitdomain(term t)
/* return 1 if the term selection menu should show explicit domain
when inequality t (or interval_as_and t) is selected. Specifically,
return 1 if there were any assumptions at line 0, and if t
is a solved inequality or OR of solved inequalities.
*/
{ unsigned short f = FUNCTOR(t);
term x;
int nextassumption;
int i;
assumption **assumptions;
if(f != '<' && f != LE && f != '>' && f != GE)
return 1;
nextassumption = get_nextassumption();
if(nextassumption == 0)
return 0;
assumptions = get_assumptions();
for(i=0;i<nextassumption;i++)
{ if(assumptions[i]->line > 0)
break;
}
if(i==0)
return 0;
x = get_eigenvariable();
return solved(t,x) ? 1 : 0;
}
/*__________________________________________________________________*/
static int powersof10(term t)
/* return 1 if t contains a power with base 10 */
{ unsigned short n;
int i;
if(ATOMIC(t))
return 0;
if(FUNCTOR(t) == '^' && equals(ARG(0,t),ten))
return 1;
n = ARITY(t);
for(i=0;i<n;i++)
{ if(powersof10(ARG(i,t)))
return 1;
}
return 0;
}
/*__________________________________________________________________*/
static int higher_powers(term t)
/* return 1 if t contains a power with exponent other than 2 */
{ unsigned short n;
int i;
if(ATOMIC(t))
return 0;
if(FUNCTOR(t) == '^' && !equals(ARG(1,t),two))
return 1;
n = ARITY(t);
for(i=0;i<n;i++)
{ if(higher_powers(ARG(i,t)))
return 1;
}
return 0;
}
/*___________________________________________________________________*/
static int two_terms(POLYnomial p)
/* return 1 if p has exactly two nonzero terms x^n and x^2n */
{ int i, founda=0,foundb=0;
unsigned short n = ARITY(p);
for(i=0;i<n;i++)
{ if(!ZERO(ARG(i,p)))
{ if(!founda)
founda = i+1;
else if(foundb)
return 0;
else if(i != 2 * (founda-1))
return 0;
else
foundb = i+1;
}
}
return 1;
}
/*________________________________________________________________________*/
static int contains_powerof(term t, term x)
/* x is a variable. Return 1 if t contains a power
which contains x, either in the base or the exponent */
{ int i;
unsigned short n;
if(ATOMIC(t))
return 0;
if(FUNCTOR(t) == '^')
return contains(t,FUNCTOR(x));
n = ARITY(t);
for(i=0;i<n;i++)
{ if(contains_powerof(ARG(i,t),x))
return 1;
}
return 0;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists