// 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_BLAS_1_CXX

/*
  Functions included in this file:

  xROTG   (GenRot)
  xROTMG  (GenModifRot)
  xROT    (ApplyRot)
  xROTM   (ApplyModifRot)
  xSWAP   (Swap)
  xSCAL   (Mlt)
  xCOPY   (Copy)
  xAXPY   (Add)
  xDOT    (DotProd)
  xDOTU   (DotProd)
  SDSDOT  (ScaledDotProd)
  xDOTC   (DotProdConj)
  xASUM   (Norm1)
  xNRM2   (Norm2)
  IxAMAX  (GetMaxAbsIndex)
*/


extern "C"
{
#include "cblas.h"
}

namespace Seldon
{


 
////////////
 
// GenRot //


 
void GenRot(float& a, float& b, float& c, float& d)
 
{
    cblas_srotg
(&a, &b, &c, &d);
 
}


 
void GenRot(double& a, double& b, double& c, double& d)
 
{
    cblas_drotg
(&a, &b, &c, &d);
 
}


 
// GenRot //
 
////////////



 
/////////////////
 
// GenModifRot //


 
void GenModifRot(float& d1, float& d2,
                   
float& x1, const float& y1,
                   
float* param)
 
{
    cblas_srotmg
(&d1, &d2, &x1, y1, param);
 
}


 
void GenModifRot(double& d1, double& d2,
                   
double& x1, const double& y1,
                   
double* param)
 
{
    cblas_drotmg
(&d1, &d2, &x1, y1, param);
 
}


 
// GenModifRot //
 
/////////////////



 
//////////////
 
// ApplyRot //


 
template <class Allocator>
 
void ApplyRot(Vector<float, VectFull, Allocator>& X,
               
Vector<float, VectFull, Allocator>& Y,
               
const float c, const float s)
 
{
    cblas_srot
(X.GetLength(), X.GetData(), 1,
               Y
.GetData(), 1, c, s);
 
}


 
template <class Allocator>
 
void ApplyRot(Vector<double, VectFull, Allocator>& X,
               
Vector<double, VectFull, Allocator>& Y,
               
const double c, const double s)
 
{
    cblas_drot
(X.GetLength(), X.GetData(), 1,
               Y
.GetData(), 1, c, s);
 
}


 
// ApplyRot //
 
//////////////



 
///////////////////
 
// ApplyModifRot //


 
template <class Allocator>
 
void ApplyModifRot(Vector<float, VectFull, Allocator>& X,
                     
Vector<float, VectFull, Allocator>& Y,
                     
const float* param)
 
{
    cblas_srotm
(X.GetLength(), X.GetData(), 1,
                Y
.GetData(), 1, param);
 
}


 
template <class Allocator>
 
void ApplyModifRot(Vector<double, VectFull, Allocator>& X,
                     
Vector<double, VectFull, Allocator>& Y,
                     
const double* param)
 
{
    cblas_drotm
(X.GetLength(), X.GetData(), 1,
                Y
.GetData(), 1, param);
 
}


 
// ApplyModifRot //
 
///////////////////



 
//////////
 
// Swap //


 
template <class Allocator>
 
void Swap(Vector<float, VectFull, Allocator>& X,
           
Vector<float, VectFull, Allocator>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "Swap(X, Y)", "X <-> Y");
#endif

    cblas_sswap
(X.GetLength(), X.GetData(), 1,
                Y
.GetData(), 1);
 
}


 
template <class Allocator>
 
void Swap(Vector<double, VectFull, Allocator>& X,
           
Vector<double, VectFull, Allocator>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "Swap(X, Y)", "X <-> Y");
#endif

    cblas_dswap
(X.GetLength(), X.GetData(), 1,
                Y
.GetData(), 1);
 
}


 
template <class Allocator>
 
void Swap(Vector<complex<float>, VectFull, Allocator>& X,
           
Vector<complex<float>, VectFull, Allocator>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "Swap(X, Y)", "X <-> Y");
#endif

    cblas_cswap
(X.GetLength(), reinterpret_cast<void*>(X.GetData()), 1,
               
reinterpret_cast<void*>(Y.GetData()), 1);
 
}


 
template <class Allocator>
 
void Swap(Vector<complex<double>, VectFull, Allocator>& X,
           
Vector<complex<double>, VectFull, Allocator>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "Swap(X, Y)", "X <-> Y");
#endif

    cblas_zswap
