// Copyright (C) 1996 DIMACS Center, Rutgers, The State University of New Jersey
// Author(s): Michael Murphy (Los Alamos National Laboratory), Jonathan Berry

// This software is copyrighted by the DIMACS Center at Rutgers, The State
// University of New Jersey.  IT IS PROVIDED AS IS, AND THE AUTHORS, DIMACS, AND
// RUTGERS, THE STATE UNIVERSITY OF NEW JERSEY  DISCLAIM
// ALL LIABILITY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
// DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
// IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
// NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
// MODIFICATIONS.

// The authors hereby grant permission to use, copy, modify, distribute,
// and license this software and its documentation for any purpose, provided
// that existing copyright notices are retained in all copies and that this
// notice is included verbatim in any distributions. No written agreement,
// license, or royalty fee is required for any of the authorized uses.
// Modifications to this software may be copyrighted by their authors
// and need not follow the licensing terms described here, provided that
// the new terms are clearly indicated on the first page of each file where
// they apply.

// Last File Update: 31-Jul-1996
// 

#ifndef MATRIX_H
#define MATRIX_H

#include <iostream.h>
#include <LINK/basic/general.h>

template <class Item> class Matrix {
protected:
    int		 numrows;   // number of rows
    int		 numcols;   // number of cols

   //checks the dimensions of a matrix
   //virtual void check_dimensions(int i,j); 

public:
    Matrix(int rows=0, int cols=0) : numrows(rows), numcols(cols) {}

    virtual ~Matrix() {};
    
    virtual void save(char* filename) = 0;
    virtual void load(char* filename) = 0;
    virtual ostream& display(ostream& os) const = 0;

    // returns element i,j.  Can also be used to set element i,j
    virtual 	Item& operator() (int i,int j) const = 0;   

    Item get(int i, int j) const 
    { 
      return ((Matrix&) *this)(i,j); // read-only copy of element
    }

    // return number of rows and number of columns
    int 	numRows() const    { return numrows;}
    int		numCols() const    { return numcols;}
    friend ostream& operator<<(ostream& os, const Matrix<Item>& m);
};


template <class Item> class SymMatrix;

template <class Item> class AsymMatrix : public Matrix<Item> { 
        
friend class SymMatrix<Item>; 

public:
    AsymMatrix(int=0, int=0);
    AsymMatrix(const AsymMatrix<Item>& A);
    ~AsymMatrix();

    void	 save(char* filename);
    void 	 load(char* filename);
    ostream&     display(ostream& os) const;

    // returns or sets element: row,col
    Item&	 operator() (int row, int col) const;
    //
    Item 	 at(int row, int col) const
                 { return ((AsymMatrix<Item>&)*this)(row,col); }

    // assigns one AsymMatrix the values of another AsymMatrix        
    AsymMatrix<Item>&	 operator=(const AsymMatrix<Item>& A);

    // overloaded operators
    AsymMatrix<Item>	 operator*(const AsymMatrix<Item>& A); //asym * asym
    AsymMatrix<Item>	 operator*(const SymMatrix<Item>&  S); //asym * sym
    AsymMatrix<Item>	 operator*(const Item& scalar);       //asym * element

    AsymMatrix<Item>	 operator+(const AsymMatrix<Item>& A); //asym + asym
    AsymMatrix<Item>	 operator+(const SymMatrix<Item>&  S); //asym + sym

    AsymMatrix<Item>	 operator-(const AsymMatrix<Item>& A); //asym - asym
    AsymMatrix<Item>	 operator-(const SymMatrix<Item>&  S); //asym - sym
        
    Bool	 operator==(const AsymMatrix<Item>& A);       //asym == asym
    Bool	 operator==(const SymMatrix<Item>& S);        //asym == sym

    Bool	 operator!=(const AsymMatrix<Item>& A);       //asym != asym
    Bool	 operator!=(const SymMatrix<Item>& S);        //asym != sym

    AsymMatrix<Item>	 transpose();

private:
    // points to the elements of the asymmetric matrix
    Item**	 Elements;                               
       
    // returns element row,col.  Used only for const asymmetric matrices
    // Does not check if element row,col is legal, therefore this is 
    // only used when we know we are within the matrix's bounds
    //Item	 operator()(int row, int col) const;
};


template <class Item> class SymMatrix : public Matrix<Item> {

friend class AsymMatrix<Item>;

public:
    SymMatrix(int dim=0, int dim2=0); // allow two arguments but use only the first
				 // to be compatible with (#rows,#cols)
    SymMatrix(const SymMatrix<Item>& S);
    ~SymMatrix();

    void	 save(char * filename);
    void	 load(char * filename);
    ostream& 	display(ostream& os) const;

    int 	 dimension() const    { return numrows;}

    // returns or sets element row,col 
    Item&	 operator() (int row, int col) const; 

    // assigns one SymMatrix the values of another SymMatrix 
    SymMatrix<Item>&	 operator=(const SymMatrix<Item>& S);

    // overloaded operators
    AsymMatrix<Item>	 operator*(const AsymMatrix<Item>& A);      //sym * asym
    AsymMatrix<Item>	 operator*(const SymMatrix<Item>&  S);      //sym * sym
    SymMatrix<Item> 	 operator*(const Item& scalar);       	 //sym * element

    SymMatrix<Item> 	 operator+(const SymMatrix<Item>&  S);      //sym + sym
    AsymMatrix<Item>	 operator+(const AsymMatrix<Item>& A);      //sym + asym

    SymMatrix<Item> 	 operator-(const SymMatrix<Item>&  S);      //sym - sym
    AsymMatrix<Item>	 operator-(const AsymMatrix<Item>& A);      //sym - asym

    Bool	 operator==(const SymMatrix<Item>& S);        //sym == sym
    Bool	 operator==(const AsymMatrix<Item>& A);       //sym == asym

    Bool	 operator!=(const SymMatrix<Item>& S);        //sym != sym
    Bool	 operator!=(const AsymMatrix<Item>& A);       //sym != asym

    SymMatrix<Item>	 transpose();

private:
    //points to the elements of the SymMatrix stored in lower triangual form
    Item*	 LowTriangMat;

    // contains the number of elements in the SymMatrix
    int		 size;
  
    // returns element row,col.  Used only for const symmetric matrices
    // Does not check if element row,col is legal, therefore is only used
    // when we know element row,col is within the matrix's bounds  
    //Item	 operator()(int row, int col) const;
};

#ifdef DEFINE_TEMPLATE
#include <LINK/basic/Matrix.cc>
#endif


#endif

