// 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 SymMatrix;
template <class Item> class MatrixWrapper;

template <class Item> class Matrix {
public:
    Matrix(int numRows=0, int numCols=0);
    Matrix(const Matrix<Item>& A);
    ~Matrix();

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

	    int 	 numRows() const { return numrows; }
	    int 	 numCols() const { return numcols; }
	    int 	 scalarMultRow(double s, int r);
	    int 	 scalarMultCol(double s, int r);
	    int 	 addRows(int r1, int r2);	// stores in r1
	    int 	 addCols(int c1, int c2);	// stores in c1
	    int 	 swapRows(int r1, int r2);
	    int 	 swapCols(int c1, int c2);
    // returns or sets element: row,col
    virtual Item&	 operator() (int row, int col) const;
    //

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

    // overloaded operators
    Matrix<Item>	 operator*(const Matrix<Item>& A); 
   // Matrix<Item>	 operator*(const SymMatrix<Item>&  S); 
    Matrix<Item>	 operator*(const Item& scalar);     

    Matrix<Item>	 operator+(const Matrix<Item>& A); 
   // Matrix<Item>	 operator+(const SymMatrix<Item>&  S); 

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

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

    Matrix<Item>	 transpose();

    int		 numrows;   // number of rows
    int		 numcols;   // number of cols
    friend class SymMatrix<Item>;
    friend class MatrixWrapper<Item>;
private:
    Item**	 Elements;                               
};


template <class Item> class SymMatrix : public Matrix<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
    Matrix<Item>	 operator*(const Matrix<Item>& A);      //sym * asym
    Matrix<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
    Matrix<Item>	 operator+(const Matrix<Item>& A);      //sym + asym

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

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

    Bool	 operator!=(const SymMatrix<Item>& S);        //sym != sym
    Bool	 operator!=(const Matrix<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_Matrix_TEMPLATE
#include <LINK/basic/Matrix.cpp>
//#endif


#endif

