Sindbad~EG File Manager

Current Path : /usr/home/beeson/MathXpert/getprob/
Upload File :
Current File : /usr/home/beeson/MathXpert/getprob/enhance.c

/* M. Beeson, for Mathpert.
   enhance_problem.
   This file is interface-independent.
   It calls on get_vars_from_user for its only interaction with the user.

11.8.92 file created from older code
8.18.99 last modified
1.12.00 corrected on MINMAX at line 300
1.16.00 corrected the correction
3.28.00  changed ARG(i,t) to ARG(j,t) in nonlinear_variables
4.07.06  changed ltoa to sprintf
10.9.10  modified around line 402 for the case when we are differentiating a constant, and need to invent a variable.
5.20.13 added include wfile.h
6.7.13  removed windows.h since wfile.h no longer needs it
8.25.24 modified enhance_problem at "subst(a,a"
10.1.24 made enhance_problem work on IMPLICITDIFF
1.22.25 modifed enhance_problem to not work on an AND of inequalities
1.23.25 modified enhance_problem around line 362 so it's not introducing a
new variable on problemtypes that are not GRAPHTYPES (like LINEAREQUATIONS).
*/

#include <assert.h>
#include <string.h>
#include <ctype.h>    /* tolower */
#include <stdio.h>    /* sprintf  */

#include "globals.h"  /* which includes setjmp.h and terms.h */
#include "tdefn.h"
#include "probtype.h"  /* possible values of problemtype */
#include "prover.h"
#include "deriv.h"
#include "checkarg.h"
#include "diff.h"   /* dif_aux     */
#include "order.h"
#include "factor.h"  /* ratpart2 */
#include "pvalaux.h"
#include "graphstr.h"
#include "mpdoc.h"
#include "getprob.h"  /* eqns_adjust_varlist */
#include "cflags.h"   /* get_minmax_intervalp */
#include "chkinput.h" /* graph_interval */
#include "islinear.h"  /* is_linear_system */
#include "dispfunc.h"  /* atom_string */
#include "mpmem.h"    /* permcopy */
#include "pstring.h"  /* log_term */

static term getnewatom(void);
static int check_order(term t);
static void erasecolors(term *t);
/*________________________________________________________________*/
void enhance_problem(term *t, int currenttopic, int problemtype)
/*  t has been entered in the problem window.  But in the case of
some problemtypes, it needs 'enhancing'.  This function does the
enhancing.  Specifically,  it supplies derivative and integral signs
when the problemtype is differentiation or integration, and it
completes nonequations by changing t to t=0 when appropriate.
It does not have to deal with creating definite integrals, as this
has been done already.

For ordinary graphs, it changes f(x) to y=f(x), and it changes
(f(t),g(t)) to (x=f(t),y=g(t)) for parametric graphs, and f(t) to r=f(t)
for polar graphs;

For SOLVE_ODE,  it does nothing.

It assumes that setup_varlist has been run, so that varlist is established
and for appropriate problemtypes, varlist[0] is the independent variable
and varlist[1] is the dependent variable.

For problemtypes that involve solving equations, it sets varinfo[0] to
EXISTENTIAL.

It also checks whether the problem is in ASCENDING order.  If so,
it sets the global variable 'orderflag' to ASCENDING, thus ensuring that
ascending order is used in automode simplification.

For MINMAX problems it makes minmax_interval point to a term in
permanent memory recording the interval given in the problem,
and deletes the interval from the problem itself.

If 'i' occurs as an index variable in the problem, it was parsed
as complexi,  and then vaux entered it in varlist as 'i' of INTEGER
type.   So enhance_problem must, in that case, substitute the
INTEGER type 'i' for complexi in the problem.
*/

