
/*****************************************************************************\

MODULE: zz_p

SUMMARY:

The class zz_p is used to represent integers mod p
for single-precision p, i.e., 1 <= p < ZZ_RADIX.
Here is a simple program that reads a modulus p,
and then reads two numbers and prints their product mod p.

#include "zz_p.h"

main()
{
   long p;

   cin >> p;  
   zz_pInit(p);

   zz_p a, b, prod;

   cin >> a;  
   cin >> b;
   mul(prod, a, b);
   cout << prod << "\n";
}

Objects of the class zz_p are represented as a zz in the range 0..p-1.

An executing program maintains a "current modulus",
which is set to p using zz_pInit(p).
The current modulus *must* be initialized before any zz_p constructors
are invoked.

The modulus may be changed, and a mechanism is provided
for saving and restoring a modulus.
When the modulus is changed, there may be extant zz_p objects.
These objects may be destroyed at any later time.
If the old modulus was saved and then later restored, these objects can be
used again as if the modulus had never changed.
Note, however, that if a zz_p object is created under
one modulus and then used in any way under another,
this condition is not checked for and program behavior is
not predictable when this happens.

\*****************************************************************************/

#include "ZZ.h"

class zz_p {
public:
   
   zz_p(); // initial value 0
   zz_p(const zz_p& a);
   void operator=(const zz_p& a);
   ~zz_p();
   
   zz_p(INIT_VAL_TYPE, long a);
   // Initial value (a mod p).  Invoke as zz_p(INIT_VAL, a)
   
   static long modulus();
   // returns the current modulus

   static double ModulusInverse();
   // returns inverse of modulus
   
   static zz_p zero();
   // returns 0

   long& LoopHole();
   // read-write access to representation...
   // use only if you know what you are doing.

   static long PrimeCnt;
   // returns # of primes needed for FFT multiplication;
   // a number from 0..4, where 0 means p is an FFT prime.

};


void zz_pInit(long p);
// set the modulus to p, where 1 < p < 2^{ZZ_NBITS}

void zz_pInit(long p, long maxroot);
// Same as above, but somewhat more efficient
// if you are going to perform arithmetic modulo a degree
// n polynomial, set maxroot to NextPowerOfTwo(n)+1.
// This is useful, for example, if you are going
// to factor a polynomial of degree n modulo p, and
// you know n in advance.

void zz_pFFTInit(long i);
// sets modulus to the i-th FFT prime (counting from 0).
// FFT primes are ZZ_NBITS-bit primes p, where
// p-1 is divisible by a high power of two.
// Thus, polynomial arithmetic mod p can be implemented
// particularly efficiently using the FFT.
// As i increases, the power of 2 that divides p-1 gets smaller,
// thus placing a more severe restriction on the degrees of the
// polynomials to be multiplied.

long rep(zz_p a); // returns representation

void clear(zz_p& x); // x = 0

void set(zz_p& x); // x = 1

void swap(zz_p& x, zz_p& y); // swap x and y 

/*****************************************************************************\

                                    Addition

\*****************************************************************************/

void add(zz_p& x, zz_p a, zz_p b); // x = a + b

void add(zz_p& x, zz_p a, long b); // x = a + b 
void add(zz_p& x, long a, zz_p b); // x = a + b


void sub(zz_p& x, zz_p a, zz_p b); // x = a - b 
void sub(zz_p& x, zz_p a, long b); // x = a - b
void sub(zz_p& x, long a, zz_p b); // x = a - b


void negate(zz_p& x, zz_p a); // x = -a

/*****************************************************************************\

                                  Multiplication

\*****************************************************************************/

void mul(zz_p& x, zz_p a, zz_p b); // x = a * b

void mul(zz_p& x, zz_p a, long b); // x = a * b 
void mul(zz_p& x, long a, zz_p b); // x = a * b

void sqr(zz_p& x, zz_p a); // x = a^2

/*****************************************************************************\

                                     Division

\*****************************************************************************/

void div(zz_p& x, zz_p a, zz_p b);
// x = a/b

void div(zz_p& x, zz_p a, long b);
void div(zz_p& x, long a, zz_p b);

void inv(zz_p& x, zz_p a);
// x = 1/a

/*****************************************************************************\

                                  Exponentiation

\*****************************************************************************/

void power(zz_p& x, zz_p a, long e); // x = a^e (e >= 0)

/*****************************************************************************\

                                  Conversion

\*****************************************************************************/

void operator<<(zz_p& x, const ZZ& a); // x = (a mod p)

void operator<<(zz_p& x, long a); // x = (a mod p)

void operator<<(ZZ& x, zz_p a); // x = rep(a)

/*****************************************************************************\

                                  Comparison

\*****************************************************************************/

long IsZero(zz_p a);  // test for 0

long IsOne(zz_p a);  // test for 1

long operator==(zz_p a, zz_p b);
long operator!=(zz_p a, zz_p b);

/*****************************************************************************\

                               Random Elements

\*****************************************************************************/

void random(zz_p& x);
// x = random element in zz_p.
// Uses RandomBnd from zz.

/*****************************************************************************\

                                Input/Output

\*****************************************************************************/

ostream& operator<<(ostream& s, zz_p a);

istream& operator>>(istream& s, zz_p& x);
// a ZZ is read and reduced mod p

/*****************************************************************************\

                              Modulus Switching 

Generally you do the following:

   zz_pBak bak;
   bak.save();   // save current modulus (if any)

   zz_pInit(p);  // set modulus to desired value p

      // ...

   bak.restore(); // restore old modulus (if any)

Note that between the save and restore, you may have
several calls to zz_pInit, each of which simply clobbers
the previous modulus.

\*****************************************************************************/


class zz_pBak {
public:

   zz_pBak();
   ~zz_pBak();

  void save();
   // bak.save() moves the current modulus into bak.
   // It clobbers whatever was previously saved in bak, and effectively
   // makes the current modulus "empty".
   // If this modulus is not restored before the destructor is
   // is called, the destructor will restore it.

   void move();
   // same semantics as save(), except that if this modulus
   // is not restored before the destructor is called, the
   // destructor will not restore it.

   // The main reason for these two different methods is in
   // the context of exceptions: a saved modulus will automatically
   // be restored, while a moved modulus will not.

   void restore();
   // bak.restore() moves the modulus stored in bak into the current modulus.
   // It clobbers the current modulus, and effectively makes the contents
   // of bak "empty"



private:

   zz_pBak(const zz_pBak&);  // disabled
   void operator=(const zz_pBak&);  // disabled
};

