Sindbad~EG File Manager

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

/* M. Beeson, for Mathpert.
Functions called by the GetProblem dialog that are interface-independent.

10.25.90  original date
11.13.99 last modified
5.3.00 added if(i!=0) at line 234
6.17.04 modified set_complex_types and initialize_complex  \
9.4.07 modified initialize_complex
10.21.10 made setup_and_check NOT call enhance_problem on IMPLICIT_DIFF problems.
12.16.10 modified setup_parameters to change dependencies on IMPLICIT_DIFF problems,
         and made setup_parameters an exported function so it can be called from wgetprob.c
         and moved the call to setup_parameters at the end of setup_and_check up, so it's not called on IMPLICIT_DIFF problems,
         since it needs to be called from process_ok in wgetprob.c.
5.20.13  removed getprob.h and wfile.h as now they are included by mpdoc.h
        added third argument 1.0 to all calls to initialize_parameter
6.7.13 removed windows.h, no longer needed
12.12.23  replaced oem_atom_string by atom_string
8.3.24 included stubs.h instead of interact.h
9.9.24  included HDE next to ODE in setup_and_check so invent_independent_variable will be called.
9.25.24  modified setup_parameters
10.7.24  made initialize_complex public and removed unused first argument
10.29.24 made setup_and_check call invent_new_independent_variable also
on ODE2
12.7.24  added set_real_types and called it in initialize_complex
12.9.24  corrected set_real_types to match its spec
12.9.24  added  code just at the end of  setup_and_check to
          set_factorflag(1) when problemtype is FACTOR
          [removed that mistaken code 1.22.25]
1.1.25  made final_adjustments take pDocData as its only arg.
1.19.25  commented out line 542 containing ODE
1.20.25  also for HDE
1.22.25  removed the set_factorflag(1) from 12.9.24
1.26.25 added clear_error_buffer and clear_comment_buffer in final_adjustments
1.27.25  made x,y, and t always get type R, not DCOMPLEX
*/
#include <assert.h>
#include <string.h>
#include <ctype.h>    /* tolower */
#include <search.h>   /* qsort   */
#include <stddef.h> 

#include "globals.h"  /* which includes setjmp.h and terms.h */
#include "graphstr.h"
#include "mpdoc.h"
#include "getprob.h"
#include "tdefn.h"
#include "prover.h"
#include "pcontrol.h"
#include "setup.h"
#include "display.h"
#include "display1.h"
#include "probtype.h"  /* possible values of problemtype */
#include "chkprob.h"   /* checkproblem */
#include "deriv.h"
#include "algaux.h"
#include "factor.h"  /* for ratpart2 */
#include "order.h"
#include "nextline.h" /* maxscope etc. */
#include "checkarg.h" /* automode.h needs it */
#include "automode.h" /* setlocus      */
#include "diff.h"     /* dif_aux */
#include "userfunc.h"
#include "cflags.h"   /* get_minmax_interval, get_controldata */
#include "dispfunc.h" /* atom_string */
#include "inqindep.h"
#include "chkinput.h"   /* input_check */
#include "docdata.h"   /* get_ndocuments */
#include "problem.h"

