Sindbad~EG File Manager
/* operators for MathXpert's absolute value menu
M. Beeson
original date 12.14.90
3.1.98 last modified
3.28.00 corrected divabs2 at line 850, ARG(i,t) changed to ARG(i,num)
4.2.00 added intervaltoabs1, intervaltoabs2, absevepowerrev, and abspowerrev
3.17.06 changed 'LE' to LE. This must have happened when eliminating the OEM character for LE.
5.5.13 include stdlib.h
3.18.23 corrected != at line 514
11.9.24 put reason in absroot in display math
2.16.25 removed unused 'x' in absneg and abspos
*/
#include <string.h>
#include <assert.h>
#include <math.h>
#include <stdlib.h> /* labs */
#include "globals.h"
#include "ops.h"
#include "prover.h" /* lpt */
#include "eqn.h" /* ssolve */
#include "deval.h" /* nearint */
#include "cancel.h" /* cancel */
#include "pvalaux.h" /* topflatten, iseven */
#include "symbols.h"
#include "sqrtfrac.h" /* cancel_abs */
#include "errbuf.h"
#include "order.h" /* iscomplex */
/*__________________________________________________________________*/
int abspos(term t, term arg, term *next, char *reason)
/* |a|=a if a>=0 */
/* This is called when integrating |f(x)|. Therefore it must be
able to work when professors can easily infer that f(x) is nonnegative
(on the interval of integration). But the prover doesn't reduce all
inequalities to solved form, because that introduces ugly Boolean
combinations. Hence the direct call to ssolve in this operator and
in absneg. */
{ int err;
short savenextassumption;
int savenvariables;
int savenextdefn;
term u,ineq;
if(FUNCTOR(t) != ABSFUNCTOR)
return 1;
if(PRIME(t))
return 1;
/* PRIME on an ABSFUNCTOR term means no use trying to determine the sign */
savenextdefn = get_nextdefn();
savenextassumption = get_nextassumption();
savenvariables = get_nvariables();
u = ARG(0,t);
ineq = le(zero,u);
err = infer(ineq);
if(!err)
{ *next = u;
HIGHLIGHT(*next);
strcpy(reason, english(288)); /* |a|=a if a>=0 */
return 0;
}
/* Now fail */
set_nextassumption(savenextassumption);
set_nvariables(savenvariables);
set_nextdefn(savenextdefn);
errbuf(0,""); /* erase any misleading messages left by ssolve */
return 1;
}
/*__________________________________________________________________*/
int absposandassume(term t, term arg, term *next, char *reason)
/* |a|=a and assume a >= 0 if it can't be inferred */
{ int err;
if(FUNCTOR(t) != ABSFUNCTOR)
return 1;
err= abspos(t,arg,next,reason);
if(!err)
return 0;
if(!PRIME(t))
{ err = infer(lessthan(ARG(0,t),zero));
if(!err)
return 1;
}
assume(le(zero,ARG(0,t)));
*next = ARG(0,t);
HIGHLIGHT(*next);
strcpy(reason, english(288)); /* |a|=a if a>=0 */
return 0;
}
/*__________________________________________________________________*/
int absneg(term t, term arg, term *next, char *reason)
/* |a|= -a if a \le 0 */
/* See additional comments under abspos */
{ int err;
short savenextassumption;
int savenextdefn;
int savenvariables;
term u,ineq;
if(FUNCTOR(t) != ABSFUNCTOR)
return 1;
if(PRIME(t))
return 1;
savenvariables = get_nvariables();
savenextdefn = get_nextdefn();
savenextassumption = get_nextassumption();
u = ARG(0,t);
ineq = le(u,zero);
err = infer(ineq);
if(!err)
{ *next = tnegate(u);
HIGHLIGHT(*next);
strcpy(reason, english(289)); /* |a|= -a if a \le 0 */
return 0;
}
/* Now fail */
set_nextassumption(savenextassumption);
set_nvariables(savenvariables);
set_nextdefn(savenextdefn);
errbuf(0,""); /* erase any misleading messages left by ssolve */
return 1;
}
/*__________________________________________________________________*/
int absdef(term t, term arg, term *next, char *reason)
/* |u|=u if u>=0; -u if u \le 0 */
{ int err;
term u,arg0,arg1;
if(ATOMIC(t))
return 1;
if(FUNCTOR(t) != ABSFUNCTOR)
return 1;
if(PRIME(t))
return 1;
u = ARG(0,t);
err = infer(le(zero,u));
if(!err)
{ *next = u;
strcpy(reason, english(290)); /* |u|=u if u>=0 */
HIGHLIGHT(*next);
return 0;
}
err = infer(le(u,zero));
if(!err)
{ *next = tnegate(u);
strcpy(reason,english(291)); /* |u|=-u if u \le 0 */
HIGHLIGHT(*next);
return 0;
}
/* if can't infer either one use a CASES term */
*next = make_term(CASES,2);
arg0 = make_term(IF,2);
arg1 = make_term(IF,2);
ARGREP(arg0,0,le(zero,u));
ARGREP(arg1,0,le(u,zero));
ARGREP(arg0,1,u);
ARGREP(arg1,1,tnegate(u));
ARGREP(*next,0,arg0);
ARGREP(*next,1,arg1);
strcpy(reason, english(292)); /* definition of |u| */
HIGHLIGHT(*next);
return 0;
}
/*__________________________________________________________________*/
int abslessthan(term t, term arg, term *next, char *reason)
/* |u|<v iff -v < u < v */
{ term left,u,v;
int err;
if(ATOMIC(t))
return 1;
if(FUNCTOR(t) == LE)
errbuf(0, english(293)); /* Maybe you meant \le instead of <" */
if(FUNCTOR(t) != '<')
return 1;
left = ARG(0,t);
if(ATOMIC(left))
return 1;
if(FUNCTOR(left) != ABSFUNCTOR)
return 1;
u = ARG(0,left);
v = ARG(1,t);
if(constant(v))
err = check1(le(zero,v));
else
err = infer(le(zero,v));
if(err)
{ errbuf(0, english(1549)); /* Right side must be non-negative */
return 1;
}
*next = and(lessthan(tnegate(v),u), lessthan(u,v));
HIGHLIGHT(*next);
strcpy(reason, english(294)); /* |u|<v iff -v < u < v */
return 0;
}
/*__________________________________________________________________*/
int absgreaterthan(term t, term arg, term *next, char *reason)
/* v > |u| iff -v < u < v */
{ term right,u,v;
int err;
if(ATOMIC(t))
return 1;
if(FUNCTOR(t) != '>')
return 1;
right = ARG(1,t);
if(ATOMIC(right))
return 1;
if(FUNCTOR(right) != ABSFUNCTOR)
return 1;
u = ARG(0,right);
v = ARG(0,t);
if(constant(v))
err = check1(le(zero,v));
else
err = infer(le(zero,v));
if(err)
{ errbuf(0, english(1598)); /* Left side must be non-negative */
return 1;
}
*next = and(lessthan(tnegate(v),u), lessthan(u,v));
HIGHLIGHT(*next);
strcpy(reason, english(1599)); /* v>|u| iff -v < u < v */
return 0;
}
/*__________________________________________________________________*/
int absle(term t, term arg, term *next, char *reason)
/* |u| \le v iff -v \le u \le v */
{ term left,u,v;
int err;
if(ATOMIC(t))
return 1;
if(FUNCTOR(t) == '<')
errbuf(0, english(295));
/* Maybe you meant < instead of \le */
if(FUNCTOR(t) != LE)
return 1;
left = ARG(0,t);
if(ATOMIC(left))
return 1;
if(FUNCTOR(left) != ABSFUNCTOR)
return 1;
u = ARG(0,left);
v = ARG(1,t);
if(constant(v))
err = check1(le(zero,v));
else
err = infer(le(zero,v));
if(err)
{ errbuf(0, english(1549)); /* Right side must be non-negative */
return 1;
}
*next = and(le(tnegate(v),u), le(u,v));
HIGHLIGHT(*next);
strncpy(reason, english(296),DIMREASONBUFFER); /* |u| \le v iff -v \le u \le v */
return 0;
}
/*__________________________________________________________________*/
int absge(term t, term arg, term *next, char *reason)
/* v>=|u| iff -v \le u \le v */
{ term right,u,v;
int err;
if(ATOMIC(t))
return 1;
if(FUNCTOR(t) != GE)
return 1;
right = ARG(1,t);
if(ATOMIC(right))
return 1;
if(FUNCTOR(right) != ABSFUNCTOR)
return 1;
u = ARG(0,right);
v = ARG(0,t);
if(constant(v))
err = check1(le(zero,v));
else
err = infer(le(zero,v));
if(err)
{ errbuf(0, english(1598)); /* Left side must be non-negative */
return 1;
}
*next = and(le(tnegate(v),u), le(u,v));
HIGHLIGHT(*next);
strncpy(reason, english(1600),DIMREASONBUFFER); /* v>=|u| iff -v \le u \le v */
return 0;
}
/*__________________________________________________________________*/
int lessthanabs(term t, term arg, term *next, char *reason)
/* u<|v| iff u<-v or u<v */
{ term right,u,v;
if(ATOMIC(t))
return 1;
if(FUNCTOR(t) == LE)
errbuf(0, english(293));
/* Maybe you meant \le instead of < */
if(FUNCTOR(t) != '<')
return 1;
right = ARG(1,t);
if(ATOMIC(right))
return 1;
if(FUNCTOR(right) != ABSFUNCTOR)
return 1;
v = ARG(0,right);
u = ARG(0,t);
*next = or(lessthan(v,tnegate(u)), lessthan(u,v));
HIGHLIGHT(*next);
strncpy(reason, english(297),DIMREASONBUFFER); /* u<|v| iff v<-u or u<v */
return 0;
}
/*__________________________________________________________________*/
int greaterthanabs(term t, term arg, term *next, char *reason)
/* |v|>u iff v < -u or v > u */
{ term left,u,v;
if(ATOMIC(t))
return 1;
if(FUNCTOR(t) != '>')
return 1;
left = ARG(0,t);
if(ATOMIC(left))
return 1;
if(FUNCTOR(left) != ABSFUNCTOR)
return 1;
v = ARG(0,left);
u = ARG(1,t);
*next = or(lessthan(v,tnegate(u)), greaterthan(v,u));
HIGHLIGHT(*next);
strncpy(reason, english(1601),DIMREASONBUFFER); /* |v|>u iff v<-u or v>u */
return 0;
}
/*__________________________________________________________________*/
int leabs(term t, term arg, term *next, char *reason)
/* u \le |v| if v \le -u or u \le v */
{ term right,u,v;
if(ATOMIC(t))
return 1;
if(FUNCTOR(t) == '<')
errbuf(0,english(295));
/* Maybe you meant < instead of \le */
if(FUNCTOR(t) != LE)
return 1;
right = ARG(1,t);
if(ATOMIC(right))
return 1;
if(FUNCTOR(right) != ABSFUNCTOR)
return 1;
v = ARG(0,right);
u = ARG(0,t);
*next = or(le(v,tnegate(u)), le(u,v));
HIGHLIGHT(*next);
strncpy(reason, english(298),DIMREASONBUFFER); /* u \le |v| iff v \le -u or u \le v */
return 0;
}
/*__________________________________________________________________*/
int geabs(term t, term arg, term *next, char *reason)
/*|v|>=u if v \le -u or v >= u */
{ term left,u,v;
if(ATOMIC(t))
return 1;
if(FUNCTOR(t) != GE)
return 1;
left = ARG(0,t);
if(ATOMIC(left))
return 1;
if(FUNCTOR(left) != ABSFUNCTOR)
return 1;
v = ARG(0,left);
u = ARG(1,t);
*next = or(le(v,tnegate(u)), ge(v,u));
HIGHLIGHT(*next);
strcpy(reason, english(1602)); /* |v|>=u if v \le -u or v \le u */
return 0;
}
/*_____________________________________________________________________*/
int absevenpower(term in, term arg, term *next, char *reason)
/* |u|^2^n =u^2^n (u real) */
{ term t,u,n;
int err;
if(FUNCTOR(in) != '^')
return 1;
t = ARG(0,in);
if(FUNCTOR(t) != ABSFUNCTOR)
return 1;
u = ARG(0,t);
n = ARG(1,in);
if(!iseven(n))
return 1;
if(get_complex())
{ err = infer(type(u,R));
if(err)
{ errbuf(0, english(299));
/* |u|^2^n =u^2^n requires u to be real */
return 1;
}
}
/* complex_visible = 1; cause "Using real numbers only" to get displayed */
*next = make_power(u,n);
HIGHLIGHT(*next);
strncpy(reason, english(300), DIMREASONBUFFER); /* |u|^2^n = u^2^n */
return 0;
}
/*_____________________________________________________________________*/
int abspower(term in, term arg, term *next, char *reason)
/* |u^2|=|u|^2 if n is real */
/* and if(! complex) then check1(u>=0) */
{ term t,u,n;
int err;
if(FUNCTOR(in) != ABSFUNCTOR)
return 1;
t = ARG(0,in);
if(FUNCTOR(t) != '^')
return 1;
u = ARG(0,t);
n = ARG(1,t);
err = infer(type(n,R));
if(err)
return 1;
/* There are difficulties: how about if n = 1/2 and
u = -2; so we are talking about |sqrt(-2)| which is undefined if
we don't allow complex numbers, while on the right we have sqrt 2 which
is defined in any case. */
*next = make_power(absolute(u),n);
HIGHLIGHT(*next);
strcpy(reason, english(301)); /* |u^n|=|u|^n (u real) */
if(get_complex())
return 0; /* no problem */
/* but if !complex, the left side has to be defined */
err = check1(domain(t));
if(err)
{ errbuf(0, english(302));
/* Undefined power. You have complex numbers off. */
/* You could only get here if such an undefined expression
arises inside a limit term. */
return 1;
}
return 0;
}
/*___________________________________________________________________*/
/* multiplyabsval is in radsimp.c */
/* absofproduct is in sqrtfrac.c */
/*___________________________________________________________________*/
int abslinear(term t, term arg, term *next, char *reason)
/* |cu| = c|u| if c >= 0 */
{ term u,c,w;
unsigned short n,j,k;
int i,err;
if(FUNCTOR(t) != ABSFUNCTOR || FUNCTOR(ARG(0,t)) != '*')
return 1;
strcpy(reason, english(305)); /* |cu| = c|u| if c \ge 0 */
w = ARG(0,t);
n = ARITY(w);
c = make_term('*',n);
u = make_term('*',n);
j=k=0;
for(i=0;i<n;i++) /* throw positive factors in c, others in u */
{ err = infer(le(zero,ARG(i,w)));
if(!err)
{ ARGREP(c,j,ARG(i,w));
++j;
}
else
{ ARGREP(u,k,ARG(i,w));
++k;
}
}
if(j==0)
return 1;
if(k==0)
{ *next = c;
HIGHLIGHT(*next);
strcpy(reason, english(306)); /* |u| = c if c \ge 0 */
RELEASE(u);
return 0;
}
if(j==1 && k==1) /* and n == 2 */
{ *next = product(ARG(0,c),abs1(ARG(0,u)));
RELEASE(c);
RELEASE(u);
}
else if(j==1)
{ SETFUNCTOR(u,'*',k);
*next = product(ARG(0,c),abs1(u));
RELEASE(c);
}
else if(k==1)
{ SETFUNCTOR(c,'*',j);
*next = product(c,abs1(ARG(0,u)));
RELEASE(u);
}
else
{ SETFUNCTOR(c,'*',j);
SETFUNCTOR(u,'*',k);
*next = product(c,abs1(u));
}
HIGHLIGHT(*next);
return 0;
}
/*___________________________________________________________________*/
int absineqtrue(term t, term arg, term *next, char *reason)
/* |u| \ge 0 is always true */
{ if(FUNCTOR(t) != LE && FUNCTOR(t) != GE)
return 1;
if(FUNCTOR(t) == LE)
{ if(FUNCTOR(ARG(1,t)) != ABSFUNCTOR)
return 1;
if(! ZERO(ARG(0,t)))
return 1;
strcpy(reason, english(307)); /* 0 \le |u| is true */
}
else /* GE */
{ if(FUNCTOR(ARG(0,t)) != ABSFUNCTOR)
return 1;
if( ! ZERO(ARG(1,t)))
return 1;
strcpy(reason, english(308)); /* |u| \ge 0 is true */
}
*next = trueterm;
HIGHLIGHT(*next);
return 0;
}
/*___________________________________________________________________*/
int absineqfalse(term t, term arg, term *next, char *reason)
/* |u| < 0 is always false */
{ if(FUNCTOR(t) != '<' && FUNCTOR(t) != '>')
return 1;
if(FUNCTOR(t) == '<')
{ if(FUNCTOR(ARG(0,t)) != ABSFUNCTOR)
return 1;
if(! ZERO(ARG(1,t)))
return 1;
strcpy(reason, english(309)); /* |u| < 0 is false */
}
else /* > */
{ if(FUNCTOR(ARG(1,t)) != ABSFUNCTOR)
return 1;
if( ! ZERO(ARG(0,t)))
return 1;
strcpy(reason, english(310)); /* 0 > |u| is false */
}
*next = falseterm;
HIGHLIGHT(*next);
return 0;
}
/*___________________________________________________________________*/
int abseqn2(term t, term arg, term *next, char *reason)
/* |u|/u = c => c = \pm 1 */
/* reject |u|/u=c unless c=\pm 1, by returning 'false' */
/* also works on u/|u| = c */
{ int err;
term a,b,c,u;
const char *reason1 = english(311); /* |u|/u=1 iff 0 < u */
const char *reason2 = english(312); /* u/|u|=1 iff 0 < u */
const char *reason3 = english(313); /* |u|/u=-1 iff u<0 */
const char *reason4 = english(314); /* u/|u|=-1 iff u<0 */
const char *reason5 = english(315); /* |u|/u=c => c= \pm 1 */
long kk;
double cval;
if(FUNCTOR(t) != '=')
return 1;
if(FUNCTOR(ARG(0,t)) != '/')
return 1;
a = ARG(0,ARG(0,t));
b = ARG(1,ARG(0,t));
c = ARG(1,t);
if( FUNCTOR(a) == ABSFUNCTOR && equals(ARG(0,a),b))
u = b;
else if (FUNCTOR(b)==ABSFUNCTOR && equals(ARG(0,b),a))
u = a;
else return 1;
if(seminumerical(c))
{ err = deval(c,&cval);
if(err)
goto reject;
if(nearint(cval,&kk) && labs(kk)==1 )
{ out:
if(kk > 0)
{ *next = lessthan(zero,u);
strcpy(reason,FUNCTOR(a)==ABSFUNCTOR ? reason1 : reason2);
return 0;
}
else
{ *next = lessthan(u,zero);
strcpy(reason,FUNCTOR(a)==ABSFUNCTOR ? reason3 : reason4);
return 0;
}
}
else
{ reject:
*next = falseterm;
strcpy(reason,reason5);
return 0;
}
}
err = infer(equation(c,one));
if(!err)
{ kk = 1;
goto out;
}
err = infer(equation(c,minusone));
if(!err)
{ kk = -1;
goto out;
}
err = refute(equation(c,one));
if(!err)
{ *next = le(u,zero);
strcpy(reason,reason5);
HIGHLIGHT(*next);
return 0;
}
err = refute(equation(c,minusone));
if(!err)
{ *next = le(zero,u);
strcpy(reason,reason5);
HIGHLIGHT(*next);
return 0;
}
*next = or(equation(c,one),equation(c,minusone));
set_checksolutionsflag(1);
/* Really it should be or(and(equation(c,okne),lessthan(u,zero))
and(equation(c,minusone),lessthan(zero,u))
)
but MathXpert can't cope with and inside or, so instead we
just generate spurious solutions and check them in the end.
Consider two examples: |x|/x = x and |x|/x = -x */
strcpy(reason,reason5);
HIGHLIGHT(*next);
return 0;
}
/*______________________________________________________________*/
int fractionofabs(term t, term arg, term *next, char *reason)
/* |a|/|b| = |a/b| */
{ term a,b;
if(! FRACTION(t) || FUNCTOR(ARG(0,t)) != ABSFUNCTOR || FUNCTOR(ARG(1,t)) != ABSFUNCTOR)
return 1;
a = ARG(0,ARG(0,t));
b = ARG(0,ARG(1,t));
*next = abs1(make_fraction(a,b));
HIGHLIGHT(*next);
strcpy(reason, english(1131)); /* |a|/|b| = |a/b| */
return 0;
}
/*______________________________________________________________*/
int absoffraction(term t, term arg, term *next, char *reason)
/* |a/b| = |a|/|b| */
{ term a,b,absa,absb;
if(FUNCTOR(t) != ABSFUNCTOR || !FRACTION(ARG(0,t)))
return 1;
a = ARG(0,ARG(0,t));
b = ARG(1,ARG(0,t));
absa = abs1(a);
absb = abs1(b);
if(PRIME(t))
{ void *savenode = heapmax();
int err = infer(le(zero,a));
if(err)
{ reset_heap(savenode);
err = infer(le(a,zero));
if(err)
{ /* can't determine the sign of a */
SETPRIME(absa);
SETPRIME(absb); /* since t was PRIME */
/* Saves further repeated attempts to apply absneg, abspos */
}
}
reset_heap(savenode);
}
*next = make_fraction(absa,absb);
HIGHLIGHT(*next);
strcpy(reason,english(1132)); /* |a/b| = |a|/|b| */
return 0;
}
/*______________________________________________________________*/
int abslinearquo(term t, term arg, term *next, char *reason)
/* |a/b| = |a|/b if b > 0 */
{ term a,b;
if(FUNCTOR(t) != ABSFUNCTOR || !FRACTION(ARG(0,t)))
return 1;
a = ARG(0,ARG(0,t));
b = ARG(1,ARG(0,t));
if(!OBJECT(b))
return 1;
*next = make_fraction(abs1(a),b);
if(PRIME(t))
SETPRIME(*next);
HIGHLIGHT(*next);
strcpy(reason,english(1133)); /* |a/b| = |a|/b if b>0 */
return 0;
}
/*______________________________________________________________*/
int abssqrt(term t, term arg, term *next, char *reason)
/* |\sqrt a| = \sqrt|a| */
{ term a;
if(FUNCTOR(t) != ABSFUNCTOR || FUNCTOR(ARG(0,t)) != SQRT)
return 1;
a = ARG(0,ARG(0,t));
*next = make_sqrt(abs1(a));
if(PRIME(t))
SETPRIME(ARG(0,*next));
HIGHLIGHT(*next);
strcpy(reason,"$|\\sqrt a| = \\sqrt|a|$");
return 0;
}
/*______________________________________________________________*/
int absroot(term t, term arg, term *next, char *reason)
/* |root(n,a)| = root(n,|a|) */
{ term a,n;
if(FUNCTOR(t) != ABSFUNCTOR || FUNCTOR(ARG(0,t)) != ROOT)
return 1;
n = ARG(0,ARG(0,t));
a = ARG(1,ARG(0,t));
*next = make_root(n,abs1(a));
if(PRIME(t))
SETPRIME(ARG(1,*next));
HIGHLIGHT(*next);
strcpy(reason,"$$abs(root(n,a)) = root(n,abs(a))$$");
return 0;
}
/*_______________________________________________________________________*/
int cancelabs3(term t, term arg, term *next, char *reason)
/* example: |((x-y)(x+y)|/ |(x-y)| =|(x+y)|
Similar to cancelsqrt3 and cancelroot3 */
{ int err = cancel_abs(t,next);
if(err)
return 1;
if(FRACTION(*next))
strcpy(reason, "|ab|/|ac| = |b|/|c|");
else
strcpy(reason," |ab|/|a| = |b|");
if(PRIME(t))
SETPRIME(*next);
HIGHLIGHT(*next);
return 0;
}
/*___________________________________________________________________*/
/* |ab|=|a||b| */
int absofproduct(term t, term arg, term *next, char *reason)
{ term u;
unsigned short n;
int i;
if(FUNCTOR(t) != ABSFUNCTOR)
return 1;
if(FUNCTOR(ARG(0,t)) != '*')
return 1;
u = ARG(0,t);
n = ARITY(u);
*next = make_term('*',n);
for(i=0;i<n;i++)
ARGREP(*next,i,abs1(ARG(i,u)));
strcpy(reason,english(304)); /* |uv|=|u||v| */
HIGHLIGHT(*next);
return 0;
}
/*___________________________________________________________________*/
int multabs(term t, term arg, term *next, char *reason)
/* a|b|=|ab| if 0 \le a */
{ term a,b,u;
unsigned short n;
int i,j,err;
if(FUNCTOR(t) != '*')
return 1;
n = ARITY(t);
/* identify the (first) ABSFUNCTOR factor */
for(i=0;i<n;i++)
{ if(FUNCTOR(ARG(i,t)) == ABSFUNCTOR)
break;
}
if(i==n)
return 1; /* no ABSFUNCTOR factor */
b = ARG(0,ARG(i,t));
if(n == 2)
a = ARG(i ? 0 : 1, t);
else
{ a = make_term('*',(unsigned short)(n-1));
for(j=0;j<n-1;j++)
ARGREP(a,j,ARG(j<i? j : j+1,t));
}
err = infer(lessthan(zero,a));
if(err)
{ errbuf(0,english(1445));
/* Coefficient must be nonnegative. */
return 1;
}
u = make_term('*',n);
for(j=0;j<n;j++)
ARGREP(u,j,j==i ? b : ARG(j,t));
*next = abs1(u);
strcpy(reason,english(2221)); /* $a|b| = |ab|$ if $0 \le a$ */
HIGHLIGHT(*next);
return 0;
}
/*___________________________________________________________________*/
int divabs(term t, term arg, term *next, char *reason)
/* |b|/c=|b/c| if 0 < c */
{ term b,c,num;
int err;
if(FUNCTOR(t) != '/')
return 1;
num = ARG(0,t);
c = ARG(1,t);
if(FUNCTOR(num) != ABSFUNCTOR)
return 1;
b = ARG(0,num);
err = infer(lessthan(zero,c));
if(err)
{ errbuf(0,english(1446));
/* Denominator must be positive. */
return 1;
}
*next = abs1(make_fraction(b,c));
strcpy(reason,"|b|/c = |b/c| if 0<c");
HIGHLIGHT(*next);
return 0;
}
/*___________________________________________________________________*/
int divabs2(term t, term arg, term *next, char *reason)
/* a|b|/c=|ab/c| if 0 < a/c */
{ term a,b,c,num,u;
unsigned short n;
int i,j,err;
if(FUNCTOR(t) != '/')
return 1;
num = ARG(0,t);
c = ARG(1,t);
if(FUNCTOR(num) != '*')
return 1;
n = ARITY(num);
/* identify the (first) ABSFUNCTOR factor */
for(i=0;i<n;i++)
{ if(FUNCTOR(ARG(i,num)) == ABSFUNCTOR)
break;
}
if(i==n)
return 1; /* no ABSFUNCTOR factor */
b = ARG(0,ARG(i,num));
if(n == 2)
a = ARG(i ? 0 : 1, num);
else
{ a = make_term('*',(unsigned short)(n-1));
for(j=0;j<n-1;j++)
ARGREP(a,j,ARG(j<i? j : j+1,num));
}
err = infer(lessthan(zero,product(a,c)));
/* save one step in infer(lessthan(zero,make_fraction(a,c))) */
if(err)
{ errbuf(0,english(1447));
/* a/c must be positive. */
return 1;
}
u = make_term('*',n);
for(j=0;j<n;j++)
ARGREP(u,j,j==i ? b : ARG(j,num));
*next = abs1(make_fraction(u,c));
strcpy(reason, english(2222)); /* a|b|/c = |ab/c| if $0 \le a/c$ */
HIGHLIGHT(*next);
return 0;
}
/*________________________________________________________________*/
int abseqntoineq1(term t, term arg, term *next, char *reason)
/* abs(u) = u => 0 <= u */
{ term u;
if(FUNCTOR(t) != '=' || FUNCTOR(ARG(0,t)) != ABSFUNCTOR)
return 1;
u = ARG(0,ARG(0,t));
if(!equals(ARG(1,t),u))
return 1;
*next = le(zero,u);
HIGHLIGHT(*next);
strcpy(reason, english(2188)); /* |u| = u iff 0 \le u */
return 0;
}
/*________________________________________________________________*/
int abseqntoineq2(term t, term arg, term *next, char *reason)
/* abs(u) = -u => u <= 0 */
{ term u,v,w;
if(FUNCTOR(t) != '=' || FUNCTOR(ARG(0,t)) != ABSFUNCTOR)
return 1;
u = ARG(0,ARG(0,t));
v = ARG(1,t);
polyval(sum(u,v),&w);
if(!ZERO(w))
return 1;
*next = le(u,zero);
HIGHLIGHT(*next);
strcpy(reason, english(2189)); /* |u| = -u iff u \le 0 */
return 0;
}
/*__________________________________________________________________*/
int absineqtrue2(term t, term arg, term *next, char *reason)
/* -c \le |u| is true (c \ge 0) */
{ int err;
if(FUNCTOR(t) != LE)
return 1;
if(FUNCTOR(ARG(1,t)) != ABSFUNCTOR)
return 1;
err = infer(le(ARG(0,t),zero));
if(err)
return 1;
*next = trueterm;
HIGHLIGHT(*next);
strcpy(reason, english(1695)); /* -c \le |u| is true (c \ge 0) */
return 0;
}
/*__________________________________________________________________*/
int absineqtrue3(term t, term arg, term *next, char *reason)
/* -c < |u| is true (c > 0) */
{ int err;
if(FUNCTOR(t) != '<')
return 1;
if(FUNCTOR(ARG(1,t)) != ABSFUNCTOR)
return 1;
err = infer(lessthan(ARG(0,t),zero));
if(err)
return 1;
*next = trueterm;
HIGHLIGHT(*next);
strcpy(reason, english(1696)); /* -c<|u| is true (c>0) */
return 0;
}
/*__________________________________________________________________*/
int absineqtrue2g(term t, term arg, term *next, char *reason)
/* |u| \ge -c is true (c \ge 0) */
{ int err;
if(FUNCTOR(t) != GE)
return 1;
if(FUNCTOR(ARG(0,t)) != ABSFUNCTOR)
return 1;
err = infer(le(ARG(1,t),zero));
if(err)
return 1;
*next = trueterm;
HIGHLIGHT(*next);
strcpy(reason, english(1709)); /* |u| \ge -c is true (c \ge 0) */
return 0;
}
/*__________________________________________________________________*/
int absineqtrue3g(term t, term arg, term *next, char *reason)
/* |u| > -c is true (c>0) */
{ int err;
if(FUNCTOR(t) != '>')
return 1;
if(FUNCTOR(ARG(0,t)) != ABSFUNCTOR)
return 1;
err = infer(lessthan(ARG(1,t),zero));
if(err)
return 1;
*next = trueterm;
HIGHLIGHT(*next);
strcpy(reason, english(1710)); /* |u|>-c is true (c>0) */
return 0;
}
/*__________________________________________________________________*/
int abslessthanneg(term t, term arg, term *next, char *reason)
/* |u| < -c has no solution if c \ge 0 */
{ int err;
if(FUNCTOR(t) != '<')
return 1;
if(FUNCTOR(ARG(0,t)) != ABSFUNCTOR)
return 1;
err = infer(le(ARG(1,t),zero));
if(err)
return 1;
*next = falseterm;
HIGHLIGHT(*next);
strcpy(reason, english(1697)); /* |u|<-c has no solution if c \ge 0 */
return 0;
}
/*__________________________________________________________________*/
int absleneg(term t, term arg, term *next, char *reason)
/* |u| \le -c has no solution if c > 0 */
{ int err;
if(FUNCTOR(t) != LE)
return 1;
if(FUNCTOR(ARG(0,t)) != ABSFUNCTOR)
return 1;
err = infer(lessthan(ARG(1,t),zero));
if(err)
return 1;
*next = falseterm;
HIGHLIGHT(*next);
strcpy(reason, english(1698)); /* |u| \le -c has no solution if c>0 */
return 0;
}
/*__________________________________________________________________*/
int abseqnneg(term t, term arg, term *next, char *reason)
/* |u| = -c iff u = 0 (assuming c = 0) */
{ if(FUNCTOR(t) != '=')
return 1;
return absleneg2(t,arg,next,reason);
}
/*__________________________________________________________________*/
int absleneg2(term t, term arg, term *next, char *reason)
/* |u| \le -c iff u = 0 (assuming c = 0) */
/* Example: |x^3-x| \le -x^2. In MathXpert you can't convert this
to x^3-x = 0 and x^2=0, so instead we assume x^2 = 0 and solve
x^3-x = 0; then two solutions are rejected as contradicting x = 0.
*/
{ int err;
term p;
if(FUNCTOR(t) != LE && FUNCTOR(t) != '=')
return 1;
if(FUNCTOR(t) == '=' && FUNCTOR(ARG(0,t)) != ABSFUNCTOR && FUNCTOR(ARG(1,t)) == ABSFUNCTOR)
t = equation(ARG(1,t),ARG(0,t));
if(FUNCTOR(ARG(0,t)) != ABSFUNCTOR)
return 1;
err = infer(le(ARG(1,t),zero));
if(err)
{ errbuf(0, english(1699)); /* The right-hand side must be non-positive */
return 1;
}
err = infer(lessthan(ARG(1,t),zero));
if(!err)
{ errbuf(0, english(1700)); /* Right hand side can never be zero. */
return 1;
}
p = lpt(equation(ARG(1,t),zero));
if(!equals(p,trueterm))
assume(p);
*next = equation(ARG(0,ARG(0,t)),zero);
HIGHLIGHT(*next);
if(FUNCTOR(t) == LE)
strcpy(reason,english(1701));
/* |u| \le -c iff u = 0 (assuming c = 0) */
else
strcpy(reason, english(1720));
/* |u| = -c iff u = 0 (assuming c = 0) */
set_checksolutionsflag(1);
return 0;
}
/*__________________________________________________________________*/
int absineqtrueg(term t, term arg, term *next, char *reason)
/* |u| \ge 0 is true */
{ if(FUNCTOR(t) != GE)
return 1;
if(FUNCTOR(ARG(0,t)) != ABSFUNCTOR)
return 1;
if(!ZERO(ARG(1,t)))
return 1;
*next = trueterm;
HIGHLIGHT(*next);
strcpy(reason, english(1702)); /* |u| \ge 0 is true */
return 0;
}
/*__________________________________________________________________*/
int absineqfalseg(term t, term arg, term *next, char *reason)
/* 0 > |u| has no solution */
{ if(FUNCTOR(t) != '>')
return 1;
if(FUNCTOR(ARG(1,t)) != ABSFUNCTOR)
return 1;
if(!ZERO(ARG(0,t)))
return 1;
*next = falseterm;
HIGHLIGHT(*next);
strcpy(reason, english(1703)); /* 0>|u| has no solution */
return 0;
}
/*__________________________________________________________________*/
int absgreaterthanneg(term t, term arg, term *next, char *reason)
/* -c > |u| has no solution (c \ge 0) */
{ int err;
if(FUNCTOR(t) != '>')
return 1;
if(FUNCTOR(ARG(1,t)) != ABSFUNCTOR)
return 1;
err = infer(le(ARG(0,t),zero));
if(err)
return 1;
*next = falseterm;
HIGHLIGHT(*next);
strcpy(reason, english(1704));
/* -c > |u| has no solution (c \ge 0) */
return 0;
}
/*__________________________________________________________________*/
int absgeneg(term t, term arg, term *next, char *reason)
/* -c \ge |u| has no solution (c > 0) */
{ int err;
if(FUNCTOR(t) != GE)
return 1;
if(FUNCTOR(ARG(1,t)) != ABSFUNCTOR)
return 1;
err = infer(lessthan(ARG(0,t),zero));
if(err)
return 1;
*next = falseterm;
HIGHLIGHT(*next);
strcpy(reason, english(1705));
/* -c \ge |u| has no solution (c > 0) */
return 0;
}
/*__________________________________________________________________*/
int absgeneg2(term t, term arg, term *next, char *reason)
/* -c \ge |u| iff u = 0, assuming c = 0 */
{ int err;
term p;
if(FUNCTOR(t) != GE)
return 1;
if(FUNCTOR(ARG(1,t)) != ABSFUNCTOR)
return 1;
err = infer(le(ARG(0,t),zero));
if(err)
{ errbuf(0, english(1706)); /* The left-hand side must be non-positive */
return 1;
}
err = infer(lessthan(ARG(0,t),zero));
if(!err)
{ errbuf(0, english(1707)); /* Left-hand side can never be zero. */
return 1;
}
p = lpt(equation(ARG(0,t),zero));
if(!equals(p,trueterm))
assume(p);
*next = equation(ARG(0,ARG(1,t)),zero);
HIGHLIGHT(*next);
strcpy(reason,english(1708));
/* -c \ge |u| iff u = 0, (assuming c = 0) */
set_checksolutionsflag(1);
return 0;
}
/*____________________________________________________________________*/
int introduceabs(term t, term arg, term *next, char *reason)
/* [p = a, p = -a] becomes p = abs(a) if p >= 0 and the sign of
a cannot be determined. Example, [x^2 = a, x^2 = -a] becomes
x^2 = abs(a). Without this operation, MathXpert will solve the
equation (x^2-a)(x^2+a) = 0 and get four square roots with the
assumptions a >= 0 and a <= 0. With it, it will get x = sqrt(abs(a))
and x = -sqrt(abs(a)) with no assumption on a.
*/
{ unsigned short n;
int i,j,k,err;
term u,v,p,a,b,temp;
if(FUNCTOR(t) != OR)
return 1;
if(iscomplex(t))
return 1;
/* this leads to wrong results e.g. on [x^2 = i, x^2 = -i] */
n = ARITY(t);
if(n == 2)
{ u = ARG(0,t);
v = ARG(1,t);
if(FUNCTOR(u) != '=' || FUNCTOR(v) != '=')
return 1;
p = ARG(0,u);
if(!equals(p,ARG(0,v)))
return 1;
a = ARG(1,u);
b = ARG(1,v);
if(
!(NEGATIVE(a) && equals(ARG(0,a),b)) &&
!(NEGATIVE(b) && equals(ARG(0,b),a)) &&
!(
FUNCTOR(a) == '+' && FUNCTOR(b) == '+' &&
ARITY(a) == ARITY(b) && equals(strongnegate(a),b)
)
)
return 1;
if(obviously_nonnegative(a) || obviously_nonnegative(b))
return 1;
if(!infer(nonnegative(a)) || !infer(nonnegative(b)))
return 1;
*next = equation(p,abs1(NEGATIVE(a) ? ARG(0,a) : a));
strcpy(reason, english(2187));
/* [p=a,p=-a] and p \ge 0 iff p=|a| */
return 0;
}
/* Now n > 2 */
u = make_term(OR,2);
for(i=0;i<n;i++)
{ for(j=i+1;j<n;j++)
{ ARGREP(u,0,ARG(i,t));
ARGREP(u,1,ARG(j,t));
err = introduceabs(u,arg,&temp,reason);
if(!err)
goto success;
}
}
RELEASE(u);
return 1;
success:
*next = make_term(OR,(unsigned short)(n-1));
for(k=0;k<n-1;k++)
ARGREP(*next,k, k<i ? ARG(k,t) : k==i ? temp : k<j ? ARG(k,t) : ARG(k+1,t));
return 0;
}
/*_______________________________________________________*/
int intervaltoabs1(term t, term arg, term *next, char *reason)
/* -a <= u <= a iff |u| <= a */
{ term u,a;
if(!interval_as_and(t))
return 1;
if(FUNCTOR(ARG(0,t)) != LE || FUNCTOR(ARG(1,t)) != LE)
return 1;
u = ARG(0,ARG(1,t));
a = ARG(1,ARG(1,t));
if(!NEGATIVE(ARG(0,ARG(0,t))))
return 1;
if(!equals(a,ARG(0,ARG(0,ARG(0,t)))))
return 1;
*next = le(abs1(u),a);
strcpy(reason, english(2421)); /* $-a \\le u \\le a$ iff $|u|\\le a$ */
return 0;
}
/*_______________________________________________________*/
int intervaltoabs2(term t, term arg, term *next, char *reason)
/* -a < u <= a iff |u| < a */
{ term u,a;
if(!interval_as_and(t))
return 1;
if(FUNCTOR(ARG(0,t)) != '<' || FUNCTOR(ARG(1,t)) != '<')
return 1;
u = ARG(0,ARG(1,t));
a = ARG(1,ARG(1,t));
if(!NEGATIVE(ARG(0,ARG(0,t))))
return 1;
if(!equals(a,ARG(0,ARG(0,ARG(0,t)))))
return 1;
*next = le(abs1(u),a);
strcpy(reason, english(2422)); /* $-a < u < a$ iff $|u|<a$ */
return 0;
}
/*_______________________________________________________*/
int absevenpowerrev(term t, term arg, term *next, char *reason)
/* u^(2n) = |u|^(2n) if u is real */
{ if(FUNCTOR(t) != '^')
return 1;
if(!iseven(ARG(1,t)))
return 1;
if(iscomplex(t))
return 1;
*next = make_power(abs1(ARG(0,t)),ARG(1,t));
strcpy(reason, "$u^(2n)=|u|^(2n)$ if u is real");
return 0;
}
/*_______________________________________________________*/
int abspowerrev(term t, term arg, term *next, char *reason)
/* |u|^n = |u^n| if u is real */
{ if(FUNCTOR(t) != '^')
return 1;
if(FUNCTOR(ARG(0,t)) != ABSFUNCTOR)
return 1;
if(iscomplex(ARG(1,t)))
return 1;
*next = abs1(make_power(ARG(0,ARG(0,t)),ARG(1,t)));
strcpy(reason, "$|u|^n = |u^n|$ if u is real");
return 0;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists