Sindbad~EG File Manager

Current Path : /usr/home/beeson/MathXpert/automode/
Upload File :
Current File : /usr/home/beeson/MathXpert/automode/nextline.c

/* common code needed by both exec.c and autosimp.c */
/* M. Beeson, for Mathpert */
/*
6.1.93  extracted from exec.c
10.4.98 modified
6.18.06 made push_multiplicities exported
4.23.13  corrected subcomputation
5.6.13 include stddef.h
5.8.13 removed the definition of cons, which is now exported by symsout.dll
4.25.24  changed the dimension of buffer in fixup to DIMREASONBUFFER
*/

#include <assert.h>
#include <stdlib.h>
#include <stddef.h>   
#include "globals.h"
#include "graphstr.h"
#include "display.h"
#include "display1.h"
#include "mpdoc.h"
#include "tdefn.h"
#include "checkarg.h"
#include "operator.h"
#include "nextline.h"
#include "ops.h"
#include "trig.h"
#include "calc.h"
#include "prover.h"
#include "automode.h"
#include "probtype.h"
#include "mpminmax.h"     /* complement */
#include "algaux.h"     /* topflatten */
#include "symbols.h"
#include "bigrect.h"
#include "lterm.h"      /* pathlist, cons */
#include "cflags.h"     /* get_currenttopic */
#include "optable.h"    /* access_optable */
#include "eqn.h"        /* econstant      */
#include "autosimp.h"   /* SaveShowStepState */
#include "pvalaux.h"    /* topflatten     */
#include "series.h"

static term flatten_multiplicities(term);
static int substleft(term new, term old, term t, term *ans);
static int fixup(actualop code,term arg,term q,term p,term t,term *next);
static int special_subst(term new, term old, term t, term *ans);
static int legal_interval(term t);

static int  subcomputation(int linenumber);

static term maxscope;
  /* if an operator is applied inside a binding operator, maxscope is
     used to record the 'locus' of binding, i.e. the term containing
     the binding operator.   The result of (this application of)
     the operator will then not be used outside this term (although
     the operator itself can be APPLIED again outside maxscope).
     Maxscope will be initialized to ILLEGAL by exec and one_step, and
     set by exec_aux (in menu mode) or autosimp (in auto mode) when
     exiting from binding terms (just before releasebinders is called. */


/*_________________________________________________________________*/
pathlist *copy_pathlist(pathlist *source)
{ if(!source)
     return NULL;
  return cons(source->data,source->functor,copy_pathlist(source->next));
}


/*____________________________________________________________*/
void reset_maxscope(void)
{ SETFUNCTOR(maxscope, ILLEGAL,0);
}
/*____________________________________________________________*/
void set_maxscope(term t)
{ maxscope = t;
}
/*____________________________________________________________*/
term get_maxscope(void)
{ return maxscope;
}

/*____________________________________________________________*/
int nextline(actualop code, term arg, term q, term p, term t, term *next)
/* t is the previous line; the operator 'code' has just transformed
p to q.  But we don't just subst(q,p,t,next);  because

(1)  the operator may be contextsensitive, in which case we want to
substitute only for the correct occurrence

(2)  the application of the operator within the scope of a bound
variable may have depended on inferences only valid within that scope,
e.g. in rewriting integral(abs(1-x^2),x,-1,1) => integral(1-x^2,x,-1,1);
we wouldn't want to drop abs in other integrals with different scopes.
This problem is solved using maxscope, documented above.  We substitute
only within maxscope, if maxscope is not ILLEGAL.

(3)  We want to apply the operator to certain other terms (within maxscope
if it is non-NULL) including at least the right-hand brothers of p if
p is a child inequality of an interval_as_and term, using the same arg.

(4) Even if the operator is not context-sensitive we don't want to
substitute into colored terms (which are the result of previous applications
of the operator whose secondary applications to the same line are being
done when this function is called).  Therefore special_subst is used
instead of subst.

See further comments in exec.c just before exec_aux.

Finally, we have to call update_assumptions.
Return 0 for success, 1 for failure. Failure is rare, but can occur,
e.g. if posnum1 was applied to one half on an interval-as-and pair of
inequalities, it won't apply to the other half, so we refuse to use it.
*/

{ term temp,u;
  int err;
  unsigned short f = FUNCTOR(p);
  int change_maxscope = 0;
  int problemtype = get_problemtype();
  if(!heap_ok())
     assert(0);
  if(problemtype == MINMAX && contains(q,MULTIPLICITY))
     q = strip_multiplicities(q);
  else if(f == '=' && equals(q,falseterm) && FUNCTOR(t) == AND)
     { *next = falseterm;
       return 0;
     }
  else if(f == '=' &&
          (FUNCTOR(q) == OR  || equals(q,falseterm) || equals(q,trueterm)) &&
          contains(t,MULTIPLICITY)
         )
     /* we never solve equations inside the scope of a bound variable */
     { special_subst(q,p,t,&temp);
       *next = push_multiplicities(temp);
       update_assumptions(p,q,next);
       return 0;
     }
  else if(f == '=' && FUNCTOR(q) == MULTIPLICITY && contains(t,MULTIPLICITY))
     { special_subst(q,p,t,&temp);
       *next = flatten_multiplicities(temp);
       update_assumptions(p,q,next);
       return 0;
     }
  if(JUMPER(code))  /* defined in ops.h */
     *next = q;
  else if(contextsensitive(code))
     { if(get_mathmode() == AUTOMODE)
          { /* the leftmost occurrence may not necessarily be the correct one
               to substitute for, e.g.  in bringing (2-i)i to complex polar
               form, we want to work on the second 'i'. */
            unsigned short *path = get_path();
            int err = subterm_at_path(t,path,&u);
            if(err || !equals(u,p))
               /* assert(0);  oops, this can happen!  check_problem sets
                  the default mathmode to AUTOMODE */
               substleft(q,p,t,next);
            else
               pathsub(path,q,t,next);
          }
       else
          substleft(q,p,t,next);  /* using the Operations menu */
     }
  else if(FUNCTOR(maxscope) == ILLEGAL)
     { if(INEQUALITY(f) && contains(t,AND))  /* so in particular !equals(p,t) */
           { err = fixup(code,arg,q,p,t,next);  /* apply code to the brothers of p too */
             if(err)
                return 1;
           }
       else
           special_subst(q,p,t,next);
       if(FUNCTOR(q)==OR && FUNCTOR(t) == OR && FUNCTOR(*next)==OR)
          *next = topflatten(*next);
       if(FUNCTOR(q)==AND && FUNCTOR(t) == AND && FUNCTOR(*next)==AND)
          *next = topflatten(*next);
       if(problemtype == RELATED_RATES)
          { if( (void *) code == (void *) difeqn &&
                FUNCTOR(*next) == OR
              )
                { u = ARG(0,*next);
                  if(FUNCTOR(u) == AND)
                     u = topflatten(u);
                  ARGREP(*next,0,u);
                  SETFUNCTOR(*next,AND,ARITY(*next));
                  *next = topflatten(*next);
                  /* Once the equation has been differentiated, t refers to
                  a specific instant of time and all the equations can be
                  treated as a normal system of equations. */
                }
            else if( FUNCTOR(q)==AND && FUNCTOR(*next) == OR &&
                FUNCTOR(ARG(0,*next))==AND
              )
               { temp = topflatten(ARG(0,*next));
                 ARGREP(*next,0,temp);
               }
          }
     }
  else /* the operator worked within the scope of a bound variable */
     { special_subst(q,p,maxscope,&temp);
       special_subst(temp, maxscope,t,next);
       change_maxscope = 1;
     }
  if(equals(t,*next)  /* this happens if p is not actually a subterm of t,
                               see the comments above */
                &&  (void  *) code != (void  *) lineupvars
                &&  (void  *) code != (void  *) selecteqn
                &&  (void  *) code != (void  *) showalleqns
                &&  (void  *) code != (void  *) evalatpoint
                            /* these are the only operators that succeed
                               without changing the formula */
               )
                return 1;
  if(change_maxscope)
     maxscope = temp;  /* needed so maxscope is correct if the operator
                          succeeds again somewhere to the right of
                          its original focus. */
  return 0;
}
/*_____________________________________________________________________*/
 void update_assumptions(term old, term new, term *next)
