//===========================================================================
// SINTEF LSMG library - version 1.1
//
// Copyright (C) 2000-2005 SINTEF ICT, Applied Mathematics, Norway.
//
// This program is free software; you can redistribute it and/or          
// modify it under the terms of the GNU General Public License            
// as published by the Free Software Foundation version 2 of the License. 
//
// This program is distributed in the hope that it will be useful,        
// but WITHOUT ANY WARRANTY; without even the implied warranty of         
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          
// GNU General Public License for more details.                           
//
// You should have received a copy of the GNU General Public License      
// along with this program; if not, write to the Free Software            
// Foundation, Inc.,                                                      
// 59 Temple Place - Suite 330,                                           
// Boston, MA  02111-1307, USA.                                           
//
// Contact information: e-mail: tor.dokken@sintef.no                      
// SINTEF ICT, Department of Applied Mathematics,                         
// P.O. Box 124 Blindern,                                                 
// 0314 Oslo, Norway.                                                     
//
// Other licenses are also available for this software, notably licenses
// for:
// - Building commercial software.                                        
// - Building software whose source code you wish to keep private.        
//===========================================================================
#include <MatSparse.h>
#include <math.h>
#include <algorithm>
#include <iostream>


void MatSparse::init(std::vector<std::pair<int,int> >& entries, int m, int n, bool sorted) {


  if (!sorted)
    std::sort(entries.begin(), entries.end());


  resize(m, n, entries.size());
  
  std::fill(irow_.begin(), irow_.end(), -1);
  
  int offset=0;
  int prev_row = -999;
  std::vector<std::pair<int,int> >::const_iterator it;
  for (it = entries.begin(); it != entries.end(); ++it) {
    int row = it->first;
    int col = it->second;
    if (row != prev_row) {
      irow_[row] = offset;
      prev_row = row;
    }
    jcol_[offset] = col;
    offset++;

  }
  irow_[noR_] = offset;
  
}

void MatSparse::init(const BitMatrix& pattern) {
  

  std::cout << "MatSparse::init(const BitMatrix& pattern) ..., but obsolete ??? " << std::endl; 


  
  int m,n;
  pattern.size(m,n);

  int nonzeros=0;
  for (int i = 0; i < m; i++)
    for (int j = 0; j < n; j++)
      if (pattern.get(i, j))
	nonzeros++;

  resize(m, n, nonzeros);


  int offset = 0;
  for (int i = 0; i < m; i++) { 
    irow_[i] = offset; 
    
    for (int j = 0; j < n; j++) { 
      if (pattern.get(i,j)) {
	jcol_[offset] = j;
	a_[offset] = 0.0; 
	offset++;
      }
    }
  }

  irow_[m] = offset;  
}


void MatSparse::init(const MatSparse& mat, bool copyElements) { 
  
  noR_ = mat.noR_;
  noC_ = mat.noC_;
  p_   = mat.p_;
  irow_.resize(mat.irow_.size());
  std::copy(mat.irow_.begin(), mat.irow_.end(), irow_.begin()); 

  jcol_.resize(mat.jcol_.size());
  std::copy(mat.jcol_.begin(), mat.jcol_.end(), jcol_.begin()); 

  a_.resize(mat.a_.size());

  if (copyElements)
    std::copy(mat.a_.begin(), mat.a_.end(), a_.begin());
  else
    std::fill(a_.begin(), a_.end(), 0.0);
}


void MatSparse::operator += (const MatSparse& mat) { 
  
  std::vector<double>::iterator it1;
  std::vector<double>::const_iterator it2;
  for (it1 = a_.begin(), it2 = mat.a_.begin(); it1 != a_.end(); ++it1, ++it2)
    *it1 += *it2;
}

void MatSparse::operator *= (double fac) {
  std::vector<double>::iterator it;
  for (it = a_.begin(); it != a_.end(); ++it)
    *it *= fac;
}


void MatSparse::resize(int n1, int n2, int num_nonzero) {
  noR_ = n1;
  noC_ = n2;
  p_ = num_nonzero;
  irow_.resize(n1+1);
  jcol_.resize(num_nonzero);
  a_.resize(num_nonzero);
  irow_[noR_] = num_nonzero;
}
 



