//=============================================================================
/*! _zgbmatrix+zgbmatrix operator */
inline _zgbmatrix operator+(const _zgbmatrix& matA, const zgbmatrix& matB)
{
#ifdef  CPPL_VERBOSE
  std::cerr << "# [MARK] operator+(const _zgbmatrix&, const zgbmatrix&)"
            << std::endl;
#endif//CPPL_VERBOSE
  
#ifdef  CPPL_DEBUG
  if(matA.N!=matB.N || matA.M!=matB.M){
    std::cerr << "[ERROR] operator+(_zgbmatrix&, zgbmatrix&)" << std::endl
              << "These two matrises can not make a summation." << std::endl
              << "Your input was (" << matA.M << "x" << matA.N << ") + ("
              << matB.M << "x" << matB.N << ")." << std::endl;
    exit(1);
  }
#endif//CPPL_DEBUG
  
  if(matA.KL>=matB.KL && matA.KU>=matB.KU){
    for(long i=0; i<matB.M; i++){
      for(long j=std::max(long(0),i-matB.KL); j<std::min(matB.N,i+matB.KU+1); j++){
        matA(i,j)+=matB(i,j);
      }
    }
    
    return matA;
  }
  
  else{
    zgbmatrix newmat(matA.M,matA.N,std::max(matA.KL,matB.KL),std::max(matA.KU,matB.KU));
    newmat.zero();
    
    for(long i=0; i<matA.M; i++){
      for(long j=std::max(long(0),i-matA.KL); j<std::min(matA.N,i+matA.KU+1); j++){
        newmat(i,j)+=matA(i,j);
      }
      for(long j=std::max(long(0),i-matB.KL); j<std::min(matB.N,i+matB.KU+1); j++){
        newmat(i,j)+=matB(i,j);
      }
    }
    
    matA.destroy();
    return _(newmat);
  }
}
//=============================================================================
/*! _zgbmatrix-zgbmatrix operator */
inline _zgbmatrix operator-(const _zgbmatrix& matA, const zgbmatrix& matB)
{
#ifdef  CPPL_VERBOSE
  std::cerr << "# [MARK] operator-(const _zgbmatrix&, const zgbmatrix&)"
            << std::endl;
#endif//CPPL_VERBOSE
  
#ifdef  CPPL_DEBUG
  if(matA.N!=matB.N || matA.M!=matB.M){
    std::cerr << "[ERROR] operator-(_zgbmatrix&, zgbmatrix&)" << std::endl
              << "These two matrises can not make a subtraction." << std::endl
              << "Your input was (" << matA.M << "x" << matA.N << ") - ("
              << matB.M << "x" << matB.N << ")." << std::endl;
    exit(1);
  }
#endif//CPPL_DEBUG
  
  if(matA.KL>=matB.KL && matA.KU>=matB.KU){
    for(long i=0; i<matB.M; i++){
      for(long j=std::max(long(0),i-matB.KL); j<std::min(matB.N,i+matB.KU+1); j++){
        matA(i,j)-=matB(i,j);
      }
    }
    
    return matA;
  }
  
  else{
    zgbmatrix newmat(matA.M,matA.N,std::max(matA.KL,matB.KL),std::max(matA.KU,matB.KU));
    newmat.zero();
    
    for(long i=0; i<matA.M; i++){
      for(long j=std::max(long(0),i-matA.KL); j<std::min(matA.N,i+matA.KU+1); j++){
        newmat(i,j)+=matA(i,j);
      }
      for(long j=std::max(long(0),i-matB.KL); j<std::min(matB.N,i+matB.KU+1); j++){
        newmat(i,j)-=matB(i,j);
      }
    }
    
    return _(newmat);
  }
}
//=============================================================================
/*! _zgbmatrix*zgbmatrix operator */
inline _zgbmatrix operator*(const _zgbmatrix& matA, const zgbmatrix& matB)
{
#ifdef  CPPL_VERBOSE
  std::cerr << "# [MARK] operator*(const _zgbmatrix&, const zgbmatrix&)"
            << std::endl;
#endif//CPPL_VERBOSE
  
#ifdef  CPPL_DEBUG
  if(matA.N!=matB.M){
    std::cerr << "[ERROR] operator*(_zgbmatrix&, zgbmatrix&)" << std::endl
              << "These two matrises can not make a product." << std::endl
              << "Your input was (" << matA.M << "x" << matA.N << ") * ("
              << matB.M << "x" << matB.N << ")." << std::endl;
    exit(1);
  }
#endif//CPPL_DEBUG
  
  zgbmatrix newmat( matA.M, matB.N, matA.KU+matB.KL-1, matA.KL+matB.KU+1 );
  newmat.zero();
  
  for(long i=0; i<newmat.m; i++){
    for(long j=std::max(long(0),i-newmat.kl); j<std::min(newmat.n,i+newmat.ku+1); j++){
      for(long k=std::max( std::max(long(0),i-matA.KL), std::max(long(0),j-matB.KU) );
          k< std::min( std::min(matA.N,i+matA.KU+1), std::min(matB.M,j+matB.KL+1) ); k++){
        newmat(i,j)+= matA(i,k)*matB(k,j);
      }
    }
  }
  
  matA.destroy();
  return _(newmat);
}