/*
//@HEADER
// ************************************************************************
//
//                        Kokkos v. 3.0
//       Copyright (2020) National Technology & Engineering
//               Solutions of Sandia, LLC (NTESS).
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Siva Rajamanickam (srajama@sandia.gov)
//
// ************************************************************************
//@HEADER
*/

#include <Kokkos_Core.hpp>
#include <iostream>
#include <string>

#ifdef KOKKOSKERNELS_ENABLE_TPL_CUSPARSE
#include "cusparse.h"
#endif
#ifndef _SPGEMMHANDLE_HPP
#define _SPGEMMHANDLE_HPP
//#define VERBOSE

namespace KokkosSparse {

// TODO:SPGEMM_KK_MEMORY2 option is for testing in openmp.
// it wont work on cuda, not bind to a test program.
// hidden parameter for StringToSPGEMMAlgorithm for now.
enum SPGEMMAlgorithm {
  /*DEFAULT*/ SPGEMM_KK,
  SPGEMM_KK_DENSE,
  SPGEMM_KK_MEMORY,
  SPGEMM_KK_LP,  // KKVARIANTS
  SPGEMM_CUSPARSE,
  SPGEMM_CUSP,
  SPGEMM_MKL,
  SPGEMM_MKL2PHASE,
  SPGEMM_VIENNA,  // TPLS

  // TRIANGLE COUNTING SPECIALIZED
  SPGEMM_KK_TRIANGLE_AI,  // SPGEMM_KK_TRIANGLE_DEFAULT, SPGEMM_KK_TRIANGLE_MEM,
                          // SPGEMM_KK_TRIANGLE_DENSE,
  SPGEMM_KK_TRIANGLE_IA_UNION,  // SPGEMM_KK_TRIANGLE_DEFAULT_IA_UNION,
                                // SPGEMM_KK_TRIANGLE_MEM_IA_UNION,
                                // SPGEMM_KK_TRIANGLE_DENSE_IA_UNION,
  SPGEMM_KK_TRIANGLE_IA,        // SPGEMM_KK_TRIANGLE_IA_DEFAULT,
                                // SPGEMM_KK_TRIANGLE_IA_MEM,
                                // SPGEMM_KK_TRIANGLE_IA_DENSE,
  SPGEMM_KK_TRIANGLE_LL,
  SPGEMM_KK_TRIANGLE_LU,

  // below research code.
  SPGEMM_KK_MULTIMEM,
  SPGEMM_KK_OUTERMULTIMEM,
  SPGEMM_DEFAULT,
  SPGEMM_DEBUG,
  SPGEMM_SERIAL,
  SPGEMM_KK_CUCKOO,            // USE CUCKOO HASHING
  SPGEMM_KK_TRACKED_CUCKOO,    // USE SCALED CUCKOO HASHING
  SPGEMM_KK_TRACKED_CUCKOO_F,  // USE SCALED FANCY CUCKOO HASHING
  SPGEMM_KK_SPEED,             // DENSE ACCUMULATOR SAME AS SPEED
  SPGEMM_KK_MEMORY_SORTED,
  SPGEMM_KK_MEMORY_TEAM,
  SPGEMM_KK_MEMORY_BIGTEAM,
  SPGEMM_KK_MEMORY_SPREADTEAM,
  SPGEMM_KK_MEMORY_BIGSPREADTEAM,
  SPGEMM_KK_MEMORY2,
  SPGEMM_KK_MEMSPEED
};

enum SPGEMMAccumulator {
  SPGEMM_ACC_DEFAULT,
  SPGEMM_ACC_DENSE,
  SPGEMM_ACC_SPARSE,
};
template <class size_type_, class lno_t_, class scalar_t_, class ExecutionSpace,
          class TemporaryMemorySpace, class PersistentMemorySpace>
class SPGEMMHandle {
 public:
  typedef ExecutionSpace HandleExecSpace;
  typedef TemporaryMemorySpace HandleTempMemorySpace;
  typedef PersistentMemorySpace HandlePersistentMemorySpace;

  typedef typename std::remove_const<size_type_>::type size_type;
  typedef const size_type const_size_type;

  typedef typename std::remove_const<lno_t_>::type nnz_lno_t;
  typedef const nnz_lno_t const_nnz_lno_t;

  typedef typename std::remove_const<scalar_t_>::type nnz_scalar_t;
  typedef const nnz_scalar_t const_nnz_scalar_t;

  typedef typename Kokkos::View<size_type *, HandleTempMemorySpace>
      row_lno_temp_work_view_t;
  typedef typename Kokkos::View<size_type *, HandlePersistentMemorySpace>
      row_lno_persistent_work_view_t;
  typedef typename row_lno_persistent_work_view_t::HostMirror
      row_lno_persistent_work_host_view_t;  // Host view type

  typedef typename Kokkos::View<nnz_scalar_t *, HandleTempMemorySpace>
      scalar_temp_work_view_t;
  typedef typename Kokkos::View<nnz_scalar_t *, HandlePersistentMemorySpace>
      scalar_persistent_work_view_t;

  typedef typename Kokkos::View<nnz_lno_t *, HandleTempMemorySpace>
      nnz_lno_temp_work_view_t;
  typedef typename Kokkos::View<nnz_lno_t *, HandlePersistentMemorySpace>
      nnz_lno_persistent_work_view_t;
  typedef typename nnz_lno_persistent_work_view_t::HostMirror
      nnz_lno_persistent_work_host_view_t;  // Host view type

#ifdef KOKKOSKERNELS_ENABLE_TPL_CUSPARSE
  struct cuSparseHandleType {
    cusparseHandle_t handle;
    cusparseOperation_t transA;
    cusparseOperation_t transB;
    cusparseMatDescr_t a_descr;
    cusparseMatDescr_t b_descr;
    cusparseMatDescr_t c_descr;
    cuSparseHandleType(bool transposeA, bool transposeB) {
      cusparseStatus_t status;
      status = cusparseCreate(&handle);
      if (status != CUSPARSE_STATUS_SUCCESS) {
        throw std::runtime_error("cusparseCreate ERROR\n");
        // return;
      }
      cusparseSetPointerMode(handle, CUSPARSE_POINTER_MODE_HOST);

      if (transposeA) {
        transA = CUSPARSE_OPERATION_TRANSPOSE;
      } else {
        transA = CUSPARSE_OPERATION_NON_TRANSPOSE;
      }
      if (transposeB) {
        transB = CUSPARSE_OPERATION_TRANSPOSE;
      } else {
        transB = CUSPARSE_OPERATION_NON_TRANSPOSE;
      }

      status = cusparseCreateMatDescr(&a_descr);
      if (status != CUSPARSE_STATUS_SUCCESS) {
        throw std::runtime_error("cusparseCreateMatDescr a_descr ERROR\n");
        // return;
      }
      cusparseSetMatType(a_descr, CUSPARSE_MATRIX_TYPE_GENERAL);
      cusparseSetMatIndexBase(a_descr, CUSPARSE_INDEX_BASE_ZERO);

      status = cusparseCreateMatDescr(&b_descr);
      if (status != CUSPARSE_STATUS_SUCCESS) {
        throw std::runtime_error("cusparseCreateMatDescr b_descr ERROR\n");
        // return;
      }
      cusparseSetMatType(b_descr, CUSPARSE_MATRIX_TYPE_GENERAL);
      cusparseSetMatIndexBase(b_descr, CUSPARSE_INDEX_BASE_ZERO);

      status = cusparseCreateMatDescr(&c_descr);
      if (status != CUSPARSE_STATUS_SUCCESS) {
        throw std::runtime_error("cusparseCreateMatDescr  c_descr ERROR\n");
        // return;
      }
      cusparseSetMatType(c_descr, CUSPARSE_MATRIX_TYPE_GENERAL);
      cusparseSetMatIndexBase(c_descr, CUSPARSE_INDEX_BASE_ZERO);
    }
    ~cuSparseHandleType() {
      cusparseDestroyMatDescr(a_descr);
      cusparseDestroyMatDescr(b_descr);
      cusparseDestroyMatDescr(c_descr);
      cusparseDestroy(handle);
    }
  };

  typedef cuSparseHandleType SPGEMMcuSparseHandleType;
#endif
 private:
  SPGEMMAlgorithm algorithm_type;
  SPGEMMAccumulator accumulator_type;
  size_type result_nnz_size;

  bool called_symbolic;
  bool called_numeric;

  int suggested_vector_size;
  int suggested_team_size;
  nnz_lno_t max_nnz_inresult;
  nnz_lno_t max_nnz_compressed_result;

  size_type compressed_b_size;
  row_lno_temp_work_view_t
      compressed_b_rowmap;  // compressed_b_set_begins, compressed_b_set_nexts;
  nnz_lno_temp_work_view_t compressed_b_set_indices, compressed_b_sets;

  row_lno_temp_work_view_t compressed_c_rowmap;

  nnz_lno_temp_work_view_t c_column_indices;

  row_lno_temp_work_view_t tranpose_a_xadj, tranpose_b_xadj, tranpose_c_xadj;
  nnz_lno_temp_work_view_t tranpose_a_adj, tranpose_b_adj, tranpose_c_adj;

  bool transpose_a, transpose_b, transpose_c_symbolic;

  nnz_lno_t num_colors;
  nnz_lno_persistent_work_host_view_t color_xadj;
  nnz_lno_persistent_work_view_t color_adj, vertex_colors;
  nnz_lno_t num_multi_colors, num_used_colors;
  nnz_lno_persistent_work_view_t min_result_row_for_each_row;

  bool create_lower_triangular;
  int sort_lower_triangular;  // 0 - do not sort // 1 - sort // 2 - Algorithm
                              // decides (default)
  int sort_option;
  nnz_lno_persistent_work_view_t lower_triangular_permutation;

  row_lno_persistent_work_view_t lower_triangular_matrix_rowmap;
  nnz_lno_persistent_work_view_t lower_triangular_matrix_entries;

  row_lno_persistent_work_view_t incidence_matrix_row_map;
  nnz_lno_persistent_work_view_t incidence_matrix_entries;
  bool compress_second_matrix;

  double multi_color_scale;
  int mkl_sort_option;
  bool calculate_read_write_cost;

 public:
  std::string coloring_input_file;
  std::string coloring_output_file;

  int min_hash_size_scale;
  double compression_cut_off;
  double first_level_hash_cut_off;
  size_t original_max_row_flops, original_overall_flops;
  row_lno_persistent_work_view_t row_flops;

  size_t compressed_max_row_flops, compressed_overall_flops;

  void set_first_level_hash_cut_off(double first_level_hash_cut_off_) {
    this->first_level_hash_cut_off = first_level_hash_cut_off_;
  }

  double get_first_level_hash_cut_off() {
    return this->first_level_hash_cut_off;
  }

  void set_compression_cut_off(double compression_cut_off_) {
    this->compression_cut_off = compression_cut_off_;
  }

  double get_compression_cut_off() { return this->compression_cut_off; }
  void set_min_hash_size_scale(int scale) { min_hash_size_scale = scale; }
  int get_min_hash_size_scale() { return min_hash_size_scale; }
  void set_read_write_cost_calc(bool read_write_cost_cal) {
    this->calculate_read_write_cost = read_write_cost_cal;
  }
  int get_read_write_cost_calc() { return this->calculate_read_write_cost; }

  typename Kokkos::View<int *, HandlePersistentMemorySpace> persistent_c_xadj,
      persistent_a_xadj, persistent_b_xadj, persistent_a_adj, persistent_b_adj;
  size_t MaxColDenseAcc;
  bool mkl_keep_output;
  bool mkl_convert_to_1base;
  bool is_compression_single_step;

  void set_mkl_sort_option(int mkl_sort_option_) {
    this->mkl_sort_option = mkl_sort_option_;
  }
  int get_mkl_sort_option() { return this->mkl_sort_option; }

#ifdef KOKKOSKERNELS_ENABLE_TPL_CUSPARSE
 private:
  SPGEMMcuSparseHandleType *cuSPARSEHandle;

 public:
#endif

  void set_c_column_indices(nnz_lno_temp_work_view_t c_col_indices_) {
    this->c_column_indices = c_col_indices_;
  }

  nnz_lno_temp_work_view_t get_c_column_indices() {
    return this->c_column_indices;
  }

  void set_color_xadj(nnz_lno_t num_colors_,
                      nnz_lno_persistent_work_host_view_t color_xadj_,
                      nnz_lno_persistent_work_view_t color_adj_,
                      nnz_lno_persistent_work_view_t vertex_colors_,
                      nnz_lno_t num_multi_colors_, nnz_lno_t num_used_colors_) {
    num_colors    = num_colors_;
    color_xadj    = color_xadj_;
    color_adj     = color_adj_;
    vertex_colors = vertex_colors_;

    num_multi_colors = num_multi_colors_;
    num_used_colors  = num_used_colors_;
  }

  /**
   * \brief sets the result nnz size.
   * \param result_nnz_size: size of the output matrix.
   */
  void set_c_nnz(size_type result_nnz_size_) {
    this->result_nnz_size = result_nnz_size_;
  }
  /**
   * \brief returns the result nnz size.
   */
  size_type get_c_nnz() { return this->result_nnz_size; }

  void set_multi_color_scale(double multi_color_scale_) {
    this->multi_color_scale = multi_color_scale_;
  }

  double get_multi_color_scale() { return this->multi_color_scale; }

  void get_color_xadj(nnz_lno_t &num_colors_,
                      nnz_lno_persistent_work_host_view_t &color_xadj_,
                      nnz_lno_persistent_work_view_t &color_adj_,
                      nnz_lno_persistent_work_view_t &vertex_colors_,
                      nnz_lno_t &num_multi_colors_,
                      nnz_lno_t &num_used_colors_) {
    num_colors_       = num_colors;
    color_xadj_       = color_xadj;
    color_adj_        = color_adj;
    num_multi_colors_ = num_multi_colors;
    num_used_colors_  = num_used_colors;
    vertex_colors_    = vertex_colors;
  }

  void set_compressed_c(row_lno_temp_work_view_t compressed_c_rowmap_) {
    compressed_c_rowmap = compressed_c_rowmap_;
  }

  void get_compressed_c(row_lno_temp_work_view_t &compressed_c_rowmap_) {
    compressed_c_rowmap_ = compressed_c_rowmap;
  }

  // TODO: store transpose here.
  void get_c_transpose_symbolic() {}

  void set_sort_lower_triangular(int option) {
    this->sort_lower_triangular = option;
  }
  int get_sort_lower_triangular() { return this->sort_lower_triangular; }

  void set_sort_option(int option) { this->sort_option = option; }
  int get_sort_option() { return this->sort_option; }

  void set_create_lower_triangular(bool option) {
    this->create_lower_triangular = option;
  }
  bool get_create_lower_triangular() { return this->create_lower_triangular; }

  void set_lower_triangular_permutation(nnz_lno_persistent_work_view_t ltp_) {
    this->lower_triangular_permutation = ltp_;
  }

  nnz_lno_persistent_work_view_t get_lower_triangular_permutation() {
    return this->lower_triangular_permutation;
  }

  void set_lower_triangular_matrix(
      row_lno_persistent_work_view_t lower_triangular_matrix_rowmap_,
      nnz_lno_persistent_work_view_t lower_triangular_matrix_entries_) {
    this->lower_triangular_matrix_rowmap  = lower_triangular_matrix_rowmap_;
    this->lower_triangular_matrix_entries = lower_triangular_matrix_entries_;
  }
  void get_lower_triangular_matrix(
      row_lno_persistent_work_view_t &lower_triangular_matrix_rowmap_,
      nnz_lno_persistent_work_view_t &lower_triangular_matrix_entries_) {
    lower_triangular_matrix_rowmap_  = this->lower_triangular_matrix_rowmap;
    lower_triangular_matrix_entries_ = this->lower_triangular_matrix_entries;
  }

  void set_compressed_b(size_type b_nnz_size,
                        row_lno_temp_work_view_t compressed_b_rowmap_,
                        nnz_lno_temp_work_view_t compressed_b_set_indices_,
                        nnz_lno_temp_work_view_t compressed_b_sets_) {
    compressed_b_size        = b_nnz_size;
    compressed_b_rowmap      = compressed_b_rowmap_;
    compressed_b_set_indices = compressed_b_set_indices_;
    compressed_b_sets        = compressed_b_sets_;
  }

  void get_compressed_b(size_type &b_nnz_size,
                        row_lno_temp_work_view_t &compressed_b_rowmap_,
                        nnz_lno_temp_work_view_t &compressed_b_set_indices_,
                        nnz_lno_temp_work_view_t &compressed_b_sets_) {
    b_nnz_size                = compressed_b_size;
    compressed_b_rowmap_      = compressed_b_rowmap;
    compressed_b_set_indices_ = compressed_b_set_indices;
    compressed_b_sets_        = compressed_b_sets;
  }

  /**
   * \brief Default constructor.
   */
  SPGEMMHandle(SPGEMMAlgorithm gs = SPGEMM_DEFAULT)
      : algorithm_type(gs),
        accumulator_type(SPGEMM_ACC_DEFAULT),
        result_nnz_size(0),
        called_symbolic(false),
        called_numeric(false),
        suggested_vector_size(0),
        suggested_team_size(0),
        max_nnz_inresult(0),
        c_column_indices(),
        tranpose_a_xadj(),
        tranpose_b_xadj(),
        tranpose_c_xadj(),
        tranpose_a_adj(),
        tranpose_b_adj(),
        tranpose_c_adj(),
        transpose_a(false),
        transpose_b(false),
        transpose_c_symbolic(false),
        num_colors(0),
        color_xadj(),
        color_adj(),
        vertex_colors(),
        num_multi_colors(0),
        num_used_colors(0),
        min_result_row_for_each_row(),

        create_lower_triangular(false),
        sort_lower_triangular(2),
        sort_option(-1),
        lower_triangular_permutation(),
        lower_triangular_matrix_rowmap(),
        lower_triangular_matrix_entries(),
        incidence_matrix_row_map(),
        incidence_matrix_entries(),
        compress_second_matrix(true),

        multi_color_scale(1),
        mkl_sort_option(7),
        calculate_read_write_cost(false),
        coloring_input_file(""),
        coloring_output_file(""),
        min_hash_size_scale(1),
        compression_cut_off(0.85),
        first_level_hash_cut_off(0.50),
        original_max_row_flops(std::numeric_limits<size_t>::max()),
        original_overall_flops(std::numeric_limits<size_t>::max()),
        persistent_a_xadj(),
        persistent_b_xadj(),
        persistent_a_adj(),
        persistent_b_adj(),
        MaxColDenseAcc(250001),
        mkl_keep_output(true),
        mkl_convert_to_1base(true),
        is_compression_single_step(false)
#ifdef KOKKOSKERNELS_ENABLE_TPL_CUSPARSE
        ,
        cuSPARSEHandle(NULL)
#endif
  {
    if (gs == SPGEMM_DEFAULT) {
      this->choose_default_algorithm();
    }
  }

  virtual ~SPGEMMHandle() {
#ifdef KOKKOSKERNELS_ENABLE_TPL_CUSPARSE
    this->destroy_cuSPARSE_Handle();
#endif
  };

#ifdef KOKKOSKERNELS_ENABLE_TPL_CUSPARSE
  void create_cuSPARSE_Handle(bool transA, bool transB) {
    this->destroy_cuSPARSE_Handle();
    this->cuSPARSEHandle = new cuSparseHandleType(transA, transB);
  }
  void destroy_cuSPARSE_Handle() {
    if (this->cuSPARSEHandle != NULL) {
      delete this->cuSPARSEHandle;
      this->cuSPARSEHandle = NULL;
    }
  }

  SPGEMMcuSparseHandleType *get_cuSparseHandle() {
    return this->cuSPARSEHandle;
  }
#endif
  void choose_default_algorithm() {
#if defined(KOKKOS_ENABLE_SERIAL)
    if (std::is_same<Kokkos::Serial, ExecutionSpace>::value) {
      this->algorithm_type = SPGEMM_SERIAL;
#ifdef VERBOSE
      std::cout << "Serial Execution Space, Default Algorithm: SPGEMM_SERIAL"
                << std::endl;
#endif
    }
#endif

#if defined(KOKKOS_ENABLE_THREADS)
    if (std::is_same<Kokkos::Threads, ExecutionSpace>::value) {
      this->algorithm_type = SPGEMM_SERIAL;
#ifdef VERBOSE
      std::cout << "THREADS Execution Space, Default Algorithm: SPGEMM_SERIAL"
                << std::endl;
#endif
    }
#endif

#if defined(KOKKOS_ENABLE_OPENMP)
    if (std::is_same<Kokkos::OpenMP, ExecutionSpace>::value) {
      this->algorithm_type = SPGEMM_SERIAL;
#ifdef VERBOSE
      std::cout << "OpenMP Execution Space, Default Algorithm: SPGEMM_SERIAL"
                << std::endl;
#endif
    }
#endif

#if defined(KOKKOS_ENABLE_CUDA)
    if (std::is_same<Kokkos::Cuda, ExecutionSpace>::value) {
#ifdef KOKKOSKERNELS_ENABLE_TPL_CUSPARSE
      this->algorithm_type = SPGEMM_CUSPARSE;
#else
      this->algorithm_type = SPGEMM_KK;
#endif
#ifdef VERBOSE
      std::cout << "Cuda Execution Space, Default Algorithm: SPGEMM_CUSPARSE"
                << std::endl;
#endif
    }
#endif

#if defined(KOKKOS_ENABLE_HIP)
    if (std::is_same<Kokkos::Experimental::HIP, ExecutionSpace>::value) {
      this->algorithm_type = SPGEMM_KK;
#ifdef VERBOSE
      std::cout << "HIP Execution Space, Default Algorithm: SPGEMM_KK"
                << std::endl;
#endif
    }
#endif

#if defined(KOKKOS_ENABLE_SYCL)
    if (std::is_same<Kokkos::Experimental::SYCL, ExecutionSpace>::value) {
      this->algorithm_type = SPGEMM_KK;
#ifdef VERBOSE
      std::cout << "SYCL Execution Space, Default Algorithm: SPGEMM_KK"
                << std::endl;
#endif
    }
#endif
  }

  void set_compression(bool compress_second_matrix_) {
    this->compress_second_matrix = compress_second_matrix_;
  }

  bool get_compression() { return this->compress_second_matrix; }

  SPGEMMAccumulator get_accumulator_type() const {
    return this->accumulator_type;
  }
  void set_accumulator_type(const SPGEMMAccumulator &acc_type) {
    this->accumulator_type = acc_type;
  }

  // getters
  SPGEMMAlgorithm get_algorithm_type() const { return this->algorithm_type; }

  bool is_symbolic_called() { return this->called_symbolic; }
  bool is_numeric_called() { return this->called_numeric; }

  nnz_lno_t get_max_result_nnz() const { return this->max_nnz_inresult; }

  nnz_lno_t get_max_compresed_result_nnz() const {
    return this->max_nnz_compressed_result;
  }

  // setters
  void set_algorithm_type(const SPGEMMAlgorithm &sgs_algo) {
    this->algorithm_type = sgs_algo;
  }
  void set_call_symbolic(bool call = true) { this->called_symbolic = call; }
  void set_call_numeric(bool call = true) { this->called_numeric = call; }

  void set_max_result_nnz(nnz_lno_t num_result_nnz_) {
    this->max_nnz_inresult = num_result_nnz_;
  }

  void set_max_compresed_result_nnz(nnz_lno_t num_result_nnz_) {
    this->max_nnz_compressed_result = num_result_nnz_;
  }

  void vector_team_size(int max_allowed_team_size, int &suggested_vector_size_,
                        int &suggested_team_size_, size_type nr,
                        size_type nnz) {
    // suggested_team_size_ =  this->suggested_team_size = 1;
    // suggested_vector_size_=this->suggested_vector_size = 1;
    // return;
    if (this->suggested_team_size && this->suggested_vector_size) {
      // already set in the handle
      suggested_vector_size_ = this->suggested_vector_size;
      suggested_team_size_   = this->suggested_team_size;
      return;
    }

    // otherwise, recompute team_size/vector_size based on heuristic and save
    // them in the handle
    suggested_vector_size_ = KokkosKernels::Impl::kk_get_suggested_vector_size(
        nr, nnz, KokkosKernels::Impl::kk_get_exec_space_type<ExecutionSpace>());
    if (KokkosKernels::Impl::kk_is_gpu_exec_space<ExecutionSpace>())
      suggested_team_size_ = max_allowed_team_size / suggested_vector_size_;
    else
      suggested_team_size = max_allowed_team_size;
    this->suggested_vector_size = suggested_vector_size_;
    this->suggested_team_size   = suggested_vector_size_;
  }

  void set_compression_steps(bool isCompressionSingleStep) {
    this->is_compression_single_step = isCompressionSingleStep;
  }

  void set_min_col_of_row(
      nnz_lno_persistent_work_view_t min_result_row_for_each_row_) {
    this->min_result_row_for_each_row = min_result_row_for_each_row_;
  }

  nnz_lno_persistent_work_view_t get_min_col_of_row() {
    return this->min_result_row_for_each_row;
  }

  bool get_compression_step() { return is_compression_single_step; }
};

inline SPGEMMAlgorithm StringToSPGEMMAlgorithm(std::string &name) {
  if (name == "SPGEMM_DEFAULT")
    return SPGEMM_KK;
  else if (name == "SPGEMM_KK")
    return SPGEMM_KK;
  else if (name == "SPGEMM_KK_MEMORY")
    return SPGEMM_KK_MEMORY;
  else if (name == "SPGEMM_KK_DENSE")
    return SPGEMM_KK_DENSE;
  else if (name == "SPGEMM_KK_LP")
    return SPGEMM_KK_LP;
  else if (name == "SPGEMM_KK_MEMSPEED")
    return SPGEMM_KK;

  else if (name == "SPGEMM_DEBUG")
    return SPGEMM_SERIAL;
  else if (name == "SPGEMM_SERIAL")
    return SPGEMM_SERIAL;
  else if (name == "SPGEMM_CUSPARSE")
    return SPGEMM_CUSPARSE;
  else if (name == "SPGEMM_CUSP")
    return SPGEMM_CUSP;
  else if (name == "SPGEMM_MKL")
    return SPGEMM_MKL;
  else if (name == "SPGEMM_VIENNA")
    return SPGEMM_VIENNA;
  else
    throw std::runtime_error("Invalid SPGEMMAlgorithm name");
}

}  // namespace KokkosSparse

#endif