/*  substitute new for old throughout the list of current assumptions;
if anything changes, store the result as a revised version of
that assumption.
   Then, call simplify_assumptions (in prover.c)
   When this is called, an operator has been successfully applied to
history[currentline], changing old to new, but currentline hasn't been
incremented yet.  Indeed, this is called while we are still in the
midst of traversing the term, and the SAME operator (if not
context-sensitive) may yet be applied at another 'focus', i.e. to another
subterm.  Consequently 'binders' may still be in force if the traversal
is in the scope of a bound variable--this is no problem as the bound
variables can't be appearing in the assumptions anyway, unless in a
protected formula.
   This function does not check for contradictions among the assumptions
or do anything special if one of the assumptions simplifies to false.

The pointer 'next' is used only in MINMAX problems.
For example:  if f(x) = abs(x); when we differentiate it the
assumption x != 0 is generated, but we don't want to keep that as an assumption;
instead its negation should go into the current line as another case
to consider.  Otherwise, when for example we consider points where f'(x)
is undefined, the equation x=0 will be rejected as contradicting assumptions,
and we won't find the minimum at x=0.  This can't be corrected in individual
operators, as MANY operators might generate assumptions, and logically
SHOULDN'T be: minmax problems are different than other kinds, in that we
definitely DON'T want to make any assumption that x is not equal to
certain values, except that it is in the interval under consideration.
Anyway, in MINMAX problems, we have to remove any assumptions made at the
current line and enlarge the current line (passed as *next) to a disjunction
including the new cases. */

{ int i,j;
  unsigned short m,m2,k;
  term t,u,ans,x,temp;
  int flag = 0;   /* set if we need to call simplify_assumptions */
  int currentline;
  int problemtype = get_problemtype();
  int nextassumption = get_nextassumption();
  assumption **assumptions = get_assumptions();
  if(nextassumption == 0)
     return;  /* nothing to do so get out fast */
  currentline = get_currentline();
  SaveShowStepState();
  /* lpt can call ssolve, which calls ResetShowStepOperation, so
     we have to save and restore the ShowStepOperation if any,
     in order that it should not be changed by this function */
  for(i=0;i<nextassumption;i++)
     { t = assumptions[i]->prop;
       if(assumptions[i]->line == currentline+1)
          flag = 1;
       special_subst(new,old,t,&u);
       if(!equals(t,u))
          { ans = lpt(u);
            /* Now push ans onto assumptions[i] */
            /* EXCEPT:  lpt can possibly have created an AND,
                        which has to be split.  The first conjunct will
                        go into assumptions[i], and the rest will just be
                        fresh assumptions.
            */
            if(FUNCTOR(ans) != AND && !interval_as_and(ans))
               { push_assumption(ans,i);
                 flag = 1;
               }
            else
               { push_assumption(ARG(0,ans),i);
                 flag = 1;
                 for(j=1;j<ARITY(ans);j++)
                    assume(ARG(j,ans));
               }
          }
     }
  if(flag)
     { if(problemtype == MINMAX)
          { /* Count the assumptions that have been made at this line.
               Put them all into a new term 'newcases'.  Decrement
               nextassumption, which effectively gets rid of the new
               assumption(s).  Form the disjunction of the new cases and
               the current line and make that the new current line (taking
               care to flatten if the old current line is already
               a disjunction).  Finally remove duplicate disjuncts
               from the new current line.
               */
            k=0;
            x = get_eigenvariable();
            for(i=nextassumption-1;i>=0 && assumptions[i]->line==currentline+1;i--)
               ++k;
            assert(k > 0);  /*otherwise flag would have been zero */
            ans = make_term(OR,(unsigned short)( FUNCTOR(*next) == OR ? ARITY(*next) + k : k+1));
            temp = make_term(OR,k);
            if(FUNCTOR(*next) == OR)
               { /* copy the old cases into the first args of ans */
                  for(i=0;i<ARITY(*next);i++)
                     ARGREP(ans,i,ARG(i,*next));
               }
            else
               { ARGREP(ans,0,*next);
                 i=1;
               }
            /* Now put the new assumptions (negated) into the other args */
            m = m2 = 0;
            for(j=0;j<k;j++)
               { u = assumptions[nextassumption-1-j]->prop;
                 if(contains(u,FUNCTOR(x)))
                    { ARGREP(ans,i+m,complement(u));
                      ++m;
                    }
                 else
                    { ARGREP(temp,m2,u);
                      ++m2;
                    }
               }
            SETFUNCTOR(ans,OR,i+m);
            assert(nextassumption >= k);
            set_nextassumption((unsigned short) (nextassumption-k));  /* get rid of these assumptions */
            if(m2)
                { for(j=0;j<m2;j++)
                     assume(ARG(j,temp));
                }
            RELEASE(temp);
            remove_dups(ans,next);   /* this will be the new current line */
          }
       else
          simplify_assumptions(new);
          /* does any old assumption simplify in
             light of the most recent assumption(s) ? */
     }
  RestoreShowStepState();
}
/*___________________________________________________________*/
 int specialop(term arg, actualop code)
/* return 1 if the next history[currentline] should not reflect the
actual results of the operator, else return 0. */
{ if(    (void  *) code ==  (void  *) evalatpoint
      || (void  *) code ==  (void  *) checknumerically
      || (void  *) code ==  (void  *) solvenumerically
      || (void  *) code ==  (void  *) testlimit
    )
     return 1;
  if(FUNCTOR(arg) != ILLEGAL &&
      (    (void  *) code == (void  *) evaluatesigmatorational
        || (void  *) code == (void  *) evaluatesigmatodecimal
        || (void  *) code == (void  *) integratenumerically
      )
    )
    return 1;
  return 0;
}

/*______________________________________________________________*/
 term strip_multiplicities(term t)
/*  remove all MULTIPLICITY functors from t */
{ unsigned short n;
  int i;
  term ans;
  if(ATOMIC(t))
     return t;
  if(FUNCTOR(t) == MULTIPLICITY)
     return strip_multiplicities(ARG(0,t));
  if(!contains(t,MULTIPLICITY))
     return t;
     /* MULTIPLICITY functors are never deeply buried so this will
        not waste much time.  At most they are in an OR of equations
        two levels deep.  */

  n = ARITY(t);
  ans = make_term(FUNCTOR(t),n);
  for(i=0;i<n;i++)
     ARGREP(ans,i,strip_multiplicities(ARG(i,t)));
  return ans;
}
/*_______________________________________________________________*/
 term push_multiplicities(term t)
/* push MULTIPLICITY in through OR and return the result;
   drop MULTIPLICITY around 'false' or 'true'
*/
{ unsigned short f = FUNCTOR(t);
  unsigned short n;
  term ans,mm,u,temp;
  int i;
  if(f == MULTIPLICITY)
     { u = ARG(0,t);
       mm = ARG(1,t);
       if(FUNCTOR(u) == OR)
          { n = ARITY(u);
            ans = make_term(OR,n);
            for(i=0;i<n;i++)
               { temp = make_term(MULTIPLICITY,2);
                 ARGREP(temp,0,ARG(i,u));
                 ARGREP(temp,1,mm);
                 ARGREP(ans,i,temp);
               }
            return ans;
          }
       if(equals(u,falseterm) || equals(u,trueterm))
          return u;
       return t;
     }
  if(FUNCTOR(t) == OR)
     { n = ARITY(t);
       ans = make_term(OR,n);
       for(i=0;i<n;i++)
          ARGREP(ans,i,push_multiplicities(ARG(i,t)));
       return topflatten(ans);
     }
  return t;
}

/*______________________________________________________________*/
static int substleft(term new, term old, term t, term *ans)
/* substitute new for leftmost occurrence which is not COLOR'ed
   (and only this occurrence) of old in t getting ans */
/*  (the head of) *ans will not change;
    space must be allocated for (the head of) *ans before subst is called.
    You pass it the address of a term, and it
    uses the head of that term, creating new space for the args. */

/*  *ans will be in fresh space (except for the head of *ans)
   Return value nonzero means *ans is not equal to t;
   return value 0 means *ans is equal to t;
   this is used to make sure that subst does preserve the .info fields
   of unchanged subterms. */

{ int change=0;
  unsigned i,j;
  unsigned short k,n = ARITY(t);
  unsigned short nargs;
  unsigned short f = FUNCTOR(t);
  term temp;
  if( equals(t,old))
     { copy(new,ans);
       return (equals(new,old) ? 0 : 1);
     }
  if( ATOMIC(t) )
     { copy(t,ans);
       return 0;
     }
  if(COLOR(t))
     { copy(t,ans);
       return 0;
     }
  *ans = make_term(f,n);
  if(COLOR(t))
     SETCOLOR(*ans,COLOR(t));
  if(f == INTEGRAL && n == 4 && IMPROPER(t))
     SETIMPROPER(*ans);
  for(i=0;i<n;i++)
     { if(!change)
           change = substleft(new,old,ARG(i,t),ARGPTR(*ans)+i);
       else
           ARGREP(*ans,i,ARG(i,t));
     }
  if(!change)
     ans->info = t.info;
    /* Now *ans is the unflattened result of the substitution,
       but we may still need to flatten the answer */
  if(f == '/' && SOME_INFINITESIMAL(t))
     copy_infinitesimal_markers(t,ans);
  if(f != '+' && f != '*' && f != AND && f != OR)
     return change;  /* no need to flatten */
       /* count how many args the flattened term will have */
  for(i=j=0;i<n;i++)
     { if(FUNCTOR(ARG(i,*ans)) == f)
          j += ARITY(ARG(i,*ans));
       else
          ++j;
     }
  if(j==n)
     return change;  /* no need to flatten */
  nargs = (unsigned short) j;  /* number of args of flattened term  to be created */
  temp = *ans;
  *ans = make_term(f,nargs);
  for(i=j=0;i<n;i++)
     { if(FUNCTOR(ARG(i,temp)) == f)
           /* copy the args of ARG(i,temp)  into the appropriate args of *ans,
              namely  j, j+1,...,j+ARITY(ARG(i,temp)) */
          { unsigned short color = COLOR(ARG(i,temp));
            for(k=0;k<ARITY(ARG(i,temp));k++)
                { *(ARGPTR(*ans) + j + k)=ARG(k,ARG(i,temp));
                  if(color)
                     SETCOLOR(ARG(j+k,*ans),color);
                }
            j += ARITY(ARG(i,temp));
          }
       else
          { *(ARGPTR(*ans) + j) = ARG(i,temp);
            ++j;
          }
     }
  RELEASE(temp);  /* allocated by the first call to make_term */
  return change;
}
/*________________________________________________________________*/
static int path_to_leftmost(term t, term p, pathlist **ans)
/* return in *ans the path to the leftmost occurrence of p in t,
if there is one, returning 0 for success. If there is no
occurrence of p in t, return 1, in which case *ans is garbage.
All the nodes on the returned path will be created
on the document heap, using cons.
*/
{ int i,err;
  pathlist *temp;
  unsigned short n;
  if(equals(p,t))
     { *ans = NULL;
       return 0;
     }
  if(ATOMIC(t))
     return 1;
  n = ARITY(t);
  for(i=0;i<n;i++)
     { err = path_to_leftmost(ARG(i,t),p,&temp);
       if(!err)
          { *ans = cons(i,FUNCTOR(t),temp);
            return 0;
          }
     }
  return 1;
}

/*________________________________________________________________*/
static int fixup(actualop code,term arg,term q,term p,term t, term *next)
/* code has just transformed p in t to q; p is an inequality
and t contains AND.  If p is a (left) child of an interval_as_and term,
apply code to the brother of p too, then make the two substitutions
producing next.  Return 0 for success.
*/
{ /* The main problem is to get our hands on the parent of p in t */
  pathlist *path_to_p, *marker,*last, *penultimate;
  term s,u,temp;
  char buffer[DIMREASONBUFFER];
  int err = path_to_leftmost(t,p,&path_to_p);
  assert(!err);  /* it is assumed that p is a subterm of t */
  last = NULL;
  temp = t;
  /* Now make temp = the parent of p in t */
  for(marker=path_to_p;marker && (marker->data >= 0);marker=marker->next)
     { penultimate = last;
       if(penultimate)
           { assert(!ATOMIC(temp) && penultimate->data < ARITY(temp));
              temp = ARG(penultimate->data,temp);
           }
       last = marker;
     }
  if(interval_as_and(temp))
     { /* In case (*code) calls set_pathtail, we have to restore it to the
          present value. */
       unsigned short savetail[MAXTAIL];
       pathcopy(savetail,get_pathtail());
       err = (*code)(ARG(1,temp),arg,&s,buffer);
       if(err)
          return 1;
       set_pathtail(savetail);
       u = and(q,s);
       if(interval_as_and(u))
          { if(legal_interval(temp) && !legal_interval(u))
               return 1;
            special_subst(u,temp,t,next);
          }
       else
          { RELEASE(u);
            u = and(s,q);  /* needed if changesigns was applied */
            HIGHLIGHT(u);
            if(interval_as_and(u))
               special_subst(u,temp,t,next);
            else
               return 1;  /* don't destroy an interval_as_and */
          }
     }
  else
     special_subst(q,p,t,next);
  return 0;
}
/*_________________________________________________________________*/
static int special_subst(term new, term old, term t, term *ans)
/* This is a copy of 'subst' in speed.c, modified so that
it refuses to substitute into a term with the COLOR bit set
in its info field. It is used only in nextline.  Return 0
if something is changed, but in any case *ans is sensible.
*/
{ int i,change=0;
  unsigned short j,n = ARITY(t);
  unsigned short k,nargs;
  unsigned short f = FUNCTOR(t);
  term temp;
  if( equals(t,old))
     { copy(new,ans);
       return (equals(new,old) ? 0 : 1);
     }
  if(ATOMIC(t) || COLOR(t))
     { copy(t,ans);
       return 0;
     }
  if(f == MULTIPLICITY && equals(old,ARG(0,t)) && equals(new,falseterm))
     { /* don't generate  multiplicity(false,n); just generate false. */
       *ans = falseterm;
       return 0;
     }
  *ans = make_term(f,n);
  if(f == INTEGRAL && n == 4 && IMPROPER(t))
     SETIMPROPER(*ans);
  if(COLOR(t))
     SETCOLOR(*ans,COLOR(t));
  for(i=0;i<n;i++)
     change += special_subst(new,old,ARG(i,t),ARGPTR(*ans)+i);
  if(!change)
     ans->info = t.info;
    /* Now *ans is the unflattened result of the substitution,
       but we may still need to flatten the answer */
  if( f == '/' && SOME_INFINITESIMAL(t))
     /* t is a fraction with infinitesimal denominator; substitutions
        done into t will always preserve the infinitesimal-denominator
                  property and must be so labelled */
     copy_infinitesimal_markers(t,ans);
  if(f != '+' && f != '*')
     return change;  /* no need to flatten */
  /* else go on and flatten the answer */
  /* count how many args the flattened term will have */
  for(i=j=0;i<n;i++)
     { if(FUNCTOR(ARG(i,*ans)) == f)
          j += ARITY(ARG(i,*ans));
       else
          ++j;
     }
  if(j==n)
     return change;  /* no need to flatten */
  nargs = j;  /* number of args of flattened term  to be created */
  temp = *ans;
  *ans = make_term(f,nargs);
  for(i=j=0;i<n;i++)
     { if(FUNCTOR(ARG(i,temp)) == f)
           /* copy the args of ARG(i,temp)  into the appropriate args of *ans,
              namely  j, j+1,...,j+ARITY(ARG(i,temp)) */
          { unsigned short color = COLOR(temp);
            if(!color)
               color = COLOR(ARG(i,temp));
            for(k=0;k<ARITY(ARG(i,temp));k++)
               { *(ARGPTR(*ans) + j + k) = ARG(k,ARG(i,temp));
                 if(color)
                    SETCOLOR(ARG(j+k,*ans),color);
               }
            j += ARITY(ARG(i,temp));
          }
       else
          { *(ARGPTR(*ans) + j) = ARG(i,temp);
            if(COLOR(temp))
               SETCOLOR(ARG(j,*ans),COLOR(temp));
            ++j;
          }
     }
  RELEASE(temp);  /* allocated by the first call to make_term */
  return change;
}

/*_______________________________________________________________________*/
static term flatten_multiplicities(term t)
/* multiplicity(multiplicity(x,2),3) => multiplicity(x,6) for example,
   anywhere within t */
{ unsigned short n;
  unsigned short f;
  int i,err;
  term p,q;
  term ans;
  if(ATOMIC(t))
     return t;
  f = FUNCTOR(t);
  if(f == MULTIPLICITY && FUNCTOR(ARG(0,t))== MULTIPLICITY)
     { ans = make_term(MULTIPLICITY,2);
       ARGREP(ans,0, ARG(0,ARG(0,t)));
       p = product(ARG(1,t),ARG(1,ARG(0,t)));
       err = value(p,&q);
       if(err)
          q = p;
       ARGREP(ans,1,q);
       return ans;
     }
  n = ARITY(t);
  ans = make_term(f,n);
  for(i=0;i<n;i++)
     ARGREP(ans,i, flatten_multiplicities(ARG(i,t)));
  return ans;
}

/*_________________________________________________________________*/
static int subcomputation(int linenumber)
/* return 1 if history[linenumber] was generated by a
specialop, 0 otherwise.  So if it returns 0, then
history[linenumber] resulted by simplifying the
original problem, hence modulo the current assumptions it
is a consequence of the original problem if that was
a proposition.
*/

{ controldata d;
  if(linenumber == 0) 
       return 0;  // since history[0] is the original problem
  get_controldata(&d);
  if(d.opseq[linenumber].choice == 0)
       return 0;  // shouldn't happen, but anyway avoid a negative index in the next line
  return specialop(zero,access_optable(d.opseq[linenumber].men)[d.opseq[linenumber].choice-1]);
}


/*__________________________________________________________________*/
static term neg_ineq(term t)
/* assuming t is an inequality, return another inequality equivalent
to the negation of t, e.g. if t is 0 < x, return x <= 0.
There's another static copy of this in prover.c
*/
{ unsigned short f = FUNCTOR(t);
  unsigned short g;
  int i = 0;  /* used to get args switched on <, LE, GE, > , but not on = and NE */
  term ans;
  switch(f)
     {  case '<' : g = LE;   break;
        case LE  : g = '<'; break;
        case GE  : g = '>'; break;
        case '>' : g = GE ; break;
        case NE  : g = '='; i=1; break;
        case '=' : g = NE;  i=1; break;
        default:  assert(0);
     }
  ans = make_term(g,2);
  ARGREP(ans,i,ARG(1,t));
  ARGREP(ans,(i ? 0: 1),ARG(0,t));
  return ans;
}

/*_____________________________________________________________________*/
 int inconsistent(term t)
