/*
 * 
 * Copyright (c) Kresimir Fresl 2002, 2003
 *
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 *
 * Author acknowledges the support of the Faculty of Civil Engineering, 
 * University of Zagreb, Croatia.
 *
 */

#ifndef BOOST_NUMERIC_BINDINGS_CBLAS2_OVERLOADS_HPP
#define BOOST_NUMERIC_BINDINGS_CBLAS2_OVERLOADS_HPP

#include <complex> 
#include <boost/numeric/bindings/atlas/cblas_inc.hpp>
#include <boost/numeric/bindings/traits/type.hpp>


namespace boost { namespace numeric { namespace bindings { 

  namespace atlas { namespace detail {


    // y <- alpha * op (A) * x + beta * y

    inline 
    void gemv (CBLAS_ORDER const Order, 
               CBLAS_TRANSPOSE const TransA, int const M, int const N,
               float const alpha, float const* A, int const lda,
               float const* X, int const incX, 
               float const beta, float* Y, int const incY) 
    {
      cblas_sgemv (Order, TransA, M, N, alpha, A, lda, 
                   X, incX,
                   beta, Y, incY); 
    }
    
    inline 
    void gemv (CBLAS_ORDER const Order, 
               CBLAS_TRANSPOSE const TransA, int const M, int const N,
               double const alpha, double const* A, int const lda,
               double const* X, int const incX, 
               double const beta, double* Y, int const incY) 
    {
      cblas_dgemv (Order, TransA, M, N, alpha, A, lda, 
                   X, incX,
                   beta, Y, incY); 
    }
    
    inline 
    void gemv (CBLAS_ORDER const Order, 
               CBLAS_TRANSPOSE const TransA, int const M, int const N,
               traits::complex_f const& alpha, 
               traits::complex_f const* A, int const lda,
               traits::complex_f const* X, int const incX, 
               traits::complex_f const& beta, 
               traits::complex_f* Y, int const incY) 
    {
      cblas_cgemv (Order, TransA, M, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (A), lda, 
                   static_cast<void const*> (X), incX,
                   static_cast<void const*> (&beta), 
                   static_cast<void*> (Y), incY); 
    }
    
    inline 
    void gemv (CBLAS_ORDER const Order, 
               CBLAS_TRANSPOSE const TransA, int const M, int const N,
               traits::complex_d const& alpha, 
               traits::complex_d const* A, int const lda,
               traits::complex_d const* X, int const incX, 
               traits::complex_d const& beta, 
               traits::complex_d* Y, int const incY) 
    {
      cblas_zgemv (Order, TransA, M, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (A), lda, 
                   static_cast<void const*> (X), incX,
                   static_cast<void const*> (&beta), 
                   static_cast<void*> (Y), incY); 
    }


    // y <- alpha * A * x + beta * y
    // A real symmetric

    inline 
    void symv (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               int const N, float const alpha, float const* A,
               int const lda, float const* X, int const incX,
               float const beta, float* Y, int const incY) 
    {
      cblas_ssymv (Order, Uplo, N, alpha, A, lda, 
                   X, incX, beta, Y, incY);
    }

    inline 
    void symv (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               int const N, double const alpha, double const* A,
               int const lda, double const* X, int const incX,
               double const beta, double* Y, int const incY) 
    {
      cblas_dsymv (Order, Uplo, N, alpha, A, lda, 
                   X, incX, beta, Y, incY);
    }


    // y <- alpha * A * x + beta * y
    // A real symmetric in packed form 

    inline
    void spmv (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               int const N, float const alpha, float const* Ap,
               float const* X, int const incX,
               float const beta, float* Y, int const incY) 
    {
      cblas_sspmv (Order, Uplo, N, alpha, Ap, X, incX, beta, Y, incY);
    }

    inline
    void spmv (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               int const N, double const alpha, double const* Ap,
               double const* X, int const incX,
               double const beta, double* Y, int const incY) 
    {
      cblas_dspmv (Order, Uplo, N, alpha, Ap, X, incX, beta, Y, incY);
    }


    // y <- alpha * A * x + beta * y
    // A complex hermitian 

    inline 
    void hemv (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               int const N, traits::complex_f const& alpha, 
               traits::complex_f const* A, int const lda, 
               traits::complex_f const* X, int const incX,
               traits::complex_f const& beta, 
               traits::complex_f* Y, int const incY) 
    {
      cblas_chemv (Order, Uplo, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (A), lda, 
                   static_cast<void const*> (X), incX, 
                   static_cast<void const*> (&beta), 
                   static_cast<void*> (Y), incY);
    }

    inline 
    void hemv (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               int const N, traits::complex_d const& alpha, 
               traits::complex_d const* A, int const lda, 
               traits::complex_d const* X, int const incX,
               traits::complex_d const& beta, 
               traits::complex_d* Y, int const incY) 
    {
      cblas_zhemv (Order, Uplo, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (A), lda, 
                   static_cast<void const*> (X), incX, 
                   static_cast<void const*> (&beta), 
                   static_cast<void*> (Y), incY);
    }


    // y <- alpha * A * x + beta * y
    // A complex hermitian in packed form 

    inline 
    void hpmv (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               int const N, traits::complex_f const& alpha, 
               traits::complex_f const* Ap, 
               traits::complex_f const* X, int const incX,
               traits::complex_f const& beta, 
               traits::complex_f* Y, int const incY) 
    {
      cblas_chpmv (Order, Uplo, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (Ap), 
                   static_cast<void const*> (X), incX, 
                   static_cast<void const*> (&beta), 
                   static_cast<void*> (Y), incY);
    }

    inline 
    void hpmv (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               int const N, traits::complex_d const& alpha, 
               traits::complex_d const* Ap, 
               traits::complex_d const* X, int const incX,
               traits::complex_d const& beta, 
               traits::complex_d* Y, int const incY) 
    {
      cblas_zhpmv (Order, Uplo, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (Ap), 
                   static_cast<void const*> (X), incX, 
                   static_cast<void const*> (&beta), 
                   static_cast<void*> (Y), incY);
    }


    // A <- alpha * x * y^T + A 
    // .. real types:    calls cblas_xger
    // .. complex types: calls cblas_xgeru

    inline 
    void ger (CBLAS_ORDER const Order, int const M, int const N,
              float const alpha, float const* X, int const incX,
              float const* Y, int const incY, float* A, int const lda)
    {
      cblas_sger (Order, M, N, alpha, X, incX, Y, incY, A, lda); 
    }

    inline 
    void ger (CBLAS_ORDER const Order, int const M, int const N,
              double const alpha, double const* X, int const incX,
              double const* Y, int const incY, double* A, int const lda)
    {
      cblas_dger (Order, M, N, alpha, X, incX, Y, incY, A, lda); 
    }

    inline 
    void ger (CBLAS_ORDER const Order, int const M, int const N,
              traits::complex_f const& alpha, 
              traits::complex_f const* X, int const incX,
              traits::complex_f const* Y, int const incY, 
              traits::complex_f* A, int const lda)
    {
      cblas_cgeru (Order, M, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (X), incX, 
                   static_cast<void const*> (Y), incY, 
                   static_cast<void*> (A), lda); 
    }

    inline 
    void ger (CBLAS_ORDER const Order, int const M, int const N,
              traits::complex_d const& alpha, 
              traits::complex_d const* X, int const incX,
              traits::complex_d const* Y, int const incY, 
              traits::complex_d* A, int const lda)
    {
      cblas_zgeru (Order, M, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (X), incX, 
                   static_cast<void const*> (Y), incY, 
                   static_cast<void*> (A), lda); 
    }

    // A <- alpha * x * y^T + A 
    // .. complex types only 

    inline 
    void geru (CBLAS_ORDER const Order, int const M, int const N,
               traits::complex_f const& alpha, 
               traits::complex_f const* X, int const incX,
               traits::complex_f const* Y, int const incY, 
               traits::complex_f* A, int const lda)
    {
      cblas_cgeru (Order, M, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (X), incX, 
                   static_cast<void const*> (Y), incY, 
                   static_cast<void*> (A), lda); 
    }

    inline 
    void geru (CBLAS_ORDER const Order, int const M, int const N,
               traits::complex_d const& alpha, 
               traits::complex_d const* X, int const incX,
               traits::complex_d const* Y, int const incY, 
               traits::complex_d* A, int const lda)
    {
      cblas_zgeru (Order, M, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (X), incX, 
                   static_cast<void const*> (Y), incY, 
                   static_cast<void*> (A), lda); 
    }
    
    // A <- alpha * x * y^H + A 
    // .. complex types only 

    inline 
    void gerc (CBLAS_ORDER const Order, int const M, int const N,
               traits::complex_f const& alpha, 
               traits::complex_f const* X, int const incX,
               traits::complex_f const* Y, int const incY, 
               traits::complex_f* A, int const lda)
    {
      cblas_cgerc (Order, M, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (X), incX, 
                   static_cast<void const*> (Y), incY, 
                   static_cast<void*> (A), lda); 
    }

    inline 
    void gerc (CBLAS_ORDER const Order, int const M, int const N,
               traits::complex_d const& alpha, 
               traits::complex_d const* X, int const incX,
               traits::complex_d const* Y, int const incY, 
               traits::complex_d* A, int const lda)
    {
      cblas_zgerc (Order, M, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (X), incX, 
                   static_cast<void const*> (Y), incY, 
                   static_cast<void*> (A), lda); 
    }


    // A <- alpha * x * x^T + A 
    // A real symmetric 

    inline 
    void syr (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
              int const N, float const alpha, 
              float const* X, int const incX, float* A, int const lda)
    {
      cblas_ssyr (Order, Uplo, N, alpha, X, incX, A, lda); 
    }

    inline 
    void syr (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
              int const N, double const alpha, 
              double const* X, int const incX, double* A, int const lda)
    {
      cblas_dsyr (Order, Uplo, N, alpha, X, incX, A, lda); 
    }


    // A <- alpha * x * x^T + A 
    // A real symmetric in packed form 
    