{ int i,c;
  term x,y,yprime,temp;
  unsigned f = FUNCTOR(*t);
  term *varlist = get_varlist();
  static term savey;
  int nvariables = get_nvariables();
  varinf *varinfo = get_varinfo();
  /* first take care of the last item in the specs, renaming complexi
     in case i occurs as an index variable */
  SETFUNCTOR(savey,ILLEGAL,0);
  for(i=0;i<nvariables;i++)
     { if(FUNCTOR(varlist[i]) == 'i')
           break;
     }
  if(i<nvariables)  /* yep, we have a variable 'i' at hand */
     { subst(varlist[i],complexi,*t,&temp);
       *t = temp;
     }
  if(currenttopic == _comparefandfprime)
     {  /* input_check rejects non-mathematical input except for
           equations with an atom on the left or f(x) on the left */
        x = get_eigenvariable();
        if(f != '=')
            { y = *t;
              *t = equation( FUNCTOR(x)=='y' ? getnewatom() : make_atom_from_string("y"), y);
              let_aux(ARG(0,*t),x,0);
              nvariables = get_nvariables();
              if(nvariables > 2)
                 swapvars(nvariables-1,1);
            }
        else
            { 
              y = ARG(1,*t);
            }
        *t = and(*t, equation(pr(ARG(0,*t),one),derivative(y,x)));
        erasecolors(t);
        return;
     }
  if(currenttopic == _comparetwoderivs)
     {  x = get_eigenvariable();
        if(f != '=')
            { y = *t;
              *t = equation( FUNCTOR(x)=='y' ? getnewatom() : make_atom_from_string("y"), y);
              let_aux(ARG(0,*t),x,0);
              nvariables = get_nvariables();
              if(nvariables > 2)
                 swapvars(nvariables-1,1);
            }
        else
            { assert(ISATOM(ARG(0,*t)));
              y = ARG(1,*t);
            }
        yprime = derivative(y,x);
        *t = and3(*t, equation(pr(ARG(0,*t),one),yprime),
                      equation(pr(ARG(0,*t),two),derivative(yprime,x))
                 );
        erasecolors(t);
        return;
     }

  /* First check if orderflag should be set to ASCENDING */
  c = check_order(*t);
  if(c > 0)  /* c == 0 means some sum contained in *t not in ascending order;
                c < 0 means no sums contained in *t
                c > 0 means all sums in *t are in ascending order, and there
                      is at least one such sum */
     set_orderflag(ASCENDING);
  if(problemtype == SOLVE_EQUATION ||
     problemtype == LINEAR_EQUATION ||
     problemtype == INEQUALITIES ||
     problemtype == LINEAR_EQUATIONS
    )
     { varinfo[0].scope = EXISTENTIAL;
     }
  if(problemtype == RIEMANN_SUMS ||
     problemtype == TRAPEZOID_RULE ||
     problemtype == SIMPSONS_RULE
    )
     return;  /* no enhancement needed */
  if(problemtype == PARAMETRIC_GRAPH
        && ARITY(*t) >= 2  /* shouldn't ever be < 2, but be careful */
    )
      { int xflag = -1;
        int yflag = -1;
        if(FUNCTOR(ARG(0,*t)) != '=')
           { temp = equation(contains(*t,'x') ? getnewatom() : make_atom_from_string("x"), ARG(0,*t));
             ARGREP(*t,0,temp);
             let_aux(ARG(0,temp),get_eigenvariable(),0);
             nvariables = get_nvariables();
             xflag = nvariables-1;
           }
        if(FUNCTOR(ARG(1,*t)) != '=')
           { temp = equation(contains(*t,'y') ? getnewatom() : make_atom_from_string("y"), ARG(1,*t));
             ARGREP(*t,1,temp);
             let_aux(ARG(0,temp),get_eigenvariable(),0);
             nvariables = get_nvariables();
             yflag = nvariables -1;
           }
        if(nvariables > 3)  /* there are some parameters; they must come
                               AFTER the new variable or variables */
          { if(xflag >=0)
               swapvars(xflag,1);
            if(yflag >=0)
               swapvars(yflag,2);
          }
        if(ARITY(*t) == 2)
          { // then we need to create the default parameter interval
             x = get_eigenvariable();
            term twopi = product(two,pi_term);
            term interval = and( le(zero,x),le(x,twopi));
            *t = and3(ARG(0,*t),ARG(1,*t),interval);
          }
        return;
      }
  if(problemtype == SPACE_CURVE)
      { int xflag = -1;
        int yflag = -1;
        int zflag = -1;
        if(FUNCTOR(ARG(0,*t)) != '=')
           { temp = equation(contains(*t,'x') ? getnewatom() : make_atom_from_string("x"), ARG(0,*t));
             ARGREP(*t,0,temp);
             let_aux(ARG(0,temp),get_eigenvariable(),0);
             nvariables = get_nvariables();
             xflag = nvariables-1;
           }
        if(FUNCTOR(ARG(1,*t)) != '=')
           { temp = equation(contains(*t,'y') ? getnewatom() : make_atom_from_string("y"), ARG(1,*t));
             ARGREP(*t,1,temp);
             let_aux(ARG(0,temp),get_eigenvariable(),0);
             nvariables = get_nvariables();
             yflag = nvariables -1;
           }
        if(FUNCTOR(ARG(2,*t)) != '=')
           { temp = equation(contains(*t,'z') ? getnewatom() : make_atom_from_string("z"), ARG(1,*t));
             ARGREP(*t,1,temp);
             let_aux(ARG(0,temp),get_eigenvariable(),0);
             nvariables = get_nvariables();
             zflag = nvariables -1;
           }
        if(nvariables > 4)  /* there are some parameters; they must come
                               AFTER the new variable or variables */
          { if(xflag >=0)
               swapvars(xflag,1);
            if(yflag >=0)
               swapvars(yflag,2);
            if(zflag >= 0)
               swapvars(zflag,3);
         }
        return;
      }
  if(problemtype == PARAMETRIC_SURFACE)
      { int xflag = -1;
        int yflag = -1;
        int zflag = -1;
        if(FUNCTOR(ARG(0,*t)) != '=')
           { temp = equation(contains(*t,'x') ? getnewatom() : make_atom_from_string("x"), ARG(0,*t));
             ARGREP(*t,0,temp);
             let_aux(ARG(0,temp),get_eigenvariable(),0);
             nvariables = get_nvariables();
             xflag = nvariables-1;
           }
        if(FUNCTOR(ARG(1,*t)) != '=')
           { temp = equation(contains(*t,'y') ? getnewatom() : make_atom_from_string("y"), ARG(1,*t));
             ARGREP(*t,1,temp);
             let_aux(ARG(0,temp),get_eigenvariable(),0);
             nvariables = get_nvariables();
             yflag = nvariables -1;
           }
        if(FUNCTOR(ARG(2,*t)) != '=')
           { temp = equation(contains(*t,'z') ? getnewatom() : make_atom_from_string("z"), ARG(1,*t));
             ARGREP(*t,1,temp);
             let_aux(ARG(0,temp),get_eigenvariable(),0);
             nvariables = get_nvariables();
             zflag = nvariables -1;
           }
        if(nvariables > 5)  /* there are some parameters; they must come
                               AFTER the new variable or variables */
          { if(xflag >=0)
               swapvars(xflag,2);
            if(yflag >=0)
               swapvars(yflag,3);
            if(zflag >=0)
               swapvars(zflag,4);
          }
        return;
      }
  if(problemtype == INTEGRATION)
     { if(f == INTEGRAL)
          return;  /* without 'enhancing' it */
       else if(contains(*t,INTEGRAL))
          return;  /* input will be rejected later;
                      don't add a second integral sign */
       else if(nvariables > 0)
          *t = integral(*t,varlist[0]);
       else  /* constant integrand entered, for example e^2  */
          { /* introduce new variable x */
            term x = make_atom_from_string("x");
            vaux(x);
            nvariables = get_nvariables();
            assert(nvariables == 1);
            *t = integral(*t,varlist[0]);
          }
       return;
     }
  if(problemtype == GRAPH_INEQUALITY)
     { if(nvariables == 1)
          { if(FUNCTOR(varlist[0])=='y')
               { x = getnewvar(*t,"x");
                 swapvars(0,1);
               }
            else
               x = getnewvar(*t,"y");
            if(f == '<')
              /* example, x < 5  gets enhanced to x < y < 5 */
               *t = and(lessthan(ARG(0,*t),x),lessthan(x,ARG(1,*t)));
            else if(f == LE)
               *t = and(le(ARG(0,*t),x),le(x,ARG(1,*t)));
            else if(f == '>')
               *t = and(lessthan(ARG(1,*t),x),lessthan(x,ARG(0,*t)));
            else if(f == GE)
               *t = and(le(ARG(1,*t),x),le(x,ARG(1,*t)));
          }
       return;
     }
  if(problemtype == MINMAX )
     { term interval;
       x = varlist[0];
       if(f != AND || (f == AND && equals(ARG(1,*t),trueterm)))
          { permcopy(and(lessthan(minusinfinity,x),lessthan(x,infinity)),&interval);
            if(f == AND)
               *t = ARG(0,*t);  
            set_minmax_interval(interval);
            return;
          }
       if(f == AND)  /* interval has been specified */
          { term the_interval = ARG(1,*t);
            term interval;
            assert(ARITY(*t) == 2);
            if(FUNCTOR(interval) == AND)
                assert(interval_as_and(interval));
            switch(FUNCTOR(the_interval))  /* reverse > and >= */
               { case '>' :  the_interval = lessthan(ARG(1,the_interval),ARG(0,the_interval));
                             break;
                 case GE  :  the_interval = le(ARG(1,the_interval),ARG(0,the_interval));
                             break;
               }
            permcopy(the_interval,&interval);
            set_minmax_interval(interval); /* sets it in pDocData->DocControlData */
            /*  assume(interval);  NOT YET; this will be done in check_problem in chkprob.c */
            *t = ARG(0,*t);  /* delete the interval now that it is stored */
            f = FUNCTOR(*t);
            if(f == '=')
               return;
            else
               { *t=equation( (FUNCTOR(varlist[0])=='y' ? getnewatom() : make_atom_from_string("y")), *t);
                 let_aux(ARG(0,*t),varlist[0],0);
               }
            return;
         }
     }
  if(problemtype == RELATED_RATES)
     return;
  if(problemtype == IMPLICIT_DIFF)
     { if(FUNCTOR(*t) == AND)
         { // *t is and(equation, dy/dx)  from the PHP entry page
           // From the Problem Library, only the equation is passed;
           // the independent variable is always 'x' and the dependent var is 'y'.
           y = ARG(0,ARG(1,*t));
           x = ARG(1,ARG(1,*t));
           // make x the independent variable and y the dependent variable
           int i = get_index(x);
           swapvars(i,0);  // put x in varlist[0]
           i = get_index(y);
           swapvars(i,1);  // put y in varlist[1];
           *t = ARG(0,*t);  // discard dy/dx from the problem
         }
       return;
     }
  if( GRAPHTYPE(problemtype) &&
      (f==AND && ! interval_as_and(*t))
    )
     /* a system, or maybe a term and a parameter interval */
     { if(graph_interval(*t))
          return;
       char * default_dependent_var = "y";
       if(problemtype == POLAR_GRAPH)
          default_dependent_var = "r";
        if(problemtype == PARAMETRIC_GRAPH)
           default_dependent_var = "t";
        
        if(!contains(*t,default_dependent_var[0]))
           savey =  make_atom_from_string(default_dependent_var);
       else
          savey = getnewatom();
       vaux(savey);
       for(i=0;i<ARITY(*t);i++)
          if(FUNCTOR(ARG(i,*t)) != '='
             && ! graph_interval(ARG(i,*t))
             && FUNCTOR(ARG(i,*t)) != '<'
             && FUNCTOR(ARG(i,*t)) != LE
            )
              ARGREP(*t,i,equation(savey,ARG(i,*t)));
          // enhance_problem(ARGPTR(*t) + i,currenttopic, problemtype);
       return;
     }
     /* from now on, we're not dealing with a system */
  if(GRAPHTYPE(problemtype) && INEQUALITY(f) && is_graph_inequality(*t))
     return;
  if(  problemtype == SOLVE_EQUATION ||
       problemtype == LINEAR_EQUATION ||
       problemtype == LINEAR_EQUATIONS ||
       problemtype == GRAPH_RELATION ||
       problemtype == TRIG_IDENTITY
    )   /* then assume when a non-equation t is entered that t=0 is meant */
     { if(FUNCTOR(*t) == '='  || FUNCTOR(*t) == AND)
          return;  /* do nothing to equalities */
       else   /* change t to 't=0' */
          { *t = equation(*t,zero);
            return;
          }
     }
  if(currenttopic == _logarithmic_differentiation)
     { term p;
       int eigen = get_eigenindex();
       if(FUNCTOR(*t) == '=')
          { if(ISATOM(ARG(0,*t)))
               { permcopy(ARG(1,*t),&p);
                 let(ARG(0,*t),p);
                 set_eigenvariable(eigen);  /* let has changed it */
                 SETDEPENDENT(ARG(0,*t));
               }
            return;
          }
       if(!contains(*t,'y'))
          savey = make_atom_from_string("y");
       else
          savey = getnewatom();
       permcopy(*t,&p);
       let(savey,p);
       set_eigenvariable(eigen);  /* let changed it */
       SETDEPENDENT(savey);
       *t = equation(savey, *t);
       for(i=0;i<nvariables;i++)
          { if(FUNCTOR(varlist[i])==FUNCTOR(ARG(0,*t)))
               { /*  we're doing the second or more arg of a system, e.g.
                     under problemtype compare graphs */
                  break;
               }
          }
       if(i==nvariables)
          { let_aux(ARG(0,*t),varlist[0],0);
            nvariables = get_nvariables();
            if(nvariables > 2)  /* there are some parameters; they must come
                                 AFTER the new variable */
                swapvars(nvariables-1,1);
          }
       return;
     }
  if( problemtype == DIFFERENTIATE ||
      problemtype == DIFFERENTIATE_FROM_DEFN
    )
     { if(nvariables == 0)
          { // differentiating a constant, so invent a variable
            getnewvar(one,"x");
            nvariables = 1; 
            varlist = get_varlist();
          }

       if(FUNCTOR(*t) == '=')
          { term x= varlist[0];
            *t = equation(dif_aux(ARG(0,*t),x),dif_aux(ARG(1,*t),x));
          }
       else
          *t = dif_aux(*t,varlist[0]);  /* inquire_independent_variable has
                               already been called if necessary to make
                               sure varlist[0] is the independent variable */
       return;
     }

/* in ordinary graphs, an expression f(x)  becomes y = f(x) */
  if(  (problemtype == ORDINARY_GRAPH  ||
        problemtype == COMPARE_GRAPHS
       ) &&
       FUNCTOR(*t) != '='
    )
     { if(FUNCTOR(savey) == ILLEGAL)
        { if(!contains(*t,'y'))
             savey = make_atom_from_string("y");
          else
             savey = getnewatom();
        }
     *t = equation(savey, *t);
     for(i=0;i<nvariables;i++)
        { if(FUNCTOR(varlist[i])==FUNCTOR(ARG(0,*t)))
             { /*  we're doing the second or more arg of a system, e.g.
                   under problemtype compare graphs */
                break;
             }
        }
     if(i==nvariables)
        { let_aux(ARG(0,*t),varlist[0],0);
          nvariables = get_nvariables();
          term *varlist = get_varlist();
          if(nvariables > 2)  /* there are some parameters; they must come
                               AFTER the new variable */
             { swapvars(nvariables-1,1);
               // Now a  = varlist[nvariables-1], the former varlist[1],
               // got its valuepointer changed, but the a occurring in
               // *t did not get its valuepointer changed.
               term a = varlist[nvariables-1];
               term temp;
               subst(a,a,*t,&temp);
               // This substitution looks like it does nothing, but the first "a"
               // has the correct value pointer, so it does the necessary thing.
               *t = temp;
             }
        }
     return;
   }
if(  (problemtype == NONPARAMETRIC_SURFACE || problemtype == POLAR_NONPARAMETRIC_SURFACE)
     &&
     FUNCTOR(*t) != '='
  )
   { *t = equation( contains(*t,'z') ? getnewatom() : make_atom_from_string("z"), *t);
     let_aux(ARG(0,*t),varlist[0],0);
     nvariables = get_nvariables();
     if(nvariables > 3)  /* there are some parameters; they must come
                               AFTER the new variable */
     swapvars(nvariables-1,2);
     return;
   }
if( problemtype == POLAR_GRAPH && FUNCTOR(*t) != '=' )
   { *t = equation(FUNCTOR(varlist[0]) == 'r' ? getnewatom() : make_atom_from_string("r"), *t);
      let_aux(ARG(0,*t),varlist[0],0);
      nvariables = get_nvariables();
      if(nvariables > 2)
         swapvars(nvariables-1,1);
     return;
   }
}
/*_________________________________________________________________*/