/* return 1 if proposition t contradicts one of the lines
   of the computation so far, as when we have a=0 as one
   line and try to divide by a, so t comes to this
   function as a != 0.
   Return 0 if we can't easily see a contradiction.
      Is not used when solving inequalities, as it
   may permit reducing terms to false when they
   contradict the inequality to be derived, thus causing
   restrictions which should be kept in the assumptions
   to disappear.
*/
{ int currentline = get_currentline();
  int problemtype = get_problemtype();
  term u;
  int i;
  unsigned short f = FUNCTOR(t);
  if(!SOLVETYPE(problemtype) || !INEQUALITY(f))
     return 0;
  if(problemtype == INEQUALITIES)
     return 0;
  if(problemtype == MINMAX)
     return 0;  /* when not all the initial operations have been used,
                   you could have x=0 and then later on x=2, x= -1 are
                   added, and x = 2 is rejected for contradicting x = 0. */
  for(i=0;i<=currentline;i++)
     { if(subcomputation(i))
          continue;
       u = history(i);
       if(implies_instantly(u,neg_ineq(t)))
          return 1;
     }
  return 0;  /* can't do anything */
}
/*_______________________________________________________________________*/
static int legal_interval(term t)
/* t is an interval_as_and, that is, has the form a <= c <= b.
Return 1 if a and b are econstant, 0 otherwise.
*/

{ term a,b;
  unsigned short f,g;
  if(FUNCTOR(t) != AND)
     return 0;
  f = FUNCTOR(ARG(0,t));
  g = FUNCTOR(ARG(1,t));
  if(f != LE && f != '<')
     return 0;
  if(g != LE && g != '<')
     return 0;
  a = ARG(0,ARG(0,t));
  b = ARG(1,ARG(1,t));
  if(!econstant(a))
     return 0;
  if(!econstant(b))
     return 0;
  return 1;
}

/*_________________________________________________________________________*/
 int pathsub(unsigned short *path, term u, term t, term *next)
/* substitute u for the term at the specified path in t, getting
*next.  Return 0 for success.  If the specified path isn't a path
in t, return 1.
   Subranges are indicated in path by using  SUBRANGE in the functor
position, e.g. (+,1,SUBRANGE,2) to indicate a two-summand subrange.
*/

{ term v;
  unsigned short n,min,max;
  unsigned short f = FUNCTOR(t);
  int i,k,err;
  if(path[0]==0 || path[1] == 0)
     /* If the path was generated by autosimp with dir == UP, and the
        focus wasn't atomic, the functor of the focus is at the end of
        the path and the following path[2n+1] is zero, so when we
        get to the end of the path on a recursive call, we arrive here
        with path[0] nonzero and path[1] == 0.
     */
     { *next = u;
       return 0;
     }
  if(path[2] == SUBRANGE)
     { min = (unsigned short) (path[1]-1);
       max = (unsigned short) (path[3]-1);
       if(path[3] == 0  || max <= min)
          return 1;  /* assert(0) */
       n = ARITY(t);
       *next = make_term(f,(unsigned short) (n-(max-min)));
       for(i=0;i<n;i++)
          ARGREP(*next,i, i < min ? ARG(i,t) : i==min ? u : ARG(i-(max-min),t));
       if(FUNCTOR(u) == f)
          *next = topflatten(*next);
       return 0;
     }
  if(ATOMIC(t))
     return 1;
  if(FUNCTOR(t) != path[0])
     return 1;
  if(path[1] > ARITY(t))
     return 1;
  k = path[1]-1;
  err = pathsub(path+2,u,ARG(k,t),&v);
  if(err)
     return 1;
  n = ARITY(t);
  *next = make_term(f,n);
  if(f == INTEGRAL && n == 4 && IMPROPER(t))
     SETIMPROPER(*next);  /* nothing you do to the integrand makes the integral proper */
  for(i=0;i<n;i++)
     ARGREP(*next,i,i==k ? v : ARG(i,t));
  if(f == '/' && SOME_INFINITESIMAL(t))
     copy_infinitesimal_markers(t,next);
  if(f != '+' && f != '*' && f != AND && f != OR)
     return 0;  /* no need to flatten */
  if(FUNCTOR(u) != f)
     return 0;
  *next = topflatten(*next);
  return 0;
}

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists