/*
 * 
 * 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_CBLAS3_OVERLOADS_HPP
#define BOOST_NUMERIC_BINDINGS_CBLAS3_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 {

    // C <- alpha * op (A) * op (B) + beta * C 
  
    inline 
    void gemm (CBLAS_ORDER const Order, 
               CBLAS_TRANSPOSE const TransA, CBLAS_TRANSPOSE const TransB, 
               int const M, int const N, int const K, 
               float const alpha, float const* A, int const lda,
               float const* B, int const ldb, 
               float const beta, float* C, int const ldc) 
    {
      cblas_sgemm (Order, TransA, TransB, M, N, K, 
                   alpha, A, lda, 
                   B, ldb,
                   beta, C, ldc); 
    }

    inline 
    void gemm (CBLAS_ORDER const Order, 
               CBLAS_TRANSPOSE const TransA, CBLAS_TRANSPOSE const TransB, 
               int const M, int const N, int const K, 
               double const alpha, double const* A, int const lda,
               double const* B, int const ldb, 
               double const beta, double* C, int const ldc) 
    {
      cblas_dgemm (Order, TransA, TransB, M, N, K, 
                   alpha, A, lda, 
                   B, ldb,
                   beta, C, ldc); 
    }

    inline 
    void gemm (CBLAS_ORDER const Order, 
               CBLAS_TRANSPOSE const TransA, CBLAS_TRANSPOSE const TransB, 
               int const M, int const N, int const K, 
               traits::complex_f const& alpha, 
               traits::complex_f const* A, int const lda,
               traits::complex_f const* B, int const ldb, 
               traits::complex_f const& beta, 
               traits::complex_f* C, int const ldc) 
    {
      cblas_cgemm (Order, TransA, TransB, M, N, K, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (A), lda, 
                   static_cast<void const*> (B), ldb,
                   static_cast<void const*> (&beta), 
                   static_cast<void*> (C), ldc); 
    }
    
    inline 
    void gemm (CBLAS_ORDER const Order, 
               CBLAS_TRANSPOSE const TransA, CBLAS_TRANSPOSE const TransB, 
               int const M, int const N, int const K, 
               traits::complex_d const& alpha, 
               traits::complex_d const* A, int const lda,
               traits::complex_d const* B, int const ldb, 
               traits::complex_d const& beta, 
               traits::complex_d* C, int const ldc) 
    {
      cblas_zgemm (Order, TransA, TransB, M, N, K, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (A), lda, 
                   static_cast<void const*> (B), ldb,
                   static_cast<void const*> (&beta), 
                   static_cast<void*> (C), ldc); 
    }

    
    // C <- alpha * A * B + beta * C 
    // C <- alpha * B * A + beta * C 
    // A == A^T

    inline 
    void symm (CBLAS_ORDER const Order, CBLAS_SIDE const Side,
               CBLAS_UPLO const Uplo, int const M, int const N, 
               float const alpha, float const* A, int const lda,
               float const* B, int const ldb, 
               float const beta, float* C, int const ldc) 
    {
      cblas_ssymm (Order, Side, Uplo, M, N, 
                   alpha, A, lda, 
                   B, ldb,
                   beta, C, ldc); 
    }
  
    inline 
    void symm (CBLAS_ORDER const Order, CBLAS_SIDE const Side,
               CBLAS_UPLO const Uplo, int const M, int const N, 
               double const alpha, double const* A, int const lda,
               double const* B, int const ldb, 
               double const beta, double* C, int const ldc) 
    {
      cblas_dsymm (Order, Side, Uplo, M, N, 
                   alpha, A, lda, 
                   B, ldb,
                   beta, C, ldc); 
    }
  
    inline 
    void symm (CBLAS_ORDER const Order, CBLAS_SIDE const Side,
               CBLAS_UPLO const Uplo, int const M, int const N, 
               traits::complex_f const& alpha, 
               traits::complex_f const* A, int const lda,
               traits::complex_f const* B, int const ldb, 
               traits::complex_f const& beta, 
               traits::complex_f* C, int const ldc) 
    {
      cblas_csymm (Order, Side, Uplo, M, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (A), lda, 
                   static_cast<void const*> (B), ldb,
                   static_cast<void const*> (&beta), 
                   static_cast<void*> (C), ldc); 
    }
  
    inline 
    void symm (CBLAS_ORDER const Order, CBLAS_SIDE const Side,
               CBLAS_UPLO const Uplo, int const M, int const N, 
               traits::complex_d const& alpha, 
               traits::complex_d const* A, int const lda,
               traits::complex_d const* B, int const ldb, 
               traits::complex_d const& beta, 
               traits::complex_d* C, int const ldc) 
    {
      cblas_zsymm (Order, Side, Uplo, M, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (A), lda, 
                   static_cast<void const*> (B), ldb,
                   static_cast<void const*> (&beta), 
                   static_cast<void*> (C), ldc); 
    }
  

    // C <- alpha * A * B + beta * C 
    // C <- alpha * B * A + beta * C 
    // A == A^H
  
    inline 
    void hemm (CBLAS_ORDER const Order, CBLAS_SIDE const Side,
               CBLAS_UPLO const Uplo, int const M, int const N, 
               traits::complex_f const& alpha, 
               traits::complex_f const* A, int const lda,
               traits::complex_f const* B, int const ldb, 
               traits::complex_f const& beta, 
               traits::complex_f* C, int const ldc) 
    {
      cblas_chemm (Order, Side, Uplo, M, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (A), lda, 
                   static_cast<void const*> (B), ldb,
                   static_cast<void const*> (&beta), 
                   static_cast<void*> (C), ldc); 
    }
  
    inline 
    void hemm (CBLAS_ORDER const Order, CBLAS_SIDE const Side,
               CBLAS_UPLO const Uplo, int const M, int const N, 
               traits::complex_d const& alpha, 
               traits::complex_d const* A, int const lda,
               traits::complex_d const* B, int const ldb, 
               traits::complex_d const& beta, 
               traits::complex_d* C, int const ldc) 
    {
      cblas_zhemm (Order, Side, Uplo, M, N, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (A), lda, 
                   static_cast<void const*> (B), ldb,
                   static_cast<void const*> (&beta), 
                   static_cast<void*> (C), ldc); 
    }


    // C <- alpha * A * A^T + beta * C
    // C <- alpha * A^T * A + beta * C
    // C == C^T

    inline
    void syrk (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               CBLAS_TRANSPOSE const Trans, int const N, int const K,
               float const alpha, float const* A, int const lda,
               float const beta, float* C, int const ldc) 
    {
      cblas_ssyrk (Order, Uplo, Trans, N, K, alpha, A, lda, beta, C, ldc); 
    }

    inline
    void syrk (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               CBLAS_TRANSPOSE const Trans, int const N, int const K,
               double const alpha, double const* A, int const lda,
               double const beta, double* C, int const ldc) 
    {
      cblas_dsyrk (Order, Uplo, Trans, N, K, alpha, A, lda, beta, C, ldc); 
    }

    inline
    void syrk (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               CBLAS_TRANSPOSE const Trans, int const N, int const K,
               traits::complex_f const& alpha, 
               traits::complex_f const* A, int const lda,
               traits::complex_f const& beta, 
               traits::complex_f* C, int const ldc) 
    {
      cblas_csyrk (Order, Uplo, Trans, N, K, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (A), lda, 
                   static_cast<void const*> (&beta), 
                   static_cast<void*> (C), ldc); 
    }

    inline
    void syrk (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               CBLAS_TRANSPOSE const Trans, int const N, int const K,
               traits::complex_d const& alpha, 
               traits::complex_d const* A, int const lda,
               traits::complex_d const& beta, 
               traits::complex_d* C, int const ldc) 
    {
      cblas_zsyrk (Order, Uplo, Trans, N, K, 
                   static_cast<void const*> (&alpha), 
                   static_cast<void const*> (A), lda, 
                   static_cast<void const*> (&beta), 
                   static_cast<void*> (C), ldc); 
    }


    // C <- alpha * A * B^T + conj(alpha) * B * A^T + beta * C
    // C <- alpha * A^T * B + conj(alpha) * B^T * A + beta * C
    // C == C^T

    inline
    void syr2k (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
                CBLAS_TRANSPOSE const Trans, int const N, int const K,
                float const alpha, float const* A, int const lda,
                float const* B, int const ldb,
                float const beta, float* C, int const ldc) 
    {
      cblas_ssyr2k (Order, Uplo, Trans, N, K, 
                    alpha, A, lda, B, ldb, beta, C, ldc); 
    }

    inline
    void syr2k (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
                CBLAS_TRANSPOSE const Trans, int const N, int const K,
                double const alpha, double const* A, int const lda,
                double const* B, int const ldb,
                double const beta, double* C, int const ldc) 
    {
      cblas_dsyr2k (Order, Uplo, Trans, N, K, 
                    alpha, A, lda, B, ldb, beta, C, ldc); 
    }

    inline
    void syr2k (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
                CBLAS_TRANSPOSE const Trans, int const N, int const K,
                traits::complex_f const& alpha, 
                traits::complex_f const* A, int const lda,
                traits::complex_f const* B, int const ldb,
                traits::complex_f const& beta, 
                traits::complex_f* C, int const ldc) 
    {
      cblas_csyr2k (Order, Uplo, Trans, N, K, 
                    static_cast<void const*> (&alpha), 
                    static_cast<void const*> (A), lda, 
                    static_cast<void const*> (B), ldb, 
                    static_cast<void const*> (&beta), 
                    static_cast<void*> (C), ldc); 
    }

    inline
    void syr2k (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
                CBLAS_TRANSPOSE const Trans, int const N, int const K,
                traits::complex_d const& alpha, 
                traits::complex_d const* A, int const lda,
                traits::complex_d const* B, int const ldb,
                traits::complex_d const& beta, 
                traits::complex_d* C, int const ldc) 
    {
      cblas_zsyr2k (Order, Uplo, Trans, N, K, 
                    static_cast<void const*> (&alpha), 
                    static_cast<void const*> (A), lda, 
                    static_cast<void const*> (B), ldb, 
                    static_cast<void const*> (&beta), 
                    static_cast<void*> (C), ldc); 
    }


    // C <- alpha * A * A^H + beta * C
    // C <- alpha * A^H * A + beta * C
    // C == C^H

    inline
    void herk (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               CBLAS_TRANSPOSE const Trans, int const N, int const K,
               float alpha, traits::complex_f const* A, int const lda,
               float beta, traits::complex_f* C, int const ldc) 
    {
      cblas_cherk (Order, Uplo, Trans, N, K, 
                   alpha, static_cast<void const*> (A), lda, 
                   beta, static_cast<void*> (C), ldc); 
    }

    inline
    void herk (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
               CBLAS_TRANSPOSE const Trans, int const N, int const K,
               double alpha, traits::complex_d const* A, int const lda,
               double beta, traits::complex_d* C, int const ldc) 
    {
      cblas_zherk (Order, Uplo, Trans, N, K, 
                   alpha, static_cast<void const*> (A), lda, 
                   beta, static_cast<void*> (C), ldc); 
    }


    // C <- alpha * A * B^H + conj(alpha) * B * A^H + beta * C
    // C <- alpha * A^H * B + conj(alpha) * B^H * A + beta * C
    // C == C^H

    inline
    void her2k (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
                CBLAS_TRANSPOSE const Trans, int const N, int const K,
                traits::complex_f const& alpha, 
                traits::complex_f const* A, int const lda,
                traits::complex_f const* B, int const ldb,
                float beta, traits::complex_f* C, int const ldc) 
    {
      cblas_cher2k (Order, Uplo, Trans, N, K, 
                    static_cast<void const*> (&alpha), 
                    static_cast<void const*> (A), lda, 
                    static_cast<void const*> (B), ldb, 
                    beta, static_cast<void*> (C), ldc); 
    }

    inline
    void her2k (CBLAS_ORDER const Order, CBLAS_UPLO const Uplo,
                CBLAS_TRANSPOSE const Trans, int const N, int const K,
                traits::complex_d const& alpha, 
                traits::complex_d const* A, int const lda,
                traits::complex_d const* B, int const ldb,
                double beta, traits::complex_d* C, int const ldc) 
    {
      cblas_zher2k (Order, Uplo, Trans, N, K, 
                    static_cast<void const*> (&alpha), 
                    static_cast<void const*> (A), lda, 
                    static_cast<void const*> (B), ldb, 
                    beta, static_cast<void*> (C), ldc); 
    }

  
  }} // namepaces detail & atlas

}}} 


#endif // BOOST_NUMERIC_BINDINGS_CBLAS3_OVERLOADS_HPP
