

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

MODULE: zz_pE

SUMMARY:

The class zz_pE is used to represent polynomials in Z_p[X] modulo a
polynomial P.  The modulus P may be any polynomial with deg(P) > 0,
not necessarily irreducible.  The modulus p defining Z_p need
not be prime either.

Objects of the class zz_pE are represented as a zz_pX of degree < deg(P).

An executing program maintains a "current modulus", which is set to P
using zz_pE::init(P).  The current modulus for zz_pE (as well as for zz_p)
*must* be initialized before an operations on zz_pE's are performed.

The modulus may be changed, and a mechanism is provided for saving and
restoring a modulus (see classes zz_pEPush and zz_pEContext below).

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

#include <NTL/lzz_pX.h>

class zz_pE {
public:
   
   zz_pE(); // initial value 0

   zz_pE(const zz_pE& a); // copy constructor
   explicit zz_pE(const zz_p& a); // promotion 
   explicit zz_pE(long a); // promotion 
   
   zz_pE& operator=(const zz_pE& a); // assignment
   zz_pE& operator=(const zz_p& a); // assignment
   zz_pE& operator=(long a); // assignment
   
   ~zz_pE(); // destructor

   void init(const zz_pX& P);
   // zz_pE::init(P) initializes the current modulus to P;
   // required: deg(P) >= 1.
   
   static const zz_pXModulus& modulus();
   // zz_pE::modulus() yields read-only reference to the current modulus 

   static long degree();
   // zz_pE::degree() returns deg(P)

   // typedefs to aid generic programming
   typedef zz_pX rep_type;
   typedef zz_pEContext context_type;
   typedef zz_pEBak bak_type;
   typedef zz_pEPush push_type;
   typedef zz_pEX poly_type;

};


const zz_pX& rep(const zz_pE& a); // read-only access to representation of a



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

                                  Comparison

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

long operator==(const zz_pE& a, const zz_pE& b);
long operator!=(const zz_pE& a, const zz_pE& b);

long IsZero(const zz_pE& a);  // test for 0
long IsOne(const zz_pE& a);  // test for 1

// PROMOTIONS: ==, != promote {long, zz_p} to zz_pE on (a, b).


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

                                    Addition 

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

// operator notation:

zz_pE operator+(const zz_pE& a, const zz_pE& b);

zz_pE operator-(const zz_pE& a, const zz_pE& b);
zz_pE operator-(const zz_pE& a);

zz_pE& operator+=(zz_pE& x, const zz_pE& a);
zz_pE& operator+=(zz_pE& x, const zz_p& a);
zz_pE& operator+=(zz_pE& x, long a);

zz_pE& operator++(zz_pE& x); // prefix
void operator++(zz_pE& x, int); // postfix

zz_pE& operator-=(zz_pE& x, const zz_pE& a);
zz_pE& operator-=(zz_pE& x, const zz_p& a);
zz_pE& operator-=(zz_pE& x, long a);

zz_pE& operator--(zz_pE& x); // prefix
void operator--(zz_pE& x, int); // postfix

// procedural versions:

void add(zz_pE& x, const zz_pE& a, const zz_pE& b); // x = a + b
void sub(zz_pE& x, const zz_pE& a, const zz_pE& b); // x = a - b 
void negate(zz_pE& x, const zz_pE& a); // x = - a 

// PROMOTIONS: +, -, add, sub promote {long, zz_p} to zz_pE on (a, b).


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

                                  Multiplication 

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


// operator notation:

zz_pE operator*(const zz_pE& a, const zz_pE& b);

zz_pE& operator*=(zz_pE& x, const zz_pE& a);
zz_pE& operator*=(zz_pE& x, const zz_p& a);
zz_pE& operator*=(zz_pE& x, long a);

// procedural versions:


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

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

// PROMOTIONS: *, mul promote {long, zz_p} to zz_pE on (a, b).



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

                                     Division

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


// operator notation:

zz_pE operator/(const zz_pE& a, const zz_pE& b);

zz_pE& operator/=(zz_pE& x, const zz_pE& a);
zz_pE& operator/=(zz_pE& x, const zz_p& a);
zz_pE& operator/=(zz_pE& x, long a);


// procedural versions:

void div(zz_pE& x, const zz_pE& a, const zz_pE& b);
// x = a/b.  If b is not invertible, an error is raised.

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

PROMOTIONS: /, div promote {long, zz_p} to zz_pE on (a, b).


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

                                  Exponentiation

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



void power(zz_pE& x, const zz_pE& a, const ZZ& e); 
zz_pE power(const zz_pE& a, const ZZ& e);

void power(zz_pE& x, const zz_pE& a, long e); 
zz_pE power(const zz_pE& a, long e);

// x = a^e (e may be negative)



/************************************************                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            