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

MODULE: matrix

SUMMARY:

Matrix templates.

The declaration 

   Mat<T> M;

creates a 0 x 0 matrix.  

We can make it have 10 rows and 20 columns like this:

   M.SetDims(10, 20);

A row can be accessed as M[i], indexing from 0, or as M(i), indexing from 1.
A matrix entry can be accessed as M[i][j], indexing from 0, or as
M(i, j), indexing from 1.

A matrix is represented as a Vec< Vec<T> >: a vector of rows, where
each row is a Vec<T>.  Any attempt to resize one of the rows so
as to create a non-rectangular matrix will result in a run-time 
error.

The dimensions of an existing matrix may be changed.  If the number of
columns does not change, then the matrix is just "resized" like a vector,
and no information is lost.  Otherwise, if the number of columns changes,
the matrix is completely destroyed, and a new matrix is created


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


// EXCEPTIONS: all functions below do not throw any exceptions,
//   except as noted

template<class T>
class Mat {

   typedef typename Vec<T>::value_type value_type;
   typedef typename Vec<T>::reference reference;
   typedef typename Vec<T>::const_reference const_reference;


   Mat(); // initially 0 x 0

   Mat(const Mat<T>& a);
   // copy constructor

   // EXCEPTIONS: may throw


   Mat& operator=(const Mat<T>& a);
   // assignment

   // EXCEPTIONS: may throw, weak ES (but dimensions of LHS
   //   will be either that of old LHS or RHS)

   ~Mat();
   // destructor

   Mat(Mat&& other) noexcept;
#ifndef NTL_DISABLE_MOVE_ASSIGN
   Mat& operator=(Mat&& other) noexcept;
#endif
   // move semantics (C++11 only)

   Mat(INIT_SIZE_TYPE, long n, long m);
   // Mat(INIT_SIZE, n, m) initializes an n x m matrix, invoking
   // the default constructor for T to initialize entries.

   // EXCEPTIONS: may throw

   void SetDims(long n, long m);
   // M.SetDims(n, m) makes M have dimension n x m.  If the number of
   // columns (m) changes, previous storage is freed, and space for M
   // is reallocated and initialized; otherwise, more rows are
   // allocated as necessary (when number of rows increases), 
   // excess rows are retained (when number of rows decreases),
   // and--importantly--the contents do not change.

   // EXCEPTIONS: strong ES (although underlying vector representation
   //    may be reallocated)

   void kill(); free storage and make 0 x 0

   long NumRows() const;
   // M.NumRows() returns the number of rows of M

   long NumCols() const;
   // M.NumCols() returns the number of columns of M

   Vec<T>& operator[](long i);
   const Vec<T>& operator[](long i) const;
   // access row i, initial index 0.  
   // Even if one has read/write access to a row, any attempt
   // to change its length will raise an error.

   // EXCEPTIONS: may throw if range checking is turned on

   Vec<T>& operator()(long i);
   const Vec<T>& operator()(long i) const;
   // access row i, initial index 1. 
   // Even if one has read/write access to a row, any attempt
   // to change its length will raise an error.
   // of this row will raise an error.

   // EXCEPTIONS: may throw if range checking is turned on

   reference operator()(long i, long j);
   const_reference operator()(long i, long j) const;
   // access element (i, j), both indices starting at 1

   // EXCEPTIONS: may throw if range checking is turned on

   const_reference get(long i, long j) const;
   // access element (i, j), both indices starting at 0

   // EXCEPTIONS: may throw if range checking is turned on

   void put(long i, long j, const T& a);
   // same as M[i].put(j, a)

   template <class U>
   void put(long i, long j, const U& a);
   // same as M[i].put(j, a)

   long position(const Vec<T>& a) const;
   // returns index of a in matrix, or -1 if not present;
   // equivalent to rep(*this).position(a).

   long position1(const Vec<T>& a) const;
   // returns index of a in matrix, or -1 if not present;
   // equivalent to rep(*this).position1(a).

   long alias(const Vec<T>& a) const;
   // returns 1 if a aliases a row of the matrix, and 0 otherwise.

   void swap(Mat<T>& other);
   // quick swap *this and other

   void move(Mat<T>& other);
   // quick move other to *this

};

template<class T>
const Vec< Vec<T> >& rep(const Mat<T>& a);
// read-only access to underlying representation

template<class T>
void swap(Mat<T>& X, Mat<T>& Y);
// quick swap of X and Y 

template<class T>
void MakeMatrix(Mat<T>& x, const vec_vec_T& a);
// copies a to x, checking that it is "rectangular"

// EXCEPTIONS: may thow, weak ES (but dimensions of x either
//    remain unchanged or are set to the new dimensions implied by a)

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

                            Input/Output

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


template<class T>
istream& operator>>(istream&, Mat<T>&);

// EXCEPTIONS: may throw, weak ES

template<class T>
ostream& operator<<(ostream&, const Mat<T>&);

// EXCEPTIONS: may throw, weak ES


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

                              Equality Testing


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


template<class T>
long operator==(const Mat<T>& a, const Mat<T>& b);

template<class T>
long operator!=(const Mat<T>& a, const Mat<T>& b);