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

/*
  Functions defined in this file:

  alpha.X -> X
  Mlt(alpha, X)

  alpha.X + Y -> Y
  Add(alpha, X, Y)
 
  X -> Y
  Copy(X, Y)
 
  X <-> Y
  Swap(X, Y)
 
  X.Y
  DotProd(X, Y)
  DotProdConj(X, Y)
 
  ||X||
  Norm1(X)
  Norm2(X)
  GetMaxAbsIndex(X)
 
  Omega*X
  GenRot(x, y, cos, sin)
  ApplyRot(x, y, cos, sin)
 
*/


namespace Seldon
{


 
/////////
 
// MLT //


 
template <class T0,
           
class T1, class Storage1, class Allocator1>
 
void Mlt(const T0 alpha,
           
Vector<T1, Storage1, Allocator1>& X)  throw()
 
{
    X
*= alpha;
 
}


 
// MLT //
 
/////////



 
/////////
 
// ADD //


 
template <class T0,
           
class T1, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2>
 
void Add(const T0 alpha,
           
const Vector<T1, Storage1, Allocator1>& X,
           
Vector<T2, Storage2, Allocator2>& Y)  throw(WrongDim, NoMemory)
 
{
   
if (alpha != T0(0))
     
{
        T1 alpha_
= alpha;

       
int ma = X.GetM();
       
#ifdef SELDON_CHECK_BOUNDS
       
CheckDim(X, Y, "Add(alpha, X, Y)");
#endif

       
for (int i = 0; i < ma; i++)
          Y
(i) += alpha_ * X(i);
     
}
 
}
 
 
 
template <class T0,
           
class T1, class Allocator1,
           
class T2, class Allocator2>
 
void Add(const T0 alpha,
           
const Vector<T1, VectSparse, Allocator1>& X,
           
Vector<T2, VectSparse, Allocator2>& Y)  throw(WrongDim, NoMemory)
 
{
   
if (alpha != T0(0))
     
{
       
Vector<T1, VectSparse, Allocator1> Xalpha = X;
       
Xalpha *= alpha;
        Y
.AddInteractionRow(Xalpha.GetSize(),
                           
Xalpha.GetIndex(), Xalpha.GetData(), true);
     
}
 
}


 
// ADD //
 
/////////
 
 
 
 
//////////
 
// COPY //

 
 
template <class T1, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2>
 
void Copy(const Vector<T1, Storage1, Allocator1>& X,
           
Vector<T2, Storage2, Allocator2>& Y)
 
{
    Y
.Copy(X);
 
}
 
 
 
// COPY //
 
//////////
 
 
 
 
//////////
 
// SWAP //

 
 
template <class T1, class Storage1, class Allocator1,
           
class Storage2, class Allocator2>
 
void Swap(Vector<T1, Storage1, Allocator1>& X,
           
Vector<T1, Storage2, Allocator2>& Y)
 
{
   
int nx = X.GetM();
    T1
* data = X.GetData();
    X
.Nullify();
    X
.SetData(Y.GetM(), Y.GetData());
    Y
.Nullify();
    Y
.SetData(nx, data);
 
}
 
 
 
template <class T1, class Allocator1, class Allocator2>
 
void Swap(Vector<T1, VectSparse, Allocator1>& X,
           
Vector<T1, VectSparse, Allocator2>& Y)
 
{
   
int nx = X.GetM();
    T1
* data = X.GetData();
   
int* index = X.GetIndex();
    X
.Nullify();
    X
.SetData(Y.GetM(), Y.GetData(), Y.GetIndex());
    Y
.Nullify();
    Y
.SetData(nx, data, index);
 
}
 
 
 
// SWAP //
 
//////////
 
 
 
 
/////////////
 
// DOTPROD //
 
 
 
//! Scalar product between two vectors.
 
template<class T1, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2>
  T1
DotProd(const Vector<T1, Storage1, Allocator1>& X,
             
const Vector<T2, Storage2, Allocator2>& Y)
 
{
    T1 value
(0);

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

   
for (int i = 0; i < X.GetM(); i++)
      value
+= X(i) * Y(i);
   
   
return value;
 
}
 
 
 
//! Scalar product between two vectors.
 
template<class T1, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2>
  T1
DotProdConj(const Vector<T1, Storage1, Allocator1>& X,
                 
const Vector<T2, Storage2, Allocator2>& Y)
 
{
   
return DotProd(X, Y);
 
}
 
 
 
//! Scalar product between two vectors.
 
template<class T1, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2>
  complex
<T1> DotProdConj(const Vector<complex<T1>, Storage1, Allocator1>& X,
                         
const Vector<T2, Storage2, Allocator2>& Y)
 
{
    complex
<T1> value(0);

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

   
for (int i = 0; i < X.GetM(); i++)
      value
+= conj(X(i)) * Y(i);
   
   
return value;
 
}
 
 
 
//! Scalar product between two sparse vectors.
 
template<class T1, class Allocator1,
           
class T2, class Allocator2>
  T1
DotProd(const Vector<T1, VectSparse, Allocator1>& X,
             
const Vector<T2, VectSparse, Allocator2>& Y)
 
{
    T1 value
(0);

   
int size_x = X.GetSize();
   
int size_y = Y.GetSize();
   
int kx = 0, ky = 0, pos_x;
   
while (kx < size_x)
     
{
        pos_x
= X.Index(kx);
       
while (ky < size_y && Y.Index(ky) < pos_x)
          ky
++;
       
       
if (ky < size_y && Y.Index(ky) == pos_x)
          value
+= X.Value(kx) * Y.Value(ky);
       
        kx
++;
     
}
   
   
return value;
 
}
 
 
 
//! Scalar product between two sparse vectors.
 
template<class T1, class Allocator1,
           
class T2, class Allocator2>
  complex
<T1>
 
DotProdConj(const Vector<complex<T1>, VectSparse, Allocator1>& X,
             
const Vector<T2, VectSparse, Allocator2>& Y)
 
{
    complex
<T1> value(0);
   
   
int size_x = X.GetSize();
   
int size_y = Y.GetSize();
   
int kx = 0, ky = 0, pos_x;
   
while (kx < size_x)
     
{
        pos_x
= X.Index(kx);
       
while (ky < size_y && Y.Index(ky) < pos_x)
          ky
++;
       
       
if (ky < size_y && Y.Index(ky) == pos_x)
          value
+= conj(X.Value(kx)) * Y.Value(ky);
       
        kx
++;
     
}
   
   
return value;
 
}
 
 
 
// DOTPROD //
 
/////////////
 
 
 
 
///////////
 
// NORM1 //
 
 
 
template<class T1, class Storage1, class Allocator1>
  T1
Norm1(const Vector<T1, Storage1, Allocator1>& X)
 
{
    T1 value
(0);
   
   
for (int i = 0; i < X.GetM(); i++)
      value
+= abs(X(i));
   
   
return value;
 
}
 
 
 
template<class T1, class Storage1, class Allocator1>
  T1
Norm1(const Vector<complex<T1>, Storage1, Allocator1>& X)
 
{
    T1 value
(0);
   
   
for (int i = 0; i < X.GetM(); i++)
      value
+= abs(X(i));
   
   
return value;
 
}
 
 
 
template<class T1, class Allocator1>
  T1
Norm1(const Vector<T1, VectSparse, Allocator1>& X)
 
{
    T1 value
(0);
   
   
for (int i = 0; i < X.GetSize(); i++)
      value
+= abs(X.Value(i));
   
   
return value;
 
}
 
 
 
template<class T1, class Allocator1>
  T1
Norm1(const Vector<complex<T1>, VectSparse, Allocator1>& X)
 
{
    T1 value
(0);
   
   
for (int i = 0; i < X.GetSize(); i++)
      value
+= abs(X.Value(i));
   
   
return value;
 
}
 
 
 
// NORM1 //
 
///////////
 
 
 
 
///////////
 
// NORM2 //
 
 
 
template<class T1, class Storage1, class Allocator1>
  T1
Norm2(const Vector<T1, Storage1, Allocator1>& X)
 
{
    T1 value
(0);
   
   
for (int i = 0; i < X.GetM(); i++)
      value
+= X(i) * X(i);
   
   
return sqrt(value);
 
}
 
 
 
template<class T1, class Storage1, class Allocator1>
  T1
Norm2(const Vector<complex<T1>, Storage1, Allocator1>& X)
 
{
    T1 value
(0);
   
   
for (int i = 0; i < X.GetM(); i++)
      value
+= real(X(i) * conj(X(i)));
   
   
return sqrt(value);
 
}
 
 
 
template<class T1, class Allocator1>
  T1
Norm2(const Vector<T1, VectSparse, Allocator1>& X)
 
{
    T1 value
(0);
   
   
for (int i = 0; i < X.GetSize(); i++)
      value
+= X.Value(i) * X.Value(i);
   
   
return sqrt(value);
 
}
 
 
 
template<class T1, class Allocator1>
  T1
Norm2(const Vector<complex<T1>, VectSparse, Allocator1>& X)
 
{
    T1 value
(0);
   
   
for (int i = 0; i < X.GetSize(); i++)
      value
+= real(X.Value(i) * conj(X.Value(i)));
   
   
return sqrt(value);
 
}
 
 
 
// NORM2 //
 
///////////
 
 
 
 
////////////////////
 
// GETMAXABSINDEX //
 
 
 
template<class T, class Storage, class Allocator>
 
int GetMaxAbsIndex(const Vector<T, Storage, Allocator>& X)
 
{
   
return X.GetNormInfIndex();
 
}
 
 
 
// GETMAXABSINDEX //
 
////////////////////
 
 
 
 
//////////////
 
// APPLYROT //
 
 
 
//! Computation of rotation between two points.
 
template<class T>
 
void GenRot(T& a_in, T& b_in, T& c_, T& s_)
 
{
   
// Old BLAS version.
    T roe
;
   
if (abs(a_in) > abs(b_in))
      roe
= a_in;
   
else
      roe
= b_in;
     
    T scal
= abs(a_in) + abs(b_in);
    T r
, z;
   
if (scal != T(0))
     
{
        T a_scl
= a_in / scal;
        T b_scl
= b_in / scal;
        r
= scal * sqrt(a_scl * a_scl + b_scl * b_scl);
       
if (roe < T(0))
          r
*= T(-1);
       
        c_
= a_in / r;
        s_
= b_in / r;
        z
= T(1);
       
if (abs(a_in) > abs(b_in))
          z
= s_;
       
else if (abs(b_in) >= abs(a_in) && c_ != T(0))
          z
= T(1) / c_;
     
}
   
else
     
{
        c_
= T(1);
        s_
= T(0);
        r
= T(0);
        z
= T(0);
     
}
    a_in
= r;
    b_in
= z;
 
}
 
 
 
//! Computation of rotation between two points.
 
template<class T>
 
void GenRot(complex<T>& a_in, complex<T>& b_in, T& c_, complex<T>& s_)
 
{
     
    T a
= abs(a_in), b = abs(b_in);
   
if (a == T(0))
     
{
        c_
= T(0);
        s_
= complex<T>(1, 0);
        a_in
= b_in;
     
}
   
else
     
{
        T scale
= a + b;
        T a_scal
= abs(a_in / scale);
        T b_scal
= abs(b_in / scale);
        T norm
= sqrt(a_scal * a_scal + b_scal * b_scal) * scale;
       
        c_
= a / norm;
        complex
<T> alpha = a_in / a;
        s_
= alpha * conj(b_in) / norm;
        a_in
= alpha * norm;
     
}
    b_in
= complex<T>(0, 0);
 
}
 
 
 
//! Rotation of a point in 2-D.
 
template<class T>
 
void ApplyRot(T& x, T& y, const T c_, const T s_)
 
{
    T temp
= c_ * x + s_ * y;
    y
= c_ * y - s_ * x;
    x
= temp;
 
}
 
 
 
//! Rotation of a complex point in 2-D.
 
template<class T>
 
void ApplyRot(complex<T>& x, complex<T>& y,
               
const T& c_, const complex<T>& s_)
 
{
    complex
<T> temp = s_ * y + c_ * x;
    y
= -conj(s_) * x + c_ * y;
    x
= temp;
 
}
 
 
 
// APPLYROT //
 
//////////////
 
 
 
 
//////////////
 
// CHECKDIM //


 
//! Checks the compatibility of the dimensions.
 
/*! Checks that X + Y is possible according to the dimensions of
    the vectors X and Y. If the dimensions are incompatible,
    an exception is raised (a WrongDim object is thrown).
    \param X vector.
    \param Y vector.
    \param function (optional) function in which the compatibility is checked.
    Default: "".
    \param op (optional) operation to be performed on the vectors.
    Default: "X + Y".
  */

 
template <class T0, class Storage0, class Allocator0,
           
class T1, class Storage1, class Allocator1>
 
void CheckDim(const Vector<T0, Storage0, Allocator0>& X,
               
const Vector<T1, Storage1, Allocator1>& Y,
               
string function = "", string op = "X + Y")
 
{
   
if (X.GetLength() != Y.GetLength())
     
throw WrongDim(function, string("Operation ") + op
                     
+ string(" not permitted:")
                     
+ string("\n     X (") + to_str(&X) + string(") is a ")
                     
+ string("vector of length ") + to_str(X.GetLength())
                     
+ string(";\n     Y (") + to_str(&Y) + string(") is a ")
                     
+ string("vector of length ") + to_str(Y.GetLength())
                     
+ string("."));
 
}


 
// CHECKDIM //
 
//////////////


 
 
///////////////
 
// CONJUGATE //
 
 
 
//! Sets a vector to its conjugate.
 
template<class T, class Prop, class Allocator>
 
void Conjugate(Vector<T, Prop, Allocator>& X)
 
{
   
for (int i = 0; i < X.GetM(); i++)
      X
(i) = conj(X(i));
 
}
 
 
 
//! Sets a vector to its conjugate.
 
template<class T, class Allocator>
 
void Conjugate(Vector<T, VectSparse, Allocator>& X)
 
{
   
for (int i = 0; i < X.GetSize(); i++)
      X
.Value(i) = conj(X.Value(i));
 
}
 
 
 
// CONJUGATE //
 
///////////////
 
 
} // namespace Seldon.

#define SELDON_FILE_FUNCTIONS_VECTOR_CXX
#endif