static term getnewatom(void)
/* make a new atom different from any in the varlist */

{ int i,j;
  char s[18];
  term ans;
  int nvariables = get_nvariables();
  term *varlist = get_varlist();
  char *v[10] = {"x","y","u","v","w","z","p","q","t","s"};
  for(i=0;i<10;i++)
   { for(j=0;j<nvariables;j++)
        { if(FUNCTOR(varlist[j]) == v[i][0])
             break;
        }
     if(j==nvariables)
        { ans = make_atom_from_string(v[i]);
          return ans;
        }
   }
 /* we could only get here if ALL those variables are in varlist */
 s[0] =  'x';
 for(i=0;;i++)  /* construct x1, x2, x3, till we get one not in varlist */
   { sprintf(s+1,"%d",i);
     for(j=0;j<nvariables;j++)
        { if(!strcmp(atom_string(varlist[j]),s))
             break;
       }
     if( j == nvariables)
        { ans = make_atom_from_string(s);
          return ans;
        }
   }
}
/*_____________________________________________________________________*/
static int check_order(term t)
/* return 1 if all sums which are subterms of t are in ASCENDING order
            or indeterminate order and at least one of them is ASCENDING.
   return -1 if there are no sums contained in t, so can't say about orderflag.
   return -1 if t is the same in ascending and descending order, e.g. a^n-b^n.
   return -1 on a sum if we don't want to call t ASCENDING or DESCENDING,
             i.e. is of 'indeterminate' order.
             e.g. it contains two variables and doesn't contain
             a power, e.g. 1/x  + 1/y  (otherwise this example will come
             out in ASCENDING order, with x the eigenvariable)
   But  1-b^n counts as in ascending order because it begins with a constant.
   return 0 otherwise, i.e. if there are sums not in ascending order. */
{  int saveit = get_orderflag();
   unsigned short f = FUNCTOR(t);
   unsigned short n = ARITY(t);
   int problemtype;
   term temp,temp2,u,v;
   int i,r,rr,flag;
   if(ATOMIC(t))
      return -1;   /* can't tell */
   if(f=='+')
      { flag = 0;
        set_orderflag(ASCENDING);
        for(i=0;i<n;i++)
          { rr=check_order(ARG(i,t));
            if(rr == 0)  /* some arg not in ascending order */
               { set_orderflag(saveit);
                 return 0;         /* no need to go further */
               }
            if(rr == 1)
               flag = 1;     /* some arg definitely in ascending order */
          }
        /* all args were in ascending order or contained no sums */
        u = make_term('+',n);
        for(i=0;i<n;i++)
           { v = ARG(i,t);
             ARGREP(u,i,NEGATIVE(v) ? ARG(0,v) : v);
           }
        temp = additive_order(u);  /* while orderflag is ASCENDING */
        if(equals(temp,u))
            { if(flag || constant(ARG(0,t)))
                 { set_orderflag(saveit);
                   return 1;  /* 1-cos x is definitely in ascending order */
                 }
              /* But we have to trap cases like a^n-b^n which are the same in
                 ascending and descending order!  Whether there are any
                 of these when all signs are '+' as they must be at this
                 point, I'm not sure; perhaps this check is superfluous.  */

              set_orderflag(DESCENDING);
              temp2 = additive_order(u);
              if(equals(temp2,u))  /* same either way! */
                 { set_orderflag(saveit);
                   return -1;
                 }
              set_orderflag(saveit);
              problemtype = get_problemtype();
              if(get_nvariables() == 1 ||
                 SOLVETYPE(problemtype) ||
                 LIMITS <= problemtype
                )
                 return 1;   /* t is in ascending order */
              else
                 return -1;  /* don't-care order */
            }
        RELEASE(temp);   /* created by additive_order */
        set_orderflag(saveit);
        return 0;        /* t is a sum not in ascending order */
      }
   if(f != '+')
      { r= -1;
        for(i=0;i<n;i++)
           { rr = check_order(ARG(i,t));
             if(rr==0)  /* some arg contains a sum not in ascending order */
                { set_orderflag(saveit);
                  return 0;
                }
             if(rr==1)  /* this arg contains a sum in ascending order */
                r=1;
           }
        set_orderflag(saveit);
        return r;  /* at least one sum encountered, and all sums encountered
                     were in ascending order */
      }
  assert(0);
  return 0;
}
 /*__________________________________________________________*/
int eqns_adjustvarlist(term t)
  /* Identify the parameters e.g. if an equation ax + y =1 has been entered */
  /* Return 0 for success, 1 if the input is unacceptable. */
{ int cntbound = 0; /* number of bound variables */
  term vlist;
  int i,n;
  int err; /* nonzero means we must ask the user about parameters */
           /* theoretically a coefficient could involve a bound variable! */
  int nvariables = get_nvariables();
  varinf *varinfo = get_varinfo();
  term *varlist = get_varlist();
  for(i=0;i<nvariables;i++)  /* count the bound variables */
     { if(varinfo[i].scope == BOUND)
          ++cntbound;
     }
  n = nvariables-cntbound; /* number of variables */
         /* first we sort the non-bound variables alphabetically,
            as lineupvars expects that to have been done; note that
            setup_varlist has put the non-bound variables first */
  sortatoms(varlist,n);
  err = is_linear_system(t,0,&vlist);
  if(!err)
     { RELEASE(vlist);  /* allocated by is_linear_system */
       return 0;
     }
  /* it's not linear */
  errbuf(0,english(615));
  /* Not linear. You cannot solve nonlinear systems with MathXpert. */
  errbuf(1,english(1864));
  /* Try again, choosing letters in the last half of the alphabet for your variables, */
  errbuf(2,english(1865));
  /* and letters in first half (or Greek letters) for your constants. */
  return 1;
}
/*_______________________________________________________________________*/
static void erasecolors(term *t)
/* erase the color info in all subterms of *t */
/* duplicate of function in gsub.c but it's short and makes this file
   not depend on exec.c, for efficiency in overlays. */
{ unsigned short i,n;
  if(COLOR(*t))   /* don't try to erase the color bit unless it's set, because
                     if you try SETCOLOR on one of the constant integers, it
                     causes an access violation in Win32 */
     SETCOLOR(*t,0);
  if(!ATOMIC(*t))
     { n = ARITY(*t);
       for(i=0;i<n;i++)
          erasecolors(ARGPTR(*t) + i);
     }
}

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