



// LiDIA - a library for computational number theory
//   Copyright (c) 1995 by the LiDIA Group
//
// File        : base_dense_power_serie.h 
// Author      : Frank Lehmann (FL), Markus Maurer (MM) 
// Last change : FL/MM, Oct 2 1995, initial version
//		 FL/MM, Oct 2 1995, removed the randomize-function to allow
//				    power series over Q, R and C.




#ifndef LiDIA_BASE_DENSE_POWER_SERIE_H
#define LiDIA_BASE_DENSE_POWER_SERIE_H


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

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



template < class T > class base_dense_power_serie
 {

    protected :

      lidia_size_t    first ;
      lidia_size_t    last  ;
      math_vector< T > *coeff ;

      lidia_size_t    max_num_coeff ;


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

    void add ( const base_dense_power_serie< T > & a, const base_dense_power_serie< T > & b );
    void add ( const base_dense_power_serie< T > & a, const T & b );
    void add ( const T & b, const base_dense_power_serie< T > & a );

    void subtract ( const base_dense_power_serie< T > & a, const base_dense_power_serie< T > & b );
    void subtract ( const base_dense_power_serie< T > & a, const T & b );
    void subtract ( const T & b, const base_dense_power_serie< T > & a );

    void multiply ( const base_dense_power_serie< T > & a, const T & b );
    void multiply ( const T & b,const base_dense_power_serie< T > & a );

    void divide ( const base_dense_power_serie< T > & a, const T & b );
    void negate ( const base_dense_power_serie< T >& a );

    void swap ( base_dense_power_serie< T >& a );


    //
    // ***** constructors / destructor *****
    //

    public :

    base_dense_power_serie ();
    base_dense_power_serie ( const T & elem, lidia_size_t l );
    base_dense_power_serie ( const base_vector< T > & c, lidia_size_t f );
    base_dense_power_serie ( const base_dense_power_serie< T > & a );
    ~base_dense_power_serie ();


    //
    // ***** utility routines *****
    //

    protected :

    bool is_zero ( lidia_size_t & non_zero_index ) const;


    public :

    bool is_zero () const;
    bool is_one ();


    protected :

    void allocate ( lidia_size_t cp, math_vector< T > * c );


    public :
    
    lidia_size_t get_first ( void ) const;
    lidia_size_t get_last  ( void ) const;
    void  reduce_last ( lidia_size_t l );



    //
    // ***** coefficient handling *****
    //

    void get_coeff ( T & elem, lidia_size_t e );
    void get ( base_vector< T > & c );
    void get ( T * & c, lidia_size_t & sz );
    void set_coeff ( const T & elem, lidia_size_t e );
    void set_coeff ( const T & elem, lidia_size_t e, const base_dense_power_serie< T > & a );
    void set ( base_vector< T > & c, lidia_size_t f );
    void set ( const T *c, lidia_size_t prec, lidia_size_t f );
    void set ( const T & elem, lidia_size_t l );


    //
    // ***** more utility functions *****
    //

    void clear ();
    void normalize ();
    void set_max_num_of_coeff ( lidia_size_t sz );
    lidia_size_t get_max_num_of_coeff ();
    void  clear_max_num_of_coeff ();


    // 
    // ***** subscripting *****
    // 

    const T operator[] ( lidia_size_t e ) const;
    T &     operator() ( lidia_size_t e );


    //
    // ***** assignment *****
    //

    void assign_zero ( lidia_size_t f );
    void assign_one ( lidia_size_t l );

    const base_dense_power_serie< T > & operator= ( const base_dense_power_serie< T > & a );
    const base_dense_power_serie< T > & operator= ( const base_sparse_power_serie< T > & a );


    //
    // ***** cast - operator *****
    //

    operator base_sparse_power_serie< T >();


    //
    // ***** comparisons *****
    //

    bool operator== ( const base_dense_power_serie< T > & a ) const;
    bool operator!= ( const base_dense_power_serie< T > & a ) const;


    //
    // ***** arithmetic via operators *****
    //


    inline friend 
    base_dense_power_serie< T >
    operator+ ( const base_dense_power_serie< T > & a,
                const base_dense_power_serie< T > & b)
     {base_dense_power_serie< T > c; c.add(a,b); return(c);}


    inline friend 
    base_dense_power_serie< T >
    operator+ ( const base_dense_power_serie< T > & a,
	        const T & b )
     {base_dense_power_serie< T > c; c.add(a,b); return(c);}


    inline friend
    base_dense_power_serie< T >
    operator+ ( const T & b,
 	        const base_dense_power_serie< T > & a )
     {base_dense_power_serie< T > c; c.add(b,a); return(c);}


    inline friend 
    const base_dense_power_serie< T > &
    operator+= ( base_dense_power_serie< T > & a,
		 const base_dense_power_serie< T > & b )
     {a.add(a,b); return (a);}


    inline friend
    const base_dense_power_serie< T > &
    operator+= ( base_dense_power_serie< T > & a,
		 const T & b )
     {a.add(a,b); return (a);}

    inline friend
    base_dense_power_serie< T >
    operator- ( const base_dense_power_serie< T > & a,
                const base_dense_power_serie< T > & b )
    {base_dense_power_serie< T > c; c.subtract (a,b); return(c);}


    inline friend
    base_dense_power_serie< T >
    operator- ( const base_dense_power_serie< T > & a,
	        const T & b )
    {base_dense_power_serie< T > c; c.subtract (a,b); return(c);}


    inline friend
    base_dense_power_serie< T >
    operator- ( const T & b,
	        const base_dense_power_serie< T > & a )
    {base_dense_power_serie< T > c; c.subtract(b,a); return(c);}


    inline friend
    const base_dense_power_serie< T > &
    operator-= ( base_dense_power_serie< T > & a,
		 const base_dense_power_serie< T > & b )
     {a.subtract(a,b); return(a);}


    inline friend
    const base_dense_power_serie< T > &
    operator-= ( base_dense_power_serie< T > & a,
		 const T & b )
    {a.subtract(a,b); return(a);}

    inline friend
    base_dense_power_serie< T >
    operator* ( const base_dense_power_serie< T > & a,
	        const T & b )
    {base_dense_power_serie< T > c; c.multiply(a,b); return(c);}


    inline friend
    base_dense_power_serie< T >
    operator* ( const T & b,
	        const base_dense_power_serie< T > & a )
    {base_dense_power_serie< T > c; c.multiply(b,a); return(c);}

    inline friend 
    const base_dense_power_serie< T > &
    operator*= ( base_dense_power_serie< T > & a,
		 const T & b)
    {a.multiply(a,b); return(a);}


    inline friend
    base_dense_power_serie< T >
    operator/ ( const base_dense_power_serie< T > & a,
	        const T & b )
     {base_dense_power_serie< T > c; T x; invert(x,b); c.multiply(a,x); return(c);}


    inline friend 
    const base_dense_power_serie< T > &
    operator/= ( base_dense_power_serie< T > & a, 
		 const T & b)
     {T x; invert(x,b); a.multiply(a,x); return(a);}



    //
    // ***** input / output *****
    //

    int read ( istream & in );
    void write ( ostream & out ) const;

    inline friend
    istream &
    operator>> ( istream & in, base_dense_power_serie< T > & a )
     {a.read(in); return(in);}


    inline friend
    ostream &
    operator<< ( ostream & out, const base_dense_power_serie< T > & a )
     {a.write(out); return(out);}



    // 
    // ***** miscellaneous *****
    // 

    void multiply_by_xn ( lidia_size_t n );
    void compose ( lidia_size_t n );

    //friend void randomize ( base_dense_power_serie< T > & a,
    //			    lidia_size_t f, lidia_size_t l,
    //			    const T & coeff_bound );
 


    // 
    // ***** arithmetic via functions *****
    // 

    inline friend
    void
    add (       base_dense_power_serie< T > & c,
	  const base_dense_power_serie< T > & a,
	  const base_dense_power_serie< T > & b )
     {c.add(a,b);}
    
    inline friend
    void
    add (       base_dense_power_serie< T > & c,
	  const base_dense_power_serie< T > & a,
	  const 	                 T  & b )
     {c.add(a,b);}

    inline friend
    void
    add (       base_dense_power_serie< T > & c ,
	  const                   T  & b ,
	  const base_dense_power_serie< T > & a )
     {c.add(b,a);}

    inline friend
    void
    subtract (       base_dense_power_serie< T > & c,
	       const base_dense_power_serie< T > & a,
	       const base_dense_power_serie< T > & b )
     {c.subtract(a,b);}

    inline friend
    void
    subtract (       base_dense_power_serie< T > & c,
	       const base_dense_power_serie< T > & a,
	       const              T  & b )
     {c.subtract(a,b);}

    inline friend
    void
    subtract (       base_dense_power_serie< T > & c,
	       const              T  & b,
	       const base_dense_power_serie< T > & a )
     {c.subtract(b,a);}

    inline friend
    void
    multiply (       base_dense_power_serie< T > & c,
	       const base_dense_power_serie< T > & a,
	       const  	             T  & b )
     {c.multiply(a,b);}

    inline friend
    void
    multiply (       base_dense_power_serie< T > & c,
	       const                   T  & b,
	       const base_dense_power_serie< T > & a )
     {c.multiply(b,a);}

    inline friend
    void
    divide (       base_dense_power_serie< T > & c,
	     const base_dense_power_serie< T > & a,
	     const T  & b )
     {c.divide(a,b);}

    inline friend
    void
    negate ( base_dense_power_serie< T >& c, const base_dense_power_serie< T >& a )
     {c.negate(a);}



    //
    // ***** miscellaneous *****
    //

    inline friend
    void
    swap ( base_dense_power_serie< T >& c, base_dense_power_serie< T >& a )
     {c.swap(a);}

  } ;


#ifdef LIDIA_INCLUDE_C
#include <LiDIA/base_dense_power_serie.c>
#endif 

#endif


