


#if defined(HAVE_MAC_DIRS) || defined(__MWERKS__)
#include <LiDIA:base_sparse_power_serie.h>

#else
#include <LiDIA/base_sparse_power_serie.h>
#endif

    //
    // ****  constructor/destructor functions    ******
    //

    template < class T >
    base_sparse_power_serie< T >::
    base_sparse_power_serie ()
      {
	debug_handler ( "base_sparse_power_serie< T >",
		        "base_sparse_power_serie( void )" ) ;

	errmess = new char[256] ;	
	coeff = new sort_vector< spc< T > > ;
	coeff->set_sort_direction ( SORT_VECTOR_UP ) ;

	sorted  = true ;
      }

    template < class T >
    base_sparse_power_serie< T >::
    base_sparse_power_serie ( const T & elem , lidia_size_t l )
      {
	debug_handler ( "base_sparse_power_serie< T >",
		        "base_sparse_power_serie( const T&, lidia_size_t )" ) ;

	errmess = new char[256] ;
	coeff = new sort_vector< spc< T > > ;
	coeff->set_sort_direction ( SORT_VECTOR_UP ) ;
	
	if ( ! elem.is_zero () )
	  {
	    coeff->set_capacity( 1 ) ;
	    (*coeff)[0].coeff = elem ;
	    (*coeff)[0].exp   = 0    ;
	    
	    first = 0 ;
	    last  = l ;
	    
	    sorted = true ;
	  }
	else
	  {
	    assign_zero ( l ) ;
	  }
      }

    template < class T >
    base_sparse_power_serie< T >::
    base_sparse_power_serie ( const base_vector< T > & c, lidia_size_t f )
      {
	debug_handler ( "base_sparse_power_serie< T >", 
		        "base_sparse_power_serie(const base_vector< T >&,lidia_size_t,lidia_size_t)" ) ;

	errmess = new char[256] ;
	coeff = new sort_vector< spc< T > > ;
	coeff->set_sort_direction ( SORT_VECTOR_UP ) ;
	sorted = true ;

	lidia_size_t prec, start ;
	lidia_size_t num, i ;
	T   zero_T ;

	zero_T.assign_zero () ;
	prec   = c.size() ;
	start  = prec ;
	num    = 1 ;


	// find first element in c which is not equal to zero
	// and count the number of non-zero elements

	for ( i = 0 ; i < prec && start == prec ; i++ )
	 {
	    if ( c[i] != zero_T )
	       start = i ;
	 }

	for ( i = start+1 ; i < prec ; i++ )
	 {
	    if ( c[i] != zero_T )
  	       num ++ ;
	 }
	

	// all elements are zero

	if ( start == prec )
	 {
	    assign_zero ( f + prec - 1 ) ;
	 }

	// a non-zero element was found

	else
	 {
	   coeff->set_capacity ( num ) ;
	   first = f + start ;
	   last  = f + prec - 1 ;

	   for ( i = start, num = 0 ; i < prec ; i++ )
	    {
	       if ( c[i] != zero_T )
		{
		   (*coeff)[num].coeff = c[i]  ;
		   (*coeff)[num].exp   = f + i ;
		   num ++ ;
		}
	    }
	 }
      }

    template < class T >
    base_sparse_power_serie< T >::	
    base_sparse_power_serie ( const base_sparse_power_serie< T > & a )
      {
	debug_handler ( "base_sparse_power_serie< T >", 
		        "base_sparse_power_serie( const base_sparse_power_serie< T > & )" ) ;

	errmess = new char[256] ;
	a.init_test ( "base_sparse_power_serie( const base_sparse_power_serie< T > & )" ) ;

	coeff = new sort_vector< spc< T > > ;
	coeff->set_sort_direction ( SORT_VECTOR_UP ) ;

	if ( a.is_zero() )
	  {
	    assign_zero ( a.last ) ;
	  }
	else
	  {
	    first  =  a.first ;
	    last   =  a.last  ;
	    *coeff = *a.coeff ;
	    
	    sorted = a.sorted ;
	  }
      }


    template < class T >
    base_sparse_power_serie< T >::
   ~base_sparse_power_serie ()
     {
       debug_handler ( "base_sparse_power_serie< T >", 
		       "~base_sparse_power_serie( )" ) ;
       
       delete coeff ;
       delete errmess ;
     }



    //
    //  *****  initialization functions  *****
    //

    template < class T >
    bool 
    base_sparse_power_serie < T >::
    is_zero ( void ) const
      {
	debug_handler ( "base_sparse_power_serie< T >",
		        "is_zero( )" ) ;

	init_test ( "is_zero()" ) ;

	if ( coeff->size() == 0 ) 
	  return true ;
	else
	  return false ;
      } 

    template < class T >
    bool 
    base_sparse_power_serie < T >::
    is_one ( void ) const
      {
	debug_handler ( "base_sparse_power_serie< T >",
		        "is_one()" ) ;
	bool rc;
	init_test ("is_one()");

	if ((coeff->size() != (lidia_size_t)1) ||
	    (first != (lidia_size_t)0)) 
	   rc = false;
	else
	 {
	   if ((*coeff)[0].coeff.is_one())
	      rc = true;
	   else
	      rc = false;
	 }

	return rc;
      } 


    template < class T >
    void 
    base_sparse_power_serie < T >::
    assign_zero ( lidia_size_t l )
      {
	debug_handler ( "base_sparse_power_serie< T >", 
		        "assign_zero( lidia_size_t )" ) ;

	coeff->set_capacity ( 1 ) ;
	coeff->set_size     ( 0 ) ;
	
	first = last = l ;
	sorted = true ;
      } 

    template < class T >
    void 
    base_sparse_power_serie < T >::
    assign_one ( lidia_size_t l )
      {
	debug_handler ( "base_sparse_power_serie< T >", 
		        "assign_one( lidia_size_t )" ) ;

	if ( l < 0 )
	  {
	    assign_zero ( l ) ;
	  }
	else
	  {
	    coeff->set_capacity ( 1 ) ;
	    coeff->set_size     ( 1 ) ;
	    
	    ((*coeff)[0].coeff).assign_one () ;
	    (*coeff)[0].exp = 0 ;

	    first = 0 ;
	    last = l ;
	    sorted = true ;
	  } 
      }

    template < class T >
    void 
    base_sparse_power_serie < T >::
    set ( const T & elem , lidia_size_t l )
      {
	debug_handler ( "base_sparse_power_serie< T >",
		        "set ( const T &, lidia_size_t )" ) ;
      
	if ( ! elem.is_zero () )
	  {
	    coeff->set_capacity( 1 ) ;
	    (*coeff)[0].coeff = elem ;
	    (*coeff)[0].exp   = 0    ;
	    
	    first = 0 ;
	    last  = l ;
	    
	    sorted = true ;	  
	  }
	else
	  {
	    assign_zero ( l ) ;
	  }
      }



    template < class T >
    void
    base_sparse_power_serie< T >:: 
    set ( const T * c, const lidia_size_t * e, lidia_size_t num, lidia_size_t l )
      {
	debug_handler ( "base_sparse_power_serie< T >", 
		        "set(const T*,const lidia_size_t*,lidia_size_t)" ) ;
	
	lidia_size_t i, j;

       coeff->set_capacity ( num ) ;

	// --- copying the two vectors into the spc<.> structure

	  for ( i = 0, j = 0 ; i < num ; i++ )
	   {
	    if ( c[i] != (T) 0 )
	      {
		(*coeff)[j].coeff = c[i] ;
		(*coeff)[j].exp   = e[i] ;
		j ++ ;
	      }

	    if (l < e[i])
	       lidia_error_handler ("base_sparse_power_serie< T >",
				    "set(const T*,...)::Invalid value for l.");
	   }

	if ( j == 0 )
	  {
	    assign_zero ( l ) ;
	  }
	else
	  {
	    coeff->sort() ;
	    first  = (*coeff)[0].exp ;
	    last   = l    ;
	    sorted = true ;
	  }
      }


/*
    template < class T >
    void 
    base_sparse_power_serie< T >:: 
    set ( const base_vector< T > & c, const base_vector< lidia_size_t > & e , lidia_size_t l )
      {
	debug_handler ( "base_sparse_power_serie< T >", 
		        "set( const base_vector< T > &, const base_vector< T > &, lidia_size_t )" ) ;
	
	if ( c.size() != e.size() )
	 {
	   lidia_error_handler ( "base_sparse_power_serie< T >", 
		         "set( 2x base_vector<T>, lidia_size_t)::incompatible vector sizes" ) ; 
	 }

	lidia_size_t i, j, num ;

	num = c.size() ;
	coeff->set_capacity ( num ) ;

	// --- copying the two vectors into the spc<.> structure

	  for ( i = 0, j = 0 ; i < num ; i++ )
	   {
	    if ( c[i] != (T) 0 )
	      {
		(*coeff)[j].coeff = c[i] ;
		(*coeff)[j].exp   = e[i] ;
		
		j ++ ;
	      }

	    if (l < e[i])
	       lidia_error_handler ("base_sparse_power_serie< T >",
				    "set(const base_vector<T>&,...)::Invalid value for l.");
	   }

	if ( j == 0 )
	  {
	    assign_zero ( l ) ;
	  }
	else
	  {
	    coeff->sort() ;
	    
	    first  = (*coeff)[0].exp ;
	    last   = l    ;
	    sorted = true ;
	  }
      }
*/


    template < class T >
    void  
    base_sparse_power_serie < T >::
    set_coeff ( const T & elem , lidia_size_t exp )
      {
	debug_handler ( "base_sparse_power_serie< T >",
		        "set_coeff ( const T &, lidia_size_t )" ) ;
	
	lidia_size_t where, sz ;
	bool el_is_zero ;
	bool found ;
	spc< T > c( elem, exp ) ;

	sz = coeff->capacity() ;               // i.e. not initialized 
	el_is_zero = ( elem.is_zero () ) ;

	if ( sz == 0 )   // serie not yet initialized
	  {
	    if ( el_is_zero )
	      {
		assign_zero ( exp ) ;
	      }
	    else
	      {
		coeff->set_capacity ( 1 ) ;
		first = exp ;
		last  = exp ;
		(*coeff)[0] = c ;
		
		sorted = true ;
	      }
	  }
	else if ( is_zero ( ) )
	  {
	    if ( el_is_zero && exp > last )
	      {
		assign_zero ( exp ) ;
	      }
	    else
	      {
		coeff->set_capacity ( 1 ) ;
		first = exp ;
		if ( exp > last	) 
		  last = exp ;
		(*coeff)[0] = c ;
		
		sorted = true ;
	      }
	  }
	else  // update an already initialized non-zero serie
	  {
	    if ( sorted )
	      found = coeff->bin_search ( c , where ) ;
	    else
	      found = coeff->linear_search ( c , where ) ;
	    
	    if ( found ) 
	      {
		if ( el_is_zero )  // delete zero-element by overwriting it
		  {
		    // if ( ( where < sz-1 ) )
		    //  {
		    //	  (*coeff)[where] = (*coeff)[sz-1] ;
		    //    if ( (*coeff)[where+1] < (*coeff)[where] ) 
		    //      sorted = false ;
		    //  }
		    // coeff->set_size ( sz - 1 ) ;
		    // first = ???
		
		    coeff->remove_from ( where ) ;

		    if ( coeff->size() == 0 )
		      assign_zero ( last ) ;
		    else
		      first = (*coeff)[0].exp ;
		  }
		else               // overwrite coeff with new value 
		  {
		    (*coeff)[where] = c ;
		  }
	      }
	    else if ( ! el_is_zero )  // put element at the end of coeff.-vector or
	                              // insert it at corresponding position 'where'
	      {
		if ( coeff->capacity() < sz+1 )
		  coeff->set_capacity ( alloc_size ( sz + 1 ) ) ;
		
		// (*coeff)[sz] = c ;
		// if ( sorted && (*coeff)[sz-1].exp > exp )
		//   sorted = false ;
		
		coeff->insert_at ( c , where ) ;
		first = (*coeff)[0].exp ;
	      }
	    
	    if ( exp > last ) last = exp ;
	  }
      }

    template < class T >
    void 
    base_sparse_power_serie < T >::
    reduce_last ( lidia_size_t l )
      {
	debug_handler ( "base_sparse_power_serie< T >", "reduce_last ( lidia_size_t )" ) ;

	init_test ( "reduce_last ( lidia_size_t )" ) ;
	sort_test ( ) ;

	lidia_size_t where ;
	bool found ;
	spc< T > c( (*coeff)[0].coeff , l ) ;

	if ( l > last )
	  {
	    lidia_error_handler( "base_sparse_power_serie< T >", "reduce_last( lidia_size_t )::new value exceeded 'last'" ) ;
	  }
	else if ( l < first )
	  {
	    assign_zero ( l ) ;
	  }
	else
	  {
	    found = coeff->bin_search ( c , where ) ;

	    where += ( found ? 1 : 0 ) ;
	    coeff->set_size ( where ) ;
	    last = l ;
	  }

      }

    template < class T >
    void 
    base_sparse_power_serie < T >:: 
    clear ( void )
      {
	debug_handler ( "base_sparse_power_serie< T >", "clear ( void )" ) ;
	
	coeff->kill () ;
	sorted = false ;
      }

    template < class T >
    void  
    base_sparse_power_serie < T >::
    normalize ( void )
      {
	debug_handler ( "base_sparse_power_serie< T >", "normalize ( void )" ) ;
	
	init_test ( "normalize()" ) ;
	sort_test ( ) ;

	if ( ! is_zero () ) coeff->set_capacity ( coeff->size () ) ;
      }



    //
    //  *****  information functions  *****
    //

    template < class T >
    lidia_size_t
    base_sparse_power_serie < T >::
    get_first ( void ) const
      {
	debug_handler ( "base_sparse_power_serie< T >", "get_first ( void )" ) ;

	init_test ("get_first ( void )") ;
	return first ;
      }

    template < class T >
    lidia_size_t
    base_sparse_power_serie < T >::
    get_last ( void ) const
      {
	debug_handler ( "base_sparse_power_serie< T >", "get_last ( void )" ) ;
	
	init_test ( "get_last ( void )" ) ;
	return last ;
      }


    template < class T >
    void
    base_sparse_power_serie < T >::
    get ( T * & c , lidia_size_t * & e, lidia_size_t & sz ) const
      {
	debug_handler ( "base_sparse_power_serie< T >", 
		        "get(T* &, lidia_size_t* &, lidia_size_t& )" ) ;

	lidia_size_t i;

	init_test ( "get(T* &, T* &, lidia_size_t&)" ) ;
	sort_test () ;
	sz = coeff->size() ;

	if (c!=nil) delete [] c;
	if (e!=nil) delete [] e;


	if (sz != (lidia_size_t)0)
	 {
	   c = new T[sz];
	   e = new lidia_size_t[sz];
	 }
	else
	 {
	   c = new T[1];
	   e = new lidia_size_t[1];
	 }

	memory_handler (c,"base_sparse_power_serie<T>",
			  "get(T*,lidia_size_t*,lidia_size_t)::out of memory(c)");
	memory_handler (e,"base_sparse_power_serie<T>",
			  "get(T*,lidia_size_t*,lidia_size_t)::out of memory(e)");

	for ( i = 0 ; i < sz ; i++ )
	  {
	    c[i] = (*coeff)[i].coeff ;
	    e[i] = (*coeff)[i].exp   ;
	  }

	if (sz == (lidia_size_t)0)
	 {
	   c[0].assign_zero();
	   e[0] = last;
	 }
      }


/*
    template < class T >
    void
    base_sparse_power_serie < T >::
    get ( base_vector< T > & c , base_vector< lidia_size_t > & e ) const
      {
	debug_handler ( "base_sparse_power_serie< T >", 
		        "get ( base_vector< T > &, base_vector< lidia_size_t > & )" ) ;

	init_test ( "get ( base_vector< T > &, base_vector< T > & )" ) ;
	sort_test ( ) ;

	lidia_size_t i, sz = coeff->size() ;

	if (sz != (lidia_size_t)0)
	 {
	   c.set_capacity ( sz ) ;
	   c.set_size     ( sz ) ;
	   e.set_capacity ( sz ) ;
	   e.set_size     ( sz ) ;
	
	   for ( i = 0 ; i < sz ; i++ )
	    {
	       c[i] = (*coeff)[i].coeff ;
	       e[i] = (*coeff)[i].exp   ;
	    }
	 }
	else
	 {
	   sz++;
	   c.set_capacity ( sz ) ;
	   c.set_size     ( sz ) ;
	   e.set_capacity ( sz ) ;
	   e.set_size     ( sz ) ;
	   c[0].assign_zero();
	   e[0] = last;
	 }
      }
*/


    template < class T >
    void 
    base_sparse_power_serie < T >::
    get_coeff ( T & elem , lidia_size_t exp ) const
      {
	debug_handler ( "base_sparse_power_serie< T >", "get_coeff (  T &, lidia_size_t )" ) ;

	init_test ( "get_coeff (  T &, lidia_size_t & )" ) ;
	sort_test ( ) ;

	if ( exp > last )
	  lidia_error_handler ("base_sparse_power_serie< T >",
			       "get_coeff( T &, lidia_size_t )::exponent exceeded 'last'" );

	bool found ;
	lidia_size_t where ;
	spc< T > c( elem, exp ) ;
	
	found = coeff->bin_search ( c , where ) ;

	if ( found )
	  elem = (*coeff)[where].coeff ;
	else
	  elem.assign_zero () ;
      }


    //
    //  *****  subscription operator  *****
    //

    template < class T >
    T 
    base_sparse_power_serie < T >::
    operator [] ( lidia_size_t exp ) const
      {
	debug_handler ( "base_sparse_power_serie< T >", "operator [] ( lidia_size_t )" ) ;

	init_test ( "operator [] ( lidia_size_t )" ) ;
	sort_test () ;

	if ( exp > last )
	  lidia_error_handler ("base_sparse_power_serie< T >",
			       "operator [] ( lidia_size_t )::exponent exceeded 'last'" );

	if (is_zero())
	   return (T) 0;

	bool found ;
	lidia_size_t where ;
	T elem ;
	spc< T > c( elem, exp ) ;

	found = coeff->bin_search ( c , where ) ;

	if ( found )
	  return (*coeff)[where].coeff ;
	else
	  return (T) 0 ;
      }


    //
    //  *****  I/O functions and operators  *****
    //

    template < class T >
    int
    base_sparse_power_serie < T >::
    read ( istream & in )
      { 
	debug_handler ( "base_sparse_power_serie< T >", "read( istream& )" ) ;

	int  rc ;
	bool found ;
	lidia_size_t pos ;
	char ch ;
	
	spc< T > zero_elem ;
	
	(zero_elem.coeff).assign_zero () ;
	zero_elem.exp = 0 ;
	
	in >> ch ;
	if ( ch != '[' )
	  lidia_error_handler ( "base_sparse_power_serie< T >" , "read():: character '[' expected" ) ;
	
	in >>  *coeff ;
	in >>   last  ;
	
	in >> ch ;
	if ( ch != ']' )
	  lidia_error_handler ( "base_sparse_power_serie< T >" , "read():: character ']' expected" ) ;
	
	if ( coeff->capacity () == 0 ) assign_zero( last ) ;

	//  ---  delete any zero element in the input  ---
	  
	coeff->set_sort_direction ( coeff_cmp_zero ) ;
	coeff->sort ( ) ;
	
	found = coeff->bin_search ( zero_elem , pos ) ;
      
	if ( found )
	  {
	    coeff->set_size ( pos ) ;
	  }

	coeff->set_sort_direction ( SORT_VECTOR_UP ) ;

	rebuild() ;
	normalize() ;

	if ( last < (*coeff)[coeff->size()-1].exp )
	   lidia_error_handler ( "base_sparse_power_serie",
				 "read::Coefficient with exponent greater than last was found." ) ;

	rc = 0 ;
	return (rc) ;
      }
 
    template < class T > 
    int
    base_sparse_power_serie < T >::
    write ( ostream & out ) const
      {
	debug_handler ( "base_sparse_power_serie< T >", "write( ostream& )" ) ;

	int rc ;
	for ( rc = 0 ; rc < 0 ; ) {}

	T zero_T = (T) 0 ;

	if ( is_zero() )
	  out << "[ " << zero_T << " " << last << " ]" ;
	else
	  out << "[ " << (*coeff) << " " << last << " ]" ;

	return (rc) ;
      }  

    template < class T >
    void 
    base_sparse_power_serie < T >::
    info ( ostream & out ) const
      {
	debug_handler ( "base_sparse_power_serie< T >", "info ( ostream& )" ) ;
	
	out << "{ first = " << first << " last = " << last ;
	out << " size = " << coeff->size() ;
	out << " cap = " << coeff->capacity() ;
	out << ( sorted ? " TRUE" : " FALSE" ) << " }" ;
      }




    //
    //  *****  assignment operator  *****
    //

    template < class T >
    const base_sparse_power_serie< T > &
    base_sparse_power_serie < T >::
    operator = ( const base_sparse_power_serie< T > & a ) 
      {
	debug_handler ( "base_sparse_power_serie< T >", "operator = ( const sp_pow & )" ) ;
	
	a.init_test ( "operator = ( const sp_pow & )" ) ;
	
	if ( this != &a )
	  {
	    if ( a.is_zero ( ) )
	        assign_zero ( a.last ) ;
	    else
	      {
		first  = a.first  ;
		last   = a.last   ;
		sorted = a.sorted ;
		
		*coeff = *a.coeff ;
	      }
	  }
	
	return ( *this ) ;
      }
  

    //
    //  ***** swap - function *****
    //

    template < class T >
    void
    base_sparse_power_serie< T >::
    swap ( base_sparse_power_serie< T > & b )
      {
	debug_handler ( "base_sparse_power_serie< T >", "swap ( sp_pow & , sp_pow & )" ) ;

	lidia_size_t f, l ;
	bool s    ;
	sort_vector< spc< T > > *c ;

	f = this->first  ;
	l = this->last   ;
	s = this->sorted ;
	c = this->coeff  ;

	this->first  = b.first  ;
	this->last   = b.last   ;
	this->sorted = b.sorted ;
	this->coeff  = b.coeff  ;

	b.first  = f ;
	b.last   = l ;
	b.sorted = s ;
	b.coeff  = c ;
      }


    //
    //  *****  comparison of series *****
    //

    template < class T >
    bool
    base_sparse_power_serie< T >::
    operator == ( const base_sparse_power_serie< T > & b ) const 
      {
	debug_handler ( "base_sparse_power_serie< T >", "operator == ( const sp_pow & )" ) ;

	this->init_test ( "operator == ( const sp_pow & )" ) ;
	b.init_test ( "operator == ( const sp_pow & )" ) ;
	this->sort_test () ;
	b.sort_test () ;
	
	if ( ( this->first == b.first ) && ( this->last == b.last ) && ( ! this->coeff->lex_compare ( *b.coeff ) ) )
	  {
	    return true ;
	  }
	else
	  {
	    return false ;
	  }
      }

    template < class T >
    bool
    base_sparse_power_serie< T >::
    operator != ( const base_sparse_power_serie< T > & b ) const
      {
	debug_handler ( "base_sparse_power_serie< T >", "operator == ( const sp_pow & )" ) ;

	this->init_test ( "operator != ( const sp_pow & )" ) ;
	b.init_test ( "operator != ( const sp_pow & )" ) ;
	this->sort_test () ;
	b.sort_test () ;
	
	if ( ( this->first == b.first ) && ( this->last == b.last ) && ( ! this->coeff->lex_compare ( *b.coeff ) ) )
	  {
	    return false ;
	  }
	else
	  {
	    return true  ;
	  }
      }



    //
    //  *****  generating random series  *****
    //

/*
    friend
    void
    randomize ( base_sparse_power_serie< T > & a , lidia_size_t f, lidia_size_t l , lidia_size_t all , const T & max )
      {
	debug_handler ( "base_sparse_power_serie< T >", "random ( sp_pow & , lidia_size_t , lidia_size_t , lidia_size_t , const T & )" ) ;

	lidia_size_t i ;
	lidia_size_t e ;
	bigint L( l ), E ;
	
	T one_T = (T) 1 ;

	if ( all > 0 )
	  {
	    a.coeff->set_capacity ( all ) ;

	    if ( all > 0 )
	     {
		(*a.coeff)[0].exp   = f ;
  		(*a.coeff)[0].coeff = randomize ( max ) + one_T ;
	     }

	    for ( i = 1 ; i < all ; i++ )
	      {
		do
		  {
		    E = randomize ( L ) ;
		    e = (lidia_size_t) E.least_significant_digit();
		  } 
		while ( e < f ) ;
		
		(*a.coeff)[i].exp   = e ;
  		(*a.coeff)[i].coeff = randomize ( max ) + one_T ;
	      }
	    
	    a.last = l ;
	    a.rebuild ( ) ;
	  }
	else
	  {
	    a.assign_zero ( l ) ;
	  }
      }
*/

    //
    //  *****  some protected member functions  *****
    //

    template < class T >
    void 
    base_sparse_power_serie < T >::
    init_test ( char * mess ) const
      {
	strcpy  ( errmess, "uninitialized argument in function " ) ;
	strncat ( errmess, mess , 200 ) ;

	if ( coeff->capacity() == 0 )
	  lidia_error_handler ( "base_sparse_power_serie< T >" , errmess ) ;
      }

    template < class T >
    void 
    base_sparse_power_serie < T >::
    rebuild ( void ) 
      {
	lidia_size_t i, j ;

	coeff->sort() ;
	sorted = true ;
	
	// --- only non-zero elements in the vector ---

	for ( i = 0 ; i < coeff->size()-1 ; )
	  {
	    j = 1 ;

	    while ( ( i+j < coeff->size() ) && ( (*coeff)[i].exp == (*coeff)[i+j].exp ) )
	      {
		(*coeff)[i].coeff +=  (*coeff)[i+j].coeff ;
		j ++ ;
	      }
	    if ( ((*coeff)[i].coeff).is_zero () ) 
	      {
		coeff->remove_from ( i, j ) ;
	      }
	    else if ( j > 1 )
	      {
		coeff->remove_from ( i+1 , j-1 ) ;
		i ++ ;
	      }
	    else
	      {
		i ++ ;
	      }
	  }
	
	if ( coeff->size() == 0 )
	  {
	    assign_zero ( last ) ;
	  }
	else
	  {
	    first = (*coeff)[0].exp ;
	  }
      }



    //
    //  *****  arithmetical operations  *****
    //

    template < class T >
    void
    base_sparse_power_serie < T >::
    multiply_by_xn ( lidia_size_t n )
      {
	debug_handler ( "base_sparse_power_serie< T >", "multiply_by_xn ( lidia_size_t )" ) ;

	init_test ( "multiply_by_xn ( lidia_size_t )" ) ;

	lidia_size_t i, sz ;
	
	if ( n != 0 )
	  {
	    sz = coeff->size() ;
	    for ( i = 0 ; i < sz ; i++ )
	      {
		(*coeff)[i].exp += n ;
	      }

	    first += n ;
	    last  += n ;
	  }
      }

    template < class T >
    void
    base_sparse_power_serie < T >::
    compose ( lidia_size_t n )
      {
	debug_handler ( "base_sparse_power_serie< T >", "compose ( lidia_size_t )" ) ;

	init_test ( "compose ( lidia_size_t )" ) ;
	
	lidia_size_t i, sz ;

	if ( n != 0 )
	  {
	    sz = coeff->size() ;
	    for ( i = 0 ; i < sz ; i++ )
	      {
		(*coeff)[i].exp *= n ;
	      }

	    first *= n ;
	    last  *= n ;
	  }
      }

    template < class T >
    void
    base_sparse_power_serie < T >::
    add (const base_sparse_power_serie< T > & a   ,
	 const base_sparse_power_serie< T > & b   )
      {
	debug_handler ( "base_sparse_power_serie< T >", "add ( sp_pow & , const sp_pow & , const sp_pow & )" ) ;

	a.init_test ( "add ( 3 x sp_pow )" ) ;
	b.init_test ( "add ( 3 x sp_pow )" ) ;	

	a.sort_test() ;
	b.sort_test() ;

	lidia_size_t i, ap, bp  ;
	lidia_size_t astop, bstop, cf, cl ;

	lidia_size_t  cont, c_all ;  

	base_sparse_power_serie< T > c ;
	sort_vector< spc< T > > *ac, *bc, *cc ;

	c_all = a.coeff->size() + b.coeff->size()          ; // max. number of non-zero elts. in result
	cf    = comparator<lidia_size_t>::min ( a.first , b.first ) ;
	cl    = comparator<lidia_size_t>::min ( a.last  , b.last  ) ;
                   
	c.coeff->set_capacity ( c.alloc_size ( c_all ) ) ;
     
	i     = 0 ;
	cont  = 0 ;
	ap    = 0 ;
	bp    = 0 ;
	astop = a.coeff->size() - 1 ;
	bstop = b.coeff->size() - 1 ;

	ac = a.coeff ;
	bc = b.coeff ;
	cc = c.coeff ;
	
	// --- determine significant coefficients ---

	while ( ( astop >= 0 ) && ( (*ac)[astop].exp > cl ) )  astop-- ;
	while ( ( bstop >= 0 ) && ( (*bc)[bstop].exp > cl ) )  bstop-- ;


	while ( ( ap <= astop ) && ( bp <= bstop ) )
	  { 	
	    if ( (*ac)[ap].exp == (*bc)[bp].exp )   // add corresponding coefficients
	      {
		::add ( (*cc)[cont].coeff , (*ac)[ap].coeff , (*bc)[bp].coeff ) ;

		if ( ! ((*cc)[cont].coeff).is_zero ()  )  // store non-zero elements only
		  {
		    (*cc)[cont].exp = (*ac)[ap].exp ;
		    cont++ ;
		  }

		ap++ ;
		bp++ ;
	      }
	    else if ( (*ac)[ap].exp < (*bc)[bp].exp )   // copy coeff. that occurs only once; least one first
	      {
		// copy coeff of serie a

		(*cc)[cont].exp   = (*ac)[ap].exp   ;
		(*cc)[cont].coeff = (*ac)[ap].coeff ;

		cont++  ;
		ap++ ;
	      }
	    else if ( (*bc)[bp].exp < (*ac)[ap].exp )  // copy coeff. that occurs only once; larger one later
	      {
		// copy coeff of serie b

		(*cc)[cont].exp   = (*bc)[bp].exp   ;
		(*cc)[cont].coeff = (*bc)[bp].coeff ;

		cont++  ;
		bp++ ;
	      } 
	  }

	while ( ap <= astop )    // copy remaining coeff of serie b
	  {
	    (*cc)[cont].exp   = (*ac)[ap].exp   ;
	    (*cc)[cont].coeff = (*ac)[ap].coeff ;
	    
	    cont++  ;
	    ap++ ;
	  }
	while ( bp <= bstop ) 	// copy remaining coeff of serie b
	  {
	    (*cc)[cont].exp   = (*bc)[bp].exp   ;
	    (*cc)[cont].coeff = (*bc)[bp].coeff ;
	    
	    cont++  ;
	    bp++ ;
	  }

	if ( cont == 0 )
	  {
	    c.assign_zero ( cl ) ;
	  }
	else
	  {
	    c.coeff->set_capacity ( cont ) ;
	    c.first = (*c.coeff)[0].exp ;
	    c.last  = cl ;
	  }
     
	// --- move temporary result to 'res'

	c.swap (*this) ;
      }


    template < class T >
    void
    base_sparse_power_serie < T >::
    subtract (const base_sparse_power_serie< T > & a   ,
	      const base_sparse_power_serie< T > & b   )
      {
	debug_handler ( "base_sparse_power_serie< T >", "subtract ( sp_pow & , const sp_pow & , const sp_pow & )" ) ;

	a.init_test ( "subtract ( 3 x sp_pow )" ) ;
	b.init_test ( "subtract ( 3 x sp_pow )" ) ;	

	a.sort_test() ;
	b.sort_test() ;


	lidia_size_t i, ap, bp  ;
	lidia_size_t astop, bstop, cf, cl ;

	lidia_size_t  cont, c_all ;  

	base_sparse_power_serie< T > c ;
	sort_vector< spc< T > > *ac, *bc, *cc ;

	c_all = a.coeff->size() + b.coeff->size()          ; // max. number of non-zero elts. in result
	cf    = comparator<lidia_size_t>::min ( a.first , b.first ) ;
	cl    = comparator<lidia_size_t>::min ( a.last  , b.last  ) ;
                   
	c.coeff->set_capacity ( c.alloc_size ( c_all ) ) ;
     
	i     = 0 ;
	cont  = 0 ;
	ap    = 0 ;
	bp    = 0 ;
	astop = a.coeff->size() - 1 ;
	bstop = b.coeff->size() - 1 ;

	ac = a.coeff ;
	bc = b.coeff ;
	cc = c.coeff ;
	
	// --- determine significant coefficients ---

	while ( ( astop >= 0 ) && ( (*ac)[astop].exp > cl ) )  astop-- ;
	while ( ( bstop >= 0 ) && ( (*bc)[bstop].exp > cl ) )  bstop-- ;


	while ( ( ap <= astop ) && ( bp <= bstop ) )
	  { 	
	    if ( (*ac)[ap].exp == (*bc)[bp].exp )   // subtract corresponding coefficients
	      {
		::subtract ( (*cc)[cont].coeff , (*ac)[ap].coeff , (*bc)[bp].coeff ) ;

		if ( ! ((*cc)[cont].coeff).is_zero ()  )  // store non-zero elements only
		  {
		    (*cc)[cont].exp = (*ac)[ap].exp ;
		    cont++ ;
		  }

		ap++ ;
		bp++ ;
	      }
	    else if ( (*ac)[ap].exp < (*bc)[bp].exp )   // copy coeff. that occurs only once; least one first
	      {
		// copy coeff of serie a

		(*cc)[cont].exp   = (*ac)[ap].exp   ;
		(*cc)[cont].coeff = (*ac)[ap].coeff ;

		cont++  ;
		ap++ ;
	      }
	    else if ( (*bc)[bp].exp < (*ac)[ap].exp )  // copy coeff. that occurs only once; larger one later
	      {
		// copy negative value of coeff of serie b

		(*cc)[cont].exp   = (*bc)[bp].exp   ;
		::negate ( (*cc)[cont].coeff , (*bc)[bp].coeff ) ;

		cont++  ;
		bp++ ;
	      } 
	  }

	while ( ap <= astop )    // copy remaining coeff of serie b
	  {
	    (*cc)[cont].exp   = (*ac)[ap].exp   ;
	    (*cc)[cont].coeff = (*ac)[ap].coeff ;
	    
	    cont++  ;
	    ap++ ;
	  }
	while ( bp <= bstop ) 	// copy remaining coeff of serie b
	  {
	    (*cc)[cont].exp   = (*bc)[bp].exp   ;
	    ::negate ( (*cc)[cont].coeff , (*bc)[bp].coeff ) ;
	    
	    cont++  ;
	    bp++ ;
	  }

	if ( cont == 0 )
	  {
	    c.assign_zero ( cl ) ;
	  }
	else
	  {
	    c.coeff->set_capacity ( cont ) ;
	    c.first = (*c.coeff)[0].exp ;
	    c.last  = cl ;
	  }
     
	// --- move temporary result to 'res'

	c.swap(*this) ;
      }


    template < class T >
    void
    base_sparse_power_serie < T >::
    negate ( const base_sparse_power_serie< T > & a )
      {
	debug_handler ( "base_sparse_power_serie< T >", "negate ( sp_pow & , const sp_pow & )" ) ;

	a.init_test ( "negate ( 2 x sp_pow )" ) ;

	lidia_size_t i, sa ;
	sort_vector< spc< T > > *ac, *rc ;

	ac = a.coeff   ;
	rc = coeff ;
	
	sa = ac->size() ;
	rc->set_capacity ( sa ) ;

	for ( i = 0 ; i < sa ; i++ )
	  {
	    ::negate ( (*rc)[i].coeff , (*ac)[i].coeff ) ;
	    (*rc)[i].exp = (*ac)[i].exp ;
	  }

	first = a.first ;
	last  = a.last  ;
	sort() ;
      }



    //
    //  *****  scalar - operations  *****
    //


    template < class T >
    void
    base_sparse_power_serie < T >::
    add ( const base_sparse_power_serie< T > & a,
	 const T                     & b)
      {
	debug_handler ( "base_sparse_power_serie< T >", "add ( sp_pow & , const sp_pow & , const T & )" ) ;

	a.init_test ( "add ( 2 x sp_pow , cont T & )" ) ;
	a.sort_test() ;

	lidia_size_t at, where, rsz ;
	bool found ;

	lidia_size_t e = 0;
	T bb ;
	spc< T > c( b , e ) ;

	if ( ( a.last < e ) || ( b.is_zero () ) )
	  {
	    if ( this != &a ) *this = a ;
	  }
	else
	  {
	    found = a.coeff->bin_search ( c , where ) ;
	    
	    if ( this == &a )
	      {
		if ( found )
		  {
		    ::add ( (*coeff)[where].coeff , (*coeff)[where].coeff , b ) ;	       
		
		    if ( ((*coeff)[where].coeff).is_zero () )
		      {
			coeff->remove_from ( where ) ;

			if ( coeff->size() == 0 )
			  assign_zero ( a.last ) ;
			else
			  first = (*coeff)[0].exp ;
		      }	    
		  }
		else
		  {
		    if ( coeff->capacity() < a.coeff->size() + 1 )
		      coeff->set_capacity ( alloc_size ( a.coeff->size() + 1 ) ) ;

		    coeff->insert_at ( c , where ) ;
		    first = (*coeff)[0].exp ;
		  }
	      }
	    else  // res does not alias a
	      {
		found = a.coeff->bin_search ( c , where ) ;

		rsz = a.coeff->size() + ( found ? 0 : 1 ) ;
		if ( coeff->capacity() < rsz )
		  coeff->set_capacity ( alloc_size ( rsz ) ) ;
		coeff->set_size ( 0 ) ;

		if ( where > 0 )
		  coeff->assign ( 0 , (*a.coeff) , 0 , where-1 ) ;

		if ( found )
		  {
		    ::add ( bb , (*a.coeff)[where].coeff, b ) ;
		    
		    if ( ! bb.is_zero () )
		      {
			(*coeff)[where].coeff = bb ;
			(*coeff)[where].exp   = e  ;
			at = where + 1 ;
		      }
		    else
		        at = where ;

		    if ( where+1 < a.coeff->size() )
		      coeff->assign ( at , (*a.coeff) , where+1 , a.coeff->size()-1 ) ;

		    if ( coeff->size() == 0 )
		      assign_zero ( a.last ) ;
		    else
		      first = (*coeff)[0].exp ;
		  }
		else
		  {
		    (*coeff)[where] = c ;

		    if ( where < a.coeff->size() )
		      coeff->assign ( where+1 , (*a.coeff) , where , a.coeff->size()-1 ) ;   

		    first = (*coeff)[0].exp ;		   
		  }		

		last  = a.last ;
	      }
	  }
      }

    template < class T >
    void
    base_sparse_power_serie < T >::
    add ( const T & b,
	 const base_sparse_power_serie< T > & a )
      {
	debug_handler ( "base_sparse_power_serie< T >", "add ( sp_pow &, const T &, const sp_pow & )" ) ;
      	this->add(a,b);
      }


    template < class T >
    void
    base_sparse_power_serie < T >::
    subtract (const base_sparse_power_serie< T > & a   ,
	      const T                     & b)
      {
	debug_handler ( "base_sparse_power_serie< T >", "add ( sp_pow & , const sp_pow & , const T & )" ) ;

	a.init_test ( "subtract ( 2 x sp_pow , const T & )" ) ;
	a.sort_test() ;

	lidia_size_t at, where, rsz ;
	bool found ;

	T bb ;
	spc< T > c ;
	lidia_size_t e = 0;

	::negate ( c.coeff , b ) ;
	c.exp = e ;

	if ( ( a.last < e ) || ( b.is_zero () ) )
	  {
	    if ( this != &a ) *this = a ;
	  }
	else
	  {
	    found = a.coeff->bin_search ( c , where ) ;
	    
	    if ( this == &a )
	      {
		if ( found )
		  {
		    ::subtract ( (*coeff)[where].coeff , (*coeff)[where].coeff , b ) ;	       
		
		    if ( ((*coeff)[where].coeff).is_zero () )
		      {
			coeff->remove_from ( where ) ;

			if ( coeff->size() == 0 )
			  assign_zero ( a.last ) ;
			else
			  first = (*coeff)[0].exp ;
		      }	    
		  }
		else
		  {
		    if ( coeff->capacity() < a.coeff->size() + 1 )
		      coeff->set_capacity ( alloc_size ( a.coeff->size() + 1 ) ) ;

		    coeff->insert_at ( c , where ) ;
		    first = (*coeff)[0].exp ;
		  }
	      }
	    else  // res does not alias a
	      {
		found = a.coeff->bin_search ( c , where ) ;

		rsz = a.coeff->size() + ( found ? 0 : 1 ) ;
		if ( coeff->capacity() < rsz )
		  coeff->set_capacity ( alloc_size ( rsz ) ) ;
		coeff->set_size ( 0 ) ;

		if ( where > 0 )
		  coeff->assign ( 0 , (*a.coeff) , 0 , where-1 ) ;

		if ( found )
		  {
		    ::subtract ( bb , (*a.coeff)[where].coeff, b ) ;
		    
		    if ( ! bb.is_zero () )
		      {
			(*coeff)[where].coeff = bb ;
			(*coeff)[where].exp   = e  ;
			at = where + 1 ;
		      }
		    else
		        at = where ;

		    if ( where+1 < a.coeff->size() )
		      coeff->assign ( at , (*a.coeff) , where+1 , a.coeff->size()-1 ) ;

		    if ( coeff->size() == 0 )
		      assign_zero ( a.last ) ;
		    else
		      first = (*coeff)[0].exp ;
		  }
		else
		  {
		    (*coeff)[where] = c ;

		    if ( where < a.coeff->size() )
		      coeff->assign ( where+1 , (*a.coeff) , where , a.coeff->size()-1 ) ;   

		    first = (*coeff)[0].exp ;		   
		  }		

		last  = a.last ;
	      }
	  }
      }

    template < class T >
    void
    base_sparse_power_serie < T >::
    subtract (const T                     & b   ,
	      const base_sparse_power_serie< T > & a   )
      {
	debug_handler ( "base_sparse_power_serie< T >", "add ( sp_pow & , const T & , const sp_pow & )" ) ;

	a.init_test ( "subtract ( sp_pow , cont T & , sp_pow )" ) ;
	a.sort_test() ;

	lidia_size_t at, where, rsz ;
	bool found ;
	lidia_size_t e = 0 ;
	T bb ;
	spc< T > c( b, e ) ;

	if ( ( a.last < e ) || ( b.is_zero () ) )
	  {
	    if ( this != &a ) *this = a ;
	  }
	else
	  {
	    found = a.coeff->bin_search ( c , where ) ;
	    
	    if ( this == &a )
	      {
		if ( found )
		  {
		    ::subtract ( (*coeff)[where].coeff , b, (*coeff)[where].coeff ) ;	       
		
		    if ( ((*coeff)[where].coeff).is_zero () )
		      {
			coeff->remove_from ( where ) ;

			if ( coeff->size() == 0 )
			  assign_zero ( a.last ) ;
			else
			  first = (*coeff)[0].exp ;
		      }	    
		  }
		else
		  {
		    if ( coeff->capacity() < a.coeff->size() + 1 )
		      coeff->set_capacity ( alloc_size ( a.coeff->size() + 1 ) ) ;

		    coeff->insert_at ( c , where ) ;
		    first = (*coeff)[0].exp ;
		  }
	      }
	    else  // res does not alias a
	      {
		found = a.coeff->bin_search ( c , where ) ;

		rsz = a.coeff->size() + ( found ? 0 : 1 ) ;
		if ( coeff->capacity() < rsz )
		  coeff->set_capacity ( alloc_size ( rsz ) ) ;
		coeff->set_size ( 0 ) ;

		if ( where > 0 )
		  coeff->assign ( 0 , (*a.coeff) , 0 , where-1 ) ;

		if ( found )
		  {
		    ::subtract ( bb , b, (*a.coeff)[where].coeff ) ;
		    
		    if ( ! bb.is_zero () )
		      {
			(*coeff)[where].coeff = bb ;
			(*coeff)[where].exp   = e  ;
			at = where + 1 ;
		      }
		    else
		        at = where ;

		    if ( where+1 < a.coeff->size() )
		      coeff->assign ( at , (*a.coeff) , where+1 , a.coeff->size()-1 ) ;

		    if ( coeff->size() == 0 )
		      assign_zero ( a.last ) ;
		    else
		      first = (*coeff)[0].exp ;
		  }
		else
		  {
		    (*coeff)[where] = c ;

		    if ( where < a.coeff->size() )
		      coeff->assign ( where+1 , (*a.coeff) , where , a.coeff->size()-1 ) ;   

		    first = (*coeff)[0].exp ;		   
		  }		

		last  = a.last ;
	      }
	  }
      }



    template < class T >
    void
    base_sparse_power_serie < T >::
    multiply (const base_sparse_power_serie< T > & a,
	      const T                     & b   )
      {
	debug_handler ( "base_sparse_power_serie< T >", "multiply ( sp_pow & , const sp_pow & , const T & )" ) ;

	a.init_test ( "multiply ( 2 x sp_pow , cont T & )" ) ;
	a.sort_test ( ) ;

	lidia_size_t i, j, sz  ;
	T  zero_T ; 

	zero_T.assign_zero () ;

	sort_vector< spc< T > > *ac, *rc ;

	if ( a.is_zero ( ) || b == zero_T )
	  {
	    assign_zero ( a.last ) ;
	  }
	else
	  {
	    sz = a.coeff->size() ;
	    if ( ( this != &a ) && ( coeff->capacity() < sz ) )
	      coeff->set_capacity( alloc_size ( sz ) ) ;

	    ac = a.coeff ;
	    rc = coeff ;

	    for ( i = j = 0 ; i < sz ; i++ )
	      {
		::multiply ( (*rc)[j].coeff , (*ac)[i].coeff , b ) ;

		if ( (*rc)[j].coeff != zero_T )
		  {
		    (*rc)[j].exp = (*ac)[i].exp ;
		    j ++ ;
		  }
	      }

	    if ( j == 0 )
	        assign_zero ( a.last ) ;
	    else
	      {
		coeff->set_size ( j ) ;
		first = (*rc)[0].exp ;
		last  = a.last ;

		sorted = true ;
	      }
	  }
      }

    template < class T >
    void
    base_sparse_power_serie < T >::
    multiply (const T                     & b   ,
	      const base_sparse_power_serie< T > & a   )
      {
	debug_handler ( "base_sparse_power_serie< T >", "multiply ( sp_pow &, const T &, const sp_pow & )" ) ;

	a.init_test ( "multiply ( sp_pow , cont T & , sp_pow )" ) ;
	a.sort_test ( ) ;

	lidia_size_t i, j, sz  ;
	T  zero_T ;

	zero_T.assign_zero () ;

	sort_vector< spc< T > > *ac, *rc ;

	if ( a.is_zero ( ) || b == zero_T )
	  {
	    assign_zero ( a.last ) ;
	  }
	else
	  {
	    sz = a.coeff->size() ;
	    if ( ( this != &a ) && ( coeff->capacity() < sz ) )
	      coeff->set_capacity( alloc_size ( sz ) ) ;

	    ac = a.coeff ;
	    rc = coeff ;

	    for ( i = j = 0 ; i < sz ; i++ )
	      {
		::multiply ( (*rc)[j].coeff , b , (*ac)[i].coeff ) ;

		if ( (*rc)[j].coeff != zero_T )
		  {
		    (*rc)[j].exp = (*ac)[i].exp ;
		    j ++ ;
		  }
	      }

	    if ( j == 0 )
	        assign_zero ( a.last ) ;
	    else
	      {
		coeff->set_size ( j ) ;
		first = (*rc)[0].exp ;
		last  = a.last ;

		sorted = true ;
	      }
	  }
      }


    template < class T >
    void
    base_sparse_power_serie < T >::
    divide ( const base_sparse_power_serie< T > & a,
	    const T                     & b   )
      {
	debug_handler ( "base_sparse_power_serie< T >", "divide ( sp_pow & , const sp_pow & , const T & )" ) ;
	a.init_test ( "divide ( 2 x sp_pow , cont T & )" ) ;

	lidia_size_t i, sz ;
	sort_vector< spc< T > > *ac, *rc ;


	if ( b.is_zero () )  // this should be : b is not invertible
	  lidia_error_handler ( "base_sparse_power_serie< T >", "divide ( sp_pow & , const sp_pow & , const T & )::non-invertible element" ) ;

	sz = a.coeff->size() ;
	ac = a.coeff ;
	rc = coeff ;

	if ( this != &a )
	  {
	    if ( a.is_zero() )
	      assign_zero ( a.last ) ;
	    else
	      if ( rc->capacity() < sz )
		rc->set_capacity ( alloc_size ( sz ) ) ;
	  }

	for ( i = 0 ; i < sz ; i++ )
	  {
	    ::divide ( (*rc)[i].coeff , (*ac)[i].coeff , b ) ; 
	    (*rc)[i].exp = (*ac)[i].exp ;
	  }

	first  = a.first  ;
	last   = a.last   ;
	sorted = a.sorted ;
      }