    inline 
    void spr (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
              int const N, float const alpha, 
              float const* X, int const incX, float* Ap)
    {
      cblas_sspr (Order, Uplo, N, alpha, X, incX, Ap); 
    }

    inline 
    void spr (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
              int const N, double const alpha, 
              double const* X, int const incX, double* Ap)
    {
      cblas_dspr (Order, Uplo, N, alpha, X, incX, Ap); 
    }


    // A <- alpha * x * y^T + alpha * y * x^T + A 
    // A real symmetric 

    inline 
    void syr2 (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               int const N, float const alpha, 
               float const* X, int const incX, 
               float const* Y, int const incY, 
               float* A, int const lda)
    {
      cblas_ssyr2 (Order, Uplo, N, alpha, X, incX, Y, incY, A, lda); 
    }

    inline 
    void syr2 (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               int const N, double const alpha, 
               double const* X, int const incX, 
               double const* Y, int const incY, 
               double* A, int const lda)
    {
      cblas_dsyr2 (Order, Uplo, N, alpha, X, incX, Y, incY, A, lda); 
    }


    // A <- alpha * x * y^T + alpha * y * x^T + A 
    // A real symmetric in packed form 
    
    inline 
    void spr2 (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               int const N, float const alpha, 
               float const* X, int const incX, 
               float const* Y, int const incY, float* Ap)
    {
      cblas_sspr2 (Order, Uplo, N, alpha, X, incX, Y, incY, Ap); 
    }

    inline 
    void spr2 (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               int const N, double const alpha, 
               double const* X, int const incX, 
               double const* Y, int const incY, double* Ap)
    {
      cblas_dspr2 (Order, Uplo, N, alpha, X, incX, Y, incY, Ap); 
    }


    // A <- alpha * x * x^H + A 
    // A hermitian

    inline 
    void her (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
              int const N, float const alpha, 
              traits::complex_f const* X, int const incX, 
              traits::complex_f* A, int const lda)
    {
      cblas_cher (Order, Uplo, N, alpha, 
                  static_cast<void const*> (X), incX, 
                  static_cast<void*> (A), lda); 
    }

    inline 
    void her (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
              int const N, double const alpha, 
              traits::complex_d const* X, int const incX, 
              traits::complex_d* A, int const lda)
    {
      cblas_zher (Order, Uplo, N, alpha, 
                  static_cast<void const*> (X), incX, 
                  static_cast<void*> (A), lda); 
    }


    // A <- alpha * x * x^H + A 
    // A hermitian in packed form 
    
    inline 
    void hpr (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
              int const N, float const alpha, 
              traits::complex_f const* X, int const incX, 
              traits::complex_f* Ap)
    {
      cblas_chpr (Order, Uplo, N, alpha, 
                  static_cast<void const*> (X), incX, 
                  static_cast<void*> (Ap)); 
    }

    inline 
    void hpr (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
              int const N, double const alpha, 
              traits::complex_d const* X, int const incX, 
              traits::complex_d* Ap)
    {
      cblas_zhpr (Order, Uplo, N, alpha, 
                  static_cast<void const*> (X), incX, 
                  static_cast<void*> (Ap)); 
    }


    // A <- alpha * x * y^H + y * (alpha * x)^H + A 
    // A hermitian

    inline 
    void her2 (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               int const N, traits::complex_f const& alpha, 
               traits::complex_f const* X, int const incX, 
               traits::complex_f const* Y, int const incY, 
               traits::complex_f* A, int const lda)
    {
      cblas_cher2 (Order, Uplo, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (X), incX, 
                   static_cast<void const*> (Y), incY, 
                   static_cast<void*> (A), lda); 
    }

    inline 
    void her2 (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               int const N, traits::complex_d const& alpha, 
               traits::complex_d const* X, int const incX, 
               traits::complex_d const* Y, int const incY, 
               traits::complex_d* A, int const lda)
    {
      cblas_zher2 (Order, Uplo, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (X), incX, 
                   static_cast<void const*> (Y), incY, 
                   static_cast<void*> (A), lda); 
    }


    // A <- alpha * x * y^H + y * (alpha * x)^H + A 
    // A hermitian in packed form 
    
    inline 
    void hpr2 (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               int const N, traits::complex_f const& alpha, 
               traits::complex_f const* X, int const incX, 
               traits::complex_f const* Y, int const incY, 
               traits::complex_f* Ap)
    {
      cblas_chpr2 (Order, Uplo, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (X), incX, 
                   static_cast<void const*> (Y), incY, 
                   static_cast<void*> (Ap)); 
    }

    inline 
    void hpr2 (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               int const N, traits::complex_d const& alpha, 
               traits::complex_d const* X, int const incX, 
               traits::complex_d const* Y, int const incY, 
               traits::complex_d* Ap)
    {
      cblas_zhpr2 (Order, Uplo, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (X), incX, 
                   static_cast<void const*> (Y), incY, 
                   static_cast<void*> (Ap)); 
    }


  }} // namepaces detail & atlas

}}} 


#endif // BOOST_NUMERIC_BINDINGS_CBLAS2_OVERLOADS_HPP
