// Copyright (C) 2003-2009 Marc Duruflé
// Copyright (C) 2001-2009 Vivien Mallet
//
// This file is part of the linear-algebra library Seldon,
// http://seldon.sourceforge.net/.
//
// Seldon is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the Free
// Software Foundation; either version 2.1 of the License, or (at your option)
// any later version.
//
// Seldon 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 Lesser General Public License for
// more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Seldon. If not, see http://www.gnu.org/licenses/.


#ifndef SELDON_FILE_MATRIX_CONVERSIONS_CXX

namespace Seldon
{
  
  /*
    From CSR formats to "Matlab" coordinate format.
  */
  
  
  //! Conversion from RowSparse to coordinate format.
  template<class T, class Prop, class Allocator1, class Allocator2>
  void
  ConvertMatrix_to_Coordinates(const Matrix<T, Prop, RowSparse,
			       Allocator1>& A,
			       IVect& IndRow, IVect& IndCol,
			       Vector<T, VectFull, Allocator2>& Val,
			       int index = 0, bool sym = false)
  {
    int i, j;
    int m = A.GetM();
    int nnz = A.GetDataSize();
    IndRow.Reallocate(nnz);
    IndCol.Reallocate(nnz);
    Val.Reallocate(nnz);
    int* ptr = A.GetPtr();
    int* ind = A.GetInd();
    T* val = A.GetData();
    for (i = 0; i < m; i++)
      for (j = ptr[i]; j< ptr[i+1]; j++)
	{
	  IndRow(j) = i + index;
	  IndCol(j) = ind[j] + index;
	  Val(j) = val[j];
	}
  }
  
  
  //! Conversion from ColSparse to coordinate format.
  template<class T, class Prop, class Allocator1, class Allocator2>
  void
  ConvertMatrix_to_Coordinates(const Matrix<T, Prop, ColSparse,
			       Allocator1>& A,
			       IVect& IndRow, IVect& IndCol,
			       Vector<T, VectFull, Allocator2>& Val,
			       int index = 0, bool sym = false)
  {
    int i, j;
    int n = A.GetN();
    int nnz = A.GetDataSize();
    IndCol.Reallocate(nnz);
    IndRow.Reallocate(nnz);
    Val.Reallocate(nnz);
    int* ptr = A.GetPtr();
    int* ind = A.GetInd();
    T* val = A.GetData();
    for (i = 0; i< n; i++)
      for (j = ptr[i]; j< ptr[i+1]; j++)
	{
	  IndCol(j) = i + index;
	  IndRow(j) = ind[j] + index;
	  Val(j) = val[j];
	}
  }
  
  
  //! Conversion from RowSymSparse to coordinate format.
  template<class T, class Prop, class Allocator1, class Allocator2>
  void
  ConvertMatrix_to_Coordinates(const Matrix<T, Prop,
			       RowSymSparse, Allocator1>& A,
			       IVect& IndRow, IVect& IndCol,
			       Vector<T, VectFull, Allocator2>& Val,
			       int index = 0, bool sym = false)
  {
    int i, j;
    int m = A.GetM();
    int nnz = A.GetDataSize();
    int* ptr = A.GetPtr();
    int* ind = A.GetInd();
    T* val = A.GetData();
    if (sym)
      {
	nnz *= 2;
	for (i = 0; i < m; i++)
	  if (ind[ptr[i]] == i)
	    nnz--;
	
	IndRow.Reallocate(nnz);
	IndCol.Reallocate(nnz);
	Val.Reallocate(nnz);
	IVect Ptr(m);
	Ptr.Zero();
	int nb = 0;
	for (i = 0; i < m; i++)
	  for (j = ptr[i]; j < ptr[i + 1]; j++)
	    {
	      IndRow(nb) = i + index;
	      IndCol(nb) = ind[j] + index;
	      Val(nb) = val[j];
	      Ptr(ind[j])++;
	      nb++;
	      
	      if (ind[j] != i)
		{
		  IndRow(nb) = ind[j] + index;
		  IndCol(nb) = i + index;
		  Val(nb) = val[j];
		  Ptr(i)++;
		  nb++;
		}
	    }
	
	// Sorting the row numbers...
	Sort(IndRow, IndCol, Val);
	
	// ... and the column numbers.
	int offset = 0;
	for (i = 0; i < m; i++)
	  {
	    Sort(offset, offset + Ptr(i) - 1, IndCol, Val);
	    offset += Ptr(i);
	  }
	
      }
    else
      {
	IndRow.Reallocate(nnz);
	IndCol.Reallocate(nnz);
	Val.Reallocate(nnz);
	for (i = 0; i < m; i++)
	  for (j = ptr[i]; j< ptr[i + 1]; j++)
	    {
	      IndRow(j) = i + index;
	      IndCol(j) = ind[j] + index;
	      Val(j) = val[j];
	    }
      }
  }
  
  
  //! Conversion from ColSymSparse to coordinate format.
  template<class T, class Prop, class Allocator1, class Allocator2>
  void
  ConvertMatrix_to_Coordinates(const Matrix<T, Prop,
			       ColSymSparse, Allocator1>& A,
			       IVect& IndRow, IVect& IndCol,
			       Vector<T, VectFull, Allocator2>& Val,
			       int index = 0, bool sym = false)
  {
    int i, j;
    int m = A.GetM();
    int nnz = A.GetDataSize();
    int* ptr = A.GetPtr();
    int* ind = A.GetInd();
    T* val = A.GetData();
    if (sym)
      {
	nnz *= 2;
	for (i = 0; i < m; i++)
	  for (j = ptr[i]; j < ptr[i + 1]; i++)
	    if (ind[j] == i)
	      nnz--;
	
	IndRow.Reallocate(nnz);
	IndCol.Reallocate(nnz);
	Val.Reallocate(nnz);
	IVect Ptr(m);
	Ptr.Zero();
	int nb = 0;
	for (i = 0; i < m; i++)
	  for (j = ptr[i]; j < ptr[i + 1]; j++)
	    {
	      IndRow(nb) = i + index;
	      IndCol(nb) = ind[j] + index;
	      Val(nb) = val[j];
	      Ptr(ind[j])++;
	      nb++;
	      
	      if (ind[j] != i)
		{
		  IndRow(nb) = ind[j] + index;
		  IndCol(nb) = i + index;
		  Val(nb) = val[j];
		  Ptr(i)++;
		  nb++;
		}
	    }
	
	// Sorting the row numbers...
	Sort(IndRow, IndCol, Val);
	
	// ...and the column numbers.
	int offset = 0;
	for (i = 0; i < m; i++)
	  {
	    Sort(offset, offset + Ptr(i) - 1, IndCol, Val);
	    offset += Ptr(i);
	  }
	
      }
    else
      {
	IndRow.Reallocate(nnz);
	IndCol.Reallocate(nnz);
	Val.Reallocate(nnz);
	for (i = 0; i < m; i++)
	  for (j = ptr[i]; j< ptr[i + 1]; j++)
	    {
	      IndRow(j) = i + index;
	      IndCol(j) = ind[j] + index;
	      Val(j) = val[j];
	    }
      }
  }
  
  
  /*
    From Sparse Array formats to "Matlab" coordinate format.
  */
  
  
  //! Conversion from ArrayRowSparse to coordinate format.
  template<class T, class Prop, class Allocator1, class Allocator2>
  void
  ConvertMatrix_to_Coordinates(const Matrix<T, Prop,
			       ArrayRowSparse, Allocator1>& A,
			       IVect& IndRow, IVect& IndCol,
			       Vector<T, VectFull, Allocator2>& Val,
			       int index = 0, bool sym = false)
  {
    int i, j;
    int m = A.GetM();
    int nnz = A.GetDataSize();
    // Allocating arrays.
    IndRow.Reallocate(nnz);
    IndCol.Reallocate(nnz);
    Val.Reallocate(nnz);
    int nb = 0;
    for (i = 0; i < m; i++)
      for (j = 0; j < A.GetRowSize(i); j++)
	{
	  IndRow(nb) = i + index;
	  IndCol(nb) = A.Index(i, j) + index;
	  Val(nb) = A.Value(i, j);
	  nb++;
	}
  }
  
  
  //! Conversion from ArrayColSparse to coordinate format.
  template<class T, class Prop, class Allocator1, class Allocator2>
  void
  ConvertMatrix_to_Coordinates(const Matrix<T, Prop,
			       ArrayColSparse, Allocator1>& A,
			       IVect& IndRow, IVect& IndCol,
			       Vector<T, VectFull, Allocator2>& Val,
			       int index = 0, bool sym = false)
  {
    int i, j;
    int n = A.GetN();
    int nnz = A.GetDataSize();
    // Allocating arrays.
    IndRow.Reallocate(nnz);
    IndCol.Reallocate(nnz);
    Val.Reallocate(nnz);
    int nb = 0;
    for (i = 0; i < n; i++)
      for (j = 0; j < A.GetColumnSize(i); j++)
	{
	  IndRow(nb) = A.Index(i, j) + index;
	  IndCol(nb) = i + index;
	  Val(nb) = A.Value(i, j);
	  nb++;
	}
  }
  
  
  //! Conversion from ArrayRowSymSparse to coordinate format.
  template<class T, class Prop, class Allocator1, class Allocator2>
  void
  ConvertMatrix_to_Coordinates(const Matrix<T, Prop,
			       ArrayRowSymSparse, Allocator1>& A,
			       IVect& IndRow, IVect& IndCol,
			       Vector<T, VectFull, Allocator2>& Val,
			       int index = 0, bool sym = false)
  {
    int i, j;
    int m = A.GetM();
    int nnz = A.GetDataSize();
    if (sym)
      {
	nnz *= 2;
	for (i = 0; i < m; i++)
	  for (j = 0; j < A.GetRowSize(i); j++)
	    if (A.Index(i, j) == i)
	      nnz--;
	
	IndRow.Reallocate(nnz);
	IndCol.Reallocate(nnz);
	Val.Reallocate(nnz);
	IVect Ptr(m);
	Ptr.Zero();
	int nb = 0;
	for (i = 0; i < m; i++)
	  for (j = 0; j < A.GetRowSize(i); j++)
	    {
	      IndRow(nb) = i + index;
	      IndCol(nb) = A.Index(i, j) + index;
	      Val(nb) = A.Value(i, j);
	      Ptr(A.Index(i, j))++;
	      nb++;
	      
	      if (A.Index(i, j) != i)
		{
		  IndRow(nb) = A.Index(i, j) + index;
		  IndCol(nb) = i + index;
		  Val(nb) = A.Value(i, j);
		  Ptr(i)++;
		  nb++;
		}
	    }
	
	// Sorting the row numbers...
	Sort(IndRow, IndCol, Val);
	
	// ...and the column numbers.
	int offset = 0;
	for (i = 0; i < m; i++)
	  {
	    Sort(offset, offset + Ptr(i) - 1, IndCol, Val);
	    offset += Ptr(i);
	  }
      }
    else
      {
	// Allocating arrays.
	IndRow.Reallocate(nnz);
	IndCol.Reallocate(nnz);
	Val.Reallocate(nnz);
	int nb = 0;
	for (i = 0; i < m; i++)
	  for (j = 0; j < A.GetRowSize(i); j++)
	    {
	      IndRow(nb) = i + index;
	      IndCol(nb) = A.Index(i, j) + index;
	      Val(nb) = A.Value(i, j);
	      nb++;
	    }
      }
  }
  
  
  //! Conversion from ArrayColSymSparse to coordinate format.
  template<class T, class Prop, class Allocator1, class Allocator2>
  void
  ConvertMatrix_to_Coordinates(const Matrix<T, Prop,
			       ArrayColSymSparse, Allocator1>& A,
			       IVect& IndRow, IVect& IndCol,
			       Vector<T, VectFull, Allocator2>& Val,
			       int index = 0, bool sym = false)
  {
    int i, j;
    int m = A.GetM();
    int nnz = A.GetDataSize();
    if (sym)
      {
	nnz *= 2;
	for (i = 0; i < m; i++)
	  for (j = 0; j < A.GetRowSize(i); j++)
	    if (A.Index(i, j) == i)
	      nnz--;
	
	IndRow.Reallocate(nnz);
	IndCol.Reallocate(nnz);
	Val.Reallocate(nnz);
	IVect Ptr(m);
	Ptr.Zero();
	int nb = 0;
	for (i = 0; i < m; i++)
	  for (j = 0; j < A.GetRowSize(i); j++)
	    {
	      IndRow(nb) = i + index;
	      IndCol(nb) = A.Index(i, j) + index;
	      Val(nb) = A.Value(i, j);
	      Ptr(A.Index(i, j))++;
	      nb++;
	      
	      if (A.Index(i, j) != i)
		{
		  IndRow(nb) = A.Index(i, j) + index;
		  IndCol(nb) = i + index;
		  Val(nb) = A.Value(i, j);
		  Ptr(i)++;
		  nb++;
		}
	    }
	
	// Sorting the row numbers...
	Sort(IndRow, IndCol, Val);
	
	// ...and the column numbers.
	int offset = 0;
	for (i = 0; i < m; i++)
	  {
	    Sort(offset, offset + Ptr(i) - 1, IndCol, Val);
	    offset += Ptr(i);
	  }
      }
    else
      {
	// Allocating arrays.
	IndRow.Reallocate(nnz);
	IndCol.Reallocate(nnz);
	Val.Reallocate(nnz);
	int nb = 0;
	for (i = 0; i < m; i++)
	  for (j = 0; j < A.GetColumnSize(i); j++)
	    {
	      IndRow(nb) = A.Index(i, j) + index;
	      IndCol(nb) = i + index;
	      Val(nb) = A.Value(i, j);
	      nb++;
	    }
      }
  }
  
  
  /*
    From "Matlab" coordinate format to CSR formats.
  */
  
  
  //! Conversion from coordinate format to RowSparse.
  template<class T, class Prop, class Allocator>
  void
  ConvertMatrix_from_Coordinates(IVect& IndRow, IVect& IndCol,
				 Vector<T, VectFull, Allocator>& Val,
				 Matrix<T, Prop, RowSparse, Allocator>& A,
				 int index = 0)
  {
    // Assuming that there is no duplicate value.
    if (IndRow.GetM() <= 0)
      return;
    
    int i;

    int row_max = IndRow.GetNormInf();
    int col_max = IndCol.GetNormInf();
    int m = row_max - index + 1;
    int n = col_max - index + 1;
    int nnz = IndRow.GetM();
    
    // Sorts the array 'IndRow'.
    Sort(IndRow, IndCol, Val);

    // Construction of array 'Ptr'.
    IVect Ptr(m + 1);
    Ptr.Zero();
    for (int i = 0; i < nnz; i++)
      {
	IndRow(i) -= index;
	IndCol(i) -= index;
	Ptr(IndRow(i) + 1)++;
      }
    
    for (i = 0; i < m; i++)
      Ptr(i + 1) += Ptr(i);
    
    // Sorts 'IndCol'.
    for (i = 0; i < m; i++)
      Sort(Ptr(i), Ptr(i + 1) - 1, IndCol, Val);
    
    A.SetData(m, n, nnz, Val, Ptr, IndCol);
  }
  
  
  //! Conversion from coordinate format to ColSparse.
  template<class T, class Prop, class Allocator>
  void
  ConvertMatrix_from_Coordinates(IVect& IndRow, IVect& IndCol,
				 Vector<T, VectFull, Allocator>& Val,
				 Matrix<T, Prop, ColSparse, Allocator>& A,
				 int index = 0)
  {
    // Assuming that there is no duplicate value.
    if (IndRow.GetM() <= 0)
      return;
    
    int i;

    int row_max = IndRow.GetNormInf();
    int col_max = IndCol.GetNormInf();
    int m = row_max - index + 1;
    int n = col_max - index + 1;
    int nnz = IndRow.GetM();
    
    // Sorts the array 'IndCol'.
    Sort(IndCol, IndRow, Val);

    // Construction of array 'Ptr'.
    IVect Ptr(n + 1);
    Ptr.Zero();
    for (i = 0; i < nnz; i++)
      {
	IndRow(i) -= index;
	IndCol(i) -= index;
	Ptr(IndCol(i) + 1)++;
      }
    
    for (i = 0; i < n; i++)
      Ptr(i + 1) += Ptr(i);
    
    // Sorts 'IndRow'
    for (i = 0; i < n; i++)
      Sort(Ptr(i), Ptr(i + 1) - 1, IndRow, Val);
    
    A.SetData(m, n, nnz, Val, Ptr, IndRow);
  }
  
  
  //! Conversion from coordinate format to RowSymSparse.
  template<class T, class Prop, class Allocator>
  void
  ConvertMatrix_from_Coordinates(IVect& IndRow, IVect& IndCol,
				 Vector<T, VectFull, Allocator>& Val,
				 Matrix<T, Prop, RowSymSparse, Allocator>& A,
				 int index = 0)
  {
    // Assuming there is no duplicate value.
    if (IndRow.GetM() <= 0)
      return;
    
    int i;

    int row_max = IndRow.GetNormInf();
    int col_max = IndCol.GetNormInf();
    int m = row_max - index + 1;
    int n = col_max - index + 1;
    int nnz = IndRow.GetM();
    
    // First, removing the lower part of the matrix (if present).
    int nb_low = 0;
    for (i = 0; i < nnz; i++)
      if (IndRow(i) > IndCol(i))
	nb_low++;
    
    if (nb_low > 0)
      {
	int nb = 0;
	for (i = 0; i < nnz; i++)
	  if (IndRow(i) <= IndCol(i))
	    {
	      IndRow(nb) = IndRow(i);
	      IndCol(nb) = IndCol(i);
	      Val(nb) = Val(i);
	      nb++;
	    }
	
	IndRow.Resize(nb);
	IndCol.Resize(nb);
	Val.Resize(nb);
	nnz = nb;
      }

    // Sorts the array 'IndRow'.
    Sort(IndRow, IndCol, Val);

    // Construction of array 'Ptr'.
    IVect Ptr(m + 1);
    Ptr.Zero();
    for (int i = 0; i < nnz; i++)
      {
	IndRow(i) -= index;
	IndCol(i) -= index;
	Ptr(IndRow(i) + 1)++;
      }
    
    for (int i = 0; i < m; i++)
      Ptr(i + 1) += Ptr(i);
    
    // Sorts 'IndCol'.
    for (int i = 0; i < m; i++)
      Sort(Ptr(i), Ptr(i + 1) - 1, IndCol, Val);
    
    A.SetData(m, n, nnz, Val, Ptr, IndCol);
  }
  
  
  //! Conversion from coordinate format to ColSymSparse.
  template<class T, class Prop, class Allocator>
  void
  ConvertMatrix_from_Coordinates(IVect& IndRow, IVect& IndCol,
				 Vector<T, VectFull, Allocator>& Val,
				 Matrix<T, Prop, ColSymSparse, Allocator>& A,
				 int index = 0)
  {
    // Assuming there is no duplicate value.
    if (IndRow.GetM() <= 0)
      return;
    
    int i;

    int row_max = IndRow.GetNormInf();
    int col_max = IndCol.GetNormInf();
    int m = row_max - index + 1;
    int n = col_max - index + 1;
    int nnz = IndRow.GetM();
    
    // First, removing the lower part of the matrix (if present).
    int nb_low = 0;
    for (i = 0; i < nnz; i++)
      if (IndRow(i) > IndCol(i))
	nb_low++;
    
    if (nb_low > 0)
      {
	int nb = 0;
	for (i = 0; i < nnz; i++)
	  if (IndRow(i) <= IndCol(i))
	    {
	      IndRow(nb) = IndRow(i);
	      IndCol(nb) = IndCol(i);
	      Val(nb) = Val(i);
	      nb++;
	    }
	
	IndRow.Resize(nb);
	IndCol.Resize(nb);
	Val.Resize(nb);
	nnz = nb;
      }

    // Sorts the array 'IndRow'.
    Sort(IndRow, IndCol, Val);

    // Construction of array 'Ptr'.
    IVect Ptr(m + 1);
    Ptr.Zero();
    for (i = 0; i < nnz; i++)
      {
	IndRow(i) -= index;
	IndCol(i) -= index;
	Ptr(IndRow(i) + 1)++;
      }
    
    for (i = 0; i < m; i++)
      Ptr(i + 1) += Ptr(i);
    
    // Sorts 'IndCol'.
    for (int i = 0; i < m; i++)
      Sort(Ptr(i), Ptr(i + 1) - 1, IndCol, Val);
    
    A.SetData(m, n, nnz, Val, Ptr, IndCol);
  }
  
  
  /*
    From Sparse Array formats to "Matlab" coordinate format.
  */
  
  
  //! Conversion from coordinate format to ArrayRowSparse.
  template<class T, class Prop, class Allocator>
  void
  ConvertMatrix_from_Coordinates(IVect& IndRow, IVect& IndCol,
				 Vector<T, VectFull, Allocator>& Val,
				 Matrix<T, Prop, ArrayRowSparse,
				 Allocator>& A,
				 int index = 0)
  {
    if (IndRow.GetM() <= 0)
      return;
    
    int i, j;

    int row_max = IndRow.GetNormInf();
    int col_max = IndCol.GetNormInf();
    int m = row_max - index + 1;
    int n = col_max - index + 1;
    int nnz = IndRow.GetM();
    
    // Sorts the array 'IndRow'.
    Sort(IndRow, IndCol, Val);

    // Number of elements per row.
    IVect Ptr(m);
    Ptr.Zero();
    for (i = 0; i < nnz; i++)
      {
	IndRow(i) -= index;
	IndCol(i) -= index;
	Ptr(IndRow(i))++;
      }
    
    // Fills matrix 'A'.
    A.Reallocate(m, n);
    int offset = 0;
    for (i = 0; i < m; i++)
      if (Ptr(i) > 0)
	{
	  A.ReallocateRow(i, Ptr(i));
	  for (j = 0; j < Ptr(i); j++)
	    {
	      A.Index(i, j) = IndCol(offset + j);
	      A.Value(i, j) = Val(offset + j);
	    }
	  offset += Ptr(i);
	}
    
    // Assembles 'A' to sort column numbers.
    A.Assemble();
  }
  
  
  //! Conversion from coordinate format to ArrayColSparse.
  template<class T, class Prop, class Allocator>
  void
  ConvertMatrix_from_Coordinates(IVect& IndRow, IVect& IndCol,
				 Vector<T, VectFull, Allocator>& Val,
				 Matrix<T, Prop, ArrayColSparse,
				 Allocator>& A,
				 int index = 0)
  {
    // Assuming there is no duplicate value.
    if (IndRow.GetM() <= 0)
      return;
    
    int i, j;

    int row_max = IndRow.GetNormInf();
    int col_max = IndCol.GetNormInf();
    int m = row_max - index + 1;
    int n = col_max - index + 1;
    int nnz = IndRow.GetM();
    
    // Sorts array 'IndCol'.
    Sort(IndCol, IndRow, Val);

    // Construction of array 'Ptr'.
    IVect Ptr(n);
    Ptr.Zero();
    for (i = 0; i < nnz; i++)
      {
	IndRow(i) -= index;
	IndCol(i) -= index;
	Ptr(IndCol(i))++;
      }
    
    // Fills matrix 'A'.
    A.Reallocate(m, n);
    int offset = 0;
    for (i = 0; i < n; i++)
      if (Ptr(i) > 0)
	{
	  A.ReallocateColumn(i, Ptr(i));
	  for (j = 0; j < Ptr(i); j++)
	    {
	      A.Index(i, j) = IndRow(offset + j);
	      A.Value(i, j) = Val(offset + j);
	    }
	  offset += Ptr(i);
	}
    
    // Assembles 'A' to sort row numbers.
    A.Assemble();
  }
  
  
  //! Conversion from coordinate format to ArrayRowSymSparse.
  template<class T, class Prop, class Allocator>
  void
  ConvertMatrix_from_Coordinates(IVect& IndRow, IVect& IndCol,
				 Vector<T, VectFull, Allocator>& Val,
				 Matrix<T, Prop,
				 ArrayRowSymSparse, Allocator>& A,
				 int index = 0)
  {
    // Assuming that there is no duplicate value.
    if (IndRow.GetM() <= 0)
      return;
    
    int i, j;

    int row_max = IndRow.GetNormInf();
    int col_max = IndCol.GetNormInf();
    int m = row_max - index + 1;
    int n = col_max - index + 1;
    int nnz = IndRow.GetM();
    
    // First, removing the lower part of the matrix (if present).
    int nb_low = 0;
    for (i = 0; i < nnz; i++)
      if (IndRow(i) > IndCol(i))
	nb_low++;
    
    if (nb_low > 0)
      {
	int nb = 0;
	for (i = 0; i < nnz; i++)
	  if (IndRow(i) <= IndCol(i))
	    {
	      IndRow(nb) = IndRow(i);
	      IndCol(nb) = IndCol(i);
	      Val(nb) = Val(i);
	      nb++;
	    }
	
	IndRow.Resize(nb);
	IndCol.Resize(nb);
	Val.Resize(nb);
	nnz = nb;
      }

    // Sorts the array 'IndRow'.
    Sort(IndRow, IndCol, Val);

    // Construction of array 'Ptr'.
    IVect Ptr(m);
    Ptr.Zero();
    for (i = 0; i < nnz; i++)
      {
	IndRow(i) -= index;
	IndCol(i) -= index;
	Ptr(IndRow(i))++;
      }
    
    // Fills matrix 'A'.
    A.Reallocate(m, n);
    int offset = 0;
    for (i = 0; i < m; i++)
      if (Ptr(i) > 0)
	{
	  A.ReallocateRow(i, Ptr(i));
	  for (j = 0; j < Ptr(i); j++)
	    {
	      A.Index(i, j) = IndCol(offset + j);
	      A.Value(i, j) = Val(offset + j);
	    }
	  offset += Ptr(i);
	}
    
    // Assembles 'A' to sort column numbers.
    A.Assemble();
  }
  
  
  //! Conversion from coordinate format to ArrayColSymSparse.
  template<class T, class Prop, class Allocator>
  void
  ConvertMatrix_from_Coordinates(IVect& IndRow, IVect& IndCol,
				 Vector<T, VectFull, Allocator>& Val,
				 Matrix<T, Prop,
				 ArrayColSymSparse, Allocator>& A,
				 int index = 0)
  {
    // Assuming that there is no duplicate value.
    if (IndRow.GetM() <= 0)
      return;
    
    int i, j;

    int row_max = IndRow.GetNormInf();
    int col_max = IndCol.GetNormInf();
    int m = row_max - index + 1;
    int n = col_max - index + 1;
    int nnz = IndRow.GetM();
    
    // First, removing the lower part of the matrix (if present).
    int nb_low = 0;
    for (i = 0; i < nnz; i++)
      if (IndRow(i) > IndCol(i))
	nb_low++;
    
    if (nb_low > 0)
      {
	int nb = 0;
	for (i = 0; i < nnz; i++)
	  if (IndRow(i) <= IndCol(i))
	    {
	      IndRow(nb) = IndRow(i);
	      IndCol(nb) = IndCol(i);
	      Val(nb) = Val(i);
	      nb++;
	    }
	
	IndRow.Resize(nb);
	IndCol.Resize(nb);
	Val.Resize(nb);
	nnz = nb;
      }

    // Sorts the array 'IndRow'.
    Sort(IndRow, IndCol, Val);

    // Construction of array 'Ptr'.
    IVect Ptr(m);
    Ptr.Zero();
    for (i = 0; i < nnz; i++)
      {
	IndRow(i) -= index;
	IndCol(i) -= index;
	Ptr(IndRow(i))++;
      }
    
    // Fills matrix 'A'.
    A.Reallocate(m, n);
    int offset = 0;
    for (i = 0; i < m; i++)
      if (Ptr(i) > 0)
	{
	  A.ReallocateColumn(i, Ptr(i));
	  for (j = 0; j < Ptr(i); j++)
	    {
	      A.Index(i, j) = IndCol(offset + j);
	      A.Value(i, j) = Val(offset + j);
	    }
	  offset += Ptr(i);
	}
    
    // Assembles 'A' to sort column numbers.
    A.Assemble();
  }
  
  
  /*
    From CSR to other CSR formats.
  */
  
  
  //! B = A.
  template<class T, class Prop, class Alloc1, class Alloc2>
  void Copy(const Matrix<T, Prop, ColSparse, Alloc1>& A,
	    Matrix<T, Prop, ColSparse, Alloc2>& B)
  {
    int i;

    int m = A.GetM(), n = A.GetN(), nnz = A.GetDataSize();
    int* ptr_ = A.GetPtr();
    int* ind_ = A.GetInd();
    T* data_ = A.GetData();
    
    IVect Ptr(n+1), Ind(nnz);
    Vector<T, VectFull, Alloc2> Val(nnz);
    for (i = 0; i <= n; i++)
      Ptr(i) = ptr_[i];
    
    for (i = 0; i < nnz; i++)
      {
	Ind(i) = ind_[i];
	Val(i) = data_[i];
      }
    
    B.SetData(m, n, Val, Ptr, Ind);
  }
  
  
  //! Conversion from row-sparse to column-sparse.
  template<class T, class Prop, class Alloc1, class Alloc2>
  void Copy(const Matrix<T, Prop, RowSparse, Alloc1>& A,
	    Matrix<T, Prop, ColSparse, Alloc2>& B)
  {
    int i, j;

    int m = A.GetM(), n = A.GetN(), nnz = A.GetDataSize();
    int* ptr_ = A.GetPtr();
    int* ind_ = A.GetInd();
    T* data_ = A.GetData();
    
    // Computation of the indices of the beginning of columns.
    IVect Ptr(n + 1);
    Ptr.Fill(0);
    // Counting the number of entries per column.
    for (i = 0; i < nnz; i++)
      Ptr(ind_[i])++;
    
    // Incrementing in order to get indices.
    int increment = 0, size, num_col;
    for (i = 0; i < n; i++)
      {
	size = Ptr(i);
	Ptr(i) = increment;
	increment += size;
      }
    // Last index.
    Ptr(n) = increment;
    
    // 'Offset' will be used to get current positions of new entries.
    IVect Offset = Ptr;
    IVect Ind(nnz);
    Vector<T, VectFull, Alloc2> Val(nnz);
    
    // Loop over rows.
    for (i = 0; i < m; i++)
      for (j = ptr_[i]; j < ptr_[i + 1]; j++)
	{
	  num_col = ind_[j];
	  Ind(Offset(num_col)) = i;
	  Val(Offset(num_col)) = data_[j];
	  Offset(num_col)++;
	}
    
    B.SetData(m, n, Val, Ptr, Ind);
  }
  
  
  //! Conversion from row-sparse to column-sparse.
  template<class T, class Prop1, class Prop2,
	   class Storage, class Alloc1, class Alloc2>
  void
  ConvertMatrixSymSparse_to_ColSparse(const Matrix<T, Prop1,
				      Storage, Alloc1>& A,
				      Matrix<T, Prop2, ColSparse, Alloc2>& B)
  {
    int i, j;

    int m = A.GetM(), n = A.GetN();
    int* ptr_ = A.GetPtr();
    int* ind_ = A.GetInd();
    T* data_ = A.GetData();
    
    // Computation of the indices of the beginning of columns.
    IVect Ptr(n + 1);
    Ptr.Fill(0);
    // Counting the number of entries per column.
    for (i = 0; i < m; i++)
      for (j = ptr_[i]; j < ptr_[i + 1]; j++)
	{
	  Ptr(ind_[j])++;
	  if (i != ind_[j])
	    Ptr(i)++;
	}
    
    // Incrementing in order to get indices.
    int nnz = 0, size, num_col;
    for (i = 0; i < n; i++)
      {
	size = Ptr(i);
	Ptr(i) = nnz;
	nnz += size;
      }
    // Last index.
    Ptr(n) = nnz;
    
    // 'Offset' will be used to get current positions of new entries.
    IVect Offset = Ptr;
    IVect Ind(nnz);
    Vector<T, VectFull, Alloc2> Val(nnz);
    
    // Loop over rows.
    for (i = 0; i < m; i++)
      for (j = ptr_[i]; j < ptr_[i + 1]; j++)
	{
	  num_col = ind_[j];
	  Ind(Offset(num_col)) = i;
	  Val(Offset(num_col)) = data_[j];
	  Offset(num_col)++;
	  if (i != ind_[j])
	    {
	      Ind(Offset(i)) = num_col;
	      Val(Offset(i)) = data_[j];
	      Offset(i)++;
	    }
	}
    
    B.SetData(m, n, Val, Ptr, Ind);
  }
  
  
  //! Conversion from RowSymSparse to column-sparse.
  template<class T, class Prop1, class Prop2, class Alloc1, class Alloc2>
  void Copy(const Matrix<T, Prop1, RowSymSparse, Alloc1>& A,
	    Matrix<T, Prop2, ColSparse, Alloc2>& B)
  {
    ConvertMatrixSymSparse_to_ColSparse(A, B);
  }
  
  
  //! Conversion from ColSymSparse to column-sparse.
  template<class T, class Prop1, class Prop2, class Alloc1, class Alloc2>
  void Copy(const Matrix<T, Prop1, ColSymSparse, Alloc1>& A,
	    Matrix<T, Prop2, ColSparse, Alloc2>& B)
  {
    ConvertMatrixSymSparse_to_ColSparse(A, B);
  }
  
  
  /*
    From ArraySparse matrices to CSR matrices.
  */
  
  
  //! Conversion from ArrayRowSparse to RowSparse.
  template<class T0, class Prop0, class Allocator0,
	   class T1, class Prop1, class Allocator1>
  void Copy(const Matrix<T0, Prop0, ArrayRowSparse,Allocator0>& mat_array,
	    Matrix<T1, Prop1, RowSparse, Allocator1>& mat_csr)
  {
    int i, k;

    // Matrix (m,n) with 'nnz' entries.
    int nnz = mat_array.GetDataSize();
    int m = mat_array.GetM();
    int n = mat_array.GetN();
    
    // Allocating arrays needed for CSR format.
    Vector<T1> Val(nnz);
    IVect IndRow(m + 1);
    IVect IndCol(nnz);
    
    // Filling the arrays.
    int ind = 0;
    IndRow(0) = 0;
    for (i = 0; i < m; i++)
      {
	for (k = 0; k < mat_array.GetRowSize(i); k++)
	  {
	    IndCol(ind) = mat_array.Index(i, k);
	    Val(ind) = mat_array.Value(i, k);
	    ind++;
	  }
	IndRow(i + 1) = ind;
      }
    
    mat_csr.SetData(m, n, Val, IndRow, IndCol);
  }
  
  
  //! Conversion from ArrayRowSparse to ColSparse.
  template<class T0, class Prop0, class Allocator0,
	   class T1, class Prop1, class Allocator1>
  void Copy(const Matrix<T0, Prop0, ArrayRowSparse,Allocator0>& mat_array,
	    Matrix<T1, Prop1, ColSparse, Allocator1>& mat_csr)
  {
    int i;

    // Matrix (m,n) with nnz entries.
    int nnz = mat_array.GetDataSize();
    int m = mat_array.GetM();
    int n = mat_array.GetN();
   
    // Conversion in coordinate format.
    Vector<T1> Val;
    IVect IndRow, IndCol;
    ConvertMatrix_to_Coordinates(mat_array, IndRow, IndCol, Val);
    
    // Sorting with respect to column numbers.
    Sort(IndCol, IndRow, Val);
    
    // Constructing pointer array 'Ptr'.
    IVect Ptr(n + 1);
    
    // Counting non-zero entries per column.
    for (i = 0; i < nnz; i++)
      Ptr(IndCol(i) + 1)++;
    
    // Accumulation to get pointer array.
    Ptr(0) = 0;
    for (i = 0; i < n; i++)
      Ptr(i + 1) += Ptr(i);
    
    mat_csr.SetData(m, n, Val, Ptr, IndRow);
  }
  
  
  //! Conversion from ArrayRowSymSparse to RowSymSparse.
  template<class T0, class Prop0, class Allocator0,
	   class T1, class Prop1, class Allocator1>
  void Copy(const Matrix<T0, Prop0, ArrayRowSymSparse,Allocator0>& mat_array,
	    Matrix<T1, Prop1, RowSymSparse, Allocator1>& mat_csr)
  {
    int i, k;

    // Number of rows and non-zero entries.
    int nnz = mat_array.GetDataSize();
    int m = mat_array.GetM();
    
    // Allocation of arrays for CSR format.
    Vector<T1> Val(nnz);
    Vector<int, VectFull, CallocAlloc<int> > IndRow(m + 1);
    Vector<int, VectFull, CallocAlloc<int> > IndCol(nnz);
    
    int ind = 0;
    IndRow(0) = 0;
    for (i = 0; i < m; i++)
      {
	for (k = 0; k < mat_array.GetRowSize(i); k++)
	  {
	    IndCol(ind) = mat_array.Index(i, k);
	    Val(ind) = mat_array.Value(i, k);
	    ind++;
	  }
	IndRow(i + 1) = ind;
      }
    
    mat_csr.SetData(m, m, Val, IndRow, IndCol);
  }
  
  
  //! Conversion from ArrayRowComplexSparse to RowComplexSparse.
  template<class T0, class Prop0, class Allocator0,
	   class T1, class Prop1, class Allocator1>
  void
  Copy(const Matrix<T0, Prop0, ArrayRowComplexSparse, Allocator0>& mat_array,
       Matrix<T1, Prop1, RowComplexSparse, Allocator1>& mat_csr)
  {
    int i, k;

    // Non-zero entries (real and imaginary part).
    int nnz_real = mat_array.GetRealDataSize();
    int nnz_imag = mat_array.GetImagDataSize();
    int m = mat_array.GetM();
    
    // Allocation of arrays for CSR.
    Vector<T0> Val_real(nnz_real), Val_imag(nnz_imag);
    IVect IndRow_real(m + 1), IndRow_imag(m + 1);
    IVect IndCol_real(nnz_real), IndCol_imag(nnz_imag);
    
    int ind_real = 0, ind_imag = 0;
    IndRow_real(0) = 0;
    IndRow_imag(0) = 0;
    // Loop over rows.
    for (i = 0; i < m; i++)
      {
	for (k = 0; k < mat_array.GetRealRowSize(i); k++)
	  {
	    IndCol_real(ind_real) = mat_array.IndexReal(i, k);
	    Val_real(ind_real) = mat_array.ValueReal(i, k);
	    ind_real++;
	  }
	
	IndRow_real(i + 1) = ind_real;
	for (k = 0; k < mat_array.GetImagRowSize(i); k++)
	  {
	    IndCol_imag(ind_imag) = mat_array.IndexImag(i, k);
	    Val_imag(ind_imag) = mat_array.ValueImag(i, k);
	    ind_imag++;
	  }
	
	IndRow_imag(i + 1) = ind_imag;
      }
    
    mat_csr.SetData(m, m, Val_real, IndRow_real, IndCol_real,
		    Val_imag, IndRow_imag, IndCol_imag);
  }
  
  
  //! Conversion from ArrayRowSymComplexSparse to RowSymComplexSparse.
  template<class T0, class Prop0, class Allocator0,
	   class T1, class Prop1, class Allocator1>
  void
  Copy(const Matrix<T0, Prop0,
       ArrayRowSymComplexSparse, Allocator0>& mat_array,
       Matrix<T1, Prop1, RowSymComplexSparse, Allocator1>& mat_csr)
  {
    int i, k;

    // Non-zero entries (real and imaginary part).
    int nnz_real = mat_array.GetRealDataSize();
    int nnz_imag = mat_array.GetImagDataSize();
    int m = mat_array.GetM();
    
    // Allocation of arrays for CSR.
    Vector<T0> Val_real(nnz_real), Val_imag(nnz_imag);
    IVect IndRow_real(m + 1), IndRow_imag(m + 1);
    IVect IndCol_real(nnz_real), IndCol_imag(nnz_imag);
    
    int ind_real = 0, ind_imag = 0;
    IndRow_real(0) = 0;
    IndRow_imag(0) = 0;
    // Loop over rows.
    for (i = 0; i < m; i++)
      {
	for (k = 0; k < mat_array.GetRealRowSize(i); k++)
	  {
	    IndCol_real(ind_real) = mat_array.IndexReal(i, k);
	    Val_real(ind_real) = mat_array.ValueReal(i, k);
	    ind_real++;
	  }
	
	IndRow_real(i + 1) = ind_real;
	for (int k = 0; k < mat_array.GetImagRowSize(i); k++)
	  {
	    IndCol_imag(ind_imag) = mat_array.IndexImag(i, k);
	    Val_imag(ind_imag) = mat_array.ValueImag(i, k);
	    ind_imag++;
	  }
	
	IndRow_imag(i + 1) = ind_imag;
      }
    
    mat_csr.SetData(m, m, Val_real, IndRow_real, IndCol_real,
		    Val_imag, IndRow_imag, IndCol_imag);
  }
  
  
  template<class T0, class Prop0, class Allocator0,
	   class T1, class Prop1, class Allocator1>
  void Copy(const Matrix<T0, Prop0, ArrayRowSymSparse, Allocator0>& A,
	    Matrix<T1, Prop1, ArrayRowSparse, Allocator1>& B)
  {
    int i, j;

    int nnz = A.GetDataSize();
    int n = A.GetM();
    IVect IndRow(nnz),IndCol(nnz);
    Vector<T1> Val(nnz);
    int ind = 0;
    for (i = 0; i < n; i++)
      for (j = 0; j < A.GetRowSize(i); j++)
	if (A.Index(i, j) != i)
	  {
	    IndRow(ind) = i;
	    IndCol(ind) = A.Index(i, j);
	    Val(ind) = A.Value(i, j);
	    ind++;
	  }
    Sort(ind, IndCol, IndRow, Val);
    nnz = ind;
    ind = 0;
    
    B.Reallocate(n, n);
    for (i = 0; i < n; i++)
      {
	int first_index = ind;
	while (ind < nnz && IndCol(ind) <= i)
	  ind++;
	int size_lower = ind - first_index;
	int size_upper = A.GetRowSize(i);
	int size_row = size_lower + size_upper;
	B.ResizeRow(i, size_row);
	ind = first_index;
	for (j = 0; j < size_lower; j++)
	  {
	    B.Index(i, j) = IndRow(ind);
	    B.Value(i, j) = Val(ind);
	    ind++;
	  }
	for (j = 0; j < size_upper; j++)
	  {
	    B.Index(i, size_lower + j) = A.Index(i, j);
	    B.Value(i, size_lower + j) = A.Value(i, j);
	  }
	B.AssembleRow(i);
      }
  }
  
  
  template<class T0, class Prop0, class Allocator0,
	   class T1, class Prop1, class Allocator1>
  void Copy(const Matrix<T0, Prop0, ArrayRowSymSparse, Allocator0>& A,
	    Matrix<T1, Prop1, ArrayColSparse, Allocator1>& B)
  {
    int i, j;

    int nnz = A.GetDataSize();
    int n = A.GetM();
    IVect IndRow(nnz), IndCol(nnz);
    Vector<T1> Val(nnz);
    int ind = 0;
    for (i = 0; i < n; i++)
      for (j = 0; j < A.GetRowSize(i); j++)
	if (A.Index(i, j) != i)
	  {
	    IndRow(ind) = i;
	    IndCol(ind) = A.Index(i, j);
	    Val(ind) = A.Value(i, j);
	    ind++;
	  }
    Sort(ind, IndCol, IndRow, Val);
    nnz = ind;
    ind = 0;
    
    B.Reallocate(n, n);
    for (i = 0; i < n; i++)
      {
	int first_index = ind;
	while (ind < nnz && IndCol(ind) <= i)
	  ind++;
	int size_lower = ind - first_index;
	int size_upper = A.GetRowSize(i);
	int size_row = size_lower + size_upper;
	B.ResizeColumn(i, size_row);
	ind = first_index;
	for (j = 0; j < size_lower; j++)
	  {
	    B.Index(i, j) = IndRow(ind);
	    B.Value(i, j) = Val(ind);
	    ind++;
	  }
	for (j = 0; j < size_upper; j++)
	  {
	    B.Index(i, size_lower + j) = A.Index(i, j);
	    B.Value(i, size_lower + j) = A.Value(i, j);
	  }
	B.AssembleColumn(i);
      }
  }
  
  
  //! Conversion from ArrayColSparse to ColSparse.
  template<class T0, class Prop0, class Allocator0,
	   class T1, class Prop1, class Allocator1>
  void Copy(const Matrix<T0, Prop0, ArrayColSparse, Allocator0>& mat_array,
	    Matrix<T1, Prop1, ColSparse, Allocator1>& mat_csc)
  {
    int i, k;

    // Matrix (m,n) with 'nnz' entries.
    int nnz = mat_array.GetDataSize();
    int m = mat_array.GetM();
    int n = mat_array.GetN();
    
    // Allocating arrays needed for CSC format.
    Vector<T1> Val(nnz);
    IVect IndRow(nnz);
    IVect IndCol(n+1);
    
    // Filling the arrays.
    int ind = 0;
    IndCol(0) = 0;
    for (i = 0; i < n; i++)
      {
	for (k = 0; k < mat_array.GetColumnSize(i); k++)
	  {
	    IndRow(ind) = mat_array.Index(i, k);
	    Val(ind) = mat_array.Value(i, k);
	    ind++;
	  }
	IndCol(i + 1) = ind;
      }
    
    mat_csc.SetData(m, n, Val, IndCol, IndRow);
  }
  
  
  //! Conversion from ArrayRowSparse to ArrayColSparse.
  template<class T0, class Prop0, class Allocator0,
	   class T1, class Prop1, class Allocator1>
  void Copy(const Matrix<T0, Prop0, ArrayRowSparse,Allocator0>& A,
	    Matrix<T1, Prop1, ArrayColSparse, Allocator1>& B)
  {
    int i;
    
    // Matrix (m,n) with nnz entries.
    int nnz = A.GetDataSize();
    int n = A.GetN();
   
    // Conversion in coordinate format.
    Vector<T1> Val;
    IVect IndRow, IndCol;
    ConvertMatrix_to_Coordinates(A, IndRow, IndCol, Val);
    
    // Sorting with respect to column numbers.
    Sort(IndCol, IndRow, Val);
    
    // Constructing pointer array 'Ptr'.
    IVect Ptr(n + 1);
    
    // Counting non-zero entries per column.
    for (i = 0; i < nnz; i++)
      Ptr(IndCol(i) + 1)++;
    
    // Accumulation to get pointer array.
    Ptr(0) = 0;
    for (i = 0; i < n; i++)
      Ptr(i + 1) += Ptr(i);
    
    // we fill matrix B
    for (int i = 0; i < n; i++)
      {
	int size_col = Ptr(i+1) - Ptr(i);
	if (size_col > 0)
	  {
	    B.ReallocateColumn(i, size_col);
	    for (int j = Ptr(i); j < Ptr(i+1); j++)
	      {
		B.Index(i, j-Ptr(i)) = IndRow(j);
		B.Value(i, j-Ptr(i)) = Val(j);
	      }
	  }
      }
  }
  
} // namespace Seldon.

#define SELDON_FILE_FUNCTIONS_MATRIX_CXX
#endif