

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



#if defined(HAVE_MAC_DIRS) || defined(__MWERKS__)

#include <LiDIA:math_vector.h>
#include <LiDIA:crt.h>

#else

#include <LiDIA/math_vector.h>
#include <LiDIA/crt.h>

#endif


void fill_random ( bigint *& bv , lidia_size_t l , bigint & max )
{
  lidia_size_t i ;

  bv = new bigint [ l ] ;
  
  if ( bv == nil )
    lidia_error_handler ( "crt_appl" , "fill_random::out of memory" ) ;

  for ( i = 0 ; i < l ; i++ )
    {
      if ( i & 1 )
	bv[i] = randomize ( max ) ;
      else
	bv[i] = randomize ( abs(max) ) ;
    }
}
void fill_random ( bigmod *& bv , lidia_size_t l )
{
  lidia_size_t i ;

  bv = new bigmod [ l ] ;

  if ( bv == nil )
    lidia_error_handler ( "crt_appl" , "fill_random::out of memory" ) ;

  for ( i = 0 ; i < l ; i++ )
    {
      bv[i].randomize ( ) ;
    }
}

void fill_random ( base_vector<bigint> & bv , lidia_size_t l , bigint & max )
{
  lidia_size_t i ;

  bv.set_capacity ( l ) ;
  bv.set_size     ( l ) ;  

  for ( i = 0 ; i < l ; i++ )
    {
      bv[i] = randomize ( max ) ;
    }
}
void fill_random ( base_vector<bigmod> & bv , lidia_size_t l )
{
  lidia_size_t i ;

  bv.set_capacity ( l ) ;
  bv.set_size     ( l ) ;  

  for ( i = 0 ; i < l ; i++ )
    {
      bv[i].randomize ( ) ;
    }
}


void fill_random ( base_matrix<bigint> & bv , lidia_size_t row , lidia_size_t col, bigint & max )
{
  lidia_size_t i, j ;
  bigint tmp ;

  bv.set_no_of_rows ( row ) ;
  bv.set_no_of_columns ( col ) ;

  for ( i = 0 ; i < row ; i++ )
    for ( j = 0 ; j < col ; j++ )
      {
	tmp = randomize ( max ) ;
	bv.sto ( i,j , tmp ) ;
      }
}

void fill_random ( base_matrix<bigmod> & bv , lidia_size_t row , lidia_size_t col )
{
  lidia_size_t i, j ;
  bigmod tmp ;

  bv.set_no_of_rows ( row ) ;
  bv.set_no_of_columns ( col ) ;

  for ( i = 0 ; i < row ; i++ )
    for ( j = 0 ; j < col ; j++ )
      {
	tmp.randomize (  ) ;
	bv.sto ( i,j , tmp ) ;
      }
}


bool equal ( const bigint * a , const bigint * b , lidia_size_t l )
{
  lidia_size_t i ;

  for ( i = 0 ; i < l ; i++ )
    if ( a[i] != b[i] )
      return false ;

  return true ;
}
bool equal ( const bigmod * a , const bigmod * b , lidia_size_t l )
{
  lidia_size_t i ;

  for ( i = 0 ; i < l ; i++ )
    if ( a[i] != b[i] )
      return false ;

  return true ;
}


bool equal ( const base_matrix<bigint> & a , const base_matrix<bigint> & b )
{
  lidia_size_t i,j ;
  lidia_size_t ar, ac, br, bc ;

  ar = a.get_no_of_rows() ;
  ac = a.get_no_of_columns() ;
  br = b.get_no_of_rows() ;
  bc = b.get_no_of_columns() ;

  if ( ar != br || ac != bc )
    return false ;

  for ( i = 0 ; i < ar ; i++ )
    for ( j = 0 ; j < ac ; j++ )
      {
	if ( a(i,j) != b(i,j) )
	  return false ;
      }

  return true ;
}

bool equal ( const base_matrix<bigmod> & a , const base_matrix<bigmod> & b )
{
  lidia_size_t i,j ;
  lidia_size_t ar, ac, br, bc ;

  ar = a.get_no_of_rows() ;
  ac = a.get_no_of_columns() ;
  br = b.get_no_of_rows() ;
  bc = b.get_no_of_columns() ;

  if ( ar != br || ac != bc )
    return false ;

  for ( i = 0 ; i < ar ; i++ )
    for ( j = 0 ; j < ac ; j++ )
      {
	if ( a(i,j) != b(i,j) )
	  return false ;
      }

  return true ;
}



sdigit
new_next_prime ( const sdigit & udq )
 {
   sdigit rc ;
   bigint q = udq ;
   
   inc( q ) ;

   if ( q.is_even() )
     inc( q ) ;

   while (q > 0)
     {  
       if ( is_prime(q, 8) )
	 {
	   q.longify ( rc ) ;
	   return rc ;
	 }
       q += 2 ;
     }

   return rc ;
 }


main ( int argc, char *argv[] ) 
 {
    int info, errors = 0  ;
    int run ;
    lidia_size_t i, n, N ;

    crt_table T_int[2], T_mod ;
    crt       doit_int, doit_mod ;

    bigint p, max ;

    if ( argc > 1 ) info = 1 ; else info = 0 ;

    // ~~~~~~  INTEGER data ~~~~~~

    bigint                 bigint_single , *bigint_pointer ;
    math_vector< bigint >  bigint_vector ;   

    base_matrix< bigint >  bigint_matrix ;    


    // ~~~~~~  INTEGER result ~~~~~~

    bigint                 resint_single , *resint_pointer ;
    math_vector< bigint >  resint_vector ;   

    base_matrix< bigint >  resint_matrix ;    


    // ~~~~~~  MODULAR data ~~~~~~

    bigmod                 bigmod_single , *bigmod_pointer ;
    math_vector< bigmod >  bigmod_vector ;   

    base_matrix< bigmod >  bigmod_matrix ;    


    // ~~~~~~  MODULAR result  ~~~~~~

    bigmod                 resmod_single , *resmod_pointer ;
    math_vector< bigmod >  resmod_vector ;   

    base_matrix< bigmod >  resmod_matrix ;    


    // ~~~~~~  temporary data ~~~~~~

    sdigit                 sdigit_single , *sdigit_pointer ;
    math_vector< sdigit >  sdigit_vector ;   

    base_matrix< sdigit >  sdigit_matrix ;    


    lidia_size_t ptrlen, veclen, rows, cols ;


    //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //  ~~~~~~~~~~~~  build tables for computation  ~~~~~~~~~~~~
    //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


    cout << "\n\n Testprogram for crt- and crt_table-class " << endl ;
    cout <<     " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" << endl ;
    
    cout << " Modul for MODULAR test : " ; cin >> p ;
    p.absolute_value() ;
    bigmod::set_modulus ( p ) ;

    cout << " Bound for INTEGER test : " ;
    cin  >> max ;

    T_mod.set_prime_generator ( new_next_prime ) ;

    T_int[0].init ( abs(max) ) ;
    T_int[1].init ( max*max  ) ;
    T_mod.init    ( p, 5, p  ) ;


    //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //  ~~~~~~~~~~~~      generate random data      ~~~~~~~~~~~~
    //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


    cout << "\n Input size of data  " << endl ;
    cout << " ~~~~~~~~~~~~~~~~~~ " << endl ;
    cout << "\n       length  of pointer :  " ; cin >> ptrlen ;
    cout << "       length  of vector  :  "   ; cin >> veclen ;

    cout << "       rows    of matrix  :  "   ; cin >> rows   ;
    cout << "       columns of matrix  :  "   ; cin >> cols   ;


    bigint_single = randomize ( max ) ;
    fill_random ( bigint_pointer , ptrlen , max ) ;
    fill_random ( bigint_vector  , veclen , max ) ;

    fill_random ( bigint_matrix  , rows,cols , max ) ;


    bigmod_single = randomize ( ) ;
    fill_random ( bigmod_pointer , ptrlen ) ;
    fill_random ( bigmod_vector  , veclen ) ;

    fill_random ( bigmod_matrix  , rows,cols ) ;


    sdigit_pointer = new sdigit [ ptrlen ] ;

    
    //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //  ~~~~~~~~~~~~        reduce and combine      ~~~~~~~~~~~~
    //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


    //  ~~~~~~~~~~~~   INTEGER-test with (un)suitable table   ~~~~~~~~~~~~

    for ( run = 0 ; run < 2 ; run ++ ) 
      {
	cout << "\n ~~~~~~~~~  INTEGER RUN " << (run+1) << " ~~~~~~~~~ \n" << endl ;
 
	doit_int.init ( T_int[ run ] ) ;

	N = doit_int.number_of_primes() ;
	n = doit_int.how_much_to_use( abs(max) ) ;

	cout << " Using " << n << " out of " << N << " chinese primes \n" << endl ;

	cout << "  INTEGER single mode ... " << endl ;

	for ( i = 0 ; i < n ; i++ )
	  {
	    doit_int.reduce  ( sdigit_single, bigint_single , i ) ;
	    doit_int.combine ( sdigit_single, i ) ;
	  }
	
	doit_int.get_result ( resint_single ) ;
	
	if ( info )
	  {
	    cout << "      " << bigint_single << endl ;
	    cout << "      " << resint_single << endl ;
	  }
	
	if ( resint_single == bigint_single )
	  cout << "  OK " << endl ;
	else
	  { cout << "  >>>>>> FAILED <<<<< " << endl ; errors ++ ; }
	
	
	cout << "  INTEGER pointer mode ... " << endl ;
	
	for ( i = 0 ; i < n ; i++ )
	  {
	    doit_int.reduce  ( sdigit_pointer, bigint_pointer , ptrlen, i ) ;
	    doit_int.combine ( sdigit_pointer, ptrlen , i ) ;
	  }
	
	i = 0 ;
	doit_int.get_result ( resint_pointer , i ) ;
	
	if ( i != ptrlen )
	  lidia_error_handler ( "crt_appl" , "incompatible pointer size (resint_pointer)" ) ;
	
	if ( info )
	  {
	    cout << "      " ;
	    for ( i = 0 ; i < ptrlen ; i++ )
	      cout << bigint_pointer[i] << " " ;
	    cout << endl ;
	    
	    cout << "      " ;
	    for ( i = 0 ; i < ptrlen ; i++ )
	      cout << resint_pointer[i] << " " ;
	    cout << endl ;
	  }
	
	if ( equal ( resint_pointer, bigint_pointer, ptrlen ) )
	  cout << "  OK " << endl ;
	else
	  { cout << "  >>>>>> FAILED <<<<< " << endl ; errors ++ ; }
	
	delete [] resint_pointer ;	

	cout << "  INTEGER vector mode ... " << endl ;
	
	for ( i = 0 ; i < n ; i++ )
	  {
	    doit_int.reduce  ( sdigit_vector, bigint_vector , i ) ;
	    doit_int.combine ( sdigit_vector, i ) ;
	  }

	doit_int.get_result ( resint_vector ) ;
	
	if ( info )
	  {
	    cout << "      " << bigint_vector << endl ;
	    cout << "      " << resint_vector << endl ;
	  }
	
	if ( resint_vector == bigint_vector )
	  cout << "  OK " << endl ;
	else
	  { cout << "  >>>>>> FAILED <<<<< " << endl ; errors ++ ; }


	cout << "  INTEGER matrix mode ... " << endl ;
	
	for ( i = 0 ; i < n ; i++ )
	  {
	    doit_int.reduce  ( sdigit_matrix, bigint_matrix , i ) ;
	    doit_int.combine ( sdigit_matrix, i ) ;
	  }
	
	doit_int.get_result ( resint_matrix ) ;
	
	if ( info )
	  {
	    cout << "      " << bigint_matrix << endl ;
	    cout << "      " << resint_matrix << endl ;
	  }
	
	if ( equal ( resint_matrix , bigint_matrix ) )
	  cout << "  OK " << endl ;
	else
	  { cout << "  >>>>>> FAILED <<<<< " << endl ; errors ++ ; }

      }

    //  ~~~~~~~~~~~~   MODULAR-test with suitable table   ~~~~~~~~~~~~

    for ( run = 0 ; run < 1 ; run ++ ) 
      {
	cout << "\n ~~~~~~~~~  MODULAR RUN " << (run+1) << " ~~~~~~~~~ \n" << endl ;
 
	doit_int.init ( T_mod ) ;

	N = doit_int.number_of_primes() ;
	n = doit_int.how_much_to_use( p ) ;

	cout << " Using " << n << " out of " << N << " chinese primes \n" << endl ;

	cout << "  MODULAR single mode ... " << endl ;

	for ( i = 0 ; i < n ; i++ )
	  {
	    doit_int.reduce  ( sdigit_single, bigmod_single , i ) ;
	    doit_int.combine ( sdigit_single, i ) ;
	  }
	
	doit_int.get_result ( resmod_single ) ;
	
	if ( info )
	  {
	    cout << "      " << bigmod_single << endl ;
	    cout << "      " << resmod_single << endl ;
	  }
	
	if ( resmod_single == bigmod_single )
	  cout << "  OK " << endl ;
	else
	  { cout << "  >>>>>> FAILED <<<<< " << endl ; errors ++ ; }
	
	
	cout << "  MODULAR pointer mode ... " << endl ;
	
	for ( i = 0 ; i < n ; i++ )
	  {
	    doit_int.reduce  ( sdigit_pointer, bigmod_pointer , ptrlen, i ) ;
	    doit_int.combine ( sdigit_pointer, ptrlen , i ) ;
	  }
	
	i = 0 ;
	doit_int.get_result ( resmod_pointer , i ) ;
	
	if ( i != ptrlen )
	  lidia_error_handler ( "crt_appl" , "incompatible pointer size (resmod_pointer)" ) ;
	
	if ( info )
	  {
	    cout << "      " ;
	    for ( i = 0 ; i < ptrlen ; i++ )
	      cout << bigmod_pointer[i] << " " ;
	    cout << endl ;
	    
	    cout << "      " ;
	    for ( i = 0 ; i < ptrlen ; i++ )
	      cout << resmod_pointer[i] << " " ;
	    cout << endl ;
	  }
	
	if ( equal ( resmod_pointer, bigmod_pointer, ptrlen ) )
	  cout << "  OK " << endl ;
	else
	  { cout << "  >>>>>> FAILED <<<<< " << endl ; errors ++ ; }
	
	delete [] resmod_pointer ;
	
	cout << "  MODULAR vector mode ... " << endl ;
	
	for ( i = 0 ; i < n ; i++ )
	  {
	    doit_int.reduce  ( sdigit_vector, bigmod_vector , i ) ;
	    doit_int.combine ( sdigit_vector, i ) ;
	  }

	doit_int.get_result ( resmod_vector ) ;
	
	if ( info )
	  {
	    cout << "      " << bigmod_vector << endl ;
	    cout << "      " << resmod_vector << endl ;
	  }
	
	if ( resmod_vector == bigmod_vector )
	  cout << "  OK " << endl ;
	else
	  { cout << "  >>>>>> FAILED <<<<< " << endl ; errors ++ ; }


	cout << "  MODULAR matrix mode ... " << endl ;
	
	for ( i = 0 ; i < n ; i++ )
	  {
	    doit_int.reduce  ( sdigit_matrix, bigmod_matrix , i ) ;
	    doit_int.combine ( sdigit_matrix, i ) ;
	  }
	
	doit_int.get_result ( resmod_matrix ) ;
	
	if ( info )
	  {
	    cout << "      " << bigmod_matrix << endl ;
	    cout << "      " << resmod_matrix << endl ;
	  }
	
	if ( equal ( resmod_matrix , bigmod_matrix ) )
	  cout << "  OK " << endl ;
	else
	  { cout << "  >>>>>> FAILED <<<<< " << endl ; errors ++ ; }


      }

    if ( ! errors )
      {
	cout << "\n ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "  ;
	cout << "\n ~~~~~~  No errors detected  ~~~~~~ "  ;
	cout << "\n ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \n" << endl ;
      }
    else
      {
	cout << "\n ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "  ;
	cout << "\n ~~~~~~ Test FAILED !!!  (" << errors << ") ~~~~~~ "  ;
	cout << "\n ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \n" << endl ;
      }
 }
