Sindbad~EG File Manager

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

/* factoring integers and Gaussian integers for MathXpert */
/*
5.12.91 original date
6.14.98 modified
12.21.99  added a missing 8 in memory allocation in factor_integer.
3.27.00 modified factor_gaussian_integer near the end.
3.27.00 modified gtest
4.6.04 moved primality_test to bigmod.c 
6.17.04 removed conditional 16-bit compilation.
3.17.06 removed include heap.h (it's already indirectly included)
3.18.23 added two assert(0)'s  in factor_integer, to suppress warnings
*/


#include <math.h>
#include <string.h>
#include <assert.h>
#include "globals.h"
#include "dcomplex.h"
#include "algaux.h"
#include "factor.h"
#include "nfactor.h"
#include "symbols.h"
#include "progress.h"
#include "errbuf.h"
#include "pvalaux.h"

static int factorprime_aux(term, term *);
static void sumof2squares(unsigned long, unsigned long *, unsigned long *);
static int  fgi_aux(term, unsigned *, term *);
static term fgi_simp(term);  /* public so can be called from factquad.c */

/* _______________________________________________________________*/
int factor_gaussian_integer(term t, unsigned *nfactors, term *ans)
/* if t is a term representing a complex integer, it will be factored as much
as possible by removing 16-bit factors, arriving at a product of
Gaussian primes, Gaussian prime powers, and unfactored Gaussian bignums
of at least 17 bits (in the real or imag part).  If a unit is required,
i will be put in as the first factor (for i or -i), and if required *ans will
be negated (if the unit is -1 or -i).
(If there is only one non-unit factor, and it's 32 bits or less in both parts,
it's prime.)
The possible outcomes and return values are as follows:

-1:  input not a Gaussian integer (or zero)
0:   success, t factors into a product of Gaussian primes and prime powers
2:   number is certainly prime (or is 1); then t is returned in *ans
4:   some 16-bit factors found but an unfactored bignum
          (more than 32 bits) remains.
6:   the input has no 16-bit factors
8:   user interrupted by pressing Esc

The number of distinct factors (prime, prime-power, or unfactored),
NOT COUNTING THE UNIT IF THERE IS ONE, is returned in nfactors.

If t represents 1,  *nfactors is returned as 0 and *ans = one,
and the official return value is 0  (success) */

{ term a,b,temp,u,oneplusi;
  int err;
  int sign=1;
  unsigned short k=0;
  unsigned short i;
  unsigned nreal;
  if(ONE(t))
    { *nfactors = 1;
      *ans = one;
      return 2;
    }
  parts(t,&a,&b);
  if(FUNCTOR(b) == '-' && FUNCTOR(a) == '-')   /* third quadrant */
    { err = factor_gaussian_integer(make_complex(ARG(0,a),ARG(0,b)),nfactors,&temp);
      if(err)
         return err;
      tneg(temp,ans);
      return 0;
    }
  if(FUNCTOR(b) == '-')  /* fourth quadrant */
    { err = factor_gaussian_integer(make_complex(ARG(0,b),a),nfactors,&temp);
      if(err) return err;
      if(FUNCTOR(temp)=='-')
         *ans = product(complexi,ARG(0,temp));
      else
         tneg(product(complexi,temp),ans);
      return 0;
    }
  if(FUNCTOR(a) == '-')   /* second quadrant */
    { err = factor_gaussian_integer(make_complex(b,ARG(0,a)), nfactors,&temp);
      if(err) return err;
      if(FUNCTOR(temp)=='-')
         *ans = tnegate(product(complexi,ARG(0,temp)));
      else
         *ans = product(complexi,temp);
      return 0;
    }
    /* Now the input has to be in the first quadrant */
  if(!INTEGERP(a) || !INTEGERP(b))
      return -1;  /* input not a Gaussian integer */
  if(!ZERO(b))
     return fgi_aux(t,nfactors,ans);
  if(ZERO(b))  /* factor a rational integer into complex factors */
     { err = factor_integer(a,&nreal,&u);
       if(err == 8)  
          return 8;   /* user interrupted computation */
       if(nreal == 1)  /* a is rational prime or rational prime power */
                       /* or an unfactored bignum */
           {
             if(FUNCTOR(u) == '^' && equals(ARG(0,u),two))  /* power of 2 */
                      /* The correct factorization of 2 is -i(1+i)^2 */
                { term temp0;
                  oneplusi = make_complex(one,one);
                  mult(two,ARG(1,u),&temp0);
                  switch( ((unsigned) INTDATA(ARG(1,u))) & 3)
                     { case 0: *ans = make_power(oneplusi,temp0);
                               break;
                       case 1: tneg(product(complexi,make_power(oneplusi,temp0)),ans);
                               break;
                       case 2: tneg(make_power(oneplusi,temp0),ans);
                               break;
                       case 3: *ans = product(complexi,make_power(oneplusi,temp0));
                               break;
                     }
                  HIGHLIGHT(*ans);
                  return 0;
                }
             if(equals(u,two))
                { oneplusi = make_complex(one,one);
                  tneg(product(complexi,make_power(oneplusi,two)),ans);
                  HIGHLIGHT(*ans);
                  return 0;
                }
             err = factorprime_aux(u,ans);  /* Now u isn't a power of 2 */
             if(err)
                return 1;   /* wrong input somehow */
             if(ATOMIC(*ans))
                 { *nfactors = 1;
                   return (TYPE(*ans) == BIGNUM ? 4 : 2);
                 }
             if(FUNCTOR(*ans) == '^')
                   {*nfactors = 1;
                    return 0;
                   }
             if(FUNCTOR(*ans) == '*')
                   {*nfactors = ARITY(*ans);
                    assert(*nfactors==2);
                   }
             return 0;
           }

       /* Now a has more than one prime factor.  Factor them separately
          into Gaussian primes */
       /* Each prime factor generates either:
              [a unit times] a power of (1+i) (in case of 2)
              a product  p^n(p-bar)^n or p(p-bar) (primes of form 4n+1)
              a product p^n or p (primes of form 4n+3) */

       *ans = make_term('*', (unsigned short) (2*nreal));  /* at most twice as many factors */
       for(i=0;i<nreal;i++)
          { factorprime_aux(ARG(i,u),&temp);
            if(FUNCTOR(temp)=='-')
               { sign = -1;
                 temp = ARG(0,temp);
               }
            if(FUNCTOR(temp) == '*')
               { ARGREP(*ans,k,ARG(0,temp));
                 ++k;
                 ARGREP(*ans,k,ARG(1,temp));
                 ++k;
               }
            else
               { ARGREP(*ans,k,temp);
                 ++k;
               }
          }
       SETFUNCTOR(*ans,'*',k);
       if(sign == -1)
          { temp = *ans;
            tneg(temp,ans);
          }
       HIGHLIGHT(*ans);
       *nfactors = k;
       /* Was the first factor i? */
       if(NEGATIVE(*ans))
          temp = ARG(0,ARG(0,*ans));
       else
          temp = ARG(0,*ans);
       if(equals(temp,complexi))
           --(*nfactors);
       return 0;
     }
  return 1;
}

/*_________________________________________________________________*/
static int  factorprime_aux(term temp, term *next)
/* temp is a rational prime or rational prime power.  Factor it
into a product of Gaussian primes or prime powers.  Return 0
for success.  In case temp is 2 or a power of 2, the answer
can also contain a factor of 'i' and can be negated.  */

{ term p,temp0, temp1,oneplusi,a,b,k;
  unsigned long d,pp,aa,bb;
  if(FUNCTOR(temp) == '^')  /* prime power */
      p = ARG(0,temp);  /* the rational prime */
  else
      p = temp;
  if(equals(p,two))   /* Note:  1-i is not prime, since (1-i) = -i(1+i) and -i is a unit */
                      /* The correct factorization of 2 is -i(1+i)^2 */
      { oneplusi = make_complex(one,one);
        if(FUNCTOR(temp) == '^')
           { mult(two,ARG(1,temp),&temp0);
             switch( ((unsigned) INTDATA(ARG(1,temp))) & 3)
                { case 0: *next = make_power(oneplusi,temp0);
                          break;
                  case 1: tneg(product(complexi,make_power(oneplusi,temp0)),next);
                          break;
                  case 2: tneg(make_power(oneplusi,temp0),next);
                          break;
                  case 3: *next = product(complexi,make_power(oneplusi,temp0));
                          break;
                }
           }
        else
           { temp0 = product(complexi,make_power(oneplusi,two));
             tneg(temp0,next);
           }
        HIGHLIGHT(*next);
        return 0;
      }
  /* Now:  is p congruent to 1 or to 3 mod 4?  */
  if(TYPE(p) == INTEGER)
      d = INTDATA(p) -1;
   else
      { assert(TYPE(p) == BIGNUM);
        d = BIGNUMDATA(p).val[0] -1;
      }
   if( (d >> 1) & 1)  /* p congruent to 3 mod 4 */
     { *next = temp;
       HIGHLIGHT(*next);
       return 0;
     }
   else  /*  p congruent to 1 mod 4 */
     { if(TYPE(p) == BIGNUM)
          { if(BIGNUMDATA(p).ln > 2)
               return 1;  /* can't (and don't have to) handle bignum primes */
            if(BIGNUMDATA(p).ln == 1)
               pp = BIGNUMDATA(p).val[0];
            else
               return 1;
          }
       else
          pp = INTDATA(p);
       sumof2squares(pp,&aa,&bb);  /* write pp = a^2+b^2 */
       a = make_int(aa);
       b = make_int(bb);
       temp1 = make_complex(a,b);
       temp0 = make_complex(a,tnegate(b));
       if(FUNCTOR(temp) == '^')
          { *next = make_term('*',2);
            k = ARG(1,temp);
            ARGREP(*next,0,make_power(temp0,k));
            ARGREP(*next,1,make_power(temp1,k));
          }
       else
          *next = product(temp0,temp1);
       HIGHLIGHT(*next);
       return 0;
     }
}

/*_______________________________________________________________________*/
static void sumof2squares( unsigned long p, unsigned long *a, unsigned long *b)
/* given a rational prime p congruent to 1 mod 4, find positive integers
a and b such that p = a^2 + b^2. */
{ unsigned long i,j,c,looplimit;
  double epsilon = 1.0e-12;  /* less than 1/ (twice the maximum unsigned long) */
  looplimit = (unsigned long) sqrt((double) p);
  for(i=0;i<looplimit;i++)
    { c = p - i*i;
      j = (unsigned long) (sqrt(c) + epsilon); /* epsilon for round-off problems */
      if(j*j==c) break;  /* success, c was a perfect square */
    }
  assert(i<p);  /* every prime of stated form has a solution */
  *a = i;
  *b = j;
}

/*__________________________________________________________________________*/
int gtest(term p, term r, term q, term s, term b, int sign, term *ansp, term *ansr, term *ansq, term *anss)
/* public because mentioned in an equality test in advfact.c */
/* Passed as function parameter to finish_factor_aux by fgi_aux.  See
specs for test() in factor.c, which is also passed to finish_factor_aux.
Here q and s will be passed as 'one' so do not need to be copied.
Test whether p multiplies out to the complex number b, up to a unit;
return the required unit (or 'one') in  *anss.  */
/* Return 0 if the test is passed, 1 if not */

{ int err;
  aflag flag = get_arithflag();
  term val,temp;
  flag.complex = 1;
  flag.varadd = 1;
  flag.complexpowers = 1;
  err = arith(p,&val,flag);
  if(err) 
     return err;
  if(equals(val,b))
     { copy(p,ansp);
       copy(r,ansr);
       *ansq = *anss = one;
       return 0;
     }
  if(equals(strongnegate(val),b))
     { copy(p,ansp);
       copy(r,ansr);
       *ansq = one;
       *anss = minusone;
       return 0;
     }
   cmult(complexi,val,&temp);
   if(equals(temp,b))
     { copy(p,ansp);
       copy(r,ansr);
       *ansq = one;
       *anss = complexi;
       return 0;
      }
   if(equals(strongnegate(temp),b))
      { copy(p,ansp);
        copy(r,ansr);
        *ansq = one;
        tneg(complexi,anss);
        return 0;
      }
  return 1;
}
/*_____________________________________________________________________*/
static int  fgi_aux(term t ,unsigned *nfactors,term *ans)
/* Factor t = a+bi into a product
Gaussian primes or prime powers, possibly with an initial '-' and/or factor of i.
The value returned in *nfactors is the number of distinct Gaussian prime
factors, counting any unfactored 17-bit-or-longer portion, but not counting
the factor of i (if there is one).
It is assumed that b is not zero.
Method: compute the absolute value squared of a + bi, and factor that; then
try products of powers of primes in that factorization.
Zero return value is success.
Return 2 with *ans = t and *nfactors = 1 if t is already a Gaussian prime
Other nonzero returns are various failures.
 */
{ term a,b,p,q,r,s,u,magsq,temp;
  int err,i;
  unsigned m;
  long nn,mm;
  parts(t,&a,&b);
  mult(a,a,&p);
  mult(b,b,&q);
  add(p,q,&magsq);     /* magsq = |a+bi|^2  */
  err = factor_gaussian_integer(magsq,&m,&u);  /* r is real */
      /* but there still can be a unit, from factors of 2 in magsq */
  if(err)
     { *ans = t;
       return err;
     }
  if(FUNCTOR(u) == '-')
     u = ARG(0,u);   /* later we'll choose the right unit */
  if(FUNCTOR(u) == '*' && equals(ARG(0,u),complexi)) /* then discard the factor of i */
     { if(ARITY(u) == 2)
           u = ARG(1,u);
       else
          { temp = make_term('*',(unsigned short) (ARITY(u)-1));
            for(i=0;i<ARITY(temp);i++)
               ARGREP(temp,i,ARG(i+1,u));
            u = temp;
          }
     }
  if(FUNCTOR(u)=='^')
     { /* only one prime involved, it must be a rational prime, or (1+i) */
       /* if (1+i), and 2^e is the power of 2 in a+bi, then (1+i)^4e
          occurs in u */
       p = ARG(0,u);
       assert(ISINTEGER(ARG(1,u)));
       nn = INTDATA(ARG(1,u));
       assert(!(nn&1));  /* nn is even */
       mm = nn >> 1;
       if(nn==2)
          temp = p;
       else
          temp = make_power(p,make_int(mm));
       *nfactors = 1;
       /* Now compute the unit to throw in */
       parts(p,&a,&b);
       assert(mm <= 0xffff);
       complexfastexp(a,b, (unsigned) mm,&r);
       if(equals(r,t))
          *ans = temp;
       else if(equals(strongnegate(r),t))
          tneg(temp,ans);
       else
          { cmult(complexi,r,&q);
            cmult(complexi,temp,&s);
            if(equals(q,t))
               *ans = s;
            else
               tneg(s,ans);
          }
       HIGHLIGHT(*ans);
       return 0;
     }
  assert(FUNCTOR(u)=='*');
  err = finish_factor_aux(u,one,gtest,t,1,&p,&q,&r,&s);
  /* search until pr = u, q=s=1, and  p multiplies out to equal a+bi up to a unit */
  /* The required unit is returned in s */
  if(err) 
     return err;
   /* p is a product of powers, including some with exponents 0 and 1,
      or a negation of such a product */
   /* get rid of those superfluous factors and exponents */
  p = fgi_simp(p);
  if(ATOMIC(p) || FUNCTOR(p) == '^')
     *nfactors = 1;
  else if(FUNCTOR(p) == '*')
     *nfactors = ARITY(p);
  else if(FUNCTOR(p) == '-')
     { if(ATOMIC(ARG(0,p)) || FUNCTOR(ARG(0,p))=='^')
           *nfactors = 1;
       else if(FUNCTOR(ARG(0,p))=='*')
           *nfactors = ARITY(ARG(0,p));
       else assert(0);
     }
  else
     { *nfactors = 1;  /* input was prime, because p came out to the form a+bi */
       *ans = t;
       return 2;
     }
  if(equals(s,one))
     *ans = p;
  else if(equals(s,minusone))
     tneg(p,ans);
  else if(equals(s,complexi))
     { if(FUNCTOR(p)=='-')
          *ans = tnegate(product(complexi,ARG(0,p)));
       else
          *ans = product(complexi,p);
     }
  else if(FUNCTOR(s) == '-')  /* s = -i */
     { if(FUNCTOR(p) == '-')
           *ans = product(complexi,ARG(0,p));
       else
           tneg(product(complexi,p),ans);
     }
  HIGHLIGHT(*ans);
  return 0;
}
/*_________________________________________________________*/
static term fgi_simp(term t)
/* apply the laws a^0 = 1 and a^1 = a and a*1 = a,
   not fully recursively, just enough for fgi_aux */
{ unsigned short f = FUNCTOR(t);
  unsigned short k,n = ARITY(t);
  int i;
  term ans,temp;
  if(ATOMIC(t))
     return t;
  if(f =='^')
    { if(ZERO(ARG(1,t)))
         return one;
      if(ONE(ARG(1,t)))
         return ARG(0,t);
      return t;
    }
  if(f== '-')
    { tneg(fgi_simp(ARG(0,t)),&ans);
      return ans;
    }
  if(f=='*')
    { ans = make_term('*',n);
      k = 0;
      for(i=0;i<n;i++)
         { temp = fgi_simp(ARG(i,t));
           if(!ONE(temp))
               { ARGREP(ans,k,temp);
                 ++k;
               }
          }
      if(k==0)
          { RELEASE(ans);
            return one;
          }
      if(k==1)
          { temp = ARG(0,ans);
            RELEASE(ans);
            return temp;
          }
      SETFUNCTOR(ans,'*',k);
      return ans;
    }
  return t;
}

/*_______________________________________________________________*/
int factor_integer(term t, unsigned *nfactors, term *ans)
/* if t is a term representing an integer, it will be factored as much
as possible by removing 16-bit factors, arriving at a product of
primes, prime powers, and unfactored bignums of at least 17 bits.
(If there is only one of these and it's 32 bits or less, it's prime.)
The possible outcomes and return values are as follows:

0:   success, t factors into a product of primes and prime powers
1:   inappropriate input
2:   number is certainly prime (or is 1); then *ans is returned as t.
4:   some 16-bit factors found but an unfactored bignum
          (more than 32 bits) remains which is definitely composite
5:   some 16-bit factors found but an unfactored bignum
          (more than 32 bits) remains which is probably prime
6:   the input has no 16-bit factors but is definitely composite
7:   the input has no 16-bit factors and is probably prime
8:   user interrupted the computation by pressing Esc before all 16-bit factors
          were found (or not found)
10:  probabilistically prime
11:  no more space

The number of distinct factors (prime, prime-power, or unfactored)
is returned in nfactors.

If t represents 1,  *nfactors is returned as 0 and *ans = one,
and the official return value is 0  (success) */

{ unsigned *workspace;
     /* a 32-bit number has at most 17 prime factors */
     /* an n-bit number has at most 11 + n/5  prime factors */
     /* workspace must have TWO digits for each prime factor */
  unsigned long x;  /* number to be factored */
  unsigned long q;  /* 17-to-32 bit unfactored part */
  int n;            /* how many distinct factors */

  if (! OBJECT(t))
     return 1;
  if(ZERO(t))
     return 1;
  if(TYPE(t)==BIGNUM &&   /* and the bignum is more than 32 bits */
     (BIGNUMDATA(t).ln > 2 || (BIGNUMDATA(t).ln > 1 && sizeof(digit) > 2))
    )
        { bignum b,rest;
          term temp;
          int err;
          unsigned sofar;
          term showit = make_int(100L);
          b = BIGNUMDATA(t);

          workspace = (unsigned *) callocate(b.ln *sizeof(digit)*8 / 5 + 11,2*sizeof(digit));
          /* sizeof(digit) is in bytes, so multiply by 8 to get bits */
          if(workspace==NULL)
             { nospace();
               return 11;
             }
          sofar = 0;
          err = get_small_factors(b,workspace,&n,&rest,&sofar);
          *nfactors = n;
             /* err == 0 means it factored as a product of 16-bit integers */
             /* n is in that case the number of prime factors */
             /* err == 1 means rest is 17 to 32 bits and prime,
                       and n is 1 + the number of 16-bit factors found */
             /* err == 2 means rest is more than 32 bits */
          if(err==2)
             { err = primality_test(rest);
               if(err)  /* rest is composite */
                  err = 4;
               else
                  err = 5;
             }
          if(err==0)  /* it factored as a product of 16-bit integers */
             { q=1;
               finish_factor(n,workspace,q,ans);
               free2(workspace);
               if(OBJECT(*ans))
                   return 2;   /* it's prime */
               return 0;
             }
          else if(n==1)  /* no small factors */
             { free2(workspace);
              *ans = t;
              if(err==4)
                  return 6;   /* failure to factor but is composite */
              else
                  return 7;   /* failure to factor but is probably prime */
             }
          finish_factor(n-1,workspace,1L,&temp);
          free2(workspace);
          *ans = product(temp,make_bignum(rest));
          HIGHLIGHT(*ans);
          RELEASE(showit);
          return (err == 1 ? 0 : 4);
        }
  if (TYPE(t)==INTEGER)
      x =  (unsigned long) INTDATA(t);  /* the data is a signed long */
  else if (TYPE(t)==BIGNUM)  /* and the bignum can be expressed in 32 bits */
     { bignum b;
       b = BIGNUMDATA(t);
       if(b.ln == 1)  /* 32 bit bignums */
          x = b.val[0];
       else if(b.ln == 2 && sizeof(digit)==2)  /* 16-bit bignums */
          x = b.val[0] | (((unsigned long) b.val[1]) << 16);
       else
          assert(0);
     }
  else
     assert(0);
  if(x==1)
     { *ans = one;
       *nfactors = 0;
       return 2;
     }
  workspace = (unsigned *) callocate(17, sizeof(unsigned));
  if(workspace==NULL)
     { nospace();
       return 11;
     }
  n = smallfactors(x,workspace,&q);
  if(q != 1)
    ++n;
  *nfactors = n;
  finish_factor(n,workspace,q,ans);
  HIGHLIGHT(*ans);
  free2(workspace);
  if(OBJECT(*ans))
     return 2;
  return 0;
}

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