

//
// LiDIA - a library for computational number theory
//   Copyright (c) 1995 by the LiDIA Group
//
// File        : crt_table.h
//		
// Author      : Frank J. Lehmann (FL), Thomas Pfahler (TPF)
// Last change : FL, Dec 5 1995, initial version
//



#ifndef LIDIA_CRT_TABLE_H
#define LIDIA_CRT_TABLE_H

#include <LiDIA/bigint.h>
#include <LiDIA/bigmod.h>
#include <LiDIA/base_vector.h>
  
#define SDIGIT_MAX 0x7fffffff



/***************************************************************

				  class crt_table

****************************************************************/

class crt_table
 {
     friend class crt ;

     public :

       static const char MODULAR ;
       static const char INTEGER ;


     private :

       base_vector<sdigit> primes ;
       lidia_size_t num_primes ;               

       char mode ;     
       bigint p  ;     
               
       lidia_size_t reference_counter;
	
       base_vector<bigint> coeff_mod_p ;
       base_vector<double> x           ;

       bigint M, M_over_2 ;
       bigint minus_M_mod_p ; 	 // = - (product of all primes) mod p

       sdigit (*NEXT_PRIME) ( const sdigit & q ) ;
	
       static sdigit next_prime ( const sdigit & udq ) ;     

       void gen_primes (       bigint  B ,  const sdigit & bound ) ;
       void set_primes ( const base_vector< sdigit > & Prime_vec ) ;
 
       void build_tables ( void ) ;

     private :

       inline void SINGLE_REMAINDER(sdigit &s, const bigint &b, lidia_size_t index)
	{
	  remainder(s, b, primes[index]);
	}
     
       inline void SINGLE_REMAINDER(sdigit &s, const bigmod &b, lidia_size_t index)
	{
	  remainder(s, b.mantissa(), primes[index]);
	}
     
       inline void MULTI_REMAINDER(sdigit *s, const bigint *b, lidia_size_t bsize, lidia_size_t index)
	{
	  for (lidia_size_t i=0; i<bsize; i++)
	   {
	     remainder(s[i], b[i], primes[index]);
	   }
	}
     
       inline void MULTI_REMAINDER(sdigit *s, const bigmod *b, lidia_size_t bsize, lidia_size_t index)
	{
	  for (lidia_size_t i=0; i<bsize; i++)
	   {
	     remainder(s[i], b[i].mantissa(), primes[index]);
	   }
	}
     
     inline void NORMALIZE ( bigint & big , bigint & p_over_2 , const bigint & pr )
       {
	 if ( big.is_positive() )
	   {
	     if ( big >= p_over_2 )
	       subtract ( big, big, pr ) ;
	   }
	 else
	   {
	     p_over_2.negate() ;

	     if ( big <= p_over_2 )
	       add ( big, big, pr ) ;
	     
	     p_over_2.negate() ;
	   }
       }

   public:

     //
     //  *****  initialization function  *****
     //

     void init ( const bigint &B, const bigint & P ) ;      
     void init ( const bigint &B, const sdigit & prime_bound, const bigint & P  ) ;
     void init ( const base_vector<sdigit> & Primes, const bigint & P ) ;    

     void init ( const bigint &B ) { init ( B , (bigint) 0 ) ; }       
     void init ( const bigint &B, const sdigit & prime_bound ) { init ( B, prime_bound, (bigint) 0 ) ; } 
     void init ( const base_vector<sdigit> & Primes ) { init ( Primes, (bigint) 0 ) ; }    


     void clear ( void ) ; 

     //
     // *****  constructors for INTEGER and MODULAR mode respectively  *****
     //

     crt_table ( ) ;
     crt_table ( const bigint &B, const bigint & P ) ;      
     crt_table ( const bigint &B, const sdigit & prime_bound, const bigint & P ) ;
     crt_table ( const base_vector<sdigit> & Primes, const bigint & P ) ;

     crt_table ( const bigint &B ) ;
     crt_table ( const bigint &B, const sdigit & prime_bound ) ;
     crt_table ( const base_vector<sdigit> & Primes ) ;


    ~crt_table();

     // 
     // *****  some tools  ***** 
     //

     inline int number_of_primes() const { return num_primes; }

     sdigit get_prime ( lidia_size_t index ) const ;

     lidia_size_t  how_much_to_use    ( bigint B ) const ;
     void set_prime_generator ( sdigit (*np) ( const sdigit & q ) = nil ) ;

     void info ( void ) const ;

};
// class crt_table


#endif
