Sindbad~EG File Manager

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

/*
M. Beeson, for Mathpert
Implement the operation "put solution in periodic form"
Original date 7.10.96
last modified 1.29.98
5.5.13 added include periodic.h
8.8.24 changed math.h to sincos.h
2.18.25 and back again
*/

#include <string.h>
#include <math.h>
#include <assert.h>
#include "globals.h"
#include "ops.h"
#include "trig.h"
#include "cancel.h"
#include "prover.h"
#include "probtype.h"
#include "symbols.h"
#include "errbuf.h"
#include "ssolve.h"    /* solved       */
#include "islinear.h"  /* is_linear_in */
#include "algaux.h"    /* topflatten   */
#include "deval.h"     /* deval        */
#include "pvalaux.h"   /* topflatten, twoparts  */
#include "periodic.h" 

/*__________________________________________________________________________*/
int period_aux(term t, term x, term period,term *ans, term *next)
/* x is an atom.  Some unspecified function is periodic with period 'period'.
t is an equation x = c, or an OR or AND of such equations, possibly containing
an existential variable.  Example:  period = 2 pi_term, and t = (2m+1)pi/2.
Then we want *ans = [x = pi_term/2, x = 3pi/2] and *next to be
[x = pi_term/2 + 2m pi_term, x = 3pi/2 + 2m pi].  In general, *ans will be a list of
equations x = c, where the c are seminumerical terms giving all the possible
values of t in one period, and *next will be a corresponding list of
parametrized equations giving all values of t, but such that for each value of
the integer variable m, there values in *next give all the values of t in
one period.  The functor of *ans will be OR if it's a list.
   Return 0 for success, nonzero for failure.  For it to be successful, it must
work on ALL the args of t.  If 1 is returned, *ans and *next are garbage.
   It is possible that equals(*next,t); this is useful when what we really
want are the numerical values in *ans.  If this is not desired, the calling
function must specifically check whether equals(*next,t) or not.
   Return value 2 means that t did not contain an integer parameter.
*/
{ unsigned short n;
  int i,j,err,retval,nvariables;
  unsigned short k;
  term u,m,right,mperiod,temp,aa,b,c,tempans,p,q;
  term *varlist;
  double a  = 0.0,z,dperiod;
  if(FUNCTOR(t) == MULTIPLICITY)
     t = ARG(0,t);
  if(FUNCTOR(t) != '=' && FUNCTOR(t) != OR && FUNCTOR(t) != AND)
     return 1;
  n = ARITY(t);
  if(FUNCTOR(t) == OR || FUNCTOR(t) == AND)
     { temp = make_term(OR,n);
       tempans = make_term(OR,n);
       retval = 1;
       for(i=0;i<n;i++)
          { err = period_aux(ARG(i,t),x,period, ARGPTR(tempans) + i,ARGPTR(temp)+i);
            if(err == 2)
               { ARGREP(tempans,i,ARG(i,t));
                 ARGREP(temp,i,ARG(i,t));
               }
            else if(err)
               return 1;
            else
               retval = 0;
          }
       if(retval == 1)
          return 1;
       *next = topflatten(temp);
       *ans = topflatten(tempans);
       return 0;
     }
  if(FUNCTOR(t) != '=')
     assert(0);
  right = equals(ARG(0,t),x) ? ARG(1,t) : ARG(0,t);
  /* Does t contain an existential integer variable ? */
  nvariables = get_nvariables();
  varlist = get_varlist();
  for(i=0;i<nvariables;i++)
     { m = varlist[i];
       if(ISEXISTENTIALVAR(m) &&
          TYPE(m) == INTEGER &&
          contains(right,FUNCTOR(m))
         )
          break;
     }
  if(i==nvariables)
     return 2;  /* no integer parameter */

  /* OK, it's periodic. Express the solution in the form c + m*period */
  /* find all the integers k such that c = right[m:=k] is in [a,a+period),
     where a is right[m:=0]-period/2 if this is defined,
     or right[m:=j]-period/2 for some j.
     The answer is the OR of terms c + m * period for these values of k.
  */
  /* For now this will only work when c(m) is linear in m */
  if(FRACTION(right) || FUNCTOR(right) == '*')
     { twoparts(right,m,&p,&q);
       if(!islinear(q,m,&aa,&b))
          return 1;
       polyval(product(p,aa),&q);
       aa = q;
     }
  else if(!islinear(right,m,&aa,&b))
     return 1;
  /* if period is already larger than the coefficient of m in right,
     there is nothing to do.  We could of course continue, e.g. expressing
     things in period pi instead of 2pi if the original equation were periodic
     with period pi_term, but there's no way in Mathpert to combine e.g. four
     roots to two, and this function isn't written to do it, so we just don't
     handle that case.  Besides it's a mysterious step if we DO perform it.
  */
  polyval(make_fraction(aa,period),&c);
  /* Not just cancel, because if aa = pi_term and period = pi_term/2, it won't cancel. */
  /* take m=0,1,.. until c(m)-c(0) >= period */
  /* or, if m==0 won't do, try m = 1, ...m = 10 before giving up */
  for(j=0;j<=10;j++)
     { SETVALUE(m,(double) j);
       deval(right,&a);
       if(a != BADVAL)
          break;
     }
  if(j==11)
     return 1;
  deval(period,&dperiod);
  if(dperiod == BADVAL)
     return 1;
  for(k=0;k < 100; k++)
     { SETVALUE(m, (double)(j+k));
       deval(right,&z);
       if(z == BADVAL)
          return 1;
       if(fabs(z-a) > dperiod-VERYSMALL)
          break;
     }
  if(k==100)
     return 1;  /* something's badly wrong, or else this is just
                   a very strange equation. */
  polyval(product(m,period),&mperiod);
  if(k==1)
     { subst(zero,m,right,&temp);
       polyval(temp,&u);
       *ans = equation(x,u);
       *next = equation(x,sum(u, mperiod));
       SETORDERED(ARG(1,*next));  /* prevent reordering -pi/3 + 4n pi */
     }
  else
     { *next = make_term(OR,k);
       *ans = make_term(OR,k);
       for(i=0;i<k;i++)
          { subst(make_int(i),m,right,&temp);
            polyval(temp,&u);
            ARGREP(*ans,i,equation(x,u));
            ARGREP(*next,i,equation(x,sum(u,mperiod)));
            SETORDERED(ARG(1,ARG(i,*next)));  /* prevent reordering -pi/3 + 4n pi */
            SET_ALREADY(ARG(1,ARG(i,*next)));
            SET_ALREADY(ARG(i,*next));
            /* prevent 2m pi + pi/3 =>  (6mpi + pi_term)/3 */
          }
     }
  return 0;
}
/*_______________________________________________________________________*/
int periodic_in(term t, term x, term *period)
/* If t is a function of trig functions of x, all of whose
arguments are multiples of x, return in *period the gcd of
all those multiples, multiplied by 2 pi for trig functions except
TAN and COT, which use pi instead.  Examples:
   if t = sin(2x)/cos(3x) return *period = 2 pi
   if t = sin(2x)/cos(4x) return *period = 4 pi
   if t = sin(x/2)/cos(x/3) return *period = 2 pi *(1/6) = 1/3 pi
   if t = sin(x) / tan(x) return *period = pi_term
Return 0 for success, 1 for not-periodic, 2 for doesn't contain x.
*/
{ unsigned short n,f;
  int i,err,flag = 0;
  term temp,ans,u,c,s;
  if(ATOMIC(t))
     return contains(t,FUNCTOR(x)) ? 1 : 2;
  f = FUNCTOR(t);
  n = ARITY(t);
  if(n == 1)
     { u = ARG(0,t);
       switch(f)
          { case SIN:
            case COS:
            case CSC:
            case SEC:
               if(equals(u,x))
                  { *period = product(two,pi_term);
                    return 0;
                  }
               twoparts(u,x,&c,&s);
               if(!equals(s,x))
                  return 1;
               if(FRACTION(c))
                  polyval(product3(two,pi_term,reciprocal(c)),period);
               else
                  polyval(make_fraction(product(two,pi_term),c),period);
               return 0;
            case TAN:
            case COT:
               if(equals(u,x))
                  { *period = pi_term;
                    return 0;
                  }
               twoparts(u,x,&c,&s);
               if(!equals(s,x))
                  return 1;
               if(FRACTION(c))
                  polyval(product(reciprocal(c),pi_term),period);
               else
                  polyval(make_fraction(pi_term,c),period);
               return 0;
          }
     }
  for(i=0;i<n;i++)
     { err = periodic_in(ARG(i,t),x,&temp);
       if(err == 2)
          continue;
       if(err == 1)
          return 1;
       if(!flag)
          { ans = temp;
            flag = 1;
          }
       else
          naive_lcm(ans,temp,&ans);
     }
  if(!flag)
     return 2;
  *period = ans;
  return 0;
}

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