//
// LiDIA - a library for computational number theory
//   Copyright (c) 1994, 1995 by the LiDIA Group
//
// File        : base_matrix.c
// Author      : Patrick Theobald (PT)
// Last change : PT, Oct 28 1995, initial version 
//               

/*
$Id: base_matrix.c,v 1.15 1997/02/05 17:19:01 lidiaadm Exp $
*/

#if defined(HAVE_MAC_DIRS) || defined(__MWERKS__)
#include <LiDIA:base_matrix.h>
#include <LiDIA:arith.inl>
#include <LiDIA:xerror.h>
#else
#include <LiDIA/base_matrix.h>
#include <LiDIA/arith.inl>
#include <LiDIA/xerror.h>
#endif

/**
 ** debug defines / error defines
 **/

extern const char *PRT;
extern const char *matrix_error_msg[];

#define DV_BM LDBL_MATRIX        /* Debug value   */
#define DM_BM "base_matrix"      /* Debug message / Error message */
#define LBM_ERROR matrix_error_msg

/**
 ** debug level
 **
 **   0 : constructors / destructor
 **   1 : input / output      
 **   2 : access functions
 **   3 : split / compose
 **   4 : swap functions
 **   5 : structur functions
 **   6 : assignments
 **   7 : diagonal and transpose functions
 **   8 : stream handling
 **/

/**
 ** constructors
 **/

template < class T >
base_matrix < T >::base_matrix()
{
  debug_handler_l(DM_BM, "in constructor "
		  "base_matrix()", DV_BM);
  
  storage_mode = DEFAULT_STORAGE_MODE;
  structure_mode = DEFAULT_STRUCTURE_MODE;
  info_mode = DEFAULT_INFO_MODE;
  print_mode = DEFAULT_PRINT_MODE;
  lattice_mode = DEFAULT_LATTICE_MODE;
  rows = 1;
  columns = 1;
  
  value = new T *[1];
  memory_handler(value, DM_BM, "base_matrix() :: "
		 "Error in memory allocation (value)");
  
  value[0] = new T[1];
  memory_handler(value[0], DM_BM, "base_matrix() :: "
		 "Error in memory allocation (value[0])");
}

/*
template < class T >
base_matrix < T >::base_matrix(lidia_size_t r)
{
  debug_handler_l(DM_BM, "in constructor "
		  "base_matrix(lidia_size_t)", DV_BM);
  
  if (r < 1)
    lidia_error_handler_para(r, "r", "r > 0", 
			     "base_matrix < T >::"
			     "base_matrix(lidia_size_t r)", 
			     DM_BM, LBM_ERROR[0]);
  
  storage_mode = DEFAULT_STORAGE_MODE;
  structure_mode = DEFAULT_STRUCTURE_MODE;
  info_mode = DEFAULT_INFO_MODE;
  print_mode = DEFAULT_PRINT_MODE;
  lattice_mode = DEFAULT_LATTICE_MODE;
  rows = r;
  columns = 1;
  
  value = new T *[r];
  memory_handler(value, DM_BM, "base_matrix(lidia_size_t) :: "
		 "Error in memory allocation (value)");

  register lidia_size_t i;  
  for (i = 0; i < r; i++)
    {
      value[i] = new T[1];
      memory_handler(value[i], DM_BM, "base_matrix(lidia_size_t) :: "
		     "Error in memory allocation (value[i])");
    }
}
*/

template < class T >
base_matrix < T >::base_matrix(lidia_size_t r, lidia_size_t c)
{
  debug_handler_l(DM_BM, "in constructor "
		  "base_matrix(lidia_size_t, lidia_size_t)", DV_BM);
  
  if (r < 1 || c < 1)
    lidia_error_handler_para(r, "r", "r > 0", 
			     c, "c", "c > 0", 
			     "base_matrix < T >::"
			     "base_matrix(lidia_size_t r, lidia_size_t c)",
			     DM_BM, LBM_ERROR[0]);
  
  storage_mode = DEFAULT_STORAGE_MODE;
  structure_mode = DEFAULT_STRUCTURE_MODE;
  info_mode = DEFAULT_INFO_MODE;
  print_mode = DEFAULT_PRINT_MODE;
  lattice_mode = DEFAULT_LATTICE_MODE;
  rows = r;
  columns = c;
  
  value = new T *[r];
  memory_handler(value, DM_BM, "base_matrix(lidia_size_t, lidia_size_t) :: "
		 "Error in memory allocation (value)");

  register lidia_size_t i;
  for (i = 0; i < r; i++)
    {
      value[i] = new T[c];
      memory_handler(value[i], DM_BM, "base_matrix(lidia_size_t, lidia_size_t) :: "
		     "Error in memory allocation (value[i])");
    }
}

template < class T >
base_matrix < T >::base_matrix(lidia_size_t r, lidia_size_t c, const T **A)
{
  debug_handler_l(DM_BM, "in constructor "
		  "base_matrix(lidia_size_t, lidia_size_t, const T **)", DV_BM);
  
  if (r < 1 || c < 1 || A == NULL)
    lidia_error_handler_para(r, "r", "r > 0", 
			     c, "c", "c > 0", 
			     PRT, "A", "A != NULL",
			     "base_matrix < T >::"
			     "base_matrix(lidia_size_t r, lidia_size_t c, const T **A)", 
			     DM_BM, LBM_ERROR[1]);
  
  storage_mode = DEFAULT_STORAGE_MODE;
  structure_mode = DEFAULT_STRUCTURE_MODE;
  info_mode = DEFAULT_INFO_MODE;
  print_mode = DEFAULT_PRINT_MODE;
  lattice_mode = DEFAULT_LATTICE_MODE;
  rows = r;
  columns = c;
  
  value = new T *[r];
  memory_handler(value, DM_BM, "base_matrix(lidia_size_t, lidia_size_t, const T **) :: "
		 "Error in memory allocation (value)");

  register lidia_size_t i, j;
  register T *tmp;
  register const T *Atmp;
  for (i = 0; i < r; i++)
    {
      tmp = new T[c];
      Atmp = A[i];
      memory_handler(tmp, DM_BM, "base_matrix(lidia_size_t, lidia_size_t, const T **) :: "
		     "Error in memory allocation (tmp)");
      
      for (j = 0; j < c; j++)
	tmp[j] = Atmp[j];
      value[i] = tmp;
    }
}

template < class T >
base_matrix < T >::base_matrix(const base_matrix < T > &M)
{
  debug_handler_l(DM_BM, "in constructor "
		  "base_matrix(const base_matrix < T > &)", DV_BM);
  
  storage_mode = M.storage_mode;
  structure_mode = M.structure_mode;
  info_mode = M.info_mode;
  print_mode = M.print_mode;
  lattice_mode = M.lattice_mode;
  rows = M.rows;
  columns = M.columns;
  
  value = new T *[rows];
  memory_handler(value, DM_BM, "base_matrix(const base_matrix < T > &) :: "
		 "Error in memory allocation (value)");

  register lidia_size_t i, j;
  register T *tmp, *Mtmp;
  for (i = 0; i < rows; i++)
    {
      tmp = new T[columns];
      Mtmp = M.value[i];
      memory_handler(tmp, DM_BM, "base_matrix(const base_matrix < T > &) :: "
		     "Error in memory allocation (tmp)");
      
      for (j = 0; j < columns; j++)
	tmp[j] = Mtmp[j];
      value[i] = tmp;
    }
}

/**
 ** destructor
 **/

template < class T >
base_matrix < T >::~base_matrix()
{
  debug_handler_l(DM_BM, "in destructor "
		  "~base_matrix()", DV_BM);
  
  register lidia_size_t i;  
  for (i = 0; i < rows; i++)
    delete[] value[i];
  delete[] value;
}

/**
 ** Operator Input / Output
 **/

