/*
 * 
 * Copyright (c) Kresimir Fresl 2002 
 *
 * 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_CBLAS1_OVERLOADS_HPP
#define BOOST_NUMERIC_BINDINGS_CBLAS1_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 {

    // dot <- x^T * y
    // .. real types:    calls cblas_xdot
    // .. complex types: calls cblas_xdotu
    inline 
    float dot (int const N, float const* X, int const incX,
               float const* Y, int const incY) {
      return cblas_sdot (N, X, incX, Y, incY); 
    }
    inline 
    double dot (int const N, double const* X, int const incX,
                double const* Y, int const incY) {
      return cblas_ddot (N, X, incX, Y, incY); 
    }
    inline 
    traits::complex_f 
    dot (int const N, traits::complex_f const* X, int const incX,
         traits::complex_f const* Y, int const incY) {
      traits::complex_f val; 
      cblas_cdotu_sub (N, 
                       static_cast<void const*> (X), incX, 
                       static_cast<void const*> (Y), incY, 
                       static_cast<void*> (&val)); 
      return val; 
    }
    inline 
    traits::complex_d 
    dot (int const N, traits::complex_d const* X, int const incX,
         traits::complex_d const* Y, int const incY) {
      traits::complex_d val; 
      cblas_zdotu_sub (N, 
                       static_cast<void const*> (X), incX, 
                       static_cast<void const*> (Y), incY, 
                       static_cast<void*> (&val)); 
      return val; 
    }

    // dotu <- x^T * y  
    // .. complex types only
    inline 
    void dotu (int const N, traits::complex_f const* X, int const incX,
               traits::complex_f const* Y, int const incY,
               traits::complex_f* val) 
    {
      cblas_cdotu_sub (N, 
                       static_cast<void const*> (X), incX, 
                       static_cast<void const*> (Y), incY, 
                       static_cast<void*> (val)); 
    }
    inline 
    void dotu (int const N, traits::complex_d const* X, int const incX,
               traits::complex_d const* Y, int const incY,
               traits::complex_d* val) 
    {
      cblas_zdotu_sub (N, 
                       static_cast<void const*> (X), incX, 
                       static_cast<void const*> (Y), incY, 
                       static_cast<void*> (val)); 
    }

    // dotc <- x^H * y  
    // .. complex types only 
    inline 
    void dotc (int const N, traits::complex_f const* X, int const incX,
               traits::complex_f const* Y, int const incY,
               traits::complex_f* val) 
    {
      cblas_cdotc_sub (N, 
                       static_cast<void const*> (X), incX, 
                       static_cast<void const*> (Y), incY, 
                       static_cast<void*> (val)); 
    }
    inline 
    void dotc (int const N, traits::complex_d const* X, int const incX,
               traits::complex_d const* Y, int const incY,
               traits::complex_d* val) 
    {
      cblas_zdotc_sub (N, 
                       static_cast<void const*> (X), incX, 
                       static_cast<void const*> (Y), incY, 
                       static_cast<void*> (val)); 
    }

    // nrm2 <- ||x||_2
    inline 
    float nrm2 (int const N, float const* X, int const incX) {
      return cblas_snrm2 (N, X, incX);
    }
    inline 
    double nrm2 (int const N, double const* X, int const incX) {
      return cblas_dnrm2 (N, X, incX);
    }
    inline 
    float nrm2 (int const N, traits::complex_f const* X, int const incX) {
      return cblas_scnrm2 (N, static_cast<void const*> (X), incX);
    }
    inline 
    double nrm2 (int const N, traits::complex_d const* X, int const incX) {
      return cblas_dznrm2 (N, static_cast<void const*> (X), incX);
    }

    // asum <- ||re (x)|| + ||im (x)||
    inline 
    float asum (int const N, float const* X, int const incX) {
      return cblas_sasum (N, X, incX);
    }
    inline 
    double asum (int const N, double const* X, int const incX) {
      return cblas_dasum (N, X, incX);
    }
    inline 
    float asum (int const N, traits::complex_f const* X, int const incX) {
      return cblas_scasum (N, static_cast<void const*> (X), incX);
    }
    inline 
    double asum (int const N, traits::complex_d const* X, int const incX) {
      return cblas_dzasum (N, static_cast<void const*> (X), incX);
    }

    // iamax <- 1st i: max (|re (x_i)| + |im (x_i)|)
    inline 
    CBLAS_INDEX iamax (int const N, float const* X, int const incX) {
      return cblas_isamax (N, X, incX);
    }
    inline 
    CBLAS_INDEX iamax (int const N, double const* X, int const incX) {
      return cblas_idamax (N, X, incX);
    }
    inline 
    CBLAS_INDEX 
    iamax (int const N, traits::complex_f const* X, int const incX) {
      return cblas_icamax (N, static_cast<void const*> (X), incX);
    }
    inline 
    CBLAS_INDEX 
    iamax (int const N, traits::complex_d const* X, int const incX) {
      return cblas_izamax (N, static_cast<void const*> (X), incX);
    }

    // x <-> y
    inline 
    void swap (int const N, float* X, int const incX,
               float* Y, int const incY) {
      cblas_sswap (N, X, incX, Y, incY); 
    }
    inline 
    void swap (int const N, double* X, int const incX,
               double* Y, int const incY) {
      cblas_dswap (N, X, incX, Y, incY); 
    }
    inline 
    void swap (int const N, traits::complex_f* X, int const incX,
               traits::complex_f* Y, int const incY) {
      cblas_cswap (N, 
                   static_cast<void*> (X), incX, 
                   static_cast<void*> (Y), incY); 
    }
    inline 
    void swap (int const N, traits::complex_d* X, int const incX,
               traits::complex_d* Y, int const incY) {
      cblas_zswap (N, 
                   static_cast<void*> (X), incX, 
                   static_cast<void*> (Y), incY); 
    }

    // y <- x
    inline
    void copy (int const N, float const* X, int const incX,
               float* Y, int const incY) {
      cblas_scopy (N, X, incX, Y, incY); 
    }
    inline
    void copy (int const N, double const* X, int const incX,
               double* Y, int const incY) {
      cblas_dcopy (N, X, incX, Y, incY); 
    }
    inline 
    void copy (int const N, traits::complex_f const* X, int const incX,
               traits::complex_f* Y, int const incY) {
      cblas_ccopy (N, 
                   static_cast<void const*> (X), incX, 
                   static_cast<void*> (Y), incY); 
    }
    inline 
    void copy (int const N, traits::complex_d const* X, int const incX,
               traits::complex_d* Y, int const incY) {
      cblas_zcopy (N, 
                   static_cast<void const*> (X), incX, 
                   static_cast<void*> (Y), incY); 
    }

    // y <- alpha * x + y
    inline
    void axpy (int const N, 
               float const alpha, float const* X, int const incX, 
               float* Y, int const incY) 
    {
      cblas_saxpy (N, alpha, X, incX, Y, incY);
    }
    inline
    void axpy (int const N, 
               double const alpha, double const* X, int const incX, 
               double* Y, int const incY) 
    {
      cblas_daxpy (N, alpha, X, incX, Y, incY);
    }
    inline
    void axpy (int const N, 
               traits::complex_f const& alpha, 
               traits::complex_f const* X, int const incX, 
               traits::complex_f* Y, int const incY) 
    {
      cblas_caxpy (N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (X), incX, 
                   static_cast<void*> (Y), incY);
    }
    inline
    void axpy (int const N, 
               traits::complex_d const& alpha, 
               traits::complex_d const* X, int const incX, 
               traits::complex_d* Y, int const incY) 
    {
      cblas_zaxpy (N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (X), incX, 
                   static_cast<void*> (Y), incY);
    }

    // y <- alpha * x + beta * y
    inline
    void axpby (int const N, 
                float const alpha, float const* X, int const incX, 
                float const beta, float* Y, int const incY) 
    {
      catlas_saxpby (N, alpha, X, incX, beta, Y, incY);
    }
    inline
    void axpby (int const N, 
                double const alpha, double const* X, int const incX, 
                double const beta, double* Y, int const incY) 
    {
      catlas_daxpby (N, alpha, X, incX, beta, Y, incY);
    }
    inline
    void axpby (int const N, 
                traits::complex_f const& alpha, 
                traits::complex_f const* X, int const incX, 
                traits::complex_f const& beta, 
                traits::complex_f* Y, int const incY) 
    {
      catlas_caxpby (N, 
                     static_cast<void const*> (&alpha), 
                     static_cast<void const*> (X), incX, 
                     static_cast<void const*> (&beta), 
                     static_cast<void*> (Y), incY);
    }
    inline
    void axpby (int const N, 
                traits::complex_d const& alpha, 
                traits::complex_d const* X, int const incX, 
                traits::complex_d const& beta, 
                traits::complex_d* Y, int const incY) 
    {
      catlas_zaxpby (N, 
                     static_cast<void const*> (&alpha), 
                     static_cast<void const*> (X), incX, 
                     static_cast<void const*> (&beta), 
                     static_cast<void*> (Y), incY);
    }

    // x_i <- alpha for all i
    inline
    void set (int const N, float const alpha, float* X, int const incX) {
      catlas_sset (N, alpha, X, incX); 
    }
    inline
    void set (int const N, double const alpha, double* X, int const incX) {
      catlas_dset (N, alpha, X, incX); 
    }
    inline
    void set (int const N, traits::complex_f const& alpha, 
              traits::complex_f* X, int const incX) {
      catlas_cset (N, static_cast<void const*> (&alpha), 
                   static_cast<void*> (X), incX);
    }
    inline
    void set (int const N, traits::complex_d const& alpha, 
              traits::complex_d* X, int const incX) {
      catlas_zset (N, static_cast<void const*> (&alpha), 
                   static_cast<void*> (X), incX);
    }

    // x <- alpha * x
    inline
    void scal (int const N, float const alpha, float* X, int const incX) {
      cblas_sscal (N, alpha, X, incX); 
    }
    inline
    void scal (int const N, double const alpha, double* X, int const incX) {
      cblas_dscal (N, alpha, X, incX); 
    }
    inline
    void scal (int const N, traits::complex_f const& alpha, 
               traits::complex_f* X, int const incX) {
      cblas_cscal (N, static_cast<void const*> (&alpha), 
                   static_cast<void*> (X), incX);
    }
    inline
    void scal (int const N, float const alpha, 
               traits::complex_f* X, int const incX) {
      cblas_csscal (N, alpha, static_cast<void*> (X), incX);
    }
    inline
    void scal (int const N, traits::complex_d const& alpha, 
               traits::complex_d* X, int const incX) {
      cblas_zscal (N, static_cast<void const*> (&alpha), 
                   static_cast<void*> (X), incX);
    }
    inline
    void scal (int const N, double const alpha, 
               traits::complex_d* X, int const incX) {
      cblas_zdscal (N, alpha, static_cast<void*> (X), incX);
    }

  }} // namepaces detail & atlas

}}} 


#endif // BOOST_NUMERIC_BINDINGS_CBLAS1_OVERLOADS_HPP