double& MatSparse::operator () (int i, int j) {

  for(int k=irow(i); k<irow(i+1); k++) {
    if(jcol(k) == j)
      return a_[k];
  }

  std::cerr << "ERROR op1: (" << i << ',' << j << ") not in sparsity pattern" << std::endl;
  exit(-1);
}

const double& MatSparse::operator () (int i, int j) const {

  for(int k=irow(i); k<irow(i+1); k++) {
    if(jcol(k) == j)
      return a_[k];
  }
  std::cerr << "ERROR op2: (" << i << ',' << j << ") not in sparsity pattern" << std::endl;
  exit(-1);
}

double MatSparse::getVal(int i, int j) const { 
  for(int k=irow(i); k<irow(i+1); k++) {
    if(jcol(k) == j)
      return a_[k];
  }
  return 0.0;
}

int MatSparse::getOffset(int i, int j) const {
  for(int k=irow(i); k<irow(i+1); k++) {
    if(jcol(k) == j)
      return k;
  }
  std::cerr << "ERROR op2: (" << i << ',' << j << ") not in sparsity pattern" << std::endl;
  exit(-1);
}

double MatSparse::norml2() const {
  
  double sum2 = 0.0;
  for (int i = 0; i < noR_; i++) {
    for (int offset = irow(i); offset < irow(i+1); offset++)
      sum2 += operator()(offset)*operator()(offset);    
  }
  return sqrt(sum2);
}

bool MatSparse::isSymmetric() const {

  if (noR_ != noC_) 
    return false;

  for (int ii = 0; ii < noR_; ii++) {
    for (int offset = irow(ii); offset < irow(ii+1); offset++) {
      int jj = jcol(offset);
      if ( operator()(offset) != operator()(jj,ii))
        return false;
    }
  }
  return true;
}

bool MatSparse::isDiagonallyDominant() const {

  for (int ii = 0; ii < noR_; ii++) {

    double sum = 0.0;
    double a_ii = 0.0; 
    
    for (int offset = irow(ii); offset < irow(ii+1); offset++) {
      int jj = jcol(offset); 
      if (jj == ii)
        a_ii = fabs(operator()(offset));
      else
        sum += fabs(operator()(offset));
    }
    if (sum > a_ii)
      return false;
  }
  return true;
}

void MatSparse::printPattern(std::ostream& os) const {
  for (int ii = 0; ii < noR_; ii++) {
    int offset = irow(ii);
    int jj = jcol(offset);
    for (int j = 0; j < noC_; j++) {
      if (j == jj) {
        os << '1';
        offset++;
        jj = jcol(offset);
      }
      else
        os << '0';
    }
    os << '\n';
  }
}

void MatSparse::print(std::ostream& os) const {
  for (int ii = 0; ii < noR_; ii++) {
    int offset = irow(ii);
    int jj = jcol(offset);
    for (int j = 0; j < noC_; j++) {
      if (j == jj) {
        os << a_[offset] << ' ';
        offset++;
        jj = jcol(offset);
      }
      else
        os << "XXX ";
    }
    os << '\n';
  }
}

void MatSparse::printMatlab(std::ostream& os) const {
  std::cout << "MatSparse: Printing file to Matlab format..." << std::endl;
  os << "A = [\n";
  for (int ii = 0; ii < noR_; ii++) {
    int offset = irow(ii);
    int jj = jcol(offset);
    for (int j = 0; j < noC_; j++) {
      if (j == jj) {
        os << a_[offset] << ' ';
        offset++;
        jj = jcol(offset);
      }
      else
        os << "0 ";
    }
    os << ";\n";
  }
  os << ']';
}

void MatSparse::printPatternGnuplot(std::ostream& os) const {
  std::cout << "MatSparse: Printing file to Gnuplot format..." << std::endl;
  for (int ii = 0; ii < noR_; ii++) {
    int offset = irow(ii);
    int jj = jcol(offset);
    for (int j = 0; j < noC_; j++) {
      if (j == jj) {
        os << ii << ' ' << jj << '\n';
        offset++;
        jj = jcol(offset);
      }
    }
  }
}


 