template < class T >
ostream & base_matrix < T >::
print(ostream &out) const
{
  /**
   ** DESCRIPTION: Output to stream 
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "print(ostream &)", DV_BM + 1);
  
  switch(print_mode)
    {
    case BEAUTY_MODE:   
      register lidia_size_t i, j;
      register T *tmp;
      for (i = 0; i < rows; i++)
	{
	  tmp = value[i];
	  out << endl << "( ";
	  for (j = 0; j < columns; j++)
	    out << tmp[j] << " ";
	  out << ")";
	}
      out << endl << flush;
      break;
    case LIDIA_MODE:
      write_to_stream(out);
      break;
    case GP_MODE:
      write_to_gp(out);
      break;
    case MAPLE_MODE:
      write_to_maple(out);
      break;
    case MATHEMATICA_MODE:
      write_to_mathematica(out);
      break;
    case KASH_MODE:
      write_to_kash(out);
      break;
    }
  return out;
}

template < class T >
istream & base_matrix < T >::
read(istream &in)
{
  /**
   ** DESCRIPTION: Input from stream
   ** ERROR: first character not in {[,{,1,2,3,4,5,6,7,8,9,M,a}
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "read(istream &)", DV_BM + 1);
  
  char c;
  in >> c;
  in.putback(c);
  switch(c)
    {
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':      
      register T *tmp;
      lidia_size_t i, j;
      
      in >> i >> j;
      if (i != rows)
	set_no_of_rows(i);
      if (j != columns)
	set_no_of_columns(j);
      for (i = 0; i < rows; i++)
	{
	  tmp = value[i];
	  for (j = 0; j < columns; j++)
	    in >> tmp[j];
	}
      break;
    case '[':
      read_from_gp(in);
      break;
    case 'a':
      read_from_maple(in);
      break;
    case '{':
      read_from_mathematica(in);
      break;
    case 'M':
      read_from_kash(in);
      break;
    default:
      lidia_error_handler_para(c, "c", "Character c have to be in {[,{,a,M,1,2,3,4,5,6,7,8,9}",
			       "istream & base_matrix < T >::"
			       "read(istream &in)", 
			       DM_BM, LBM_ERROR[2]);
    }
  return in;
}

/**
 ** BEGIN: access functions
 **/

/**
 ** element access 
 **/

template < class T >
void base_matrix < T >::
sto(lidia_size_t x, lidia_size_t y, const T &e)
{
  /**
   ** DESCRIPTION: A.sto(x,y,e) stores e at position (x,y) in matrix A.
   ** ERROR: x < 0 or 
   **        x >= rows or 
   **        y < 0 or 
   **        y >= columns
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "sto(lidia_size_t, lidia_size_t, const T &)", DV_BM + 2);
  
  if (x < 0 || x >= rows || y < 0 || y >= columns)
    lidia_error_handler_para(x, "x", "0 <= x < rows", 
			     rows, "rows", "0 <= x < rows",
			     y, "y", "0 <= y < columns",
			     columns, "columns", "0 <= y < columns",
			     "void base_matrix < T >::"
			     "sto(lidia_size_t x, lidia_size_t y, const T &e)", 
			     DM_BM, LBM_ERROR[3]);  
  
  value[x][y] = e;
}

template < class T >
T & base_matrix < T >::
operator () (lidia_size_t x, lidia_size_t y)
{
  /**
   ** DESCRIPTION: A(x,y) = reference of position (x,y) in matrix A
   ** ERROR: x < 0 or 
   **        y < 0 or 
   **        x >= A.rows or 
   **        y >= A.columns
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "operator()"
		  "(lidia_size_t, lidia_size_t)", DV_BM + 2);
  
  if (x < 0 || y < 0 || x >= rows || y >= columns)
    lidia_error_handler_para(x, "x", "0 <= x < rows",
			     rows, "rows", "0 <= x < rows",
			     y, "y", "0 <= y < columns",
			     columns, "columns", "0 <= y < columns",
			     "T base_matrix < T >::"
			     "operator () (lidia_size_t x, lidia_size_t y) const", 
			     DM_BM, LBM_ERROR[3]);
  
  return value[x][y];
}

template < class T >
const T & base_matrix < T >::
member(lidia_size_t x, lidia_size_t y) const
{
  /**
   ** DESCRIPTION: A.member(x,y) = value at position (x,y) in matrix A
   ** ERROR: x < 0 or 
   **        y < 0 or 
   **        x >= A.rows or 
   **        y >= A.columns
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "member(lidia_size_t, lidia_size_t)", DV_BM + 2);
  
  if (x < 0 || y < 0 || x >= rows || y >= columns)
    lidia_error_handler_para(x, "x", "0 <= x < rows",
			     rows, "rows", "0 <= x < rows",
			     y, "y", "0 <= y < columns",
			     columns, "columns", "0 <= y < columns",
			     "T base_matrix < T >::"
			     "member(lidia_size_t x, lidia_size_t y) const", 
			     DM_BM, LBM_ERROR[3]);
  
  return value[x][y];
}

/**
 ** column access
 **/

template < class T >
void base_matrix < T >::
sto_column(const T *v, lidia_size_t l, lidia_size_t j)
{
  /**
   ** DESCRIPTION: A.sto_column(v,l,j) stores v[0],...,v[l-1] in column j 
   **              of matrix A.
   ** ERROR: j > A.columns or 
   **        l > A.rows or 
   **        j < 0 or 
   **        l < 0 or 
   **        v == NULL
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "sto_column(const T *, lidia_size_t, lidia_size_t)", DV_BM + 2);
  
  if (j >= columns || rows < l || j < 0 || l <= 0 || v == NULL)
    lidia_error_handler_para(j, "j", "0 <= j < columns", 
			     columns, "columns", "0 <= j < columns",
			     l, "l", "0 < l <= rows", 
			     rows, "rows", "0 < l < rows",
			     PRT, "v", " v != NULL",
			     "void base_matrix < T >::"
			     "sto_column(const T *v, lidia_size_t l, lidia_size_t j)",
			     DM_BM, LBM_ERROR[1]);
  
  register lidia_size_t k;

  for (k = 0; k < l; k++)	
    value[k][j] = v[k];	
}

template < class T >
void base_matrix < T >::
sto_column_vector(const base_vector < T > &v, lidia_size_t l, lidia_size_t j)
{
  /**
   ** DESCRIPTION: A.sto_column_vector(v,l,j) stores v[0],...,v[l-1] in column j 
   **              of matrix A.
   ** ERROR: j > A.columns or 
   **        l > A.rows or 
   **        j < 0 or 
   **        l < 0 or 
   **        l > v.size
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "sto_column_vector(const base_vector < T > &, lidia_size_t, lidia_size_t)", DV_BM + 2);
  
  if (j >= columns || rows < l || j < 0 || l <= 0 || l > v.size())
    lidia_error_handler_para(j ,"j", "0 <= j < columns", 
			     columns, "columns", "0 <= j < columns",
			     l, "l", "0 < l <= min(v.size, rows)", 
			     rows, "rows", "0 < l < min(v.size, rows)",
			     v.size(), "v.size", "0 < l <= min(v.size, rows)",
			     "void base_matrix < T >::"
			     "sto_column_vector(const base_vector < T > &v, lidia_size_t l, lidia_size_t j)",
			     DM_BM, LBM_ERROR[3]);
  
  register T *tmpv = v.get_data_address(); 
  
  register lidia_size_t k;
  for (k = 0; k < l; k++)
    value[k][j] = tmpv[k];
}

template < class T >
T *base_matrix < T >::
column(lidia_size_t i) const
{
  /**
   ** DESCRIPTION: RES = A.column(i);
   **              => RES[0] = A.value[0][i],...,
   **                 RES[A.rows-1] = A.value[A.rows-1][i]
   ** ERROR: 0 < i or 
   **        i >= A.columns
   ** VERSION: 2.0
   **/

  debug_handler_l(DM_BM, "in member - function "
		  "column(lidia_size_t)", DV_BM + 2);
  
  if (i >= columns || i < 0)
    lidia_error_handler_para(i, "i", "0 <= i < columns",
			     columns, "columns", "0 <= i < columns",
			     "T *base_matrix < T >::"
			     "column(lidia_size_t i) const", 
			     DM_BM, LBM_ERROR[3]);
  
  register T *RES = new T[rows];
  memory_handler(RES, DM_BM, "column :: "
		 "Error in memory allocation (RES)");
  
  register lidia_size_t k;

  for (k = 0; k < rows; k++)
    RES[k] = value[k][i];
  return RES;
}

template < class T >
void base_matrix < T >::
column(T *RES, lidia_size_t i) const
{
  /**
   ** DESCRIPTION: A.column(RES,i);
   **              => RES[0] = A.value[0][i],...,
   **                 RES[l-1] = A.value[l-1][i]
   ** ERROR: 0 < i or 
   **        i >= A.columns or 
   **        RES == NULL
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "column(T *, lidia_size_t)", DV_BM + 2);

  if (i >= columns || i < 0 || RES == NULL)
    lidia_error_handler_para(i, "i", "0 <= i < columns", 
			     columns, "columns", "0 <= i < columns",
			     PRT, "RES", "RES != NULL",
			     "void base_matrix < T >::"
			     "column(T *RES, lidia_size_t i) const", 
			     DM_BM, LBM_ERROR[1]);

  register lidia_size_t k;

  for (k = 0; k < rows; k++)
    RES[k] = value[k][i];
}

template < class T >
void base_matrix < T >::
column_vector(base_vector < T > &RES, lidia_size_t i) const
{
  /**
   ** DESCRIPTION: A.column_vector(RES,i);
   **              => RES[0] = A.value[0][i],...,
   **                 RES[A.rows-1] = A.value[A.rows-1][i]
   ** ERROR: 0 > i or 
   **        i >= A.columns
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "column_vector(base_vector < T > &, lidia_size_t)", DV_BM + 2);
  
  if (i >= columns || i < 0)
    lidia_error_handler_para(i, "i", "0 <= i < columns",
			     columns, "columns", "0 <= i < columns",
			     "void base_matrix < T >::"
			     "column_vector(base_vector < T > &RES, lidia_size_t i) const", 
			     DM_BM, LBM_ERROR[3]);
  
  if (RES.capacity() < rows)
    RES.set_capacity(rows);
  if (RES.size() != rows)
    RES.set_size(rows);	

  register T *tmpRES = RES.get_data_address();
  register lidia_size_t k;

  for (k = 0; k < rows; k++)
    tmpRES[k] = value[k][i];
}

/** 
 ** row access 
 **/

template < class T >
void base_matrix < T >::
sto_row(const T *v, lidia_size_t l, lidia_size_t i)
{
  /**
   ** DESCRIPTION: A.sto_row(v,l,j) stores v[0],...,v[l-1] in row i of matrix A.
   ** ERROR: i > A.rows or 
   **        l > A.columns or 
   **        i < 0 or 
   **        l < 0 or
   **        v == NULL
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "sto_row(const T *, lidia_size_t, lidia_size_t)", DV_BM + 2);
  
  if (i >= rows || l > columns || i < 0 || l <= 0 || v == NULL)
    lidia_error_handler_para(i, "i", "0 <= i < rows",
			     rows, "rows", "0 <= i < rows",
			     l, "l", "0 < l <= columns", 
			     columns, "columns", "0 < l <= columns",
			     PRT, "v", "v != NULL",
			     "void base_matrix < T >::"
			     "sto_row(const T *v, lidia_size_t l, lidia_size_t i)", 
			     DM_BM, LBM_ERROR[1]);
  
  register T *tmp = value[i];
  register lidia_size_t k;

  for (k = 0; k < l; k++)
    tmp[k] = v[k];
}

template < class T >
void base_matrix < T >::
sto_row_vector(const base_vector < T > &v, lidia_size_t l, lidia_size_t i)
{
  /**
   ** DESCRIPTION: A.sto_row_vector(v,l,j) stores v[0],...,v[l-1] in row i of matrix A.
   ** ERROR: i > A.rows or 
   **        l > A.columns or 
   **        i < 0 or 
   **        l < 0 or 
   **        l > v.size
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "sto_row_vector(const base_vector < T > &, lidia_size_t, lidia_size_t)", DV_BM + 2);
  
  if (i >= rows || l > columns || i < 0 || l <= 0 || l > v.size())
    lidia_error_handler_para(i, "i", "0 <= i < rows", 
			     rows, "rows", "0 <= i < rows",
			     l, "l", "0 < l <= min(columns, v.size)", 
			     columns, "columns", "0 < l <= min(columns, v.size)",
			     v.size(), "v.size", "0 < l <= min(columns, v.size)",
			     "void base_matrix < T >::"
			     "sto_row_vector(const base_vector < T > &v, lidia_size_t l, lidia_size_t i)", 
			     DM_BM, LBM_ERROR[3]);
  
  register T *tmp = value[i];
  register T *tmpv = v.get_data_address(); 
  register lidia_size_t k;

  for (k = 0; k < l; k++)
    tmp[k] = tmpv[k];
}

template < class T >
T *base_matrix < T >::
row(lidia_size_t i) const
{
  /**
   ** DESCRIPTION: RES = A.row(i);
   **              => RES[0] = A.value[i][0],...,
   **                 RES[A.columns-1] = A.value[i][A.columns-1]
   ** ERROR: 0 > i or 
   **        i >= A.rows 
   ** VERSION: 2.0
   **/

  debug_handler_l(DM_BM, "in member - function "
		  "row(lidia_size_t)", DV_BM + 2);
  
  if (i >= rows || i < 0)
    lidia_error_handler_para(i, "i", "0 <= i < rows",
			     rows, "rows", "0 <= i < rows",
			     "T *base_matrix < T >::"
			     "row(lidia_size_t i) const", 
			     DM_BM, LBM_ERROR[3]);
  
  register T *RES = new T[columns];
  memory_handler(RES, DM_BM, "row :: "
		 "Error in memory allocation (RES)");
  
  register T *tmp = value[i];
  register lidia_size_t k;

  for (k = 0; k < columns; k++)
    RES[k] = tmp[k];
  return RES;
}

template < class T >
void base_matrix < T >::
row(T *RES, lidia_size_t i) const
{
  /**
   ** DESCRIPTION: A.row(RES,i);
   **              => RES[0] = A.value[i][0],...,
   **                 RES[l-1] = A.value[i][l-1]
   ** ERROR: 0 > i or 
   **        i >= A.rows or 
   **        RES == NULL
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "row(T *, lidia_size_t)", DV_BM + 2);
  
  if (i >= rows || i < 0 || RES == NULL)
    lidia_error_handler_para(i, "i", "0 <= i < rows", 
			     rows, "rows", "0 <= i < rows",
			     PRT, "RES", "RES != NULL", 
			     "void base_matrix < T >::"
			     "row(T *RES, lidia_size_t i) const", 
			     DM_BM, LBM_ERROR[3]);
  
  register lidia_size_t k;

  for (k = 0; k < columns; k++)
    RES[k] = value[i][k];
}

template < class T >
void base_matrix < T >::
row_vector(base_vector < T > &RES, lidia_size_t i) const
{
  /**
   ** DESCRIPTION: A.row(RES, i);
   **              => RES[0] = A.value[i][0],...,
   **                 RES[A.columns-1] = A.value[i][A.columns-1]
   ** ERROR: 0 > i or 
   **        i >= A.rows
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "row_vector(base_vector < T > &, lidia_size_t)", DV_BM + 2);
  
  if (i >= rows || i < 0)
    lidia_error_handler_para(i, "i", "0 <= i < rows",
			     rows, "rows", "0 <= i < rows",
			     "void base_matrix < T >::"
			     "row_vector(base_vector < T > &RES, lidia_size_t i) const", 
			     DM_BM, LBM_ERROR[3]);
  
  if (RES.capacity() < columns)
    RES.set_capacity(columns);
  if (RES.size() != columns)
    RES.set_size(columns);
  
  register T *tmpRES = RES.get_data_address();
  register lidia_size_t k;

  for (k = 0; k < columns; k++)
    tmpRES[k] = value[i][k];
}

/**
 ** array access
 **/

template < class T >
T ** base_matrix < T >::
get_data() const
{
  /**
   ** DESCRIPTION: prt = A.get_value()
   **              => prt = pointer to a copy of array A.value
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "get_value()", DV_BM + 2);
  
  register T **copy = new T *[rows];
  memory_handler(copy, DM_BM, "get_value :: "
		 "Error in memory allocation (copy)");

  register lidia_size_t i, j;
  register T *tmp, *tmp1;  
  for (i = 0; i < rows; i++)
    {
      tmp1 = value[i];
      tmp = new T[columns];
      memory_handler(tmp, DM_BM, "get_value :: "
		     "Error in memory allocation (tmp)");
      for (j = 0; j < columns; j++)
	tmp[j] = tmp1[j];
      copy[i] = tmp;
    }
  return copy;
}

template < class T >
void base_matrix < T >::
set_data(const T **v, lidia_size_t r, lidia_size_t c) 
{
  /**
   ** DESCRIPTION: A.set_value(v,r,c)
   **              => A.value[i][j] = v[i][j]
   **                 0 <= i < r and 0 <= j < c
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "set_value(const T **, lidia_size_t, lidia_size_t)", DV_BM + 2);

  if (r < 1 || c < 1 || v == NULL)
    lidia_error_handler_para(r, "r", "0 < r",
			     c, "c", "0 < c", 
			     PRT, "v", "v != NULL",
			     "void base_matrix < T >::"
			     "set_data(const T **v, lidia_size_t r, lidia_size_t c)", 
			     DM_BM, LBM_ERROR[1]);
  
  if (r != rows)
    set_no_of_rows(r);
  if (c != columns)
    set_no_of_columns(c);
  
  register lidia_size_t i, j;
  
  const T *tmp;
  register T *tmp1;  

  for (i = 0; i < rows; i++)
    {
      tmp1 = value[i];
      tmp = v[i];
      for (j = 0; j < columns; j++)
	tmp1[j] = tmp[j];
    }
}

/**
 ** END: access functions
 **/

/**
 ** split functions
 **/

template < class T >
void base_matrix < T >::
split_t(base_matrix < T > &A, base_matrix < T > &B, base_matrix < T > &C, base_matrix < T > &D) const
{
  /**
   ** DESCRIPTION: E.split(A,B,C,D);
   **              => splits matrix E longo the submatrices A,B,C,D
   **                     (A B)
   **              => E = (C D)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or
   **        B.columns > columns or 
   **        B.rows > rows or 
   **        C.columns > columns or 
   **        C.rows > rows or
   **        D.columns > columns or 
   **        D.rows > rows 
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "split(base_matrix < T > &, base_matrix < T > &, "
		  "base_matrix < T > &, base_matrix < T > &)", DV_BM + 3);
  
  if (A.rows > rows || A.columns > columns ||
      B.rows > rows || B.columns > columns ||
      C.rows > rows || C.columns > columns ||
      D.rows > rows || D.columns > columns)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows", 
			     A.columns, "A.columns", "A.columns <= columns",
			     B.rows, "B.rows", "B.rows <= rows", 
			     B.columns, "B.columns", "B.columns <= columns",
			     C.rows, "C.rows", "C.rows <= rows", 
			     C.columns, "C.columns", "C.columns <= columns",
			     D.rows, "D.rows", "D.rows <= rows", 
			     D.columns, "D.columns", "D.columns <= columns",
			     rows, "rows", "",
			     columns, "columns", "",
			     "void base_matrix < T >::"
			     "split(base_matrix < T > &A, base_matrix < T > &B, "
			     "base_matrix < T > &C, base_matrix < T > &D) const", 
			     DM_BM, LBM_ERROR[4]);
  
  register lidia_size_t i, j;
  register T *tmp, *tmp1;

  for (i = 0; i < A.rows; i++)
    {
      tmp = value[i];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp1[j] = tmp[j];
    }
  
  for (i = 0; i < B.rows; i++)
    {
      tmp = &value[i][columns - B.columns];
      tmp1 = B.value[i];
      for (j = 0; j < B.columns; j++)
	tmp1[j] = tmp[j];
    }
  
  for (i = 0; i < C.rows; i++)
    {
      tmp = value[rows - C.rows + i];
      tmp1 = C.value[i];
      for (j = 0; j < C.columns; j++)
	tmp1[j] = tmp[j];
    }
  
  for (i = 0; i < D.rows; i++)
    {
      tmp = &value[rows - D.rows + i][columns - D.columns];
      tmp1 = D.value[i];
      for (j = 0; j < D.columns; j++)
	tmp1[j] = tmp[j];
    }
}

template < class T >
void base_matrix < T >::
split_h(base_matrix < T > &A, base_matrix < T > &B) const
{
  /**
   ** DESCRIPTION: C.split_h(A,B);
   **              => splits matrix C into the submatrices A,B
   **              => C = (A B)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or
   **        B.columns > columns or 
   **        A.rows > rows
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "split_h(base_matrix < T > &, base_matrix < T > &)", DV_BM + 3);
  
  if (A.rows > rows || A.columns > columns ||
      B.rows > rows || B.columns > columns)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows", 
			     A.columns, "A.columns", "A.columns <= coluns",
			     B.rows, "B.rows", "B.rows <= rows", 
			     B.columns, "B.columns", "B.columns <= coluns",
			     rows, "rows", "",
			     columns, "columns", "",
			     "void base_matrix < T >::"
			     "split_h(base_matrix < T > &A, base_matrix < T > &B) const", 
			     DM_BM, LBM_ERROR[4]);

  register lidia_size_t i, j;
  register T *tmp, *tmp1;  

  for (i = 0; i < A.rows; i++)
    {
      tmp = value[i];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp1[j] = tmp[j];
    }
  
  for (i = 0; i < B.rows; i++)
    {
      tmp = &value[i][columns - B.columns];
      tmp1 = B.value[i];
      for (j = 0; j < B.columns; j++)
	tmp1[j] = tmp[j];
    }
}

template < class T >
void base_matrix < T >::
split_h(T *v, base_matrix < T > &A) const
{
  /**
   ** DESCRIPTION: C.split_h(v, A);
   **              => splits matrix C into the array v and the submatrix A
   **              => C = (v A)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or
   **        v == NULL  
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "split_h(T *, base_matrix < T > &)", DV_BM + 3);
  
  if (A.rows > rows || A.columns > columns || v == NULL)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows", 
			     A.columns, "A.columns", "A.columns <= columns",
			     rows, "rows", "",
			     columns, "columns", "",  
			     PRT, "v", "v != NULL",
			     "void base_matrix < T >::"
			     "split_h(T *v, base_matrix < T > &A) const",
			     DM_BM, LBM_ERROR[4]);
  
  register lidia_size_t i, j;
  register T *tmp, *tmp1;  

  for (i = 0; i < rows; i++)
    v[i] = value[i][0];
  
  for (i = 0; i < A.rows; i++)
    {
      tmp = &value[i][columns - A.columns];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp1[j] = tmp[j];
    }
}

template < class T >
void base_matrix < T >::
split_h(base_vector < T > &v, base_matrix < T > &A) const
{
  /**
   ** DESCRIPTION: C.split_h(v, A);
   **              => splits matrix C into the vector v and the submatrix A
   **              => C = (v A)
   ** ERROR: v.size > rows or 
   **        A.columns > columns or 
   **        A.rows > rows
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "split_h(base_vector < T > &, base_matrix < T > &)", DV_BM + 3);

  lidia_size_t l = v.size();
  register T *tmp1;
  
  if (A.rows > rows || A.columns > columns || l > rows)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows", 
			     A.columns, "A.columns", "A.columns <= columns",
			     rows, "rows", "",
			     columns, "columns", "",
			     l, "v.size", "v.size <= rows",
			     "void base_matrix < T >::"
			     "split_h(base_vector < T > &v, base_matrix < T > &A) const", 
			     DM_BM, LBM_ERROR[4]);

  register T *tmp = v.get_data_address();

  register lidia_size_t i, j; 
  for (i = 0; i < l; i++)
    tmp[i] = value[i][0];
  
  for (i = 0; i < A.rows; i++)
    {
      tmp = &value[i][columns - A.columns];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp1[j] = tmp[j];
    }
}

template < class T >
void base_matrix < T >::
split_h(base_matrix < T > &A, T *v) const
{
  /**
   ** DESCRIPTION: C.split_h(A, v);
   **              => splits matrix C into the submatrix A and the array v
   **              => C = (A v)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or
   **        v == NULL
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "split_h(base_matrix < T > &, T *)", DV_BM + 3);
  
  if (A.rows > rows || A.columns > columns || v == NULL)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows", 
			     A.columns, "A.columns", "A.columns <= columns",
			     rows, "rows", "",
			     columns, "columns", "",
			     PRT, "v", "v != NULL",
			     "void base_matrix < T >::"
			     "split_h(base_matrix < T > &A, T *v) const", 
			     DM_BM, LBM_ERROR[4]);

  register T *tmp, *tmp1;  
  register lidia_size_t i, j;  

  for (i = 0; i < A.rows; i++)
    {
      tmp = value[i];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp1[j] = tmp[j];
    }
  
  j = columns - 1;
  for (i = 0; i < rows; i++)
    v[i] = value[i][j];
}

template < class T >
void base_matrix < T >::
split_h(base_matrix < T > &A, base_vector < T > &v) const
{
  /**
   ** DESCRIPTION: C.split_h(A, v);
   **              => splits matrix C into the submatrix A and the vector v
   **              => C = (A v)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or 
   **        v.size > rows
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "split_h(base_matrix < T > &, base_vector < T > &)", DV_BM + 3);

  lidia_size_t l = v.size();
  register T *tmp, *tmp1;
  
  if (A.rows > rows || A.columns > columns || l > rows)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows", 
			     A.columns, "A.columns", "A.columns <= columns",
			     rows, "rows", "",
			     columns, "columns", "",
			     l, "v.size", "v.size <= rows",
			     "void base_matrix < T >::"
			     "split_h(base_matrix < T > &A, base_vector < T > &v) const", 
			     DM_BM, LBM_ERROR[4]);

  register lidia_size_t i, j;  
  for (i = 0; i < A.rows; i++)
    {
      tmp = value[i];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp1[j] = tmp[j];
    }
  
  j = columns - 1;
  tmp = v.get_data_address();
  
  for (i = 0; i < l; i++)
    tmp[i] = value[i][j];
}

template < class T >
void base_matrix < T >::
split_v(base_matrix < T > &A, base_matrix < T > &B) const
{
  /**
   ** DESCRIPTION: C.split_v(A,B);
   **              => splits matrix C into the submatrices A,B
   **                     (A)
   **              => C = (B)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or
   **        B.columns > columns or 
   **        A.rows > rows 
   ** VERSION: 2.0
   **/

  debug_handler_l(DM_BM, "in member - function "
		  "split_v(base_matrix < T > &, base_matrix < T > &)", DV_BM + 3);

  if (A.rows > rows || A.columns > columns ||
      B.rows > rows || B.columns > columns)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows",
			     A.columns, "A.columns", "A.columns <= columns",
			     B.rows, "B.rows", "B.rows <= rows",
			     B.columns, "B.columns", "B.columns <= columns",
			     rows, "rows", "",
			     columns, "columns", "",
			     "void base_matrix < T >::"
			     "split_v(base_matrix < T > &A, base_matrix < T > &B) const", 
			     DM_BM, LBM_ERROR[4]);

  register lidia_size_t i, j;
  register T *tmp, *tmp1;  

  for (i = 0; i < A.rows; i++)
    {
      tmp = value[i];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp1[j] = tmp[j];
    }
  
  for (i = 0; i < B.rows; i++)
    {
      tmp = value[rows - B.rows + i];
      tmp1 = B.value[i];
      for (j = 0; j < B.columns; j++)
	tmp1[j] = tmp[j];
    }
}

template < class T >
void base_matrix < T >::
split_v(T *v, base_matrix < T > &A) const
{
  /**
   ** DESCRIPTION: C.split_v(v, A);
   **              => splits matrix C into the array v and the submatrix A
   **                     (v)
   **              => C = (A)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or
   **        v == NULL
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "split_v(T *, base_matrix < T > &)", DV_BM + 3);
  
  if (A.rows > rows || A.columns > columns || v == NULL)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows",
			     A.columns, "A.columns", "A.columns <= columns", 
			     rows, "rows", "",
			     columns, "columns", "",
			     PRT, "v", "v != NULL",
			     "void base_matrix < T >::"
			     "split_v(T *v, base_matrix < T > &A) const", 
			     DM_BM, LBM_ERROR[4]);

  register lidia_size_t i, j;
  register T *tmp1, *tmp = value[0];

  for (j = 0; j < columns; j++)
    v[j] = tmp[j];
  
  for (i = 0; i < A.rows; i++)
    {
      tmp = value[rows - A.rows + i];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp1[j] = tmp[j];
    }
}

template < class T >
void base_matrix < T >::
split_v(base_vector < T > &v, base_matrix < T > &A) const
{
  /**
   ** DESCRIPTION: C.split_v(v, A);
   **              => splits matrix C into the vector v and the submatrix A
   **                     (v)
   **              => C = (A)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or 
   **        v.size > columns
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "split_v(base_vector < T > &, base_matrix < T > &)", DV_BM + 3);

  lidia_size_t l = v.size();
  
  if (A.rows > rows || A.columns > columns || l > columns)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows",
			     A.columns, "A.columns", "A.columns <= columns",
			     rows, "rows", "",
			     columns, "columns", "",
			     l, "v.size", "v.size <= columns",
			     "void base_matrix < T >::"
			     "split_v(base_vector < T > &v, base_matrix < T > &A) const", 
			     DM_BM, LBM_ERROR[4]);
  
  register T *tmp = value[0];
  register T *tmp1 = v.get_data_address();
  register lidia_size_t i, j;

  for (j = 0; j < l; j++)
    tmp1[j] = tmp[j];
  
  for (i = 0; i < A.rows; i++)
    {
      tmp = value[rows - A.rows + i];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp1[j] = tmp[j];
    }
}

template < class T >
void base_matrix < T >::
split_v(base_matrix < T > &A, T *v) const
{
  /**
   ** DESCRIPTION: C.split_v(A,B);
   **              => splits matrix C into the submatrix A and the vector v
   **                     (A)
   **              => C = (v)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or
   **        v == NULL
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "split_v(base_matrix < T > &, T *)", DV_BM + 3);

  register lidia_size_t i, j;
  register T *tmp, *tmp1;
  
  if (A.rows > rows || A.columns > columns || v == NULL)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows",
			     A.columns, "A.columns", "A.columsn <= columns",
			     rows, "rows", "",
			     columns, "columns", "",
			     PRT, "v", "v != NULL",
			     "void base_matrix < T >::"
			     "split_v(base_matrix < T > &A, T *v) const", 
			     DM_BM, LBM_ERROR[4]);
  
  for (i = 0; i < A.rows; i++)
    {
      tmp = value[i];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp1[j] = tmp[j];
    }
  
  tmp = value[rows-1];
  for (j = 0; j < columns; j++)
    v[j] = tmp[j];
}

template < class T >
void base_matrix < T >::
split_v(base_matrix < T > &A, base_vector < T > &v) const
{
  /**
   ** DESCRIPTION: C.split_v(A,B);
   **              => splits matrix C into the submatrix A and the vector v
   **                     (A)
   **              => C = (v)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or 
   **        v.size > columns
   ** VERSION: 2.0
   **/

  debug_handler_l(DM_BM, "in member - function "
		  "split_v(base_matrix < T > &, base_vector < T > &)", DV_BM + 3);

  lidia_size_t l = v.size();
  register T *tmp, *tmp1;
  
  if (A.rows > rows || A.columns > columns || l > columns)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows",
			     A.columns, "A.columns", "A.columns <= columns",
			     rows, "rows", "",
			     columns, "columns", "",
			     l, "v.size", "v.size <= columns",
			     "void base_matrix < T >::"
			     "split_v(base_matrix < T > &A, base_vector < T > &v) const", 
			     DM_BM, LBM_ERROR[4]);

  register lidia_size_t i, j;   

  for (i = 0; i < A.rows; i++)
    {
      tmp = value[i];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp1[j] = tmp[j];
    }
  
  tmp = value[rows-1];
  tmp1 = v.get_data_address();
  for (j = 0; j < l; j++)
    tmp1[j] = tmp[j];
}

/**
 ** compose functions
 **/

template < class T >
void base_matrix < T >::
compose_t(const base_matrix < T > &A, const base_matrix < T > &B, const base_matrix < T > &C, const base_matrix < T > &D)
{
  /**
   ** DESCRIPTION: E.compose(A,B,C,D)
   **              => compose the submatrices A,B,C,D to E
   **                     (A B)
   **              => E = (C D)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or
   **        B.columns > columns or 
   **        B.rows > rows or 
   **        C.columns > columns or 
   **        C.rows > rows or 
   **        D.columns > columns or 
   **        D.rows > rows
   ** VERSION: 2.0
   **/

  debug_handler_l(DM_BM, "in member - function "
		  "compose(const base_matrix < T > &, const base_matrix < T > &, "
		  "const base_matrix < T > &, const base_matrix < T > &)", DV_BM + 3);
  
  if (A.rows > rows || A.columns > columns ||
      B.rows > rows || B.columns > columns ||
      C.rows > rows || C.columns > columns ||
      D.rows > rows || D.columns > columns)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows",
			     A.columns, "A.columns", "A.columns <= columns",
			     B.rows, "B.rows", "B.rows <= rows",
			     B.columns, "B.columns", "B.columns <= columns",
			     C.rows, "C.rows", "C.rows <= rows",
			     C.columns, "C.columns", "C.columns <= columns",
			     D.rows, "D.rows", "D.rows <= rows",
			     D.columns, "D.columns", "D.columns <= columns",
			     rows, "rows", "",
			     columns, "columns", "",
			     "void base_matrix < T >::"
			     "compose(const base_matrix < T > &A, const base_matrix < T > &B, "
			     "const base_matrix < T > &C, const base_matrix < T > &D)",
			     DM_BM, LBM_ERROR[4]);
  
  register lidia_size_t i, j;
  T *tmp, *tmp1;  
  for (i = 0; i < A.rows; i++)
    {
      tmp = value[i];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp[j] = tmp1[j];
    }
  
  for (i = 0; i < B.rows; i++)
    {
      tmp = &value[i][columns - B.columns];
      tmp1 = B.value[i];
      for (j = 0; j < B.columns; j++)
	tmp[j] = tmp1[j];
    }
  
  for (i = 0; i < C.rows; i++)
    {
      tmp = value[rows - C.rows + i];
      tmp1 = C.value[i];
      for (j = 0; j < C.columns; j++)
	tmp[j] = tmp1[j];
    }
  
  for (i = 0; i < D.rows; i++)
    {
      tmp = &value[rows - D.rows + i][columns - D.columns];
      tmp1 = D.value[i];
      for (j = 0; j < B.columns; j++)
	tmp[j] = tmp1[j];
    }
}

template < class T >
void base_matrix < T >::
compose_h(const base_matrix < T > &A, const base_matrix < T > &B)
{
  /**
   ** DESCRIPTION: C.compose_h(A,B);
   **              => compose the submatrices A,B to C
   **              => C = (A B)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or
   **        B.columns > columns or 
   **        B.rows > rows
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "compose_h(const base_matrix < T > &, const base_matrix < T > &)", DV_BM + 3);

  if (A.rows > rows || A.columns > columns ||
      B.rows > rows || B.columns > columns)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows",
			     A.columns, "A.columns", "A.columns <= columns",
			     B.rows, "B.rows", "B.rows <= rows",
			     B.columns, "B.columns", "B.columns <= columns",
			     rows, "rows", "",
			     columns, "columns", "",
			     "void base_matrix < T >::"
			     "compose_h(const base_matrix < T > &A, const base_matrix < T > &B)",
			     DM_BM, LBM_ERROR[4]);
  
  register lidia_size_t i, j;
  T *tmp, *tmp1;
  for (i = 0; i < A.rows; i++)
    {
      tmp = value[i];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp[j] = tmp1[j];
    }
  
  for (i = 0; i < B.rows; i++)
    {
      tmp = &value[i][columns - B.columns];
      tmp1 = B.value[i];
      for (j = 0; j < B.columns; j++)
	tmp[j] = tmp1[j];
    }
}

template < class T >
void base_matrix < T >::
compose_h(const T *v, const base_matrix < T > &A)
{
  /**
   ** DESCRIPTION: C.compose_h(v, A);
   **              => compose the submatrix A and the vector v to matrix C
   **              => C = (v A)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or
   **        v == NULL
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "compose_h(const T *, const base_matrix < T > &)", DV_BM + 3);

  if (A.rows > rows || A.columns > columns || v == NULL) 
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows",
			     A.columns, "A.columns", "A.columns <= columns",
			     rows, "rows", "",
			     columns, "columns", "",
			     PRT, "v", "v != NULL",
			     "void base_matrix < T >::"
			     "compose_h(const T *v, const base_matrix < T > &A)",
			     DM_BM, LBM_ERROR[4]);

  register lidia_size_t i, j;
  T *tmp, *tmp1;  
  for (i = 0; i < rows; i++)
    value[i][0] = v[i];
  
  for (i = 0; i < A.rows; i++)
    {
      tmp = &value[i][columns - A.columns];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp[j] = tmp1[j];
    }
}

template < class T >
void base_matrix < T >::
compose_h(const base_vector < T > &v, const base_matrix < T > &A)
{
  /**
   ** DESCRIPTION: C.compose_h(v, A);
   **              => compose the submatrix A and the vector v to matrix C
   **              => C = (v A)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or 
   **        v.size > rows
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "compose_h(const base_vector < T > &, const base_matrix < T > &)", DV_BM + 3);

  lidia_size_t l = v.size();
  T *tmp1;
  
  if (A.rows > rows || A.columns > columns || l > rows)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows",
			     A.columns, "A.columns", "A.columns <= columns",
			     rows, "rows", "",
			     columns, "columns", "",
			     l, "v.size", "v.size <= rows",
			     "void base_matrix < T >::"
			     "compose_h(const base_vector < T > &v, const base_matrix < T > &A)",
			     DM_BM, LBM_ERROR[4]);
  
  T *tmp = v.get_data_address();

  register lidia_size_t i, j; 
  for (i = 0; i < l; i++)
    value[i][0] = tmp[i];
  
  for (i = 0; i < A.rows; i++)
    {
      tmp = &value[i][columns - A.columns];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp[j] = tmp1[j];
    }
}

template < class T >
void base_matrix < T >::
compose_h(const base_matrix < T > &A, const T *v)
{
  /**
   ** DESCRIPTION: C.compose_h(A, v);
   **              => compose the submatrix A and vector v to matrix C
   **              => C = (A v)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or
   **        v == NULL
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "compose_h(const base_matrix < T > &, const T *)", DV_BM + 3);

  if (A.rows > rows || A.columns > columns || v == NULL)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows",
			     A.columns, "A.columns", "A.columns <= columns",
			     rows, "rows", "",
			     columns, "columns", "",
			     PRT, "v", "v != NULL",
			     "void base_matrix < T >::"
			     "compose_h(const base_matrix < T > &A, const T *v)",
			     DM_BM, LBM_ERROR[4]);

  register lidia_size_t i, j;
  T *tmp, *tmp1;  
  for (i = 0; i < A.rows; i++)
    {
      tmp = value[i];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp[j] = tmp1[j];
    }
  
  j = columns - 1;
  for (i = 0; i < rows; i++)
    value[i][j] = v[i];
}

template < class T >
void base_matrix < T >::
compose_h(const base_matrix < T > &A, const base_vector < T > &v)
{
  /**
   ** DESCRIPTION: C.compose_h(A, v);
   **              => compose the submatrix A and vector v to matrix C
   **              => C = (A v)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or 
   **        v.size > rows
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "compose_h(const base_matrix < T > &, base_vector < T > &)", DV_BM + 3);

  lidia_size_t l = v.size();
  T *tmp, *tmp1;
  
  if (A.rows > rows || A.columns > columns || l > rows)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows",
			     A.columns, "A.columns", "A.columns <= columns",
			     rows, "rows", "",
			     columns, "columns", "",
			     l, "v.size", "v.size <= rows",
			     "void base_matrix < T >::"
			     "compose_h(const base_matrix < T > &A, const base_vector < T > &v)",
			     DM_BM, LBM_ERROR[4]);

  register lidia_size_t i, j;  
  for (i = 0; i < A.rows; i++)
    {
      tmp = value[i];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp[j] = tmp1[j];
    }

  j = columns - 1;
  tmp = v.get_data_address();
  for (i = 0; i < l; i++)
    value[i][j] = tmp[i];
}

template < class T >
void base_matrix < T >::
compose_v(const base_matrix < T > &A, const base_matrix < T > &B)
{
  /**
   ** DESCRIPTION: C.compose_v(A,B);
   **              => compose the submatrices A,B to C
   **                     (A)
   **              => C = (B)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or
   **        B.columns > columns or
   **        B.rows > rows
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "compose_v(const base_matrix < T > &, const base_matrix < T > &)", DV_BM + 3);
  
  if (A.rows > rows || A.columns > columns ||
      B.rows > rows || B.columns > columns)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows",
			     A.columns, "A.columns", "A.columns <= columns",
			     B.rows, "B.rows", "B.rows <= rows",
			     B.columns, "B.columns", "B.columns <= columns",
			     rows, "rows", "",
			     columns, "columns", "",
			     "void base_matrix < T >::"
			     "compose_v(const base_matrix < T > &A, const base_matrix < T > &B)",
			     DM_BM, LBM_ERROR[4]);

  register lidia_size_t i, j;
  T *tmp, *tmp1;  
  for (i = 0; i < A.rows; i++)
    {
      tmp = value[i];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp[j] = tmp1[j];
    }
  
  for (i = 0; i < B.rows; i++)
    {
      tmp = value[rows - B.rows + i];
      tmp1 = B.value[i];
      for (j = 0; j < B.columns; j++)
	tmp[j] = tmp1[j];
    }
}

template < class T >
void base_matrix < T >::
compose_v(const T *v, const base_matrix < T > &A)
{
  /**
   ** DESCRIPTION: C.compose_v(v, A);
   **              => compose the vector v and submatrix A to matrix C
   **                     (v)
   **              => C = (A)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or
   **        v == NULL
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "compose_v(const T *, const base_matrix < T > &)", DV_BM + 3);
  
  if (A.rows > rows || A.columns > columns || v == NULL)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows",
			     A.columns, "A.columns", "A.columns <= columns",
			     rows, "rows", "",
			     columns, "columns", "",
			     PRT, "v", "v != NULL",
			     "void base_matrix < T >::"
			     "compose_v(const T *v, const base_matrix < T > &A)",
			     DM_BM, LBM_ERROR[4]);

  register lidia_size_t i, j;
  T *tmp1;  
  T *tmp = value[0];
  for (j = 0; j < columns; j++)
    tmp[j] = v[j];
  
  for (i = 0; i < A.rows; i++)
    {
      tmp = value[rows - A.rows + i];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp[j] = tmp1[j];
    }
}

template < class T >
void base_matrix < T >::
compose_v(const base_vector < T > &v, const base_matrix < T > &A)
{
  /**
   ** DESCRIPTION: C.compose_v(v, A);
   **              => compose the vector v and submatrix A to matrix C
   **                     (v)
   **              => C = (A)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or 
   **        v.size > columns
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "compose_v(const base_vector < T > &, const base_matrix < T > &)", DV_BM + 3);
  
  lidia_size_t l = v.size();
  
  if (A.rows > rows || A.columns > columns || l > columns)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows",
			     A.columns, "A.columns", "A.columns <= columns",
			     rows, "rows", "",
			     columns, "columns", "",
			     l, "v.size", "v.size <= coluns",
			     "void base_matrix < T >::"
			     "compose_v(const base_vector < T > &v, const base_matrix < T > &A)",
			     DM_BM, LBM_ERROR[4]);
  
  T *tmp = value[0];
  T *tmp1 = v.get_data_address();

  register lidia_size_t i, j;
  for (j = 0; j < l; j++)
    tmp[j] = tmp1[j];
  
  for (i = 0; i < A.rows; i++)
    {
      tmp = value[rows - A.rows + i];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp[j] = tmp1[j];
    }
}

template < class T >
void base_matrix < T >::
compose_v(const base_matrix < T > &A, const T *v)
{
  /**
   ** DESCRIPTION: C.compose_v(A, v);
   **              => compose the submatrix A and the vector v to matrix C
   **                     (A)
   **              => C = (v)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or
   **        v == NULL
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "compose_v(const base_matrix < T > &, const T *)", DV_BM + 3);
  
  if (A.rows > rows || A.columns > columns || v == NULL)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows",
			     A.columns, "A.columns", "A.columns <= columns", 
			     rows, "rows", "",
			     columns, "columns", "",
			     PRT, "v", "v != NULL",
			     "void base_matrix < T >::"
			     "compose_v(const base_matrix < T > &A, const T *v)",
			     DM_BM, LBM_ERROR[4]);

  register lidia_size_t i, j;
  T *tmp, *tmp1;
  for (i = 0; i < A.rows; i++)
    {
      tmp = value[i];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp[j]=tmp1[j];
    }
  
  tmp = value[rows - 1]; 
  for (j = 0; j < columns; j++)
    tmp[j]=v[j];
}

template < class T >
void base_matrix < T >::
compose_v(const base_matrix < T > &A, const base_vector < T > &v)
{
  /**
   ** DESCRIPTION: C.compose_v(A, v);
   **              => compose the submatrix A and the vector v to matrix C
   **                     (A)
   **              => C = (v)
   ** ERROR: A.columns > columns or 
   **        A.rows > rows or 
   **        v.size > columns
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "compose_v(const base_matrix < T > &, const base_vector < T > &)", DV_BM + 3);
  
  lidia_size_t l = v.size();
  T *tmp, *tmp1;

  if (A.rows > rows || A.columns > columns || l > columns)
    lidia_error_handler_para(A.rows, "A.rows", "A.rows <= rows",
			     A.columns, "A.columns", "A.columns <= columns",
			     rows, "rows", "",
			     columns, "columns", "",
			     l, "v.size", "v.size <= columns",
			     "void base_matrix < T >::"
			     "compose_v(const base_matrix < T > &A, const base_vector < T > &v)",
			     DM_BM, LBM_ERROR[4]);

  register lidia_size_t i, j;   
  for (i = 0; i < A.rows; i++)
    {
      tmp = value[i];
      tmp1 = A.value[i];
      for (j = 0; j < A.columns; j++)
	tmp[j] = tmp1[j];
    }
  
  tmp = value[rows - 1]; 
  tmp1 = v.get_data_address();
  for (j = 0; j < l; j++)
    tmp[j] = tmp1[j];
}

/**
 ** exchange functions / swap functions
 **/

template < class T >
void base_matrix < T >::
swap(base_matrix < T > &B)
{
  /**
   ** DESCRIPTION: A.swap(A) exchanges matrix A with matrix B.
   ** VERSION: 2.0
   **/

  debug_handler_l(DM_BM, "in member - function "
		  "swap(base_matrix < T > &)", DV_BM + 4);
  
  T **tmp;
  
  /* swap no_of_columns */
  ::swap(columns, B.columns);

  /* swap no_of_rows */
  ::swap(rows, B.rows);

  /* swap values */
  tmp = value;
  value = B.value;
  B.value = tmp;
}

template < class T >
void base_matrix < T >::
swap_columns(lidia_size_t i, lidia_size_t j)
{
  /**
   ** DESCRIPTION: A.swap_columns(i,j) exchanges column i with column j 
   **              in matrix A.
   ** ERROR: i < 0 or 
   **        j < 0 or 
   **        i >= A.columns or 
   **        j >= A.columns
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "swap_columns(lidia_size_t , lidia_size_t)", DV_BM + 4);
  
  if (i < 0 || i >= columns || j < 0 || j >= columns)
    lidia_error_handler_para(i, "i", "0 <= i < columns",
			     j, "j", "0 <= j < columns",
			     columns, "columns", "",
			     "void base_matrix < T >::"
			     "swap_columns(lidia_size_t i, lidia_size_t j)",
			     DM_BM, LBM_ERROR[1]);
  
  register lidia_size_t z;
  T *tmp;

  for (z = 0; z < rows; z++)
    {
      tmp = value[z];
      ::swap(tmp[i], tmp[j]);
    }
}

template < class T >
void base_matrix < T >::
swap_rows(lidia_size_t i, lidia_size_t j)
{
  /**
   ** DESCRIPTION: A.swap_rows(i,j) exchanges row i with row j in matrix A.
   ** ERROR: i < 0 or 
   **        j < 0 or 
   **        i >= A.rows or 
   **        j >= A.rows
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "swap_rows(lidia_size_t , lidia_size_t)", DV_BM + 4);
  
  if (i < 0 || i >= rows || j < 0 || j >= rows)
    lidia_error_handler_para(i, "i", "0 <= i < rows",
			     j, "j", "0 <= j < rows",
			     rows, "rows", "",
			     "void base_matrix < T >::"
			     "swap_rows(lidia_size_t i, lidia_size_t j)",
			     DM_BM, LBM_ERROR[1]);

  T *tmp = value[i];
  value[i] = value[j];
  value[j] = tmp;
}

/**
 ** structur functions
 **/

template < class T >
void base_matrix < T >::
set_no_of_rows(lidia_size_t r)
{
  /**
   ** DESCRIPTION: A.set_no_of_rows(r) sets number of rows of matrix A to r.
   ** ERROR: r < 1
   ** VERSION: 2.0
   **/

  debug_handler_l(DM_BM, "in member - function "
		  "set_no_of_rows(lidia_size_t)", DV_BM + 5);
  
  if (r < 1)
    lidia_error_handler_para(r, "r", "r > 0", 
			     "void base_matrix < T >::"
			     "set_no_of_rows(lidia_size_t r)",
			     DM_BM, LBM_ERROR[1]);
  
  if (r == rows)
    return;

  T **tmp = value;
  register lidia_size_t i;
  
  if (r < rows)
    {
      for (i = r; i < rows; i++)
	delete[] value[i];
      value = new T *[r];
      for (i = 0; i < r; i++)
	value[i] = tmp[i];
    }
  else
    {
      value = new T *[r];
      memory_handler(value, DM_BM, "set_no_of_rows :: "
		     "Error in memory allocation (value)");
      for (i = 0; i < rows; i++)
	value[i] = tmp[i];
      for (i = rows; i < r; i++)
	{
	  value[i] = new T[columns];
	  memory_handler(tmp1, DM_BM, "set_no_of_rows :: "
			 "Error in memory allocation (tmp1)");
	}
    }
  
  rows = r;
  delete[] tmp;
}

template < class T >
void base_matrix < T >::
set_no_of_columns(lidia_size_t c)
{
  /**
   ** DESCRIPTION: A.set_no_of_columns(c) sets number of columns of matrix A to c.
   ** ERROR: c < 1
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "set_no_of_columns(lidia_size_t)", DV_BM + 5);

  if (c < 1)
    lidia_error_handler_para(c, "c", "c > 0", 
			     "void base_matrix < T >::"
			     "set_no_of_columns(lidia_size_t c)",
			     DM_BM, LBM_ERROR[1]);
  
  if (columns == c)
    return;
  
  register lidia_size_t i, j;
  T *tmp, *tmp1;
  
  if (c < columns)
    {
      for (i = 0; i < rows; i++)
	{
	  tmp1 = value[i];
	  tmp = new T[c];
	  memory_handler(tmp, DM_BM, "set_no_of_columns :: "
			 "Error in memory allocation (tmp)");
	  for (j = 0; j < c; j++)
	    tmp[j] = tmp1[j];
	  value[i] = tmp;
	  delete[] tmp1;
	}
    }
  else
    {
      for (i = 0; i < rows; i++)
	{
	  tmp1 = value[i];
	  tmp = new T[c];
	  memory_handler(tmp, DM_BM, "set_no_of_columns :: "
			 "Error in memory allocation (tmp)");
	  for (j = 0; j < columns; j++)
	    tmp[j]=tmp1[j];
	  value[i] = tmp;
	  delete[] tmp1;
	}
    }
  columns = c;
}

template < class T >
void base_matrix < T >::
resize(lidia_size_t r, lidia_size_t c)
{
  /**
   ** DESCRIPTION: A.resize(r,c) 
   **              => sets number of columns of matrix A to c and 
   **                 number of rows of matrix A to r.
   ** ERROR: c < 1
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "resize(lidia_size_t, lidia_size_t)", DV_BM + 5);

  if (c < 1 || r < 1)
    lidia_error_handler_para(r, "r", "r > 0",
			     c, "c", "c > 0",
			     "void base_matrix < T >::"
			     "resize(lidia_size_t r, lidia_size_t c)",
			     DM_BM, LBM_ERROR[1]);
  
  if (columns != c)
    set_no_of_columns(c);
  if (rows != r)
    set_no_of_rows(r);
}

template < class T >
void base_matrix < T >::
kill()
{
  /**
   ** DESCRIPTION: A.kill() 
   **              => sets number of columns of matrix A to 1 and 
   **                 number of rows of matrix A to 1.
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "resize(lidia_size_t, lidia_size_t)", DV_BM + 5);

  register lidia_size_t i;
  if (rows != 1 || columns != 1)
    {
      for (i = 0; i < rows; i++)
	delete[] value[i];
      delete[] value;
      
      value = new T *[1];
      memory_handler(value, DM_BM, "kill :: "
		     "Error in memory allocation (value)");
      
      value[0] = new T[1];
      memory_handler(value[0], DM_BM, "kill :: "
		     "Error in memory allocation (value[0])");
      rows = 1;
      columns =1;
    }
}
 
/**
 ** assignments
 **/

template < class T >
void base_matrix < T >::
assign(const base_matrix < T > &M)
{
  /**
   ** DESCRIPTION: A.assign(B);
   **              => A.value[x][y] = B.value[x][y],
   **                 x=0,...,A.rows-1, y=0,...,A.columns-1
   **              => A.rows = B.rows and A.columns = B.columns
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "assign(const base_matrix < T > &)", DV_BM + 6);
  
  if (rows != M.rows)
    set_no_of_rows(M.rows);
  if (columns != M.columns)
    set_no_of_columns(M.columns);
  
  T *tmp, *Mtmp;
  register lidia_size_t i, j;
  for (i = 0; i < rows; i++)
    {
      tmp = value[i];
      Mtmp = M.value[i];
      for (j = 0; j < columns; j++)
	tmp[j] = Mtmp[j];
    }
  storage_mode = M.storage_mode;
  structure_mode = M.structure_mode;
  info_mode = M.info_mode;
  print_mode = M.print_mode;
  lattice_mode = M.lattice_mode;
}

/**
 ** diagonal function
 **/

template < class T >
void base_matrix < T >::
diag(const T &a, const T &b)
{
  /**
   ** DESCRIPTION: A.diag(a,b);
   **              => A.value[i][i] = a, i=0,...,min(columns,rows)
   **              => A.value[i][j] = b, i=0,...,rows and j=0,...,columns 
   **              and i != j
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "diag(const T &, const T &)", DV_BM + 7);

  register lidia_size_t i, j;
  T *tmp;
  
  for (i = 0; i < rows; i++)
    {
      tmp = value[i];
      for (j = 0; j < columns; j++)
	tmp[j] = (i == j) ? a : b;
    }
}

/**
 ** transpose function
 **/

template < class T >
base_matrix < T > base_matrix < T >::
trans() const
{
  /**
   ** DESCRIPTION: AT = A.trans();
   **              => AT.value[x][y] = A.value[y][x],
   **              x=0,...,A.columns-1, y=0,...,A.rows-1
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "trans()", DV_BM + 7);

  register lidia_size_t i, j;
  T *tmp;
  
  base_matrix < T > TRANS(columns, rows);
  for (i = 0; i < rows; i++)
    {
      tmp = value[i];
      for (j = 0; j < columns; j++)
	TRANS.value[j][i] = tmp[j];
    }
  return TRANS;
}

template < class T >
void base_matrix < T >::
trans(const base_matrix < T > &A)
{
  /**
   ** DESCRIPTION: AT.trans(A);
   **              => AT.value[x][y] = A.value[y][x],
   **              x=0,...,A.columns-1, y=0,...,A.rows-1
   **              => AT.rows = A.columns and AT.columns = A.rows
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "trans(const base_matrix < T > &)", DV_BM + 7);
  
  register lidia_size_t i, j;
  T *Atmp;
  
  if (A.value != value)
    {
      if (columns != A.rows)
	set_no_of_columns(A.rows);
      if (rows != A.columns)
	set_no_of_rows(A.columns);
      
      for (i = 0; i < A.rows; i++)
	{
	  Atmp = A.value[i];
	  for (j = 0; j < A.columns; j++)
	    value[j][i] = Atmp[j];
	}
    }
  else
    {
      register lidia_size_t oldrows = rows, oldcolumns = columns;
      if (rows != columns)
	if (columns > rows)
	  {
	    set_no_of_rows(oldcolumns);
	    for (i = 0; i < rows; i++)
	      for (j = 0; j < i; j++)
		::swap(value[i][j], value[j][i]);
	    set_no_of_columns(oldrows);
	  }
	else
	  {
	    set_no_of_columns(oldrows);
	    for (i = 0; i < rows; i++)
	      for (j = 0; j < i; j++)
		::swap(value[i][j], value[j][i]);
	    set_no_of_rows(oldcolumns);
	  }
      else
	{
	  for (i = 0; i < rows; i++)
	    for (j = 0; j < i; j++)
	      ::swap(value[i][j], value[j][i]);
	}
      
    }
}

/**
 ** stream handling - LIDIA 
 **/

template < class T >
void base_matrix < T >::
write_to_stream(ostream &out) const
{
  /**
   ** DESCRIPTION: A.write_to_stream(out);
   **              => writes matrix A to stream out in LiDIA - format.
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "write_to_stream(ostream &)", DV_BM + 8);
  
  register lidia_size_t i, j, col = columns - 1;
  T *tmp;
  
  out << rows << " " << columns << endl;
  for (i = 0; i < rows; i++)
    {
      tmp = value[i];
      for (j = 0; j < col; j++)
	out << tmp[j] << " ";
      out << tmp[j] << endl << flush;
    }
}

template < class T >
void base_matrix < T >::
read_from_stream(istream &in)
{
  /**
   ** DESCRIPTION: A.read_from_stream(in);
   **              => reads matrix A in LiDIA - format from stream in .
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "read_from_stream(istream &)", DV_BM + 8);
  
  lidia_size_t i, j;
  T *tmp;

  in >> i >> j;
  if (i != rows)
    set_no_of_rows(i);
  if (j != columns)
    set_no_of_columns(j);
  
  for (i = 0; i < rows; i++)
    {
      tmp = value[i];
      for (j = 0; j < columns; j++)
	in >> tmp[j];
    }
}

/**
 ** stream handling - MATHEMATICA
 **/

template < class T >
void base_matrix < T >::
write_to_mathematica(ostream &out) const
{
  /**
   ** DESCRIPTION: A.write_to_mathematica(out);
   **              => writes matrix A to stream out in mathematica format
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "write_to_mathematica(ostream &)", DV_BM + 8);
  
  register lidia_size_t i, j, l = columns - 1, k = rows - 1;
  T *tmp;

  out << "{";
  for (i = 0; i < rows; i++)
    {
      tmp = value[i];
      out << "{";
      for (j = 0; j < columns; j++)
	{
	  out << tmp[j];
	  if (j != l)
	    out << ",";
          else
	    if (i != k)
	      out << "}," << endl;
        }
    }
  out << "}}" << endl << flush;
}

template < class T >
void base_matrix < T >::
read_from_mathematica(istream &dz)
{
  /**
   ** DESCRIPTION: A.read_from_mathematica(dz);
   **              => reads matrix A from stream dz in mathematica format
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "read_from_mathematica(istream &dz)", DV_BM + 8);
  
  char c = 0;

  streampos p = dz.tellg();  /* read position */
  
  dz >> ws >> c;
  if (c != '{')
    lidia_error_handler_para("void base_matrix < T >::"
			     "read_from_mathematica(istream &dz)",
			     DM_BM, LBM_ERROR[5]);
  
  register lidia_size_t i1 = 0, i2 = 0, i3 = 1, i, j;
  
  while (!dz.eof() && i3 != 0)
    {
      dz >> ws >> c; 
      if (c == ',')
	i1++;
      if (c == '{')
	{
	  i2++;i3++;
	}
      if (c == '}')
	i3--;
    }
  i1 += i2;
  i1 = i1 / i2;
  
  if (rows != i2)
    set_no_of_rows(i2);
  if (columns != i1)
    set_no_of_columns(i1);
  
  dz.seekg(p,ios::beg);
  
  dz >> ws >> c >> ws >> c;
  for (i = 0; i < i2; i++)
    {
      for (j = 0; j < i1; j++)
	dz >> ws >> value[i][j] >> ws >> c;
      dz >> ws >> c >> ws >> c;
    }
}

/**
 ** stream handling - MAPLE
 **/

template < class T >
void base_matrix < T >::
write_to_maple(ostream &out) const
{
  /**
   ** DESCRIPTION: A.write_to_maple(out);
   **              => writes matrix A to stream out in maple format
   ** VERSION: 2.0
   **/

  debug_handler_l(DM_BM, "in member - function "
		  "write_to_maple(ostream &)", DV_BM + 8);
  
  register lidia_size_t i, j, l = columns - 1, k = rows - 1;
  T *tmp;
  
  out << "array(1 .. " << rows << ", 1 .. " << columns << ",[";
  
  for (i = 0; i < rows; i++)
    {
      tmp = value[i];
      for (j = 0; j < columns; j++)
	{
	  out << "(" << i+1 << ", " << j+1 << ")=" << tmp[j];
	  if (!(j == l && i == k))
	    out << ",";
        }
    }
  out << "]); " << endl << flush;
}

template < class T >
void base_matrix < T >::
read_from_maple(istream &dz)
{
  /**
   ** DESCRIPTION: A.read_from_maple(dz);
   **              => reads matrix A from stream dz in maple format
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "read_from_maple(istream &dz)", DV_BM + 8);
  
  char c = 0;
  while(c != '(' && dz.good())
    dz >> ws >> c;
  
  if (dz.bad())
    lidia_error_handler_para("void base_matrix < T >::"
			     "read_from_maple(istream &dz)", 
			     DM_BM, LBM_ERROR[5]);
  
  register lidia_size_t i, j;
  lidia_size_t startr, startc, endr, endc, x, y;
  T TMP;
  
  /* read row dimension */
  dz >> startr >> ws >> c >> ws >> c >> endr >> ws >> c;
  
  /* read column dimension */ 
  dz >> startc >> ws >> c >> ws >> c >> endc >> ws >> c;
  
  endr = endr - startr + 1;
  if (endr < 0)
    endr = -endr;
  endc = endc - startc + 1;
  if (endc < 0)
    endc = -endc;
  
  if (columns != endc)
    set_no_of_columns(endc);
  if (rows != endr)
    set_no_of_rows(endr);
  
  dz >> ws >> c; 
  
  for (i = 0; i < endc; i++)
    for (j = 0; j < endr; j++) 
      {
	dz >> ws >> c >> x >> ws >> c >> y; 
	dz >> ws >> c >> ws >> c >> ws >> TMP >> ws >> c;
	value[x - startr][y - startc] = TMP;
      }
  dz >> ws >> c >> ws >> c;
}

/**
 ** stream handling - PARI
 **/

template < class T >
void base_matrix < T >::
write_to_gp(ostream &out) const
{
  /**
   ** DESCRIPTION: A.write_to_gp(out);
   **              => writes matrix A to stream out in PARI format
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "write_to_gp(ostream &)", DV_BM + 8);
  
  register lidia_size_t i, j, l = columns - 1, k = rows - 1;
  T *tmp;

  out << "[";
  for (i = 0; i < rows; i++)
    {
      tmp = value[i];
      for (j = 0; j < columns; j++)
	{
	  out << tmp[j];
	  if (j != l)
	    out << ", ";
	}
      if (i != k)
	out << "; ";
    }
  out << "]" << flush;
}

template < class T >
void base_matrix < T >::
read_from_gp(istream &dz)
{
  /**
   ** DESCRIPTION: A.read_from_gp(dz);
   **              => reads matrix A from stream dz in PARI format
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "read_from_gp(istream &)", DV_BM + 8);
  
  char c = 0;
  
  streampos p = dz.tellg();
  
  dz >> ws >> c;
  if (c != '[')
    lidia_error_handler_para("void base_matrix < T >::"
			     "read_from_gp(istream &dz)",
			     DM_BM, LBM_ERROR[5]);
  
  register lidia_size_t i, j, i1 = 0, i2 = 0, i3 = 1;  
  while (!dz.eof() && i3 != 0)
    {
      dz >> ws >> c; 
      if (c == ',')
	i1++;
      if (c == ';')
	i2++;
      if (c == ']')
	i3--;
    }
  i2++;
  i1 += i2;
  i1 = i1 / i2;
  
  if (rows != i2)
    set_no_of_rows(i2);
  if (columns != i1)
    set_no_of_columns(i1);
  
  dz.seekg(p,ios::beg);
  
  dz >> ws >> c;
  
  for (i = 0; i < i2; i++)
    for (j = 0; j < i1; j++)
      dz >> ws >> value[i][j] >> ws >> c;
}

/**
 ** stream handling - KANT
 **/

template < class T >
void base_matrix < T >::
write_to_kash(ostream &out) const
{
  /**
   ** DESCRIPTION: A.write_to_kash(out);
   **              => writes matrix A to stream out in kash format
   ** VERSION: 2.0
   **/

  debug_handler_l(DM_BM, "in member - function "
		  "write_to_kash(ostream &)", DV_BM + 8);
  
  register lidia_size_t i, j, l = columns - 1, k = rows - 1;
  T *tmp;

  out << "LIDIA:=Mat(Z,[";
  for (i = 0; i < rows; i++)
    {
      tmp = value[i];
      out << "[";
      for (j = 0; j < columns; j++)
	{
	  out << tmp[j];
	  if (j != l)
	    out << ",";
          else
	    if (i != k)
	      out << "]," << endl;
        }
    }
  out << "]]);" << endl << flush;
}

template < class T >
void base_matrix < T >::
read_from_kash(istream &dz)
{
  /**
   ** DESCRIPTION: A.read_from_kash(dz);
   **              => reads matrix A from stream dz in kash format
   ** VERSION: 2.0
   **/
  
  debug_handler_l(DM_BM, "in member - function "
		  "read_from_kash(istream &dz)", DV_BM + 8);
  
  char c = 0;
  do
    {
      dz >> ws >> c;
    }
  while(c != 'M' || dz.eof());
  if (c != 'M')
    lidia_error_handler_para("void base_matrix < T >::"
			     "read_from_kash(istream &dz)",
			     DM_BM, LBM_ERROR[5]);

  dz >> ws >> c >> ws >> c >> ws >> c >> ws >> c >> ws >> c >> ws >> c;

  streampos p = dz.tellg();  /* read position */

  register lidia_size_t i1 = 0, i2 = 0, i3 = 1, i, j;
  while (!dz.eof() && i3 != 0)
    {
      dz >> ws >> c; 
      
      if (c == ',')
	i1++;
      if (c == '[')
	{
	  i2++;
	  i3++;
	}
      if (c == ']')
	i3--;
    }
  i1 += i2;
  i1 = i1 / i2;

  if (rows != i2)
    set_no_of_rows(i2);
  if (columns != i1)
    set_no_of_columns(i1);
  
  dz.seekg(p,ios::beg);
  
  dz >> ws >> c;

  for (i = 0; i < i2; i++)
    {
      for (j = 0; j < i1; j++)
	dz >> ws >> value[i][j] >> ws >> c;
      dz >> ws >> c >> ws >> c;
    }
}

#undef DV_BM 
#undef DM_BM 
#undef LBM_ERROR









