Sindbad~EG File Manager
/* M. Beeson, for MathXpert */
/*
11.20.90 original date
1.22.98 last modified
1.13.00 removed "pragma argsused"
2.9.05 modified includes
6.3.13 added $ in some reason strings, esp. doubleminus, to prevent standalone 'a' being displayed in Roman typeface.
*/
/* Operators to put terms in order. The real work is done in order.c;
this file just contains the top-level shell and produces the
reason strings. */
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <search.h>
#include "globals.h"
#include "tdefn.h"
#include "prover.h" /* for immediate and infer */
#include "order.h"
#include "trig.h" /* for TRIGFUNCTOR */
#include "deval.h"
#include "checkarg.h" /* must precede automode.h */
#include "graphstr.h"
#include "mpdoc.h"
#include "automode.h" /* limitflag */
#include "pvalaux.h" /* summands */
#include "symbols.h"
#include "mathmode.h"
#include "orderops.h" /* no_complicated_factors */
#include "autosimp.h" /* SetShowStepOperation */
/*___________________________________________*/
int orderfactors(term in, term arg, term *next, char *reason)
/* in must be a product; order the factors properly in next */
/* Can also apply to an equation, in which case it orders one side. */
{ int i,err,err2;
unsigned short n;
term u;
if(FUNCTOR(in) == '=')
{ term a,b;
unsigned short path[5];
err = orderfactors(ARG(0,in),arg,&a,reason);
if(!err && equals(ARG(1,in),a))
{ path[0] = '=';
path[1] = 1;
path[2] = 0;
set_pathtail(path);
*next = equation(a,ARG(1,in));
return 0;
}
err2 = orderfactors(ARG(1,in),arg,&b,reason);
if(!err2 &&
(
(err && equals(ARG(0,in),b)) ||
(!err && equals(a,b))
)
)
{ *next = equation(ARG(0,in),b);
path[0] = '=';
path[1] = 2;
path[2] = 0;
set_pathtail(path);
return 0;
}
}
if(FUNCTOR(in) != '*')
return 1; /* inapplicable */
if(contains(in,MATRIX) || contains(in,VECTOR))
return 1;
n = ARITY(in);
*next = make_term('*',n);
/* example: (sqrt 3+4)(sqrt 3-7); if you don't prevent it,
=> (sqrt 3-7)(sqrt 3+4) => (7-sqrt 3)(sqrt 3+4) => (sqrt 3+4)(7-sqrt 3) */
if(get_currenttopic() != _verify_algebraic_identity)
{ for(i=0;i<n;i++)
{ u = ARG(i,in);
if(FUNCTOR(u) == '+' && !PROTECTED(u))
ARGREP(*next,i, additive_order(u));
else
ARGREP(*next,i,u);
}
}
else
{ for(i=0;i<n;i++)
ARGREP(*next,i,ARG(i,in));
}
HIGHLIGHT(*next);
err = sortargs(*next);
if(!err)
{ strcpy(reason, english(429)); /* put factors in order */
SETORDERED(*next);
return 0;
}
return 1;
}
/*_____________________________________________________________________*/
int orderterms(term in, term arg, term *next, char *reason)
/* in must be a sum; order the terms properly in next */
/* Can also work on an equation, in which case it orders one side,
but only if the result, or ordering both sides, will make them equal. */
/* We use qsort only in case the arity is more than two */
{ int i,j,err=1,err2,count;
term a,b,c,d,u,v,ll,rr;
unsigned short path[11];
if(FUNCTOR(in) == '=')
{ if(FUNCTOR(ARG(0,in)) == '+' &&
(err = orderterms(ARG(0,in),arg,&a,reason)) == 0 &&
equals(ARG(1,in),a)
)
{ path[0] = '=';
path[1] = 1;
path[2] = 0;
set_pathtail(path);
*next = equation(a,ARG(1,in));
return 0;
}
if(FUNCTOR(ARG(1,in)) == '+' &&
!orderterms(ARG(1,in),arg,&b,reason) &&
(equals(ARG(0,in),b) || (!err && equals(a,b)))
)
{ *next = equation(ARG(0,in),b);
path[0] = '=';
path[1] = 2;
path[2] = 0;
set_pathtail(path);
return 0;
}
ll = ARG(0,in);
rr = ARG(1,in);
if(FUNCTOR(ll) == '*' && FUNCTOR(rr) == '*' && ARITY(ll) == ARITY(rr))
{ /* look for an i such that ARG(i,ll) is a sum and ARG(i,rr)
is a sum and ll and rr differ only in this one argument. */
count = 0;
for(i=0;i<ARITY(ll);i++)
{ if(!equals(ARG(i,ll),ARG(i,rr)))
{ ++count;
j = i;
}
if(count > 1)
return 1; /* fail */
}
/* Now check if ARG(j,ll) and ARG(j,rr) differ only by order. */
u = ARG(j,ll);
v = ARG(j,rr);
if(FUNCTOR(u) != '+' || FUNCTOR(v) != '+' || ARITY(u) != ARITY(v))
return 1;
err = orderterms(u,arg,&a,reason);
if(!err && equals(a,v))
{ copy(ll,&b);
ARGREP(b,j,a);
*next = equation(b,rr);
path[0] = '=';
path[1] = 1;
path[2] = '*';
path[3] = j+1;
path[4] = 0;
set_pathtail(path);
return 0;
}
err2 = orderterms(v,arg,&b,reason);
if(!err && !err2 && equals(a,b))
{ copy(ll,&c);
copy(rr,&d);
ARGREP(c,j,a);
ARGREP(d,j,b);
*next = equation(c,d);
path[0] = '=';
path[1] = 1;
path[2] = '*';
path[3] = j+1;
path[4] = 0;
set_pathtail(path);
return 0;
}
if(!err2 && equals(u,b))
{ copy(rr,&d);
ARGREP(d,j,b);
*next = equation(ll,d);
path[0] = '=';
path[1] = 2;
path[2] = '*';
path[3] = j+1;
path[4] = 0;
set_pathtail(path);
return 0;
}
return 1;
}
}
if(FUNCTOR(in) != '+')
return 1; /* inapplicable */
if(get_mathmode() == AUTOMODE && ORDERED(in))
return 1; /* ORDERED means don't want this term re-ordered */
*next = additive_order(in);
HIGHLIGHT(*next);
SETORDERED(*next);
/* was the order really changed? */
for(i=0;i<ARITY(in);i++)
{ if(!equals(ARG(i,in),ARG(i,*next)))
{ strcpy(reason, english(430)); /* put terms in order */
return 0;
}
}
return 1; /* in was already in order */
}
/*_________________________________________________________*/
int ordersimplefactors(term t, term arg, term *next, char *reason)
/* This operator is used only in auto mode, where it is pre-associated
to '*'. It puts the numerical and constant terms to the front, and
the atoms and powers of variables after that, in sorted order, and the
compound terms after that, in the original order. Except, if all the
factors are already mvpolys, it will call orderfactors, to avoid
two steps in a row labelled "order factors".
*/
{ int err,i,j;
unsigned short k, count = 0;
unsigned short n = ARITY(t);
term v,vv;
int *scratchpad;
if(FUNCTOR(t) != '*')
return 1; /* inapplicable */
if(contains(t,MATRIX) || contains(t,VECTOR))
return 1; /* matrix multiplication is not commutive */
/* try to avoid repetitions of "order factors" : */
if(no_complicated_factors(t))
{ SetShowStepOperation(orderfactors);
return orderfactors(t,arg,next,reason);
}
*next = make_term('*',n);
scratchpad = callocate(n,sizeof(int));
if(!scratchpad)
{ nospace();
return 1;
}
/* Count the non-compound constant factors (the ones to be sorted) */
for(i=0;i<n;i++)
{ if(constant(ARG(i,t)) || monomial(ARG(i,t)))
{ ++count;
scratchpad[i] = 1;
}
}
if(count < 2)
{ free2(scratchpad);
return 1;
}
/* Put the terms in two piles */
k=count;
j=0;
for(i=0;i<n;i++)
{ if(scratchpad[i])
{ ARGREP(*next,j,ARG(i,t));
++j;
}
else
{ ARGREP(*next,k,ARG(i,t));
++k;
}
}
HIGHLIGHT(*next);
SETFUNCTOR(*next,'*',count);
/* only sort the first 'count' terms, not all of them */
/* To accomplish this using sortargs, temporarily reset the arity */
/* example: (sqrt 3+4)(sqrt 3-7); if you don't prevent it,
=> (sqrt 3-7)(sqrt 3+4) => (7-sqrt 3)(sqrt 3+4) => (sqrt 3+4)(7-sqrt 3) */
if(get_currenttopic() != _verify_algebraic_identity)
{ for(i=0;i<count;i++)
{ v = ARG(i,*next);
if(FUNCTOR(v) == '+')
{ /* don't just additive_sortargs(v), because that
will screw up the order in a subterm of the
current line. We must make a copy one level deep
of v and sort that. */
vv = make_term('+', ARITY(v));
for(j=0;j<ARITY(v);j++)
ARGREP(vv,j,ARG(j,v));
additive_sortargs(vv);
if(!equals(vv,v))
ARGREP(*next,i,vv);
else
RELEASE(vv);
}
}
}
err = sortargs(*next);
SETFUNCTOR(*next,'*',n); /* restore the original arity */
free2(scratchpad);
/* was the order really changed? */
if(err)
return 1; /* t was in order, or some additive subterms
got rearranged but not the multiplicative
order, so fail. */
strcpy(reason, english(429)); /* put factors in order */
SetShowStepOperation(orderfactors);
return 0;
}
/*__________________________________________________________________*/
int regroupterms(term t, term arg, term *next, char *reason)
/* flatten + terms and use pushminusin and doubleminus repeatedly */
/* takes a sum and produces a sum */
{ int err = summands(t,next);
if(err)
return 1; /* nothing to do */
strcpy(reason, english(434)); /* regroup terms */
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________________________*/
int doubleminus(term t, term arg, term *next, char *reason)
{ if(FUNCTOR(t) != '-')
return 1; /* inapplicable */
if(FUNCTOR(ARG(0,t)) == '/' && FUNCTOR(ARG(0,ARG(0,t))) == '-')
{ /* -(-a/b) = a/b */
*next = make_term('/',2);
ARGREP(*next,0,ARG(0,ARG(0,ARG(0,t))));
ARGREP(*next,1,ARG(1,ARG(0,t)));
strcpy(reason,"$-(-a/b) = a/b$");
return 0;
}
if(FUNCTOR(ARG(0,t)) != '-')
return 1; /* inapplicable */
*next = ARG(0,ARG(0,t));
HIGHLIGHT(*next);
strcpy(reason,"$-(-a) = a$");
return 0;
}
/*_____________________________________________________________________*/
int pushminusin(term t, term arg, term *next, char *reason)
/* -(a+b) = -a-b */
{ int i;
term s;
if(FUNCTOR(t) != '-')
return 1; /* inapplicable */
s = ARG(0,t);
if(FUNCTOR(s) != '+')
return 1; /* inapplicable */
*next = make_term('+',ARITY(s));
for(i=0;i<ARITY(s);i++)
ARGREP(*next,i,tnegate(ARG(i,s)));
HIGHLIGHT(*next);
strcpy(reason,"$-(a+b) = -a-b$");
return 0;
}
/*________________________________________________________________________*/
int no_complicated_factors(term t)
/* assumes t is a product. Return nonzero iff all the factors
are constants, monomials, or have been through polyval. This
is used to decide whether to call orderfactors or not. If it
returns nonzero, orderfactors is used.
*/
{ int i;
term u;
unsigned short n = ARITY(t);
if(FUNCTOR(t) != '*')
assert(0);
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(ATOMIC(u) || ALREADY(u))
continue;
if(FUNCTOR(u) == '^' && FUNCTOR(ARG(0,u)) == '^')
return 0; /* if (a^b)^c occurs, don't order the factors. Wait
till it has been changed to a^(bc) */
if(FUNCTOR(u) == '^' && ATOMIC(ARG(1,u)))
u = ARG(0,u);
if(contains(u,'+'))
break;
if(!mvpoly(u))
break;
}
return i==n;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists