text: /*
   * (C) Copyright 2013 ECMWF.
   *
   * This software is licensed under the terms of the Apache Licence Version 2.0
   * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
   * In applying this licence, ECMWF does not waive the privileges and immunities
   * granted to it by virtue of its status as an intergovernmental organisation
   * nor does it submit to any jurisdiction.
   */
  
  #pragma once
  
  #include "eckit/config/Configuration.h"
  #include "eckit/linalg/SparseMatrix.h"
  
  #include "atlas/linalg/Indexing.h"
  #include "atlas/linalg/View.h"
  #include "atlas/linalg/sparse/Backend.h"
  #include "atlas/runtime/Exception.h"
  #include "atlas/util/Config.h"
  
  namespace atlas {
  namespace linalg {
  
  using SparseMatrix  = eckit::linalg::SparseMatrix;
  using Configuration = eckit::Configuration;
  
  template <typename Matrix, typename SourceView, typename TargetView>
  void sparse_matrix_multiply(const Matrix& matrix, const SourceView& src, TargetView& tgt);
  
  template <typename Matrix, typename SourceView, typename TargetView>
  void sparse_matrix_multiply(const Matrix& matrix, const SourceView& src, TargetView& tgt, const Configuration& config);
  
  template <typename Matrix, typename SourceView, typename TargetView>
  void sparse_matrix_multiply(const Matrix& matrix, const SourceView& src, TargetView& tgt, Indexing);
  
  template <typename Matrix, typename SourceView, typename TargetView>
  void sparse_matrix_multiply(const Matrix& matrix, const SourceView& src, TargetView& tgt, Indexing,
                              const Configuration& config);
  
  class SparseMatrixMultiply {
  public:
      SparseMatrixMultiply() = default;
      SparseMatrixMultiply(const std::string& backend): backend_{backend} {}
      SparseMatrixMultiply(const sparse::Backend& backend): backend_(backend) {}
  
      template <typename Matrix, typename SourceView, typename TargetView>
      void operator()(const Matrix& matrix, const SourceView& src, TargetView& tgt) const {
          sparse_matrix_multiply(matrix, src, tgt, backend());
      }
  
      template <typename Matrix, typename SourceView, typename TargetView>
      void operator()(const Matrix& matrix, const SourceView& src, TargetView& tgt, Indexing indexing) const {
          sparse_matrix_multiply(matrix, src, tgt, indexing, backend());
      }
  
      const sparse::Backend& backend() const { return backend_; }
  
  private:
      sparse::Backend backend_;
  };
  
  namespace sparse {
  
  // Template class which needs (full or partial) specialization for concrete template parameters
  template <typename Backend, Indexing, int Rank, typename SourceValue, typename TargetValue>
  struct SparseMatrixMultiply {
      static void apply(const SparseMatrix&, const View<SourceValue, Rank>&, View<TargetValue, Rank>&,
                        const Configuration&) {
          throw_NotImplemented("SparseMatrixMultiply needs a template specialization with the implementation", Here());
      }
  };
  }  // namespace sparse
  
  }  // namespace linalg
  }  // namespace atlas
  
  #include "SparseMatrixMultiply.tcc"
  #include "SparseMatrixMultiply_EckitLinalg.h"
  #include "SparseMatrixMultiply_OpenMP.h"
  