Sindbad~EG File Manager

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

/* M. Beeson, for Mathpert */
/*
10.25.90 original date
3.13.99 modified
1.4.00  modified check_problem at the dated lines
1.6.00  modified check_problem at the dated lines
9.2.04  modified call to enter_definition and added call to mstring before it.
9.9.04 modified check_problem at NOTDEFINED so that infinity is rejected.
1.25.06 replaced "check" by "infer" in check_problem for MINMAX
9.4.07  put in calls to defined_on_interval, and moved make_true to domain.c
5.6.13  include stdef.h
9.26.14 changed static function finite() to finite3()  to avoid an error message from Xcode
10.22.23 changed n=2 to n==2 line 513 and fixed RIGHT on that line
*/
#include <assert.h>
#include <stdlib.h>
#include <stddef.h>
#include "globals.h"
#include "graphstr.h"
#include "display.h"
#include "mpdoc.h"
#include "prover.h"
#include "checkarg.h"
#include "automode.h"
#include "chkprob.h"
#include "probtype.h"
#include "userfunc.h"
#include "nextline.h"   /* maxscope */
#include "symbols.h"
#include "cflags.h"
#include "dispfunc.h"   /* functor_string */
#include "domain.h"     /* contains_defined_variables */
#include "order.h"      /* common_variables  */
#include "pdomain.h"    /* punctured_domain  */
#include "mpmem.h"
#include "binders.h"
#include "tdefn.h"
#include "trigpoly.h"
#include "converge.h"
#include "deval.h"
#include "mstring.h"

static term closure(term a);
static int finite3(term t, term x, term a, term b);
static int leaves_gaps(term t, term x, term a, term b);
/*___________________________________________________________*/
int checkproblem(term t, int problemtype, int currenttopic)
/*  check if the problem is defined, except don't go into limit terms */
/*  This can result in making some assumptions; and if the (non-limit parts
    of) the problem are undefined, in returning an error.  Zero return
    means success, the problem is ok modulo the assumptions that have
    been made.   Nonzero returns are indices of error messages in 
    input_error_message in engerr.c.  
*/

/*  For improper integrals, if the integrand is not defined on the
interval of integration, we return 27.  Final_adjustments() will
SETIMPROPER on the integral before storing it in the history list.
For infinite series entered under problemtype TESTCONVERGENCE, we
also return 27; final_adjustments will then call SETIMPROPER.
*/

/*  In case of minmax problems, this function makes the assumption that
the independent variable lies in the closure of *minmax_interval */

{ unsigned n;
  unsigned f = FUNCTOR(t);
  int i,j,nvariables;
  int mathmode;
  char rhs_name[128];
  term *varlist = get_varlist();
  term p,dom,x,a,b;
  varinf *varinfo = get_varinfo();
  term savelocus;
  int err;
  int saveit,savej,savebinderflag;
  term left,right,defn;
  char printname[32];
  short nextassumption = get_nextassumption();
  int limflag=contains(t,LIMIT);
  int dflag = domainflag(problemtype,currenttopic);
  set_polyvaldomainflag(dflag);
  n = ARITY(t);
  mathmode = get_mathmode();
  set_mathmode(AUTOMODE);
  /* mathmode hasn't been initialized yet, and so by
  default it is zero, which is MENUMODE;  this will cause
  intsub not to reject new fractional exponents, and when
  simple_integral is called to test the convergence of an
  infinite series, a loop results.  Moreover it may cause
  trouble elsewhere too. */
  if(problemtype == MINMAX && FUNCTOR(t) == AND)
     { err = checkproblem(ARG(0,t),problemtype, currenttopic);
       if(err)
          { set_mathmode(mathmode);
            return err;
          }

       /* example:  if tan x is entered, a new variable
          n is created, but it doesn't appear in the
          assumptions because tan x is defined on
          the minmax interval.  Let's get rid of n */
       nvariables = get_nvariables();
       if(nvariables > 1)
          { for(i=nvariables-1;i>=0;i--)
               { for(j=0;j<nextassumption;j++)
                    { if(contains(get_assumption(j),FUNCTOR(varlist[i])))
                         break;
                    }
                 if(j==nextassumption && !contains(t,FUNCTOR(varlist[i])))
                    /* this is a superfluous variable */
                    { --nvariables;
                      set_nvariables(nvariables);
                    }
                 else
                    break;
               }
          }
       set_mathmode(mathmode);
       return 0;
     }
  if(problemtype == MINMAX
     && n ==2 && f == '='  /* check for input of form f(x)=... */
     && !ATOMIC(ARG(0,t))
     && !PREDEFINED_FUNCTOR(FUNCTOR(ARG(0,t)))
    )
     {
       term interval = get_minmax_interval();
       term closed_interval;
       term x = get_eigenvariable();
       functor_string(FUNCTOR(ARG(0,t)),SCREEN, printname);
       err = check_syntax(t);
       if(err == 88 || err == 89)
          err=0;  /* warnings about constant functions */
       if(err)
          { set_mathmode(mathmode);
            return err;
          }
       if(FUNCTOR(interval) != 0)
          { closed_interval = closure(interval);
            assert(nextassumption==0);  /* nothing has been assumed yet */
            assume(interval);  /* until we can check that the
                                  problem is defined there */
            err = infer(domain(ARG(1,t)));
            if(err)
               { set_nextassumption(0);
                 set_mathmode(mathmode);
                 return 158;   /* The function must be defined on the interval */
               }
            saveit = nextassumption;
            if(nextassumption > saveit)
               { for(i=saveit; i< nextassumption; i++)
                   { if(contains(get_assumption(i),FUNCTOR(x)))
                        break;
                   }
                 if(i<nextassumption)
                    { discharge(saveit);
                      set_mathmode(mathmode);
                      return 110;
                    }
                 /* else the only assumptions made did not involve x,
                    for example  that a parameter is positive, etc.
                    These can be harmlessly left in place. */
               }
            if(!equals(interval,closed_interval))
              /* get rid of the assumption that the variable is in
                 the (open) minmax interval.  We only want to assume
                 it is in the closed minmax interval.  */

               { if(nextassumption > saveit)
                    { for(i=0;i<saveit;i++)
                         replace_assumption(i,trueterm);
                    }
                 else
                    discharge(0);
                 assume(closed_interval);
               }
          }
       if(is_defined(FUNCTOR(ARG(0,t))) >= 0)
          remove_definition(FUNCTOR(ARG(0,t)));
       mstring(ARG(1,t),rhs_name);
       enter_definition(ARG(0,t),ARG(1,t),printname,rhs_name);
       set_mathmode(mathmode);
       return 0;
     }

  if(n ==2 && f == '='  /* check for input of form f(x)=... */
     && !ATOMIC(ARG(0,t))
     && !PREDEFINED_FUNCTOR(FUNCTOR(ARG(0,t)))
    )
     { err = check_syntax(t);
       if(err == 88 || err == 89)
          err=0;  /* warnings about constant functions */
       if(err)
          { set_mathmode(mathmode);
            return err;
          }
       err = check1(domain(ARG(1,t)));
       if(err)
          { set_mathmode(mathmode);
            return 20;
          }
       functor_string(FUNCTOR(ARG(0,t)),SCREEN,printname);
       mstring(ARG(1,t),rhs_name);
       enter_definition(ARG(0,t),ARG(1,t),printname, rhs_name);
       deletep(t);
       set_mathmode(mathmode);
       return 0;
     }
  if(currenttopic == _logarithmic_differentiation)
     { assert(FUNCTOR(t) == '=');
       left = ARG(0,t);
       right = ARG(1,t);
       err = check1(domain(ARG(1,t)));
       if(err)
          { set_mathmode(mathmode);
            return 20;
          }  
       if(ATOMIC(left))
          { term pleft,pright;
            permcopy(left,&pleft);
            permcopy(right,&pright);
            let_permanent(pleft,pright);  /* example y = 1/x  */
          }
       else  /* example  f(x) = 1/x */
          { defn = equation(left,right);
            functor_string(FUNCTOR(ARG(0,defn)),SCREEN,printname);
            mstring(ARG(1,defn),rhs_name);
            enter_definition(ARG(0,defn),ARG(1,defn), printname, rhs_name);
          }
       deletep(t);
       set_mathmode(mathmode);
       return 0;
     }
  if(problemtype == DIFFERENTIATE &&  /* check for f'(x) == ... and y' = ... */
     n ==2  && f == '='
    )
     { assert(FUNCTOR(ARG(1,t)) == DIFF);
       assert(FUNCTOR(ARG(0,t)) == PR || FUNCTOR(ARG(0,t)) == DIFF);
       right = ARG(0,ARG(1,t));
       left = ARG(0,ARG(0,t));
       if(!ATOMIC(left))
         { defn = equation(left,right);
           err = check_syntax(defn);
           if(err == 88 || err == 89)
              err=0;  /* warnings about constant functions */
           if(err)
              { set_mathmode(mathmode);
                return err;
              }
         }
       err = check1(domain(ARG(1,t)));
       if(err)
          { set_mathmode(mathmode);
            return 20;
          }
       if(ATOMIC(left))
          { term pleft,pright;
            permcopy(left,&pleft);
            permcopy(right,&pright);
            let_permanent(pleft,pright);  /* example y = 1/x  */
          }
       else  /* example  f(x) = 1/x */
          { functor_string(FUNCTOR(ARG(0,defn)),SCREEN,printname);
            mstring(ARG(1,defn),rhs_name);
            enter_definition(ARG(0,defn),ARG(1,defn), printname, rhs_name);
          }
       deletep(t);
       set_mathmode(mathmode);
       return 0;
     }
  if(f == INTEGRAL && ARITY(t) == 4 &&
     currenttopic == _improper_integrals
     /* If other topics allow improper integrals, list them here */
    )
     { x = ARG(1,t);  /* variable of integration */
       a = ARG(2,t);
       b = ARG(3,t);
       if(!ISATOM(x))
          { set_mathmode(mathmode);
            return 106;  /* No variable of integration. Edit your problem. */
          }
       if(contains(ARG(0,t),CASES))
          { set_mathmode(mathmode);
            return 154;  /* Mathpert cannot handle definition by cases
                          in an improper integral. */
          }
       if(!ISINFINITE(a) && !INTEGERP(a))
          { err = check1(domain(ARG(2,t)));
            if(err)
               { deletep(t);
                 set_mathmode(mathmode);
                 return 107;  /* Undefined lower limit of integration */
               }
          }
       if(!ISINFINITE(b) && !INTEGERP(b))
          { err = check1(domain(ARG(3,t)));
            if(err)
               { deletep(t);
                 set_mathmode(mathmode);
                 return 108;  /* Undefined upper limit of integration */
               }
          }
       if(trigrational(ARG(0,t)))
          { set_mathmode(mathmode);
            return 27;
            /* trigrational functions can have only finitely many zeroes
               in any finite interval. */
          }
       setlocus(x,&savelocus,&savej,t);
       fillbinders(t);
       savebinderflag = get_lpt_binderflag();
       set_lpt_binderflag(0);
       dom = lpt(domain(ARG(0,t)));
       set_lpt_binderflag(savebinderflag);
       if(!contains(dom,FUNCTOR(x)) && !equals(dom,trueterm))
          { err = check1(dom);
            if(err)
               { varinfo[savej].locus = savelocus;
                 releasebinders();
                 deletep(t);
                 set_mathmode(mathmode);
                 return 155;  /* function not defined on interval */
               }
          }
       err = equals(dom,trueterm) ? 0 : infer(dom);
       if(err)
          { if(finite3(dom,x,a,b))
               err = 27;
            else if(leaves_gaps(dom,x,a,b))
               err = 155;
               /* The integrand is undefined at more than isolated points, so the integral cannot be defined. */
            else
               err = 1;
          }
       varinfo[savej].locus = savelocus;
       releasebinders();
       if(err == 27 || err == 155)
          { deletep(t);
            set_mathmode(mathmode);
            return err;
          }
       if(err)
          { deletep(t);
            set_mathmode(mathmode);
            return 152;
              /* Sorry, Mathpert cannot analyze this integral, so it cannot be accepted. */
          }
       if(ISINFINITE(a) || ISINFINITE(b))
          err = 27;   /* so final_adjustments will call SETIMPROPER */
       deletep(t);
       set_mathmode(mathmode);
       return err;
     }

  if(f == INTEGRAL && ARITY(t) == 4) /* definite integral */
     { term u;   
       u = ARG(0,t);  /* integrand */
       x = ARG(1,t);  /* variable of integration */
       a = ARG(2,t);  /* lower limit */
       b = ARG(3,t);  /* upper limit */
    
       if(!ISATOM(x))
          return 106;  /* No variable of integration. Edit your problem. */
       err = check1(domain(a));
       if(err)
          { deletep(t);
            set_mathmode(mathmode);
            return 107;  /* Undefined lower limit of integration */
          }
       err = check1(domain(b));
       if(err)
          { deletep(t);
            set_mathmode(mathmode);
            return 108;
          }
       dom = defined_on_interval(u,x,a,b);
       if(equals(dom,falseterm) || check1(dom))  
          { deletep(t);   /* dom is false or can't be checked */
            set_mathmode(mathmode);
            return 105;
              /* Integrand must be defined on the interval of integration. */
              /* Improper integrals are not allowed.          */
              /* Not even removable singularities are allowed. */
              /* You can get this message if the integrand is too complicated
                 for Mathpert to determine if it is defined on the interval of integration. */
          }
       deletep(t);
       set_mathmode(mathmode);
       return 0;
     }
  if(f == SUM || f == PRODUCT)    /* indexed sum or product*/
     { term x = ARG(1,t);  /* variable of summation */
       assert(ARITY(t) == 4 || ARITY(t) == 5);
       if(!ISATOM(x))
          { set_mathmode(mathmode);
            return 106;  /* No variable of summation. Edit your problem. */
          }
       if(contains(t,CASES))
          return 157;  /* Mathpert cannot handle definition by cases in an infinite series. */
       if(equals(ARG(2,t),minusinfinity))
          err = 0;
       else
          { err = check1(type(ARG(2,t),INTEGER));
            if(err)
               { set_mathmode(mathmode);
                 return f==SUM ? 111 : 130;  /* Lower limit of sum must be an integer. */
               }
          }
       if(equals(ARG(3,t),infinity))
          err = 0;  /* infinite sums OK */
       else
          { err = check1(domain(ARG(3,t)));
            if(err)
               { set_mathmode(mathmode);
                 return f==SUM ? 112 : 131;  /* Upper limit of sum must be an integer. */
               }
            err = check1(le(ARG(2,t),ARG(3,t)));
            if(err)
               { set_mathmode(mathmode);
                 return f == SUM ? 127 : 129;  /* Lower limit of sum must be less than or equal to upper limit. */
               }
          }
       setlocus(x,&savelocus,&savej,t);
       fillbinders(t);
       p = domain(ARG(0,t));
       if(!contains(p,FUNCTOR(x)))
          err = check1(p);  /* example, in sum(z^k,k,-3,3), p will be z != 0,
                            and we want to assume that and accept the problem */
       else
          err = infer(p);  /* example, in sum (k^k,k,-3,3) p will be k!= 0
                              and we want to reject this sum. */
                           /* Actually, p will be all(k, -3 <=k<=3 -> k != 0) */
       varinfo[savej].locus = savelocus;
       releasebinders();
       if(err)
          { set_mathmode(mathmode);
            return 128;
            /* Either the expression is undefined for some value
               of the index variable, or the problem is too
               complicated for Mathpert to analyze the domain.
            */
          }
       deletep(t);
       if(problemtype == ADDSERIES)
          { /* only accept series which Mathpert can prove
               convergent */
            term ans;
            if(equals(ARG(3,t),infinity) || equals(ARG(2,t),minusinfinity))
               { err = convergence(t,&ans);
                 if(!err && equals(ans,falseterm))
                    { set_mathmode(mathmode);
                      return 153;  /* This series does not converge.  You can
                              enter it under a topic designed to test convergence. */
                    }
                 if(!err && !equals(ans,trueterm))
                    { assume(ans);
                      set_mathmode(mathmode);
                      return 0;
                    }
                 /* here Mathpert can't analyze the convergence.
                    Should we reject such input?  */
               }
          }
       if(problemtype == TESTCONVERGENCE)
          { if(f != SUM || ARITY(t) < 4)
               { set_mathmode(mathmode);
                 return 156;  /* please enter an infinite series */
               }
            if(!equals(ARG(2,t),minusinfinity) && !equals(ARG(3,t),infinity))
               { set_mathmode(mathmode);
                 return 156;
               }

          }
       return 0;
     }
  if(ATOMIC(t))   /* stop the recursion */
     { deletep(t);
       set_mathmode(mathmode);
       if(NOTDEFINED(t))
           return 20;  /* You entered an undefined expression */
       return 0;
     }
  if(!dflag)
     { err = check1(domain(t));
       set_mathmode(mathmode);
       if(err)
          return 20;
       deletep(t);
       return 0;
     }
  if(f == LIMIT)
     { term u,x;
       int savenvariables, saveoldnvariables;
       int j,k,p;
       x = ARG(0,ARG(0,t));
       setlocus(x,&savelocus,&savej,t);
       saveoldnvariables = get_nvariables();  /* BEFORE fillbinders -- 1.6.00 */
       fillbinders(t);
       savenvariables = get_nvariables();  /* AFTER fillbinders, which introduces a new
                                infinitesimal variable */
       u = domain(n==2 ? ARG(1,t): ARG(2,t));
       err = check1(u);
       if(err)  /* can REFUTE that the limitand is defined in a neighborhood,
                   e.g. lim(x->0, sqrt(x))  */
          { set_nvariables(savenvariables);
            releasebinders();
            varinfo[savej].locus = savelocus;
            set_mathmode(mathmode);
            return  (n==2 ? 92 : (FUNCTOR(ARG(1,t)) == RIGHT) ? 93 : 94);
          }
       if(get_nextassumption() > nextassumption+1)
          /* two or more assumptions were made, e.g. a != 0 and 0 < a in the 
             case of lim(x->a, ln x) */
          simplify_assumptions(zero); /* added 1.4.00  */
       if(punctured_domain(t))
          { set_nvariables(savenvariables);
            releasebinders();
            varinfo[savej].locus = savelocus;
            set_mathmode(mathmode);
            return 141;
            /* This function is undefined for certain values arbitrarily close to the limit point, so the limit is undefined. */
          }
       /* Now at least the limitand is defined under some assumptions;
          but e.g.  lim(x->0, 1/sin(1/x)) gets this far even though
          the limitand is not defined in a neighborhood of 0.   We want
          the user to go ahead and calculate with such limits, though;
          but we DON'T want to generate assumptions that depend on x,
          such as have been generated so far.   However, simply wiping
          out ALL assumptions would be too drastic: consider
              lim(x->0, 1/(a sin x))  where we have generated an
          assumption a!=0 as well as an assumption about x.  We want
          to keep a != 0.   We keep all assumptions that don't mention x. */
       releasebinders();
       nextassumption = get_nextassumption();
       if(nextassumption == 0)  /* nothing to worry about */
          { varinfo[savej].locus = savelocus;
            set_mathmode(mathmode);
            set_nvariables(saveoldnvariables);   /* 1.6.00 */
            return 0;
          }
       for(j=nextassumption-1; j >=0; j--)
          { if(contains(get_assumption(j),FUNCTOR(x)))
               {--nextassumption;
                set_nextassumption(nextassumption);
               }
            else if(!common_variables(u,get_assumption(j)))
               {--nextassumption;
                set_nextassumption(nextassumption);
               }
            else
               break;
          }
       if(j>1)  /* some assumption doesn't contain x, does have
                   common variables with u, and there
                  are more assumptions below that one */
          { for(j=j-1;j>=0;j--)
              { if(contains(get_assumption(j),FUNCTOR(x)) ||
                   !common_variables(get_assumption(j),u)
                  )
                   replace_assumption(j,trueterm);
                   /* effectively wiping out the old one */
              }
          }
       /* Now get rid of any variables that were only used in the
          deleted assumptions  */
       nvariables = get_nvariables();
       for(j=savenvariables;j<nvariables;j++)
          { for(k=0;k<nextassumption;k++)
               { if(contains(get_assumption(k),FUNCTOR(varlist[j])))
                    break;
               }
            if(k==nextassumption)
               { /* get rid of the j-th variable */
                 if(j == nvariables-1)
                    { --nvariables;
                      set_nvariables(nvariables);
                    }
                 else
                    { /* slide the rest of the varlist down by 1 */
                      for(p=j;p<nvariables-1;p++)
                        { varlist[p] = varlist[p+1];
                          varinfo[p] = varinfo[p+1];
                        }
                      --j;
                      --nvariables;
                      set_nvariables(nvariables);
                    }
               }
          }

       varinfo[savej].locus = savelocus;
       return 0;
     }
  if(!limflag)
     { deletep(t);
       set_mathmode(mathmode);
       return 0;
     }
  for(i=0;i< (int) n;i++)
     { err = checkproblem(ARG(i,t), problemtype, currenttopic);
       if(err)
          { set_mathmode(mathmode);
            return err;
          }
     }
  deletep(t);
  return 0;
}
/*__________________________________________________________*/
static term closure(term a)
/* a is an inequality or interval_as_and term.  Return the
closure of the interval it defines, i.e. replace < by <=  */
{  switch(FUNCTOR(a))
      { case '<' : return le(ARG(0,a),ARG(1,a));
        case '>' : return le(ARG(1,a),ARG(0,a));
        case AND : return and(closure(ARG(0,a)),closure(ARG(1,a)));
        default:   return a;
      }
}
/* ____________________________________________________________________*/
int check_syntax(term t)
/* check if t is a legal definition */
{  unsigned f,n;
   unsigned i,j;
   term left,right;
   if(FUNCTOR(t) != '=' || ATOMIC(ARG(0,t)))
       return 85;
   left = ARG(0,t);
   right = ARG(1,t);
   f = FUNCTOR(left);
   n = ARITY(left);
   if(n >=4 )
       return 87;
   for(i=0;i<n;i++)
     { if(!ISATOM(ARG(i,left)))
          return 85;
       for(j=0;j<i;j++)
          { if(equals(ARG(j,left),ARG(i,left)))
                 return 85;
          }
     }
   if(PREDEFINED_FUNCTOR(f))
       return 86;
   for(i=0;i<n;i++)
     { if(!contains(right,FUNCTOR(ARG(i,left))))
           return n==1 ? 88 : 89;
     }
   return 0;
}
/*________________________________________________________*/
static int finite3(term t, term x, term a, term b)
/* return 1 if t is a proposition such that the set of
x such that a <= x <= b && t  omits only a finite number
of points in the interval [a,b].  Actually, t must be
a conjunction of NE terms x != c and possibly
a < x, x < b.  There may also be conjunctions that
do not contain x.  These will be 'checked', i.e.
assumed if they can't be proved or refuted.
*/
{ unsigned short f = FUNCTOR(t);
  unsigned short n;
  int err,i;
  if(!contains(t,FUNCTOR(x)))
     { err = check1(t);
       return !err;
     }
  if(f == '<' && equals(ARG(0,t),a) && equals(ARG(1,t),x))
     return 1;
  if(f == '<' && equals(ARG(1,t),b) && equals(ARG(0,t),x))
     return 1;
  if(f == NE && equals(ARG(0,t),x) && !contains(ARG(1,t),FUNCTOR(x)))
     return 1;
  if(f == NE && equals(ARG(1,t),x) && !contains(ARG(0,t),FUNCTOR(x)))
     return 1;
  if(f == AND)
     { n = ARITY(t);
       for(i=0;i<n;i++)
          { if(!finite3(ARG(i,t),x,a,b))
              return 0;
          }
       return 1;
     }
  return 0;
}

/*___________________________________________________________________________*/
static int leaves_gaps(term t,term x,term a,term b)
/* return 1 if [a,b] - the set of x in [a,b] such that t
contains an open subset.  Of course we can only get simple
cases.  This will at least let us conclude that
integral(1/sqrt x, x, -1,1) is not defined.
*/

{ unsigned short f = FUNCTOR(t);
  int err;
  if(f == '<' && equals(ARG(0,t),x) && !contains(ARG(1,t),FUNCTOR(x)))
     { err = infer(lessthan(ARG(1,t),b));
       if(!err)
          return 1;
       return 0;
     }
  if(f == '<' && equals(ARG(1,t),x) && !contains(ARG(0,t),FUNCTOR(x)))
     { err = infer(lessthan(a,ARG(0,t)));
       if(!err)
           return 1;
       return 0;
     }
  if(interval_as_and(t) && equals(ARG(1,ARG(0,t)),x) &&
     !contains(ARG(0,ARG(0,t)),FUNCTOR(x)) &&
     !contains(ARG(1,ARG(1,t)),FUNCTOR(x))
    )
     { err = infer(lessthan(a,ARG(0,ARG(0,t))));
       if(!err)
          return 1;
       err = infer(lessthan(ARG(1,ARG(1,t)),b));
       if(!err)
          return 1;
     }
  return 0;
}

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