(X.GetLength(), reinterpret_cast<void*>(X.GetData()), 1,
               
reinterpret_cast<void*>(Y.GetData()), 1);
 
}


 
// Swap //
 
//////////



 
/////////
 
// Mlt //


 
template <class Allocator>
 
void Mlt(const float alpha,
           
Vector<float, VectFull, Allocator>& X)
 
{
    cblas_sscal
(X.GetLength(), alpha, X.GetData(), 1);
 
}


 
template <class Allocator>
 
void Mlt(const double alpha,
           
Vector<double, VectFull, Allocator>& X)
 
{
    cblas_dscal
(X.GetLength(), alpha, X.GetData(), 1);
 
}


 
template <class Allocator>
 
void Mlt(const float alpha,
           
Vector<complex<float>, VectFull, Allocator>& X)
 
{
    cblas_csscal
(X.GetLength(), alpha,
                 
reinterpret_cast<void*>(X.GetData()), 1);
 
}


 
template <class Allocator>
 
void Mlt(const double alpha,
           
Vector<complex<double>, VectFull, Allocator>& X)
 
{
    cblas_zdscal
(X.GetLength(), alpha,
                 
reinterpret_cast<void*>(X.GetData()), 1);
 
}


 
template <class Allocator>
 
void Mlt(const complex<float> alpha,
           
Vector<complex<float>, VectFull, Allocator>& X)
 
{
    cblas_cscal
(X.GetLength(),
               
reinterpret_cast<const void*>(&alpha),
               
reinterpret_cast<void*>(X.GetData()), 1);
 
}


 
template <class Allocator>
 
void Mlt(const complex<double> alpha,
           
Vector<complex<double>, VectFull, Allocator>& X)
 
{
    cblas_zscal
(X.GetLength(),
               
reinterpret_cast<const void*>(&alpha),
               
reinterpret_cast<void*>(X.GetData()), 1);
 
}


 
// Mlt //
 
/////////



 
//////////
 
// Copy //


 
template <class Allocator0, class Allocator1>
 
void Copy(const Vector<float, VectFull, Allocator0>& X,
           
Vector<float, VectFull, Allocator1>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "Copy(X, Y)", "X -> Y");
#endif

    cblas_scopy
(Y.GetLength(),
               
reinterpret_cast<const float*>(X.GetData()), 1,
               
reinterpret_cast<float*>(Y.GetData()), 1);
 
}


 
template <class Allocator0, class Allocator1>
 
void Copy(const Vector<double, VectFull, Allocator0>& X,
           
Vector<double, VectFull, Allocator1>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "Copy(X, Y)", "X -> Y");
#endif

    cblas_dcopy
(Y.GetLength(),
               
reinterpret_cast<const double*>(X.GetData()), 1,
               
reinterpret_cast<double*>(Y.GetData()), 1);
 
}


 
template <class Allocator0, class Allocator1>
 
void Copy(const Vector<complex<float>, VectFull, Allocator0>& X,
           
Vector<complex<float>, VectFull, Allocator1>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "Copy(X, Y)", "X -> Y");
#endif

    cblas_ccopy
(Y.GetLength(),
               
reinterpret_cast<const void*>(X.GetData()), 1,
               
reinterpret_cast<void*>(Y.GetData()), 1);
 
}


 
template <class Allocator0, class Allocator1>
 
void Copy(const Vector<complex<double>, VectFull, Allocator0>& X,
           
Vector<complex<double>, VectFull, Allocator1>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "Copy(X, Y)", "X -> Y");
#endif

    cblas_zcopy
(Y.GetLength(),
               
reinterpret_cast<const void*>(X.GetData()), 1,
               
reinterpret_cast<void*>(Y.GetData()), 1);
 
}


 
// Copy //
 
//////////



 
/////////
 
// Add //


 
template <class Allocator0, class Allocator1>
 
void Add(const float alpha,
           
const Vector<float, VectFull, Allocator0>& X,
           
Vector<float, VectFull, Allocator1>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "Add(alpha, X, Y)");
#endif

    cblas_saxpy
(Y.GetLength(),
                alpha
,
               
reinterpret_cast<const float*>(X.GetData()), 1,
               
reinterpret_cast<float*>(Y.GetData()), 1);
 
}


 
template <class Allocator0, class Allocator1>
 
void Add(const double alpha,
           
const Vector<double, VectFull, Allocator0>& X,
           
Vector<double, VectFull, Allocator1>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "Add(alpha, X, Y)");
#endif

    cblas_daxpy
(Y.GetLength(),
                alpha
,
               
reinterpret_cast<const double*>(X.GetData()), 1,
               
reinterpret_cast<double*>(Y.GetData()), 1);
 
}


 
template <class Allocator0, class Allocator1>
 
void Add(const complex<float> alpha,
           
const Vector<complex<float>, VectFull, Allocator0>& X,
           
Vector<complex<float>, VectFull, Allocator1>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "Add(alpha, X, Y)");
#endif

    cblas_caxpy
(Y.GetLength(),
               
reinterpret_cast<const void*>(&alpha),
               
reinterpret_cast<const void*>(X.GetData()), 1,
               
reinterpret_cast<float*>(Y.GetData()), 1);
 
}


 
template <class Allocator0, class Allocator1>
 
void Add(const complex<double> alpha,
           
const Vector<complex<double>, VectFull, Allocator0>& X,
           
Vector<complex<double>, VectFull, Allocator1>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "Add(alpha, X, Y)");
#endif

    cblas_zaxpy
(Y.GetLength(),
               
reinterpret_cast<const void*>(&alpha),
               
reinterpret_cast<const void*>(X.GetData()), 1,
               
reinterpret_cast<double*>(Y.GetData()), 1);
 
}


 
// Add //
 
/////////



 
/////////////
 
// DotProd //


 
template <class Allocator0, class Allocator1>
 
float DotProd(const Vector<float, VectFull, Allocator0>& X,
               
const Vector<float, VectFull, Allocator1>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "DotProd(X, Y)", "dot(X, Y)");
#endif

   
return cblas_sdot(Y.GetLength(),
                     
reinterpret_cast<const float*>(X.GetData()), 1,
                     
reinterpret_cast<const float*>(Y.GetData()), 1);
 
}


 
template <class Allocator0, class Allocator1>
 
double DotProd(const Vector<double, VectFull, Allocator0>& X,
                 
const Vector<double, VectFull, Allocator1>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "DotProd(X, Y)", "dot(X, Y)");
#endif

   
return cblas_ddot(Y.GetLength(),
                     
reinterpret_cast<const double*>(X.GetData()), 1,
                     
reinterpret_cast<const double*>(Y.GetData()), 1);
 
}


 
template <class Allocator0, class Allocator1>
  complex
<float>
 
DotProd(const Vector<complex<float>, VectFull, Allocator0>& X,
         
const Vector<complex<float>, VectFull, Allocator1>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "DotProd(X, Y)", "dot(X, Y)");
#endif

    complex
<float> dotu;
    cblas_cdotu_sub
(Y.GetLength(),
                   
reinterpret_cast<const void*>(X.GetData()), 1,
                   
reinterpret_cast<const void*>(Y.GetData()), 1,
                   
reinterpret_cast<void*>(&dotu));
   
return dotu;
 
}


 
template <class Allocator0, class Allocator1>
  complex
<double>
 
DotProd(const Vector<complex<double>, VectFull, Allocator0>& X,
         
const Vector<complex<double>, VectFull, Allocator1>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "DotProd(X, Y)", "dot(X, Y)");
#endif

    complex
<double> dotu;
    cblas_zdotu_sub
(Y.GetLength(),
                   
reinterpret_cast<const void*>(X.GetData()), 1,
                   
reinterpret_cast<const void*>(Y.GetData()), 1,
                   
reinterpret_cast<void*>(&dotu));
   
return dotu;
 
}


 
// DotProd //
 
/////////////



 
///////////////////
 
// SCALEDDOTPROD //


 
template <class Allocator0, class Allocator1>
 
float ScaledDotProd(const float alpha,
                     
const Vector<float, VectFull, Allocator0>& X,
                     
const Vector<float, VectFull, Allocator1>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "ScaledDotProd(X, Y)", "dot(X, Y)");
#endif

   
return cblas_sdsdot(Y.GetLength(), alpha,
                       
reinterpret_cast<const float*>(X.GetData()), 1,
                       
reinterpret_cast<const float*>(Y.GetData()), 1);
 
}


 
// SCALEDDOTPROD //
 
///////////////////



 
/////////////////
 
// DotProjConj //


 
template <class Allocator0, class Allocator1>
  complex
<float>
 
DotProdConj(const Vector<complex<float>, VectFull, Allocator0>& X,
             
const Vector<complex<float>, VectFull, Allocator1>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "DotProdConj(X, Y)", "dot(X, Y)");
#endif

    complex
<float> dotc;
    cblas_cdotc_sub
(Y.GetLength(),
                   
reinterpret_cast<const void*>(X.GetData()), 1,
                   
reinterpret_cast<const void*>(Y.GetData()), 1,
                   
reinterpret_cast<void*>(&dotc));
   
return dotc;
 
}


 
template <class Allocator0, class Allocator1>
  complex
<double>
 
DotProdConj(const Vector<complex<double>, VectFull, Allocator0>& X,
             
const Vector<complex<double>, VectFull, Allocator1>& Y)
 
{

#ifdef SELDON_CHECK_BOUNDS
   
CheckDim(X, Y, "DotProdConj(X, Y)", "dot(X, Y)");
#endif

    complex
<double> dotc;
    cblas_zdotc_sub
(Y.GetLength(),
                   
reinterpret_cast<const void*>(X.GetData()), 1,
                   
reinterpret_cast<const void*>(Y.GetData()), 1,
                   
reinterpret_cast<void*>(&dotc));
   
return dotc;
 
}


 
// DotProdConj //
 
/////////////////



 
///////////
 
// Norm1 //


 
template <class Allocator>
 
float Norm1(const Vector<float, VectFull, Allocator>& X)
 
{
   
return cblas_sasum(X.GetLength(),
                       
reinterpret_cast<const float*>(X.GetData()), 1);
 
}


 
template <class Allocator>
 
double Norm1(const Vector<double, VectFull, Allocator>& X)
 
{
   
return cblas_dasum(X.GetLength(),
                       
reinterpret_cast<const double*>(X.GetData()), 1);
 
}


 
template <class Allocator>
 
float Norm1(const Vector<complex<float>, VectFull, Allocator>& X)
 
{
   
return cblas_scasum(X.GetLength(),
                       
reinterpret_cast<const void*>(X.GetData()), 1);
 
}


 
template <class Allocator>
 
double Norm1(const Vector<complex<double>, VectFull, Allocator>& X)
 
{
   
return cblas_dzasum(X.GetLength(),
                       
reinterpret_cast<const void*>(X.GetData()), 1);
 
}


 
// Norm1 //
 
///////////



 
///////////
 
// Norm2 //


 
template <class Allocator>
 
float Norm2(const Vector<float, VectFull, Allocator>& X)
 
{
   
return cblas_snrm2(X.GetLength(),
                       
reinterpret_cast<const float*>(X.GetData()), 1);
 
}


 
template <class Allocator>
 
double Norm2(const Vector<double, VectFull, Allocator>& X)
 
{
   
return cblas_dnrm2(X.GetLength(),
                       
reinterpret_cast<const double*>(X.GetData()), 1);
 
}


 
template <class Allocator>
 
float Norm2(const Vector<complex<float>, VectFull, Allocator>& X)
 
{
   
return cblas_scnrm2(X.GetLength(),
                       
reinterpret_cast<const void*>(X.GetData()), 1);
 
}


 
template <class Allocator>
 
double Norm2(const Vector<complex<double>, VectFull, Allocator>& X)
 
{
   
return cblas_dznrm2(X.GetLength(),
                       
reinterpret_cast<const void*>(X.GetData()), 1);
 
}


 
// Norm2 //
 
///////////



 
////////////////////
 
// GetMaxAbsIndex //


 
template <class Allocator>
  size_t
GetMaxAbsIndex(const Vector<float, VectFull, Allocator>& X)
 
{
   
return cblas_isamax(X.GetLength(),
                       
reinterpret_cast<const float*>(X.GetData()), 1);
 
}


 
template <class Allocator>
  size_t
GetMaxAbsIndex(const Vector<double, VectFull, Allocator>& X)
 
{
   
return cblas_idamax(X.GetLength(),
                       
reinterpret_cast<const double*>(X.GetData()), 1);
 
}
 
 
 
template <class Allocator>
  size_t
GetMaxAbsIndex(const Vector<complex<float>, VectFull, Allocator>& X)
 
{
   
return cblas_icamax(X.GetLength(),
                       
reinterpret_cast<const void*>(X.GetData()), 1);
 
}


 
template <class Allocator>
  size_t
 
GetMaxAbsIndex(const Vector<complex<double>, VectFull, Allocator>& X)
 
{
   
return cblas_izamax(X.GetLength(),
                       
reinterpret_cast<const void*>(X.GetData()), 1);
 
}


 
// GetMaxAbsIndex //
 
////////////////////


} // namespace Seldon.

#define SELDON_FILE_BLAS_1_CXX
#endif