Sindbad~EG File Manager

Current Path : /usr/home/beeson/Otter-Lambda/yyy/automode/
Upload File :
Current File : /usr/home/beeson/Otter-Lambda/yyy/automode/fremark.c

/* M. Beeson, for Mathpert */
/* final_remark */
/*
10.5.90 original date
1.14.99 modified
1.15.00 added 2396
2.28.00 added series_fremark call
1.25.06  modified for MINMAX
*/

#define AUTOMODE_DLL
#include <assert.h>
#include "globals.h"
#include "graphstr.h"
#include "display.h"
#include "document.h"
#include "tdefn.h"
#include "probtype.h"
#include "cflags.h"
#include "trig.h"     /* checknumerically */
#include "eqn.h"      /* solved           */
#include "order.h"    /* mvpoly           */
#include "factor.h"   /* factored         */
#include "automode.h" /* lookupop         */
#include "algaux.h"   /* contains_monomially */
#include "ops.h"
#include "calc.h"
#include "optable.h"  /* access_optable   */
#include "prover.h"   /* interval_as_and  */
#include "symbols.h"  /* get_checksolutionsflag */
#include "pvalaux.h"  /* complex_number */
#include "fremark.h"
#include "cancel.h"
#include "complex.h"  /* is_polar_complex */
#include "autosum.h"  /* contains_arctrigs */
#include "deval.h"    /* seminumerical     */
#include "mpminmax.h" /* used2, TABULATE, etc. */
#include "series.h"   /* used4, DIVERGENCETEST, etc. */
#include "domain.h"   /* contains_defined_variables */
#include "polynoms.h" /* ispolyin         */
#include "scontrol.h" /* series_fremark */

static int solved_system(term p);
static int needs_commondenom(term t);
static int contains_cf(term t);
static int contains_ratexp(term t);
static int needs_expand(term t);
static int noderivs(term t);
static int needs_negexp(term t);
static int contains_negexp(term t);
static int trivial_op(operation);
static int contains_trigproduct(term t);
static int linear_in_series(term t);
/*___________________________________________________________________*/
MEXPORT_AUTOMODE const char * final_remark(int *flag, operation *plan)
/* get the string to write after Finished is pressed,
or after AutoFinish completes.  At entrance, *flag is
0, 1, or 2.  It is 0 if automode will do nothing more,
1 if automode will take 1 step more, 2 if automode will
take 2 or more additional steps.
   Determine whether the problem is acceptably finished,
and if so put *flag = 1 (if you want it to say "Finished),
or *flag = 3 (it will say "OK"), or put *flag = 0 (it will
say "Not yet". In any
case return the remark that the user should see.
   Note that the answer may be acceptable even if automode
would do more; and conversely, automode may find nothing
to do even if it hasn't yet solved the problem.
   If *flag is nonzero at input, then plan contains *flag
valid entries indicating what automode would do next.
This will be the case when the user has pressed the
Finished button.  When automode itself completes a problem,
*flag is zero at input.
*/

{ operation op;
  controldata q;
  int currentline = get_currentline();
  int currenttopic = get_currenttopic();
  term p = history(currentline);
  int problemtype,nsteps,i,err;
  unsigned short f = FUNCTOR(p);
  const char *ans;
  term x = get_eigenvariable();
  term u,v;
  get_controldata(&q);
  problemtype = q.problemtype;
  nsteps = *flag;  /* number of additional steps needed (0,1,2) */
  *flag = 0;  /* set it to 1 if the problem is solved */
  /* First we look for a reason to reject the proposed answer. */
  switch(problemtype)
     { case LINEAR_EQUATION:  /* fall through */
       case SOLVE_EQUATION:
          if(
              ( FUNCTOR(p) == '=' && equals(ARG(0,p),ARG(1,p))) ||
              equals(p,true)
            )
             { *flag = 1;
               if(get_checksolutionsflag())
                  return english(1728);
                  /* The equation appears to be an identity, but you have
                     taken some steps that could have introduced new solutions,
                     so you haven't proved that the original equation was an
                     identity.  This work is inconclusive.";
                  */
               return english(1688);
               /* Equation is an identity, true whenever both sides are defined." */
             }
          if(!solved(p,x))
             { if(nsteps == 1)
                  { /* check for the case  3 = x */
                    if(solved(equation(ARG(1,p),ARG(0,p)),x))
                       { *flag = 1;   /* accept this as finished */
                         return english(2224);
                         /* That equation is solved, but it is customary to put the
                            variable on the left side, so Mathpert would take one more step. */
                       }
                  }
               return nsteps ? english(1668): english(5);
               /* Not yet solved. */
               /* Too difficult.  You can still try numerical or graphical solution. */
             }
          if(
             (currenttopic == _complex_cubics || currenttopic == _cubic_one_root) &&
             FUNCTOR(p) == OR && ARITY(p) > 3
            )
             { return english(1879);
               /* There can be at most three roots of a cubic equation.
                  Simplify the expressions for the roots until some of them are identical. */
             }
          if(
             (currenttopic == _complex_cubics || currenttopic == _cubic_one_root) &&
                                  equals(p,false)
             )
             { return english(1878);
         /* The original cubic must have more than one real root.  In that case
                        complex solutions of the intermediate equations will be involved,
         which is beyond the scope of this topic.  Your intermediate equation
         has no real solutions, but of course the original cubic does have solutions. */
             }
          if(COMPLEXTOPIC(currenttopic))
             { /* answer must be in the form a + bi */
               if(FUNCTOR(p) == '=')
                  { if( iscomplex(ARG(1,p)) &&  !complexexpression(ARG(1,p)))
                       return english(2396);
                       /* Solution(s) should be reduced to the form a + bi */
                  }
               if(FUNCTOR(p) == OR)
                  { for(i=0;i<ARITY(p);i++)
                       { if(iscomplex(ARG(1,ARG(i,p))) && !complexexpression(ARG(1,ARG(i,p))))
                             return english(2396);
                             /* Solution(s) should be reduced to the form a + bi */
                       }
                  }
               if(currenttopic == _complex_trig)
                  { if(iscomplex(p) && !complexexpression(p))
                       { return english(2402);
                          /* The answer should be reduced to the form a + bi */
                       }
                  }

             }
          if(nsteps == 0)
             { *flag = 1;
               return english(7);  /* That's the answer */
             }
          if(contains(p,FALSEFUNCTOR) || contains(p,TRUEFUNCTOR))
             return nsteps == 1 ? english(1869) : english(1870);
             /* You have solved the equation, but Mathpert would take one more step. */
             /* You have solved the equation, but perhaps the answer should be simplified. */
          if(nsteps)
             { if(currenttopic == _solve_linear_eqn ||
                  currenttopic == _quadratic_formula ||
                  currenttopic == _alg1_quadratic_formula ||
                  currenttopic == _solve_quadratic_equation
                 )
                  return english(1882);
                  /* You have solved the equation, but the answer should be simplified. */
               else
                  return english(1870);
                  /* You have solved the equation, but perhaps the answer should be simplified. */
                                 }
          break;
       case ABSOLUTE_VALUE:  /* fall through */
       case INEQUALITIES:
                         if(interval_as_and(p) || INEQUALITY(f) || f == OR)
             err = !solved(p,x);
          else if(equals(p,true) || equals(p,false))
             err = 0;
          if(err)
             return nsteps? english(1668) : english(1551);
             /* Not yet solved. */
             /* Too difficult.  You can still try graphical solution. */

          if(nsteps)
             { if(DEPENDENT(x))
                  return english(1724);
                  /* This looks solved, but the variable is not the original one */
               else if( (void  *) access_optable(plan[0].men)[plan[0].choice-1] == (void  *) explicitdomain)
                  return english(1685);
                  /* Although this looks solved, you have included solutions
                     that are ruled out by current assumptions.  Use the
                     assumptions to eliminate or correct the solution. */
               else
                  return english(1725);
                  /* This is solved, but Mathpert would simplify the answer further. */
             }
          break;

       case INTEGRATION:
          if (FUNCTOR(p)== '=' ?
              contains(ARG(1,p),INTEGRAL) :
              contains(p,INTEGRAL)
             )
             { if(nsteps)
                  return english(1668); /* Not yet solved. */
               if(currenttopic == _simple_int)
                  return  english(1398);
                  /* Mathpert can't solve that problem without more advanced
                  techniques.  You entered it under Simple Integration, which
                  means Mathpert won't try integration by substitution or parts. */
               if(currenttopic == _int_by_substitution)
                  return english(1491);
                  /* Mathpert can't solve that problem without more advanced
                  techniques. You entered it under integration by substitution,
                  which means Mathpert won't try integration by parts. */
               return english(17);  /* That's the best Mathpert can do. */
             }
          /* Now the integral sign has been eliminated */
          if(contains(p,LIMIT))
             { /* an improper integral was reduced to a limit but the
                  limit hasn't been evaluated. */
               return english(17);
             }
          /* Don't okay it until all defined variables have been eliminated. */
          if(contains_defined_variables(p))
             return english(2314);
          break;

       case FACTOR:
          if(factored(p))  /* no non-irreducible sums */
             { if(mvpoly(p))
                  return english(16);  /* That polynomial is irreducible */
               if(nsteps == 0)
                  { *flag = 1;
                    return english(7);  /* That's the answer */
                  }
               break;
             }
          if(nsteps == 0)
             return english(17);
             /* That's the best Mathpert can do */
          /* Mathpert would take one more step, and
             the "answer" doesn't pass factored */
          return nsteps == 1 ? english(1449) : english(1450);
              /* Mathpert would take one more step. */
              /* Mathpert would take two or more additional steps. */

       case SIGMA_NOTATION:
          if(contains(p,SUM))
             return nsteps ? english(1670): english(1060);
             /* There is an unevaluated indexed sum. */
             /* Mathpert can't evaluate the sum.  Evaluate it numerically. */
          break;

       case ADDSERIES:
          if(contains(p,SUM))
             return nsteps ? english(2234): english(2235);
             /* There is an unevaluated infinite series. */
             /* Mathpert can't find a closed form for this series. */
          break;

       case POWERSERIES:
          if(FUNCTOR(p) == SUM)
             break;
          if(contains(p,SUM) && linear_in_series(p))
             break;
          if(nsteps == 0)
             return english(17);  /* That's the best Mathpert can do */
          return nsteps == 1 ? english(1449) : english(1450);
               /* Mathpert would take one more step. */
              /* Mathpert would take two or more additional steps. */


       case TESTCONVERGENCE:
          ans = series_fremark(p);
          if(ans)
             return ans;
          break;

       case TRIG_IDENTITY:
          if(FUNCTOR(p) != '=')
             assert(0);
          if(equals(ARG(0,p),ARG(1,p)))
             { *flag = 1;
               return english(1673);
               /* That's the answer: the identity is verified. */
             }
          if(nsteps)
             return english(1671);
             /*  Identity not yet verified.  The two sides are not identical. */
          /* Now, it's not verified, and Mathpert won't go further. */
          /* is this an identity that flunked checknumerically ? */
          code_to_op(checknumerically, &op);
          if(q.opseq[currentline].men == op.men && q.opseq[currentline].choice == op.choice)
             return english(1097);  /* Identity is not valid. */
          return english(1096);
          /* Identity not verified.  Test it numerically. */

       case LINEAR_EQUATIONS:
          if(solved_system(p))
             { *flag = 1;
               if(nsteps == 0)
                  return english(7);  /* That's the answer. */
               else
                  return english(1868);
                  /* You have solved the equations, but perhaps the answers should be simplified. */

             }
          if(currenttopic == _cramers_rule)
             { return nsteps ? english(1668) : english(1344);
               /* Not yet solved. */
               /* Cramer's rule only works when the equations
               have a unique solution, which these don't.
               You can continue working on this by some other method,
               but Mathpert stops here because you chose
               the topic Cramer's Rule. */
             }
          if(currenttopic == _eqns_by_matrix_inverse)
             { return nsteps ? english(1668) : english(1350);
               /* Not yet solved. */
               /* Taking the matrix inverse only works when the equations
               have a unique solution, which these don't.
               You can continue working on this by some other method,
               but Mathpert stops here because you chose
               the topic Solve Equations by Matrix Inverse. */
             }
          if(nsteps)
             return english(1668);  /* Not solved yet */
          else
             { *flag = 1;
               return english(7); /* That's the answer */
             }

       case DIFFERENTIATE:
          if(currenttopic == _higher_order_diff)
             { if(nsteps == 0 || noderivs(p))
                  { *flag = 1;
                    return english(612);
                    /* That's a good answer. Use u=v => du/dx = dv/dx for more derivatives. */
                  }
               return nsteps == 1 ? english(1449) : english(1450);
                  /* Mathpert would take one more step. */
                  /* Mathpert would take two or more additional steps. */
             }
          if(nsteps == 0)
             { *flag = 1;
               return english(1672); /* That's a good answer. */
             }
          if(!noderivs(p))
             return english(1674);
             /* There is still an unevaluated derivative */
          break;

       case IMPLICIT_DIFF:
          if(FUNCTOR(p) == '='
             && (contains(ARG(1,p),DIFF) ||
                 !(
                   (FUNCTOR(ARG(0,p)) == DIFF || FUNCTOR(ARG(0,p)) == PR)
                    && ATOMIC(ARG(0,ARG(0,p)))
                  )
                )
            )
             return nsteps ? english(1668) : english(17);
            /* Not solved yet. */
            /* That's the best Mathpert can do. */
          if(nsteps == 0)
             { *flag = 1;
               return english(1672); /* That's a good answer. */
             }
          if(!noderivs(p))
             return english(1674);
             /* There is still an unevaluated derivative */
          break;

       case DIFFERENTIATE_FROM_DEFN:
          if(contains(p,DIFF))
             return english(1674);
             /* There is still an unevaluated derivative */
          /* fall through to LIMITS */
       case LIMITS:
       case LHOPITAL:
          if (contains(p,LIMIT))  /* an unevaluated limit remains */
             return nsteps ? english(1669): english(17);
             /* There is an unevaluated limit term */
             /* That's the best Mathpert can do. */
          if(contains_zero_denom(p))
             return english(1966);
             /* Eliminate zero denominators */
          if(ISATOM(p) || equals(p,minusinfinity))
             break;
          if(contains_undefined(p))
             return nsteps ? english(1988) : english(17);
             /* There is an unevaluated infinite or undefined subterm. */
             /* That's the best Mathpert can do. */
          break;
       case SIMPLIFY:
          if(currenttopic == _evaluate_numerically)
             { if(seminumerical(p))
                  { *flag = 1;
                    return english(7);  /* That's the answer */
                  }
               else
                  return english(1523);
                 /* To get a meaningful answer, you must specify values of the variables.  Mathpert can't do this for you. */
             }
          if(currenttopic == _inverse_trig_functions)
             { if(contains_arctrigs(p))
                  return english(1832);
                  /* That expression still contains an inverse trig function. */
             }
          if(currenttopic == _trig_product)
             { if(contains_trigproduct(p))
                  return english(1952);
                  /* That expression still contains a product of trig functions. */
             }
          break;
       case COMMON_DENOMINATOR:
          /* Reject it if it contains a sum that contains
             a fraction. */
          if(nsteps == 0)
             { *flag = 1;
               return english(1672);  /* That's a good answer */
             }
          if(needs_commondenom(p))
             return english(1675);
             /* There are still fractions to put over a common denominator. */
          break;
       case COMPOUND_FRACTIONS:
          /* Reject it if it contains a fraction whose
             numerator or denominator contains a fraction. */
          if(nsteps == 0)
             { *flag = 1;
               return english(1672);  /* That's a good answer */
             }
          if(contains_cf(p))
             return english(1676);
             /* There is still a compound fraction to be eliminated. */
          break;
       case NEGATIVE_EXPONENTS:
          /* Reject it if it contains a fraction which
             contains_monomially an exponent in the denominator  */
          if(nsteps == 0)
             { *flag = 1;
               return english(1672);  /* That's a good answer */
             }
          if(needs_negexp(p))
             return english(1676);
             /* There is still a compound fraction to be eliminated. */
          break;
       case ELIMINATE_NEGATIVE_EXPONENTS:
          /* Reject it if if contains a negative exponent */
          if(nsteps == 0)
             { *flag = 1;
               return english(1672);  /* That's a good answer */
             }
          if(contains_negexp(p))
             return english(1677);
             /* There is still a negative exponent to be eliminated. */
          break;
       case FRACTIONAL_EXPONENTS:
          if(nsteps == 0)
             { *flag = 1;
               return english(1672);  /* That's a good answer */
             }
          /* Reject if it contains a root or sqrt */
          if(contains(p,ROOT) || contains(p,SQRT))
             return english(1678);
             /* There is still a root to be eliminated. */
          break;
       case ROOTS:
          if(nsteps == 0)
             { *flag = 1;
               return english(1672);  /* That's a good answer */
             }
          /* Reject if it contains a fractional exponent */
          if(contains_ratexp(p))
             return english(1678);
             /* There is a fractional exponent to be eliminated. */
          break;

       case BINOMIAL_THEOREM: /* fall through */
       case EXPAND:
          if(nsteps == 0)
             { *flag = 1;
               return english(1672);  /* That's a good answer */
             }
          /* Reject it if it contains an expandable
             product */
          err = needs_expand(p);
          if(err == 2)
             return english(1679);
             /* There is a product of sums to multiply out. */
          if(err == 1)
             return english(1680);
             /* There is a power of a sum to expand. */
          break;

       case COMPLEX_NUMBERS:
          /* if you change this, changed SolvedDoc in getprob\autolog.c too */
          switch(currenttopic)
              { case _complex_arithmetic:  /* fall-through */
                case _de_moivre:
                   if(!iscomplex(p))
                       break;  /* i was eliminated, answer is real */
                   if(complex_number(p))
                       break;  /* answer has the form a + bi */
                   return english(1822);
                    /* Reduce complex numbers to the form $a + bi$. */
                case _polar_form:
                   if(is_polar_complex(p))
                      break;
                   if(!complexparts(p,&u,&v) && ZERO(v))
                      { /* lastline has no imaginary part, but we still
                           have to watch out for negative real part. */
                        if(NEGATIVE(u) && obviously_positive(ARG(0,u)))
                           return english(1951);
                           /* That expression is real, but it is negative, so
                              it's not in polar form, which is $re^(it)$ with
                              $r$ positive. */
                        if(obviously_positive(u))
                           break;  /* acceptable */
                        err = check(le(zero,u));
                        if(!err)
                           break;
                        return english(1951);
                           /* That expression is real, but it is negative, so
                              it's not in polar form, which is $re^(it)$ with
                              $r$ positive. */
                      }
                   return english(1821);
                   /* That expression is not in polar form. Polar form is re^(iT). */
                default:
                   assert(0);  /* no more topics for COMPLEX_NUMBERS */
              }
          break;
       case TRIG_EXPAND:
          break;
       case INDUCTION:
          /* It's acceptable if 'thereforeasdesired' has been used
             and the current line is an identity. */
          break;
       case MINMAX:
          if(equals(p,false))
             break;
          if(used2(FUNCTIONISCONSTANT))
             break;
          if(!used2(TABULATE) && !used2(TABULATEEXACT))
             return english(2228);
             /* You must compute a table of function values and select the maximum or minimum. */
          if(!used2(SELECTMIN) && !used2(SELECTMAX) && !get_minflag() && !get_maxflag())
             return english(2229);
             /* You should select the maximum and/or the minimum to complete the problem. */
          break;
       case RELATED_RATES:
          if(solved_related_rates(p))
             return english(1923);
             /* You must solve each equation, either for a derivative or a variable. */
          break;
     }

  /* If we get here, then the answer hasn't been rejected.  This means
     the main goal of the problemtype has been met: an equation is
     solved, an integral sign or limit is eliminated, etc.  The question
     is whether the answer is sufficiently simplified.
  */

  if(nsteps == 0)
     { *flag = 1;
       return english(1672);  /* That's a good answer */
     }

  /* Now check for the case in which plan contains only
     trivial operations. */

  for(i=0;i<nsteps;i++)
     { if(!trivial_op(plan[i]))
          break;
     }
  if(i == nsteps)
     /* The next steps are trivial and after all the
        main goal has already been achieved. */

     { *flag = 1;
       return english(1672);  /* That's a good answer */
     }
  if(nsteps == 1)
     { *flag = 3;
       return english(1682);
       /* Your answer is acceptable, but perhaps it could be
          simplified.  Mathpert would take one more step. */
     }
  if(nsteps == 2)
     return english(1683);
  /* Your answer is acceptable, but perhaps it could be
     simplified.  Mathpert would take two more steps. */
  return english(1684);
  /* Your answer is acceptable, but perhaps it could be
     simplified.  Mathpert would take at least three more steps. */
}

/*______________________________________________________________________*/
static int solved_system(term p)
/* return 1 if the equation or system of equations p is solved */
{ unsigned n,f,i;
  term lhs, rhs, swap;
  n = ARITY(p);
  f = FUNCTOR(p);
  if(equals(p,false))
     return 1;    /*  No solution;  'That's the answer' is appropriate */
  if(INEQUALITY(f))
     { lhs = ARG(0,p);
       rhs = ARG(1,p);
       if(!ATOMIC(lhs) && f != '=' && ATOMIC(rhs))
          { swap = lhs;
            lhs = rhs;
            rhs = swap;
          }
       if(!ATOMIC(lhs))
          return 0;
       if(!constant(rhs))
          return 0;
       if(contains(rhs,DET) && seminumerical(rhs))
          return 0;  /* in Cramer's rule, you must evaluate numerical determinants */
       return 1;  /* This still counts x = 2/2 as solved. */
     }
  if(f == AND || f == OR)
     { for(i=0;i<n;i++)
          { if(!solved_system(ARG(i,p)))
               return 0;
          }
       return 1;
     }
  /* Note the above code also works on interval_as_and terms */
  return 0;
}
/*________________________________________________________________*/
static int needs_commondenom(term t)
/* return 1 if t contains a sum, one of whose summands is a
fraction or power of a fraction, or a product which has a fraction
or power of a fraction as a factor. */
{ unsigned short f,n;
  int i,j;
  term u,v;
  if(ATOMIC(t))
    return 0;
  f = FUNCTOR(t);
  n = ARITY(t);
  if(f != '+')
     { for(i=0;i<n;i++)
          { if(needs_commondenom(ARG(i,t)))
               return 1;
          }
       return 0;
     }
  for(i=0;i<n;i++)
     { u = ARG(i,t);
       while(NEGATIVE(u) || FUNCTOR(u) == '^')
          u = ARG(0,u);
       if(FRACTION(u))
          return 1;
       if(FUNCTOR(u) == '*')
          { for(j=0;j<ARITY(u);j++)
               { v = ARG(j,u);
                 while(NEGATIVE(v) || FUNCTOR(v) == '^')
                    v = ARG(0,v);
                 if(FRACTION(v))
                    return 1;
               }
          }
     }
  return 0;
}

/*_________________________________________________________________________*/
static int contains_cf(term t)
/* return 1 if t contains a compound fraction */
{ unsigned short f,n;
  int i;
  term u;
  if(ATOMIC(t))
     return 0;
  n = ARITY(t);
  f = FUNCTOR(t);
  if(f == '/')
     { for(i=0;i<2;i++)
          { u = ARG(i,t);
            if(contains_monomially(u,'/'))
               return 1;  /* example:  e^(1/2)/2 is ok */
          }
     }
  for(i=0;i<n;i++)
     { if(contains_cf(ARG(i,t)))
          return 1;
     }
  return 0;
}
/*____________________________________________________________________*/
static int needs_negexp(term t)
/* return 1 if t contains an exponent as a denominator or a factor
of a denominator. */
{ int i,j;
  unsigned short f,n;
  term u,v;
  if(ATOMIC(t))
     return 0;
  f = FUNCTOR(t);
  n = ARITY(t);
  if(f == '/')
     { if(needs_negexp(ARG(0,t)))
          return 1;
       u = ARG(1,t);
       while(NEGATIVE(u))
          u = ARG(0,u);
       if(FUNCTOR(u) == '^')
          return 1;
       if(FUNCTOR(u) == '*')
          { for(j=0;j<ARITY(u);j++)
               { v = ARG(j,u);
                 while(NEGATIVE(v))
                    v = ARG(0,v);
                 if(FUNCTOR(v) == '^')
                    return 1;
               }
          }
       return needs_negexp(u);
     }
  for(i=0;i<n;i++)
     { if(needs_negexp(ARG(i,t)))
          return 1;
     }
  return 0;
}
/*________________________________________________________*/
static int contains_ratexp(term t)
/* return 1 if t contains a rational exponent */
{ int i,j;
  unsigned short n,f;
  term u,v;
  if(ATOMIC(t))
     return 0;
  f = FUNCTOR(t);
  n = ARITY(t);
  if(f == '^')
     { u = ARG(1,t);
       while(NEGATIVE(u))
          u = ARG(0,u);
       if(RATIONALP(u))
          return 1;
       if(FUNCTOR(u) == '*')
          { for(j=0;j<ARITY(u);j++)
               { v = ARG(j,u);
                 while(NEGATIVE(v))
                    v = ARG(0,v);
                 if(RATIONALP(v))
                    return 1;
               }
          }
     }
  for(i=0;i<n;i++)
     { if(contains_ratexp(ARG(i,t)))
          return 1;
     }
  return 0;
}
/*________________________________________________________*/
static int contains_negexp(term t)
/* return 1 if t contains a negative exponent, also
if the minus sign is in num or denom of a fractional exponent.
*/

{ int i,j;
  unsigned short n,f;
  term u,v;
  if(ATOMIC(t))
     return 0;
  f = FUNCTOR(t);
  n = ARITY(t);
  if(f == '^')
     { u = ARG(1,t);
       if(NEGATIVE(u))
          return 1;
       if(FRACTION(u))
          { if(NEGATIVE(ARG(0,u)) || NEGATIVE(ARG(1,u)))
               return 1;
            for(i=0;i<2;i++)
               { v = ARG(i,u);
                 if(FUNCTOR(v) == '*')
                     { for(j=0;j<ARITY(v);j++)
                          { if(NEGATIVE(ARG(j,v)))
                               return 1;
                          }
                     }
               }
          }
     }
  for(i=0;i<n;i++)
     { if(contains_negexp(ARG(i,t)))
          return 1;
     }
  return 0;
}

/*________________________________________________________________________*/
static int needs_expand(term t)
/* return 1 or 2  if t contains a power or product or sums
 that can be expanded, 0 if not. */

{ unsigned f = FUNCTOR(t);
  unsigned n = ARITY(t);
  int count,err;
  unsigned i;
  if(ATOMIC(t))
     return 0;
  if (f == '^' && FUNCTOR(ARG(0,t)) == '+')
     { term power = ARG(1,t);
       if(!ISINTEGER(power))
          return 0;  /* You can't expand a bignum power anyway */
       return 1;
     }
  if (f == '*')
     { count = 0;  /* count the sums */
       for(i=0;i<n;i++)
          { if(FUNCTOR(ARG(i,t))== '+')
               ++count;
          }
       if(count > 1)
          return 2;
     }
  for(i=0;i<n;i++)
     { err = needs_expand(ARG(i,t));
       if(err)
          return err;
     }

  return 0;
}
/*___________________________________________________________*/
static int noderivs(term t)
/* return 1 if t has no evaluable derivatives.  It may
contain a derivative like df/dx where f is neither
pre-defined nor user-defined */
{ unsigned short f,n;
  int i;
  if(ATOMIC(t))
     return 1;
  n = ARITY(t);
  f = FUNCTOR(t);
  if(f == DIFF)
     { f = FUNCTOR(ARG(0,t));
       if(PREDEFINED_ATOM(f))
          return 1;
       if( ('a' <= f  && f <= 'z') || ('A' <= f && f <= 'Z'))
          return 1;
       return 0;
     }
  for(i=0;i<n;i++)
     { if(!noderivs(ARG(i,t)))
          return 0;
     }
  return 1;
}
/*________________________________________________*/

static actualop trivialops[] =
{ orderterms,
  orderfactors,
  apart,
  factoroutnumber,
  contentfactor,
  cleardenoms,
  pulloutrational,
  polyvalop,
  switchsides
};

static int trivial_op(operation op)
/* return 1 if o is 'trivial', i.e. an answer is
acceptable if all Mathpert wants to do to it is
apply trivial ops.
*/
{ unsigned n = sizeof(trivialops)/sizeof(actualop);
  unsigned i;
  actualop o = access_optable(op.men)[op.choice-1];
  for(i=0;i<n;i++)
     { if((void  *) o == (void  *) trivialops[i])
          return 1;
     }
  return 0;
}

/*__________________________________________________________________*/
MEXPORT_AUTOMODE int solved_related_rates(term t)
/* return 0 if t counts as a solution to a related rates problem, 1 if not.
A good solution should be an equation with an atom on the left
and that atom not occurring on the right, or a derivative
of an atom on the left, and no DIFF on the right,
or an AND of such expressions.  A PROTECTED equation can still
remain in the answer; that's just the original equation.
*/
{ unsigned short n;
  int i;
  term u;
  if(FUNCTOR(t) == AND)
     { n = ARITY(t);
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            if(FUNCTOR(u) != '=')
               return 1;
            if(PROTECTED(u))
               continue;  /* ignore original equation */
            if(FUNCTOR(ARG(0,u)) == DIFF)
               { if(!ISATOM(ARG(0,ARG(0,u))))
                    return 1;
                 if(contains(ARG(1,u),DIFF))
                    return 1;
               }
            else if(!ISATOM(ARG(0,u)) || contains(ARG(1,u),FUNCTOR(ARG(0,u))))
               return 1;
          }
       return 0;
     }
  if(FUNCTOR(t) == '=' && FUNCTOR(ARG(0,t)) == DIFF &&
     ISATOM(ARG(0,ARG(0,t))) && !contains(ARG(1,t),DIFF)
    )
     return 0;
  if(FUNCTOR(t) == '=' && ISATOM(ARG(0,t)) &&
     !contains(ARG(1,t),FUNCTOR(ARG(0,t)))
    )
     return 0;
  return 1;
}

/*________________________________________________________________________*/
static int contains_trigproduct(term t)
/* return 1 if t contains f(x)g(y) where f and
g are trig functions.
*/
{ unsigned short n,f;
  int i,j,count;
  if(ATOMIC(t))
     return 0;
  n = ARITY(t);
  if(FUNCTOR(t) == '*')
     { count = 0;
       for(j=0;j<ARITY(t);j++)
          { f = FUNCTOR(ARG(j,t));
            if(TRIGFUNCTOR(f))
               ++count;
          }
       return count > 1 ? 1 : 0;
     }
  for(i=0;i<n;i++)
     { if(contains_trigproduct(ARG(i,t)))
          return 1;
     }
  return 0;
}

/*_____________________________________________________*/
MEXPORT_AUTOMODE int contains_zero_denom(term t)
/* return 1 if t contains a zero in a denominator, or
a power of zero in a denominator. */

{ unsigned short n,i;
  term denom;
  if(ATOMIC(t))
     return 0;
  if(FRACTION(t))
     { denom = ARG(1,t);
       if(ZERO(denom))
          return 1;
       if(FUNCTOR(denom) == '^' && ZERO(ARG(0,denom)))
          return 1;
       if(contains_zero_denom(ARG(0,t)))
          return 1;
       return 0;
     }
  n = ARITY(t);
  for(i=0;i<n;i++)
     { if(contains_zero_denom(ARG(i,t)))
           return 1;
     }
  return 0;
}

/*__________________________________________________________*/
static int linear_in_series(term t)
/* return 1 if t is a linear combination of infinite series */
{ unsigned short n,f,i;
  int count,flag;
  int nvariables = get_nvariables();
  term a,u;
  term x = get_eigenvariable();
  f = FUNCTOR(t);
  if(f == '-')
     { t = ARG(0,t);
       f = FUNCTOR(t);
     }
  if(f == SUM)
     return nvariables > 1 ? is_power_series(t,x,&a) : 1;
  n = ARITY(t);
  if(f == '*')
     { count = 0;
       for(i=0;i<n;i++)
          { if(constant(ARG(i,t)) && !contains(ARG(i,t),SUM))
               continue;
            if(FUNCTOR(ARG(i,t)) == SUM)
               { if(count)
                    return 0;
                 ++count;
                 flag = i;
               }
          }
       if(count == 0)
          { if(constant(t))
               return 1;
            if(nvariables && ispolyin(t,x))
               return 1;
            return 0;
          }
       return linear_in_series(ARG(flag,t));
     }
  if(f == '+')
     { for(i=0;i<n;i++)
          { u = ARG(i,t);
            if(NEGATIVE(u))
               u = ARG(0,u);
            if(constant(u))
               continue;
            if(FUNCTOR(u) == '*' || FUNCTOR(u) == SUM)
               { if(!linear_in_series(u))
                    return 0;
               }
            if(nvariables > 1 && ispolyin(u,x))
               continue;
            return 0;
          }
       return 1;
     }
  return 0;
}

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