Sindbad~EG File Manager
/* M. Beeson, for Mathpert */
/* Functions to build the SelectOperator menu */
/*
1.29.95 Original date
3.9.01 last modified
6.17.04 modified is_complex to count complex variables as well as complexi.
6.18.04 made is_complex exported
*/
#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 "series.h"
#include "pvalaux.h" /* content_factor */
/* rawcollectpowers */
/* contains_at_toplevel */
/* expandable_sum */
#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, long_quadratic */
#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 "nfactor.h" /* small_prime */
#include "select2.h" /* select_integration_op etc */
#include "selineq.h" /* select_inequality_ops */
#include "userfunc.h" /* is_defined */
#include "numpower.h" /* possible_power */
#include "preops.h" /* almost_algebraic */
#include "sqrts.h" /* fractexps */
#include "dcomplex.h" /* needed by ceval.h */
#include "ceval.h" /* complexnumerical */
#include "domain.h" /* contains_defined_variables */
#include "relrates.h" /* used, DIFEQN */
#include "binders.h"
#include "mpminmax.h" /* used2, ADDLIMITS, etc. */
#include "autosimp.h" /* contains_calc */
#include "selfract.h"
#include "sselect.h" /* select_series_op */
#define SIGNED_INTEGERP(x) (INTEGERP(x) || (NEGATIVE(x) && INTEGERP(ARG(0,x))))
/*______________________________________________________________________*/
void selectfractops(term t, actualop *o, int *nops)
/* finish selectops1 when FUNCTOR(t) =='/' */
{ term u,v,w,x,p,q;
unsigned short g,h,g2,h2;
int i = 0;
int err;
unsigned short j,k;
int k2;
int problemtype = get_problemtype();
term *atomlist;
char buffer[DIMREASONBUFFER];
u = ARG(0,t);
v = ARG(1,t);
g = FUNCTOR(u);
h = FUNCTOR(v);
x = get_eigenvariable();
if(ZERO(u))
{ o[i] = zeronum; ++i;
}
if(ONE(u) && h == '^')
{ o[i] = poweroutofrecip; ++i;
}
if(ONE(v))
{ o[i] = unitdenom; ++i;
}
if(equals(v,complexi))
{ o[i] = ONE(u) ? recipofi : recipofi2; ++i;
/* 1/i = -i, a/i = -ai */
}
if(FUNCTOR(v) == '*' && iscomplex(v) && !recipofi3(t,zero,&w,buffer))
{ o[i] = recipofi3; ++i;
}
if(g == SUM && h == SUM)
/* series division can be performed only on power series with numerical coefficients.
We don't check the power series condition here. */
{ term *atomlist;
int nvars = variablesin(u,&atomlist);
free2(atomlist);
if(nvars == 2)
{ nvars = variablesin(v,&atomlist);
free2(atomlist);
if(nvars == 2)
{ o[i] = dividepowerseries; ++i;
}
}
}
if(problemtype == POWERSERIES)
{ select_series_op(t,o+i,&k2);
i += k2;
}
if(equals(v,two) && FUNCTOR(u) == '+' && ARITY(u) == 2 &&
FUNCTOR(ARG(0,u)) == '^' && equals(ARG(0,ARG(0,u)),eulere)
)
{ if(!coshdefrev(t,zero,&w,buffer))
{ o[i] = coshdefrev; ++i;
}
if(!sinhdefrev(t,zero,&w,buffer))
{ o[i] = sinhdefrev; ++i;
}
if(!complexcosrev(t,zero,&w,buffer))
{ o[i] = complexcosrev; ++i;
}
}
if(h == '*' && ARITY(v) == 2 && equals(ARG(0,v),two) &&
equals(ARG(1,v),complexi) && g == '+' && ARITY(u) == 2 &&
FUNCTOR(ARG(0,u)) == '^' && equals(ARG(0,ARG(0,u)),eulere) &&
!sinhdefrev(t,zero,&w,buffer)
)
{ o[i] = sinhdefrev; ++i;
}
if(h == '^' && equals(ARG(0,v),eulere) && iscomplex(ARG(1,v)))
{ o[i] = complexexptonum; ++i;
}
if(h == '*' && !complexexptonum(t,zero,&w,buffer))
{ o[i] = complexexptonum; ++i;
}
if(INTEGERP(v))
{ o[i] = pulloutrational; ++i; /* sqrt(3)/2 = (1/2) sqrt(3) */
}
if(is_complex(v))
{ o[i] = cleardenomofi; ++i; /* clear denominator of i */
}
if(is_complex(u) && !is_complex(v))
{ o[i] = complexapart; ++i; /* (u+vi)/w = u/w + (v/w)i */
}
if(NEGATIVE(u) && NEGATIVE(v))
{ o[i] = cancelminusinquotient; ++i;
}
else
{ if(NEGATIVE(u))
{ o[i] = minusoutfromnum; ++i;
}
if(NEGATIVE(v))
{ o[i] = minusoutfromdenom; ++i;
}
}
if(numerical(t) && contains(u,'^') && contains(v,'^'))
{ o[i] = producttopower; ++i;
/* example, 10^(1/2) / (2^(1/2) 5^(1/2)) */
}
if((h == '^' || h == '*') &&
(contains(v,'^') || contains(v,'+')) &&
/* It doesn't have to contain '^', e.g. 1/(x(x-1)) */
rational_function(t,x)
)
{ o[i] = partialfractionsop; ++i;
}
if(g == DEG && NUMBER(v))
{ o[i] = divdegrees; ++i;
}
if(g == ABS)
{ o[i] = divabs; ++i;
}
if(g == '*' && contains_at_toplevel(u,ABS))
{ o[i] = divabs2; ++i;
}
if(g == '*' && isinteger(v))
{ o[i] = breakfraction2; ++i; /* ab/c = (a/c) b */
/* needed to convert sqrt(3)x/2 to (sqrt(3)/2) x */
}
if(h == '*')
{ int flag = contains_sqrt(v);
if(flag == SQRT)
{ o[i] = cancelsqrt; ++i;
}
else if(flag == ROOT)
{ o[i] = cancelroot; ++i;
}
for(j=0;j<ARITY(v);j++)
{ if(INTEGERP(ARG(j,v)))
{ o[i] = pulloutrational; ++i;
break;
}
}
if(contains_at_toplevel(v,SG))
{ o[i] = sgrecip; ++i;
}
if(iscomplex(u) && !iscomplex(v))
{ if(FUNCTOR(u) == '*')
{ o[i] = pulloutreal; ++i;
}
else if(problemtype != POWERSERIES)
/* if problemtype is POWERSERIES, pulloutdenom gets shown
regardless, so we don't want to show it twice. */
{ o[i] = pulloutdenom; ++i;
}
}
}
if(h == SG)
{ o[i] = sgrecip; ++i;
}
if(g == '*')
{ int flag = contains_sqrt(u);
if(flag == SQRT)
{ o[i] = cancelsqrt2; ++i;
}
else if(flag == ROOT)
{ o[i] = cancelroot2; ++i;
}
o[i] = breakfraction1; ++i;
}
g2 = g == '-' ? FUNCTOR(ARG(0,u)) : g;
h2 = h == '-' ? FUNCTOR(ARG(0,v)) : h;
if(
equals(u,v) || /* examples, x/x or ln(5)/ln(5) */
(NEGATIVE(u) && equals(ARG(0,u),v)) ||
(NEGATIVE(v) && equals(ARG(0,v),u))
)
/* The conditions below let these cases slip through */
{ o[i] = cancelop; ++i;
}
else if(g2 == '*' || g2 == '^' || h2 == '*' || h2 == '^' ||
g2 == '+' || h2 == '+' || /* example, (2(x+3) + 8x) /14 */
g2 == '/' || h2 == '/' || /* example (2x/a)/2, the 2 will cancel */
(SIGNED_INTEGERP(u) && SIGNED_INTEGERP(v))
)
{ err = cancel(u,v,&p,&q);
if(!err)
{ o[i] = cancelop; ++i;
}
if(g != '-' && h != '-' &&
common_variables(u,v) &&
(
g == '^' || (g == '*' && contains_at_toplevel(u,'^')) ||
h == '^' || (h == '*' && contains_at_toplevel(v,'^'))
)
)
{ if(!powerstonum(t,zero,&w,buffer))
{ o[i] = powerstonum; ++i;
}
if(!powerstodenom(t,zero,&w,buffer))
{ o[i] = powerstodenom; ++i;
}
}
if( h != '-' &&
(
(g == '^' && NEGATIVE(ARG(1,u))) ||
(g == '*' && contains_neg_exp(u))
)
)
{ if(!eliminateconstnegexpnum(t,zero,&w,buffer))
{ o[i] = eliminateconstnegexpnum; ++i;
}
else
{ o[i] = eliminatenegexpnum; ++i;
}
}
if( g != '-' &&
(
(h == '^' && NEGATIVE(ARG(1,v))) ||
(h == '*' && contains_neg_exp(v))
)
)
{ o[i] = eliminatenegexpdenom; ++i;
}
if(status(introducenegexp) >= LEARNING &&
!ZERO(ARG(1,t)) &&
!SOME_INFINITESIMAL(t)
)
{ if(
h == '^' ||
(h == '*' && contains_at_toplevel(v,'^'))
)
{ o[i] = introducenegexp; ++i;
}
else
{ o[i] = introducenegexp1; ++i;
}
}
}
if(g == SQRT && h == SQRT)
{ o[i] = quotientofsqrts; ++i; /* �x/�y = �(x/y) */
o[i] = cancelsqrtgcd; ++i; /* show common factor in �u/�v */
o[i] = cancelsqrt3; ++i; /* cancel �: �(xy)/�y = �x */
}
else if((g == SQRT || g == '*') && (h == SQRT || h == '*'))
{ if(contains_sqrt(u) && contains_sqrt(v))
{ /* then cancelsqrt3 can still work */
err = cancelsqrt3(t,zero,&u,buffer);
if(!err)
{ o[i] = cancelsqrt3; ++i;
}
if(!cancelsqrtgcd(t,zero,&u,buffer))
{ o[i] = cancelsqrtgcd; ++i;
}
}
}
if(contains_sqrt(u) || contains_sqrt(v))
{ if(!cancelroot3(t,zero,&w,buffer))
{ o[i] = cancelroot3; ++i; /* cancel ��: ��(xy)/��y = ��x */
}
if(!cancelsqrt2(t,zero,&w,buffer))
{ o[i] = cancelsqrt2; ++i;
}
}
if(g == SQRT || h == SQRT)
{ o[i] = cancelsqrt; ++i;
}
if(g == SQRT && h != SQRT)
{ o[i] = sqrtnum; ++i;
}
if(h == SQRT && g != SQRT)
{ o[i] = sqrtdenom; ++i;
}
if(g == ROOT && h != ROOT)
{ o[i] = rootnum; ++i;
}
if(h == ROOT && g != ROOT)
{ o[i] = rootdenom; ++i;
}
if(g == ROOT && h == ROOT)
{ o[i] = quotientofroots; ++i; /* ��x/��y = ��(x/y) */
o[i] = cancelrootgcd; ++i; /* show common factor in ��u/��v */
}
if(g == ROOT || h == ROOT)
{ o[i] = cancelroot; ++i; /* x/��x = (��x)^(n-1) */
o[i] = cancelroot2; ++i; /* ��x/x = 1/(��x)^(n-1) */
o[i] = cancelrootgcd; ++i; /* show common factor in ��u/��v */
}
if(h == SQRT && status(sqrtexpdenom) >= LEARNING)
{ o[i] = sqrtexpdenom; ++i; /* negative fractional exponents */
}
if(h == ROOT && status(rootexpdenom) >= LEARNING)
{ o[i] = rootexpdenom; ++i; /* negative fractional exponents */
}
if(g == ABS && h == ABS)
{ o[i] = fractionofabs; ++i; /* |u| / |v| = |u/v| */
o[i] = cancelabsgcd; ++i; /* show common factor in |u|/|v| */
}
if(g == '+')
{ o[i] = apart; ++i;
o[i] = apartandcancel; ++i;
if(all_args_negative(u))
{ o[i] = minusoutfromnum2; ++i; /* (-a-b)/c = -(a+b)/c */
}
}
if(h == '+' && all_args_negative(v))
{ o[i] = minusoutfromdenom2; ++i; /* a/(-b-c) = -a/(b+c) */
}
if(h == '+' && ARITY(v) == 2 &&
(NEGATIVE(ARG(0,v)) || NEGATIVE(ARG(1,v))) &&
!(NEGATIVE(ARG(0,v)) && NEGATIVE(ARG(1,v)))
)
{ o[i] = minusoutfromdenom3; ++i; /* a/(b-c) = -a/(c-b) */
}
if(contains(t,'+') && /* don't show it on xy/x for example */
atomsin(t,&atomlist) == 1 /* just one atom occurs */
)
{ term z = atomlist[0];
free2(atomlist);
if(ispolyin(u,z) && contains(u,FUNCTOR(z)) &&
ispolyin(v,z) && contains(v,FUNCTOR(z))
)
{ o[i] = polydivop; ++i;
}
if(g == '+' && h == '+')
{ o[i] = cancelbypolydiv; ++i;
}
}
if(g == '*' && h == '*')
{ if(!pulloutrational(t,zero,&w,buffer))
{ o[i] = pulloutrational; ++i;
}
else
{ o[i] = breakfraction; ++i;
}
}
if(g == '/' && h == '/')
{ o[i] = compoundfractions1; ++i;
}
if(h == '/')
{ if(ONE(u))
{ o[i] = invertandmultiply2; ++i;
}
else
{ o[i] = invertandmultiply; ++i;
}
}
if(h == '*' && contains_at_toplevel(v,'/'))
{ /* invertandmultiply can work if one of the factors of the
denominator is a fraction */
o[i] = invertandmultiply; ++i;
}
if(
(g == FACTORIAL ||( g == '*' && contains_at_toplevel(u,FACTORIAL))) &&
!cancelfactorial1(t,zero,&w,buffer)
)
{ o[i] = cancelfactorial1; ++i;
}
if(
(h == FACTORIAL ||( h == '*' && contains_at_toplevel(v,FACTORIAL))) &&
!cancelfactorial1b(t,zero,&w,buffer)
)
{ o[i] = cancelfactorial1b; ++i;
}
if(
(g == FACTORIAL || (g == '*' && contains_at_toplevel(u,FACTORIAL))) &&
(h == FACTORIAL || (h == '*' && contains_at_toplevel(v,FACTORIAL)))
)
{ if(!cancelfactorial2(t,zero,&w,buffer))
{ o[i] = cancelfactorial2; ++i;
}
if(!cancelfactorial2b(t,zero,&w,buffer))
{ o[i] = cancelfactorial2b; ++i;
}
if(!cancelfactorial3(t,zero,&w,buffer))
{ o[i] = cancelfactorial3; ++i;
}
if(!cancelfactorial3b(t,zero,&w,buffer))
{ o[i] = cancelfactorial3b; ++i;
}
}
if(g == '/')
{ o[i] = compoundfractions2; ++i;
}
if(g == SIN && h == COS && equals(ARG(0,u),ARG(0,v)))
{ o[i] = tanrule2; ++i; /* sin u / cos u = tan u */
}
if(g == '^' && FUNCTOR(ARG(0,u)) == COS &&
h == '^' && FUNCTOR(ARG(0,v)) == SIN &&
equals(ARG(1,u),ARG(1,v)) &&
equals(ARG(0,ARG(0,u)),ARG(0,ARG(0,v)))
)
{ o[i] = cotrule2; ++i;
}
if(g == '^' && FUNCTOR(ARG(0,u)) == SIN &&
h == '^' && FUNCTOR(ARG(0,v)) == COS &&
equals(ARG(1,u),ARG(1,v)) &&
equals(ARG(0,ARG(0,u)),ARG(0,ARG(0,v)))
)
{ o[i] = tanrule2; ++i;
}
if(g == COS && h == SIN && equals(ARG(0,u),ARG(0,v)))
{ o[i] = cotrule2; ++i; /* cos u / sin u = cot u */
}
if(contains_factor(v, SIN))
{ o[i] = cscrule2; ++i; /* 1 / sin u = csc u */
}
if(contains_factor(v,COS)) /* 1 / cos u = sec u */
{ o[i] = secrule2; ++i;
}
if(contains_factor(v,TAN))
{ o[i] = tanrecip; ++i;
o[i] = tanrecip2; ++i;
}
if(contains_factor(v,COT))
{ o[i] = cotrecip; ++i;
}
if(contains_factor(v,SEC))
{ o[i] = secrecip; ++i;
}
if(contains_factor(v,CSC))
{ o[i] = cscrecip; ++i;
}
if(contains_factor(v,COSH))
{ o[i] = sechdefrev; ++i; /* 1 / cosh u = sech u */
}
if(contains_factor(v,SINH))
{ o[i] = cschdefrev; ++i; /* 1 / sinh u = csch u */
}
if(g == SIN && h == '+')
{ if(!tanhalf1rev(t,zero,&w,buffer))
{ o[i] = tanhalf1rev; ++i; /* (sin u)/(1+cos u) = tan(u/2) */
}
if(!cothalf2rev(t,zero,&w,buffer))
{ o[i] = cothalf2rev; ++i; /* sin u/(1-cos u) = cot(u/2) */
}
}
if(h == SIN && g == '+')
{ if(!tanhalf2rev(t,zero,&w,buffer))
{ o[i] = tanhalf2rev; ++i; /* (1-cos u)/sin u = tan(u/2) */
}
if(!cothalf1rev(t,zero,&w,buffer))
{ o[i] = cothalf1rev; ++i; /* (1+cos u)/(sin u) = cot(u/2) */
}
}
if(g == '+' && h == '+' &&
ARITY(u) == 2 && ARITY(v) == 2
)
{ if(NEGATIVE(ARG(1,u)) && !tandifrev(t,zero,&w,buffer))
{ o[i] = tandifrev; ++i;
/* (tan u-tan v)/(1+tan u tan v) = tan(u-v) */
}
if(ONE(ARG(0,v)) && NEGATIVE(ARG(1,v)) && !tansumrev(t,zero,&w,buffer))
{ o[i] = tansumrev; ++i;
/* (tan u+tan v)/(1-tan u tan v) = tan(u+v) */
}
if(!cotsumrev(t,zero,&w,buffer))
{ o[i] = cotsumrev; ++i;
/* (cot u cot v-1)/(cot u+cot v) = cot(u+v) */
}
if(!cotdifrev(t,zero,&w,buffer))
{ o[i] = cotdifrev; ++i;
/* (1+cot u cot v)/(cot v-cot u) = cot(u-v) */
}
}
x = get_eigenvariable();
if(!ONE(u) && rational_function(t,x) && contains(t,FUNCTOR(x)))
{ o[i] = cancelgcd; ++i;
}
if(FRACTION(u))
{ o[i] = compoundfractions3; ++i;
}
if(g == '*') /* check for a fraction in the numerator */
{ for(k=0;k<ARITY(u);k++)
{ if(FRACTION(ARG(k,u)))
{ o[i] = compoundfractions4; ++i;
break;
}
}
}
/* we don't put in factordenominator; you would
select the denominator if you wanted to do that;
similarly we don't put in commondenominfraction */
if(g == '^' && h == '^' && equals(ARG(1,u),ARG(1,v)))
{ o[i] = poweroutoffraction; ++i;
}
if(
contains(v,SQRT) || contains(v,ROOT) || contains(v,'i') ||
(FUNCTOR(v) == '+' && ARITY(v) == 2 && contains_exponent_onehalf(v))
)
{ o[i] = rationalizedenom; ++i;
o[i] = ratdenomandsimp; ++i;
}
if(
contains(u,SQRT) || contains(u,ROOT) || contains(u,'i') ||
(FUNCTOR(u) == '+' && ARITY(u) == 2 && contains_exponent_onehalf(u))
)
{ o[i] = rationalizenum; ++i;
}
if(NOTDEFINED(u) && !ZERO(v))
{ o[i] = infinityovernonzero; ++i;
}
if(NOTDEFINED(v) && !ZERO(u))
{ o[i] = nonzerooverinfinity; ++i;
}
if(FUNCTOR(v) == '^' && ZERO(ARG(0,v)))
{ if(equals(ARG(1,v),two))
{ if(equals(u,infinity))
{ o[i] = infinityoverzerosq; ++i;
}
else if(obviously_positive(u))
{ o[i] = zerosqdenom; ++i;
}
else if(obviously_negative(u))
{ o[i] = zerosqdenom2; ++i;
}
else
{ o[i] = zerosqdenom; ++i;
o[i] = zerosqdenom2; ++i;
}
}
else if(iseven(ARG(1,v)))
{ if(equals(u,infinity))
{ o[i] = infinityoverzero2n; ++i;
}
else if(obviously_positive(u))
{ o[i] = zero2ndenom; ++i;
}
else if(obviously_negative(u))
{ o[i] = zero2ndenom2; ++i;
}
else
{ o[i] = zerosqdenom; ++i;
o[i] = zerosqdenom2; ++i;
}
}
}
if(ZERO(v))
{ o[i] = zerodenom; ++i;
o[i] = zerodenom2; ++i;
o[i] = zerodenom3; ++i;
if(equals(u,infinity))
{ o[i] = infinityoverzero; ++i;
o[i] = infinityoverzero2; ++i;
o[i] = infinityoverzero3; ++i;
}
}
o[i] = multnumanddenom; ++i;
if(problemtype == POWERSERIES || (seminumerical(v) && !seminumerical(u)))
{ o[i] = pulloutdenom; ++i;
}
if(g == '+' && h == '+' && ARITY(u) == 2 && ARITY(v) == 2 &&
NEGATIVE(ARG(1,u)) && NEGATIVE(ARG(1,v))
)
{ o[i] = negatenumdenom; ++i;
}
*nops = i;
}
/*______________________________________________________________________*/
int contains_factor(term t, unsigned short f)
/* return 1 if t has functor f or is a power with a term with
functor f as base, or a product with such a term as a factor. */
{ unsigned short g = FUNCTOR(t);
unsigned short n;
int i;
if(g == f)
return 1;
if(ATOMIC(t))
return 0;
if(g == '^' && FUNCTOR(ARG(0,t)) == f)
return 1;
if(g != '*')
return 0;
n = ARITY(t);
for(i=0;i<n;i++)
{ if(contains_factor(ARG(i,t),f))
return 1;
}
return 0;
}
/*______________________________________________________________________*/
int all_args_negative(term t)
/* t is presumed to be a sum. If all summands are negative return 1,
else return 0. */
{ unsigned short n = ARITY(t);
int i;
for(i=0;i<n;i++)
{ if(!NEGATIVE(ARG(i,t)))
return 0;
}
return 1;
}
/*___________________________________________________________________*/
int contains_exponent_onehalf(term t)
/* return 1 if t contains a power with exponent 1/2, 0 if not;
does not count exponents occurring in the base of another power term.
*/
{ unsigned short n;
int i;
if(ATOMIC(t))
return 0;
if(FUNCTOR(t) == '^')
{ if(ONEHALF(ARG(1,t)))
return 1;
return 0;
}
n = ARITY(t);
for(i=0;i<n;i++)
{ if(contains_exponent_onehalf(ARG(i,t)))
return 1;
}
return 0;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists