Sindbad~EG File Manager

Current Path : /home/beeson/Otter-Lambda/yyy/polyval/
Upload File :
Current File : //home/beeson/Otter-Lambda/yyy/polyval/islinear.c

/* M. Beeson, for Mathpert */
/*
7.11.94, moved this ancient code to its own file
1.29.98 last modified
*/

#include <assert.h>
#include <stdlib.h>   /* qsort */
#define POLYVAL_DLL
#include "globals.h"  /* which includes setjmp.h and terms.h */
#include "cancel.h"
#include "pvalaux.h"
#include "order.h"     /* atomorder */
static int atomcompare(const void *x, const void *y);
/*_______________________________________________________________*/
MEXPORT_POLYVAL int is_linear(term t)
/* check if t is a linear term; zero return means it is */
/* this is called by is_linear_system, below */
/* and is also called in chkinput.c          */
{ int err;
  int n,i;
  term u;
  if(FUNCTOR(t) == '+') /* a sum is linear if all its summands are linear */
     { n = ARITY(t);
       for(i=0;i<n;i++)
           { err = is_linear(ARG(i,t));
             if(err)
                return 1;
           }
       return 0;
     }
  if(FUNCTOR(t) == '-')
     return is_linear(ARG(0,t));
  if(ATOMIC(t))
     return 0;   /* an atom or number is linear */
  if(constant(t))
     return 0;   /* any constant is linear */
  if(FUNCTOR(t) == '/')
    { if(constant(ARG(1,t)))  /* linear numerator, constant denom is ok */
         return is_linear(ARG(0,t));
      else
         return 1;
    }
  if(FUNCTOR(t) == '^')
     { if(ONE(ARG(1,t)))    /* x^1 is linear; x^0 isn't */
          return is_linear(ARG(0,t));
       else
          return 1;
     }
  if(FUNCTOR(t) == '*')
     { n = ARITY(t);
       err = 0;
       for(i=0;i<n;i++)
          { u = ARG(i,t);
            if(is_linear(u))  /* remember is_linear returns non-zero for error */
               return 1;
            if(!constant(u))
               { if(err)
                    return 1;  /* second non-constant factor */
                 err =1;
               }
          }
       return 0;  /* at most one non-constant factor, and that one linear */
     }
   return 1;   /* no other functors legal */
}
/*_______________________________________________________________*/
MEXPORT_POLYVAL int is_linear_system(term t, int linenumber, term *vlist)
/* called from getprob.c to test input.  (User gets a chance in getprob.c
to name some variables parameters to make it pass this test.)  It's also
called in show2d to see whether to make a LINEARSYSTEMS term so that
a linear system can be displayed with variables lined up, and
similarly in lterm.c  */
/* Zero return means it passed, it is a linear system */
/* A linear system in ONE variable is considered legal here. */
/* In case of success, *vlist is used to return an AND term which is a
list of all the variables used in this linear system.  Parameters
are not included. */
/* t is supposed to already be checked to be an AND term; the arguments
of t may be equations, but if they aren't, enhance_problem is going to
set them equal to zero, so they don't HAVE to be equations when this
function is called. */
/* temp is return as an AND of variables; space for the args is
made here. */

{ int k = ARITY(t);  /* number of equations */
  int i,err,index;
  unsigned short natoms;
  term u,temp;
  term *atomlist;
  parameter *parameters;
  assert(FUNCTOR(t)==AND);
  for(i=0;i<k;i++)
     { u = ARG(i,t);
       if(FUNCTOR(u) == '=')
          { err = is_linear(ARG(0,u));
            if(err)
               return 1;
            err = is_linear(ARG(1,u));
            if(err)
               return 1;
          }
       else
          { err = is_linear(u);
            if(err)
               return 1;
          }
     }
   /* Now determine the variables involved */
   natoms = variablesin(t,&atomlist);
   temp = make_term(AND,natoms);
   parameters = get_parameters();
   k = 0;
   for(i=0;i<natoms;i++)
      { index = isparameter(atomlist[i]);
        if(index >= 0 && parameters[index].linenumber <= linenumber)
           continue;  /* don't count this atom, it's a parameter */
        /* We check when it became a parameter; the user can use
           regardvarasconst to make a variable a parameter, but we
           still call this function to paint earlier lines and
           they need to use the variables that were not parameters
           at that point. */
        ARGREP(temp,k,atomlist[i]);
        ++k;
      }
   SETFUNCTOR(temp,AND,k);
   if(k > 1)
      sortatoms(ARGPTR(temp), ARITY(temp));
   *vlist = temp;
   free2(atomlist);
   return 0;
}
/*__________________________________________________________*/

static int atomcompare(const void *x, const void *y)
/* used by qsort to sort atoms */
{ term a,b;
  unsigned f,g;
  a = * (term *) x;
  b = * (term *) y;
  f = FUNCTOR(a);
  g = FUNCTOR(b);
  return atomorder(f,g);
}
/*____________________________________________________________________*/
MEXPORT_POLYVAL int islinear(term t, term x, term *a, term *b)
/* return 1 if t is of the form ax +b, or x+b, or ax, or x, or -x, or -ax,
instantiating a and b; match both orders of the summands.
Of course a and b must not contain x.  Note that b can be a sum
such as 2 + sqrt 2, so t can be a sum of arity 3 or more.
Return zero if not of this form.  Returns 0 on ax + bx + c;
there must be just ONE term containing x.
*/

{ term u,v,cancelled;
  int err,flag;
  int sign = 1;
  unsigned short i,n;
  if(equals(t,x))
     { *a = one;
       *b= zero;
       return 1;
     }
  if(ISATOM(t))
     return 0;
  if(OBJECT(t))
     { *a = zero;
       *b = t;
       return 1;
     }
  if(NEGATIVE(t))
     { u = ARG(0,t);
       if(equals(u,x))
          { *a = minusone;
            *b = zero;
            return 1;
          }
       if(FUNCTOR(u) == '*')
          { if(!islinear(u,x,a,b))
               return 0;
            assert(ZERO(*b));
            *a = tnegate(*a);
            return 1;
          }
     }
  if(FUNCTOR(t) == '*')
      { if(ARITY(t)==2 && equals(ARG(1,t),x) && !contains(ARG(0,t),FUNCTOR(x)))
           { *b = zero;
             *a = ARG(0,t);
             return 1;
           }
               /* this avoids calling cancel in common cases */
        err = cancel(t,x,&cancelled,a);
        if(!err &&  !contains(*a,FUNCTOR(x)) && equals(x,cancelled))
           { *b = zero;
             return 1;
           }
        return 0;  /* failure */
      }
  if(FUNCTOR(t) == '+')
      { n = ARITY(t);
        flag = 0;
        for(i=0;i<n;++i)
           { if(contains(ARG(i,t),FUNCTOR(x)))
                { if(flag)
                     return 0;
                  flag = i+1;
                }
           }
        if(!flag)     /* no term containing x found */
           return 0;  /* constants don't count as linear here */
        u = ARG(flag-1,t);
        if(n==2)
           v = ARG(flag == 1 ? 1 : 0, t);
        else
           { v = make_term('+', (unsigned short)(n-1));
             for(i=0;i<(unsigned)(n-1);i++)
                ARGREP(v,i,ARG(i+1 < flag ? i : i+1,t));
           }
        *b = v;
        if (FUNCTOR(u) == '-')
           { sign = -1;
             u = ARG(0,u);
           }
        if(equals(u,x))
            { *a = sign < 0 ? minusone : one;
              return 1;
            }
        else if (FUNCTOR(u) != '*')
           return 0; /* failure */
        else if(ARITY(u) == 2 && equals(ARG(1,u),x) && !contains(ARG(0,u),FUNCTOR(x)))
            { *a = ARG(0,u);
              if(sign < 0)
                 *a = tnegate(*a);
              return 1;
            }
            /* the above avoids calling cancel in common cases */
        err = cancel(u,x,&cancelled,a);
        if(!err && !contains(*a,FUNCTOR(x)) && equals(x,cancelled))
            { if(sign < 0)
                 *a = tnegate(*a);
              return 1;
            }
        return 0;
      }
  return 0;
}
/*______________________________________________________*/
MEXPORT_POLYVAL void sortatoms(term *data, unsigned n)
/* data is an array of n atoms.  Sort them (in place) */
{  qsort(data, n, sizeof(term), atomcompare);
}
/*______________________________________________________*/
MEXPORT_POLYVAL int is_linear_in(term t, term x)
/* return 1 if t is linear in x, 0 if not.  Compare to
islinear and is_linear (which won't accept non-linear constant terms)
in enhance.c.  Will accept a linear equation or inequality as well
as a linear function of x. */

{ unsigned f = FUNCTOR(t);
  unsigned i,n;
  term c,s;
  if(ATOMIC(t))
     return 1;
  if(f == '-')
     return is_linear_in(ARG(0,t),x);
  if(INEQUALITY(f))
     return is_linear_in(ARG(0,t),x) && is_linear_in(ARG(1,t),x);
  if(f == '+')
     { n = ARITY(t);
       for(i=0;i<n;i++)
          { if(!is_linear_in(ARG(i,t),x))
               return 0;
          }
        return 1;
     }
  if(f == '*' || f == '/')
     { twoparts(t,x,&c,&s);
       if(ATOMIC(s))
          return 1;
       if(FUNCTOR(s) == '+')
          return is_linear_in(s,x);
       /* if the input is 2(-2x) for example, we get here with s = -2x */
       if(!ONE(c))
          return is_linear_in(s,x);
       return 0;
     }
  if(!contains(t,FUNCTOR(x)))
     return 1;
  return 0;
}

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