static void mark_dependencies(term *t);
static void set_default_parameters(void);
static void adjust_ringflag(void);
static int contains_fractional_exponent(term);
static int count_logs(term t);
/*_______________________________________________________*/
int setup_varlist(term t)
/* Not static because called in graph_button */
/* t is the problem as entered */
/* Presumes varlist and varinfo are already allocated.
   initialize the global arrays 'varlist' and 'varinfo',
   and the global variable 'nvariables'.
   Does not attempt to identify independent or dependent variable, just
   lists all atoms occurring in the problem (throwing out PI, e, and i )
   Always leaves at least two unused spaces in varlist for
   enhance_problem to use.  Also makes sure all bound variables come
   after all non-bound variables. But, when this is called, a variable
   of (indefinite) integration or differentiation hasn't been identified
   yet, so isn't BOUND or HALFBOUND; this is taken care of later by
   inquire_independent_variable, which puts this variable FIRST,
   not after the non-bound variables.
*/
{  int err;
   int i;
   int nvars;
   varinf* varinfo = get_varinfo();
   int problemtype = get_problemtype();
   if(problemtype == RELATED_RATES)
      /* The independent variable is literally "t".  You can't change it,
         and often the problem doesn't contain "t" explicitly, so we need
         to get it into varlist. */
      { term time = make_atom_from_string("t");
        vaux(time);
      }
   err = vaux(t);
     /* this puts all atoms in t into the varlist array, making space if needed */
     /* But some of those atoms may be only parameters */
     /* Now make sure all bound variables come after the unbound variables */
     /* and half-bound variables come first */
   if(err)
      return err;
   err = 0;
   nvars = get_nvariables();
   while (err==0)
      { for(i=0;i<nvars-1;i++)
           { if(
                (varinfo[i].scope == BOUND && varinfo[i+1].scope != BOUND)
                || (varinfo[i+1].scope == HALFBOUND && varinfo[i].scope != HALFBOUND)
               )
                { swapvars(i,i+1);
                  break;  /* out of the for-loop */
                }
           }
        err = 1;  /* leave the while-loop */
      }
   return 0;
}
/*_______________________________________________________________*/
void setup_parameters(PDOCDATA pDocData, term problem)
/*  When this is called, varlist has already been set up, and
the independent variable has been identified and confirm_problem
has succeeded, so the problem is in standard form.
Source is set to SOURCE_USER or SOURCE_MATHPERT.
Don't ask the user anything, just decide correctly which variables
are parameters.  [In Windows MathXpert, there was ask_user_about_parameters.
That's history now.]
   For problemtype LINEAR_EQUATIONS, just assume variables t or later in
the alphabet depend on the independent variable and those before do not.
   For differentiation and integration problems, by now the variable
of integration is in varlist[0];  all other variables should be parameters.

   Thus later on we can assume du/dx = 0 if u is a parameter.
   Parameters in graphing problems are initialized by setupdata,
NOT by this function, except for type POLYROOTS.
   When problemtype is one where we have to solve an equation or inequality,
this function enters every variable except varlist[0] as a parameter.
*/
{ int i,count,intflag;
  unsigned g;
  int nvariables = pDocData->DocVarData.nvariables;
  term *varlist = pDocData->DocVarData.varlist;
  varinf *varinfo = pDocData->DocVarData.varinfo;
  int problemtype;
  if(pDocData->kind == GRAPHDOC)
     problemtype = pDocData->graphproblemtype;
  else
     problemtype = pDocData->problemtype;
  int currenttopic = pDocData->currenttopic;
  if(nvariables <=1 )
     return;   /* only one variable in the problem */
  /* Possibly there is only one non-bound variable in addition to
     varlist[0] -- check for this case: */
  count = 0;
  for(i=1; i < nvariables; i++)  /* start from 1 so as not to count varlist[0] */
     { if (varinfo[i].scope != BOUND && varinfo[i].scope != EXISTENTIAL
                  /* an existential variable can be generated by domain,
                     e.g. when tan x is entered */
          )
          ++count;
     }
  if (count == 0)
     {   
       return;   /* no extra variables */
     }

  /* count is the number of non-bound, non-existential variables
     other than varlist[0]  */
  if(problemtype == INTEGRATION)
     { // make all the non-bound variables parameters
       // e.g. if the integrand contains a derivative there will be a bound variable other than
       // the variable of integration
       for(i=1;i<nvariables;i++)
          {  if( varinfo[i].scope != BOUND)
               initialize_parameter(i,0,1.0);
          }
       return;  // done!
     }
  intflag  = contains(problem,INTEGRAL);
  if(problemtype == RELATED_RATES ||
     problemtype == MINMAX ||
     problemtype == IMPLICIT_DIFF || 
     contains(problem,DIFF) ||
     intflag
    )
      { if( count == 1 &&
            (problemtype == IMPLICIT_DIFF ||
             problemtype == RELATED_RATES ||
             problemtype == MINMAX ||
             currenttopic == _higher_order_diff
            )
          )
          /* then don't ask; just assume the other variable is dependent */
           {
             varinfo[1].dp |= 1;   /* set bit 0, telling that varlist[1] depends on varlist[0] */
             SETDEPENDENT(varlist[1]);  /* so depends doesn't fail immediately */
           }
        else  // whatever the problem source!
           { for(i=1; i < nvariables; i++)  /* start from 1 so as not to count varlist[0] */
                { g = FUNCTOR(varlist[i]);
                  if(PREDEFINED_ATOM(g))
                     { initialize_parameter(i,0, 1.0);  /* Greek letters are parameters
                                   unless they're the independent variable */
                       continue;
                     }
                  if('A' <= g && g <= 'Z')
                     g = tolower(g);
                  if( varinfo[i].scope == BOUND ||
                      /* This means that in a definite integral problem,
                         all other variables will be considered
                         independent of the variable of integration.
                         Example: integral(f(t),t,0,x), x is independent
                         of t; also in integral(f(t,x),t,0,1).  Also in
                         limit problems.
                      */
                      (varinfo[i].scope != BOUND &&
                       varinfo[i].scope != EXISTENTIAL &&
                       ( g < 't' || intflag)
                       /* Thus 'y' occurring in an integral with
                          respect to x will be treated as constant,
                          but 'y' occurring in a derivative with
                          respect to x will NOT be assumed constant. */
                      )
                    )
                     initialize_parameter(i,0, 1.0);
                  else
                     { varinfo[i].dp |= 1;
                       SETDEPENDENT(varlist[i]);
                     }
                }
              mark_dependencies(&problem);
              return;
            }
     
        mark_dependencies(&problem);
      }
  if(solvetype(problemtype))
     { for(i=1;i<nvariables;i++)
          { initialize_parameter(i,0, 1.0);
          }
     }
}

/*______________________________________________________________*/
static void set_default_parameters(void)
/* make n,m,j,k occurring unbound into parameters, unless there is
no OTHER variable.  Rearrange variables in varlist so that
varlist[0] is not a parameter, because it will be taken as the
eigenvariable and hence the independent variable for a graph when the
graph button is used.  */
{ int i;
  term *varlist = get_varlist();
  int nvariables = get_nvariables();
  varinf *varinfo = get_varinfo();
  unsigned a;
  /* is there a variable other than n,m,k,j ? */
  for(i=0;i<nvariables;i++)
     { a = tolower(FUNCTOR(varlist[i]));
       if( a != 'n' && a != 'm' && a != 'k' && a != 'j')
           break;
     }
  if(i==nvariables)
    return;  /* doing nothing */
  if(i != 0)
     swapvars(0,i);
  for(i=1;i<nvariables;i++)
     { a = tolower(FUNCTOR(varlist[i]));
       if(a=='n' || a == 'm' || a == 'k' || a == 'j')
           { if(varinfo[i].scope != BOUND &&
                varinfo[i].scope != HALFBOUND
               )
                initialize_parameter(i,0, 1.0);
           }
     }
}
/*_________________________________________________________*/
static void mark_dependencies(term *t)
/* go through *t and call SETDEPENDENT on every atom which
has its DEPENDS bit set in varlist */

{ unsigned short i, n = ARITY(*t);
  int nvariables = get_nvariables();
  term *varlist = get_varlist();
  if(OBJECT(*t))
     return;
  if(equals(*t,complexi) ||
     equals(*t,eulere) ||
     equals(*t,pi_term) ||
     equals(*t,infinity) ||
     equals(*t,left) ||
     equals(*t,right) ||
     equals(*t,undefined) ||
     equals(*t,bounded_oscillations) ||
     equals(*t,unbounded_oscillations)
    )
     return;  /* even if i is an index variable of a sum it doesn't depend on anything */
  if(ISATOM(*t))
     { for(i=0;i<nvariables;i++)
          { if(equals(varlist[i],*t))
               { if(DEPENDENT(varlist[i]))
                      SETDEPENDENT(*t);
                 break;
               }
          }
       assert(i<nvariables);  /* you must find every non-constant atom in varlist */
       return;
     }
  for(i=0;i<n;i++)
     mark_dependencies(ARGPTR(*t)+i);
}
/*__________________________________________________________________*/
static void determine_radicalflag(term problem)
/*  radicalflag = 1 means eliminate fractional exponents;
                = -1 means convert roots to fractional exponents
                = 0 means tolerate both.
                = -2 means tolerate \sqrt x standing alone, but eliminate
                    them in products which contain powers of x,
                    and eliminate all non-square roots.

radicalflag is set by set_control_flags for special problemtypes.
If it's still zero when this function is called, it is to be adjusted
depending on the problem.  If there are fractional exponents already
in the problem, then any roots should also be converted to fractional
exponents.
   This function also sets logcollectflag.
*/

{ controldata p;
  get_controldata(&p);
  if(p.radicalflag < 0)
     set_polyvalfractexpflag(1);
  if(p.radicalflag != 1  &&  p.radicalflag != -1  &&
                 /* don't change a pre-set  value  of 1 or -1,
                 but DO adjust pre-set value of -2 as in calculus,
                 else we can't get d/dx(\sqrt x - x^(1/2)) done right */
     contains_fractional_exponent(problem)
    )
     { p.radicalflag = -1;
       set_polyvalfractexpflag(1);
     }
  /* are we expanding or collecting logs?  */
  if(get_currenttopic() == _logarithms)
     p.logcollectflag = count_logs(problem) > 1 ? 1 : 0;
  else
     p.logcollectflag = (SOLVETYPE(get_problemtype())) ? 1 : 0;
  set_controldata(&p);
}
/*____________________________________________________________*/
void set_real_types(term *t)
/* set the types of all atoms in *t which are of type DCOMPLEX to R */
/* Don't touch atoms of type NATNUM or other types */
/* Used by initialize_complex */
{ unsigned short i, n = ARITY(*t);
  if(ISATOM(*t) && FUNCTOR(*t) == 'i')
     { SETTYPE(*t,INTEGER);
       vaux(*t);
       return;
     }
  if(ISATOM(*t) && TYPE(*t) == DCOMPLEX)
     { SETTYPE(*t,R);
       return;
     }
  if(OBJECT(*t))
     return;
  for(i=0;i<n;i++)
     set_real_types(ARGPTR(*t) + i);
}
/*____________________________________________________________*/
void set_complex_types(term *t)
/* set the types of all atoms in *t which are
      --of type R
      --have functor other than r, theta,e,pi_term,i.
   Don't forget to set the type of 'i' itself to that of complexi */
/* Used by initialize_complex */
{ unsigned short i, n = ARITY(*t);
  unsigned short f = FUNCTOR(*t);
  if(ISATOM(*t))
     { if(f == 'i')
          SETTYPE(*t, TYPE(complexi));
       if(TYPE(*t) == R && f != PI_ATOM && f != 'e' && f != THETA && f != 'r' && f != 'R')
          SETTYPE(*t,DCOMPLEX);
       return;
     }
  if(OBJECT(*t))
     return; 
  for(i=0;i<n;i++)
     set_complex_types(ARGPTR(*t) + i);
}

/*____________________________________________________________*/
void initialize_complex( int currenttopic,term *t)
/* set value of 'complex' appropriately, where *t is the problem to solve */
/* But don't set arithflag.complex; this is done in init_model and we DO
   want arithflag.complex to remain zero even when complex is on, e.g.
   for de Moivre problems.  Complex arithmetic takes big steps.
*/
{ int i;
  aflag arithflag = get_arithflag();
  int problemtype = get_problemtype();
  unsigned short f;
  int nvariables = get_nvariables();
  varinf *varinfo = get_varinfo();
  term *varlist = get_varlist();
  if( 
      problemtype == COMPLEX_NUMBERS
      || COMPLEXTOPIC(currenttopic)
      || (!GRAPH_TOPIC(currenttopic) &&
          contains(*t,'i') &&
          !contains_bound(*t,'i') /* can't use 'iscomplex' here because the
                                   type bits of 'i' in *t aren't set yet */
         )
    )
      {
        set_complex(1);
         /* But, varlist may be set up with all variables real or integer */
         /* All non-integer variables will be complex now except r and theta,
         */
        for(i=0;i<nvariables;i++)
           { f = FUNCTOR(varlist[i]);
             if(varinfo[i].type == R && 
                f!= 'r' && f != 'R' && f != THETA &&
                f!= 'x' && f != 'y' && f != 't'
               )
                { varinfo[i].type = DCOMPLEX;
                  SETTYPE(varlist[i],DCOMPLEX);
                }
           }
        set_complex_types(t);  /* Not enough to set them in varlist only */
        set_complex(1);
      }
  else
     { set_complex(0);
       arithflag.complex = 0;
       set_arithflag(arithflag);
       /* varlist is set up with all variables DCOMPLEX,
          so they need changing  */
        for(i=0;i<nvariables;i++)
           { f = FUNCTOR(varlist[i]);
             if(f == 'i')
                { varinfo[i].type = INTEGER;
                  SETTYPE(varlist[i],INTEGER);
                }
             if(varinfo[i].type == DCOMPLEX  || TYPE(varlist[i]) == DCOMPLEX)
                { varinfo[i].type = R;
                  SETTYPE(varlist[i],R);
                }
           }
        set_real_types(t);  /* Not enough to set them in varlist only */
        set_complex(0);
     }
  adjust_ringflag();
  set_complex_frozen(1);
}
/*___________________________________________________________________*/
static void adjust_ringflag(void)
 /* Now set the bit of 'ringflag' that determines whether complex factors
     are desired, to keep it in sync with 'complex' */
{ int ringflag = get_ringflag();
  if(get_complex())
       ringflag |= GAUSSINT;
  else  /* set the bit of ringflag to zero where GAUSSINT has a 1 */
       ringflag &= (0xffff^GAUSSINT);
  set_ringflag(ringflag);
}
/*___________________________________________________________________*/
static int count_logs(term t)
/* return the number of occurrences of LN, LOG, or LOGB in t */
{ unsigned short i,f,n;
  int ans;
  if(ATOMIC(t))
     return 0;
  f = FUNCTOR(t);
  if(f == LN || f == LOG)
     return 1 + count_logs(ARG(0,t));
  if(f == LOGB)
     return 1 + count_logs(ARG(1,t));
  n = ARITY(t);
  ans = 0;
  for(i=0;i<n;i++)
     ans += count_logs(ARG(i,t));
  return ans;
}
/*______________________________________________________________________*/
int setup_and_check(PDOCDATA pDocData)
/* sets up varlist, parameters, independent variable,
value pointers, radicalflag, and calls input_check.
Returns 0 for success, nonzero if input_check fails or user
cancels out of naming the independent variable.  The error
value returned can be used to recover an error message via
input_error_message(err).
  At input, pDocData->problemsource is SOURCE_USER or SOURCE_MATHPERT
Don't  ask the user about the independent variables or parameters
[as Windows MathXpert did], but just make assumptions.
*/

{ int err;
  int problemtype = pDocData->problemtype;
  int graphproblemtype = pDocData->graphproblemtype;
  int currenttopic = pDocData->currenttopic;
  int nvariables;
  varinf *varinfo;
  term *varlist;
  term problem = pDocData-> function;
  activate(pDocData);  // setup_varlist needs get_varlist(), etc. to work 
  err = setup_varlist(problem);  /* lists all atoms in the problem under varlist */
              /* in the order encountered in the problem, except that bound
                 variables are put after all other kinds and halfbound
                 variables are put first.  Does not set 'eigenvariable' */
  if(err)
     return err;
  nvariables = get_nvariables();
  varlist = get_varlist();
  varinfo = get_varinfo();
  if(SOLVETYPE(problemtype) || problemtype >= LIMITS)
      /* make n,m,j,k occurring unbound into parameters,
         but not on factoring or simplification problems, where it
         makes them be treated as constants and hence put first in
         multiplicative order, so e.g.  am becomes ma, and in
         factoring by grouping there can be four successive such steps,
         which looks silly.
      */
      set_default_parameters();
  if(problemtype==DIFFERENTIATE && nvariables == 0)
      invent_new_independent_variable(problem,problemtype);
  else if(problemtype==INTEGRATION && FUNCTOR(problem)==AND)
     /* integrand, lo, hi */
     { if(ARITY(problem) != 3)
          return 80;
       err = inquire_independent_variable(pDocData,problem);
       if(err)
          return err;
       // inquire_independent_variable puts the independent variable in varlist[0].
       set_eigenvariable(0);
       varinfo[0].scope = BOUND;  /* it has been set to HALFBOUND */
       problem = definite_integral(ARG(0, problem),varlist[0],ARG(1, problem),ARG(2, problem));
       /* we can't wait for enhance_problem to do this below, because
          input_check needs to see a definite integral to check that the
          variable of integration can't appear in the limits. */
       pDocData->function = problem;
     }
  else if (
           ( nvariables == 1 &&
             (graphproblemtype == ODE || graphproblemtype == HDE)
           )
          ||
          ( nvariables == 2 && graphproblemtype == ODE2)
         )
      invent_new_independent_variable(problem,problemtype);
  else if(
           (nvariables > 1 || GRAPHTYPE(problemtype))
           && problemtype != IMPLICIT_DIFF
           && pDocData->graphproblemtype != ODE2  // where user must enter the independent variable in the parameter interval
           
        //   && pDocData->graphproblemtype != ODE
        //   && pDocData->graphproblemtype != HDE
        //   In Windows MathXpert, the user had to enter the independent variable on ODE problems
        //   but not in Web MathXpert, which is supposed to figure it out.
        
           && pDocData->graphproblemtype != ODESYSTEM
          
         )
  /* if there's only one variable in a symbolic problem,
     it is the independent one.  But this is not true in
     graph problems, e.g. y = 5 or y'= y */
     { err = inquire_independent_variable(pDocData, problem);  /* if necessary */
               /* can only return nonzero err if user presses Esc, refusing to
                  give the independent variable and wants to "start over" */
       if(err)
          return -1;
       set_eigenvariable(0);
     }
  if(problemtype == RIEMANN_SUMS ||
     problemtype == SIMPSONS_RULE ||
     problemtype == TRAPEZOID_RULE
    )
     { /* input_check will call deval, which won't work on pi without
          the following; but for other problemtypes we want to wait
          until after enhance_problem */
       set_valuepointers(&pDocData->function);
     }
  if(problemtype == MINMAX && FUNCTOR( problem) == AND)
     set_valuepointers(ARGPTR(problem)+1);  /* so deval will work on pi */
  if(GRAPHTYPE(problemtype))
     { if(FUNCTOR(problem) == OR  && ARITY(problem) == 2)
          /* range inequalities in the second argument */
          { term function = ARG(0, problem);
            err = input_check(function);
               /* watch out for 'y=2 | 0<= x <= 1.  At this point 
               y is the eigenvariable, so input_check will fail because
               the independent variable is on the left. */
            if(err == 83 &&
               FUNCTOR(function) == '=' && ISATOM(ARG(0,function)) &&
               equals(ARG(0,function),get_eigenvariable()) 
              )
               err = 0;
            if(err)
               return err;
            enhance_problem(ARGPTR(problem), currenttopic, problemtype);
            /* change f to diff(f,x) etc. and set varinfo correctly */
          }
       else
          { err = input_check(problem);
            if(err)
               return err;
            enhance_problem(&pDocData->function, currenttopic, problemtype);
            /* change f to diff(f,x) etc. and set varinfo correctly */
          }
       initialize_complex(currenttopic,&pDocData->function);
       set_valuepointers(&pDocData->function);
       determine_radicalflag(pDocData->function);
       /* init_params will be called from setupdata for graph problems */
       return 0;
     }
  /* Now it's a symbolic problemtype */
  initialize_complex( currenttopic,&pDocData-> function);
     /* set value of 'complex' appropriately and change types of variables */
                            /* does nothing if complex_frozen is set */
  if(is_complex(pDocData->function))
      { // adjust the topic,
         switch(pDocData->DocControlData.currenttopic)
            { case _factor_quadratics:
                  pDocData->DocControlData.currenttopic = _advanced_factoring;
                 break;
              case _solve_equation:
                  pDocData->DocControlData.currenttopic = _complex_roots;
                 break;
              default:
                 break;
            }
      }
  err = input_check(problem);
  if(err)
     return err;
  if(problemtype == IMPLICIT_DIFF && pDocData->problemsource == SOURCE_MATHPERT)
     {  default_independent_variable(0,NULL,1);
       
        enhance_problem(&pDocData->function,_implicit_diff,IMPLICIT_DIFF);
        setup_parameters(pDocData, problem);
        set_valuepointers(&pDocData-> function);
     }
  else
     { set_valuepointers(&pDocData-> function);  /* BEFORE enhance_problem because in at
             least one topic, enhance_problem calls 'let' and we need the value
              pointers to be set in the stored definition. */
       enhance_problem(&pDocData-> function,currenttopic,problemtype);
       set_valuepointers(&pDocData-> function);  /* again AFTER enhance_problem to include the new
                                    variables introduced by enhance_problem */
       setup_parameters(pDocData,problem);
     }
  determine_radicalflag(problem);   /* should fractional exponents be created,
                                 eliminated, or what?  Also sets logcollectflag. */
  deactivate(pDocData);   // local variables copied into document.
  activate(pDocData);     //  but leave the document active
  return 0;
}

/*___________________________________________________________________________*/
int final_adjustments(PDOCDATA pDocData)
/* problem is the problem as entered by the user or in the problem file.
On certain problemtypes, part of what is entered is stored elsewhere,
rather than becoming part of history[0].  This is done here. 
*/
{ int err;
  int problemtype = pDocData->problemtype;
  term problem = pDocData->function;
  err = checkproblem(problem, pDocData->problemtype, pDocData->DocControlData.currenttopic);
  if(err == 27)
    { SETIMPROPER(problem); /* an improper integral or series whose
                               convergence is to be tested */
      err = 0;
    }
  if(err)
     return err;
  if(problemtype == MINMAX && FUNCTOR(problem) == AND)
     set_history(0,ARG(0,problem));
  else
     set_history(0,problem);
            /* actual_condition, which is called by check if there are
               bound variables in problem, needs history[0] to contain
               problem; this is why we can't wait till after get_problem
               to stash the problem in history[0].  */
  clear_error_buffer();  // prevent a mysterious message appearing when the
                         // problem first loads, as for example
                         // "That only works on polynomials in one variable"
                         // which can be generated while analyzing the domain.
  clear_comment_buffer();
  return 0;
}
/*_______________________________________________________________*/
int solvetype(int ptype)
/* given the value of problemtype, determine if it is a type
that requires solving an equation or inequality; this info will be
used to make all other letters than varlist[0] into parameters.
This does not include the types included in macro SOLVETYPE
under which we solve for a derivative subterm.
*/
{  switch(ptype)
     {  case LINEAR_EQUATION: return 1;
        case SOLVE_EQUATION:  return 1;
        case INEQUALITIES:    return 1;
        case POLYROOTS:       return 1;
        case ABSOLUTE_VALUE:  return 1;
     }
   return 0;
}
/*_______________________________________________________________*/
static int contains_fractional_exponent(term t)
/* count the number of fractional exponents in t.
Does count x^(4/2) as a fractional exponent, also x^(x/2).
Does not count e^(7/6) pi i  as a fractional exponent;
in general if the base is e and the power is complex it
doesn'tcount it.
*/
{  unsigned short i,n;
   int ct=0;
   term power,s;
   if(ATOMIC(t))
      return 0;
   if(FUNCTOR(t) == '^')
      { power = ARG(1,t);
        if(ATOMIC(power))
           return 0;   /* trap this common case  */
        if(FRACTION(power))
           return 1;
        if(equals(ARG(0,t),eulere) && iscomplex(ARG(1,t)))
           return 0;  /* see specs above */
        if(FUNCTOR(power)=='*')
           { n = ARITY(power);
             for(i=0;i<n;i++)
                { s = ARG(i,power);
                  if(NEGATIVE(s))
                     s = ARG(0,s);
                  if(FRACTION(s))
                     return 1;
                }
             return 0;
           }
        return 0;
      }
   n = ARITY(t);
   for(i=0;i<n;i++)
      { ct += contains_fractional_exponent(ARG(i,t));
      }
   return ct;
}



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