<|start_filename|>rokko/lapack/htebz.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_HTEBZ_HPP
#define ROKKO_LAPACK_HTEBZ_HPP

#include <complex>
#include <lapacke.h>
#undef I
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>
#include "complex_cast.hpp"
#include <rokko/alias_template_function.hpp>

namespace rokko {
namespace lapack {

namespace {

template<typename T> struct htebz_dispatch;

template<>
struct htebz_dispatch<float> {
  template<typename VECTOR, typename VECTOR_INT>
  static lapack_int htebz(char range, char order, lapack_int n, float vl, float vu, lapack_int il, lapack_int iu, float abstol,
                          VECTOR& d, VECTOR& e, lapack_int& m, lapack_int& nsplit, VECTOR& w, VECTOR_INT& iblock, VECTOR_INT& isplit) {
    return LAPACKE_sstebz(range, order, n, vl, vu, il, iu, abstol, storage(d), storage(e), &m, &nsplit, storage(w), storage(iblock), storage(isplit));
  }
};

template<>
struct htebz_dispatch<double> {
  template<typename VECTOR, typename VECTOR_INT>
  static lapack_int htebz(char range, char order, lapack_int n, double vl, double vu, lapack_int il, lapack_int iu, double abstol,
                          VECTOR& d, VECTOR& e, lapack_int& m, lapack_int& nsplit, VECTOR& w, VECTOR_INT& iblock, VECTOR_INT& isplit) {
    return LAPACKE_dstebz(range, order, n, vl, vu, il, iu, abstol, storage(d), storage(e), &m, &nsplit, storage(w), storage(iblock), storage(isplit));
  }
};

template<>
struct htebz_dispatch<std::complex<float>> {
  template<typename VECTOR, typename VECTOR_INT>
  static lapack_int htebz(char range, char order, lapack_int n, float vl, float vu, lapack_int il, lapack_int iu, float abstol,
                          VECTOR& d, VECTOR& e, lapack_int& m, lapack_int& nsplit, VECTOR& w, VECTOR_INT& iblock, VECTOR_INT& isplit) {
    return LAPACKE_cstebz(range, order, n, vl, vu, il, iu, abstol, storage(d), storage(e), &m, &nsplit, storage(w), storage(iblock), storage(isplit));
  }
};

template<>
struct htebz_dispatch<std::complex<double>> {
  template<typename VECTOR, typename VECTOR_INT>
  static lapack_int htebz(char range, char order, lapack_int n, double vl, double vu, lapack_int il, lapack_int iu, double abstol,
                          VECTOR& d, VECTOR& e, lapack_int& m, lapack_int& nsplit, VECTOR& w, VECTOR_INT& iblock, VECTOR_INT& isplit) {
    return LAPACKE_zstebz(range, order, n, vl, vu, il, iu, abstol, storage(d), storage(e), &m, &nsplit, storage(w), storage(iblock), storage(isplit));
  }
};

} // end of anonymous namespace

template<typename T, typename VECTOR, typename VECTOR_INT>
lapack_int htebz(char range, char order, T vl, T vu, lapack_int il, lapack_int iu, T abstol,
                 VECTOR& d, VECTOR& e, lapack_int& m, lapack_int& nsplit, VECTOR& w, VECTOR_INT& iblock, VECTOR_INT& isplit) {
  static_assert(std::is_same<value_t<VECTOR>, T>::value, "");

  lapack_int n = size(d);
  if (size(e) != (n-1))
    throw std::invalid_argument("vector e size mismatch");
  if (size(w) != n)
    throw std::invalid_argument("vector w size mismatch");
  return htebz_dispatch<value_t<VECTOR>>::
    htebz(range, order, n, vl, vu, il, iu, abstol, d, e, m, nsplit, w, iblock, isplit);
}

// use all (without range, vl, vu, il, iu)
template<typename T, typename VECTOR, typename VECTOR_INT>
lapack_int htebz(char order, T abstol,
                 VECTOR& d, VECTOR& e, lapack_int& m, lapack_int& nsplit, VECTOR& w, VECTOR_INT& iblock, VECTOR_INT& isplit) {
  constexpr real_t<VECTOR> real_zero = 0;
  return htebz('A', order, real_zero, real_zero, 0, 0, abstol, d, e, m, nsplit, w, iblock, isplit);
}

// use vl, vu (without range, il, iu)
template<typename T, typename VECTOR, typename VECTOR_INT>
lapack_int htebz(char order, T vl, T vu, T abstol,
                 VECTOR& d, VECTOR& e, lapack_int& m, lapack_int& nsplit, VECTOR& w, VECTOR_INT& iblock, VECTOR_INT& isplit) {
  return htebz('V', order, vl, vu, 0, 0, abstol, d, e, m, nsplit, w, iblock, isplit);
}

// use il, iu (without range, vl, vu)
template<typename T, typename VECTOR, typename VECTOR_INT>
lapack_int htebz(char order, lapack_int il, lapack_int iu, T abstol,
                 VECTOR& d, VECTOR& e, lapack_int& m, lapack_int& nsplit, VECTOR& w, VECTOR_INT& iblock, VECTOR_INT& isplit) {
  constexpr real_t<VECTOR> real_zero = 0;
  return htebz('I', order, real_zero, real_zero, il, iu, abstol, d, e, m, nsplit, w, iblock, isplit);
}

ALIAS_TEMPLATE_FUNCTION(stebz, htebz);

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_HTEBZ_HPP


<|start_filename|>rokko/pyrokko_distributed_crs_matrix.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_DISTRIBUTED_CRS_MATRIX_HPP
#define PYROKKO_DISTRIBUTED_CRS_MATRIX_HPP

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#include <rokko/pyrokko_communicator.hpp>
#include <rokko/pyrokko_mapping_1d.hpp>
#include <rokko/distributed_crs_matrix.hpp>
#include <rokko/utility/tuple_to_array.hpp>

namespace rokko {

class wrap_distributed_crs_matrix : public rokko::distributed_crs_matrix {
public:
  explicit wrap_distributed_crs_matrix(wrap_mapping_1d const& map, int num_entries_per_row)
    : distributed_crs_matrix(static_cast<mapping_1d>(map), num_entries_per_row) {}

  void insert(int row, std::vector<int> const& cols, std::vector<double> const& values) const {
    rokko::distributed_crs_matrix::insert(row, cols, values);
  }

  ~wrap_distributed_crs_matrix() = default;

};


} // end namespace rokko

#endif // PYROKKO_DISTRIBUTED_CRS_MATRIX_HPP


<|start_filename|>benchmark/no_rokko/sparse_heisenberg_file_mpi/slepc_crs.cpp<|end_filename|>
#include <slepceps.h>
#include <petscblaslapack.h>
#include <vector>
#include <rokko/utility/lattice.hpp>

#undef __FUNCT__
#define __FUNCT__ "main"
int main(int argc,char **argv)
{
  Mat            A;               /* operator matrix */
  EPS            eps;             /* eigenproblem solver context */
  EPSType        type;
  PetscMPIInt    rank;
  PetscInt       nev;
  PetscErrorCode ierr;
  double init_tick, initend_tick, gen_tick, diag_tick, end_tick;

  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  MPI_Barrier(MPI_COMM_WORLD);
  init_tick = MPI_Wtime();
  SlepcInitialize(&argc, &argv, (char*)0, 0);
  ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
  MPI_Barrier(MPI_COMM_WORLD);
  initend_tick = MPI_Wtime();

  std::string lattice_file("xyz.dat");
  if (argc >= 2) lattice_file = argv[1];
  int L;
  std::vector<std::pair<int, int>> lattice;
  rokko::read_lattice_file(lattice_file, L, lattice);
  int dim = 1 << L;

  // Create Hermitean matrix
  MPI_Barrier(MPI_COMM_WORLD);
  gen_tick = MPI_Wtime();
  ierr = MatCreate(PETSC_COMM_WORLD, &A); CHKERRQ(ierr);
  ierr = MatSetSizes(A, PETSC_DECIDE, PETSC_DECIDE, dim, dim); CHKERRQ(ierr);
  ierr = MatSetFromOptions(A); CHKERRQ(ierr);
  const int NumEntriesPerRow = lattice.size() + 1;
  ierr = MatSeqAIJSetPreallocation(A, NumEntriesPerRow, NULL); CHKERRQ(ierr);
  ierr = MatMPIAIJSetPreallocation(A, NumEntriesPerRow, NULL, NumEntriesPerRow, NULL); CHKERRQ(ierr);
  ierr = MatSetUp(A); CHKERRQ(ierr);

  PetscInt Istart, Iend;
  ierr = MatGetOwnershipRange(A, &Istart, &Iend); CHKERRQ(ierr);

  std::vector<PetscInt> cols;
  std::vector<double> values;
  cols.reserve(NumEntriesPerRow);
  values.reserve(NumEntriesPerRow);

  for (int row=Istart; row<Iend; ++row) {
    cols.clear();
    values.clear();
    double diag = 0.;
    for (int l=0; l<lattice.size(); ++l) {
      int i = lattice[l].first;
      int j = lattice[l].second;
      int m1 = 1 << i;
      int m2 = 1 << j;
      int m3 = m1 + m2;
      if (((row & m3) == m1) || ((row & m3) == m2)) {  // when (bit i == 1, bit j == 0) or (bit i == 0, bit j == 1)
        cols.emplace_back(row^m3);
        values.emplace_back(0.5);
        diag += -0.25;
      } else {
        diag += 0.25;
      }
    }
    if (diag != 0.) {
      cols.emplace_back(row);
      values.emplace_back(diag);
    }
    ierr = MatSetValues(A, 1, &row, cols.size(), cols.data(), values.data(), ADD_VALUES); CHKERRQ(ierr);
  }

  ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
  ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
  //ierr = MatGetLocalSize(A, &n, NULL); CHKERRQ(ierr);
  //MatView(A, PETSC_VIEWER_STDOUT_WORLD);

  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                Create the eigensolver and set various options
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  /*
     Create eigensolver context
  */
  MPI_Barrier(MPI_COMM_WORLD);
  diag_tick = MPI_Wtime();
  ierr = EPSCreate(PETSC_COMM_WORLD, &eps); CHKERRQ(ierr);
  /*
     Set operators. In this case, it is a standard eigenvalue problem
  */
  ierr = EPSSetOperators(eps, A, NULL); CHKERRQ(ierr);
  ierr = EPSSetProblemType(eps, EPS_HEP); CHKERRQ(ierr);
  //ierr = EPSSetDimensions(eps, 10, PETSC_DECIDE, PETSC_DECIDE); CHKERRQ(ierr);
  //char routine_name[] = "lobpcg";
  //ierr = EPSSetType(eps,routine_name); CHKERRQ(ierr);
  /*
     Set solver parameters at runtime
  */
  ierr = EPSSetFromOptions(eps); CHKERRQ(ierr);

  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      Solve the eigensystem
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  ierr = EPSSolve(eps); CHKERRQ(ierr);
  MPI_Barrier(MPI_COMM_WORLD);
  end_tick = MPI_Wtime();

  /*
     Optional: Get some information from the solver and display it
  */
  ierr = EPSGetType(eps,&type); CHKERRQ(ierr);
  ierr = PetscPrintf(PETSC_COMM_WORLD,"solution method: %s\n\n",type); CHKERRQ(ierr);
  ierr = EPSGetDimensions(eps,&nev,NULL,NULL); CHKERRQ(ierr);
  ierr = PetscPrintf(PETSC_COMM_WORLD,"number of requested eigenvalues: %D\n",nev); CHKERRQ(ierr);
  int num_conv;
  EPSGetConverged(eps, &num_conv);
  PetscScalar eval_r, eval_i;
  if (rank == 0) {
    std::cout << "number of converged eigenpairs = " << num_conv << std::endl;
    for (int i=0; i<num_conv; ++i) {
      EPSGetEigenvalue(eps, i, &eval_r, &eval_i);
      std::cout << ' ' << eval_r;
    }
    std::cout << std::endl;
    std::cout << "init_time = " << initend_tick - init_tick << std::endl
	      << "gen_time = " << diag_tick - gen_tick << std::endl
	      << "diag_time = " << end_tick - diag_tick << std::endl;
  }
  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    Display solution and clean up
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  ///ierr = EPSValuesView(eps,NULL); CHKERRQ(ierr);
  ierr = EPSDestroy(&eps); CHKERRQ(ierr);
  ierr = MatDestroy(&A); CHKERRQ(ierr);
  ierr = SlepcFinalize();
  MPI_Finalize();
  return 0;
}


<|start_filename|>rokko/collective.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2016 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_COLLECTIVE_H
#define ROKKO_COLLECTIVE_H

#include <rokko/eigen_matrix.h>
#include <rokko/distributed_matrix.h>

#ifdef __cplusplus
extern "C" {
#endif

void rokko_gather(struct rokko_distributed_matrix matrix, double* array, int root);

void rokko_scatter(double* global_array, struct rokko_distributed_matrix matrix, int root);

void rokko_gather_eigen_matrix(struct rokko_distributed_matrix matrix, struct rokko_eigen_matrix lmatrix, int root);
void rokko_scatter_eigen_matrix(struct rokko_eigen_matrix lmatrix, struct rokko_distributed_matrix matrix, int root);

void rokko_all_gather(struct rokko_distributed_matrix matrix, double* array);

#ifdef __cplusplus
}
#endif

#endif /* ROKKO_COLLECTIVE_H */


<|start_filename|>rokko/scalapack/pdelget.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <rokko/scalapack/scalapack_interface.h>

double cscalapack_pdelget(char scope, char top, const double* A, int ia, int ja, const int* descA) {
  double alpha;
  int ia_f = ia + 1;
  int ja_f = ja + 1;
  SCALAPACK_pdelget(&scope, &top, &alpha, A, &ia_f, &ja_f, descA);
  return alpha;
}


<|start_filename|>rokko/utility/laplacian_mfree.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_LAPLACIAN_MFREE_HPP
#define ROKKO_UTILITY_LAPLACIAN_MFREE_HPP

#include <rokko/distributed_mfree.hpp>

namespace rokko {

class laplacian_mfree : public rokko::distributed_mfree_default {
public:
  laplacian_mfree(int dim, MPI_Comm comm = MPI_COMM_WORLD)
    : laplacian_mfree(dim, rokko::mpi_comm{comm}) {}

  laplacian_mfree(int dim, rokko::mpi_comm const& comm)
    : distributed_mfree_default(dim, mpi_comm{comm}),
      nprocs(get_mpi_comm().get_nprocs()), myrank(get_mpi_comm().get_myrank()),
      num_local_rows_(get_num_local_rows()), end_k_(num_local_rows_ - 1),
      need_send_recv_(get_num_local_rows() != dim),
      is_first_proc(start_row() == 0), is_last_proc(end_row() == dim),
      previous_rank_(previous_rank()), next_rank_(next_rank()) {}

  laplacian_mfree(int dim, int num_local_rows, rokko::mpi_comm const& comm)
    : distributed_mfree_default(dim, num_local_rows, mpi_comm{comm}),
      nprocs(get_mpi_comm().get_nprocs()), myrank(get_mpi_comm().get_myrank()),
      num_local_rows_(get_num_local_rows()), end_k_(num_local_rows_ - 1),
      need_send_recv_(get_num_local_rows() != dim),
      is_first_proc(start_row() == 0), is_last_proc(end_row() == dim),
      previous_rank_(previous_rank()), next_rank_(next_rank()) {}

  ~laplacian_mfree() = default;

  int next_rank() {
    const int myrank = get_mpi_comm().get_myrank();
    const int nprocs = get_mpi_comm().get_nprocs();

    Eigen::VectorXi target(get_mpi_comm().get_nprocs());

    MPI_Allgather(&num_local_rows_, 1, MPI_INT,
                  target.data(), 1, MPI_INT,
                  get_mpi_comm().get_comm());

    if (is_last_proc)  return -1;

    for (int rank = myrank+1; rank < nprocs; ++rank)
      if (target(rank) != 0)  return rank;  // if num_local_rows is not 0

    return -2;
  }

  int previous_rank() {
    const int myrank = get_mpi_comm().get_myrank();
    const int nprocs = get_mpi_comm().get_nprocs();

    Eigen::VectorXi target(get_mpi_comm().get_nprocs());

    MPI_Allgather(&num_local_rows_, 1, MPI_INT,
                  target.data(), 1, MPI_INT,
                  get_mpi_comm().get_comm());

    if (is_first_proc)  return -1;

    for (int rank = myrank-1; rank >= 0; --rank)
      if (target(rank) != 0)  return rank;  // if num_local_rows is not 0

    return -2;
  }

  void multiply(const double *const x, double *const y) const override {
    if (num_local_rows_ == 0) return;

    double buf_m, buf_p;
    MPI_Status status_m, status_p;

    if ((!is_first_proc) && need_send_recv_) {
      MPI_Send(x, 1, MPI_DOUBLE, previous_rank_, 0, get_comm());
      MPI_Recv(&buf_m, 1, MPI_DOUBLE, previous_rank_, 0, get_comm(), &status_m);
    }

    if ((!is_last_proc) && need_send_recv_) {
      MPI_Recv(&buf_p, 1, MPI_DOUBLE, next_rank_, 0, get_comm(), &status_p);
      MPI_Send(&x[end_k_], 1, MPI_DOUBLE, next_rank_, 0, get_comm());
    }

    if (is_first_proc) {
      if (num_local_rows_ > 1) {
        y[0] = x[0] - x[1];
        if (need_send_recv_) y[end_k_] = - x[end_k_ - 1] + 2 * x[end_k_] - buf_p;
      } else {
        y[0] = x[0] - buf_p;
      }
    }

    if (is_last_proc) {
      if (num_local_rows_ > 1) {
        if (need_send_recv_) y[0] = - buf_m + 2 * x[0] - x[1];
        y[end_k_] = 2 * x[end_k_] - x[end_k_ - 1];
      } else {
        y[end_k_] = 2 * x[end_k_] - buf_m;
      }
    }
    if (!(is_first_proc || is_last_proc)) { // neither first or last process
      if (num_local_rows_ > 1) {
        y[0] = - buf_m + 2 * x[0] - x[1];
        y[end_k_] = - x[end_k_ - 1] + 2 * x[end_k_] - buf_p;
      } else {
        y[0] = - buf_m + 2 * x[0] - buf_p;
      }
    }
    // from 1 to end-1
    for (int k=1; k<end_k_; ++k) {
      y[k] = - x[k-1] + 2 * x[k] - x[k+1];
    }
  }

  void fill_diagonal(double *const x) const override {
    if (num_local_rows_ == 0) return;

    if (is_first_proc)  x[0] = 1.;

    for(int k=is_first_proc ? 1 : 0; k<num_local_rows_; ++k)
      x[k] = 2.;
  }

private:
  int nprocs, myrank;
  int num_local_rows_, end_k_;
  bool need_send_recv_;
  bool is_first_proc, is_last_proc;
  int previous_rank_, next_rank_;
};

} // namespace rokko

#endif // ROKKO_UTILITY_LAPLACIAN_MFREE_HPP


<|start_filename|>rokko/scalapack/pstebz_work.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <rokko/scalapack/scalapack_interface.h>

#define CSCALAPACK_PSTEBZ_WORK_IMPL(NAMES, NAMEL, TYPE) \
int cscalapack_## NAMES ##_work(int ictxt, char range, char order, int n, \
                                TYPE vl, TYPE vu, int il, int iu, \
                                TYPE abstol, const TYPE* d, const TYPE* e, int* m, int* nsplit, \
                                TYPE* w, int* iblock, int* isplit, \
                                TYPE* work, int lwork, int* iwork, int liwork) { \
  int info; \
  ROKKO_GLOBAL(NAMES, NAMEL) (&ictxt, &range, &order, &n, \
                              &vl, &vu, &il, &iu, \
                              &abstol, d, e, m, nsplit, \
                              w, iblock, isplit, \
                              work, &lwork, iwork, &liwork, &info); \
  return info; \
}

CSCALAPACK_PSTEBZ_WORK_IMPL(psstebz, PSSTEBZ, float)
CSCALAPACK_PSTEBZ_WORK_IMPL(pdstebz, PDSTEBZ, double)

#undef CSCALAPACK_PSTEBZ_WORK_IMPL


<|start_filename|>rokko/scalapack/psyevx.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_PSYEVX_HPP
#define ROKKO_SCALAPACK_PSYEVX_HPP

#include <rokko/cscalapack.h>
#include <rokko/eigen3.hpp>
#include <rokko/lapack/storage.hpp>
#include <rokko/lapack/complex_cast.hpp>
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>

namespace rokko {
namespace scalapack {

using rokko::lapack::storage;
using rokko::lapack::complex_cast;

namespace {

inline int psyevx_dispatch(char jobz, char range, char uplo, int n, float* A, int ia, int ja, const int* descA,
                           float vl, float vu, int il, int iu,
                           float abstol, int& m, int& nz,
                           float* w, float orfac, float* Z, int iz, int jz, const int* descZ,
                           float* work, int lwork, int* iwork, int liwork,
                           int* ifail, int* iclustr, float* gap) {
  return cscalapack_pssyevx_work(jobz, range, uplo, n, A, ia, ja, descA, vl, vu, il, iu, abstol, &m, &nz, w, orfac, Z, iz, jz, descZ,
                                 work, lwork, iwork, liwork,
                                 ifail, iclustr, gap);
}

inline int psyevx_dispatch(char jobz, char range, char uplo, int n, float* A, int ia, int ja, const int* descA,
                           float vl, float vu, int il, int iu,
                           float abstol, int& m, int& nz,
                           float* w, float orfac, float* Z, int iz, int jz, const int* descZ,
                           int* ifail, int* iclustr, float* gap) {
  return cscalapack_pssyevx(jobz, range, uplo, n, A, ia, ja, descA, vl, vu, il, iu, abstol, &m, &nz, w, orfac, Z, iz, jz, descZ,
                            ifail, iclustr, gap);
}

inline int psyevx_dispatch(char jobz, char range, char uplo, int n, double* A, int ia, int ja, const int* descA,
                           double vl, double vu, int il, int iu,
                           double abstol, int& m, int& nz,
                           double* w, double orfac, double* Z, int iz, int jz, const int* descZ,
                           double* work, int lwork, int* iwork, int liwork,
                           int* ifail, int* iclustr, double* gap) {
  return cscalapack_pdsyevx_work(jobz, range, uplo, n, A, ia, ja, descA, vl, vu, il, iu, abstol, &m, &nz, w, orfac, Z, iz, jz, descZ,
                                 work, lwork, iwork, liwork,
                                 ifail, iclustr, gap);
}

inline int psyevx_dispatch(char jobz, char range, char uplo, int n, double* A, int ia, int ja, const int* descA,
                           double vl, double vu, int il, int iu,
                           double abstol, int& m, int& nz,
                           double* w, double orfac, double* Z, int iz, int jz, const int* descZ,
                           int* ifail, int* iclustr, double* gap) {
  return cscalapack_pdsyevx(jobz, range, uplo, n, A, ia, ja, descA, vl, vu, il, iu, abstol, &m, &nz, w, orfac, Z, iz, jz, descZ,
                            ifail, iclustr, gap);
}

inline int psyevx_dispatch(char jobz, char range, char uplo, int n, std::complex<float>* A, int ia, int ja, const int* descA,
                           float vl, float vu, int il, int iu,
                           float abstol, int& m, int& nz,
                           float* w, float orfac, std::complex<float>* Z, int iz, int jz, const int* descZ,
                           int* ifail, int* iclustr, float* gap) {
  return cscalapack_pcheevx(jobz, range, uplo, n, complex_cast(A), ia, ja, descA, vl, vu, il, iu, abstol, &m, &nz, w, orfac, complex_cast(Z), iz, jz, descZ,
                            ifail, iclustr, gap);
}

inline int psyevx_dispatch(char jobz, char range, char uplo, int n, std::complex<double>* A, int ia, int ja, const int* descA,
                           double vl, double vu, int il, int iu,
                           double abstol, int& m, int& nz,
                           double* w, double orfac, std::complex<double>* Z, int iz, int jz, const int* descZ,
                           int* ifail, int* iclustr, double* gap) {
  return cscalapack_pzheevx(jobz, range, uplo, n, complex_cast(A), ia, ja, descA, vl, vu, il, iu, abstol, &m, &nz, w, orfac, complex_cast(Z), iz, jz, descZ,
                            ifail, iclustr, gap);
}

} // end of anonymous namespace

template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT, typename VECTOR2>
int psyevx(char jobz, char range, char uplo, MATRIX& a,
           T vl, T vu, int il, int iu,
           T abstol, int& m, int& nz,
           VECTOR& w, double orfac, MATRIX& z,
           VECTOR_INT& ifail, VECTOR_INT& iclustr, VECTOR2& gap) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR>>::value, "");
  static_assert(std::is_same<value_t<VECTOR>, value_t<VECTOR2>>::value, "");
  static_assert(std::is_same<value_t<VECTOR>, T>::value, "");

  const int* descA = a.get_mapping().get_blacs_descriptor().data();
  const int* descZ = z.get_mapping().get_blacs_descriptor().data();
  return psyevx_dispatch(jobz, range, uplo, a.get_m_global(), a.get_array_pointer(), 0, 0, descA,
                         vl, vu, il, iu, abstol, m, nz,
                         storage(w), orfac, z.get_array_pointer(), 0, 0, descZ,
                         storage(ifail), storage(iclustr), storage(gap));
}

template<typename T, typename MATRIX, typename VECTOR0, typename VECTOR1, typename VECTOR_INT, typename VECTOR2>
int psyevx(char jobz, char range, char uplo, MATRIX& a,
           T vl, T vu, int il, int iu,
           T abstol, int& m, int& nz,
           VECTOR0& w, double orfac, MATRIX& z, VECTOR0& work, VECTOR1& iwork,
           VECTOR_INT& ifail, VECTOR_INT& iclustr, VECTOR2& gap) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR0>>::value, "");
  static_assert(std::is_same<value_t<VECTOR0>, value_t<VECTOR2>>::value, "");
  static_assert(std::is_same<value_t<VECTOR0>, T>::value, "");

  const int* descA = a.get_mapping().get_blacs_descriptor().data();
  const int* descZ = z.get_mapping().get_blacs_descriptor().data();
  return psyevx_dispatch(jobz, range, uplo, a.get_m_global(), a.get_array_pointer(), 0, 0, descA,
                         vl, vu, il, iu, abstol, m, nz,
                         storage(w), orfac, z.get_array_pointer(), 0, 0, descZ,
                         storage(work), work.size(), storage(iwork), iwork.size(),
                         storage(ifail), storage(iclustr), storage(gap));
}

// eigenvalues & eigenvectors (without jobz)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT, typename VECTOR2>
int psyevx(char range, char uplo, MATRIX& a,
           T vl, T vu, int il, int iu,
           T abstol, int& m, int& nz,
           VECTOR& w, T orfac, MATRIX& z,
           VECTOR_INT& ifail, VECTOR_INT& iclustr, VECTOR2& gap) {
  return psyevx('V', range, uplo, a,
                vl, vu, il, iu, abstol, m, nz,
                w, orfac, z,
                ifail, iclustr, gap);
}

// eigenvalues & eigenvectors, use all (without jobz, range, vl, vu, il, iu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT, typename VECTOR2>
int psyevx(char uplo, MATRIX& a,
           T abstol, int& m, int& nz,
           VECTOR& w, T orfac, MATRIX& z,
           VECTOR_INT& ifail, VECTOR_INT& iclustr, VECTOR2& gap) {
  constexpr real_t<MATRIX> real_zero = 0;
  return psyevx('A', uplo, a,
                real_zero, real_zero, 0, 0, abstol, m, nz,
                w, orfac, z,
                ifail, iclustr, gap);
}

// eigenvalues & eigenvectors, use vl, vu (without jobz, range, il, iu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT, typename VECTOR2>
int psyevx(char uplo, MATRIX& a,
           T vl, T vu,
           T abstol, int& m, int& nz,
           VECTOR& w, T orfac, MATRIX& z,
           VECTOR_INT& ifail, VECTOR_INT& iclustr, VECTOR2& gap) {
  return psyevx('V', uplo, a,
                vl, vu, 0, 0, abstol, m, nz,
                w, orfac, z,
                ifail, iclustr, gap);
}

// eigenvalues & eigenvectors, use il, iu (without jobz, range, vl, vu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT, typename VECTOR2>
int psyevx(char uplo, MATRIX& a,
           int il, int iu,
           T abstol, int& m, int& nz,
           VECTOR& w, T orfac, MATRIX& z,
           VECTOR_INT& ifail, VECTOR_INT& iclustr, VECTOR2& gap) {
  constexpr real_t<MATRIX> real_zero = 0;
  return psyevx('I', uplo, a,
                real_zero, real_zero, il, iu, abstol, m, nz,
                w, orfac, z,
                ifail, iclustr, gap);
}

// only eigenvalues (without jobz)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT, typename VECTOR2>
int psyevx(char range, char uplo, MATRIX& a,
           T vl, T vu, int il, int iu,
           T abstol, int& m, int& nz,
           VECTOR& w, T orfac,
           VECTOR_INT& ifail, VECTOR_INT& iclustr, VECTOR2& gap) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR>>::value, "");
  static_assert(std::is_same<value_t<VECTOR>, value_t<VECTOR2>>::value, "");
  static_assert(std::is_same<value_t<VECTOR>, T>::value, "");

  const int* descA = a.get_mapping().get_blacs_descriptor().data();
  return psyevx_dispatch('N', range, uplo, a.get_m_global(), a.get_array_pointer(), 0, 0, descA,
                         vl, vu, il, iu, abstol, m, nz,
                         storage(w), orfac, NULL, 0, 0, NULL,
                         storage(ifail), storage(iclustr), storage(gap));
}

// only eigenvalues, use all (without jobz, range, vl, vu, il, iu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT, typename VECTOR2>
int psyevx(char uplo, MATRIX& a,
           T abstol, int& m, int& nz,
           VECTOR& w, T orfac,
           VECTOR_INT& ifail, VECTOR_INT& iclustr, VECTOR2& gap) {
  constexpr real_t<MATRIX> real_zero = 0;
  return psyevx('A', uplo, a,
                real_zero, real_zero, 0, 0, abstol, m, nz,
                w, orfac,
                ifail, iclustr, gap);
}

// only eigenvalues, use vl, vu (without jobz, range, il, iu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT, typename VECTOR2>
int psyevx(char uplo, MATRIX& a,
           T vl, T vu,
           T abstol, int& m, int& nz,
           VECTOR& w, T orfac,
           VECTOR_INT& ifail, VECTOR_INT& iclustr, VECTOR2& gap) {
  return psyevx('V', uplo, a,
                vl, vu, 0, 0, abstol, m, nz,
                w, orfac,
                ifail, iclustr, gap);
}

// only eigenvalues, use il, iu (without jobz, range, vl, vu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT, typename VECTOR2>
int psyevx(char uplo, MATRIX& a,
           int il, int iu,
           T abstol, int& m, int& nz,
           VECTOR& w, T orfac,
           VECTOR_INT& ifail, VECTOR_INT& iclustr, VECTOR2& gap) {
  constexpr real_t<MATRIX> real_zero = 0;
  return psyevx('I', uplo, a,
                real_zero, real_zero, il, iu, abstol, m, nz,
                w, orfac,
                ifail, iclustr, gap);
}

} // end namespace scalapack
} // end namespace rokko

#endif // ROKKO_SCALAPACK_PSYEVX_HPP


<|start_filename|>rokko/lapack/lange.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_LANGE_HPP
#define ROKKO_LAPACK_LANGE_HPP

#include <complex>
#ifdef I
# undef I
#endif
#include <stdexcept>
#include <lapacke.h>
#undef I
#include <rokko/traits/real_t.hpp>
#include "complex_cast.hpp"

namespace rokko {
namespace lapack {

namespace {

template<typename T> struct lange_dispatch;
  
template<>
struct lange_dispatch<float> {
  template<typename MATRIX>
  static float lange(int matrix_layout, char norm, lapack_int m, lapack_int n,
                     MATRIX const& a) {
    return LAPACKE_slange(matrix_layout, norm, m, n, storage(a), ld(a));
  }
};

template<>
struct lange_dispatch<double> {
  template<typename MATRIX>
  static double lange(int matrix_layout, char norm, lapack_int m, lapack_int n,
                      MATRIX const& a) {
    return LAPACKE_dlange(matrix_layout, norm, m, n, storage(a), ld(a));
  }
};

template<>
struct lange_dispatch<std::complex<float>> {
  template<typename MATRIX>
  static float lange(int matrix_layout, char norm, lapack_int m, lapack_int n,
                     MATRIX const& a) {
    return LAPACKE_clange(matrix_layout, norm, m, n, complex_cast((storage(a))), ld(a));
  }
};

template<>
struct lange_dispatch<std::complex<double>> {
  template<typename MATRIX>
  static double lange(int matrix_layout, char norm, lapack_int m, lapack_int n,
                      MATRIX const& a) {
    return LAPACKE_zlange(matrix_layout, norm, m, n, complex_cast((storage(a))), ld(a));
  }
};

}

template<typename MATRIX>
real_t<MATRIX> lange(char norm, MATRIX const& a) {
  lapack_int m = rows(a);
  lapack_int n = cols(a);
  return lange_dispatch<value_t<MATRIX>>
    ::lange((is_col_major(a) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR), norm,
            m, n, a);
}

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_LANGE_HPP


<|start_filename|>rokko/eigen3.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_EIGEN3_HPP
#define ROKKO_EIGEN3_HPP

#include <rokko/eigen3/matrix_major.hpp>
#include <Eigen/Dense>

namespace Eigen {

template<typename T, int ROWS, int MATRIX_MAJOR>
int size(Eigen::Matrix<T, ROWS, 1, MATRIX_MAJOR> const& vec) {
  return vec.size();
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
bool is_col_major(Eigen::Matrix<T, ROWS, COLS, MATRIX_MAJOR> const&) {
  return MATRIX_MAJOR == Eigen::ColMajor;
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
bool is_row_major(Eigen::Matrix<T, ROWS, COLS, MATRIX_MAJOR> const&) {
  return MATRIX_MAJOR == Eigen::RowMajor;
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
int rows(Eigen::Matrix<T, ROWS, COLS, MATRIX_MAJOR> const& mat) {
  return mat.rows();
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
int cols(Eigen::Matrix<T, ROWS, COLS, MATRIX_MAJOR> const& mat) {
  return mat.cols();
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
int ld(Eigen::Matrix<T, ROWS, COLS, MATRIX_MAJOR> const& mat) {
  return mat.innerSize();
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
const T* storage(Eigen::Matrix<T, ROWS, COLS, MATRIX_MAJOR> const& mat) {
  return mat.data();
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
T* storage(Eigen::Matrix<T, ROWS, COLS, MATRIX_MAJOR>& mat) {
  return mat.data();
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
const T* storage(Eigen::Ref<Eigen::Matrix<T, ROWS, COLS, MATRIX_MAJOR>> const& mat) {
  return mat.data();
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
T* storage(Eigen::Ref<Eigen::Matrix<T, ROWS, COLS, MATRIX_MAJOR>>& mat) {
  return mat.data();
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
const std::complex<T>* storage(Eigen::Matrix<std::complex<T>, ROWS, COLS, MATRIX_MAJOR> const& mat) {
  return mat.data();
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
std::complex<T>* storage(Eigen::Matrix<std::complex<T>, ROWS, COLS, MATRIX_MAJOR>& mat) {
  return mat.data();
}

template<typename T, int ROWS = Eigen::Dynamic>
using Vector = Eigen::Matrix<T, ROWS, 1>;

template<typename T>
using RefVec = Eigen::Ref<Vector<T>>;

} // namespace Eigen

#endif // ROKKO_EIGEN3_HPP


<|start_filename|>example/lapack/getrs.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2017 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <rokko/blas.hpp>
#include <rokko/lapack/getrf.hpp>
#include <rokko/lapack/getrs.hpp>
#include <rokko/eigen3.hpp>
#include <iostream>

int main(int argc, char** argv) {
  constexpr double eps = 1e-10;
  int n = 5;
  if (argc > 1) n = std::stoi(argv[1]);

  // generate matrix and rhs vector
  Eigen::MatrixXd a(n, n);
  for (int j = 0; j < n; ++j) {
    for (int i = 0; i < n; ++i) {
      a(i, j) = std::min(i, j) + 1;
    }
  }
  std::cout << "Matrix A: " << std::endl << a << std::endl;
  Eigen::VectorXd b(n);
  for (int i = 0; i < n; ++i) b(i) = i * i + 1;
  std::cout << "Vector b: " << std::endl << b << std::endl;

  // solve linear equation
  Eigen::MatrixXd lu = a;
  Eigen::VectorXd x = b;
  Eigen::VectorXi ipiv(n);
  rokko::lapack::getrf(lu, ipiv);
  rokko::lapack::getrs('n', 1, lu, ipiv, x);
  std::cout << "Solution x: " << std::endl << x << std::endl;

  /* solution check */
  Eigen::VectorXd check = a * x - b;
  double norm = check.norm();
  std::cout << "|| A x - b || = " << norm << std::endl;
  if (norm > eps) throw std::runtime_error("Error: solution check");

  return 0;
}


<|start_filename|>example/lapack/orgqr.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2017 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <rokko/blas.hpp>
#include <rokko/lapack/geqrf.hpp>
#include <rokko/lapack/orgqr.hpp>
#include <rokko/lapack/lange.hpp>
#include <rokko/eigen3.hpp>
#include <iostream>
#include <stdexcept>

int main(int argc, char** argv) {
  constexpr double eps = 1e-10;
  int m = 10;
  int n = 6;
  if (argc > 2) {
    m = std::stoi(argv[1]);
    n = std::stoi(argv[2]);
  }
  int k = std::min(m, n);
  if (m < n) throw std::invalid_argument("Error: m < n");
  
  // generate matrix
  Eigen::MatrixXd a = Eigen::MatrixXd::Random(m, n);
  std::cout << "Matrix A: " << std::endl << a << std::endl;

  // orthonormaliation
  Eigen::MatrixXd mat = a;
  Eigen::VectorXd tau(k);
  int info = rokko::lapack::geqrf(mat, tau);
  if (info) throw std::runtime_error("Error: geqrf failed");

  Eigen::MatrixXd r = mat.topLeftCorner(k, n);
  for (int i = 0; i < k; ++i)  // Zeros out lower triangular part of r;
    for (int j = 0; j < std::min(i,n); ++j)
      r(i, j) = 0;
  std::cout << "Upper triangle matrix R:" << std::endl << r << std::endl;
  info = rokko::lapack::orgqr(k, mat, tau);
  Eigen::MatrixXd q = mat.topLeftCorner(m, n);
  std::cout << "Orthonormalized column vectors Q:" << std::endl << q << std::endl;
  
  // orthogonality check
  Eigen::MatrixXd check1 = q.adjoint() * q - Eigen::MatrixXd::Identity(k, k);
  double norm1 = rokko::lapack::lange('F', check1);
  std::cout << "|| Q^t Q - I || = " << norm1 << std::endl;
  if (norm1 > eps) throw std::runtime_error("Error: orthogonality check");

  // solution check
  Eigen::MatrixXd check2 = q * r - a;
  double norm2 = rokko::lapack::lange('F', check2);
  std::cout << "|| Q R - A || = " << norm2 << std::endl;
  if (norm2 > eps) throw std::runtime_error("Error: solution check");

  return 0;
}


<|start_filename|>3rd-party/cblas/include/cblas_f77.h<|end_filename|>
/*
 * cblas_f77.h
 * Written by <NAME>
 *
 * Updated by <NAME>
 * Merged cblas_f77.h and cblas_fortran_header.h
 */

#ifndef CBLAS_F77_H
#define CBLAS_f77_H

#ifdef CRAY
   #include <fortran.h>
   #define F77_CHAR _fcd
   #define C2F_CHAR(a) ( _cptofcd( (a), 1 ) )
   #define C2F_STR(a, i) ( _cptofcd( (a), (i) ) )
   #define F77_STRLEN(a) (_fcdlen)
#endif

#ifdef WeirdNEC
   #define F77_INT long
#endif

#ifdef  F77_CHAR
   #define FCHAR F77_CHAR
#else
   #define FCHAR char *
#endif

#ifdef F77_INT
   #define FINT const F77_INT *
   #define FINT2 F77_INT *
#else
   #define FINT const int *
   #define FINT2 int *
#endif

#include "cblas_mangling.h"

#define F77_xerbla     BLAS_GLOBAL(xerbla,    XERBLA)
/*
 * Level 1 BLAS
 */
#define F77_srotg      BLAS_GLOBAL(srotg,     SROTG)
#define F77_srotmg     BLAS_GLOBAL(srotmg,    SROTMG)
#define F77_srot       BLAS_GLOBAL(srot,      SROT)
#define F77_srotm      BLAS_GLOBAL(srotm,     SROTM)
#define F77_drotg      BLAS_GLOBAL(drotg,     DROTG)
#define F77_drotmg     BLAS_GLOBAL(drotmg,    DROTMG)
#define F77_drot       BLAS_GLOBAL(drot,      DROT)
#define F77_drotm      BLAS_GLOBAL(drotm,     DROTM)
#define F77_sswap      BLAS_GLOBAL(sswap,     SSWAP)
#define F77_scopy      BLAS_GLOBAL(scopy,     SCOPY)
#define F77_saxpy      BLAS_GLOBAL(saxpy,     SAXPY)
#define F77_isamax_sub BLAS_GLOBAL(isamaxsub, ISAMAXSUB)
#define F77_dswap      BLAS_GLOBAL(dswap,     DSWAP)
#define F77_dcopy      BLAS_GLOBAL(dcopy,     DCOPY)
#define F77_daxpy      BLAS_GLOBAL(daxpy,     DAXPY)
#define F77_idamax_sub BLAS_GLOBAL(idamaxsub, IDAMAXSUB)
#define F77_cswap      BLAS_GLOBAL(cswap,     CSWAP)
#define F77_ccopy      BLAS_GLOBAL(ccopy,     CCOPY)
#define F77_caxpy      BLAS_GLOBAL(caxpy,     CAXPY)
#define F77_icamax_sub BLAS_GLOBAL(icamaxsub, ICAMAXSUB)
#define F77_zswap      BLAS_GLOBAL(zswap,     ZSWAP)
#define F77_zcopy      BLAS_GLOBAL(zcopy,     ZCOPY)
#define F77_zaxpy      BLAS_GLOBAL(zaxpy,     ZAXPY)
#define F77_izamax_sub BLAS_GLOBAL(izamaxsub, IZAMAXSUB)
#define F77_sdot_sub   BLAS_GLOBAL(sdotsub,   SDOTSUB)
#define F77_ddot_sub   BLAS_GLOBAL(ddotsub,   DDOTSUB)
#define F77_dsdot_sub  BLAS_GLOBAL(dsdotsub,  DSDOTSUB)
#define F77_sscal      BLAS_GLOBAL(sscal,     SSCAL)
#define F77_dscal      BLAS_GLOBAL(dscal,     DSCAL)
#define F77_cscal      BLAS_GLOBAL(cscal,     CSCAL)
#define F77_zscal      BLAS_GLOBAL(zscal,     ZSCAL)
#define F77_csscal     BLAS_GLOBAL(csscal,    CSSCAL)
#define F77_zdscal     BLAS_GLOBAL(zdscal,    ZDSCAL)
#define F77_cdotu_sub  BLAS_GLOBAL(cdotusub,  CDOTUSUB)
#define F77_cdotc_sub  BLAS_GLOBAL(cdotcsub,  CDOTCSUB)
#define F77_zdotu_sub  BLAS_GLOBAL(zdotusub,  ZDOTUSUB)
#define F77_zdotc_sub  BLAS_GLOBAL(zdotcsub,  ZDOTCSUB)
#define F77_snrm2_sub  BLAS_GLOBAL(snrm2sub,  SNRM2SUB)
#define F77_sasum_sub  BLAS_GLOBAL(sasumsub,  SASUMSUB)
#define F77_dnrm2_sub  BLAS_GLOBAL(dnrm2sub,  DNRM2SUB)
#define F77_dasum_sub  BLAS_GLOBAL(dasumsub,  DASUMSUB)
#define F77_scnrm2_sub BLAS_GLOBAL(scnrm2sub, SCNRM2SUB)
#define F77_scasum_sub BLAS_GLOBAL(scasumsub, SCASUMSUB)
#define F77_dznrm2_sub BLAS_GLOBAL(dznrm2sub, DZNRM2SUB)
#define F77_dzasum_sub BLAS_GLOBAL(dzasumsub, DZASUMSUB)
#define F77_sdsdot_sub BLAS_GLOBAL(sdsdotsub, SDSDOTSUB)
/*
 * Level 2 BLAS
 */
#define F77_ssymv      BLAS_GLOBAL(ssymv, SSYMV)
#define F77_ssbmv      BLAS_GLOBAL(ssbmv, SSBMV)
#define F77_sspmv      BLAS_GLOBAL(sspmv, SSPMV)
#define F77_sger       BLAS_GLOBAL(sger,  SGER)
#define F77_ssyr       BLAS_GLOBAL(ssyr,  SSYR)
#define F77_sspr       BLAS_GLOBAL(sspr,  SSPR)
#define F77_ssyr2      BLAS_GLOBAL(ssyr2, SSYR2)
#define F77_sspr2      BLAS_GLOBAL(sspr2, SSPR2)
#define F77_dsymv      BLAS_GLOBAL(dsymv, DSYMV)
#define F77_dsbmv      BLAS_GLOBAL(dsbmv, DSBMV)
#define F77_dspmv      BLAS_GLOBAL(dspmv, DSPMV)
#define F77_dger       BLAS_GLOBAL(dger,  DGER)
#define F77_dsyr       BLAS_GLOBAL(dsyr,  DSYR)
#define F77_dspr       BLAS_GLOBAL(dspr,  DSPR)
#define F77_dsyr2      BLAS_GLOBAL(dsyr2, DSYR2)
#define F77_dspr2      BLAS_GLOBAL(dspr2, DSPR2)
#define F77_chemv      BLAS_GLOBAL(chemv, CHEMV)
#define F77_chbmv      BLAS_GLOBAL(chbmv, CHBMV)
#define F77_chpmv      BLAS_GLOBAL(chpmv, CHPMV)
#define F77_cgeru      BLAS_GLOBAL(cgeru, CGERU)
#define F77_cgerc      BLAS_GLOBAL(cgerc, CGERC)
#define F77_cher       BLAS_GLOBAL(cher,  CHER)
#define F77_chpr       BLAS_GLOBAL(chpr,  CHPR)
#define F77_cher2      BLAS_GLOBAL(cher2, CHER2)
#define F77_chpr2      BLAS_GLOBAL(chpr2, CHPR2)
#define F77_zhemv      BLAS_GLOBAL(zhemv, ZHEMV)
#define F77_zhbmv      BLAS_GLOBAL(zhbmv, ZHBMV)
#define F77_zhpmv      BLAS_GLOBAL(zhpmv, ZHPMV)
#define F77_zgeru      BLAS_GLOBAL(zgeru, ZGERU)
#define F77_zgerc      BLAS_GLOBAL(zgerc, ZGERC)
#define F77_zher       BLAS_GLOBAL(zher,  ZHER)
#define F77_zhpr       BLAS_GLOBAL(zhpr,  ZHPR)
#define F77_zher2      BLAS_GLOBAL(zher2, ZHER2)
#define F77_zhpr2      BLAS_GLOBAL(zhpr2, ZHPR2)
#define F77_sgemv      BLAS_GLOBAL(sgemv, SGEMV)
#define F77_sgbmv      BLAS_GLOBAL(sgbmv, SGBMV)
#define F77_strmv      BLAS_GLOBAL(strmv, STRMV)
#define F77_stbmv      BLAS_GLOBAL(stbmv, STBMV)
#define F77_stpmv      BLAS_GLOBAL(stpmv, STPMV)
#define F77_strsv      BLAS_GLOBAL(strsv, STRSV)
#define F77_stbsv      BLAS_GLOBAL(stbsv, STBSV)
#define F77_stpsv      BLAS_GLOBAL(stpsv, STPSV)
#define F77_dgemv      BLAS_GLOBAL(dgemv, DGEMV)
#define F77_dgbmv      BLAS_GLOBAL(dgbmv, DGBMV)
#define F77_dtrmv      BLAS_GLOBAL(dtrmv, DTRMV)
#define F77_dtbmv      BLAS_GLOBAL(dtbmv, DTBMV)
#define F77_dtpmv      BLAS_GLOBAL(dtpmv, DTPMV)
#define F77_dtrsv      BLAS_GLOBAL(dtrsv, DTRSV)
#define F77_dtbsv      BLAS_GLOBAL(dtbsv, DTBSV)
#define F77_dtpsv      BLAS_GLOBAL(dtpsv, DTPSV)
#define F77_cgemv      BLAS_GLOBAL(cgemv, CGEMV)
#define F77_cgbmv      BLAS_GLOBAL(cgbmv, CGBMV)
#define F77_ctrmv      BLAS_GLOBAL(ctrmv, CTRMV)
#define F77_ctbmv      BLAS_GLOBAL(ctbmv, CTBMV)
#define F77_ctpmv      BLAS_GLOBAL(ctpmv, CTPMV)
#define F77_ctrsv      BLAS_GLOBAL(ctrsv, CTRSV)
#define F77_ctbsv      BLAS_GLOBAL(ctbsv, CTBSV)
#define F77_ctpsv      BLAS_GLOBAL(ctpsv, CTPSV)
#define F77_zgemv      BLAS_GLOBAL(zgemv, ZGEMV)
#define F77_zgbmv      BLAS_GLOBAL(zgbmv, ZGBMV)
#define F77_ztrmv      BLAS_GLOBAL(ztrmv, ZTRMV)
#define F77_ztbmv      BLAS_GLOBAL(ztbmv, ZTBMV)
#define F77_ztpmv      BLAS_GLOBAL(ztpmv, ZTPMV)
#define F77_ztrsv      BLAS_GLOBAL(ztrsv, ZTRSV)
#define F77_ztbsv      BLAS_GLOBAL(ztbsv, ZTBSV)
#define F77_ztpsv      BLAS_GLOBAL(ztpsv, ZTPSV)
/*
 * Level 3 BLAS
 */
#define F77_chemm      BLAS_GLOBAL(chemm,  CHEMM)
#define F77_cherk      BLAS_GLOBAL(cherk,  CHERK)
#define F77_cher2k     BLAS_GLOBAL(cher2k, CHER2K)
#define F77_zhemm      BLAS_GLOBAL(zhemm,  ZHEMM)
#define F77_zherk      BLAS_GLOBAL(zherk,  ZHERK)
#define F77_zher2k     BLAS_GLOBAL(zher2k, ZHER2K)
#define F77_sgemm      BLAS_GLOBAL(sgemm,  SGEMM)
#define F77_ssymm      BLAS_GLOBAL(ssymm,  SSYMM)
#define F77_ssyrk      BLAS_GLOBAL(ssyrk,  SSYRK)
#define F77_ssyr2k     BLAS_GLOBAL(ssyr2k, SSYR2K)
#define F77_strmm      BLAS_GLOBAL(strmm,  STRMM)
#define F77_strsm      BLAS_GLOBAL(strsm,  STRSM)
#define F77_dgemm      BLAS_GLOBAL(dgemm,  DGEMM)
#define F77_dsymm      BLAS_GLOBAL(dsymm,  DSYMM)
#define F77_dsyrk      BLAS_GLOBAL(dsyrk,  DSYRK)
#define F77_dsyr2k     BLAS_GLOBAL(dsyr2k, DSYR2K)
#define F77_dtrmm      BLAS_GLOBAL(dtrmm,  DTRMM)
#define F77_dtrsm      BLAS_GLOBAL(dtrsm,  DTRSM)
#define F77_cgemm      BLAS_GLOBAL(cgemm,  CGEMM)
#define F77_csymm      BLAS_GLOBAL(csymm,  CSYMM)
#define F77_csyrk      BLAS_GLOBAL(csyrk,  CSYRK)
#define F77_csyr2k     BLAS_GLOBAL(csyr2k, CSYR2K)
#define F77_ctrmm      BLAS_GLOBAL(ctrmm,  CTRMM)
#define F77_ctrsm      BLAS_GLOBAL(ctrsm,  CTRSM)
#define F77_zgemm      BLAS_GLOBAL(zgemm,  ZGEMM)
#define F77_zsymm      BLAS_GLOBAL(zsymm,  ZSYMM)
#define F77_zsyrk      BLAS_GLOBAL(zsyrk,  ZSYRK)
#define F77_zsyr2k     BLAS_GLOBAL(zsyr2k, ZSYR2K)
#define F77_ztrmm      BLAS_GLOBAL(ztrmm,  ZTRMM)
#define F77_ztrsm      BLAS_GLOBAL(ztrsm,  ZTRSM)

#ifdef __cplusplus
extern "C" {
#endif

   void F77_xerbla(FCHAR, void *);
/*
 * Level 1 Fortran Prototypes
 */

/* Single Precision */

   void F77_srot(FINT, float *, FINT, float *, FINT, const float *, const float *);
   void F77_srotg(float *,float *,float *,float *);    
   void F77_srotm( FINT, float *, FINT, float *, FINT, const float *);
   void F77_srotmg(float *,float *,float *,const float *, float *);
   void F77_sswap( FINT, float *, FINT, float *, FINT);
   void F77_scopy( FINT, const float *, FINT, float *, FINT);
   void F77_saxpy( FINT, const float *, const float *, FINT, float *, FINT);
   void F77_sdot_sub(FINT, const float *, FINT, const float *, FINT, float *);
   void F77_sdsdot_sub( FINT, const float *, const float *, FINT, const float *, FINT, float *);
   void F77_sscal( FINT, const float *, float *, FINT);
   void F77_snrm2_sub( FINT, const float *, FINT, float *);
   void F77_sasum_sub( FINT, const float *, FINT, float *);
   void F77_isamax_sub( FINT, const float * , FINT, FINT2);

/* Double Precision */

   void F77_drot(FINT, double *, FINT, double *, FINT, const double *, const double *);
   void F77_drotg(double *,double *,double *,double *);    
   void F77_drotm( FINT, double *, FINT, double *, FINT, const double *);
   void F77_drotmg(double *,double *,double *,const double *, double *);
   void F77_dswap( FINT, double *, FINT, double *, FINT);
   void F77_dcopy( FINT, const double *, FINT, double *, FINT);
   void F77_daxpy( FINT, const double *, const double *, FINT, double *, FINT);
   void F77_dswap( FINT, double *, FINT, double *, FINT);
   void F77_dsdot_sub(FINT, const float *, FINT, const float *, FINT, double *);
   void F77_ddot_sub( FINT, const double *, FINT, const double *, FINT, double *);
   void F77_dscal( FINT, const double *, double *, FINT);
   void F77_dnrm2_sub( FINT, const double *, FINT, double *);
   void F77_dasum_sub( FINT, const double *, FINT, double *);
   void F77_idamax_sub( FINT, const double * , FINT, FINT2);

/* Single Complex Precision */

   void F77_cswap( FINT, void *, FINT, void *, FINT);
   void F77_ccopy( FINT, const void *, FINT, void *, FINT);
   void F77_caxpy( FINT, const void *, const void *, FINT, void *, FINT);
   void F77_cswap( FINT, void *, FINT, void *, FINT);
   void F77_cdotc_sub( FINT, const void *, FINT, const void *, FINT, void *);
   void F77_cdotu_sub( FINT, const void *, FINT, const void *, FINT, void *);
   void F77_cscal( FINT, const void *, void *, FINT);
   void F77_icamax_sub( FINT, const void *, FINT, FINT2);
   void F77_csscal( FINT, const float *, void *, FINT);
   void F77_scnrm2_sub( FINT, const void *, FINT, float *);
   void F77_scasum_sub( FINT, const void *, FINT, float *);

/* Double Complex Precision */

   void F77_zswap( FINT, void *, FINT, void *, FINT);
   void F77_zcopy( FINT, const void *, FINT, void *, FINT);
   void F77_zaxpy( FINT, const void *, const void *, FINT, void *, FINT);
   void F77_zswap( FINT, void *, FINT, void *, FINT);
   void F77_zdotc_sub( FINT, const void *, FINT, const void *, FINT, void *);
   void F77_zdotu_sub( FINT, const void *, FINT, const void *, FINT, void *);
   void F77_zdscal( FINT, const double *, void *, FINT);
   void F77_zscal( FINT, const void *, void *, FINT);
   void F77_dznrm2_sub( FINT, const void *, FINT, double *);
   void F77_dzasum_sub( FINT, const void *, FINT, double *);
   void F77_izamax_sub( FINT, const void *, FINT, FINT2);

/*
 * Level 2 Fortran Prototypes
 */

/* Single Precision */

   void F77_sgemv(FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);
   void F77_sgbmv(FCHAR, FINT, FINT, FINT, FINT, const float *,  const float *, FINT, const float *, FINT, const float *, float *, FINT);
   void F77_ssymv(FCHAR, FINT, const float *, const float *, FINT, const float *,  FINT, const float *, float *, FINT);
   void F77_ssbmv(FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);
   void F77_sspmv(FCHAR, FINT, const float *, const float *, const float *, FINT, const float *, float *, FINT);
   void F77_strmv( FCHAR, FCHAR, FCHAR, FINT, const float *, FINT, float *, FINT);
   void F77_stbmv( FCHAR, FCHAR, FCHAR, FINT, FINT, const float *, FINT, float *, FINT);
   void F77_strsv( FCHAR, FCHAR, FCHAR, FINT, const float *, FINT, float *, FINT);
   void F77_stbsv( FCHAR, FCHAR, FCHAR, FINT, FINT, const float *, FINT, float *, FINT);
   void F77_stpmv( FCHAR, FCHAR, FCHAR, FINT, const float *, float *, FINT);
   void F77_stpsv( FCHAR, FCHAR, FCHAR, FINT, const float *, float *, FINT);
   void F77_sger( FINT, FINT, const float *, const float *, FINT, const float *, FINT, float *, FINT);
   void F77_ssyr(FCHAR, FINT, const float *, const float *, FINT, float *, FINT);
   void F77_sspr(FCHAR, FINT, const float *, const float *, FINT, float *); 
   void F77_sspr2(FCHAR, FINT, const float *, const float *, FINT, const float *, FINT,  float *); 
   void F77_ssyr2(FCHAR, FINT, const float *, const float *, FINT, const float *, FINT,  float *, FINT);

/* Double Precision */

   void F77_dgemv(FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);
   void F77_dgbmv(FCHAR, FINT, FINT, FINT, FINT, const double *,  const double *, FINT, const double *, FINT, const double *, double *, FINT);
   void F77_dsymv(FCHAR, FINT, const double *, const double *, FINT, const double *,  FINT, const double *, double *, FINT);
   void F77_dsbmv(FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);
   void F77_dspmv(FCHAR, FINT, const double *, const double *, const double *, FINT, const double *, double *, FINT);
   void F77_dtrmv( FCHAR, FCHAR, FCHAR, FINT, const double *, FINT, double *, FINT);
   void F77_dtbmv( FCHAR, FCHAR, FCHAR, FINT, FINT, const double *, FINT, double *, FINT);
   void F77_dtrsv( FCHAR, FCHAR, FCHAR, FINT, const double *, FINT, double *, FINT);
   void F77_dtbsv( FCHAR, FCHAR, FCHAR, FINT, FINT, const double *, FINT, double *, FINT);
   void F77_dtpmv( FCHAR, FCHAR, FCHAR, FINT, const double *, double *, FINT);
   void F77_dtpsv( FCHAR, FCHAR, FCHAR, FINT, const double *, double *, FINT);
   void F77_dger( FINT, FINT, const double *, const double *, FINT, const double *, FINT, double *, FINT);
   void F77_dsyr(FCHAR, FINT, const double *, const double *, FINT, double *, FINT);
   void F77_dspr(FCHAR, FINT, const double *, const double *, FINT, double *); 
   void F77_dspr2(FCHAR, FINT, const double *, const double *, FINT, const double *, FINT,  double *); 
   void F77_dsyr2(FCHAR, FINT, const double *, const double *, FINT, const double *, FINT,  double *, FINT);

/* Single Complex Precision */

   void F77_cgemv(FCHAR, FINT, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT);
   void F77_cgbmv(FCHAR, FINT, FINT, FINT, FINT, const void *,  const void *, FINT, const void *, FINT, const void *, void *, FINT);
   void F77_chemv(FCHAR, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT);
   void F77_chbmv(FCHAR, FINT, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT);
   void F77_chpmv(FCHAR, FINT, const void *, const void *, const void *, FINT, const void *, void *, FINT);
   void F77_ctrmv( FCHAR, FCHAR, FCHAR, FINT, const void *, FINT, void *, FINT);
   void F77_ctbmv( FCHAR, FCHAR, FCHAR, FINT, FINT, const void *, FINT, void *, FINT);
   void F77_ctpmv( FCHAR, FCHAR, FCHAR, FINT, const void *, void *, FINT);
   void F77_ctrsv( FCHAR, FCHAR, FCHAR, FINT, const void *, FINT, void *, FINT);
   void F77_ctbsv( FCHAR, FCHAR, FCHAR, FINT, FINT, const void *, FINT, void *, FINT);
   void F77_ctpsv( FCHAR, FCHAR, FCHAR, FINT, const void *, void *,FINT);
   void F77_cgerc( FINT, FINT, const void *, const void *, FINT, const void *, FINT, void *, FINT);
   void F77_cgeru( FINT, FINT, const void *, const void *, FINT, const void *, FINT, void *,  FINT);
   void F77_cher(FCHAR, FINT, const float *, const void *, FINT, void *, FINT);
   void F77_cher2(FCHAR, FINT, const void *, const void *, FINT, const void *, FINT, void *, FINT);
   void F77_chpr(FCHAR, FINT, const float *, const void *, FINT, void *);
   void F77_chpr2(FCHAR, FINT, const float *, const void *, FINT, const void *, FINT, void *);

/* Double Complex Precision */

   void F77_zgemv(FCHAR, FINT, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT);
   void F77_zgbmv(FCHAR, FINT, FINT, FINT, FINT, const void *,  const void *, FINT, const void *, FINT, const void *, void *, FINT);
   void F77_zhemv(FCHAR, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT);
   void F77_zhbmv(FCHAR, FINT, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT);
   void F77_zhpmv(FCHAR, FINT, const void *, const void *, const void *, FINT, const void *, void *, FINT);
   void F77_ztrmv( FCHAR, FCHAR, FCHAR, FINT, const void *, FINT, void *, FINT);
   void F77_ztbmv( FCHAR, FCHAR, FCHAR, FINT, FINT, const void *, FINT, void *, FINT);
   void F77_ztpmv( FCHAR, FCHAR, FCHAR, FINT, const void *, void *, FINT);
   void F77_ztrsv( FCHAR, FCHAR, FCHAR, FINT, const void *, FINT, void *, FINT);
   void F77_ztbsv( FCHAR, FCHAR, FCHAR, FINT, FINT, const void *, FINT, void *, FINT);
   void F77_ztpsv( FCHAR, FCHAR, FCHAR, FINT, const void *, void *,FINT);
   void F77_zgerc( FINT, FINT, const void *, const void *, FINT, const void *, FINT, void *, FINT);
   void F77_zgeru( FINT, FINT, const void *, const void *, FINT, const void *, FINT, void *,  FINT);
   void F77_zher(FCHAR, FINT, const double *, const void *, FINT, void *, FINT);
   void F77_zher2(FCHAR, FINT, const void *, const void *, FINT, const void *, FINT, void *, FINT);
   void F77_zhpr(FCHAR, FINT, const double *, const void *, FINT, void *);
   void F77_zhpr2(FCHAR, FINT, const double *, const void *, FINT, const void *, FINT, void *);

/*
 * Level 3 Fortran Prototypes
 */

/* Single Precision */

   void F77_sgemm(FCHAR, FCHAR, FINT, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);
   void F77_ssymm(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);
   void F77_ssyrk(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, float *, FINT);
   void F77_ssyr2k(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);
   void F77_strmm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, float *, FINT);
   void F77_strsm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, float *, FINT);

/* Double Precision */

   void F77_dgemm(FCHAR, FCHAR, FINT, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);
   void F77_dsymm(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);
   void F77_dsyrk(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, double *, FINT);
   void F77_dsyr2k(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);
   void F77_dtrmm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, double *, FINT);
   void F77_dtrsm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, double *, FINT);

/* Single Complex Precision */

   void F77_cgemm(FCHAR, FCHAR, FINT, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);
   void F77_csymm(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);
   void F77_chemm(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);
   void F77_csyrk(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, float *, FINT);
   void F77_cherk(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, float *, FINT);
   void F77_csyr2k(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);
   void F77_cher2k(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);
   void F77_ctrmm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, float *, FINT);
   void F77_ctrsm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, float *, FINT);

/* Double Complex Precision */

   void F77_zgemm(FCHAR, FCHAR, FINT, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);
   void F77_zsymm(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);
   void F77_zhemm(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);
   void F77_zsyrk(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, double *, FINT);
   void F77_zherk(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, double *, FINT);
   void F77_zsyr2k(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);
   void F77_zher2k(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);
   void F77_ztrmm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, double *, FINT);
   void F77_ztrsm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, double *, FINT);

#ifdef __cplusplus
}
#endif

#endif /*  CBLAS_F77_H */


<|start_filename|>example/cxx/dense/helmert_9x9value_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/collective.hpp>
#include <rokko/utility/solver_name.hpp>
#include <rokko/utility/helmert_matrix.hpp>
#include <iostream>

using matrix_major = rokko::matrix_col_major;


double func(int i, int j) {
  Eigen::MatrixXd mat_loc(9, 9);
  //  mat_loc << 2.828968253968254132,  0.8289682539682539097,  0.3289682539682539097,  -0.004365079365079349571,  -0.2543650793650793496,  -0.4543650793650793052,  -0.6210317460317460458,  -0.7638888888888888395,  -0.8888888888888888395;
  
  mat_loc << 2.828968253968254132,  0.8289682539682539097,  0.3289682539682539097,  -0.004365079365079349571,  -0.2543650793650793496,  -0.4543650793650793052,  -0.6210317460317460458,  -0.7638888888888888395,  -0.8888888888888888395,
    0.8289682539682539097,  2.828968253968254132,  0.3289682539682539097,  -0.004365079365079349571,  -0.2543650793650793496,  -0.4543650793650793052,  -0.6210317460317460458,  -0.7638888888888888395,  -0.8888888888888888395,
    0.3289682539682539097,  0.3289682539682539097,  3.328968253968254132,  -0.004365079365079349571,  -0.2543650793650793496,  -0.4543650793650793052,  -0.6210317460317460458,  -0.7638888888888888395,  -0.8888888888888888395,
    -0.004365079365079349571,  -0.004365079365079349571,  -0.004365079365079349571,  3.99563492063492065,  -0.2543650793650793496,  -0.4543650793650793052,  -0.6210317460317460458,  -0.7638888888888888395,  -0.8888888888888888395,
    -0.2543650793650793496,  -0.2543650793650793496,  -0.2543650793650793496,  -0.2543650793650793496,  4.745634920634920206,  -0.4543650793650793052,  -0.6210317460317460458,  -0.7638888888888888395,  -0.8888888888888888395,
    -0.4543650793650793052,  -0.4543650793650793052,  -0.4543650793650793052,  -0.4543650793650793052,  -0.4543650793650793052,  5.545634920634920917,  -0.6210317460317460458,  -0.7638888888888888395,  -0.8888888888888888395,
    -0.6210317460317460458,  -0.6210317460317460458,  -0.6210317460317460458,  -0.6210317460317460458,  -0.6210317460317460458,  -0.6210317460317460458,  6.378968253968253954,  -0.7638888888888888395,  -0.8888888888888888395,
    -0.7638888888888888395,  -0.7638888888888888395,  -0.7638888888888888395,  -0.7638888888888888395,  -0.7638888888888888395,  -0.7638888888888888395,  -0.7638888888888888395,  7.236111111111110716,  -0.8888888888888888395,
    -0.8888888888888888395,  -0.8888888888888888395,  -0.8888888888888888395,  -0.8888888888888888395,  -0.8888888888888888395,  -0.8888888888888888395,  -0.8888888888888888395,  -0.8888888888888888395,  8.111111111111110716;

  return mat_loc(i,j);
}
  
int main(int argc, char *argv[]) {

  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  MPI_Comm comm = MPI_COMM_WORLD;
  std::string library_routine(rokko::parallel_dense_ev::default_solver());
  std::string library, routine;
  int dim = 9;
  if (argc >= 2) library_routine = argv[1];
  if (argc >= 3) dim = std::stoi(argv[2]);
  rokko::split_solver_name(library_routine, library, routine);

  rokko::grid g(comm);
  int myrank = g.get_myrank();

  std::cout.precision(std::numeric_limits<unsigned long long>::digits10);

  rokko::parallel_dense_ev solver(library);
  solver.initialize(argc, argv);
  if (myrank == 0)
    std::cout << "Eigenvalue decomposition of Helmert matrix" << std::endl
              << "num_procs = " << g.get_nprocs() << std::endl
              #ifdef _OPENMP
              << "num_threads per process = " << omp_get_max_threads() << std::endl
              #endif
      	      << "library:routine = " << library_routine << std::endl
              << "dimension = " << dim << std::endl;

  rokko::mapping_bc<matrix_major> map = solver.default_mapping(dim, g);
  rokko::distributed_matrix<double, matrix_major> mat(map);
  mat.generate(&func);
  mat.print();

  Eigen::VectorXd eigval(dim);
  rokko::distributed_matrix<double, matrix_major> eigvec(map);
  rokko::parameters params;
  params.set("routine", routine);
  solver.diagonalize(mat, eigval, eigvec, params);

  if (myrank == 0) {
    std::cout << "largest eigenvalues:";
    //for (int i = 0; i < std::min(dim, 10); ++i) std::cout << ' ' << eigval(dim - 1 - i);
    for (int i = 0; i < dim; ++i) std::cout << ' ' << eigval(dim - 1 - i);
    std::cout << std::endl;
  }

  solver.finalize();
  MPI_Finalize();
}


<|start_filename|>rokko/serial_dense_ev_c.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/serial_dense_ev.h>
#include <rokko/serial_dense_ev.hpp>
#include <rokko/copy_string.hpp>

void rokko_serial_dense_ev_construct(rokko_serial_dense_ev* solver, const char* solver_name, int argc, char** argv) {
  solver->ptr = new rokko::serial_dense_ev(std::string(solver_name));
  static_cast<rokko::serial_dense_ev*>(solver->ptr)->initialize(argc, argv);
}

void rokko_serial_dense_ev_construct_f(rokko_serial_dense_ev* solver, const char* solver_name) {
  int argc = 0;
  char** argv = nullptr;
  rokko_serial_dense_ev_construct(solver, solver_name, argc, argv);
}

void rokko_serial_dense_ev_destruct(rokko_serial_dense_ev* solver) {
  rokko::serial_dense_ev* ptr = static_cast<rokko::serial_dense_ev*>(solver->ptr);
  ptr->finalize();
  delete ptr;
  solver->ptr = nullptr;
}

// eigenvalues/eigenvectors, no parameters
struct rokko_parameters rokko_serial_dense_ev_diagonalize_eigen_matrix(struct rokko_serial_dense_ev solver,
									   struct rokko_eigen_matrix mat, struct rokko_eigen_vector eigvals,
									   struct rokko_eigen_matrix eigvecs) {
  struct rokko_parameters params_out;
  rokko_parameters_construct(&params_out);
  if (mat.major == rokko_matrix_col_major)
    *static_cast<rokko::parameters*>(params_out.ptr) = static_cast<rokko::serial_dense_ev*>(solver.ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(mat.ptr),
								       *static_cast<Eigen::VectorXd*>(eigvals.ptr),
								       *static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(eigvecs.ptr));
  else
    *static_cast<rokko::parameters*>(params_out.ptr) = static_cast<rokko::serial_dense_ev*>(solver.ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(mat.ptr),
								       *static_cast<Eigen::VectorXd*>(eigvals.ptr));
  return params_out;
}

// only eigenvalues, no parameters
struct rokko_parameters rokko_serial_dense_ev_diagonalize_eigvals(struct rokko_serial_dense_ev solver,
						   struct rokko_eigen_matrix mat, struct rokko_eigen_vector eigvals) {
  struct rokko_parameters params_out;
  rokko_parameters_construct(&params_out);
  if (mat.major == rokko_matrix_col_major)
    *static_cast<rokko::parameters*>(params_out.ptr) = static_cast<rokko::serial_dense_ev*>(solver.ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(mat.ptr),
								       *static_cast<Eigen::VectorXd*>(eigvals.ptr));
  else
    *static_cast<rokko::parameters*>(params_out.ptr) = static_cast<rokko::serial_dense_ev*>(solver.ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(mat.ptr),
								       *static_cast<Eigen::VectorXd*>(eigvals.ptr));
  return params_out;
}

// only eigenvalues, parameters
struct rokko_parameters rokko_serial_dense_ev_diagonalize_eigvals_params(struct rokko_serial_dense_ev solver,
    struct rokko_eigen_matrix mat, struct rokko_eigen_vector eigvals,
    struct rokko_parameters /* params */) {
  struct rokko_parameters params_out;
  rokko_parameters_construct(&params_out);
  if (mat.major == rokko_matrix_col_major)
    *static_cast<rokko::parameters*>(params_out.ptr) = static_cast<rokko::serial_dense_ev*>(solver.ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(mat.ptr),
								       *static_cast<Eigen::VectorXd*>(eigvals.ptr));
  else
    *static_cast<rokko::parameters*>(params_out.ptr) = static_cast<rokko::serial_dense_ev*>(solver.ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(mat.ptr),
								       *static_cast<Eigen::VectorXd*>(eigvals.ptr));
  return params_out;
}

// eigenvalues/eigenvectors, parameters
struct rokko_parameters rokko_serial_dense_ev_diagonalize_params(struct rokko_serial_dense_ev solver,
								 struct rokko_eigen_matrix mat, struct rokko_eigen_vector eigvals,
								 struct rokko_eigen_matrix eigvecs,
								 struct rokko_parameters params) {
  struct rokko_parameters params_out;
  rokko_parameters_construct(&params_out);
  if (mat.major == rokko_matrix_col_major)
    *static_cast<rokko::parameters*>(params_out.ptr) = static_cast<rokko::serial_dense_ev*>(solver.ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(mat.ptr),
								       *static_cast<Eigen::VectorXd*>(eigvals.ptr),
								       *static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(eigvecs.ptr),
								       *static_cast<rokko::parameters*>(params.ptr));
  else
    *static_cast<rokko::parameters*>(params_out.ptr) = static_cast<rokko::serial_dense_ev*>(solver.ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(mat.ptr),
								       *static_cast<Eigen::VectorXd*>(eigvals.ptr),
								       *static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(eigvecs.ptr),
								       *static_cast<rokko::parameters*>(params.ptr));
  return params_out;
}

// For Fortran binding
// eigenvalues/eigenvectors, parameters
void rokko_serial_dense_ev_diagonalize_f(struct rokko_serial_dense_ev* solver,
					 struct rokko_eigen_matrix* mat, struct rokko_eigen_vector* eigvals,
					 struct rokko_eigen_matrix* eigvecs,
					 struct rokko_parameters* params, struct rokko_parameters* params_out) {
  rokko_parameters_construct(params_out);
  if (mat->major == rokko_matrix_col_major)
    *static_cast<rokko::parameters*>(params_out->ptr) = static_cast<rokko::serial_dense_ev*>(solver->ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(mat->ptr),
								       *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								       *static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(eigvecs->ptr),
								       *static_cast<rokko::parameters*>(params->ptr));
  else
    *static_cast<rokko::parameters*>(params_out->ptr) = static_cast<rokko::serial_dense_ev*>(solver->ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(mat->ptr),
								       *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								       *static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(eigvecs->ptr),
								       *static_cast<rokko::parameters*>(params->ptr));
}

void rokko_serial_dense_ev_diagonalize_no_params_out_f(struct rokko_serial_dense_ev* solver,
						       struct rokko_eigen_matrix* mat, struct rokko_eigen_vector* eigvals,
						       struct rokko_eigen_matrix* eigvecs,
						       struct rokko_parameters* params) {
  if (mat->major == rokko_matrix_col_major)
    static_cast<rokko::serial_dense_ev*>(solver->ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(mat->ptr),
								   *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								   *static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(eigvecs->ptr),
								   *static_cast<rokko::parameters*>(params->ptr));
  else
    static_cast<rokko::serial_dense_ev*>(solver->ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(mat->ptr),
								   *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								   *static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(eigvecs->ptr),
								   *static_cast<rokko::parameters*>(params->ptr));
}


void rokko_serial_dense_ev_diagonalize_no_params_inout_f(struct rokko_serial_dense_ev* solver,
							 struct rokko_eigen_matrix* mat, struct rokko_eigen_vector* eigvals,
							 struct rokko_eigen_matrix* eigvecs) {
  if (mat->major == rokko_matrix_col_major)
    static_cast<rokko::serial_dense_ev*>(solver->ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(mat->ptr),
								   *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								   *static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(eigvecs->ptr));
  else
    static_cast<rokko::serial_dense_ev*>(solver->ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(mat->ptr),
								   *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								   *static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(eigvecs->ptr));
}

void rokko_serial_dense_ev_diagonalize_eigvals_f(struct rokko_serial_dense_ev* solver,
						 struct rokko_eigen_matrix* mat, struct rokko_eigen_vector* eigvals,
						 struct rokko_parameters* params, struct rokko_parameters* params_out) {
  rokko_parameters_construct(params_out);
  if (mat->major == rokko_matrix_col_major)
    *static_cast<rokko::parameters*>(params_out->ptr) = static_cast<rokko::serial_dense_ev*>(solver->ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(mat->ptr),
								       *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								       *static_cast<rokko::parameters*>(params->ptr));
  else
    *static_cast<rokko::parameters*>(params_out->ptr) = static_cast<rokko::serial_dense_ev*>(solver->ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(mat->ptr),
								       *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								       *static_cast<rokko::parameters*>(params->ptr));
}

void rokko_serial_dense_ev_diagonalize_eigvals_no_params_out_f(struct rokko_serial_dense_ev* solver,
							       struct rokko_eigen_matrix* mat, struct rokko_eigen_vector* eigvals,
							       struct rokko_parameters* params) {
  if (mat->major == rokko_matrix_col_major)
    static_cast<rokko::serial_dense_ev*>(solver->ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(mat->ptr),
								   *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								   *static_cast<rokko::parameters*>(params->ptr));
  else
    static_cast<rokko::serial_dense_ev*>(solver->ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(mat->ptr),
								   *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								   *static_cast<rokko::parameters*>(params->ptr));
}

void rokko_serial_dense_ev_diagonalize_eigvals_no_params_inout_f(struct rokko_serial_dense_ev* solver,
								 struct rokko_eigen_matrix* mat, struct rokko_eigen_vector* eigvals) {
  if (mat->major == rokko_matrix_col_major)
    static_cast<rokko::serial_dense_ev*>(solver->ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(mat->ptr),
								   *static_cast<Eigen::VectorXd*>(eigvals->ptr));
  else
    static_cast<rokko::serial_dense_ev*>(solver->ptr)->diagonalize(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(mat->ptr),
								   *static_cast<Eigen::VectorXd*>(eigvals->ptr));
}


int rokko_serial_dense_ev_num_solvers() {
  return rokko::serial_dense_ev::solvers().size();
}

char** rokko_serial_dense_ev_solvers() {
  std::vector<std::string> solvers = rokko::serial_dense_ev::solvers();
  char **solvers_c = (char**)malloc((size_t)(solvers.size() * sizeof(char*)));
  for (std::size_t i = 0; i < solvers.size(); ++i) {
    solvers_c[i] = copy_string(solvers[i]);
  }
  return solvers_c;
}

const char* rokko_serial_dense_ev_default_solver() {
  return rokko::serial_dense_ev::default_solver().c_str();
}


<|start_filename|>rokko/collective.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_COLLECTIVE_HPP
#define ROKKO_COLLECTIVE_HPP

#include <mpi.h>
#include <array>
#include <stdexcept>
#include <rokko/blacs.hpp>
#include <rokko/scalapack.hpp>
#include <rokko/pblas/pcopy.hpp>
#include <rokko/distributed_matrix.hpp>
#include <rokko/eigen3.hpp>

namespace rokko {

template<typename T, typename MATRIX_MAJOR>
void gather(rokko::distributed_matrix<T, MATRIX_MAJOR> const& from, T* to, int root) {
  if (!from.is_col_major()) {
    throw std::invalid_argument("gather: matrix_row_major is not supported");
  }
  int ictxt = from.get_grid().get_blacs_context();
  int m = from.get_m_global();
  int n = from.get_n_global();
  int rsrc = (from.get_grid().is_row_major() ? (root / from.get_npcol()) :
              (root % from.get_nprow()));
  int csrc = (from.get_grid().is_row_major() ? (root % from.get_npcol()) :
              (root / from.get_nprow()));
  const std::array<int,9>& descFrom = from.get_mapping().get_blacs_descriptor();
  std::array<int,9> descTo;
  scalapack::descinit(descTo, m, n, m, n, rsrc, csrc, ictxt, m);
  for (int j = 0; j < n; ++j)
    pblas::pcopy(m, from.get_array_pointer(), 0, j, descFrom.data(), 1, to, 0, j, descTo.data(), 1);
}

template<typename T, int ROWS, int COLS, typename MATRIX_MAJOR>
void gather(rokko::distributed_matrix<T, MATRIX_MAJOR> const& from,
  Eigen::Matrix<T,ROWS,COLS,rokko::eigen3_major<MATRIX_MAJOR>>& to, int root) {
  gather(from, to.data(), root);
}

template<typename T, typename MATRIX_MAJOR>
void scatter(const T* from, distributed_matrix<T, MATRIX_MAJOR>& to, int root) {
  if (!to.is_col_major()) {
    throw std::invalid_argument("scatter: matrix_row_major is not supported");
  }
  int ictxt = to.get_grid().get_blacs_context();
  int m = to.get_m_global();
  int n = to.get_n_global();
  int rsrc = (to.get_grid().is_row_major() ? (root / to.get_npcol()) : (root % to.get_nprow()));
  int csrc = (to.get_grid().is_row_major() ? (root % to.get_npcol()) : (root / to.get_nprow()));
  std::array<int,9> descFrom;
  scalapack::descinit(descFrom, m, n, m, n, rsrc, csrc, ictxt, m);
  const std::array<int,9>& descTo = to.get_mapping().get_blacs_descriptor();
  for (int j = 0; j < n; ++j)
    pblas::pcopy(m, from, 0, j, descFrom.data(), 1, to.get_array_pointer(), 0, j, descTo.data(), 1);
}

template<typename T, int ROWS, int COLS, typename MATRIX_MAJOR>
void scatter(Eigen::Matrix<T,ROWS,COLS,rokko::eigen3_major<MATRIX_MAJOR>> const& from,
  distributed_matrix<T, MATRIX_MAJOR>& to, int root) {
  scatter(from.data(), to, root);
}

} // namespace rokko

#endif // ROKKO_COLLECTIVE_HPP


<|start_filename|>tutorial/titpack/03_rokko_cxx/sample-11_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

// C++ version of TITPACK Ver.2 by <NAME>

/************ Sample main program #11 *****************
* 1d Heisenberg antiferromagnet with 8 spins
* Eigenvalues and an eigenvector by diag
******************************************************/

#include <mpi.h>
#include <iostream>
#include <chrono>
#include <rokko/rokko.hpp>
#include "titpack.hpp"
#include "options.hpp"

using solver_type = rokko::parallel_dense_ev;
using matrix_major = rokko::matrix_col_major;
using matrix_type = rokko::distributed_matrix<double, matrix_major>;

int main(int argc, char** argv) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  rokko::grid g;

  std::cout.precision(10);
  options opt(argc, argv, 8, solver_type::default_solver(), g.get_myrank() == 0);
  if (!opt.valid) MPI_Abort(MPI_COMM_WORLD, 1);
  MPI_Barrier(g.get_comm());
  std::chrono::system_clock::time_point t1 = std::chrono::system_clock::now();

  // lattice structure
  int n = opt.N;
  int ibond = n;
  std::vector<int> ipair;
  for (int i = 0; i < ibond; ++i) {
    ipair.emplace_back(i);
    ipair.emplace_back((i + 1) % n);
  }

  // Hamiltonian parameters
  std::vector<double> bondwt(ibond, -1);
  std::vector<double> zrtio(ibond, 1);

  // table of configurations and Hamiltonian operator
  subspace ss(n, 0);
  hamiltonian hop(ss, ipair, bondwt, zrtio);
  solver_type solver(opt.solver);
  rokko::mapping_bc<matrix_major> map = solver.default_mapping(hop.dimension(), g);

  solver.initialize(argc, argv);

  // Hamiltonian matrix
  matrix_type elemnt(map);
  elm3(hop, elemnt);
  MPI_Barrier(g.get_comm());
  std::chrono::system_clock::time_point t2 = std::chrono::system_clock::now();
  
  Eigen::VectorXd E(hop.dimension());
  matrix_type v(map);
  solver.diagonalize(elemnt, E, v);
  std::chrono::system_clock::time_point t3 = std::chrono::system_clock::now();

  if (g.get_myrank() == 0) {
    int ne = 4;
    std::cout << "[Eigenvalues]\n";
    for (int i = 0; i < ne; ++i) std::cout << '\t' << E[i];
    std::cout << std::endl << std::flush;
  }
  MPI_Barrier(g.get_comm());

  // Do not forget to call elm3 again before calling check3
  elm3(hop, elemnt);
  matrix_type w(map);
  check3_mpi(elemnt, v, 0, w);
  std::cout << std::flush;
  MPI_Barrier(g.get_comm());
  std::chrono::system_clock::time_point t4 = std::chrono::system_clock::now();
  
  std::vector<int> npair;
  npair.emplace_back(1);
  npair.emplace_back(2);
  std::vector<double> sxx(1);
  matrix_type sxmat(map);
  xcorr3_mpi(ss, npair, v, 0, sxx, sxmat, w);
  if (v.has_global_indices({0, 0})) std::cout << "sxx: " << sxx[0] << std::endl;
  std::cout << std::flush;
  MPI_Barrier(g.get_comm());
  std::vector<double> szz(1);
  zcorr_mpi(ss, npair, v, 0, szz);
  if (g.get_myrank() == 0) std::cout << "szz: " << szz[0] << std::endl;
  std::cout << std::flush;
  MPI_Barrier(g.get_comm());
  std::chrono::system_clock::time_point t5 = std::chrono::system_clock::now();

  if (g.get_myrank() == 0) {
    std::cerr << "initialize      " << 1.0e-6 * std::chrono::duration_cast<std::chrono::microseconds>(t2-t1).count() << " sec\n"
              << "diagonalization " << 1.0e-6 * std::chrono::duration_cast<std::chrono::microseconds>(t3-t2).count() << " sec\n"
              << "check           " << 1.0e-6 * std::chrono::duration_cast<std::chrono::microseconds>(t4-t3).count() << " sec\n"
              << "correlation     " << 1.0e-6 * std::chrono::duration_cast<std::chrono::microseconds>(t5-t4).count() << " sec\n";
  }
  MPI_Finalize();
}


<|start_filename|>example/elpa/elpa.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <mpi.h>
#include <cmath>
#include <iostream>
#include <rokko/distributed_matrix.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/elpa.hpp>
#include <rokko/elpa/diagonalize_set_parameters.hpp>

int main(int argc, char** argv) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  if (elpa_init(20200417) != ELPA_OK) {
    throw std::invalid_argument("ERROR: elpa::initialize()");
  }
  rokko::grid grid(MPI_COMM_WORLD);

  int n = 8;
  if (argc > 1) n = std::atoi(argv[1]);

  if (grid.get_myrank() == 0) {
    std::cout << "n = " << n << std::endl;
    std::cout << "nprocs = " << grid.get_nprocs() << std::endl;
    std::cout << "nprow = " << grid.get_nprow() << std::endl;
    std::cout << "npcol = " << grid.get_npcol() << std::endl;
  }

  rokko::mapping_bc<rokko::matrix_col_major> map(n, 1);
  rokko::distributed_matrix<double> a(map), eigvecs(map);
  Eigen::VectorXd eigvals(n);
  for (int j = 0; j < n; ++j)
    for (int i = 0; i < n; ++i)
      a.set_global(i, j, std::min(i, j) + 1);

  int error;
  elpa_t handle = elpa_allocate(&error);

  rokko::parameters params;
  params.set("routine", "elpa2");
  rokko::elpa::set_parameters(a, params, handle);
  assert_elpa_ok(elpa_setup(handle));

  rokko::elpa::set_solver(params, handle);
  int info = rokko::elpa::diag(handle, a, eigvals, eigvecs);
  assert_elpa_ok( rokko::elpa::deallocate(handle) );

  if (grid.get_myrank() == 0)
    std::cout << "eigenvalues: " << eigvals.transpose() << std::endl;

  MPI_Finalize();
  return 0;
}


<|start_filename|>example/cxx/random/sgv.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <random>

using vector_t = Eigen::VectorXd;

int main() {
  int n = 6;
  vector_t v(n);
  std::mt19937 engine(12345lu);
  std::normal_distribution<> dist(0.0, 1.0);
  for (int i = 0; i < n; ++i) v(i) = dist(engine);
  std::cout << "v: " << v << std::endl;
}


<|start_filename|>example/lapack/lange.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2017 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <rokko/lapack/lange.hpp>
#include <rokko/eigen3.hpp>
#include <iostream>

int main() {
  int m = 5;
  int n = 3;
  
  Eigen::MatrixXf a = Eigen::MatrixXf::Random(m, n);
  std::cout << "Matrix A: " << std::endl << a << std::endl;
  std::cout << "|| A || = " << rokko::lapack::lange('F', a) << std::endl;

  Eigen::MatrixXd b = Eigen::MatrixXd::Random(m, n);
  std::cout << "Matrix B: " << std::endl << b << std::endl;
  std::cout << "|| B || = " << rokko::lapack::lange('F', b) << std::endl;

  Eigen::MatrixXcf c = Eigen::MatrixXcf::Random(m, n);
  std::cout << "Matrix : C" << std::endl << c << std::endl;
  std::cout << "|| C || = " << rokko::lapack::lange('F', c) << std::endl;

  Eigen::MatrixXcd d = Eigen::MatrixXcd::Random(m, n);
  std::cout << "Matrix D: " << std::endl << d << std::endl;
  std::cout << "|| D || = " << rokko::lapack::lange('F', d) << std::endl;
  
  return 0;
}


<|start_filename|>rokko/serial_dense_ev.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SERIAL_DENSE_SOLVER_HPP
#define ROKKO_SERIAL_DENSE_SOLVER_HPP

#include <string>
#include <rokko/factory.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/utility/macro_join.hpp>
#include <rokko/utility/timer.hpp>
#include <rokko/parameters.hpp>

namespace rokko {

namespace detail {

class sd_ev_base {
public:
  virtual ~sd_ev_base() = default;
  virtual void initialize(int& argc, char**& argv) = 0;
  virtual void finalize() = 0;
  // -------------- standard eigenvalue probelm ---------------
  // float with parameters, eigenvalues/eigenvectors
  virtual parameters diagonalize(Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
				 Eigen::VectorXf& eigvals,
				 Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
				 Eigen::VectorXf& eigvals,
				 Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
				 std::vector<float>& eigvals,
				 Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
				 std::vector<float>& eigvals,
				 Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& eigvecs,
				 parameters const& params) = 0;
  // float with parameters, only eigenvalues
  virtual parameters diagonalize(Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
				 Eigen::VectorXf& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
				 Eigen::VectorXf& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
				 std::vector<float>& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
				 std::vector<float>& eigvals,
				 parameters const& params) = 0;
  // complex float with parameters, eigenvalues/eigenvectors
  virtual parameters diagonalize(Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
				 Eigen::VectorXf& eigvals,
				 Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
				 Eigen::VectorXf& eigvals,
				 Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
				 std::vector<float>& eigvals,
				 Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
				 std::vector<float>& eigvals,
				 Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& eigvecs,
				 parameters const& params) = 0;
  // complex float with parameters, only eigenvalues
  virtual parameters diagonalize(Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
				 Eigen::VectorXf& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
				 Eigen::VectorXf& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
				 std::vector<float>& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
				 std::vector<float>& eigvals,
				 parameters const& params) = 0;
  // double with parameters, eigenvalues/eigenvectors
  virtual parameters diagonalize(Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
				 Eigen::VectorXd& eigvals,
				 Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
				 Eigen::VectorXd& eigvals,
				 Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
				 std::vector<double>& eigvals,
				 Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
				 std::vector<double>& eigvals,
				 Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& eigvecs,
				 parameters const& params) = 0;
  // double with parameters, only eigenvalues
  virtual parameters diagonalize(Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
				 Eigen::VectorXd& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
				 Eigen::VectorXd& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
				 std::vector<double>& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
				 std::vector<double>& eigvals,
				 parameters const& params) = 0;
  // complex double with parameters, eigenvalues/eigenvectors
  virtual parameters diagonalize(Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
				 Eigen::VectorXd& eigvals,
				 Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
				 Eigen::VectorXd& eigvals,
				 Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
				 std::vector<double>& eigvals,
				 Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
				 std::vector<double>& eigvals,
				 Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& eigvecs,
				 parameters const& params) = 0;
  // complex double with parameters, only eigenvalues
  virtual parameters diagonalize(Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
				 Eigen::VectorXd& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
				 Eigen::VectorXd& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
				 std::vector<double>& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
				 std::vector<double>& eigvals,
				 parameters const& params) = 0;
};
  
template<typename SOLVER>
class sd_ev_wrapper : public sd_ev_base {
  using solver_type = SOLVER;
public:
  sd_ev_wrapper() : solver_impl_() {}
  virtual ~sd_ev_wrapper() = default;
  void initialize(int& argc, char**& argv) override {
    solver_impl_.initialize(argc, argv);
  }
  void finalize() override { solver_impl_.finalize(); }
  // -------------- standard eigenvalue probelm ---------------
  // float with parameters, eigenvalues/eigenvectors
  parameters diagonalize(Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
			 Eigen::VectorXf& eigvals, Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
			 Eigen::VectorXf& eigvals, Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
			 std::vector<float>& eigvals, Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
			 std::vector<float>& eigvals, Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  // float with parameters, only eigenvalues
  parameters diagonalize(Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
			 Eigen::VectorXf& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
			 Eigen::VectorXf& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
			 std::vector<float>& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
			 std::vector<float>& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  // complex float with parameters, eigenvalues/eigenvectors
  parameters diagonalize(Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
			 Eigen::VectorXf& eigvals, Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
			 Eigen::VectorXf& eigvals, Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
			 std::vector<float>& eigvals, Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
			 std::vector<float>& eigvals, Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  // complex float with parameters, only eigenvalues
  parameters diagonalize(Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
			 Eigen::VectorXf& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
			 Eigen::VectorXf& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
			 std::vector<float>& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(Eigen::Matrix<std::complex<float>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
			 std::vector<float>& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  // double with parameters, eigenvalues/eigenvectors
  parameters diagonalize(Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
			 Eigen::VectorXd& eigvals, Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
			 Eigen::VectorXd& eigvals, Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
			 std::vector<double>& eigvals, Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
			 std::vector<double>& eigvals, Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  // double with parameters, only eigenvalues
  parameters diagonalize(Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
			 Eigen::VectorXd& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
			 Eigen::VectorXd& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
			 std::vector<double>& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
			 std::vector<double>& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  // complex double with parameters, eigenvalues/eigenvectors
  parameters diagonalize(Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
			 Eigen::VectorXd& eigvals, Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
			 Eigen::VectorXd& eigvals, Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
			 std::vector<double>& eigvals, Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
			 std::vector<double>& eigvals, Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  // complex double with parameters, only eigenvalues
  parameters diagonalize(Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
			 Eigen::VectorXd& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
			 Eigen::VectorXd& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>& mat,
			 std::vector<double>& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(Eigen::Matrix<std::complex<double>,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>& mat,
			 std::vector<double>& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }

private:
  solver_type solver_impl_;
};
    
using sd_solver_factory = factory<sd_ev_base>;
  
} // end namespace detail
  
class serial_dense_ev {
public:
  serial_dense_ev(std::string const& solver_name)
    : solver_impl_(detail::sd_solver_factory::instance()->make_product(solver_name)) {}

  serial_dense_ev() : serial_dense_ev(default_solver()) {}

  void initialize(int& argc, char**& argv) {
    solver_impl_->initialize(argc, argv);
  }
  void finalize() {
    solver_impl_->finalize();
  }
  // -------------- standard eigenvalue probelm ---------------
  // with parameters, eigenvalues/eigenvectors
  template<typename T, int MATRIX_MAJOR, typename VEC>
  parameters diagonalize(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat, VEC& eigvals,
			 Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& eigvecs,
			 parameters const& params) {
    return solver_impl_->diagonalize(mat, eigvals, eigvecs, params);
  }
  // with parameters, only eigenvalues
  template<typename T, int MATRIX_MAJOR, typename VEC>
  parameters diagonalize(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat, VEC& eigvals,
			 parameters const& params) {
    return solver_impl_->diagonalize(mat, eigvals, params);
  }
  // no parameters, eigenvalues/eigenvectors
  template<typename T, int MATRIX_MAJOR, typename VEC>
  parameters diagonalize(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat, VEC& eigvals,
			 Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& eigvecs) {
    return solver_impl_->diagonalize(mat, eigvals, eigvecs, null_params);
  }
  // no parameters, only eigenvalues
  template<typename T, int MATRIX_MAJOR, typename VEC>
  parameters diagonalize(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat, VEC& eigvals) {
    return solver_impl_->diagonalize(mat, eigvals, null_params);
  }  
  static std::vector<std::string> solvers() {
    return detail::sd_solver_factory::product_names();
  }
  static const std::string& default_solver() {
    return detail::sd_solver_factory::default_product_name();
  }
private:
  detail::sd_solver_factory::product_pointer_type solver_impl_;
  parameters null_params;
  //std::string routine_;
};

} // end namespace rokko

#define ROKKO_REGISTER_SERIAL_DENSE_SOLVER(solver, name, priority) \
namespace { namespace ROKKO_JOIN(register, __LINE__) { \
struct register_caller { \
  using factory = rokko::detail::sd_solver_factory;     \
  using product = rokko::detail::sd_ev_wrapper<solver>; \
  register_caller() { factory::instance()->register_creator<product>(name, priority); } \
} caller; \
} }

#endif // ROKKO_SERIAL_DENSE_SOLVER_HPP


<|start_filename|>rokko/pblas/pgemm.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cpblas.h>
#include <rokko/pblas/pblas_interface.h>

#define CPBLAS_PGEMM_IMPL(NAMES, NAMEL, TYPEC, TYPEX) \
void cpblas_ ## NAMES (char transa, char transb, int m, int n, int k, TYPEC alpha, const TYPEC * a, int ia, int ja, const int* desca, const TYPEC * b, int ib, int jb, const int* descb, TYPEC beta, TYPEC * c, int ic, int jc, const int* descc) { \
  int ia_f = ia + 1; \
  int ja_f = ja + 1; \
  int ib_f = ib + 1; \
  int jb_f = jb + 1; \
  int ic_f = ic + 1; \
  int jc_f = jc + 1; \
  ROKKO_GLOBAL(NAMES, NAMEL) (&transa, &transb, &m, &n, &k, &alpha, a, &ia_f, &ja_f, desca, b, &ib_f, &jb_f, descb, &beta, c, &ic_f, &jc_f, descc); \
}

CPBLAS_PGEMM_IMPL(psgemm, PSGEMM, float, float);
CPBLAS_PGEMM_IMPL(pdgemm, PDGEMM, double, double);
CPBLAS_PGEMM_IMPL(pcgemm, PCGEMM, lapack_complex_float, std::complex<float>);
CPBLAS_PGEMM_IMPL(pzgemm, PZGEMM, lapack_complex_double, std::complex<double>);

#undef CPBLAS_PGEMM_IMPL


<|start_filename|>rokko/parallel_sparse_ev.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2016 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_PARALLEL_SPARSE_EV_H
#define ROKKO_PARALLEL_SPARSE_EV_H

#include <rokko/mapping_1d.h>
#include <rokko/distributed_crs_matrix.h>
#include <rokko/distributed_mfree.h>
#include <rokko/parameters.h>

#ifdef __cplusplus
extern "C" {
#endif

struct rokko_parallel_sparse_ev {
  void* ptr;
};

void rokko_parallel_sparse_ev_construct(struct rokko_parallel_sparse_ev* solver,
  const char* solver_name, int argc, char** argv);
void rokko_parallel_sparse_ev_construct_f(struct rokko_parallel_sparse_ev* solver,
  const char* solver_name);
void rokko_parallel_sparse_ev_destruct(struct rokko_parallel_sparse_ev* solver);
struct rokko_parameters rokko_parallel_sparse_ev_diagonalize_distributed_crs_matrix(struct rokko_parallel_sparse_ev solver,
										    struct rokko_distributed_crs_matrix mat,
										    struct rokko_parameters params);
struct rokko_parameters rokko_parallel_sparse_ev_diagonalize_distributed_mfree(struct rokko_parallel_sparse_ev solver,
									       struct rokko_distributed_mfree mat,
									       struct rokko_parameters params);

/* Fortran binding */
void rokko_parallel_sparse_ev_diagonalize_distributed_crs_matrix_f(struct rokko_parallel_sparse_ev* solver,
								   struct rokko_distributed_crs_matrix* mat,
								   struct rokko_parameters* params, struct rokko_parameters* params_out);
void rokko_parallel_sparse_ev_diagonalize_distributed_crs_matrix_noreturn_f(struct rokko_parallel_sparse_ev* solver,
									    struct rokko_distributed_crs_matrix* mat,
									    struct rokko_parameters* params);
void rokko_parallel_sparse_ev_diagonalize_distributed_mfree_f(struct rokko_parallel_sparse_ev* solver,
							      struct rokko_distributed_mfree* mat,
							      struct rokko_parameters* params, struct rokko_parameters* params_out);
void rokko_parallel_sparse_ev_diagonalize_distributed_mfree_noreturn_f(struct rokko_parallel_sparse_ev* solver,
								       struct rokko_distributed_mfree* mat,
								       struct rokko_parameters* params);

double rokko_parallel_sparse_ev_eigenvalue(struct rokko_parallel_sparse_ev solver, int i);
void rokko_parallel_sparse_ev_eigenvector(struct rokko_parallel_sparse_ev solver, int i,
  double* vec);
int rokko_parallel_sparse_ev_num_conv(struct rokko_parallel_sparse_ev solver);

struct rokko_mapping_1d rokko_parallel_sparse_ev_default_mapping(struct rokko_parallel_sparse_ev solver, int dim, MPI_Comm comm);
void rokko_parallel_sparse_ev_default_mapping_f(struct rokko_parallel_sparse_ev solver, int dim, int comm_f, struct rokko_mapping_1d* map);

int rokko_parallel_sparse_ev_num_solvers();
char** rokko_parallel_sparse_ev_solvers();
const char* rokko_parallel_sparse_ev_default_solver();

#ifdef __cplusplus
}
#endif

#endif /* ROKKO_PARALLEL_SPARSE_EV_H */


<|start_filename|>rokko/scalapack/pselset.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <rokko/scalapack/scalapack_interface.h>

void cscalapack_pselset(float* A, int ia, int ja, const int* descA, float alpha) {
  int ia_f = ia + 1;
  int ja_f = ja + 1;
  SCALAPACK_pselset(A, &ia_f, &ja_f, descA, &alpha);
}


<|start_filename|>rokko/blas/gemv.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_BLAS_GEMV_HPP
#define ROKKO_BLAS_GEMV_HPP

#include <complex>
#ifdef I
# undef I
#endif
#include <stdexcept>
#include <cblas.h>
#include <rokko/blas/util.hpp>
#include <rokko/lapack/complex_cast.hpp>

namespace rokko {
namespace blas {

#define BLAS_GEMV_IMPL(NAMES, TYPE) \
inline void gemv(CBLAS_ORDER order, CBLAS_TRANSPOSE trans, int m, int n, TYPE alpha, const TYPE * a, int lda, const TYPE * x, int inc_x, TYPE beta, TYPE * y, int inc_y) { \
  cblas_ ## NAMES (order, trans, m, n, alpha, a, lda, x, inc_x, beta, y, inc_y); \
}

BLAS_GEMV_IMPL(sgemv, float);
BLAS_GEMV_IMPL(dgemv, double);
  
#undef BLAS_GEMV_IMPL  
  
#define BLAS_GEMV_IMPL(NAMES, TYPE) \
inline void gemv(CBLAS_ORDER order, CBLAS_TRANSPOSE trans, int m, int n, TYPE alpha, const TYPE * a, int lda, const TYPE * x, int inc_x, TYPE beta, TYPE * y, int inc_y) { \
  cblas_ ## NAMES (order, trans, m, n, &alpha, lapack::complex_cast(a), lda, lapack::complex_cast(x), inc_x, &beta, lapack::complex_cast(y), inc_y); \
}

BLAS_GEMV_IMPL(cgemv, std::complex<float>);
BLAS_GEMV_IMPL(zgemv, std::complex<double>);
  
#undef BLAS_GEMV_IMPL  
  
template<typename MATRIX, typename VECTOR, typename T>
void gemv(CBLAS_TRANSPOSE trans, T alpha, const MATRIX& a, const VECTOR& x, int inc_x,
          T beta, VECTOR& y, int inc_y) {
  if (util::op_cols(trans, a) != size(x) / inc_x ||
      util::op_cols(trans, a) != size(y) / inc_y)
    throw std::invalid_argument("matrix/vector size mismatch");
  int m = util::op_rows(trans, a);
  int n = util::op_cols(trans, a);
  gemv((is_col_major(a) ? CblasColMajor : CblasRowMajor), trans, m, n, alpha, storage(a),
       ld(a), storage(x), inc_x, beta, storage(y), inc_y);
}

} // namespace blas
} // namespace rokko

#endif // ROKKO_BLAS_GEMV_HPP


<|start_filename|>rokko/utility/heisenberg_hamiltonian_mpi.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_HEISENBERG_HAMILTONIAN_MPI_H
#define ROKKO_UTILITY_HEISENBERG_HAMILTONIAN_MPI_H

#include "mpi.h"

void multiply(const MPI_Comm comm, int L, int lattice_size, int lattice_first[], int lattice_second[], const double* v, double* w, double* buffer) {
  int myrank, nproc;
  MPI_Status status;

  MPI_Comm_size(comm, &nproc);
  MPI_Comm_rank(comm, &myrank);

  int n = nproc;
  int p = -1;
  do {
    n /= 2;
    ++p;
  } while (n > 0);

  if (nproc != (1 << p)) {
    if ( myrank == 0 ) {
      printf("This program can be run only for powers of 2\n");
    }
    MPI_Abort(comm, 1);
  }

  int N = 1 << (L-p);

  for(int k=0; k<N; ++k) {
    w[k] = 0.;
  }

  for (size_t l = 0; l < lattice_size; ++l) {
    int i = lattice_first[l];
    int j = lattice_second[l];
    if (i < (L-p)) {
      if (j < (L-p)) {
        int m1 = 1 << i;
        int m2 = 1 << j;
        int m3 = m1 + m2;
#ifdef _OPENMP
#pragma omp parallel for
#endif
        for (int k=0; k<N; ++k) {
          if ((k & m3) == m1) {  // when (bit i == 1, bit j == 0) or (bit i == 0, bit j == 1)
            w[k] += 0.5 * v[k^m3] - 0.25 * v[k];
          } else if ((k & m3) == m2) {
            w[k] += 0.5 * v[k^m3] - 0.25 * v[k];
          } else {
            w[k] += 0.25 * v[k];
          }
        }
      } else {
        int m = 1 << (j-(L-p));
        MPI_Sendrecv(v, N, MPI_DOUBLE,
                     myrank ^ m, 0,
                     buffer, N, MPI_DOUBLE,
                     myrank ^ m, 0,
                     comm, &status);
        int m1 = 1 << i;
        if ((myrank & m) == m) {
#ifdef _OPENMP
#pragma omp parallel for
#endif
          for (int k=0; k<N; ++k) {
            if ((k & m1) == m1) {
              w[k] += 0.25 * v[k];
            } else {
              w[k] += 0.5 * buffer[k^m1] - 0.25 * v[k];
            }
          }
        } else {
#ifdef _OPENMP
#pragma omp parallel for
#endif
          for (int k=0; k<N; ++k) {
            if ((k & m1) == m1) {
              w[k] += 0.5 * buffer[k^m1] - 0.25 * v[k];
            } else {
              w[k] += 0.25 * v[k];
            }
          }
        }
      }
    } else {
      if (j < (L-p)) {
        int m = 1 << (i-(L-p));
        MPI_Sendrecv(v, N, MPI_DOUBLE,
                     myrank ^ m, 0,
                     buffer, N, MPI_DOUBLE,
                     myrank ^ m, 0,
                     comm, &status);
        int m1 = 1 << j;
        if ((myrank & m) == m) {
#ifdef _OPENMP
#pragma omp parallel for
#endif
          for (int k=0; k<N; ++k) {
            if ((k & m1) == m1) {
              w[k] += 0.25 * v[k];
            } else {
              w[k] += 0.5 * buffer[k^m1] - 0.25 * v[k];
            }
          }
        } else {
#ifdef _OPENMP
#pragma omp parallel for
#endif
          for (int k=0; k<N; ++k) {
            if ((k & m1) == m1) {
              w[k] += 0.5 * buffer[k^m1] - 0.25 * v[k];
            } else {
              w[k] += 0.25 * v[k];
            }
          }
        }
      } else {
        int m = (1 << (i-(L-p))) + (1 << (j-(L-p)));
        if (((myrank & m) != m) && ((myrank & m) != 0)) {
          MPI_Sendrecv(v, N, MPI_DOUBLE,
                       myrank ^ m, 0,
                       buffer, N, MPI_DOUBLE,
                       myrank ^ m, 0,
                       comm, &status);
#ifdef _OPENMP
#pragma omp parallel for
#endif
          for (int k=0; k<N; ++k) {
            w[k] += 0.5 * buffer[k] - 0.25 * v[k];
          }
        } else {
#ifdef _OPENMP
#pragma omp parallel for
#endif
          for (int k=0; k<N; ++k) {
            w[k] += 0.25 * v[k];
          }
        }
      }
    }
  }
}

#endif // ROKKO_UTILITY_HEISENBERG_HAMILTONIAN_MPI_H


<|start_filename|>example/cxx/sparse/laplacian_crs_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/laplacian_matrix.hpp>
#include <rokko/utility/solver_name.hpp>

#include <stdexcept>

int main(int argc, char *argv[]) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  int rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);

  std::string library_routine(rokko::parallel_sparse_ev::default_solver());
  std::string library, routine;
  if (argc >= 2) library_routine = argv[1];
  rokko::split_solver_name(library_routine, library, routine);
  
  int dim = (argc >= 3) ? std::stoi(argv[2]) : 100;

  rokko::parameters params;
  if (!routine.empty()) params.set("routine", routine);
  params.set("Block Size", 5);
  params.set("Maximum Iterations", 500);
  params.set("Convergence Tolerance", 1.0e-8);
  params.set("num_eigenvalues", 10);
  rokko::parallel_sparse_ev solver(library);
  auto map = solver.default_mapping(dim, rokko::mpi_comm{MPI_COMM_WORLD});
  rokko::distributed_crs_matrix mat(map, 3);

  if (map.start_row() == 0) {
    mat.insert(0, {0, 1}, {1., -1.});
  }

  for (int row = std::max(1,map.start_row()); row < std::min(map.end_row(),dim-1); ++row) {
    mat.insert(row, {row-1, row, row+1}, {-1., 2., -1.});
  }

  if (map.end_row() == dim) {
    mat.insert(dim-1, {dim-2, dim-1}, {-1., 2.});
  }

  mat.complete();
  if (rank == 0)
    std::cout << "Eigenvalue decomposition of Laplacian" << std::endl
	      << "solver = " << library << std::endl
	      << "dimension = " << dim << std::endl;
  
  rokko::parameters info = solver.diagonalize(mat, params);
  
  int num_conv = info.get<int>("num_conv");
  if (num_conv == 0)
    throw std::runtime_error("num_conv=0: solver did not converge");
  std::vector<double> eigvec;
  solver.eigenvector(0, eigvec);
  if (rank == 0) {
    std::cout << "number of converged eigenpairs = " << num_conv << std::endl;
    std::cout << "largest eigenvalues:     ";
    for (int i = 0; i < num_conv; ++i) std::cout << solver.eigenvalue(i) << ' ';
    std::cout << std::endl;
    std::cout << "theoretical eigenvalues: ";
    for (int k = dim - 1; k >= dim - num_conv; --k)
        std::cout << rokko::laplacian_matrix::eigenvalue(dim, k) << ' ';
    std::cout << std::endl;
    std::cout << "largest eigenvector: ";
    for (int j = 0; j < eigvec.size(); ++j) std::cout << eigvec[j] << ' ';
    std::cout << std::endl;
  }
  
  solver.finalize();
  MPI_Finalize();
}


<|start_filename|>benchmark/no_rokko/sparse_heisenberg_file_mpi/slepc_mfree.cpp<|end_filename|>
#include <slepceps.h>
#include <rokko/utility/heisenberg_hamiltonian_mpi.hpp>
#include <rokko/utility/lattice.hpp>

struct model {
  MPI_Comm comm;
  int L;
  std::vector<std::pair<int, int>> lattice;
  double* buffer;
};

/*
   User-defined routines
*/
PetscErrorCode MatMult(Mat A, Vec x, Vec y);
PetscErrorCode MatGetDiagonal(Mat A, Vec diag);

#undef __FUNCT__
#define __FUNCT__ "main"
int main(int argc,char **argv)
{
  Mat            A;               /* operator matrix */
  EPS            eps;             /* eigenproblem solver context */
  EPSType        type;
  PetscMPIInt    rank, nproc;
  PetscInt       nev;
  PetscErrorCode ierr;
  double init_tick, initend_tick, gen_tick, diag_tick, end_tick;

  int provided;
  MPI_Barrier(MPI_COMM_WORLD);
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  init_tick = MPI_Wtime();
  SlepcInitialize(&argc, &argv, (char*)0, 0);
  ierr = MPI_Comm_size(PETSC_COMM_WORLD,&nproc); CHKERRQ(ierr);
  ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
  MPI_Barrier(MPI_COMM_WORLD);
  initend_tick = MPI_Wtime();

  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     Compute the operator matrix that defines the eigensystem, Ax=kx
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

  model m;
  std::string lattice_file("xyz.dat");
  if (argc >= 2) lattice_file = argv[1];
  int L;
  rokko::read_lattice_file(lattice_file, L, m.lattice);
  
  MPI_Barrier(MPI_COMM_WORLD);
  gen_tick = MPI_Wtime();
  int dim = 1 << L;
  PetscInt N_global = dim;
  PetscInt N_local = N_global / nproc;
  m.L = L;
  m.comm = PETSC_COMM_WORLD;
  m.buffer = new double[N_local];
  if (m.buffer == 0) {
    MPI_Abort(MPI_COMM_WORLD, 4);
  }
  ierr = MatCreateShell(PETSC_COMM_WORLD, N_local, N_local, N_global, N_global, &m, &A); CHKERRQ(ierr);
  ierr = MatSetFromOptions(A); CHKERRQ(ierr);
  ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)())MatMult); CHKERRQ(ierr);
  ierr = MatShellSetOperation(A,MATOP_MULT_TRANSPOSE,(void(*)())MatMult); CHKERRQ(ierr);
  //ierr = MatShellSetOperation(A,MATOP_GET_DIAGONAL,(void(*)())MatGetDiagonal); CHKERRQ(ierr);

  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                Create the eigensolver and set various options
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

  /*
     Create eigensolver context
  */
  MPI_Barrier(MPI_COMM_WORLD);
  diag_tick = MPI_Wtime();
  ierr = EPSCreate(PETSC_COMM_WORLD,&eps); CHKERRQ(ierr);

  /*
     Set operators. In this case, it is a standard eigenvalue problem
  */
  ierr = EPSSetOperators(eps,A,NULL); CHKERRQ(ierr);
  ierr = EPSSetProblemType(eps,EPS_HEP); CHKERRQ(ierr);
  //ierr = EPSSetDimensions(eps, 5, 100, 100); CHKERRQ(ierr);
  //ierr = EPSSetDimensions(eps, 1, PETSC_DECIDE, PETSC_DECIDE); CHKERRQ(ierr);
  //ierr = EPSSetTolerances(eps, (PetscScalar) 1., (PetscInt) 2000);   CHKERRQ(ierr);
  /*  Vec v0;
  MatCreateVecs(A, &v0, NULL);
  VecSet(v0,1.0);
  EPSSetInitialSpace(eps,1,&v0);*/

  /*
     Set solver parameters at runtime
  */
  ierr = EPSSetFromOptions(eps); CHKERRQ(ierr);

  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      Solve the eigensystem
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  ierr = EPSSolve(eps);CHKERRQ(ierr);
  MPI_Barrier(MPI_COMM_WORLD);
  end_tick = MPI_Wtime();
  /*
     Optional: Get some information from the solver and display it
  */
  ierr = EPSGetType(eps,&type); CHKERRQ(ierr);
  ierr = PetscPrintf(PETSC_COMM_WORLD,"solution method: %s\n\n",type); CHKERRQ(ierr);
  ierr = EPSGetDimensions(eps,&nev,NULL,NULL); CHKERRQ(ierr);
  ierr = PetscPrintf(PETSC_COMM_WORLD,"number of requested eigenvalues: %D\n",nev); CHKERRQ(ierr);
  int num_conv;
  EPSGetConverged(eps, &num_conv);
  PetscScalar eval_r, eval_i;
  if (rank == 0) {
    std::cout << "number of converged eigenpairs = " << num_conv << std::endl;
    for (int i=0; i<num_conv; ++i) {
      EPSGetEigenvalue(eps, i, &eval_r, &eval_i);
      std::cout << ' ' << eval_r;
    }
    std::cout << std::endl;
    std::cout << "init_time = " << initend_tick - init_tick << std::endl
	      << "gen_time = " << diag_tick - gen_tick << std::endl
	      << "diag_time = " << end_tick - diag_tick << std::endl;
  }
  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    Display solution and clean up
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  //ierr = EPSValuesView(eps,NULL); CHKERRQ(ierr);
  ierr = EPSDestroy(&eps); CHKERRQ(ierr);
  ierr = MatDestroy(&A); CHKERRQ(ierr);
  ierr = SlepcFinalize();

  MPI_Finalize();
  return 0;
}

#undef __FUNCT__
#define __FUNCT__ "MatMult"
PetscErrorCode MatMult(Mat A,Vec x,Vec y)
{
  PetscFunctionBeginUser;
  PetscErrorCode ierr;
  model *m;
  ierr = MatShellGetContext(A, &m); CHKERRQ(ierr);

  const PetscScalar *px;
  PetscScalar       *py;

  ierr = VecGetArrayRead(x, &px); CHKERRQ(ierr);
  ierr = VecGetArray(y, &py); CHKERRQ(ierr);
  PetscInt len_x, len_y;
  ierr = VecGetLocalSize(x, &len_x);  CHKERRQ(ierr);
  ierr = VecGetLocalSize(y, &len_y); CHKERRQ(ierr);
  //for(int j = 0; j < len_y; ++j) {
  //  py[j] = 0.;
  //}
  rokko::heisenberg_hamiltonian::multiply(m->comm, m->L, m->lattice, px, py, m->buffer);
  ierr = VecRestoreArrayRead(x,&px); CHKERRQ(ierr);
  ierr = VecRestoreArray(y,&py); CHKERRQ(ierr);

  PetscFunctionReturn(0);
}


#undef __FUNCT__
#define __FUNCT__ "MatGetDiagonal"
PetscErrorCode MatGetDiagonal(Mat A, Vec diag)
{
  PetscFunctionBeginUser;
  PetscErrorCode ierr;
  model *m;
  ierr = MatShellGetContext(A, &m); CHKERRQ(ierr);

  PetscScalar       *pd;

  ierr = VecGetArray(diag, &pd); CHKERRQ(ierr);
  rokko::heisenberg_hamiltonian::fill_diagonal(m->comm, m->L, m->lattice, pd);
  ierr = VecRestoreArray(diag ,&pd); CHKERRQ(ierr);

  PetscFunctionReturn(0);
}


<|start_filename|>rokko/pyrokko_matrix_major_enum.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_MATRIX_MAJOR_ENUM_HPP
#define PYROKKO_MATRIX_MAJOR_ENUM_HPP


namespace rokko {

enum matrix_major_enum {
  col = 0, row = 1
};

} // end namespace rokko

#endif // PYROKKO_MATRIX_MAJOR_ENUM_HPP


<|start_filename|>config/FindEigenExa.cmake<|end_filename|>
# - Try to find EigenExa
# Once done this will define
#
#  EIGENEXA_FOUND        - system has EigenExa
#  EIGENEXA_INCLUDE_DIR  - include directories for EigenExa
#  EIGENEXA_LIBARIES     - libraries for EigenExa
#  EIGENEXA_DIR          - directory where EigenExa is installed

if(DEFINED EIGENEXA_FOUND)
  return()
endif(DEFINED EIGENEXA_FOUND)
  
message(STATUS "Checking for EigenExa library")
set(EIGENEXA_FOUND FALSE)

# Standard search path
set(_PATHS "")
if(EIGENEXA_DIR)
  set(_PATHS ${EIGENEXA_DIR})
else(EIGENEXA_DIR)
  list(APPEND _PATHS
  	      ${EIGENEXA_ROOT}/${CMAKE_BUILD_TYPE}
	      ${EIGENEXA_ROOT}
  	      $ENV{EIGENEXA_ROOT}/${CMAKE_BUILD_TYPE}
	      $ENV{EIGENEXA_ROOT}
  	      ${ROKKO_SOLVER_ROOT}/eigenexa/${CMAKE_BUILD_TYPE}
	      ${ROKKO_SOLVER_ROOT}/eigenexa
  	      $ENV{ROKKO_SOLVER_ROOT}/eigenexa/${CMAKE_BUILD_TYPE}
	      $ENV{ROKKO_SOLVER_ROOT}/eigenexa
	      ${CMAKE_INSTALL_PREFIX}/eigenexa/${CMAKE_BUILD_TYPE}
	      ${CMAKE_INSTALL_PREFIX}/${CMAKE_BUILD_TYPE}
	      $ENV{HOME}/rokko/eigenexa/${CMAKE_BUILD_TYPE}
	      $ENV{HOME}/rokko/eigenexa
	      /opt/rokko/eigenexa/${CMAKE_BUILD_TYPE}
	      /opt/rokko/eigenexa
	      /opt/rokko/${CMAKE_BUILD_TYPE}
	      /opt/rokko
	      /opt/local /opt
	      )
endif(EIGENEXA_DIR)

find_path(EIGENEXA_DIR include/eigen_libs_mod.mod PATHS ${_PATHS} DOC "EigenExa directory")

if(EIGENEXA_DIR)
  set(EIGENEXA_INCLUDE_DIR "${EIGENEXA_DIR}/include")
  message(STATUS "EigenExa include directory: ${EIGENEXA_INCLUDE_DIR}")
else(EIGENEXA_DIR)
  message(STATUS "EigenExa library: include file not found")
  return()
endif(EIGENEXA_DIR)

find_library(_EIGENEXA_LIBRARY
  NAME EigenExa
  PATHS ${EIGENEXA_DIR}/lib
  DOC "The EigenExa library")
if(_EIGENEXA_LIBRARY)
  list(APPEND EIGENEXA_LIBRARIES ${_EIGENEXA_LIBRARY})
else(_EIGENEXA_LIBRARY)
  message(STATUS "EigenExa library: library file not found")
  set(EIGENEXA_FOUND FALSE)
  return()
endif(_EIGENEXA_LIBRARY)

set(EIGENEXA_FOUND TRUE)
message(STATUS "EigenExa libraries: ${EIGENEXA_LIBRARIES}")


<|start_filename|>rokko/pyrokko_parallel_dense_ev.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_PARALLEL_DENSE_EV_HPP
#define PYROKKO_PARALLEL_DENSE_EV_HPP

#include <rokko/pyrokko_mapping_bc.hpp>
#include <rokko/pyrokko_distributed_matrix.hpp>
#include <rokko/parallel_dense_ev.hpp>

namespace rokko {

class wrap_parallel_dense_ev : public parallel_dense_ev {
public:
  wrap_parallel_dense_ev(std::string const& solver_name) : parallel_dense_ev(solver_name) {}
  
  wrap_parallel_dense_ev() = default;

  void initialize() {
    int num = 1;
    char** ptr = NULL;
    parallel_dense_ev::initialize(num, ptr);
  }

  wrap_mapping_bc<matrix_col_major> default_mapping(int dim, wrap_grid const& g) const {
    return wrap_mapping_bc<matrix_col_major>(parallel_dense_ev::default_mapping(dim, g));
  }

  template<typename T, typename MATRIX_MAJOR, typename VEC>
  wrap_parameters diagonalize(wrap_distributed_matrix<T,MATRIX_MAJOR>& mat, VEC& eigvals, wrap_distributed_matrix<T,MATRIX_MAJOR>& eigvecs,
			 wrap_parameters const& params) {
    return parallel_dense_ev::diagonalize(mat, eigvals, eigvecs, parameters(params));
  }

  template<typename T, typename MATRIX_MAJOR, typename VEC>
  wrap_parameters diagonalize(wrap_distributed_matrix<T,MATRIX_MAJOR>& mat, VEC& eigvals,
			 wrap_parameters const& params) {
    return parallel_dense_ev::diagonalize(mat, eigvals, parameters(params));
  }

};

} // end namespace rokko

#endif // PYROKKO_PARALLEL_DENSE_EV_HPP


<|start_filename|>rokko/pyrokko_parallel_sparse_ev.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_PARALLEL_SPARSE_EV_HPP
#define PYROKKO_PARALLEL_SPARSE_EV_HPP

#include <rokko/parallel_sparse_ev.hpp>
#include <rokko/pyrokko_mapping_1d.hpp>
#include <rokko/pyrokko_distributed_crs_matrix.hpp>
#include <rokko/pyrokko_distributed_mfree.hpp>

namespace rokko {

class wrap_parallel_sparse_ev : public parallel_sparse_ev {
public:
  wrap_parallel_sparse_ev(std::string const& solver_name) : parallel_sparse_ev(solver_name) {}
  
  wrap_parallel_sparse_ev() = default;

  void initialize() {
    int num = 1;
    char** ptr = nullptr;
    parallel_sparse_ev::initialize(num, ptr);
  }

  wrap_mapping_1d default_mapping(int dim, pybind11::handle const& comm_handle) const {
    return static_cast<wrap_mapping_1d>(parallel_sparse_ev::default_mapping(dim, static_cast<mpi_comm>(wrap_communicator{comm_handle})));
  }

  wrap_parameters diagonalize(wrap_distributed_crs_matrix const& mat, wrap_parameters const& params) {
    return parallel_sparse_ev::diagonalize(mat, parameters(params));
  }

  wrap_parameters diagonalize(distributed_mfree const& mat, wrap_parameters const& params) {
    return parallel_sparse_ev::diagonalize(mat, parameters(params));
  }

  wrap_parameters diagonalize(wrap_distributed_mfree const& mat, wrap_parameters const& params) {
    return parallel_sparse_ev::diagonalize(mat, parameters(params));
  }

  std::vector<double> python_eigenvector(int k) const {
    std::vector<double> vec;
    parallel_sparse_ev::eigenvector(k, vec);
    return vec;
  }
};

} // end namespace rokko

#endif // PYROKKO_PARALLEL_SPARSE_EV_HPP


<|start_filename|>rokko/scalapack/indxg2p.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <rokko/scalapack/scalapack_interface.h>

int cscalapack_indxg2p(int indxglob, int nb, int iproc, int isrcproc, int nprocs) {
  int indxglob_f = indxglob + 1;
  int iproc_f = iproc + 1;
  int isrcproc_f = isrcproc + 1;
  return SCALAPACK_indxg2p(&indxglob_f, &nb, &iproc_f, &isrcproc_f, &nprocs);
}


<|start_filename|>example/blas/gemm.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <iostream>
#include <rokko/eigen3.hpp>
#include <rokko/blas.hpp>

int main() {
  std::size_t n = 4;
  Eigen::MatrixXd a(n, n);
  a << 0.959291425205444, 0.257508254123736, 0.243524968724989, 0.251083857976031,
    0.547215529963803, 0.840717255983663, 0.929263623187228, 0.616044676146639,
    0.138624442828679, 0.254282178971531, 0.349983765984809, 0.473288848902729,
    0.149294005559057, 0.814284826068816, 0.196595250431208, 0.351659507062997;
  Eigen::MatrixXd b(n, n);
  b << 0.567821640725221, 0.779167230102011, 0.469390641058206, 0.794284540683907,
    0.0758542895630636, 0.934010684229183, 0.0119020695012414, 0.311215042044805,
    0.0539501186666072, 0.129906208473730, 0.337122644398882, 0.528533135506213,
    0.530797553008973, 0.568823660872193, 0.162182308193243, 0.165648729499781;
  Eigen::MatrixXd c(n, n);
  c << 0.601981941401637, 0.748151592823710, 0.913337361501670, 0.996134716626886,
    0.262971284540144, 0.450541598502498, 0.152378018969223, 0.0781755287531837,
    0.654079098476782, 0.0838213779969326, 0.825816977489547, 0.442678269775446,
    0.689214503140008, 0.228976968716819, 0.538342435260057, 0.106652770180584;
  
  double alpha = 2.1;
  double beta = 0.8;

  std::cout << "a = [\n" << a << "\n]\n";
  std::cout << "b = [\n" << b << "\n]\n";
  std::cout << "c = [\n" << c << "\n]\n";
  
  rokko::blas::gemm(CblasNoTrans, CblasNoTrans, alpha, a, b, beta, c);

  std::cout << alpha << " * a * b + " << beta << " * c = [\n" << c << "\n]\n";
}

/* gemm.m

A = [0.959291425205444,0.257508254123736,0.243524968724989,0.251083857976031;0.547215529963803,0.840717255983663,0.929263623187228,0.616044676146639;0.138624442828679,0.254282178971531,0.349983765984809,0.473288848902729;0.149294005559057,0.814284826068816,0.196595250431208,0.351659507062997]
B = [0.567821640725221,0.779167230102011,0.469390641058206,0.794284540683907;0.0758542895630636,0.934010684229183,0.0119020695012414,0.311215042044805;0.0539501186666072,0.129906208473730,0.337122644398882,0.528533135506213;0.530797553008973,0.568823660872193,0.162182308193243,0.165648729499781]
C = [0.601981941401637,0.748151592823710,0.913337361501670,0.996134716626886;0.262971284540144,0.450541598502498,0.152378018969223,0.0781755287531837;0.654079098476782,0.0838213779969326,0.825816977489547,0.442678269775446;0.689214503140008,0.228976968716819,0.538342435260057,0.106652770180584]
2.1 * A * B + 0.8 * C

*/


<|start_filename|>test/matrix_product/product_v_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/collective.hpp>

#include <gtest/gtest.h>

constexpr double eps = 1e-11;

int global_argc;
char** global_argv;

TEST(product_v_mpi, product_v_mpi) {
  constexpr int root_proc = 0;
  MPI_Comm comm = MPI_COMM_WORLD;
  int rank;
  MPI_Comm_rank(comm, &rank);

  int dim = 100;
  if (global_argc > 1) {
    dim = std::stoi(global_argv[1]);
  }

  if (rank == root_proc) std::cout << "dimension = " << dim << std::endl;
  rokko::parallel_dense_ev solver(rokko::parallel_dense_ev::default_solver());
  rokko::grid g(comm);
  rokko::mapping_bc<rokko::matrix_col_major> map = solver.default_mapping(dim, g);
  rokko::distributed_matrix<double, rokko::matrix_col_major> matA(map);
  rokko::mapping_bc<rokko::matrix_col_major> mapvec({dim, 1}, {1, 1}, g);
  rokko::distributed_matrix<double, rokko::matrix_col_major> vecX(mapvec);
  rokko::distributed_matrix<double, rokko::matrix_col_major> vecY(mapvec);
  Eigen::MatrixXd locA(dim, dim);
  Eigen::VectorXd locX(dim), locY(dim);
  locA.setRandom();
  locX.setRandom();
  locY.setRandom();
  rokko::scatter(locA, matA, root_proc);
  rokko::scatter(locX, vecX, root_proc);
  rokko::scatter(locY, vecY, root_proc);

  // local calculation
  locY += locA * locX;

  // global calculation
  rokko::product_v(1.0, matA, false, vecX, false, 0, 1, vecY, false, 0);

  for (int i = 0; i < dim; ++i) {
    if (vecY.has_global_indices({i, 0}))
      EXPECT_NEAR(vecY.get_global(i,0), locY(i), eps);
  }
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>example/lapack/slange.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2017 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <math.h>
#include <cblas.h>
#include <lapacke.h>
#include <rokko/cmatrix.h>

int imin(int x, int y) { return (x < y) ? x : y; }

int main(int argc, char** argv) {
  int n = 5;
  int i, j;
  float norm, check;
  float **a;
  float *work;

  if (argc > 1) n = atoi(argv[1]);

  // generate matrix and rhs vector
  a = alloc_smatrix(n, n);
  for (j = 0; j < n; ++j) {
    for (i = 0; i < n; ++i) {
      mat_elem(a, i, j) = imin(i+1, j+1);
    }
  }
  printf("Matrix A: ");
  fprint_smatrix(stdout, n, n, a);
  work = alloc_svector(n);

  /* calculate various norms */
  norm = LAPACKE_slange_work(LAPACK_COL_MAJOR, 'M', n, n, mat_ptr(a), n, vec_ptr(work));
  printf("element of largest absolute value = %e\n", norm);

  norm = LAPACKE_slange(LAPACK_COL_MAJOR, '1', n, n, mat_ptr(a), n);
  printf("one norm = %e\n", norm);

  norm = LAPACKE_slange(LAPACK_COL_MAJOR, 'I', n, n, mat_ptr(a), n);
  printf("infinity norm = %e\n", norm);

  norm = LAPACKE_slange(LAPACK_COL_MAJOR, 'F', n, n, mat_ptr(a), n);
  printf("Frobenius norm = %e\n", norm);

  /* check of result */
  check = 0;
  for (j = 0; j < n; ++j) {
    for (i = 0; i < n; ++i) {
      check += mat_elem(a, i, j) * mat_elem(a, i, j);
    }
  }
  if (fabsf(check - norm * norm) > 1e-6 * check) {
    fprintf(stderr, "Error: check error %e != %e\n", norm * norm, check);
    exit(255);
  }

  free_smatrix(a);
  return 0;
}


<|start_filename|>example/cxx/sparse/heisenberg_mfree_matrix_market.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/heisenberg_hamiltonian_mfree.hpp>
#include <rokko/utility/math.hpp>
#include <rokko/utility/output_matrix_market.hpp>

int main(int argc, char *argv[]) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  int rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);

  std::string library(rokko::parallel_sparse_ev::default_solver());
  if (argc >= 2) library = argv[1];
  
  int L = (argc >= 3) ? std::stoi(argv[2]) : 10;
  int dim = 1 << L;
  std::vector<std::pair<int, int>> lattice;
  for (int i = 0; i < L; ++i) lattice.emplace_back(std::make_pair(i, (i+1) % L));

  rokko::parallel_sparse_ev solver(library);
  rokko::heisenberg_mfree op(L, lattice);
  rokko::output_matrix_market(op);

  solver.finalize();
  MPI_Finalize();
}


<|start_filename|>rokko/scalapack/solver.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_SOLVER_HPP
#define ROKKO_SCALAPACK_SOLVER_HPP

#include <rokko/config.h>
#include <rokko/parameters.hpp>
#include <rokko/scalapack/diagonalize_psyev.hpp>
#include <rokko/scalapack/diagonalize_psyevx.hpp>
#include <rokko/scalapack/diagonalize_psyevd.hpp>
#include <rokko/scalapack/diagonalize_qr.hpp>
#include <rokko/scalapack/diagonalize_bisection.hpp>
#ifdef ROKKO_HAVE_SCALAPACK_PDSYEVR
#include <rokko/scalapack/diagonalize_psyevr.hpp>
#endif

namespace rokko {
namespace scalapack {

class solver {
public:
  template <typename GRID_MAJOR>
  bool is_available_grid_major(GRID_MAJOR const& /* grid_major */) { return true; }
  void initialize(int& /* argc */, char**& /* argv */) {}
  void finalize() {}
  mapping_bc<matrix_col_major> default_mapping(int dim, grid const& g)  const {
    // Determine mb, nb, lld, larray
    int mb = dim / g.get_nprow();
    if (mb == 0)  mb = 1;
    int nb = dim / g.get_npcol();
    if (nb == 0)  nb = 1;
    // Note: it should be that mb = nb in pdsyev.
    int b = std::min(mb, nb);
    return mapping_bc<matrix_col_major>(dim, b, g);
  }

  template<typename T, typename MATRIX_MAJOR, typename VEC>
  parameters diagonalize(distributed_matrix<T, MATRIX_MAJOR>& mat,
			 VEC& eigvals, distributed_matrix<T, MATRIX_MAJOR>& eigvecs,
			 parameters const& params);
  template<typename T, typename MATRIX_MAJOR, typename VEC>
  parameters diagonalize(distributed_matrix<T, MATRIX_MAJOR>& mat,
			 VEC& eigvals,
			 parameters const& params);
};

// eigenvalues / eigenvectors
template<typename T, typename MATRIX_MAJOR, typename VEC>
parameters solver::diagonalize(distributed_matrix<T, MATRIX_MAJOR>& mat,
			       VEC& eigvals, distributed_matrix<T, MATRIX_MAJOR>& eigvecs,
			       parameters const& params) {
  const std::string routine = params.defined("routine") ? params.get_string("routine") : "";

  if ((routine=="syev") || (routine=="qr")) {
    return rokko::scalapack::diagonalize_psyev(mat, eigvals, eigvecs, params);
  } else if ((routine=="syevr") || (routine=="mr3")) {
#ifdef ROKKO_HAVE_SCALAPACK_PDSYEVR
    return rokko::scalapack::diagonalize_psyevr(mat, eigvals, eigvecs, params);
#else
    throw std::invalid_argument("scalapack::diagonalize() : the routine pdsyevr does not exist in your machine.");
#endif
  } else if ((routine=="syevd") || (routine=="dc")) {
    return rokko::scalapack::diagonalize_psyevd(mat, eigvals, eigvecs, params);
  } else if (routine=="syevx") {
    return rokko::scalapack::diagonalize_psyevx(mat, eigvals, eigvecs, params);
  } else if (routine=="bisection") {
    return rokko::scalapack::diagonalize_bisection(mat, eigvals, eigvecs, params);
  } else if (routine=="qr") {
    return rokko::scalapack::diagonalize_qr(mat, eigvals, eigvecs, params);
  } else if (routine=="") {
    if (lapack::is_interval(params)) {
#ifdef ROKKO_HAVE_SCALAPACK_PDSYEVR
      return rokko::scalapack::diagonalize_psyevr(mat, eigvals, eigvecs, params);
#else
      throw std::invalid_argument("scalapack::diagonalize() : the default routine for a range of eigenvalues, pdsyevr does not exist in your machine.");
#endif
    } else {
      return rokko::scalapack::diagonalize_psyev(mat, eigvals, eigvecs, params);
    }
  } else {
    throw std::invalid_argument("scalapack::diagonalize() : " + routine + " is invalid routine name");
  }
}

// only eigenvalues
template<typename T, typename MATRIX_MAJOR, typename VEC>
parameters solver::diagonalize(distributed_matrix<T, MATRIX_MAJOR>& mat,
			       VEC& eigvals,
			       parameters const& params) {
  const std::string routine = params.defined("routine") ? params.get_string("routine") : "";

  if ((routine=="syev") || (routine=="qr")) {
    return rokko::scalapack::diagonalize_psyev(mat, eigvals, params);
  } else if ((routine=="syevr") || (routine=="mr3")) {
#ifdef ROKKO_HAVE_SCALAPACK_PDSYEVR
    return rokko::scalapack::diagonalize_psyevr(mat, eigvals, params);
#else
    throw std::invalid_argument("scalapack::diagonalize() : the routine pdsyevr does not exist in your machine.");
#endif
  } else if ((routine=="syevd") || (routine=="dc")) {
    throw std::invalid_argument("scalapack::diagonalize() : " + routine + " does not support computing only eigenvalues");
  } else if (routine=="syevx") {
    return rokko::scalapack::diagonalize_psyevx(mat, eigvals, params);
  } else if (routine=="bisection") {
    return rokko::scalapack::diagonalize_bisection(mat, eigvals, params);
  } else if (routine=="qr") {
    return rokko::scalapack::diagonalize_qr(mat, eigvals, params);
  } else if (routine=="") {
    if (lapack::is_interval(params)) {
#ifdef ROKKO_HAVE_SCALAPACK_PDSYEVR
      return rokko::scalapack::diagonalize_psyevr(mat, eigvals, params);
#else
      throw std::invalid_argument("scalapack::diagonalize() : the default routine for a range of eigenvalues, pdsyevr does not exist in your machine.");
#endif
    } else {
      return rokko::scalapack::diagonalize_psyev(mat, eigvals, params);
    }
  } else {
    throw std::invalid_argument("scalapack::diagonalize() : " + routine + " is invalid routine name");
  }
}

} // namespace sclapack
} // namespace rokko

#endif // ROKKO_SCALAPACK_SOLVER_HPP


<|start_filename|>rokko/eigenexa.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_EIGENEXA_HPP
#define ROKKO_EIGENEXA_HPP

#include <rokko/config.h>
#include <rokko/ceigenexa.h>

namespace rokko {
namespace eigenexa {

inline void init() { ceigenexa_init(); }
inline void init(MPI_Comm comm) { ceigenexa_init1(comm); }
inline void init(MPI_Comm comm, char grid_major) { ceigenexa_init2(comm, grid_major); }

inline void free() { ceigenexa_free(); }
inline void free(int flag) { ceigenexa_free1(flag); }

template<typename GRID>
std::pair<int, int> get_matdims(const GRID& grid, int n) {
  int nx, ny;
  ceigenexa_get_matdims(grid.get_nprow(), grid.get_npcol(), n, &nx, &ny);
  return std::make_pair(nx, ny);
}
  
template<typename MATRIX, typename VECTOR>
void eigen_s(MATRIX& a, VECTOR& w, MATRIX& z, int m_forward = 48, int m_backword = 128,
             char mode = 'A') {
  ceigenexa_eigen_s(a.get_m_global(), a.get_m_global(), a.get_array_pointer(), a.get_lld(),
                    storage(w), z.get_array_pointer(), z.get_lld(), m_forward, m_backword, mode);
}
  
template<typename MATRIX, typename VECTOR>
void eigen_s(MATRIX& a, VECTOR& w, int m_forward = 48, int m_backword = 128, char mode = 'N') {
  ceigenexa_eigen_s(a.get_m_global(), a.get_m_global(), a.get_array_pointer(), a.get_lld(),
                    storage(w), 0, 0, m_forward, m_backword, mode);
}
  
template<typename MATRIX, typename VECTOR>
void eigen_sx(MATRIX& a, VECTOR& w, MATRIX& z, int m_forward = 48, int m_backword = 128,
              char mode = 'A') {
  ceigenexa_eigen_sx(a.get_m_global(), a.get_m_global(), a.get_array_pointer(), a.get_lld(),
                     storage(w), z.get_array_pointer(), z.get_lld(), m_forward, m_backword, mode);
}
  
template<typename MATRIX, typename VECTOR>
void eigen_sx(MATRIX& a, VECTOR& w, int m_forward = 48, int m_backword = 128, char mode = 'N') {
  ceigenexa_eigen_sx(a.get_m_global(), a.get_m_global(), a.get_array_pointer(), a.get_lld(),
                     storage(w), 0, 0, m_forward, m_backword, mode);
}
  
} // end namespace eigenexa
} // end namespace rokko

#endif // ROKKO_EIGENEXA_HPP


<|start_filename|>rokko/utility/string_trim.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2010-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTIL_STRING_TRIM_HPP
#define ROKKO_UTIL_STRING_TRIM_HPP

namespace rokko {

#include <algorithm>
#include <cctype>
#include <locale>
#include <string>

// trim from start (in place)
static inline void trim_left(std::string&& str) {
  str.erase(str.begin(), std::find_if_not(str.cbegin(), str.cend(), isspace));
}

// trim from end (in place)
inline void trim_right(std::string&& str) {
  str.erase(std::find_if_not(str.crbegin(), str.crend(), isspace).base(), str.end());
}

// trim from both ends (in place)
inline void trim(std::string&& str) {
  trim_left(std::move(str));
  trim_right(std::move(str));
}

// trim from start (copying)
inline std::string trim_left_copy(std::string&& str) {
  trim_left(std::move(str));
  return str;
}

// trim from end (copying)
inline std::string trim_right_copy(std::string&& str) {
  trim_right(std::move(str));
  return str;
}

// trim from both ends (copying)
inline std::string trim_copy(std::string&& str) {
  trim(std::move(str));
  return str;
}

} // namespace rokko

#endif // ROKKO_UTIL_STRING_TRIM_HPP


<|start_filename|>rokko/distributed_mfree_f.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/distributed_mfree.h>
#include <rokko/distributed_mfree.hpp>

void rokko_distributed_mfree_f_construct(struct rokko_distributed_mfree* matrix,
					 void (*multiply)(const int*, const double *const, double *const),
					 int dim, int comm_f) {
  MPI_Comm comm = MPI_Comm_f2c(comm_f);
  matrix->ptr = new rokko::distributed_mfree_holder(multiply, rokko::skel::mapping_1d{dim, rokko::mpi_comm{comm}});
}

void rokko_distributed_mfree_f_destruct(struct rokko_distributed_mfree* matrix) {
  delete static_cast<rokko::distributed_mfree_holder*>(matrix->ptr);
}


int rokko_distributed_mfree_f_dim(struct rokko_distributed_mfree* matrix) {
  return static_cast<rokko::distributed_mfree_holder*>(matrix->ptr)->get_dim();
}

int rokko_distributed_mfree_f_num_local_rows(struct rokko_distributed_mfree* matrix) {
  return static_cast<rokko::distributed_mfree_holder*>(matrix->ptr)->get_num_local_rows();
}

int rokko_distributed_mfree_f_start_row(struct rokko_distributed_mfree* matrix) {
  return static_cast<rokko::distributed_mfree_holder*>(matrix->ptr)->start_row();
}

int rokko_distributed_mfree_f_end_row(struct rokko_distributed_mfree* matrix) {
  return static_cast<rokko::distributed_mfree_holder*>(matrix->ptr)->end_row();
}

int rokko_distributed_mfree_f_offset(struct rokko_distributed_mfree* matrix) {
  return static_cast<rokko::distributed_mfree_holder*>(matrix->ptr)->get_local_offset();
}


<|start_filename|>rokko/scalapack/scalapack.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2014 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <rokko/parallel_dense_ev.hpp>
#include <rokko/scalapack/solver.hpp>

ROKKO_REGISTER_PARALLEL_DENSE_SOLVER(rokko::scalapack::solver, "scalapack", 20)


<|start_filename|>rokko/original/solver.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_ORIGINAL_SOLVER_HPP
#define ROKKO_ORIGINAL_SOLVER_HPP

#include <tuple>

#include <rokko/distributed_vector.hpp>
#include <rokko/distributed_mfree.hpp>
#include <rokko/skel/mapping_1d.hpp>
#include <rokko/parameters.hpp>
#include <rokko/original/lanczos_tridiagonalization.hpp>
#include <rokko/lapack/diagonalize_tridiagonal_matrix_bisection.hpp>

namespace rokko {

namespace original {

class solver {
public:
  using value_type = double;

  solver() = default;

  ~solver() = default;

  void initialize(int& argc, char**& argv) {}
  void finalize() {}

  parameters diagonalize(const rokko::distributed_crs_matrix& mat, rokko::parameters const& params) {
    throw std::invalid_argument("rokko::original::solver::diagonalize() is not implemented.");
  }

  parameters diagonalize(const rokko::distributed_mfree& mat, rokko::parameters const& params) {
    map_ = std::make_shared<rokko::skel::mapping_1d>(mat.get_dim(), mat.get_num_local_rows(), mpi_comm{mat.get_comm()});

    // tridiagonaliation by Lanczos method
    const int dim = mat.get_dim();
    Eigen::VectorXd alpha(dim), beta(dim-1);
    Eigen::MatrixXd u(dim, dim);
    lanczos::tridiagonalization(mat, alpha, beta, u);

    // calculating eigenvalues & eigenvectors of tridiagonalized matrix
    auto params_out = rokko::lapack::diagonalize_bisection(alpha, beta, eigvals, eigvecs, params);
    num_conv = params_out.get<int>("num_conv");

    // calculating eigenvectors of mat
    eigvecs = u * eigvecs;

    return params_out;
  }

  value_type eigenvalue(int k) const { return eigvals(k); }

  void eigenvector(int k, std::vector<value_type>& vec) const {
    if (vec.size() < map_->get_num_local_rows()) vec.resize(map_->get_num_local_rows());
    eigenvector(k, vec.data());
  }

  void eigenvector(int k, distributed_vector<double>& vec) const {
    vec.initialize(map_->get_dim(), map_->start_row(), map_->end_row());
    eigenvector(k, vec.get_storage());
  }

  void eigenvector(int k, value_type *const vec) const {
    value_type const*const vec_pt = eigvecs.col(k).data();
    std::copy(vec_pt, vec_pt + map_->get_num_local_rows(), vec);
  }

  int get_num_conv() const {
    return num_conv;
  }

private:
  std::shared_ptr<const rokko::skel::mapping_1d> map_;
  Eigen::VectorXd eigvals;
  Eigen::MatrixXd eigvecs;
  int num_conv;
};

} // namespace original

} // namespace rokko

#endif // ROKKO_ORIGINAL_SOLVER_HPP


<|start_filename|>rokko/elpa.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_ELPA_DIAG_HPP
#define ROKKO_ELPA_DIAG_HPP

#include <rokko/elpa/elpa.h>
#include <complex>
#undef complex

inline auto elpa_complex_cast(std::complex<double>* c) {
  return reinterpret_cast<__complex__ double*>(c);
}

inline auto elpa_complex_cast(std::complex<float>* c) {
  return reinterpret_cast<__complex__ float*>(c);
}

namespace rokko {
namespace elpa {

int deallocate(elpa_t handle) {
  int error;
  elpa_deallocate(handle, &error);
  return error;
}

int set(elpa_t handle, const char *name, int value) {
  int error;
  elpa_set_integer(handle, name, value, &error);
  return error;
}

int set(elpa_t handle, const char *name, double value) {
  int error;
  elpa_set_double(handle, name, value, &error);
  return error;
}


int diag(elpa_t handle, double* a, double* ev, double* q) {
  int error;
  elpa_eigenvectors_d(handle, a, ev, q, &error);
  return error;
}

int diag(elpa_t handle, float* a, float* ev, float* q) {
  int error;
  elpa_eigenvectors_f(handle, a, ev, q, &error);
  return error;
}

int diag(elpa_t handle, std::complex<double>* a, double* ev, std::complex<double>* q) {
  int error;
  elpa_eigenvectors_dc(handle, elpa_complex_cast(a), ev, elpa_complex_cast(q), &error);
  return error;
}

int diag(elpa_t handle, std::complex<float>* a, float* ev, std::complex<float>* q) {
  int error;
  elpa_eigenvectors_fc(handle, elpa_complex_cast(a), ev, elpa_complex_cast(q), &error);
  return error;
}

int diag(elpa_t handle, double* a, double* ev) {
  int error;
  elpa_eigenvalues_d(handle, a, ev, &error);
  return error;
}

int diag(elpa_t handle, float* a, float* ev) {
  int error;
  elpa_eigenvalues_f(handle, a, ev, &error);
  return error;
}

int diag(elpa_t handle, std::complex<double>* a, double* ev) {
  int error;
  elpa_eigenvalues_dc(handle, elpa_complex_cast(a), ev, &error);
  return error;
}

int diag(elpa_t handle, std::complex<float>* a, float* ev) {
  int error;
  elpa_eigenvalues_fc(handle, elpa_complex_cast(a), ev, &error);
  return error;
}

template<typename MATRIX, typename VECTOR>
int diag(elpa_t handle, MATRIX& a, VECTOR& ev, MATRIX& q) {
  return diag(handle, a.get_array_pointer(), storage(ev), q.get_array_pointer());
}

template<typename MATRIX, typename VECTOR>
int diag(elpa_t handle, MATRIX& a, VECTOR& ev) {
  return diag(handle, a.get_array_pointer(), storage(ev));
}

} // namespace elpa
} // namespace rokko

#endif // ROKKO_ELPA_DIAG_HPP


<|start_filename|>rokko/scalapack/psyevx_work.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <rokko/scalapack/scalapack_interface.h>

#define CSCALAPACK_PSYEVX_WORK_IMPL(NAMES, NAMEL, TYPE, TYPE_REAL) \
int cscalapack_ ## NAMES ## _work(char jobz, char range, char uplo, int n, \
                                  TYPE* A, int ia, int ja, const int* descA, \
                                  TYPE_REAL vl, TYPE_REAL vu, int il, int iu, \
                                  TYPE_REAL abstol, int* m, int* nZ, TYPE_REAL* w, TYPE_REAL orfac, \
                                  TYPE* Z, int iz, int jz, const int* descZ, \
                                  TYPE* work, int lwork, int* iwork, int liwork, \
                                  int* ifail, int* iclustr, TYPE_REAL* gap) { \
  int ia_f = ia + 1; \
  int ja_f = ja + 1; \
  int il_f = il + 1; \
  int iu_f = iu + 1; \
  int iz_f = iz + 1; \
  int jz_f = jz + 1; \
  int info; \
  ROKKO_GLOBAL(NAMES, NAMEL) (&jobz, &range, &uplo, &n, A, &ia_f, &ja_f, descA, &vl, &vu, &il_f, &iu_f, \
                              &abstol, m, nZ, w, &orfac, Z, &iz_f, &jz_f, descZ, work, &lwork, iwork, &liwork, \
                              ifail, iclustr, gap, &info); \
  return info; \
}

CSCALAPACK_PSYEVX_WORK_IMPL(pssyevx, PSSYEVX, float, float)
CSCALAPACK_PSYEVX_WORK_IMPL(pdsyevx, PDSYEVX, double, double)
CSCALAPACK_PSYEVX_WORK_IMPL(pcheevx, PCHEEVX, lapack_complex_float, float)
CSCALAPACK_PSYEVX_WORK_IMPL(pzheevx, PZHEEVX, lapack_complex_double, double)

#undef CSCALAPACK_PSYEVX_WORK_IMPL


<|start_filename|>rokko/lapack/htegr.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_HTEGR_HPP
#define ROKKO_LAPACK_HTEGR_HPP

#include <complex>
#include <lapacke.h>
#undef I
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>
#include "complex_cast.hpp"
#include <rokko/lapack/storage.hpp>
#include <rokko/alias_template_function.hpp>

namespace rokko {
namespace lapack {

namespace {

template<typename T> struct htegr_dispatch;

template<>
struct htegr_dispatch<float> {
  template<typename MATRIX, typename VECTOR, typename VECTOR_INT>
  static lapack_int htegr(int matrix_layout, char jobz, char range, lapack_int n, VECTOR& d, VECTOR& e,
                          float vl, float vu, lapack_int il, lapack_int iu, float abstol,
                          lapack_int& m, VECTOR& w, MATRIX& z, VECTOR_INT& isuppz) {
    return LAPACKE_sstegr(matrix_layout, jobz, range, n, storage(d), storage(e), vl, vu, il, iu, abstol, &m, storage(w), storage(z), ld(z), storage(isuppz));
  }
};

template<>
struct htegr_dispatch<double> {
  template<typename MATRIX, typename VECTOR, typename VECTOR_INT>
  static lapack_int htegr(int matrix_layout, char jobz, char range, lapack_int n, VECTOR& d, VECTOR& e,
                          double vl, double vu, lapack_int il, lapack_int iu, double abstol,
                          lapack_int& m, VECTOR& w, MATRIX& z, VECTOR_INT& isuppz) {
    return LAPACKE_dstegr(matrix_layout, jobz, range, n, storage(d), storage(e), vl, vu, il, iu, abstol, &m, storage(w), storage(z), ld(z), storage(isuppz));
  }
};

template<>
struct htegr_dispatch<std::complex<float>> {
  template<typename MATRIX, typename VECTOR, typename VECTOR_INT>
  static lapack_int htegr(int matrix_layout, char jobz, char range, lapack_int n, VECTOR& d, VECTOR& e,
                          float vl, float vu, lapack_int il, lapack_int iu, float abstol,
                          lapack_int& m, VECTOR& w, MATRIX& z, VECTOR_INT& isuppz) {
    return LAPACKE_sstegr(matrix_layout, jobz, range, n, storage(d), storage(e), vl, vu, il, iu, abstol, &m, storage(w), complex_cast(storage(z)), ld(z), storage(isuppz));
  }
};

template<>
struct htegr_dispatch<std::complex<double>> {
  template<typename MATRIX, typename VECTOR, typename VECTOR_INT>
  static lapack_int htegr(int matrix_layout, char jobz, char range, lapack_int n, VECTOR& d, VECTOR& e,
                          double vl, double vu, lapack_int il, lapack_int iu, double abstol,
                          lapack_int& m, VECTOR& w, MATRIX& z, VECTOR_INT& isuppz) {
    return LAPACKE_dstegr(matrix_layout, jobz, range, n, storage(d), storage(e), vl, vu, il, iu, abstol, &m, storage(w), complex_cast(storage(z)), ld(z), storage(isuppz));
  }
};

} // end of anonymous namespace

template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int htegr(char jobz, char range, VECTOR& d, VECTOR& e,
                 T vl, T vu, lapack_int il, lapack_int iu, T abstol,
                 lapack_int& m, VECTOR& w, MATRIX& z, VECTOR_INT& isuppz) {
  static_assert(std::is_same<real_t<MATRIX>, T>::value, "");
  static_assert(std::is_same<value_t<VECTOR>, T>::value, "");

  lapack_int n = size(d);
  if (size(e) != n)  // e(n) is used as internal workspace
    throw std::invalid_argument("vector e size mismatch");
  if (size(w) != n)
    throw std::invalid_argument("vector w size mismatch");
  return htegr_dispatch<value_t<MATRIX>>::
    htegr((is_col_major(z) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR), jobz, range, n, d, e, vl, vu, il, iu, abstol, m, w, z, isuppz);
}

// only eigenvalues (without jobz)
template<typename T, typename VECTOR, typename VECTOR_INT>
lapack_int htegr(char range, VECTOR& d, VECTOR& e,
                 T vl, T vu, lapack_int il, lapack_int iu, T abstol,
                 lapack_int& m, VECTOR& w, VECTOR_INT& isuppz) {
  static_assert(std::is_same<value_t<VECTOR>, T>::value, "");

  lapack_int n = size(d);
  constexpr null_matrix<T> z_null;
  return htegr_dispatch<T>::
    htegr(LAPACK_COL_MAJOR, 'N', range, n, d, e, vl, vu, il, iu, abstol, m, w, z_null, isuppz);
}

// eigenvalues & eigenvectors (without jobz)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int htegr(char range, VECTOR& d, VECTOR& e,
                 T vl, T vu, lapack_int il, lapack_int iu, T abstol,
                 lapack_int& m, VECTOR& w, MATRIX& z, VECTOR_INT& isuppz) {
  return htegr('V', range, d, e, vl, vu, il, iu, abstol, m, w, z, isuppz);
}

// eigenvalues & eigenvectors, use all (without jobz, range, vl, vu, il, iu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int htegr(VECTOR& d, VECTOR& e,
                 T abstol,
                 lapack_int& m, VECTOR& w, MATRIX& z, VECTOR_INT& isuppz) {
  constexpr real_t<VECTOR> real_zero = 0;
  return htegr('A', d, e, real_zero, real_zero, 0, 0, abstol, m, w, z, isuppz);
}

// eigenvalues & eigenvectors, use vl, vu (without jobz, range, il, iu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int htegr(VECTOR& d, VECTOR& e,
                 T vl, T vu, T abstol,
                 lapack_int& m, VECTOR& w, MATRIX& z, VECTOR_INT& isuppz) {
  return htegr('V', d, e, vl, vu, 0, 0, abstol, m, w, z, isuppz);
}

// eigenvalues & eigenvectors, use il, iu (without jobz, range, vl, vu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int htegr(VECTOR& d, VECTOR& e,
                 lapack_int il, lapack_int iu, T abstol,
                 lapack_int& m, VECTOR& w, MATRIX& z, VECTOR_INT& isuppz) {
  constexpr real_t<VECTOR> real_zero = 0;
  return htegr('I', d, e, real_zero, real_zero, il, iu, abstol, m, w, z, isuppz);
}

// only eigenvalues, use all (without jobz, range, vl, vu, il, iu)
template<typename T, typename VECTOR, typename VECTOR_INT>
lapack_int htegr(VECTOR& d, VECTOR& e,
                 T abstol,
                 lapack_int& m, VECTOR& w, VECTOR_INT& isuppz) {
  static_assert(std::is_same<value_t<VECTOR>, T>::value, "");
  constexpr real_t<VECTOR> real_zero = 0;

  return htegr('A', d, e, real_zero, real_zero, 0, 0, abstol, m, w, isuppz);
}

// only eigenvalues, use vl, vu (without jobz, range, il, iu)
template<typename T, typename VECTOR, typename VECTOR_INT>
lapack_int htegr(VECTOR& d, VECTOR& e,
                 T vl, T vu, T abstol,
                 lapack_int& m, VECTOR& w, VECTOR_INT& isuppz) {
  static_assert(std::is_same<value_t<VECTOR>, T>::value, "");

  return htegr('V', d, e, vl, vu, 0, 0, abstol, m, w, isuppz);
}

// only eigenvalues, use il, iu (without jobz, range, vl, vu)
template<typename T, typename VECTOR, typename VECTOR_INT>
lapack_int htegr(VECTOR& d, VECTOR& e,
                 lapack_int il, lapack_int iu, T abstol,
                 lapack_int& m, VECTOR& w, VECTOR_INT& isuppz) {
  constexpr real_t<VECTOR> real_zero = 0;
  return htegr('I', d, e, real_zero, real_zero, il, iu, abstol, m, w, isuppz);
}

ALIAS_TEMPLATE_FUNCTION(stegr, htegr);

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_HTEGR_HPP


<|start_filename|>rokko/pblas/pblas_interface.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_PBLAS_INTERFACE_H
#define ROKKO_PBLAS_INTERFACE_H

#include <lapacke.h>
#undef I
#include <rokko/mangling.h>

/* PvCOPY */

#define PBLAS_PCOPY_DECL(NAMES, NAMEL, TYPE) \
void ROKKO_GLOBAL(NAMES, NAMEL) (const int* N, const TYPE * X, const int* IX, const int* JX, const int* DESCX, const int* INCX, TYPE * Y, const int* IY, int* JY, const int* DESCY, const int* INCY);

#ifdef __cplusplus
extern "C" {
#endif

PBLAS_PCOPY_DECL(pscopy, PSCOPY, float);
PBLAS_PCOPY_DECL(pdcopy, PDCOPY, double);
PBLAS_PCOPY_DECL(pccopy, PCCOPY, lapack_complex_float);
PBLAS_PCOPY_DECL(pzcopy, PZCOPY, lapack_complex_double);

#ifdef __cplusplus
}
#endif

#undef PBLAS_PCOPY_DECL

/* PvDOT, PvDOTU, PvDOTC */

#define PBLAS_PDOT_DECL(NAMES, NAMEL, TYPE) \
void ROKKO_GLOBAL(NAMES, NAMEL) (const int* N, TYPE * DOT, const TYPE * X, const int* IX, const int* JX, const int* DESCX, const int* INCX, const TYPE * Y, const int* IY, const int* JY, const int* DESCY, const int* INCY);

#ifdef __cplusplus
extern "C" {
#endif

PBLAS_PDOT_DECL(psdot, PSDOT, float);
PBLAS_PDOT_DECL(pddot, PDDOT, double);
PBLAS_PDOT_DECL(pcdotu, PCDOTU, lapack_complex_float);
PBLAS_PDOT_DECL(pzdotu, PZDOTU, lapack_complex_double);
PBLAS_PDOT_DECL(pcdotc, PCDOTC, lapack_complex_float);
PBLAS_PDOT_DECL(pzdotc, PZDOTC, lapack_complex_double);

#ifdef __cplusplus
}
#endif

#undef PBLAS_PDOT_DECL

/* PvGEMV */

#define PBLAS_PGEMV_DECL(NAMES, NAMEL, TYPE) \
void ROKKO_GLOBAL(NAMES, NAMEL) (const char* TRANS, const int* M, const int* N, const TYPE * ALPHA, const TYPE * A, const int* IA, const int* JA, const int* DESCA, const TYPE * X, const int* IX, const int* JX, const int* DESCX, const int* INCX, const TYPE * BETA, TYPE * Y, const int* IY, const int* JY, const int* DESCY, const int* INCY);

#ifdef __cplusplus
extern "C" {
#endif

PBLAS_PGEMV_DECL(psgemv, PSGEMV, float);
PBLAS_PGEMV_DECL(pdgemv, PDGEMV, double);
PBLAS_PGEMV_DECL(pcgemv, PCGEMV, lapack_complex_float);
PBLAS_PGEMV_DECL(pzgemv, PZGEMV, lapack_complex_double);

#ifdef __cplusplus
}
#endif

#undef PBLAS_PGEMV_DECL

/* PvGEMM */

#define PBLAS_PGEMM_DECL(NAMES, NAMEL, TYPE) \
void ROKKO_GLOBAL(NAMES, NAMEL) (const char* TRANSA, const char* TRANSB, const int* M, const int* N, const int* K, const TYPE * ALPHA, const TYPE * A, const int* IA, const int* JA, const int* DESCA, const TYPE * B, const int* IB, const int* JB, const int* DESCB, const TYPE * BETA, TYPE * C, const int* IC, const int* JC, const int* DESCC);

#ifdef __cplusplus
extern "C" {
#endif

PBLAS_PGEMM_DECL(psgemm, PSGEMM, float);
PBLAS_PGEMM_DECL(pdgemm, PDGEMM, double);
PBLAS_PGEMM_DECL(pcgemm, PCGEMM, lapack_complex_float);
PBLAS_PGEMM_DECL(pzgemm, PZGEMM, lapack_complex_double);

#ifdef __cplusplus
}
#endif

#undef PBLAS_PGEMM_DECL

#endif // ROKKO_PBLAS_INTERFACE_H


<|start_filename|>rokko/blas/gemm.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_BLAS_GEMM_HPP
#define ROKKO_BLAS_GEMM_HPP

#include <complex>
#ifdef I
# undef I
#endif
#include <stdexcept>
#include <cblas.h>
#include <rokko/blas/util.hpp>
#include <rokko/lapack/complex_cast.hpp>

namespace rokko {
namespace blas {

#define BLAS_GEMM_IMPL(NAMES, TYPE) \
  inline void gemm(CBLAS_ORDER order, CBLAS_TRANSPOSE trans_a, CBLAS_TRANSPOSE trans_b, int m, int n, int k, TYPE alpha, const TYPE * a, int lda_a, const TYPE * b, int lda_b, TYPE beta, TYPE * c, int lda_c) { \
  cblas_ ## NAMES (order, trans_a, trans_b, m, n, k, alpha, a, lda_a, b, lda_b, beta, c, lda_c); \
}
  
BLAS_GEMM_IMPL(sgemm, float);
BLAS_GEMM_IMPL(dgemm, double);
  
#undef BLAS_GEMM_IMPL  

#define BLAS_GEMM_IMPL(NAMES, TYPE) \
inline void gemm(CBLAS_ORDER order, CBLAS_TRANSPOSE trans_a, CBLAS_TRANSPOSE trans_b, int m, int n, int k, TYPE alpha, const TYPE * a, int lda_a, const TYPE * b, int lda_b, TYPE beta, TYPE * c, int lda_c) { \
  cblas_ ## NAMES (order, trans_a, trans_b, m, n, k, &alpha, lapack::complex_cast(a), lda_a, lapack::complex_cast(b), lda_b, &beta, lapack::complex_cast(c), lda_c); \
}
  
BLAS_GEMM_IMPL(cgemm, std::complex<float>);
BLAS_GEMM_IMPL(zgemm, std::complex<double>);
  
#undef BLAS_GEMM_IMPL  

template<typename MATRIX, typename T>
void gemm(CBLAS_TRANSPOSE trans_a, CBLAS_TRANSPOSE trans_b,
          T alpha, MATRIX const& a, MATRIX const& b, T beta, MATRIX& c) {
  if (util::op_cols(trans_a, a) != util::op_rows(trans_b, b))
    throw std::invalid_argument("matrix size mismatch");
  int m = util::op_rows(trans_a, a);
  int n = util::op_cols(trans_b, b);
  int k = util::op_cols(trans_a, a);
  gemm((is_col_major(a) ? CblasColMajor : CblasRowMajor), trans_a, trans_b,
       m, n, k, alpha, storage(a), ld(a), storage(b), ld(b), beta, storage(c), ld(c));
}

} // namespace blas
} // namespace rokko

#endif // ROKKO_BLAS_GEMM_HPP


<|start_filename|>rokko/utility/output_matrix_market.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_OUTPUT_MATRIX_MARKET_HPP
#define ROKKO_OUTPUT_MATRIX_MARKET_HPP

#include <rokko/distributed_mfree.hpp>
#include <rokko/utility/mpi_vector.hpp>
#include <iostream>
#include <sstream>

namespace rokko {

void output_matrix_market(distributed_mfree const& op, std::ostream& os = std::cout) {
  rokko::mpi_comm comm(op.get_comm());
  const int nprocs = comm.get_nprocs();
  const int myrank = comm.get_myrank();
  const int dim = op.get_dim();
  rokko::mpi_vector mpi(dim, op.get_comm());
  rokko::mapping_1d map(dim, comm);
  const int start_row = map.start_row();
  const int end_row = map.end_row();

  Eigen::Vector<double> x(op.get_num_local_rows()), y(op.get_num_local_rows());
  Eigen::Vector<double> vec(dim);

  constexpr int root_proc = 0;
  std::vector<int> cols;
  std::vector<double> values;

  std::ostringstream ss;
  int nnz = 0;
  for (int row=0; row<dim; ++row) {
    x.setZero();
    y.setZero();
    if ((row >= start_row) && (row < end_row)) {
      x[row - start_row] = 1.;
    }
    op.multiply(x.data(), y.data());
    mpi.gather(y, vec, root_proc);
    if (myrank == root_proc) {
      for (int col=0; col<dim; ++col) {
        if (vec[col] != 0) {
          ss << row + 1 << " " << col+ 1 << " " << vec[col] << std::endl;
          ++nnz;
        }
      }
    }
  }

  if (comm.get_myrank() == root_proc) {
    os << "%%MatrixMarket matrix coordinate real general" << std::endl
       << dim << " " << dim << " " << nnz << std::endl
       << ss.str();
  }
}

} // end namespace rokko

#endif // ROKKO_OUTPUT_MATRIX_MARKET_HPP


<|start_filename|>benchmark/no_rokko/dense_minij_mpi/scalapack_pdsyevd_fixed_block.f<|end_filename|>
*     This is a modified version of the example on the Netlib,
*     which can be found at
*     http://www.netlib.org/scalapack/examples/sample_pdsyev_call.f

*     The license of the original one is the modified BSD license.
*     http://www.netlib.org/scalapack/LICENSE
*
      PROGRAM SAMPLE_PDSYEVD_CALL
*
*  -- ScaLAPACK routine (version 1.2) --
*     University of Tennessee, Knoxville, Oak Ridge National Laboratory,
*     and University of California, Berkeley.
*     May 10, 1996
*
*     This routine contains a sample call to PDSYEV.
*     When compiled and run, it produces output which can be
*     pasted directly into matlab.
*
      IMPLICIT NONE
*     .. Parameters ..
      INTEGER            N
      character(len=10) :: tmp_str
      integer arg_len, status
*     ..
*     .. Local Scalars ..
      INTEGER            IERR
      INTEGER            LWORK, LIWORK, LDA
      INTEGER            CONTEXT, I, INFO, MYCOL, MYROW,
     $                   NPCOL, NPROCS, NPROW
      INTEGER            BB, M_LOCAL, N_LOCAL
      DOUBLE PRECISION   INIT_TICK, GEN_TICK, DIAG_TICK, END_TICK
*     ..
*     .. Local Arrays ..
      INTEGER            DESC( 50 )
      DOUBLE PRECISION, pointer :: A(:,:),W(:),Z(:,:)
      DOUBLE PRECISION   TMP_WORK(1)
      INTEGER            TMP_IWORK(1)
      DOUBLE PRECISION, allocatable :: WORK(:)
      INTEGER, allocatable :: IWORK(:)
*     ..
*     .. External Subroutines ..
      EXTERNAL           BLACS_EXIT, BLACS_GET, BLACS_GRIDEXIT,
     $                   BLACS_GRIDINFO, BLACS_GRIDINIT, BLACS_PINFO,
     $                   BLACS_SETUP, DESCINIT,
     $                   PDSYEV
      INTEGER            NUMROC
*     ..
*     .. Executable Statements ..
*
*
*     Set up the problem
*
      include 'mpif.h'

      call mpi_init_thread( MPI_THREAD_MULTIPLE, i, ierr )
      print *,"MPI_THREAD_MULTIPLE=",  MPI_THREAD_MULTIPLE
      if (command_argument_count().eq.1) then
      call get_command_argument(1, tmp_str, arg_len, status)
      read(tmp_str, *) n
      else
      write(*,'(A)') "Error: argument dimension is needed"
      stop
      endif
      call mpi_barrier(mpi_comm_world, ierr)
      INIT_TICK = MPI_WTIME()
      call MPI_Comm_Size(mpi_comm_world,nprocs,ierr)
      NPROW = INT(SQRT(NPROCS + 0.5))
      DO WHILE ( (NPROW .ne. 1) .AND. (MOD(NPROCS,NPROW).ne.0) )
         NPROW = NPROW - 1
      ENDDO
      NPCOL = NPROCS / NPROW
*     
*     Initialize a single BLACS context
*
      CALL BLACS_GET( -1, 0, CONTEXT )
      CALL BLACS_GRIDINIT( CONTEXT, 'R', NPROW, NPCOL )
      CALL BLACS_GRIDINFO( CONTEXT, NPROW, NPCOL, MYROW, MYCOL )
*     
*     These are basic array descriptors
*
      call mpi_barrier(mpi_comm_world, ierr)
      GEN_TICK = MPI_WTIME()
      BB = 64
      M_LOCAL = NUMROC(N, BB, MYROW, 0, NPROW)
      N_LOCAL = NUMROC(N, BB, MYCOL, 0, NPCOL)
!      print*, "M_LOCAL=", M_LOCAL, " N_LOCAL=", N_LOCAL
      LDA = MAX(M_LOCAL, 1)
      allocate( A(M_LOCAL, N_LOCAL), Z(M_LOCAL, N_LOCAL), W(N) )
      CALL DESCINIT( DESC, N, N, BB, BB, 0, 0, CONTEXT, LDA, INFO )
      CALL MINIJ_MATRIX( N, A, DESC, INFO )
*      CALL PDLAPRNT( N, N, A, 1, 1, DESC, 0, 0, 'A', 6, PRNWORK )
*     
*     Ask PDSYEV to compute the entire eigendecomposition
*
      call mpi_barrier(mpi_comm_world, ierr)
      DIAG_TICK = MPI_WTIME()
      CALL PDSYEVD( 'V', 'U', N, A, 1, 1, DESC, W, Z, 1, 1,
     $             DESC, TMP_WORK, -1, TMP_IWORK, -1, INFO )
      LWORK = INT(TMP_WORK(1))
      allocate ( WORK(LWORK) )
      LIWORK = TMP_IWORK(1)
      allocate ( IWORK(LIWORK) )
      CALL PDSYEVD( 'V', 'U', N, A, 1, 1, DESC, W, Z, 1, 1,
     $             DESC, WORK, LWORK, IWORK, LIWORK, INFO )
      call mpi_barrier(mpi_comm_world, ierr)
      END_TICK = MPI_WTIME()
*     
*     Print out the eigenvalues and eigenvectors
*
      IF( MYROW.EQ.0 .AND. MYCOL.EQ.0 ) THEN
         write(*,'(" Eigenvalues:",5E12.5e2)') W(1:N)
         write(*,*) "init_time = ", GEN_TICK - INIT_TICK
         write(*,*) "gen_time = ", DIAG_TICK - GEN_TICK
         write(*,*) "diag_time = ", END_TICK - DIAG_TICK
      END IF

      CALL BLACS_GRIDEXIT( CONTEXT )
      call mpi_finalize(ierr)
      STOP
      END
*

*
      SUBROUTINE MINIJ_MATRIX( N, A, DESCA, INFO )
*  This is originally PDLAMODHILB in ScaLAPACK
*  -- ScaLAPACK routine (version 1.2) --
*     University of Tennessee, Knoxville, Oak Ridge National Laboratory,
*     and University of California, Berkeley.
*     May 10, 1996
*     ..
*     .. Scalar Arguments ..
      INTEGER            N
*     ..
*     .. Array Arguments ..
      INTEGER            DESCA( * )
      DOUBLE PRECISION   A( * )
*     ..
*     .. Local Scalars ..
      INTEGER            I, J
*     ..
*     .. External Subroutines ..
      EXTERNAL           PDELSET
*
*     Create minij matrix
      DO 20 J = 1, N
         DO 10 I = 1, N
            CALL PDELSET( A, I, J, DESCA, dble(MIN(I,J)))
   10    CONTINUE
   20 CONTINUE

*     
*
      RETURN
*
*     End of MINIJ_MATRIX
*
      END


<|start_filename|>rokko/distributed_matrix.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_DISTRIBUTED_MATRIX_HPP
#define ROKKO_DISTRIBUTED_MATRIX_HPP

#include <rokko/grid.hpp>
#include <rokko/matrix_major.hpp>
#include <rokko/mapping_bc.hpp>
#include <rokko/blacs.hpp>
#include <rokko/pblas.hpp>
#include <rokko/scalapack.hpp>
#include <rokko/mpi/mpi_type_traits.hpp>

#include <iostream>
#include <cstdlib>
#include <stdexcept>
#include <functional>

namespace rokko {

class parallel_dense_ev;

template<typename T, typename MATRIX_MAJOR = rokko::matrix_col_major>
class distributed_matrix {
public:
  using value_type = T;
  distributed_matrix(mapping_bc<MATRIX_MAJOR> const& map_in) : map(map_in) {
    bool is_col_major = std::is_same<MATRIX_MAJOR, matrix_col_major>::value;
    if (is_col_major != map.is_col_major()) {
      throw std::invalid_argument("distributed_matrix() : matrix major of template parameter and one of given mapping are different.");
    }
    allocate_array();
  }

  distributed_matrix(mapping_bc<MATRIX_MAJOR> const& map_in, value_type *const array_in) : map(map_in) {
    bool is_col_major = std::is_same<MATRIX_MAJOR, matrix_col_major>::value;
    if (is_col_major != map.is_col_major()) {
      throw std::invalid_argument("distributed_matrix() : matrix major of template parameter and one of given mapping are different.");
    }
    array = array_in;
  }

  ~distributed_matrix() {
    if (!array) {
      delete[] array;
      array = nullptr;
    }
  }

  void allocate_array() {
    array = new value_type[map.get_length_array()];
    if (array == nullptr) {
      throw std::runtime_error("failed to allocate array.");
    }
  }

  value_type* get_array_pointer() { return array; }
  const value_type* get_array_pointer() const { return array; }

  // void set_mapping(mapping_bc<MATRIX_MAJOR> const& map_in) { map = map_in; }
  const mapping_bc<MATRIX_MAJOR>& get_mapping() const { return map; }

  void set_local(int local_i, int local_j, value_type value) {
    array[map.get_array_index(local_i, local_j)] = value;
  }

  void update_local(int local_i, int local_j, value_type value) {
    array[map.get_array_index(local_i, local_j)] += value;
  }

  value_type get_local(int local_i, int local_j) const {
    return array[map.get_array_index(local_i, local_j)];
  }

  void set_global(int global_i, int global_j, value_type value) {
    if ((map.has_global_indices(global_i, global_j)))
      set_local(map.translate_g2l_row(global_i), map.translate_g2l_col(global_j), value);
  }

  void update_global(int global_i, int global_j, value_type value) {
    if ((map.has_global_indices(global_i, global_j)))
      update_local(map.translate_g2l_row(global_i), map.translate_g2l_col(global_j), value);
  }

  value_type get_global(int global_i, int global_j) const {
    return get_local(map.translate_g2l_row(global_i), map.translate_g2l_col(global_j));
  }

  value_type get_global_checked(int global_i, int global_j) const {
    if ((map.has_global_indices(global_i, global_j))) {
      return get_local(map.translate_g2l_row(global_i), map.translate_g2l_col(global_j));
    } else {
      throw std::out_of_range("element not on this process.");
    }
  }

  void set_zeros() {
    for (int local_j=0; local_j<map.get_n_local(); ++local_j) {
      for (int local_i=0; local_i<map.get_m_local(); ++local_i) {
        set_local(local_i, local_j, 0);
      }
    }
  }

  template<class FUNC>
  void generate(FUNC func) {
    for(int local_j = 0; local_j < map.get_n_local(); ++local_j) {
      int global_j = map.translate_l2g_col(local_j);
      for(int local_i = 0; local_i < map.get_m_local(); ++local_i) {
        int global_i = map.translate_l2g_row(local_i);
        set_local(local_i, local_j, func(global_i, global_j));
      }
    }
  }

  void generate(std::function<value_type(int, int)> func) {
    for(int local_j = 0; local_j < map.get_n_local(); ++local_j) {
      int global_j = map.translate_l2g_col(local_j);
      for(int local_i = 0; local_i < map.get_m_local(); ++local_i) {
        int global_i = map.translate_l2g_row(local_i);
        set_local(local_i, local_j, func(global_i, global_j));
      }
    }
  }
  
  void print(std::ostream& os = std::cout) const;

  // map member function
  int get_mb() const { return map.get_mb(); }
  int get_nb() const { return map.get_nb(); }
  std::array<int,2> get_block_size() const { return map.get_block_size(); }

  int get_m_global() const { return map.get_m_global(); }
  int get_n_global() const { return map.get_n_global(); }
  std::array<int,2> get_global_size() const { return map.get_global_size(); }
  int get_m_local() const { return map.get_m_local(); }
  int get_n_local() const { return map.get_n_local(); }
  std::array<int,2> get_local_size() const { return map.get_local_size(); }
  int get_m_size() const { return map.get_m_size(); }
  int get_n_size() const { return map.get_n_size(); }

  int translate_l2g_row(int local_i) const { return map.translate_l2g_row(local_i); }
  int translate_l2g_col(int local_j) const { return map.translate_l2g_col(local_j); }
  std::array<int,2> translate_l2g(std::array<int,2> local) const { return map.translate_l2g(local); }
  int translate_g2l_row(int global_i) const { return map.translate_g2l_row(global_i); }
  int translate_g2l_col(int global_j) const { return map.translate_g2l_col(global_j); }
  std::array<int,2> translate_g2l(std::array<int,2> global) const { return map.translate_g2l(global); }
  bool has_global_row_index(int global_i) const { return map.has_global_row_index(global_i); }
  bool has_global_col_index(int global_j) const { return map.has_global_col_index(global_j); }
  bool has_global_indices(std::array<int,2> global) const { return map.has_global_indices(global); }

  int get_length_array() const { return map.get_length_array(); }
  int get_lld() const { return map.get_lld(); };
  int get_default_length_array() const { return map.get_default_length_array(); }
  int get_array_index(int local_i, int local_j) const { return map.get_array_index(local_i, local_j); }
  bool is_row_major() const { return map.is_row_major(); }
  bool is_col_major() const { return map.is_col_major(); }
  grid const& get_grid() const { return map.get_grid(); }
  int get_nprow() const { return map.get_nprow(); }
  int get_npcol() const { return map.get_npcol(); }
  int get_nprocs() const { return map.get_nprocs(); }
  int get_myrank() const { return map.get_myrank(); }
  int get_myrow() const { return map.get_myrow(); }
  int get_mycol() const { return map.get_mycol(); }

  // temporary
  void set_default_lld() { map.set_default_lld(); }
  void set_default_length_array() { map.set_default_length_array(); }

private:
  mapping_bc<MATRIX_MAJOR> map;
  value_type* array;
};

template<typename T, typename MATRIX_MAJOR>
void distributed_matrix<T, MATRIX_MAJOR>::print(std::ostream& os) const {
  for (int proc = 0; proc < map.get_nprocs(); ++proc) {
    if (proc == map.get_myrank()) {
      os << "Rank = " << map.get_myrank() << ", myrow = " << map.get_myrow() << ", mycol = " << map.get_mycol() << std::endl;
      for (int local_i = 0; local_i < map.get_m_local(); ++local_i) {
        for (int local_j = 0; local_j < map.get_n_local(); ++local_j)
          os << "  " << get_local(local_i, local_j);
        os << std::endl;
      }
      os.flush();
    }
    MPI_Barrier(map.get_comm());
  }
}

template<typename T, typename MATRIX_MAJOR>
void print_matrix(const rokko::distributed_matrix<T, MATRIX_MAJOR>& mat) { mat.print(); }

template<typename T, typename MATRIX_MAJOR>
std::ostream& operator<<(std::ostream& os, rokko::distributed_matrix<T, MATRIX_MAJOR> const& mat) {
  mat.print(os);
  return os;
}

// C = alpha A * B + beta C
template<typename T, typename MATRIX_MAJOR>
void product(typename distributed_matrix<T, MATRIX_MAJOR>::value_type alpha,
             const distributed_matrix<T, MATRIX_MAJOR>& matA, bool transA,
             const distributed_matrix<T, MATRIX_MAJOR>& matB, bool transB,
             typename distributed_matrix<T, MATRIX_MAJOR>::value_type beta,
             distributed_matrix<T, MATRIX_MAJOR>& matC) {
  char char_transA = (transA ? 'T' : 'N');
  char char_transB = (transB ? 'T' : 'N');
  pblas::pgemm(char_transA, char_transB, alpha, matA, matB, beta, matC);
}

// Y = alpha A * X + beta Y
template<typename T, typename MATRIX_MAJOR>
void product_v(typename distributed_matrix<T, MATRIX_MAJOR>::value_type alpha,
               const distributed_matrix<T, MATRIX_MAJOR>& matA, bool transA,
               const distributed_matrix<T, MATRIX_MAJOR>& vecX, bool transX, int /* xindex */,
               typename distributed_matrix<T, MATRIX_MAJOR>::value_type beta,
               distributed_matrix<T, MATRIX_MAJOR>& vecY, bool transY, int /* yindex */) {
  char char_transA = (transA ? 'T' : 'N');
  int incx = (transX ? vecX.get_m_global() : 1);
  int incy = (transY ? vecY.get_m_global() : 1);
  pblas::pgemv(char_transA, alpha, matA, vecX, incx, beta, vecY, incy);
}

// dot = X * Y
template<typename T, typename MATRIX_MAJOR>
T dot_product(const distributed_matrix<T, MATRIX_MAJOR>& vecX, bool transX, int xindex,
              const distributed_matrix<T, MATRIX_MAJOR>& vecY, bool transY, int yindex) {
  int n = (transX ? vecX.get_n_global() : vecX.get_m_global());
  int ix = (transX ? xindex : 0);
  int jx = (transX ? 0 : xindex);
  int incx = (transX ? vecX.get_m_global() : 1);
  int iy = (transY ? yindex: 0);
  int jy = (transY ? 0 : yindex);
  int incy = (transY ? vecY.get_m_global() : 1);
  return pblas::pdot(n, vecX, ix, jx, incx, vecY, iy, jy, incy);
}

template <typename T, typename MAJOR>
T trace(rokko::distributed_matrix<T,MAJOR> const& mat) {
  using value_type = T;
  constexpr int root_proc = 0;
  const auto& map = mat.get_mapping();

  value_type local_sum = 0;
  for (int i=0; i<std::min(map.get_m_global(), map.get_n_global()); ++i) {
    if (map.has_global_indices(i, i)) {
      local_sum += mat.get_global(i, i);
    }
  }

  value_type sum;
  MPI_Reduce(&local_sum, &sum, 1, rokko::mpi_type<T>,
             MPI_SUM, root_proc, map.get_grid().get_comm());

  return sum;
}

} // namespace rokko

#endif // ROKKO_DISTRIBUTED_MATRIX_HPP


<|start_filename|>example/c/dense/generate_matrix/matrix012.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.h>
#include <rokko/utility/matrix012.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
  struct rokko_eigen_matrix mat;
  int dim;

  dim = 10;
  rokko_eigen_matrix_construct(&mat, dim, dim, rokko_matrix_col_major);
  rokko_matrix012_generate_eigen_matrix(mat);
  rokko_eigen_matrix_print(mat);

  rokko_eigen_matrix_destruct(&mat);

  return 0;
}


<|start_filename|>rokko/pyrokko_grid.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_GRID_HPP
#define PYROKKO_GRID_HPP

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#include <rokko/pyrokko_communicator.hpp>
#include <rokko/grid.hpp>
#include <rokko/utility/tuple_to_array.hpp>

#include <memory>

namespace rokko {

namespace py = pybind11;

class wrap_grid : public grid {
public:
  using grid::grid;

  wrap_grid() : grid(to_MPI_Comm()) {}

  template <typename GRID_MAJOR>
  wrap_grid(GRID_MAJOR const& grid_major = grid_row_major) : grid(to_MPI_Comm(), grid_major) {}

  template <typename GRID_MAJOR>
  wrap_grid(pybind11::handle const& comm_handle, std::tuple<int,int> const& size_in, GRID_MAJOR const& grid_major = grid_row_major)
    : grid(to_MPI_Comm(comm_handle), to_array(size_in), grid_major) {}

  template <typename GRID_MAJOR>
  wrap_grid(pybind11::handle const& comm_handle, GRID_MAJOR const& grid_major = grid_row_major)
    : grid(to_MPI_Comm(comm_handle), grid_major) {}

  wrap_grid(rokko::grid const& g) : grid(g) {}

  std::string get_major_string() const {
    return grid::is_row_major() ? "row" : "col";
  }

  pybind11::handle get_comm() const {
    return pybind11::handle(PyMPIComm_New(grid::get_comm()));
  }

  std::tuple<int,int> get_shape() const {
    return grid::get_size();
  }

  std::tuple<int,int> get_mine() const {
    return grid::get_my_coordinate();
  }
};

} // end namespace rokko

#endif // PYROKKO_GRID_HPP


<|start_filename|>rokko/alias_template_function.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_ALIAS_TEMPLATE_FUNCTION_HPP
#define ROKKO_ALIAS_TEMPLATE_FUNCTION_HPP

#define ALIAS_TEMPLATE_FUNCTION(target, source)  \
template<typename... Types> \
inline auto target(Types&&... args) -> decltype(source(std::forward<Types>(args)...)) { \
  return source(std::forward<Types>(args)...); \
}

#endif // ROKKO_ALIAS_TEMPLATE_FUNCTION_HPP


<|start_filename|>rokko/eigen3/solver.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_EIGEN3_SOLVER_HPP
#define ROKKO_EIGEN3_SOLVER_HPP

#include <rokko/eigen3/diagonalize.hpp>

namespace rokko {
namespace eigen3 {

class solver {
public:
  void initialize(int& /* argc */, char**& /* argv */) {}
  void finalize() {}
  // -------------------------standard eigenvalue problem-----------------------------
  // eigenvalues/eigenvectors
  template<typename T, int MATRIX_MAJOR, typename VEC>
  parameters diagonalize(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat,
			 VEC& eigvals,
			 Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& eigvecs,
			 rokko::parameters const& params) {
    std::string routine = params.defined("routine") ? params.get_string("routine") : "";

    if ((routine == "") || (routine == "qr")) {
      return rokko::eigen3::diagonalize(mat, eigvals, eigvecs, params);
    } else {
      throw std::invalid_argument("eigen3::diagonalize() : " + routine + " is invalid routine name");
    }
  }
  // only eigenvalues
  template<typename T, int MATRIX_MAJOR, typename VEC>
  parameters diagonalize(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat,
			 VEC& eigvals,
			 rokko::parameters const& params) {
    std::string routine = params.defined("routine") ? params.get_string("routine") : "";

    if ((routine == "") || (routine == "qr")) {
      return rokko::eigen3::diagonalize(mat, eigvals, params);
    } else {
      throw std::invalid_argument("eigen3::diagonalize() : " + routine + " is invalid routine name");
    }
  }
};

} // namespace eigen3
} // namespace rokko

#endif // ROKKO_EIGEN3_SOLVER_HPP


<|start_filename|>test/generate_matrix/xyz.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <iostream>
#include <fstream>
#include <vector>
#include <tuple>

#include <rokko/utility/xyz_hamiltonian.hpp>
#include <rokko/eigen3.hpp>

#include <gtest/gtest.h>

TEST(generate_matrix, xyz_hamiltonian) {
  std::size_t L = 4;
  std::size_t num_bonds = L - 1;
  std::size_t N = 1 << L;
  std::vector<std::pair<int, int>> lattice;
  std::vector<std::tuple<double, double, double>> coupling;
  for (std::size_t i=0; i<L-1; ++i) {
    lattice.emplace_back(std::make_pair(i, i+1));
    coupling.emplace_back(std::make_tuple(1, 1, 1));
  }

  std::cout << "dim=" << N << std::endl;  
  std::cout << "L=" << L << std::endl;
  for (std::size_t i=0; i<num_bonds; ++i) {
    std::cout << lattice[i].first << " " << lattice[i].second << " " << std::get<0>(coupling[i]) << " " << std::get<1>(coupling[i]) << " " << std::get<2>(coupling[i]) << std::endl;
  }

  Eigen::MatrixXd mat1(N, N);
  Eigen::VectorXd v(N), w(N);
  std::cout << "multiply:" << std::endl;
  for (int i=0; i<N; ++i) {
    v.setZero();
    v(i) = 1;
    w.setZero();
    rokko::xyz_hamiltonian::multiply(L, lattice, coupling, v, w);
    mat1.col(i) = w;
    std::cout << "w = " << w.transpose() << std::endl;
  }

  std::cout << "fill_diagonal:" << std::endl;
  Eigen::VectorXd diagonal(N);
  rokko::xyz_hamiltonian::fill_diagonal(L, lattice, coupling, diagonal);
  std::cout << "diagonal = " << diagonal.transpose() << std::endl;

  std::cout << "fill_matrix:" << std::endl;
  Eigen::MatrixXd mat2(N, N);
  rokko::xyz_hamiltonian::generate(L, lattice, coupling, mat2);
  std::cout << mat2 << std::endl;

  EXPECT_TRUE(mat1 == mat2) << "matrix generated by 'multiply' is differnet from the matrix generated by 'generate'.";

  EXPECT_TRUE(diagonal == mat2.diagonal()) << "diagonal elements generated by 'fill_diagonal' is differnet from diagonal elements of the matrix generated by 'genertate'.";
}

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}


<|start_filename|>rokko/utility/xyz_hamiltonian_mpi.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_XYZ_HAMILTONIAN_MPI_HPP
#define ROKKO_UTILITY_XYZ_HAMILTONIAN_MPI_HPP

#include "mpi.h"
#include <vector>
#include <tuple>

#include <iostream>

#include <rokko/distributed_matrix.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/utility/math.hpp>

namespace rokko {

namespace xyz_hamiltonian {

void multiply(const MPI_Comm& comm, int L, const std::vector<std::pair<int, int>>& lattice, const std::vector<std::tuple<double, double, double>>& coupling, const double* v, double* w, double* buffer) {
  int myrank, nproc;
  MPI_Status status;

  MPI_Comm_size(comm, &nproc);
  MPI_Comm_rank(comm, &myrank);

  const int p = rokko::find_power_of_two(nproc);
  if (nproc != (1 << p)) {
    throw std::invalid_argument("This program can be run only with 2^n MPI processes");
  }
  int N = 1 << (L-p);

  for (std::size_t l = 0; l < lattice.size(); ++l) {
    int i = lattice[l].first;
    int j = lattice[l].second;
    double jx = std::get<0>(coupling[l]);
    double jy = std::get<1>(coupling[l]);
    double jz = std::get<2>(coupling[l]);

    double diag_plus = jz / 4.0;
    double diag_minus = - jz / 4.0;
    double offdiag_plus = (jx + jy) / 4.0;
    double offdiag_minus = (jx - jy) / 4.0;

    if (i < (L-p)) {
      if (j < (L-p)) {
        int m1 = 1 << i;
        int m2 = 1 << j;
        int m3 = m1 + m2;
        for (int k = 0; k < N; ++k) {
          if (((k & m3) == m1) || ((k & m3) == m2)) {  // when (bit i == 1, bit j == 0) or (bit i == 0, bit j == 1)
            w[k] += diag_minus * v[k] + offdiag_plus * v[k^m3];
          } else {
            w[k] += diag_plus * v[k] + offdiag_minus * v[k^m3];
          }
        }
      } else {
        int m = 1 << (j-(L-p));
        MPI_Sendrecv(v, N, MPI_DOUBLE,
                     myrank ^ m, 0,
                     buffer, N, MPI_DOUBLE,
                     myrank ^ m, 0,
                     comm, &status);
        int m1 = 1 << i;
        if ((myrank & m) == m) { 
          for (int k = 0; k < N; ++k) {
            if ((k & m1) == m1) {
              w[k] += diag_plus * v[k] + offdiag_minus * buffer[k^m1];
            } else {
              w[k] += diag_minus * v[k] + offdiag_plus * buffer[k^m1];
            }
          }
        } else {
          for (int k = 0; k < N; ++k) {
            if ((k & m1) == m1) {
              w[k] += diag_minus * v[k] + offdiag_plus * buffer[k^m1];
            } else {
              w[k] += diag_plus * v[k] + offdiag_minus * buffer[k^m1];
            }
          }
        }
      }
    } else {
      if (j < (L-p)) {
        int m = 1 << (i-(L-p));
        MPI_Sendrecv(v, N, MPI_DOUBLE,
                     myrank ^ m, 0,
                     buffer, N, MPI_DOUBLE,
                     myrank ^ m, 0,
                     comm, &status);
        int m1 = 1 << j;
        if ((myrank & m) == m) {
          for (int k = 0; k < N; ++k) {
            if ((k & m1) == m1) {
              w[k] += diag_plus * v[k] + offdiag_minus * buffer[k^m1];
            } else {
              w[k] += diag_minus * v[k] + offdiag_plus * buffer[k^m1];
            }
          }
        } else {
          for (int k = 0; k < N; ++k) {
            if ((k & m1) == m1) {
              w[k] += diag_minus * v[k] + offdiag_plus * buffer[k^m1];
            } else {
              w[k] += diag_plus * v[k] + offdiag_minus * buffer[k^m1];
            }
          }
        }
      } else {
        int m = (1 << (i-(L-p))) + (1 << (j-(L-p)));
        MPI_Sendrecv(v, N, MPI_DOUBLE,
                     myrank ^ m, 0,
                     buffer, N, MPI_DOUBLE,
                     myrank ^ m, 0,
                     comm, &status);
        if (((myrank & m) != m) && ((myrank & m) != 0)) {
          for (int k = 0; k < N; ++k) {
            w[k] += diag_minus * v[k] + offdiag_plus * buffer[k];
          }
        } else {
          for (int k = 0; k < N; ++k) {
            w[k] += diag_plus * v[k] + offdiag_minus * buffer[k];
          }
        }
      }
    }
  }
}

void multiply(const MPI_Comm& comm, int L, const std::vector<std::pair<int, int>>& lattice, const std::vector<std::tuple<double, double, double>>& coupling, const std::vector<double>& v, std::vector<double>& w, std::vector<double>& buffer) {
  multiply(comm, L, lattice, coupling, v.data(), w.data(), buffer.data());
}

void fill_diagonal(const MPI_Comm& comm, int L, const std::vector<std::pair<int, int>>& lattice, const std::vector<std::tuple<double, double, double>>& coupling, double* w) {
  int myrank, nproc;

  MPI_Comm_size(comm, &nproc);
  MPI_Comm_rank(comm, &myrank);

  const int p = rokko::find_power_of_two(nproc);
  if (nproc != (1 << p)) {
    throw std::invalid_argument("This program can be run only with 2^n MPI processes");
  }

  int N_seq = 1 << L;
  int N = 1 << (L-p);
  int myrank_shift = myrank * N;
  int nproc_shift = (nproc-1) * N;
  int mask = N - 1;

  for (int k = 0; k < N; ++k) {
    w[k] = 0;
  }

  for (std::size_t l = 0; l < lattice.size(); ++l) {
    int i = lattice[l].first;
    int j = lattice[l].second;
    double jz = std::get<2>(coupling[l]); // jx and jy are unused
    double diag_plus = jz / 4.0;
    double diag_minus = - jz / 4.0;

    int m1 = 1 << i;
    int m2 = 1 << j;
    int m3 = m1 + m2;

    for (int k = 0; k < N_seq; ++k) {
      if (myrank_shift == (k & nproc_shift)) {
        if (((k & m3) == m1) || ((k & m3) == m2)) {  // when (bit i == 1, bit j == 0) or (bit i == 0, bit j == 1)
          w[k & mask] += diag_minus;
        } else {
          w[k & mask] += diag_plus;
        }        
      }
    }  // end for k
  } // end for lattice
}

void fill_diagonal(const MPI_Comm& comm, int L, const std::vector<std::pair<int, int>>& lattice, const std::vector<std::tuple<double, double, double>>& coupling, std::vector<double>& w) {
  fill_diagonal(comm, L, lattice, coupling, w.data());
}

template<typename T, typename MATRIX_MAJOR>
void generate(int L, const std::vector<std::pair<int, int>>& lattice,
  const std::vector<std::tuple<double, double, double>>& coupling,
  rokko::distributed_matrix<T, MATRIX_MAJOR>& mat) {
  const auto& map = mat.get_mapping();

  mat.set_zeros();
  int N = 1 << L;
  for (std::size_t l = 0; l < lattice.size(); ++l) {
    int i = lattice[l].first;
    int j = lattice[l].second;
    double jx = std::get<0>(coupling[l]);
    double jy = std::get<1>(coupling[l]);
    double jz = std::get<2>(coupling[l]);
    double diag_plus = jz / 4.0;
    double diag_minus = - jz/ 4.0;
    double offdiag_plus = (jx + jy) / 4.0;
    double offdiag_minus = (jx - jy) / 4.0;

    int m1 = 1 << i;
    int m2 = 1 << j;
    int m3 = m1 + m2;

    for (int k = 0; k < N; ++k) {
      if (map.has_global_col_index(k)) {
        int local_k = map.translate_g2l_col(k);
        if (((k & m3) == m1) || ((k & m3) == m2)) {  // when (bit i == 1, bit j == 0) or (bit i == 0, bit j == 1)
          if (map.has_global_row_index(k^m3)) {
            mat.update_local(map.translate_g2l_row(k^m3), local_k, offdiag_plus);
          }
          if (map.has_global_row_index(k)) {
            mat.update_local(map.translate_g2l_row(k), local_k, diag_minus);
          }
        } else {
          if (map.has_global_row_index(k^m3)) {
            mat.update_local(map.translate_g2l_row(k^m3), local_k, offdiag_minus);
          }
          if (map.has_global_row_index(k)) {
            mat.update_local(map.translate_g2l_row(k), local_k, diag_plus);
          }
        }
      }
    }
  }
}

// The following routine uses local indices.  It works correctly.
/*
template <typename MATRIX_MAJOR>
void generate(int L, const std::vector<std::pair<int, int>>& lattice, const std::vector<std::tuple<double, double, double>>& coupling, rokko::distributed_matrix<MATRIX_MAJOR>& mat) {
  const auto& map = mat.get_mapping();

  mat.set_zeros();
  int N = 1 << L;
  for (int l=0; l<lattice.size(); ++l) {
    int i = lattice[l].first;
    int j = lattice[l].second;
    double jx = std::get<0>(coupling[l]);
    double jy = std::get<1>(coupling[l]);
    double jz = std::get<2>(coupling[l]);
    double diag_plus = jz / 4.0;
    double diag_minus = - jz/ 4.0;
    double offdiag_plus = (jx + jy) / 4.0;
    double offdiag_minus = (jx - jy) / 4.0;

    int m1 = 1 << i;
    int m2 = 1 << j;
    int m3 = m1 + m2;
    for(int local_i = 0; local_i < map.get_m_local(); ++local_i) {
      int k1 = map.translate_l2g_row(local_i);
      for(int local_j = 0; local_j < map.get_n_local(); ++local_j) {
        int k2 = map.translate_l2g_col(local_j);
        if (((k2 & m3) == m1) || ((k2 & m3) == m2)) {  // when (bit i == 1, bit j == 0) or (bit i == 0, bit j == 1)
          if (k1 == (k2^m3)) {
            mat.update_local(local_i, local_j, offdiag_plus);
          }
          if (k1 == k2) {
            mat.update_local(local_i, local_j, diag_minus);
          }
        } else {
          if (k1 == (k2^m3)) {
            mat.update_local(local_i, local_j, offdiag_minus);
          }
          if (k1 == k2) {
            //std::cout << "k1=" << k1 << " k2=" << k2 << std::endl;
            mat.update_local(local_i, local_j, diag_plus);
          }
        }
      }
    }
  }
}
*/

} // namespace xyz_hamiltonian

} // namespace rokko

#endif // ROKKO_UTILITY_XYZ_HAMILTONIAN_MPI_HPP


<|start_filename|>test/diagonalize/heisenberg.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2013-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/heisenberg_hamiltonian.hpp>

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

TEST(diagonalize, heisenberg) {
  std::vector<std::string> names;
  if (global_argc == 1) {
    names = rokko::serial_dense_ev::solvers();
  } else {
    for (int num=1; num < global_argc; ++num) {
      names.emplace_back(global_argv[num]);
    }
  }

  for(auto name : names) {
    int L = 5;
    int dim = 1 << L;
    std::vector<std::pair<int, int>> lattice;
    for (int i=0; i<L-1; ++i) {
      lattice.emplace_back(std::make_pair(i, i+1));
    }

    std::cout << "solver=" << name << std::endl;
    rokko::serial_dense_ev solver(name);
    solver.initialize(global_argc, global_argv);
    Eigen::MatrixXd mat(dim, dim);
    rokko::heisenberg_hamiltonian::generate(L, lattice, mat);
    Eigen::VectorXd w(dim);
    Eigen::MatrixXd Z(dim, dim);
    std::cout << "mat=" << mat << std::endl;
    solver.diagonalize(mat, w, Z);
    
    double sum = 0;
    for(int i=0; i<dim; ++i) {
      sum += w[i];
    }

    std::cout << "w=" << w.transpose() << std::endl;
    
    solver.finalize();
  }
}

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  global_argc = argc;
  global_argv = argv;
  return RUN_ALL_TESTS();
}


<|start_filename|>rokko/eigen3/generate_matrix.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_EIGEN3_GENERATE_MATRIX_HPP
#define ROKKO_EIGEN3_GENERATE_MATRIX_HPP

#include <iostream>
#include <rokko/eigen3.hpp>

namespace rokko {

template<typename T, int ROWS, int COLS, class FUNC>
void generate(Eigen::Matrix<T,ROWS,COLS,Eigen::RowMajor>& mat, FUNC func) {
  for(int i = 0; i < mat.rows(); ++i) {
    for(int j = 0; j < mat.cols(); ++j) {
      mat(i, j) = func(i, j);
    }
  }
}

template<typename T, int ROWS, int COLS, class FUNC>
void generate(Eigen::Matrix<T,ROWS,COLS,Eigen::ColMajor>& mat, FUNC func) {
  for(int j = 0; j < mat.cols(); ++j) {
    for(int i = 0; i < mat.rows(); ++i) {
      mat(i, j) = func(i, j);
    }
  }
}

template<typename T, int ROWS, int COLS>
void generate(Eigen::Matrix<T,ROWS,COLS,Eigen::RowMajor>& mat, std::function<T(int, int)> const& func) {
  for(int i = 0; i < mat.rows(); ++i) {
    for(int j = 0; j < mat.cols(); ++j) {
      mat(i, j) = func(i, j);
    }
  }
}

template<typename T, int ROWS, int COLS>
void generate(Eigen::Matrix<T,ROWS,COLS,Eigen::ColMajor>& mat, std::function<T(int, int)> const& func) {
  for(int j = 0; j < mat.cols(); ++j) {
    for(int i = 0; i < mat.rows(); ++i) {
      mat(i, j) = func(i, j);
    }
  }
}

} // namespace rokko

#endif // ROKKO_EIGEN3_GENERATE_MATRIX_HPP


<|start_filename|>example/cxx/dense/heisenberg.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/heisenberg_hamiltonian.hpp>
#include <iostream>


int main(int argc, char *argv[]) {
  std::string solver_name(rokko::serial_dense_ev::default_solver());
  int L = 8;
  if (argc >= 2) solver_name = argv[1];
  if (argc >= 3) L = std::stoi(argv[2]);

  std::cout.precision(5);

  std::vector<std::pair<int, int>> lattice;
  for (int i = 0; i < L-1; ++i) { lattice.emplace_back(std::make_pair(i, i+1)); }
  lattice.emplace_back(std::make_pair(L-1, 0));
  int dim = 1 << L;

  rokko::serial_dense_ev solver(solver_name);
  solver.initialize(argc, argv);
  std::cout << "Eigenvalue decomposition of antiferromagnetic Heisenberg chain" << std::endl
            << "solver = " << solver_name << std::endl
            << "L = " << L << std::endl
            << "dimension = " << dim << std::endl;

  Eigen::MatrixXd mat(dim, dim);
  rokko::heisenberg_hamiltonian::generate(L, lattice, mat);

  Eigen::VectorXd eigval(dim);
  Eigen::MatrixXd eigvec(dim, dim);
  solver.diagonalize(mat, eigval, eigvec);
  rokko::heisenberg_hamiltonian::generate(L, lattice, mat);

  std::cout << "smallest eigenvalues:";
  for (int i = 0; i < std::min(dim, 10); ++i) std::cout << ' ' << eigval(i);
  std::cout << std::endl;
  std::cout << "residual of the smallest eigenvalue/vector: |x A x - lambda| = "
            << std::abs(eigvec.col(0).transpose() * mat * eigvec.col(0) - eigval(0))
            << std::endl;

  solver.finalize();
}


<|start_filename|>config/Findmpi4py.cmake<|end_filename|>
# - Try to find mpi4py
# Once done this will define
#
#  MPI4PY_FOUND        - system has mpi4py
#  MPI4PY_DIR          - directory where mpi4py is installed

if(DEFINED MPI4PY_FOUND)
  return()
endif(DEFINED MPI4PY_FOUND)

message(STATUS "Checking for mpi4py for Python Binding")
set(MPI4PY_FOUND FALSE)

execute_process(COMMAND ${PYTHON_EXECUTABLE} "-c"
"import mpi4py
print(mpi4py.__path__[0])
"
    RESULT_VARIABLE _PYTHON_SUCCESS
    OUTPUT_VARIABLE _PYTHON_OUTPUT_VALUES
    ERROR_VARIABLE _PYTHON_ERROR_VALUES
    OUTPUT_STRIP_TRAILING_WHITESPACE
    )

if(_PYTHON_SUCCESS MATCHES 0)
  set(MPI4PY_DIR ${_PYTHON_OUTPUT_VALUES})
  message(STATUS "Found mpi4py: ${MPI4PY_DIR}")
  set(MPI4PY_FOUND TRUE)
else(_PYTHON_SUCCESS MATCHES 0)
  message(FATAL_ERROR "Failed to find mpi4py:")
  message(FATAL_ERROR "  error: ${_PYTHON_ERROR_VALUES}")
  set(MPI4PY_FOUND FALSE)
endif(_PYTHON_SUCCESS MATCHES 0)


<|start_filename|>rokko/eigenexa/eigenexa_interface.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_EIGENEXA_EIGENEXA_INTERFACE_H
#define ROKKO_EIGENEXA_EIGENEXA_INTERFACE_H

#include <mpi.h>
#include <rokko/mangling.h>

#ifdef __cplusplus
extern "C" {
#endif

#define EIGENEXA_init_wrap0 ROKKO_GLOBAL(eigen_init_wrap0,EIGEN_INIT_WRAP0)
void EIGENEXA_init_wrap0();

#define EIGENEXA_init_wrap1 ROKKO_GLOBAL(eigen_init_wrap1,EIGEN_INIT_WRAP1)
void EIGENEXA_init_wrap1(const MPI_Fint* comm);

#define EIGENEXA_init_wrap2 ROKKO_GLOBAL(eigen_init_wrap2,EIGEN_INIT_WRAP2)
void EIGENEXA_init_wrap2(const MPI_Fint* comm, const char* grid_major);

#define EIGENEXA_free_wrap0 ROKKO_GLOBAL(eigen_free_wrap0,EIGEN_FREE_WRAP0)
void EIGENEXA_free_wrap0();

#define EIGENEXA_free_wrap1 ROKKO_GLOBAL(eigen_free_wrap1,EIGEN_FREE_WRAP1)
void EIGENEXA_free_wrap1(const int* flag);

#define EIGENEXA_get_matdims_wrap ROKKO_GLOBAL(eigen_get_matdims_wrap,EIGEN_GET_MATDIMS_WRAP)
void EIGENEXA_get_matdims_wrap(const int* nprow, const int* npcol, const int* n, int* nx, int* ny);

#define EIGENEXA_get_procs_wrap ROKKO_GLOBAL(eigen_get_procs_wrap,EIGEN_GET_PROCS_WRAP)
void EIGENEXA_get_procs_wrap(int* procs, int* x_procs, int* y_procs);

#define EIGENEXA_get_id_wrap ROKKO_GLOBAL(eigen_get_id_wrap,EIGEN_GET_ID_WRAP)
void EIGENEXA_get_id_wrap(int* id, int* x_id, int* y_id);

#define EIGENEXA_loop_start_wrap ROKKO_GLOBAL(eigen_loop_start_wrap,EIGEN_LOOP_START_WRAP)
int EIGENEXA_loop_start_wrap(const int* istart, const int* nnod, const int* inod);

#define EIGENEXA_loop_end_wrap ROKKO_GLOBAL(eigen_loop_end_wrap,EIGEN_LOOP_END_WRAP)
int EIGENEXA_loop_end_wrap(const int* iend, const int* nnod, const int* inod);

#define EIGENEXA_translate_l2g_wrap ROKKO_GLOBAL(eigen_translate_l2g_wrap,EIGEN_TRANSLATE_L2G_WRAP)
int EIGENEXA_translate_l2g_wrap(const int* ictr, const int* nnod, const int* inod);

#define EIGENEXA_translate_g2l_wrap ROKKO_GLOBAL(eigen_translate_g2l_wrap,EIGEN_TRANSLATE_G2L_WRAP)
int EIGENEXA_translate_g2l_wrap(const int* ictr, const int* nnod, const int* inod);

#define EIGENEXA_eigen_s ROKKO_GLOBAL(eigen_s,EIGEN_S)
void EIGENEXA_eigen_s(const int* n, const int* nvec, double* a, const int* lda,
                      double* w, double* z, const int* ldz,
                      const int* m_forward, const int* m_backword, const char* mode);
  
#define EIGENEXA_eigen_sx ROKKO_GLOBAL(eigen_sx,EIGEN_SX)
void EIGENEXA_eigen_sx(const int* n, const int* nvec, double* a, const int* lda,
                       double* w, double* z, const int* ldz,
                       const int* m_forward, const int* m_backword, const char* mode);

#ifdef __cplusplus
}
#endif

#endif // ROKKO_EIGENEXA_EIGENEXA_INTERFACE_H


<|start_filename|>example/fortran/dense/generate_matrix/frank_array.f90<|end_filename|>
!*****************************************************************************
!
! Rokko: Integrated Interface for libraries of eigenvalue decomposition
!
! Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
!
! 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)
!
!*****************************************************************************

program frank_matrix
  use rokko
  implicit none
  integer :: dim
  type(rokko_eigen_matrix) :: mat
  double precision, allocatable :: array(:,:)
  double precision :: val
  integer :: i, j

  dim = 10
  print *,"dimension = ", dim
  allocate( array(dim, dim) )

  call rokko_construct(mat, array, rokko_matrix_col_major)

  ! generate frank matrix
  do i = 1, dim
     do j = 1, dim
        val = dble(dim+1 - max(i, j))
        array(i, j) = val
     enddo
  enddo
  call rokko_print(mat)

  call rokko_destruct(mat)

end program frank_matrix


<|start_filename|>example/cxx/dense/generate_vector/eigen_vector_generate.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/eigen3/generate_vector.hpp>
#include <iostream>

int main(int argc, char *argv[]) {
  const auto f = [](int i) { return static_cast<double>(2*i); };

  unsigned int dim = 10;
  Eigen::VectorXd vec(dim);
  rokko::generate(vec, f);

  std::cout << "vec:\n"
            << vec.transpose() << std::endl;
}


<|start_filename|>rokko/utility/matrix012.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_MATRIX012_HPP
#define ROKKO_UTILITY_MATRIX012_HPP

#include <cmath>
#include <stdexcept>
#include <rokko/config.h>
#include <rokko/eigen3.hpp>
#if defined(ROKKO_HAVE_PARALLEL_DENSE_SOLVER)
# include <rokko/distributed_matrix.hpp>
#endif

namespace rokko {

class matrix012 {
public:

  template<int MATRIX_MAJOR>
  static int get_index(int lld, int global_i, int global_j);

  template<typename T, int ROWS, int COLS>
  static void generate(Eigen::Matrix<T,ROWS,COLS,Eigen::ColMajor>& mat) {
    const int ld = mat.rows();

    for(int j = 0; j < mat.cols(); ++j) {
      for(int i = 0; i < mat.rows(); ++i) {
        mat(i,j) = get_index<Eigen::ColMajor>(ld, i, j);
      }
    }
  }

  template<typename T, int ROWS, int COLS>
  static void generate(Eigen::Matrix<T,ROWS,COLS,Eigen::RowMajor>& mat) {
    const int ld = mat.cols();

    for(int i = 0; i < mat.rows(); ++i) {
      for(int j = 0; j < mat.cols(); ++j) {
        mat(i,j) = get_index<Eigen::RowMajor>(ld, i, j);
      }
    }
  }

  static int get_index(rokko::mapping_bc<rokko::matrix_col_major> const& map, int global_i, int global_j) {
    return global_i + map.get_m_global() * global_j;
  }

  static int get_index(rokko::mapping_bc<rokko::matrix_row_major> const& map, int global_i, int global_j) {
    return map.get_n_global() * global_i + global_j;
  }

  template<typename T>
  static void generate(rokko::distributed_matrix<T, matrix_col_major>& mat) {
    const auto& map = mat.get_mapping();

    for (int local_j = 0; local_j < map.get_n_local(); ++local_j) {
      int global_j = map.translate_l2g_col(local_j);
      for (int local_i = 0; local_i < map.get_m_local(); ++local_i) {
        int global_i = map.translate_l2g_row(local_i);
        mat.set_local(local_i, local_j, get_index(map, global_i, global_j));
      }
    }
  }

  template<typename T>
  static void generate(rokko::distributed_matrix<T, matrix_row_major>& mat) {
    const auto& map = mat.get_mapping();

    for (int local_i = 0; local_i < map.get_m_local(); ++local_i) {
      int global_i = map.translate_l2g_row(local_i);
      for (int local_j = 0; local_j < map.get_n_local(); ++local_j) {
        int global_j = map.translate_l2g_col(local_j);
        mat.set_local(local_i, local_j, get_index(map, global_i, global_j));
      }
    }
  }
};

template<>
int matrix012::get_index<Eigen::ColMajor>(int ld, int global_i, int global_j) {
  return global_i + ld * global_j;
}

template<>
int matrix012::get_index<Eigen::RowMajor>(int ld, int global_i, int global_j) {
  return ld * global_i + global_j;
}

} // namespace rokko

#endif // ROKKO_UTILITY_MATRIX012_HPP


<|start_filename|>rokko/elpa/diagonalize_get_parameters.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_ELPA_DIAGONALIZE_GET_PARAMETERS_HPP
#define ROKKO_ELPA_DIAGONALIZE_GET_PARAMETERS_HPP

#include <rokko/parameters.hpp>
#include <rokko/elpa/elpa.h>

namespace rokko {
namespace elpa {

void get_nev(parameters const& params, int& nev) {
  if (params.defined("num_eigvals"))
    nev = params.get<int>("num_eigvals");
  if (params.defined("nev"))
    nev = params.get<int>("nev");
}

int get_kernel(parameters const& params) {
  return params.defined("kernel") ? params.get<int>("kernel") : ELPA_2STAGE_REAL_GENERIC_SIMPLE;
}

int get_blocked_qr(parameters const& params) {
  return params.defined("blocked_qr") ? static_cast<int>(params.get<bool>("blocked_qr")) : 0;
}

int get_solver(parameters const& params) {
  const std::string routine = params.defined("routine") ? params.get_string("routine") : "";

  if (routine=="elpa1") {
    return ELPA_SOLVER_1STAGE;
  } else if (routine=="elpa2") {
    return ELPA_SOLVER_2STAGE;
  } else if (routine=="") {  // default
    return ELPA_SOLVER_2STAGE;
  } else {
    throw std::invalid_argument("elpa::get_solver() : " + routine + " is invalid routine name");
  }
}

} // namespace elpa
} // namespace rokko

#endif // ROKKO_ELPA_DIAGONALIZE_GET_PARAMETERS_HPP



<|start_filename|>benchmark/no_rokko/dense_minij_mpi/elemental.cpp<|end_filename|>
/*
   Copyright (c) 2009-2014, <NAME>
   All rights reserved.

   This file is part of Elemental and is under the BSD 2-Clause License, 
   which can be found in the LICENSE file in the root directory, or at 
   http://opensource.org/licenses/BSD-2-Clause
*/
#include "El.hpp"
#include <rokko/utility/machine_info.hpp>

int main( int argc, char* argv[] ) {
  double init_tick, initend_tick, gen_tick, diag_tick, end_tick;
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  int nprocs;
  MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
  // This detects whether or not you have already initialized MPI and 
  // does so if necessary. The full routine is El::Initialize.
  MPI_Barrier(MPI_COMM_WORLD);
  init_tick = MPI_Wtime();
  El::Initialize( argc, argv );
  MPI_Barrier(MPI_COMM_WORLD);
  initend_tick = MPI_Wtime();

  El::Int dim = 100; //30000;
  if (argc >= 2) dim = std::stoi(argv[1]);
  
  if (El::mpi::Rank() == 0)
    std::cout << "Eigenvalue decomposition of minij matrix" << std::endl
              << "num_procs = " << nprocs << std::endl
#ifdef _OPENMP
              << "num_threads per process = " << omp_get_max_threads() << std::endl
#endif
              << "dimension = " << dim << std::endl;
    
  // Surround the Elemental calls with try/catch statements in order to 
  // safely handle any exceptions that were thrown during execution.
  try {
    MPI_Barrier(MPI_COMM_WORLD);
    gen_tick = MPI_Wtime();

    // Create a 2d process grid from a communicator. In our case, it is
    // MPI_COMM_WORLD. There is another constructor that allows you to 
    // specify the grid dimensions, Grid g( comm, r ), which creates a
    // grid of height r.
    El::Grid g( El::mpi::COMM_WORLD );
    
    // Create an n x n complex distributed matrix, 
    // We distribute the matrix using grid 'g'.
    //
    // There are quite a few available constructors, including ones that 
    // allow you to pass in your own local buffer and to specify the 
    // distribution alignments (i.e., which process row and column owns the
    // top-left element)
    El::DistMatrix<double> H( dim, dim, g );
    
    // Fill the matrix since we did not pass in a buffer. 
    //
    // We will fill entry (i,j) with the complex value (i+j,i-j) so that 
    // the global matrix is Hermitian. However, only one triangle of the 
    // matrix actually needs to be filled, the symmetry can be implicit.
    //
    const El::Int localHeight = H.LocalHeight();
    const El::Int localWidth = H.LocalWidth();
    for( El::Int jLoc=0; jLoc<localWidth; ++jLoc ) {
      // Our process owns the rows colShift:colStride:n,
      //           and the columns rowShift:rowStride:n
      const El::Int j = H.GlobalCol(jLoc);
      for( El::Int iLoc=0; iLoc<localHeight; ++iLoc ) {
        const El::Int i = H.GlobalRow(iLoc);
        H.SetLocal( iLoc, jLoc, std::min(i, j) + 1 );
      }
    }
    
    // Call the eigensolver. We first create an empty complex eigenvector 
    // matrix, X[MC,MR], and an eigenvalue column vector, w[VR,* ]
    //
    // Optional: set blocksizes and algorithmic choices here. See the 
    //           'Tuning' section of the README for details.
    MPI_Barrier(MPI_COMM_WORLD);
    diag_tick = MPI_Wtime();
    El::DistMatrix<double,El::VR,El::STAR> w( g );
    El::DistMatrix<double> X( g );
    El::HermitianEig( El::LOWER, H, w, X );
    MPI_Barrier(MPI_COMM_WORLD);
    end_tick = MPI_Wtime();

    std::vector<double> eigvals(dim);
    for (int i = 0; i < dim; ++i) {
      eigvals[i] = w.Get(i,0);
    }
    
    if( El::mpi::Rank() == 0 ) {
      std::cout << "init_time = " << initend_tick - init_tick << std::endl
                << "gen_time = " << diag_tick - gen_tick << std::endl
                << "diag_time = " << end_tick - diag_tick << std::endl;
      rokko::machine_info();
      //bool sorted = true;
      //for (unsigned int i = 1; i < dim; ++i) sorted &= (eigvals[i-1] <= eigvals[i]);
      //if (!sorted) std::cout << "Warning: eigenvalues are not sorted in ascending order!\n";
      std::cout << "largest eigenvalues:";
      for (int i = 0; i < std::min(dim, 10); ++i)
        std::cout << ' ' << eigvals[i];
      std::cout << std::endl;
    }

  } catch( std::exception& e ) { El::ReportException(e); }
  
  El::Finalize();
  MPI_Finalize();
  return 0;
}



<|start_filename|>test/mpi_collective/gather_vector.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2013-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/solver.hpp>
#include <rokko/utility/mpi_vector.hpp>

#include <random>

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

void run_test(MPI_Comm comm, int dim) {
  int size, rank;
  MPI_Comm_size(comm, &size);
  MPI_Comm_rank(comm, &rank);
  rokko::mpi_vector mpi(dim);

  // same seed for all processes
  std::mt19937 engine(123lu);
  std::uniform_real_distribution<> dist(-1.0, 1.0);

  rokko::distributed_vector<double> vec(dim, mpi.get_displacement(), mpi.get_displacement() + mpi.get_count());
  for (int i = 0; i < dim; ++i) {
    double d = dist(engine);
    if (vec.has_global_index(i)) vec.set_global(i, d);
  }

  Eigen::VectorXd lvec(dim);
  for (int r = 0; r < size; ++r) {
    mpi.gather(vec, lvec, r);
    if (rank == r) {
#ifndef NDEBUG
      std::cout << "rank=" << rank << std::endl
                << lvec.transpose() << std::endl;
      std::cout.flush();
#endif
      for (int i = 0; i < dim; ++i) {
        if (vec.has_global_index(i))
          ASSERT_EQ(vec.get_global(i), lvec(i));
      }
    }
#ifndef NDEBUG
    MPI_Barrier(comm);
#endif
  }

}

TEST(mpi_communication, gather_vector) {
  MPI_Comm comm = MPI_COMM_WORLD;
  int rank;
  MPI_Comm_rank(comm, &rank);

  int dim = 100;
  if (global_argc > 1) {
    dim = std::stoi(global_argv[1]);
  }
  if (rank == 0) std::cout << "dimension = " << dim << std::endl;

  run_test(comm, dim);
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  MPI_Init(&argc, &argv);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>tutorial/titpack/03_rokko_cxx/hamiltonian.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#ifndef TITPACK_HAMILTONIAN_HPP
#define TITPACK_HAMILTONIAN_HPP

#include <rokko/rokko.hpp>
#include "subspace.hpp"

//
// hamiltonian
//

class hamiltonian : public rokko::distributed_mfree {
public:
  hamiltonian(subspace const& ss, std::vector<int> const& ipair, std::vector<double> const& bondwt,
              std::vector<double> const& zrtio);
  int num_sites() const { return ss_.num_sites(); }
  int num_bonds() const { return bondwt_.size(); }
  int dimension() const { return ss_.dimension(); }
  int config(int i) const { return ss_.config(i); }
  int config2index(int c) const { return ss_.config2index(c); }
  std::pair<int, int> site_pair(int k) const {
    return std::make_pair(ipair_[2 * k], ipair_[2 * k + 1]);
  }
  double bond_weight (int k) const { return bondwt_[k]; }
  double z_ratio (int k) const { return zrtio_[k]; }
  void multiply(const double *v1, double *v0) const;

  // for rokko distributed_mfree (It can be run only with 1 MPI proc.)
  int get_dim() const { return dimension(); }
  int get_local_offset() const { return 0; }
  int get_num_local_rows() const { return dimension(); }
  MPI_Comm get_comm() const { return MPI_COMM_WORLD; }
  
private:
  subspace const& ss_;
  std::vector<int> ipair_;
  std::vector<double> bondwt_, zrtio_;
};

#endif


<|start_filename|>rokko/lapack/sterf.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_STERF_HPP
#define ROKKO_LAPACK_STERF_HPP

#include <complex>
#include <lapacke.h>
#undef I
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>
#include "complex_cast.hpp"

namespace rokko {
namespace lapack {

namespace {

template<typename T> struct sterf_dispatch;

template<>
struct sterf_dispatch<float> {
  template<typename VECTOR>
  static lapack_int sterf(lapack_int n,
                          VECTOR& d, VECTOR& e) {
    return LAPACKE_ssterf(n, storage(d), storage(e));
  }
};

template<>
struct sterf_dispatch<double> {
  template<typename VECTOR>
  static lapack_int sterf(lapack_int n,
                          VECTOR& d, VECTOR& e) {
    return LAPACKE_dsterf(n, storage(d), storage(e));
  }
};

} // end of anonymous namespace

template<typename VECTOR>
lapack_int sterf(VECTOR& d, VECTOR& e) {
  lapack_int n = size(d);
  if (size(e) != (n-1))
    throw std::invalid_argument("vector e size mismatch");
  return sterf_dispatch<value_t<VECTOR>>::
    sterf(n, d, e);
}

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_STERF_HPP


<|start_filename|>rokko/utility/frank_matrix_c.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/utility/frank_matrix.hpp>
#include <rokko/utility/frank_matrix.h>

#if defined(ROKKO_HAVE_PARALLEL_DENSE_SOLVER)
void rokko_frank_matrix_generate_distributed_matrix(rokko_distributed_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    rokko::frank_matrix::generate(*static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr));
  else
    rokko::frank_matrix::generate(*static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr));
}
#endif

void rokko_frank_matrix_generate_eigen_matrix(rokko_eigen_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    rokko::frank_matrix::generate(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(matrix.ptr));
  else
    rokko::frank_matrix::generate(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(matrix.ptr));
}


<|start_filename|>rokko/eigenexa/eigenexa.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2016 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/parallel_dense_ev.hpp>
#include <rokko/eigenexa/solver.hpp>

ROKKO_REGISTER_PARALLEL_DENSE_SOLVER(rokko::eigenexa::solver, "eigenexa", 40)


<|start_filename|>example/scalapack/pstedc.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <mpi.h>
#include <cmath>
#include <iostream>
#include <rokko/distributed_matrix.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/scalapack.hpp>
#include <rokko/utility/laplacian_matrix.hpp>

int main(int argc, char** argv) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  rokko::grid grid(MPI_COMM_WORLD);

  int n = 20;
  if (argc > 1) n = std::atoi(argv[1]);

  // generate matrix
  Eigen::VectorXd d(n), e(n-1);
  rokko::laplacian_matrix::generate(d, e);

  if (grid.get_myrank() == 0) {
    std::cout << "n = " << n << std::endl;
    std::cout << "nprocs = " << grid.get_nprocs() << std::endl;
    std::cout << "nprow = " << grid.get_nprow() << std::endl;
    std::cout << "npcol = " << grid.get_npcol() << std::endl;
    if ((grid.get_nprocs() != grid.get_nprow() * grid.get_npcol()) ||
        (n % grid.get_nprow() != 0) || (n % grid.get_npcol() != 0)) {
      std::cerr << "incompatible matrix size and number of processes\n";
      MPI_Abort(MPI_COMM_WORLD, 127);
    }
  }

  rokko::mapping_bc<rokko::matrix_col_major> map(n, 1);
  rokko::distributed_matrix<double> z(map);
  Eigen::VectorXd w = d;

  int info = rokko::scalapack::pstedc('I', w, e, z);
  if (info) {
    std::cerr << "Error in rokko::scalapack::psyevd\n";
    MPI_Abort(MPI_COMM_WORLD, info);
  }
  if (grid.get_myrank() == 0)
    std::cout << "eigenvalues: " << w.transpose() << std::endl;

  MPI_Finalize();
}


<|start_filename|>rokko/lapack/diagonalize_get_parameters.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/parameters.hpp>

namespace rokko {
namespace lapack {

char get_matrix_part(parameters const& params) {
  std::string matrix_part;

  if (params.defined("matrix_part"))
    matrix_part = params.get_string("matrix_part");
  else if (params.defined("uplow"))
    matrix_part = params.get_string("uplow");

  if (!matrix_part.empty()) {
    char matrix_part_letter = matrix_part[0];
    if ((matrix_part_letter == 'u') || (matrix_part_letter == 'U'))
      return 'U';
    if ((matrix_part_letter == 'l') || (matrix_part_letter == 'L'))
      return 'L';
  }
  return 'U';  // default
}
  
std::string get_matrix_part(char const& uplow) {
  if (uplow == 'U')
    return "upper";
  else if (uplow == 'L')
    return "lower";
  else
    return "none";
}

template<typename T>
char get_eigenvalues_range(parameters const& params, T& vl, T& vu, int& il, int& iu) {
  bool is_lower_value = get_key(params, "lower_value", vl);
  bool is_lower_index = get_key(params, "lower_index", il);
  bool is_upper_value = get_key(params, "upper_value", vu);
  bool is_upper_index = get_key(params, "upper_index", iu);

  if (is_lower_index && is_upper_index)   return 'I';
  else if (is_lower_value && is_upper_value)   return 'V';
  else if (!(is_lower_index && is_lower_value && is_upper_index && is_upper_value))
    return 'A';
  else
    throw std::invalid_argument("error: sepcify either of a pair of upper_value and lower_value or a pair of upper_index and lower_index");
}

void print_verbose(std::string const& routine, char const& jobz, char const& uplow) {
  std::cout << "specified solver: " << routine << std::endl;
  if (jobz == 'V') {
    std::cout << "eigenvalues / eigenvectors were requested" << std::endl;
  } else if (jobz == 'N') {
    std::cout << "only eigenvalues were requested" << std::endl;
  } else {
    std::cout << "jobz '" << jobz << "' is not valid." << std::endl;
  }

  std::cout << "The " << get_matrix_part(uplow) << " part of the matrix was used" << std::endl;
}

template<typename T>
void print_verbose(std::string const& routine, char const& jobz, char const& range, char const& uplow,
		   T vl, T vu, int il, int iu) {
  std::cout << "specified solver: " << routine << std::endl;
  if (jobz == 'V') {
    std::cout << "eigenvalues / eigenvectors were requested" << std::endl;
  } else if (jobz == 'N') {
    std::cout << "only eigenvalues were requested" << std::endl;
  } else {
    std::cout << "jobz '" << jobz << "' is not valid." << std::endl;
  }

  if (range == 'A') {
    std::cout << "All eigenvalues were requested" << std::endl;
  } else if (range == 'V') {
    std::cout << "Eigenvalues contained in the interval [" << vl << ", " << vu << "]" << " were requested" << std::endl;
  } else if (range == 'I') {
    std::cout << "Eigenvalues from " << il << "th" << " to " << iu << "th" << " were requested" << std::endl;
  } else {
    std::cout << "range '" << range << "' is not valid." << std::endl;
  }

  std::cout << "The " << get_matrix_part(uplow) << " part of the matrix was used" << std::endl;
}

template<typename T>
void print_verbose(std::string const& routine, char const& jobz, char const& range, char const& uplow,
		   T vl, T vu, int il, int iu,
		   parameters const& params) {
  print_verbose(routine, jobz, range, uplow, vl, vu, il, iu);
  if (routine == "syevx") {
    std::cout << "The number of found eigenvalues = " << params.get_string("m") << std::endl;
    //std::cout << "ifail = " << params.get_string("ifail") << std::endl;
  }
  if (!params.defined("abstol")) {
    //std::cout << "abstol was not specified, so used optimal value for bisection method: 2 * LAPACKE_dlamch('S')" << std::endl;
    std::cout << "specified value: abstol=" << params.get_string("abstol") << std::endl;
  }
}

bool is_interval(parameters const& params) {
  if (params.defined("lower_value") || params.defined("upper_value") || params.defined("lower_index") || params.defined("upper_index")) {
    return true;
  }
  else if (params.defined("vl") || params.defined("vu") || params.defined("il") || params.defined("iu")) {
    return true;
  } else {
    return false;
  }
}

template
char get_eigenvalues_range(parameters const& params, double& vl, double& vu, int& il, int& iu);

template
char get_eigenvalues_range(parameters const& params, float& vl, float& vu, int& il, int& iu);

void print_verbose(std::string const& routine, char const& jobz, char const& uplow);

template
void print_verbose(std::string const& routine, char const& jobz, char const& range, char const& uplow,
		   double vl, double vu, int il, int iu);

template void print_verbose<double>(std::string const& routine, char const& jobz, char const& range, char const& uplow,
		   double vl, double vu, int il, int iu,
		   parameters const& params);

template void print_verbose<float>(std::string const& routine, char const& jobz, char const& range, char const& uplow,
		   float vl, float vu, int il, int iu,
		   parameters const& params);

} // namespace lapack
} // namespace rokko


<|start_filename|>rokko/lapack/diagonalize_sygvx.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_DIAGONALIZE_SYGVX_HPP
#define ROKKO_LAPACK_DIAGONALIZE_SYGVX_HPP

#include <rokko/parameters.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/utility/timer.hpp>
#include <rokko/lapack.hpp>
#include <rokko/lapack/diagonalize_get_parameters.hpp>

namespace rokko {
namespace lapack {

// only eigenvalues
template<typename T, int MATRIX_MAJOR, typename VEC>
parameters diagonalize_sygvx(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mata, Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& matb,
			      VEC& eigvals,
			      parameters const& params) {
  parameters params_out;
  const char jobz = 'N';  // only eigenvalues
  lapack_int m;  // output: found eigenvalues
  real_t<T> abstol = params.defined("abstol") ? params.get<real_t<T>>("abstol") : 0.;
  params_out.set("abstol", abstol);

  lapack_int il, iu;
  real_t<T> vl, vu;
  const char range = get_eigenvalues_range(params, vl, vu, il, iu);
  const char uplow = get_matrix_part(params);

  const int dim = mata.outerSize();
  std::vector<lapack_int> ifail(dim);
  constexpr int itype = 1;
  int info = sygvx(itype, jobz, range, uplow,
                   mata, matb, vl, vu, il, iu,
                   abstol, m, eigvals, NULL, ifail);

  if (info) {
    std::cerr << "error at dsygvx function. info=" << info << std::endl;
    if (info < 0) {
      std::cerr << "This means that ";
      std::cerr << "the " << abs(info) << "-th argument had an illegal value." << std::endl;
    }
  }
  params_out.set("m", m);
  params_out.set("ifail", ifail);
  
  if (params.get_bool("verbose")) {
    print_verbose("sygvx", jobz, range, uplow, vl, vu, il, iu, params_out);
  }

  return params_out;
}


// eigenvalues / eigenvectors
template<typename T, int MATRIX_MAJOR, typename VEC>
parameters diagonalize_sygvx(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mata, Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& matb,
			      VEC& eigvals,
			      Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& eigvecs,
			      parameters const& params) {
  rokko::parameters params_out;
  const char jobz = 'V';  // eigenvalues / eigenvectors
  const int dim = mata.outerSize();
  std::vector<lapack_int> ifail(dim);

  lapack_int m;  // output: found eigenvalues
  real_t<T> abstol = params.defined("abstol") ? params.get<real_t<T>>("abstol") : 0.;
  params_out.set("abstol", abstol);

  lapack_int il, iu;
  real_t<T>  vl, vu;
  const char range = get_eigenvalues_range(params, vl, vu, il, iu);
  const char uplow = get_matrix_part(params);

  constexpr int itype = 1;
  int info = sygvx(itype, jobz, range, uplow,
                   mata, matb,
                   vl, vu, il, iu,
                   abstol, m, eigvals, eigvecs, ifail);

  if (info) {
    std::cerr << "Error at dsygvx function. info=" << info << std::endl;
    if (params.get_bool("verbose")) {
      std::cerr << "This means that ";
      if (info < 0) {
	std::cerr << "the " << abs(info) << "-th argument had an illegal value." << std::endl;
      } else {
	std::cerr << "This means that "	<< info << " eigenvectors failed to converge." << std::endl;
	std::cerr << "The indices of the eigenvectors that failed to converge:" << std::endl;
	for (int i=0; i<ifail.size(); ++i) {
	  if (ifail[i] == 0) break;
	  std::cerr << ifail[i] << " ";
	}
	std::cerr << std::endl;
      }
    }
  }
  params_out.set("m", m);
  params_out.set("ifail", ifail);
  
  if (params.get_bool("verbose")) {
    print_verbose("sygvx", jobz, range, uplow, vl, vu, il, iu, params_out);
  }

  return params_out;
}


} // namespace lapack
} // namespace rokko

#endif // ROKKO_LAPACK_DIAGONALIZE_SYGVX_HPP


<|start_filename|>rokko/lapack/getrs.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_GETRS_HPP
#define ROKKO_LAPACK_GETRS_HPP

#include <complex>
#ifdef I
# undef I
#endif
#include <stdexcept>
#include <boost/type_traits/is_same.hpp>
#include <lapacke.h>
#include <rokko/traits/value_t.hpp>
#include "complex_cast.hpp"

namespace rokko {
namespace lapack {

namespace {

template<typename T> struct getrs_dispatch;
  
template<>
struct getrs_dispatch<float> {
  template<typename MATRIX0, typename MATRIX1, typename VECTOR>
  static lapack_int getrs(int matrix_layout, char trans, lapack_int n, lapack_int nrhs,
                          MATRIX0& a, VECTOR& ipiv, MATRIX1& b) {
    return LAPACKE_sgetrs(matrix_layout, trans, n, nrhs, storage(a), ld(a), storage(ipiv),
                          storage(b), ld(b));
  }
};

template<>
struct getrs_dispatch<double> {
  template<typename MATRIX0, typename MATRIX1, typename VECTOR>
  static lapack_int getrs(int matrix_layout, char trans, lapack_int n, lapack_int nrhs,
                          MATRIX0& a, VECTOR& ipiv, MATRIX1& b) {
    return LAPACKE_dgetrs(matrix_layout, trans, n, nrhs, storage(a), ld(a), storage(ipiv),
                          storage(b), ld(b));
  }
};

template<>
struct getrs_dispatch<std::complex<float>> {
  template<typename MATRIX0, typename MATRIX1, typename VECTOR>
  static lapack_int getrs(int matrix_layout, char trans, lapack_int n, lapack_int nrhs,
                          MATRIX0& a, VECTOR& ipiv, MATRIX1& b) {
    return LAPACKE_cgetrs(matrix_layout, trans, n, nrhs, complex_cast(storage(a)), ld(a),
                          storage(ipiv), complex_cast(storage(b)), ld(b));
  }
};

template<>
struct getrs_dispatch<std::complex<double>> {
  template<typename MATRIX0, typename MATRIX1, typename VECTOR>
  static lapack_int getrs(int matrix_layout, char trans, lapack_int n, lapack_int nrhs,
                          MATRIX0& a, VECTOR& ipiv, MATRIX1& b) {
    return LAPACKE_zgetrs(matrix_layout, trans, n, nrhs, complex_cast(storage(a)), ld(a),
                          storage(ipiv), complex_cast(storage(b)), ld(b));
  }
};

}
  
template<typename MATRIX0, typename MATRIX1, typename VECTOR>
lapack_int getrs(char trans, lapack_int nrhs, MATRIX0 const& a,
                 VECTOR const& ipiv, MATRIX1& b) {
  static_assert(std::is_same<value_t<VECTOR>, lapack_int>::value, "");
  static_assert(std::is_same<value_t<MATRIX0>, value_t<MATRIX1>>::value, "");
  lapack_int n = rows(a);
  if (rows(a) != cols(a))
    throw std::invalid_argument("matrix A size mismatch");
  if (size(ipiv) != n)
    throw std::invalid_argument("vector ipiv size mismatch");
  if (rows(b) != n || cols(b) != nrhs)
    throw std::invalid_argument("matrix B size mismatch");
  return getrs_dispatch<value_t<MATRIX0>>
    ::getrs((is_col_major(a) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR), trans, n, nrhs, a,
            ipiv, b);
}

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_GETRS_HPP


<|start_filename|>tutorial/titpack/03_rokko_cxx/common.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

// C++ version of TITPACK Ver.2 by <NAME>

#ifndef TITPACK_COMMON_HPP
#define TITPACK_COMMON_HPP

#include "subspace.hpp"
#include <cmath>
#include <iostream>
#include <vector>
#include <mpi.h>

//
// xx correlation function
//
// n           @ lattice size
// npair       @ pair of sites (k,l) <Sx(k)Sx(l)>
// x           @ eigenvetor
// sxx         # xx correlation function
// list1,list2 @ spin configurations generated in 'sz'

void xcorr(subspace const& ss, std::vector<int> const& npair, const double *x,
           std::vector<double>& sxx);

void xcorr(subspace const& ss, std::vector<int> const& npair,
           std::vector<double> const& x, std::vector<double>& sxx);

template<typename MATRIX>
void xcorr(subspace const& ss, std::vector<int> const& npair,
           MATRIX const& x, int xindex, std::vector<double>& sxx) {
  xcorr(ss, npair, &x(0, xindex), sxx);
}

//
// ************* zz correlation function **************
//

template<typename MATRIX>
void zcorr(subspace const& ss, std::vector<int> const& npair,
           MATRIX const& x, int xindex, std::vector<double>& szz) {
  int nbond = npair.size() / 2;
  for (int k = 0; k < nbond; ++k) {
    int i1 = npair[k * 2];
    int i2 = npair[k * 2 + 1];
    if (i1 < 0 || i1 >= ss.num_sites() || i2 < 0 || i2 >= ss.num_sites() || i1 == i2) {
      std::cerr << " #(W02)# Wrong site number given to zcorr\n";
      return;
    }
    double corr = 0;
    int is = (1 << i1) + (1 << i2);
    for (int i = 0; i < ss.dimension(); ++i) {
      int ibit = ss.config(i) & is;
      corr += ((ibit == 0 || ibit == is) ? 1.0 : -1.0) * x(i, xindex) * x(i, xindex);
    }
    szz[k] = corr / 4;
  }
}

template<typename MATRIX>
void zcorr_mpi(subspace const& ss, std::vector<int> const& npair,
               MATRIX const& x, int xindex, std::vector<double>& szz) {
  int nbond = npair.size() / 2;
  std::vector<double> szz_local(nbond);
  if (x.has_global_col_index(xindex)) {
    for (int k = 0; k < nbond; ++k) {
      int i1 = npair[k * 2];
      int i2 = npair[k * 2 + 1];
      if (i1 < 0 || i1 >= ss.num_sites() || i2 < 0 || i2 >= ss.num_sites() || i1 == i2) {
        std::cerr << " #(W02)# Wrong site number given to zcorr\n";
        return;
      }
      double corr = 0;
      int is = (1 << i1) + (1 << i2);
      for (int local_i = 0; local_i < x.get_m_local(); ++local_i) {
        int i = x.translate_l2g_row(local_i);
        int ibit = ss.config(i) & is;
        double val = x.get_global(i, xindex);
        corr += ((ibit == 0 || ibit == is) ? 1.0 : -1.0) * val * val;
      }
      szz_local[k] = corr / 4;
    }
  }
  MPI_Reduce(szz_local.data(), szz.data(), nbond, MPI_DOUBLE, MPI_SUM, 0, x.get_grid().get_comm());
}

//
// Orthogonalization of the eigenvectors
//
// return value #  degree of degenearcy
// ev      @# vectors to be orthogonalized / orthogonalized vectors
// norm(j) #  norm of the j-th vector returned
// numvec  @  number of vectors to be checked

template<typename MATRIX>
int orthg(MATRIX& ev, std::vector<double>& norm, int numvec) {
  if (numvec <= 1) {
    std::cerr << " #(W03)# Number of vectors is less than 2 in orthg\n";
    return -1;
  }
  if (norm.size() < numvec) norm.resize(numvec);
  int idim = ev.rows();
  for (int i = 0; i < numvec; ++i) {
    double dnorm = 0;
    for (int j = 0; j < idim; ++j) dnorm += ev(j, i) * ev(j, i);
    if (dnorm < 1e-20) {
      std::cerr << " #(W04)# Null vector given to orthg. Location is " << i << std::endl;
      return -1;
    }
    dnorm = 1 / std::sqrt(dnorm);
    for (int j = 0; j < idim; ++j) ev(j, i) *= dnorm;
  }
  int idgn = numvec;
  norm[0] = 1;

  // orthogonalization
  for (int i = 1; i < numvec; ++i) {
    norm[i] = 1;
    for (int j = 0; j < i; ++j) {
      double prjct = 0;
      for (int l = 0; l < idim; ++l) prjct += ev(l, i) * ev(l, j);
      for (int l = 0; l < idim; ++l) ev(l, i) -= prjct * ev(l, j);
    }
    double vnorm = 0;
    for (int l = 0; l < idim; ++l) vnorm += ev(l, i) * ev(l, i);
    if (vnorm > 1e-15) {
      vnorm = 1 / std::sqrt(vnorm);
      for (int l = 0; l < idim; ++l) ev(l, i) *= vnorm;
    } else {
      for (int l = 0; l < idim; ++l) ev(l, i) = 0;
      --idgn;
      norm[i] = 0;
    }
  }

  // check orthogonality
  for (int i = 1; i < numvec; ++i) {
    for (int j = 0; j < i; ++j) {
      double prd = 0;
      for (int l = 0; l < idim; ++l) prd += ev(l, i) * ev(l, j);
      if (std::abs(prd) > 1e-10) {
        std::cerr << " #(W05)# Non-orthogonal vectors at " << i << ' ' << j << std::endl
                  << "         Overlap : " << prd << std::endl;
      }
    }
  }
  return idgn;
}

#endif


<|start_filename|>rokko/elpa/diagonalize.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_ELPA_DIAGONALIZE_HPP
#define ROKKO_ELPA_DIAGONALIZE_HPP

#include <rokko/distributed_matrix.hpp>
#include <rokko/parameters.hpp>
#include <rokko/elpa/elpa.h>
#include <rokko/elpa.hpp>
#include <rokko/elpa/diagonalize_get_parameters.hpp>
#include <rokko/elpa/diagonalize_set_parameters.hpp>
#include <rokko/utility/timer.hpp>

namespace rokko {
namespace elpa {

template<typename T, typename VEC>
parameters diagonalize(distributed_matrix<T, rokko::matrix_col_major>& mat,
			     VEC& eigvals, distributed_matrix<T, rokko::matrix_col_major>& eigvecs,
			     parameters const& params) {
  parameters params_out;

  int error;
  elpa_t handle = elpa_allocate(&error);

  set_parameters(mat, params, handle);
  assert_elpa_ok(elpa_setup(handle));

  set_solver(params, handle);
  int info = elpa::diag(handle, mat, eigvals, eigvecs);
  assert_elpa_ok( deallocate(handle) );

  params_out.set("info", info);
  return params_out;
}

template<typename T, typename VEC>
parameters diagonalize(distributed_matrix<T, rokko::matrix_row_major>& mat,
			     VEC& eigvals, distributed_matrix<T, rokko::matrix_row_major>& eigvecs,
			     parameters const& params) {
  throw std::invalid_argument("elpa::diagonalize_elpa2() : elpa doesn't support matrix_row_major.  Use elpa with matrix_col_major.");
}

template<typename T, typename VEC>
parameters diagonalize(distributed_matrix<T, rokko::matrix_col_major>& mat,
			     VEC& eigvals,
			     parameters const& params) {
  parameters params_out;

  int error;
  elpa_t handle = elpa_allocate(&error);

  set_parameters(mat, params, handle);
  assert_elpa_ok(elpa_setup(handle));

  set_solver(params, handle);
  int info = elpa::diag(handle, mat, eigvals);
  assert_elpa_ok( deallocate(handle) );

  params_out.set("info", info);
  return params_out;
}

template<typename T, typename VEC>
parameters diagonalize(distributed_matrix<T, rokko::matrix_row_major>& mat,
			     VEC& eigvals,
			     parameters const& params) {
  throw std::invalid_argument("elpa::diagonalize_elpa2() : elpa doesn't support matrix_row_major.  Use elpa with matrix_col_major.");
}

} // namespace elpa
} // namespace rokko

#endif // ROKKO_ELPA_DIAGONALIZE_HPP


<|start_filename|>example/scalapack/pstebz_tein.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <mpi.h>
#include <cmath>
#include <iostream>
#include <rokko/distributed_matrix.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/scalapack.hpp>
#include <rokko/utility/laplacian_matrix.hpp>

int main(int argc, char** argv) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  rokko::grid grid(MPI_COMM_WORLD);

  int n = 20;
  if (argc > 1) n = std::atoi(argv[1]);

  // generate matrix
  Eigen::VectorXd d(n), e(n-1);
  rokko::laplacian_matrix::generate(d, e);

  if (grid.get_myrank() == 0) {
    std::cout << "n = " << n << std::endl;
    std::cout << "nprocs = " << grid.get_nprocs() << std::endl;
    std::cout << "nprow = " << grid.get_nprow() << std::endl;
    std::cout << "npcol = " << grid.get_npcol() << std::endl;
    if ((grid.get_nprocs() != grid.get_nprow() * grid.get_npcol()) ||
        (n % grid.get_nprow() != 0) || (n % grid.get_npcol() != 0)) {
      std::cerr << "incompatible matrix size and number of processes\n";
      MPI_Abort(MPI_COMM_WORLD, 127);
    }
  }

  const int ictxt = grid.get_blacs_context();
  Eigen::VectorXd w(n);
  constexpr double abstol = 0.;
  int m, nsplit;
  Eigen::VectorXi iblock(n), isplit(n);

  int info = rokko::scalapack::pstebz(ictxt, 'I', 'E',
                                      0., 0., 0, 0,
                                      abstol, d, e, m, nsplit,
                                      w, iblock, isplit);

  rokko::mapping_bc<rokko::matrix_col_major> map(n, 1);
  rokko::distributed_matrix<double> z(map);
  double orfac = 0;
  Eigen::VectorXi ifail(map.get_m_global());
  Eigen::VectorXi iclustr(2 * map.get_nprow() * map.get_npcol());
  Eigen::VectorXd gap(map.get_nprow() * map.get_npcol());

  info = rokko::scalapack::pstein(d, e, m,
                                  w, iblock, isplit, orfac,
                                  z,
                                  ifail, iclustr, gap);

  if (info) {
    std::cerr << "Error in rokko::scalapack::psyevd\n";
    MPI_Abort(MPI_COMM_WORLD, info);
  }
  if (grid.get_myrank() == 0)
    std::cout << "eigenvalues: " << w.transpose() << std::endl;

  MPI_Finalize();
}


<|start_filename|>rokko/pyrokko_collective.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_COLLECTIVE_HPP
#define PYROKKO_COLLECTIVE_HPP

#include <rokko/pyrokko_distributed_matrix.hpp>

#include <rokko/collective.hpp>

namespace rokko {

template<typename T, typename MATRIX_MAJOR>
void pyrokko_gather(wrap_distributed_matrix<T,MATRIX_MAJOR> const& from, Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,rokko::eigen3_major<MATRIX_MAJOR>>> to_in, int root) {
  constexpr int major = rokko::eigen3_major<MATRIX_MAJOR>;
  Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,major> to;
  new (&to) Eigen::Map<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,major>>(to_in.data(), to_in.rows(), to_in.cols());

  gather(from, to, root);

  new (&to) Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,major>();
}

template<typename T, typename MATRIX_MAJOR>
void pyrokko_scatter(Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,rokko::eigen3_major<MATRIX_MAJOR>>> from_in, wrap_distributed_matrix<T,MATRIX_MAJOR>& to, int root) {
  constexpr int major = rokko::eigen3_major<MATRIX_MAJOR>;
  Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,major> from;
  new (&from) Eigen::Map<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,major>>(from_in.data(), from_in.rows(), from_in.cols());

  scatter(from, to, root);

  new (&from) Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,major>();
}

} // end namespace rokko

#endif // PYROKKO_COLLECTIVE_HPP


<|start_filename|>example/c/sparse/heisenberg_crs_mpi.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*    
* 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)
*
*****************************************************************************/

#include <rokko/rokko.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  int rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);

  char* library_routine, *library, *routine;
  if (argc >= 2) {
    library_routine = rokko_parallel_sparse_ev_default_solver();
    if (argc >= 2) library_routine = argv[1];
  } else {
    library_routine = rokko_parallel_sparse_ev_default_solver();
  }
  rokko_split_solver_name(library_routine, &library, &routine);
  
  int L = (argc >= 3) ? atoi(argv[2]) : 10;
  int dim = 1 << L;
  int lattice_first[L], lattice_second[L];
  int l;
  for (l = 0; l < L; ++l) {
    lattice_first[l] = l;
    lattice_second[l] = (l+1) % L;
  }

  struct rokko_parallel_sparse_ev solver;
  rokko_parallel_sparse_ev_construct(&solver, library, argc, argv);
  struct rokko_mapping_1d map = rokko_parallel_sparse_ev_default_mapping(solver, dim, MPI_COMM_WORLD);
  struct rokko_distributed_crs_matrix mat;
  rokko_distributed_crs_matrix_construct(&mat, map, L+1);
  int row;
  int row_start = rokko_mapping_1d_start_row(map);
  int row_end = rokko_mapping_1d_end_row(map);
  int cols[dim];
  double values[dim];
  int count;
  double diag;
  int i, j, m1, m2, m3;
  for (row = row_start; row < row_end; ++row) {
    count = 0;
    diag = 0;
    for (l = 0; l < L; ++l) {
      i = lattice_first[l];
      j = lattice_second[l];
      m1 = 1 << i;
      m2 = 1 << j;
      m3 = m1 + m2;
      if (((row & m3) == m1) || ((row & m3) == m2)) {
        cols[count] = row^m3;
        values[count] = 0.5;
        ++count;
        diag += -0.25;
      } else {
        diag += 0.25;
      }
    }
    cols[count] = row;
    values[count] = diag;
    ++count;
    rokko_distributed_crs_matrix_insert(mat, row, count, cols, values);
  }
  rokko_distributed_crs_matrix_complete(mat);
  if (rank == 0) {
    printf("Eigenvalue decomposition of antiferromagnetic Heisenberg chain\n");
    printf("solver = %s\n", library);
    printf("L = %d\n", L);
    printf("dimension = %d\n", dim);
  }
  
  struct rokko_parameters params;
  rokko_parameters_construct(&params);
  // set some parameters
  if (routine[0] != '\0')  rokko_parameters_set_string(params, "routine", routine);
  rokko_parameters_set_int(params, "block_size", 5);
  rokko_parameters_set_int(params, "max_iters", 500);
  rokko_parameters_set_double(params, "conv_tol", 1.0e-12);
  rokko_parameters_set_int(params, "num_eigvals", 1);
  rokko_parallel_sparse_ev_diagonalize_distributed_crs_matrix(solver, mat, params);
  
  int num_conv = rokko_parallel_sparse_ev_num_conv(solver);
  printf("num_conv = %d\n", num_conv);
  if (num_conv == 0) MPI_Abort(MPI_COMM_WORLD, -1);
  int num_local_rows = rokko_distributed_crs_matrix_num_local_rows(mat);
  double eig_vec[num_local_rows];
  rokko_parallel_sparse_ev_eigenvector(solver, 0, eig_vec);

  if (rank == 0) {
    printf("number of converged eigenpairs = %d\n", num_conv);
    printf("smallest eigenvalues: ");
    for (i = 0; i < num_conv; ++i) printf("%30.20f", rokko_parallel_sparse_ev_eigenvalue(solver, i));
    printf("\n");
    printf("smallest eigenvector: ");
    for (j = 0; j < num_local_rows; ++j)
      printf("%30.20f ", eig_vec[j]);
    printf("\n");    
  }
  rokko_distributed_crs_matrix_destruct(&mat);
  rokko_parallel_sparse_ev_destruct(&solver);
  MPI_Finalize();
  return 0;
}


<|start_filename|>rokko/elpa/elpa.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_ELPA_H
#define ROKKO_ELPA_H

#ifdef __cplusplus
extern "C" {
#endif

#define complex   _Complex
//#include <elpa/elpa.h>
// **** begining of fixed elpa.h ****
#include <limits.h>
//#include <complex.h>

#include <elpa/elpa_version.h>

struct elpa_struct;
typedef struct elpa_struct *elpa_t;

struct elpa_autotune_struct;
typedef struct elpa_autotune_struct *elpa_autotune_t;


#include <elpa/elpa_constants.h>
#include <elpa/elpa_generated_c_api.h>
#include <elpa/elpa_generated.h>
//#include <elpa/elpa_generic.h>

const char *elpa_strerr(int elpa_error);
// **** end of fixed elpa.h ****
#include <assert.h>

#define assert_elpa_ok(x) assert(x == ELPA_OK)

#ifdef __cplusplus
}
#endif

#endif // ROKKO_ELPA_H


<|start_filename|>example/lapack/dsyev.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2017 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <cblas.h>
#include <lapacke.h>
#include <rokko/cmatrix.h>

int imax(int x, int y) { return (x > y) ? x : y; }

int main(int argc, char** argv) {
  int n = 5;
  int i, j, info;
  double norm;
  double *w;
  double **a, **u, **t;

  if (argc > 1) n = atoi(argv[1]);
    
  /* generate matrix */
  a = alloc_dmatrix(n, n);
  for (j = 0; j < n; ++j) {
    for (i = 0; i < n; ++i) {
      mat_elem(a, i, j) = n - imax(i, j);
    }
  }
  printf("Matrix A: ");
  fprint_dmatrix(stdout, n, n, a);

  /* diagonalization */
  u = alloc_dmatrix(n, n);
  cblas_dcopy(n * n, mat_ptr(a), 1, mat_ptr(u), 1);
  w = alloc_dvector(n);
  info = LAPACKE_dsyev(LAPACK_COL_MAJOR, 'V', 'U', n, mat_ptr(u), n, vec_ptr(w));
  if (info != 0) {
    fprintf(stderr, "Error: dsyev fails with error code %d\n", info);
    exit(255);
  }
  printf("Eigenvalues: ");
  fprint_dvector(stdout, n, w);
  printf("Eigenvectors: ");
  fprint_dmatrix(stdout, n, n, u);

  /* orthogonality check */
  t = alloc_dmatrix(n, n);
  cblas_dgemm(CblasColMajor, CblasTrans, CblasNoTrans, n, n, n, 1, mat_ptr(u), n,
              mat_ptr(u), n, 0, mat_ptr(t), n);
  for (i = 0; i < n; ++i) mat_elem(t, i, i) -= 1;
  norm = LAPACKE_dlange(LAPACK_COL_MAJOR, 'F', n, n, mat_ptr(t), n);
  printf("|| U^t U - I || = %e\n", norm);
  if (norm > 1e-10) {
    fprintf(stderr, "Error: orthogonality check\n");
    exit(255);
  }

  /* eigenvalue check */
  cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, n, n, n, 1, mat_ptr(a), n,
              mat_ptr(u), n, 0, mat_ptr(t), n);
  cblas_dgemm(CblasColMajor, CblasTrans, CblasNoTrans, n, n, n, 1, mat_ptr(u), n,
              mat_ptr(t), n, 0, mat_ptr(a), n);
  for (i = 0; i < n; ++i) mat_elem(a, i, i) -= w[i];
  norm = LAPACKE_dlange(LAPACK_COL_MAJOR, 'F', n, n, mat_ptr(a), n);
  printf("|| U^t A U - diag(w) || = %e\n", norm);
  if (norm > 1e-10) {
    fprintf(stderr, "Error: eigenvalue check\n");
    exit(255);
  }

  free_dmatrix(a);
  free_dmatrix(u);
  free_dvector(w);
  free_dmatrix(t);
  return 0;
}


<|start_filename|>rokko/distributed_mfree_to_crs.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2013-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_DISTRIBUTED_MFREE_TO_CRS_HPP
#define ROKKO_DISTRIBUTED_MFREE_TO_CRS_HPP

#include <rokko/distributed_crs_matrix.hpp>
#include <rokko/distributed_mfree.hpp>
#include <rokko/utility/mpi_vector.hpp>

namespace rokko {

void distributed_mfree_to_crs(rokko::distributed_mfree const& op, rokko::distributed_crs_matrix& mat) {
  rokko::mpi_comm mpi_comm(op.get_comm());
  const int nprocs = mpi_comm.get_nprocs();
  const int dim = op.get_dim();
  rokko::mpi_vector mpi(dim, op.get_comm());
  rokko::mapping_1d map(dim, mpi_comm);
  const int start_row = map.start_row();
  const int end_row = map.end_row();

  Eigen::Vector<double> x(op.get_num_local_rows()), y(op.get_num_local_rows());
  Eigen::Vector<double> vec(dim);

  for (int row=0; row<dim; ++row) {
    x.setZero();
    y.setZero();
    if ((row >= start_row) && (row < end_row)) {
      x[row - start_row] = 1.;
    }
    op.multiply(x.data(), y.data());
    const int proc = (nprocs * row) / dim;
    mpi.gather(y, vec, proc);
    if ((row >= start_row) && (row < end_row)) {
      for (int col=0; col<dim; ++col) {
        if (vec[col] != 0) {
          mat.insert(row, 1, &col, &vec[col]);
        }
      }
    }
  }
  mat.complete();
}

} // end namespace rokko

#endif // ROKKO_DISTRIBUTED_MFREE_TO_CRS_HPP


<|start_filename|>example/fortran/dense/generate_matrix/minij_array_mpi.f90<|end_filename|>
!*****************************************************************************
!
! Rokko: Integrated Interface for libraries of eigenvalue decomposition
!
! Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
!
! 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)
!
!*****************************************************************************

program generate_minij_array_mpi
  use rokko
  use mpi
  implicit none
  integer :: dim
  type(rokko_distributed_matrix) :: mat
  type(rokko_grid) :: grid
  type(rokko_mapping_bc) :: map
  double precision, allocatable :: array(:,:)
  integer :: m_size, n_size, m_local, n_local
  integer :: provided, ierr, myrank, nprocs
  integer :: local_i, local_j, global_i, global_j

  call MPI_init_thread(MPI_THREAD_MULTIPLE, provided, ierr)
  call MPI_comm_rank(MPI_COMM_WORLD, myrank, ierr)
  call MPI_comm_size(MPI_COMM_WORLD, nprocs, ierr)

  dim = 10

  if (myrank == 0) then
     print *,"dimension = ", dim
  endif

  call rokko_construct(grid, MPI_COMM_WORLD, rokko_grid_row_major)
  call rokko_construct(map, dim, 1, grid)
  m_size = rokko_get_m_size(map)
  n_size = rokko_get_n_size(map)
  allocate(array(m_size, n_size))

  ! generate minij matrix
  m_local = rokko_get_m_local(map)
  n_local = rokko_get_n_local(map)
  do local_j = 0, n_local-1
     global_j = rokko_translate_l2g_col0(map, local_j)
     do local_i = 0, m_local-1
        global_i = rokko_translate_l2g_row0(map, local_i)
        array(local_i+1, local_j+1) = min(global_i, global_j) + 1
     enddo
  enddo

  call rokko_construct(mat, map, array)
  call rokko_print(mat)

  deallocate(array)
  call rokko_destruct(mat)
  call rokko_destruct(map)
  call rokko_destruct(grid)

  call MPI_finalize(ierr)
end program generate_minij_array_mpi


<|start_filename|>config/check_ggsvd.f90<|end_filename|>
program main
  call sggsvd()
  call dggsvd()
  call cggsvd()
  call zggsvd()
end program



<|start_filename|>example/c/utility/solvers.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.h>
#include <stdio.h>
#include <stdlib.h>

int main(/* int argc , char** argv */) {
  int i, n;
  char** solver_names;

  n = rokko_serial_dense_ev_num_solvers();
  solver_names = rokko_serial_dense_ev_solvers();
  for (i = 0; i < n; ++i)
    printf("%s\n", solver_names[i]);
  for (i = 0; i < n; ++i) free(solver_names[i]);
  free(solver_names);

#ifdef ROKKO_HAVE_PARALLEL_DENSE_SOLVER
  n = rokko_parallel_dense_ev_num_solvers();
  solver_names = rokko_parallel_dense_ev_solvers();
  for (i = 0; i < n; ++i)
    printf("%s\n", solver_names[i]);
  for (i = 0; i < n; ++i) free(solver_names[i]);
  free(solver_names);
#endif

#ifdef ROKKO_HAVE_PARALLEL_SPARSE_SOLVER
  n = rokko_parallel_sparse_ev_num_solvers();
  solver_names = rokko_parallel_sparse_ev_solvers();
  for (i = 0; i < n; ++i)
    printf("%s\n", solver_names[i]);
  for (i = 0; i < n; ++i) free(solver_names[i]);
  free(solver_names);
#endif

  return 0;
}


<|start_filename|>config/FindELPA.cmake<|end_filename|>
# - Try to find ELPA
# Once done this will define
#
#  ELPA_FOUND        - system has ELPA
#  ELPA_INCLUDE_DIR  - include directory for ELPA
#  ELPA_LIBARIES     - libraries for ELPA

if(DEFINED ELPA_FOUND)
  return()
endif(DEFINED ELPA_FOUND)
  
message(STATUS "Checking for ELPA library")
set(ELPA_FOUND FALSE)

# Standard search path
set(_PATHS "")
if(ELPA_DIR)
  set(_PATHS ${ELPA_DIR})
else(ELPA_DIR)
  list(APPEND _PATHS
  	      ${ELPA_ROOT}/${CMAKE_BUILD_TYPE}
	      ${ELPA_ROOT}
  	      $ENV{ELPA_ROOT}/${CMAKE_BUILD_TYPE}
	      $ENV{ELPA_ROOT}
  	      ${ROKKO_SOLVER_ROOT}/elpa/${CMAKE_BUILD_TYPE}
	      ${ROKKO_SOLVER_ROOT}/elpa
  	      $ENV{ROKKO_SOLVER_ROOT}/elpa/${CMAKE_BUILD_TYPE}
	      $ENV{ROKKO_SOLVER_ROOT}/elpa
	      ${CMAKE_INSTALL_PREFIX}/elpa/${CMAKE_BUILD_TYPE}
	      ${CMAKE_INSTALL_PREFIX}/${CMAKE_BUILD_TYPE}
	      $ENV{HOME}/rokko/elpa/${CMAKE_BUILD_TYPE}
	      $ENV{HOME}/rokko/elpa
	      /opt/rokko/elpa/${CMAKE_BUILD_TYPE}
	      /opt/rokko/elpa
	      /opt/rokko/${CMAKE_BUILD_TYPE}
	      /opt/rokko
	      /opt/local /opt
	      )
endif(ELPA_DIR)

foreach (_PATH ${_PATHS})
  list(APPEND _INCPATHS "${_PATH}/include")
endforeach()

foreach (_INCPATH ${_INCPATHS})
  file(GLOB _ELPA_INCLUDE_FILE "${_INCPATH}/elpa_*/elpa/elpa.h")
  if(_ELPA_INCLUDE_FILE)
    string(REGEX REPLACE "elpa/+elpa.h" "" ELPA_INCLUDE_DIR ${_ELPA_INCLUDE_FILE})  # cut the trailing "elpa/elpa.h" from _ELPA_INCLUDE_FILE
    break()
  endif(_ELPA_INCLUDE_FILE)
endforeach()

if(ELPA_INCLUDE_DIR)
  message(STATUS "ELPA include directory: ${ELPA_INCLUDE_DIR}")
else(ELPA_INCLUDE_DIR)
  message(STATUS "ELPA library: include file not found")
  return()
endif(ELPA_INCLUDE_DIR)

foreach (_PATH ${_PATHS})
  list(APPEND _LIBPATHS "${_PATH}/lib")
endforeach()

find_library(_ELPA_LIBRARY
  NAMES elpa_openmp elpa
  PATHS ${_LIBPATHS}
  DOC "The ELPA library")
if(_ELPA_LIBRARY)
  list(APPEND ELPA_LIBRARIES ${_ELPA_LIBRARY})
else(_ELPA_LIBRARY)
  message(STATUS "ELPA library: library file not found")
  set(ELPA_FOUND FALSE)
  return()
endif(_ELPA_LIBRARY)

set(ELPA_FOUND TRUE)
message(STATUS "ELPA libraries: ${ELPA_LIBRARIES}")


<|start_filename|>benchmark/use_rokko/sparse_heisenberg_ladder_mpi/crs_verify.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/lattice.hpp>
#include <rokko/utility/machine_info.hpp>

int main(int argc, char *argv[]) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  int rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  double init_tick, initend_tick, gen_tick, diag_tick, end_tick;

  std::string name("anasazi");
  if (argc >= 2) name = argv[1];
  int len_ladder = 5;
  if (argc >= 3) len_ladder = std::stoi(argv[2]);

  const int L = 2 * len_ladder;
  std::vector<std::pair<int, int>> lattice;
  rokko::create_ladder_lattice_1dim(len_ladder, lattice);
  if (rank == 0)
    rokko::print_lattice(lattice);
  const int dim = 1 << L;
  if (rank == 0)
    std::cout << "Eigenvalue decomposition of antiferromagnetic Heisenberg 1D ladder lattice" << std::endl
              << "solver = " << name << std::endl
              << "L = " << L << std::endl
              << "dimension = " << dim << std::endl;

  MPI_Barrier(MPI_COMM_WORLD);
  init_tick = MPI_Wtime();
  rokko::parallel_sparse_ev solver(name);
  MPI_Barrier(MPI_COMM_WORLD);
  initend_tick = MPI_Wtime();

  MPI_Barrier(MPI_COMM_WORLD);
  gen_tick = MPI_Wtime();
  const int num_entries_per_row = lattice.size() + 1;
  auto map = solver.default_mapping(dim, rokko::mpi_comm{MPI_COMM_WORLD});
  rokko::distributed_crs_matrix mat(map, num_entries_per_row);
  std::vector<int> cols;
  std::vector<double> values;
  cols.reserve(num_entries_per_row);
  values.reserve(num_entries_per_row);
  for (int row = map.start_row(); row < map.end_row(); ++row) {
    cols.clear();
    values.clear();
    double diag = 0;
    for (int l = 0;  l < lattice.size(); ++l) {
      int i = lattice[l].first;
      int j = lattice[l].second;
      int m1 = 1 << i;
      int m2 = 1 << j;
      int m3 = m1 + m2;
      if (((row & m3) == m1) || ((row & m3) == m2)) {
        cols.emplace_back(row^m3);
        values.emplace_back(0.5);
        diag += -0.25;
      } else {
        diag += 0.25;
      }
    }
    if (diag != 0.) {
      cols.emplace_back(row);
      values.emplace_back(diag);
    }
    //std::cout << "num_cols=" << cols.size() << std::endl;
    mat.insert(row, cols, values);
  }
  mat.complete();
  //mat.print();
  
  MPI_Barrier(MPI_COMM_WORLD);
  diag_tick = MPI_Wtime();
  rokko::parameters params;
  //params.set("max_block_size", 5);
  //params.set("max_iters", 500);
  //params.set("conv_tol", 1.0e-12);
  //params.set("num_eigvals", 1);
  params.set("verbose", true);

  rokko::parameters params_out = solver.diagonalize(mat, params);
  MPI_Barrier(MPI_COMM_WORLD);
  end_tick = MPI_Wtime();
  
  const int num_conv = params_out.get<int>("num_conv");
  if (num_conv == 0) {
    throw std::runtime_error("diagonalize : solver does not converge.");
  }
  std::vector<double> eigvec;
  solver.eigenvector(0, eigvec);
  if (rank == 0) {
    std::cout << "number of converged eigenpairs = " << num_conv << std::endl;
    std::cout << "smallest eigenvalues: ";
    for (int i = 0; i < num_conv; ++i) std::cout << ' ' << solver.eigenvalue(i);
    std::cout << std::endl;
    std::cout << "init_time = " << initend_tick - init_tick << std::endl
              << "gen_time = " << diag_tick - gen_tick << std::endl
              << "diag_time = " << end_tick - diag_tick << std::endl;
    rokko::machine_info();
  }

  solver.finalize();
  MPI_Finalize();
}


<|start_filename|>example/cxx/sparse/heisenberg_crs_slepc_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/slepc/solver.hpp>

#include <stdexcept>

int main(int argc, char *argv[]) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  int rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);

  int L = (argc >= 2) ? std::stoi(argv[1]) : 10;
  int dim = 1 << L;
  std::vector<std::pair<int, int>> lattice;
  for (int i = 0; i < L; ++i) lattice.emplace_back(std::make_pair(i, (i+1) % L));

  rokko::parameters params;
  params.set("Block Size", 5);
  params.set("Maximum Iterations", 500);
  params.set("Convergence Tolerance", 1.0e-8);
  params.set("num_eigenvalues", 10);

  rokko::slepc::solver solver;
  rokko::slepc::mapping_1d map(dim, rokko::mpi_comm{MPI_COMM_WORLD});
  const int num_entries_per_row = lattice.size() + 1;
  rokko::slepc::distributed_crs_matrix mat(map, num_entries_per_row);
  std::vector<int> cols;
  std::vector<double> values;
  cols.reserve(num_entries_per_row);
  values.reserve(num_entries_per_row);

  for (int row = map.start_row(); row < map.end_row(); ++row) {
    cols.clear();
    values.clear();
    double diag = 0;
    for (int l = 0; l < lattice.size(); ++l) {
      int i = lattice[l].first;
      int j = lattice[l].second;
      int m1 = 1 << i;
      int m2 = 1 << j;
      int m3 = m1 + m2;
      if (((row & m3) == m1) || ((row & m3) == m2)) {
        cols.emplace_back(row^m3);
        values.emplace_back(0.5);
        diag += -0.25;
      } else {
        diag += 0.25;
      }
    }
    if (diag != 0.) {
      cols.emplace_back(row);
      values.emplace_back(diag);
    }
    std::cout << "row=" << row << " size=" << cols.size() << std::endl;
    mat.insert(row, cols, values);
  }
  mat.complete();
  mat.print();
  if (rank == 0)
    std::cout << "Eigenvalue decomposition of antiferromagnetic Heisenberg chain" << std::endl
	      << "L = " << L << std::endl
	      << "dimension = " << dim << std::endl;

  rokko::parameters info = solver.diagonalize(mat, params);

  int num_conv = info.get<int>("num_conv");
  if (num_conv == 0)
    throw std::runtime_error("num_conv=0: solver did not converge");
  std::vector<double> eigvec;
  solver.eigenvector(0, eigvec);
  if (rank == 0) {
    std::cout << "number of converged eigenpairs = " << num_conv << std::endl;
    std::cout << "smallest eigenvalues: ";
    for (int i = 0; i < num_conv; ++i) std::cout << ' ' << solver.eigenvalue(i);
    std::cout << std::endl;
    std::cout << "smallest eigenvector: ";
    for (int j = 0; j < eigvec.size(); ++j) std::cout << eigvec[j] << ' ';
    std::cout << std::endl;
  }

  solver.finalize();
  MPI_Finalize();
}


<|start_filename|>tutorial/titpack/03_rokko_cxx/common.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

// C++ version of TITPACK Ver.2 by <NAME>

#include "common.hpp"
#include <lapacke.h>
#include <iostream>

void xcorr(subspace const& ss, std::vector<int> const& npair, const double *x,
           std::vector<double>& sxx) {
  int nbond = npair.size() / 2;
  for (int k = 0; k < nbond; ++k) {
    int i1 = npair[k * 2];
    int i2 = npair[k * 2 + 1];
    if (i1 < 0 || i1 >= ss.num_sites() || i2 < 0 || i2 >= ss.num_sites() || i1 == i2) {
      std::cerr << " #(W01)# Wrong site number given to xcorr\n";
      return;
    }
    double corr = 0;
    int is = (1 << i1) + (1 << i2);
    for (int j = 0; j < ss.dimension(); ++j) {
      int ibit = ss.config(j) & is;
      if (ibit != 0 && ibit != is) corr += x[j] * x[ss.config2index(ss.config(j) ^ is)];
    }
    sxx[k] = corr / 4;
  }
}

void xcorr(subspace const& ss, std::vector<int> const& npair, std::vector<double> const& x,
           std::vector<double>& sxx) {
  xcorr(ss, npair, x.data(), sxx);
}


<|start_filename|>rokko/lapack/getrf.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_GETRF_HPP
#define ROKKO_LAPACK_GETRF_HPP

#include <complex>
#include <stdexcept>
#include <boost/type_traits/is_same.hpp>
#include <lapacke.h>
#undef I
#include <rokko/traits/value_t.hpp>
#include "complex_cast.hpp"

namespace rokko {
namespace lapack {

namespace {

template<typename T> struct getrf_dispatch;
  
template<>
struct getrf_dispatch<float> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int getrf(int matrix_layout, lapack_int m, lapack_int n,
                          MATRIX& a, VECTOR& ipiv) {
    return LAPACKE_sgetrf(matrix_layout, m, n, storage(a), ld(a), storage(ipiv));
  }
};

template<>
struct getrf_dispatch<double> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int getrf(int matrix_layout, lapack_int m, lapack_int n,
                          MATRIX& a, VECTOR& ipiv) {
    return LAPACKE_dgetrf(matrix_layout, m, n, storage(a), ld(a), storage(ipiv));
  }
};

template<>
struct getrf_dispatch<std::complex<float>> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int getrf(int matrix_layout, lapack_int m, lapack_int n,
                          MATRIX& a, VECTOR& ipiv) {
    return LAPACKE_cgetrf(matrix_layout, m, n, complex_cast(storage(a)), ld(a),
                          storage(ipiv));
  }
};

template<>
struct getrf_dispatch<std::complex<double>> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int getrf(int matrix_layout, lapack_int m, lapack_int n,
                          MATRIX& a, VECTOR& ipiv) {
    return LAPACKE_zgetrf(matrix_layout, m, n, complex_cast(storage(a)), ld(a),
                          storage(ipiv));
  }
};

}

template<typename MATRIX, typename VECTOR>
lapack_int getrf(MATRIX& a, VECTOR& ipiv) {
  lapack_int m = rows(a);
  lapack_int n = cols(a);
  static_assert(std::is_same<value_t<VECTOR>, lapack_int>::value, "");
  if (size(ipiv) < std::min(m, n))
    throw std::invalid_argument("vector ipiv size mismatch");
  return getrf_dispatch<value_t<MATRIX>>
    ::getrf((is_col_major(a) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR),
            m, n, a, ipiv);
}

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_GETRF_HPP


<|start_filename|>rokko/copy_string.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <string>

char* copy_string(std::string const& str) {
  char* p = (char*) malloc( sizeof(char) * (str.size() + 1) );
  str.copy(p, str.size(), 0);
  p[str.size()] = '\0';
  return p;
}


<|start_filename|>rokko/lapack/htein.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_HTEIN_HPP
#define ROKKO_LAPACK_HTEIN_HPP

#include <complex>
#include <lapacke.h>
#undef I
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>
#include "complex_cast.hpp"
#include <rokko/alias_template_function.hpp>

namespace rokko {
namespace lapack {

namespace {

template<typename T> struct htein_dispatch;

template<>
struct htein_dispatch<float> {
  template<typename MATRIX, typename VECTOR, typename VECTOR_INT>
  static lapack_int htein(int matrix_layout, lapack_int n,
                          VECTOR& d, VECTOR& e,
                          lapack_int m, VECTOR& w,
                          MATRIX& z,
                          const VECTOR_INT& iblock, const VECTOR_INT& isplit,
                          VECTOR_INT& ifailv) {
    return LAPACKE_sstein(matrix_layout, n, storage(d), storage(e),
                          m, storage(w), storage(iblock), storage(isplit), storage(z), ld(z), storage(ifailv));
  }
};

template<>
struct htein_dispatch<double> {
  template<typename MATRIX, typename VECTOR, typename VECTOR_INT>
  static lapack_int htein(int matrix_layout, lapack_int n,
                          VECTOR& d, VECTOR& e,
                          lapack_int m, VECTOR& w,
                          MATRIX& z,
                          const VECTOR_INT& iblock, const VECTOR_INT& isplit,
                          VECTOR_INT& ifailv) {
    return LAPACKE_dstein(matrix_layout, n, storage(d), storage(e),
                          m, storage(w), storage(iblock), storage(isplit), storage(z), ld(z), storage(ifailv));
  }
};

template<>
struct htein_dispatch<std::complex<float>> {
  template<typename MATRIX, typename VECTOR, typename VECTOR_INT>
  static lapack_int htein(int matrix_layout, lapack_int n,
                          VECTOR& d, VECTOR& e,
                          lapack_int m, VECTOR& w,
                          MATRIX& z,
                          const VECTOR_INT& iblock, const VECTOR_INT& isplit,
                          VECTOR_INT& ifailv) {
    return LAPACKE_cstein(matrix_layout, n, storage(d), storage(e),
                          m, storage(w), srorage(iblock), storage(isplit), complex_cast(storage(z)), ld(z), storage(ifailv));
  }
};

template<>
struct htein_dispatch<std::complex<double>> {
  template<typename MATRIX, typename VECTOR, typename VECTOR_INT>
  static lapack_int htein(int matrix_layout, lapack_int n,
                          VECTOR& d, VECTOR& e,
                          lapack_int m, VECTOR& w,
                          MATRIX& z,
                          const VECTOR_INT& iblock, const VECTOR_INT& isplit,
                          VECTOR_INT& ifailv) {
    return LAPACKE_zstein(matrix_layout, n, storage(d), storage(e),
                          m, storage(w), storage(iblock), storage(isplit), complex_cast(storage(z)), ld(z), storage(ifailv));
  }
};

} // end of anonymous namespace

template<typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int htein(VECTOR& d, VECTOR& e, lapack_int m, VECTOR& w, MATRIX& z,
                 const VECTOR_INT& iblock, const VECTOR_INT& isplit, VECTOR_INT& ifailv) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR>>::value, "");
  lapack_int n = size(d);
  if (rows(z) != n)
    throw std::invalid_argument("matrix Z row size mismatch");
  if (cols(z) < m)
    throw std::invalid_argument("matrix Z col size mismatch");
  if (size(d) != n)
    throw std::invalid_argument("vector d size mismatch");
  if (size(e) != (n-1))
    throw std::invalid_argument("vector e size mismatch");
  if (size(w) != n)
    throw std::invalid_argument("vector w size mismatch");
  return htein_dispatch<value_t<MATRIX>>::
    htein((is_col_major(z) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR), n, d, e, m, w, z, iblock, isplit, ifailv);
}

ALIAS_TEMPLATE_FUNCTION(stein, htein);

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_HTEIN_HPP


<|start_filename|>rokko/utility/heisenberg_hamiltonian_mfree.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_HEISENBERG_HAMILTONIAN_MFREE_HPP
#define ROKKO_UTILITY_HEISENBERG_HAMILTONIAN_MFREE_HPP

#include <rokko/utility/heisenberg_hamiltonian_mpi.hpp>
#include <rokko/distributed_mfree.hpp>
#include <rokko/utility/math.hpp>

namespace rokko {

class heisenberg_mfree : public rokko::distributed_mfree_default {
public:
  heisenberg_mfree(int L, const std::vector<std::pair<int, int>>& lattice, MPI_Comm comm = MPI_COMM_WORLD)
    : L_(L), lattice_(lattice), distributed_mfree_default{1 << L, rokko::mpi_comm{comm}} {
    check_nprocs(rokko::mpi_comm{comm});
    buffer_.resize(get_num_local_rows());
  }
  ~heisenberg_mfree() = default;

  void check_nprocs(rokko::mpi_comm const& mpi_comm) const {
    const int nprocs = mpi_comm.get_nprocs();
    const int p = rokko::find_power_of_two(nprocs);
    if (nprocs != (1 << p))
      throw std::invalid_argument("This program can be run only with 2^n MPI processes");
  }

  void multiply(const double *const x, double *const y) const override {
    rokko::heisenberg_hamiltonian::multiply(get_comm(), L_, lattice_, x, y, buffer_.data());
  }

  void fill_diagonal(double *const x) const override {
    rokko::heisenberg_hamiltonian::fill_diagonal(get_comm(), L_, lattice_, x);
  }

private:
  int L_;
  std::vector<std::pair<int, int>> lattice_;
  mutable std::vector<double> buffer_;
};

} // namespace rokko

#endif // ROKKO_UTILITY_HEISENBERG_HAMILTONIAN_MFREE_HPP


<|start_filename|>rokko/pyrokko.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/numpy.h>
#include <pybind11/eigen.h>

#include <rokko/utility/tuple_to_array.hpp>

#include <rokko/eigen3.hpp>
#include <rokko/pyrokko_serial_dense_ev.hpp>
#include <rokko/utility/pyrokko_generate_matrix.hpp>

#include <rokko/pyrokko_parameters.hpp>
#include <rokko/pyrokko_grid.hpp>
#include <rokko/pyrokko_mapping_bc.hpp>
#include <rokko/pyrokko_distributed_matrix.hpp>
#include <rokko/pyrokko_parallel_dense_ev.hpp>
#include <rokko/pyrokko_collective.hpp>

#include <rokko/utility/pyrokko_minij_matrix.hpp>
#include <rokko/utility/pyrokko_frank_matrix.hpp>
#include <rokko/utility/pyrokko_helmert_matrix.hpp>
#include <rokko/utility/pyrokko_laplacian_matrix.hpp>
#include <rokko/utility/pyrokko_matrix012.hpp>

#include <rokko/pyrokko_parallel_sparse_ev.hpp>
#include <rokko/pyrokko_mapping_1d.hpp>
#include <rokko/pyrokko_distributed_crs_matrix.hpp>
#include <rokko/pyrokko_distributed_mfree.hpp>

#include <rokko/utility/pyrokko_sort_eigenpairs.hpp>
#include <rokko/utility/pyrokko_solver_name.hpp>


namespace rokko {

namespace py = pybind11;

template<typename MATRIX_MAJOR>
void declare_wrap_mapping_bc(py::module &m, std::string const& typestr) {
  std::string pyclass_name = std::string("mapping_bc_") + typestr;
  py::class_<wrap_mapping_bc<MATRIX_MAJOR>, base_mapping_bc, std::shared_ptr<wrap_mapping_bc<MATRIX_MAJOR>>>(m, pyclass_name.c_str())
    .def(py::init<int, int, wrap_grid>(), py::arg("global_dim"), py::arg("block_size"), py::arg("grid"))
    .def(py::init<int, int, int, wrap_grid>(), py::arg("global_dim"), py::arg("block_size"), py::arg("lld"), py::arg("grid"))
    .def(py::init<std::tuple<int,int> const&, std::tuple<int,int> const&, wrap_grid>(), py::arg("global_size"), py::arg("block_size"), py::arg("grid"))
    .def("get_mb", &wrap_mapping_bc<MATRIX_MAJOR>::get_mb)
    .def("get_nb", &wrap_mapping_bc<MATRIX_MAJOR>::get_nb)
    .def_property_readonly("block_shape", &wrap_mapping_bc<MATRIX_MAJOR>::get_block_shape)
    .def_property_readonly("m_global", &wrap_mapping_bc<MATRIX_MAJOR>::get_m_global)
    .def_property_readonly("n_global", &wrap_mapping_bc<MATRIX_MAJOR>::get_n_global)
    .def_property_readonly("global_shape", &wrap_mapping_bc<MATRIX_MAJOR>::get_global_shape)
    .def_property_readonly("m_local", &wrap_mapping_bc<MATRIX_MAJOR>::get_m_local)
    .def_property_readonly("n_local", &wrap_mapping_bc<MATRIX_MAJOR>::get_n_local)
    .def_property_readonly("local_shape", &wrap_mapping_bc<MATRIX_MAJOR>::get_local_shape)
    .def("translate_l2g_row", &wrap_mapping_bc<MATRIX_MAJOR>::translate_l2g_row)
    .def("translate_l2g_col", &wrap_mapping_bc<MATRIX_MAJOR>::translate_l2g_col)
    .def("translate_l2g", &wrap_mapping_bc<MATRIX_MAJOR>::translate_l2g) // tuple
    .def("translate_g2l_row", &wrap_mapping_bc<MATRIX_MAJOR>::translate_g2l_row)
    .def("translate_g2l_col", &wrap_mapping_bc<MATRIX_MAJOR>::translate_g2l_col)
    .def("translate_g2l", &wrap_mapping_bc<MATRIX_MAJOR>::translate_g2l) // tuple
    .def("has_global_row_index", &wrap_mapping_bc<MATRIX_MAJOR>::has_global_row_index)
    .def("has_global_col_index", &wrap_mapping_bc<MATRIX_MAJOR>::has_global_col_index)
    .def("has_global_indices", &wrap_mapping_bc<MATRIX_MAJOR>::has_global_indices)
    .def("get_grid", &wrap_mapping_bc<MATRIX_MAJOR>::get_grid)
    .def_property_readonly("major", &wrap_mapping_bc<MATRIX_MAJOR>::get_major_string);
}

template<typename T, typename MATRIX_MAJOR>
void declare_wrap_distributed_matrix(py::module &m, std::string const& typestr) {
  std::string pyclass_name = std::string("distributed_matrix_") + typestr;
  py::class_<wrap_distributed_matrix<T,MATRIX_MAJOR>, base_distributed_matrix, std::shared_ptr<wrap_distributed_matrix<T,MATRIX_MAJOR>>>(m, pyclass_name.c_str())
    .def(py::init<wrap_mapping_bc<MATRIX_MAJOR>>())
    .def_property_readonly("mb", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_mb)
    .def_property_readonly("nb", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_nb)
    .def_property_readonly("block_shape", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_block_shape)
    .def_property_readonly("m_global", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_m_global)
    .def_property_readonly("n_global", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_n_global)
    .def_property_readonly("m_local", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_m_local)
    .def_property_readonly("n_local", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_n_local)
    .def_property_readonly("global_shape", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_global_shape)
    .def_property_readonly("local_shape", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_local_shape)
    .def("translate_l2g_row", &wrap_distributed_matrix<T,MATRIX_MAJOR>::translate_l2g_row)
    .def("translate_l2g_col", &wrap_distributed_matrix<T,MATRIX_MAJOR>::translate_l2g_col)
    .def("translate_l2g", &wrap_distributed_matrix<T,MATRIX_MAJOR>::translate_l2g) // tuple
    .def("translate_g2l_row", &wrap_distributed_matrix<T,MATRIX_MAJOR>::translate_g2l_row)
    .def("translate_g2l_col", &wrap_distributed_matrix<T,MATRIX_MAJOR>::translate_g2l_col)
    .def("translate_g2l", &wrap_distributed_matrix<T,MATRIX_MAJOR>::translate_g2l) // tuple
    .def("has_global_row_index", &wrap_distributed_matrix<T,MATRIX_MAJOR>::has_global_row_index)
    .def("has_global_col_index", &wrap_distributed_matrix<T,MATRIX_MAJOR>::has_global_col_index)
    .def("has_global_indices", &wrap_distributed_matrix<T,MATRIX_MAJOR>::has_global_indices)
    .def("get_local", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_local)
    .def("get_global", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_global)
    .def("set_local", &wrap_distributed_matrix<T,MATRIX_MAJOR>::set_local)
    .def("set_global", &wrap_distributed_matrix<T,MATRIX_MAJOR>::set_global)
    .def("update_local", &wrap_distributed_matrix<T,MATRIX_MAJOR>::update_local)
    .def("update_global", &wrap_distributed_matrix<T,MATRIX_MAJOR>::update_global)
    .def("set_zeros", &wrap_distributed_matrix<T,MATRIX_MAJOR>::set_zeros)
    .def_property_readonly("length_array", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_length_array)
    .def_property_readonly("lld", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_lld)
    .def("generate", py::overload_cast<std::function<T(int, int)>>(&distributed_matrix<T,MATRIX_MAJOR>::template generate<std::function<T(int, int)>>))
    .def("print", &wrap_distributed_matrix<T,MATRIX_MAJOR>::print)
    .def("get_map", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_map)
    .def_property_readonly("major", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_major_string)
    .def("set_ndarray", &wrap_distributed_matrix<T,MATRIX_MAJOR>::set_ndarray)
    .def("get_ndarray", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_ndarray, py::return_value_policy::reference_internal)
    .def_property("ndarray", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_ndarray, &wrap_distributed_matrix<T,MATRIX_MAJOR>::set_ndarray)
    .def_property_readonly("map", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_map)
    .def_property_readonly("major", &wrap_distributed_matrix<T,MATRIX_MAJOR>::get_major_string);
}

template <typename T>
void declare_gather(py::module &m) {
  m.def("gather", py::overload_cast<wrap_distributed_matrix<T,matrix_row_major> const&, Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>>, int>(&pyrokko_gather<T,matrix_row_major>));
  m.def("gather", py::overload_cast<wrap_distributed_matrix<T,matrix_col_major> const&, Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>>, int>(&pyrokko_gather<T,matrix_col_major>));
}

template <typename T>
void declare_scatter(py::module &m) {
  m.def("scatter", py::overload_cast<Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>>, wrap_distributed_matrix<T,matrix_row_major>&, int>(&pyrokko_scatter<T,matrix_row_major>));
  m.def("scatter", py::overload_cast<Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>>, wrap_distributed_matrix<T,matrix_col_major>&, int>(&pyrokko_scatter<T,matrix_col_major>));
}

template <typename T>
void declare_collective(py::module &m) {
  declare_gather<T>(m);
  declare_scatter<T>(m);
}

template<typename T, class CLASS>
void declare_matrix(py::class_<CLASS>& obj) {
  obj.def_static("generate", py::overload_cast<Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>>>(&CLASS::template generate<T,Eigen::RowMajor>))
    .def_static("generate", py::overload_cast<Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>>>(&CLASS::template generate<T,Eigen::ColMajor>))
    .def_static("generate", py::overload_cast<wrap_distributed_matrix<T,matrix_col_major>&>(&CLASS::template generate<T,matrix_col_major>));
}

template<typename T>
void declare_helmert_matrix(py::class_<wrap_helmert_matrix>& obj) {
  declare_matrix<T>(obj);

  obj.def_static("generate_for_given_eigenvalues", py::overload_cast<Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>>,Eigen::Ref<Eigen::Vector<T>>>(&wrap_helmert_matrix::template generate_for_given_eigenvalues_eigen<T, Eigen::RowMajor>))
    .def_static("generate_for_given_eigenvalues", py::overload_cast<Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>>,Eigen::Ref<Eigen::Vector<T>>>(&wrap_helmert_matrix::template generate_for_given_eigenvalues_eigen<T, Eigen::ColMajor>))
    .def_static("generate_for_given_eigenvalues", py::overload_cast<wrap_distributed_matrix<T,matrix_col_major>&,Eigen::Ref<Eigen::Vector<T>>>(&wrap_helmert_matrix::template generate_for_given_eigenvalues<T,matrix_col_major>));
}

template<typename T>
void declare_sd_diagonalize(py::class_<wrap_serial_dense_ev>& obj) {
  obj.def("diagonalize", py::overload_cast<Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>>,Eigen::Ref<Eigen::Vector<real_t<T>>>,Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>>,wrap_parameters const&>(&wrap_serial_dense_ev::diagonalize<T,Eigen::RowMajor>),
          py::arg("mat"), py::arg("eigval"), py::arg("eigvec"), py::arg("params") = wrap_parameters())
    .def("diagonalize", py::overload_cast<Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>>,Eigen::Ref<Eigen::Vector<real_t<T>>>,Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>>,wrap_parameters const&>(&wrap_serial_dense_ev::diagonalize<T,Eigen::ColMajor>),
         py::arg("mat"), py::arg("eigval"), py::arg("eigvec"), py::arg("params") = wrap_parameters())
    .def("diagonalize", py::overload_cast<Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>>,Eigen::Ref<Eigen::Vector<real_t<T>>>,wrap_parameters const&>(&wrap_serial_dense_ev::diagonalize<T,Eigen::RowMajor>),
         py::arg("mat"), py::arg("eigval"), py::arg("params") = wrap_parameters())
    .def("diagonalize", py::overload_cast<Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>>,Eigen::Ref<Eigen::Vector<real_t<T>>>,wrap_parameters const&>(&wrap_serial_dense_ev::diagonalize<T,Eigen::ColMajor>),
         py::arg("mat"), py::arg("eigval"), py::arg("params") = wrap_parameters());
}

template<typename T>
void declare_pd_diagonalize(py::class_<wrap_parallel_dense_ev>& obj) {
  obj.def("diagonalize", py::overload_cast<wrap_distributed_matrix<T,matrix_col_major>&, Eigen::RefVec<real_t<T>>&, wrap_parameters const&>(&wrap_parallel_dense_ev::diagonalize<T,matrix_col_major,Eigen::RefVec<real_t<T>>>),
          py::arg("mat"), py::arg("eigvals"), py::arg("params") = wrap_parameters())
    .def("diagonalize", py::overload_cast<wrap_distributed_matrix<T,matrix_col_major>&, Eigen::RefVec<real_t<T>>&, wrap_distributed_matrix<T,matrix_col_major>&, wrap_parameters const&>(&wrap_parallel_dense_ev::diagonalize<T,matrix_col_major,Eigen::RefVec<real_t<T>>>),
         py::arg("mat"), py::arg("eigvals"), py::arg("eigvecs"), py::arg("params") = wrap_parameters());
}

PYBIND11_MODULE(pyrokko, m) {
  py::class_<wrap_parameters>(m, "parameters")
    .def(py::init<>())
    .def("clear", py::overload_cast<>(&parameters::clear))
    .def("clear", py::overload_cast<parameters::key_type const&>(&parameters::clear))
    .def("set", static_cast<void (parameters::*)(parameters::key_type const&, const char *)>(&parameters::set))
    .def("set", &parameters::set<double>, py::arg(), py::arg("value").noconvert())
    .def("set", &parameters::set<bool>, py::arg(), py::arg("value").noconvert()) // needed to place before <int>
    .def("set", &parameters::set<int>, py::arg(), py::arg("value").noconvert())
    //.def("set", py::overload_cast<parameters::key_type const&, double const&>(&parameters::set<double>))
    //.def("set", py::overload_cast<parameters::key_type const&, bool const&>(&parameters::set<bool>))
    //.def("set", py::overload_cast<parameters::key_type const&, int const&>(&parameters::set<int>))
    .def("defined", &parameters::defined)
    .def_property_readonly("keys", &parameters::keys)
    .def("get", &wrap_parameters::python_get)
    //.def("get", &parameters::get<int>)
    //.def("get", &parameters::get<double>)
    //.def("get", &parameters::get<bool>)
    .def("get_string", &parameters::get_string)
    .def("get_bool", &parameters::get_bool)
    .def_property_readonly("dict", &wrap_parameters::dict);

  py::enum_<matrix_major_enum>(m, "matrix_major")
    .value("row", matrix_major_enum::row)
    .value("col", matrix_major_enum::col);

  auto sd_obj = py::class_<wrap_serial_dense_ev>(m, "serial_dense_ev")
    .def(py::init<std::string const&>())
    .def(py::init<>())
    //.def("initialize", py::overload_cast<int&, char**&>(&serial_dense_ev::initialize))
    .def("finalize", &serial_dense_ev::finalize)
    .def_property_readonly_static("solvers", &serial_dense_ev::solvers)
    .def_property_readonly_static("default_solver", &serial_dense_ev::default_solver);
  declare_sd_diagonalize<float>(sd_obj);
  declare_sd_diagonalize<double>(sd_obj);
  declare_sd_diagonalize<std::complex<float>>(sd_obj);
  declare_sd_diagonalize<std::complex<double>>(sd_obj);

  // For grid
  py::class_<grid_row_major_t>(m,"grid_row_major")
    .def(py::init<>());
  m.attr("grid_row_major") = py::cast(grid_row_major);
  
  py::class_<grid_col_major_t>(m,"grid_col_major")
    .def(py::init<>());
  m.attr("grid_col_major") = py::cast(grid_col_major);
  
  py::class_<wrap_grid>(m, "grid")
    .def(py::init<>())
    .def(py::init<grid_row_major_t>())
    .def(py::init<grid_col_major_t>())
    .def(py::init<pybind11::handle const&, std::tuple<int,int> const&, grid_row_major_t>(), py::arg("comm"), py::arg("size"), py::arg("major") = grid_row_major)
    .def(py::init<pybind11::handle const&, std::tuple<int,int> const&, grid_col_major_t>(), py::arg("comm"), py::arg("size"), py::arg("major") = grid_col_major)
    .def(py::init<pybind11::handle const&, grid_row_major_t>(), py::arg("comm"), py::arg("major") = grid_row_major)
    .def(py::init<pybind11::handle const&, grid_col_major_t>(), py::arg("comm"), py::arg("major") = grid_col_major)
    .def("calculate_rank_form_coords", &wrap_grid::calculate_rank_form_coords)
    .def("get_comm", &wrap_grid::get_comm)
    .def_property_readonly("comm", &wrap_grid::get_comm)
    .def_property_readonly("nprocs", &wrap_grid::get_nprocs)
    .def_property_readonly("nprow", &wrap_grid::get_nprow)
    .def_property_readonly("npcol", &wrap_grid::get_npcol)
    .def_property_readonly("myrank", &wrap_grid::get_myrank)
    .def_property_readonly("myrow", &wrap_grid::get_myrow)
    .def_property_readonly("mycol", &wrap_grid::get_mycol)
    .def_property_readonly("shape", &wrap_grid::get_shape)
    .def_property_readonly("mine", &wrap_grid::get_mine)
    .def_property_readonly("major", &wrap_grid::get_major_string);

  py::class_<base_mapping_bc, std::shared_ptr<base_mapping_bc>>(m, "base_mapping_bc");
  declare_wrap_mapping_bc<matrix_col_major>(m, "col");
  declare_wrap_mapping_bc<matrix_row_major>(m, "row");

  m.def("mapping_bc", py::overload_cast<std::tuple<int,int> const&, std::tuple<int,int> const&, wrap_grid const&, matrix_major_enum const&>(&create_mapping_bc),
        py::arg("global_size"), py::arg("block_size"), py::arg("grid"), py::arg("major") = matrix_major_enum::col);
  m.def("mapping_bc", py::overload_cast<int, int, int, wrap_grid const&, matrix_major_enum const&>(&create_mapping_bc),
        py::arg("global_dim"), py::arg("block_size"), py::arg("lld"), py::arg("grid"), py::arg("major") = matrix_major_enum::col);
  m.def("mapping_bc", py::overload_cast<int, int, wrap_grid const&, matrix_major_enum const&>(&create_mapping_bc),
        py::arg("global_dim"), py::arg("block_size"), py::arg("grid"), py::arg("major") = matrix_major_enum::col);

  py::class_<base_distributed_matrix, std::shared_ptr<base_distributed_matrix>>(m, "base_distributed_matrix");
  declare_wrap_distributed_matrix<double,matrix_col_major>(m, "double_col");
  declare_wrap_distributed_matrix<double,matrix_row_major>(m, "double_row");
  declare_wrap_distributed_matrix<float,matrix_col_major>(m, "float_col");
  declare_wrap_distributed_matrix<float,matrix_row_major>(m, "float_row");
  declare_wrap_distributed_matrix<std::complex<double>,matrix_col_major>(m, "cdouble_col");
  declare_wrap_distributed_matrix<std::complex<double>,matrix_row_major>(m, "cdouble_row");
  declare_wrap_distributed_matrix<std::complex<float>,matrix_col_major>(m, "cfloat_col");
  declare_wrap_distributed_matrix<std::complex<float>,matrix_row_major>(m, "cfloat_row");
  m.def("distributed_matrix", py::overload_cast<wrap_mapping_bc<matrix_col_major>const&,std::string const&>(&create_distributed_matrix<matrix_col_major>),
        py::arg("mat"), py::arg("dtype") = "double");
  m.def("distributed_matrix", py::overload_cast<wrap_mapping_bc<matrix_row_major>const&,std::string const&>(&create_distributed_matrix<matrix_row_major>),
        py::arg("mat"), py::arg("dtype") = "double");

  m.def("product", py::overload_cast<double, wrap_distributed_matrix<double,matrix_col_major> const&, bool, wrap_distributed_matrix<double,matrix_col_major> const&, bool, double, wrap_distributed_matrix<double,matrix_col_major>&>(&pyrokko_product<double,matrix_col_major>), py::arg("alpha"), py::arg("matA"), py::arg("transA"), py::arg("matB"), py::arg("transB"), py::arg("beta"), py::arg("matC"));

  auto pd_obj = py::class_<wrap_parallel_dense_ev>(m, "parallel_dense_ev")
    .def(py::init<std::string const&>())
    .def(py::init<>())
    .def("initialize", &wrap_parallel_dense_ev::initialize)
    .def("finalize", &wrap_parallel_dense_ev::finalize)
    .def("default_mapping", &wrap_parallel_dense_ev::default_mapping)
    .def_property_readonly_static("solvers", &wrap_parallel_dense_ev::solvers)
    .def_property_readonly_static("default_solver", &wrap_parallel_dense_ev::default_solver);
  declare_pd_diagonalize<float>(pd_obj);
  declare_pd_diagonalize<double>(pd_obj);
  declare_pd_diagonalize<std::complex<float>>(pd_obj);
  declare_pd_diagonalize<std::complex<double>>(pd_obj);

  py::class_<wrap_minij_matrix> minij_obj(m, "minij_matrix");
  declare_matrix<float>(minij_obj);
  declare_matrix<double>(minij_obj);
  declare_matrix<std::complex<float>>(minij_obj);
  declare_matrix<std::complex<double>>(minij_obj);
  minij_obj.def_static("eigenvalue", &minij_matrix::eigenvalue);

  py::class_<wrap_frank_matrix> frank_obj(m, "frank_matrix");
  declare_matrix<float>(frank_obj);
  declare_matrix<double>(frank_obj);
  declare_matrix<std::complex<float>>(frank_obj);
  declare_matrix<std::complex<double>>(frank_obj);
  frank_obj.def_static("eigenvalue", &frank_matrix::eigenvalue);

  py::class_<wrap_laplacian_matrix> laplacian_obj(m, "laplacian_matrix");
  declare_matrix<float>(laplacian_obj);
  declare_matrix<double>(laplacian_obj);
  declare_matrix<std::complex<float>>(laplacian_obj);
  declare_matrix<std::complex<double>>(laplacian_obj);
  laplacian_obj.def_static("eigenvalue", &laplacian_matrix::eigenvalue);

  py::class_<wrap_matrix012> matrix012_obj(m, "matrix012");
  declare_matrix<float>(matrix012_obj);
  declare_matrix<double>(matrix012_obj);
  declare_matrix<std::complex<float>>(matrix012_obj);
  declare_matrix<std::complex<double>>(matrix012_obj);

  py::class_<wrap_helmert_matrix> helmert_obj(m, "helmert_matrix");
  declare_helmert_matrix<float>(helmert_obj);
  declare_helmert_matrix<double>(helmert_obj);

  // collective MPI communication
  declare_collective<float>(m);
  declare_collective<double>(m);
  declare_collective<std::complex<float>>(m);
  declare_collective<std::complex<double>>(m);

  py::class_<distributed_mfree>(m, "distributed_mfree_base");

  py::class_<distributed_mfree_default, distributed_mfree>(m, "distributed_mfree_default");

  py::class_<distributed_mfree_inherit, wrap_distributed_mfree_inherit, distributed_mfree_default, distributed_mfree>(m, "distributed_mfree_inherit")
    .def(py::init<int>())
    .def(py::init<int, pybind11::handle const&>())
    .def("multiply", py::overload_cast<const Eigen::VectorXd&,Eigen::Ref<Eigen::VectorXd>>(&distributed_mfree_inherit::multiply, py::const_))
    .def_property_readonly("dim", &distributed_mfree_default::get_dim)
    .def_property_readonly("num_local_rows", &distributed_mfree_default::get_num_local_rows)
    .def_property_readonly("start_row", &distributed_mfree_default::start_row)
    .def_property_readonly("end_row", &distributed_mfree_default::end_row);

  py::class_<wrap_distributed_mfree>(m, "distributed_mfree")
    .def(py::init<std::function<void(ConstMapVec,MapVec)>, int>())
    .def(py::init<std::function<void(ConstMapVec,MapVec)>, int, pybind11::handle const&>())
    .def(py::init<std::function<void(ConstMapVec,MapVec)>, wrap_mapping_1d const&>())
    .def_property_readonly("dim", &distributed_mfree_default::get_dim)
    .def_property_readonly("num_local_rows", &distributed_mfree_default::get_num_local_rows)
    .def_property_readonly("start_row", &distributed_mfree_default::start_row)
    .def_property_readonly("end_row", &distributed_mfree_default::end_row);

  // sparse
  py::class_<wrap_mapping_1d>(m, "mapping_1d")
    .def(py::init<int, pybind11::handle const&, std::string const&>())
    .def_property_readonly("dim", &mapping_1d::get_dim)
    .def_property_readonly("num_local_rows", &mapping_1d::num_local_rows)
    .def_property_readonly("start_row", &mapping_1d::start_row)
    .def_property_readonly("end_row", &mapping_1d::end_row)
    .def_property_readonly("get_solver_name", &mapping_1d::get_solver_name);

  py::class_<wrap_distributed_crs_matrix>(m, "distributed_crs_matrix")
    .def(py::init<wrap_mapping_1d, int>())
    .def("insert", py::overload_cast<int, std::vector<int> const&, std::vector<double> const&>(&wrap_distributed_crs_matrix::insert, py::const_))
    .def("complete", &distributed_crs_matrix::complete)
    .def_property_readonly("dim", &distributed_crs_matrix::get_dim)
    .def_property_readonly("num_local_rows", &distributed_crs_matrix::get_num_local_rows)
    .def_property_readonly("start_row", &distributed_crs_matrix::start_row)
    .def_property_readonly("end_row", &distributed_crs_matrix::end_row)
    .def_property_readonly("nnz", &distributed_crs_matrix::get_nnz)
    .def("print", &distributed_crs_matrix::print)
    .def("output_matrix_market", &distributed_crs_matrix::output_matrix_market)
    .def_property_readonly("solver_name", &distributed_crs_matrix::get_solver_name);

  py::class_<wrap_parallel_sparse_ev>(m, "parallel_sparse_ev")
    .def(py::init<std::string const&>())
    .def(py::init<>())
    .def("initialize", &wrap_parallel_sparse_ev::initialize)
    .def("finalize", &parallel_sparse_ev::finalize)
    .def("default_mapping", &wrap_parallel_sparse_ev::default_mapping)
    .def("eigenvalue", &parallel_sparse_ev::eigenvalue)
    .def("eigenvector", &wrap_parallel_sparse_ev::python_eigenvector)
    .def_property_readonly("num_conv", &parallel_sparse_ev::get_num_conv)
    .def("diagonalize", py::overload_cast<wrap_distributed_crs_matrix const&, wrap_parameters const&>(&wrap_parallel_sparse_ev::diagonalize),
         py::arg("mat"), py::arg("params") = wrap_parameters())
    .def("diagonalize", py::overload_cast<distributed_mfree const&, wrap_parameters const&>(&wrap_parallel_sparse_ev::diagonalize),
         py::arg("mat"), py::arg("params") = wrap_parameters())
    .def("diagonalize", py::overload_cast<wrap_distributed_mfree const&, wrap_parameters const&>(&wrap_parallel_sparse_ev::diagonalize),
         py::arg("mat"), py::arg("params") = wrap_parameters())
    .def_property_readonly_static("solvers", &parallel_sparse_ev::solvers)
    .def_property_readonly_static("default_solver", &parallel_sparse_ev::default_solver);
  
  // Eigen3 matrix
  m.def("generate", py::overload_cast<Eigen::Ref<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>>,std::function<double(int, int)>const&>(&pyrokko_generate<Eigen::ColMajor>));
  m.def("generate", py::overload_cast<Eigen::Ref<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>>,std::function<double(int, int)>const&>(&pyrokko_generate<Eigen::RowMajor>));

  // utility functions
  m.def("sort_eigenpairs", py::overload_cast<Eigen::Ref<Eigen::VectorXd>,Eigen::Ref<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>>,Eigen::Ref<Eigen::VectorXd>,Eigen::Ref<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>>,bool>(&pyrokko_sort_eigenpairs<Eigen::RowMajor>),
        py::arg("eigval"), py::arg("eigvec"), py::arg("eigval_sorted"), py::arg("eigvec_sorted"), py::arg("ascending") = true);
  
  m.def("sort_eigenpairs", py::overload_cast<Eigen::Ref<Eigen::VectorXd>,Eigen::Ref<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>>,Eigen::Ref<Eigen::VectorXd>,Eigen::Ref<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>>,bool>(&pyrokko_sort_eigenpairs<Eigen::ColMajor>),
        py::arg("eigval"), py::arg("eigvec"), py::arg("eigval_sorted"), py::arg("eigvec_sorted"), py::arg("ascending") = true);

  m.def("split_solver_name", &wrap_split_solver_name);
}

} // end namespace rokko


<|start_filename|>example/scalapack/psyevd_float.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <mpi.h>
#include <cmath>
#include <iostream>
#include <rokko/distributed_matrix.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/scalapack.hpp>

int main(int argc, char** argv) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  rokko::grid grid(MPI_COMM_WORLD);

  int n = 8;
  if (argc > 1) n = std::atoi(argv[1]);

  if (grid.get_myrank() == 0) {
    std::cout << "n = " << n << std::endl;
    std::cout << "nprocs = " << grid.get_nprocs() << std::endl;
    std::cout << "nprow = " << grid.get_nprow() << std::endl;
    std::cout << "npcol = " << grid.get_npcol() << std::endl;
    if ((grid.get_nprocs() != grid.get_nprow() * grid.get_npcol()) ||
        (n % grid.get_nprow() != 0) || (n % grid.get_npcol() != 0)) {
      std::cerr << "incompatible matrix size and number of processes\n";
      MPI_Abort(MPI_COMM_WORLD, 127);
    }
  }

  rokko::mapping_bc<rokko::matrix_col_major> map(n, 1);
  rokko::distributed_matrix<float> a(map);
  rokko::distributed_matrix<float> z(map);
  Eigen::VectorXf w(n);
  for (int j = 0; j < n; ++j)
    for (int i = 0; i < n; ++i)
      a.set_global(i, j, std::min(i, j) + 1);

  a.print();
  int info = rokko::scalapack::psyevd('U', a, w, z);
  if (info) {
    std::cerr << "Error in rokko::scalapack::psyevd\n";
    MPI_Abort(MPI_COMM_WORLD, info);
  }
  if (grid.get_myrank() == 0)
    std::cout << "eigenvalues: " << w.transpose() << std::endl;

  MPI_Finalize();
}


<|start_filename|>example/fortran/utility/parameters.f90<|end_filename|>
!*****************************************************************************
!
! Rokko: Integrated Interface for libraries of eigenvalue decomposition
!
! Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
!
! 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)
!
!*****************************************************************************

program frank_matrix
  use parameters
  implicit none

  type(rokko_parameters) :: params
  integer :: i
  double precision :: d
  logical :: is
  character :: c
  character(len=255) :: str_fixed
  character(len=255), allocatable :: str_alloc_fixed
  character(len=:), pointer :: str_ptr
  character(len=:), allocatable :: str
  type(string), allocatable :: keys(:)

  call rokko_parameters_construct(params)

  call rokko_parameters_set_int(params, "INTE", 3)
  call rokko_parameters_get_int(params, "INTE", i)
  print*, "T=", i

  call rokko_parameters_set_double(params, "DABURU", 1.2D0)
  call rokko_parameters_get_double(params, "DABURU", d)
  print*, "D=", d

  call rokko_parameters_set_logical(params, "is", .true.)
  call rokko_parameters_get_logical(params, "is", is)
  print*, "is=", is

  call rokko_parameters_set_char(params, "cyara", 'A')
  call rokko_parameters_get_char(params, "cyara", c)
  print*, "cyara=", c

  call rokko_parameters_set_string(params, "solver", "ansazi")
  call rokko_get(params, "solver", str)
  print*, "solver=", str

  print*, "By function:"
  str = rokko_parameters_get_string(params, "solver")
  print*, "  deferred length & allocatable=", str
  str_fixed = rokko_parameters_get_string(params, "solver")
  print*, "  fixed length=", trim(str_fixed)
  str_alloc_fixed = rokko_parameters_get_string(params, "solver")
  print*, "  fixed length & allocatable=", trim(str_alloc_fixed)
  str_ptr => rokko_parameters_get_string(params, "solver")
  print*, "  deferred length & pointer=", str_ptr

  call rokko_parameters_keys(params, keys)
  do i = 1, size(keys)
     print*, "i=", i, "str=", keys(i)%str
  enddo
  call rokko_parameters_destruct(params)

end program frank_matrix


<|start_filename|>rokko/scalapack/pstedc.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_PSTEDC_HPP
#define ROKKO_SCALAPACK_PSTEDC_HPP

#include <lapacke.h>
#include <rokko/cscalapack.h>
#include <rokko/eigen3.hpp>
#include <rokko/lapack/storage.hpp>
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>

namespace rokko {
namespace scalapack {

namespace {

inline int pstedc_dispatch(char compz, int n, double* d, double* e,
                           double* Q, int iq, int jq, const int* descQ) {
  return cscalapack_pdstedc(compz, n, d, e,
                            Q, iq, jq, descQ);
}

} // end of anonymous namespace

template<typename MATRIX, typename VECTOR>
int pstedc(char compz, VECTOR& d, VECTOR& e, MATRIX& z) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR>>::value, "");

  lapack_int n = size(d);
  const int* descZ = z.get_mapping().get_blacs_descriptor().data();
  return pstedc_dispatch(compz, n, storage(d), storage(e),
                         z.get_array_pointer(), 0, 0, descZ);
}

// eigenvalues & eigenvectors (without compz)
template<typename MATRIX, typename VECTOR>
int pstedc(MATRIX& a, VECTOR& w, MATRIX& z) {
  return pstedc('I', a, w, z);
}

} // end namespace scalapack
} // end namespace rokko

#endif // ROKKO_SCALAPACK_PSTEDC_HPP


<|start_filename|>rokko/pyrokko_distributed_mfree.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_DISTRIBUTED_MFREE_HPP
#define PYROKKO_DISTRIBUTED_MFREE_HPP

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/numpy.h>
#include <pybind11/eigen.h>

#include <rokko/eigen3.hpp>

#include <rokko/mpi_communicator.hpp>
#include <rokko/distributed_mfree.hpp>
#include <rokko/pyrokko_communicator.hpp>
#include <rokko/pyrokko_mapping_1d.hpp>

namespace rokko {

class wrap_distributed_mfree : public distributed_mfree_holder {
public:
  wrap_distributed_mfree(std::function<void(ConstMapVec,MapVec)> const& multiply, int dim)
    : distributed_mfree_holder(multiply, skel::mapping_1d(dim, rokko::mpi_comm{MPI_COMM_WORLD})) {}

  wrap_distributed_mfree(std::function<void(ConstMapVec,MapVec)> const& multiply, int dim, pybind11::handle const& comm_handle)
    : distributed_mfree_holder(multiply, skel::mapping_1d(dim, wrap_communicator{comm_handle})) {}

  wrap_distributed_mfree(std::function<void(ConstMapVec,MapVec)> const& multiply, wrap_mapping_1d const& map)
    : distributed_mfree_holder(multiply, skel::mapping_1d(map.get_dim(), map.get_mpi_comm())) {}

  ~wrap_distributed_mfree() = default;
};


class distributed_mfree_inherit : public distributed_mfree_default {
public:
  using distributed_mfree_default::distributed_mfree_default;

  distributed_mfree_inherit(int dim, pybind11::handle const& comm_handle)
  : distributed_mfree_default(skel::mapping_1d(dim, wrap_communicator{comm_handle})) {}

  virtual void multiply(const Eigen::VectorXd& x, Eigen::Ref<Eigen::VectorXd> y) const { // Not pure virtual to display error message
    std::cerr << "distributed_mfree_inherit : multiply is not implemented in Python" << std::endl;
  };

  void multiply(const double* x, double *const y) const override {
    const int num_local_rows = get_num_local_rows();
    Eigen::Vector<double> X, Y;
    new (&X) Eigen::Map<const Eigen::Vector<double>>(x, num_local_rows);
    new (&Y) Eigen::Map<Eigen::Vector<double>>(y, num_local_rows);
    multiply(X, Y);
    new (&X) Eigen::Vector<double>{};
    new (&Y) Eigen::Vector<double>{};
  }
};

class wrap_distributed_mfree_inherit : public distributed_mfree_inherit {
public:
  using distributed_mfree_inherit::distributed_mfree_inherit;

  void multiply(const Eigen::VectorXd& x, Eigen::Ref<Eigen::VectorXd> y) const override {
    PYBIND11_OVERLOAD(void, distributed_mfree_inherit, multiply, x, y);
  }
};

} // end namespace rokko

#endif // PYROKKO_DISTRIBUTED_MFREE_HPP


<|start_filename|>rokko/lapack/heevx.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_HEEVX_HPP
#define ROKKO_LAPACK_HEEVX_HPP

#include <complex>
#include <lapacke.h>
#undef I
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>
#include "complex_cast.hpp"
#include <rokko/lapack/storage.hpp>
#include <rokko/alias_template_function.hpp>

namespace rokko {
namespace lapack {

namespace {

template<typename T> struct heevx_dispatch;

template<>
struct heevx_dispatch<float> {
  template<typename MATRIX, typename MATRIX2, typename VECTOR, typename VECTOR_INT>
  static lapack_int heevx(int matrix_layout, char jobz, char range, char uplo, lapack_int n, MATRIX& a,
                          float vl, float vu, lapack_int il, lapack_int iu, float abstol,
                          lapack_int& m, VECTOR& w, MATRIX2& z, VECTOR_INT& ifail) {
    return LAPACKE_ssyevx(matrix_layout, jobz, range, uplo, n, storage(a), ld(a), vl, vu, il, iu, abstol, &m, storage(w), storage(z), ld(z), storage(ifail));
  }
};

template<>
struct heevx_dispatch<double> {
  template<typename MATRIX, typename MATRIX2, typename VECTOR, typename VECTOR_INT>
  static lapack_int heevx(int matrix_layout, char jobz, char range, char uplo, lapack_int n, MATRIX& a,
                          double vl, double vu, lapack_int il, lapack_int iu, double abstol,
                          lapack_int& m, VECTOR& w, MATRIX2& z, VECTOR_INT& ifail) {
    return LAPACKE_dsyevx(matrix_layout, jobz, range, uplo, n, storage(a), ld(a), vl, vu, il, iu, abstol, &m, storage(w), storage(z), ld(z), storage(ifail));
  }
};

template<>
struct heevx_dispatch<std::complex<float>> {
  template<typename MATRIX, typename MATRIX2, typename VECTOR, typename VECTOR_INT>
  static lapack_int heevx(int matrix_layout, char jobz, char range, char uplo, lapack_int n, MATRIX& a,
                          float vl, float vu, lapack_int il, lapack_int iu, float abstol,
                          lapack_int& m, VECTOR& w, MATRIX2& z, VECTOR_INT& ifail) {
    return LAPACKE_cheevx(matrix_layout, jobz, range, uplo, n, complex_cast(storage(a)), ld(a), vl, vu, il, iu, abstol, &m, storage(w), complex_cast(storage(z)), ld(z), storage(ifail));
  }
};

template<>
struct heevx_dispatch<std::complex<double>> {
  template<typename MATRIX, typename MATRIX2, typename VECTOR, typename VECTOR_INT>
  static lapack_int heevx(int matrix_layout, char jobz, char range, char uplo, lapack_int n, MATRIX& a,
                          double vl, double vu, lapack_int il, lapack_int iu, double abstol,
                          lapack_int& m, VECTOR& w, MATRIX2& z, VECTOR_INT& ifail) {
    return LAPACKE_zheevx(matrix_layout, jobz, range, uplo, n, complex_cast(storage(a)), ld(a), vl, vu, il, iu, abstol, &m, storage(w), complex_cast(storage(z)), ld(z), storage(ifail));
  }
};

} // end of anonymous namespace

template<typename T, typename MATRIX, typename MATRIX2, typename VECTOR, typename VECTOR_INT>
lapack_int heevx(char jobz, char range, char uplo, MATRIX& a,
                 T vl, T vu, lapack_int il, lapack_int iu, T abstol,
                 lapack_int& m, VECTOR& w, MATRIX2& z, VECTOR_INT& ifail) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR>>::value, "");
  lapack_int n = rows(a);
  if (rows(a) != cols(a))
    throw std::invalid_argument("matrix A size mismatch");
  //if (size(w) != n)
  //  throw std::invalid_argument("vector w size mismatch");
  return heevx_dispatch<value_t<MATRIX>>::
    heevx((is_col_major(a) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR), jobz, range, uplo, n, a, vl, vu, il, iu, abstol, m, w, z, ifail);
}

// eigenvalues & eigenvectors (without jobz)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int heevx(char range, char uplo, MATRIX& a,
                 T vl, T vu, lapack_int il, lapack_int iu, T abstol,
                 lapack_int& m, VECTOR& w, MATRIX& z, VECTOR_INT& ifail) {
  return heevx('V', range, uplo, a, vl, vu, il, iu, abstol, m, w, z, ifail);
}

// eigenvalues & eigenvectors, use all (without jobz, range, vl, vu, il, iu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int heevx(char uplo, MATRIX& a,
                 T abstol,
                 lapack_int& m, VECTOR& w, MATRIX& z, VECTOR_INT& ifail) {
  constexpr real_t<MATRIX> real_zero = 0;
  return heevx('A', uplo, a, real_zero, real_zero, 0, 0, abstol, m, w, z, ifail);
}

// eigenvalues & eigenvectors, use vl, vu (without jobz, range, il, iu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int heevx(char uplo, MATRIX& a,
                 T vl, T vu, T abstol,
                 lapack_int& m, VECTOR& w, MATRIX& z, VECTOR_INT& ifail) {
  return heevx('V', uplo, a, vl, vu, 0, 0, abstol, m, w, z, ifail);
}

// eigenvalues & eigenvectors, use il, iu (without jobz, range, vl, vu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int heevx(char uplo, MATRIX& a,
                 lapack_int il, lapack_int iu, T abstol,
                 lapack_int& m, VECTOR& w, MATRIX& z, VECTOR_INT& ifail) {
  constexpr real_t<MATRIX> real_zero = 0;
  return heevx('I', uplo, a, real_zero, real_zero, il, iu, abstol, m, w, z, ifail);
}

// only eigenvalues (without jobz)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int heevx(char range, char uplo, MATRIX& a,
                 T vl, T vu, lapack_int il, lapack_int iu, T abstol,
                 lapack_int& m, VECTOR& w, VECTOR_INT& ifail) {
  constexpr null_matrix<value_t<MATRIX>> z_null;
  return heevx('N', range, uplo, a, vl, vu, il, iu, abstol, m, w, z_null, ifail);
}

// only eigenvalues, use all (without jobz, range, vl, vu, il, iu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int heevx(char uplo, MATRIX& a,
                 T abstol,
                 lapack_int& m, VECTOR& w, VECTOR_INT& ifail) {
  constexpr real_t<MATRIX> real_zero = 0;
  return heevx('A', uplo, a, real_zero, real_zero, 0, 0, abstol, m, w, ifail);
}

// only eigenvalues, use vl, vu (without jobz, range, il, iu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int heevx(char uplo, MATRIX& a,
                 T vl, T vu, T abstol,
                 lapack_int& m, VECTOR& w, VECTOR_INT& ifail) {
  return heevx('V', uplo, a, vl, vu, 0, 0, abstol, m, w, ifail);
}

// only eigenvalues, use il, iu (without jobz, range, vl, vu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int heevx(char uplo, MATRIX& a,
                 lapack_int il, lapack_int iu, T abstol,
                 lapack_int& m, VECTOR& w, VECTOR_INT& ifail) {
  constexpr real_t<MATRIX> real_zero = 0;
  return heevx('I', uplo, a, real_zero, real_zero, il, iu, abstol, m, w, ifail);
}

ALIAS_TEMPLATE_FUNCTION(syevx, heevx);

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_HEEVX_HPP


<|start_filename|>rokko/eigen_vector.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_EIGEN_VECTOR_H
#define ROKKO_EIGEN_VECTOR_H

#ifdef __cplusplus
extern "C" {
#endif

struct rokko_eigen_vector {
  void* ptr;
};

void rokko_eigen_vector_construct(struct rokko_eigen_vector* vec, int dim1);
void rokko_eigen_vector_construct_array_size(struct rokko_eigen_vector* vector,
                                             int dim, double* ptr);
void rokko_eigen_vector_destruct(struct rokko_eigen_vector* vec);
int rokko_eigen_vector_get_dim(struct rokko_eigen_vector vec);
double* rokko_eigen_vector_get_array_pointer(struct rokko_eigen_vector vec);
void rokko_eigen_vector_set(struct rokko_eigen_vector vec, int i, double val);
void rokko_eigen_vector_set1(struct rokko_eigen_vector vec, int i, double val);
double rokko_eigen_vector_get(struct rokko_eigen_vector vec, int i);
double rokko_eigen_vector_get1(struct rokko_eigen_vector vec, int i);
void rokko_eigen_vector_print(struct rokko_eigen_vector vec);
void rokko_eigen_vector_generate_function(struct rokko_eigen_vector vec,
                                          double (*func)(int i));
void rokko_eigen_vector_generate_function_p(struct rokko_eigen_vector vec,
                                            double (*func)(const int* i));
void rokko_eigen_vector_generate_function1(struct rokko_eigen_vector vec,
                                            double (*func)(int i));
void rokko_eigen_vector_generate_function1_p(struct rokko_eigen_vector vec,
                                              double (*func)(const int* i));

#ifdef __cplusplus
}
#endif

#endif /* ROKKO_EIGEN_VECTOR_H */


<|start_filename|>example/lapack/stegr.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/blas.hpp>
#include <rokko/lapack/stegr.hpp>
#include <rokko/lapack/lange.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/utility/laplacian_matrix.hpp>
#include <iostream>

int main(int argc, char** argv) {
  constexpr double eps = 1e-10;
  int n = 5;
  if (argc > 1) n = std::stoi(argv[1]);

  // generate matrix
  Eigen::VectorXd d(n), e(n);
  rokko::laplacian_matrix::generate(d, e);

  // diagonalization
  Eigen::VectorXd w(n);
  Eigen::MatrixXd u(n,n);
  int m;
  const double vl = 0, vu = 0;
  const int il = 0, iu = 0;
  constexpr double abstol = 0.;
  Eigen::VectorXi isuppz(2*n);
  int info = rokko::lapack::stegr('V', 'A', d, e, vl, vu, il, iu, abstol, m, w, u, isuppz);
  std::cout << "Eigenvalues: " << std::endl << w << std::endl;
  std::cout << "Eigenvectors: " << std::endl << u << std::endl;

  // orthogonality check
  Eigen::MatrixXd check1 = u.adjoint() * u - Eigen::MatrixXd::Identity(n, n);
  double norm1 = rokko::lapack::lange('F', check1);
  std::cout << "|| U^t U - I || = " << norm1 << std::endl;
  if (norm1 > eps) throw std::runtime_error("Error: orthogonality check");

  // eigenvalue check
  Eigen::MatrixXd a(n,n);
  rokko::laplacian_matrix::generate(a);
  Eigen::MatrixXd check2 = u.adjoint() * a * u;
  check2.diagonal() -= w;
  double norm2 = rokko::lapack::lange('F', check2);
  std::cout << check2 << std::endl;
  std::cout << "|| U^t A U - diag(w) || = " << norm2 << std::endl;
  if (norm2 > eps) throw std::runtime_error("Error: eigenvalue check");

  return 0;
}


<|start_filename|>rokko/scalapack/pdlange.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <stdlib.h>
#include <rokko/Cblacs.h>
#include <rokko/scalapack/scalapack_interface.h>

double cscalapack_pdlange(char norm, int m, int n, const double* A, const int* descA) {
  int ia = 0;
  int ja = 0;
  int lwork = 0;
  if (norm == '1' || norm == 'O' || norm == 'o' || norm == 'I' || norm == 'i') {
    int context = descA[1];
    int nprow, npcol, myrow, mycol;
    Cblacs_gridinfo(context, &nprow, &npcol, &myrow, &mycol);
    if (norm == '1' || norm == 'O' || norm == 'o') {
      int nb_a = descA[5];
      int csrc_a = descA[7];
      int icoffa = ja % nb_a;
      int iacol = cscalapack_indxg2p(ja, nb_a, mycol, csrc_a, npcol);
      lwork = cscalapack_numroc(n + icoffa, nb_a, mycol, iacol, npcol);
    } else if (norm == 'I' || norm == 'i') {
      int mb_a = descA[4];
      int rsrc_a = descA[6];
      int ifoffa = ia % mb_a;
      int iarow = cscalapack_indxg2p(ia, mb_a, myrow, rsrc_a, nprow);
      lwork = cscalapack_numroc(m + ifoffa, mb_a, myrow, iarow, nprow);
    }
  }
  double* work = NULL;
  if (lwork) work = (double*)malloc(sizeof(double) * lwork);
  double result = cscalapack_pdlange_work(norm, m, n, A, descA, work);
  if (lwork) free(work);
  return result;
}


<|start_filename|>rokko/eigen3/diagonalize.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_EIGEN3_DIAGONALIZE_HPP
#define ROKKO_EIGEN3_DIAGONALIZE_HPP

#include <rokko/eigen3.hpp>
#include <rokko/traits/real_t.hpp>
#include <rokko/parameters.hpp>

namespace rokko {
namespace eigen3 {

char get_matrix_part(rokko::parameters const& params) {
  std::string matrix_part;
  if (params.defined("uplow"))
    matrix_part = params.get_string("uplow");
  if (params.defined("matrix_part"))
    matrix_part = params.get_string("matrix_part");
  if ((matrix_part[0] == 'u') || (matrix_part[0] == 'U'))
    return 'U';
  if ((matrix_part[0] == 'l') || (matrix_part[0] == 'L'))
    return 'L';
  else
    return '\0';
}

// only eigenvalues
template<typename T, int ROWS, int COLS, int MATRIX_MAJOR, int SIZE>
parameters diagonalize(Eigen::Matrix<T,ROWS,COLS,MATRIX_MAJOR>& mat, Eigen::Vector<real_t<T>, SIZE>& eigvals,
		       rokko::parameters const& params) {
  parameters params_out;
  if (get_matrix_part(params) == 'U') {
    throw std::invalid_argument("eigen3::diagonalize() : Eigen3's SelfAdjointEigenSolver does not support upper part of matrix.");
  }
  Eigen::SelfAdjointEigenSolver<Eigen::Matrix<T,ROWS,COLS,MATRIX_MAJOR>> ES(mat);
  eigvals = ES.eigenvalues();
  return params_out;
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
parameters diagonalize(Eigen::Matrix<T,ROWS,COLS,MATRIX_MAJOR>& mat, std::vector<real_t<T>>& eigvals_in,
		       rokko::parameters const& params) {
  parameters params_out;
  if (get_matrix_part(params) == 'U') {
    throw std::invalid_argument("eigen3::diagonalize() : Eigen3's SelfAdjointEigenSolver does not support upper part of matrix.");
  }
  std::size_t dim = mat.rows();
  if (eigvals_in.size() < dim) eigvals_in.resize(dim);
  Eigen::Map<Eigen::Vector<real_t<T>>> eigvals(eigvals_in.data(), eigvals_in.size());
  Eigen::SelfAdjointEigenSolver<Eigen::Matrix<T,ROWS,COLS,MATRIX_MAJOR>> ES(mat);
  eigvals = ES.eigenvalues();
  return params_out;
}

// eigenvalues/eigenvectors
template<typename T, int ROWS, int COLS, int MATRIX_MAJOR, int SIZE>
parameters diagonalize(Eigen::Matrix<T,ROWS,COLS,MATRIX_MAJOR>& mat, Eigen::Vector<real_t<T>, SIZE> & eigvals,
		       Eigen::Matrix<T,ROWS,COLS,MATRIX_MAJOR>& eigvecs, rokko::parameters const& params) {
  parameters params_out;
  if (get_matrix_part(params) == 'U') {
    throw std::invalid_argument("eigen3::diagonalize() : Eigen3's SelfAdjointEigenSolver does not support upper part of matrix.");
  }
  Eigen::SelfAdjointEigenSolver<Eigen::Matrix<T,ROWS,COLS,MATRIX_MAJOR>> ES(mat);
  eigvals = ES.eigenvalues();
  eigvecs = ES.eigenvectors();
  return params_out;
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
parameters diagonalize(Eigen::Matrix<T,ROWS,COLS,MATRIX_MAJOR>& mat, std::vector<real_t<T>>& eigvals_in,
                Eigen::Matrix<T,ROWS,COLS,MATRIX_MAJOR>& eigvecs, rokko::parameters const& params) {
  parameters params_out;
  if (get_matrix_part(params) == 'U') {
    throw std::invalid_argument("eigen3::diagonalize() : Eigen3's SelfAdjointEigenSolver does not support upper part of matrix.");
  }
  std::size_t dim = mat.rows();
  if (eigvals_in.size() < dim) eigvals_in.resize(dim);
  Eigen::Map<Eigen::Vector<real_t<T>>> eigvals(eigvals_in.data(), eigvals_in.size());
  Eigen::SelfAdjointEigenSolver<Eigen::Matrix<T,ROWS,COLS,MATRIX_MAJOR>> ES(mat);
  eigvals = ES.eigenvalues();
  eigvecs = ES.eigenvectors();
  return params_out;
}


} // namespace eigen3
} // namespace rokko

#endif // ROKKO_EIGEN3_DIAGONALIZE_HPP


<|start_filename|>rokko/serial_dense_ev.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2016 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SERIAL_DENSE_EV_H
#define ROKKO_SERIAL_DENSE_EV_H

#include <rokko/eigen_matrix.h>
#include <rokko/eigen_vector.h>
#include <rokko/parameters.h>

#ifdef __cplusplus
extern "C" {
#endif

struct rokko_serial_dense_ev {
  void* ptr;
};

void rokko_serial_dense_ev_construct(struct rokko_serial_dense_ev* solver,
  const char* solver_name, int argc, char** argv);
void rokko_serial_dense_ev_destruct(struct rokko_serial_dense_ev* solver);
struct rokko_parameters rokko_serial_dense_ev_diagonalize_eigen_matrix(
  struct rokko_serial_dense_ev solver, struct rokko_eigen_matrix mat,
  struct rokko_eigen_vector eigval, struct rokko_eigen_matrix eigvecs);
struct rokko_parameters rokko_serial_dense_ev_diagonalize_eigvals(
  struct rokko_serial_dense_ev solver, struct rokko_eigen_matrix mat,
  struct rokko_eigen_vector eigval);
struct rokko_parameters rokko_serial_dense_ev_diagonalize_eigvals_params(
  struct rokko_serial_dense_ev solver, struct rokko_eigen_matrix mat,
  struct rokko_eigen_vector eigvals, struct rokko_parameters params);
struct rokko_parameters rokko_serial_dense_ev_diagonalize_params(
  struct rokko_serial_dense_ev solver, struct rokko_eigen_matrix mat,
  struct rokko_eigen_vector eigvals, struct rokko_eigen_matrix eigvecs,
  struct rokko_parameters params);

/* For Fortran binding */
void rokko_serial_dense_ev_construct_f(struct rokko_serial_dense_ev* solver,
  const char* solver_name);
void rokko_serial_dense_ev_diagonalize_f(struct rokko_serial_dense_ev* solver,
					 struct rokko_eigen_matrix* mat, struct rokko_eigen_vector* eigvals,
					 struct rokko_eigen_matrix* eigvecs,
					 struct rokko_parameters* params, struct rokko_parameters* params_out);

void rokko_serial_dense_ev_diagonalize_no_params_out_f(struct rokko_serial_dense_ev* solver,
						       struct rokko_eigen_matrix* mat, struct rokko_eigen_vector* eigvals,
						       struct rokko_eigen_matrix* eigvecs,
						       struct rokko_parameters* params);

void rokko_serial_dense_ev_diagonalize_no_params_inout_f(struct rokko_serial_dense_ev* solver,
						       struct rokko_eigen_matrix* mat, struct rokko_eigen_vector* eigvals,
						       struct rokko_eigen_matrix* eigvecs);

void rokko_serial_dense_ev_diagonalize_eigvals_f(struct rokko_serial_dense_ev* solver,
						 struct rokko_eigen_matrix* mat, struct rokko_eigen_vector* eigvals,
						 struct rokko_parameters* params, struct rokko_parameters* params_out);

void rokko_serial_dense_ev_diagonalize_eigvals_no_params_out_f(struct rokko_serial_dense_ev* solver,
							       struct rokko_eigen_matrix* mat, struct rokko_eigen_vector* eigvals,
							       struct rokko_parameters* params);

void rokko_serial_dense_ev_diagonalize_eigvals_no_params_inout_f(struct rokko_serial_dense_ev* solver,
								 struct rokko_eigen_matrix* mat, struct rokko_eigen_vector* eigvals);


int rokko_serial_dense_ev_num_solvers();
char** rokko_serial_dense_ev_solvers();
const char* rokko_serial_dense_ev_default_solver();

#ifdef __cplusplus
}
#endif

#endif /* ROKKO_SERIAL_DENSE_EV_H */


<|start_filename|>rokko/pblas/pcopy.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_PCOPY_HPP
#define ROKKO_SCALAPACK_PCOPY_HPP

#include <rokko/cpblas.h>
#include <rokko/lapack/complex_cast.hpp>

namespace rokko {
namespace pblas {

using rokko::lapack::complex_cast;

inline void pcopy(int n, const float* X, int ix, int jx, const int* descX, int incX,
                  float* Y, int iy, int jy, const int* descY, int incY) {
  cpblas_pscopy(n, X, ix, jx, descX, incX, Y, iy, jy, descY, incY);
}

inline void pcopy(int n, const double* X, int ix, int jx, const int* descX, int incX,
                  double* Y, int iy, int jy, const int* descY, int incY) {
  cpblas_pdcopy(n, X, ix, jx, descX, incX, Y, iy, jy, descY, incY);
}

inline void pcopy(int n, const std::complex<float>* X, int ix, int jx, const int* descX, int incX,
                  std::complex<float>* Y, int iy, int jy, const int* descY, int incY) {
  cpblas_pccopy(n, complex_cast(X), ix, jx, descX, incX, complex_cast(Y), iy, jy, descY, incY);
}

inline void pcopy(int n, const std::complex<double>* X, int ix, int jx, const int* descX, int incX,
                  std::complex<double>* Y, int iy, int jy, const int* descY, int incY) {
  cpblas_pzcopy(n, complex_cast(X), ix, jx, descX, incX, complex_cast(Y), iy, jy, descY, incY);
}

} // end namespace pblas
} // end namespace rokko

#endif // ROKKO_SCALAPACK_PCOPY_HPP


<|start_filename|>rokko/slepc/solver.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SLEPC_SOLVER_HPP
#define ROKKO_SLEPC_SOLVER_HPP

#include <rokko/slepc.hpp>

#include <rokko/slepc/distributed_crs_matrix.hpp>
#include <rokko/slepc/distributed_mfree.hpp>

namespace rokko {

namespace slepc {

class solver {
public:
  static const std::map<std::string,EPSLanczosReorthogType> lanczos_reorthog_map;

  solver() {
    SlepcInitialize(NULL, NULL, (char*)NULL, NULL);
  }
  ~solver() = default;

  void initialize(int& argc, char**& argv) {}
  void finalize() { SlepcFinalize(); }

  static std::string get_routine(rokko::parameters const& params) {
    if (params.defined("routine")) {
      if ((params.type("routine") != typeid(std::string)) && params.type("routine") != typeid(const char*))
        throw std::invalid_argument("slepc::get_routine() : routine must be charatcters or string.");
      std::string routine = params.get_string("routine");
      if (!routine.empty()) {
        return routine;
      } else {
        return EPSKRYLOVSCHUR;
      }
    } else {
      return EPSKRYLOVSCHUR;
    }
  }

  static PetscInt get_num_eigvals(rokko::parameters const& params) {
    return params.defined("num_eigvals") ? (PetscInt) params.get<int>("num_eigvals") : 1;
  }

  static PetscInt get_max_block_size(rokko::parameters const& params) {
    return params.defined("max_block_size") ? params.get<int>("max_block_size") : PETSC_DECIDE;
  }

  static PetscReal get_conv_tol(rokko::parameters const& params) {
    return params.defined("conv_tol") ? params.get<double>("conv_tol") : (PetscReal)PETSC_DEFAULT;
  }

  static PetscInt get_max_iters(rokko::parameters const& params) {
    return params.defined("max_iters") ? params.get<int>("max_iters") : PETSC_DECIDE;
  }

  static EPSWhich get_wanted_eigenvalues(std::string const& str) {
    if ((str == "largest") || (str == "EPS_LARGEST_MAGNITUDE"))
      return EPS_LARGEST_MAGNITUDE;
    if ((str == "smallest") || (str == "EPS_SMALLEST_MAGNITUDE"))
      return EPS_SMALLEST_MAGNITUDE;
    if ((str == "largest_real") || (str == "EPS_LARGEST_REAL"))
      return EPS_LARGEST_REAL;
    if ((str == "smallest_real") || (str == "EPS_SMALLEST_REAL"))
      return EPS_SMALLEST_REAL;
    else
      throw std::invalid_argument("get_wanted_eigenvalues: invalid parameter");
  }

  void set_lanczos_reorthog(rokko::parameters const& params) {
    if (params.defined("reorthog")) {
      std::string str = params.get<std::string>("reorthog");
      if (lanczos_reorthog_map.find(str) == lanczos_reorthog_map.end())
        throw std::invalid_argument(str + " is not lanczos reorthog in SLEPc");
      PetscErrorCode ierr = EPSLanczosSetReorthog(eps, lanczos_reorthog_map.at(str));
    }
  }

  void set_block_size(rokko::parameters const& params) {
    PetscErrorCode ierr;
    if (params.defined("block_size")) {
      int block_size = params.get<int>("block_size");
      if (get_routine(params) == "lobpcg") {
        //ierr = EPSLOBPCGSetBlockSize(eps, block_size);
      } else if (get_routine(params) == "jd") {
        ierr = EPSJDSetBlockSize(eps, block_size);
      }
    }
  }

  void set_restart(rokko::parameters const& params) {
    PetscErrorCode ierr;
    if (params.defined("restart")) {
      double restart = params.get<double>("restart");
      if (get_routine(params) == "lobpcg") {
        ierr = EPSLOBPCGSetRestart(eps, restart);
      } else if (get_routine(params) == "krylovschur") {
        ierr = EPSKrylovSchurSetRestart(eps, restart);
      } else if (get_routine(params) == "jd") {
        //ierr = EPSJDSetRestart(eps, restart);
      }
    }
  }

  void set_locking(rokko::parameters const& params) {
    PetscErrorCode ierr;
    if (params.defined("locking")) {
      PetscBool locking = params.get<bool>("locking") ? PETSC_TRUE : PETSC_FALSE;
      if (get_routine(params) == "lobpcg") {
        ierr = EPSLOBPCGSetLocking(eps, locking);
      } else if (get_routine(params) == "krylovschur") {
        ierr = EPSKrylovSchurSetLocking(eps, locking);
      }
    }
  }

  void set_wanted_eigenvalues(rokko::parameters const& params) {
    std::string str = params.defined("wanted_eigenvalues") ? params.get_string("wanted_eigenvalues") : std::string{};
    if (!str.empty()) {
      EPSSetWhichEigenpairs(eps, get_wanted_eigenvalues(str));
    }
  }

  parameters diagonalize(const rokko::slepc::distributed_crs_matrix& mat, rokko::parameters const& params) {
    dimension_ = mat.get_dim();
    offset_local_ = mat.start_row();
    num_local_rows_ = mat.get_num_local_rows();
    comm_ = mat.get_map().get_mpi_comm().get_comm();

    return diagonalize_common(mat.get_matrix(), params);
  }

  parameters diagonalize(const rokko::distributed_crs_matrix& mat, rokko::parameters const& params) {
    if (mat.get_solver_name() != "slepc") {
      throw std::invalid_argument("rokko::slepc::solver::diagonalize() : " + mat.get_solver_name() + "'s distributed_crs_matrix is given.");
    }
    return diagonalize(*std::static_pointer_cast<const rokko::slepc::distributed_crs_matrix>(mat.get_ptr()), params);
  }

  parameters diagonalize(const rokko::distributed_mfree& mat, rokko::parameters const& params) {
    Mat A;
    PetscErrorCode ierr;
    ierr = MatCreateShell(mat.get_comm(), mat.get_num_local_rows(), mat.get_num_local_rows(), mat.get_dim(), mat.get_dim(), const_cast<rokko::distributed_mfree*>(&mat), &A);
    ierr = MatSetFromOptions(A);
    ierr = MatShellSetOperation(A, MATOP_MULT, (void(*)())MatMult);
    ierr = MatShellSetOperation(A, MATOP_MULT_TRANSPOSE, (void(*)())MatMult);
    ierr = MatShellSetOperation(A, MATOP_GET_DIAGONAL, (void(*)())MatGetDiagonal);

    dimension_ = mat.get_dim();
    offset_local_ = mat.get_local_offset();
    num_local_rows_ = mat.get_num_local_rows();
    comm_ = mat.get_comm();

    return diagonalize_common(A, params);
  }

  #undef __FUNCT__
  #define __FUNCT__ "slepc::solver::MatMult"
  static PetscErrorCode MatMult(Mat A, Vec x, Vec y) {
    PetscFunctionBeginUser;
    PetscErrorCode ierr;

    rokko::distributed_mfree *op_ctx;
    ierr = MatShellGetContext(A, &op_ctx); CHKERRQ(ierr);

    PetscScalar const* px;
    PetscScalar * py;

    ierr = VecGetArrayRead(x, &px);  CHKERRQ(ierr);
    ierr = VecGetArray(y, &py);  CHKERRQ(ierr);

    op_ctx->multiply(px, py);

    ierr = VecRestoreArrayRead(x,&px);  CHKERRQ(ierr);
    ierr = VecRestoreArray(y,&py);  CHKERRQ(ierr);

    PetscFunctionReturn(0);
  }

  #undef __FUNCT__
  #define __FUNCT__ "slepc::solver::MatGetDiagonal"
  static PetscErrorCode MatGetDiagonal(Mat A, Vec diag) {
    PetscFunctionBeginUser;
    PetscErrorCode ierr;

    rokko::distributed_mfree *op_ctx;
    ierr = MatShellGetContext(A, &op_ctx); CHKERRQ(ierr);

    PetscScalar *pd;

    ierr = VecGetArray(diag, &pd); CHKERRQ(ierr);
    op_ctx->fill_diagonal(pd);
    ierr = VecRestoreArray(diag ,&pd); CHKERRQ(ierr);

    PetscFunctionReturn(0);
  }

  parameters diagonalize_common(Mat const& A, rokko::parameters const& params) {
    parameters params_out;

    PetscInt num_evals = get_num_eigvals(params);
    PetscInt max_block_size = get_max_block_size(params);
    PetscReal tol = get_conv_tol(params);
    PetscInt max_iters = get_max_iters(params);

    PetscErrorCode ierr;
    ierr = EPSCreate(comm_, &eps);

    // Set operators for a standard eigenvalue problem
    ierr = EPSSetOperators(eps, A, NULL);
    ierr = EPSSetProblemType(eps, EPS_HEP);
    ierr = EPSSetType(eps, get_routine(params).c_str());
    ierr = EPSSetDimensions(eps, num_evals, max_block_size, PETSC_DECIDE);
    ierr = EPSSetTolerances(eps, tol, max_iters);
    set_wanted_eigenvalues(params);

    set_block_size(params);
    set_restart(params);
    set_locking(params);

    if (get_routine(params) == "lanczos")
      set_lanczos_reorthog(params);

    // Set solver parameters at runtime
    ierr = EPSSetFromOptions(eps);

    // Solve the eigensystem
    ierr = EPSSolve(eps);

    set_output_parameters(params_out);

    int myrank;
    MPI_Comm_rank(comm_, &myrank);
    if (params.get_bool("verbose") && (myrank == 0))
      info_verbose();

    return params_out;
  }

  void set_output_parameters(rokko::parameters& params_out) const {
    int num_conv = get_num_conv();
    params_out.set("num_conv", num_conv);
  }

  void info_verbose() const {
    PetscErrorCode ierr;

    EPSType type;
    ierr = EPSGetType(eps, &type);

    PetscInt nev, ncv, mpd;
    PetscReal tol;
    PetscInt maxits, its;

    ierr = EPSGetDimensions(eps, &nev, &ncv, &mpd);
    ierr = EPSGetTolerances(eps, &tol, &maxits);
    ierr = EPSGetIterationNumber(eps, &its);

    std::cout << "input parameters:" << std::endl;
    std::cout << "  solution method: " << type << std::endl;
    std::cout << "  number of eigenvalues to compute=" << nev << std::endl;
    std::cout << "  maximum dimension of the subspace=" << ncv << std::endl;
    std::cout << "  maximum dimension allowed for the projected problem=" << mpd << std::endl;
    std::cout << "  convergence tolerance=" << tol << std::endl;
    std::cout << "  maximum number of iterations=" << maxits << std::endl;
    std::cout << "results:" << std::endl;
    std::cout << "  number of converged eigenpairs=" << get_num_conv() << std::endl;
    std::cout << "  number of iterations=" << its << std::endl;
  }
  
  double eigenvalue(int i) const {
    PetscScalar eval_r, eval_i;
    EPSGetEigenvalue(eps, i, &eval_r, &eval_i);
    return eval_r;
  }

  void eigenvector(int k, double *const vec) const {
    Vec evec_r;
    VecCreateMPIWithArray(comm_, PETSC_DECIDE, num_local_rows_, dimension_, vec, &evec_r);
    EPSGetEigenvector(eps, k, evec_r, NULL);
    VecDestroy(&evec_r);
  }

  void eigenvector(int k, std::vector<double>& vec) const {
    if (vec.size() < num_local_rows_) vec.resize(num_local_rows_);
    eigenvector(k, vec.data());
  }

  void eigenvector(int k, distributed_vector<double>& vec) const {
    vec.initialize(dimension_, offset_local_, offset_local_ + num_local_rows_);
    eigenvector(k, vec.get_storage());
  }

  int get_num_conv() const {
    PetscErrorCode ierr;
    PetscInt num_conv;
    ierr = EPSGetConverged(eps, &num_conv);
    return static_cast<int>(num_conv);
  }

  const EPS& get_object() const {
    return eps;
  }

  EPS& get_object() {
    return eps;
  }

private:
  int dimension_, offset_local_, num_local_rows_;
  MPI_Comm comm_;
  EPS eps;  // eigenproblem solver context
};

const std::map<std::string,EPSLanczosReorthogType> solver::lanczos_reorthog_map{
  {"local", EPS_LANCZOS_REORTHOG_LOCAL}, {"full", EPS_LANCZOS_REORTHOG_FULL},
  {"selective", EPS_LANCZOS_REORTHOG_SELECTIVE}, {"periodic", EPS_LANCZOS_REORTHOG_PERIODIC},
  {"partial", EPS_LANCZOS_REORTHOG_PARTIAL}, {"delayed", EPS_LANCZOS_REORTHOG_DELAYED} };

} // namespace slepc

} // namespace rokko

#endif // ROKKO_SLEPC_SOLVER_HPP


<|start_filename|>test/mapping_1d/sizes_for_all_libraries.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/parallel_sparse_ev.hpp>
#include <rokko/mapping_1d.hpp>
#include <rokko/skel/mapping_1d.hpp>
#include <rokko/distributed_crs_matrix.hpp>

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

void check_map_mat(rokko::skel::mapping_1d const& map, rokko::distributed_crs_matrix const& mat) {
  ASSERT_EQ(map.get_dim(), mat.get_dim());
  ASSERT_EQ(map.get_num_local_rows(), mat.get_num_local_rows());
  ASSERT_EQ(map.start_row(), mat.start_row());
  ASSERT_EQ(map.end_row(), mat.end_row());
}

TEST(mapping_1d, start_row) {
  constexpr int dim = 100;
  rokko::skel::mapping_1d skel_map(dim, rokko::mpi_comm{MPI_COMM_WORLD});

  for (auto const& name : rokko::parallel_sparse_ev::solvers()) {
    rokko::parallel_sparse_ev solver(name);
    auto const map = solver.default_mapping(dim, rokko::mpi_comm{MPI_COMM_WORLD});
    const int num_entries_per_row = 3;
    rokko::distributed_crs_matrix mat(map, num_entries_per_row);
    check_map_mat(skel_map, mat);
  }
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>example/lapack/stedc.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/blas.hpp>
#include <rokko/lapack/stedc.hpp>
#include <rokko/lapack/lange.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/utility/laplacian_matrix.hpp>
#include <iostream>

int main(int argc, char** argv) {
  constexpr double eps = 1e-10;
  int n = 5;
  if (argc > 1) n = std::stoi(argv[1]);

  // generate matrix
  Eigen::VectorXd d(n), e(n-1);
  rokko::laplacian_matrix::generate(d, e);

  // diagonalization
  Eigen::VectorXd w = d;
  Eigen::MatrixXd u(n,n);
  int info = rokko::lapack::stedc('I', w, e, u);
  std::cout << "Eigenvalues: " << std::endl << w << std::endl;
  std::cout << "Eigenvectors: " << std::endl << u << std::endl;

  // orthogonality check
  Eigen::MatrixXd check1 = u.adjoint() * u - Eigen::MatrixXd::Identity(n, n);
  double norm1 = rokko::lapack::lange('F', check1);
  std::cout << "|| U^t U - I || = " << norm1 << std::endl;
  if (norm1 > eps) throw std::runtime_error("Error: orthogonality check");

  // eigenvalue check
  Eigen::MatrixXd a(n,n);
  rokko::laplacian_matrix::generate(a);
  Eigen::MatrixXd check2 = u.adjoint() * a * u;
  check2.diagonal() -= w;
  double norm2 = rokko::lapack::lange('F', check2);
  std::cout << check2 << std::endl;
  std::cout << "|| U^t A U - diag(w) || = " << norm2 << std::endl;
  if (norm2 > eps) throw std::runtime_error("Error: eigenvalue check");

  return 0;
}


<|start_filename|>example/blas/gemv.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <iostream>
#include <rokko/eigen3.hpp>
#include <rokko/blas.hpp>

int main() {
  std::size_t n = 4;
  Eigen::MatrixXd a(n, n);
  a << 0.959291425205444, 0.257508254123736, 0.243524968724989, 0.251083857976031,
    0.547215529963803, 0.840717255983663, 0.929263623187228, 0.616044676146639,
    0.138624442828679, 0.254282178971531, 0.349983765984809, 0.473288848902729,
    0.149294005559057, 0.814284826068816, 0.196595250431208, 0.351659507062997;
  Eigen::VectorXd x(n);
  x << 0.830828627896291, 0.585264091152724, 0.549723608291140, 0.917193663829810;
  Eigen::VectorXd y(n);
  y << 0.961898080855054, 0.00463422413406744, 0.774910464711502, 0.817303220653433;
  double alpha = 2.3;
  double beta = 0.5;

  std::cout << "a = [\n" << a << "\n]\n";
  std::cout << "x = [" << x.transpose() << "]^t\n";
  std::cout << "y = [" << y.transpose() << "]^t\n";
  
  rokko::blas::gemv(CblasNoTrans, alpha, a, x, 1, beta, y, 1);

  std::cout << alpha << " * a * x + " << beta << " * y = [" << y.transpose() << "]^t\n";
}

/* gemv.m

A = [0.959291425205444,0.257508254123736,0.243524968724989,0.251083857976031;0.547215529963803,0.840717255983663,0.929263623187228,0.616044676146639;0.138624442828679,0.254282178971531,0.349983765984809,0.473288848902729;0.149294005559057,0.814284826068816,0.196595250431208,0.351659507062997]
x = [0.830828627896291;0.585264091152724;0.549723608291140;0.917193663829810]
y = [0.961898080855054;0.00463422413406744;0.774910464711502;0.817303220653433]
2.3 * A * x + 0.5 * y

*/


<|start_filename|>rokko/anasazi/distributed_mfree.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_ANASAZI_DISTRIBUTED_MFREE_HPP
#define ROKKO_ANASAZI_DISTRIBUTED_MFREE_HPP

#include <rokko/distributed_mfree.hpp>
#include <rokko/anasazi/mapping_1d.hpp>

#include <AnasaziEpetraAdapter.hpp>
#include <Epetra_MpiComm.h>
#include <Epetra_Map.h>

namespace rokko {

namespace anasazi {

class anasazi_mfree_operator : public Epetra_Operator {
public:
  anasazi_mfree_operator(rokko::distributed_mfree const& op, mapping_1d const& map) :
    op_(op), ep_map(map.get_epetra_map()), ep_comm(map.get_epetra_comm()) {}
  ~anasazi_mfree_operator() = default;
  virtual int SetUseTranspose(bool UseTranspose) override { return 0; };
  virtual int Apply(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const override {
    const int numvectors = X.NumVectors();
    Y.PutScalar(0);
    for (int i=0; i<numvectors; ++i) {
      const double* x = X[i];
      double* y = Y[i];
      op_.multiply(x, y);
    }
    return 0;
  }
  virtual int ApplyInverse(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const override { return 0; }
  virtual double NormInf() const override { return 0; }
  virtual const char * Label() const override { return "Anasazi matrix_free"; }
  virtual bool UseTranspose() const override { return false; }
  virtual bool HasNormInf() const override { return false; }
  virtual const Epetra_Comm & Comm() const override { return ep_comm; }
  virtual const Epetra_Map & OperatorDomainMap() const override { return ep_map; }
  virtual const Epetra_Map & OperatorRangeMap() const override { return ep_map; }

private:
  const distributed_mfree& op_;
  Epetra_MpiComm ep_comm;
  Epetra_Map ep_map;
};

} // end namespace anasazi

} // end namespace rokko

#endif // ROKKO_ANASAZI_DISTRIBUTED_MFREE_HPP


<|start_filename|>example/fortran/dense/generate_vector/eigen_vector_set_elem.f90<|end_filename|>
!*****************************************************************************
!
! Rokko: Integrated Interface for libraries of eigenvalue decomposition
!
! Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
!
! 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)
!
!*****************************************************************************

program generate_eigen_vector
  use rokko
  implicit none
  integer :: dim
  type(rokko_eigen_vector) :: vec

  integer :: i

  dim = 10
  print *,"dimension = ", dim

  call rokko_construct(vec, dim)

  do i = 1, dim
     call rokko_set_elem(vec, i, dble(i))
  enddo
  call rokko_print(vec)

  call rokko_destruct(vec)

end program generate_eigen_vector


<|start_filename|>rokko/mpi/mpi_type_traits.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2013-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_MPI_TYPE_TRAITS_HPP
#define ROKKO_MPI_TYPE_TRAITS_HPP

#include <mpi.h>

namespace rokko {

namespace detail {

template <typename T>
struct mpi_type_traits {
  static inline MPI_Datatype get_type();
};


#define DEF_MPI_TRAITS(type, mpi_type) \
  template<> \
  inline MPI_Datatype mpi_type_traits<type>::get_type() { \
    return mpi_type; \
  }

DEF_MPI_TRAITS(int,  MPI_INT);
DEF_MPI_TRAITS(char,  MPI_CHAR);
DEF_MPI_TRAITS(float,  MPI_FLOAT);
DEF_MPI_TRAITS(double,  MPI_DOUBLE);
DEF_MPI_TRAITS(long int,  MPI_LONG_INT);
DEF_MPI_TRAITS(long double,  MPI_LONG_DOUBLE);

#undef DEF_MPI_TRAITS

} // end namespace detail

template <typename T>
static const auto mpi_type = detail::mpi_type_traits<T>::get_type();

} // namespace rokko

#endif // ROKKO_MPI_TYPE_TRAITS_HPP


<|start_filename|>rokko/scalapack/pdelset.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <rokko/scalapack/scalapack_interface.h>

void cscalapack_pdelset(double* A, int ia, int ja, const int* descA, double alpha) {
  int ia_f = ia + 1;
  int ja_f = ja + 1;
  SCALAPACK_pdelset(A, &ia_f, &ja_f, descA, &alpha);
}


<|start_filename|>rokko/mapping_bc.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_MAPPING_BC_HPP
#define ROKKO_MAPPING_BC_HPP

#include <array>
#include <rokko/grid.hpp>
#include <rokko/matrix_major.hpp>
#include <rokko/mapping_global2local.hpp>
#include <rokko/mapping_local2array.hpp>
#include <rokko/scalapack.hpp>

namespace rokko {

template <typename MATRIX_MAJOR>
class mapping_bc : public mapping_global2local, public mapping_local2array<MATRIX_MAJOR> {
public:
  using matrix_major = MATRIX_MAJOR;
  explicit mapping_bc() = default;
  explicit mapping_bc(int global_dim, int block_size)
    : mapping_global2local(global_dim, block_size, grid()),
      mapping_local2array<MATRIX_MAJOR>() {
    set_blacs_descriptor();
  }
  // default_mapping func of solver interface for elpa, elemental, scalapack
  explicit mapping_bc(int global_dim, int block_size, MATRIX_MAJOR matrix_major, grid const& g_in)
    : mapping_global2local(global_dim, block_size, g_in),
      mapping_local2array<MATRIX_MAJOR>() {
    set_blacs_descriptor();
  }
  
  // default_mapping func of solver interface for eigen_exa
  explicit mapping_bc(int global_dim, int block_size, std::array<int,2> const& padded_size,
                      grid const& g_in)
    : mapping_global2local(global_dim, block_size, g_in),
      mapping_local2array<MATRIX_MAJOR>(padded_size) {
    set_blacs_descriptor();
  }
  
  explicit mapping_bc(int global_dim, int block_size, int lld, grid const& g_in)
    : mapping_global2local(global_dim, block_size, g_in),
      mapping_local2array<MATRIX_MAJOR>(lld) {
    set_blacs_descriptor();
  }
  
  explicit mapping_bc(int global_dim, int block_size, grid const& g_in)
    : mapping_global2local(global_dim, block_size, g_in),
      mapping_local2array<MATRIX_MAJOR>() {
    set_blacs_descriptor();
  }
  
  explicit mapping_bc(std::array<int,2> const& global_size_in, std::array<int,2> const& block_size_in, grid const& g_in)
    : mapping_global2local(global_size_in, block_size_in, g_in),
      mapping_local2array<MATRIX_MAJOR>() {
    set_blacs_descriptor();
  }

  void set_blacs_descriptor() {
    int m = mapping_global2local::get_m_global();
    int n = mapping_global2local::get_n_global();
    int mb = mapping_global2local::get_mb();
    int nb = mapping_global2local::get_nb();
    int blacs_context = mapping_global2local::get_grid().get_blacs_context();
    int lld = mapping_local2array<matrix_major>::get_lld();
    if (lld == 0)  lld = 1;  // to avoid segmentation fault in descinit
    int info = scalapack::descinit(blacs_descriptor, m, n, mb, nb, 0, 0, blacs_context, lld);
    if (info) {
      throw std::invalid_argument("scalapack::descinit : info=" + std::to_string(info));
    }
  }
  const std::array<int,9>& get_blacs_descriptor() const { return blacs_descriptor; }

private:
  std::array<int,9> blacs_descriptor;
};

} // namespace rokko

#endif // ROKKO_MAPPING_BC_HPP


<|start_filename|>rokko/lapack/hteqr.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_HTEQR_HPP
#define ROKKO_LAPACK_HTEQR_HPP

#include <complex>
#include <lapacke.h>
#undef I
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>
#include "complex_cast.hpp"
#include <rokko/lapack/storage.hpp>
#include <rokko/alias_template_function.hpp>

namespace rokko {
namespace lapack {

namespace {

template<typename T> struct hteqr_dispatch;

template<>
struct hteqr_dispatch<float> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int hteqr(int matrix_layout, char compz, lapack_int n,
                          VECTOR& d, VECTOR& e, MATRIX& z) {
    return LAPACKE_ssteqr(matrix_layout, compz, n, storage(d), storage(e), storage(z), ld(z));
  }
};

template<>
struct hteqr_dispatch<double> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int hteqr(int matrix_layout, char compz, lapack_int n,
                          VECTOR& d, VECTOR& e, MATRIX& z) {
    return LAPACKE_dsteqr(matrix_layout, compz, n, storage(d), storage(e), storage(z), ld(z));
  }
};

template<>
struct hteqr_dispatch<std::complex<float>> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int hteqr(int matrix_layout, char compz, lapack_int n,
                          VECTOR& d, VECTOR& e, MATRIX& z) {
    return LAPACKE_csteqr(matrix_layout, compz, n, storage(d), storage(e), complex_cast(storage(z)), ld(z));
  }
};

template<>
struct hteqr_dispatch<std::complex<double>> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int hteqr(int matrix_layout, char compz, lapack_int n,
                          VECTOR& d, VECTOR& e, MATRIX& z) {
    return LAPACKE_zsteqr(matrix_layout, compz, n, storage(d), storage(e), complex_cast(storage(z)), ld(z));
  }
};

} // end of anonymous namespace

template<typename MATRIX, typename VECTOR>
lapack_int hteqr(char compz, VECTOR& d, VECTOR& e, MATRIX& z) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR>>::value, "");
  lapack_int n = size(d);
  if (rows(z) != cols(z))
    throw std::invalid_argument("matrix Z size mismatch");
  if (size(d) != n)
    throw std::invalid_argument("vector d size mismatch");
  if (size(e) != (n-1))
    throw std::invalid_argument("vector e size mismatch");
  return hteqr_dispatch<value_t<MATRIX>>::
    hteqr((is_col_major(z) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR), compz, n, d, e, z);
}

// eigenvalues & eigenvectors (without compz)
template<typename MATRIX, typename VECTOR>
lapack_int hteqr(VECTOR& d, VECTOR& e, MATRIX& z) {
  return hteqr('I', d, e, z);
}

// only eigenvalues (without compz)
template<typename VECTOR>
lapack_int hteqr(VECTOR& d, VECTOR& e) {
  lapack_int n = size(d);

  using T = value_t<VECTOR>;
  constexpr null_matrix<T> z_null;

  return hteqr_dispatch<value_t<VECTOR>>::
    hteqr(LAPACK_COL_MAJOR, 'N', n, d, e, z_null);
}

ALIAS_TEMPLATE_FUNCTION(steqr, hteqr);

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_HTEQR_HPP


<|start_filename|>test/grid/grid_matrix_default_shape_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/grid.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/traits/grid2matrix_major.hpp>
#include <rokko/utility/matrix012.hpp>

#include <gtest/gtest.h>


template<typename GRID_MAJOR>
void run_test(GRID_MAJOR) {
  rokko::grid g(MPI_COMM_WORLD, GRID_MAJOR{});
  ASSERT_TRUE(g.get_comm() == MPI_COMM_WORLD);
  ASSERT_EQ(g.get_nprow() * g.get_npcol(), g.get_nprocs());

  Eigen::Matrix<int, Eigen::Dynamic,Eigen::Dynamic,rokko::eigen3_major<GRID_MAJOR>> mat(g.get_nprow(), g.get_npcol());
  rokko::matrix012::generate(mat);
  ASSERT_EQ(mat(g.get_myrow(), g.get_mycol()), g.get_myrank());
}

TEST(grid_matrix, default_shape) {
  // default shape: square or nearly square
  run_test(rokko::grid_row_major);
  run_test(rokko::grid_col_major);
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  MPI_Init(&argc, &argv);
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>config/FindPETSc.cmake<|end_filename|>
# - Try to find PETSc
# Once done this will define
#
#  PETSC_FOUND        - system has PETSc
#  PETSC_INCLUDE_DIR  - the PETSc include directory
#  PETSC_LIBRARIES    - Link these to use PETSc
#  PETSC_DEFINITIONS  - Compiler switches for using PETSc
#  PETSC_DIR          - directory where PETSc is installed

if(DEFINED PETSC_FOUND)
  return()
endif(DEFINED PETSC_FOUND)
  
message(STATUS "Checking for PETSc library")
set(PETSC_FOUND FALSE)

# Standard search path
set(_PATHS "")
if(PETSC_DIR)
  set(_PATHS ${PETSC_DIR})
else(PETSC_DIR)
  list(APPEND _PATHS
  	      ${PETSC_ROOT}/${CMAKE_BUILD_TYPE}
	      ${PETSC_ROOT}
  	      $ENV{PETSC_ROOT}/${CMAKE_BUILD_TYPE}
	      $ENV{PETSC_ROOT}
  	      ${ROKKO_SOLVER_ROOT}/petsc/${CMAKE_BUILD_TYPE}
	      ${ROKKO_SOLVER_ROOT}/petsc
  	      $ENV{ROKKO_SOLVER_ROOT}/petsc/${CMAKE_BUILD_TYPE}
	      $ENV{ROKKO_SOLVER_ROOT}/petsc
	      ${CMAKE_INSTALL_PREFIX}/petsc/${CMAKE_BUILD_TYPE}
	      ${CMAKE_INSTALL_PREFIX}/${CMAKE_BUILD_TYPE}
	      $ENV{HOME}/rokko/petsc/${CMAKE_BUILD_TYPE}
	      $ENV{HOME}/rokko/petsc
	      /opt/rokko/petsc/${CMAKE_BUILD_TYPE}
	      /opt/rokko/petsc
	      /opt/rokko/${CMAKE_BUILD_TYPE}
	      /opt/rokko
	      /opt/local /opt
              /usr
	      )
  # Standard paths for Debian with version number
  file(GLOB tmp "/usr/lib/petscdir/*")
  list(APPEND _PATHS ${tmp})
  unset(tmp)
endif(PETSC_DIR)

find_path(PETSC_DIR NAMES include/petscversion.h PATHS ${_PATHS} DOC "PETSc directory")
if(PETSC_DIR)
  set(PETSC_INCLUDE_DIR "${PETSC_DIR}/include")
else(PETSC_DIR)
  find_path(PETSC_DIR NAMES include/petsc/petscversion.h PATHS ${_PATHS} DOC "PETSc directory")
  if(PETSC_DIR)
    set(PETSC_INCLUDE_DIR "${PETSC_DIR}/include/petsc")
  else(PETSC_DIR)
    message(STATUS "PETSc library: include file not found")
    set(PETSC_FOUND FALSE)
    return()
  endif(PETSC_DIR)
endif(PETSC_DIR)
message(STATUS "PETSc include directory: ${PETSC_INCLUDE_DIR}")

find_library(_PETSC_LIBRARY
  NAMES petsc
  PATHS ${PETSC_DIR}/lib
  DOC "The PETSC library")
if(_PETSC_LIBRARY)
  list(APPEND PETSC_LIBRARIES ${_PETSC_LIBRARY})
else(_PETSC_LIBRARY)
  message(STATUS "PETSc library: library file not found")
  set(PETSC_FOUND FALSE)
  return()
endif(_PETSC_LIBRARY)

set(PETSC_DEFINITIONS "-D__INSDIR__=" CACHE STRING "PETSc definitions" FORCE)

set(PETSC_FOUND TRUE)
message(STATUS "PETSc libraries: ${PETSC_LIBRARIES}")
message(STATUS "PETSc definitions: ${PETSC_DEFINITIONS}")


<|start_filename|>rokko/utility/pyrokko_sort_eigenpairs.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_UTILITY_SORT_EIGENPAIRS_HPP
#define PYROKKO_UTILITY_SORT_EIGENPAIRS_HPP

#include <rokko/eigen3.hpp>

#include <rokko/utility/sort_eigenpairs.hpp>

namespace rokko {

template <int MAJOR>
void pyrokko_sort_eigenpairs(Eigen::Ref<Eigen::VectorXd> eigval_in,
                             Eigen::Ref<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,MAJOR>> eigvec_in,
                             Eigen::Ref<Eigen::VectorXd> eigval_sorted_in,
                             Eigen::Ref<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,MAJOR>> eigvec_sorted_in,
                             bool ascending = true) {
  Eigen::VectorXd eigval, eigval_sorted;
  Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,MAJOR> eigvec(eigvec_in.rows(),eigvec_in.cols()), eigvec_sorted(eigvec_in.rows(),eigvec_in.cols());

  new (&eigval) Eigen::Ref<Eigen::VectorXd>(eigval_in);
  new (&eigvec) Eigen::Ref<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,MAJOR>>(eigvec_in);
  new (&eigval_sorted) Eigen::Ref<Eigen::VectorXd>(eigval_sorted_in);
  new (&eigvec_sorted) Eigen::Ref<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,MAJOR>>(eigvec_sorted_in);

  sort_eigenpairs(eigval, eigvec, eigval_sorted, eigvec_sorted, ascending);

  new (&eigval) Eigen::VectorXd();
  new (&eigvec) Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,MAJOR>();
  new (&eigval_sorted) Eigen::VectorXd();
  new (&eigvec_sorted) Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,MAJOR>();
}

} // namespace rokko

#endif // PYROKKO_UTILITY_SORT_EIGENPAIRS_HPP


<|start_filename|>rokko/utility/laplacian_matrix.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2016 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_LAPLACIAN_MATRIX_H
#define ROKKO_UTILITY_LAPLACIAN_MATRIX_H

#include <math.h>

// calculate k-th smallest eigenvalue of dim-dimensional Laplacian matrix (k=0...dim-1)
double rokko_laplacian_matrix_eigenvalue(int dim, int k) {
  return 2 * (1 - cos(M_PI * (2 * k + 1) / (2 * dim + 1)));
}

#endif // ROKKO_UTILITY_LAPLACIAN_MATRIX_H


<|start_filename|>rokko/mapping_1d.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_MAPPING_1D_H
#define ROKKO_MAPPING_1D_H

#include <mpi.h>

#ifdef __cplusplus
extern "C" {
#endif

struct rokko_mapping_1d {
  void* ptr;
};

void rokko_mapping_1d_construct(struct rokko_mapping_1d* map, int dim, MPI_Comm comm);
void rokko_mapping_1d_construct_f(struct rokko_mapping_1d* map, int dim, int comm_f);
void rokko_mapping_1d_destruct(struct rokko_mapping_1d* map);
int rokko_mapping_1d_get_dim(struct rokko_mapping_1d map);
int rokko_mapping_1d_num_local_rows(struct rokko_mapping_1d map);
int rokko_mapping_1d_start_row(struct rokko_mapping_1d map);
int rokko_mapping_1d_end_row(struct rokko_mapping_1d map);
MPI_Comm rokko_mapping_1d_get_comm(struct rokko_mapping_1d map);

MPI_Fint rokko_mapping_1d_get_comm_f(struct rokko_mapping_1d map);

#ifdef __cplusplus
}
#endif

#endif /* ROKKO_MAPPING_1D_H */


<|start_filename|>rokko/elpa/diagonalize_set_parameters.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_ELPA_DIAGONALIZE_SET_PARAMETERS_HPP
#define ROKKO_ELPA_DIAGONALIZE_SET_PARAMETERS_HPP

#include <rokko/distributed_matrix.hpp>
#include <rokko/parameters.hpp>
#include <rokko/elpa.hpp>
#include <rokko/elpa/diagonalize_get_parameters.hpp>

namespace rokko {
namespace elpa {

void set_solver(parameters const& params, elpa_t handle) {
  assert_elpa_ok( set(handle, "solver", get_solver(params)) );
  if (get_solver(params) == ELPA_SOLVER_2STAGE)
    assert_elpa_ok( set(handle, "real_kernel", get_kernel(params)) );
}

template<typename T, typename MATRIX_MAJOR>
void set_parameters(distributed_matrix<T, MATRIX_MAJOR> const& mat, parameters const& params, elpa_t handle) {
  assert_elpa_ok( set(handle, "na", mat.get_m_global()) );
  int nev = mat.get_m_global();
  get_nev(params, nev);
  assert_elpa_ok( set(handle, "nev", nev) );

  assert_elpa_ok( set(handle, "local_nrows", mat.get_m_local()) );
  assert_elpa_ok( set(handle, "local_ncols", mat.get_n_local()) );

  assert_elpa_ok( set(handle, "nblk", mat.get_mb()) );

  MPI_Comm comm = mat.get_grid().get_comm();
  assert_elpa_ok( set(handle, "mpi_comm_parent", MPI_Comm_c2f(comm)) );

  int my_prow = mat.get_grid().get_myrow();
  int my_pcol = mat.get_grid().get_mycol();
  MPI_Comm mpi_comm_rows, mpi_comm_cols;
  MPI_Comm_split(comm, my_pcol, my_prow, &mpi_comm_rows);  // color = my_pcol, key = my_prow
  MPI_Comm_split(comm, my_prow, my_pcol, &mpi_comm_cols);  // color = my_prow, key = my_pcol
  assert_elpa_ok( set(handle, "mpi_comm_rows", MPI_Comm_c2f(mpi_comm_rows)) );
  assert_elpa_ok( set(handle, "mpi_comm_cols", MPI_Comm_c2f(mpi_comm_cols)) );

  // For 2STAGE only
  assert_elpa_ok( set(handle, "qr", get_blocked_qr(params)) );
}

} // namespace elpa
} // namespace rokko

#endif // ROKKO_ELPA_DIAGONALIZE_SET_PARAMETERS_HPP


<|start_filename|>example/cxx/sparse/heisenberg_ladder_mfree_matrix_market.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/heisenberg_hamiltonian_mfree.hpp>
#include <rokko/utility/lattice.hpp>
#include <rokko/utility/math.hpp>
#include <rokko/distributed_mfree_to_crs.hpp>

int main(int argc, char *argv[]) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  int rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  
  std::string library(rokko::parallel_sparse_ev::default_solver());
  if (argc >= 2) library = argv[1];
  
  int len_ladder = (argc >= 3) ? std::stoi(argv[2]) : 5;
  int L = 2 * len_ladder;
  int dim = 1 << L;
  std::vector<std::pair<int, int>> lattice;
  rokko::create_ladder_lattice_1dim(len_ladder, lattice);

  rokko::parallel_sparse_ev solver(library);
  rokko::heisenberg_mfree op(L, lattice);
  auto map = solver.default_mapping(dim, rokko::mpi_comm{MPI_COMM_WORLD});
  const int num_entries_per_row = lattice.size() + 1;
  rokko::distributed_crs_matrix mat(map, num_entries_per_row);
  rokko::distributed_mfree_to_crs(op, mat);
  mat.output_matrix_market();
  //mat.print();
  
  solver.finalize();
  MPI_Finalize();
}


<|start_filename|>rokko/blacs_grid.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_BLACS_GRID_HPP
#define ROKKO_BLACS_GRID_HPP

#include <mpi.h>
#include <array>
#include <rokko/blacs.hpp>

namespace rokko {

class blacs_grid {
public:
  blacs_grid() = default;

  void set_blacs_grid(MPI_Comm comm, bool is_row, std::array<int,2> const& grid_size) {
    blacs_context = blacs::sys2blacs_handle(comm);
    char char_grid_major = is_row ? 'R' : 'C';
    blacs::gridinit(blacs_context, char_grid_major, grid_size[0], grid_size[1]);
  }

  int get_blacs_context() const { return blacs_context; }

private:
  int blacs_context;
};

} // namespace rokko

#endif // ROKKO_BLACS_GRID_HPP


<|start_filename|>example/blas/dgemm.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <stdio.h>
#include <cblas.h>
#include <rokko/cmatrix.h>

int main() {
  int n = 4;
  double** a = alloc_dmatrix(n, n);
  mat_elem(a, 0, 0) = 0.959291425205444;
  mat_elem(a, 0, 1) = 0.257508254123736;
  mat_elem(a, 0, 2) = 0.243524968724989;
  mat_elem(a, 0, 3) = 0.251083857976031;
  mat_elem(a, 1, 0) = 0.547215529963803;
  mat_elem(a, 1, 1) = 0.840717255983663;
  mat_elem(a, 1, 2) = 0.929263623187228;
  mat_elem(a, 1, 3) = 0.616044676146639;
  mat_elem(a, 2, 0) = 0.138624442828679;
  mat_elem(a, 2, 1) = 0.254282178971531;
  mat_elem(a, 2, 2) = 0.349983765984809;
  mat_elem(a, 2, 3) = 0.473288848902729;
  mat_elem(a, 3, 0) = 0.149294005559057;
  mat_elem(a, 3, 1) = 0.814284826068816;
  mat_elem(a, 3, 2) = 0.196595250431208;
  mat_elem(a, 3, 3) = 0.351659507062997;
  double** b = alloc_dmatrix(n, n);
  mat_elem(b, 0, 0) = 0.567821640725221;
  mat_elem(b, 0, 1) = 0.779167230102011;
  mat_elem(b, 0, 2) = 0.469390641058206;
  mat_elem(b, 0, 3) = 0.794284540683907;
  mat_elem(b, 1, 0) = 0.0758542895630636;
  mat_elem(b, 1, 1) = 0.934010684229183;
  mat_elem(b, 1, 2) = 0.0119020695012414;
  mat_elem(b, 1, 3) = 0.311215042044805;
  mat_elem(b, 2, 0) = 0.0539501186666072;
  mat_elem(b, 2, 1) = 0.129906208473730;
  mat_elem(b, 2, 2) = 0.337122644398882;
  mat_elem(b, 2, 3) = 0.528533135506213;
  mat_elem(b, 3, 0) = 0.530797553008973;
  mat_elem(b, 3, 1) = 0.568823660872193;
  mat_elem(b, 3, 2) = 0.162182308193243;
  mat_elem(b, 3, 3) = 0.165648729499781;
  double** c = alloc_dmatrix(n, n);
  mat_elem(c, 0, 0) = 0.601981941401637;
  mat_elem(c, 0, 1) = 0.748151592823710;
  mat_elem(c, 0, 2) = 0.913337361501670;
  mat_elem(c, 0, 3) = 0.996134716626886;
  mat_elem(c, 1, 0) = 0.262971284540144;
  mat_elem(c, 1, 1) = 0.450541598502498;
  mat_elem(c, 1, 2) = 0.152378018969223;
  mat_elem(c, 1, 3) = 0.0781755287531837;
  mat_elem(c, 2, 0) = 0.654079098476782;
  mat_elem(c, 2, 1) = 0.0838213779969326;
  mat_elem(c, 2, 2) = 0.825816977489547;
  mat_elem(c, 2, 3) = 0.442678269775446;
  mat_elem(c, 3, 0) = 0.689214503140008;
  mat_elem(c, 3, 1) = 0.228976968716819;
  mat_elem(c, 3, 2) = 0.538342435260057;
  mat_elem(c, 3, 3) = 0.106652770180584;
  double alpha = 2.1;
  double beta = 0.8;

  printf("a: "); fprint_dmatrix(stdout, n, n, a);
  printf("b: "); fprint_dmatrix(stdout, n, n, b);
  printf("c: "); fprint_dmatrix(stdout, n, n, c);
  
  cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, n, n, n, alpha, mat_ptr(a),
              n, mat_ptr(b), n, beta, mat_ptr(c), n);

  printf("%10.5f * a * b + %10.5f * c: ", alpha, beta); fprint_dmatrix(stdout, n, n, c);

  free_dmatrix(a);
  free_dmatrix(b);
  free_dmatrix(c);
}

/* gemm.m

A = [0.959291425205444,0.257508254123736,0.243524968724989,0.251083857976031;0.547215529963803,0.840717255983663,0.929263623187228,0.616044676146639;0.138624442828679,0.254282178971531,0.349983765984809,0.473288848902729;0.149294005559057,0.814284826068816,0.196595250431208,0.351659507062997]
B = [0.567821640725221,0.779167230102011,0.469390641058206,0.794284540683907;0.0758542895630636,0.934010684229183,0.0119020695012414,0.311215042044805;0.0539501186666072,0.129906208473730,0.337122644398882,0.528533135506213;0.530797553008973,0.568823660872193,0.162182308193243,0.165648729499781]
C = [0.601981941401637,0.748151592823710,0.913337361501670,0.996134716626886;0.262971284540144,0.450541598502498,0.152378018969223,0.0781755287531837;0.654079098476782,0.0838213779969326,0.825816977489547,0.442678269775446;0.689214503140008,0.228976968716819,0.538342435260057,0.106652770180584]
2.1 * A * B + 0.8 * C

*/


<|start_filename|>rokko/gev_fixedB_mpi_c.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <mpi.h>
#include <rokko/rokko.h>
#include <rokko/utility/frank_matrix.h>
#include <stdio.h>
#include <stdlib.h>

using matrix_major = rokko::matrix_col_major;

void diagonalize_fixedB(struct rokko_parallel_dense_ev* solver_in, struct rokko_distributed_matrix* A_in, struct rokko_distributed_matrix* B, struct rokko_eigen_vector* eigval_in, struct rokko_distributed_matrix* eigvec_in, double tol) {
  rokko::mapping_bc<matrix_major> map = A->ptr->get_mapping();
  rokko::distributed_matrix<double, matrix_major> tmp(map), Binvroot(map), mat(map);
  rokko::parameters params = *(params->ptr);
  int myrank = A.get_myrank();
  params.set(params, "routine", "");
  solver.diagonalize(B, eigval, eigvec, params);
  // computation of B^{-1/2}
  for(int i=0; i<eigval.size(); ++i)
    eigval(i) = (eigval(i) > tol) ? sqrt(1/eigval(i)) : 0;
  function_matrix(eigval, eigvec, Binvroot, tmp);
  
  // computation of B^{-1/2} A B^{-1/2}
  product(1, Binvroot, false, A, false, 0, tmp);
  product(1, tmp, false, Binvroot, false, 0, mat);
  // diagonalization of B^{-1/2} A B^{-1/2}
  solver.diagonalize(mat, eigval, tmp, params);

  // computation of {eigvec of Ax=lambda Bx} = B^{-1/2} {eigvec of B^{-1/2} A B^{-1/2}}
  product(1, Binvroot, false, tmp, false, 0, eigvec);
}



<|start_filename|>example/cxx/dense/helmert.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/helmert_matrix.hpp>
#include <iostream>


int main(int argc, char *argv[]) {
  std::string solver_name(rokko::serial_dense_ev::default_solver());
  unsigned int dim = 10;
  if (argc >= 2) solver_name = argv[1];
  if (argc >= 3) dim = std::stoi(argv[2]);

  std::cout.precision(5);

  rokko::serial_dense_ev solver(solver_name);
  solver.initialize(argc, argv);
  std::cout << "Eigenvalue decomposition of Helmert matrix" << std::endl
            << "solver = " << solver_name << std::endl
            << "dimension = " << dim << std::endl;

  Eigen::MatrixXd mat(dim, dim);
  Eigen::VectorXd diag(dim);
  diag.setLinSpaced(diag.size(), 1, diag.size()); // diag = [1, 2, 3, ..., dim]
  rokko::helmert_matrix::generate_for_given_eigenvalues(mat, diag);
  std::cout << "matrix whose eigenvectors are Helmert matrix:\n" << mat << std::endl;

  Eigen::VectorXd eigval(dim);
  Eigen::MatrixXd eigvec(dim, dim);
  solver.diagonalize(mat, eigval, eigvec);
  rokko::helmert_matrix::generate_for_given_eigenvalues(mat, diag);

  bool sorted = true;
  for (unsigned int i = 1; i < dim; ++i) sorted &= (eigval(i-1) <= eigval(i));
  if (!sorted) std::cout << "Warning: eigenvalues are not sorted in ascending order!\n";

  std::cout << "eigenvalues:\n" << eigval.transpose() << std::endl
            << "eigvectors:\n" << eigvec << std::endl;
  std::cout << "orthogonality of eigenvectors:" << std::endl
            << eigvec.transpose() * eigvec << std::endl;
  std::cout << "residual of the smallest eigenvalue/vector (A x - lambda x):" << std::endl
            << (mat * eigvec.col(0) - eigval(0) * eigvec.col(0)).transpose() << std::endl;

  solver.finalize();
}


<|start_filename|>rokko/pyrokko_parameters.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_PARAMETERS_HPP
#define PYROKKO_PARAMETERS_HPP

#include <rokko/parameters.hpp>

namespace rokko {

namespace py = pybind11;

class wrap_parameters : public rokko::parameters {
public:
  wrap_parameters() = default;
  wrap_parameters(rokko::parameters const& params_in) : parameters(params_in) {}
  py::object python_get(std::string const& key) const {
    if (type(key) == typeid(int)) {
      return py::cast(get<int>(key));
    } else if (type(key) == typeid(double)) {
      return py::cast(get<double>(key));
    } else if (type(key) == typeid(std::string)) {
      return py::cast(get<std::string>(key));
    } else if (type(key) == typeid(bool)) {
      return py::cast(get<bool>(key));
    } else if (type(key) == typeid(char)) {
      return py::cast(get<char>(key));
    }
    throw std::invalid_argument("wrap_parameters::python_get() : value type given as template parameter must be char*, string, int, or double.");
  }
  py::list python_keys() const {
    py::list py_list;
    for(auto const& p : get_map()) {
      py_list.append(p.first);
    }
    return py_list;
  }
  py::dict dict() const {
    py::dict dict;
    for(auto const& p : get_map()) {
      dict[p.first.c_str()] = python_get(p.first);
    }
    return dict;
  }
};

} // end namespace rokko

#endif // PYROKKO_PARAMETERS_HPP


<|start_filename|>rokko/distributed_mfree_c.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/distributed_mfree.h>
#include <rokko/distributed_mfree.hpp>

void rokko_distributed_mfree_construct(struct rokko_distributed_mfree* matrix,
				       void (*multiply)(const double *const, double *const, void*),
				       void* vars,
				       int dim, MPI_Comm comm = MPI_COMM_WORLD) {
  matrix->ptr = new rokko::distributed_mfree_holder(multiply, vars, rokko::skel::mapping_1d{dim, rokko::mpi_comm{comm}});
}

void rokko_distributed_mfree_construct_no_context(struct rokko_distributed_mfree* matrix,
				       void (*multiply)(const double *const, double *const),
				       int dim, MPI_Comm comm = MPI_COMM_WORLD) {
  matrix->ptr = new rokko::distributed_mfree_holder(multiply, rokko::skel::mapping_1d{dim, rokko::mpi_comm{comm}});
}

void rokko_distributed_mfree_destruct(struct rokko_distributed_mfree* matrix) {
  delete static_cast<rokko::distributed_mfree_holder*>(matrix->ptr);
  matrix->ptr = nullptr;
}

int rokko_distributed_mfree_dim(struct rokko_distributed_mfree matrix) {
  return static_cast<rokko::distributed_mfree_holder*>(matrix.ptr)->get_dim();
}

int rokko_distributed_mfree_num_local_rows(struct rokko_distributed_mfree matrix) {
  return static_cast<rokko::distributed_mfree_holder*>(matrix.ptr)->get_num_local_rows();
}

int rokko_distributed_mfree_start_row(struct rokko_distributed_mfree matrix) {
  return static_cast<rokko::distributed_mfree_holder*>(matrix.ptr)->start_row();
}

int rokko_distributed_mfree_end_row(struct rokko_distributed_mfree matrix) {
  return static_cast<rokko::distributed_mfree_holder*>(matrix.ptr)->end_row();
}

int rokko_distributed_mfree_offset(struct rokko_distributed_mfree matrix) {
  return static_cast<rokko::distributed_mfree_holder*>(matrix.ptr)->get_local_offset();
}


<|start_filename|>rokko/eigenexa/eigen_get_procs.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/ceigenexa.h>
#include <rokko/eigenexa/eigenexa_interface.h>

void ceigenexa_get_procs(int* procs, int* x_procs, int* y_procs) {
  EIGENEXA_get_procs_wrap(procs, x_procs, y_procs);
}


<|start_filename|>rokko/elpa/elpa.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2016 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/parallel_dense_ev.hpp>
#include <rokko/elpa/solver.hpp>

ROKKO_REGISTER_PARALLEL_DENSE_SOLVER(rokko::elpa::solver, "elpa", 30)


<|start_filename|>test/mpi_unit_test/mpi_thread_multiple.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <mpi.h>
#include <iostream>

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

TEST(mpi, mpi_thread_multiple) {
  const int required = MPI_THREAD_MULTIPLE;
  int provided;
  MPI_Init_thread(&global_argc, &global_argv, required, &provided);
  if (provided == required) {
     std::cerr << "MPI_THREAD_MULTIPLE is supported\n";
   } else {
     std::cerr << "MPI_THREAD_MULTIPLE is NOT supported\n";
   }
  MPI_Finalize();
}

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  global_argc = argc;
  global_argv = argv;
  return RUN_ALL_TESTS();
}


<|start_filename|>config/check_ggsvp.f90<|end_filename|>
program main
  call sggsvp()
  call dggsvp()
  call cggsvp()
  call zggsvp()
end program



<|start_filename|>rokko/lapack/diagonalize_bisection.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_DIAGONALIZE_BISECTION_HPP
#define ROKKO_LAPACK_DIAGONALIZE_BISECTION_HPP

#include <rokko/parameters.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/utility/timer.hpp>
#include <rokko/lapack.hpp>
#include <rokko/lapack/diagonalize_syevx.hpp>

namespace rokko {
namespace lapack {

// bisection (dsyevx) only eigenvalues
template<typename T, int MATRIX_MAJOR, typename VEC>
parameters diagonalize_bisection(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat, VEC& eigvals,
                 rokko::parameters const& params) {
  if (params.defined("abstol")) {
    if (params.get<real_t<T>>("abstol") < 0) {
      std::stringstream msg;
      msg << "lapack::diagonalize_bisection() : " << std::endl
          << "abstol is negative value, which means QR method." << std::endl
          << "To use dsyevx as bisection solver, set abstol a positive value" << std::endl;
      throw std::invalid_argument(msg.str());
    }
  }

  parameters params_out = diagonalize_syevx(mat, eigvals, params);

  if (params.get_bool("verbose")) {
    std::cout << "finished dsyevx (bisection)" << std::endl;
  }

  return params_out;
}


// bisection (dsyevx) eigenvalues / eigenvectors
template<typename T, int MATRIX_MAJOR, typename VEC>
parameters diagonalize_bisection(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat, VEC& eigvals,
				 Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& eigvecs,
                 rokko::parameters const& params) {
  if (params.defined("abstol")) {
    if (params.get<real_t<T>>("abstol") < 0) {
      std::stringstream msg;
      msg << "lapack::diagonalize_bisection() : " << std::endl
          << "abstol is negative value, which means QR method." << std::endl
          << "To use dsyevx as bisection solver, set abstol a positive value" << std::endl;
      throw std::invalid_argument(msg.str());
    }
  }

  parameters params_out = diagonalize_syevx(mat, eigvals, eigvecs, params);

  if (params.get_bool("verbose")) {
    std::cout << "finished dsyevx (bisection)" << std::endl;
  }

  return params_out;
}


} // namespace lapack
} // namespace rokko

#endif // ROKKO_LAPACK_DIAGONALIZE_BISECTION_HPP


<|start_filename|>test/mpi_collective/scatter.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/solver.hpp>
#include <rokko/collective.hpp>

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

template<typename GRID_MAJOR, typename DIST_MAT_MAJOR, typename LOC_MAT_MAJOR>
void run_test(MPI_Comm comm, int dim, GRID_MAJOR const& grid_major, DIST_MAT_MAJOR const&, LOC_MAT_MAJOR const&) {
  int size, rank;
  MPI_Comm_size(comm, &size);
  MPI_Comm_rank(comm, &rank);

  Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,rokko::eigen3_major<LOC_MAT_MAJOR>> lmat(dim, dim);
  lmat.setRandom();
#ifndef NDEBUG
  if (rank == 0) std::cout << lmat << std::endl;
#endif
  
  rokko::parallel_dense_ev solver(rokko::parallel_dense_ev::default_solver());
  rokko::grid g(comm, grid_major);
  rokko::mapping_bc<DIST_MAT_MAJOR> map = solver.default_mapping(dim, g);
  for (int r = 0; r < size; ++r) {
    rokko::distributed_matrix<double, DIST_MAT_MAJOR> mat(map);
    rokko::scatter(lmat, mat, r);
#ifndef NDEBUG
    mat.print();
#endif
    for (int i = 0; i < dim; ++i) {
      for (int j = 0; j < dim; ++j) {
        if (mat.has_global_indices({i, j}))
          ASSERT_EQ(mat.get_global(i, j), lmat(i, j));
      }
    }
  }
}

TEST(mpi_communication, scatter) {
  MPI_Comm comm = MPI_COMM_WORLD;
  int rank;
  MPI_Comm_rank(comm, &rank);

  int dim = 100;
  if (global_argc > 1) {
    dim = std::stoi(global_argv[1]);
  }
  if (rank == 0) std::cout << "dimension = " << dim << std::endl;

  if (rank == 0) std::cout << "test for grid = col, dist = col, loc = col\n";
  run_test(comm, dim, rokko::grid_col_major, rokko::matrix_col_major(), rokko::matrix_col_major());

  /*
  if (rank == 0) std::cout << "test for grid = col, dist = col, loc = row\n";
  run_test(comm, dim, rokko::grid_col_major, rokko::matrix_col_major(), rokko::matrix_row_major());

  if (rank == 0) std::cout << "test for grid = col, dist = row, loc = col\n";
  run_test(comm, dim, rokko::grid_col_major, rokko::matrix_row_major(), rokko::matrix_col_major());

  if (rank == 0) std::cout << "test for grid = col, dist = row, loc = row\n";
  run_test(comm, dim, rokko::grid_col_major, rokko::matrix_row_major(), rokko::matrix_row_major());
  */

  if (rank == 0) std::cout << "test for grid = row, dist = col, loc = col\n";
  run_test(comm, dim, rokko::grid_row_major, rokko::matrix_col_major(), rokko::matrix_col_major());

  /*
  if (rank == 0) std::cout << "test for grid = row, dist = col, loc = row\n";
  run_test(comm, dim, rokko::grid_row_major, rokko::matrix_col_major(), rokko::matrix_row_major());

  if (rank == 0) std::cout << "test for grid = row, dist = row, loc = col\n";
  run_test(comm, dim, rokko::grid_row_major, rokko::matrix_row_major(), rokko::matrix_col_major());

  if (rank == 0) std::cout << "test for grid = row, dist = row, loc = row\n";
  run_test(comm, dim, rokko::grid_row_major, rokko::matrix_row_major(), rokko::matrix_row_major());
  */
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  MPI_Init(&argc, &argv);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>example/lapack/dgesvd.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2017 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <cblas.h>
#include <lapacke.h>
#include <rokko/cmatrix.h>

int imin(int x, int y) { return (x < y) ? x : y; }
int imax(int x, int y) { return (x > y) ? x : y; }

int main(int argc, char** argv) {
  int m = 3;
  int n = 5;
  int r, lwork, i, j, info;
  double norm;
  double *s, *work;
  double **a, **u, **vt, **t;

  if (argc > 2) {
    m = atoi(argv[1]);
    n = atoi(argv[2]);
  }
  r = imin(m, n);
  
  /* generate matrix */
  a = alloc_dmatrix(m, n);
  for (j = 0; j < n; ++j) {
    for (i = 0; i < m; ++i) {
      mat_elem(a, i, j) = n - imax(i, j);
    }
  }
  printf("Matrix A: ");
  fprint_dmatrix(stdout, m, n, a);

  /* singular value decomposition */
  u = alloc_dmatrix(m, r);
  vt = alloc_dmatrix(r, n);
  s = alloc_dvector(r);
  t = alloc_dmatrix(m, n);
  cblas_dcopy(m * n, mat_ptr(a), 1, mat_ptr(t), 1);
  lwork = imax(3 * r + imax(m, n), 5 * r);
  work = alloc_dvector(lwork);
  info = LAPACKE_dgesvd_work(LAPACK_COL_MAJOR, 'S', 'S', m, n, mat_ptr(t), m,
                             vec_ptr(s), mat_ptr(u), m, mat_ptr(vt), r,
                             vec_ptr(work), lwork);
  if (info != 0) {
    fprintf(stderr, "Error: dgesvd fails\n");
    exit(255);
  }
  free_dmatrix(t);
  printf("Matrix U: ");
  fprint_dmatrix(stdout, m, r, u);
  printf("Singular values: ");
  fprint_dvector(stdout, r, s);
  printf("Matrix Vt: ");
  fprint_dmatrix(stdout, r, n, vt);

  /* orthogonality check */
  t = alloc_dmatrix(r, r);
  cblas_dgemm(CblasColMajor, CblasTrans, CblasNoTrans, r, r, m, 1, mat_ptr(u), m,
              mat_ptr(u), m, 0, mat_ptr(t), r);
  for (i = 0; i < r; ++i) mat_elem(t, i, i) -= 1;
  norm = LAPACKE_dlange(LAPACK_COL_MAJOR, 'F', r, r, mat_ptr(t), r);
  printf("|| U^t U - I || = %e\n", norm);
  if (norm > 1e-10) {
    fprintf(stderr, "Error: orthogonality check\n");
    exit(255);
  }

  cblas_dgemm(CblasColMajor, CblasNoTrans, CblasTrans, r, r, n, 1, mat_ptr(vt), r,
              mat_ptr(vt), r, 0, mat_ptr(t), r);
  for (i = 0; i < r; ++i) mat_elem(t, i, i) -= 1;
  norm = LAPACKE_dlange(LAPACK_COL_MAJOR, 'F', r, r, mat_ptr(t), r);
  printf("|| V^t V - I || = %e\n", norm);
  if (norm > 1e-10) {
    fprintf(stderr, "Error: orthogonality check\n");
    exit(255);
  }
  free_dmatrix(t);

  /* solution check */
  t = alloc_dmatrix(m, r);
  cblas_dgemm(CblasColMajor, CblasNoTrans, CblasTrans, m, r, n, 1, mat_ptr(a), m,
              mat_ptr(vt), r, 0, mat_ptr(t), m);
  free_dmatrix(vt);
  vt = alloc_dmatrix(r, r);
  cblas_dgemm(CblasColMajor, CblasTrans, CblasNoTrans, r, r, m, 1, mat_ptr(u), m,
              mat_ptr(t), m, 0, mat_ptr(vt), r);
  for (i = 0; i < r; ++i) mat_elem(vt, i, i) -= s[i];
  norm = LAPACKE_dlange(LAPACK_COL_MAJOR, 'F', r, r, mat_ptr(vt), r);
  printf("|| U^t A V - diag(S) || = %e\n", norm);
  if (norm > 1e-10) {
    fprintf(stderr, "Error: solution check\n");
    exit(255);
  }
  free_dmatrix(t);

  free_dmatrix(a);
  free_dmatrix(u);
  free_dmatrix(vt);
  free_dvector(s);
  return 0;
}


<|start_filename|>rokko/utility/string_format.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2010-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTIL_STRING_FORMAT_HPP
#define ROKKO_UTIL_STRING_FORMAT_HPP

#include <cstdio>
#include <string>
#include <vector>

namespace rokko {

template <typename ... Args>
std::string format(const std::string& fmt, Args ... args) {
  size_t len = std::snprintf( nullptr, 0, fmt.c_str(), args ... );
  std::vector<char> buf(len + 1);
  std::snprintf(buf.data(), len + 1, fmt.c_str(), args ... );
  return std::string(buf.data(), buf.data() + len);
}

} // namespace rokko

#endif // ROKKO_UTIL_STRING_FORMAT_HPP


<|start_filename|>config/check_lapacke.c<|end_filename|>
#include <lapacke.h>
int main() { LAPACKE_dlapy2(0, 0); }


<|start_filename|>rokko/mapping_bc.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_MAPPING_BC_H
#define ROKKO_MAPPING_BC_H

#include <rokko/grid.h>
#include <rokko/matrix_major.h>

#ifdef __cplusplus
extern "C" {
#endif

struct rokko_mapping_bc {
  void* ptr;
  int major;
};

void rokko_mapping_bc_construct_block_size(struct rokko_mapping_bc* map, int global_dim, int block_size, struct rokko_grid grid);
void rokko_mapping_bc_destruct(struct rokko_mapping_bc* map);
int rokko_mapping_bc_get_mb(struct rokko_mapping_bc map);
int rokko_mapping_bc_get_nb(struct rokko_mapping_bc map);
int rokko_mapping_bc_get_m_local(struct rokko_mapping_bc map);
int rokko_mapping_bc_get_n_local(struct rokko_mapping_bc map);
int rokko_mapping_bc_get_m_global(struct rokko_mapping_bc map);
int rokko_mapping_bc_get_n_global(struct rokko_mapping_bc map);
int rokko_mapping_bc_get_lld(struct rokko_mapping_bc map);
int rokko_mapping_bc_get_m_size(struct rokko_mapping_bc map);
int rokko_mapping_bc_get_n_size(struct rokko_mapping_bc map);
int rokko_mapping_bc_get_length_array(struct rokko_mapping_bc map);
int rokko_mapping_bc_get_nprocs(struct rokko_mapping_bc map);
int rokko_mapping_bc_get_myrank(struct rokko_mapping_bc map);
int rokko_mapping_bc_get_nprow(struct rokko_mapping_bc map);
int rokko_mapping_bc_get_npcol(struct rokko_mapping_bc map);
int rokko_mapping_bc_get_myrow(struct rokko_mapping_bc map);
int rokko_mapping_bc_get_mycol(struct rokko_mapping_bc map);
int rokko_mapping_bc_translate_l2g_row(struct rokko_mapping_bc map, int local_i);
int rokko_mapping_bc_translate_l2g_col(struct rokko_mapping_bc map, int local_j);
int rokko_mapping_bc_translate_g2l_row(struct rokko_mapping_bc map, int global_i);
int rokko_mapping_bc_translate_g2l_col(struct rokko_mapping_bc map, int global_j);
/* offset by one for Fortran */
int rokko_mapping_bc_translate_l2g_row1(struct rokko_mapping_bc map, int local_i);
int rokko_mapping_bc_translate_l2g_col1(struct rokko_mapping_bc map, int local_j);
int rokko_mapping_bc_translate_g2l_row1(struct rokko_mapping_bc map, int global_i);
int rokko_mapping_bc_translate_g2l_col1(struct rokko_mapping_bc map, int global_j);
bool rokko_mapping_bc_is_row_major(struct rokko_mapping_bc map);
bool rokko_mapping_bc_is_col_major(struct rokko_mapping_bc map);

#ifdef __cplusplus
}
#endif

#endif /* ROKKO_MAPPING_BC_H */


<|start_filename|>rokko/mapping_1d_c.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/mapping_1d.h>
#include <rokko/mpi_communicator.hpp>
#include <rokko/mapping_1d.hpp>

void rokko_mapping_1d_construct(struct rokko_mapping_1d* map, int dim, MPI_Comm comm) {
  map->ptr = new rokko::mapping_1d(dim, rokko::mpi_comm{comm});
}

void rokko_mapping_1d_construct_f(struct rokko_mapping_1d* map, int dim, int comm_f) {
  MPI_Comm comm = MPI_Comm_f2c(comm_f);
  map->ptr = new rokko::mapping_1d(dim, rokko::mpi_comm{comm});
}

void rokko_mapping_1d_destruct(struct rokko_mapping_1d* map) {
  delete static_cast<rokko::mapping_1d*>(map->ptr);
  map->ptr = nullptr;
}

int rokko_mapping_1d_get_dim(struct rokko_mapping_1d map) {
  return static_cast<rokko::mapping_1d*>(map.ptr)->get_dim();
}

int rokko_mapping_1d_num_local_rows(struct rokko_mapping_1d map) {
  return static_cast<rokko::mapping_1d*>(map.ptr)->num_local_rows();
}

int rokko_mapping_1d_start_row(struct rokko_mapping_1d map) {
  return static_cast<rokko::mapping_1d*>(map.ptr)->start_row();
}

int rokko_mapping_1d_end_row(struct rokko_mapping_1d map) {
  return static_cast<rokko::mapping_1d*>(map.ptr)->end_row();
}

MPI_Comm rokko_mapping_1d_get_comm(struct rokko_mapping_1d map) {
  return static_cast<rokko::mapping_1d*>(map.ptr)->get_mpi_comm().get_comm();
}

MPI_Fint rokko_mapping_1d_get_comm_f(struct rokko_mapping_1d map) {
  return MPI_Comm_c2f(rokko_mapping_1d_get_comm(map));
}


<|start_filename|>tool/rokko_solvers.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/solver.hpp>

int main() {
  std::cout << "[serial dense solvers]\n";
  for(auto name : rokko::serial_dense_ev::solvers()) {
    std::cout << "  " << name << std::endl;
  }

#ifdef ROKKO_HAVE_PARALLEL_DENSE_SOLVER
  std::cout << "[parallel dense solvers]\n";
  for(auto name : rokko::parallel_dense_ev::solvers()) {
    std::cout << "  " << name << std::endl;
  }
#endif // ROKKO_HAVE_PARALLEL_DENSE_SOLVER

#ifdef ROKKO_HAVE_PARALLEL_SPARSE_SOLVER
  std::cout << "[parallel sparse solvers]\n";
  for(auto name : rokko::parallel_sparse_ev::solvers()) {
    std::cout << "  " << name << std::endl;
  }
#endif // ROKKO_HAVE_PARALLEL_SPARSE_SOLVER

  return 0;
}


<|start_filename|>example/c/dense/gev_fixedB_mpi.hpp<|end_filename|>
#include <mpi.h>
#include <rokko/rokko.h>
#include <stdio.h>
#include <stdlib.h>

using matrix_major = rokko::matrix_col_major;

template<typename T, typename MATRIX_MAJOR>
void function_matrix(Eigen::VectorXd const& eigval_tmp, rokko::distributed_matrix<T, MATRIX_MAJOR> const& eigvec, rokko::distributed_matrix<T, MATRIX_MAJOR>& result, rokko::distributed_matrix<T, MATRIX_MAJOR>& tmp) {
  for (int local_j=0; local_j<eigvec.get_n_local(); ++local_j) {
    int global_j = eigvec.translate_l2g_col(local_j);
    double coeff = eigval_tmp(global_j);
    for (int local_i=0; local_i<eigvec.get_m_local(); ++local_i) {
      double value = eigvec.get_local(local_i, local_j);
      tmp.set_local(local_i, local_j, coeff * value); 
    }
  }
  product(1, tmp, false, eigvec, true, 0, result);
}

template<typename T, typename MATRIX_MAJOR>
void diagonalize_fixedB(rokko::parallel_dense_ev& solver, rokko::distributed_matrix<T, MATRIX_MAJOR>& A, rokko::distributed_matrix<T, MATRIX_MAJOR>& B, Eigen::VectorXd& eigval, rokko::distributed_matrix<T, MATRIX_MAJOR>& eigvec, T tol = 0) {
  rokko::distributed_matrix<double, matrix_major> tmp(A.get_mapping()), Binvroot(A.get_mapping()), mat(A.get_mapping());
  rokko::parameters params;
  params.set("routine", "");
  solver.diagonalize(B, eigval, eigvec, params);
  // computation of B^{-1/2}
  for(int i=0; i<eigval.size(); ++i)
    eigval(i) = (eigval(i) > tol) ? sqrt(1/eigval(i)) : 0;
  function_matrix(eigval, eigvec, Binvroot, tmp);
  
  // computation of B^{-1/2} A B^{-1/2}
  product(1, Binvroot, false, A, false, 0, tmp);
  product(1, tmp, false, Binvroot, false, 0, mat);
  // diagonalization of B^{-1/2} A B^{-1/2}
  solver.diagonalize(mat, eigval, tmp, params);

  // computation of {eigvec of Ax=lambda Bx} = B^{-1/2} {eigvec of B^{-1/2} A B^{-1/2}}
  product(1, Binvroot, false, tmp, false, 0, eigvec);
}

template<typename T, int MATRIX_MAJOR>
void set_A_B(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& locA, Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& locB) {
  if ((locA.rows() != 4) || (locA.cols() != 4) || (locB.rows() != 4) || (locB.cols() != 4)) {
    std::cerr << "error: size must be 4!" << std::endl;
    throw;
  }
  locA << 0.24, 0.39, 0.42, -0.16,
          0.39, -0.11, 0.79, 0.63,
          0.42, 0.79, -0.25, 0.48,
         -0.16, 0.63, 0.48, -0.03;

  locB << 4.16, -3.12, 0.56, -0.10,
         -3.12, 5.03, -0.83, 1.09,
          0.56, -0.83, 0.76, 0.34,
         -0.10, 1.09, 0.34, 1.18;
}



<|start_filename|>rokko/lapack/heevd.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_HEEVD_HPP
#define ROKKO_LAPACK_HEEVD_HPP

#include <complex>
#include <lapacke.h>
#undef I
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>
#include "complex_cast.hpp"
#include <rokko/lapack/storage.hpp>
#include <rokko/alias_template_function.hpp>

namespace rokko {
namespace lapack {

namespace {

template<typename T> struct heevd_dispatch;

template<>
struct heevd_dispatch<float> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int heevd(int matrix_layout, char jobz, char uplo, lapack_int n,
                         MATRIX& a, VECTOR& w) {
    return LAPACKE_ssyevd(matrix_layout, jobz, uplo, n, storage(a), ld(a), storage(w));
  }
};

template<>
struct heevd_dispatch<double> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int heevd(int matrix_layout, char jobz, char uplo, lapack_int n,
                         MATRIX& a, VECTOR& w) {
    return LAPACKE_dsyevd(matrix_layout, jobz, uplo, n, storage(a), ld(a), storage(w));
  }
};

template<>
struct heevd_dispatch<std::complex<float>> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int heevd(int matrix_layout, char jobz, char uplo, lapack_int n,
                         MATRIX& a, VECTOR& w) {
    return LAPACKE_cheevd(matrix_layout, jobz, uplo, n, complex_cast(storage(a)), ld(a),
                         storage(w));
  }
};

template<>
struct heevd_dispatch<std::complex<double>> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int heevd(int matrix_layout, char jobz, char uplo, lapack_int n,
                         MATRIX& a, VECTOR& w) {
    return LAPACKE_zheevd(matrix_layout, jobz, uplo, n, complex_cast(storage(a)), ld(a),
                         storage(w));
  }
};

} // end of anonymous namespace

template<typename MATRIX, typename VECTOR>
lapack_int heevd(char jobz, char uplo, MATRIX& a, VECTOR& w) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR>>::value, "");
  lapack_int n = rows(a);
  if (rows(a) != cols(a))
    throw std::invalid_argument("matrix A size mismatch");
  //if (size(w) != n)
  //  throw std::invalid_argument("vector w size mismatch");
  return heevd_dispatch<value_t<MATRIX>>::
    heevd((is_col_major(a) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR), jobz, uplo, n, a, w);
}

ALIAS_TEMPLATE_FUNCTION(syevd, heevd);

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_HEEVD_HPP


<|start_filename|>tutorial/Fortran/Rokko.f90<|end_filename|>
!*****************************************************************************
!
! Rokko: Integrated Interface for libraries of eigenvalue decomposition
!
! Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
!
! 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)
!
!*****************************************************************************

program frank_matrix
  use rokko
  use mpi
  implicit none
  integer :: dim
  type(rokko_distributed_matrix) :: mat, Z
  type(rokko_grid) :: grid
  type(rokko_mapping_bc) :: map
  type(rokko_parallel_dense_ev) :: solver
  type(rokko_eigen_vector) :: w
  character(len=:), allocatable :: solver_name, tmp_str
  integer :: provided, ierr, myrank, nprocs
  integer :: i, j
  double precision :: value

  call MPI_init_thread(MPI_THREAD_MULTIPLE, provided, ierr)
  call MPI_comm_rank(MPI_COMM_WORLD, myrank, ierr)
  call MPI_comm_size(MPI_COMM_WORLD, nprocs, ierr)

  if (command_argument_count().eq.1) then
     call get_command_argument_deferred(1, tmp_str)
     solver_name = trim(tmp_str)
     !call get_command_argument_deferred(2, tmp_str)
     !read(tmp_str, *) dim
     dim = 4
  else
     write(*,'(A)') "Error: Rokko solver_name"
     stop
  endif

  write(*,*) "solver name = ", trim(solver_name)
  write(*,*) "matrix dimension = ", dim

  call rokko_construct(solver, solver_name)
  call rokko_construct(grid, MPI_COMM_WORLD, rokko_grid_row_major)

  call rokko_default_mapping(solver, dim, grid, map)
  call rokko_construct(mat, map)
  call rokko_construct(Z, map)
  call rokko_construct(w, dim)

  ! generate frank matrix
  do  i = 0, dim-1
     do j = 0, dim-1
      value = dim - max(i,j)
         call rokko_set_global(mat, i, j, value)
     enddo
  enddo

  
  if (myrank.eq.0) then
     write(*,'(A)') "Frank matrix = "
  endif
  call rokko_print(mat)

  call MPI_Barrier(MPI_COMM_WORLD, ierr)

  call rokko_diagonalize(solver, mat, w, Z)
  
  call MPI_Barrier(MPI_COMM_WORLD, ierr)

  if (myrank.eq.0) then
     write(*,'(A)') "Computed Eigenvalues = "
     do i = 1, dim
        write(*,"(f30.20)") rokko_eigen_vector_get_f(w ,i)
     enddo
  endif

  if (myrank.eq.0) then
     write(*,'(A)') "Eigenstates = "
  endif

  call MPI_Barrier(MPI_COMM_WORLD, ierr)

  call rokko_print(Z)

  call rokko_destruct(mat)
  call rokko_destruct(Z)
  call rokko_destruct(w)
  call rokko_destruct(solver)
  call rokko_destruct(map)
  call rokko_destruct(grid)

  call MPI_finalize(ierr)
end program frank_matrix


<|start_filename|>rokko/mpi_communicator.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_MPI_COMMNUNICATOR_HPP
#define ROKKO_MPI_COMMNUNICATOR_HPP

#include <mpi.h>

namespace rokko {

class mpi_comm {
public:
  explicit mpi_comm(MPI_Comm comm_in = MPI_COMM_WORLD) : comm(comm_in) {
    if (comm != MPI_COMM_NULL) {
      MPI_Comm_size(comm, &nprocs);
      MPI_Comm_rank(comm, &myrank);
    } else {
      nprocs = 0;
      myrank = -1;
    }
  }

  MPI_Comm get_comm() const { return comm; }
  void set_comm(MPI_Comm comm_in) { comm = comm_in; }
  int get_nprocs() const { return nprocs; }
  int get_myrank() const { return myrank; }

  void barrier() const {
    MPI_Barrier(comm);
  }

  static bool is_MPI_Cart(MPI_Comm comm) {
    int topo_type;
    /* int ierr = */ MPI_Topo_test(comm, &topo_type);
    return topo_type == MPI_CART;
  }

  static bool is_MPI_2dim_Cart(MPI_Comm comm) {
    if (is_MPI_Cart(comm)) {
      int cart_dim;
      /* int ierr = */ MPI_Cartdim_get(comm, &cart_dim);
      return cart_dim == 2;
    } else {
      return false;
    }
  }

protected:
  MPI_Comm comm;
  int nprocs, myrank;
};

} // namespace rokko

#endif // ROKKO_MPI_COMMNUNICATOR_HPP


<|start_filename|>benchmark/no_rokko/sparse_heisenberg_file_mpi/anasazi_mfree_krylov.cpp<|end_filename|>
#include "AnasaziConfigDefs.hpp"
#include "AnasaziBasicEigenproblem.hpp"
#include "AnasaziBlockKrylovSchurSolMgr.hpp"
//#include "AnasaziBlockKrylovSchurSolMgr.hpp"
#include "AnasaziBasicOutputManager.hpp"
#include "AnasaziEpetraAdapter.hpp"
#include "Epetra_CrsMatrix.h"
#include "Teuchos_CommandLineProcessor.hpp"

#ifdef HAVE_MPI
#include "Epetra_MpiComm.h"
#include <mpi.h>
#else
#include "Epetra_SerialComm.h"
#endif
#include "Epetra_Map.h"

#include <rokko/utility/heisenberg_hamiltonian_mpi.hpp>
#include <rokko/utility/lattice.hpp>
#include <rokko/utility/math.hpp>
#include <vector>

class HeisenbergOp : public Epetra_Operator {
 public:
  //! @name Constructor/Destructor
  //@{

  //! Basic constructor.  Accepts reference-counted pointer to an Epetra_Operator.
  HeisenbergOp(const MPI_Comm& comm, int L, const std::vector<std::pair<int, int>>& lattice) : comm_(comm), L_(L), lattice_(lattice), ep_comm(comm), ep_map(1 << L_, 0, ep_comm) {
    int nproc;
    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
    const int p = rokko::find_power_of_two(nproc);
    int local_N = 1 << (L-p);
    buffer_.assign(local_N, 0);
  }

  //! Destructor
  ~HeisenbergOp() {}
  //@}

  virtual int SetUseTranspose(bool UseTranspose) { return 0; };
  //@}
  
  //! @name Mathematical functions
  //@{ 

    //! Returns the result of a Epetra_Operator applied to a Epetra_MultiVector X in Y.
    /*! 
    \param In
	   X - A Epetra_MultiVector of dimension NumVectors to multiply with matrix.
    \param Out
	   Y -A Epetra_MultiVector of dimension NumVectors containing result.

    \return Integer error code, set to 0 if successful.
  */
  virtual int Apply(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const {
    const int numvectors = X.NumVectors();
    //std::cout << "numvectors=" << numvectors << std::endl;
    //std::cout << "X.GlobalLength()=" << X.GlobalLength() << std::endl;
    //std::cout << "X.MyLength()=" << X.MyLength() << std::endl;

    Y.PutScalar(0);
    for (int i=0; i<numvectors; ++i) {
      const double* x = X[i];
      double* y = Y[i];
      rokko::heisenberg_hamiltonian::multiply(comm_, L_, lattice_, x, y, buffer_.data());
    }
    //std::cout << "X=" << X << std::endl;
    return 0;
  }

    //! Returns the result of a Epetra_Operator inverse applied to an Epetra_MultiVector X in Y.
    /*! 
    \param In
	   X - A Epetra_MultiVector of dimension NumVectors to solve for.
    \param Out
	   Y -A Epetra_MultiVector of dimension NumVectors containing result.

    \return Integer error code, set to 0 if successful.

    \warning In order to work with AztecOO, any implementation of this method must 
              support the case where X and Y are the same object.
  */
  virtual int ApplyInverse(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const { return 0; }

    //! Returns the infinity norm of the global matrix.
    /* Returns the quantity \f$ \| A \|_\infty\f$ such that
       \f[\| A \|_\infty = \max_{1\lei\lem} \sum_{j=1}^n |a_{ij}| \f].

       \warning This method must not be called unless HasNormInf() returns true.
    */ 
  virtual double NormInf() const { return 0; }
  //@}
  
  //! @name Attribute access functions
  //@{ 

    //! Returns a character string describing the operator
  virtual const char * Label() const { return "<NAME>"; }

    //! Returns the current UseTranspose setting.
  virtual bool UseTranspose() const { return false; }

    //! Returns true if the \e this object can provide an approximate Inf-norm, false otherwise.
  virtual bool HasNormInf() const  { return false; }

    //! Returns a pointer to the Epetra_Comm communicator associated with this operator.
  virtual const Epetra_Comm & Comm() const { return ep_comm; }

    //! Returns the Epetra_Map object associated with the domain of this operator.
  virtual const Epetra_Map & OperatorDomainMap() const { return ep_map; }

    //! Returns the Epetra_Map object associated with the range of this operator.
  virtual const Epetra_Map & OperatorRangeMap() const { return ep_map; }
  //@}

  //! @name Operator application method
  //@{

  /*! \brief This method takes the Anasazi::MultiVec \c X and
      applies the operator to it resulting in the Anasazi::MultiVec \c Y.
  */
  //@}

 private:
  MPI_Comm comm_;
  mutable std::vector<double> buffer_;
  int L_;
  std::vector<std::pair<int, int>> lattice_;
  Epetra_MpiComm ep_comm;
  Epetra_Map ep_map;
};

int main(int argc, char *argv[]) {
  using std::endl;
  double init_tick, initend_tick, gen_tick, diag_tick, end_tick;

#ifdef HAVE_MPI
  // Initialize MPI
  //
  MPI_Init(&argc,&argv);
#endif
  init_tick = MPI_Wtime();
  // Create an Epetra communicator
  //
#ifdef HAVE_MPI
  Epetra_MpiComm Comm(MPI_COMM_WORLD);
#else
  Epetra_SerialComm Comm;
#endif
  initend_tick = MPI_Wtime();

  // Create an Anasazi output manager
  Anasazi::BasicOutputManager<double> printer;
  printer.stream(Anasazi::Errors) << Anasazi::Anasazi_Version() << endl << endl;

  std::string lattice_file("xyz.dat");
  if (argc >= 2) lattice_file = argv[1];
  int L;
  std::vector<std::pair<int, int>> lattice;
  rokko::read_lattice_file(lattice_file, L, lattice);
  const int N = 1 << L;

  gen_tick = MPI_Wtime();
  // Construct a Map that puts approximately the same number of
  // equations on each processor.
  Epetra_Map Map(N, 0, Comm);

  // Get update list and number of local equations from newly created Map.
  const int NumMyElements = Map.NumMyElements();

  std::vector<int> MyGlobalElements(NumMyElements);
  Map.MyGlobalElements(MyGlobalElements.data());

  // Create an Epetra_Matrix
  Teuchos::RCP<HeisenbergOp> A = Teuchos::rcp( new HeisenbergOp(MPI_COMM_WORLD, L, lattice) );

  //************************************
  // Call the LOBPCG solver manager
  //***********************************
  //  Variables used for the LOBPCG Method
  diag_tick = MPI_Wtime();
  std::string which("LM");
  constexpr int    nev       = 10;
  constexpr int    blockSize = 40;
  constexpr int    maxIters  = 500;
  constexpr double tol       = 1.0e-8;

  using MV = Epetra_MultiVector;
  using OP = Epetra_Operator;
  using MVT = Anasazi::MultiVecTraits<double, Epetra_MultiVector>;

  // Create an Epetra_MultiVector for an initial vector to start the solver.
  // Note:  This needs to have the same number of columns as the blocksize.
  Teuchos::RCP<Epetra_MultiVector> ivec = Teuchos::rcp( new Epetra_MultiVector(Map, blockSize) );
  ivec->Random();

  // Create the eigenproblem.
  Teuchos::RCP<Anasazi::BasicEigenproblem<double, MV, OP>> MyProblem =
    Teuchos::rcp( new Anasazi::BasicEigenproblem<double, MV, OP>(A, ivec) );

  // Inform the eigenproblem that the operator A is symmetric
  MyProblem->setHermitian(true);

  // Set the number of eigenvalues requested
  MyProblem->setNEV( nev );

  // Inform the eigenproblem that you are finishing passing it information
  bool boolret = MyProblem->setProblem();
  if (boolret != true) {
    printer.print(Anasazi::Errors,"Anasazi::BasicEigenproblem::setProblem() returned an error.\n");
#ifdef HAVE_MPI
    MPI_Finalize();
#endif
    return -1;
  }

  // Create parameter list to pass into the solver manager
  Teuchos::ParameterList MyPL;
  MyPL.set( "Which", which );
  MyPL.set( "Block Size", blockSize );
  MyPL.set( "Maximum Iterations", maxIters );
  MyPL.set( "Convergence Tolerance", tol );

  // Create the solver manager
  Anasazi::BlockKrylovSchurSolMgr<double, MV, OP> MySolverMan(MyProblem, MyPL);
  //Anasazi::BlockKrylovSchurSolMgr<double, MV, OP> MySolverMan(MyProblem, MyPL);

  // Solve the problem
  Anasazi::ReturnType returnCode = MySolverMan.solve();
  end_tick = MPI_Wtime();

  // Get the eigenvalues and eigenvectors from the eigenproblem
  Anasazi::Eigensolution<double,MV> sol = MyProblem->getSolution();
  std::vector<Anasazi::Value<double>> evals = sol.Evals;
  Teuchos::RCP<MV> evecs = sol.Evecs;

  // Compute residuals.
  std::vector<double> normR(sol.numVecs);
  if (sol.numVecs > 0) {
    Teuchos::SerialDenseMatrix<int,double> T(sol.numVecs, sol.numVecs);
    Epetra_MultiVector tempAevec( Map, sol.numVecs );
    T.putScalar(0.0);
    for (int i=0; i<sol.numVecs; i++) {
      T(i,i) = evals[i].realpart;
    }
    A->Apply( *evecs, tempAevec );
    MVT::MvTimesMatAddMv( -1.0, *evecs, T, 1.0, tempAevec );
    MVT::MvNorm( tempAevec, normR );
  }

  // Print the results
  std::ostringstream os;
  os.setf(std::ios_base::right, std::ios_base::adjustfield);
  os<<"Solver manager returned " << (returnCode == Anasazi::Converged ? "converged." : "unconverged.") << endl;
  os<<endl;
  os<<"------------------------------------------------------"<<endl;
  os<<std::setw(16)<<"Eigenvalue"
    <<std::setw(18)<<"Direct Residual"
    <<endl;
  os<<"------------------------------------------------------"<<endl;
  for (int i=0; i<sol.numVecs; i++) {
    os<<std::setw(16)<<evals[i].realpart
      <<std::setw(18)<<normR[i]/evals[i].realpart
      <<endl;
  }
  os<<"------------------------------------------------------"<<endl;
  os << "init_time = " << initend_tick - init_tick << std::endl
     << "gen_time = " << diag_tick - gen_tick << std::endl
     << "diag_time = " << end_tick - diag_tick << std::endl;
  printer.print(Anasazi::Errors,os.str());

#ifdef HAVE_MPI
  MPI_Finalize();
#endif
  return 0;
}


<|start_filename|>example/c/dense/generate_vector/eigen_vector_construct_by_array.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.h>
#include <stdio.h>
#include <stdlib.h>

#define DIM 5

int main(int argc, char *argv[]) {
  struct rokko_eigen_vector vector;
  double array[DIM];
  int i;

  for(i=0; i<DIM; ++i)
    array[i] = i + 1;

  rokko_eigen_vector_construct_array_size(&vector, DIM, array);
  rokko_eigen_vector_print(vector);

  /*rokko_eigen_vector_destruct(&vector);*/

  return 0;
}


<|start_filename|>rokko/lapack.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_HPP
#define ROKKO_LAPACK_HPP

#include <lapacke.h>
#undef I
#include <rokko/traits/real_t.hpp>

namespace rokko {
namespace lapack {

// LAPACKE_*gesvd is called if size(work) == min(rows(a),cols(a))-1,
// otherwise LAPACKE_sgesvd_work or LAPACKE_dgesvd_work is called
template<typename MATRIX, typename VECTOR>
lapack_int gesvd(char jobu, char jobvt, MATRIX& a, VECTOR& s, MATRIX& u, MATRIX& vt,
                 VECTOR& work);

// LAPACKE_cgesvd_work or LAPACKE_zgesvd_work is called
template<typename MATRIX, typename VECTOR0, typename VECTOR1>
lapack_int gesvd(char jobu, char jobvt, MATRIX& a, VECTOR0& s, MATRIX& u, MATRIX& vt,
                 VECTOR1& work, VECTOR0& rwork);

template<typename MATRIX, typename VECTOR>
lapack_int getrf(MATRIX& a, VECTOR& ipiv);

template<typename MATRIX, typename VECTOR>
lapack_int dgetri(MATRIX& a, VECTOR const& ipiv);

template<typename MATRIX, typename VECTOR0, typename VECTOR1>
lapack_int dgetri(MATRIX& a, VECTOR0 const& ipiv, VECTOR1& work);

template<typename MATRIX0, typename MATRIX1, typename VECTOR>
lapack_int getrs(char trans, lapack_int nrhs, MATRIX0 const& a, VECTOR const& ipiv,
                 MATRIX1& b);

template<typename MATRIX, typename VECTOR>
lapack_int geqrf(MATRIX& a, VECTOR& tau);

template<typename MATRIX, typename VECTOR>
lapack_int geqrf(MATRIX& a, VECTOR& tau, VECTOR& work);
  
template<typename MATRIX>
rokko::real_t<MATRIX> lange(char norm, MATRIX const& a);

template<typename MATRIX, typename VECTOR>
rokko::real_t<MATRIX> lange(char norm, MATRIX const& a, VECTOR& work);
  
template<typename MATRIX, typename VECTOR>
lapack_int orgqr(lapack_int k, MATRIX& a, VECTOR const& tau);
  
template<typename MATRIX, typename VECTOR>
lapack_int orgqr(lapack_int k, MATRIX& a, VECTOR const& tau, VECTOR& work);
  
template<typename MATRIX, typename VECTOR>
lapack_int ungqr(lapack_int k, MATRIX& a, VECTOR const& tau);
  
template<typename MATRIX, typename VECTOR>
lapack_int ungqr(lapack_int k, MATRIX& a, VECTOR const& tau, VECTOR& work);
  
template<typename MATRIX, typename VECTOR>
lapack_int heev(char jobz, char uplo, MATRIX& a, VECTOR& w);

template<typename MATRIX, typename VECTOR0, typename VECTOR1>
lapack_int heev(char jobz, char uplo, MATRIX& a, VECTOR0& w, VECTOR1& work, VECTOR1& rwork);
  
template<typename MATRIX, typename VECTOR>
lapack_int hegv(lapack_int itype, char jobz, char uplo, MATRIX& a, VECTOR& b, VECTOR& w);
  
template<typename MATRIX, typename VECTOR0, typename VECTOR1>
lapack_int hegv(lapack_int itype, char jobz, char uplo, MATRIX& a, VECTOR0& b, VECTOR0& w,
                VECTOR1& work);

template<typename MATRIX, typename VECTOR0, typename VECTOR1>
lapack_int syev(char jobz, char uplo, MATRIX& a, VECTOR0& w, VECTOR1& work, VECTOR1& rwork);

template<typename MATRIX, typename VECTOR>
lapack_int sygv(lapack_int itype, char jobz, char uplo, MATRIX& a, VECTOR& b,
                VECTOR& w);
  
template<typename MATRIX, typename VECTOR0, typename VECTOR1>
lapack_int sygv(lapack_int itype, char jobz, char uplo, MATRIX& a, VECTOR0& b,
                VECTOR0& w, VECTOR1& work);
  
} // end namespace lapack
} // end namespace rokko

#include "lapack/geqrf.hpp"
#include "lapack/gesvd.hpp"
#include "lapack/getrf.hpp"
#include "lapack/getrs.hpp"
#include "lapack/heev.hpp"
#include "lapack/heevx.hpp"
#include "lapack/heevd.hpp"
#include "lapack/heevr.hpp"
#include "lapack/hegv.hpp"
#include "lapack/hegvd.hpp"
#include "lapack/hegvx.hpp"
#include "lapack/lange.hpp"
#include "lapack/ungqr.hpp"

// eigensolvers for tridiagonal matrix
#include "lapack/hteqr.hpp"
#include "lapack/htedc.hpp"
#include "lapack/htebz.hpp"
#include "lapack/htein.hpp"
#include "lapack/htegr.hpp"
#include "lapack/sterf.hpp"

#endif // ROKKO_LAPACK_HPP


<|start_filename|>rokko/pyrokko_distributed_matrix.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_DISTRIBUTED_MATRIX_HPP
#define PYROKKO_DISTRIBUTED_MATRIX_HPP

#include <pybind11/pybind11.h>

#include <rokko/pyrokko_mapping_bc.hpp>
#include <rokko/distributed_matrix.hpp>
#include <rokko/utility/tuple_to_array.hpp>

#include <memory>

namespace rokko {

class base_distributed_matrix {
public:
  virtual ~base_distributed_matrix() = default;
};

template <typename T, typename MATRIX_MAJOR>
class wrap_distributed_matrix : public distributed_matrix<T,MATRIX_MAJOR>, public base_distributed_matrix {
public:
  using distributed_matrix<T,MATRIX_MAJOR>::get_global_size;
  using distributed_matrix<T,MATRIX_MAJOR>::get_local_size;
  using distributed_matrix<T,MATRIX_MAJOR>::get_block_size;
  using distributed_matrix<T,MATRIX_MAJOR>::get_m_local;
  using distributed_matrix<T,MATRIX_MAJOR>::get_n_local;
  using distributed_matrix<T,MATRIX_MAJOR>::get_lld;
  using distributed_matrix<T,MATRIX_MAJOR>::get_array_pointer;
  using distributed_matrix<T,MATRIX_MAJOR>::is_col_major;

  wrap_distributed_matrix(wrap_mapping_bc<MATRIX_MAJOR> const& map) : distributed_matrix<T,MATRIX_MAJOR>(map) {}

  wrap_distributed_matrix() = default;
  
  std::tuple<int,int> get_block_shape() const {
    return get_block_size();
  }
  
  bool has_global_indices(std::tuple<int,int> const& global) const {
    return has_global_indices(to_array(global));
  }
  
  std::tuple<int,int> get_global_shape() const {
    return get_global_size();
  }
  
  std::tuple<int,int> get_local_shape() const {
    return get_local_size();
  }

  std::tuple<int,int> translate_l2g(std::tuple<int,int> const& local) const {
    return translate_l2g(to_array(local));
  }

  std::tuple<int,int> translate_g2l(std::tuple<int,int> const& global) const {
    return translate_g2l(to_array(global));
  }

  void print() const {
    distributed_matrix<T,MATRIX_MAJOR>::print();
  }

  std::string get_major_string() const {
    return is_col_major() ? "col" : "row";
  }

  wrap_mapping_bc<MATRIX_MAJOR> get_map() const {
    return distributed_matrix<T,MATRIX_MAJOR>::get_mapping();
  }

  py::array_t<T> get_ndarray() {
    if (is_col_major())
      return py::array_t<T>(get_local_size(), {sizeof(T), sizeof(T)*get_lld()}, get_array_pointer(), py::cast(*this));
    else
     return py::array_t<T>(get_local_size(), {sizeof(T)*get_lld(), sizeof(T)}, get_array_pointer(), py::cast(*this));
  }

  auto get_eigen_map() {
    return Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, rokko::eigen3_major<MATRIX_MAJOR>>,0,Eigen::OuterStride<>>(get_array_pointer(), get_m_local(), get_n_local(), Eigen::OuterStride<Eigen::Dynamic>(get_lld()));
  }

  void set_ndarray(py::array_t<T> const& mat) {
    py::array_t<T> array;
    if (is_col_major()) {
      array = py::array_t<T>(get_local_size(), {sizeof(T), sizeof(T)*get_lld()}, get_array_pointer(), py::cast(*this));
    } else {
      array = py::array_t<T>(get_local_size(), {sizeof(T)*get_lld(), sizeof(T)}, get_array_pointer(), py::cast(*this));
    }

    auto r = array.template mutable_unchecked<2>();
    for (auto i = 0; i < r.shape(0); ++i) {
      for (auto j = 0; j < r.shape(1); ++j) {
        r(i, j) = *mat.data(i, j);
      }
    }
  }

  void set_col_major_matrix(Eigen::Ref<const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>> mat) {
    if (!is_col_major())
      throw std::invalid_argument("Cannot set col-major ndarray to row-major distributed_matrix");

    get_eigen_map() = static_cast<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>>(mat);
  }

  void set_row_major_matrix(Eigen::Ref<const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> mat) {
    if (is_col_major())
      throw std::invalid_argument("Cannot set row-major ndarray to col-major distributed_matrix");

    get_eigen_map() = static_cast<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>(mat);
  }
};


template<typename MATRIX_MAJOR>
std::shared_ptr<base_distributed_matrix> create_distributed_matrix(wrap_mapping_bc<MATRIX_MAJOR> const& map, std::string const& dtype = "double") {
  if (dtype == "double")
    return std::make_shared<wrap_distributed_matrix<double,MATRIX_MAJOR>>(map);
  else if (dtype == "float")
    return std::make_shared<wrap_distributed_matrix<float,MATRIX_MAJOR>>(map);
  else if (dtype == "cdouble")
    return std::make_shared<wrap_distributed_matrix<std::complex<double>,MATRIX_MAJOR>>(map);
  else if (dtype == "cfloat")
    return std::make_shared<wrap_distributed_matrix<std::complex<float>,MATRIX_MAJOR>>(map);
  else
    throw std::invalid_argument("create_distributed_matrix : unknwon type '" + dtype + "'");
}

template<typename T, typename MATRIX_MAJOR>
void pyrokko_product(T alpha,
                     wrap_distributed_matrix<T, matrix_col_major> const& matA, bool transA,
                     wrap_distributed_matrix<T, matrix_col_major> const& matB, bool transB,
                     T beta,
                     wrap_distributed_matrix<T, matrix_col_major>& matC) {
  product(alpha, matA, transA, matB, transB, beta, matC);
}

} // end namespace rokko

#endif // PYROKKO_DISTRIBUTED_MATRIX_HPP


<|start_filename|>rokko/grid.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2016 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_GRID_H
#define ROKKO_GRID_H

#include <stdbool.h>
#include <mpi.h>

#ifdef __cplusplus
extern "C" {
#endif

enum {
  rokko_grid_col_major = 1, rokko_grid_row_major = 2
};

struct rokko_grid {
  void* ptr;
  int major;
};

void rokko_grid_construct(struct rokko_grid* grid, MPI_Comm comm, int grid_major);
void rokko_grid_construct_f(struct rokko_grid* grid, int comm, int grid_major);
void rokko_grid_destruct(struct rokko_grid* grid);
int rokko_grid_get_myrank(struct rokko_grid grid);
int rokko_grid_get_nprocs(struct rokko_grid grid);
int rokko_grid_get_myrow(struct rokko_grid grid);
int rokko_grid_get_mycol(struct rokko_grid grid);
int rokko_grid_get_nprow(struct rokko_grid grid);
int rokko_grid_get_npcol(struct rokko_grid grid);
bool rokko_grid_is_row_major(struct rokko_grid grid);
bool rokko_grid_is_col_major(struct rokko_grid grid);

#ifdef __cplusplus
}
#endif

#endif /* ROKKO_GRID_H */


<|start_filename|>example/fortran/dense/generate_vector/eigen_vector_generate.f90<|end_filename|>
!*****************************************************************************
!
! Rokko: Integrated Interface for libraries of eigenvalue decomposition
!
! Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
!
! 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)
!
!*****************************************************************************

program generate_eigen_vector
  use rokko
  implicit none
  integer :: dim
  type(rokko_eigen_vector) :: vec

  dim = 5
  print *,"dimension = ", dim

  call rokko_construct(vec, dim)

  print *, "vec (0-started index):"
  call rokko_generate0(vec, func0)
  call rokko_print(vec)
  print *, "vec (1-started index):"
  call rokko_generate(vec, func)
  call rokko_print(vec)

  call rokko_destruct(vec)

contains

  function func0(i)
    implicit none
    double precision :: func0
    integer, intent(in) :: i
    func0 = dble(2*(i+1))
  end function func0

  function func(i)
    implicit none
    double precision :: func
    integer, intent(in) :: i
    func = dble(2*i)
  end function func

end program generate_eigen_vector


<|start_filename|>rokko/eigenexa/eigenexa_wrap.f90<|end_filename|>
!*****************************************************************************
!
! Rokko: Integrated Interface for libraries of eigenvalue decomposition
!
! Copyright (C) 2012-2019 by <NAME> <<EMAIL>>,
!                            <NAME> <<EMAIL>>
!
! 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)
!
!*****************************************************************************

subroutine eigen_init_wrap0()
  use eigen_libs_mod, only : eigen_init
  implicit none
  call eigen_init()
  return
end subroutine eigen_init_wrap0

subroutine eigen_init_wrap1(comm)
  use eigen_libs_mod, only : eigen_init
  implicit none
  integer, intent(in) :: comm
  call eigen_init(comm)
  return
end subroutine eigen_init_wrap1

subroutine eigen_init_wrap2(comm, order)
  use eigen_libs_mod, only : eigen_init
  implicit none
  integer, intent(in) :: comm
  character*(*), intent(in) :: order
  call eigen_init(comm, order)
  return
end subroutine eigen_init_wrap2

subroutine eigen_free_wrap0()
  use eigen_libs_mod, only : eigen_free
  implicit none
  call eigen_free()
  return
end subroutine eigen_free_wrap0

subroutine eigen_free_wrap1(flag)
  use eigen_libs_mod, only : eigen_free
  implicit none
  integer, intent(in) :: flag
  call eigen_free(flag)
  return
end subroutine eigen_free_wrap1

subroutine eigen_get_matdims_wrap(NPROW, NPCOL, n, nx, ny)
  use eigen_libs_mod, only : eigen_NB
  use CSTAB_mod, only : CSTAB_get_optdim
  implicit none
  integer, intent(in) :: NPROW, NPCOL, n
  integer, intent(out) :: nx, ny

  integer :: NB
  integer :: n1, nm, nmz, nmw, nn, larray

  if (n <= 0) then
     nx = -1; ny = -1
     return
  end if

  n1 = ((n-1)/NPROW+1)
  call CSTAB_get_optdim(n1, 6, 16*4, 16*4*2, nm)

  NB  = eigen_NB

  nmz = ((n-1)/NPROW+1)
  nmz = ((nmz-1)/NB+1)*NB+1
  nn  = nmz
  nmz = (n-1)/NB+1
  nmz = ((nmz-1)/NPROW+1)*NB
  ! Fix on version 2.2b
  ! to avoid unexpected SIGSEGV,
  ! use the maximum of nn and nmz.
  nmz = MAX(nn, nmz)
  
  nmw = ((n-1)/NPCOL+1)
  nmw = ((nmw-1)/NB+1)*NB+1
  nn  = nmw
  nmw = (n-1)/NB+1
  nmw = ((nmw-1)/NPCOL+1)*NB
  ! Fix on version 2.2b
  ! to avoid unexpected SIGSEGV,
  ! use the maximum of nn and nmz.
  nmw = MAX(nn, nmw)
  
  larray = MAX(nmz, nm)*nmw
  
  nx = nm
  ny = (larray-1)/nm+1

  return
end subroutine eigen_get_matdims_wrap

subroutine eigen_get_procs_wrap(procs, x_procs, y_procs)
  use eigen_libs_mod, only : eigen_get_procs
  implicit none
  integer, intent(out) :: procs, x_procs, y_procs
  call eigen_get_procs(procs, x_procs, y_procs)
  return
end subroutine eigen_get_procs_wrap

subroutine eigen_get_id_wrap(id, x_id, y_id)
  use eigen_libs_mod, only : eigen_get_id
  implicit none
  integer, intent(out) :: id, x_id, y_id
  call eigen_get_id(id, x_id, y_id)
  return
end subroutine eigen_get_id_wrap

function eigen_loop_start_wrap(id, x_id, y_id)
  use eigen_libs_mod, only : eigen_loop_start
  implicit none
  integer :: eigen_loop_start_wrap
  integer, intent(in) :: id, x_id, y_id
  eigen_loop_start_wrap = eigen_loop_start(id, x_id, y_id)
end function eigen_loop_start_wrap

function eigen_loop_end_wrap(id, x_id, y_id)
  use eigen_libs_mod, only : eigen_loop_end
  implicit none
  integer :: eigen_loop_end_wrap
  integer, intent(in) :: id, x_id, y_id
  eigen_loop_end_wrap = eigen_loop_end(id, x_id, y_id)
end function eigen_loop_end_wrap

function eigen_translate_l2g_wrap(ictr, nnod, inod)
  use eigen_libs_mod, only : eigen_translate_l2g
  implicit none
  integer :: eigen_translate_l2g_wrap
  integer, intent(in) :: ictr, nnod, inod
  eigen_translate_l2g_wrap = eigen_translate_l2g(ictr, nnod, inod)
end function eigen_translate_l2g_wrap

function eigen_translate_g2l_wrap(ictr, nnod, inod)
  use eigen_libs_mod, only : eigen_translate_g2l
  implicit none
  integer :: eigen_translate_g2l_wrap
  integer, intent(in) :: ictr, nnod, inod
  eigen_translate_g2l_wrap = eigen_translate_g2l(ictr, nnod, inod)
end function eigen_translate_g2l_wrap


<|start_filename|>rokko/anasazi/solver.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_ANASAZI_SOLVER_HPP
#define ROKKO_ANASAZI_SOLVER_HPP

#include <tuple>

#include <rokko/distributed_vector.hpp>
#include <rokko/distributed_mfree.hpp>
#include <rokko/anasazi/mapping_1d.hpp>
#include <rokko/anasazi/distributed_crs_matrix.hpp>
#include <rokko/anasazi/distributed_mfree.hpp>
#include <rokko/parameters.hpp>
#include <rokko/solver_parameters.hpp>

#include <AnasaziEpetraAdapter.hpp>
#include <Epetra_CrsMatrix.h>
#include <Epetra_MpiComm.h>
#include <Epetra_Map.h>

#include <AnasaziBasicEigenproblem.hpp>
#include <AnasaziLOBPCGSolMgr.hpp>
#include <AnasaziBlockKrylovSchurSolMgr.hpp>
#include <AnasaziBlockDavidsonSolMgr.hpp>
#include <AnasaziRTRSolMgr.hpp>
#include <Teuchos_RCPDecl.hpp>

namespace rokko {

namespace anasazi {

class solver {
public:
  using value_type = double;
  using eigenproblem_t = Anasazi::BasicEigenproblem<value_type, Epetra_MultiVector, Epetra_Operator>;
  using solvermanager_t = Anasazi::SolverManager<value_type, Epetra_MultiVector, Epetra_Operator>;

  static const std::vector<std::string> names;
  
  solver() = default;

  ~solver() = default;
  void initialize(int& argc, char**& argv) {}
  void finalize() {}

  static std::unique_ptr<solvermanager_t> create_solver_manager(std::string const& routine, Teuchos::RCP<eigenproblem_t> problem, Teuchos::ParameterList& pl) {
    if ((routine == "lobpcg") || (routine == ""))
      return std::make_unique<Anasazi::LOBPCGSolMgr<value_type, Epetra_MultiVector, Epetra_Operator>>(problem, pl);
    else if (routine == "block_krylov_schur")
      return std::make_unique<Anasazi::BlockKrylovSchurSolMgr<value_type, Epetra_MultiVector, Epetra_Operator>>(problem, pl);
    else if (routine == "block_davidson")
      return std::make_unique<Anasazi::BlockDavidsonSolMgr<value_type, Epetra_MultiVector, Epetra_Operator>>(problem, pl);
    else if (routine == "rtr")
      return std::make_unique<Anasazi::RTRSolMgr<value_type, Epetra_MultiVector, Epetra_Operator>>(problem, pl);
    else {
      std::stringstream msg;
      msg << "anasazi::solver::create_solver_manager : " << routine << " is not a solver in Anasazi" << std::endl;
      msg << "list of Anasazi solvers:" << std::endl;
      for (int i=0; i<names.size(); ++i) {
        msg << names[i] << " " << std::endl;
      }
      throw std::invalid_argument(msg.str());
    }
  }

  static std::tuple<int,int> retrieve_number_size(rokko::parameters const& params) {
    int num_eigvals = params.defined("num_eigvals") ?
      params.get<int>("num_eigvals") : 1;
    int max_block_size = params.defined("max_block_size") ?
      params.get<int>("max_block_size") : num_eigvals;  // fix me : This default value must depend on eigenalgorithm such as 2 * num_eigvals
    return {num_eigvals, max_block_size};
  }

  static std::string get_routine(rokko::parameters const& params) {
    std::string routine;

    if (params.defined("routine")) {
      if ((params.type("routine") == typeid(std::string)) && params.type("routine") == typeid(const char*))
        throw std::invalid_argument("anasazi::solver::diagonalize() : routine must be charatcters or string");
      routine = params.get_string("routine");
    } else {  // default
      routine = "lobpcg";
    }
    return routine;
  }

  static std::string get_wanted_eigenvalues(std::string const& str) {
    if ((str == "largest") || (str == "LM"))
      return "LM";
    if ((str == "smallest") || (str == "SM"))
      return "SM";
    if ((str == "largest_real") || (str == "LR"))
      return "LR";
    if ((str == "smallest_real") || (str == "SR"))
      return "SR";
    else
      throw std::invalid_argument("get_wanted_eigenvalues: invalid parameter");
  }

  static Teuchos::ParameterList set_anasazi_parameters(rokko::parameters const& params) {
    Teuchos::ParameterList pl;

    if (params.defined("block_size"))  // if block size is provided by common key name "block_size"
      pl.set("Block Size", params.get<int>("block_size"));
    if (params.defined("conv_tol"))
      pl.set("Convergence Tolerance", params.get<value_type>("conv_tol"));
    if (params.defined("max_iters"))
      pl.set("Maximum Iterations", params.get<int>("max_iters"));

    if (params.defined("wanted_eigenvalues")) {
      pl.set("Which", get_wanted_eigenvalues(params.get_string("wanted_eigenvalues")));
    }

    if (params.get_bool("verbose")) {
      pl.set( "Verbosity", Anasazi::Errors | Anasazi::Warnings | Anasazi::IterationDetails | Anasazi::FinalSummary | Anasazi::Debug | Anasazi::OrthoDetails );
    }

    std::list<std::string> keys = params.keys();
    for(auto const& key : keys) {
      if (!is_rokko_solver_key(key)) {
        if (params.type(key) == typeid(int))
          pl.set(key, params.get<int>(key));
        else if (params.type(key) == typeid(value_type))
          pl.set(key, params.get<value_type>(key));
        else if (params.type(key) == typeid(std::string))
          pl.set(key, params.get<std::string>(key));
        else if (params.type(key) == typeid(const char*))
          pl.set(key, params.get<const char*>(key));
      }
    }

    return pl;
  }

  parameters diagonalize(const rokko::distributed_crs_matrix& mat, rokko::parameters const& params) {
    if (mat.get_solver_name() != "anasazi") {
      throw std::invalid_argument("rokko::anasazi::solver::diagonalize() : " + mat.get_solver_name() + "'s distributed_crs_matrix is given.");
    }
    return diagonalize(*std::static_pointer_cast<const rokko::anasazi::distributed_crs_matrix>(mat.get_ptr()), params);
  }

  parameters diagonalize(const rokko::anasazi::distributed_crs_matrix& mat, rokko::parameters const& params) {
    map_ = mat.get_map_ptr();
    return diagonalize_common(mat.get_matrix(), params);
  }

  parameters diagonalize(const rokko::distributed_mfree& mat, rokko::parameters const& params) {
    map_ = std::make_shared<mapping_1d>(mat.get_dim(), mat.get_num_local_rows(), mpi_comm{mat.get_comm()});
    Teuchos::RCP<const anasazi_mfree_operator> anasazi_op = Teuchos::rcp(new anasazi_mfree_operator(mat, *map_));
    return diagonalize_common(anasazi_op, params);
  }

  parameters diagonalize_common(Teuchos::RCP<const Epetra_Operator> op, rokko::parameters const& params) {
    int num_eigvals, max_block_size;
    std::tie(num_eigvals, max_block_size) = retrieve_number_size(params);
    Teuchos::ParameterList pl = set_anasazi_parameters(params);

    Teuchos::RCP<Epetra_MultiVector> multivector = Teuchos::rcp(new Epetra_MultiVector(map_->get_epetra_map(), max_block_size));
    multivector->Random();
    problem_ = Teuchos::rcp(new eigenproblem_t(op, multivector));
    problem_->setHermitian(true);
    problem_->setNEV(num_eigvals);
    problem_->setProblem();

    std::unique_ptr<solvermanager_t> solvermanager = create_solver_manager(get_routine(params), problem_, pl);
    
    bool boolret = problem_->setProblem();
    if (!boolret) {
      throw std::invalid_argument("anasazi::solver::diagonalize : Return value from setProblem() is false");
    }

    Anasazi::ReturnType returnCode = solvermanager->solve();
    if (params.get_bool("verbose") && (returnCode == Anasazi::Unconverged)) {
      std::cout << "anasazi::solver::diagonalize : solve() does not converge." << std::endl;
    }
    parameters params_out;
    params_out.set("num_conv", get_num_conv());
    return params_out;
  }

  value_type eigenvalue(int i) const { return problem_->getSolution().Evals[i].realpart; }

  void eigenvector(int k, std::vector<value_type>& vec) const {
    if (vec.size() < map_->get_num_local_rows()) vec.resize(map_->get_num_local_rows());
    eigenvector(k, vec.data());
  }
  void eigenvector(int k, value_type *const vec) const {
    value_type const*const vec_pt = (*problem_->getSolution().Evecs)[k];
    std::copy(vec_pt, vec_pt + map_->get_num_local_rows(), vec);
  }
  void eigenvector(int k, distributed_vector<value_type>& vec) const {
    vec.initialize(map_->get_dim(), map_->get_epetra_map().MinMyGID(),
                   map_->get_epetra_map().MaxMyGID() + 1);
    eigenvector(k, vec.get_storage());
  }

  int get_num_conv() const {
    return problem_->getSolution().numVecs;
  }

  const Teuchos::RCP<eigenproblem_t> get_object() const {
    return problem_;
  }

  Teuchos::RCP<eigenproblem_t> get_object() {
    return problem_;
  }

private:
  //std::list<std::string> anasazi_keys = { "Which", "Maximum Iterations", "Convergence Tolerance" };
  std::shared_ptr<const rokko::anasazi::mapping_1d> map_;
  Teuchos::RCP<eigenproblem_t> problem_;
};

const std::vector<std::string> solver::names{ "lobpcg", "block_krylov_schur", "block_davidson", "rtr" };

} // namespace anasazi

} // namespace rokko

#endif // ROKKO_ANASAZI_SOLVER_HPP


<|start_filename|>rokko/factory.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_FACTORY_HPP
#define ROKKO_FACTORY_HPP

#include <rokko/noncopyable.hpp>
#include <rokko/utility/macro_join.hpp>
#include <memory>
#include <iostream>
#include <stdexcept>
#include <map>
#include <string>
#include <vector>

namespace rokko {

template<typename BASE, class... Types>
class factory : private rokko::noncopyable<factory<BASE>> {
private:
  class abstract_creator {
  public:
    virtual ~abstract_creator() = default;
    virtual std::shared_ptr<BASE> create(Types... args) const = 0;
  };
  template<typename PRODUCT>
  class creator : public abstract_creator {
  public:
    virtual ~creator() = default;
    std::shared_ptr<BASE> create(Types... args) const override {
      return std::static_pointer_cast<BASE>(std::make_shared<PRODUCT>(args...));
    }
  };

public:
  using product_pointer_type = std::shared_ptr<BASE>;

private:
  using creator_pointer_type = std::shared_ptr<abstract_creator>;
  using creator_map_type = std::map<std::string, creator_pointer_type>;
public:
  factory() : largest_priority_(0) {}
  static product_pointer_type make_product(std::string const& name = "", Types... args) {
    factory* f = factory::instance();
    if (name == "") {
      if (f->default_product_ != "") {
        return f->make_creator(f->default_product_)->create(args...);
      } else {
        std::cerr << "Error: default product is not defined\n";
        throw std::runtime_error("factory::make_product()");
      }
    } else {
      return f->make_creator(name)->create(args...);
    }
  }
  template<typename PRODUCT>
  bool register_creator(std::string const& name, int priority = 0) {
    bool isnew = (creators_.find(name) == creators_.cend());
    creators_[name] = std::static_pointer_cast<abstract_creator>(std::make_shared<creator<PRODUCT>>());
    if (priority >= largest_priority_) {
      largest_priority_ = priority;
      default_product_ = name;
    }
    return isnew;
  }
  bool unregister_creator(std::string const& name); // to be implemented
  static std::vector<std::string> product_names() {
    factory* f = factory::instance();
    std::vector<std::string> retvec;
    for (typename creator_map_type::const_iterator it = f->creators_.cbegin();
         it != f->creators_.cend(); ++it) {
      retvec.emplace_back(it->first);
    }
    return retvec;
  }

  static const std::string& default_product_name() {
    return instance()->default_product_;
  }
  static factory* instance() {
    if (!instance_) instance_ = new factory;
    return instance_;
  }
protected:
  creator_pointer_type make_creator(std::string const& name) const {
    typename creator_map_type::const_iterator itr = creators_.find(name);
    if (itr == creators_.cend() || itr->second == nullptr) {
      std::cerr << "Error: unknown product: \"" << name << "\" (registered products: ";
      for (typename creator_map_type::const_iterator itr = creators_.cbegin();
           itr != creators_.cend(); ++itr) {
        if (itr != creators_.cbegin()) std::cerr << ", ";
        std::cerr << "\"" << itr->first << "\"";
      }
      std::cerr << ")\n";
      throw std::runtime_error("factory::make_creator()");
    }
    return itr->second;
  }
      
private:
  static factory* instance_;
  creator_map_type creators_;
  int largest_priority_;
  std::string default_product_;
};

} // end namespace rokko

#define ROKKO_REGISTER_PRODUCT(base, product, name, priority) \
  namespace { namespace ROKKO_JOIN(product_register, __LINE__) { struct register_caller { register_caller() { rokko::factory::instance()->register_creator<product>(name, priority); } } caller; } }

#endif // ROKKO_FACTORY_HPP


<|start_filename|>rokko/parameters_c.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/parameters.h>
#include <rokko/parameters.hpp>
#include <rokko/copy_string.hpp>

void rokko_parameters_construct(struct rokko_parameters* params) {
  params->ptr = new rokko::parameters();
}

void rokko_parameters_destruct(struct rokko_parameters* params) {
  rokko::parameters* ptr = static_cast<rokko::parameters*>(params->ptr);
  delete ptr;
  params->ptr = nullptr;
}

void rokko_parameters_clear_all(struct rokko_parameters params) {
  static_cast<rokko::parameters*>(params.ptr)->clear();
}

void rokko_parameters_clear(struct rokko_parameters params, const char* key) {
  static_cast<rokko::parameters*>(params.ptr)->clear(key);
}

void rokko_parameters_set_int(rokko_parameters params, const char* key, int value) {
  static_cast<rokko::parameters*>(params.ptr)->set<int>(key, value);
}

void rokko_parameters_set_double(rokko_parameters params, const char* key, double value) { 
  static_cast<rokko::parameters*>(params.ptr)->set<double>(key, value);
}

void rokko_parameters_set_true(rokko_parameters params, const char* key) {
  static_cast<rokko::parameters*>(params.ptr)->set<bool>(key, true);
}

void rokko_parameters_set_false(rokko_parameters params, const char* key) {
  static_cast<rokko::parameters*>(params.ptr)->set<bool>(key, false);
}

void rokko_parameters_set_char(rokko_parameters params, const char* key, char value) { 
  static_cast<rokko::parameters*>(params.ptr)->set<char>(key, value);
}

void rokko_parameters_set_string(struct rokko_parameters params, const char* key, const char* value) {
  static_cast<rokko::parameters*>(params.ptr)->set<std::string>(key, std::string(value));
}

int rokko_parameters_get_int(rokko_parameters params, const char* key) { 
  return static_cast<rokko::parameters*>(params.ptr)->get<int>(key);
}

int rokko_parameters_get_logicalint(rokko_parameters params, const char* key) { 
  return static_cast<rokko::parameters*>(params.ptr)->get<bool>(key);  // automatically cast bool to int
}

double rokko_parameters_get_double(rokko_parameters params, const char* key) {
  return static_cast<rokko::parameters*>(params.ptr)->get<double>(key);
}

char rokko_parameters_get_char(rokko_parameters params, const char* key) { 
  return static_cast<rokko::parameters*>(params.ptr)->get<char>(key);
}


char* rokko_parameters_get_string(struct rokko_parameters params, const char* key) {
  std::string tmp = static_cast<rokko::parameters*>(params.ptr)->get_string(key);
  char* p = copy_string(tmp);
  return p;
}

int rokko_parameters_defined(struct rokko_parameters params, const char* key) {
  return static_cast<int>(static_cast<rokko::parameters*>(params.ptr)->defined(key));
}

int rokko_parameters_get_key_size(struct rokko_parameters params, const char* key) {
  return static_cast<rokko::parameters*>(params.ptr)->get_string(key).size();
}

int rokko_parameters_size(struct rokko_parameters params) {
  return static_cast<rokko::parameters*>(params.ptr)->get_map().size();
}

char** rokko_parameters_keys(struct rokko_parameters params) {
  rokko::parameters* ptr = static_cast<rokko::parameters*>(params.ptr);
  int num_keys = ptr->get_map().size();
  char** keys = (char**) malloc( sizeof(char*) * num_keys );
  int i = 0;
  for(auto const& term : ptr->get_map()) {
    keys[i] = copy_string(term.first);
    ++i;
  }
  return keys;
}

char* rokko_string_i(char** strings, int i) {
  //  std::cout << "i=" << i << " string" << strings[i] << std::endl;
  return strings[i];
}




<|start_filename|>tutorial/titpack/02_refactored_cxx/options.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#ifndef OPTIONS_HPP
#define OPTIONS_HPP

#include <iosfwd>

struct options {
  unsigned int N;
  bool valid;

  options(unsigned int argc, char *argv[], unsigned int N_def) :
    N(N_def), valid(true) {
    for (unsigned int i = 1; i < argc; ++i) {
      switch (argv[i][0]) {
      case '-' :
        switch (argv[i][1]) {
        case 'N' :
          if (++i == argc) { usage(); return; }
          N = std::stoi(argv[i]); break;
        case 'h' :
          usage(std::cout); return;
        default :
          usage(); return;
        }
        break;
      default :
        usage(); return;
      }
    }
    if (N <= 0) {
      std::cerr << "invalid parameter\n"; usage(); return;
    }
    std::cout << "System Size = " << N << '\n';
  }

  void usage(std::ostream& os = std::cerr) {
    os << "[command line options]\n"
       << "  -N int    System Size\n"
       << "  -h        this help\n";
    valid = false;
  }
};

#endif


<|start_filename|>rokko/eigenexa/eigen_get_id.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/ceigenexa.h>
#include <rokko/eigenexa/eigenexa_interface.h>

void ceigenexa_get_id(int* id, int* x_id, int* y_id) {
  EIGENEXA_get_id_wrap(id, x_id, y_id);
  *id -= 1;
  *x_id -= 1;
  *y_id -= 1;
}


<|start_filename|>config/use-rokko.cmake<|end_filename|>
#
# This module is provided as ROKKO_USE_FILE by rokko-config.cmake.  It can
# be included in a project to load the needed compiler and linker
# settings to use Rokko.
#

if(NOT ROKKO_USE_FILE_INCLUDED)
  set(ROKKO_USE_FILE_INCLUDED 1)
  list(APPEND CMAKE_MODULE_PATH ${ROKKO_ROOT_DIR}/share/rokko)

  # compilers and common options
  if(NOT PREVENT_ROKKO_COMPILERS)
    set(CMAKE_BUILD_TYPE ${ROKKO_CMAKE_BUILD_TYPE} CACHE STRING "Type of build" FORCE)
    message(STATUS "Build type: " ${CMAKE_BUILD_TYPE})

    set(CMAKE_C_COMPILER ${ROKKO_CMAKE_C_COMPILER} CACHE FILEPATH "C compiler." FORCE)
    set(CMAKE_C_FLAGS ${ROKKO_CMAKE_C_FLAGS} CACHE STRING "Flags used by the compiler during all build types." FORCE)
    set(CMAKE_C_FLAGS_DEBUG ${ROKKO_CMAKE_C_FLAGS_DEBUG} CACHE STRING "Flags used by the compiler during debug builds." FORCE)
    set(CMAKE_C_FLAGS_RELEASE ${ROKKO_CMAKE_C_FLAGS_RELEASE} CACHE STRING "Flags used by the compiler during release builds." FORCE)
    set(CMAKE_CXX_COMPILER ${ROKKO_CMAKE_CXX_COMPILER} CACHE FILEPATH "CXX compiler." FORCE)
    set(CMAKE_CXX_FLAGS ${ROKKO_CMAKE_CXX_FLAGS} CACHE STRING "Flags used by the compiler during all build types." FORCE)
    set(CMAKE_CXX_FLAGS_DEBUG ${ROKKO_CMAKE_CXX_FLAGS_DEBUG} CACHE STRING "Flags used by the compiler during debug builds." FORCE)
    set(CMAKE_CXX_FLAGS_RELEASE ${ROKKO_CMAKE_CXX_FLAGS_RELEASE} CACHE STRING "Flags used by the compiler during release builds." FORCE)
    set(CMAKE_Fortran_COMPILER ${ROKKO_CMAKE_Fortran_COMPILER} CACHE FILEPATH "Fortran compiler." FORCE)
    set(CMAKE_Fortran_FLAGS ${ROKKO_CMAKE_Fortran_FLAGS} CACHE STRING "Flags used by the compiler during all build types." FORCE)
    set(CMAKE_Fortran_FLAGS_DEBUG ${ROKKO_CMAKE_Fortran_FLAGS_DEBUG} CACHE STRING "Flags used by the compiler during debug builds." FORCE)
    set(CMAKE_Fortran_FLAGS_RELEASE ${ROKKO_CMAKE_Fortran_FLAGS_RELEASE} CACHE STRING "Flags used by the compiler during release builds." FORCE)
    set(CMAKE_BUILD_TYPE ${ROKKO_CMAKE_BUILD_TYPE} CACHE STRING "Type of build" FORCE)

    if(ROKKO_Fortran_BINDING)
      enable_language(CXX C Fortran)
    else(ROKKO_Fortran_BINDING)
      enable_language(CXX C)
    endif(ROKKO_Fortran_BINDING)

    # OpenMP
    find_package(OpenMP)
    if(OPENMP_FOUND)
      set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
      set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${OpenMP_Fortran_FLAGS}")
    endif(OPENMP_FOUND)

    # MPI library
    find_package(MPI)
    set(CMAKE_EXE_LINKER_FLAGS ${MPI_CXX_LINK_FLAGS})
    set(ROKKO_LIBRARIES ${ROKKO_LIBRARIES} ${MPI_CXX_LIBRARIES})

  endif(NOT PREVENT_ROKKO_COMPILERS)

  # Add include directories needed to use ROKKO and dependent libraries
  include_directories(${MPI_CXX_INCLUDE_PATH} ${MPI_Fortran_INCLUDE_PATH} ${ROKKO_INCLUDE_DIR} ${ROKKO_Boost_INCLUDE_DIR} ${ROKKO_EIGENEXA_INCLUDE_DIR} ${ROKKO_ELEMENTAL_INCLUDE_DIR} ${ROKKO_ANASAZI_INCLUDE_DIR} ${ROKKO_PETSC_INCLUDE_DIR} ${ROKKO_SLEPC_INCLUDE_DIR})

  # Add link directories needed to use ROKKO and dependent libraries
  link_directories(${ROKKO_ROOT_DIR}/lib)

  # RPATH setting
  set(CMAKE_INSTALL_NAME_DIR "${ROKKO_ROOT_DIR}/lib" FORCE)
  set(CMAKE_INSTALL_RPATH "${ROKKO_ROOT_DIR}/lib" FORCE)

  # test macro
  include(${ROKKO_ROOT_DIR}/share/rokko/add_rokko_test.cmake)
endif(NOT ROKKO_USE_FILE_INCLUDED)

macro(display_rokko_components)
  message(STATUS "Boost_INCLUDE_DIR=${ROKKO_Boost_INCLUDE_DIR}")

  message(STATUS "Solvers:")
  # serial dense solvers
  message(STATUS "  BLAS_LIBRARIES=${ROKKO_BLAS_LIBRARIES}")
  message(STATUS "  LAPACK_LIBRARIES=${ROKKO_LAPACK_LIBRARIES}")

  # parallel dense solvers
  message(STATUS "  ROKKO_HAVE_SCALAPACK:" ${ROKKO_HAVE_SCALAPACK})
  if(ROKKO_HAVE_SCALAPACK)
    message(STATUS "  SCALAPACK_LIBRARIES=${ROKKO_SCALAPACK_LIBRARIES}")
  endif(ROKKO_HAVE_SCALAPACK)

  message(STATUS "  ROKKO_HAVE_EIGENEXA:" ${ROKKO_HAVE_EIGENEXA})
  if(ROKKO_HAVE_EIGENEXA)
    message(STATUS "  EIGENEXA_INCLUDE_DIR=${ROKKO_EIGENEXA_INCLUDE_DIR}")
    message(STATUS "  EIGENEXA_LIBRARIES=${ROKKO_EIGENEXA_LIBRARIES}")
  endif(ROKKO_HAVE_EIGENEXA)

  message(STATUS "  ROKKO_HAVE_ELPA:" ${ROKKO_HAVE_ELPA})
  if(ROKKO_HAVE_ELPA)
    message(STATUS "  ELPA_INCLUDE_DIR=${ROKKO_ELPA_INCLUDE_DIR}")
    message(STATUS "  ELPA_LIBRARIES=${ROKKO_ELPA_LIBRARIES}")
  endif(ROKKO_HAVE_ELPA)

  message(STATUS "  ROKKO_HAVE_ELEMENTAL:" ${ROKKO_HAVE_ELEMENTAL})
  if(ROKKO_HAVE_ELEMENTAL)
    message(STATUS "  ELEMENTAL_INCLUDE_DIR=${ROKKO_ELEMENTAL_INCLUDE_DIR}")
    message(STATUS "  ELEMENTAL_LIBRARIES=${ROKKO_ELEMENTAL_LIBRARIES}")
  endif(ROKKO_HAVE_ELEMENTAL)

  # parallel sparse solvers
  message(STATUS "  ROKKO_HAVE_PETSC:" ${ROKKO_HAVE_PETSC})
  if(ROKKO_HAVE_PETSC)
    message(STATUS "  PETSC_INCLUDE_DIR=${ROKKO_PETSC_INCLUDE_DIR}")
    message(STATUS "  PETSC_LIBRARIES=${ROKKO_PETSC_LIBRARIES}")
  endif(ROKKO_HAVE_PETSC)

  message(STATUS "  ROKKO_HAVE_SLEPC:" ${ROKKO_HAVE_SLEPC})
  if(ROKKO_HAVE_SLEPC)
    message(STATUS "  SLEPC_INCLUDE_DIR=${ROKKO_SLEPC_INCLUDE_DIR}")
    message(STATUS "  SLEPC_LIBRARIES=${ROKKO_SLEPC_LIBRARIES}")
  endif(ROKKO_HAVE_SLEPC)

  message(STATUS "  ROKKO_HAVE_ANASAZI:" ${ROKKO_HAVE_ANASAZI})
  if(ROKKO_HAVE_ANASAZI)
    message(STATUS "  ANASAZI_INCLUDE_DIR=${ROKKO_ANASAZI_INCLUDE_DIR}")
    message(STATUS "  ANASAZI_LIBRARIES=${ROKKO_ANASAZI_LIBRARIES}")
  endif(ROKKO_HAVE_ANASAZI)

  # paths for the all solvers
  message(STATUS "ROKKO_INCLUDE_DIR=${ROKKO_INCLUDE_DIR}")
  message(STATUS "ROKKO_LIBRARIES=${ROKKO_LIBRARIES}")

  message(STATUS "ROKKO_HAVE_SERIAL_DENSE_SOLVER:" ${ROKKO_HAVE_SERIAL_DENSE_SOLVER})
  message(STATUS "ROKKO_HAVE_PARALLEL_DENSE_SOLVER:" ${ROKKO_HAVE_PARALLEL_DENSE_SOLVER})
  message(STATUS "ROKKO_HAVE_PARALLEL_SPARSE_SOLVER:" ${ROKKO_HAVE_PARALLEL_SPARSE_SOLVER})

  # bindings
  message(STATUS "ROKKO_Python_BINDING:" ${ROKKO_Python_BINDING})

endmacro(display_rokko_components)


<|start_filename|>rokko/parallel_dense_ev.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_PARALLEL_DENSE_EV_H
#define ROKKO_PARALLEL_DENSE_EV_H

#include <rokko/grid.h>
#include <rokko/mapping_bc.h>
#include <rokko/distributed_matrix.h>
#include <rokko/eigen_vector.h>
#include <rokko/parameters.h>

#ifdef __cplusplus
extern "C" {
#endif

struct rokko_parallel_dense_ev {
  void* ptr;
};

void rokko_parallel_dense_ev_construct(struct rokko_parallel_dense_ev* solver,
  const char* solver_name, int argc, char** argv);
void rokko_parallel_dense_ev_construct_f(struct rokko_parallel_dense_ev* solver,
  const char* solver_name);
void rokko_parallel_dense_ev_destruct(struct rokko_parallel_dense_ev* solver);

struct rokko_parameters rokko_parallel_dense_ev_diagonalize(
  struct rokko_parallel_dense_ev solver, struct rokko_distributed_matrix mat,
  struct rokko_eigen_vector eigval, struct rokko_distributed_matrix eigvecs, struct rokko_parameters);
struct rokko_parameters rokko_parallel_dense_ev_diagonalize_distributed_matrix(
  struct rokko_parallel_dense_ev solver, struct rokko_distributed_matrix mat,
  struct rokko_eigen_vector eigval, struct rokko_distributed_matrix eigvecs);
struct rokko_parameters rokko_parallel_dense_ev_diagonalize_eigvals(
  struct rokko_parallel_dense_ev solver, struct rokko_distributed_matrix mat,
  struct rokko_eigen_vector eigval);
struct rokko_parameters rokko_parallel_dense_ev_diagonalize_eigvals_params(
  struct rokko_parallel_dense_ev solver, struct rokko_distributed_matrix mat,
  struct rokko_eigen_vector eigvals, struct rokko_parameters params);
struct rokko_parameters rokko_parallel_dense_ev_diagonalize_params(
  struct rokko_parallel_dense_ev solver, struct rokko_distributed_matrix mat,
  struct rokko_eigen_vector eigvals, struct rokko_distributed_matrix eigvecs,
  struct rokko_parameters params);

/* For Fortran binding */
void rokko_parallel_dense_ev_construct_f(struct rokko_parallel_dense_ev* solver,
  const char* solver_name);
void rokko_parallel_dense_ev_diagonalize_f(struct rokko_parallel_dense_ev* solver,
					 struct rokko_distributed_matrix* mat, struct rokko_eigen_vector* eigvals,
					 struct rokko_distributed_matrix* eigvecs,
					 struct rokko_parameters* params, struct rokko_parameters* params_out);

void rokko_parallel_dense_ev_diagonalize_no_params_out_f(struct rokko_parallel_dense_ev* solver,
						       struct rokko_distributed_matrix* mat, struct rokko_eigen_vector* eigvals,
						       struct rokko_distributed_matrix* eigvecs,
						       struct rokko_parameters* params);

void rokko_parallel_dense_ev_diagonalize_no_params_inout_f(struct rokko_parallel_dense_ev* solver,
						       struct rokko_distributed_matrix* mat, struct rokko_eigen_vector* eigvals,
						       struct rokko_distributed_matrix* eigvecs);

void rokko_parallel_dense_ev_diagonalize_eigvals_f(struct rokko_parallel_dense_ev* solver,
						 struct rokko_distributed_matrix* mat, struct rokko_eigen_vector* eigvals,
						 struct rokko_parameters* params, struct rokko_parameters* params_out);

void rokko_parallel_dense_ev_diagonalize_eigvals_no_params_out_f(struct rokko_parallel_dense_ev* solver,
							       struct rokko_distributed_matrix* mat, struct rokko_eigen_vector* eigvals,
							       struct rokko_parameters* params);

void rokko_parallel_dense_ev_diagonalize_eigvals_no_params_inout_f(struct rokko_parallel_dense_ev* solver,
								 struct rokko_distributed_matrix* mat, struct rokko_eigen_vector* eigvals);

struct rokko_mapping_bc rokko_parallel_dense_ev_default_mapping(struct rokko_parallel_dense_ev solver, int dim, struct rokko_grid g);
void rokko_parallel_dense_ev_default_mapping_f(struct rokko_parallel_dense_ev solver, int dim, struct rokko_grid g, struct rokko_mapping_bc* map);

int rokko_parallel_dense_ev_num_solvers();
char** rokko_parallel_dense_ev_solvers();
const char* rokko_parallel_dense_ev_default_solver();

#ifdef __cplusplus
}
#endif

#endif /* ROKKO_PARALLEL_DENSE_EV_H */


<|start_filename|>tutorial/titpack/03_rokko_cxx/medium.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

// C++ version of TITPACK Ver.2 by <NAME>

#ifndef TITPACK_MEDIUM_HPP
#define TITPACK_MEDIUM_HPP

#include "common.hpp"
#include "hamiltonian.hpp"

template<typename CRS_MATRIX>
void elm2_mpi(hamiltonian const& hop, CRS_MATRIX& mat) {
  int ibond = hop.num_bonds();
  std::vector<int> cols;
  std::vector<double> values;
  const auto& map = mat.get_map();
  for (int i = map.start_row(); i < map.end_row(); ++i) {
    cols.clear();
    values.clear();
    double diag = 0;

    // diagonal element
    for (int k = 0; k < ibond; ++k) {
      int isite1, isite2;
      std::tie(isite1, isite2) = hop.site_pair(k);
      int is = (1 << isite1) + (1 << isite2);
      double wght = -hop.bond_weight(k) * hop.z_ratio(k) * 0.5;
      int ibit = hop.config(i) & is;
      diag += (ibit == 0 || ibit == is) ? wght : -wght;
    }
    cols.emplace_back(i);
    values.emplace_back(diag);

    // off-diagonal elements
    for (int k = 0; k < ibond; ++k) {
      int isite1, isite2;
      std::tie(isite1, isite2) = hop.site_pair(k);
      int is = (1 << isite1) + (1 << isite2);
      double wght = -hop.bond_weight(k);
      int ibit = hop.config(i) & is;
      if (ibit != 0 && ibit != is) {
        cols.emplace_back(hop.config2index(hop.config(i) ^ is));
        values.emplace_back(wght);
      }
    }
    mat.insert(i, cols, values);
  }
  mat.complete();
}

#endif


<|start_filename|>rokko/distributed_matrix_c.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/distributed_matrix.h>
#include <rokko/distributed_matrix.hpp>

void rokko_distributed_matrix_construct(struct rokko_distributed_matrix* matrix, struct rokko_mapping_bc map) {
  if (map.major == rokko_matrix_col_major)
    matrix->ptr = new rokko::distributed_matrix<double, rokko::matrix_col_major>(*static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr));
  else
    matrix->ptr = new rokko::distributed_matrix<double, rokko::matrix_row_major>(*static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr));
  matrix->major = map.major;
}

void rokko_distributed_matrix_construct_array(struct rokko_distributed_matrix* matrix, struct rokko_mapping_bc map, double *array) {
  if (map.major == rokko_matrix_col_major)
    matrix->ptr = new rokko::distributed_matrix<double, rokko::matrix_col_major>(*static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr), array);
  else
    matrix->ptr = new rokko::distributed_matrix<double, rokko::matrix_row_major>(*static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr), array);
  matrix->major = map.major;
}

void rokko_distributed_matrix_construct_array_sizes(struct rokko_distributed_matrix* matrix, struct rokko_mapping_bc map, int dim1, int dim2, double *array) {
  if (map.major == rokko_matrix_col_major)
    matrix->ptr = new rokko::distributed_matrix<double, rokko::matrix_col_major>(*static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr), array);
  else
    matrix->ptr = new rokko::distributed_matrix<double, rokko::matrix_row_major>(*static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr), array);
  matrix->major = map.major;
}

void rokko_distributed_matrix_destruct(struct rokko_distributed_matrix* matrix) {
  if (matrix->major == rokko_matrix_col_major)
    delete static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix->ptr);
  else
    delete static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix->ptr);
  matrix->ptr = nullptr;
}

void rokko_distributed_matrix_generate_function(struct rokko_distributed_matrix matrix,
						double (*func)(int i, int j)) {
  if (matrix.major == rokko_matrix_col_major)
    static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->generate(func);
  else
    static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->generate(func);
}

void rokko_distributed_matrix_generate_function_p(struct rokko_distributed_matrix matrix,
						double (*func)(const int* i, const int* j)) {
  const auto g = [&func](int i, int j) { return func(&i, &j); };

  if (matrix.major == rokko_matrix_col_major)
    static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->generate(g);
  else
    static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->generate(g);
}

void rokko_distributed_matrix_generate_function1(struct rokko_distributed_matrix matrix,
						double (*func)(int i, int j)) {
  auto const g = [&func](int i, int j) { return func(i+1, j+1); };

  if (matrix.major == rokko_matrix_col_major)
    static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->generate(g);
  else
    static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->generate(g);
}

void rokko_distributed_matrix_generate_function1_p(struct rokko_distributed_matrix matrix,
						double (*func)(const int* i, const int* j)) {
  const auto g = [&func](int i, int j) {
    const int i1 = i+1, j1 = j+1;
    return func(&i1, &j1);
  };
  
  if (matrix.major == rokko_matrix_col_major)
    static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->generate(g);
  else
    static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->generate(g);
}

void rokko_distributed_matrix_print(rokko_distributed_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->print();
  else
    static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->print();
}

void rokko_distributed_matrix_set_local(rokko_distributed_matrix matrix, int local_i, int local_j, double value) {
  if (matrix.major == rokko_matrix_col_major)
    static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->set_local(local_i,local_j,value);
  else
    static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->set_local(local_i,local_j,value);
}

double rokko_distributed_matrix_get_local(rokko_distributed_matrix matrix, int local_i, int local_j) { 
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_local(local_i,local_j);
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_local(local_i,local_j);
}

void rokko_distributed_matrix_set_global(rokko_distributed_matrix matrix, int global_i, int global_j, double value) {
  if (matrix.major == rokko_matrix_col_major)
    static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->set_global(global_i,global_j,value);
  else
    static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->set_global(global_i,global_j,value);
}

double rokko_distributed_matrix_get_global(rokko_distributed_matrix matrix, int global_i, int global_j) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_global(global_i,global_j);
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_global(global_i,global_j);
}

void rokko_distributed_matrix_set_local1(rokko_distributed_matrix matrix, int local_i, int local_j, double value) {
  if (matrix.major == rokko_matrix_col_major)
    static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->set_local(local_i-1,local_j-1,value);
  else
    static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->set_local(local_i-1,local_j-1,value);
}

double rokko_distributed_matrix_get_local1(rokko_distributed_matrix matrix, int local_i, int local_j) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_local(local_i-1,local_j-1);
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_local(local_i-1,local_j-1);
}

void rokko_distributed_matrix_set_global1(rokko_distributed_matrix matrix, int global_i, int global_j, double value) {
  if (matrix.major == rokko_matrix_col_major)
    static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->set_global(global_i-1,global_j-1,value);
  else
    static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->set_global(global_i-1,global_j-1,value);
}

double rokko_distributed_matrix_get_global1(rokko_distributed_matrix matrix, int global_i, int global_j) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_global(global_i-1,global_j-1);
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_global(global_i-1,global_j-1);
}

int rokko_distributed_matrix_get_mb(struct rokko_distributed_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_mb();
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_mb();
}

int rokko_distributed_matrix_get_nb(struct rokko_distributed_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_nb();
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_nb();
}

int rokko_distributed_matrix_get_m_local(struct rokko_distributed_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_m_local();
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_m_local();
}

int rokko_distributed_matrix_get_n_local(struct rokko_distributed_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_n_local();
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_n_local();
}

int rokko_distributed_matrix_get_m_global(struct rokko_distributed_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_m_global();
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_m_global();
}

int rokko_distributed_matrix_get_n_global(struct rokko_distributed_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_n_global();
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_n_global();
}

int rokko_distributed_matrix_get_lld(struct rokko_distributed_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_lld();
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_lld();
}

int rokko_distributed_matrix_get_m_size(struct rokko_distributed_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_m_size();
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_m_size();
}

int rokko_distributed_matrix_get_n_size(struct rokko_distributed_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_n_size();
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_n_size();
}

int rokko_distributed_matrix_get_nprocs(struct rokko_distributed_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_nprocs();
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_nprocs();
}

int rokko_distributed_matrix_get_myrank(struct rokko_distributed_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_myrank();
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_myrank();
}

int rokko_distributed_matrix_get_nprow(struct rokko_distributed_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_nprow();
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_nprow();
}

int rokko_distributed_matrix_get_npcol(struct rokko_distributed_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_npcol();
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_npcol();
}

int rokko_distributed_matrix_get_myrow(struct rokko_distributed_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_myrow();
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_myrow();
}

int rokko_distributed_matrix_get_mycol(struct rokko_distributed_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_mycol();
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_mycol();
}

int rokko_distributed_matrix_translate_l2g_row(struct rokko_distributed_matrix matrix, int local_i) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->translate_l2g_row(local_i);
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->translate_l2g_row(local_i);
}

int rokko_distributed_matrix_translate_l2g_col(struct rokko_distributed_matrix matrix, int local_j) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->translate_l2g_col(local_j);
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->translate_l2g_col(local_j);
}

int rokko_distributed_matrix_translate_g2l_row(struct rokko_distributed_matrix matrix, int global_i) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->translate_g2l_row(global_i);
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->translate_g2l_row(global_i);
}

int rokko_distributed_matrix_translate_g2l_col(struct rokko_distributed_matrix matrix, int global_j) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->translate_g2l_col(global_j);
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->translate_g2l_col(global_j);
}

// offset by one for Fortran
int rokko_distributed_matrix_translate_l2g_row1(struct rokko_distributed_matrix matrix, int local_i) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->translate_l2g_row(local_i - 1) + 1;
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->translate_l2g_row(local_i - 1) + 1;
}

int rokko_distributed_matrix_translate_l2g_col1(struct rokko_distributed_matrix matrix, int local_j) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->translate_l2g_col(local_j - 1) + 1;
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->translate_l2g_col(local_j - 1) + 1;
}

int rokko_distributed_matrix_translate_g2l_row1(struct rokko_distributed_matrix matrix, int global_i) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->translate_g2l_row(global_i - 1) + 1;
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->translate_g2l_row(global_i - 1) + 1;
}

int rokko_distributed_matrix_translate_g2l_col1(struct rokko_distributed_matrix matrix, int global_j) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->translate_g2l_col(global_j - 1) + 1;
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->translate_g2l_col(global_j - 1) + 1;
}

bool rokko_distributed_matrix_is_row_major(struct rokko_distributed_matrix matrix) {
  return matrix.major == rokko_matrix_row_major;
}

bool rokko_distributed_matrix_is_col_major(struct rokko_distributed_matrix matrix) {
  return matrix.major == rokko_matrix_col_major;
}

double* rokko_distributed_matrix_get_array_pointer(struct rokko_distributed_matrix matrix) { 
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr)->get_array_pointer();
  else
    return static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr)->get_array_pointer();
}




<|start_filename|>rokko/scalapack/pstebz.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <stdlib.h>
#include <rokko/scalapack/scalapack_interface.h>

#define CSCALAPACK_PSTEBZ_IMPL(NAMES, NAMEL, TYPE) \
int cscalapack_## NAMES (int ictxt, char range, char order, int n, \
                         TYPE vl, TYPE vu, int il, int iu, \
                         TYPE abstol, const TYPE* d, const TYPE* e, int* m, int* nsplit, \
                         TYPE* w, int* iblock, int* isplit) { \
  /* call for querying optimal size of work array */ \
  int lwork = -1; \
  int liwork = -1; \
  TYPE work_query[1]; \
  int iwork_query[1]; \
  int info; \
  info = cscalapack_## NAMES ##_work(ictxt, range, order, n, \
                                     vl, vu, il, iu, \
                                     abstol, d, e, m, nsplit, \
                                     w, iblock, isplit, \
                                     work_query, lwork, iwork_query, liwork); \
  if (info) return info; \
  \
  /* allocate work arrays */ \
  lwork = (int)work_query[0]; \
  TYPE* work = (TYPE*)malloc( sizeof(TYPE) * lwork ); \
  liwork = iwork_query[0]; \
  int* iwork = (int*)malloc( sizeof(int) * liwork ); \
  if (work == NULL || iwork == NULL) return 1; \
  \
  /* call for computation */ \
  info = cscalapack_## NAMES ##_work(ictxt, range, order, n, \
                                     vl, vu, il, iu, \
                                     abstol, d, e, m, nsplit, \
                                     w, iblock, isplit, \
                                     work, lwork, iwork, liwork); \
  free(work); \
  free(iwork); \
  return info; \
}

CSCALAPACK_PSTEBZ_IMPL(psstebz, PSSTEBZ, float)
CSCALAPACK_PSTEBZ_IMPL(pdstebz, PDSTEBZ, double)

#undef CSCALAPACK_PSTEBZ_IMPL


<|start_filename|>rokko/lapack/storage.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_STORAGE_HPP
#define ROKKO_LAPACK_STORAGE_HPP

#include <rokko/lapack/null_matrix.hpp>
#include <vector>

namespace rokko {
namespace lapack {

template <typename T>
T* storage(T* ptr) { return ptr; }

template <typename T>
const T* storage(const T* ptr) { return ptr; }

template <typename T>
T* storage(std::vector<T>& vec) { return vec.data(); }

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_STORAGE_HPP


<|start_filename|>rokko/grid.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_GRID_HPP
#define ROKKO_GRID_HPP

#include <array>
#include <iostream>
#include <mpi.h>
#include <cmath>
#include <rokko/mpi_communicator.hpp>
#include <rokko/blacs_grid.hpp>

namespace rokko {

extern struct grid_row_major_t {} grid_row_major;

extern struct grid_col_major_t {} grid_col_major;

class grid : public mpi_comm, public blacs_grid {
public:
  template <typename GRID_MAJOR>
  grid(MPI_Comm comm_in, GRID_MAJOR const& grid_major = grid_row_major)
    : mpi_comm(comm_in) {
    if (comm == MPI_COMM_NULL) {
      set_size({0, 0});  // to avoid zero dividing and blacs does not take (0,0) size grid
      set_my_coordinate({-1,-1});
      return;
    }

    if (is_MPI_2dim_Cart(comm))
      set_sizes_cart(grid_major);
    else
      set_sizes_default(grid_major);

    set_blacs_grid(get_comm(), is_row_major(), get_size());
  }

  template <typename GRID_MAJOR>
  grid(MPI_Comm comm_in, std::array<int,2> const& size_in, GRID_MAJOR const& grid_major = grid_row_major) : mpi_comm(comm_in) {
    if ((std::get<0>(size_in) * std::get<1>(size_in)) != nprocs) {
      throw std::invalid_argument("grid::grid() : (rows * cols) != nprocs");
    }

    set_size(size_in);

    set_major<GRID_MAJOR>();

    set_my_coordinate();

    set_blacs_grid(get_comm(), is_row_major(), get_size());
  }

  explicit grid(MPI_Comm comm_in = MPI_COMM_WORLD) : grid(comm_in, grid_row_major) {}

  static int find_square_root_like_divisor(int n) {
    int i = int(std::sqrt((double)n));
    for (; i > 1; --i) {
      if ( (n % i) == 0 ) break;
    }
    return i;
  }

  int get_nprow() const { return std::get<0>(size); }
  int get_npcol() const { return std::get<1>(size); }
  std::array<int,2> get_size() const { return size; }
  int get_myrow() const { return std::get<0>(my_coordinate); }
  int get_mycol() const { return std::get<1>(my_coordinate); }
  std::array<int,2> get_my_coordinate() const { return my_coordinate; }

  void set_size(std::array<int,2> const& size_in) { size = size_in; }
  void set_my_coordinate(std::array<int,2> const& my_coordinate_in) { my_coordinate = my_coordinate_in; }
  void set_my_coordinate() { set_my_coordinate(calculate_coordinate(myrank)); }

  template <typename GRID_MAJOR>
  void set_major() { is_row = std::is_same<GRID_MAJOR, grid_row_major_t>::value; }

  bool is_row_major() const { return is_row; }
  bool is_col_major() const { return !is_row; }

  int calculate_grid_row(int proc_rank) const { 
    return is_row ? proc_rank / size[1] : proc_rank % size[0];
  }
  int calculate_grid_col(int proc_rank) const { 
    return is_row ? proc_rank % size[1] : proc_rank / size[0];
  }

  std::array<int,2> calculate_coordinate(int proc_rank) const {
    return {calculate_grid_row(proc_rank), calculate_grid_col(proc_rank)};
  }

  int calculate_rank_form_coords(int proc_row, int proc_col) const {
    return is_row ? (proc_row * size[1] + proc_col)
      : (proc_col * size[0] + proc_row);
  }

protected:
  template <typename GRID_MAJOR>
  void set_sizes_default(GRID_MAJOR) {
    int nprow = find_square_root_like_divisor(nprocs);
    set_size({nprow, nprocs/nprow});
    set_major<GRID_MAJOR>();
    set_my_coordinate();
  }

  static std::string mpi_error_string(int ierr) {
    if (ierr == MPI_ERR_TOPOLOGY)
      return "MPI_ERR_TOPOLOGY";
    else if (ierr == MPI_ERR_COMM)
      return "MPI_ERR_COMM";
    else if (ierr == MPI_ERR_ARG)
      return "MPI_ERR_ARG";
    else
      return "MPI_SUCCESS";
  }

  void set_sizes_cart(grid_row_major_t) {
    constexpr int cart_dim = 2;
    std::array<int,2> dims, periods, coords;
    int ierr = MPI_Cart_get(comm, cart_dim, dims.data(), periods.data(), coords.data());
    if (ierr != MPI_SUCCESS)
      throw std::invalid_argument("set_sizes_cart : MPI_Cart_get returns " + mpi_error_string(ierr));

    set_size(dims);
    set_my_coordinate(coords);

    set_major<grid_row_major_t>();
  }

  static void set_sizes_cart(grid_col_major_t) {
    throw std::invalid_argument("calculate_sizes_cart : MPI Cartesian doesn't support grid_col_major.  Use it with grid_row_major.");
  }

private:
  std::array<int,2> size, my_coordinate;
  bool is_row;
};

} // namespace rokko

#endif // ROKKO_GRID_HPP


<|start_filename|>rokko/scalapack/diagonalize_psyevx.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_DIAGONALIZE_PSYEVX_HPP
#define ROKKO_SCALAPACK_DIAGONALIZE_PSYEVX_HPP

#include <rokko/distributed_matrix.hpp>
#include <rokko/parameters.hpp>
#include <rokko/cscalapack.h>
#include <rokko/lapack/diagonalize_get_parameters.hpp>
#include <rokko/scalapack/psyevx.hpp>
#include <rokko/utility/timer.hpp>

#include <mpi.h>

namespace rokko {
namespace scalapack {

// eigenvalues & eigenvectors
template<typename T, typename VEC>
parameters diagonalize_psyevx(distributed_matrix<T, rokko::matrix_col_major>& mat,
			       VEC& eigvals, distributed_matrix<T, rokko::matrix_col_major>& eigvecs,
			       parameters const& params) {
  parameters params_out;
  const char uplow = lapack::get_matrix_part(params);
  real_t<T> vl, vu;
  int il, iu;
  const char range = lapack::get_eigenvalues_range(params, vl, vu, il, iu);
  const int ictxt = mat.get_grid().get_blacs_context();
  real_t<T> abstol = params.defined("abstol") ? params.get<real_t<T>>("abstol") : cscalapack_pdlamch(ictxt, 'U');
  real_t<T> orfac = params.defined("orfac") ? params.get<real_t<T>>("orfac") : -1.;  // default value is 10^{-3} for a minus value.
  std::vector<int> ifail(mat.get_m_global());
  std::vector<int> iclustr(2 * mat.get_nprow() * mat.get_npcol());
  std::vector<real_t<T>> gap(mat.get_nprow() * mat.get_npcol());
  int m, nz;
  int info = psyevx(range, uplow, mat,
                    vl, vu, il, iu,
                    abstol, m, nz,
                    eigvals, orfac, eigvecs,
                    ifail, iclustr, gap);
  params_out.set("info", info);
  params_out.set("m", m);
  params_out.set("nz", nz);
  params_out.set("ifail", ifail);
  params_out.set("iclustr", iclustr);
  params_out.set("gap", gap);
  if (params.get_bool("verbose")) {
    lapack::print_verbose("syevx", 'V', range, uplow, vl, vu, il, iu, params_out);
  }
  return params_out;
}

template<typename T, typename VEC>
parameters diagonalize_psyevx(distributed_matrix<T, rokko::matrix_row_major>& mat,
			       VEC& eigvals, distributed_matrix<T, rokko::matrix_row_major>& eigvecs,
			       parameters const& params) {
  throw std::invalid_argument("scalapack::diagonalize_psyevx() : scalapack doesn't support matrix_row_major.  Use scalapack with matrix_col_major.");
}

// only eigenvalues
template<typename T, typename VEC>
parameters diagonalize_psyevx(distributed_matrix<T, rokko::matrix_col_major>& mat,
			       VEC& eigvals,
			       parameters const& params) {
  rokko::parameters params_out;
  const char uplow = lapack::get_matrix_part(params);
  real_t<T> vl, vu;
  int il, iu;
  const char range = lapack::get_eigenvalues_range(params, vl, vu, il, iu);
  const int ictxt = mat.get_grid().get_blacs_context();
  real_t<T> abstol = params.defined("abstol") ? params.get<real_t<T>>("abstol") : cscalapack_pdlamch(ictxt, 'U');
  real_t<T> orfac = params.defined("orfac") ? params.get<real_t<T>>("orfac") : -1.;  // default value is 10^{-3} for a minus value.
  std::vector<int> ifail(mat.get_m_global());
  std::vector<int> iclustr(2 * mat.get_nprow() * mat.get_npcol());
  std::vector<real_t<T>> gap(mat.get_nprow() * mat.get_npcol());
  int m, nz;
  int info = psyevx(range, uplow, mat,
                    vl, vu, il, iu,
                    abstol, m, nz, eigvals, orfac,
                    ifail, iclustr, gap);
  params_out.set("info", info);
  params_out.set("m", m);
  params_out.set("nz", nz);
  params_out.set("ifail", ifail);
  params_out.set("iclustr", iclustr);
  params_out.set("gap", gap);
  if (params.get_bool("verbose")) {
    lapack::print_verbose("syevx", 'N', range, uplow, vl, vu, il, iu, params_out);
  }
  return params_out;
}

template<typename T, typename VEC>
parameters diagonalize_psyevx(distributed_matrix<T, rokko::matrix_row_major>& mat,
			       VEC& eigvals,
			       parameters const& params) {
  throw std::invalid_argument("scalapack::diagonalize_psyevx() : scalapack doesn't support matrix_row_major.  Use scalapack with matrix_col_major.");
}

} // namespace scalapack
} // namespace rokko

#endif // ROKKO_SCALAPACK_DIAGONALIZE_PSYEVX_HPP


<|start_filename|>test/c/grid.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv) {
  int provided;
  struct rokko_grid grid;
  bool flag;
  int flag_int;
  
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);

  rokko_grid_construct(&grid, MPI_COMM_WORLD, rokko_grid_row_major);

  flag = rokko_grid_is_row_major(grid);
  printf("rokko_grid_is_row_major = %d\n", flag);
  flag = rokko_grid_is_col_major(grid);
  printf("rokko_grid_is_col_major = %d\n", flag);

  flag_int = rokko_grid_is_row_major(grid);
  printf("rokko_grid_is_row_major = %d\n", flag_int);
  flag_int = rokko_grid_is_col_major(grid);
  printf("rokko_grid_is_col_major = %d\n", flag_int);

  rokko_grid_destruct(&grid);

  MPI_Finalize();
}


<|start_filename|>rokko/slepc/distributed_mfree.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SLEPC_DISTRIBUTED_MFREE_HPP
#define ROKKO_SLEPC_DISTRIBUTED_MFREE_HPP

#include <rokko/distributed_mfree.hpp>

#include <rokko/slepc.hpp>

namespace rokko {

namespace slepc {

class distributed_mfree_holder : public rokko::distributed_mfree_holder {
  using rokko::distributed_mfree_holder::distributed_mfree_holder;
public:
  distributed_mfree_holder(std::function<void(const double *const, double *const)> const& multiply_in,
                           std::function<void(double *const)> const& fill_diagonal_in,
                           rokko::skel::mapping_1d const& map)
    : rokko::distributed_mfree_holder(multiply_in, map), fill_diagonal_(fill_diagonal_in) {}

  // For function pointer
  distributed_mfree_holder(void (*multiply_in)(const double *const, double *const),
                           void (*fill_diagonal_in)(double *const),
                           rokko::skel::mapping_1d const& map)
    : rokko::distributed_mfree_holder(multiply_in, map), fill_diagonal_(fill_diagonal_in) {}

  // For C binding
  distributed_mfree_holder(std::function<void(const double *const, double *const, void*)> const& multiply_in,
                           std::function<void(double *const, void*)> const& fill_diagonal_in,
                           void* vars, rokko::skel::mapping_1d const& map)
    : rokko::distributed_mfree_holder(multiply_in, vars, map), fill_diagonal_([fill_diagonal_in, vars](double *const x) {
        fill_diagonal_in(x, vars);
      }) {}

  // For Fortran binding
  distributed_mfree_holder(std::function<void(const int*, const double *const, double *const)> const& multiply_in,
                           std::function<void(const int*, double *const)> const& fill_diagonal_in,
                           rokko::skel::mapping_1d const& map)
    : rokko::distributed_mfree_holder(multiply_in, map), fill_diagonal_([this, fill_diagonal_in](double *const x) {
        int num_local_rows = get_num_local_rows();
        fill_diagonal_in(&num_local_rows, x);
      }) {}

  // Use Eigen3 for Python binding
  distributed_mfree_holder(std::function<void(ConstMapVec,MapVec)> const& multiply_in,
                           std::function<void(MapVec)> const& fill_diagonal_in,
                           rokko::skel::mapping_1d const& map)
    : rokko::distributed_mfree_holder(multiply_in, map), fill_diagonal_([this, fill_diagonal_in](double *const x) {
        const int num_local_rows = get_num_local_rows();
        MapVec  X(x, num_local_rows);
        fill_diagonal_in(X);
      }) {}

  ~distributed_mfree_holder() = default;

  void fill_diagonal(double *const x) const override {
    fill_diagonal_(x);
  }

private:
  std::function<void(double *const)> fill_diagonal_;
};

} // end namespace slepc

} // end namespace rokko

#endif // ROKKO_SLEPC_DISTRIBUTED_MFREE_HPP


<|start_filename|>test/scalapack/plange.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2017 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <gtest/gtest.h>
#include <cmath>
#include <rokko/eigen3.hpp>
#include <rokko/distributed_matrix.hpp>
#include <rokko/scalapack.hpp>
#include <rokko/lapack.hpp>
#include <rokko/collective.hpp>

constexpr double eps = 1e-10;

TEST(lange, pdlange) {
  rokko::grid grid(MPI_COMM_WORLD);

  int m = 20;
  int n = 30;

  // generate matrix
  Eigen::MatrixXd a(m, n);
  if (grid.get_myrank() == 0) a = Eigen::MatrixXd::Random(m, n);
  
  // distributed matrix
  rokko::mapping_bc<rokko::matrix_col_major> map({m, n}, {1, 1}, grid);
  rokko::distributed_matrix<double, rokko::matrix_col_major> mat(map);
  rokko::scatter(a, mat, 0);

  double norm, expect;
  
  norm = rokko::scalapack::plange('M', mat);
  if (grid.get_myrank() == 0) {
    expect = rokko::lapack::lange('M', a);
    std::cout << "max norm of A = " << norm << " (expect: " << expect << ")" << std::endl;
    EXPECT_NEAR(expect, norm, eps);
  }
  
  norm = rokko::scalapack::plange('1', mat);
  if (grid.get_myrank() == 0) {
    expect = rokko::lapack::lange('1', a);
    std::cout << "1-norm of A = " << norm << " (expect: " << expect << ")" << std::endl;
    EXPECT_NEAR(expect, norm, eps);
  }
  
  norm = rokko::scalapack::plange('I', mat);
  if (grid.get_myrank() == 0) {
    expect = rokko::lapack::lange('I', a);
    std::cout << "infinity norm of A = " << norm << " (expect: " << expect << ")" << std::endl;
    EXPECT_NEAR(expect, norm, eps);
  }
  
  norm = rokko::scalapack::plange('F', mat);
  if (grid.get_myrank() == 0) {
    expect = rokko::lapack::lange('F', a);
    std::cout << "Frobenius norm of A = " << norm << " (expect: " << expect << ")" << std::endl;
    EXPECT_NEAR(expect, norm, eps);
  }
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  MPI_Init(&argc, &argv);
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>rokko/mapping_global2local.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_MAPPING_GLOBAL2LOCAL_HPP
#define ROKKO_MAPPING_GLOBAL2LOCAL_HPP

#include <array>
#include <rokko/grid.hpp>
#include <rokko/mapping_common_sizes.hpp>

namespace rokko {

class mapping_global2local : virtual public mapping_common_sizes {
public:
  explicit mapping_global2local() = default;

  explicit mapping_global2local(std::array<int,2> const& global_size_in, std::array<int,2> const& block_size_in, grid const& g_in)
    : global_size(global_size_in),
      g(g_in), my_coordinate(g_in.get_my_coordinate()), grid_size(g_in.get_size()) {
    set_block_size(block_size_in);
    set_default_local_size();
    set_stride();
  }

  // For square matrix
  explicit mapping_global2local(int global_dim, int block_size, grid const& g_in)
    : mapping_global2local({global_dim, global_dim}, {block_size, block_size}, g_in) {}

  std::array<int,2> get_stride_mine() const { return stride_mine; }
  std::array<int,2> get_stride_grid() const { return stride_grid; }

  void set_stride_mine() {
    stride_mine[0] = my_coordinate[0] * block_size[0];
    stride_mine[1] = my_coordinate[1] * block_size[1];
  }

  void set_stride_grid() {
    stride_grid[0] = block_size[0] * (grid_size[0] - 1);
    stride_grid[1] = block_size[1] * (grid_size[1] - 1);
  }

  void set_stride() {
    set_stride_mine();
    set_stride_grid();
  }

  int get_m_global() const { return std::get<0>(global_size); }
  int get_n_global() const { return std::get<1>(global_size); }
  std::array<int,2> get_global_size() const { return global_size; }

  void set_default_local_size() {
    set_local_size(calculate_default_local_size(my_coordinate));
  }

  template <int IND>
  int calculate_default_local_size(int proc) const {
    const int quotient = global_size[IND] / block_size[IND];
    const int local_num_block = (quotient + (grid_size[IND]-1 - proc)) / grid_size[IND];
    const int remainder_proc = quotient % grid_size[IND];
    const int remainder_size = (proc == remainder_proc) ? global_size[IND] % block_size[IND] : 0;  // size of the remainder block (< block_size)
    return local_num_block * block_size[IND] + remainder_size;
  }

  std::array<int,2> calculate_default_local_size(std::array<int,2> const& proc) const {
    return {calculate_default_local_size<0>(proc[0]), calculate_default_local_size<1>(proc[1])};
  }

  template <int IND>
  int translate_l2g(int local_ind) const {
    return stride_mine[IND] + local_ind + (local_ind / block_size[IND]) * stride_grid[IND];
  }

  std::array<int,2> translate_l2g(std::array<int,2> const& local_indices) const {
    return {translate_l2g<0>(local_indices[0]), translate_l2g<1>(local_indices[1])};
  }

  int translate_l2g_row(int local_i) const {
    return translate_l2g<0>(local_i);
  }

  int translate_l2g_col(int local_j) const {
    return translate_l2g<1>(local_j);
  }

  template <int IND>
  int translate_g2l(int global_index) const {
    const int local_offset_block = global_index / block_size[IND];
    return (local_offset_block - my_coordinate[IND]) / grid_size[IND] * block_size[IND] + global_index % block_size[IND];
  }

  std::array<int,2> translate_g2l(std::array<int,2> const& global_indices) const {
    return {translate_g2l<0>(global_indices[0]), translate_g2l<1>(global_indices[1])};
  }

  int translate_g2l_row(int global_i) const {
    return translate_g2l<0>(global_i);
  }

  int translate_g2l_col(int global_j) const {
    return translate_g2l<1>(global_j);
  }

  template <int IND>
  bool has_global_indices(int global_index) const {
    const int local_offset_block = global_index / block_size[IND];
    return (local_offset_block % grid_size[IND]) == my_coordinate[IND];
  }

  bool has_global_row_index(int global_i) const {
    return has_global_indices<0>(global_i);
  }

  bool has_global_col_index(int global_j) const {
    return has_global_indices<1>(global_j);
  }

  bool has_global_indices(std::array<int,2> const& global_indices) const {
    return has_global_indices<0>(global_indices[0]) && has_global_indices<1>(global_indices[1]);
  }

  bool has_global_indices(int global_i, int global_j) const {
    return has_global_indices<0>(global_i) && has_global_indices<1>(global_j);
  }

  MPI_Comm get_comm() const { return g.get_comm(); }
  int get_nprow() const { return g.get_nprow(); }
  int get_npcol() const { return g.get_npcol(); }
  int get_nprocs() const { return g.get_nprocs(); }
  int get_myrank() const { return g.get_myrank(); }
  int get_myrow() const { return g.get_myrow(); }
  int get_mycol() const { return g.get_mycol(); }
  grid const& get_grid() const { return g; }

private:
  std::array<int,2> global_size;
  std::array<int,2> stride_mine, stride_grid;
  grid g;
  // common variables of class grid
  std::array<int,2> grid_size;
  std::array<int,2> my_coordinate;

  // block_number is also needed?
};

} // namespace rokko

#endif // ROKKO_MAPPING_GLOBAL2LOCAL_HPP


<|start_filename|>rokko/pblas/pdotu.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cpblas.h>

#define CPBLAS_PDOTU_IMPL(NAMES, NAMEL, TYPE) \
TYPE cpblas_ ## NAMES (int n, const TYPE * x, int ix, int jx, const int* descx, int incx, const TYPE * y, int iy, int jy, const int* descy, int incy) { \
  int ix_f = ix + 1; \
  int jx_f = jx + 1; \
  int iy_f = iy + 1; \
  int jy_f = jy + 1; \
  TYPE dotu; \
  ROKKO_GLOBAL(NAMES, NAMEL) (&n, &dotu, x, &ix_f, &jx_f, descx, &incx, y, &iy_f, &jy_f, descy, &incy); \
  return dotu; \
} \
void cpblas_ ## NAMES ## _sub (int n, TYPE * dotu, const TYPE * x, int ix, int jx, const int* descx, int incx, const TYPE * y, int iy, int jy, const int* descy, int incy) { \
  int ix_f = ix + 1; \
  int jx_f = jx + 1; \
  int iy_f = iy + 1; \
  int jy_f = jy + 1; \
  ROKKO_GLOBAL(NAMES, NAMEL) (&n, dotu, x, &ix_f, &jx_f, descx, &incx, y, &iy_f, &jy_f, descy, &incy); \
}

CPBLAS_PDOTU_IMPL(pcdotu, PCDOTU, lapack_complex_float);
CPBLAS_PDOTU_IMPL(pzdotu, PZDOTU, lapack_complex_double);

#undef CPBLAS_PDOTU_IMPL


<|start_filename|>rokko/blacs.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_BLACS_HPP
#define ROKKO_BLACS_HPP

#include <vector>
#include <rokko/Cblacs.h>

namespace rokko {
namespace blacs {

inline void barrier(int ictxt, char score) { Cblacs_barrier(ictxt, &score); }

inline MPI_Comm blacs2sys_handle(int BlacsCtxt) { return Cblacs2sys_handle(BlacsCtxt); }

inline void exit(int NotDone) { Cblacs_exit(NotDone); }
  
inline void free_blacs_system_handle(int ISysCxt) { Cfree_blacs_system_handle(ISysCxt); }

inline void get(int ConTxt, int what, int& val) { Cblacs_get(ConTxt, what, &val); }
  
inline void gridexit(int ConTxt) { Cblacs_gridexit(ConTxt); }

inline void gridinfo(int ConTxt, int& nprow, int& npcol, int& myrow, int& mycol) {
  Cblacs_gridinfo(ConTxt, &nprow, &npcol, &myrow, &mycol);
}

inline void gridinit(int& ConTxt, char order, int nprow, int npcol) {
  Cblacs_gridinit(&ConTxt, &order, nprow, npcol);
}

inline void gridmap(int& ConTxt, const std::vector<int>& usermap, int ldup,
                    int nprow0, int npcol0) {
  Cblacs_gridmap(&ConTxt, const_cast<int*>(usermap.data()), ldup, nprow0, npcol0);
}
  
inline int sys2blacs_handle(const MPI_Comm& comm) {
  return Csys2blacs_handle(comm);
}

} // end namespace blacs
} // end namespace rokko

#endif // ROKKO_BLACS_HPP


<|start_filename|>rokko/noncopyable.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_NONCOPYABLE_HPP
#define ROKKO_NONCOPYABLE_HPP

namespace rokko {

template <class T>
class noncopyable {
protected:
  noncopyable() = default;
  ~noncopyable() = default;

public:
  noncopyable(const noncopyable&) = delete;
  noncopyable& operator=(const noncopyable&) = delete;
};

} // end namespace rokko

#endif // ROKKO_NONCOPYABLE_HPP


<|start_filename|>rokko/utility/solver_name.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_SOLVER_NAME_HPP
#define ROKKO_UTILITY_SOLVER_NAME_HPP

#include <regex>
#include <vector>

namespace rokko {

void split_solver_name(std::string const& str, std::string& library, std::string& routine) {
  const std::regex separator{":"};
  auto it = std::sregex_token_iterator{str.cbegin(), str.cend(), separator, -1};
  const auto end_it = std::sregex_token_iterator{};
  if (it != end_it)
    library = *it++;

  if (it != end_it)
    routine = *it++;

  if (it != end_it)
    throw std::invalid_argument("split_solver_name() : More than one colon were detected from given string.");
}

} // namespace rokko

#endif // ROKKO_UTILITY_SOLVER_NAME_HPP


<|start_filename|>example/scalapack/pdstebz.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <mpi.h>
#include <math.h>
#include <stdio.h>
#include <rokko/Cblacs.h>
#include <rokko/cscalapack.h>
#include <rokko/cmatrix.h>


void laplacian_generate(int n, double* d, double* e) {
  int i;

  d[0] = 1;
  for(i = 1; i < n; ++i)
    d[i] = 2;
  for(i = 0; i < (n-1); ++i)
    e[i] = -1;
}

int main(int argc, char** argv) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  int nprocs, myrank;
  MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
  MPI_Comm_rank(MPI_COMM_WORLD, &myrank);

  int n = 8;
  if (argc > 1) n = atoi(argv[1]);

  int nprow = (int)(sqrt(1. * nprocs + 0.5));
  int npcol = (int)(1. * nprocs / nprow);
  if (myrank == 0) {
    printf("n = %d\n", n);
    printf("nprocs = %d\n", nprocs);
    printf("nprow = %d\n", nprow);
    printf("npcol = %d\n", npcol);
    if ((nprocs != nprow * npcol) || (n % nprow != 0) || (n % npcol != 0)) {
      printf("incompatible matrix size and number of processes");
      MPI_Abort(MPI_COMM_WORLD, 127);
    }
  }
  int context;
  Cblacs_get(0, 0, &context);
  char order = 'R';
  Cblacs_gridinit(&context, &order, nprow, npcol);

  double *d = alloc_dvector(n);
  double *e = alloc_dvector(n);
  laplacian_generate(n, d, e);

  double *w = alloc_dvector(n);

  char range = 'A', order_stored = 'E';
  double vl = 0, vu = 0.;
  int il = 0, iu = 0;
  double abstol = 0.;
  int m, nsplit;
  int *iblock = alloc_ivector(n);
  int *isplit = alloc_ivector(n);

  int info = cscalapack_pdstebz(context, range, order_stored, n,
                                vl, vu, il, iu,
                                abstol, d, e, &m, &nsplit,
                                w, iblock, isplit);

  if (info) {
    fprintf(stderr, "Error in cscalapack_pdstebz\n");
    MPI_Abort(MPI_COMM_WORLD, info);
  }
  if (myrank == 0) {
    printf("eigenvalues: ");
    fprint_dvector(stdout, n, vec_ptr(w));
  }

  free_ivector(iblock);
  free_ivector(isplit);
  free_dvector(w);
  free_dvector(d);
  free_dvector(e);
  Cblacs_gridexit(context);
  MPI_Finalize();
}


<|start_filename|>3rd-party/lapacke_mkl/lapacke.h<|end_filename|>
#ifdef __cplusplus
# include <complex>
# define lapack_complex_float std::complex<float>
# define lapack_complex_double std::complex<double>
#else
# include <complex.h>
# undef I
# define MKL_Complex8 complex float
# define MKL_Complex16 complex double
#endif

#include <mkl.h>
#include <mkl_lapacke.h>


<|start_filename|>example/blas/dgemv.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <stdio.h>
#include <cblas.h>
#include <rokko/cmatrix.h>

int main() {
  int n = 4;
  double** a = alloc_dmatrix(n, n);
  mat_elem(a, 0, 0) = 0.959291425205444;
  mat_elem(a, 0, 1) = 0.257508254123736;
  mat_elem(a, 0, 2) = 0.243524968724989;
  mat_elem(a, 0, 3) = 0.251083857976031;
  mat_elem(a, 1, 0) = 0.547215529963803;
  mat_elem(a, 1, 1) = 0.840717255983663;
  mat_elem(a, 1, 2) = 0.929263623187228;
  mat_elem(a, 1, 3) = 0.616044676146639;
  mat_elem(a, 2, 0) = 0.138624442828679;
  mat_elem(a, 2, 1) = 0.254282178971531;
  mat_elem(a, 2, 2) = 0.349983765984809;
  mat_elem(a, 2, 3) = 0.473288848902729;
  mat_elem(a, 3, 0) = 0.149294005559057;
  mat_elem(a, 3, 1) = 0.814284826068816;
  mat_elem(a, 3, 2) = 0.196595250431208;
  mat_elem(a, 3, 3) = 0.351659507062997;
  double* x = alloc_dvector(n);
  x[0] = 0.830828627896291;
  x[1] = 0.585264091152724;
  x[2] = 0.549723608291140;
  x[3] = 0.917193663829810;
  double* y = alloc_dvector(n);
  y[0] = 0.961898080855054;
  y[1] = 0.00463422413406744;
  y[2] = 0.774910464711502;
  y[3] = 0.817303220653433;
  double alpha = 2.3;
  double beta = 0.5;

  printf("a: "); fprint_dmatrix(stdout, n, n, a);
  printf("x: "); fprint_dvector(stdout, n, x);
  printf("y: "); fprint_dvector(stdout, n, y);
  
  cblas_dgemv(CblasColMajor, CblasNoTrans, n, n, alpha, mat_ptr(a), n, vec_ptr(x), 1,
              beta, vec_ptr(y), 1);

  printf("%10.5f * a * x + %10.5f * y: ", alpha, beta); fprint_dvector(stdout, n, y);

  free_dmatrix(a);
  free_dvector(x);
  free_dvector(y);
}

/* gemv.m

A = [0.959291425205444,0.257508254123736,0.243524968724989,0.251083857976031;0.547215529963803,0.840717255983663,0.929263623187228,0.616044676146639;0.138624442828679,0.254282178971531,0.349983765984809,0.473288848902729;0.149294005559057,0.814284826068816,0.196595250431208,0.351659507062997]
x = [0.830828627896291;0.585264091152724;0.549723608291140;0.917193663829810]
y = [0.961898080855054;0.00463422413406744;0.774910464711502;0.817303220653433]
2.3 * A * x + 0.5 * y

*/


<|start_filename|>test/generate_matrix/xyz_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <iostream>
#include <vector>
#include <tuple>

#include <rokko/solver.hpp>
#include <rokko/grid.hpp>
#include <rokko/distributed_matrix.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/utility/xyz_hamiltonian.hpp>
#include <rokko/utility/xyz_hamiltonian_mpi.hpp>
#include <rokko/collective.hpp>

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

TEST(xyz_hamiltonian, serial_mpi) {
  rokko::parallel_dense_ev solver;
  solver.initialize(global_argc, global_argv);
  rokko::grid g(MPI_COMM_WORLD);

  std::size_t L = 4;
  std::size_t num_bonds = L - 1;
  std::vector<std::pair<int, int>> lattice;
  std::vector<std::tuple<double, double, double>> coupling;
  for (std::size_t i=0; i<L-1; ++i) {
    lattice.emplace_back(std::make_pair(i, i+1));
    coupling.emplace_back(std::make_tuple(1, 0.3, 0.2));
  }

  int myrank, nprocs;
  MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
  MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
  constexpr int root = 0;

  if (myrank == root) {
    std::cout << "L=" << L << " num_bonds=" << num_bonds << std::endl;
    for (std::size_t i=0; i<num_bonds; ++i) {
      std::cout << lattice[i].first << " " << lattice[i].second << " "
                << std::get<0>(coupling[i]) << " " << std::get<1>(coupling[i]) << " " << std::get<2>(coupling[i]) << std::endl;
    }
  }

  const int p = rokko::find_power_of_two(nprocs);
  if (nprocs != (1 << p)) {    
    throw std::invalid_argument("This program can be run only with 2^n MPI processes");
  }
  int N = 1 << (L-p);

  int N_seq = 1 << L;
  int N_seq_proc = (myrank == root) ? N_seq : 0;
  Eigen::VectorXd buffer(N);
  Eigen::VectorXd v_seq(N_seq_proc), w_seq(N_seq_proc), w_gather(N_seq_proc);
  Eigen::VectorXd v(N), w(N);

  // testing multiply
  for (int i=0; i<N; ++i) {
    // MPI version
    v.setZero();
    if (myrank == (i / N))  v(i % N) = 1;
    w.setZero();
    rokko::xyz_hamiltonian::multiply(MPI_COMM_WORLD, L, lattice, coupling, v.data(), w.data(), buffer.data());
    for (int proc=0; proc<nprocs; ++proc) {
      if (proc == myrank) {
        std::cout << "myrank=" << myrank << std::endl;
        std::cout << w.transpose() << std::endl;
      }
      MPI_Barrier(MPI_COMM_WORLD);
    }
    MPI_Gather(w.data(), N, MPI_DOUBLE, w_gather.data(), N, MPI_DOUBLE, root, MPI_COMM_WORLD);
    if (myrank == root) {
      // sequential version
      v_seq.setZero();
      v_seq(i) = 1;
      w_seq.setZero();
      rokko::xyz_hamiltonian::multiply(L, lattice, coupling, v_seq, w_seq);
      std::cout << "multiply: i=" << i << std::endl;
      std::cout << "seq = " << w_seq.transpose() << std::endl;
      std::cout << "gather = " << w_gather.transpose() << std::endl;
      ASSERT_TRUE(w_seq == w_gather);
    }
  }

  // testing fill_diagonal
  // MPI version
  rokko::xyz_hamiltonian::fill_diagonal(MPI_COMM_WORLD, L, lattice, coupling, w.data());
  for (int proc=0; proc<nprocs; ++proc) {
    if (proc == myrank) {
      std::cout << "myrank=" << myrank << std::endl;
      std::cout << w.transpose() << std::endl;
    }
    MPI_Barrier(MPI_COMM_WORLD);
  }

  MPI_Gather(w.data(), N, MPI_DOUBLE, w_gather.data(), N, MPI_DOUBLE, root, MPI_COMM_WORLD);
  if (myrank == root) {
    rokko::xyz_hamiltonian::fill_diagonal(L, lattice, coupling, w_seq.data());
    std::cout << "fill_diagonal:" << std::endl;
    std::cout << "seq = " << w_seq.transpose() << std::endl;
    std::cout << "gather = " << w_gather.transpose() << std::endl;
    ASSERT_TRUE(w_seq == w_gather);
  }

  // testing generate
  rokko::mapping_bc<rokko::matrix_col_major> map = solver.default_mapping(N_seq, g);
  rokko::distributed_matrix<double,rokko::matrix_col_major> mat(map);
  rokko::xyz_hamiltonian::generate(L, lattice, coupling, mat);
  Eigen::MatrixXd lmat_gather(N_seq_proc, N_seq_proc);
  rokko::gather(mat, lmat_gather, root);

  if (myrank == root) {
    Eigen::MatrixXd lmat(N_seq, N_seq);
    rokko::xyz_hamiltonian::generate(L, lattice, coupling, lmat);
    std::cout << "generate:" << std::endl;
    std::cout << "lmat:" << std::endl << lmat << std::endl;
    std::cout << "lmat_gather:" << std::endl << lmat_gather << std::endl;
    ASSERT_TRUE(lmat_gather == lmat);
  }
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>rokko/eigen3/matrix_major.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2013-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_EIGEN3_MATRIX_MAJOR_HPP
#define ROKKO_EIGEN3_MATRIX_MAJOR_HPP

#include <rokko/matrix_major.hpp>
#include <Eigen/Dense>

namespace rokko {

namespace detail {

template<typename T>
struct major_t {};

template<typename T, int ROWS>
struct major_t<Eigen::Matrix<T, ROWS, 1, Eigen::ColMajor>> {
  using major_type = rokko::matrix_col_major;
};

template<typename T, int ROWS, int COLS>
struct major_t<Eigen::Matrix<T, ROWS, COLS, Eigen::ColMajor>> {
  using major_type = rokko::matrix_col_major;
};

template<typename T, int ROWS, int COLS>
struct major_t<Eigen::Matrix<T, ROWS, COLS, Eigen::RowMajor>> {
  using major_type = rokko::matrix_row_major;
};

} // end namespace detail

template<typename MATRIX_MAJOR>
using matrix_major = typename detail::major_t<MATRIX_MAJOR>::major_type;

namespace detail {

template<typename MATRIX_MAJOR>
struct eigen3_matrix_major;

template<>
struct eigen3_matrix_major<rokko::matrix_row_major> {
  static constexpr int value = Eigen::RowMajor;
};

template<>
struct eigen3_matrix_major<rokko::matrix_col_major> {
  static constexpr int value = Eigen::ColMajor;
};

} // end namespace detail

template<typename MATRIX_MAJOR>
constexpr int eigen3_major = detail::eigen3_matrix_major<MATRIX_MAJOR>::value;

} // namespace rokko

#endif // ROKKO_EIGEN3_MATRIX_MAJOR_HPP


<|start_filename|>config/check_cblas.c<|end_filename|>
#include <cblas.h>
int main() { double *x, *y; cblas_ddot(0, x, 0, y, 0); }


<|start_filename|>rokko/distributed_vector.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_DISTRIBUTED_VECTOR_HPP
#define ROKKO_DISTRIBUTED_VECTOR_HPP

namespace rokko {

template<typename T>
class distributed_vector {
public:
  using value_type = T;
  distributed_vector() = default;
  distributed_vector(int n_global, int begin_local, int end_local) {
    initialize(n_global, begin_local, end_local);
  }
  void initialize(int n_global, int begin_local, int end_local) {
    n_global_ = n_global;
    offset_ = begin_local;
    if (storage_.size() < end_local - begin_local) storage_.resize(end_local - begin_local);
  }

  value_type* get_storage() { return storage_.data(); }
  const value_type* get_storage() const { return storage_.data(); }
  int size() const { return n_global_; }
  int size_local() const { return storage_.size(); }

  bool has_global_index(int gi) const {
    return (gi >= offset_ && gi < offset_ + storage_.size());
  }

  void set_local(int li, value_type value) { storage_[li] = value; }
  void update_local(int li, value_type value) { storage_[li] += value; }
  value_type get_local(int li) const { return storage_[li]; }

  void set_global(int gi, value_type value) {
    if (has_global_index(gi)) set_local(gi - offset_, value);
  }
  void update_global(int gi, value_type value) {
    if (has_global_index(gi)) update_local(gi - offset_, value);
  }
  value_type get_global(int gi) const { return get_local(gi - offset_); }
  value_type get_global_checked(int gi) const {
    if (has_global_index(gi)) {
      return get_global(gi);
    } else {
      throw std::out_of_range("element not on this process.");
    }
  }

  void set_zeros() { std::fill(storage_.begin(), storage_.end(), 0); }

private:
  int n_global_, offset_;
  std::vector<value_type> storage_;
};

} // namespace rokko

#endif // ROKKO_DISTRIBUTED_VECTOR_HPP


<|start_filename|>test/generate_matrix/xyz_file.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2013-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <iostream>
#include <fstream>
#include <vector>
#include <tuple>

#include <rokko/utility/xyz_hamiltonian.hpp>
#include <rokko/eigen3.hpp>

int main(int argc, char *argv[]) {
  if (argc <= 1) {
    throw std::invalid_argument("Specify input file name by command line argument");
  }

  std::ifstream ifs(argv[1]);
  if (!ifs) {
    throw std::runtime_error("can't open file \"" + std::string(argv[1]) + "\"");
  }

  std::size_t L, num_bonds;
  std::vector<std::pair<int, int>> lattice;
  std::vector<std::tuple<double, double, double>> coupling;
  ifs >> L >> num_bonds;
  for (int i=0; i<num_bonds; ++i) {
    int j, k;
    ifs >> j >> k;
    lattice.emplace_back(std::make_pair(j, k));
  }
  
  for (int i=0; i<num_bonds; ++i) {
    double jx, jy, jz;
    ifs >> jx >> jy >> jz;
    coupling.emplace_back(std::make_tuple(jx, jy, jz));
  }
  
  std::cout << "L=" << L << " num_bonds=" << num_bonds << std::endl;
  for (int i=0; i<num_bonds; ++i) {
    std::cout << lattice[i].first << " " << lattice[i].second << " " << std::get<0>(coupling[i]) << " " << std::get<1>(coupling[i]) << " " << std::get<2>(coupling[i]) << std::endl;
  }
  int dim = 1 << L;
  int N = dim;
  std::cout << "dim=" << dim << std::endl;

  Eigen::MatrixXd mat1(N, N);
  std::cout << "multiply:" << std::endl;
  for (int i=0; i<N; ++i) {
    Eigen::VectorXd v(N), w(N);
    v.setZero();
    v(i) = 1;
    w.setZero();
    rokko::xyz_hamiltonian::multiply(L, lattice, coupling, v, w);
    mat1.col(i) = w;
    std::cout << w.transpose() << std::endl;
  }

  std::cout << "fill_diagonal:" << std::endl;
  Eigen::VectorXd diagonal(N);
  rokko::xyz_hamiltonian::fill_diagonal(L, lattice, coupling, diagonal);
  std::cout << "diagonal = " << diagonal.transpose() << std::endl;

  std::cout << "fill_matrix:" << std::endl;
  Eigen::MatrixXd mat2(N, N);
  rokko::xyz_hamiltonian::generate(L, lattice, coupling, mat2);
  std::cout << mat2 << std::endl;

  if (mat1 == mat2) {
    std::cout << "OK: matrix by 'multiply' equals to a matrix by 'generate'." << std::endl;
  } else {
    std::cout << "ERROR: matrix by 'multiply' is differnet from a matrix by 'generate'."<< std::endl;
    exit(1);
  }

  if (diagonal == mat2.diagonal()) {
    std::cout << "OK: diagonal by 'fill_diagonal' equals to diagonal elementas of a matrix by 'genertate'."<< std::endl;
  } else {
    std::cout << "ERROR: diagonal by 'fill_diagonal' is differnet from diagonal elementas of a matrix by 'genertate'."<< std::endl;
    exit(1);
  }

}




<|start_filename|>rokko/lapack/heevr.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_HEEVR_HPP
#define ROKKO_LAPACK_HEEVR_HPP

#include <complex>
#include <lapacke.h>
#undef I
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>
#include "complex_cast.hpp"
#include <rokko/lapack/storage.hpp>
#include <rokko/alias_template_function.hpp>

namespace rokko {
namespace lapack {

namespace {

template<typename T> struct heevr_dispatch;

template<>
struct heevr_dispatch<float> {
  template<typename MATRIX, typename MATRIX2, typename VECTOR, typename VECTOR_INT>
  static lapack_int heevr(int matrix_layout, char jobz, char range, char uplo, lapack_int n, MATRIX& a,
                          float vl, float vu, lapack_int il, lapack_int iu, float abstol,
                          lapack_int& m, VECTOR& w, MATRIX2& z, VECTOR_INT& isuppz) {
    return LAPACKE_ssyevr(matrix_layout, jobz, range, uplo, n, storage(a), ld(a), vl, vu, il, iu, abstol, &m, storage(w), storage(z), ld(z), storage(isuppz));
  }
};

template<>
struct heevr_dispatch<double> {
  template<typename MATRIX, typename MATRIX2, typename VECTOR, typename VECTOR_INT>
  static lapack_int heevr(int matrix_layout, char jobz, char range, char uplo, lapack_int n, MATRIX& a,
                          double vl, double vu, lapack_int il, lapack_int iu, double abstol,
                          lapack_int& m, VECTOR& w, MATRIX2& z, VECTOR_INT& isuppz) {
    return LAPACKE_dsyevr(matrix_layout, jobz, range, uplo, n, storage(a), ld(a), vl, vu, il, iu, abstol, &m, storage(w), storage(z), ld(z), storage(isuppz));
  }
};

template<>
struct heevr_dispatch<std::complex<float>> {
  template<typename MATRIX, typename MATRIX2, typename VECTOR, typename VECTOR_INT>
  static lapack_int heevr(int matrix_layout, char jobz, char range, char uplo, lapack_int n, MATRIX& a,
                          float vl, float vu, lapack_int il, lapack_int iu, float abstol,
                          lapack_int& m, VECTOR& w, MATRIX2& z, VECTOR_INT& isuppz) {
    return LAPACKE_cheevr(matrix_layout, jobz, range, uplo, n, complex_cast(storage(a)), ld(a), vl, vu, il, iu, abstol, &m, storage(w), complex_cast(storage(z)), ld(z), storage(isuppz));
  }
};

template<>
struct heevr_dispatch<std::complex<double>> {
  template<typename MATRIX, typename MATRIX2, typename VECTOR, typename VECTOR_INT>
  static lapack_int heevr(int matrix_layout, char jobz, char range, char uplo, lapack_int n, MATRIX& a,
                          double vl, double vu, lapack_int il, lapack_int iu, double abstol,
                          lapack_int& m, VECTOR& w, MATRIX2& z, VECTOR_INT& isuppz) {
    return LAPACKE_zheevr(matrix_layout, jobz, range, uplo, n, complex_cast(storage(a)), ld(a), vl, vu, il, iu, abstol, &m, storage(w), complex_cast(storage(z)), ld(z), storage(isuppz));
  }
};

} // end of anonymous namespace

template<typename T, typename MATRIX, typename MATRIX2, typename VECTOR, typename VECTOR_INT>
lapack_int heevr(char jobz, char range, char uplo, MATRIX& a,
                 T vl, T vu, lapack_int il, lapack_int iu, T abstol,
                 lapack_int& m, VECTOR& w, MATRIX2& z, VECTOR_INT& isuppz) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR>>::value, "");
  lapack_int n = rows(a);
  if (rows(a) != cols(a))
    throw std::invalid_argument("matrix A size mismatch");
  //if (size(w) != n)
  //  throw std::invalid_argument("vector w size mismatch");
  return heevr_dispatch<value_t<MATRIX>>::
    heevr((is_col_major(a) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR), jobz, range, uplo, n, a, vl, vu, il, iu, abstol, m, w, z, isuppz);
}

// eigenvalues & eigenvectors (without jobz)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int heevr(char range, char uplo, MATRIX& a,
                 T vl, T vu, lapack_int il, lapack_int iu, T abstol,
                 lapack_int& m, VECTOR& w, MATRIX& z, VECTOR_INT& isuppz) {
  return heevr('V', range, uplo, a, vl, vu, il, iu, abstol, m, w, z, isuppz);
}

// eigenvalues & eigenvectors, use all (without jobz, range, vl, vu, il, iu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int heevr(char uplo, MATRIX& a,
                 T abstol,
                 lapack_int& m, VECTOR& w, MATRIX& z, VECTOR_INT& isuppz) {
  constexpr real_t<MATRIX> real_zero = 0;
  return heevr('A', uplo, a, real_zero, real_zero, 0, 0, abstol, m, w, z, isuppz);
}

// eigenvalues & eigenvectors, use vl, vu (without jobz, range, il, iu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int heevr(char uplo, MATRIX& a,
                 T vl, T vu, T abstol,
                 lapack_int& m, VECTOR& w, MATRIX& z, VECTOR_INT& isuppz) {
  return heevr('V', uplo, a, vl, vu, 0, 0, abstol, m, w, z, isuppz);
}

// eigenvalues & eigenvectors, use il, iu (without jobz, range, vl, vu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int heevr(char uplo, MATRIX& a,
                 lapack_int il, lapack_int iu, T abstol,
                 lapack_int& m, VECTOR& w, MATRIX& z, VECTOR_INT& isuppz) {
  constexpr real_t<MATRIX> real_zero = 0;
  return heevr('I', uplo, a, real_zero, real_zero, il, iu, abstol, m, w, z, isuppz);
}

// only eigenvalues (without jobz)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int heevr(char range, char uplo, MATRIX& a,
                 T vl, T vu, lapack_int il, lapack_int iu, T abstol,
                 lapack_int& m, VECTOR& w, VECTOR_INT& isuppz) {
  constexpr null_matrix<value_t<MATRIX>> z_null;
  return heevr('N', range, uplo, a, vl, vu, il, iu, abstol, m, w, z_null, isuppz);
}

// only eigenvalues, use all (without jobz, range, vl, vu, il, iu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int heevr(char uplo, MATRIX& a,
                 T abstol,
                 lapack_int& m, VECTOR& w, VECTOR_INT& isuppz) {
  constexpr real_t<MATRIX> real_zero = 0;
  return heevr('A', uplo, a, real_zero, real_zero, 0, 0, abstol, m, w, isuppz);
}

// only eigenvalues, use vl, vu (without jobz, range, il, iu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int heevr(char uplo, MATRIX& a,
                 T vl, T vu, T abstol,
                 lapack_int& m, VECTOR& w, VECTOR_INT& isuppz) {
  return heevr('V', uplo, a, vl, vu, 0, 0, abstol, m, w, isuppz);
}

// only eigenvalues, use il, iu (without jobz, range, vl, vu)
template<typename T, typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int heevr(char uplo, MATRIX& a,
                 lapack_int il, lapack_int iu, T abstol,
                 lapack_int& m, VECTOR& w, VECTOR_INT& isuppz) {
  constexpr real_t<MATRIX> real_zero = 0;
  return heevr('I', uplo, a, real_zero, real_zero, il, iu, abstol, m, w, isuppz);
}

ALIAS_TEMPLATE_FUNCTION(syevr, heevr);

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_HEEVR_HPP


<|start_filename|>test/mfree/laplacian_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/utility/laplacian_mfree.hpp>
#include "test_fill_diagonal.hpp"

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

TEST(laplacian_mfree, fill_diagonal) {
  constexpr std::size_t dim = 20;

  rokko::laplacian_mfree mat(dim, MPI_COMM_WORLD);
  test_fill_diagonal(mat);
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>test/blas/gemm.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <gtest/gtest.h>
#include <rokko/eigen3.hpp>
#include <rokko/blas.hpp>

constexpr double eps = 1e-12;

TEST(GemmTest, GemmTest) {
  std::size_t n = 16;
  Eigen::MatrixXd a = Eigen::MatrixXd::Random(n, n);
  Eigen::MatrixXd b = Eigen::MatrixXd::Random(n, n);
  Eigen::MatrixXd c = Eigen::MatrixXd::Random(n, n);
  Eigen::MatrixXd cr = c;
  double alpha = 2.1;
  double beta = 0.8;

  rokko::blas::gemm(CblasNoTrans, CblasNoTrans, alpha, a, b, beta, cr);

  Eigen::MatrixXd cc(n, n);
  for (std::size_t i = 0; i < n; ++i) {
    for (std::size_t j = 0; j < n; ++j) {
      cc(i, j) = beta * c(i, j);
      for (std::size_t k = 0; k < n; ++k) {
        cc(i, j) += alpha * a(i, k) * b(k, j);
      }
      EXPECT_NEAR(cc(i, j), cr(i, j), eps);
    }
  }
}


<|start_filename|>rokko/anasazi/distributed_crs_matrix.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_ANASAZI_DISTRIBUTED_CRS_MATRIX_HPP
#define ROKKO_ANASAZI_DISTRIBUTED_CRS_MATRIX_HPP

#include <rokko/anasazi/mapping_1d.hpp>
#include <rokko/distributed_crs_matrix.hpp>

#include <Epetra_CrsMatrix.h>
#include <AnasaziEpetraAdapter.hpp>
#include <Teuchos_RCPDecl.hpp>

#include <numeric>
#include <iostream>

namespace rokko {
namespace anasazi {

class distributed_crs_matrix : public rokko::detail::ps_crs_base {
public:
  distributed_crs_matrix() = default;
  ~distributed_crs_matrix() = default;

  explicit distributed_crs_matrix(rokko::mapping_1d const& map, int num_entries_per_row)
    : distributed_crs_matrix(cast_map(map), num_entries_per_row) {}

  explicit distributed_crs_matrix(rokko::anasazi::mapping_1d const& map, int num_entries_per_row)
    : distributed_crs_matrix(std::make_shared<const rokko::anasazi::mapping_1d>(map), num_entries_per_row) {}

  explicit distributed_crs_matrix(std::shared_ptr<const rokko::anasazi::mapping_1d> map, int num_entries_per_row)
    : map_(map), matrix_(Teuchos::rcp(new Epetra_CrsMatrix(Copy, map_->get_epetra_map(), num_entries_per_row))) {}

  static std::shared_ptr<const rokko::anasazi::mapping_1d> cast_map(rokko::mapping_1d const& map) {
    if (map.get_solver_name() != "anasazi") {
      throw std::invalid_argument("Anasazi's distributed_crs_matrix() : " + map.get_solver_name() + "'s mapping_1d is given.");
    }
    return std::static_pointer_cast<const rokko::anasazi::mapping_1d>(map.get_ptr());
  }

  void insert(int row, std::vector<int> const& cols, std::vector<double> const& values) override {
    matrix_->InsertGlobalValues(row, cols.size(), values.data(), cols.data());
  }
  void insert(int row, int col_size, int const*const cols, double const*const values) override {
    matrix_->InsertGlobalValues(row, col_size, values, cols);
  }
  void complete() override {
    matrix_->FillComplete();
    matrix_->SetTracebackMode(1);
  }
  void extract(int row, std::vector<int>& cols, std::vector<double>& values) const override {
    int num_cols;
    int* cols_tmp;
    double* values_tmp;
    matrix_->ExtractMyRowView(matrix_->LRID(row), num_cols, values_tmp, cols_tmp);
    cols.clear();
    cols.reserve(num_cols);
    values.clear();
    values.reserve(num_cols);
    std::vector<int> idx(num_cols);
    std::iota(idx.begin(), idx.end(), 0);
    std::sort(idx.begin(), idx.end(), [this,cols_tmp](auto i, auto j) { return matrix_->GCID(cols_tmp[i]) < matrix_->GCID(cols_tmp[j]); });
    for (int i=0; i<num_cols; ++i) {
      cols.emplace_back(matrix_->GCID(cols_tmp[idx[i]]));
      values.emplace_back(values_tmp[idx[i]]);
    }
  }
  Teuchos::RCP<Epetra_CrsMatrix> get_matrix() const {
    return matrix_;
  }
  int get_dim() const override {
    return map_->get_dim();
  }
  int get_num_local_rows() const override {
    return map_->get_num_local_rows();
  }
  int start_row() const override {
    return map_->start_row();
  }
  int end_row() const override {
    return map_->end_row();
  }
  int get_nnz() const override {
    return matrix_->NumGlobalNonzeros();
  }
  void print() const override {
    std::cout << *matrix_ << std::endl;
  }
  void output_matrix_market(std::ostream& os = std::cout) const override {
    constexpr int root_proc = 0;
    std::vector<int> cols;
    std::vector<double> values;
    if (map_->get_epetra_comm().MyPID() == root_proc) {
      os << "%%MatrixMarket matrix coordinate real general" << std::endl
         << get_dim() << " " << get_dim() << " " << get_nnz() << std::endl;
    }
    map_->get_epetra_comm().Barrier();
    for (int global_row=0; global_row<get_dim(); ++global_row) {
      if ((global_row >= start_row()) && (global_row < end_row())) {
        extract(global_row, cols, values);
        for (int i=0; i<cols.size(); ++i) {
          os << global_row + 1 << " " << cols[i] + 1 << " " << values[i] << std::endl;
        }
      }
      map_->get_epetra_comm().Barrier();
    }
  }

  std::shared_ptr<const rokko::anasazi::mapping_1d> get_map_ptr() const { return map_; }

  const rokko::anasazi::mapping_1d& get_map() const override { return *map_; }

private:
  std::shared_ptr<const rokko::anasazi::mapping_1d> map_;
  Teuchos::RCP<Epetra_CrsMatrix> matrix_;
};

} // namespace anasazi
} // namespace rokko

#endif // ROKKO_ANASAZI_DISTRIBUTED_CRS_MATRIX_HPP


<|start_filename|>benchmark/use_rokko/sparse_heisenberg_ladder_mpi/mfree.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/solver_name.hpp>
#include <rokko/utility/heisenberg_hamiltonian_mfree.hpp>
#include <rokko/utility/lattice.hpp>
#include <rokko/utility/machine_info.hpp>

int main(int argc, char *argv[]) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  int rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  double init_tick, initend_tick, gen_tick, diag_tick, end_tick;

  std::string library_routine(rokko::parallel_sparse_ev::default_solver());
  if (argc >= 2) library_routine = argv[1];
  std::string library, routine;
  rokko::split_solver_name(library_routine, library, routine);
  int len_ladder = 5;
  if (argc >= 3) len_ladder = std::stoi(argv[2]);

  const int L = 2 * len_ladder;
  std::vector<std::pair<int, int>> lattice;
  rokko::create_ladder_lattice_1dim(len_ladder, lattice);
  if (rank == 0)
    rokko::print_lattice(lattice);
  const int dim = 1 << L;
  if (rank == 0)
    std::cout << "Eigenvalue decomposition of antiferromagnetic Heisenberg 1D ladder lattice" << std::endl
      	      << "solver = " << library << std::endl
              << "routine = " << routine << std::endl
              << "L = " << L << std::endl
              << "dimension = " << dim << std::endl;

  MPI_Barrier(MPI_COMM_WORLD);
  init_tick = MPI_Wtime();
  rokko::parallel_sparse_ev solver(library);
  MPI_Barrier(MPI_COMM_WORLD);
  initend_tick = MPI_Wtime();
  
  MPI_Barrier(MPI_COMM_WORLD);
  gen_tick = MPI_Wtime();
  rokko::heisenberg_mfree mat(L, lattice);
  
  MPI_Barrier(MPI_COMM_WORLD);
  diag_tick = MPI_Wtime();
  rokko::parameters params;
  params.set("routine", routine);
  //params.set("max_block_size", 5);
  params.set("max_iters", 200);
  params.set("conv_tol", 1.0e-8);
  //params.set("num_eigvals", 1)
  rokko::parameters params_out = solver.diagonalize(mat, params);
  MPI_Barrier(MPI_COMM_WORLD);
  end_tick = MPI_Wtime();

  const int num_conv = params_out.get<int>("num_conv");
  if (num_conv == 0) {
    throw std::runtime_error("diagonalize : solver does not converge.");
  }
  std::vector<double> eigvec;
  solver.eigenvector(0, eigvec);
  if (rank == 0) {
    std::cout << "number of converged eigenpairs = " << num_conv << std::endl;
    std::cout << "smallest eigenvalues: ";
    for (int i = 0; i < num_conv; ++i) std::cout << ' ' << solver.eigenvalue(i);
    std::cout << std::endl;
    std::cout << "init_time = " << initend_tick - init_tick << std::endl
              << "gen_time = " << diag_tick - gen_tick << std::endl
              << "diag_time = " << end_tick - diag_tick << std::endl;
    rokko::machine_info();
  }

  solver.finalize();
  MPI_Finalize();
}


<|start_filename|>rokko/collective_c.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/collective.h>
#include <rokko/collective.hpp>

void rokko_gather(struct rokko_distributed_matrix matrix, double* array, int root) {
  if (matrix.major == rokko_matrix_col_major){
    rokko::distributed_matrix<double, rokko::matrix_col_major>* ptr_ = static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr);
    rokko::gather(*ptr_, array, root);
  } else {
    rokko::distributed_matrix<double, rokko::matrix_row_major>* ptr_ = static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr);
    rokko::gather(*ptr_, array, root);
  }
}

void rokko_scatter(double* global_array, struct rokko_distributed_matrix matrix, int root) {
  if (matrix.major == rokko_matrix_col_major){
    rokko::distributed_matrix<double, rokko::matrix_col_major>* ptr_ = static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr);
    rokko::scatter(global_array, *ptr_, root);
  } else {
    rokko::distributed_matrix<double, rokko::matrix_row_major>* ptr_ = static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr);
    rokko::scatter(global_array, *ptr_, root);
  }
}

void rokko_gather_eigen_matrix(struct rokko_distributed_matrix matrix, struct rokko_eigen_matrix lmatrix, int root) {
  if (matrix.major == rokko_matrix_col_major){
    rokko::distributed_matrix<double, rokko::matrix_col_major>* ptr_ = static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr);
    Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>* loc_ptr_ = static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(lmatrix.ptr);
    rokko::gather(*ptr_, *loc_ptr_, root);
  } else {
    rokko::distributed_matrix<double, rokko::matrix_row_major>* ptr_ = static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr);
    Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>* loc_ptr_ = static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(lmatrix.ptr);
    rokko::gather(*ptr_, *loc_ptr_, root);
  }
}

void rokko_scatter_eigen_matrix(struct rokko_eigen_matrix lmatrix, struct rokko_distributed_matrix matrix, int root) {
  if (matrix.major == rokko_matrix_col_major){
    rokko::distributed_matrix<double, rokko::matrix_col_major>* ptr_ = static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr);
    Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>* loc_ptr_ = static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(lmatrix.ptr);
    rokko::scatter(*loc_ptr_, *ptr_, root);
  } else {
    rokko::distributed_matrix<double, rokko::matrix_row_major>* ptr_ = static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr);
    Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>* loc_ptr_ = static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(lmatrix.ptr);
    rokko::scatter(*loc_ptr_, *ptr_, root);
  }
}

void rokko_all_gather(struct rokko_distributed_matrix matrix, double* array) {
  if (matrix.major == rokko_matrix_col_major){
    rokko::distributed_matrix<double, rokko::matrix_col_major>* ptr_ = static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(matrix.ptr);
    for(int root = 0; root < ptr_->get_nprocs(); ++root) {
      rokko::gather(*ptr_, array, root);
    }
  } else {
    rokko::distributed_matrix<double, rokko::matrix_row_major>* ptr_ = static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(matrix.ptr);
    for(int root = 0; root < ptr_->get_nprocs(); ++root) {
      rokko::gather(*ptr_, array, root);
    }
  }
}


<|start_filename|>test/diagonalize/helmert_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2013-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/helmert_matrix.hpp>
#include <rokko/collective.hpp>
#include <rokko/utility/compare_vectors.hpp>

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

constexpr double eps = 1e-5;

template <typename GRID_MAJOR>
void test(MPI_Comm comm, int dim, std::string const& name, GRID_MAJOR const& grid_major) {
  std::cout << "solver=" << name << std::endl;
  if (name == "eigenexa") {
    std::cout << "warning: skipping test for eigenexa\n";
  } else {
    rokko::parallel_dense_ev solver(name);
    if (solver.is_available_grid_major(grid_major)) {
      solver.initialize(global_argc, global_argv);
      rokko::grid g(comm, grid_major);
      rokko::mapping_bc<rokko::matrix_col_major> map = solver.default_mapping(dim, g);
      rokko::distributed_matrix<double, rokko::matrix_col_major> mat(map);
      Eigen::VectorXd diag(dim);
      diag.setLinSpaced(diag.size(), 1, diag.size()); // diag = [1, 2, 3, ..., dim]
      rokko::helmert_matrix::generate_for_given_eigenvalues(mat, diag);
      Eigen::VectorXd w(dim);
      rokko::distributed_matrix<double, rokko::matrix_col_major> Z(map);

      solver.diagonalize(mat, w, Z);

      EXPECT_NEAR(w.sum(), diag.sum(), eps);

      Eigen::MatrixXd locZ(dim,dim);
      constexpr int root = 0;
      rokko::gather(Z, locZ, root);

      Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,rokko::eigen3_major<rokko::matrix_col_major>> u(dim, dim);
      rokko::helmert_matrix::generate(u);
      for (int i = 0; i < dim; ++i) {
        EXPECT_NEAR(diag(i), w(i), eps);

        // The following test utilizes that the fact that all these eigenvectors have freedom of minus sign at most, because all these eigenvalues are simple.
        if (g.get_myrank() == root)
          EXPECT_NEAR(rokko::norm_diff(u.transpose().col(i), locZ.col(i)), 0, eps);
      }

      solver.finalize();
    }
  }
}

TEST(diagonalize, helmert_mpi) {
  MPI_Comm comm = MPI_COMM_WORLD;
  constexpr int dim = 100;

  std::vector<std::string> names;
  if (global_argc == 1) {
    names = rokko::parallel_dense_ev::solvers();
  } else {
    for (int num=1; num < global_argc; ++num) {
      names.emplace_back(global_argv[num]);
    }
  }

  for(auto name : names) {
    test(comm, dim, name, rokko::grid_col_major);
  }

  for(auto name : names) {
    test(comm, dim, name, rokko::grid_row_major);
  }
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>rokko/elemental/diagonalize.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_ELEMENTAL_DIAGONALIZE_HPP
#define ROKKO_ELEMENTAL_DIAGONALIZE_HPP

#include <rokko/distributed_matrix.hpp>
#include <El.hpp>
#include <rokko/utility/timer.hpp>

namespace rokko {
namespace elemental {

template<typename T>
struct complex_type_traits {
  using type = T;
};

template<typename T>
struct complex_type_traits<std::complex<T>> {
  using type = El::Complex<T>;
};


template<typename T>
using complex_t = typename complex_type_traits<T>::type;


El::UpperOrLower get_matrix_part(parameters const& params) {
  std::string matrix_part;
  char matrix_part_letter;
  if (params.defined("uplow"))
    matrix_part = params.get_string("uplow");
  if (params.defined("matrix_part"))
    matrix_part = params.get_string("matrix_part");
  if (!matrix_part.empty()) {
    matrix_part_letter = matrix_part[0];
    if ((matrix_part_letter == 'u') || (matrix_part_letter == 'U'))
      return El::UPPER;
    if ((matrix_part_letter == 'l') || (matrix_part_letter == 'L'))
      return El::LOWER;
  }
  return El::LOWER;  // default
}

template <typename T>
El::HermitianEigSubset<T> get_subset(parameters const& params) {
  El::HermitianEigSubset<T> subset;
  bool is_lower_value, is_lower_index, is_upper_value, is_upper_index;
  is_lower_value = get_key(params, "lower_value", subset.lowerBound);
  is_lower_index = get_key(params, "lower_index", subset.lowerIndex);
  is_upper_value = get_key(params, "upper_value", subset.upperBound);
  is_upper_index = get_key(params, "upper_index", subset.upperIndex);
  if (is_lower_value && is_upper_value) {
    subset.rangeSubset = true;
  } else if (is_lower_index && is_upper_index) {
    subset.indexSubset = true;
  } else if (!(is_lower_index && is_lower_value && is_upper_index && is_upper_value)) {  
  } else {
    throw std::invalid_argument("elemental::get_subset() : sepcify either of a pair of upper_value and lower_value or a pair of upper_index and lower_index");
  }
  return subset;
}

template <typename T>
El::HermitianEigCtrl<T> get_ctrl(parameters const& params) {
  El::HermitianEigCtrl<T> ctrl;
  if (params.defined("useSDC")) {
    ctrl.useSDC = params.get<bool>("useSDC");
  }
  if (params.defined("cutoff")) {
    ctrl.sdcCtrl.cutoff = params.get<int>("cutoff");
  }
  if (params.defined("maxInnerIts")) {
    ctrl.sdcCtrl.maxInnerIts = params.get<int>("maxInnerIts");
  }
  if (params.defined("maxOuterIts")) {
    ctrl.sdcCtrl.maxOuterIts = params.get<int>("maxOuterIts");
  }
  if (params.defined("tol")) {
    ctrl.sdcCtrl.tol = params.get<real_t<T>>("tol");
  }
  if (params.defined("spreadFactor")) {
    ctrl.sdcCtrl.spreadFactor = params.get<real_t<T>>("spreadFactor");
  }
  if (params.defined("progress")) {
    ctrl.sdcCtrl.progress = params.get<bool>("progress");
  }
  //if (params.defined("verbose")) {
  //  ctrl.sdcCtrl.progress = true;
  //}
  return ctrl;
}

El::SortType get_sort(parameters const& params) {
  El::SortType elem_sort = El::ASCENDING;
  if (params.defined("sort")) {
    std::string str_sort = params.get<std::string>("sort");    
    if (str_sort == "ascending") elem_sort =  El::ASCENDING;
    else if (str_sort == "descending") elem_sort =  El::DESCENDING;
    else if (str_sort == "unsorted") elem_sort =  El::UNSORTED;
  }
  return elem_sort;
}

// eigenvalues / eigenvectors
template<typename T, typename VEC>
parameters diagonalize(distributed_matrix<T, rokko::matrix_col_major>& mat,
		       VEC& eigvals, distributed_matrix<T, rokko::matrix_col_major>& eigvecs,
		       parameters const& params) {
  if((mat.get_mb() != 1) || (mat.get_nb() != 1))
    throw std::invalid_argument("elemental::diagonalize() : elemental supports only 1x1 block size.");
  parameters params_out;
  MPI_Comm comm = mat.get_grid().get_comm();
  enum El::GridOrder elemental_grid_order = (mat.get_grid().is_row_major()) ?
    El::ROW_MAJOR : El::COLUMN_MAJOR;
  El::Grid elem_grid(comm, mat.get_grid().get_nprow(), elemental_grid_order);
  El::DistMatrix<complex_t<T>> elem_mat;
  elem_mat.Attach(mat.get_m_global(), mat.get_n_global(), elem_grid, 0, 0,
                  static_cast<complex_t<T>*>(mat.get_array_pointer()), mat.get_lld());
  El::DistMatrix<complex_t<T>> elem_eigvecs(0, 0, elem_grid);
  El::DistMatrix<real_t<T>, El::VR, El::STAR> elem_w(elem_grid);

  El::UpperOrLower elem_uplow = get_matrix_part(params);
  El::HermitianEigCtrl<complex_t<T>> ctrl = get_ctrl<complex_t<T>>(params);
  El::HermitianEigSubset<real_t<T>> subset = get_subset<real_t<T>>(params);
  ctrl.tridiagEigCtrl.subset = get_subset<real_t<T>>(params);
  ctrl.tridiagEigCtrl.sort = get_sort(params);

  El::HermitianEig(elem_uplow, elem_mat, elem_w, elem_eigvecs, ctrl);

  for (int i = 0; i < elem_w.Height(); ++i) eigvals(i) = elem_w.Get(i, 0);
  T* result_mat = elem_eigvecs.Buffer();
  for(int local_j=0; local_j<elem_w.LocalHeight(); ++local_j) {
    for(int local_i=0; local_i<mat.get_m_local(); ++local_i) {
      eigvecs.set_local(local_i, local_j, result_mat[local_j * mat.get_lld() + local_i]);
    }
  }
  return params_out;
}

template<typename T, typename VEC>
parameters diagonalize(distributed_matrix<T, rokko::matrix_row_major>& mat,
		       VEC& eigvals, distributed_matrix<T, rokko::matrix_row_major>& eigvecs,
		       parameters const& params) {
  throw std::invalid_argument("elemental::diagonalize() : elemental doesn't support matrix_row_major.  Use it with matrix_col_major.");
}

// only eigenvalues
template<typename T, typename VEC>
parameters diagonalize(distributed_matrix<T, rokko::matrix_col_major>& mat,
		       VEC& eigvals,
		       parameters const& params) {
  if((mat.get_mb() != 1) || (mat.get_nb() != 1))
    throw std::invalid_argument("elemental::diagonalize() : elemental supports only 1x1 block size.");
  parameters params_out;
  MPI_Comm comm = mat.get_grid().get_comm();
  enum El::GridOrder elemental_grid_order = (mat.get_grid().is_row_major()) ?
    El::ROW_MAJOR : El::COLUMN_MAJOR;
  El::Grid elem_grid(comm, mat.get_grid().get_nprow(), elemental_grid_order);
  El::DistMatrix<complex_t<T>> elem_mat;
  elem_mat.Attach(mat.get_m_global(), mat.get_n_global(), elem_grid, 0, 0,
                  static_cast<complex_t<T>*>(mat.get_array_pointer()), mat.get_lld());
  El::DistMatrix<complex_t<T>> elem_eigvecs(0, 0, elem_grid);
  El::DistMatrix<real_t<T>, El::VR, El::STAR> elem_w(elem_grid);

  El::UpperOrLower elem_uplow = get_matrix_part(params);
  El::HermitianEigCtrl<complex_t<T>> ctrl = get_ctrl<complex_t<T>>(params);
  El::HermitianEigSubset<real_t<T>> subset = get_subset<real_t<T>>(params);
  ctrl.tridiagEigCtrl.subset = get_subset<real_t<T>>(params);
  ctrl.tridiagEigCtrl.sort = get_sort(params);

  El::HermitianEig(elem_uplow, elem_mat, elem_w, ctrl);
  for (int i = 0; i < elem_w.Height(); ++i) eigvals(i) = elem_w.Get(i, 0);

  return params_out;
}

template<typename T, typename VEC>
parameters diagonalize(distributed_matrix<T, rokko::matrix_row_major>& mat,
		       VEC& eigvals,
		       parameters const& params) {
  throw std::invalid_argument("elemental::diagonalize() : elemental doesn't support matrix_row_major.  Use it with matrix_col_major.");
}

} // namespace elemental
} // namespace rokko

#endif // ROKKO_ELEMENTAL_DIAGONALIZE_HPP


<|start_filename|>test/solver_class/serial_dense_ev.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/solver.hpp>

#include <gtest/gtest.h>

TEST(serial_dense_ev, names) {
  for(auto name : rokko::serial_dense_ev::solvers()) {
    std::cerr << name << std::endl;
  }
}

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}


<|start_filename|>test/mpi_collective/scatter_vector.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/solver.hpp>
#include <rokko/utility/mpi_vector.hpp>

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

void run_test(MPI_Comm comm, int dim) {
  int size, rank;
  MPI_Comm_size(comm, &size);
  MPI_Comm_rank(comm, &rank);
  rokko::mpi_vector mpi(dim);

  Eigen::VectorXd lvec(dim);
  lvec.setRandom();
#ifndef NDEBUG
  if (rank == 0) std::cout << lvec.transpose() << std::endl;
#endif

  for (int r = 0; r < size; ++r) {
    rokko::distributed_vector<double> vec(dim, mpi.get_displacement(), mpi.get_displacement() + mpi.get_count());
    mpi.scatter(lvec, vec, r);
    for (int i = 0; i < dim; ++i) {
      if (vec.has_global_index(i))
        ASSERT_EQ(vec.get_global(i), lvec(i));
    }
  }
}

TEST(mpi_communication, scatter_vector) {
  MPI_Comm comm = MPI_COMM_WORLD;
  int rank;
  MPI_Comm_rank(comm, &rank);

  int dim = 100;
  if (global_argc > 1) {
    dim = std::stoi(global_argv[1]);
  }
  if (rank == 0) std::cout << "dimension = " << dim << std::endl;

  run_test(comm, dim);
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  MPI_Init(&argc, &argv);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>rokko/pblas/pgemv.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cpblas.h>

#define CPBLAS_PGEMV_IMPL(NAMES, NAMEL, TYPEC, TYPEX) \
void cpblas_ ## NAMES (char trans, int m, int n, TYPEC alpha, const TYPEC * a, int ia, int ja, const int* desca, const TYPEC * x, int ix, int jx, const int* descx, int incx, TYPEC beta, TYPEC * y, int iy, int jy, const int* descy, int incy) { \
  int ia_f = ia + 1; \
  int ja_f = ja + 1; \
  int ix_f = ix + 1; \
  int jx_f = jx + 1; \
  int iy_f = iy + 1; \
  int jy_f = jy + 1; \
  ROKKO_GLOBAL(NAMES, NAMEL) (&trans, &m, &n, &alpha, a, &ia_f, &ja_f, desca, x, &ix_f, &jx_f, descx, &incx, &beta, y, &iy_f, &jy_f, descy, &incy); \
}

CPBLAS_PGEMV_IMPL(psgemv, PSGEMV, float, float);
CPBLAS_PGEMV_IMPL(pdgemv, PDGEMV, double, double);
CPBLAS_PGEMV_IMPL(pcgemv, PCGEMV, lapack_complex_float, std::complex<float>);
CPBLAS_PGEMV_IMPL(pzgemv, PZGEMV, lapack_complex_double, std::complex<double>);

#undef CPBLAS_PGEMV_IMPL


<|start_filename|>rokko/lapack/diagonalize_syevr.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_DIAGONALIZE_SYEVR_HPP
#define ROKKO_LAPACK_DIAGONALIZE_SYEVR_HPP

#include <rokko/parameters.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/utility/timer.hpp>
#include <rokko/lapack.hpp>
#include <rokko/lapack/diagonalize_get_parameters.hpp>
#include <rokko/lapack/syevr.hpp>

namespace rokko {
namespace lapack {

// only eigenvalues
template<typename T, int MATRIX_MAJOR, typename VEC>
parameters diagonalize_syevr(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat, VEC& eigvals,
			      parameters const& params) {
  parameters params_out;
  real_t<T> abstol = params.defined("abstol") ? params.get<real_t<T>>("abstol") : 0.;
  params_out.set("abstol", abstol);

  lapack_int il, iu;
  real_t<T> vl, vu;
  const char range = get_eigenvalues_range(params, vl, vu, il, iu);
  const char uplow = get_matrix_part(params);

  lapack_int m;  // output: found eigenvalues
  const int dim = mat.outerSize();
  std::vector<lapack_int> isuppz(2*dim+1);

  int info = syevr(range, uplow, mat,
                   vl, vu, il, iu, abstol,
                   m, eigvals, isuppz);

  if (info) {
    std::cerr << "error at syevr function. info=" << info << std::endl;
  }
  params_out.set("info", info);
  params_out.set("m", m);
  params_out.set("isuppz", isuppz);

  if (params.get_bool("verbose")) {
    print_verbose("syevr", 'N', range, uplow, vl, vu, il, iu, params_out);
  }

  return params_out;
}


// eigenvalues / eigenvectors
template<typename T, int MATRIX_MAJOR, typename VEC>
parameters diagonalize_syevr(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat, VEC& eigvals,
			      Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& eigvecs,
			      parameters const& params) {
  rokko::parameters params_out;

  real_t<T> abstol = params.defined("abstol") ? params.get<real_t<T>>("abstol") : 0.;
  params_out.set("abstol", abstol);

  lapack_int il = 0, iu = 0;
  real_t<T> vl = 0, vu = 0;
  const char range = get_eigenvalues_range(params, vl, vu, il, iu);
  const char uplow = get_matrix_part(params);

  lapack_int m;  // output: found eigenvalues
  const int dim = mat.outerSize();
  std::vector<lapack_int> isuppz(2*dim+1);

  int info = syevr(range, uplow, mat,
                   vl, vu, il, iu, abstol,
                   m, eigvals, eigvecs, isuppz);

  if (info) {
    std::cerr << "error at syevr function. info=" << info << std::endl;
  }
  params_out.set("info", info);
  params_out.set("m", m);
  params_out.set("isuppz", isuppz);
  
  if (params.get_bool("verbose")) {
    print_verbose("syevr", 'V', range, uplow, vl, vu, il, iu, params_out);
  }
  return params_out;
}


} // namespace lapack
} // namespace rokko

#endif // ROKKO_LAPACK_DIAGONALIZE_SYEVR_HPP


<|start_filename|>rokko/slepc/slepc.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/parallel_sparse_ev.hpp>
#include <rokko/slepc/solver.hpp>
#include <rokko/slepc/mapping_1d.hpp>
#include <rokko/slepc/distributed_crs_matrix.hpp>

ROKKO_REGISTER_PARALLEL_SPARSE_SOLVER(rokko::slepc::solver, "slepc", 10)

ROKKO_REGISTER_PARALLEL_SPARSE_MAPPING_1D(rokko::slepc::mapping_1d, "slepc", 10)

ROKKO_REGISTER_PARALLEL_SPARSE_CRS(rokko::slepc::distributed_crs_matrix, "slepc", 10)


<|start_filename|>test/generate_matrix/matrix_major_template_transformation.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/eigen3.hpp>
#include <type_traits>

#include <gtest/gtest.h>

TEST(matrix, major_template_transformation) {
  static_assert( std::is_same<rokko::matrix_major<Eigen::MatrixXd>, rokko::matrix_col_major>::value, "rokko::matrix_major<Eigen::MatrixXd> != rokko::matrix_col_major");
}

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}


<|start_filename|>rokko/pblas/pcopy.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cpblas.h>

#define CPBLAS_PCOPY_IMPL(NAMES, NAMEL, TYPE) \
void cpblas_ ## NAMES (int N, const TYPE * X, int ix, int jx, const int* DESCX, int INCX, TYPE * Y, int iy, int jy, const int* DESCY, int INCY) { \
  int ix_f = ix + 1; \
  int jx_f = jx + 1; \
  int iy_f = iy + 1; \
  int jy_f = jy + 1; \
  ROKKO_GLOBAL(NAMES, NAMEL) (&N, X, &ix_f, &jx_f, DESCX, &INCX, Y, &iy_f, &jy_f, DESCY, &INCY); \
}

CPBLAS_PCOPY_IMPL(pscopy, PSCOPY, float);
CPBLAS_PCOPY_IMPL(pdcopy, PDCOPY, double);
CPBLAS_PCOPY_IMPL(pccopy, PCCOPY, lapack_complex_float);
CPBLAS_PCOPY_IMPL(pzcopy, PZCOPY, lapack_complex_double);

#undef CPBLAS_PCOPY_IMPL


<|start_filename|>test/utility/solver_name.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/utility/solver_name.hpp>

#include <gtest/gtest.h>

TEST(split_solver_name, const_string) {
  std::string library, routine;
  rokko::split_solver_name("lapack:syevd", library, routine);
  ASSERT_TRUE(library == "lapack");
  ASSERT_TRUE(routine == "syevd");
}

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}


<|start_filename|>rokko/utility/tridiagonal_toeplitz_matrix.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_TRIDIAGONAL_TOEPLITZ_MATRIX_HPP
#define ROKKO_UTILITY_TRIDIAGONAL_TOEPLITZ_MATRIX_HPP

#include <cmath>
#include <stdexcept>
#include <rokko/eigen3.hpp>
#if defined(ROKKO_HAVE_PARALLEL_DENSE_SOLVER)
# include <rokko/distributed_matrix.hpp>
#endif

namespace rokko {

// tridiagonal_toeplitz_matrix can be defined for n >= 2.
class tridiagonal_toeplitz_matrix {
public:
  template<typename T>
  static void multiply(int dim, const T* x, T* y, T a, T b) {
    y[0] = a * x[0] + b * x[1];
    y[dim-1] = a * x[dim-1] + b * x[dim - 2];
    for (int k = 1; k < (dim-1); ++k) { // from 1 to end-1
      y[k] = b * x[k-1] + a * x[k] + b * x[k+1];
    }
  }

  template<typename T>
  static void multiply(int dim, const std::vector<T>& v, std::vector<T>& w, T a, T b) {
    multiply(dim, v.data(), w.data());
  }

  template<typename T, int ROWS, int COLS>
  static void generate(Eigen::Matrix<T,ROWS,COLS,Eigen::ColMajor>& mat, T a, T b) {
    if (mat.rows() != mat.cols())
      throw std::invalid_argument("tridiagonal_toeplitz_matrix::generate() : non-square matrix");
    mat.setZero();
    const int n = mat.cols();
    mat(0, 0) = a;  mat(1, 0) = b;
    for(int i = 1; i < n-1; ++i) {
      mat(i-1, i) = b;
      mat(i,   i) = a;
      mat(i+1, i) = b;
    }
    mat(n-2, n-1) = b;  mat(n-1, n-1) = a;
  }

  template<typename T, int ROWS, int COLS>
  static void generate(Eigen::Matrix<T,ROWS,COLS,Eigen::RowMajor>& mat, T a, T b) {
    if (mat.rows() != mat.cols())
      throw std::invalid_argument("tridiagonal_toeplitz_matrix::generate() : non-square matrix");
    mat.setZero();
    const int n = mat.rows();
    mat(0, 0) = a;  mat(0, 1) = b;
    for(int i = 1; i < n-1; ++i) {
      mat(i, i-1) = b;
      mat(i, i) = a;
      mat(i, i+1) = b;
    }
    mat(n-1, n-2) = b;  mat(n-1, n-1) = a;
  }

  template<typename T>
  static void generate(rokko::distributed_matrix<T, matrix_col_major>& mat, T a, T b) {
    if (mat.get_m_global() != mat.get_n_global())
      throw std::invalid_argument("tridiagonal_toeplitz_matrix::generate() : non-square matrix");
    mat.set_zeros();
    const int n = mat.get_n_global();
    mat.set_global(0, 0, a);  mat.set_global(1, 0, b);
    for(int i = 1; i < n-1; ++i) {
      mat.set_global(i-1, i, b);
      mat.set_global(i,   i, a);
      mat.set_global(i+1, i, b);
    }
    mat.set_global(n-2, n-1, b);  mat.set_global(n-1, n-1, a);
  }

  template<typename T>
  static void generate(rokko::distributed_matrix<T, matrix_row_major>& mat, T a, T b) {
    if (mat.get_m_global() != mat.get_n_global())
      throw std::invalid_argument("tridiagonal_toeplitz_matrix::generate() : non-square matrix");
    mat.set_zeros();
    const int n = mat.get_m_global();
    mat.set_global(0, 0, a);  mat.set_global(0, 1, b);
    for(int i = 1; i < n-1; ++i) {
      mat.set_global(i, i-1, b);
      mat.set_global(i, i, a);
      mat.set_global(i, i+1, b);
    }
    mat.set_global(n-1, n-2, b);  mat.set_global(n-1, n-1, a);
  }

  // calculate k-th smallest eigenvalue of dim-dimensional Tridiagonal_Toeplitz matrix (k=0...dim-1)
  template<typename T>
  static T eigenvalue(int dim, int k, T a, T b) {
    return a - 2 * b * std::cos(M_PI * (k + 1) / (dim + 1));
  }
};

} // namespace rokko

#endif // ROKKO_UTILITY_TRIDIAGONAL_TOEPLITZ_MATRIX_HPP


<|start_filename|>rokko/slepc/mapping_1d.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SLEPC_MAPPING_1D_HPP
#define ROKKO_SLEPC_MAPPING_1D_HPP

#include <rokko/skel/mapping_1d.hpp>

namespace rokko {

namespace slepc {

using mapping_1d = rokko::skel::mapping_1d;

} // namespace slepc

} // namespace rokko

#endif // ROKKO_SLEPC_MAPPING_1D_HPP


<|start_filename|>rokko/pyrokko_mapping_1d.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_MAPPING_1D_HPP
#define PYROKKO_MAPPING_1D_HPP

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#include <rokko/pyrokko_communicator.hpp>
#include <rokko/mapping_1d.hpp>

namespace rokko {

class wrap_mapping_1d : public mapping_1d {
public:
  using mapping_1d::mapping_1d;
  wrap_mapping_1d(mapping_1d const& map) : mapping_1d(map) {}

  explicit wrap_mapping_1d(int dim, pybind11::handle const& comm_handle, std::string const& solver_name)
    : mapping_1d(dim, wrap_communicator{comm_handle}, solver_name) {}

  explicit wrap_mapping_1d(int dim, pybind11::handle const& comm_handle)
    : mapping_1d(dim, wrap_communicator{comm_handle}) {}

  ~wrap_mapping_1d() = default;

};

} // end namespace rokko

#endif // PYROKKO_MAPPING_1D_HPP


<|start_filename|>rokko/parallel_sparse_ev.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_PARALLEL_SPARSE_SOLVER_HPP
#define ROKKO_PARALLEL_SPARSE_SOLVER_HPP

#include <rokko/factory.hpp>
#include <rokko/mapping_1d.hpp>
#include <rokko/distributed_crs_matrix.hpp>
#include <rokko/distributed_mfree.hpp>
#include <rokko/distributed_vector.hpp>
#include <rokko/utility/macro_join.hpp>
#include <rokko/utility/timer.hpp>
#include <rokko/parameters.hpp>

namespace rokko {

namespace detail {
    
class ps_ev_base {
public:
  virtual ~ps_ev_base() = default;
  virtual void initialize(int& argc, char**& argv) = 0;
  virtual void finalize() = 0;
  virtual parameters diagonalize(const rokko::distributed_crs_matrix& mat, rokko::parameters const& params) = 0;
  virtual parameters diagonalize(const rokko::distributed_mfree& mat, rokko::parameters const& params) = 0;
  virtual double eigenvalue(int k) const = 0;
  virtual void eigenvector(int k, std::vector<double>& vec) const = 0;
  virtual void eigenvector(int k, double* vec) const = 0;
  virtual void eigenvector(int k, distributed_vector<double>& vec) const = 0;
  virtual int get_num_conv() const = 0;
};

template<typename SOLVER>
class ps_ev_wrapper : public ps_ev_base {
  using solver_type = SOLVER;
public:
  ps_ev_wrapper() : solver_impl_() {}
  virtual ~ps_ev_wrapper() = default;
  void initialize(int& argc, char**& argv) override { solver_impl_.initialize(argc, argv); }
  void finalize() override { solver_impl_.finalize(); }
  parameters diagonalize(const rokko::distributed_crs_matrix& mat, rokko::parameters const& params) override {
    return solver_impl_.diagonalize(mat, params);
  }
  parameters diagonalize(const rokko::distributed_mfree& mat, rokko::parameters const& params) override {
    return solver_impl_.diagonalize(mat, params);
  }
  double eigenvalue(int k) const override { return solver_impl_.eigenvalue(k); }
  void eigenvector(int k, std::vector<double>& vec) const override { solver_impl_.eigenvector(k, vec); }
  void eigenvector(int k, double* vec) const override { solver_impl_.eigenvector(k, vec); }
  void eigenvector(int k, distributed_vector<double>& vec) const override { solver_impl_.eigenvector(k, vec); }
  int get_num_conv() const override { return solver_impl_.get_num_conv(); }

private:
  solver_type solver_impl_;
};

using ps_solver_factory = factory<ps_ev_base>;
  
} // end namespace detail
  
class parallel_sparse_ev {
public:
  parallel_sparse_ev(std::string const& solver_name)
    : solver_name_(solver_name), solver_impl_(detail::ps_solver_factory::instance()->make_product(solver_name)) {}

  parallel_sparse_ev() : parallel_sparse_ev(default_solver()) {}

  void initialize(int& argc, char**& argv) {
    solver_impl_->initialize(argc, argv);
  }
  void finalize() {
    solver_impl_->finalize();
  }
  rokko::mapping_1d default_mapping(int dim, mpi_comm const& mpi_comm_in) const {
    return rokko::mapping_1d(dim, mpi_comm_in, get_solver_name());
  }
  rokko::mapping_1d default_mapping(int dim, int num_local_rows, mpi_comm const& mpi_comm_in) const {
    return rokko::mapping_1d(dim, num_local_rows, mpi_comm_in, get_solver_name());
  }

  parameters diagonalize(const rokko::distributed_crs_matrix& mat, rokko::parameters const& params) {
    if(get_solver_name() != mat.get_solver_name())
      throw std::invalid_argument(get_solver_name() + "'s diagonalize() : " + mat.get_solver_name() + "'s distributed_crs_matrix is given.");

    return solver_impl_->diagonalize(mat, params);
  }
  parameters diagonalize(const rokko::distributed_mfree& mat, rokko::parameters const& params) {
    return solver_impl_->diagonalize(mat, params);
  }
  double eigenvalue(int k) const { return solver_impl_->eigenvalue(k); }
  void eigenvector(int k, std::vector<double>& vec) const { solver_impl_->eigenvector(k, vec); }
  void eigenvector(int k, double* vec) const { solver_impl_->eigenvector(k, vec); }
  void eigenvector(int k, distributed_vector<double>& vec) const { solver_impl_->eigenvector(k, vec); }
  int get_num_conv() const { return solver_impl_->get_num_conv(); }
  std::string get_solver_name() const { return solver_name_; }
  static std::vector<std::string> solvers() { return detail::ps_solver_factory::product_names(); }
  static const std::string& default_solver() { return detail::ps_solver_factory::default_product_name(); }
private:
  detail::ps_solver_factory::product_pointer_type solver_impl_;
  std::string solver_name_;
};

} // end namespace rokko

#define ROKKO_REGISTER_PARALLEL_SPARSE_SOLVER(solver, name, priority) \
namespace { namespace ROKKO_JOIN(register, __LINE__) { \
struct register_caller { \
  using factory = rokko::detail::ps_solver_factory;     \
  using product = rokko::detail::ps_ev_wrapper<solver>; \
  register_caller() { factory::instance()->register_creator<product>(name, priority); } \
} caller; \
} }

#endif // ROKKO_PARALLEL_SPARSE_SOLVER_HPP


<|start_filename|>rokko/scalapack/scalapack_interface.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_SCALAPACK_INTERFACE_H
#define ROKKO_SCALAPACK_SCALAPACK_INTERFACE_H

#include <rokko/config.h>
#include <rokko/mangling.h>
#include <lapacke.h>

#ifdef __cplusplus
extern "C" {
#endif

#define SCALAPACK_descinit ROKKO_GLOBAL(descinit,DESCINIT)
void SCALAPACK_descinit(int* desc, const int* m, const int* n, const int* mb, const int* nb,
                        const int* irsrc, const int* icsrc, const int* ictxt, const int* lld,
                        int* info);
  
#define SCALAPACK_indxg2p ROKKO_GLOBAL(indxg2p,INDXG2P)
int SCALAPACK_indxg2p(int* indxglob, int* nb, int* iproc, int* isrcproc, int* nprocs);

#define SCALAPACK_numroc ROKKO_GLOBAL(numroc,NUMROC)
int SCALAPACK_numroc(int* n, int* nb, int* iproc, int* isrcproc, int* nprocs);

#define SCALAPACK_pdelget ROKKO_GLOBAL(pdelget,PDELGET)
void SCALAPACK_pdelget(const char* scope, const char* top, double* alpha,
                       const double* A, const int* ia, const int* ja, const int* descA);

#define SCALAPACK_pdelset ROKKO_GLOBAL(pdelset,PDELSET)
void SCALAPACK_pdelset(double* A, const int* ia, const int* ja, const int* descA,
                       const double* alpha);

#define SCALAPACK_pdlamch ROKKO_GLOBAL(pdlamch,PDLAMCH)
double SCALAPACK_pdlamch(const int* icnt, const char* cmch);

#define SCALAPACK_pdlange ROKKO_GLOBAL(pdlange,PDLANGE)
double SCALAPACK_pdlange(const char* norm, int* m, int* n, const double* A,
                         const int* ia, const int* ja, const int* descA, double* work);

#define SCALAPACK_pdlaprnt ROKKO_GLOBAL(pdlaprnt,PDLAPRNT)
void SCALAPACK_pdlaprnt(const int* m, const int* n, const double* A, const int* ia, const int* ja,
                        const int* descA, const int* irprnt, const int* icprnt, const char* cmatnm,
                        const int* nout, double* work);

#define SCALAPACK_PSYEV_DECL(NAMES, NAMEL, TYPE, TYPE_REAL) \
void ROKKO_GLOBAL(NAMES, NAMEL) (const char* jobz, const char* uplo, const int* n, \
                                 TYPE* A, const int* ia, const int* ja, const int* descA, \
                                 TYPE_REAL* w, TYPE* Z, const int* iz, const int* jz, const int* descZ, \
                                 TYPE* work, const int* lwork, int* info);

SCALAPACK_PSYEV_DECL(pssyev, PSSYEV, float, float);
SCALAPACK_PSYEV_DECL(pdsyev, PDSYEV, double, double);
SCALAPACK_PSYEV_DECL(pcheev, PCHEEV, lapack_complex_float, float);
SCALAPACK_PSYEV_DECL(pzheev, PZHEEV, lapack_complex_double, double);

#undef SCALAPACK_PSYEV_DECL


#define SCALAPACK_PSYEVD_DECL(NAMES, NAMEL, TYPE, TYPE_REAL) \
void ROKKO_GLOBAL(NAMES, NAMEL) (const char* jobz, const char* uplo, const int* n, \
  TYPE* A, const int* ia, const int* ja, const int* descA, \
  TYPE_REAL* w, \
  TYPE* Z, const int* iz, const int* jz, const int* descZ, \
  TYPE* work, const int* lwork, int* iwork, const int* liwork, int* info);

SCALAPACK_PSYEVD_DECL(pssyevd, PSSYEVD, float, float);
SCALAPACK_PSYEVD_DECL(pdsyevd, PDSYEVD, double, double);
SCALAPACK_PSYEVD_DECL(pcheevd, PCHEEVD, lapack_complex_float, float);
SCALAPACK_PSYEVD_DECL(pzheevd, PZHEEVD, lapack_complex_double, double);

#undef SCALAPACK_PSYEVD_DECL


#define SCALAPACK_PSYEVX_DECL(NAMES, NAMEL, TYPE, TYPE_REAL) \
void ROKKO_GLOBAL(NAMES, NAMEL) (const char* jobz, const char* range, const char* uplo, const int* n, \
  TYPE* A, const int* iA, const int* jA, const int* descA, \
  const TYPE_REAL* vl, const TYPE_REAL* vu, const int* il, const int* iu, \
  const TYPE_REAL* abstol, int* m, int* nZ, TYPE_REAL* w, const TYPE_REAL* orfac, \
  TYPE* Z, const int* iZ, const int* jZ, const int* descZ, \
  TYPE* work, const int* lwork, int* iwork, const int* liwork, \
  int* ifail, int* iclustr, TYPE_REAL* gap, int* info);

SCALAPACK_PSYEVX_DECL(pssyevx, PSSYEVX, float, float);
SCALAPACK_PSYEVX_DECL(pdsyevx, PDSYEVX, double, double);
SCALAPACK_PSYEVX_DECL(pcheevx, PCHEEVX, lapack_complex_float, float);
SCALAPACK_PSYEVX_DECL(pzheevx, PZHEEVX, lapack_complex_double, double);

#undef SCALAPACK_PSYEVX_DECL

#ifdef ROKKO_HAVE_SCALAPACK_PDSYEVR
#define SCALAPACK_PSYEVR_DECL(NAMES, NAMEL, TYPE, TYPE_REAL) \
void ROKKO_GLOBAL(NAMES, NAMEL) (const char* jobz, const char* range, const char* uplo, const int* n, \
  TYPE* A, const int* iA, const int* jA, const int* descA, \
  const TYPE_REAL* vl, const TYPE_REAL* vu, const int* il, const int* iu, \
  int* m, int* nz, \
  TYPE_REAL* w, TYPE* Z, const int* iz, const int* jz, const int* descZ, \
  TYPE* work, const int* lwork, int* iwork, const int* liwork, int* info);

SCALAPACK_PSYEVR_DECL(pssyevr, PSSYEVR, float, float);
SCALAPACK_PSYEVR_DECL(pdsyevr, PDSYEVR, double, double);
SCALAPACK_PSYEVR_DECL(pcheevr, PCHEEVR, lapack_complex_float, float);
SCALAPACK_PSYEVR_DECL(pzheevr, PZHEEVR, lapack_complex_double, double);

#undef SCALAPACK_PSYEVR_DECL
#endif

#define SCALAPACK_pselget ROKKO_GLOBAL(pselget,PSELGET)
void SCALAPACK_pselget(const char* scope, const char* top, float* alpha,
                       const float* A, const int* ia, const int* ja, const int* descA);

#define SCALAPACK_pselset ROKKO_GLOBAL(pselset,PSELSET)
void SCALAPACK_pselset(float* A, const int* ia, const int* ja, const int* descA,
                       const float* alpha);

#define SCALAPACK_pslamch ROKKO_GLOBAL(pslamch,PSLAMCH)
float SCALAPACK_pslamch(const int* icnt, const char* cmch);

#define SCALAPACK_pslange ROKKO_GLOBAL(pslange,PSLANGE)
float SCALAPACK_pslange(const char* norm, int* m, int* n, const float* A,
                        const int* ia, const int* ja, const int* descA, float* work);

#define SCALAPACK_pslaprnt ROKKO_GLOBAL(pslaprnt,PSLAPRNT)
void SCALAPACK_pslaprnt(const int* m, const int* n, const float* A, const int* ia, const int* ja,
                        const int* descA, const int* irprnt, const int* icprnt, const char* cmatnm,
                        const int* nout, float* work);


#define SCALAPACK_PSTEBZ_DECL(NAMES, NAMEL, TYPE) \
void ROKKO_GLOBAL(NAMES, NAMEL) (const int* ictxt, const char* range, const char* order, const int* n, \
                                 const TYPE* vl, const TYPE* vu, const int* il, const int* iu, \
                                 const TYPE* abstol, const TYPE* d, const TYPE* e, int* m, int* nsplit, \
                                 TYPE* w, int* iblock, int* isplit, \
                                 TYPE* work, const int* lwork, int* iwork, const int* liwork, int* info);

SCALAPACK_PSTEBZ_DECL(psstebz, PSSTEBZ, float);
SCALAPACK_PSTEBZ_DECL(pdstebz, PDSTEBZ, double);

#undef SCALAPACK_PSTEBZ_DECL


#define SCALAPACK_PSTEIN_DECL(NAMES, NAMEL, TYPE, TYPE_REAL) \
void ROKKO_GLOBAL(NAMES, NAMEL) (const int* n, const TYPE_REAL* d, const TYPE_REAL* e, const int* m, \
                                 TYPE_REAL* w, const int* iblock, const int* isplit, const TYPE_REAL* orfac, \
                                 TYPE* Z, const int* iZ, const int* jZ, const int* descZ, \
                                 TYPE* work, const int* lwork, int* iwork, const int* liwork, \
                                 int* ifail, int* iclustr, TYPE_REAL* gap, int* info);

SCALAPACK_PSTEIN_DECL(psstein, PSSTEIN, float, float);
SCALAPACK_PSTEIN_DECL(pdstein, PDSTEIN, double, double);
SCALAPACK_PSTEIN_DECL(pcstein, PCSTEIN, lapack_complex_float, float);
SCALAPACK_PSTEIN_DECL(pzstein, PZSTEIN, lapack_complex_double, double);

#undef SCALAPACK_PSTEIN_DECL


#define SCALAPACK_PSTEDC_DECL(NAMES, NAMEL, TYPE) \
void ROKKO_GLOBAL(NAMES, NAMEL) (const char* compz, const int* n, TYPE* d, TYPE* e, \
                                 TYPE* Q, const int* iq, const int* jq, const int* descQ, \
                                 TYPE* work, const int* lwork, int* iwork, const int* liwork, int* info);

SCALAPACK_PSTEDC_DECL(psstedc, PSSTEDC, float);
SCALAPACK_PSTEDC_DECL(pdstedc, PDSTEDC, double);

#undef SCALAPACK_PSTEDC_DECL

#ifdef __cplusplus
}
#endif

#endif // ROKKO_SCALAPACK_SCALAPACK_INTERFACE_H


<|start_filename|>test/mfree/test_fill_diagonal.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <iostream>

#include <rokko/eigen3.hpp>
#include <rokko/distributed_mfree.hpp>

#include <gtest/gtest.h>

void test_fill_diagonal(rokko::distributed_mfree_default const& mat) {
  const int myrank = mat.get_mpi_comm().get_myrank();
  constexpr int root = 0;

  if (myrank == root)  std::cout << "dim = " << mat.get_dim() << std::endl;
  const int N = mat.get_num_local_rows();
  Eigen::VectorXd v(N), w(N), diag(N);
  mat.fill_diagonal(diag.data());

  for (int i=0; i<mat.get_dim(); ++i) {
    const int local_i = i - mat.start_row();
    v.setZero();
    if ((i >= mat.start_row()) && (i < mat.end_row()))  v(local_i) = 1.;
    w.setZero();
    mat.multiply(v.data(), w.data());
    if ((i >= mat.start_row()) && (i < mat.end_row()))  ASSERT_EQ(diag(local_i), w(local_i));
  }
}


<|start_filename|>rokko/mapping_1d.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_MAPPING_1D_HPP
#define ROKKO_MAPPING_1D_HPP

#include <rokko/factory.hpp>
#include <rokko/mpi_communicator.hpp>
#include <rokko/mapping_1d_common.hpp>
#include <rokko/utility/macro_join.hpp>

namespace rokko {

namespace detail {

class ps_mapping_1d_base : virtual public mapping_1d_common {
public:
  explicit ps_mapping_1d_base(int dim) : ps_mapping_1d_base(dim, mpi_comm(MPI_COMM_WORLD)) {}
  explicit ps_mapping_1d_base(int dim, mpi_comm const& mpi_comm_in) : dim_(dim), mpi_comm_(mpi_comm_in) {}
  ps_mapping_1d_base() = default;
  virtual ~ps_mapping_1d_base() = default;
  int get_dim() const override { return dim_; }
  virtual int start_row() const = 0;
  virtual int end_row() const = 0;
  const rokko::mpi_comm& get_mpi_comm() const { return mpi_comm_; }

private:
  int dim_;
  rokko::mpi_comm mpi_comm_;
};

using ps_mapping_1d_factory = factory<ps_mapping_1d_base,int,mpi_comm const&>;
using ps_mapping_1d_factory_num = factory<ps_mapping_1d_base,int,int,mpi_comm const&>;

} // end namespace detail

class mapping_1d {
public:
  mapping_1d(int dim, mpi_comm const& mpi_comm_in, std::string const& solver_name)
    : solver_name_(solver_name), map_impl_(detail::ps_mapping_1d_factory::instance()->make_product(solver_name, dim, mpi_comm_in)) {}

  mapping_1d(int dim, mpi_comm const& mpi_comm_in)
    : mapping_1d(dim, mpi_comm_in, detail::ps_mapping_1d_factory::instance()->default_product_name()) {}

  mapping_1d(int dim, int num_local_rows, mpi_comm const& mpi_comm_in, std::string const& solver_name)
    : solver_name_(solver_name), map_impl_(detail::ps_mapping_1d_factory_num::instance()->make_product(solver_name, dim, num_local_rows, mpi_comm_in)) {}

  mapping_1d(int dim, int num_local_rows, mpi_comm const& mpi_comm_in)
  : mapping_1d(dim, num_local_rows, mpi_comm_in, detail::ps_mapping_1d_factory::instance()->default_product_name()) {}

  int get_dim() const { return map_impl_->get_dim(); }
  int num_local_rows() const { return map_impl_->get_num_local_rows(); }
  int start_row() const { return map_impl_->start_row(); }
  int end_row() const { return map_impl_->end_row(); }
  const rokko::mpi_comm& get_mpi_comm() const { return map_impl_->get_mpi_comm(); }

  std::string get_solver_name() const { return solver_name_; }
  void set_solver_name(std::string const& solver_name) { solver_name_ = solver_name; }

  const detail::ps_mapping_1d_factory::product_pointer_type get_ptr() const { return map_impl_; }

private:
  std::string solver_name_;
  detail::ps_mapping_1d_factory::product_pointer_type map_impl_;
};

} // end namespace rokko

#define ROKKO_REGISTER_PARALLEL_SPARSE_MAPPING_1D(map, name, priority) \
namespace { namespace ROKKO_JOIN(register, __LINE__) { \
struct register_caller { \
  using factory = rokko::detail::ps_mapping_1d_factory; \
  using product = map; \
  register_caller() { factory::instance()->register_creator<product>(name, priority); } \
} caller; \
} } \
 \
namespace { namespace ROKKO_JOIN(register2, __LINE__) { \
struct register_caller { \
  using factory = rokko::detail::ps_mapping_1d_factory_num; \
  using product = map; \
  register_caller() { factory::instance()->register_creator<product>(name, priority); } \
} caller; \
} }

#endif // ROKKO_MAPPING_1D_HPP


<|start_filename|>rokko/serial_dense.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SERIAL_DENSE_H
#define ROKKO_SERIAL_DENSE_H

#ifdef __cplusplus
extern "C" {
#endif

#include <rokko/eigen_matrix.h>
#include <rokko/eigen_vector.h>

#include <rokko/serial_dense_ev.h>


#ifdef __cplusplus
}
#endif

#endif /* ROKKO_SERIAL_DENSE_H */


<|start_filename|>rokko/distributed_mfree.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2016 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_DISTRIBUTED_MFREE_H
#define ROKKO_DISTRIBUTED_MFREE_H

#include <mpi.h>

#ifdef __cplusplus
extern "C" {
#endif

struct rokko_distributed_mfree {
  void* ptr;
};

void rokko_distributed_mfree_construct(struct rokko_distributed_mfree* matrix,
				       void (*multiply)(const double *const, double *const, void*),
				       void* vars,
				       int dim, MPI_Comm comm);
void rokko_distributed_mfree_construct_no_context(struct rokko_distributed_mfree* matrix,
				       void (*multiply)(const double *const, double *const),
				       int dim, MPI_Comm comm);
void rokko_distributed_mfree_destruct(struct rokko_distributed_mfree* matrix);
void rokko_distributed_mfree_f_construct(struct rokko_distributed_mfree* matrix,
					 void (*multiply)(const int*, const double *const, double *const),
					 int dim, int comm_f);
void rokko_distributed_mfree_f_destruct(struct rokko_distributed_mfree* matrix);
int rokko_distributed_mfree_dim(struct rokko_distributed_mfree matrix);
int rokko_distributed_mfree_num_local_rows(struct rokko_distributed_mfree matrix);
int rokko_distributed_mfree_start_row(struct rokko_distributed_mfree matrix);
int rokko_distributed_mfree_end_row(struct rokko_distributed_mfree matrix);
int rokko_distributed_mfree_offset(struct rokko_distributed_mfree matrix);

int rokko_distributed_mfree_f_dim(struct rokko_distributed_mfree* matrix);
int rokko_distributed_mfree_f_num_local_rows(struct rokko_distributed_mfree* matrix);
int rokko_distributed_mfree_f_start_row(struct rokko_distributed_mfree* matrix);
int rokko_distributed_mfree_f_end_row(struct rokko_distributed_mfree* matrix);
int rokko_distributed_mfree_f_offset(struct rokko_distributed_mfree* matrix);

#ifdef __cplusplus
}
#endif

#endif /* ROKKO_DISTRIBUTED_MFREE_H */


<|start_filename|>rokko/utility/minij_matrix.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_MINIJ_MATRIX_HPP
#define ROKKO_UTILITY_MINIJ_MATRIX_HPP

#include <cmath>
#include <stdexcept>
#include <rokko/config.h>
#include <rokko/eigen3.hpp>
#if defined(ROKKO_HAVE_PARALLEL_DENSE_SOLVER)
# include <rokko/distributed_matrix.hpp>
#endif

namespace rokko {

class minij_matrix {
public:
  template<typename T, int ROWS, int COLS>
  static void generate(Eigen::Matrix<T,ROWS,COLS,Eigen::ColMajor>& mat) {
    if (mat.rows() != mat.cols())
      throw std::invalid_argument("minij_matrix::generate() : non-square matrix");
    const int n = mat.rows();
    for(int j = 0; j < n; ++j) {
      for(int i = 0; i < n; ++i) {
        mat(i,j) = std::min(i, j) + 1;
      }
    }
  }

  template<typename T, int ROWS, int COLS>
  static void generate(Eigen::Matrix<T,ROWS,COLS,Eigen::RowMajor>& mat) {
    if (mat.rows() != mat.cols())
      throw std::invalid_argument("minij_matrix::generate() : non-square matrix");
    const int n = mat.rows();
    for(int i = 0; i < n; ++i) {
      for(int j = 0; j < n; ++j) {
        mat(i,j) = std::min(i, j) + 1;
      }
    }
  }

#if defined(ROKKO_HAVE_PARALLEL_DENSE_SOLVER)
  template<typename T>
  static void generate(rokko::distributed_matrix<T, matrix_col_major>& mat) {
    auto const& map = mat.get_mapping();
    if (map.get_m_global() != map.get_n_global())
      throw std::invalid_argument("minij_matrix::generate() : non-square matrix");

    for(int local_j = 0; local_j < map.get_n_local(); ++local_j) {
      int global_j = map.translate_l2g_col(local_j);
      for(int local_i = 0; local_i < map.get_m_local(); ++local_i) {
        int global_i = map.translate_l2g_row(local_i);
        mat.set_local(local_i, local_j, std::min(global_i, global_j) + 1);
      }
    }
  }

  template<typename T>
  static void generate(rokko::distributed_matrix<T, matrix_row_major>& mat) {
    auto const& map = mat.get_mapping();
    if (map.get_m_global() != map.get_n_global())
      throw std::invalid_argument("minij_matrix::generate() : non-square matrix");

    for(int local_i = 0; local_i < map.get_m_local(); ++local_i) {
      int global_i = map.translate_l2g_row(local_i);
      for(int local_j = 0; local_j < map.get_n_local(); ++local_j) {
        int global_j = map.translate_l2g_col(local_j);
        mat.set_local(local_i, local_j, std::min(global_i, global_j) + 1);
      }
    }
  }

  // another (slower) implementation using set_global function
  template<typename T>
  static void generate_global(rokko::distributed_matrix<T, matrix_col_major>& mat) {
    auto const& map = mat.get_mapping();
    if (map.m_global() != map.n_global())
      throw std::invalid_argument("minij_matrix::generate() : non-square matrix");

    for(int global_j=0; global_j<map.n_global(); ++global_j) {
      for(int global_i=0; global_i<map.m_global(); ++global_i) {
        mat.set_global(global_i, global_j, std::min(global_i, global_j) + 1);
      }
    }
  }

  template<typename T>
  static void generate_global(rokko::distributed_matrix<T, matrix_row_major>& mat) {
    auto const& map = mat.get_mapping();
    if (map.m_global() != map.n_global())
      throw std::invalid_argument("minij_matrix::generate() : non-square matrix");

    for(int global_i=0; global_i<map.m_global(); ++global_i) {
      for(int global_j=0; global_j<map.n_global(); ++global_j) {
        mat.set_global(global_i, global_j, std::min(global_i, global_j) + 1);
      }
    }
  }
#endif
  
  // calculate k-th smallest eigenvalue of dim-dimensional Minij matrix (k=0...dim-1)
  static double eigenvalue(int dim, int k) {
    return 1 / (2 * (1 - std::cos(M_PI * (2 * k + 1) / (2 * dim + 1))));
  }
};

} // namespace rokko

#endif // ROKKO_UTILITY_MINIJ_MATRIX_HPP


<|start_filename|>example/fortran/dense/frank_array_all_gather_mpi.f90<|end_filename|>
!*****************************************************************************
!
! Rokko: Integrated Interface for libraries of eigenvalue decomposition
!
! Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
!
! 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)
!
!*****************************************************************************

program frank_matrix
  use rokko
  use mpi
  implicit none
  integer :: dim
  type(rokko_distributed_matrix) :: mat, Z
  type(rokko_parallel_dense_ev) :: solver
  type(rokko_grid) :: grid
  type(rokko_mapping_bc) :: map
  type(rokko_eigen_vector) :: w
  character(len=:), allocatable :: library, routine
  character(len=:), allocatable :: library_routine, tmp_str
  double precision, allocatable, dimension(:,:) :: array, array_tmp

  integer :: provided,ierr, myrank, nprocs
  integer :: i, j, proc

  call MPI_init_thread(MPI_THREAD_MULTIPLE, provided, ierr)
  call MPI_comm_rank(MPI_COMM_WORLD, myrank, ierr)
  call MPI_comm_size(MPI_COMM_WORLD, nprocs, ierr)

  if (command_argument_count() >= 1) then
     call get_command_argument_deferred(1, library_routine)
  else
     library_routine = rokko_parallel_dense_ev_default_solver()
  endif
  call rokko_split_solver_name(library_routine, library, routine)

  if (command_argument_count() == 2) then
     call get_command_argument_deferred(2, tmp_str)
     read(tmp_str, *) dim
  else
     dim = 10
  endif

  if (myrank == 0) then
     print *,"library = ", library
     print *,"routine = ", routine
     print *,"matrix dimension = ", dim
  endif

  call rokko_parallel_dense_ev_construct(solver, library)
  call rokko_grid_construct(grid, MPI_COMM_WORLD, rokko_grid_row_major)
  call rokko_parallel_dense_ev_default_mapping(solver, dim, grid, map)
  call rokko_distributed_matrix_construct(mat, map)
  call rokko_distributed_matrix_construct(Z, map)
  call rokko_eigen_vector_construct(w, dim)

  ! Generating frank matrix as a "eigen array" at all processes
  allocate(array(dim, dim))
  do i=1, dim
     do j=1, dim
        array(i,j) = dble(dim + 1 - max(i, j))
     end do
  end do

  call rokko_distributed_matrix_generate_from_array(mat, array)
  call rokko_distributed_matrix_print(mat)
  call rokko_parallel_dense_ev_diagonalize(solver, mat, w, Z)

  allocate(array_tmp(dim, dim))
  call rokko_all_gather(Z, array_tmp)
  array = matmul(transpose(array_tmp), array_tmp)
  call mpi_barrier(mpi_comm_world, ierr)
  
  ! Display orthogonality of eigenvectors
  do proc = 0, nprocs-1
     if (proc == myrank) then
        print*, "myrank=", myrank
        do i = 1, dim
           write(*,'(10f8.4)') (array(i, j), j=1, dim)
        end do
     endif
     call mpi_barrier(mpi_comm_world, ierr)
     !   call sleep(0.1)
  end do
  
  if (myrank.eq.0) then
     write(*,*) "Computed Eigenvalues = "
     do i = 1, dim
        write(*,"(f30.20)") rokko_get_elem(w ,i)
     enddo
  endif

  call mpi_barrier(mpi_comm_world, ierr)
  
  call rokko_distributed_matrix_destruct(mat)
  call rokko_distributed_matrix_destruct(Z)
  call rokko_eigen_vector_destruct(w)
  call rokko_parallel_dense_ev_destruct(solver)
  call rokko_grid_destruct(grid)
  deallocate(array,array_tmp)

  call MPI_finalize(ierr)
end program frank_matrix


<|start_filename|>rokko/mapping_common_sizes.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2016 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_MAPPING_COMMON_SIZES_HPP
#define ROKKO_MAPPING_COMMON_SIZES_HPP

namespace rokko {

class mapping_common_sizes {
public:
  int get_m_local() const { return std::get<0>(local_size); }
  int get_n_local() const { return std::get<1>(local_size); }
  std::array<int,2> get_local_size() const { return local_size; }

  void set_m_local(int m_local) { std::get<0>(local_size) = m_local; }
  void set_n_local(int n_local) { std::get<1>(local_size) = n_local; }
  void set_local_size(std::array<int,2> local_size_in) { local_size = local_size_in; }

  void set_block_size(std::array<int,2> const& block_size_in) {
    block_size = block_size_in;
  }

  int get_mb() const { return std::get<0>(block_size); }
  int get_nb() const { return std::get<1>(block_size); }
  std::array<int,2> get_block_size() const { return block_size; }

protected:
  explicit mapping_common_sizes() = default;
  std::array<int,2> block_size;

private:
  std::array<int,2> local_size;
};

} // namespace rokko

#endif // ROKKO_MAPPING_COMMON_SIZES_HPP


<|start_filename|>rokko/eigenexa/diagonalize_eigen_s.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_EIGENEXA_DIAGONALIZE_EIGEN_S_HPP
#define ROKKO_EIGENEXA_DIAGONALIZE_EIGEN_S_HPP

#include <rokko/distributed_matrix.hpp>
#include <rokko/eigenexa.hpp>
#include <rokko/utility/timer.hpp>

namespace rokko {
namespace eigenexa {

// eigen_s eigenvalues / eigenvectors
template <typename VEC>
parameters diagonalize_eigen_s(rokko::distributed_matrix<double, rokko::matrix_col_major>& mat,
			       VEC& eigvals, rokko::distributed_matrix<double, rokko::matrix_col_major>& eigvecs,
			       parameters const& params) {
  parameters params_out;
  if((mat.get_mb() != 1) || (mat.get_nb() != 1))
    throw std::invalid_argument("eigenexa::diagonalize_eigen_s() : eigenexa supports only 1x1 block size.");
  rokko::eigenexa::init(mat.get_grid().get_comm(), (mat.get_grid().is_row_major() ? 'R' : 'C'));
  int m_forward = 48, m_backward = 128;
  get_key(params, "m_forward", m_forward);
  get_key(params, "m_backward", m_backward);

  rokko::eigenexa::eigen_s(mat, eigvals, eigvecs, m_forward, m_backward, 'A');

  rokko::eigenexa::free(1);
  return params_out;
}

template <typename VEC>
parameters diagonalize_eigen_s(rokko::distributed_matrix<double, rokko::matrix_row_major>& mat,
			       VEC& eigvals, rokko::distributed_matrix<double, rokko::matrix_row_major>& eigvecs,
			       parameters const& params) {
  throw std::invalid_argument("eigenexa::diagonalize_eigen_s() : eigenexa doesn't support matrix_row_major.  Use eigenexa with matrix_col_major.");
}

// eigen_s only eigenvalues
template <typename VEC>
parameters diagonalize_eigen_s(rokko::distributed_matrix<double, rokko::matrix_col_major>& mat,
			       VEC& eigvals,
			       parameters const& params) {
  parameters params_out;
  if((mat.get_mb() != 1) || (mat.get_nb() != 1))
    throw std::invalid_argument("eigenexa::diagonalize_eigen_s() : eigenexa supports only 1x1 block size.");
  rokko::eigenexa::init(mat.get_grid().get_comm(), (mat.get_grid().is_row_major() ? 'R' : 'C'));
  int m_forward = 48, m_backward = 128;
  get_key(params, "m_forward", m_forward);
  get_key(params, "m_backward", m_backward);

  rokko::eigenexa::eigen_s(mat, eigvals, m_forward, m_backward, 'N');

  rokko::eigenexa::free(1);
  return params_out;
}

template <typename VEC>
parameters diagonalize_eigen_s(rokko::distributed_matrix<double, rokko::matrix_row_major>& mat,
			       VEC& eigvals,
			       parameters const& params) {
  throw std::invalid_argument("eigenexa::diagonalize_eigen_s() : eigenexa doesn't support matrix_row_major.  Use eigenexa with matrix_col_major.");
}

} // namespace eigenexa
} // namespace rokko

#endif // ROKKO_EIGENEXA_DIAGONALIZE_EIGEN_S_HPP


<|start_filename|>rokko/lapack/null_matrix.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_NULL_MATRIX_HPP
#define ROKKO_LAPACK_NULL_MATRIX_HPP

namespace rokko {
namespace lapack {

template<typename T>
class null_matrix {};

template<typename T>
int ld(null_matrix<T>) {
  return 1;
}

template<typename T>
T* storage(null_matrix<T>) {
  return NULL;
}

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_NULL_MATRIX_HPP


<|start_filename|>rokko/scalapack/pstein.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <stdlib.h>
#include <rokko/scalapack/scalapack_interface.h>

#define CSCALAPACK_PSTEIN_IMPL(NAMES, NAMEL, TYPE, TYPE_REAL) \
int cscalapack_## NAMES (int n, const TYPE_REAL* d, const TYPE_REAL* e, int m, \
                         TYPE_REAL* w, const int* iblock, const int* isplit, TYPE_REAL orfac, \
                         TYPE* Z, const int* iZ, const int* jZ, const int* descZ, \
                         int* ifail, int* iclustr, TYPE_REAL* gap) { \
   /* call for querying optimal size of work array */ \
  int lwork = -1; \
  int liwork = -1; \
  TYPE work_query[1]; \
  int iwork_query[1]; \
  int info; \
  info = cscalapack_## NAMES ##_work(n, d, e, m, \
                                     w, iblock, isplit, orfac, \
                                     Z, iZ, jZ, descZ, \
                                     work_query, lwork, iwork_query, liwork, \
                                     ifail, iclustr, gap); \
  if (info) return info; \
  \
  /* allocate work arrays */ \
  lwork = (int)work_query[0]; \
  TYPE* work = (TYPE*)malloc( sizeof(TYPE) * lwork ); \
  liwork = iwork_query[0]; \
  int* iwork = (int*)malloc( sizeof(int) * liwork ); \
  if (work == NULL || iwork == NULL) return 1; \
  \
  /* call for computation */ \
  info = cscalapack_## NAMES ##_work(n, d, e, m, \
                                     w, iblock, isplit, orfac, \
                                     Z, iZ, jZ, descZ, \
                                     work, lwork, iwork, liwork, \
                                     ifail, iclustr, gap); \
  free(work); \
  free(iwork); \
  return info; \
}

CSCALAPACK_PSTEIN_IMPL(psstein, PSSTEIN, float, float)
CSCALAPACK_PSTEIN_IMPL(pdstein, PDSTEIN, double, double)
CSCALAPACK_PSTEIN_IMPL(pcstein, PCSTEIN, lapack_complex_float, float)
CSCALAPACK_PSTEIN_IMPL(pzstein, PZSTEIN, lapack_complex_double, double)

#undef CSCALAPACK_PSTEIN_IMPL


<|start_filename|>rokko/scalapack/pslange_work.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <rokko/scalapack/scalapack_interface.h>

float cscalapack_pslange_work(char norm, int m, int n, const float* A, const int* descA,
                               float* work) {
  int ia = 1;
  int ja = 1;
  return SCALAPACK_pslange(&norm, &m, &n, A, &ia, &ja, descA, work);
}


<|start_filename|>test/grid/grid_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/grid.hpp>

#include <gtest/gtest.h>

TEST(grid, grid_processes) {
  MPI_Comm comm = MPI_COMM_WORLD;
  {
    rokko::grid g(comm); // default should be row-major
    // Test public interfaces
    ASSERT_TRUE(g.get_comm() == MPI_COMM_WORLD);
    ASSERT_TRUE(g.is_row_major());
    ASSERT_FALSE(g.is_col_major());
  }
  {
    rokko::grid g(comm, rokko::grid_row_major);
    // Test public interfaces
    ASSERT_TRUE(g.get_comm() == MPI_COMM_WORLD);
    ASSERT_TRUE(g.is_row_major());
    ASSERT_FALSE(g.is_col_major());

    // Test global values
    if (g.get_nprocs() == 2) {
      ASSERT_EQ(g.get_nprocs(), 2);
      ASSERT_EQ(g.get_nprow(), 1);
      ASSERT_EQ(g.get_npcol(), 2);
    }

    // Test local values
    ASSERT_EQ(g.get_myrow(), g.get_myrank() / g.get_npcol());
    ASSERT_EQ(g.get_mycol(), g.get_myrank() % g.get_npcol());
    ASSERT_EQ(g.calculate_rank_form_coords(g.get_myrow(), g.get_mycol()),
              g.get_myrank());
  }
  {
    rokko::grid g(comm, rokko::grid_col_major);
    // Test public interfaces
    ASSERT_TRUE(g.get_comm() == MPI_COMM_WORLD);
    ASSERT_TRUE(g.is_col_major());
    ASSERT_FALSE(g.is_row_major());

    // Test global values
    if (g.get_nprocs() == 2) {
      ASSERT_EQ(g.get_nprocs(), 2);
      ASSERT_EQ(g.get_nprow(), 1);
      ASSERT_EQ(g.get_npcol(), 2);
    }

    // Test local values
    ASSERT_EQ(g.get_myrow(), g.get_myrank() % g.get_nprow());
    ASSERT_EQ(g.get_mycol(), g.get_myrank() / g.get_nprow());
    ASSERT_EQ(g.calculate_rank_form_coords(g.get_myrow(), g.get_mycol()),
              g.get_myrank());
  }
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  MPI_Init(&argc, &argv);
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>example/scalapack/pdsyev_f.f90<|end_filename|>
program main
  use mpi
  implicit none
  integer, parameter :: n = 8, nb = 1
  integer :: provided, ierr, myrank, nprocs
  integer :: icontxt, npcol, nprow, desc(9)
  integer :: i, j, info
  double precision, allocatable :: a(:, :), z(:,:), w(:)
  integer :: lwork
  double precision, allocatable :: work(:)
  
  call MPI_init_thread(MPI_THREAD_MULTIPLE, provided, ierr)
  call MPI_comm_rank(MPI_COMM_WORLD, myrank, ierr)
  call MPI_comm_size(MPI_COMM_WORLD, nprocs, ierr)
  nprow = int(sqrt(1. * nprocs + 0.5))
  npcol = int(1. * nprocs / nprow)
  if (myrank == 0) then
     print *, "n =", n
     print *, "nprocs =", nprocs
     print *, "nprow =", nprow
     print *, "npcol =", npcol
     if ((nprocs /= nprow * npcol) .or. (mod(n, nprow) /= 0) .or. &
          (mod(n, npcol) /= 0)) then
        print *, "incompatible matrix size and number of processes"
        call MPI_Abort(MPI_COMM_WORLD, 127, ierr)
     end if
  end if
  call BLACS_get(0, 0, icontxt)
  call BLACS_gridinit(icontxt, 'R', nprow, npcol)

  call descinit(desc, n, n, nb, nb, 0, 0, icontxt, n/nprow, info)
  allocate(a(n/nprow, n/npcol), z(n/nprow, n/npcol), w(n))
  do j = 1, n
     do i = 1, n
        call pdelset(a, i, j, desc, dble(min(i, j)))
     end do
  end do

  lwork = -1
  allocate(work(1))
  call pdsyev('V', 'U', n, a, 1, 1, desc, w, z, 1, 1, desc, work, lwork, info)
  lwork = int(work(1))
  deallocate(work)
  allocate(work(lwork))

  call pdsyev('V', 'U', n, a, 1, 1, desc, w, z, 1, 1, desc, work, lwork, info)
  if (myrank == 0) then
     print *, "eigenvalues:", w(:)
  end if

  deallocate(a, z, w, work)
  call BLACS_gridexit(icontxt)
  call MPI_finalize(ierr)
end program main


<|start_filename|>rokko/lapack/complex_cast.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_COMPLEX_CAST_HPP
#define ROKKO_LAPACK_COMPLEX_CAST_HPP

#include <complex>
#ifdef I
# undef I
#endif
#include <lapacke.h>

namespace rokko {
namespace lapack {

#define COMPLEX_CAST_IMPL(T) \
inline T * complex_cast(T* data) { return data; } \
inline const T * complex_cast(const T* data) { return data; } \
inline lapack_complex_ ## T * complex_cast(std::complex< T >* data) { return reinterpret_cast<lapack_complex_ ## T *>(data); } \
inline const lapack_complex_ ## T * complex_cast(const std::complex< T >* data) { return reinterpret_cast<const lapack_complex_ ## T *>(data); } \
inline const T & complex_cast(const T & data) { return *complex_cast(&data); } \
inline const lapack_complex_ ## T & complex_cast(const std::complex< T >& data) { return *complex_cast(&data); }

COMPLEX_CAST_IMPL(float)
COMPLEX_CAST_IMPL(double)

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_COMPLEX_CAST_HPP


<|start_filename|>rokko/scalapack/psyevr.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <stdlib.h>
#include <rokko/scalapack/scalapack_interface.h>

#define CSCALAPACK_PSYEVR_IMPL(NAMES, NAMEL, TYPE, TYPE_REAL) \
int cscalapack_## NAMES (char jobz, char range, char uplo, int n, \
                         TYPE* A, int ia, int ja, const int* descA, \
                         TYPE_REAL vl, TYPE_REAL vu, int il, int iu, \
                         int* m, int* nz, \
                         TYPE_REAL* w, TYPE* Z, int iz, int jz, const int* descZ) { \
  /* call for querying optimal size of work array */ \
  int lwork = -1; \
  int liwork = -1; \
  TYPE work_query[1]; \
  int iwork_query[1]; \
  int info; \
  info = cscalapack_## NAMES ##_work(jobz, range, uplo, n, A, ia, ja, descA, \
                                     vl, vu, il, iu, m, nz, \
                                     w, Z, iz, jz, descZ, \
                                     work_query, lwork, iwork_query, liwork); \
  if (info) return info; \
  \
  /* allocate work arrays */ \
  lwork = (int)work_query[0]; \
  TYPE* work = (TYPE*)malloc( sizeof(TYPE) * lwork ); \
  liwork = iwork_query[0]; \
  int* iwork = (int*)malloc( sizeof(int) * liwork ); \
  if (work == NULL || iwork == NULL) return 1; \
  \
  /* call for computation */ \
  info = cscalapack_## NAMES ##_work(jobz, range, uplo, n, A, ia, ja, descA, \
                                     vl, vu, il, iu, m, nz, \
                                     w, Z, iz, jz, descZ, \
                                     work, lwork, iwork, liwork); \
  free(work); \
  free(iwork); \
  return info; \
}

CSCALAPACK_PSYEVR_IMPL(pssyevr, PSSYEVR, float, float)
CSCALAPACK_PSYEVR_IMPL(pdsyevr, PDSYEVR, double, double)
CSCALAPACK_PSYEVR_IMPL(pcheevr, PCHEEVR, lapack_complex_float, float)
CSCALAPACK_PSYEVR_IMPL(pzheevr, PZHEEVR, lapack_complex_double, double)

#undef CSCALAPACK_PSYEVR_IMPL


<|start_filename|>rokko/pblas/pdot.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cpblas.h>

#define CPBLAS_PDOT_IMPL(NAMES, NAMEL, TYPE) \
TYPE cpblas_ ## NAMES (int n, const TYPE * x, int ix, int jx, const int* descx, int incx, const TYPE * y, int iy, int jy, const int* descy, int incy) { \
  int ix_f = ix + 1; \
  int jx_f = jx + 1; \
  int iy_f = iy + 1; \
  int jy_f = jy + 1; \
  TYPE dot; \
  ROKKO_GLOBAL(NAMES, NAMEL) (&n, &dot, x, &ix_f, &jx_f, descx, &incx, y, &iy_f, &jy_f, descy, &incy); \
  return dot; \
} \
void cpblas_ ## NAMES ## _sub (int n, TYPE * dot, const TYPE * x, int ix, int jx, const int* descx, int incx, const TYPE * y, int iy, int jy, const int* descy, int incy) { \
  int ix_f = ix + 1; \
  int jx_f = jx + 1; \
  int iy_f = iy + 1; \
  int jy_f = jy + 1; \
  ROKKO_GLOBAL(NAMES, NAMEL) (&n, dot, x, &ix_f, &jx_f, descx, &incx, y, &iy_f, &jy_f, descy, &incy); \
}

CPBLAS_PDOT_IMPL(psdot, PSDOT, float);
CPBLAS_PDOT_IMPL(pddot, PDDOT, double);

#undef CPBLAS_PDOT_IMPL


<|start_filename|>rokko/parallel_sparse.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_PARALLEL_SPARSE_H
#define ROKKO_PARALLEL_SPARSE_H

#include <rokko/mapping_1d.h>
#include <rokko/distributed_crs_matrix.h>
#include <rokko/distributed_mfree.h>
#include <rokko/parallel_sparse_ev.h>

#endif /* ROKKO_PARALLEL_SPARSE_H */


<|start_filename|>rokko/traits/real_t.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_TRAITS_REAL_T_HPP
#define ROKKO_TRAITS_REAL_T_HPP

#include "value_t.hpp"
#include <complex>

namespace rokko {

namespace detail {

template<typename T>
struct norm_scalar_type_traits {
};

template<>
struct norm_scalar_type_traits<float> {
  using type = float;
};

template<>
struct norm_scalar_type_traits<std::complex<float>> {
  using type = float;
};

template<>
struct norm_scalar_type_traits<double> {
  using type = double;
};

template<>
struct norm_scalar_type_traits<std::complex<double>> {
  using type = double;
};

template<typename T>
struct real_type_traits {
  using value_type = rokko::value_t<T>;
  using type = typename norm_scalar_type_traits<value_type>::type;
};

} // end namespace detail

template<typename T>
using real_t = typename detail::real_type_traits<T>::type;

} // namespace rokko

#endif // ROKKO_TRAITS_REAL_T_HPP


<|start_filename|>rokko/distributed_crs_matrix.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_DISTRIBUTED_CRS_MATRIX_H
#define ROKKO_DISTRIBUTED_CRS_MATRIX_H

#include <rokko/mapping_1d.h>

#ifdef __cplusplus
extern "C" {
#endif

struct rokko_distributed_crs_matrix {
  void* ptr;
};

void rokko_distributed_crs_matrix_construct(struct rokko_distributed_crs_matrix* matrix, struct rokko_mapping_1d map, int num_entries_per_row);
void rokko_distributed_crs_matrix_destruct(struct rokko_distributed_crs_matrix* matrix);
void rokko_distributed_crs_matrix_insert(struct rokko_distributed_crs_matrix matrix, int row,
					 int col_size, int* cols, double* values);
void rokko_distributed_crs_matrix_complete(struct rokko_distributed_crs_matrix matrix);
int rokko_distributed_crs_matrix_num_local_rows(struct rokko_distributed_crs_matrix matrix);
int rokko_distributed_crs_matrix_start_row(struct rokko_distributed_crs_matrix matrix);
int rokko_distributed_crs_matrix_end_row(struct rokko_distributed_crs_matrix matrix);
void rokko_distributed_crs_matrix_print(struct rokko_distributed_crs_matrix matrix);

#ifdef __cplusplus
}
#endif

#endif /* ROKKO_DISTRIBUTED_CRS_MATRIX_H */


<|start_filename|>rokko/scalapack.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_HPP
#define ROKKO_SCALAPACK_HPP

#include <rokko/config.h>
#include <rokko/cscalapack.h>

namespace rokko {
namespace scalapack {

inline int descinit(std::array<int,9>& desc, int m, int n, int mb, int nb, int irsrc, int icsrc,
                    int ictxt, int lld) {
  return cscalapack_descinit(desc.data(), m, n, mb, nb, irsrc, icsrc, ictxt, lld);
}
  
template<typename MATRIX>
typename MATRIX::value_type pelget(char scope, char top, const MATRIX& A, int ia, int ja);

template<typename MATRIX>
void pelset(MATRIX& A, int ia, int ja, typename MATRIX::value_type alpha);

template<typename MATRIX>
typename MATRIX::value_type plange(char norm, const MATRIX& A);

template<typename MATRIX, typename VECTOR>
typename MATRIX::value_type plange(char norm, const MATRIX& A, VECTOR& work);

template<typename MATRIX, typename VECTOR>
int psyev(char jobz, char uplo, MATRIX& a, VECTOR& w, MATRIX& z);

template<typename MATRIX, typename VECTOR>
int psyev(char jobz, char uplo, MATRIX& a, VECTOR& w, MATRIX& z, VECTOR& work);

template<typename MATRIX, typename VECTOR>
int psyevd(char jobz, char uplo, MATRIX& a, VECTOR& w, MATRIX& z);

template<typename MATRIX, typename VECTOR>
int psyevd(char jobz, char uplo, MATRIX& a, VECTOR& w, MATRIX& z, VECTOR& work);

} // end namespace scalapack
} // end namespace rokko

#include "scalapack/pelget.hpp"
#include "scalapack/pelset.hpp"
#include "scalapack/plange.hpp"
#include "scalapack/psyev.hpp"
#include "scalapack/psyevd.hpp"
#ifdef ROKKO_HAVE_SCALAPACK_PDSYEVR
#include "scalapack/psyevr.hpp"
#endif

#include "scalapack/pstebz.hpp"
#include "scalapack/pstein.hpp"
#include "scalapack/pstedc.hpp"

#endif // ROKKO_SCALAPACK_HPP


<|start_filename|>rokko/utility/tuple_to_array.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2010-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTIL_TUPLE_TO_ARRAY_HPP
#define ROKKO_UTIL_TUPLE_TO_ARRAY_HPP

#include <array>
#include <tuple>
#include <utility>

namespace rokko {

template<typename T, std::size_t N, typename TUPLE, std::size_t... I>
constexpr decltype(auto) to_array_impl(const TUPLE& a, std::index_sequence<I...>) {
  return std::array<T,N>{std::get<I>(a)...};
}

template<typename HEAD, typename... T>
constexpr decltype(auto) to_array(const std::tuple<HEAD, T...>& a) {
  using TUPLE = std::tuple<HEAD, T...>;
  constexpr auto N = sizeof...(T) + 1;
  return to_array_impl<HEAD, N, TUPLE>(a, std::make_index_sequence<N>());
}

} // namespace rokko

#endif // ROKKO_UTIL_TUPLE_TO_ARRAY_HPP


<|start_filename|>rokko/mpi/reduction.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_MPI_VECTOR_REDUCTION_HPP
#define ROKKO_MPI_VECTOR_REDUCTION_HPP

#include <vector>
#include <rokko/eigen3.hpp>
#include <rokko/mpi/mpi_type_traits.hpp>

namespace rokko {

// for a scalar variable
template<typename T>
T all_reduce(T local_sum, MPI_Comm comm) {

  T sum;
  MPI_Allreduce(&local_sum, &sum, 1, rokko::mpi_type<T>,
                MPI_SUM, comm);

  return sum;
}

} // namespace rokko

#endif // ROKKO_MPI_VECTOR_REDUCTION_HPP


<|start_filename|>test/solver_class/solver.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/solver.hpp>
#ifdef ROKKO_HAVE_MPI
# include <mpi.h>
#endif

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

TEST(solver, all) {
  for(auto name : rokko::serial_dense_ev::solvers()) {
    std::cerr << name << std::endl;
    rokko::serial_dense_ev solver(name);
    solver.initialize(global_argc, global_argv);
    solver.finalize();
  }

#ifdef ROKKO_HAVE_MPI
  int provided;
  MPI_Init_thread(&global_argc, &global_argv, MPI_THREAD_MULTIPLE, &provided);

#ifdef ROKKO_HAVE_PARALLEL_DENSE_SOLVER
  for(auto name : rokko::parallel_dense_ev::solvers()) {
    std::cerr << name << std::endl;
    rokko::parallel_dense_ev solver(name);
    solver.initialize(global_argc, global_argv);
    solver.finalize();
  }
#endif // ROKKO_HAVE_PARALLEL_DENSE_SOLVER

#ifdef ROKKO_HAVE_PARALLEL_SPARSE_SOLVER
  for(auto name : rokko::parallel_sparse_ev::solvers()) {
    std::cerr << name << std::endl;
    rokko::parallel_sparse_ev solver(name);
    solver.initialize(global_argc, global_argv);
    solver.finalize();
  }
#endif // ROKKO_HAVE_PARALLEL_SPARSE_SOLVER

  MPI_Finalize();
#endif // ROKKO_HAVE_MPI
}

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  global_argc = argc;
  global_argv = argv;
  return RUN_ALL_TESTS();
}


<|start_filename|>tutorial/titpack/01_lapack_cxx/small.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

// C++ version of TITPACK Ver.2 by <NAME>

#include "small.hpp"
#include "common.hpp"
#include <lapacke.h>
#include <iostream>

void elm3(int n, std::vector<int> const& ipair, std::vector<double> const& bondwt,
          std::vector<double> const& zrtio, matrix_type& elemnt,
          std::vector<int> const& list1, std::vector<std::pair<int, int>> const& list2) {
  int ihfbit = 1 << ((n+1)/2);
  int irght = ihfbit - 1;
  int ilft = ((1 << n) - 1) ^ irght;
  int idim = list1.size();

  int ibond = ipair.size() / 2;
  if (ipair.size() != 2 * ibond || bondwt.size() != ibond || zrtio.size() != ibond) {
    std::cerr << "Incorrect size of ipair, bondwt, or zrtio\n";
    return;
  }
  datack(ipair, n);
  
  // initialization
  elemnt.resize(idim, idim);
  for (int i = 0; i < idim; ++i)
    for (int j = 0; j < idim; ++j)
      elemnt(i, j) = 0;

  // elments
  for (int k = 0; k < ibond; ++k) {
    int isite1 = ipair[2 * k];
    int isite2 = ipair[2 * k + 1];
    int is1 = 1 << isite1;
    int is2 = 1 << isite2;
    int is = is1 + is2;
    double wght = bondwt[k];
    double diag = 0.5 * wght * zrtio[k];
    for (int i = 0; i < idim; ++i) {
      int ibit = list1[i] & is;
      if (ibit == 0 || ibit == is) {
        elemnt(i,i) -= diag;
      } else {
        elemnt(i,i) += diag;
        int iexchg = list1[i] ^ is;
        int ia = iexchg & irght;
        int ib = (iexchg & ilft) / ihfbit;
        int newcfg = list2[ia].first + list2[ib].second;
        elemnt(i, newcfg) = -wght;
      }
    }
  }
}

void diag(matrix_type& elemnt, std::vector<double>& E, matrix_type& v, int nvec) {
  if (elemnt.size1() != elemnt.size2()) {
    std::cerr << "diag: Incorrect matrix size\n";
    return;
  }
  int idim = elemnt.size1();
  E.resize(idim);
  int info = LAPACKE_dsyev(LAPACK_COL_MAJOR, 'V', 'U', idim, &elemnt(0,0), idim, E.data());

  v.resize(idim, nvec);
  for (int i = 0; i < idim; ++i)
    for (int j = 0; j < nvec; ++j)
      v(i, j) = elemnt(i, j);
}

double check3(matrix_type const& elemnt, matrix_type const& x, int xindex) {
  if (elemnt.size1() != elemnt.size2() || elemnt.size1() != x.size1() || x.size2() <= xindex) {
    std::cerr << "check3: Incorrect matrix size\n";
    return 0;
  }
  int idim = elemnt.size1();

  double dnorm = 0;
  for (int j=0; j < idim; ++j) {
    dnorm += x(j, xindex) * x(j, xindex);
  }
  if (dnorm < 1e-30) {
    std::cerr << " #(W18)# Null vector given to check3\n";
    return 0;
  }
  std::vector<double> v(idim, 0);
      
  for (int i = 0; i < idim; ++i)
    for (int j = 0; j < idim; ++j)
      v[j] += elemnt(i, j) * x(i, xindex);

  double prd = 0;
  for (int i = 0; i < idim; ++i) prd += v[i] * x(i, xindex);
  
  std::cout << "---------------------------- Information from check3\n"
            << "<x*H*x> = "<< prd << std::endl
            << "H*x(j)/x(j) (j=min(idim/3,13)-1,idim,max(1,idim/20))";
  int count = 0;
  for (int i = std::min((int)(idim / 3), 13) - 1; i < idim; i += std::max(1,idim/20), ++count) {
    if (count % 4 == 0) std::cout << std::endl;
    std::cout << '\t' << v[i]/x(i, xindex);
  }
  std::cout << std::endl
            << "---------------------------------------------------\n";
  return prd;
}


<|start_filename|>rokko/traits/value_t.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_TRAITS_VALUE_T_HPP
#define ROKKO_TRAITS_VALUE_T_HPP

#include <complex>

namespace rokko {

namespace detail {

template<typename T>
struct value_type_traits {
  using type = typename T::value_type;
};

template<typename T>
struct value_type_traits<T*> {
  using type = T;
};

template<typename T>
struct value_type_traits<T**> {
  using type = T;
};

template<>
struct value_type_traits<float> {
  using type = float;
};

template<>
struct value_type_traits<std::complex<float>> {
  using type = std::complex<float>;
};

template<>
struct value_type_traits<double> {
  using type = double;
};

template<>
struct value_type_traits<std::complex<double>> {
  using type = std::complex<double>;
};

} // end namespace detail

template<typename T>
using value_t = typename detail::value_type_traits<T>::type;

} // namespace rokko

#endif // ROKKO_TRAITS_VALUE_T_HPP


<|start_filename|>rokko/utility/heisenberg_hamiltonian.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_HEISENBERG_HAMILTONIAN_HPP
#define ROKKO_UTILITY_HEISENBERG_HAMILTONIAN_HPP

#include <vector>
#include <rokko/eigen3.hpp>

namespace rokko {

namespace heisenberg_hamiltonian {

void multiply(int L, const std::vector<std::pair<int, int>>& lattice, const double* v, double* w) {
  int N = 1 << L;
  for (std::size_t l = 0; l < lattice.size(); ++l) {
    int i = lattice[l].first;
    int j = lattice[l].second;
    int m1 = 1 << i;
    int m2 = 1 << j;
    int m3 = m1 + m2;
    for (int k = 0; k < N; ++k) {
      if (((k & m3) == m1) || ((k & m3) == m2)) {  // when (bit i == 1, bit j == 0) || (bit i == 0, bit j == 1) 
        w[k] += 0.5 * v[k^m3] - 0.25 * v[k];
      } else {
        w[k] += 0.25 * v[k];
      }
    }
  }
}

void multiply(int L, const std::vector<std::pair<int, int>>& lattice, const std::vector<double>& v, std::vector<double>& w) {
  multiply(L, lattice, v.data(), w.data());
}

void fill_diagonal(int L, const std::vector<std::pair<int, int>>& lattice, double* w) {
  int N = 1 << L;
  for (int k = 0; k < N; ++k) {
    w[k] = 0;
  }

  for (std::size_t l = 0; l < lattice.size(); ++l) {
    int i = lattice[l].first;
    int j = lattice[l].second;
    int m1 = 1 << i;
    int m2 = 1 << j;
    int m3 = m1 + m2;
    for (int k = 0; k < N; ++k) {
      if (((k & m3) == m1) || ((k & m3) == m2)) {  // when (bit i == 1, bit j == 0) or (bit i == 0, bit j == 1)
        w[k] -= 0.25;
      }
      else {
        w[k] += 0.25;
      }
    }
  }
}

void fill_diagonal(int L, const std::vector<std::pair<int, int>>& lattice, std::vector<double>& w) {
  fill_diagonal(L, lattice, w.data());
}

template<typename T>
void fill_diagonal(int L, const std::vector<std::pair<int, int>>& lattice, Eigen::Vector<T>& w) {
  fill_diagonal(L, lattice, w.data());
}

template<typename T, int MATRIX_MAJOR>
void generate(int L, const std::vector<std::pair<int, int>>& lattice, Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat) {
  mat.setZero();
  int N = 1 << L;
  for (std::size_t l = 0; l < lattice.size(); ++l) {
    int i = lattice[l].first;
    int j = lattice[l].second;
    int m1 = 1 << i;
    int m2 = 1 << j;
    int m3 = m1 + m2;
    for (int k = 0; k < N; ++k) {
      if (((k & m3) == m1) || ((k & m3) == m2)) {
        // when (bit i == 1, bit j == 0) or (bit i == 0, bit j == 1)
        mat(k^m3, k) += 0.5;
        mat(k, k) -= 0.25;
      } else {
        mat(k, k) += 0.25;
      }
    }
  }
}

} // namespace heisenberg_hamiltonian

} // namespace rokko

#endif // ROKKO_UTILITY_HEISENBERG_HAMILTONIAN_HPP


<|start_filename|>example/c/dense/gev_fixedB_mpi.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <mpi.h>
#include <rokko/rokko.h>
#include <rokko/utility/frank_matrix.h>
#include <stdio.h>
#include <stdlib.h>

#include "gev_fixedB_mpi.h"


int main(int argc, char *argv[]) {
  int dim;
  struct rokko_parallel_dense_ev solver;
  struct rokko_grid grid;
  struct rokko_mapping_bc map;
  struct rokko_distributed_matrix A, B, eigvec;
  struct rokko_eigen_matrix locA, locB;
  struct rokko_eigen_vector eigval;
  char* solver_name;

  int provided, myrank, nprocs, i;

  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
  MPI_Comm_size(MPI_COMM_WORLD, &nprocs);

  if (argc == 1) {
    solver_name = argv[1];
  } else {
    solver_name = "eigen_exa";
  }

  dim = 4;
  printf("solver name = %s\n", solver_name);
  printf("matrix dimension = %d\n", dim);

  rokko_parallel_dense_ev_construct(&solver, solver_name, argc, argv);
  rokko_grid_construct(&grid, MPI_COMM_WORLD, rokko_grid_row_major);

  rokko_eigen_matrix_construct(&locA, dim, dim, rokko_matrix_col_major);
  rokko_eigen_matrix_construct(&locB, dim, dim, rokko_matrix_col_major);
  set_A_B_c(locA, locB);
  map = rokko_parallel_dense_ev_default_mapping(solver, dim, grid);
  rokko_distributed_matrix_construct(&A, map);
  rokko_distributed_matrix_construct(&B, map);
  rokko_distributed_matrix_construct(&eigvec, map);
  rokko_eigen_vector_construct(&eigval, dim);
  rokko_scatter_eigen_matrix(locA, A, 0);
  rokko_scatter_eigen_matrix(locB, B, 0);

  diagonalize_fixedB_c(solver, A, B, eigval, eigvec, 0);

  if (myrank == 0) {
    printf("Computed Eigenvalues =\n");
    for (i = 0; i < dim; ++i)
      printf("%30.20f\n", rokko_eigen_vector_get(eigval, i));
  }
  printf("Computed Eigenvectors:\n");
  rokko_distributed_matrix_print(eigvec);
  
  rokko_distributed_matrix_destruct(&A);
  rokko_distributed_matrix_destruct(&B);
  rokko_distributed_matrix_destruct(&eigvec);
  rokko_eigen_vector_destruct(&eigval);
  rokko_parallel_dense_ev_destruct(&solver);
  rokko_grid_destruct(&grid);

  MPI_Finalize();
  return 0;
}


<|start_filename|>rokko/scalapack/pstedc_work.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <rokko/scalapack/scalapack_interface.h>

#define CSCALAPACK_PSTEDC_WORK_IMPL(NAMES, NAMEL, TYPE) \
int cscalapack_## NAMES ##_work(char compz, int n, TYPE* d, TYPE* e, \
                                TYPE* Q, int iq, int jq, const int* descQ, \
                                TYPE* work, int lwork, int* iwork, int liwork) { \
  int iq_f = iq + 1; \
  int jq_f = jq + 1; \
  int info; \
  ROKKO_GLOBAL(NAMES, NAMEL) (&compz, &n, d, e, Q, &iq_f, &jq_f, descQ, \
                              work, &lwork, iwork, &liwork, &info); \
  return info; \
}

CSCALAPACK_PSTEDC_WORK_IMPL(psstedc, PSSTEDC, float)
CSCALAPACK_PSTEDC_WORK_IMPL(pdstedc, PDSTEDC, double)

#undef CSCALAPACK_PSTEDC_WORK_IMPL


<|start_filename|>test/generate_matrix/laplacian.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2013-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/laplacian_matrix.hpp>

#include <gtest/gtest.h>

template<typename T, typename MATRIX_MAJOR>
void test(int dim) {
  Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,rokko::eigen3_major<MATRIX_MAJOR>> mat(dim, dim);
  rokko::laplacian_matrix::generate(mat);
  ASSERT_EQ(mat.trace(), static_cast<T>(2*(dim-1) + 1));  // laplacian matrix consists of integer elements. Hence, its trace is also integer, and no rounding error occurs.
  ASSERT_EQ(mat.sum(), static_cast<T>(1));  // sum of all matrix elements
  ASSERT_TRUE(mat.transpose() == mat);  // checking matrix symmetry
}

TEST(generate_matrix, laplacian_matrix) {
  constexpr int dim = 20;
  std::cout << "dimension = " << dim << std::endl;

  std::cout << "  test for double, row major" << std::endl;
  test<double, rokko::matrix_row_major>(dim);
  std::cout << "  test for double, column major" << std::endl;
  test<double, rokko::matrix_col_major>(dim);
  std::cout << "  test for float, row major" << std::endl;
  test<float, rokko::matrix_row_major>(dim);
  std::cout << "  test for float, column major" << std::endl;
  test<float, rokko::matrix_col_major>(dim);
  std::cout << "  test for int, row major" << std::endl;
  test<int, rokko::matrix_row_major>(dim);
  std::cout << "  test for int, column major" << std::endl;
  test<int, rokko::matrix_col_major>(dim);
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  result = RUN_ALL_TESTS();
  return result;
}


<|start_filename|>rokko/elpa/solver.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_ELPA_SOLVER_HPP
#define ROKKO_ELPA_SOLVER_HPP

#include <rokko/parameters.hpp>
#include <rokko/elpa/elpa.h>
#include <rokko/elpa/diagonalize.hpp>

namespace rokko {
namespace elpa {

class solver {
public:
  template <typename GRID_MAJOR>
  bool is_available_grid_major(GRID_MAJOR const& /* grid_major */) { return true; }
  void initialize(int& /* argc */, char**& /* argv */) {
    if (elpa_init(20200417) != ELPA_OK) {
      throw std::invalid_argument("ERROR: elpa::initialize()");
    }
  }
  void finalize() {
    // int error;
    // elpa_uninit(&error);
  }
  mapping_bc<matrix_col_major> default_mapping(int dim, grid const& g) const {
    // Determine mb, nb, lld, larray
    int mb = dim / g.get_nprow();
    if (mb == 0)  mb = 1;
    int nb = dim / g.get_npcol();
    if (nb == 0)  nb = 1;
    // Note: it should be that mb = nb in pdsyev.
    int b = std::min(mb, nb);
    return mapping_bc<matrix_col_major>(dim, b, g);
  }
  template <typename T, typename MATRIX_MAJOR, typename VEC>
  parameters diagonalize(distributed_matrix<T, MATRIX_MAJOR>& mat, VEC& eigvals,
			 distributed_matrix<T, MATRIX_MAJOR>& eigvecs,
			 parameters const& params) {
    return rokko::elpa::diagonalize(mat, eigvals, eigvecs, params);
  }

  template <typename T, typename MATRIX_MAJOR, typename VEC>
  parameters diagonalize(distributed_matrix<T, MATRIX_MAJOR>& mat, VEC& eigvals,
			 parameters const& params) {
    return rokko::elpa::diagonalize(mat, eigvals, params);
  }
};

} // namespace elpa
} // namespace rokko

#endif // ROKKO_ELPA_SOLVER_HPP


<|start_filename|>example/c/dense/generate_matrix/frank_array.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.h>
#include <stdio.h>
#include <stdlib.h>

#define MAX(a, b) ((a) > (b) ? (a) : (b))

#define DIM 10

int main(int argc, char *argv[]) {
  struct rokko_eigen_matrix mat;
  double array_ptr[DIM*DIM];
  int i, j;

  /* generate frank matrix */
  for(i=0; i<DIM; ++i) {
    for(j=0; j<DIM; ++j) {
      array_ptr[i + j*DIM] = DIM - MAX(i, j);
    }
  }

  rokko_eigen_matrix_construct_array_sizes(&mat, DIM, DIM, array_ptr, rokko_matrix_col_major);
  rokko_eigen_matrix_print(mat);

  /*rokko_eigen_matrix_destruct(&mat);*/

  return 0;
}


<|start_filename|>rokko/lapack/diagonalize_syevd.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_DIAGONALIZE_SYEVD_HPP
#define ROKKO_LAPACK_DIAGONALIZE_SYEVD_HPP

#include <rokko/parameters.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/utility/timer.hpp>
#include <rokko/lapack.hpp>
#include <rokko/lapack/diagonalize_get_parameters.hpp>
#include <rokko/lapack/syevd.hpp>

namespace rokko {
namespace lapack {

// only eigenvalues
template<typename T, int MATRIX_MAJOR, typename VEC>
parameters diagonalize_syevd(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat, VEC& eigvals,
			      parameters const& params) {
  rokko::parameters params_out;
  const char uplow = lapack::get_matrix_part(params);

  int info = syevd('N', uplow, mat, eigvals);

  params_out.set("info", info);
  if (info) {
    std::cerr << "error at syevd function. info=" << info  << std::endl;
  }
  if (params.get_bool("verbose")) {
    print_verbose("syevd", 'N', uplow);
  }

  return params_out;
}

// eigenvalues / eigenvectors
template<typename T, int MATRIX_MAJOR, typename VEC>
parameters diagonalize_syevd(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat, VEC& eigvals,
			      Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& eigvecs,
			      parameters const& params) {
  rokko::parameters params_out;
  const char uplow = get_matrix_part(params);

  int info = syevd('V', uplow, mat, eigvals);
  eigvecs = mat;

  params_out.set("info", info);
  if (info) {
    std::cerr << "error at syevd function. info=" << info  << std::endl;
  }
  if (params.get_bool("verbose")) {
    print_verbose("syevd", 'V', uplow);
  }

  return params_out;
}


} // namespace lapack
} // namespace rokko

#endif // ROKKO_LAPACK_DIAGONALIZE_SYEVD_HPP


<|start_filename|>rokko/lapack/orgqr.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include "ungqr.hpp"


<|start_filename|>rokko/lapack/diagonalize_syevx.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_DIAGONALIZE_SYEVX_HPP
#define ROKKO_LAPACK_DIAGONALIZE_SYEVX_HPP

#include <rokko/parameters.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/utility/timer.hpp>
#include <rokko/lapack.hpp>
#include <rokko/lapack/diagonalize_get_parameters.hpp>
#include <rokko/lapack/syevx.hpp>

namespace rokko {
namespace lapack {

// only eigenvalues
template<typename T, int MATRIX_MAJOR, typename VEC>
parameters diagonalize_syevx(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat, VEC& eigvals,
			      parameters const& params) {
  parameters params_out;

  real_t<T> abstol = params.defined("abstol") ? params.get<real_t<T>>("abstol") : 2*LAPACKE_dlamch('S');
  params_out.set("abstol", abstol);

  lapack_int il, iu;
  real_t<T> vl, vu;
  const char range = get_eigenvalues_range(params, vl, vu, il, iu);
  const char uplow = get_matrix_part(params);

  lapack_int m;  // output: found eigenvalues
  const int dim = mat.outerSize();
  std::vector<lapack_int> ifail(dim);

  int info = syevx(range, uplow, mat,
                   vl, vu, il, iu, abstol,
                   m, eigvals, ifail);

  if (info) {
    std::cerr << "error at syevx function. info=" << info << std::endl;
    if (info < 0) {
      std::cerr << "This means that ";
      std::cerr << "the " << abs(info) << "-th argument had an illegal value." << std::endl;
    }
  }
  params_out.set("info", info);
  params_out.set("m", m);
  params_out.set("ifail", ifail);
  
  if (params.get_bool("verbose")) {
    print_verbose("syevx", 'N', range, uplow, vl, vu, il, iu, params_out);
  }

  return params_out;
}


// eigenvalues / eigenvectors
template<typename T, int MATRIX_MAJOR, typename VEC>
parameters diagonalize_syevx(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat, VEC& eigvals,
			      Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& eigvecs,
			      parameters const& params) {
  rokko::parameters params_out;

  real_t<T> abstol = params.defined("abstol") ? params.get<real_t<T>>("abstol") : 2*LAPACKE_dlamch('S');
  params_out.set("abstol", abstol);

  lapack_int il, iu;
  real_t<T> vl, vu;
  const char range = get_eigenvalues_range(params, vl, vu, il, iu);
  const char uplow = get_matrix_part(params);

  lapack_int m;  // output: found eigenvalues
  const int dim = mat.outerSize();
  std::vector<lapack_int> ifail(dim);

  int info = syevx(range, uplow, mat,
                   vl, vu, il, iu, abstol,
                   m, eigvals, eigvecs, ifail);

  if (info) {
    std::cerr << "Error at syevx function. info=" << info << std::endl;
    if (params.get_bool("verbose")) {
      std::cerr << "This means that ";
      if (info < 0) {
        std::cerr << "the " << abs(info) << "-th argument had an illegal value." << std::endl;
      } else {
        std::cerr << "This means that "	<< info << " eigenvectors failed to converge." << std::endl;
        std::cerr << "The indices of the eigenvectors that failed to converge:" << std::endl;
        for (std::size_t i = 0; i < ifail.size(); ++i) {
          if (ifail[i] == 0) break;
          std::cerr << ifail[i] << " ";
        }
        std::cerr << std::endl;
      }
    }
  }
  params_out.set("info", info);
  params_out.set("m", m);
  params_out.set("ifail", ifail);
  
  if (params.get_bool("verbose")) {
    print_verbose("syevx", 'V', range, uplow, vl, vu, il, iu, params_out);
  }

  return params_out;
}


} // namespace lapack
} // namespace rokko

#endif // ROKKO_LAPACK_DIAGONALIZE_SYEVX_HPP


<|start_filename|>example/fortran/dense/generate_matrix/matrix012_mpi.f90<|end_filename|>
!*****************************************************************************
!
! Rokko: Integrated Interface for libraries of eigenvalue decomposition
!
! Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
!
! 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)
!
!*****************************************************************************

program generate_matrix012_mpi
  use rokko
  use mpi
  implicit none
  integer :: dim
  type(rokko_distributed_matrix) :: mat
  type(rokko_grid) :: grid
  type(rokko_mapping_bc) :: map

  integer :: provided, ierr, myrank, nprocs

  call MPI_init_thread(MPI_THREAD_MULTIPLE, provided, ierr)
  call MPI_comm_rank(MPI_COMM_WORLD, myrank, ierr)
  call MPI_comm_size(MPI_COMM_WORLD, nprocs, ierr)

  dim = 10

  if (myrank == 0) then
     print *,"dimension = ", dim
  endif

  call rokko_construct(grid, MPI_COMM_WORLD, rokko_grid_row_major)
  call rokko_construct(map, dim, 1, grid)
  call rokko_construct(mat, map)

  ! generate matrix012
  call rokko_matrix012_generate(mat)
  call rokko_print(mat)

  call rokko_destruct(mat)
  call rokko_destruct(map)
  call rokko_destruct(grid)

  call MPI_finalize(ierr)
end program generate_matrix012_mpi


<|start_filename|>rokko/utility/pyrokko_minij_matrix.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_MINIJ_MATRIX_HPP
#define PYROKKO_MINIJ_MATRIX_HPP

#include <rokko/utility/minij_matrix.hpp>

#include <rokko/pyrokko_distributed_matrix.hpp>

namespace rokko {

class wrap_minij_matrix {
public:
  template <typename T, int MAJOR>
  static void generate(Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR>> mat_in) {
    Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR> mat(mat_in.rows(), mat_in.cols());
    new (&mat) Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR>>(mat_in);
    minij_matrix::generate(mat);
    new (&mat) Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR>();
  }

  template <typename T, typename MATRIX_MAJOR>
  static void generate(wrap_distributed_matrix<T,MATRIX_MAJOR>& mat) {
    minij_matrix::generate(mat);
  }
};

} // namespace rokko

#endif // PYROKKO_MINIJ_MATRIX_HPP


<|start_filename|>rokko/eigen3/generate_vector.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_EIGEN3_GENERATE_VECTOR_HPP
#define ROKKO_EIGEN3_GENERATE_VECTOR_HPP

#include <iostream>
#include <rokko/eigen3.hpp>

namespace rokko {

template<typename T, int ROWS, class FUNC>
void generate(Eigen::Vector<T,ROWS>& vec, FUNC func) {
  for(int i = 0; i < vec.size(); ++i) {
    vec(i) = func(i);
  }
}

template<typename T, int ROWS>
void generate(Eigen::Vector<T,ROWS>& vec, std::function<T(int)> const& func) {
  for(int i = 0; i < vec.size(); ++i) {
    vec(i) = func(i);
  }
}

} // namespace rokko

#endif // ROKKO_EIGEN3_GENERATE_VECTOR_HPP


<|start_filename|>rokko/scalapack/diagonalize_bisection.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_DIAGONALIZE_BISECTION_HPP
#define ROKKO_SCALAPACK_DIAGONALIZE_BISECTION_HPP

#include <rokko/distributed_matrix.hpp>
#include <rokko/parameters.hpp>
#include <rokko/lapack/diagonalize_get_parameters.hpp>
#include <rokko/scalapack/diagonalize_psyevx.hpp>
#include <rokko/utility/timer.hpp>

#include <mpi.h>

namespace rokko {
namespace scalapack {

// bisection (pdsyevx) eigenvalues & eigenvectors
template<typename T, typename MATRIX_MAJOR, typename VEC>
parameters diagonalize_bisection(distributed_matrix<T, MATRIX_MAJOR>& mat,
			       VEC& eigvals, distributed_matrix<T, MATRIX_MAJOR>& eigvecs,
			       parameters const& params) {
  if (params.defined("abstol")) {
    if (params.get<real_t<T>>("abstol") < 0) {
      std::stringstream msg;
      msg << "scalapack::diagonalize_bisection() : " << std::endl
          << "abstol is negative value, which means QR method." << std::endl
          << "To use pdsyevx as bisection solver, set abstol a positive value" << std::endl;
      throw std::invalid_argument(msg.str());
    }
  }
  parameters params_out = diagonalize_psyevx(mat, eigvals, eigvecs, params);

  if (params.get_bool("verbose")) {
    std::cout << "finished pdsyevx (bisection)" << std::endl;
  }

  return params_out;
}

// bisection (pdsyevx) only eigenvalues
template<typename T, typename MATRIX_MAJOR, typename VEC>
parameters diagonalize_bisection(distributed_matrix<T, MATRIX_MAJOR>& mat,
			       VEC& eigvals,
			       parameters const& params) {
  if (params.defined("abstol")) {
    if (params.get<real_t<T>>("abstol") < 0) {
      std::stringstream msg;
      msg << "scalapack::diagonalize_bisection() : " << std::endl
          << "abstol is negative value, which means QR method." << std::endl
          << "To use pdsyevx as bisection solver, set abstol a positive value" << std::endl;
      throw std::invalid_argument(msg.str());
    }
  }
  parameters params_out = diagonalize_psyevx(mat, eigvals, params);

  if (params.get_bool("verbose")) {
    std::cout << "finished pdsyevx (bisection)" << std::endl;
  }

  return params_out;
}

} // namespace scalapack
} // namespace rokko

#endif // ROKKO_SCALAPACK_DIAGONALIZE_BISECTION_HPP


<|start_filename|>rokko/scalapack/pelset.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_PELSET_HPP
#define ROKKO_SCALAPACK_PELSET_HPP

#include <rokko/cscalapack.h>

namespace rokko {
namespace scalapack {

namespace {

inline void pelset_dispatch(double* A, int ia, int ja, const int* descA, double alpha) {
  cscalapack_pdelset(A, ia, ja, descA, alpha);
}
  
inline void pelset_dispatch(float* A, int ia, int ja, const int* descA, float alpha) {
  cscalapack_pselset(A, ia, ja, descA, alpha);
}
  
}

template<typename MATRIX>
void pelset(MATRIX& A, int ia, int ja, typename MATRIX::value_type alpha) {
  pelset_dispatch(A.get_array_pointer(), ia, ja, A.get_blacs_descriptor(), alpha);
}

} // end namespace scalapack
} // end namespace rokko

#endif // ROKKO_SCALAPACK_PELSET_HPP


<|start_filename|>rokko/scalapack/pstein_work.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <rokko/scalapack/scalapack_interface.h>

#define CSCALAPACK_PSTEIN_WORK_IMPL(NAMES, NAMEL, TYPE, TYPE_REAL) \
int cscalapack_## NAMES ##_work(int n, const TYPE_REAL* d, const TYPE_REAL* e, int m, \
                                TYPE_REAL* w, const int* iblock, const int* isplit, TYPE_REAL orfac, \
                                TYPE* Z, const int* iZ, const int* jZ, const int* descZ, \
                                TYPE* work, int lwork, int* iwork, int liwork, \
                                int* ifail, int* iclustr, TYPE_REAL* gap) { \
  int info; \
  ROKKO_GLOBAL(NAMES, NAMEL) (&n, d, e, &m, \
                              w, iblock, isplit, &orfac, \
                              Z, iZ, jZ, descZ, \
                              work, &lwork, iwork, &liwork, \
                              ifail, iclustr, gap, &info); \
  return info; \
}

CSCALAPACK_PSTEIN_WORK_IMPL(psstein, PSSTEIN, float, float)
CSCALAPACK_PSTEIN_WORK_IMPL(pdstein, PDSTEIN, double, double)
CSCALAPACK_PSTEIN_WORK_IMPL(pcstein, PCSTEIN, lapack_complex_float, float)
CSCALAPACK_PSTEIN_WORK_IMPL(pzstein, PZSTEIN, lapack_complex_double, double)

#undef CSCALAPACK_PSTEIN_WORK_IMPL


<|start_filename|>rokko/scalapack/pelget.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_PELGET_HPP
#define ROKKO_SCALAPACK_PELGET_HPP

#include <rokko/cscalapack.h>

namespace rokko {
namespace scalapack {

namespace {

inline double pelget_dispatch(char scope, char top, const double* A, int ia, int ja,
                              const int* descA) {
  return cscalapack_pdelget(scope, top, A, ia, ja, descA);
}
  
inline float pelget_dispatch(char scope, char top, const float* A, int ia, int ja,
                             const int* descA) {
  return cscalapack_pselget(scope, top, A, ia, ja, descA);
}
  
}

template<typename MATRIX>
typename MATRIX::value_type pelget(char scope, char top, const MATRIX& A, int ia, int ja)  {
  return pelget_dispatch(scope, top, A.get_array_pointer(), ia, ja, A.get_blacs_descriptor());
}

} // end namespace scalapack
} // end namespace rokko

#endif // ROKKO_SCALAPACK_PELGET_HPP


<|start_filename|>rokko/distributed_matrix.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_DISTRIBUTED_MATRIX_H
#define ROKKO_DISTRIBUTED_MATRIX_H

#include <rokko/mapping_bc.h>

#ifdef __cplusplus
extern "C" {
#endif

struct rokko_distributed_matrix {
  void* ptr;
  int major;
};

void rokko_distributed_matrix_construct(struct rokko_distributed_matrix* matrix, struct rokko_mapping_bc map);
void rokko_distributed_matrix_construct_array(struct rokko_distributed_matrix* matrix, struct rokko_mapping_bc map, double *array);
void rokko_distributed_matrix_construct_array_sizes(struct rokko_distributed_matrix* matrix, struct rokko_mapping_bc map, int dim1, int dim2, double *array);
void rokko_distributed_matrix_destruct(struct rokko_distributed_matrix* matrix);
void rokko_distributed_matrix_generate_function(struct rokko_distributed_matrix matrix,
  double (*func)(int i, int j));
void rokko_distributed_matrix_generate_function_p(struct rokko_distributed_matrix matrix,
  double (*func)(const int* i, const int* j));
void rokko_distributed_matrix_generate_function1(struct rokko_distributed_matrix matrix,
  double (*func)(int i, int j));
void rokko_distributed_matrix_generate_function1_p(struct rokko_distributed_matrix matrix,
  double (*func)(const int* i, const int* j));
void rokko_distributed_matrix_print(struct rokko_distributed_matrix matrix);
void rokko_distributed_matrix_set_local(struct rokko_distributed_matrix matrix,
  int local_i, int local_j, double value);
double rokko_distributed_matrix_get_local(struct rokko_distributed_matrix matrix,
  int local_i, int local_j);
void rokko_distributed_matrix_set_global(struct rokko_distributed_matrix matrix,
  int global_i, int global_j, double value);
double rokko_distributed_matrix_get_global(struct rokko_distributed_matrix matrix,
  int global_i, int global_j);
/* offset by one for Fortran */
void rokko_distributed_matrix_set_local1(struct rokko_distributed_matrix matrix,
  int local_i, int local_j, double value);
double rokko_distributed_matrix_get_local1(struct rokko_distributed_matrix matrix,
  int local_i, int local_j);
void rokko_distributed_matrix_set_global1(struct rokko_distributed_matrix matrix,
  int global_i, int global_j, double value);
double rokko_distributed_matrix_get_global1(struct rokko_distributed_matrix matrix,
  int global_i, int global_j);
int rokko_distributed_matrix_get_mb(struct rokko_distributed_matrix matrix);
int rokko_distributed_matrix_get_nb(struct rokko_distributed_matrix matrix);
int rokko_distributed_matrix_get_m_local(struct rokko_distributed_matrix matrix);
int rokko_distributed_matrix_get_n_local(struct rokko_distributed_matrix matrix);
int rokko_distributed_matrix_get_m_global(struct rokko_distributed_matrix matrix);
int rokko_distributed_matrix_get_n_global(struct rokko_distributed_matrix matrix);
int rokko_distributed_matrix_get_lld(struct rokko_distributed_matrix matrix);
int rokko_distributed_matrix_get_m_size(struct rokko_distributed_matrix matrix);
int rokko_distributed_matrix_get_n_size(struct rokko_distributed_matrix matrix);
int rokko_distributed_matrix_get_nprocs(struct rokko_distributed_matrix matrix);
int rokko_distributed_matrix_get_myrank(struct rokko_distributed_matrix matrix);
int rokko_distributed_matrix_get_nprow(struct rokko_distributed_matrix matrix);
int rokko_distributed_matrix_get_npcol(struct rokko_distributed_matrix matrix);
int rokko_distributed_matrix_get_myrow(struct rokko_distributed_matrix matrix);
int rokko_distributed_matrix_get_mycol(struct rokko_distributed_matrix matrix);
int rokko_distributed_matrix_translate_l2g_row(struct rokko_distributed_matrix matrix,
  int local_i);
int rokko_distributed_matrix_translate_l2g_col(struct rokko_distributed_matrix matrix,
  int local_j);
int rokko_distributed_matrix_translate_g2l_row(struct rokko_distributed_matrix matrix,
  int global_i);
int rokko_distributed_matrix_translate_g2l_col(struct rokko_distributed_matrix matrix,
  int global_j);
/* offset by one for Fortran */
int rokko_distributed_matrix_translate_l2g_row1(struct rokko_distributed_matrix matrix,
  int local_i);
int rokko_distributed_matrix_translate_l2g_col1(struct rokko_distributed_matrix matrix,
  int local_j);
int rokko_distributed_matrix_translate_g2l_row1(struct rokko_distributed_matrix matrix,
  int global_i);
int rokko_distributed_matrix_translate_g2l_col1(struct rokko_distributed_matrix matrix,
  int global_j);
double* rokko_distributed_matrix_get_array_pointer(struct rokko_distributed_matrix matrix);

#ifdef __cplusplus
}
#endif

#endif /* ROKKO_DISTRIBUTED_MATRIX_H */


<|start_filename|>example/cxx/sparse/distributed_crs_symmetric_matrix_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>

int main(int argc, char *argv[]) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  int rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);

  std::string library(rokko::parallel_sparse_ev::default_solver());
  if (argc >= 2) library = argv[1];

  constexpr int dim = 8;
  std::vector<std::vector<int>> cols = {{0, 4}, {3}, {5}, {1, 7}, {0, 5, 6}, {2, 4}, {4, 7}, {3, 6}};
  std::vector<std::vector<double>> values = {{7.1, 2.8}, {6.4}, {0.5}, {6.4, 3.5}, {2.8, 0.2, 1.4}, {0.5, 0.2}, {1.4, 4.3}, {3.5, 4.3}};

  int num_entries_per_row = std::max_element(cols.cbegin(), cols.cend(),
                                              [] (auto const& a, auto const& b) {
                                                return a.size() < b.size();
                                              })->size();

  if (rank == 0) std::cout << "[solver = " << library << "]" << std::endl;
  rokko::parallel_sparse_ev solver(library);
  auto map = solver.default_mapping(dim, rokko::mpi_comm{MPI_COMM_WORLD});
  rokko::distributed_crs_matrix mat(map, num_entries_per_row);
  for (int row = map.start_row(); row < map.end_row(); ++row) {
    mat.insert(row, cols[row], values[row]);
  }
  mat.complete();
  mat.print();
  
  solver.finalize();
  MPI_Finalize();
}


<|start_filename|>example/c/sparse/laplacian_mfree_no_context_mpi.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <rokko/utility/laplacian_matrix.h>

#define min(a, b) ((a) < (b) ? (a) : (b))

struct laplacian_vars {
  MPI_Comm comm;
  int nprocs, myrank;
  int dim, local_offset, num_local_rows;
  int start_row, end_row;
  int end_k;
  int is_first_proc, is_last_proc;
} lap_var;


void laplacian_multiply(const double *const x, double *const y) {
  double buf_m, buf_p;
  MPI_Status status_m, status_p;

  if (lap_var.num_local_rows == 0) return;

  if ((!lap_var.is_first_proc) && (lap_var.nprocs != 1)) {
    //std::cout << "recv myrank=" << lap_var.myrank << std::endl;
    MPI_Send(&x[0], 1, MPI_DOUBLE, lap_var.myrank-1, 0, lap_var.comm);
    MPI_Recv(&buf_m, 1, MPI_DOUBLE, lap_var.myrank-1, 0, lap_var.comm, &status_m);
    //std::cout << "buffff=" << buf << std::endl;
  }

  if ((!lap_var.is_last_proc) && (lap_var.nprocs != 1)) {
    //std::cout << "send myrank=" << lap_var.myrank << std::endl;
    MPI_Recv(&buf_p, 1, MPI_DOUBLE, lap_var.myrank+1, 0, lap_var.comm, &status_p);
    MPI_Send(&x[lap_var.end_k], 1, MPI_DOUBLE, lap_var.myrank+1, 0, lap_var.comm);
    //std::cout << "buffff=" << buf2 << std::endl;
  }

  if (lap_var.is_first_proc) {
    if (lap_var.num_local_rows != 1) {
      y[0] = x[0] - x[1];
      if (lap_var.nprocs != 1) y[lap_var.end_k] = - x[lap_var.end_k - 1] + 2 * x[lap_var.end_k] - buf_p;
    }
    else {
      y[0] = x[0] - buf_p;
    }
  }

  if (lap_var.is_last_proc) {
    if (lap_var.num_local_rows != 1) {
      if (lap_var.nprocs != 1) y[0] = - buf_m + 2 * x[0] - x[1];
      y[lap_var.end_k] = 2 * x[lap_var.end_k] - x[lap_var.end_k - 1];
      }
    else {
      y[lap_var.end_k] = 2 * x[lap_var.end_k] - buf_m;
    }
  }
  if (!(lap_var.is_first_proc || lap_var.is_last_proc)) { // neither first or last process
    if (lap_var.num_local_rows != 1) {
      y[0] = - buf_m + 2 * x[0] - x[1];
      y[lap_var.end_k] = - x[lap_var.end_k - 1] + 2 * x[lap_var.end_k] - buf_p;
    }
    else {
      y[0] = - buf_m + 2 * x[0] - buf_p;
    }
  }
  // from 1 to end-1
  int k;
  for (k=1; k<lap_var.end_k; ++k) {
    y[k] = - x[k-1] + 2 * x[k] - x[k+1];
  }
}

void laplacian_initialize(struct rokko_distributed_mfree* mat, int dim, struct laplacian_vars* vars) {
  rokko_distributed_mfree_construct_no_context(mat, laplacian_multiply, dim, MPI_COMM_WORLD);

  lap_var.comm = MPI_COMM_WORLD;
  MPI_Comm_size(lap_var.comm, &lap_var.nprocs);
  MPI_Comm_rank(lap_var.comm, &lap_var.myrank);

  lap_var.dim = dim;
  lap_var.num_local_rows = rokko_distributed_mfree_num_local_rows(*mat);
  lap_var.start_row = rokko_distributed_mfree_start_row(*mat);
  lap_var.end_row = rokko_distributed_mfree_end_row(*mat);

  lap_var.is_first_proc = (lap_var.start_row == 0);
  lap_var.is_last_proc = (lap_var.end_row == (lap_var.dim));

  lap_var.end_k = lap_var.num_local_rows - 1;
}

int main(int argc, char *argv[]) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  int rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);

  char* library_routine, *library, *routine;
  if (argc >= 2) {
    library_routine = rokko_parallel_sparse_ev_default_solver();
    if (argc >= 2) library_routine = argv[1];
  } else {
    library_routine = rokko_parallel_sparse_ev_default_solver();
  }
  rokko_split_solver_name(library_routine, &library, &routine);
  int dim = (argc == 3) ? dim = atoi(argv[2]) : 100;

  struct rokko_parallel_sparse_ev solver;
  rokko_parallel_sparse_ev_construct(&solver, library, argc, argv);
  struct rokko_distributed_mfree mat;
  struct laplacian_vars vars;
  laplacian_initialize(&mat, dim, &vars);
  if (rank == 0) {
    printf("Eigenvalue decomposition of Laplacian matrix\n");
    printf("solver = %s\n", library);
    printf("dimension = %d\n", dim);
  }

  struct rokko_parameters params;
  rokko_parameters_construct(&params);
  // set some parameters
  if (routine[0] != '\0')  rokko_parameters_set_string(params, "routine", routine);
  rokko_parameters_set_int(params, "block_size", 5);
  rokko_parameters_set_int(params, "max_iters", 500);
  rokko_parameters_set_double(params, "conv_tol", 1.0e-8);
  rokko_parallel_sparse_ev_diagonalize_distributed_mfree(solver, mat, params);

  int num_conv = rokko_parallel_sparse_ev_num_conv(solver);
  if (num_conv == 0) MPI_Abort(MPI_COMM_WORLD, -1);
  int num_local_rows = rokko_distributed_mfree_num_local_rows(mat);
  double eig_vec[num_local_rows];
  rokko_parallel_sparse_ev_eigenvector(solver, 0, eig_vec);
  if (rank == 0) {
    printf("number of converged eigenpairs = %d\n", num_conv);
    printf("largest eigenvalues: ");
    int i, j;
    for (i = 0; i < num_conv; ++i) printf("%30.20f", rokko_parallel_sparse_ev_eigenvalue(solver, i));
    printf("\n");
    printf("smallest theoretical eigenvalues: ");
    for (i = 0; i < num_conv; ++i) printf("%30.20f", rokko_laplacian_matrix_eigenvalue(dim, i));
    //for (i = 0; i < num_conv; ++i) printf("%30.20f", rokko_laplacian_matrix_eigenvalue(dim, dim-1-i));
    printf("\n");
    printf("largest eigenvector: ");
    for (j = 0; j < num_local_rows; ++j)
      printf("%30.20f ", eig_vec[j]);
    printf("\n");
  }
  rokko_distributed_mfree_destruct(&mat);
  rokko_parallel_sparse_ev_destruct(&solver);

  MPI_Finalize();
  return 0;
}


<|start_filename|>rokko/utility/compare_vectors.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_COMPARE_VECTORS_HPP
#define ROKKO_UTILITY_COMPARE_VECTORS_HPP

#include <rokko/eigen3.hpp>

namespace rokko {

template <typename T>
T sign(T a) {
  return (a>0) - (a<0);
}

template <typename MAT1, typename MAT2>
auto norm_diff(const MAT1 source, const MAT2 target) {
  const auto sign_diff = sign(source(0,0) * target(0,0));
  return (source - sign_diff * target).norm();
}

} // namespace rokko

#endif // ROKKO_UTILITY_COMPARE_VECTORS_HPP


<|start_filename|>rokko/utility/math.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_MATH_HPP
#define ROKKO_UTILITY_MATH_HPP

namespace rokko {

// Assume that n >= 1
int find_power_of_two(int n) {
  int p = 0;
  while (n > 1) {
    n /= 2;
    ++p;
  };
  return p;
}

} // namespace rokko

#endif // ROKKO_UTILITY_MATH_HPP


<|start_filename|>rokko/anasazi/mapping_1d.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_ANASAZI_MAPPING_1D_HPP
#define ROKKO_ANASAZI_MAPPING_1D_HPP

#include <rokko/mpi_communicator.hpp>
#include <rokko/mapping_1d.hpp>

#include <Epetra_MpiComm.h>
#include <Epetra_Map.h>

#include <memory>

namespace rokko {

namespace anasazi {

class mapping_1d : public detail::ps_mapping_1d_base {
public:
  explicit mapping_1d() = default;
  explicit mapping_1d(int dim) : mapping_1d(dim, mpi_comm{MPI_COMM_WORLD}) {}
  explicit mapping_1d(int dim, mpi_comm const& mpi_comm_in)
    : detail::ps_mapping_1d_base(dim, mpi_comm_in), ep_comm_(std::make_shared<Epetra_MpiComm>(mpi_comm_in.get_comm())), map_(std::make_shared<Epetra_Map>(dim, 0, *ep_comm_)) {}
  explicit mapping_1d(int dim, int num_local_rows, mpi_comm const& mpi_comm_in)
    : detail::ps_mapping_1d_base(dim, mpi_comm_in), ep_comm_(std::make_shared<Epetra_MpiComm>(mpi_comm_in.get_comm())), map_(std::make_shared<Epetra_Map>(dim, num_local_rows, 0, *ep_comm_)) {}

  int get_num_local_rows() const override { return map_->NumMyElements();; }
  int start_row() const override {
    return get_epetra_map().MinMyGID();
  }
  int end_row() const override {
    return get_epetra_map().MaxMyGID() + 1; // to follow C++ convention
  }

  Epetra_MpiComm const& get_epetra_comm() const { return *ep_comm_; }
  Epetra_Map const& get_epetra_map() const { return *map_; }

private:
  std::shared_ptr<const Epetra_MpiComm> ep_comm_;
  std::shared_ptr<const Epetra_Map> map_;
};

} // namespace anasazi

} // namespace rokko

#endif // ROKKO_ANASAZI_MAPPING_1D_HPP


<|start_filename|>example/cxx/utility/parameters.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/parameters.hpp>
#include <iostream>

int main() {
  rokko::parameters params;
  char p = 'V';
  // set some parameters
  params.set("T", 0.95);
  params.set("Pi", 3.14);
  params.set("A", "test");
  //params.set("C", 'A');
  params.set("C", p);

  // get double
  /* double t = */ params.get<double>("T");

  // get string
  /* std::string a = */ params.get<std::string>("A");

  // get char
  /* char c = */ params.get<char>("C");

  // is "T" defined?
  /* bool t_defined = */ params.defined("T");
  
  // is "S" defined?
  /* bool s_defined = */ params.defined("S");

  // clear paramter "Pi"
  params.clear("Pi");
  
  // output list of parameters as string
  std::list<std::string> keys = params.keys();
  std::cout << "number of parameters = " << keys.size() << std::endl;
  std::cout << "key-value pairs:\n";
  for(auto const& key : keys) {
    std::cout << "  " << key << " = " << params.get_string(key) << std::endl;
  }
}


<|start_filename|>rokko/rokko.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/config.h>

#ifdef __cplusplus

#include <rokko/solver.hpp>

#else /* __cplus */

#include <rokko/solver_name.h>
#include <rokko/dense.h>
#include <rokko/sparse.h>

#endif /* __cplus */


<|start_filename|>rokko/eigenexa/eigen_loop_end.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/ceigenexa.h>
#include <rokko/eigenexa/eigenexa_interface.h>

int ceigenexa_loop_end(int iend, int nnod, int inod) {
  inod += 1;
  return EIGENEXA_loop_end_wrap(&iend, &nnod, &inod);
}


<|start_filename|>example/lapack/slange_f.f90<|end_filename|>
program main
  implicit none
  integer, parameter :: n = 5
  real :: a(n, n), norm, work(n)
  integer :: i, j
  real :: slange
  do j = 1, n
     do i = 1, n
        a(i, j) = min(i, j)
     end do
  end do
  print *, "Matrix A: ", n, n
  do j = 1, n
     print *, a(1:n, j)
  end do

  norm = slange('M', n, n, a, n)
  print *, "element of largest absolute value =", norm
  norm = slange('1', n, n, a, n)
  print *, "one norm =", norm
  norm = slange('I', n, n, a, n, work)
  print *, "infinity norm =", norm
  norm = slange('F', n, n, a, n)
  print *, "Frobenius norm =", norm
end program main


<|start_filename|>rokko/utility/laplacian_matrix.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_LAPLACIAN_MATRIX_HPP
#define ROKKO_UTILITY_LAPLACIAN_MATRIX_HPP

#include <cmath>
#include <vector>
#include <stdexcept>
#include <rokko/eigen3.hpp>
#if defined(ROKKO_HAVE_PARALLEL_DENSE_SOLVER)
# include <rokko/distributed_matrix.hpp>
#endif

namespace rokko {

// laplacian_matrix can be defined for n >= 2.
class laplacian_matrix {
public:
  template<typename T>
  static void multiply(int dim, const T* x, T* y) {
    y[0] = x[0] - x[1];
    y[dim-1] = 2 * x[dim-1] - x[dim - 2];
    for (int k = 1; k < (dim-1); ++k) { // from 1 to end-1
      y[k] = - x[k-1] + 2 * x[k] - x[k+1];
    }
  }

  template<typename T>
  static void multiply(int dim, const std::vector<T>& v, std::vector<T>& w) {
    multiply(dim, v.data(), w.data());
  }

  // Giving diagonal and sub-diagonal elements as two vectors
  template<typename VEC>
  static void generate(VEC& d, VEC& e) {
    if (d.size() > (e.size()+1))
      throw std::invalid_argument("laplacian_matrix::generate() : The vector for sub-diagonal elements is too short.");

    const int n = d.size();
    d[0] = 1;
    for(int i = 1; i < n; ++i)
      d[i] = 2;
    for(int i = 0; i < (n-1); ++i)
      e[i] = -1;
  }

  template<typename T, int ROWS, int COLS>
  static void generate(Eigen::Matrix<T,ROWS,COLS,Eigen::ColMajor>& mat) {
    if (mat.rows() != mat.cols())
      throw std::invalid_argument("laplacian_matrix::generate() : non-square matrix");
    mat.setZero();
    const int n = mat.cols();
    mat(0, 0) = 1;  mat(1, 0) = -1;
    for(int i = 1; i < n-1; ++i) {
      mat(i-1, i) = -1;
      mat(i,   i) = 2;
      mat(i+1, i) = -1;
    }
    mat(n-2, n-1) = -1;  mat(n-1, n-1) = 2;
  }

  template<typename T, int ROWS, int COLS>
  static void generate(Eigen::Matrix<T,ROWS,COLS,Eigen::RowMajor>& mat) {
    if (mat.rows() != mat.cols())
      throw std::invalid_argument("laplacian_matrix::generate() : non-square matrix");
    mat.setZero();
    const int n = mat.rows();
    mat(0, 0) = 1;  mat(0, 1) = -1;
    for(int i = 1; i < n-1; ++i) {
      mat(i, i-1) = -1;
      mat(i, i) = 2;
      mat(i, i+1) = -1;
    }
    mat(n-1, n-2) = -1;  mat(n-1, n-1) = 2;
  }

#if defined(ROKKO_HAVE_PARALLEL_DENSE_SOLVER)
  template<typename T>
  static void generate(rokko::distributed_matrix<T, matrix_col_major>& mat) {
    if (mat.get_m_global() != mat.get_n_global())
      throw std::invalid_argument("laplacian_matrix::generate() : non-square matrix");
    mat.set_zeros();
    const int n = mat.get_n_global();
    mat.set_global(0, 0, 1);  mat.set_global(1, 0, -1);
    for(int i = 1; i < n-1; ++i) {
      mat.set_global(i-1, i, -1);
      mat.set_global(i,   i, 2);
      mat.set_global(i+1, i, -1);
    }
    mat.set_global(n-2, n-1, -1);  mat.set_global(n-1, n-1, 2);
  }

  template<typename T>
  static void generate(rokko::distributed_matrix<T, matrix_row_major>& mat) {
    if (mat.get_m_global() != mat.get_n_global())
      throw std::invalid_argument("laplacian_matrix::generate() : non-square matrix");
    mat.set_zeros();
    const int n = mat.get_m_global();
    mat.set_global(0, 0, 1);  mat.set_global(0, 1, -1);
    for(int i = 1; i < n-1; ++i) {
      mat.set_global(i, i-1, -1);
      mat.set_global(i, i, 2);
      mat.set_global(i, i+1, -1);
    }
    mat.set_global(n-1, n-2, -1);  mat.set_global(n-1, n-1, 2);
  }
#endif

  // calculate k-th smallest eigenvalue of dim-dimensional Laplacian matrix (k=0...dim-1)
  static double eigenvalue(int dim, int k) {
    return 2 * (1 - std::cos(M_PI * (2 * k + 1) / (2 * dim + 1)));
  }
};

} // namespace rokko

#endif // ROKKO_UTILITY_LAPLACIAN_MATRIX_HPP


<|start_filename|>example/python/sparse/py_laplacian_mfree.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/numpy.h>
#include <pybind11/eigen.h>

#include <rokko/pyrokko_distributed_mfree.hpp>
#include <rokko/utility/laplacian_mfree.hpp>

namespace py = pybind11;

PYBIND11_MODULE(laplacian, m) {
  py::module::import("pyrokko");

  py::class_<rokko::laplacian_mfree, rokko::distributed_mfree_default, rokko::distributed_mfree>(m, "mfree")
    .def(py::init<int>());
}


<|start_filename|>benchmark/no_rokko/dense_minij_mpi/eigen_s.f90<|end_filename|>
      subroutine mat_set(n, a, nm)

      use eigen_libs_mod
      use mpi
!$    use omp_lib

      implicit none

      integer, intent(in)    :: n, nm
      real(8), intent(out)   :: a(1:nm,*)

      real(8), parameter     :: ZERO= 0.0D0
      real(8), parameter     :: ONE = 1.0D0

      integer                :: COMM, x_COMM, y_COMM
      integer                :: nnod, x_nnod, y_nnod
      integer                :: inod, x_inod, y_inod
      integer                :: iloop_sta, iloop_end
      integer                :: jloop_sta, jloop_end
      integer                :: i, i_1
      integer                :: j, j_1

      call eigen_get_comm (COMM, x_COMM, y_COMM)
      call eigen_get_procs(nnod, x_nnod, y_nnod)
      call eigen_get_id   (inod, x_inod, y_inod)

      jloop_sta = eigen_loop_start(1, x_nnod, x_inod)
      jloop_end = eigen_loop_end  (n, x_nnod, x_inod)
      iloop_sta = eigen_loop_start(1, y_nnod, y_inod)
      iloop_end = eigen_loop_end  (n, y_nnod, y_inod)

      if (iloop_sta <= iloop_end) then
!$OMP PARALLEL DO &
!$OMP& PRIVATE(i,j,i_1,j_1)
         do i_1 = iloop_sta, iloop_end
            i = eigen_translate_l2g(i_1, y_nnod, y_inod)
            do j_1 = jloop_sta, jloop_end
               j = eigen_translate_l2g(j_1, x_nnod, x_inod)
               a(j_1, i_1) = min(i,j)*ONE
            end do
         end do
!$OMP END PARALLEL DO
      end if

      end subroutine  mat_set


program EigenExa
  use eigen_libs_mod
  use mpi
  implicit none
  double precision   init_tick, gen_tick, diag_tick, end_tick
  integer :: n, m, nm, ny, mtype, i, i_inod, ierr
  real(8), pointer :: a(:,:),z(:,:),w(:)
  character(len=10) :: tmp_str
  integer arg_len, status

  call mpi_init_thread( MPI_THREAD_MULTIPLE, i, ierr )
  if (command_argument_count().eq.1) then
     call get_command_argument(1, tmp_str, arg_len, status)
     read(tmp_str, *) n
  else
     write(*,'(A)') "Error: eigen_exa dimension"
     stop
  endif
  
  call mpi_barrier(mpi_comm_world, ierr)
  init_tick = mpi_wtime()
  call mpi_comm_rank( mpi_comm_world, i_inod, ierr )
  call eigen_init()
  call mpi_barrier(mpi_comm_world, ierr)
  gen_tick = mpi_wtime()
  call eigen_get_matdims( n, nm, ny )
  allocate( a(nm, ny), z(nm, ny), w(n))
  call mat_set( n, a, nm )

  call mpi_barrier(mpi_comm_world, ierr)
  diag_tick = mpi_wtime()
  call eigen_s( n, n, a, nm, w, z, nm, 48, 128, 'A')
  call mpi_barrier(mpi_comm_world, ierr)
  end_tick = mpi_wtime()
  if ( i_inod == 0 ) then
     print *, "Matrix dimension = ", n
     do i = 1, min(100, n)
        print *, i, w(i)
     end do
     print *, "init_time = ", gen_tick - init_tick
     print *, "gen_time = ", diag_tick - gen_tick
     print *, "diag_time = ", end_tick - diag_tick
  end if

  call eigen_free( )
  call MPI_Finalize( ierr )
end program EigenExa


<|start_filename|>config/check_geqpf.f90<|end_filename|>
program main
  call sgeqpf()
  call dgeqpf()
  call cgeqpf()
  call zgeqpf()
end program



<|start_filename|>rokko/utility/pyrokko_frank_matrix.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_FRANK_MATRIX_HPP
#define PYROKKO_FRANK_MATRIX_HPP

#include <rokko/utility/frank_matrix.hpp>

#include <rokko/pyrokko_distributed_matrix.hpp>

namespace rokko {

class wrap_frank_matrix {
public:
  template <typename T, int MAJOR>
  static void generate(Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR>> mat_in) {
    Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR> mat;
    new (&mat) Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR>>(mat_in);
    frank_matrix::generate(mat);
    new (&mat) Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR>();
  }

  template<typename T, typename MATRIX_MAJOR>
  static void generate(wrap_distributed_matrix<T,MATRIX_MAJOR>& mat) {
    frank_matrix::generate(mat);
  }
};

} // namespace rokko

#endif // PYROKKO_FRANK_MATRIX_HPP


<|start_filename|>test/sparse/laplacian_crs_variable_local_rows_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/laplacian_matrix.hpp>
#include <rokko/utility/various_mpi_comm.hpp>

#include <gtest/gtest.h>

constexpr double eps = 1e-8;

int global_argc;
char** global_argv;

void run_test(std::string const& library, MPI_Comm comm) {
  constexpr int dim = 20;
  std::cout << "library = " << library << std::endl;

  rokko::parameters params;
  params.set("num_eigvals", 1);
  params.set("block_size", 5);
  params.set("max_iters", 500);
  params.set("conv_tol", eps);

  rokko::parallel_sparse_ev solver(library);
  if (comm != MPI_COMM_NULL) {
    rokko::mpi_comm rokko_comm{comm};
    const int nprocs = rokko_comm.get_nprocs();
    const int myrank = rokko_comm.get_myrank();
    const int num_local_rows = (myrank == (nprocs-1)) ? dim - (nprocs-1) : 1;
    auto map = solver.default_mapping(dim, num_local_rows, rokko_comm);
    rokko::distributed_crs_matrix mat(map, 3);

    if ((map.start_row() == 0) && (map.num_local_rows() != 0)) {
      mat.insert(0, {0, 1}, {1., -1.});
    }

    for (int row = std::max(1,map.start_row()); row < std::min(map.end_row(),dim-1); ++row) {
      mat.insert(row, {row-1, row, row+1}, {-1., 2., -1.});
    }

    if (map.end_row() == dim && (map.num_local_rows() != 0)) {
      mat.insert(dim-1, {dim-2, dim-1}, {-1., 2.});
    }

    mat.complete();

    std::vector<std::array<std::string,2>> routines;
    if (library=="anasazi")
      routines = { {"lobpcg", "largest_real"}, {"block_krylov_schur", "largest"}, {"block_davidson", "largest_real"}, {"rtr", "largest_real"} };
    else if (library=="slepc")
      routines = { {"krylovschur", "largest"}, {"lanczos", "largest"}, {"lobpcg", "largest_real"}, {"rqcg", "smallest_real"}, {"subspace", "largest"} };  // excludes not converging "power"

    for (auto routine : routines) {
      std::cout << "routine=" << routine[0] << std::endl;
      auto params_tmp = params;
      params_tmp.set("routine", routine[0]);
      if (routine[0] == "block_davidson")  params_tmp.set("block_size", 10);
      params_tmp.set("wanted_eigenvalues", routine[1]);

      rokko::parameters info = solver.diagonalize(mat, params_tmp);

      int num_conv = info.get<int>("num_conv");
      if (num_conv == 0)
        throw std::runtime_error("num_conv=0: solver did not converge");

      double eigval = solver.eigenvalue(0);
      double th_eigval = (routine[0] == "rqcg") ? rokko::laplacian_matrix::eigenvalue(dim, 0)  // smallest one
        : rokko::laplacian_matrix::eigenvalue(dim, dim-1);  // largest one
      EXPECT_NEAR(eigval, th_eigval, eigval*eps);
    }
  } // end if comm != MPI_COMM_NULL
  solver.finalize();
}

TEST(laplacian_crs, eigenvalue) {
  for(auto library : rokko::parallel_sparse_ev::solvers()) {
    run_test(library, MPI_COMM_WORLD);
    run_test(library, create_even_odd_comm_by_split());
    run_test(library, create_even_odd_comm());
    run_test(library, create_even_comm());  // MPI_COMM_NULL for odd rank number
  }
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>example/lapack/sterf.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/blas.hpp>
#include <rokko/lapack/sterf.hpp>
#include <rokko/lapack/lange.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/utility/laplacian_matrix.hpp>
#include <iostream>

int main(int argc, char** argv) {
  constexpr double eps = 1e-10;
  int n = 5;
  if (argc > 1) n = std::stoi(argv[1]);

  // generate matrix
  Eigen::VectorXd d(n), e(n-1);
  rokko::laplacian_matrix::generate(d, e);

  // diagonalization
  Eigen::VectorXd w = d;
  int info = rokko::lapack::sterf(w, e);
  std::cout << "Eigenvalues: " << std::endl << w << std::endl;

  return 0;
}


<|start_filename|>example/fortran/dense/helmert.f90<|end_filename|>
!*****************************************************************************
!
! Rokko: Integrated Interface for libraries of eigenvalue decomposition
!
! Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
!
! 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)
!
!*****************************************************************************

program minij_matrix
  use rokko
  implicit none
  integer :: dim
  type(rokko_serial_dense_ev) :: solver
  type(rokko_eigen_matrix) :: mat, Z
  type(rokko_eigen_vector) :: diag, w
  type(rokko_parameters) :: params, params_out
  character(len=:), allocatable :: library, routine
  character(len=:), allocatable :: solver_name, tmp_str
  double precision, pointer, dimension(:) :: diag_ptr
  integer :: i, info

  if (command_argument_count() >= 1) then
     call get_command_argument_deferred(1, solver_name)
  else
     solver_name = rokko_serial_dense_ev_default_solver()
  endif
  call rokko_split_solver_name(solver_name, library, routine)

  if (command_argument_count() == 2) then
     call get_command_argument_deferred(2, tmp_str)
     read(tmp_str, *) dim
  else
     dim = 10
  endif

  print *,"library = ", library
  print *,"routine = ", routine
  print *,"dimension = ", dim

  call rokko_construct(solver, library)

  call rokko_construct(mat, dim, dim, rokko_matrix_col_major)
  call rokko_construct(Z, dim, dim, rokko_matrix_col_major)
  call rokko_construct(w, dim)

  ! generate matrix whose eigenvectors are helmert matrix
  call rokko_construct(diag, dim)
  call rokko_get_array_pointer(diag, diag_ptr)
  do i=1, dim
     diag_ptr(i) = i
  enddo
  call rokko_helmert_matrix_generate(mat, diag)
  call rokko_print(mat)

  call rokko_construct(params)
  call rokko_set(params, "routine", "syev")

!  call diagonalize(solver, mat, w, Z, params, params_out)
!  call diagonalize(solver, mat, w, Z, params)
!  call diagonalize(solver, mat, w, Z)
  call rokko_diagonalize(solver, mat, w, params, params_out)
!  call diagonalize(solver, mat, w, params)
!  call diagonalize(solver, mat, w)

  call rokko_get(params_out, "info", info)

  print *, "info=", info

  write(*,'(A)') "Computed Eigenvalues = "
  do i = 1, dim
     write(*,"(f30.20)") rokko_get_elem(w ,i)
  enddo

  call rokko_destruct(mat)
  call rokko_destruct(Z)
  call rokko_destruct(w)
  call rokko_destruct(solver)

end program minij_matrix


<|start_filename|>rokko/utility/minij_matrix.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_MINIJ_MATRIX_H
#define ROKKO_UTILITY_MINIJ_MATRIX_H

#include <rokko/dense.h>

#ifdef __cplusplus
extern "C"{
#endif

void rokko_minij_matrix_generate_eigen_matrix(struct rokko_eigen_matrix matrix);

#if defined(ROKKO_HAVE_PARALLEL_DENSE_SOLVER)
void rokko_minij_matrix_generate_distributed_matrix(struct rokko_distributed_matrix matrix);
#endif /* defined(ROKKO_HAVE_PARALLEL_DENSE_SOLVER) */

#ifdef __cplusplus
}
#endif

#endif /* ROKKO_UTILITY_MINIJ_MATRIX_H */


<|start_filename|>rokko/eigenexa/eigen_get_matdims.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/ceigenexa.h>
#include <rokko/eigenexa/eigenexa_interface.h>

void ceigenexa_get_matdims(int nprow, int npcol, int n, int *nx, int *ny) {
  EIGENEXA_get_matdims_wrap(&nprow, &npcol, &n, nx, ny);
}


<|start_filename|>example/c/dense/generate_matrix/minij_get_array_pointer.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.h>
#include <stdio.h>
#include <stdlib.h>

#define MIN(a, b) ((a) < (b) ? (a) : (b))

int main(int argc, char *argv[]) {
  struct rokko_eigen_matrix mat;
  double *array_ptr;
  int dim, i, j;

  dim = 10;
  rokko_eigen_matrix_construct(&mat, dim, dim, rokko_matrix_col_major);
  array_ptr = rokko_eigen_matrix_get_array_pointer(mat);

  /* generate minij matrix */
  for(i=0; i<dim; ++i) {
    for(j=0; j<dim; ++j) {
      array_ptr[i + j*dim] = MIN(i, j) + 1;
    }
  }
  rokko_eigen_matrix_print(mat);

  rokko_eigen_matrix_destruct(&mat);

  return 0;
}


<|start_filename|>rokko/eigenexa/eigen_init.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/ceigenexa.h>
#include <rokko/eigenexa/eigenexa_interface.h>

void ceigenexa_init(void) {
  EIGENEXA_init_wrap0();
}

void ceigenexa_init1(MPI_Comm comm) {
  MPI_Fint fcomm = MPI_Comm_c2f(comm);
  EIGENEXA_init_wrap1(&fcomm);
}

void ceigenexa_init2(MPI_Comm comm, char grid_major) {
  MPI_Fint fcomm = MPI_Comm_c2f(comm);
  EIGENEXA_init_wrap2(&fcomm, &grid_major);
}


<|start_filename|>test/matrix_product/product_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2013-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/frank_matrix.hpp>
#include <rokko/collective.hpp>

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

TEST(product_mpi, product_mpi) {
  MPI_Comm comm = MPI_COMM_WORLD;
  int rank;
  MPI_Comm_rank(comm, &rank);

  int dim = 100;
  if (global_argc > 1) {
    dim = std::stoi(global_argv[1]);
  }

  if (rank == 0) std::cout << "dimension = " << dim << std::endl;
  rokko::parallel_dense_ev solver(rokko::parallel_dense_ev::default_solver());
  rokko::grid g(comm);
  rokko::mapping_bc<rokko::matrix_col_major> map = solver.default_mapping(dim, g);
  rokko::distributed_matrix<double, rokko::matrix_col_major> matA(map);
  rokko::distributed_matrix<double, rokko::matrix_col_major> matC(map);
  rokko::frank_matrix::generate(matA);
  rokko::product(1.0, matA, false, matA, false, 0, matC);
  matC.print();
  double trace_distributed = rokko::trace(matC);
  int dim_proc = (rank == 0) ? dim : 0;
  Eigen::MatrixXd g_matC(dim_proc, dim_proc);
  rokko::gather(matC, g_matC, 0);

  if (rank == 0) {
    std::cout << "trace of distributed matrix = " << trace_distributed << std::endl;
    Eigen::MatrixXd lmatA(dim, dim);
    rokko::frank_matrix::generate(lmatA);
    const Eigen::MatrixXd lmatC = lmatA * lmatA;
    std::cout << lmatC << std::endl;
    const double trace = lmatC.trace();
    std::cout << "trace of eigen matrix = " << trace << std::endl;
    ASSERT_EQ(trace_distributed, trace);
    ASSERT_TRUE(g_matC == lmatC);
  }
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>test/mapping_bc/sum_of_local_size.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/mapping_bc.hpp>

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

template <typename MATRIX_MAJOR, typename GRID_MAJOR>
void run_test(std::array<int,2> const& global_size, std::array<int,2> const& block_size, GRID_MAJOR) {
  rokko::grid g(MPI_COMM_WORLD, GRID_MAJOR{});
  rokko::mapping_bc<MATRIX_MAJOR> map(global_size, block_size, g);
  constexpr int root_proc = 0;

  if (g.get_myrank() == root_proc) {
    std::array<int,2> local_sum{0,0};

    for (int proc=0; proc<g.get_nprow(); ++proc) {
      local_sum[0] += map.template calculate_default_local_size<0>(proc);
    }
    ASSERT_EQ(local_sum[0], global_size[0]);

    for (int proc=0; proc<g.get_npcol(); ++proc) {
      local_sum[1] += map.template calculate_default_local_size<1>(proc);
    }
    ASSERT_EQ(local_sum[1], global_size[1]);
  }
}

template <typename MATRIX_MAJOR>
void test_both_grid_major(std::array<int,2> const& global_size, std::array<int,2> const& block_size) {
  run_test<MATRIX_MAJOR>(global_size, block_size, rokko::grid_row_major);
  run_test<MATRIX_MAJOR>(global_size, block_size, rokko::grid_col_major);
}

TEST(mapping_bc, sum_of_local_size) {
  test_both_grid_major<rokko::matrix_col_major>({20,8}, {4,3});
  test_both_grid_major<rokko::matrix_col_major>({8,20}, {4,3});
  test_both_grid_major<rokko::matrix_col_major>({5,7}, {9,12});
  test_both_grid_major<rokko::matrix_col_major>({7,9}, {9,5});
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>test/generate_matrix/laplacian_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/grid.hpp>
#include <rokko/solver.hpp>
#include <rokko/distributed_matrix.hpp>
#include <rokko/utility/laplacian_matrix.hpp>
#include <rokko/collective.hpp>

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

TEST(generate_matrix, laplacian_mpi) {
  constexpr int dim = 1000;
  rokko::grid g(MPI_COMM_WORLD);

  for(auto name : rokko::parallel_dense_ev::solvers()) {
    rokko::parallel_dense_ev solver(name);
    solver.initialize(global_argc, global_argv);
    rokko::mapping_bc<rokko::matrix_col_major> map = solver.default_mapping(dim, g);
    rokko::distributed_matrix<double,rokko::matrix_col_major> mat(map);
    rokko::laplacian_matrix::generate(mat);

    constexpr int root_proc = 0;
    const int dim_proc = (g.get_myrank() == root_proc) ? dim : 0;
    Eigen::MatrixXd lmat_gather(dim_proc, dim_proc);
    rokko::gather(mat, lmat_gather, root_proc);

    if (g.get_myrank() == root_proc) {
      Eigen::MatrixXd lmat(dim, dim);
      rokko::laplacian_matrix::generate(lmat);
      ASSERT_TRUE(lmat_gather == lmat);
    }

    solver.finalize();
  }
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>tutorial/titpack/03_rokko_cxx/sample-11.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

// C++ version of TITPACK Ver.2 by <NAME>

/************ Sample main program #11 *****************
* 1d Heisenberg antiferromagnet with 8 spins
* Eigenvalues and an eigenvector by diag
******************************************************/

#include <iostream>
#include <chrono>
#include <rokko/rokko.hpp>
#include "titpack.hpp"
#include "options.hpp"

using solver_type = rokko::serial_dense_ev;
using matrix_type = Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>;

int main(int argc, char** argv) {
  std::cout.precision(10);
  options opt(argc, argv, 8, solver_type::default_solver());
  if (!opt.valid) std::abort();
  std::chrono::system_clock::time_point t1 = std::chrono::system_clock::now();

  // lattice structure
  int n = opt.N;
  int ibond = n;
  std::vector<int> ipair;
  for (int i = 0; i < ibond; ++i) {
    ipair.emplace_back(i);
    ipair.emplace_back((i + 1) % n);
  }

  // Hamiltonian parameters
  std::vector<double> bondwt(ibond, -1);
  std::vector<double> zrtio(ibond, 1);

  // table of configurations and Hamiltonian operator
  subspace ss(n, 0);
  hamiltonian hop(ss, ipair, bondwt, zrtio);
  solver_type solver(opt.solver);
  solver.initialize(argc, argv);

  // Hamiltonian matrix
  matrix_type elemnt(hop.dimension(), hop.dimension());
  elm3(hop, elemnt);
  std::chrono::system_clock::time_point t2 = std::chrono::system_clock::now();
  
  std::vector<double> E(hop.dimension());
  matrix_type v(hop.dimension(), hop.dimension());
  solver.diagonalize(elemnt, E, v);
  std::chrono::system_clock::time_point t3 = std::chrono::system_clock::now();

  int ne = 4;
  std::cout << "[Eigenvalues]\n";
  for (int i = 0; i < ne; ++i) std::cout << '\t' << E[i];
  std::cout << std::endl;

  // // Do not forget to call elm3 again before calling check3
  elm3(hop, elemnt);
  matrix_type w(hop.dimension(), 1);
  check3(elemnt, v, 0, w);
  std::chrono::system_clock::time_point t4 = std::chrono::system_clock::now();

  std::vector<int> npair;
  npair.emplace_back(1);
  npair.emplace_back(2);
  std::vector<double> sxx(1);
  xcorr(ss, npair, v, 0, sxx);
  std::cout << "sxx: " << sxx[0] << std::endl;
  std::vector<double> szz(1);
  zcorr(ss, npair, v, 0, szz);
  std::cout << "szz: " << szz[0] << std::endl;
  std::chrono::system_clock::time_point t5 = std::chrono::system_clock::now();
  std::cerr << "initialize      " << 1.0e-6 * std::chrono::duration_cast<std::chrono::microseconds>(t2-t1).count() << " sec\n"
            << "diagonalization " << 1.0e-6 * std::chrono::duration_cast<std::chrono::microseconds>(t3-t2).count() << " sec\n"
            << "check           " << 1.0e-6 * std::chrono::duration_cast<std::chrono::microseconds>(t4-t3).count() << " sec\n"
            << "correlation     " << 1.0e-6 * std::chrono::duration_cast<std::chrono::microseconds>(t5-t4).count() << " sec\n";
}


<|start_filename|>rokko/lapack/htedc.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_HTEDC_HPP
#define ROKKO_LAPACK_HTEDC_HPP

#include <complex>
#include <lapacke.h>
#undef I
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>
#include "complex_cast.hpp"
#include <rokko/lapack/storage.hpp>
#include <rokko/alias_template_function.hpp>

namespace rokko {
namespace lapack {

namespace {

template<typename T> struct htedc_dispatch;

template<>
struct htedc_dispatch<float> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int htedc(int matrix_layout, char compz, lapack_int n,
                          VECTOR& d, VECTOR& e, MATRIX& z) {
    return LAPACKE_sstedc(matrix_layout, compz, n, storage(d), storage(e), storage(z), ld(z));
  }
};

template<>
struct htedc_dispatch<double> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int htedc(int matrix_layout, char compz, lapack_int n,
                          VECTOR& d, VECTOR& e, MATRIX& z) {
    return LAPACKE_dstedc(matrix_layout, compz, n, storage(d), storage(e), storage(z), ld(z));
  }
};

template<>
struct htedc_dispatch<std::complex<float>> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int htedc(int matrix_layout, char compz, lapack_int n,
                          VECTOR& d, VECTOR& e, MATRIX& z) {
    return LAPACKE_cstedc(matrix_layout, compz, n, storage(d), storage(e), complex_cast(storage(z)), ld(z));
  }
};

template<>
struct htedc_dispatch<std::complex<double>> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int htedc(int matrix_layout, char compz, lapack_int n,
                          VECTOR& d, VECTOR& e, MATRIX& z) {
    return LAPACKE_zstedc(matrix_layout, compz, n, storage(d), storage(e), complex_cast(storage(z)), ld(z));
  }
};

} // end of anonymous namespace

template<typename MATRIX, typename VECTOR>
lapack_int htedc(char compz, VECTOR& d, VECTOR& e, MATRIX& z) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR>>::value, "");
  lapack_int n = size(d);
  if (rows(z) != cols(z))
    throw std::invalid_argument("matrix Z size mismatch");
  if (size(d) != n)
    throw std::invalid_argument("vector d size mismatch");
  if (size(e) != (n-1))
    throw std::invalid_argument("vector e size mismatch");
  return htedc_dispatch<value_t<MATRIX>>::
    htedc((is_col_major(z) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR), compz, n, d, e, z);
}

// eigenvalues & eigenvectors (without compz)
template<typename MATRIX, typename VECTOR>
lapack_int htedc(VECTOR& d, VECTOR& e, MATRIX& z) {
  return htedc('I', d, e, z);
}

// only eigenvalues (without compz)
template<typename VECTOR>
lapack_int htedc(VECTOR& d, VECTOR& e) {
  lapack_int n = size(d);

  using T = value_t<VECTOR>;
  constexpr null_matrix<T> z_null;

  return htedc_dispatch<value_t<VECTOR>>::
    htedc(LAPACK_COL_MAJOR, 'N', n, d, e, z_null);
}

ALIAS_TEMPLATE_FUNCTION(stedc, htedc);

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_HTEDC_HPP


<|start_filename|>example/c/dense/generate_matrix/minij_set_local_mpi.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <mpi.h>
#include <rokko/rokko.h>
#include <stdio.h>
#include <stdlib.h>

#define MIN(a, b) ((a) < (b) ? (a) : (b))

int main(int argc, char *argv[]) {
  int dim;
  struct rokko_grid grid;
  struct rokko_mapping_bc map;
  struct rokko_distributed_matrix mat;
  int provided, myrank, nprocs;
  int m_local, n_local;
  int local_i, local_j, global_i, global_j;

  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
  MPI_Comm_size(MPI_COMM_WORLD, &nprocs);

  dim = 10;
  if (myrank == 0) {
    printf("dimension = %d\n", dim);
  }

  rokko_grid_construct(&grid, MPI_COMM_WORLD, rokko_grid_row_major);
  rokko_mapping_bc_construct_block_size(&map, dim, 1, grid);
  rokko_distributed_matrix_construct(&mat, map);

  /* generate minij matrix */
  m_local = rokko_mapping_bc_get_m_local(map);
  n_local = rokko_mapping_bc_get_n_local(map);
  for(local_j=0; local_j<n_local; ++local_j) {
    global_j = rokko_mapping_bc_translate_l2g_col(map, local_j);
    for(local_i=0; local_i<m_local; ++local_i) {
      global_i = rokko_mapping_bc_translate_l2g_row(map, local_i);
      rokko_distributed_matrix_set_local(mat, local_i, local_j, MIN(global_i, global_j) + 1);
    }
  }
  rokko_distributed_matrix_print(mat);

  rokko_distributed_matrix_destruct(&mat);
  rokko_mapping_bc_destruct(&map);
  rokko_grid_destruct(&grid);

  MPI_Finalize();
  return 0;
}


<|start_filename|>rokko/skel/mapping_1d.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SKEL_MAPPING_1D_HPP
#define ROKKO_SKEL_MAPPING_1D_HPP

#include <rokko/mpi_communicator.hpp>
#include <rokko/mapping_1d.hpp>
#include <rokko/eigen3.hpp>

namespace rokko {

namespace skel {

class mapping_1d : public detail::ps_mapping_1d_base {
public:
  explicit mapping_1d() : mapping_1d(0) {}
  explicit mapping_1d(int dim) : mapping_1d(dim, mpi_comm{MPI_COMM_WORLD}) {}
  explicit mapping_1d(int dim, mpi_comm const& mpi_comm_in)
    : detail::ps_mapping_1d_base(dim, mpi_comm_in), num_local_rows_(calculate_num_local_rows()), start_row_(calculate_start_row()), end_row_(start_row_ + num_local_rows_) {}

  explicit mapping_1d(int dim, int num_local_rows, mpi_comm const& mpi_comm_in)
    : detail::ps_mapping_1d_base(dim, mpi_comm_in),
    num_local_rows_(num_local_rows), start_row_(calculate_start_row_by_gather(num_local_rows)), end_row_(start_row_ + num_local_rows_) {}

  int get_num_local_rows() const override { return num_local_rows_; }
  int start_row() const override { return start_row_; }
  int end_row() const override { return end_row_; }

  int calculate_start_row_by_gather(int num_local_rows) const {
    const int myrank = get_mpi_comm().get_myrank();
    Eigen::VectorXi target(get_mpi_comm().get_nprocs());

    MPI_Allgather(&num_local_rows, 1, MPI_INT,
                  target.data(), 1, MPI_INT,
                  get_mpi_comm().get_comm());

    int sum = 0;
    for (int rank = 0; rank < myrank; ++rank)
      sum += target(rank);
    return sum;
  }

  int calculate_num_local_rows() const {
    return calculate_num_local_rows(get_mpi_comm().get_myrank());
  }
  int calculate_num_local_rows(int proc) const {
    return (get_dim() + get_mpi_comm().get_nprocs() - proc - 1) / get_mpi_comm().get_nprocs();
  }

  int calculate_start_row() {
    const int nprocs = get_mpi_comm().get_nprocs();
    const int myrank = get_mpi_comm().get_myrank();
    return get_dim() / nprocs * myrank + std::min(get_dim() % nprocs, myrank);
  }

private:
  int num_local_rows_;
  int start_row_, end_row_;
};

} // namespace skel

} // namespace rokko

#endif // ROKKO_SKEL_MAPPING_1D_HPP


<|start_filename|>rokko/matrix_major.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2016 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_MATRIX_MAJOR_HPP
#define ROKKO_MATRIX_MAJOR_HPP

namespace rokko {

extern struct matrix_row_major {} matrix_row_major_d;
extern struct matrix_col_major {} matrix_col_major_d;

} // namespace rokko

#endif // ROKKO_MATRIX_MAJOR_HPP


<|start_filename|>example/lapack/dlange.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2017 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <math.h>
#include <cblas.h>
#include <lapacke.h>
#include <rokko/cmatrix.h>

int imax(int x, int y) { return (x > y) ? x : y; }

int main(int argc, char** argv) {
  int n = 5;
  int i, j;
  double norm, check;
  double **a;

  if (argc > 1) n = atoi(argv[1]);

  // generate matrix and rhs vector
  a = alloc_dmatrix(n, n);
  for (j = 0; j < n; ++j) {
    for (i = 0; i < n; ++i) {
      mat_elem(a, i, j) = n - 0.253 * imax(i, j);
    }
  }
  printf("Matrix A: ");
  fprint_dmatrix(stdout, n, n, a);

  /* calculate various norms */
  norm = LAPACKE_dlange(LAPACK_COL_MAJOR, '1', n, n, mat_ptr(a), n);
  printf("norm1(A) = %e\n", norm);

  norm = LAPACKE_dlange(LAPACK_COL_MAJOR, 'I', n, n, mat_ptr(a), n);
  printf("normI(A) = %e\n", norm);

  norm = LAPACKE_dlange(LAPACK_COL_MAJOR, 'F', n, n, mat_ptr(a), n);
  printf("normF(A) = %e\n", norm);

  /* check of result */
  check = 0;
  for (j = 0; j < n; ++j) {
    for (i = 0; i < n; ++i) {
      check += mat_elem(a, i, j) * mat_elem(a, i, j);
    }
  }
  if (fabs(check - norm * norm) > 1e-12 * check) {
    fprintf(stderr, "Error: check error %e != %e\n", norm * norm, check);
    exit(255);
  }

  free_dmatrix(a);
  return 0;
}


<|start_filename|>rokko/distributed_crs_matrix_c.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/distributed_crs_matrix.h>
#include <rokko/distributed_crs_matrix.hpp>

void rokko_distributed_crs_matrix_construct(struct rokko_distributed_crs_matrix* matrix, struct rokko_mapping_1d map, int num_entries_per_row) {
  matrix->ptr = new rokko::distributed_crs_matrix(*static_cast<rokko::mapping_1d*>(map.ptr), num_entries_per_row);
}

void rokko_distributed_crs_matrix_destruct(rokko_distributed_crs_matrix* matrix) {
  delete static_cast<rokko::distributed_crs_matrix*>(matrix->ptr);
  matrix->ptr = nullptr;
}

void rokko_distributed_crs_matrix_insert(struct rokko_distributed_crs_matrix matrix, int row, int col_size, int* cols, double* values) {
  static_cast<rokko::distributed_crs_matrix*>(matrix.ptr)->insert(row, col_size, cols, values);
}

void rokko_distributed_crs_matrix_complete(struct rokko_distributed_crs_matrix matrix) {
  static_cast<rokko::distributed_crs_matrix*>(matrix.ptr)->complete();
}

int rokko_distributed_crs_matrix_start_row(struct rokko_distributed_crs_matrix matrix) {
  return static_cast<rokko::distributed_crs_matrix*>(matrix.ptr)->start_row();
}

int rokko_distributed_crs_matrix_end_row(struct rokko_distributed_crs_matrix matrix) {
  return static_cast<rokko::distributed_crs_matrix*>(matrix.ptr)->end_row();
}

int rokko_distributed_crs_matrix_num_local_rows(struct rokko_distributed_crs_matrix matrix) {
  return static_cast<rokko::distributed_crs_matrix*>(matrix.ptr)->get_num_local_rows();
}

void rokko_distributed_crs_matrix_print(struct rokko_distributed_crs_matrix matrix) {
  return static_cast<rokko::distributed_crs_matrix*>(matrix.ptr)->print();
}


<|start_filename|>rokko/sparse.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SPARSE_H
#define ROKKO_SPARSE_H

#include <rokko/config.h>

#if defined(ROKKO_HAVE_PARALLEL_SPARSE_SOLVER)
# include <rokko/parallel_sparse.h>
#endif /* defined(ROKKO_HAVE_PARALLEL_SPARSE_SOLVER) */

#endif /* ROKKO_SPARSE_H */


<|start_filename|>rokko/parallel_dense.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2016 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_PARALLEL_DENSE_H
#define ROKKO_PARALLEL_DENSE_H

#ifdef __cplusplus
extern "C" {
#endif

#include <rokko/grid.h>
#include <rokko/mapping_bc.h>
#include <rokko/distributed_matrix.h>
#include <rokko/parallel_dense_ev.h>

#include <rokko/collective.h>

#ifdef __cplusplus
}
#endif

#endif /* ROKKO_PARALLEL_DENSE_H */


<|start_filename|>rokko/pyrokko_mapping_bc.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_MAPPING_BC_HPP
#define PYROKKO_MAPPING_BC_HPP

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#include <rokko/mapping_bc.hpp>
#include <rokko/pyrokko_grid.hpp>
#include <rokko/pyrokko_matrix_major_enum.hpp>
#include <rokko/utility/tuple_to_array.hpp>

namespace rokko {

class base_mapping_bc {
public:
  virtual ~base_mapping_bc() = default;
};

template<typename MATRIX_MAJOR>
class wrap_mapping_bc : public mapping_bc<MATRIX_MAJOR>, public base_mapping_bc {
public:
  wrap_mapping_bc(std::tuple<int,int> const& global_size, std::tuple<int,int> const& block_size, wrap_grid const& g)
    : mapping_bc<MATRIX_MAJOR>(to_array(global_size), to_array(block_size), g) {}

  wrap_mapping_bc(int global_dim, int block_size, int lld, wrap_grid const& g)
    : mapping_bc<MATRIX_MAJOR>(global_dim, block_size, lld, g) {}

  wrap_mapping_bc(int global_dim, int block_size, wrap_grid const& g)
    : mapping_bc<MATRIX_MAJOR>(global_dim, block_size, g) {}

  wrap_mapping_bc(mapping_bc<MATRIX_MAJOR> const& map) : mapping_common_sizes(map), mapping_bc<MATRIX_MAJOR>(map) {}

  bool has_global_indices(std::tuple<int,int> const& global) const {
    return mapping_bc<MATRIX_MAJOR>::has_global_indices(to_array(global));
  }

  auto get_mb() const {
    return mapping_bc<MATRIX_MAJOR>::get_mb();
  }

  auto get_nb() const {
    return mapping_bc<MATRIX_MAJOR>::get_nb();
  }

  auto get_m_local() const {
    return mapping_bc<MATRIX_MAJOR>::get_m_local();
  }

  auto get_n_local() const {
    return mapping_bc<MATRIX_MAJOR>::get_n_local();
  }

  std::tuple<int,int> get_block_shape() const {
    return mapping_bc<MATRIX_MAJOR>::get_block_size();
  }
  
  std::tuple<int,int> get_global_shape() const {
    return mapping_bc<MATRIX_MAJOR>::get_global_size();
  }
  
  std::tuple<int,int> get_local_shape() const {
    return mapping_bc<MATRIX_MAJOR>::get_local_size();
  }

  std::tuple<int,int> translate_l2g(std::tuple<int,int> const& local) const {
    return mapping_bc<MATRIX_MAJOR>::translate_l2g(to_array(local));
  }

  std::tuple<int,int> translate_g2l(std::tuple<int,int> const& global) const {
    return mapping_bc<MATRIX_MAJOR>::translate_g2l(to_array(global));
  }

  wrap_grid get_grid() const {
    return wrap_grid(get_grid());
  }

  std::string get_major_string() const {
    return mapping_bc<MATRIX_MAJOR>::is_col_major() ? "col" : "row";
  }
};

std::shared_ptr<base_mapping_bc> create_mapping_bc(std::tuple<int,int> const& global_size, std::tuple<int,int> const& block_size, wrap_grid const& wrap_g, matrix_major_enum const& major = col) {
  if (major == col)
    return std::make_shared<wrap_mapping_bc<matrix_col_major>>(global_size, block_size, wrap_g);
  else
    return std::make_shared<wrap_mapping_bc<matrix_row_major>>(global_size, block_size, wrap_g);
}

std::shared_ptr<base_mapping_bc> create_mapping_bc(int global_size, int block_size, int lld, wrap_grid const& wrap_g, matrix_major_enum const& major = col) {
  if (major == col)
    return std::make_shared<wrap_mapping_bc<matrix_col_major>>(global_size, block_size, lld, wrap_g);
  else
    return std::make_shared<wrap_mapping_bc<matrix_row_major>>(global_size, block_size, lld, wrap_g);
}

std::shared_ptr<base_mapping_bc> create_mapping_bc(int global_size, int block_size, wrap_grid const& wrap_g, matrix_major_enum const& major = col) {
  if (major == col)
    return std::make_shared<wrap_mapping_bc<matrix_col_major>>(global_size, block_size, wrap_g);
  else
    return std::make_shared<wrap_mapping_bc<matrix_row_major>>(global_size, block_size, wrap_g);
}

} // end namespace rokko

#endif // PYROKKO_MAPPING_BC_HPP


<|start_filename|>rokko/utility/machine_info.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2013-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_MACHINE_INFO_HPP
#define ROKKO_UTILITY_MACHINE_INFO_HPP

#include <iostream>
#include <iomanip>
#include <sstream>      // for std::istringstream
#include <ctime>
#include <boost/asio.hpp>

#include <rokko/config.h>
#ifdef _OPENMP
#include <omp.h>
#endif

namespace rokko {

void machine_info(MPI_Comm const& comm = MPI_COMM_WORLD) {
  int nprocs;
  MPI_Comm_size(comm, &nprocs);
  std::time_t now = std::time(0);
  std::cout << "num_procs = " << nprocs << std::endl
            #ifdef _OPENMP
	    << "num_threads per process = " << omp_get_max_threads() << std::endl
            #endif
	    << "hostname = " << boost::asio::ip::host_name() << std::endl
	    << "rokko_version = " << ROKKO_VERSION << std::endl
	    << "date = " << ctime(&now);
}


void machine_info(std::ostringstream& oss, MPI_Comm const& comm = MPI_COMM_WORLD) {
  int nprocs;
  MPI_Comm_size(comm, &nprocs);
  std::time_t now = std::time(0);
  oss << "num_procs = " << nprocs << std::endl
            #ifdef _OPENMP
	    << "num_threads per process = " << omp_get_max_threads() << std::endl
            #endif
	    << "hostname = " << boost::asio::ip::host_name() << std::endl
	    << "rokko_version = " << ROKKO_VERSION << std::endl
	    << "date = " << ctime(&now);
}

} // namespace rokko

#endif // ROKKO_UTILITY_MACHINE_INFO_HPP


<|start_filename|>example/scalapack/pdsyevr.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <mpi.h>
#include <math.h>
#include <stdio.h>
#include <rokko/Cblacs.h>
#include <rokko/cscalapack.h>
#include <rokko/cmatrix.h>

int imin(int x, int y) { return (x < y) ? x : y; }

int main(int argc, char** argv) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  int nprocs, myrank;
  MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
  MPI_Comm_rank(MPI_COMM_WORLD, &myrank);

  int n = 8;
  if (argc > 1) n = atoi(argv[1]);

  int nprow = (int)(sqrt(1. * nprocs + 0.5));
  int npcol = (int)(1. * nprocs / nprow);
  if (myrank == 0) {
    printf("n = %d\n", n);
    printf("nprocs = %d\n", nprocs);
    printf("nprow = %d\n", nprow);
    printf("npcol = %d\n", npcol);
    if ((nprocs != nprow * npcol) || (n % nprow != 0) || (n % npcol != 0)) {
      printf("incompatible matrix size and number of processes");
      MPI_Abort(MPI_COMM_WORLD, 127);
    }
  }
  int context;
  Cblacs_get(0, 0, &context);
  char order = 'R';
  Cblacs_gridinit(&context, &order, nprow, npcol);

  int nb = 1;
  int desc[9];
  int info = cscalapack_descinit(desc, n, n, nb, nb, 0, 0, context, n/nprow);
  if (info) {
    fprintf(stderr, "Error in cscalapack_descinit\n");
    MPI_Abort(MPI_COMM_WORLD, info);
  }
  double **a = alloc_dmatrix(n/nprow, n/npcol);
  double **z = alloc_dmatrix(n/nprow, n/npcol);
  double *w = alloc_dvector(n);
  for (int j = 0; j < n; ++j)
    for (int i = 0; i < n; ++i)
      cscalapack_pdelset(mat_ptr(a), i, j, desc, imin(i, j) + 1);

  double vl, vu;
  int il, iu;
  int m, nz;

  info = cscalapack_pdsyevr('N', 'A', 'U', n,
                            mat_ptr(a), 0, 0, desc,
                            vl, vu, il, iu,
                            &m, &nz,
                            vec_ptr(w),
                            mat_ptr(z), 0, 0, desc);
  if (info) {
    fprintf(stderr, "Error in cscalapack_pdsyevr\n");
    MPI_Abort(MPI_COMM_WORLD, info);
  }
  if (myrank == 0) {
    printf("eigenvalues: ");
    fprint_dvector(stdout, n, vec_ptr(w));
  }

  free_dmatrix(a);
  free_dmatrix(z);
  free_dvector(w);
  Cblacs_gridexit(context);
  MPI_Finalize();
}


<|start_filename|>rokko/elemental/solver.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2014 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_ELEMENTAL_SOLVER_HPP
#define ROKKO_ELEMENTAL_SOLVER_HPP

#include <El.hpp>
#include <rokko/parameters.hpp>
#include <rokko/elemental/diagonalize.hpp>

namespace rokko {
namespace elemental {

class solver {
public:
  template <typename GRID_MAJOR>
  bool is_available_grid_major(GRID_MAJOR const& grid_major) {
    return std::is_same<GRID_MAJOR, grid_col_major_t>::value;
  }
  void initialize(int& argc, char**& argv) { El::Initialize(argc, argv); }
  void finalize() { El::Finalize(); }

  mapping_bc<matrix_col_major> default_mapping(int dim, grid const& g) const {
    return mapping_bc<matrix_col_major>(dim, 1, matrix_col_major_d, g);  // block_size = 1
  }

  template<typename T, typename MATRIX_MAJOR, typename VEC>
  parameters diagonalize(distributed_matrix<T, MATRIX_MAJOR>& mat,
			 VEC& eigvals, distributed_matrix<T, MATRIX_MAJOR>& eigvecs,
			 parameters const& params) {
    const std::string routine = params.defined("routine") ? params.get_string("routine") : "";

    if ((routine == "") || (routine == "pmrrr")) {
      return rokko::elemental::diagonalize(mat, eigvals, eigvecs, params);
    } else {
      throw std::invalid_argument("elemental::diagonalize() : " + routine + " is invalid routine name");
    }
  }
  
  template<typename T, typename MATRIX_MAJOR, typename VEC>
  parameters diagonalize(distributed_matrix<T, MATRIX_MAJOR>& mat,
			 VEC& eigvals,
			 parameters const& params) {
    const std::string routine = params.defined("routine") ? params.get_string("routine") : "";

    if ((routine == "") || (routine == "pmrrr")) {
      return rokko::elemental::diagonalize(mat, eigvals, params);
    } else {
      throw std::invalid_argument("elemental::diagonalize() : " + routine + " is invalid routine name");
    }
  }
};

} // namespace elemental
} // namespace rokko

#endif // ROKKO_ELEMENTAL_SOLVER_HPP


<|start_filename|>example/cxx/sparse/heisenberg_matrix_market.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>

int main(int argc, char *argv[]) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  int L = (argc >= 3) ? std::stoi(argv[2]) : 10;
  int dim = 1 << L;
  std::vector<std::pair<int, int>> lattice;
  for (int i = 0; i < L; ++i) lattice.emplace_back(std::make_pair(i, (i+1) % L));

  rokko::parallel_sparse_ev solver("anasazi");
  rokko::distributed_crs_matrix mat(dim, dim, solver);
  std::vector<double> values;
  std::vector<int> cols;
  for (int row = 0; row < dim; ++row) {
    cols.clear();
    values.clear();
    double diag = 0;
    for (int l = 0;  l < lattice.size(); ++l) {
      int i = lattice[l].first;
      int j = lattice[l].second;
      int m1 = 1 << i;
      int m2 = 1 << j;
      int m3 = m1 + m2;
      if (((row & m3) == m1) || ((row & m3) == m2)) {
        cols.emplace_back(row^m3);
        values.emplace_back(0.5);
        diag += -0.25;
      } else {
        diag += 0.25;
      }
    }
    cols.emplace_back(row);
    values.emplace_back(diag);
    mat.insert(row, cols, values);
  }
  mat.complete();
  //mat.print();
  mat.output_matrix_market();

  solver.finalize();
  MPI_Finalize();
}


<|start_filename|>test/diagonalize/tridiagonal_toeplitz.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2013-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/tridiagonal_toeplitz_matrix.hpp>

#include <gtest/gtest.h>

constexpr double eps = 1e-5;

int global_argc;
char** global_argv;

template<typename MATRIX_MAJOR>
void test(int dim, std::string const& name) {
  constexpr double a = 5., b = 2.;  // To obtain all non-negative eigenvalues, choose a >= b
  rokko::serial_dense_ev solver(name);
  solver.initialize(global_argc, global_argv);
  Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,rokko::eigen3_major<MATRIX_MAJOR>> mat(dim, dim);
  rokko::tridiagonal_toeplitz_matrix::generate(mat, a, b);
  Eigen::VectorXd eigval(dim);
  Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,rokko::eigen3_major<MATRIX_MAJOR>> eigvec(dim, dim);

  solver.diagonalize(mat, eigval, eigvec);

  double th = 0.;
  for (int i=0; i<dim; ++i)
    th += rokko::tridiagonal_toeplitz_matrix::eigenvalue(dim, i, a, b);
  std::cout << "eigval.sum()=" << eigval.sum() << " th=" << th << std::endl;
  EXPECT_NEAR(eigval.sum(), th, eps);

  EXPECT_NEAR(eigval.sum(), dim * a, eps);

  rokko::tridiagonal_toeplitz_matrix::generate(mat, a, b);
  for (int i = 0; i < dim; ++i) {
    double w = eigvec.col(i).transpose() * mat * eigvec.col(i);
    EXPECT_NEAR(w, eigval[i], eps);
  }

  solver.finalize();
}

TEST(diagonalize, tridiagonal_toeplitz) {
  constexpr int dim = 100;
  std::cout << "dimension = " << dim << std::endl;

  std::vector<std::string> names;
  if (global_argc == 1) {
    names = rokko::serial_dense_ev::solvers();
  } else {
    for (int num=1; num < global_argc; ++num) {
      names.emplace_back(global_argv[num]);
    }
  }

  for(auto name : names) {
    std::cout << "solver = " << name << std::endl;
    std::cout << "  test for row major" << std::endl;
    test<rokko::matrix_row_major>(dim, name);
    std::cout << "  test for column major" << std::endl;
    test<rokko::matrix_col_major>(dim, name);
  }
}

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  global_argc = argc;
  global_argv = argv;
  return RUN_ALL_TESTS();
}


<|start_filename|>rokko/original/original.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/parallel_sparse_ev.hpp>
#include <rokko/original/solver.hpp>
#include <rokko/skel/mapping_1d.hpp>

ROKKO_REGISTER_PARALLEL_SPARSE_SOLVER(rokko::original::solver, "original", 1)

ROKKO_REGISTER_PARALLEL_SPARSE_MAPPING_1D(rokko::skel::mapping_1d, "original", 1)



<|start_filename|>rokko/mapping_1d_common.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_MAPPING_1D_COMMON_HPP
#define ROKKO_MAPPING_1D_COMMON_HPP

namespace rokko {

namespace detail {

class mapping_1d_common {
public:
  mapping_1d_common() = default;
  virtual ~mapping_1d_common() = default;

  virtual int get_dim() const = 0;
  virtual int get_num_local_rows() const = 0;
};

} // end namespace detail

} // end namespace rokko

#endif // ROKKO_MAPPING_1D_COMMON_HPP


<|start_filename|>rokko/utility/lattice.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2013-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_LATTICE_HPP
#define ROKKO_UTILITY_LATTICE_HPP

#include <regex>
#include <string>
#include <sstream>      // for std::istringstream
#include <list>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <tuple>
#include <rokko/utility/string_trim.hpp>

namespace rokko {

namespace detail {

std::string retrieve_before_comment(std::string const& str) {
  std::regex separator{"#"};
  auto it = std::sregex_token_iterator{str.cbegin(), str.cend(), separator, -1};
  const auto end_it = std::sregex_token_iterator{};
  if (it != end_it)
    return *it;
  else
    return str;
}

bool read_line_with_comment(std::ifstream& ifs, std::istringstream& is) {
  std::string str_line;
  std::getline(ifs, str_line);
  std::string trimed_str = trim_copy(retrieve_before_comment(str_line));
  is.clear();
  is.str(trimed_str);
  //std::cout << "no_comment:" << trimed_str << std::endl;
  //std::cout << "str_line:" << str_line << std::endl;
  return !trimed_str.empty(); // empty means the sentence is just comment
}

std::vector<std::string> split_by_symbol(std::string const& str_line) {
  const std::regex separator{"="};
  std::vector<std::string> vec;
  for (std::sregex_token_iterator it{str_line.cbegin(), str_line.cend(), separator, -1}, end; it != end; ++it) {
    vec.emplace_back(trim_copy(*it));
  }

  return vec;
}

bool detect_offset_info(std::string const& str_line, bool& offset1) {
  auto tokens = split_by_symbol(str_line);
  if (tokens.size() < 2) {
    return false;
  }

  if (tokens[0]=="offset") {
    if (tokens[1]=="1") {
      offset1 = true;
      std::cout << "offset = 1" << std::endl;
    } else if (tokens[1]=="0") {
      offset1 = false;
      std::cout << "offset = 0" << std::endl;
    } else
      throw std::invalid_argument("detail::detect_offset_info() : give 0 or 1 after 'offset='");
    return true;
  } else {
    return false;
  }
}

bool read_offset_info(std::ifstream& ifs) {
  bool offset1 = false;
  std::string str_line;
  while(true) {
    std::ifstream::pos_type file_pos = ifs.tellg();  // save file position
    std::getline(ifs, str_line);
    if (detect_offset_info(str_line, offset1)) {
      break;
    } else if (!str_line.empty()) {  // if str_line is first sentence
      ifs.seekg(file_pos);  // resotre file position
      break;
    }
  }
  return offset1;
}

} // namespace detail

void read_lattice_stream(std::ifstream& ifs, int& num_sites, std::vector<std::pair<int, int>>& lattice) {
  std::size_t num_bonds;
  std::istringstream is;
  if (detail::read_line_with_comment(ifs, is)) {
    is >> num_sites >> num_bonds;
  }
  std::cout << "num_sites=" << num_sites << " num_bonds=" << num_bonds << std::endl;

  bool offset1 = detail::read_offset_info(ifs);

  do {
    int j, k;
    if (detail::read_line_with_comment(ifs, is)) {
      is >> j >> k;
      std::cout << "j=" << j << " k=" << k << std::endl;
      if (offset1)  lattice.emplace_back(std::make_pair(j-1, k-1));
      else  lattice.emplace_back(std::make_pair(j, k));
      //std::cout << "back()=" << lattice.back().first << ", " << lattice.back().second << std::endl;
      if ((lattice.back().first < 0) || (lattice.back().first >= num_sites)) {
        throw std::invalid_argument("read_lattice_stream() : first index of " + std::to_string(lattice.size() - 1) + "-th bond \"" + std::to_string(lattice.back().first) + "\" is out of range");
      } else if ((lattice.back().second < 0) || (lattice.back().second >= num_sites)) {
        throw std::invalid_argument("read_lattice_stream() : second index of " + std::to_string(lattice.size() - 1) + "-th bond \"" + std::to_string(lattice.back().second) + "\" is out of range");
      }
    }
  } while (lattice.size() < num_bonds);
}

void read_lattice_file(std::string const& filename, int& num_sites, std::vector<std::pair<int, int>>& lattice) {
  std::ifstream ifs(filename);
  if (!ifs) {
    throw std::runtime_error("read_lattice_file() : can't open file \"" + filename + "\"");
  }
  return read_lattice_stream(ifs, num_sites, lattice);
}

void create_ladder_lattice_1dim(int len_ladder, std::vector<std::pair<int, int>>& lattice) {
  int L = 2 * len_ladder;
  for (std::size_t i = 0; i < (len_ladder-1); ++i) {
    lattice.emplace_back(std::make_pair(i, i+1));
  }
  for (std::size_t i = len_ladder; i < (L-1); ++i) {
    lattice.emplace_back(std::make_pair(i, i+1));
  }
  for (std::size_t i = 0; i < len_ladder; ++i) {
    lattice.emplace_back(std::make_pair(i, i+len_ladder));
  }
}

void output_lattice(std::ostream& os, std::vector<std::pair<int, int>> const& lattice) {
  for (std::size_t i=0; i<lattice.size(); ++i) {
    os << "no=" << i << " <" << lattice[i].first << ", " << lattice[i].second << ">" << std::endl;
  }
}

void print_lattice(std::vector<std::pair<int, int>> const& lattice) {
  output_lattice(std::cout, lattice);
}

} // namespace rokko

#endif // ROKKO_UTILITY_LATTICE_HPP


<|start_filename|>rokko/utility/helmert_matrix.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_HELMERT_MATRIX_H
#define ROKKO_UTILITY_HELMERT_MATRIX_H

#include <rokko/dense.h>

#ifdef __cplusplus
extern "C"{
#endif

void rokko_helmert_matrix_generate_eigen_matrix(struct rokko_eigen_matrix matrix);
void rokko_helmert_matrix_generate_for_given_eigenvalues_eigen_matrix(struct rokko_eigen_matrix matrix, struct rokko_eigen_vector diag);

#if defined(ROKKO_HAVE_PARALLEL_DENSE_SOLVER)
void rokko_helmert_matrix_generate_distributed_matrix(struct rokko_distributed_matrix matrix);
void rokko_helmert_matrix_generate_for_given_eigenvalues_distributed_matrix(struct rokko_distributed_matrix matrix, struct rokko_eigen_vector diag);
#endif /* defined(ROKKO_HAVE_PARALLEL_DENSE_SOLVER) */

#ifdef __cplusplus
}
#endif

#endif /* ROKKO_UTILITY_HELMERT_MATRIX_H */


<|start_filename|>example/eigenexa/eigen_sx_f.f90<|end_filename|>
program main
  use eigen_libs_mod
  use mpi
  implicit none
  integer, parameter :: n = 8
  integer :: provided, ierr, myrank, nprocs, nprow, npcol
  integer :: inod, x_inod, y_inod
  integer :: nm, ny, i, j
  integer :: il, jl, iloop_sta, iloop_end, jloop_sta, jloop_end
  double precision, allocatable :: a(:,:), z(:,:), w(:)

  call MPI_init_thread(MPI_THREAD_MULTIPLE, provided, ierr)
  call MPI_comm_rank(MPI_COMM_WORLD, myrank, ierr)
  call eigen_init(MPI_COMM_WORLD)
  call eigen_get_procs(nprocs, npcol, nprow)
  if (myrank == 0) then
     print *, "n =", n
     print *, "nprocs =", nprocs
     print *, "nprow =", nprow
     print *, "npcol =", npcol
  end if
  call eigen_get_id(inod, x_inod, y_inod)

  call eigen_get_matdims(n, nm, ny)
  allocate(a(nm, ny), z(nm, ny), w(n))

  jloop_sta = eigen_loop_start(1, nprow, y_inod)
  jloop_end = eigen_loop_end(n, nprow, y_inod)
  iloop_sta = eigen_loop_start(1, npcol, x_inod)
  iloop_end = eigen_loop_end(n, npcol, x_inod)
  if (jloop_sta <= jloop_end) then
     do jl = jloop_sta, jloop_end
        j = eigen_translate_l2g(jl, nprow, y_inod)
        do il = iloop_sta, iloop_end
           i = eigen_translate_l2g(il, npcol, x_inod)
           a(il, jl) = dble(min(i, j))
        end do
     end do
  end if

  call eigen_sx(n, n, a, nm, w, z, nm, 48, 128, 'A')
  if (myrank == 0) then
     print *, "eigenvalues:", w(:)
  end if

  deallocate(a, z, w)
  call eigen_free()
  call MPI_Finalize(ierr)
end program main


<|start_filename|>rokko/scalapack/plange.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_PLANGE_HPP
#define ROKKO_SCALAPACK_PLANGE_HPP

#include <rokko/cscalapack.h>

namespace rokko {
namespace scalapack {

namespace {

inline double plange_dispatch(char norm, int m, int n, const double* A, const int* descA) {
  return cscalapack_pdlange(norm, m, n, A, descA);
}

inline float plange_dispatch(char norm, int m, int n, const float* A, const int* descA) {
  return cscalapack_pslange(norm, m, n, A, descA);
}
  
}

template<typename MATRIX>
typename MATRIX::value_type plange(char norm, const MATRIX& A) {
  return plange_dispatch(norm, A.get_m_global(), A.get_n_global(), A.get_array_pointer(),
                         A.get_mapping().get_blacs_descriptor().data());
}

template<typename MATRIX, typename VECTOR>
typename MATRIX::value_type plange(char norm, const MATRIX& A, VECTOR& work) {
  return plange_dispatch(norm, A.get_m_global(), A.get_n_global(), A.get_array_pointer(),
                         A.get_mapping().get_blacs_descriptor().data(), work);
}

} // end namespace scalapack
} // end namespace rokko

#endif // ROKKO_SCALAPACK_PLANGE_HPP


<|start_filename|>example/c/utility/default_solvers.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.h>
#include <stdio.h>

int main(/* int argc , char** argv */) {
  printf("%s\n", rokko_serial_dense_ev_default_solver());

#ifdef ROKKO_HAVE_PARALLEL_DENSE_SOLVER
  printf("%s\n", rokko_parallel_dense_ev_default_solver());
#endif

#ifdef ROKKO_HAVE_PARALLEL_SPARSE_SOLVER
  printf("%s\n", rokko_parallel_sparse_ev_default_solver());
#endif

  return 0;
}


<|start_filename|>rokko/lapack/hegv.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_HEGV_HPP
#define ROKKO_LAPACK_HEGV_HPP

#include <complex>
#include <lapacke.h>
#undef I
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>
#include "complex_cast.hpp"
#include <rokko/lapack/storage.hpp>
#include <rokko/alias_template_function.hpp>

namespace rokko {
namespace lapack {

namespace {

template<typename T> struct hegv_dispatch;

template<>
struct hegv_dispatch<float> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int hegv(int matrix_layout, lapack_int itype, char jobz, char uplo, lapack_int n,
                         MATRIX& a, MATRIX& b, VECTOR& w) {
    return LAPACKE_ssygv(matrix_layout, itype, jobz, uplo, n, storage(a), ld(a), storage(b), ld(b), storage(w));
  }
};

template<>
struct hegv_dispatch<double> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int hegv(int matrix_layout, lapack_int itype, char jobz, char uplo, lapack_int n,
                         MATRIX& a, MATRIX& b, VECTOR& w) {
    return LAPACKE_dsygv(matrix_layout, itype, jobz, uplo, n, storage(a), ld(a), storage(b), ld(b), storage(w));
  }
};

template<>
struct hegv_dispatch<std::complex<float>> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int hegv(int matrix_layout, lapack_int itype, char jobz, char uplo, lapack_int n,
                         MATRIX& a, MATRIX& b, VECTOR& w) {
    return LAPACKE_chegv(matrix_layout, itype, jobz, uplo, n, storage(a), ld(a), storage(b), ld(b), storage(w));
  }
};

template<>
struct hegv_dispatch<std::complex<double>> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int hegv(int matrix_layout, lapack_int itype, char jobz, char uplo, lapack_int n,
                         MATRIX& a, MATRIX& b, VECTOR& w) {
    return LAPACKE_zhegv(matrix_layout, itype, jobz, uplo, n, storage(a), ld(a), storage(b), ld(b), storage(w));
  }
};

} // end of anonymous namespace

template<typename MATRIX, typename VECTOR>
lapack_int hegv(lapack_int itype, char jobz, char uplo, MATRIX& a, MATRIX& b, VECTOR& w) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR>>::value, "");
  lapack_int n = rows(a);
  if (rows(a) != cols(a))
    throw std::invalid_argument("matrix A size mismatch");
  //if (size(w) != n)
  //  throw std::invalid_argument("vector w size mismatch");
  return hegv_dispatch<value_t<MATRIX>>::
    hegv((is_col_major(a) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR), itype, jobz, uplo, n, a, b, w);
}

ALIAS_TEMPLATE_FUNCTION(sygv, hegv);

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_HEGV_HPP


<|start_filename|>test/utility/sort_eigenpairs.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/utility/sort_eigenpairs.hpp>

#include <numeric>
#include <random>

#include <gtest/gtest.h>

template <int MAJOR>
void test(bool ascending) {
  constexpr int num = 10;
  std::vector<int> index(num);
  std::iota(index.begin(), index.end(), 0);
  std::random_device seed_gen;
  std::mt19937 engine(seed_gen());
  std::shuffle(index.begin(), index.end(), engine);
  Eigen::VectorXd eigvals(num), eigvals_sorted(num);
  Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,MAJOR> eigvecs(num, num), eigvecs_sorted(num, num);
  for(int i=0; i<num; ++i) {
    eigvals(i) = 1.0*index[i];
    if (MAJOR == Eigen::RowMajor) {
      eigvecs.row(i).setConstant(eigvals(i));
    } else {
      eigvecs.col(i).setConstant(eigvals(i));
    }
  }
  rokko::sort_eigenpairs(eigvals, eigvecs, eigvals_sorted, eigvecs_sorted, ascending);
  for(int i=0; i<num; ++i){
    std::cout << "i=" << i << std::endl;
    const double e = ascending ? 1.0 * i : 1.0*(num-i-1);
    if (MAJOR == Eigen::RowMajor) {
      ASSERT_EQ( eigvals_sorted(i), e);
      ASSERT_EQ( eigvecs_sorted(i,0), e);
      ASSERT_EQ( eigvecs_sorted(i,1), e);
    } else {
      ASSERT_EQ( eigvals_sorted(i), e);
      ASSERT_EQ( eigvecs_sorted(0,i), e);
      ASSERT_EQ( eigvecs_sorted(1,i), e);
    }
  }
}

TEST(sort_eigenpairs, matrix_majors) {
  {
    std::cout << "row_major, ascending order\n";
    test<Eigen::RowMajor>(true);
  }
  {
    std::cout << "row_major, descending order\n";
    test<Eigen::RowMajor>(false);
  }
  {
    std::cout << "col_major, ascending order\n";
    test<Eigen::ColMajor>(true);
  }
  {
    std::cout << "col_major, descending order\n";
    test<Eigen::ColMajor>(false);
  }
}

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}


<|start_filename|>config/components.cmake<|end_filename|>
macro(components_init)
  # components
  set(BUILD_BASE_C ON)
  set(BUILD_CBLAS ON)
  set(BUILD_LAPACKE ON)
  option(BUILD_SCALAPACK_C "Build scalapack_c component" ON)
  option(BUILD_EIGENEXA_C "Build eigenexa_c component" ON)
  option(BUILD_BASE_CXX "Build base_cxx component" ON)
  option(BUILD_LAPACK_CXX "Build lapack_cxx component" ON)
  option(BUILD_SCALAPACK_CXX "Build scalapack_cxx component" ON)
  option(BUILD_EIGENEXA_CXX "Build eigenexa_cxx component" ON)
  option(BUILD_ELPA_CXX "Build elpa_cxx component" ON)
  option(BUILD_SERIAL_DENSE_SOLVER "Build serial_dense_solver component" ON)
  option(BUILD_SERIAL_SPARSE_SOLVER "Build serial_sparse_solver component" ON)
  option(BUILD_PARALLEL_DENSE_SOLVER "Build parallel_dense_solver component" ON)
  option(BUILD_PARALLEL_SPARSE_SOLVER "Build parallel_sparse_solver component" ON)
  option(BUILD_C_BINDING "Build C bindings" ON)
  option(BUILD_Fortran_BINDING "Build Fortran binding" ON)
  option(BUILD_Python_BINDING "Build Python binding" OFF)
  option(BUILD_TESTS "Build test suites" ON)
  option(BUILD_EXAMPLES "Build examples" ON)
  option(BUILD_TUTORIALS "Build tutorials" ON)
  option(BUILD_BENCHMARKS "Build benchmark tests" OFF)
  option(BUILD_DEVELOPERS "Build codes for Rokko's developers" OFF)

  # libraries and solvers
  option(DISABLE_MPI "Disable MPI Parallelization" OFF)
  option(DISABLE_SCALAPACK "Disable ScaLAPACK Library" OFF)
  option(ENABLE_PDSYEVR "Enable pdsyevr in ScaLAPACK" OFF)
  option(DISABLE_EIGENEXA "Disable EigenExa Library" OFF)
  option(DISABLE_ELEMENTAL "Disable Elemental Library" OFF)
  option(DISABLE_ELPA "Disable ELPA Library" OFF)
  option(DISABLE_PETSC "Disable PETSc Library" OFF)
  option(DISABLE_SLEPC "Disable SLEPc Library" OFF)
  option(DISABLE_ANASAZI "Disable Anasazi Library" OFF)

  # libraries and solvers
  if(DISABLE_MPI)
    set(ROKKO_HAVE_MPI FALSE)
  else(DISABLE_MPI)
    set(ROKKO_HAVE_MPI TRUE)
  endif(DISABLE_MPI)
  if(DISABLE_SCALAPACK)
    set(ROKKO_HAVE_SCALAPACK FALSE)
  else(DISABLE_SCALAPACK)
    set(ROKKO_HAVE_SCALAPACK TRUE)
  endif(DISABLE_SCALAPACK)
  if(ENABLE_SCALAPACK_PDSYEVR)
    set(ROKKO_HAVE_SCALAPACK_PDSYEVR TRUE)
  else(ENABLE_SCALAPACK_PDSYEVR)
    set(ROKKO_HAVE_SCALAPACK_PDSYEVR FALSE)
  endif(ENABLE_SCALAPACK_PDSYEVR)
  if(DISABLE_EIGENEXA)
    set(ROKKO_HAVE_EIGENEXA FALSE)
  else(DISABLE_EIGENEXA)
    set(ROKKO_HAVE_EIGENEXA TRUE)
  endif(DISABLE_EIGENEXA)
  if(DISABLE_ELPA)
    set(ROKKO_HAVE_ELPA FALSE)
  else(DISABLE_ELPA)
    set(ROKKO_HAVE_ELPA TRUE)
  endif(DISABLE_ELPA)
  if(DISABLE_ELEMENTAL)
    set(ROKKO_HAVE_ELEMENTAL FALSE)
  else(DISABLE_ELEMENTAL)
    set(ROKKO_HAVE_ELEMENTAL TRUE)
  endif(DISABLE_ELEMENTAL)
  if(DISABLE_PETSC)
    set(ROKKO_HAVE_PETSC FALSE)
  else(DISABLE_PETSC)
    set(ROKKO_HAVE_PETSC TRUE)
  endif(DISABLE_PETSC)
  if(DISABLE_SLEPC)
    set(ROKKO_HAVE_SLEPC FALSE)
  else(DISABLE_SLEPC)
    set(ROKKO_HAVE_SLEPC TRUE)
  endif(DISABLE_SLEPC)
  if(DISABLE_ANASAZI)
    set(ROKKO_HAVE_ANASAZI FALSE)
  else(DISABLE_ANASAZI)
    set(ROKKO_HAVE_ANASAZI TRUE)
  endif(DISABLE_ANASAZI)

  # components
  set(ROKKO_HAVE_SCALAPACK_C ${BUILD_SCALAPACK_C})
  set(ROKKO_HAVE_EIGENEXA_C ${BUILD_HAVE_EIGENEXA_C})
  set(ROKKO_HAVE_BASE_CXX ${BUILD_BASE_CXX})
  set(ROKKO_HAVE_LAPACK_CXX ${BUILD_LAPACK_CXX})
  set(ROKKO_HAVE_SCALAPACK_CXX ${BUILD_SCALAPACK_CXX})
  set(ROKKO_HAVE_EIGENEXA_CXX ${BUILD_EIGENEXA_CXX})
  set(ROKKO_HAVE_ELPA_CXX ${BUILD_ELPA_CXX})
  set(ROKKO_HAVE_SERIAL_DENSE_SOLVER ${BUILD_SERIAL_DENSE_SOLVER})
  set(ROKKO_HAVE_SERIAL_SPARSE_SOLVER ${BUILD_SERIAL_SPARSE_SOLVER})
  set(ROKKO_HAVE_PARALLEL_DENSE_SOLVER ${BUILD_PARALLEL_DENSE_SOLVER})
  set(ROKKO_HAVE_PARALLEL_SPARSE_SOLVER ${BUILD_PARALLEL_SPARSE_SOLVER})
  set(ROKKO_HAVE_C_BINDING ${BUILD_C_BINDING})
  set(ROKKO_HAVE_FORTRAN_BINDING ${BUILD_Fortran_BINDING})
  set(ROKKO_HAVE_PYTHON_BINDING ${BUILD_Python_BINDING})
endmacro(components_init)

macro(components_check)
  if(NOT ROKKO_HAVE_BOOST)
    set(BUILD_BASE_CXX OFF)
    set(BUILD_LAPACK_CXX OFF)
    set(BUILD_SCALAPACK_CXX OFF)
    set(BUILD_EIGENEXA_CXX OFF)
    set(BUILD_ELPA_CXX OFF)
    set(BUILD_SERIAL_DENSE_SOLVER OFF)
    set(BUILD_SERIAL_SPARSE_SOLVER OFF)
    set(BUILD_PARALLEL_DENSE_SOLVER OFF)
    set(BUILD_PARALLEL_SPARSE_SOLVER OFF)
    set(BUILD_C_BINDING OFF)
    set(BUILD_Fortran_BINDING OFF)
    set(BUILD_Python_BINDING OFF)
  endif(NOT ROKKO_HAVE_BOOST)

  if(NOT ROKKO_HAVE_MPI)
    set(BUILD_SCALAPACK_C OFF)
    set(BUILD_EIGENEXA_C OFF)
    set(BUILD_SCALAPACK_CXX OFF)
    set(BUILD_EIGENEXA_CXX OFF)
    set(BUILD_ELPA_CXX OFF)
    set(BUILD_PARALLEL_DENSE_SOLVER OFF)
    set(BUILD_PARALLEL_SPARSE_SOLVER OFF)
  endif(NOT ROKKO_HAVE_MPI)

  if(NOT ROKKO_HAVE_SCALAPACK)
    set(ROKKO_HAVE_SCALAPACK_PDSYEVR FALSE)
    set(BUILD_SCALAPACK_C OFF)
    set(BUILD_EIGENEXA_C OFF)
    set(BUILD_SCALAPACK_CXX OFF)
    set(BUILD_EIGENEXA_CXX OFF)
    set(BUILD_ELPA_CXX OFF)
    set(BUILD_PARALLEL_DENSE_SOLVER OFF)
    set(BUILD_PARALLEL_SPARSE_SOLVER OFF)
  endif(NOT ROKKO_HAVE_SCALAPACK)

  if(NOT ROKKO_HAVE_EIGENEXA)
    set(BUILD_EIGENEXA_C OFF)
    set(BUILD_EIGENEXA_CXX OFF)
  endif(NOT ROKKO_HAVE_EIGENEXA)

  if(NOT ROKKO_HAVE_ELPA)
    set(BUILD_ELPA_CXX OFF)
  endif(NOT ROKKO_HAVE_ELPA)

  if(NOT ROKKO_HAVE_SLEPC AND NOT ROKKO_HAVE_ANASAZI)
    set(BUILD_PARALLEL_SPARSE_SOLVER OFF)
  endif(NOT ROKKO_HAVE_SLEPC AND NOT ROKKO_HAVE_ANASAZI)

  if(NOT BUILD_SCALAPACK_C)
    set(BUILD_EIGENEXA_C OFF)
    set(BUILD_SCALAPACK_CXX OFF)
    set(BUILD_EIGENEXA_CXX OFF)
    set(BUILD_ELPA_CXX OFF)
    set(BUILD_PARALLEL_DENSE_SOLVER OFF)
    set(BUILD_PARALLEL_SPARSE_SOLVER OFF)
  endif(NOT BUILD_SCALAPACK_C)

  if(NOT BUILD_BASE_CXX)
    set(BUILD_LAPACK_CXX OFF)
    set(BUILD_SCALAPACK_CXX OFF)
    set(BUILD_EIGENEXA_CXX OFF)
    set(BUILD_ELPA_CXX OFF)
    set(BUILD_SERIAL_DENSE_SOLVER OFF)
    set(BUILD_SERIAL_SPARSE_SOLVER OFF)
    set(BUILD_PARALLEL_DENSE_SOLVER OFF)
    set(BUILD_PARALLEL_SPARSE_SOLVER OFF)
    set(BUILD_C_BINDING OFF)
    set(BUILD_Fortran_BINDING OFF)
    set(BUILD_Python_BINDING OFF)
  endif(NOT BUILD_BASE_CXX)

  if(NOT BUILD_SCALAPACK_CXX)
    set(BUILD_EIGENEXA_CXX OFF)
    set(BUILD_ELPA_CXX OFF)
    set(BUILD_PARALLEL_DENSE_SOLVER OFF)
    set(BUILD_PARALLEL_SPARSE_SOLVER OFF)
  endif(NOT BUILD_SCALAPACK_CXX)

  if(NOT BUILD_SERIAL_DENSE_SOLVER)
    set(BUILD_SERIAL_SPARSE_SOLVER OFF)
    set(BUILD_PARALLEL_DENSE_SOLVER OFF)
    set(BUILD_PARALLEL_SPARSE_SOLVER OFF)
    set(BUILD_C_BINDING OFF)
    set(BUILD_Fortran_BINDING OFF)
    set(BUILD_Python_BINDING OFF)
  endif(NOT BUILD_SERIAL_DENSE_SOLVER)

  if(NOT BUILD_SERIAL_SPARSE_SOLVER)
    set(BUILD_SERIAL_SPARSE_SOLVER OFF)
    set(BUILD_PARALLEL_SPARSE_SOLVER OFF)
  endif(NOT BUILD_SERIAL_SPARSE_SOLVER)

  if(NOT BUILD_PARALLEL_DENSE_SOLVER)
    set(BUILD_PARALLEL_SPARSE_SOLVER OFF)
  endif(NOT BUILD_PARALLEL_DENSE_SOLVER)

  if(NOT BUILD_C_BINDING)
    set(BUILD_Fortran_BINDING OFF)
  endif(NOT BUILD_C_BINDING)

  set(ROKKO_HAVE_SCALAPACK_C ${BUILD_SCALAPACK_C})
  set(ROKKO_HAVE_EIGENEXA_C ${BUILD_HAVE_EIGENEXA_C})
  set(ROKKO_HAVE_BASE_CXX ${BUILD_BASE_CXX})
  set(ROKKO_HAVE_LAPACK_CXX ${BUILD_LAPACK_CXX})
  set(ROKKO_HAVE_SCALAPACK_CXX ${BUILD_SCALAPACK_CXX})
  set(ROKKO_HAVE_EIGENEXA_CXX ${BUILD_EIGENEXA_CXX})
  set(ROKKO_HAVE_ELPA_CXX ${BUILD_ELPA_CXX})
  set(ROKKO_HAVE_SERIAL_DENSE_SOLVER ${BUILD_SERIAL_DENSE_SOLVER})
  set(ROKKO_HAVE_SERIAL_SPARSE_SOLVER ${BUILD_SERIAL_SPARSE_SOLVER})
  set(ROKKO_HAVE_PARALLEL_DENSE_SOLVER ${BUILD_PARALLEL_DENSE_SOLVER})
  set(ROKKO_HAVE_PARALLEL_SPARSE_SOLVER ${BUILD_PARALLEL_SPARSE_SOLVER})
  set(ROKKO_HAVE_C_BINDING ${BUILD_C_BINDING})
  set(ROKKO_HAVE_FORTRAN_BINDING ${BUILD_Fortran_BINDING})
  set(ROKKO_HAVE_PYTHON_BINDING ${BUILD_Python_BINDING})
endmacro(components_check)

macro(components_summary)
  message(STATUS "Solvers:")
  message(STATUS "  scalapack: " ${ROKKO_HAVE_SCALAPACK})
  message(STATUS "  eigenexa: " ${ROKKO_HAVE_EIGENEXA})
  message(STATUS "  elpa: " ${ROKKO_HAVE_ELPA})
  message(STATUS "  elemental: " ${ROKKO_HAVE_ELEMENTAL})
  message(STATUS "  slepc: " ${ROKKO_HAVE_SLEPC})
  message(STATUS "  anasazi: " ${ROKKO_HAVE_ANASAZI})

  message(STATUS "Components:")
  message(STATUS "  base_c: ON")
  message(STATUS "  cblas: ON")
  message(STATUS "  lapacke: ON")
  message(STATUS "  scalapack_c: " ${BUILD_SCALAPACK_C})
  message(STATUS "  eigenexa_c: " ${BUILD_EIGENEXA_C})
  message(STATUS "  base_cxx: " ${BUILD_BASE_CXX})
  message(STATUS "  lapack_cxx: " ${BUILD_LAPACK_CXX})
  message(STATUS "  scalapack_cxx: " ${BUILD_SCALAPACK_CXX})
  message(STATUS "  eigenexa_cxx: " ${BUILD_EIGENEXA_CXX})
  message(STATUS "  elpa_cxx: " ${BUILD_ELPA_CXX})
  message(STATUS "  serial_dense_solver: " ${BUILD_SERIAL_DENSE_SOLVER})
  message(STATUS "  serial_sparse_solver: " ${BUILD_SERIAL_SPARSE_SOLVER})
  message(STATUS "  parallel_dense_solver: " ${BUILD_PARALLEL_DENSE_SOLVER})
  message(STATUS "  parallel_sparse_solver: " ${BUILD_PARALLEL_SPARSE_SOLVER})
  message(STATUS "  c_binding: " ${BUILD_C_BINDING})
  message(STATUS "  fortran_binding: " ${BUILD_Fortran_BINDING})
  message(STATUS "  python_binding: " ${BUILD_Python_BINDING})
endmacro(components_summary)


<|start_filename|>rokko/utility/macro_join.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_JOIN_HPP
#define ROKKO_JOIN_HPP

// based on idea of BOOST_JOIN
#define ROKKO_JOIN(X, Y) ROKKO_DO_JOIN(X, Y)
#define ROKKO_DO_JOIN(X, Y) ROKKO_DO_JOIN2(X,Y)
#define ROKKO_DO_JOIN2(X, Y) X##Y

#endif // ROKKO_JOIN_HPP


<|start_filename|>test/pblas/pgemm.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <gtest/gtest.h>
#include <random>
#include <rokko/eigen3.hpp>
#include <rokko/distributed_matrix.hpp>
#include <rokko/blas.hpp>
#include <rokko/lapack.hpp>
#include <rokko/pblas.hpp>
#include <rokko/scalapack.hpp>
#include <rokko/collective.hpp>

constexpr double eps = 1e-12;

TEST(pgemm, pdgemm) {
  constexpr int root_proc = 0;

  rokko::grid grid(MPI_COMM_WORLD);
  std::mt19937 engine(123lu);
  std::uniform_real_distribution<> dist(-1.0, 1.0);

  int n = 64;
  double alpha = 3.3;
  double beta = 2.1;

  Eigen::MatrixXd a(n, n);
  Eigen::MatrixXd b(n, n);
  Eigen::MatrixXd c(n, n);
  if (grid.get_myrank() == root_proc) {
    for (int j = 0; j < n; ++j) {
      for (int i = 0; i < n; ++i) {
        a(i, j) = dist(engine);
        b(i, j) = dist(engine);
        c(i, j) = dist(engine);
      }
    }
  }
  
  rokko::mapping_bc<rokko::matrix_col_major> map(n, 1);
  rokko::distributed_matrix<double> da(map);
  rokko::distributed_matrix<double> db(map);
  rokko::distributed_matrix<double> dc(map);
  rokko::scatter(a, da, root_proc);
  rokko::scatter(b, db, root_proc);
  rokko::scatter(c, dc, root_proc);
  
  rokko::blas::gemm(CblasNoTrans, CblasNoTrans, alpha, a, b, beta, c);
  rokko::pblas::pgemm('N', 'N', alpha, da, db, beta, dc);
  
  double r = rokko::lapack::lange('F', c);
  double dr = rokko::scalapack::plange('F', dc);
  
  if (grid.get_myrank() == root_proc) {
    EXPECT_NEAR(r, dr, eps);
  }
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  MPI_Init(&argc, &argv);
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>rokko/parallel_dense_ev_c.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2016 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/parallel_dense_ev.h>
#include <rokko/parallel_dense_ev.hpp>
#include <rokko/copy_string.hpp>

void rokko_parallel_dense_ev_construct(struct rokko_parallel_dense_ev* solver, const char* solver_name, int argc, char** argv) {
  solver->ptr = new rokko::parallel_dense_ev(std::string(solver_name));
  static_cast<rokko::parallel_dense_ev*>(solver->ptr)->initialize(argc, argv);
}

void rokko_parallel_dense_ev_construct_f(struct rokko_parallel_dense_ev* solver, const char* solver_name) {
  int argc = 0;
  char** argv = 0;
  rokko_parallel_dense_ev_construct(solver, solver_name, argc, argv);
}

void rokko_parallel_dense_ev_destruct(struct rokko_parallel_dense_ev* solver) {
  rokko::parallel_dense_ev* ptr = static_cast<rokko::parallel_dense_ev*>(solver->ptr);
  ptr->finalize();
  delete ptr;
  solver->ptr = nullptr;
}

struct rokko_parameters rokko_parallel_dense_ev_diagonalize(struct rokko_parallel_dense_ev solver,
  struct rokko_distributed_matrix mat, struct rokko_eigen_vector eigvals,
  struct rokko_distributed_matrix eigvecs, struct rokko_parameters params) {
  struct rokko_parameters params_out;
  rokko_parameters_construct(&params_out);

  if (mat.major == rokko_matrix_col_major)
    *static_cast<rokko::parameters*>(params_out.ptr) = static_cast<rokko::parallel_dense_ev*>(solver.ptr)->diagonalize(
      *static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(mat.ptr),
      *static_cast<Eigen::VectorXd*>(eigvals.ptr),
      *static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(eigvecs.ptr),
      *static_cast<rokko::parameters*>(params.ptr));
  else
    *static_cast<rokko::parameters*>(params_out.ptr) = static_cast<rokko::parallel_dense_ev*>(solver.ptr)->diagonalize(
      *static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(mat.ptr),
      *static_cast<Eigen::VectorXd*>(eigvals.ptr),
      *static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(eigvecs.ptr),
      *static_cast<rokko::parameters*>(params.ptr));
  return params_out;
}

struct rokko_parameters rokko_parallel_dense_ev_diagonalize_distributed_matrix(struct rokko_parallel_dense_ev solver,
  struct rokko_distributed_matrix mat, struct rokko_eigen_vector eigvals,
  struct rokko_distributed_matrix eigvecs) {
  struct rokko_parameters params_out;
  rokko_parameters_construct(&params_out);

  if (mat.major == rokko_matrix_col_major)
    *static_cast<rokko::parameters*>(params_out.ptr) = static_cast<rokko::parallel_dense_ev*>(solver.ptr)->diagonalize(
      *static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(mat.ptr),
      *static_cast<Eigen::VectorXd*>(eigvals.ptr),
      *static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(eigvecs.ptr));
  else
    *static_cast<rokko::parameters*>(params_out.ptr) = static_cast<rokko::parallel_dense_ev*>(solver.ptr)->diagonalize(
      *static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(mat.ptr),
      *static_cast<Eigen::VectorXd*>(eigvals.ptr),
      *static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(eigvecs.ptr));
  return params_out;
}

// For Fortran binding
// eigenvalues/eigenvectors, parameters
void rokko_parallel_dense_ev_diagonalize_f(struct rokko_parallel_dense_ev* solver,
					   struct rokko_distributed_matrix* mat, struct rokko_eigen_vector* eigvals,
					   struct rokko_distributed_matrix* eigvecs,
					   struct rokko_parameters* params, struct rokko_parameters* params_out) {
  rokko_parameters_construct(params_out);
  if (mat->major == rokko_matrix_col_major)
    *static_cast<rokko::parameters*>(params_out->ptr) = static_cast<rokko::parallel_dense_ev*>(solver->ptr)->diagonalize(*static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(mat->ptr),
								       *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								       *static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(eigvecs->ptr),
								       *static_cast<rokko::parameters*>(params->ptr));
  else
    *static_cast<rokko::parameters*>(params_out->ptr) = static_cast<rokko::parallel_dense_ev*>(solver->ptr)->diagonalize(*static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(mat->ptr),
								       *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								       *static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(eigvecs->ptr),
								       *static_cast<rokko::parameters*>(params->ptr));
}

void rokko_parallel_dense_ev_diagonalize_no_params_out_f(struct rokko_parallel_dense_ev* solver,
						       struct rokko_distributed_matrix* mat, struct rokko_eigen_vector* eigvals,
						       struct rokko_distributed_matrix* eigvecs,
						       struct rokko_parameters* params) {
  if (mat->major == rokko_matrix_col_major)
    static_cast<rokko::parallel_dense_ev*>(solver->ptr)->diagonalize(*static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(mat->ptr),
								   *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								   *static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(eigvecs->ptr),
								   *static_cast<rokko::parameters*>(params->ptr));
  else
    static_cast<rokko::parallel_dense_ev*>(solver->ptr)->diagonalize(*static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(mat->ptr),
								   *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								   *static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(eigvecs->ptr),
								   *static_cast<rokko::parameters*>(params->ptr));
}


void rokko_parallel_dense_ev_diagonalize_no_params_inout_f(struct rokko_parallel_dense_ev* solver,
							 struct rokko_distributed_matrix* mat, struct rokko_eigen_vector* eigvals,
							 struct rokko_distributed_matrix* eigvecs) {
  if (mat->major == rokko_matrix_col_major)
    static_cast<rokko::parallel_dense_ev*>(solver->ptr)->diagonalize(*static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(mat->ptr),
								   *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								   *static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(eigvecs->ptr));
  else
    static_cast<rokko::parallel_dense_ev*>(solver->ptr)->diagonalize(*static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(mat->ptr),
								   *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								   *static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(eigvecs->ptr));
}

void rokko_parallel_dense_ev_diagonalize_eigvals_f(struct rokko_parallel_dense_ev* solver,
						 struct rokko_distributed_matrix* mat, struct rokko_eigen_vector* eigvals,
						 struct rokko_parameters* params, struct rokko_parameters* params_out) {
  rokko_parameters_construct(params_out);
  if (mat->major == rokko_matrix_col_major)
    *static_cast<rokko::parameters*>(params_out->ptr) = static_cast<rokko::parallel_dense_ev*>(solver->ptr)->diagonalize(*static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(mat->ptr),
								       *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								       *static_cast<rokko::parameters*>(params->ptr));
  else
    *static_cast<rokko::parameters*>(params_out->ptr) = static_cast<rokko::parallel_dense_ev*>(solver->ptr)->diagonalize(*static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(mat->ptr),
								       *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								       *static_cast<rokko::parameters*>(params->ptr));
}

void rokko_parallel_dense_ev_diagonalize_eigvals_no_params_out_f(struct rokko_parallel_dense_ev* solver,
							       struct rokko_distributed_matrix* mat, struct rokko_eigen_vector* eigvals,
							       struct rokko_parameters* params) {
  if (mat->major == rokko_matrix_col_major)
    static_cast<rokko::parallel_dense_ev*>(solver->ptr)->diagonalize(*static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(mat->ptr),
								   *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								   *static_cast<rokko::parameters*>(params->ptr));
  else
    static_cast<rokko::parallel_dense_ev*>(solver->ptr)->diagonalize(*static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(mat->ptr),
								   *static_cast<Eigen::VectorXd*>(eigvals->ptr),
								   *static_cast<rokko::parameters*>(params->ptr));
}

void rokko_parallel_dense_ev_diagonalize_eigvals_no_params_inout_f(struct rokko_parallel_dense_ev* solver,
								 struct rokko_distributed_matrix* mat, struct rokko_eigen_vector* eigvals) {
  if (mat->major == rokko_matrix_col_major)
    static_cast<rokko::parallel_dense_ev*>(solver->ptr)->diagonalize(*static_cast<rokko::distributed_matrix<double, rokko::matrix_col_major>*>(mat->ptr),
								   *static_cast<Eigen::VectorXd*>(eigvals->ptr));
  else
    static_cast<rokko::parallel_dense_ev*>(solver->ptr)->diagonalize(*static_cast<rokko::distributed_matrix<double, rokko::matrix_row_major>*>(mat->ptr),
								   *static_cast<Eigen::VectorXd*>(eigvals->ptr));
}

struct rokko_mapping_bc rokko_parallel_dense_ev_default_mapping(struct rokko_parallel_dense_ev solver, int dim, struct rokko_grid g) {
  struct rokko_mapping_bc map;
  map.major = rokko_matrix_col_major;
  map.ptr = new rokko::mapping_bc<rokko::matrix_col_major>(static_cast<rokko::parallel_dense_ev*>(solver.ptr)->default_mapping(dim, *static_cast<rokko::grid*>(g.ptr)));
  return map;
}

void rokko_parallel_dense_ev_default_mapping_f(struct rokko_parallel_dense_ev solver, int dim, struct rokko_grid g, struct rokko_mapping_bc* map) {
  map->major = rokko_matrix_col_major;
  map->ptr = new rokko::mapping_bc<rokko::matrix_col_major>(static_cast<rokko::parallel_dense_ev*>(solver.ptr)->default_mapping(dim, *static_cast<rokko::grid*>(g.ptr)));
}

int rokko_parallel_dense_ev_num_solvers() {
  return rokko::parallel_dense_ev::solvers().size();
}

char** rokko_parallel_dense_ev_solvers() {
  std::vector<std::string> solvers = rokko::parallel_dense_ev::solvers();
  char **solvers_c = (char**)malloc((size_t)(solvers.size() * sizeof(char*)));
  for (std::size_t i = 0; i < solvers.size(); ++i) {
    solvers_c[i] = copy_string(solvers[i]);
  }
  return solvers_c;
}

const char* rokko_parallel_dense_ev_default_solver() {
  return rokko::parallel_dense_ev::default_solver().c_str();
}


<|start_filename|>test/generate_matrix/helmert.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2013-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/helmert_matrix.hpp>

#include <gtest/gtest.h>

constexpr double eps = 1e-5;

template<typename T, typename MATRIX_MAJOR>
void test(int dim) {
  Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,rokko::eigen3_major<MATRIX_MAJOR>> mat(dim, dim);
  Eigen::VectorXd diag(dim);
  diag.setLinSpaced(diag.size(), 1, diag.size()); // diag = [1, 2, 3, ..., dim]
  rokko::helmert_matrix::generate_for_given_eigenvalues(mat, diag);  
  EXPECT_NEAR(mat.trace(), diag.sum(), eps);
  ASSERT_TRUE(mat.transpose() == mat);  // checking matrix symmetry
}

TEST(generate_matrix, helmert_matrix) {
  constexpr int dim = 100;
  std::cout << "dimension = " << dim << std::endl;

  std::cout << "  test for row major" << std::endl;
  test<double, rokko::matrix_row_major>(dim);
  std::cout << "  test for column major" << std::endl;
  test<double, rokko::matrix_col_major>(dim);
}

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}


<|start_filename|>rokko/mapping_bc_c.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/mapping_bc.h>
#include <rokko/mapping_bc.hpp>

void rokko_mapping_bc_construct_block_size(struct rokko_mapping_bc* map, int global_dim, int block_size, struct rokko_grid grid) {
  // Fix me: All parallel dense solvers use matrix_col_major. So we omit its checking, so far...
  map->ptr = new rokko::mapping_bc<rokko::matrix_col_major>(global_dim, block_size, *static_cast<rokko::grid*>(grid.ptr));
  map->major = rokko_matrix_col_major;
}

void rokko_mapping_bc_destruct(struct rokko_mapping_bc* map) {
  delete static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map->ptr);
  map->ptr = nullptr;
}

int rokko_mapping_bc_get_mb(struct rokko_mapping_bc map) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->get_mb();
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->get_mb();
}

int rokko_mapping_bc_get_nb(struct rokko_mapping_bc map) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->get_nb();
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->get_nb();
}

int rokko_mapping_bc_get_m_local(struct rokko_mapping_bc map) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->get_m_local();
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->get_m_local();
}

int rokko_mapping_bc_get_n_local(struct rokko_mapping_bc map) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->get_n_local();
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->get_n_local();
}

int rokko_mapping_bc_get_m_global(struct rokko_mapping_bc map) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->get_m_global();
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->get_m_global();
}

int rokko_mapping_bc_get_n_global(struct rokko_mapping_bc map) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->get_n_global();
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->get_n_global();
}

int rokko_mapping_bc_get_lld(struct rokko_mapping_bc map) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->get_lld();
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->get_lld();
}

int rokko_mapping_bc_get_m_size(struct rokko_mapping_bc map) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->get_m_size();
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->get_m_size();
}

int rokko_mapping_bc_get_n_size(struct rokko_mapping_bc map) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->get_n_size();
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->get_n_size();
}

int rokko_mapping_bc_get_length_array(struct rokko_mapping_bc map) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->get_length_array();
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->get_length_array();
}

int rokko_mapping_bc_get_nprocs(struct rokko_mapping_bc map) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->get_nprocs();
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->get_nprocs();
}

int rokko_mapping_bc_get_myrank(struct rokko_mapping_bc map) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->get_myrank();
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->get_myrank();
}

int rokko_mapping_bc_get_nprow(struct rokko_mapping_bc map) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->get_nprow();
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->get_nprow();
}

int rokko_mapping_bc_get_npcol(struct rokko_mapping_bc map) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->get_npcol();
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->get_npcol();
}

int rokko_mapping_bc_get_myrow(struct rokko_mapping_bc map) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->get_myrow();
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->get_myrow();
}

int rokko_mapping_bc_get_mycol(struct rokko_mapping_bc map) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->get_mycol();
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->get_mycol();
}

int rokko_mapping_bc_translate_l2g_row(struct rokko_mapping_bc map, int local_i) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->translate_l2g_row(local_i);
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->translate_l2g_row(local_i);
}

int rokko_mapping_bc_translate_l2g_col(struct rokko_mapping_bc map, int local_j) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->translate_l2g_col(local_j);
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->translate_l2g_col(local_j);
}

int rokko_mapping_bc_translate_g2l_row(struct rokko_mapping_bc map, int global_i) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->translate_g2l_row(global_i);
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->translate_g2l_row(global_i);
}

int rokko_mapping_bc_translate_g2l_col(struct rokko_mapping_bc map, int global_j) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->translate_g2l_col(global_j);
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->translate_g2l_col(global_j);
}

// offset by one for Fortran
int rokko_mapping_bc_translate_l2g_row1(struct rokko_mapping_bc map, int local_i) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->translate_l2g_row(local_i - 1) + 1;
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->translate_l2g_row(local_i - 1) + 1;
}

int rokko_mapping_bc_translate_l2g_col1(struct rokko_mapping_bc map, int local_j) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->translate_l2g_col(local_j - 1) + 1;
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->translate_l2g_col(local_j - 1) + 1;
}

int rokko_mapping_bc_translate_g2l_row1(struct rokko_mapping_bc map, int global_i) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->translate_g2l_row(global_i - 1) + 1;
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->translate_g2l_row(global_i - 1) + 1;
}

int rokko_mapping_bc_translate_g2l_col1(struct rokko_mapping_bc map, int global_j) {
  if (map.major == rokko_matrix_col_major)
    return static_cast<rokko::mapping_bc<rokko::matrix_col_major>*>(map.ptr)->translate_g2l_col(global_j - 1) + 1;
  else
    return static_cast<rokko::mapping_bc<rokko::matrix_row_major>*>(map.ptr)->translate_g2l_col(global_j - 1) + 1;
}

bool rokko_mapping_bc_is_row_major(struct rokko_mapping_bc map) {
  return map.major == rokko_matrix_row_major;
}

bool rokko_mapping_bc_is_col_major(struct rokko_mapping_bc map) {
  return map.major == rokko_matrix_col_major;
}


<|start_filename|>test/mfree/heisenberg_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <iostream>

#include <rokko/utility/heisenberg_hamiltonian_mfree.hpp>
#include "test_fill_diagonal.hpp"

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

TEST(heisenberg_mfree, fill_diagonal) {
  constexpr std::size_t L = 8;
  std::vector<std::pair<int, int>> lattice;
  for (std::size_t i=0; i<L; ++i) lattice.emplace_back(std::make_pair(i, (i+1) % L));

  int myrank;
  MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
  constexpr int root = 0;

  if (myrank == root) {
    std::cout << "L=" << L << " lattice.size=" << lattice.size() << std::endl;
    for (std::size_t i=0; i < lattice.size(); ++i) {
      std::cout << lattice[i].first << " " << lattice[i].second << std::endl;
    }
  }

  rokko::heisenberg_mfree mat(L, lattice);
  test_fill_diagonal(mat);
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>rokko/lapack/diagonalize_qr.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_DIAGONALIZE_QR_HPP
#define ROKKO_LAPACK_DIAGONALIZE_QR_HPP

#include <rokko/parameters.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/utility/timer.hpp>
#include <rokko/lapack.hpp>
#include <rokko/lapack/diagonalize_syevx.hpp>

namespace rokko {
namespace lapack {

// qr (dsyevx) only eigenvalues
template<typename T, int MATRIX_MAJOR, typename VEC>
parameters diagonalize_qr(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat, VEC& eigvals,
                 rokko::parameters params) {
  if (params.defined("abstol")) {
    auto abstol = params.get<real_t<T>>("abstol");
    if (abstol > 0) {
      params.set("abstol", - abstol);
    }
  }
  parameters params_out = diagonalize_syevx(mat, eigvals, params);

  if (params.get_bool("verbose")) {
    std::cout << "finished dsyevx (qr)" << std::endl;
  }

  return params_out;
}


// qr (dsyevx) eigenvalues / eigenvectors
template<typename T, int MATRIX_MAJOR, typename VEC>
parameters diagonalize_qr(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat, VEC& eigvals,
                 Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& eigvecs,
                 rokko::parameters params) {
  if (params.defined("abstol")) {
    auto abstol = params.get<real_t<T>>("abstol");
    if (abstol > 0) {
      params.set("abstol", - abstol);
    }
  }
  parameters params_out = diagonalize_syevx(mat, eigvals, eigvecs, params);

  if (params.get_bool("verbose")) {
    std::cout << "finished dsyevx (qr)" << std::endl;
  }

  return params_out;
}

} // namespace lapack
} // namespace rokko

#endif // ROKKO_LAPACK_DIAGONALIZE_QR_HPP


<|start_filename|>benchmark/no_rokko/sparse_heisenberg_ladder_mpi/slepc_crs.cpp<|end_filename|>
#include <slepceps.h>
#include <petscblaslapack.h>
//#include <vector>
#include <rokko/utility/lattice.hpp>
#include <rokko/utility/machine_info.hpp>

#undef __FUNCT__
#define __FUNCT__ "main"
int main(int argc,char **argv)
{
  Mat            A;               /* operator matrix */
  EPS            eps;             /* eigenproblem solver context */
  EPSType        type;
  PetscMPIInt    rank;
  PetscInt       nev;
  PetscErrorCode ierr;
  double init_tick, initend_tick, gen_tick, diag_tick, end_tick;

  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  MPI_Barrier(MPI_COMM_WORLD);
  init_tick = MPI_Wtime();
  SlepcInitialize(&argc, &argv, (char*)0, 0);
  ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
  MPI_Barrier(MPI_COMM_WORLD);
  initend_tick = MPI_Wtime();

  int len_ladder = 5;
  if (argc >= 2) len_ladder = std::stoi(argv[1]);

  const int L = 2 * len_ladder;
  std::vector<std::pair<int, int>> lattice;
  rokko::create_ladder_lattice_1dim(len_ladder, lattice);
  const int dim = 1 << L;

  // Create Hermitean matrix
  MPI_Barrier(MPI_COMM_WORLD);
  gen_tick = MPI_Wtime();
  ierr = MatCreate(PETSC_COMM_WORLD, &A); CHKERRQ(ierr);
  ierr = MatSetSizes(A, PETSC_DECIDE, PETSC_DECIDE, dim, dim); CHKERRQ(ierr);
  ierr = MatSetFromOptions(A); CHKERRQ(ierr);
  //  ierr = MatSetType(A,MATAIJ); CHKERRQ(ierr);
  const int NumEntriesPerRow = lattice.size() + 1;
  ierr = MatSeqAIJSetPreallocation(A, NumEntriesPerRow, NULL); CHKERRQ(ierr);
  ierr = MatMPIAIJSetPreallocation(A, NumEntriesPerRow, NULL, NumEntriesPerRow, NULL); CHKERRQ(ierr);

  PetscInt Istart, Iend;
  ierr = MatGetOwnershipRange(A, &Istart, &Iend); CHKERRQ(ierr);

  std::vector<PetscInt> cols;
  std::vector<double> values;
  cols.reserve(NumEntriesPerRow);
  values.reserve(NumEntriesPerRow);

  for (int row=Istart; row<Iend; ++row) {
    cols.clear();
    values.clear();
    double diag = 0.;
    for (int l=0; l<lattice.size(); ++l) {
      int i = lattice[l].first;
      int j = lattice[l].second;
      int m1 = 1 << i;
      int m2 = 1 << j;
      int m3 = m1 + m2;
      if (((row & m3) == m1) || ((row & m3) == m2)) {  // when (bit i == 1, bit j == 0) or (bit i == 0, bit j == 1)
        cols.emplace_back(row^m3);
        values.emplace_back(0.5);
        diag += -0.25;
      } else {
        diag += 0.25;
      }
    }
    if (diag != 0.) {
      cols.emplace_back(row);
      values.emplace_back(diag);
    }
    ierr = MatSetValues(A, 1, &row, cols.size(), cols.data(), values.data(), ADD_VALUES); CHKERRQ(ierr);
  }

  ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
  ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
  //MatView(A, PETSC_VIEWER_STDOUT_WORLD);

  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                Create the eigensolver and set various options
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  /*
     Create eigensolver context
  */
  MPI_Barrier(MPI_COMM_WORLD);
  diag_tick = MPI_Wtime();
  ierr = EPSCreate(PETSC_COMM_WORLD, &eps); CHKERRQ(ierr);
  /*
     Set operators. In this case, it is a standard eigenvalue problem
  */
  ierr = EPSSetOperators(eps, A, NULL); CHKERRQ(ierr);
  ierr = EPSSetProblemType(eps, EPS_HEP); CHKERRQ(ierr);
  ierr = EPSSetDimensions(eps, 1, PETSC_DECIDE, PETSC_DECIDE); CHKERRQ(ierr);
  ierr = EPSSetTolerances(eps, PETSC_DEFAULT, PETSC_DECIDE);   CHKERRQ(ierr);

  /*
     Set solver parameters at runtime
  */
  ierr = EPSSetFromOptions(eps); CHKERRQ(ierr);

  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      Solve the eigensystem
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  ierr = EPSSolve(eps); CHKERRQ(ierr);
  MPI_Barrier(MPI_COMM_WORLD);
  end_tick = MPI_Wtime();

  /*
     Optional: Get some information from the solver and display it
  */
  ierr = EPSGetType(eps,&type); CHKERRQ(ierr);
  ierr = PetscPrintf(PETSC_COMM_WORLD,"solution method: %s\n\n",type); CHKERRQ(ierr);
  int num_conv;
  EPSGetConverged(eps, &num_conv);
  PetscScalar eval_r, eval_i;
  if (rank == 0) {
    std::cout << "number of converged eigenpairs = " << num_conv << std::endl;
    for (int i=0; i<num_conv; ++i) {
      EPSGetEigenvalue(eps, i, &eval_r, &eval_i);
      std::cout << ' ' << eval_r;
    }
    std::cout << std::endl;
    std::cout << "init_time = " << initend_tick - init_tick << std::endl
	      << "gen_time = " << diag_tick - gen_tick << std::endl
	      << "diag_time = " << end_tick - diag_tick << std::endl;
    rokko::machine_info();
    PetscInt nev, ncv, mpd;
    PetscReal tol;
    PetscInt maxits, its;
    ierr = EPSGetDimensions(eps, &nev, &ncv, &mpd);   CHKERRQ(ierr);
    ierr = EPSGetTolerances(eps, &tol, &maxits);   CHKERRQ(ierr);
    ierr = EPSGetIterationNumber(eps, &its);   CHKERRQ(ierr);
    std::cout << "number of eigenvalues to compute=" << nev << std::endl;
    std::cout << "maximum dimension of the subspace to be used by the solver=" << ncv << std::endl;
    std::cout << "maximum dimension allowed for the projected problem=" << mpd << std::endl;
    std::cout << "convergence tolerance=" << tol << std::endl;
    std::cout << "maximum number of iterations=" << maxits << std::endl;
    std::cout << "number of iterations=" << its << std::endl;
  }
  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    Display solution and clean up
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  ///ierr = EPSValuesView(eps,NULL); CHKERRQ(ierr);
  ierr = EPSDestroy(&eps); CHKERRQ(ierr);
  ierr = MatDestroy(&A); CHKERRQ(ierr);
  ierr = SlepcFinalize();
  MPI_Finalize();
  return 0;
}


<|start_filename|>benchmark/use_rokko/dense_heisenberg_ladder_mpi/ladder_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/mapping_bc.hpp>
#include <rokko/collective.hpp>
#include <rokko/utility/solver_name.hpp>
#include <rokko/utility/heisenberg_hamiltonian_mpi.hpp>
#include <rokko/utility/lattice.hpp>
#include <rokko/utility/machine_info.hpp>
#include <iostream>


using matrix_major = rokko::matrix_col_major;

int main(int argc, char *argv[]) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  MPI_Comm comm = MPI_COMM_WORLD;
  std::string library_routine(rokko::parallel_dense_ev::default_solver());
  std::string library, routine;
  double init_tick, initend_tick, gen_tick, diag_tick, end_tick;

  if (argc >= 2) library_routine = argv[1];
  rokko::split_solver_name(library_routine, library, routine);
  int len_ladder = 5;
  if (argc >= 3) len_ladder = std::stoi(argv[2]);
  int L = 2 * len_ladder;
  std::vector<std::pair<int, int>> lattice;
  rokko::create_ladder_lattice_1dim(len_ladder, lattice);
  int dim = 1 << L;

  rokko::grid g(comm);
  int myrank = g.get_myrank();
  if (myrank == 0) {
    std::cout << "Eigenvalue decomposition of Frank matrix" << std::endl
              << "library = " << library << std::endl
              << "routine = " << routine << std::endl
              << "dimension = " << dim << std::endl;
    rokko::print_lattice(lattice);
  }

  MPI_Barrier(MPI_COMM_WORLD);
  init_tick = MPI_Wtime();
  rokko::parallel_dense_ev solver(library);
  solver.initialize(argc, argv);
  MPI_Barrier(MPI_COMM_WORLD);
  initend_tick = MPI_Wtime();

  MPI_Barrier(MPI_COMM_WORLD);
  gen_tick = MPI_Wtime();
  rokko::mapping_bc<matrix_major> map = solver.default_mapping(dim, g);
  rokko::distributed_matrix<double, matrix_major> mat(map);
  rokko::heisenberg_hamiltonian::generate(L, lattice, mat);
  //  Eigen::MatrixXd mat_loc(dim, dim);
  //  rokko::gather(mat, mat_loc, 0);

  MPI_Barrier(MPI_COMM_WORLD);
  diag_tick = MPI_Wtime();
  Eigen::VectorXd eigval(dim);
  rokko::distributed_matrix<double, matrix_major> eigvec(map);
  rokko::parameters params;
  params.set("routine", "tri");
  solver.diagonalize(mat, eigval, eigvec); //, params);
  MPI_Barrier(MPI_COMM_WORLD);
  end_tick = MPI_Wtime();

  if (myrank == 0) {
    std::cout << "init_time = " << initend_tick - init_tick << std::endl
              << "gen_time = " << diag_tick - gen_tick << std::endl
              << "diag_time = " << end_tick - diag_tick << std::endl;
    rokko::machine_info();
    bool sorted = true;
    for (unsigned int i = 1; i < dim; ++i) sorted &= (eigval(i-1) <= eigval(i));
    if (!sorted) std::cout << "Warning: eigenvalues are not sorted in ascending order!\n";
    std::cout << "largest eigenvalues:";
    for (int i = 0; i < dim; ++i) std::cout << ' ' << eigval(dim - 1 - i);
    //for (int i = 0; i < std::min(dim, 10); ++i) std::cout << ' ' << eigval(dim - 1 - i);
    std::cout << std::endl;
  }

  solver.finalize();
  MPI_Finalize();
}


<|start_filename|>tutorial/C/Rokko.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <mpi.h>
#include <rokko/rokko.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
  int dim;
  struct rokko_parallel_dense_ev solver;
  struct rokko_distributed_matrix frank, eigvecs;
  struct rokko_grid grid;
  struct rokko_mapping_bc map;
  struct rokko_eigen_vector eigvals;
  char* solver_name;

  int provided, ierr, myrank, nprocs, i, j;

  ierr = MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  ierr = MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
  ierr = MPI_Comm_size(MPI_COMM_WORLD, &nprocs);

  dim = 4;
  if (argc == 2) {
    solver_name = argv[1];
  } else {
    fprintf(stderr, "error: %s solver_name\n", argv[0]);
    MPI_Abort(MPI_COMM_WORLD, 34);
  }
    
  printf("solver name = %s\n", solver_name);
  printf("matrix dimension = %d\n", dim);

  rokko_parallel_dense_ev_construct(&solver, solver_name, argc, argv);
  rokko_grid_construct(&grid, MPI_COMM_WORLD, rokko_grid_row_major);
  map = rokko_parallel_dense_ev_default_mapping(solver, dim, grid);
  rokko_distributed_matrix_construct(&frank, map);
  rokko_distributed_matrix_construct(&eigvecs, map);
  rokko_eigen_vector_construct(&eigvals, dim);

  /* generate frank matrix */
  for(i = 0; i<dim; ++i){
    for(j = 0; j<dim; ++j){
      double val = dim - (i>j?i:j);
      rokko_distributed_matrix_set_global(frank, i, j, val);
    }
  }
  rokko_distributed_matrix_print(frank);

  MPI_Barrier(MPI_COMM_WORLD);

  rokko_parallel_dense_ev_diagonalize_distributed_matrix(solver, frank, eigvals, eigvecs);

  MPI_Barrier(MPI_COMM_WORLD);

  if (myrank == 0) {
    printf("Eigenvalues: \n");
    for (i = 0; i < dim; ++i)
      printf("%30.20f\n", rokko_eigen_vector_get(eigvals, i));

    printf("Eigenstates: \n");
  }

  MPI_Barrier(MPI_COMM_WORLD);

  rokko_distributed_matrix_print(eigvecs);

  rokko_eigen_vector_destruct(&eigvals);
  rokko_distributed_matrix_destruct(&eigvecs);
  rokko_distributed_matrix_destruct(&frank);
  rokko_parallel_dense_ev_destruct(&solver);
  rokko_grid_destruct(&grid);

  MPI_Finalize();
  return 0;
}


<|start_filename|>rokko/scalapack/psyevx.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <stdlib.h>
#include <rokko/scalapack/scalapack_interface.h>

#define CSCALAPACK_PSYEVX_IMPL(NAMES, NAMEL, TYPE, TYPE_REAL) \
int cscalapack_ ## NAMES (char jobz, char range, char uplo, int n, \
                          TYPE* A, int ia, int ja, const int* descA, \
                          TYPE_REAL vl, TYPE_REAL vu, int il, int iu, \
                          TYPE_REAL abstol, int* m, int* nZ, TYPE_REAL* w, TYPE_REAL orfac, \
                          TYPE* Z, int iz, int jz, const int* descZ, \
                          int* ifail, int* iclustr, TYPE_REAL* gap) { \
  /* call for querying optimal size of work array */ \
  int lwork = -1; \
  int liwork = -1; \
  TYPE work_query[1]; \
  int iwork_query[1]; \
  int info; \
  info = cscalapack_## NAMES ##_work(jobz, range, uplo, n, A, ia, ja, descA, \
                                     vl, vu, il, iu, \
                                     abstol, m, nZ, w, orfac, \
                                     Z, iz, jz, descZ, \
                                     work_query, lwork, iwork_query, liwork, \
                                     ifail, iclustr, gap); \
  if (info) return info; \
  \
  /* allocate work arrays */ \
  lwork = (int)work_query[0]; \
  TYPE* work = (TYPE*)malloc( sizeof(TYPE) * lwork ); \
  liwork = iwork_query[0]; \
  int* iwork = (int*)malloc( sizeof(int) * liwork ); \
  if (work == NULL || iwork == NULL) return 1; \
  \
  /* call for computation */ \
  info = cscalapack_## NAMES ##_work(jobz, range, uplo, n, A, ia, ja, descA, \
                                    vl, vu, il, iu, \
                                    abstol, m, nZ, w, orfac, \
                                    Z, iz, jz, descZ, \
                                    work, lwork, iwork, liwork, \
                                    ifail, iclustr, gap); \
  free(work); \
  free(iwork); \
  return info; \
}

CSCALAPACK_PSYEVX_IMPL(pssyevx, PSSYEVX, float, float)
CSCALAPACK_PSYEVX_IMPL(pdsyevx, PDSYEVX, double, double)
CSCALAPACK_PSYEVX_IMPL(pcheevx, PCHEEVX, lapack_complex_float, float)
CSCALAPACK_PSYEVX_IMPL(pzheevx, PZHEEVX, lapack_complex_double, double)

#undef CSCALAPACK_PSYEVX_IMPL


<|start_filename|>rokko/distributed_crs_matrix.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include "distributed_crs_matrix.hpp"

template<>
rokko::detail::ps_crs_factory *rokko::detail::ps_crs_factory::instance_ = nullptr;


<|start_filename|>test/generate_matrix/heisenberg.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <iostream>
#include <vector>
#include <rokko/utility/heisenberg_hamiltonian.hpp>
#include <rokko/eigen3.hpp>

#include <gtest/gtest.h>

TEST(generate_matrix, heisenberg) {
  int L = 4;
  int N = 1 << L;
  std::vector<std::pair<int, int>> lattice;
  for (int i=0; i<L-1; ++i) {
    lattice.emplace_back(std::make_pair(i, i+1));
  }

  Eigen::MatrixXd mat1(N, N);

  std::cout << "multiply:" << std::endl;
  for (int i=0; i<N; ++i) {
    std::vector<double> v, w;
    v.assign(N, 0);
    v[i] = 1;
    w.assign(N, 0);
    rokko::heisenberg_hamiltonian::multiply(L, lattice, v, w);
    for (int j=0; j<N; ++j) {
      mat1(j,i) = w[j];
      std::cout << w[j] << " ";
    }
    std::cout << std::endl;
  }

  std::cout << "fill_diagonal:" << std::endl;
  Eigen::VectorXd diagonal(N);
  std::vector<double> v(N);
  rokko::heisenberg_hamiltonian::fill_diagonal(L, lattice, v);
  for (int j=0; j<N; ++j) {
    diagonal(j) = v[j];
    std::cout << v[j] << " ";
  }
  std::cout << std::endl;

  std::cout << "fill_matrix:" << std::endl;
  Eigen::MatrixXd mat2(N, N);
  rokko::heisenberg_hamiltonian::generate(L, lattice, mat2);
  for (int i=0; i<N; ++i) {
    for (int j=0; j<N; ++j) {
      std::cout << mat2(i,j) << " ";
    }
    std::cout << std::endl;
  }

  EXPECT_TRUE(mat1 == mat2) << "matrix generated by fucntion 'multiply' is differnet from the matrix generated by function 'generate'.";

  ASSERT_TRUE(mat2.transpose() == mat2);  // checking matrix symmetry

  EXPECT_TRUE(diagonal == mat2.diagonal()) << "diagonal elements generated by 'fill_diagonal' is differnet from diagonal elements of the matrix generated by function 'genertate'.";
}

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}


<|start_filename|>test/matrix_product/dot_product_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/collective.hpp>

#include <gtest/gtest.h>

constexpr double eps = 1e-11;

int global_argc;
char** global_argv;

TEST(dot_product_mpi, dot_product_mpi) {
  constexpr int root_proc = 0;
  MPI_Comm comm = MPI_COMM_WORLD;
  int rank;
  MPI_Comm_rank(comm, &rank);

  int dim = 100;
  if (global_argc > 1) {
    dim = std::stoi(global_argv[1]);
  }

  if (rank == root_proc) std::cout << "dimension = " << dim << std::endl;
  rokko::grid g(comm);
  rokko::mapping_bc<rokko::matrix_col_major> map({dim, 1}, {1, 1}, g);
  rokko::distributed_matrix<double, rokko::matrix_col_major> vecX(map);
  rokko::distributed_matrix<double, rokko::matrix_col_major> vecY(map);
  Eigen::VectorXd locX(dim), locY(dim);
  locX.setRandom();
  locY.setRandom();
  rokko::scatter(locX, vecX, root_proc);
  rokko::scatter(locY, vecY, root_proc);

  // local calculation
  double product_local = locX.dot(locY);

  // global calculation
  double product_global = rokko::dot_product(vecX, false, 0, vecY, false, 0);

  for (int i = 0; i < dim; ++i) {
    if (vecX.has_global_indices({i, 0})) {
      std::cerr << i << ' ' << rank << ' ' << product_local << ' ' << product_global << std::endl;
      std::cerr.flush();
      EXPECT_NEAR(product_local, product_global, eps);
    }
    MPI_Barrier(MPI_COMM_WORLD);
  }
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>example/cxx/sparse/heisenberg_mfree_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/heisenberg_hamiltonian_mfree.hpp>
#include <rokko/utility/solver_name.hpp>

#include <stdexcept>

int main(int argc, char *argv[]) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  int rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  
  std::string library_routine(rokko::parallel_sparse_ev::default_solver());
  std::string library, routine;
  if (argc >= 2) library_routine = argv[1];
  rokko::split_solver_name(library_routine, library, routine);

  int L = (argc >= 3) ? std::stoi(argv[2]) : 10;
  std::vector<std::pair<int, int>> lattice;
  for (int i = 0; i < L; ++i) lattice.emplace_back(std::make_pair(i, (i+1) % L));

  rokko::parameters params;
  if (!routine.empty()) params.set("routine", routine);
  params.set("Block Size", 5);
  params.set("Maximum Iterations", 500);
  params.set("Convergence Tolerance", 1.0e-8);
  params.set("num_eigenvalues", 10);
  
  rokko::parallel_sparse_ev solver(library);
  rokko::heisenberg_mfree mat(L, lattice);
  int dim = mat.get_dim();
  if (rank == 0)
    std::cout << "Eigenvalue decomposition of antiferromagnetic Heisenberg chain" << std::endl
	      << "solver = " << library << std::endl
	      << "L = " << L << std::endl
	      << "dimension = " << dim << std::endl;
  
  rokko::parameters info = solver.diagonalize(mat, params);

  int num_conv = info.get<int>("num_conv");
  if (num_conv == 0)
    throw std::runtime_error("num_conv=0: solver did not converge");
  std::vector<double> eigvec;
  solver.eigenvector(0, eigvec);
  if (rank == 0) {
    std::cout << "number of converged eigenpairs = " << num_conv << std::endl;
    std::cout << "smallest eigenvalues: ";
    for (int i = 0; i < num_conv; ++i) std::cout << ' ' << solver.eigenvalue(i);
    std::cout << std::endl;
      std::cout << "smallest eigenvector: ";
      for (int j = 0; j < eigvec.size(); ++j) std::cout << eigvec[j] << ' ';
      std::cout << std::endl;
  }
  
  solver.finalize();
  MPI_Finalize();
}


<|start_filename|>example/fortran/dense/generate_vector/eigen_vector_construct_by_array.f90<|end_filename|>
!*****************************************************************************
!
! Rokko: Integrated Interface for libraries of eigenvalue decomposition
!
! Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
!
! 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)
!
!*****************************************************************************

program eigen_vector_construct_by_array
  use rokko
  implicit none
  integer :: dim
  double precision, allocatable :: array(:)
  type(rokko_eigen_vector) :: vector
  integer :: i

  dim = 5
  print *,"dimension = ", dim

  allocate( array(dim) )
  do i=1, dim
     array(i) = i
  enddo

  call rokko_construct(vector, array)
  call rokko_print(vector)

  call rokko_destruct(vector)

end program eigen_vector_construct_by_array


<|start_filename|>example/python/sparse/py_heisenberg_mfree.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/numpy.h>
#include <pybind11/eigen.h>

#include <rokko/pyrokko_distributed_mfree.hpp>
#include <rokko/utility/heisenberg_hamiltonian_mfree.hpp>

namespace py = pybind11;

PYBIND11_MODULE(heisenberg, m) {
  py::module::import("pyrokko");

  py::class_<rokko::heisenberg_mfree, rokko::distributed_mfree_default, rokko::distributed_mfree>(m, "mfree")
    .def(py::init<int, const std::vector<std::pair<int, int>>&>());
}


<|start_filename|>test/mapping_bc/translate_l2g_g2l.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/mapping_bc.hpp>

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

template <typename MATRIX_MAJOR, typename GRID_MAJOR>
void run_test(std::array<int,2> const& global_size, std::array<int,2> const& block_size, GRID_MAJOR) {
  rokko::grid g(MPI_COMM_WORLD, GRID_MAJOR{});
  rokko::mapping_bc<MATRIX_MAJOR> map(global_size, block_size, g);
  constexpr int root_proc = 0;

  // local to global
  // for row
  for (int local=0; local<map.get_m_local(); ++local) {
    int global = map.template translate_l2g<0>(local);
    int local2 = map.template translate_g2l<0>(global);
    ASSERT_EQ(local, local2);
  }
  // for column
  for (int local=0; local<map.get_n_local(); ++local) {
    int global = map.template translate_l2g<1>(local);
    int local2 = map.template translate_g2l<1>(global);
    ASSERT_EQ(local, local2);
  }

  // global to local
  // for row
  for (int global=0; global<map.get_m_global(); ++global) {
    if (map.template has_global_indices<0>(global)) {
      int local = map.template translate_g2l<0>(global);
      int global2 = map.template translate_l2g<0>(local);
      ASSERT_EQ(global, global2);
    }
  }
  // for column
  for (int global=0; global<map.get_n_local(); ++global) {
    if (map.template has_global_indices<1>(global)) {
      int local = map.template translate_g2l<1>(global);
      int global2 = map.template translate_l2g<1>(local);
      ASSERT_EQ(global, global2);
    }
  }
}

template <typename MATRIX_MAJOR>
void test_both_grid_major(std::array<int,2> const& global_size, std::array<int,2> const& block_size) {
  run_test<MATRIX_MAJOR>(global_size, block_size, rokko::grid_row_major);
  run_test<MATRIX_MAJOR>(global_size, block_size, rokko::grid_col_major);
}

TEST(mapping_bc, translate_l2g_g2l) {
  test_both_grid_major<rokko::matrix_col_major>({20,8}, {4,3});
  test_both_grid_major<rokko::matrix_col_major>({8,20}, {4,3});
  test_both_grid_major<rokko::matrix_col_major>({5,7}, {9,12});
  test_both_grid_major<rokko::matrix_col_major>({7,9}, {9,5});
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>rokko/parallel_dense_ev.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_PARALLEL_DENSE_SOLVER_HPP
#define ROKKO_PARALLEL_DENSE_SOLVER_HPP

#include <rokko/factory.hpp>
#include <rokko/matrix_major.hpp>
#include <rokko/mapping_bc.hpp>
#include <rokko/distributed_matrix.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/utility/macro_join.hpp>
#include <rokko/utility/timer.hpp>
#include <rokko/parameters.hpp>

namespace rokko {

namespace detail {
    
class pd_ev_base {
public:
  virtual ~pd_ev_base() = default;
  virtual bool is_available_grid_major(grid_row_major_t const& grid_major) = 0;
  virtual bool is_available_grid_major(grid_col_major_t const& grid_major) = 0;
  virtual void initialize(int& argc, char**& argv) = 0;
  virtual void finalize() = 0;

  // float # eigenvalues/eigenvectors
  virtual parameters diagonalize(distributed_matrix<float, matrix_row_major>& mat,
				 Eigen::VectorXf& eigvals, distributed_matrix<float, matrix_row_major>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<float, matrix_col_major>& mat,
				 Eigen::VectorXf& eigvals, distributed_matrix<float, matrix_col_major>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<float, matrix_row_major>& mat,
				 Eigen::RefVec<float>& eigvals, distributed_matrix<float, matrix_row_major>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<float, matrix_col_major>& mat,
				 Eigen::RefVec<float>& eigvals, distributed_matrix<float, matrix_col_major>& eigvecs,
				 parameters const& params) = 0;
  // float # only eigenvalues
  virtual parameters diagonalize(distributed_matrix<float, matrix_row_major>& mat,
				 Eigen::VectorXf& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<float, matrix_col_major>& mat,
				 Eigen::VectorXf& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<float, matrix_row_major>& mat,
				 Eigen::RefVec<float>& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<float, matrix_col_major>& mat,
				 Eigen::RefVec<float>& eigvals,
				 parameters const& params) = 0;
  // complex float # eigenvalues/eigenvectors
  virtual parameters diagonalize(distributed_matrix<std::complex<float>, matrix_row_major>& mat,
				 Eigen::VectorXf& eigvals, distributed_matrix<std::complex<float>, matrix_row_major>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<std::complex<float>, matrix_col_major>& mat,
				 Eigen::VectorXf& eigvals, distributed_matrix<std::complex<float>, matrix_col_major>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<std::complex<float>, matrix_row_major>& mat,
				 Eigen::RefVec<float>& eigvals, distributed_matrix<std::complex<float>, matrix_row_major>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<std::complex<float>, matrix_col_major>& mat,
				 Eigen::RefVec<float>& eigvals, distributed_matrix<std::complex<float>, matrix_col_major>& eigvecs,
				 parameters const& params) = 0;
  // complex float # only eigenvalues
  virtual parameters diagonalize(distributed_matrix<std::complex<float>, matrix_row_major>& mat,
				 Eigen::VectorXf& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<std::complex<float>, matrix_col_major>& mat,
				 Eigen::VectorXf& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<std::complex<float>, matrix_row_major>& mat,
				 Eigen::RefVec<float>& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<std::complex<float>, matrix_col_major>& mat,
				 Eigen::RefVec<float>& eigvals,
                 parameters const& params) = 0;

  // double # eigenvalues/eigenvectors
  virtual parameters diagonalize(distributed_matrix<double, matrix_row_major>& mat,
				 Eigen::VectorXd& eigvals, distributed_matrix<double, matrix_row_major>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<double, matrix_col_major>& mat,
				 Eigen::VectorXd& eigvals, distributed_matrix<double, matrix_col_major>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<double, matrix_row_major>& mat,
				 Eigen::RefVec<double>& eigvals, distributed_matrix<double, matrix_row_major>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<double, matrix_col_major>& mat,
				 Eigen::RefVec<double>& eigvals, distributed_matrix<double, matrix_col_major>& eigvecs,
				 parameters const& params) = 0;
  // double # only eigenvalues
  virtual parameters diagonalize(distributed_matrix<double, matrix_row_major>& mat,
				 Eigen::VectorXd& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<double, matrix_col_major>& mat,
				 Eigen::VectorXd& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<double, matrix_row_major>& mat,
				 Eigen::RefVec<double>& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<double, matrix_col_major>& mat,
				 Eigen::RefVec<double>& eigvals,
				 parameters const& params) = 0;
  // complex double # eigenvalues/eigenvectors
  virtual parameters diagonalize(distributed_matrix<std::complex<double>, matrix_row_major>& mat,
				 Eigen::VectorXd& eigvals, distributed_matrix<std::complex<double>, matrix_row_major>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<std::complex<double>, matrix_col_major>& mat,
				 Eigen::VectorXd& eigvals, distributed_matrix<std::complex<double>, matrix_col_major>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<std::complex<double>, matrix_row_major>& mat,
				 Eigen::RefVec<double>& eigvals, distributed_matrix<std::complex<double>, matrix_row_major>& eigvecs,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<std::complex<double>, matrix_col_major>& mat,
				 Eigen::RefVec<double>& eigvals, distributed_matrix<std::complex<double>, matrix_col_major>& eigvecs,
				 parameters const& params) = 0;

  // complex double # only eigenvalues
  virtual parameters diagonalize(distributed_matrix<std::complex<double>, matrix_row_major>& mat,
				 Eigen::VectorXd& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<std::complex<double>, matrix_col_major>& mat,
				 Eigen::VectorXd& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<std::complex<double>, matrix_row_major>& mat,
				 Eigen::RefVec<double>& eigvals,
				 parameters const& params) = 0;
  virtual parameters diagonalize(distributed_matrix<std::complex<double>, matrix_col_major>& mat,
				 Eigen::RefVec<double>& eigvals,
                 parameters const& params) = 0;

  virtual mapping_bc<matrix_col_major> default_mapping(int dim, grid const& g) const = 0;
};
  
template<typename SOLVER>
class pd_ev_wrapper : public pd_ev_base {
  using solver_type = SOLVER;
public:
  pd_ev_wrapper() : solver_impl_() {}
  virtual ~pd_ev_wrapper() = default;
  bool is_available_grid_major(grid_row_major_t const& grid_major) override {
    return solver_impl_.is_available_grid_major(grid_major);
  }
  bool is_available_grid_major(grid_col_major_t const& grid_major) override {
    return solver_impl_.is_available_grid_major(grid_major);
  }
  void initialize(int& argc, char**& argv) override {
    solver_impl_.initialize(argc, argv);
  }
  void finalize() override { solver_impl_.finalize(); }
  // float # eigenvalues/eigenvectors
  parameters diagonalize(distributed_matrix<float, matrix_row_major>& mat,
			 Eigen::VectorXf& eigvals, distributed_matrix<float, matrix_row_major>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(distributed_matrix<float, matrix_col_major>& mat,
			 Eigen::VectorXf& eigvals, distributed_matrix<float, matrix_col_major>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(distributed_matrix<float, matrix_row_major>& mat,
			 Eigen::RefVec<float>& eigvals, distributed_matrix<float, matrix_row_major>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(distributed_matrix<float, matrix_col_major>& mat,
			 Eigen::RefVec<float>& eigvals, distributed_matrix<float, matrix_col_major>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  // float # only eigenvalues
  parameters diagonalize(distributed_matrix<float, matrix_row_major>& mat,
			 Eigen::VectorXf& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(distributed_matrix<float, matrix_col_major>& mat,
			 Eigen::VectorXf& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(distributed_matrix<float, matrix_row_major>& mat,
			 Eigen::RefVec<float>& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(distributed_matrix<float, matrix_col_major>& mat,
			 Eigen::RefVec<float>& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  // complex float # eigenvalues/eigenvectors
  parameters diagonalize(distributed_matrix<std::complex<float>, matrix_row_major>& mat,
			 Eigen::VectorXf& eigvals, distributed_matrix<std::complex<float>, matrix_row_major>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(distributed_matrix<std::complex<float>, matrix_col_major>& mat,
			 Eigen::VectorXf& eigvals, distributed_matrix<std::complex<float>, matrix_col_major>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(distributed_matrix<std::complex<float>, matrix_row_major>& mat,
			 Eigen::RefVec<float>& eigvals, distributed_matrix<std::complex<float>, matrix_row_major>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(distributed_matrix<std::complex<float>, matrix_col_major>& mat,
			 Eigen::RefVec<float>& eigvals, distributed_matrix<std::complex<float>, matrix_col_major>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  // complex float # only eigenvalues
  parameters diagonalize(distributed_matrix<std::complex<float>, matrix_row_major>& mat,
			 Eigen::VectorXf& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(distributed_matrix<std::complex<float>, matrix_col_major>& mat,
			 Eigen::VectorXf& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(distributed_matrix<std::complex<float>, matrix_row_major>& mat,
			 Eigen::RefVec<float>& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(distributed_matrix<std::complex<float>, matrix_col_major>& mat,
			 Eigen::RefVec<float>& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  // double # eigenvalues/eigenvectors
  parameters diagonalize(distributed_matrix<double, matrix_row_major>& mat,
			 Eigen::VectorXd& eigvals, distributed_matrix<double, matrix_row_major>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(distributed_matrix<double, matrix_col_major>& mat,
			 Eigen::VectorXd& eigvals, distributed_matrix<double, matrix_col_major>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(distributed_matrix<double, matrix_row_major>& mat,
			 Eigen::RefVec<double>& eigvals, distributed_matrix<double, matrix_row_major>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(distributed_matrix<double, matrix_col_major>& mat,
			 Eigen::RefVec<double>& eigvals, distributed_matrix<double, matrix_col_major>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  // double # only eigenvalues
  parameters diagonalize(distributed_matrix<double, matrix_row_major>& mat,
			 Eigen::VectorXd& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(distributed_matrix<double, matrix_col_major>& mat,
			 Eigen::VectorXd& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(distributed_matrix<double, matrix_row_major>& mat,
			 Eigen::RefVec<double>& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(distributed_matrix<double, matrix_col_major>& mat,
			 Eigen::RefVec<double>& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  // complex double # eigenvalues/eigenvectors
  parameters diagonalize(distributed_matrix<std::complex<double>, matrix_row_major>& mat,
			 Eigen::VectorXd& eigvals, distributed_matrix<std::complex<double>, matrix_row_major>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(distributed_matrix<std::complex<double>, matrix_col_major>& mat,
			 Eigen::VectorXd& eigvals, distributed_matrix<std::complex<double>, matrix_col_major>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(distributed_matrix<std::complex<double>, matrix_row_major>& mat,
			 Eigen::RefVec<double>& eigvals, distributed_matrix<std::complex<double>, matrix_row_major>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  parameters diagonalize(distributed_matrix<std::complex<double>, matrix_col_major>& mat,
			 Eigen::RefVec<double>& eigvals, distributed_matrix<std::complex<double>, matrix_col_major>& eigvecs,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, eigvecs, params);
  }
  // complex double # only eigenvalues
  parameters diagonalize(distributed_matrix<std::complex<double>, matrix_row_major>& mat,
			 Eigen::VectorXd& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(distributed_matrix<std::complex<double>, matrix_col_major>& mat,
			 Eigen::VectorXd& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(distributed_matrix<std::complex<double>, matrix_row_major>& mat,
			 Eigen::RefVec<double>& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  parameters diagonalize(distributed_matrix<std::complex<double>, matrix_col_major>& mat,
			 Eigen::RefVec<double>& eigvals,
			 parameters const& params) override {
    return solver_impl_.diagonalize(mat, eigvals, params);
  }
  // default_mapping
  mapping_bc<matrix_col_major> default_mapping(int dim, grid const& g) const override {
    return solver_impl_.default_mapping(dim, g);
  }
private:
  solver_type solver_impl_;
};

using pd_solver_factory = factory<pd_ev_base>;
  
} // end namespace detail
  
class parallel_dense_ev {
public:
  parallel_dense_ev(std::string const& solver_name) : solver_impl_(detail::pd_solver_factory::instance()->make_product(solver_name)), null_params() {};

  parallel_dense_ev() : parallel_dense_ev(default_solver()) {}

  template <typename GRID_MAJOR>
  bool is_available_grid_major(GRID_MAJOR const& grid_major) {
    return solver_impl_->is_available_grid_major(grid_major);
  }
  void initialize(int& argc, char**& argv) {
    solver_impl_->initialize(argc, argv);
  }
  void finalize() {
    solver_impl_->finalize();
  }
  // with parameters, eigenvalues/eigenvectors
  template<typename T, typename MATRIX_MAJOR, typename VEC>
  parameters diagonalize(distributed_matrix<T, MATRIX_MAJOR>& mat,
			 VEC& eigvals, rokko::distributed_matrix<T, MATRIX_MAJOR>& eigvecs,
			 parameters const& params) {
    return solver_impl_->diagonalize(mat, eigvals, eigvecs, params);
  }
  // with parameters, only eigenvalues
  template<typename T, typename MATRIX_MAJOR, typename VEC>
  parameters diagonalize(distributed_matrix<T, MATRIX_MAJOR>& mat, VEC& eigvals,
			 parameters const& params) {
    return solver_impl_->diagonalize(mat, eigvals, params);
  }
  // no parameters, eigenvalues/eigenvectors
  template<typename T, typename MATRIX_MAJOR, typename VEC>
  parameters diagonalize(distributed_matrix<T, MATRIX_MAJOR>& mat,
			 VEC& eigvals, rokko::distributed_matrix<T, MATRIX_MAJOR>& eigvecs) {
    return solver_impl_->diagonalize(mat, eigvals, eigvecs, null_params);
  }
  // no parameters, only eigenvalues
  template<typename T, typename MATRIX_MAJOR, typename VEC>
  parameters diagonalize(distributed_matrix<T, MATRIX_MAJOR>& mat,
			 VEC& eigvals) {
    return diagonalize(mat, eigvals, null_params);
  }
  mapping_bc<matrix_col_major> default_mapping(int dim, grid const& g) const {
    return solver_impl_->default_mapping(dim, g);
  }
  static std::vector<std::string> solvers() {
    return detail::pd_solver_factory::product_names();
  }
  static const std::string& default_solver() {
    return detail::pd_solver_factory::default_product_name();
  }
private:
  detail::pd_solver_factory::product_pointer_type solver_impl_;
  parameters null_params;
  std::string routine_;
};

} // end namespace rokko

#define ROKKO_REGISTER_PARALLEL_DENSE_SOLVER(solver, name, priority) \
namespace { namespace ROKKO_JOIN(register, __LINE__) { \
struct register_caller { \
  using factory = rokko::detail::pd_solver_factory;     \
  using product = rokko::detail::pd_ev_wrapper<solver>; \
  register_caller() { factory::instance()->register_creator<product>(name, priority); } \
} caller; \
} }

#endif // ROKKO_PARALLEL_DENSE_SOLVER_HPP


<|start_filename|>rokko/solver_parameters.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SOLVER_PARAMETERS_HPP
#define ROKKO_SOLVER_PARAMETERS_HPP

namespace rokko {

static const std::vector<std::string> rokko_solver_keys{ "num_eigenvalues", "max_block_size", "routine", "block_size", "conv_tol", "max_iters", "verbose" };

bool is_rokko_solver_key(std::string const& key) {
  return std::find(rokko_solver_keys.cbegin(), rokko_solver_keys.cend(), key) != rokko_solver_keys.cend();
}

} // end namespace rokko

#endif // ROKKO_SOLVER_PARAMETERS_HPP


<|start_filename|>benchmark/no_rokko/sparse_heisenberg_ladder_mpi/anasazi_crs_verify.cpp<|end_filename|>
#include "AnasaziConfigDefs.hpp"
#include "AnasaziBasicEigenproblem.hpp"
#include "AnasaziLOBPCGSolMgr.hpp"
#include "AnasaziBasicOutputManager.hpp"
#include "AnasaziEpetraAdapter.hpp"
#include "Epetra_CrsMatrix.h"
#include "Teuchos_CommandLineProcessor.hpp"

#ifdef HAVE_MPI
#include "Epetra_MpiComm.h"
#include <mpi.h>
#else
#include "Epetra_SerialComm.h"
#endif
#include "Epetra_Map.h"

#include <rokko/utility/lattice.hpp>
#include <rokko/utility/machine_info.hpp>

using namespace Anasazi;

int main(int argc, char *argv[]) {
  double init_tick, gen_tick, diag_tick, end_tick;

#ifdef HAVE_MPI
  // Initialize MPI
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
#endif
  init_tick = MPI_Wtime();
  // Create an Epetra communicator
#ifdef HAVE_MPI
  Epetra_MpiComm Comm(MPI_COMM_WORLD);
#else
  Epetra_SerialComm Comm;
#endif

  // Create an Anasazi output manager
  BasicOutputManager<double> printer;
  printer.stream(Errors) << Anasazi_Version() << std::endl << std::endl;

  int len_ladder = 5;
  if (argc >= 2) len_ladder = std::stoi(argv[1]);
  const int L = 2 * len_ladder;
  std::vector<std::pair<int, int>> lattice;
  rokko::create_ladder_lattice_1dim(len_ladder, lattice);
  rokko::output_lattice(printer.stream(Anasazi::Errors), lattice);
  const int N = 1 << L;

  gen_tick = MPI_Wtime();
  // Construct a Map that puts approximately the same number of
  // equations on each processor.
  Epetra_Map Map(N, 0, Comm);

  // Get update list and number of local equations from newly created Map.
  const int NumMyElements = Map.NumMyElements();
  std::vector<int> MyGlobalElements(NumMyElements);
  Map.MyGlobalElements(MyGlobalElements.data());

  // Create an Epetra_Matrix
  const int NumEntriesPerRow = lattice.size() + 1;
  Teuchos::RCP<Epetra_CrsMatrix> A = Teuchos::rcp( new Epetra_CrsMatrix(Copy, Map, NumEntriesPerRow) );

  // Compute coefficients for hamiltonian matrix of quantum Heisenberg model
  std::vector<int> cols;
  std::vector<double> values;
  cols.reserve(NumEntriesPerRow);
  values.reserve(NumEntriesPerRow);

  for (int local_row=0; local_row<NumMyElements; ++local_row) {
    int row = MyGlobalElements[local_row];
    cols.clear();
    values.clear();
    double diag = 0.;
    for (int l=0; l<lattice.size(); ++l) {
      int i = lattice[l].first;
      int j = lattice[l].second;
      int m1 = 1 << i;
      int m2 = 1 << j;
      int m3 = m1 + m2;
      if (((row & m3) == m1) || ((row & m3) == m2)) {  // when (bit i == 1, bit j == 0) or (bit i == 0, bit j == 1)
        cols.emplace_back(row^m3);
        values.emplace_back(0.5);
        diag += -0.25;
      } else {
        diag += 0.25;
      }
    }
    if (diag != 0.) {
      cols.emplace_back(row);
      values.emplace_back(diag);
    }
    int info = A->InsertGlobalValues(row, cols.size(), values.data(), cols.data());
    //cout << "info=" << info << endl;
    assert( info==0 );
  }

  // Finish up
  int info = A->FillComplete();
  assert( info==0 );
  A->SetTracebackMode(1); // Shutdown Epetra Warning tracebacks

  //************************************
  // Call the LOBPCG solver manager
  //***********************************
  //  Variables used for the LOBPCG Method
  diag_tick = MPI_Wtime();
  std::string which("LM");
  constexpr int    nev       = 1;
  constexpr int    blockSize = nev;
  //constexpr int    maxIters  = 500;
  //constexpr double tol       = 1.0e-12;

  using MV = Epetra_MultiVector;
  using OP = Epetra_Operator;
  using MVT = Anasazi::MultiVecTraits<double, Epetra_MultiVector>;

  // Create an Epetra_MultiVector for an initial vector to start the solver.
  // Note:  This needs to have the same number of columns as the blocksize.
  Teuchos::RCP<Epetra_MultiVector> ivec = Teuchos::rcp( new Epetra_MultiVector(Map, blockSize) );
  ivec->Random();

  // Create the eigenproblem.
  Teuchos::RCP<BasicEigenproblem<double, MV, OP>> MyProblem =
    Teuchos::rcp( new BasicEigenproblem<double, MV, OP>(A, ivec) );

  // Inform the eigenproblem that the operator A is symmetric
  MyProblem->setHermitian(true);

  // Set the number of eigenvalues requested
  MyProblem->setNEV( nev );

  // Inform the eigenproblem that you are finishing passing it information
  bool boolret = MyProblem->setProblem();
  if (boolret != true) {
    printer.print(Errors,"Anasazi::BasicEigenproblem::setProblem() returned an error.\n");
#ifdef HAVE_MPI
    MPI_Finalize();
#endif
    return -1;
  }

  // Create parameter list to pass into the solver manager
  Teuchos::ParameterList MyPL;
  //std::cout << MyPL.get<std::string>("Which") << std::endl;
  MyPL.set( "Verbosity", Anasazi::Errors | Anasazi::Warnings | Anasazi::IterationDetails | Anasazi::FinalSummary | Anasazi::Debug | Anasazi::OrthoDetails );
  //MyPL.set( "Which", which );
  //MyPL.set( "Block Size", blockSize );
  //MyPL.set( "Maximum Iterations", maxIters );
  //MyPL.set( "Convergence Tolerance", tol );

  // Create the solver manager
  LOBPCGSolMgr<double, MV, OP> MySolverMan(MyProblem, MyPL);

  // Solve the problem
  ReturnType returnCode = MySolverMan.solve();
  end_tick = MPI_Wtime();

  // Get the eigenvalues and eigenvectors from the eigenproblem
  Eigensolution<double,MV> sol = MyProblem->getSolution();
  std::vector<Value<double>> evals = sol.Evals;
  Teuchos::RCP<MV> evecs = sol.Evecs;

  // Compute residuals.
  std::vector<double> normR(sol.numVecs);
  if (sol.numVecs > 0) {
    Teuchos::SerialDenseMatrix<int,double> T(sol.numVecs, sol.numVecs);
    Epetra_MultiVector tempAevec( Map, sol.numVecs );
    T.putScalar(0.0); 
    for (int i=0; i<sol.numVecs; i++) {
      T(i,i) = evals[i].realpart;
    }
    A->Apply( *evecs, tempAevec );
    MVT::MvTimesMatAddMv( -1.0, *evecs, T, 1.0, tempAevec );
    MVT::MvNorm( tempAevec, normR );
  }

  // Print the results
  std::ostringstream os;
  os.setf(std::ios_base::right, std::ios_base::adjustfield);
  os << "Solver manager returned " << (returnCode == Converged ? "converged." : "unconverged.") << std::endl;
  os << std::endl;
  os << "------------------------------------------------------"<< std::endl;
  os << std::setw(16) << "Eigenvalue"
     << std::setw(18) << "Direct Residual"
     << std::endl;
  os<<"------------------------------------------------------" << std::endl;
  for (int i=0; i<sol.numVecs; i++) {
    os<< std::setw(16)<<evals[i].realpart
      << std::setw(18)<<normR[i]/evals[i].realpart
      << std::endl;
  }
  os<<"------------------------------------------------------" << std::endl;
  os << "gen_time = " << diag_tick - gen_tick << std::endl
     << "diag_time = " << end_tick - diag_tick << std::endl;
  rokko::machine_info(os);
  os << "the number of eigenvalues to compute=" << MyProblem->getNEV() << std::endl;
  printer.print(Errors, os.str());

#ifdef HAVE_MPI
  MPI_Finalize();
#endif
  return 0;
}


<|start_filename|>rokko/lapack/solver.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_SOLVER_HPP
#define ROKKO_LAPACK_SOLVER_HPP

#include <rokko/parameters.hpp>
#include <rokko/lapack/diagonalize_syev.hpp>
#include <rokko/lapack/diagonalize_syevd.hpp>
#include <rokko/lapack/diagonalize_syevr.hpp>
#include <rokko/lapack/diagonalize_syevx.hpp>
#include <rokko/lapack/diagonalize_bisection.hpp>
#include <rokko/lapack/diagonalize_qr.hpp>
#include <rokko/lapack/diagonalize_sygv.hpp>
#include <rokko/lapack/diagonalize_sygvd.hpp>
#include <rokko/lapack/diagonalize_sygvx.hpp>
#include <rokko/lapack/diagonalize_bisection_dsygvx.hpp>

namespace rokko {
namespace lapack {

class solver {
public:
  void initialize(int& /* argc */, char**& /* argv */) {}
  void finalize() {}

  // standard eigenvalue problem, only eigenvalues, eigenvalue:VEC&
  template<typename T, int MATRIX_MAJOR, typename VEC>
  parameters diagonalize(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat,
			 VEC& eigvals,
			 parameters const& params);
  // standard eigenvalue problem, eigenvalues/eigenvectors, eigenvalue:VEC&
  template<typename T, int MATRIX_MAJOR, typename VEC>
  parameters diagonalize(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat,
			 VEC& eigvals, Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& eigvecs,
			 parameters const& params);

private:
  //std::string routine_;  // record routine_;
};

// -------------------------standard eigenvalue problem-----------------------------
// standard eigenvalue problem, only eigenvalues
template<typename T, int MATRIX_MAJOR, typename VEC>
parameters solver::diagonalize(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat,
                   VEC& eigvals,
			       parameters const& params) {
  const std::string routine = params.defined("routine") ? params.get_string("routine") : "";

  if (routine=="syev") {
    return rokko::lapack::diagonalize_syev(mat, eigvals, params);
  } else if ((routine=="syevr") || (routine=="mr3")) {
    return rokko::lapack::diagonalize_syevr(mat, eigvals, params);
  } else if ((routine=="syevd") || (routine=="dc")) {
    return rokko::lapack::diagonalize_syevd(mat, eigvals, params);
  } else if (routine=="syevx") {
    return rokko::lapack::diagonalize_syevx(mat, eigvals, params);
  } else if (routine=="bisection") {
    return rokko::lapack::diagonalize_bisection(mat, eigvals, params);
  } else if (routine=="qr") {
    return rokko::lapack::diagonalize_qr(mat, eigvals, params);
  } else if (routine=="") {
    if (lapack::is_interval(params)) {
      return rokko::lapack::diagonalize_syevr(mat, eigvals, params);
    } else {
      return rokko::lapack::diagonalize_syev(mat, eigvals, params);
    }
  } else {
    throw std::invalid_argument("lapack::diagonalize() : " + routine + " is not lapack routine");
  }
}

// standard eigenvalue problem, eigenvalues/eigenvectors
template<typename T, int MATRIX_MAJOR, typename VEC>
parameters solver::diagonalize(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat,
                               VEC& eigvals, Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& eigvecs,
			       parameters const& params) {
  const std::string routine = params.defined("routine") ? params.get_string("routine") : "";

  if (routine=="syev") {
    return rokko::lapack::diagonalize_syev(mat, eigvals, eigvecs, params);
  } else if ((routine=="syevr") || (routine=="mr3")) {
    return rokko::lapack::diagonalize_syevr(mat, eigvals, eigvecs, params);
  } else if ((routine=="syevd") || (routine=="dc")) {
    return rokko::lapack::diagonalize_syevd(mat, eigvals, eigvecs, params);
  } else if (routine=="syevx") {
    return rokko::lapack::diagonalize_syevx(mat, eigvals, eigvecs, params);
  } else if (routine=="bisection") {
    return rokko::lapack::diagonalize_bisection(mat, eigvals, eigvecs, params);
  } else if (routine=="qr") {
    return rokko::lapack::diagonalize_qr(mat, eigvals, eigvecs, params);
  } else if (routine=="") {
    if (is_interval(params)) {
      return rokko::lapack::diagonalize_syevr(mat, eigvals, eigvecs, params);
    } else {
      return rokko::lapack::diagonalize_syev(mat, eigvals, eigvecs, params);
    }
  } else {
    throw std::invalid_argument("lapack::diagonalize() : " + routine + " is not lapack routine");
  }
}

} // namespace lapack
} // namespace rokko

#endif // ROKKO_LAPACK_SOLVER_HPP


<|start_filename|>rokko/utility/xyz_lattice.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2013-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_XYZ_LATTICE_HPP
#define ROKKO_UTILITY_XYZ_LATTICE_HPP

#include <string>
#include <list>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <tuple>

#include <rokko/utility/lattice.hpp>

namespace rokko {

void read_lattice_stream(std::ifstream& ifs, int& num_sites, std::vector<std::pair<int, int>>& lattice, std::vector<std::tuple<double, double, double>>& coupling) {
  std::size_t num_bonds;
  std::istringstream is;
  if (detail::read_line_with_comment(ifs, is)) {
    is >> num_sites >> num_bonds;
  }
  std::cout << "num_sites=" << num_sites << " num_bonds=" << num_bonds << std::endl;

  bool offset1 = detail::read_offset_info(ifs);

  do {
    int j, k;
    if (detail::read_line_with_comment(ifs, is)) {
      is >> j >> k;
      std::cout << "j=" << j << " k=" << k << std::endl;
      if (offset1)  lattice.emplace_back(std::make_pair(j-1, k-1));
      else  lattice.emplace_back(std::make_pair(j, k));
      //std::cout << "back()=" << lattice.back().first << ", " << lattice.back().second << std::endl;
      if ((lattice.back().first < 0) || (lattice.back().first >= num_sites)) {
        throw std::invalid_argument("read_lattice_stream() : first index of " + std::to_string(lattice.size() - 1) + "-th bond \"" + std::to_string(lattice.back().first) + "\" is out of range");
      } else if ((lattice.back().second < 0) || (lattice.back().second >= num_sites)) {
        throw std::invalid_argument("read_lattice_stream() : second index of " + std::to_string(lattice.size() - 1) + "-th bond \"" + std::to_string(lattice.back().second) + "\" is out of range");
      }
    }
  } while (lattice.size() < num_bonds);

  do {
    double jx, jy, jz;
    if (detail::read_line_with_comment(ifs, is)) {
      is >> jx >> jy >> jz;
      std::cout << "jx=" << jx << " jy=" << jy << " jz=" << jz << std::endl;
      coupling.emplace_back(std::make_tuple(jx, jy, jz));
    }
  } while (coupling.size() < num_bonds);
}

void read_lattice_file(std::string const& filename, int& num_sites, std::vector<std::pair<int, int>>& lattice, std::vector<std::tuple<double, double, double>>& coupling) {
  std::ifstream ifs(filename);
  if (!ifs) {
    throw std::runtime_error("read_lattice_file() : can't open file \"" + filename + "\"");
  }
  return read_lattice_stream(ifs, num_sites, lattice, coupling);
}

} // namespace rokko

#endif // ROKKO_UTILITY_XYZ_LATTICE_HPP


<|start_filename|>example/lapack/dlange_f.f90<|end_filename|>
program main
  implicit none
  integer, parameter :: n = 5
  double precision :: a(n, n), norm
  integer :: i, j
  double precision :: dlange
  do j = 1, n
     do i = 1, n
        a(i, j) = n - 0.253D0 * max(i-1, j-1)
     end do
  end do
  print *, "Matrix A: ", n, n
  do j = 1, n
     print *, a(1:n, j)
  end do

  norm = dlange('F', n, n, a, n)
  print *, "norm =", norm
end program main


<|start_filename|>tutorial/titpack/02_refactored_cxx/small.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

// C++ version of TITPACK Ver.2 by <NAME>

#include "small.hpp"
#include <lapacke.h>
#include <iostream>
#include <tuple>

void elm3(hamiltonian const& hop, matrix_type& elemnt) {
  // initialization
  elemnt.resize(hop.dimension(), hop.dimension());
  for (int i = 0; i < hop.dimension(); ++i)
    for (int j = 0; j < hop.dimension(); ++j)
      elemnt(j, i) = 0;

  // elments
  for (int k = 0; k < hop.num_bonds(); ++k) {
    int isite1, isite2;
    std::tie(isite1, isite2) = hop.site_pair(k);
    int is = (1 << isite1) + (1 << isite2);
    double wght = hop.bond_weight(k);
    double diag = 0.5 * wght * hop.z_ratio(k);
    for (int i = 0; i < hop.dimension(); ++i) {
      int ibit = hop.config(i) & is;
      if (ibit == 0 || ibit == is) {
        elemnt(i,i) -= diag;
      } else {
        elemnt(i,i) += diag;
        int newcfg = hop.config2index(hop.config(i) ^ is);
        elemnt(i, newcfg) = -wght;
      }
    }
  }
}

void diag(matrix_type& elemnt, std::vector<double>& E, matrix_type& v, int nvec) {
  if (elemnt.size1() != elemnt.size2()) {
    std::cerr << "diag: Incorrect matrix size\n";
    return;
  }
  int idim = elemnt.size1();
  if (E.size() < idim) E.resize(idim);
  int info = LAPACKE_dsyev(LAPACK_COL_MAJOR, 'V', 'U', idim, &elemnt(0,0), idim, E.data());

  if (v.size1() != idim || v.size2() < nvec) v.resize(idim, nvec);
  for (int j = 0; j < nvec; ++j)
    for (int i = 0; i < idim; ++i)
      v(i, j) = elemnt(i, j);
}

double check3(matrix_type const& elemnt, matrix_type const& x, int xindex) {
  if (elemnt.size1() != elemnt.size2() || elemnt.size2() != x.size1() || x.size2() <= xindex) {
    std::cerr << "check3: Incorrect matrix size\n";
    return 0;
  }
  int idim = elemnt.size1();

  double dnorm = 0;
  for (int j=0; j < idim; ++j) {
    dnorm += x(j, xindex) * x(j, xindex);
  }
  if (dnorm < 1e-30) {
    std::cerr << " #(W18)# Null vector given to check3\n";
    return 0;
  }
  std::vector<double> v(idim, 0);
      
  for (int i = 0; i < idim; ++i)
    for (int j = 0; j < idim; ++j)
      v[i] += elemnt(i, j) * x(j, xindex);

  double prd = 0;
  for (int i = 0; i < idim; ++i) prd += v[i] * x(i, xindex);
  
  std::cout << "---------------------------- Information from check3\n"
            << "<x*H*x> = "<< prd << std::endl
            << "H*x(j)/x(j) (j=min(idim/3,13)-1,idim,max(1,idim/20))";
  int count = 0;
  for (int i = std::min((int)(idim / 3), 13) - 1; i < idim; i += std::max(1,idim/20), ++count) {
    if (count % 4 == 0) std::cout << std::endl;
    std::cout << '\t' << v[i]/x(i, xindex);
  }
  std::cout << std::endl
            << "---------------------------------------------------\n";
  return prd;
}


<|start_filename|>example/cxx/dense/xyz.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/xyz_hamiltonian.hpp>
#include <tuple>
#include <iostream>
#include <fstream>


int main(int argc, char *argv[]) {
  std::string solver_name(rokko::serial_dense_ev::default_solver());
  std::string lattice_file("xyz.dat");
  if (argc >= 2) solver_name = argv[1];
  if (argc >= 3) lattice_file = argv[2];

  std::cout.precision(5);

  std::ifstream ifs(lattice_file);
  if (!ifs) {
    throw std::runtime_error("can't open file \"" + lattice_file + "\"");
  }
  int num_sites, num_bonds;
  std::vector<std::pair<int, int>> lattice;
  std::vector<std::tuple<double, double, double>> coupling;
  ifs >> num_sites >> num_bonds;
  for (int i = 0; i < num_bonds; ++i) {
    int j, k;
    ifs >> j >> k;
    lattice.emplace_back(std::make_pair(j, k));
  }
  for (int i = 0; i < num_bonds; ++i) {
    double jx, jy, jz;
    ifs >> jx >> jy >> jz;
    coupling.emplace_back(std::make_tuple(jx, jy, jz));
  }
  int dim = 1 << num_sites;

  rokko::serial_dense_ev solver(solver_name);
  solver.initialize(argc, argv);
  std::cout << "Eigenvalue decomposition of XYZ model" << std::endl
            << "solver = " << solver_name << std::endl
            << "lattice file = " << lattice_file << std::endl
            << "number of sites = " << num_sites << std::endl
            << "number of bonds = " << num_bonds << std::endl
            << "matrix dimension = " << dim << std::endl;

  Eigen::MatrixXd mat(dim, dim);
  rokko::xyz_hamiltonian::generate(num_sites, lattice, coupling, mat);

  Eigen::VectorXd eigval(dim);
  Eigen::MatrixXd eigvec(dim, dim);
  solver.diagonalize(mat, eigval, eigvec);
  rokko::xyz_hamiltonian::generate(num_sites, lattice, coupling, mat);

  std::cout << "smallest eigenvalues:";
  for (int i = 0; i < std::min(dim, 10); ++i) std::cout << ' ' << eigval(i);
  std::cout << std::endl;
  std::cout << "residual of the smallest eigenvalue/vector: |x A x - lambda| = "
            << std::abs(eigvec.col(0).transpose() * mat * eigvec.col(0) - eigval(0))
            << std::endl;

  solver.finalize();
}


<|start_filename|>rokko/scalapack/descinit.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <rokko/scalapack/scalapack_interface.h>

int cscalapack_descinit(int* desc, int m, int n, int mb, int nb, int irsrc, int icsrc,
                    int ictxt, int lld) {
  int info;
  SCALAPACK_descinit(desc, &m, &n, &mb, &nb, &irsrc, &icsrc, &ictxt, &lld, &info);
  return info;
}


<|start_filename|>example/cxx/sparse/distributed_crs_matrix_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>

int main(int argc, char *argv[]) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  int rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);

  std::string library(rokko::parallel_sparse_ev::default_solver());
  if (argc >= 2) library = argv[1];
  
  constexpr int dim = 4;
  int num_nonzero_cols[] = {2, 1, 2, 1};
  int cols[] = {0, 1, 3, 0, 3, 2};
  double values[] = {7.1, 5.2, 6.4, 0.2, 4.3, 0.5};

  if (rank == 0) std::cout << "[solver = " << library << "]" << std::endl;
  rokko::parallel_sparse_ev solver(library);
  rokko::distributed_crs_matrix mat(solver.default_mapping(dim, rokko::mpi_comm{MPI_COMM_WORLD}), 2);
  int current = 0;
  for (int row = 0; row < dim; ++row) {
    mat.insert(row, num_nonzero_cols[row], &cols[current], &values[current]);
    current += num_nonzero_cols[row];
  }
  mat.complete();
  mat.print();
  
  solver.finalize();
  MPI_Finalize();
}


<|start_filename|>test/generate_matrix/matrix_major.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/eigen3.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/io.hpp>

#include <gtest/gtest.h>

TEST(matrix, major) {
  int dim = 3;

  // M = 1 2 3
  //     4 5 6
  //     7 8 9

  Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> M0(dim,dim); // row major
  M0 << 1,2,3,4,5,6,7,8,9;
  std::cout << M0 << std::endl;
  ASSERT_EQ(M0(0,0),1.0);
  ASSERT_EQ(M0(0,1),2.0);
  ASSERT_EQ(M0(1,0),4.0);
  double* ptr0 = &M0(0,0);
  ASSERT_EQ(*(ptr0 + 1), 2.0); // row major
  ASSERT_EQ((M0.row(0))(1), 2.0);
  ASSERT_EQ((M0.col(0))(1), 4.0);

  Eigen::MatrixXd M1(dim,dim); // column major
  M1 << 1,2,3,4,5,6,7,8,9;
  std::cout << M1 << std::endl;
  ASSERT_EQ(M1(0,0),1.0);
  ASSERT_EQ(M1(0,1),2.0);
  ASSERT_EQ(M1(1,0),4.0);
  double* ptr1 = &M1(0,0);
  ASSERT_EQ(*(ptr1 + 1), 4.0); // column major
  ASSERT_EQ((M1.row(0))(1), 2.0);
  ASSERT_EQ((M1.col(0))(1), 4.0);

  boost::numeric::ublas::matrix<double> M2(dim,dim); // row major
  for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) M2(i,j) = M0(i,j);
  std::cout << M2 << std::endl;
  ASSERT_EQ(M2(0,0),1.0);
  ASSERT_EQ(M2(0,1),2.0);
  ASSERT_EQ(M2(1,0),4.0);
  double* ptr2 = &M2(0,0);
  ASSERT_EQ(*(ptr2 + 1), 2.0); // row major

  boost::numeric::ublas::matrix<double, boost::numeric::ublas::column_major> M3(dim,dim); // column major
  for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) M3(i,j) = M0(i,j);
  std::cout << M3 << std::endl;
  ASSERT_EQ(M3(0,0),1.0);
  ASSERT_EQ(M3(0,1),2.0);
  ASSERT_EQ(M3(1,0),4.0);
  double* ptr3 = &M3(0,0);
  ASSERT_EQ(*(ptr3 + 1), 4.0); // column major

  Eigen::MatrixXd M4(dim, dim); // column major
  for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) M4(i,j) = M0(i,j);
  std::cout << M4 << std::endl;
  ASSERT_EQ(M4(0,0),1.0);
  ASSERT_EQ(M4(0,1),2.0);
  ASSERT_EQ(M4(1,0),4.0);
  double* ptr4 = &M4(0,0);
  ASSERT_EQ(*(ptr4 + 1), 4.0); // column major
}

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}


<|start_filename|>rokko/utility/mpi_vector.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_MPI_VECTOR_HPP
#define ROKKO_UTILITY_MPI_VECTOR_HPP

#include <vector>
#include <rokko/eigen3.hpp>
#include <rokko/distributed_vector.hpp>
#include <rokko/mpi/mpi_type_traits.hpp>

namespace rokko {

class mpi_vector {
public:
  mpi_vector(int dim, MPI_Comm comm_in = MPI_COMM_WORLD) : comm(comm_in) {
    MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);

    divisible = (dim % nprocs) == 0;
    set_num_local_rows(dim);
    set_counts_displacements(dim);
  }

  int get_num_local_rows(int dim, int rank) const {
    return (dim + nprocs - rank - 1) / nprocs;
  }

  int get_num_local_rows(int dim) const {
    return get_num_local_rows(dim, myrank);
  }

  void set_num_local_rows(int dim) {
    num_local_rows = get_num_local_rows(dim);
  }

  void set_counts_displacements(int dim) {
    counts.resize(nprocs);
    displacements.resize(nprocs);
    int offset = 0;
    for (int proc=0; proc<nprocs; ++proc) {
      displacements[proc] = offset;
      counts[proc] = get_num_local_rows(dim, proc);
      offset += counts[proc];
    }
  }

  int get_count() const {
    return counts[myrank];
  }

  int get_displacement() const {
    return displacements[myrank];
  }

  template<typename T, int SIZE>
  void scatter(const Eigen::Vector<T, SIZE>& source,
               Eigen::Vector<T, SIZE>& target, int root) const {
    if (divisible)
      MPI_Scatter(source.data(), num_local_rows, rokko::mpi_type<T>,
                  target.data(), num_local_rows, rokko::mpi_type<T>,
                  root, comm);
    else
      MPI_Scatterv(source.data(), counts.data(), displacements.data(), rokko::mpi_type<T>,
                   target.data(), num_local_rows,rokko::mpi_type<T>,
                   root, comm);
  }

  template<typename T, int SIZE>
  void gather(const Eigen::Vector<T, SIZE>& source,
              Eigen::Vector<T, SIZE>& target, int root) const {
    if (divisible)
      MPI_Gather(source.data(), num_local_rows, rokko::mpi_type<T>,
                 target.data(), num_local_rows, rokko::mpi_type<T>,
                 root, comm);
    else
      MPI_Gatherv(source.data(), num_local_rows, rokko::mpi_type<T>,
                  target.data(), counts.data(), displacements.data(), rokko::mpi_type<T>,
                  root, comm);
  }

  // for distributed_vector
  template<typename T>
  void gather(const rokko::distributed_vector<T>& source, T* target,
              int root) const {
    MPI_Gatherv(source.get_storage(), source.size_local(), rokko::mpi_type<T>,
                target, counts.data(), displacements.data(), rokko::mpi_type<T>,
                root, comm);
  }

  template<typename T, int SIZE>
  void gather(const rokko::distributed_vector<T>& source, Eigen::Vector<T, SIZE>& target, int root) const {
    gather(source, target.data(), root);
  }

  template<typename T>
  void scatter(const T* source, rokko::distributed_vector<T>& target,
               int root) const {
    MPI_Scatterv(source, counts.data(), displacements.data(), rokko::mpi_type<T>,
                 target.get_storage(), target.size_local(), rokko::mpi_type<T>,
                 root, comm);
  }

  template<typename T, int SIZE>
  void scatter(const Eigen::Vector<T, SIZE>& source, rokko::distributed_vector<T>& target, int root) const {
    scatter(source.data(), target, root);
  }

private:
  MPI_Comm comm;
  int myrank, nprocs;
  int num_local_rows;
  std::vector<int> counts, displacements;
  bool divisible;
};

} // namespace rokko

#endif // ROKKO_UTILITY_MPI_VECTOR_HPP


<|start_filename|>rokko/utility/timer.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2010-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTIL_TIMER_HPP
#define ROKKO_UTIL_TIMER_HPP

// You may define the following macros:
//   #define ROKKO_DISABLE_TIMER
//   #define ROKKO_ENABLE_TIMER_TRACE
//   #define ROKKO_ENABLE_TIMER_DETAILED

#include <rokko/utility/string_format.hpp>
#include <rokko/noncopyable.hpp>
#include <fstream>
#include <iostream>
#include <map>
#include <stdexcept>
#include <string>
#include <chrono>
#include <valarray>
#include <vector>

#ifdef __linux
#include <sys/types.h>
#include <unistd.h>
#endif

namespace rokko {

struct timer_id {
  constexpr static int solver_construct = 1;
  constexpr static int solver_initialize = 2;
  constexpr static int solver_finalize = 3;
  constexpr static int diagonalize_initialize = 4;
  constexpr static int diagonalize_diagonalize = 5;
  constexpr static int diagonalize_finalize = 6;
};

namespace detail {

class timer_base {
public:
  constexpr static int detailed = 1 << 0;
  timer_base() {
    #ifdef ROKKO_ENABLE_TIMER_DETAILED
    d_count_ = 0;
    #endif
  }
  void clear() {
    counts_ = 0;
    sums_ = 0;
    #ifdef ROKKO_TRACE_TIMER
    std::clog << "rokko::timer: cleared\n";
    #endif
  }
  void registrate(std::size_t id, std::string const& label, int option = 0) {
    if (label.empty()) {
      std::cerr << "Error: empty label\n";
      throw std::invalid_argument("empty label");
    }
    if (id < labels_.size() && !labels_[id].empty()) {
      std::cerr << "Error: duplicated id: " << id << std::endl;
      throw std::invalid_argument("duplicated id");
    }
    if (id >= labels_.size()) {
      std::size_t old_size = labels_.size();
      std::size_t new_size = std::max(2 * labels_.size(), id + 1);
      labels_.resize(new_size);
      std::valarray<std::chrono::system_clock::time_point> starts_old = starts_;
      std::valarray<double> counts_old = counts_;
      std::valarray<double> sums_old = sums_;
      starts_.resize(new_size);
      counts_.resize(new_size);
      sums_.resize(new_size);
      for (std::size_t i = 0; i < old_size; ++i) {
        starts_[i] = starts_old[i];
        counts_[i] = counts_old[i];
        sums_[i] = sums_old[i];
      }
      #ifdef ROKKO_ENABLE_TIMER_DETAILED
      d_mapping_.resize(new_size, -1);
      #endif
    }
    labels_[id] = label;
    if (option & detailed) {
      #ifdef ROKKO_ENABLE_TIMER_DETAILED
      d_mapping_[id] = d_counts_.size();
      d_counts_.emplace_back(0);
      d_sums_.emplace_back(0);
      #endif
    }
    #ifdef ROKKO_ENABLE_TIMER_TRACE
    std::clog << "rokko::timer: registered timer with id = " << id
              << " and label = \"" << label << "\"\n";
    #endif
  }

  void start(std::size_t id) { // hwm: hardware monitor
    #ifdef ROKKO_ENABLE_TIMER_TRACE
    std::clog << "rokko::timer: starting timer with id = " << id << std::endl;
    #endif
    starts_[id] = std::chrono::system_clock::now();
  }

  void stop(std::size_t id) {
    std::chrono::system_clock::time_point end_ = std::chrono::system_clock::now();
    double t = 1.0e-6 * std::chrono::duration_cast<std::chrono::microseconds>(end_ - starts_[id]).count();
    counts_[id] += 1;
    sums_[id] += t;
    #ifdef ROKKO_ENABLE_TIMER_DETAILED
    if (d_mapping_[id] >= 0) {
      d_counts_[d_mapping_[id]] += 1;
      d_sums_[d_mapping_[id]] += t;
    }
    #endif
    #ifdef ROKKO_ENABLE_TIMER_TRACE
    std::clog << "rokko::timer: stopping timer with id = " << id << std::endl;
    #endif
  }
  std::vector<std::string> const& get_labels() const { return labels_; }
  std::valarray<double> const& get_counts() const { return counts_; }
  std::valarray<double> const& get_measurements() const { return sums_; }

  bool has(std::size_t id) { return (id < labels_.size() && !labels_[id].empty()); }
  std::string const& get_label(std::size_t id) const { return labels_[id]; }
  double get_count(std::size_t id) const { return counts_[id]; }
  double get_measurement(std::size_t id) const { return sums_[id]; }
  double get_average(std::size_t id) const {
    return (counts_[id] > 0 ? sums_[id] / counts_[id] : 0.0);
  }

  std::map<std::string, int> vmem_info() const {
    std::map<std::string, int> vm_info;
// #ifdef __linux
//     vm_info.insert(std::pair<std::string, int>("VmPeak", 0));
//     vm_info.insert(std::pair<std::string, int>("VmHWM", 0));

//     // process file name: /proc/${PID}/status
//     int pid = static_cast<int>(getpid());
//     std::string filename = std::string("/proc/") + std::to_string(pid) +
//       "/status";

//     // open file
//     std::ifstream fin(filename);
//     if (fin.fail()) {
//       std::cerr << "Can't open the file" << std::endl;
//       return vm_info;
//     }

//     // extract process infomation from procfs
//     do {
//       std::string source;
//       getline(fin, source);
//       for (std::map<std::string, int>::iterator ip = vm_info.begin(); ip != vm_info.end(); ++ip) {
//         if (source.substr(0, (ip->first).size()) == ip->first) {
//           std::string mem_size;
//           for (std::string::size_type i = 0; i != source.size(); ++i) {
//             if (isdigit(source[i])) mem_size += source[i];
//           }
//           ip->second = std::stoi(mem_size);
//         }
//       }
//     } while (fin.good());
// #endif
    return vm_info;
  }

  void summarize(std::ostream& os = std::clog) const {
    os << "timer: enabled\n"
#ifdef ROKKO_ENABLE_TIMER_TRACE
       << "timer: trace = enabled\n"
#else
       << "timer: trace = disabled\n"
#endif
#ifdef ROKKO_ENABLE_TIMER_DETAILED
       << "timer: detailed report = enabled"
#else
       << "timer: detailed report = disabled"
#endif
       << std::endl;
    // std::map<std::string, int> vm = vmem_info();
    // for (std::map<std::string, int>::iterator ivm = vm.begin(); ivm != vm.end(); ++ivm) {
    //   os << "timer: " << ivm->first << "   " << ivm->second << " [kB]" << std::endl;
    // }
    for (std::size_t i = 0; i < labels_.size(); ++i) {
      if (counts_[i] > 0) {
        os << rokko::format("timer: %5d %-55s %12.3lf %10ld\n",
                            i, labels_[i].c_str(), sums_[i], counts_[i]);
      }
    }
  }

  void detailed_report(std::size_t interval = 1, std::ostream& os = std::clog) const {
    #ifdef ROKKO_ENABLE_TIMER_DETAILED
    if (d_count_ == 0) {
      os << "timer: interval = " << interval << std::endl;
    }
    if ((d_count_ + 1) % interval == 0) {
      for (std::size_t i = 0; i < labels_.size(); ++i) {
        if (d_mapping_[i] >= 0) {
          os << rokko::format("detail: %d %d %.3f %d\n",
                              d_count_, i, d_sums_[d_mapping_[i]], d_counts_[d_mapping_[i]]);
        }
      }
    }
    ++d_count_;
    std::fill(d_counts_.begin(), d_counts_.end(), 0);
    std::fill(d_sums_.begin(), d_sums_.end(), 0);
    os << std::flush;
    #endif
  }

protected:
  std::vector<std::string> labels_;
  std::valarray<std::chrono::system_clock::time_point> starts_;
  std::valarray<double> counts_, sums_;
  #ifdef ROKKO_ENABLE_TIMER_DETAILED
  mutable int d_count_;
  std::vector<int> d_mapping_;
  mutable std::vector<int> d_counts_;
  mutable std::vector<double> d_sums_;
  #endif
  std::map<std::string, int> vm_info_;
};

class timer_dumb {
public:
  constexpr static int detailed = 0;
  timer_dumb() = default;
  void clear() {}
  void registrate(std::size_t, std::string const&, int = 0) {}
  void start(std::size_t) {}
  void stop(std::size_t) {}
  bool has(std::size_t) { return false; }
  std::string get_label(std::size_t) const { return std::string(); }
  double get_count(std::size_t) const { return 0; }
  double get_measurement(std::size_t) const { return 0; }
  double get_average(std::size_t) const { return 0; }
  std::map<std::string, int> vmem_info() const { return std::map<std::string, int>(); }
  void summarize(std::ostream& = std::clog) const {}
  void detailed_report(std::size_t = 1, std::ostream& = std::clog) const {}
};

} // namespace detail

#ifndef ROKKO_DISABLE_TIMER
using timer = detail::timer_base;
#else
using timer = detail::timer_dumb;
#endif

class global_timer : private rokko::noncopyable<global_timer> {
public:
  constexpr static int detailed = rokko::timer::detailed;
  static void clear() { instance()->clear(); }
  static void registrate(std::size_t id, std::string const& label, int option = 0) {
    instance()->registrate(id, label, option);
  }
  static void start(std::size_t id) { instance()->start(id); }
  static void stop(std::size_t id) { instance()->stop(id); }
  static bool has(std::size_t id) { return instance()->has(id); }
  static std::string get_label(std::size_t id) { return instance()->get_label(id); }
  static double get_count(std::size_t id) { return instance()->get_count(id); }
  static double get_measurement(std::size_t id) { return instance()->get_measurement(id); }
  static double get_average(std::size_t id) { return instance()->get_average(id); }
  static std::map<std::string, int> vmem_info() { return instance()->vmem_info(); }
  static void summarize(std::ostream& os = std::clog) { instance()->summarize(os); }
  static rokko::timer* instance() {
    if (!instance_) instance_ = new rokko::timer;
    return instance_;
  }
private:
  static rokko::timer* instance_;
};

} // namespace rokko

#endif // ROKKO_UTIL_TIMER_HPP


<|start_filename|>rokko/lapack/ungqr.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_UNGQR_HPP
#define ROKKO_LAPACK_UNGQR_HPP

#include <complex>
#ifdef I
# undef I
#endif
#include <stdexcept>
#include <boost/type_traits/is_same.hpp>
#include <lapacke.h>
#include <rokko/traits/value_t.hpp>
#include "complex_cast.hpp"

namespace rokko {
namespace lapack {

namespace {

template<typename T> struct ungqr_dispatch;
  
template<>
struct ungqr_dispatch<float> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int ungqr(int matrix_layout, lapack_int m, lapack_int n, lapack_int k,
                          MATRIX& a, VECTOR& tau) {
    return LAPACKE_sorgqr(matrix_layout, m, n, k, storage(a), ld(a), storage(tau));
  }
  template<typename MATRIX, typename VECTOR>
  static lapack_int ungqr(int matrix_layout, lapack_int m, lapack_int n, lapack_int k,
                          MATRIX& a, VECTOR& tau, VECTOR& work) {
    return LAPACKE_sorgqr(matrix_layout, m, n, k, storage(a), ld(a), storage(tau),
                          storage(work), size(work));
  }
};

template<>
struct ungqr_dispatch<double> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int ungqr(int matrix_layout, lapack_int m, lapack_int n, lapack_int k,
                          MATRIX& a, VECTOR& tau) {
    return LAPACKE_dorgqr(matrix_layout, m, n, k, storage(a), ld(a), storage(tau));
  }
  template<typename MATRIX, typename VECTOR>
  static lapack_int ungqr(int matrix_layout, lapack_int m, lapack_int n, lapack_int k,
                          MATRIX& a, VECTOR& tau, VECTOR& work) {
    return LAPACKE_dorgqr(matrix_layout, m, n, k, storage(a), ld(a), storage(tau),
                          storage(work), size(work));
  }
};

template<>
struct ungqr_dispatch<std::complex<float>> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int ungqr(int matrix_layout, lapack_int m, lapack_int n, lapack_int k,
                          MATRIX& a, VECTOR& tau) {
    return LAPACKE_cungqr(matrix_layout, m, n, k, complex_cast(storage(a)), ld(a),
                          complex_cast(storage(tau)));
  }
  template<typename MATRIX, typename VECTOR>
  static lapack_int ungqr(int matrix_layout, lapack_int m, lapack_int n, lapack_int k,
                          MATRIX& a, VECTOR& tau, VECTOR& work) {
    return LAPACKE_cungqr(matrix_layout, m, n, k, complex_cast(storage(a)), ld(a),
                          complex_cast(storage(tau)), complex_cast(storage(work)),
                          size(work));
  }
};

template<>
struct ungqr_dispatch<std::complex<double>> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int ungqr(int matrix_layout, lapack_int m, lapack_int n, lapack_int k,
                          MATRIX& a, VECTOR& tau) {
    return LAPACKE_zungqr(matrix_layout, m, n, k, complex_cast(storage(a)), ld(a),
                          complex_cast(storage(tau)));
  }
  template<typename MATRIX, typename VECTOR>
  static lapack_int ungqr(int matrix_layout, lapack_int m, lapack_int n, lapack_int k,
                          MATRIX& a, VECTOR& tau, VECTOR& work) {
    return LAPACKE_zungqr(matrix_layout, m, n, k, complex_cast(storage(a)), ld(a),
                          complex_cast(storage(tau)), complex_cast(storage(work)),
                          size(work));
  }
};

}
  
template<typename MATRIX, typename VECTOR>
lapack_int ungqr(lapack_int k, MATRIX& a, VECTOR const& tau) {
  static_assert(std::is_same<value_t<MATRIX>, value_t<VECTOR>>::value, "");
  lapack_int m = rows(a);
  lapack_int n = cols(a);
  if (size(tau) != k)
    throw std::invalid_argument("vector tau size mismatch");
  return ungqr_dispatch<value_t<MATRIX>>
    ::ungqr((is_col_major(a) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR), m, n, k, a, tau);
}

template<typename MATRIX, typename VECTOR>
lapack_int ungqr(lapack_int k, MATRIX& a, VECTOR const& tau, VECTOR& work) {
  static_assert(std::is_same<value_t<MATRIX>, value_t<VECTOR>>::value, "");
  lapack_int m = rows(a);
  lapack_int n = cols(a);
  if (size(tau) != k)
    throw std::invalid_argument("vector tau size mismatch");
  if (size(work) < std::max(1, n))
    throw std::invalid_argument("vector work size mismatch");
  return ungqr_dispatch<value_t<MATRIX>>
    ::ungqr((is_col_major(a) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR), m, n, k, a, tau, work);
}

template<typename MATRIX, typename VECTOR>
lapack_int orgqr(lapack_int k, MATRIX& a, VECTOR const& tau) {
  return ungqr(k, a, tau);
}
  
template<typename MATRIX, typename VECTOR>
lapack_int orgqr(lapack_int k, MATRIX& a, VECTOR const& tau, VECTOR& work) {
  return ungqr(k, a, tau, work);
};
  
} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_UNGQR_HPP


<|start_filename|>test/generate_matrix/laplacian_mfree_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <iostream>
#include <vector>

#include <rokko/rokko.hpp>
#include <rokko/utility/laplacian_matrix.hpp>
#include <rokko/utility/laplacian_mfree.hpp>
#include <rokko/utility/mpi_vector.hpp>

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

TEST(laplacian_mfree, serial_mpi) {
  int myrank, nprocs;
  MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
  MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
  constexpr int root = 0;

  constexpr int N_seq = 20;
  const int N_seq_proc = (myrank == root) ? N_seq : 0;
  Eigen::VectorXd v_seq(N_seq_proc), w_seq(N_seq_proc), w_gather(N_seq_proc);

  rokko::laplacian_mfree op(N_seq);
  const int N = op.get_num_local_rows();
  Eigen::VectorXd v(N), w(N);

  rokko::mpi_vector mpi(N_seq);

  for (int i=0; i<N_seq; ++i) {
    if (myrank == root) {
      v_seq.setZero();
      v_seq(i) = 1;
      w_seq.setZero();
      rokko::laplacian_matrix::multiply(N_seq, v_seq.data(), w_seq.data());
    }

    // MPI version
    mpi.scatter(v_seq, v, root);
    w.setZero();
    op.multiply(v.data(), w.data());
    for (int proc=0; proc<nprocs; ++proc) {
      if (proc == myrank) {
        std::cout << "myrank=" << myrank << std::endl;
        std::cout << w.transpose() << std::endl;
      }
      MPI_Barrier(MPI_COMM_WORLD);
    }

    mpi.gather(w, w_gather, root);
    if (myrank == root) {
      std::cout << "i=" << i << std::endl;
      std::cout << "w_seq=" << w_seq.transpose() << std::endl;
      std::cout << "w_gather=" << w_gather.transpose() << std::endl;
      ASSERT_TRUE(w_seq == w_gather);
    }
  }
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>tutorial/titpack/02_refactored_cxx/subspace.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include "subspace.hpp"
#include <iostream>
#include <cstdlib>

subspace::subspace(int n, double szval) : n_(n), list1_(), list2_() {
  if (szval < -1e-13 || szval > (n/2 - 1 + 1e-13)) {
    std::cerr << " #(E01)# Variable szval given to sz out of range\n";
    std::abort();
  }
  
  // initialization
  int ihf = (n + 1) / 2;
  ihfbit_ = 1 << ihf;
  irght_ = ihfbit_ - 1;
  ilft_ = ((1 << n) - 1) ^ irght_;
  int iupspn = n / 2 + (n % 2) + (int)(szval + 0.001);
  
  list2_.resize(std::max(1 << ihf, 1 << (n - ihf)));

  // main loop
  int icnt = 0;
  int ja = 0;
  int jb = 0;
  int ibpatn = 0;
  for (int i = 0; i < (1 << n); ++i) {
    int isz = 0;
    for (int j = 0; j < n; ++j) {
      isz += (i >> j) & 1;
    }
    if (isz == iupspn) {
      list1_.emplace_back(i);
      int ia = i & irght_;
      int ib = (i & ilft_) / ihfbit_;
      if (ib == ibpatn) {
        list2_[ia].first = ja;
        list2_[ib].second = jb;
      } else {
        ibpatn = ib;
        ja = 0;
        jb = icnt;
        list2_[ia].first = ja;
        list2_[ib].second = jb;
      }
      ++ja;
      ++icnt;
    }
  }
}


<|start_filename|>rokko/pyrokko_communicator.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_COMMUNICATOR_HPP
#define PYROKKO_COMMUNICATOR_HPP

#include <mpi4py/mpi4py.h>

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#include <rokko/mpi_communicator.hpp>

namespace rokko {

namespace py = pybind11;

MPI_Comm to_MPI_Comm() {
  const int rc = import_mpi4py();
  assert(rc==0);
  return MPI_COMM_WORLD;
}

MPI_Comm to_MPI_Comm(pybind11::handle const& comm_handle) {
  const int rc = import_mpi4py();
  assert(rc==0);
  return *PyMPIComm_Get(comm_handle.ptr());
}

class wrap_communicator : public mpi_comm {
public:
  using mpi_comm::mpi_comm;
  wrap_communicator(pybind11::handle const& comm_handle) {
    set_comm(to_MPI_Comm(comm_handle));
  }
};

} // end namespace rokko

#endif // PYROKKO_COMMUNICATOR_HPP


<|start_filename|>test/c/solver.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.h>
#if defined(ROKKO_HAVE_MPI)
# include <mpi.h>
#endif
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv) {
  int i, n;
  char** solver_names;

  n = rokko_serial_dense_ev_num_solvers();
  solver_names = rokko_serial_dense_ev_solvers();
  struct rokko_serial_dense_ev solver_sd;
  for (i = 0; i < n; ++i) {
    printf("%s\n", solver_names[i]);
    rokko_serial_dense_ev_construct(&solver_sd, solver_names[i], argc, argv);
    rokko_serial_dense_ev_destruct(&solver_sd);
  }
  for (i = 0; i < n; ++i) free(solver_names[i]);
  free(solver_names);

#if defined(ROKKO_HAVE_MPI)
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);

#if defined(ROKKO_HAVE_PARALLEL_DENSE_SOLVER)
  n = rokko_parallel_dense_ev_num_solvers();
  solver_names = rokko_parallel_dense_ev_solvers();
  struct rokko_parallel_dense_ev solver_pd;
  for (i = 0; i < n; ++i) {
    printf("%s\n", solver_names[i]);
    rokko_parallel_dense_ev_construct(&solver_pd, solver_names[i], argc, argv);
    rokko_parallel_dense_ev_destruct(&solver_pd);
  }
  for (i = 0; i < n; ++i) free(solver_names[i]);
  free(solver_names);
#endif

#if defined(ROKKO_HAVE_PARALLEL_SPARSE_SOLVER)
  n = rokko_parallel_sparse_ev_num_solvers();
  solver_names = rokko_parallel_sparse_ev_solvers();
  struct rokko_parallel_sparse_ev solver_ps;
  for (i = 0; i < n; ++i) {
    printf("%s\n", solver_names[i]);
    rokko_parallel_sparse_ev_construct(&solver_ps, solver_names[i], argc, argv);
    rokko_parallel_sparse_ev_destruct(&solver_ps);
  }
  for (i = 0; i < n; ++i) free(solver_names[i]);
  free(solver_names);
#endif

  MPI_Finalize();

#endif // ROKKO_HAVE_MPI
}


<|start_filename|>rokko/scalapack/psyev.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <stdlib.h>
#include <rokko/scalapack/scalapack_interface.h>

#define CSCALAPACK_PSYEV_IMPL(NAMES, NAMEL, TYPE, TYPE_REAL) \
int cscalapack_ ## NAMES (char jobz, char uplo, int n, \
                          TYPE* A, int ia, int ja, const int* descA, \
                          TYPE_REAL* w, TYPE* Z, int iz, int jz, const int* descZ) { \
  /* call for querying optimal size of work array */ \
  int lwork = -1; \
  TYPE work_query[1]; \
  int info; \
  info = cscalapack_## NAMES ##_work(jobz, uplo, n, A, ia, ja, descA, w, Z, iz, jz, descZ, \
                                     work_query, lwork); \
  if (info) return info; \
  \
  /* allocate work array */ \
  lwork = (int)work_query[0]; \
  TYPE* work = (TYPE*)malloc(sizeof(TYPE) * lwork); \
  if (work == NULL) return 1; \
  \
  /* call for computation */ \
  info = cscalapack_ ## NAMES ## _work(jobz, uplo, n, A, ia, ja, descA, w, Z, iz, jz, descZ, \
                                       work, lwork); \
  free(work); \
  return info; \
}

CSCALAPACK_PSYEV_IMPL(pssyev, PSSYEV, float, float)
CSCALAPACK_PSYEV_IMPL(pdsyev, PDSYEV, double, double)
CSCALAPACK_PSYEV_IMPL(pcheev, PCHEEV, lapack_complex_float, float)
CSCALAPACK_PSYEV_IMPL(pzheev, PZHEEV, lapack_complex_double, double)

#undef CSCALAPACK_PSYEV_IMPL


<|start_filename|>test/generate_matrix/trace_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/grid.hpp>
#include <rokko/solver.hpp>
#include <rokko/distributed_matrix.hpp>
#include <rokko/utility/minij_matrix.hpp>

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

template <typename T, typename MATRIX_MAJOR>
void test_trace(rokko::mapping_bc<MATRIX_MAJOR> const& map) {
  constexpr int root_proc = 0;
  auto const& g = map.get_grid();
  const int dim = map.get_m_global();

  rokko::distributed_matrix<T,MATRIX_MAJOR> mat(map);
  rokko::minij_matrix::generate(mat);
  const T trace_mat = trace(mat);

  if (g.get_myrank() == root_proc) {
    ASSERT_EQ(trace_mat, static_cast<T>(dim * (dim+1) / 2));
  }
}

TEST(generate_matrix, minij_mpi) {
  constexpr int dim = 1000;
  rokko::grid g(MPI_COMM_WORLD);

  for(auto const& name : rokko::parallel_dense_ev::solvers()) {
    rokko::parallel_dense_ev solver(name);
    solver.initialize(global_argc, global_argv);
    rokko::mapping_bc<rokko::matrix_col_major> map = solver.default_mapping(dim, g);

    test_trace<double>(map);
    test_trace<float>(map);
    test_trace<int>(map);

    solver.finalize();
  }
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>rokko/utility/xyz_hamiltonian.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_XYZ_HAMILTONIAN_HPP
#define ROKKO_UTILITY_XYZ_HAMILTONIAN_HPP

#include <vector>
#include <tuple>
#include <rokko/eigen3.hpp>

namespace rokko {

namespace xyz_hamiltonian {

template<typename T>
void multiply(int L, const std::vector<std::pair<int, int>>& lattice,
  const std::vector<std::tuple<double, double, double>>& coupling, const T* v, T* w) {
  int N = 1 << L;
  for (std::size_t l = 0; l < lattice.size(); ++l) {
    int i = lattice[l].first;
    int j = lattice[l].second;
    double jx = std::get<0>(coupling[l]);
    double jy = std::get<1>(coupling[l]);
    double jz = std::get<2>(coupling[l]);

    double diag_plus = jz / 4.0;
    double diag_minus = - jz / 4.0;
    double offdiag_plus = (jx + jy) / 4.0;
    double offdiag_minus = (jx - jy) / 4.0;

    int m1 = 1 << i;
    int m2 = 1 << j;
    int m3 = m1 + m2;
    for (int k=0; k<N; ++k) {
      if (((k & m3) == m1) || ((k & m3) == m2)) {
        // when (bit i == 1, bit j == 0) or (bit i == 0, bit j == 1)
        w[k] += diag_minus * v[k] + offdiag_plus * v[k^m3];
      } else {
        w[k] += diag_plus * v[k] + offdiag_minus * v[k^m3];
      }
    }
  }
}

template<typename T>
void multiply(int L, const std::vector<std::pair<int, int>>& lattice,
  const std::vector<std::tuple<double, double, double>>& coupling, const std::vector<T>& v,
  std::vector<T>& w) {
  multiply(L, lattice, coupling, v.data(), w.data());
}

template<typename T>
void multiply(int L, const std::vector<std::pair<int, int>>& lattice,
  const std::vector<std::tuple<double, double, double>>& coupling, const Eigen::Vector<T>& v,
  Eigen::Vector<T>& w) {
  multiply(L, lattice, coupling, v.data(), w.data());
}

template<typename T>
void fill_diagonal(int L, const std::vector<std::pair<int, int>>& lattice,
  const std::vector<std::tuple<double, double, double>>& coupling, T* w) {
  int N = 1 << L;
  for (int k=0; k<N; ++k) {
    w[k] = 0;
  }
  for (std::size_t l = 0; l < lattice.size(); ++l) {
    int i = lattice[l].first;
    int j = lattice[l].second;
    double jz = std::get<2>(coupling[l]); // jx and jy are unused

    double diag_plus = jz / 4.0;
    double diag_minus = - jz / 4.0;

    int m1 = 1 << i;
    int m2 = 1 << j;
    int m3 = m1 + m2;
    for (int k=0; k<N; ++k) {
      if (((k & m3) == m1) || ((k & m3) == m2)) {
        // when (bit i == 1, bit j == 0) or (bit i == 0, bit j == 1)
        w[k] += diag_minus;
      } else {
        w[k] += diag_plus;
      }
    }
  }
}

template<typename T>
void fill_diagonal(int L, const std::vector<std::pair<int, int>>& lattice,
  const std::vector<std::tuple<double, double, double>>& coupling, std::vector<T>& w) {
  fill_diagonal(L, lattice, coupling, w.data());
}

template<typename T>
void fill_diagonal(int L, const std::vector<std::pair<int, int>>& lattice,
  const std::vector<std::tuple<double, double, double>>& coupling, Eigen::Vector<T>& w) {
  fill_diagonal(L, lattice, coupling, w.data());
}

template<typename T, int MATRIX_MAJOR>
void generate(int L, const std::vector<std::pair<int, int>>& lattice,
  const std::vector<std::tuple<T, T, T>>& coupling,
  Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mat) {
  mat.setZero();
  int N = 1 << L;
  for (std::size_t l = 0; l < lattice.size(); ++l) {
    int i = lattice[l].first;
    int j = lattice[l].second;
    double jx = std::get<0>(coupling[l]);
    double jy = std::get<1>(coupling[l]);
    double jz = std::get<2>(coupling[l]);
    double diag_plus = jz / 4.0;
    double diag_minus = - jz/ 4.0;
    double offdiag_plus = (jx + jy) / 4.0;
    double offdiag_minus = (jx - jy) / 4.0;

    int m1 = 1 << i;
    int m2 = 1 << j;
    int m3 = m1 + m2;
    for (int k=0; k<N; ++k) {
      if (((k & m3) == m1) || ((k & m3) == m2)) {
        // when (bit i == 1, bit j == 0) or (bit i == 0, bit j == 1)
        mat(k^m3, k) += offdiag_plus;
        mat(k, k) += diag_minus;
      } else {
        mat(k^m3, k) += offdiag_minus;
        mat(k, k) += diag_plus;
      }
    }
  }
}

} // namespace xyz_hamiltonian

} // namespace rokko

#endif // ROKKO_UTILITY_XYZ_HAMILTONIAN_HPP


<|start_filename|>example/fortran/dense/frank_cartesian_comm_mpi.f90<|end_filename|>
!*****************************************************************************
!
! Rokko: Integrated Interface for libraries of eigenvalue decomposition
!
! Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
!
! 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)
!
!*****************************************************************************

program frank_matrix
  use rokko
  use various_mpi_comm_mod
  implicit none
  integer :: dim
  type(rokko_distributed_matrix) :: mat, Z
  type(rokko_grid) :: grid
  type(rokko_mapping_bc) :: map
  type(rokko_parallel_dense_ev) :: solver
  type(rokko_eigen_vector) :: w
  character(len=:), allocatable :: library, routine
  character(len=:), allocatable :: library_routine, tmp_str
  integer :: comm
  integer :: provided, ierr, myrank, nprocs
  integer :: i
  
  call MPI_init_thread(MPI_THREAD_MULTIPLE, provided, ierr)
  call MPI_comm_rank(MPI_COMM_WORLD, myrank, ierr)
  call MPI_comm_size(MPI_COMM_WORLD, nprocs, ierr)
  comm = create_cart_comm(mpi_comm_world)

  if (comm /= MPI_COMM_NULL) then
     if (command_argument_count() >= 1) then
        call get_command_argument_deferred(1, library_routine)
     else
        library_routine = rokko_parallel_dense_ev_default_solver()
     endif
     call rokko_split_solver_name(library_routine, library, routine)
     
     if (command_argument_count() == 2) then
        call get_command_argument_deferred(2, tmp_str)
        read(tmp_str, *) dim
     else
        dim = 10
     endif

     if (myrank == 0) then
        print *,"library = ", library
        print *,"routine = ", routine
        print *,"dimension = ", dim
     endif
     
     call rokko_construct(solver, library)
     call rokko_construct(grid, comm, rokko_grid_row_major)
     call rokko_default_mapping(solver, dim, grid, map)
     call rokko_construct(mat, map)
     call rokko_construct(Z, map)
     call rokko_construct(w, dim)

     if (myrank == 0) then
        write(*,'("Created ", i0, "x", i0, " size communicator with new cartesian topology")') &
             & rokko_get_nprow(grid), rokko_get_npcol(grid)
     endif

     ! generate frank matrix
     call rokko_frank_matrix_generate(mat)
     call rokko_print(mat)
     
     call rokko_diagonalize(solver, mat, w, Z)
     
     if (myrank.eq.0) then
        write(*,'(A)') "Computed Eigenvalues = "
        do i = 1, dim
           write(*,"(f30.20)") rokko_get_elem(w, i)
        enddo
     endif
     
     call rokko_destruct(mat)
     call rokko_destruct(Z)
     call rokko_destruct(w)
     call rokko_destruct(solver)
     call rokko_destruct(map)
     call rokko_destruct(grid)
     
     call mpi_comm_free(comm, ierr)
  endif
  call MPI_finalize(ierr)
end program frank_matrix


<|start_filename|>rokko/utility/pyrokko_solver_name.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_UTILITY_SOLVER_NAME_HPP
#define PYROKKO_UTILITY_SOLVER_NAME_HPP

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/numpy.h>
#include <pybind11/eigen.h>

#include <rokko/utility/solver_name.hpp>

namespace rokko {

namespace py = pybind11;

std::tuple<std::string,std::string> wrap_split_solver_name(std::string const& str) {
  std::string library, routine;
  split_solver_name(str, library, routine);
  return std::tuple<std::string,std::string>(library, routine);
}

} // end namespace rokko

#endif // PYROKKO_UTILITY_SOLVER_NAME_HPP


<|start_filename|>rokko/eigenexa/eigen_free.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/ceigenexa.h>
#include <rokko/eigenexa/eigenexa_interface.h>

void ceigenexa_free(void) { EIGENEXA_free_wrap0(); }

void ceigenexa_free1(int flag) { EIGENEXA_free_wrap1(&flag); }


<|start_filename|>rokko/lapack/diagonalize_tridiagonal_matrix_bisection.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_DIAGONALIZE_TRIDIAGONALIZED_MATRIX_BISECTION_HPP
#define ROKKO_LAPACK_DIAGONALIZE_TRIDIAGONALIZED_MATRIX_BISECTION_HPP

#include <rokko/parameters.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/utility/timer.hpp>
#include <rokko/lapack.hpp>
#include <rokko/lapack/diagonalize_get_parameters.hpp>
#include <rokko/lapack/stebz.hpp>
#include <rokko/lapack/stein.hpp>

namespace rokko {
namespace lapack {

// eigenvalues / eigenvectors
template<typename VEC, typename T, int MATRIX_MAJOR>
parameters diagonalize_bisection(VEC& alpha, VEC& beta,
			      VEC& eigvals,
			      Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& eigvecs,
			      parameters const& params) {
  // calculating eigenvalues
  int num_conv;
  const int dim = alpha.size();
  eigvals.resize(dim);
  constexpr T abstol = 0.;
  int il = dim, iu = dim;
  int nsplit;
  Eigen::VectorXi iblock(dim), isplit(dim);
  int info = rokko::lapack::stebz('E', il, iu, abstol, alpha, beta, num_conv, nsplit, eigvals, iblock, isplit);

  // calculating eigenvectors
  eigvecs.resize(dim, num_conv);
  Eigen::VectorXi ifailv(num_conv);
  info = rokko::lapack::stein(alpha, beta, num_conv, eigvals, eigvecs, iblock, isplit, ifailv);

  rokko::parameters params_out;
  params_out.set("num_conv", num_conv);
  params_out.set("info", info);
  if (info) {
    std::cerr << "error at stein function. info=" << info  << std::endl;
  }

  return params_out;
}

} // namespace lapack
} // namespace rokko

#endif // ROKKO_LAPACK_DIAGONALIZE_TRIDIAGONALIZED_MATRIX_BISECTION_HPP


<|start_filename|>rokko/scalapack/pstein.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_PSTEIN_HPP
#define ROKKO_SCALAPACK_PSTEIN_HPP

#include <lapacke.h>
#include <rokko/cscalapack.h>
#include <rokko/eigen3.hpp>
#include <rokko/lapack/storage.hpp>
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>

namespace rokko {
namespace scalapack {

using rokko::lapack::storage;

namespace {

inline int pstein_dispatch(int n, const double* d, const double* e, int m,
                           double* w, const int* iblock, const int* isplit, double orfac,
                           double* Z, const int* iZ, const int* jZ, const int* descZ,
                           int* ifail, int* iclustr, double* gap) {
  return cscalapack_pdstein(n, d, e, m,
                            w, iblock, isplit, orfac,
                            Z, iZ, jZ, descZ,
                            ifail, iclustr, gap);
}

} // end of anonymous namespace

template<typename MATRIX, typename VECTOR, typename VECTOR_INT>
int pstein(const VECTOR& d, const VECTOR& e, int& m,
           VECTOR& w, const VECTOR_INT& iblock, const VECTOR_INT& isplit, double orfac,
           MATRIX& z,
           VECTOR_INT& ifail, VECTOR_INT& iclustr, VECTOR& gap) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR>>::value, "");
  lapack_int n = size(d);
  const int* descZ = z.get_mapping().get_blacs_descriptor().data();

  return pstein_dispatch(n, storage(d), storage(e), m,
                         storage(w), storage(iblock), storage(isplit), orfac,
                         z.get_array_pointer(), 0, 0, descZ,
                         storage(ifail), storage(iclustr), storage(gap));
}

} // end namespace scalapack
} // end namespace rokko

#endif // ROKKO_SCALAPACK_PSTEIN_HPP


<|start_filename|>tutorial/titpack/01_lapack_cxx/small.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

// C++ version of TITPACK Ver.2 by <NAME>

#ifndef TITPACK_SMALL_HPP
#define TITPACK_SMALL_HPP

#include "common.hpp"
#include <vector>

//
// matrix elements
//

void elm3(int n, std::vector<int> const& ipair, std::vector<double> const& bondwt,
          std::vector<double> const& zrtio, matrix_type& elemnt,
          std::vector<int> const& list1, std::vector<std::pair<int, int>> const& list2);
// n           @ lattice size
// ipair       @ pairs of sites connected by bonds
// bondwt      @ exchange interaction of each bond Jxy
// zrtio       @ ratio of Jz to Jxy
// elemnt      # matrix elementsle
// list1,list2 @ spin configurations generated in 'sz'

//
// eigenvalues of a small matrix
//

void diag(matrix_type& elemnt, std::vector<double>& E, matrix_type& v, int nvec);
// elemnt      @ matrix elements
// E           # eigenvalues
// v           # eigenvector
// ne          @ number of eigenvalues to calculate
// nvec        @ number of eigenvectors to calculate

//
// check of the eigenvector and eigenvalue
//

double check3(matrix_type const& elemnt, matrix_type const& x, int xindex);
// elemnt    @ nonzero elements
// x         @ eigenvector to be checked
// xindex
// return value: Hexpec <x*H*x>

#endif


<|start_filename|>rokko/anasazi/anasazi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/parallel_sparse_ev.hpp>
#include <rokko/anasazi/solver.hpp>
#include <rokko/anasazi/mapping_1d.hpp>
#include <rokko/anasazi/distributed_crs_matrix.hpp>

ROKKO_REGISTER_PARALLEL_SPARSE_SOLVER(rokko::anasazi::solver, "anasazi", 40)

ROKKO_REGISTER_PARALLEL_SPARSE_MAPPING_1D(rokko::anasazi::mapping_1d, "anasazi", 40)

ROKKO_REGISTER_PARALLEL_SPARSE_CRS(rokko::anasazi::distributed_crs_matrix, "anasazi", 40)


<|start_filename|>rokko/cscalapack.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_CSCALAPACK_H
#define ROKKO_CSCALAPACK_H

#include <rokko/config.h>
#include <lapacke.h>

#ifdef __cplusplus
extern "C" {
#endif

int cscalapack_descinit(int* desc, int m, int n, int mb, int nb, int irsrc, int icsrc,
                        int ictxt, int lld);

int cscalapack_indxg2p(int indxglob, int nb, int iproc, int isrcproc, int nprocs);
  
int cscalapack_numroc(int n, int nb, int iproc, int isrcproc, int nprocs);

double cscalapack_pdelget(char scope, char top, const double* A, int ia, int ja, const int* descA);

void cscalapack_pdelset(double* A, int ia, int ja, const int* descA, double alpha);

double cscalapack_pdlamch(int icnt, char cmch);

double cscalapack_pdlange(char norm, int m, int n, const double* A, const int* descA);

double cscalapack_pdlange_work(char norm, int m, int n, const double* A, const int* descA,
                               double* work);

void cscalapack_pdlaprnt(int m, int n, const double* A, int ia, int ja, const int* descA,
                         int irprnt, int icprnt, const char* cmatnm, int nout, double* work);

#define CSCALAPACK_PSYEV_DECL(NAMES, NAMEL, TYPE, TYPE_REAL) \
int cscalapack_ ## NAMES ## _work (char jobz, char uplo, int n, \
                                   TYPE* A, int ia, int ja, const int* descA, \
                                   TYPE_REAL* w, TYPE* Z, int iz, int jz, const int* descZ, \
                                   TYPE* work, int lwork); \
int cscalapack_ ## NAMES (char jobz, char uplo, int n, \
                          TYPE* A, int ia, int ja, const int* descA, \
                          TYPE_REAL* w, TYPE* Z, int iz, int jz, const int* descZ);

CSCALAPACK_PSYEV_DECL(pssyev, PSSYEV, float, float);
CSCALAPACK_PSYEV_DECL(pdsyev, PDSYEV, double, double);
CSCALAPACK_PSYEV_DECL(pcheev, PCHEEV, lapack_complex_float, float);
CSCALAPACK_PSYEV_DECL(pzheev, PZHEEV, lapack_complex_double, double);

#undef CSCALAPACK_PSYEV_DECL


#define CSCALAPACK_PSYEVD_DECL(NAMES, NAMEL, TYPE, TYPE_REAL) \
int cscalapack_ ## NAMES ## _work (char jobz, char uplo, int n, \
                                   TYPE* A, int ia, int ja, const int* descA, \
                                   TYPE_REAL* w, TYPE* Z, int iz, int jz, const int* descZ, \
                                   TYPE* work, int lwork, int* iwork, int liwork); \
int cscalapack_ ## NAMES (char jobz, char uplo, int n, \
                          TYPE* A, int ia, int ja, const int* descA, \
                          TYPE_REAL* w, TYPE* Z, int iz, int jz, const int* descZ);

CSCALAPACK_PSYEVD_DECL(pssyevd, PSSYEVD, float, float);
CSCALAPACK_PSYEVD_DECL(pdsyevd, PDSYEVD, double, double);
CSCALAPACK_PSYEVD_DECL(pcheevd, PCHEEVD, lapack_complex_float, float);
CSCALAPACK_PSYEVD_DECL(pzheevd, PZHEEVD, lapack_complex_double, double);

#undef CSCALAPACK_PSYEVD_DECL


#define CSCALAPACK_PSYEVX_DECL(NAMES, NAMEL, TYPE, TYPE_REAL) \
int cscalapack_ ## NAMES ## _work(char jobz, char range, char uplo, int n, \
                                  TYPE* A, int ia, int ja, const int* descA, \
                                  TYPE_REAL vl, TYPE_REAL vu, int il, int iu, \
                                  TYPE_REAL abstol, int* m, int* nZ, TYPE_REAL* w, TYPE_REAL orfac, \
                                  TYPE* Z, int iz, int jz, const int* descZ, \
                                  TYPE* work, int lwork, int* iwork, int liwork, \
                                  int* ifail, int* iclustr, TYPE_REAL* gap); \
int cscalapack_ ## NAMES (char jobz, char range, char uplo, int n, \
                          TYPE* A, int ia, int ja, const int* descA, \
                          TYPE_REAL vl, TYPE_REAL vu, int il, int iu, \
                          TYPE_REAL abstol, int* m, int* nZ, TYPE_REAL* w, TYPE_REAL orfac, \
                          TYPE* Z, int iz, int jz, const int* descZ, \
                          int* ifail, int* iclustr, TYPE_REAL* gap);

CSCALAPACK_PSYEVX_DECL(pssyevx, PSSYEVX, float, float);
CSCALAPACK_PSYEVX_DECL(pdsyevx, PDSYEVX, double, double);
CSCALAPACK_PSYEVX_DECL(pcheevx, PCHEEVX, lapack_complex_float, float);
CSCALAPACK_PSYEVX_DECL(pzheevx, PZHEEVX, lapack_complex_double, double);

#undef CSCALAPACK_PSYEVX_DECL


#ifdef ROKKO_HAVE_SCALAPACK_PDSYEVR
#define CSCALAPACK_PSYEVR_DECL(NAMES, NAMEL, TYPE, TYPE_REAL) \
int cscalapack_## NAMES ##_work(char jobz, char range, char uplo, int n, \
                                TYPE* A, int ia, int ja, const int* descA, \
                                TYPE_REAL vl, TYPE_REAL vu, int il, int iu, \
                                int* m, int* nz, \
                                TYPE_REAL* w, TYPE* Z, int iz, int jz, const int* descZ, \
                                TYPE* work, int lwork, int* iwork, int liwork); \
int cscalapack_## NAMES (char jobz, char range, char uplo, int n, \
                         TYPE* A, int ia, int ja, const int* descA, \
                         TYPE_REAL vl, TYPE_REAL vu, int il, int iu, \
                         int* m, int* nz, \
                         TYPE_REAL* w, TYPE* Z, int iz, int jz, const int* descZ);

CSCALAPACK_PSYEVR_DECL(pssyevr, PSSYEVR, float, float);
CSCALAPACK_PSYEVR_DECL(pdsyevr, PDSYEVR, double, double);
CSCALAPACK_PSYEVR_DECL(pcheevr, PCHEEVR, lapack_complex_float, float);
CSCALAPACK_PSYEVR_DECL(pzheevr, PZHEEVR, lapack_complex_double, double);

#undef CSCALAPACK_PSYEVR_DECL
#endif

float cscalapack_pselget(char scope, char top, const float* A, int ia, int ja, const int* descA);

void cscalapack_pselset(float* A, int ia, int ja, const int* descA, float alpha);

float cscalapack_pslamch(int icnt, char cmch);

float cscalapack_pslange(char norm, int m, int n, const float* A, const int* descA);

float cscalapack_pslange_work(char norm, int m, int n, const float* A, const int* descA,
                              float* work);

void cscalapack_pslaprnt(int m, int n, const float* A, int ia, int ja, const int* descA,
                         int irprnt, int icprnt, const char* cmatnm, int nout, float* work);

#define CSCALAPACK_PSTEBZ_DECL(NAMES, NAMEL, TYPE) \
int cscalapack_## NAMES ##_work(int ictxt, char range, char order, int n, \
                                TYPE vl, TYPE vu, int il, int iu, \
                                TYPE abstol, const TYPE* d, const TYPE* e, int* m, int* nsplit, \
                                TYPE* w, int* iblock, int* isplit, \
                                TYPE* work, int lwork, int* iwork, int liwork); \
int cscalapack_## NAMES (int ictxt, char range, char order, int n, \
                         TYPE vl, TYPE vu, int il, int iu, \
                         TYPE abstol, const TYPE* d, const TYPE* e, int* m, int* nsplit, \
                         TYPE* w, int* iblock, int* isplit);

CSCALAPACK_PSTEBZ_DECL(psstebz, PSSTEBZ, float);
CSCALAPACK_PSTEBZ_DECL(pdstebz, PDSTEBZ, double);

#undef CSCALAPACK_PSTEBZ_DECL


#define CSCALAPACK_PSTEIN_DECL(NAMES, NAMEL, TYPE, TYPE_REAL) \
int cscalapack_## NAMES ##_work(int n, const TYPE_REAL* d, const TYPE_REAL* e, int m, \
                                TYPE_REAL* w, const int* iblock, const int* isplit, TYPE_REAL orfac, \
                                TYPE* Z, const int* iZ, const int* jZ, const int* descZ, \
                                TYPE* work, int lwork, int* iwork, int liwork, \
                                int* ifail, int* iclustr, TYPE_REAL* gap); \
int cscalapack_## NAMES (int n, const TYPE_REAL* d, const TYPE_REAL* e, int m, \
                         TYPE_REAL* w, const int* iblock, const int* isplit, TYPE_REAL orfac, \
                         TYPE* Z, const int* iZ, const int* jZ, const int* descZ, \
                         int* ifail, int* iclustr, TYPE_REAL* gap);

CSCALAPACK_PSTEIN_DECL(psstein, PSSTEIN, float, float);
CSCALAPACK_PSTEIN_DECL(pdstein, PDSTEIN, double, double);
CSCALAPACK_PSTEIN_DECL(pcstein, PCSTEIN, lapack_complex_float, float);
CSCALAPACK_PSTEIN_DECL(pzstein, PZSTEIN, lapack_complex_double, double);

#undef CSCALAPACK_PSTEIN_DECL


#define CSCALAPACK_PSTEDC_DECL(NAMES, NAMEL, TYPE) \
int cscalapack_## NAMES ##_work(char compz, int n, TYPE* d, TYPE* e, \
                                TYPE* Q, int iq, int jq, const int* descQ, \
                                TYPE* work, int lwork, int* iwork, int liwork); \
int cscalapack_## NAMES (char compz, int n, TYPE* d, TYPE* e, \
                         TYPE* Q, int iq, int jq, const int* descQ);

CSCALAPACK_PSTEDC_DECL(psstedc, PSSTEDC, float);
CSCALAPACK_PSTEDC_DECL(pdstedc, PDSTEDC, double);

#undef CSCALAPACK_PSTEDC_DECL

#ifdef __cplusplus
}
#endif

#endif // ROKKO_CSCALAPACK_H


<|start_filename|>test/lapack/lange.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2017 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <gtest/gtest.h>
#include <cmath>
#include <rokko/eigen3.hpp>
#include <rokko/lapack.hpp>

constexpr double eps = 1e-10;
constexpr double eps_float = 1e-5;

TEST(lange, dlange) {
  int m = 5;
  int n = 3;

  // generate matrix
  Eigen::MatrixXd a = Eigen::MatrixXd::Random(m, n);
  
  std::cout << a << std::endl;
  
  double norm, expect;
  
  norm = rokko::lapack::lange('M', a);
  expect = 0.0;
  for (int j = 0; j < n; ++j)
    for (int i = 0; i < m; ++i)
      expect = std::max(expect, std::abs(a(i, j)));
  std::cout << "max norm of A = " << norm << " (expect: " << expect << ")" << std::endl;
  EXPECT_NEAR(expect, norm, eps);

  norm = rokko::lapack::lange('1', a);
  expect = 0.0;
  for (int j = 0; j < n; ++j) {
    double sum = 0.0;
    for (int i = 0; i < m; ++i) sum += std::abs(a(i, j));
    expect = std::max(expect, sum);
  }
  std::cout << "1-norm of A = " << norm << " (expect: " << expect << ")" << std::endl;
  EXPECT_NEAR(expect, norm, eps);

  norm = rokko::lapack::lange('I', a);
  expect = 0.0;
  for (int i = 0; i < m; ++i) {
    double sum = 0.0;
    for (int j = 0; j < n; ++j) sum += std::abs(a(i, j));
    expect = std::max(expect, std::abs(sum));
  }
  std::cout << "infinity norm of A = " << norm << " (expect: " << expect << ")" << std::endl;
  EXPECT_NEAR(expect, norm, eps);

  norm = rokko::lapack::lange('F', a);
  expect = 0.0;
  for (int j = 0; j < n; ++j)
    for (int i = 0; i < m; ++i) expect += a(i, j) * a(i, j);
  expect = std::sqrt(expect);
  std::cout << "Frobenius norm of A = " << norm << " (expect: " << expect << ")" << std::endl;
  EXPECT_NEAR(expect, norm, eps);
}

TEST(lange, slange) {
  int m = 5;
  int n = 3;

  // generate matrix
  Eigen::MatrixXf a = Eigen::MatrixXf::Random(m, n);
  
  std::cout << a << std::endl;
  
  float norm, expect;
  
  norm = rokko::lapack::lange('M', a);
  expect = 0.0;
  for (int j = 0; j < n; ++j)
    for (int i = 0; i < m; ++i)
      expect = std::max(expect, std::abs(a(i, j)));
  std::cout << "max norm of A = " << norm << " (expect: " << expect << ")" << std::endl;
  EXPECT_NEAR(expect, norm, eps_float);

  norm = rokko::lapack::lange('1', a);
  expect = 0.0;
  for (int j = 0; j < n; ++j) {
    float sum = 0.0;
    for (int i = 0; i < m; ++i) sum += std::abs(a(i, j));
    expect = std::max(expect, sum);
  }
  std::cout << "1-norm of A = " << norm << " (expect: " << expect << ")" << std::endl;
  EXPECT_NEAR(expect, norm, eps_float);

  norm = rokko::lapack::lange('I', a);
  expect = 0.0;
  for (int i = 0; i < m; ++i) {
    float sum = 0.0;
    for (int j = 0; j < n; ++j) sum += std::abs(a(i, j));
    expect = std::max(expect, std::abs(sum));
  }
  std::cout << "infinity norm of A = " << norm << " (expect: " << expect << ")" << std::endl;
  EXPECT_NEAR(expect, norm, eps_float);

  norm = rokko::lapack::lange('F', a);
  expect = 0.0;
  for (int j = 0; j < n; ++j)
    for (int i = 0; i < m; ++i) expect += a(i, j) * a(i, j);
  expect = std::sqrt(expect);
  std::cout << "Frobenius norm of A = " << norm << " (expect: " << expect << ")" << std::endl;
  EXPECT_NEAR(expect, norm, eps_float);
}


<|start_filename|>rokko/pyrokko_serial_dense_ev.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_SERIAL_DENSE_EV_HPP
#define PYROKKO_SERIAL_DENSE_EV_HPP

#include <rokko/pyrokko_parameters.hpp>
#include <rokko/serial_dense_ev.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/traits/real_t.hpp>

namespace rokko {

class wrap_serial_dense_ev : public serial_dense_ev {
public:
  wrap_serial_dense_ev(std::string const& solver_name) : serial_dense_ev(solver_name) {}
  
  wrap_serial_dense_ev() = default;

  void initialize() {
    int num = 1;
    char** ptr = NULL;
    serial_dense_ev::initialize(num, ptr);
  }

  template<typename T, int MAJOR>
  wrap_parameters diagonalize(Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR>> mat_in,
             Eigen::RefVec<real_t<T>> eigval_in,
             Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR>> eigvec_in,
			 wrap_parameters const& params) {
    using vector_type = Eigen::Vector<real_t<T>>;
    Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR> mat;
    Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR> eigvec;
    vector_type eigval;

    new (&mat) Eigen::Map<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR>>(mat_in.data(), mat_in.rows(), mat_in.cols());
    new (&eigval) Eigen::Ref<vector_type>(eigval_in);
    new (&eigvec) Eigen::Map<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR>>(eigvec_in.data(), eigvec_in.rows(), eigvec_in.cols());

    wrap_parameters params_out = serial_dense_ev::diagonalize(mat, eigval, eigvec, parameters(params));

    new (&mat) Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR>();
    new (&eigval) vector_type();
    new (&eigvec) Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR>();

    return params_out;
  }

  template<typename T, int MAJOR>
  wrap_parameters diagonalize(Eigen::Ref<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR>> mat_in,
             Eigen::RefVec<real_t<T>> eigval_in,
			 wrap_parameters const& params) {
    using vector_type = Eigen::Vector<real_t<T>>;
    Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR> mat;
    vector_type eigval;

    new (&mat) Eigen::Map<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR>>(mat_in.data(), mat_in.rows(), mat_in.cols());
    new (&eigval) Eigen::Ref<vector_type>(eigval_in);

    wrap_parameters params_out = serial_dense_ev::diagonalize(mat, eigval, parameters(params));

    new (&mat) Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MAJOR>();
    new (&eigval) vector_type();

    return params_out;
  }
};

} // end namespace rokko

#endif // PYROKKO_SERIAL_DENSE_EV_HPP


<|start_filename|>rokko/mapping_1d.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include "mapping_1d.hpp"

template<>
rokko::detail::ps_mapping_1d_factory *rokko::detail::ps_mapping_1d_factory::instance_ = nullptr;

template<>
rokko::detail::ps_mapping_1d_factory_num *rokko::detail::ps_mapping_1d_factory_num::instance_ = nullptr;


<|start_filename|>test/generate_matrix/matrix012.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2013-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/matrix012.hpp>

#include <gtest/gtest.h>

template <typename T, int MAJOR=Eigen::ColMajor>
using VectorX = Eigen::Matrix<T, Eigen::Dynamic, 1, MAJOR>;

// for general rectangular matrix
template<typename T, typename MATRIX_MAJOR>
void test(int dim1, int dim2) {
  Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,rokko::eigen3_major<MATRIX_MAJOR>> mat(dim1, dim2);
  rokko::matrix012::generate(mat);
  Eigen::Map<VectorX<T>> vec(mat.data(), mat.size());  // flattening mat

  ASSERT_TRUE(vec == VectorX<T>::LinSpaced(vec.size(), 0, vec.size()-1));
}

// for square matrix
template<typename T, typename MATRIX_MAJOR>
void test(int dim) {
  test<T,MATRIX_MAJOR>(dim, dim);
}

template<typename T>
void test_type() {
  test<T, rokko::matrix_row_major>(10);
  test<T, rokko::matrix_col_major>(10);
  test<T, rokko::matrix_row_major>(3, 10);
  test<T, rokko::matrix_col_major>(3, 10);
  test<T, rokko::matrix_row_major>(10, 3);
  test<T, rokko::matrix_col_major>(10, 3);
}

TEST(generate_matrix, minij_matrix) {
  // for int
  std::cout << "int" << std::endl;
  test_type<int>();
  // for double
  std::cout << "dobule" << std::endl;
  test_type<double>();
  // for flaot
  std::cout << "float" << std::endl;
  test_type<float>();
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  result = RUN_ALL_TESTS();
  return result;
}


<|start_filename|>test/grid/grid_1d_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/grid_1d.hpp>

#include <gtest/gtest.h>

TEST(grid, grid_1d_mpi) {
  MPI_Comm comm = MPI_COMM_WORLD;
  rokko::grid_1d g(comm);
  // Test public interfaces
  ASSERT_TRUE(g.get_comm() == MPI_COMM_WORLD);

  // Test global values
  ASSERT_EQ(g.get_nprocs(), 2);
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  MPI_Init(&argc, &argv);
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>rokko/slepc/distributed_crs_matrix.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SLEPC_DISTRIBUTED_CRS_MATRIX_HPP
#define ROKKO_SLEPC_DISTRIBUTED_CRS_MATRIX_HPP

#include <rokko/slepc/mapping_1d.hpp>
#include <rokko/distributed_crs_matrix.hpp>
#include <rokko/utility/timer.hpp>

#include <rokko/slepc.hpp>

#include <numeric>
#include <iostream>

namespace rokko {
namespace slepc {

class distributed_crs_matrix : public rokko::detail::ps_crs_base {
public:
  distributed_crs_matrix() = default;
  ~distributed_crs_matrix() = default;

  explicit distributed_crs_matrix(rokko::mapping_1d const& map, int num_entries_per_row)
    : distributed_crs_matrix(cast_map(map), num_entries_per_row) {}

  explicit distributed_crs_matrix(rokko::slepc::mapping_1d const& map, int num_entries_per_row)
    : distributed_crs_matrix(std::make_shared<const rokko::slepc::mapping_1d>(map), num_entries_per_row) {}

  explicit distributed_crs_matrix(std::shared_ptr<const rokko::slepc::mapping_1d> map, int num_entries_per_row): map_(map) {
    int dim = map_->get_dim();
    PetscErrorCode ierr;
    ierr = MatCreate(map_->get_mpi_comm().get_comm(), &matrix_);  //CHKERRQ(ierr);
    ierr = MatSetSizes(matrix_, map_->get_num_local_rows(), map_->get_num_local_rows(), dim, dim);  //CHKERRQ(ierr);
    ierr = MatSetFromOptions(matrix_);  //CHKERRQ(ierr);
    ierr = MatSeqAIJSetPreallocation(matrix_, num_entries_per_row, NULL);
    ierr = MatMPIAIJSetPreallocation(matrix_, num_entries_per_row, NULL, num_entries_per_row, NULL);
  }

  static std::shared_ptr<const rokko::slepc::mapping_1d> cast_map(rokko::mapping_1d const& map) {
    if (map.get_solver_name() != "slepc") {
      throw std::invalid_argument("SLEPc's distributed_crs_matrix() : " + map.get_solver_name() + "'s mapping_1d is given.");
    }
    return std::static_pointer_cast<const rokko::slepc::mapping_1d>(map.get_ptr());
  }

  #undef __FUNCT__
  #define __FUNCT__ "distributed_crs_matrix/insert"
  void insert(int row, std::vector<int> const& cols, std::vector<double> const& values) override {
    PetscErrorCode ierr = MatSetValues(matrix_, 1, &row, cols.size(), cols.data(), values.data(), INSERT_VALUES);  //CHKERRQ(ierr);
  }
  void insert(int row, int col_size, int const*const cols, double const*const values) override {
    PetscErrorCode ierr = MatSetValues(matrix_, 1, &row, col_size, cols, values, INSERT_VALUES);  //CHKERRQ(ierr);
  }
  #undef __FUNCT__
  #define __FUNCT__ "distributed_crs_matrix/complete"
  void complete() override {
    PetscErrorCode ierr;
    ierr = MatAssemblyBegin(matrix_, MAT_FINAL_ASSEMBLY);  //CHKERRQ(ierr);
    ierr = MatAssemblyEnd(matrix_, MAT_FINAL_ASSEMBLY);  //CHKERRQ(ierr);
  }
  Mat& get_matrix() {
    return matrix_;
  }
  const Mat& get_matrix() const {
    return matrix_;
  }
  int get_dim() const override {
    return map_->get_dim();
  }
  int get_num_local_rows() const override {
    int start_row, end_row;
    PetscErrorCode ierr = MatGetOwnershipRange(matrix_, &start_row, &end_row); //CHKERRQ(ierr);
    return end_row - start_row;
  }
  int start_row() const override {
    int start_row;
    PetscErrorCode ierr = MatGetOwnershipRange(matrix_, &start_row, NULL); //CHKERRQ(ierr);
    return start_row;
  }
  int end_row() const override {
    int end_row;
    PetscErrorCode ierr = MatGetOwnershipRange(matrix_, NULL, &end_row); //CHKERRQ(ierr);
    return end_row;
  }
  int get_nnz() const override {
    MatInfo info;
    MatGetInfo(matrix_, MAT_GLOBAL_SUM, &info);
    return static_cast<int>(info.nz_used);
  }
  void print() const override {
    MatView(matrix_, PETSC_VIEWER_STDOUT_(map_->get_mpi_comm().get_comm()));
  }
  void extract(int row, std::vector<int>& cols, std::vector<double>& values) const override {
    PetscInt num_cols;
    const PetscInt * cols_tmp;
    const PetscScalar * values_tmp;
    MatGetRow(matrix_, row, &num_cols, &cols_tmp, &values_tmp);
    cols.clear();
    cols.reserve(num_cols);
    values.clear();
    values.reserve(num_cols);
    std::vector<int> idx(num_cols);
    std::iota(idx.begin(), idx.end(), 0);
    std::sort(idx.begin(), idx.end(), [&cols_tmp](auto i, auto j) { return cols_tmp[i] < cols_tmp[j]; });
    for (int i=0; i<num_cols; ++i) {
      cols.emplace_back(cols_tmp[idx[i]]);
      values.emplace_back(values_tmp[idx[i]]);
    }
    PetscErrorCode ierr = MatRestoreRow(matrix_, row, &num_cols, &cols_tmp, &values_tmp);
  }
  void output_matrix_market(std::ostream& os = std::cout) const override {
    const auto& comm = get_map().get_mpi_comm();
    constexpr int root_proc = 0;
    std::vector<int> cols;
    std::vector<double> values;

    const int nnz = get_nnz();
    if (comm.get_myrank() == root_proc) {
      os << "%%MatrixMarket matrix coordinate real general" << std::endl
         << get_dim() << " " << get_dim() << " " << nnz << std::endl;
    }
    comm.barrier();
    for (int global_row=0; global_row<get_dim(); ++global_row) {
      if ((global_row >= start_row()) && (global_row < end_row())) {
        extract(global_row, cols, values);
        for (int i=0; i<cols.size(); ++i) {
          os << global_row + 1 << " " << cols[i] + 1 << " " << values[i] << std::endl;
        }
      }
      comm.barrier();
    }
  }

  const rokko::slepc::mapping_1d& get_map() const override { return *map_; }

private:
  std::shared_ptr<const rokko::slepc::mapping_1d> map_;
  Mat matrix_;
};

} // namespace slepc
} // namespace rokko

#endif // ROKKO_SLEPC_DISTRIBUTED_CRS_MATRIX_HPP


<|start_filename|>tutorial/titpack/02_refactored_cxx/common.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

// C++ version of TITPACK Ver.2 by <NAME>

#include "common.hpp"
#include <lapacke.h>
#include <iostream>

std::tuple<int, int>
bisec(std::vector<double> const& alpha, std::vector<double> const& beta, int ndim,
      std::vector<double>& E, int ne, double eps, std::vector<int>& iblock,
      std::vector<int>& isplit, double *w) {
  if (E.size() < ne) E.resize(ne);
  if (iblock.size() < ndim) iblock.resize(ndim);
  if (isplit.size() < ndim) isplit.resize(ndim);
  int m, nsplit;
  int info = LAPACKE_dstebz('I', 'B', ndim, 0, 0, 1, ne, eps, alpha.data(), beta.data(),
                            &m, &nsplit, w, iblock.data(), isplit.data());
  for (int i = 0; i < ne; ++i) E[i] = w[i];
  return std::make_tuple(m, nsplit);
}

void vec12(std::vector<double> const& alpha, std::vector<double> const& beta, int ndim,
           std::vector<double> const& E, int nvec, matrix_type& z,
           std::vector<int>& iblock, std::vector<int>& isplit, double *w) {
  if (z.size1() != ndim || z.size2() < nvec) z.resize(ndim, nvec);
  for (int i = 0; i < nvec; ++i) w[i] = E[i];
  std::vector<int> ifail(nvec);
  int info = LAPACKE_dstein(LAPACK_COL_MAJOR, ndim, alpha.data(), beta.data(), nvec, w, iblock.data(),
                            isplit.data(), &z(0,0), ndim, ifail.data());
}

void xcorr(subspace const& ss, std::vector<int> const& npair, const double *x,
           std::vector<double>& sxx) {
  int nbond = npair.size() / 2;
  for (int k=0; k < nbond; ++k) {
    int i1 = npair[k * 2];
    int i2 = npair[k * 2 + 1];
    if (i1 < 0 || i1 >= ss.num_sites() || i2 < 0 || i2 >= ss.num_sites() || i1 == i2) {
      std::cerr << " #(W01)# Wrong site number given to xcorr\n";
      return;
    }
    double corr = 0;
    int is = (1 << i1) + (1 << i2);
    for (int j = 0; j < ss.dimension(); ++j) {
      int ibit = ss.config(j) & is;
      if (ibit != 0 && ibit != is) corr += x[j] * x[ss.config2index(ss.config(j) ^ is)];
    }
    sxx[k] = corr / 4;
  }
}

void xcorr(subspace const& ss, std::vector<int> const& npair, std::vector<double> const& x,
           std::vector<double>& sxx) {
  xcorr(ss, npair, x.data(), sxx);
}

void xcorr(subspace const& ss, std::vector<int> const& npair, matrix_type const& x, int xindex,
           std::vector<double>& sxx) {
  xcorr(ss, npair, &x(0, xindex), sxx);
}

void zcorr(subspace const& ss, std::vector<int> const& npair, const double *x,
           std::vector<double>& szz) {
  int nbond = npair.size() / 2;
  for (int k = 0; k < nbond; ++k) {
    int i1 = npair[k * 2];
    int i2 = npair[k * 2 + 1];
    if (i1 < 0 || i1 >= ss.num_sites() || i2 < 0 || i2 >= ss.num_sites() || i1 == i2) {
      std::cerr << " #(W02)# Wrong site number given to zcorr\n";
      return;
    }
    double corr = 0;
    int is = (1 << i1) + (1 << i2);
    for (int j = 0; j < ss.dimension(); ++j) {
      int ibit = ss.config(j) & is;
      corr += ((ibit == 0 || ibit == is) ? 1.0 : -1.0) * x[j] * x[j];
    }
    szz[k] = corr / 4;
  }
}

void zcorr(subspace const& ss, std::vector<int> const& npair, matrix_type const& x, int xindex,
           std::vector<double>& szz) {
  zcorr(ss, npair, &x(0, xindex), szz);
}

void zcorr(subspace const& ss, std::vector<int> const& npair, std::vector<double> const& x,
           std::vector<double>& szz) {
  zcorr(ss, npair, x.data(), szz);
}

int orthg(matrix_type& ev, std::vector<double>& norm, int numvec) {
  if (numvec <= 1) {
    std::cerr << " #(W03)# Number of vectors is less than 2 in orthg\n";
    return -1;
  }
  if (norm.size() < numvec) norm.resize(numvec);
  int idim = ev.size1();
  for (int i = 0; i < numvec; ++i) {
    double dnorm = 0;
    for (int j = 0; j < idim; ++j) dnorm += ev(j, i) * ev(j, i);
    if (dnorm < 1e-20) {
      std::cerr << " #(W04)# Null vector given to orthg. Location is " << i << std::endl;
      return -1;
    }
    dnorm = 1 / std::sqrt(dnorm);
    for (int j = 0; j < idim; ++j) ev(j, i) *= dnorm;
  }
  int idgn = numvec;
  norm[0] = 1;

  // orthogonalization
  for (int i = 1; i < numvec; ++i) {
    norm[i] = 1;
    for (int j = 0; j < i; ++j) {
      double prjct = 0;
      for (int l = 0; l < idim; ++l) prjct += ev(l, i) * ev(l, j);
      for (int l = 0; l < idim; ++l) ev(l, i) -= prjct * ev(l, j);
    }
    double vnorm = 0;
    for (int l = 0; l < idim; ++l) vnorm += ev(l, i) * ev(l, i);
    if (vnorm > 1e-15) {
      vnorm = 1 / std::sqrt(vnorm);
      for (int l = 0; l < idim; ++l) ev(l, i) *= vnorm;
    } else {
      for (int l = 0; l < idim; ++l) ev(l, i) = 0;
      --idgn;
      norm[i] = 0;
    }
  }

  // check orthogonality
  for (int i = 1; i < numvec; ++i) {
    for (int j = 0; j < i; ++j) {
      double prd = 0;
      for (int l = 0; l < idim; ++l) prd += ev(l, i) * ev(l, j);
      if (std::abs(prd) > 1e-10) {
        std::cerr << " #(W05)# Non-orthogonal vectors at " << i << ' ' << j << std::endl
                  << "         Overlap : " << prd << std::endl;
      }
    }
  }
  return idgn;
}


<|start_filename|>rokko/utility/various_mpi_comm.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_VARIOUS_MPI_COMM_HPP
#define ROKKO_VARIOUS_MPI_COMM_HPP

#include <mpi.h>
#include <array>
#include <rokko/grid.hpp>

MPI_Comm create_even_comm(MPI_Comm comm_in = MPI_COMM_WORLD) {
  MPI_Group group_world, even_group;
  MPI_Comm even_comm;
  int nprocs;

  MPI_Comm_size(comm_in, &nprocs);
  MPI_Comm_group(comm_in, &group_world);

  const int Neven = (nprocs + 1) / 2;
  std::vector<int> even_members(Neven);
  for (int i=0; i<Neven; ++i)
    even_members[i] = 2 * i;

  MPI_Group_incl(group_world, Neven, even_members.data(), &even_group);
  MPI_Comm_create(comm_in, even_group, &even_comm);
  MPI_Group_free(&group_world);
  MPI_Group_free(&even_group);

  return even_comm;
}

MPI_Comm create_odd_comm(MPI_Comm comm_in = MPI_COMM_WORLD) {
  MPI_Group group_world, odd_group;
  MPI_Comm odd_comm;
  int nprocs;

  MPI_Comm_size(comm_in, &nprocs);
  MPI_Comm_group(comm_in, &group_world);

  const int Nodd = nprocs / 2;
  std::vector<int> odd_members(Nodd);
  for (int i=0; i<Nodd; ++i)
    odd_members[i] = 2 * i + 1;

  MPI_Group_incl(group_world, Nodd, odd_members.data(), &odd_group);
  MPI_Comm_create(comm_in, odd_group, &odd_comm);
  MPI_Group_free(&group_world);
  MPI_Group_free(&odd_group);

  return odd_comm;
}

MPI_Comm create_even_odd_comm(MPI_Comm comm_in = MPI_COMM_WORLD) {
  int rank;
  MPI_Comm_rank(comm_in, &rank);
  MPI_Comm comm = ((rank % 2) == 0) ? create_even_comm(comm_in) : create_odd_comm(comm_in);
  return comm;
}

MPI_Comm create_even_odd_comm_by_split(MPI_Comm comm_in = MPI_COMM_WORLD) {
  MPI_Comm comm;
  int rank;
  MPI_Comm_rank(comm_in, &rank);
  int color = rank % 2;
  MPI_Comm_split(comm_in, color, rank, &comm);
  return comm;
}

std::array<int,2> get_square_like_dims(int nprocs) {
  std::array<int,2> dims;
  dims[0] = rokko::grid::find_square_root_like_divisor(nprocs);
  dims[1] = nprocs / dims[0];

  return dims;
}

MPI_Comm create_cart_comm(MPI_Comm comm_in = MPI_COMM_WORLD) {
  int nprocs;
  MPI_Comm_size(comm_in, &nprocs);

  MPI_Comm comm;
  std::array<int,2> dims = get_square_like_dims(nprocs);
  std::array<int,2> periods{0,0};
  int reorder = 0;
  MPI_Cart_create(MPI_COMM_WORLD, 2, dims.data(), periods.data(), reorder, &comm);

  return comm;
}

#endif // ROKKO_VARIOUS_MPI_COMM_HPP


<|start_filename|>rokko/mapping_local2array.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_MAPPING_LOCAL2ARRAY_HPP
#define ROKKO_MAPPING_LOCAL2ARRAY_HPP

#include <rokko/matrix_major.hpp>
#include <rokko/mapping_common_sizes.hpp>

namespace rokko {

template <typename MATRIX_MAJOR>
class mapping_local2array : virtual public mapping_common_sizes {
public:
  explicit mapping_local2array() {
    set_default_lld();
    set_default_length_array();
  }
  explicit mapping_local2array(int lld_in) : lld(lld_in) {
    set_default_length_array();
  }
  explicit mapping_local2array(std::array<int,2> padded_size) : lld(padded_size[0]) {
    set_length_array(padded_size[0] * padded_size[1]);
  }

  void set_length_array(int value) { length_array = value; }
  int get_length_array() const { return length_array; }

  int get_lld() const { return lld; };

  void set_lld(int value) { lld = value; };
  void set_default_lld() { set_lld(get_default_lld()); }

  int get_default_lld() const;

  int get_default_length_array() const;

  int get_m_size() const;
  int get_n_size() const;

  void set_default_length_array() { set_length_array(get_default_length_array()); }

  int get_array_index(int local_i, int local_j) const;

  bool is_row_major() const {
    return std::is_same<MATRIX_MAJOR, matrix_row_major>::value;
  }
  bool is_col_major() const {
    return std::is_same<MATRIX_MAJOR, matrix_col_major>::value;
  }

private:
  int length_array;
  int lld;
};


template<>
inline int mapping_local2array<rokko::matrix_row_major>::get_default_lld() const {
  return std::max(get_n_local(), get_nb());
}

template<>
inline int mapping_local2array<rokko::matrix_col_major>::get_default_lld() const {
  return std::max(get_m_local(), get_mb());
}

template<>
inline int mapping_local2array<rokko::matrix_row_major>::get_default_length_array() const {
  return get_m_local() * lld;
}

template<>
inline int mapping_local2array<rokko::matrix_col_major>::get_default_length_array() const {
  return lld * get_n_local();
}

template<>
inline int mapping_local2array<rokko::matrix_row_major>::get_array_index(int local_i, int local_j) const {
  return local_i * lld + local_j;
}

template<>
inline int mapping_local2array<rokko::matrix_col_major>::get_array_index(int local_i, int local_j) const {
  return  local_i + local_j * lld;
}

template<>
inline int mapping_local2array<rokko::matrix_row_major>::get_m_size() const {
  return get_m_local();
}

template<>
inline int mapping_local2array<rokko::matrix_col_major>::get_m_size() const {
  return get_lld();
}

template<>
inline int mapping_local2array<rokko::matrix_row_major>::get_n_size() const {
  return get_lld();
}

template<>
inline int mapping_local2array<rokko::matrix_col_major>::get_n_size() const {
  return get_n_local();
}

} // namespace rokko

#endif // ROKKO_MAPPING_LOCAL2ARRAY_HPP


<|start_filename|>rokko/lapack/heev.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_HEEV_HPP
#define ROKKO_LAPACK_HEEV_HPP

#include <complex>
#include <lapacke.h>
#undef I
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>
#include "complex_cast.hpp"
#include <rokko/lapack/storage.hpp>
#include <rokko/alias_template_function.hpp>

namespace rokko {
namespace lapack {

namespace {

template<typename T> struct heev_dispatch;
  
template<>
struct heev_dispatch<float> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int heev(int matrix_layout, char jobz, char uplo, lapack_int n,
                         MATRIX& a, VECTOR& w) {
    return LAPACKE_ssyev(matrix_layout, jobz, uplo, n, storage(a), ld(a), storage(w));
  }
};
  
template<>
struct heev_dispatch<double> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int heev(int matrix_layout, char jobz, char uplo, lapack_int n,
                         MATRIX& a, VECTOR& w) {
    return LAPACKE_dsyev(matrix_layout, jobz, uplo, n, storage(a), ld(a), storage(w));
  }
};
  
template<>
struct heev_dispatch<std::complex<float>> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int heev(int matrix_layout, char jobz, char uplo, lapack_int n,
                         MATRIX& a, VECTOR& w) {
    return LAPACKE_cheev(matrix_layout, jobz, uplo, n, complex_cast(storage(a)), ld(a),
                         storage(w));
  }
};
  
template<>
struct heev_dispatch<std::complex<double>> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int heev(int matrix_layout, char jobz, char uplo, lapack_int n,
                         MATRIX& a, VECTOR& w) {
    return LAPACKE_zheev(matrix_layout, jobz, uplo, n, complex_cast(storage(a)), ld(a),
                         storage(w));
  }
};

} // end of anonymous namespace
  
template<typename MATRIX, typename VECTOR>
lapack_int heev(char jobz, char uplo, MATRIX& a, VECTOR& w) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR>>::value, "");
  lapack_int n = rows(a);
  if (rows(a) != cols(a))
    throw std::invalid_argument("matrix A size mismatch");
  //if (size(w) != n)
  //  throw std::invalid_argument("vector w size mismatch");
  return heev_dispatch<value_t<MATRIX>>::
    heev((is_col_major(a) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR), jobz, uplo, n, a, w);
}

ALIAS_TEMPLATE_FUNCTION(syev, heev);

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_HEEV_HPP


<|start_filename|>rokko/eigen_vector_c.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/eigen_vector.h>
#include <rokko/eigen3.hpp>
#include <rokko/eigen3/generate_vector.hpp>

void rokko_eigen_vector_construct(rokko_eigen_vector* vec, int dim) {
  vec->ptr = new Eigen::VectorXd(dim);
}

void rokko_eigen_vector_construct_array_size(struct rokko_eigen_vector* vector,
                                             int dim, double* ptr) {
  vector->ptr = new Eigen::Map<Eigen::VectorXd>(ptr, dim);
}

void rokko_eigen_vector_destruct(rokko_eigen_vector* vec) {
  delete static_cast<Eigen::VectorXd*>(vec->ptr);
  vec->ptr = nullptr;
}

int rokko_eigen_vector_get_dim(rokko_eigen_vector vec) {
  return static_cast<Eigen::VectorXd*>(vec.ptr)->size();
}

double* rokko_eigen_vector_get_array_pointer(rokko_eigen_vector vec) {
  return static_cast<Eigen::VectorXd*>(vec.ptr)->data();
}

double rokko_eigen_vector_get(rokko_eigen_vector vec, int i) {
  return (*static_cast<Eigen::VectorXd*>(vec.ptr))[i];
}

/* offset by one */
double rokko_eigen_vector_get1(rokko_eigen_vector vec, int i) {
  return (*static_cast<Eigen::VectorXd*>(vec.ptr))[i-1];
}

void rokko_eigen_vector_set(rokko_eigen_vector vec, int i, double val) {
  (*static_cast<Eigen::VectorXd*>(vec.ptr))[i] = val;
}

/* offset by one */
void rokko_eigen_vector_set1(rokko_eigen_vector vec, int i, double val) {
  (*static_cast<Eigen::VectorXd*>(vec.ptr))[i-1] = val;
}

void rokko_eigen_vector_print(rokko_eigen_vector vec) {
  std::cout << *static_cast<Eigen::VectorXd*>(vec.ptr) << std::endl;
}

void rokko_eigen_vector_generate_function(rokko_eigen_vector vec,
					      double (*func)(int i)) {
  rokko::generate(*static_cast<Eigen::VectorXd*>(vec.ptr), func);
}

void rokko_eigen_vector_generate_function_p(rokko_eigen_vector vec,
                                            double (*func)(const int* i)) {
  rokko::generate(*static_cast<Eigen::VectorXd*>(vec.ptr),
                  [&func](int i) { return func(&i); } );
}

void rokko_eigen_vector_generate_function1(rokko_eigen_vector vec,
                                            double (*func)(int i)) {
  rokko::generate(*static_cast<Eigen::VectorXd*>(vec.ptr),
                  [&func](int i) { return func(i+1); });
}

void rokko_eigen_vector_generate_function1_p(rokko_eigen_vector vec,
                                              double (*func)(const int* i)) {
  rokko::generate(*static_cast<Eigen::VectorXd*>(vec.ptr),
                  [&func](int i) {
                    const int i1 = i+1;
                    return func(&i1);
                  } );
}


<|start_filename|>rokko/eigenexa/solver.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_EIGENEXA_SOLVER_HPP
#define ROKKO_EIGENEXA_SOLVER_HPP

#include <rokko/matrix_major.hpp>
#include <rokko/parameters.hpp>
#include <rokko/eigenexa/diagonalize_eigen_s.hpp>
#include <rokko/eigenexa/diagonalize_eigen_sx.hpp>
#include <complex>

namespace rokko {

namespace eigenexa {

class solver {
public:
  template <typename GRID_MAJOR>
  bool is_available_grid_major(GRID_MAJOR const& /* grid_major */) { return true; }
  void initialize(int& /* argc */, char**& /* argv */) {}
  void finalize() {}

  mapping_bc<matrix_col_major> default_mapping(int global_dim, grid const& g) const {
    int nx, ny;
    std::tie(nx, ny) = rokko::eigenexa::get_matdims(g, global_dim);
    return mapping_bc<matrix_col_major>(global_dim, 1, {nx, ny}, g);  // block_size = 1
  }

  template<typename MATRIX_MAJOR, typename VEC>
  parameters diagonalize(distributed_matrix<double, MATRIX_MAJOR>& mat,
			 VEC& eigvals, distributed_matrix<double, MATRIX_MAJOR>& eigvecs,
			 parameters const& params);
  template<typename MATRIX_MAJOR, typename VEC>
  parameters diagonalize(distributed_matrix<double, MATRIX_MAJOR>& mat,
			 VEC& eigvals,
			 parameters const& params);

  template<typename MATRIX_MAJOR, typename VEC>
  parameters diagonalize(distributed_matrix<float, MATRIX_MAJOR>& mat,
			 VEC& eigvals, distributed_matrix<float, MATRIX_MAJOR>& eigvecs,
			 parameters const& params) {
    throw std::invalid_argument("eigenexa::diagonalize() : eigenexa doesn't support float type.  Use eigenexa with double type.");
  }
  template<typename MATRIX_MAJOR, typename VEC>
  parameters diagonalize(distributed_matrix<float, MATRIX_MAJOR>& mat,
			 VEC& eigvals,
			 parameters const& params) {
    throw std::invalid_argument("eigenexa::diagonalize() : eigenexa doesn't support float type.  Use eigenexa with double type.");
  }

  template<typename T, typename MATRIX_MAJOR, typename VEC>
  parameters diagonalize(distributed_matrix<std::complex<T>, MATRIX_MAJOR>& mat,
			 VEC& eigvals, distributed_matrix<std::complex<T>, MATRIX_MAJOR>& eigvecs,
			 parameters const& params) {
    throw std::invalid_argument("eigenexa::diagonalize() : eigenexa doesn't support complex number.");
  }
  template<typename T, typename MATRIX_MAJOR, typename VEC>
  parameters diagonalize(distributed_matrix<std::complex<T>, MATRIX_MAJOR>& mat,
			 VEC& eigvals,
			 parameters const& params) {
    throw std::invalid_argument("eigenexa::diagonalize() : eigenexa doesn't support complex number.");
  }
};

template<typename MATRIX_MAJOR, typename VEC>
parameters solver::diagonalize(distributed_matrix<double, MATRIX_MAJOR>& mat,
			       VEC& eigvals, distributed_matrix<double, MATRIX_MAJOR>& eigvecs,
			       parameters const& params) {
  const std::string routine = params.defined("routine") ? params.get_string("routine") : "";

  if ((routine=="tri") || (routine=="eigen_s")) {
    return rokko::eigenexa::diagonalize_eigen_s(mat, eigvals, eigvecs, params);
  } else if ((routine=="") || (routine=="penta") || (routine=="eigen_sx")) {
    return rokko::eigenexa::diagonalize_eigen_sx(mat, eigvals, eigvecs, params);
  } else {
    throw std::invalid_argument("eigenexa::diagonalize() : " + routine + " is invalid routine name");
  }
}

template<typename MATRIX_MAJOR, typename VEC>
parameters solver::diagonalize(distributed_matrix<double, MATRIX_MAJOR>& mat,
			       VEC& eigvals,
			       parameters const& params) {
  const std::string routine = params.defined("routine") ? params.get_string("routine") : "";

  if ((routine=="tri") || (routine=="eigen_s")) {
    return rokko::eigenexa::diagonalize_eigen_s(mat, eigvals, params);
  } else if ((routine=="") || (routine=="penta") || (routine=="eigen_sx")) {
    return rokko::eigenexa::diagonalize_eigen_sx(mat, eigvals, params);
  } else {
    throw std::invalid_argument("eigenexa::diagonalize() : " + routine + " is invalid routine name");
  }
}

} // namespace eigenexa
} // namespace rokko

#endif // ROKKO_EIGENEXA_SOLVER_HPP


<|start_filename|>config/FindSLEPc.cmake<|end_filename|>
# - Try to find SLEPC
# Once done this will define
#
#  SLEPC_FOUND        - system has SLEPc
#  SLEPC_INCLUDE_DIR  - include directories for SLEPc
#  SLEPC_LIBARIES     - libraries for SLEPc
#  SLEPC_DIR          - directory where SLEPc is installed
#
# Assumes that PETSC_DIR and PETSC_ARCH has been set by
# alredy calling find_package(PETSc)

if(DEFINED SLEPC_FOUND)
  return()
endif(DEFINED SLEPC_FOUND)
  
message(STATUS "Checking for SLEPc library")
find_package(PETSc)
set(SLEPC_FOUND FALSE)

# Standard search path
set(_PATHS "")
if(SLEPC_DIR)
  set(_PATHS ${SLEPC_DIR})
else(SLEPC_DIR)
  list(APPEND _PATHS
  	      ${SLEPC_ROOT}/${CMAKE_BUILD_TYPE}
	      ${SLEPC_ROOT}
  	      $ENV{SLEPC_ROOT}/${CMAKE_BUILD_TYPE}
	      $ENV{SLEPC_ROOT}
  	      ${ROKKO_SOLVER_ROOT}/slepc/${CMAKE_BUILD_TYPE}
	      ${ROKKO_SOLVER_ROOT}/slepc
  	      $ENV{ROKKO_SOLVER_ROOT}/slepc/${CMAKE_BUILD_TYPE}
	      $ENV{ROKKO_SOLVER_ROOT}/slepc
	      ${CMAKE_INSTALL_PREFIX}/slepc/${CMAKE_BUILD_TYPE}
	      ${CMAKE_INSTALL_PREFIX}/${CMAKE_BUILD_TYPE}
	      $ENV{HOME}/rokko/slepc/${CMAKE_BUILD_TYPE}
	      $ENV{HOME}/rokko/slepc
	      /opt/rokko/slepc/${CMAKE_BUILD_TYPE}
	      /opt/rokko/slepc
	      /opt/rokko/${CMAKE_BUILD_TYPE}
	      /opt/rokko
	      /opt/local /opt
              /usr
	      )
  # Standard paths for Debian with version number
  file(GLOB tmp "/usr/lib/slepcdir/*")
  list(APPEND _PATHS ${tmp})
  unset(tmp)
endif(SLEPC_DIR)

# Try to figure out SLEPC_DIR by finding slepc.h
find_path(SLEPC_DIR NAMES include/slepc.h PATHS ${_PATHS} DOC "SLEPc directory")

if(SLEPC_DIR)
  set(SLEPC_INCLUDE_DIR "${SLEPC_DIR}/include")
else(SLEPC_DIR)
  find_path(SLEPC_DIR NAMES include/slepc/slepc.h PATHS ${_PATHS} DOC "SLEPc directory")
  if(SLEPC_DIR)
    set(SLEPC_INCLUDE_DIR "${SLEPC_DIR}/include/slepc")
  else(SLEPC_DIR)
    message(STATUS "SLEPc library: include file not found")
    set(SLEPC_FOUND FALSE)
    return()
  endif(SLEPC_DIR)
endif(SLEPC_DIR)
message(STATUS "SLEPc include directory: ${SLEPC_INCLUDE_DIR}")

find_library(SLEPC_LIBRARIES
  NAMES slepc
  HINTS ${SLEPC_DIR}/lib
  HINTS ${SLEPC_DIR}/${PETSC_ARCH}/lib
  DOC "The SLEPc library"
  )
mark_as_advanced(SLEPC_LIBRARIES)

set(SLEPC_FOUND TRUE)
message(STATUS "SLEPc libraries: ${SLEPC_LIBRARIES}")

return()


<|start_filename|>test/mapping_1d/various_num_local_rows_for_all_libraries.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/parallel_sparse_ev.hpp>
#include <rokko/mapping_1d.hpp>
#include <rokko/skel/mapping_1d.hpp>
#include <rokko/distributed_crs_matrix.hpp>

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

void check_map_mat(rokko::skel::mapping_1d const& map, rokko::distributed_crs_matrix const& mat) {
  ASSERT_EQ(map.get_dim(), mat.get_dim());
  ASSERT_EQ(map.get_num_local_rows(), mat.get_num_local_rows());
  ASSERT_EQ(map.start_row(), mat.start_row());
  ASSERT_EQ(map.end_row(), mat.end_row());
}

TEST(mapping_1d, various_num_local_rows_for_all_libraries) {
  constexpr int dim = 100;

  rokko::mpi_comm comm{MPI_COMM_WORLD};
  const int nprocs = comm.get_nprocs();
  const int myrank = comm.get_myrank();

  const int num_local_rows = (myrank == (nprocs-1)) ? dim - (nprocs-1) : 1;
  rokko::skel::mapping_1d skel_map(dim, num_local_rows, comm);

  for (auto const& name : rokko::parallel_sparse_ev::solvers()) {
    std::cout << "name=" << name << std::endl;
    rokko::parallel_sparse_ev solver(name);

    auto const map = solver.default_mapping(dim, num_local_rows, comm);
    const int num_entries_per_row = 3;
    rokko::distributed_crs_matrix mat(map, num_entries_per_row);
    check_map_mat(skel_map, mat);
  }
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>rokko/scalapack/psyev.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_PSYEV_HPP
#define ROKKO_SCALAPACK_PSYEV_HPP

#include <rokko/cscalapack.h>
#include <rokko/lapack/storage.hpp>
#include <rokko/lapack/complex_cast.hpp>
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>

namespace rokko {
namespace scalapack {

using rokko::lapack::storage;
using rokko::lapack::complex_cast;

namespace {

inline int psyev_dispatch(char jobz, char uplo, int n, double* A, int ia, int ja, const int* descA,
                          double* w, double* Z, int iz, int jz, const int* descZ,
                          double* work, int lwork) {
  return cscalapack_pdsyev_work(jobz, uplo, n, A, ia, ja, descA, w, Z, iz, jz, descZ, work, lwork);
}

inline int psyev_dispatch(char jobz, char uplo, int n, float* A, int ia, int ja, const int* descA,
                          float* w, float* Z, int iz, int jz, const int* descZ) {
  return cscalapack_pssyev(jobz, uplo, n, A, ia, ja, descA, w, Z, iz, jz, descZ);
}

inline int psyev_dispatch(char jobz, char uplo, int n, double* A, int ia, int ja, const int* descA,
                          double* w, double* Z, int iz, int jz, const int* descZ) {
  return cscalapack_pdsyev(jobz, uplo, n, A, ia, ja, descA, w, Z, iz, jz, descZ);
}

inline int psyev_dispatch(char jobz, char uplo, int n, std::complex<float>* A, int ia, int ja, const int* descA,
                          float* w, std::complex<float>* Z, int iz, int jz, const int* descZ) {
  return cscalapack_pcheev(jobz, uplo, n, complex_cast(A), ia, ja, descA, w, complex_cast(Z), iz, jz, descZ);
}

inline int psyev_dispatch(char jobz, char uplo, int n, std::complex<double>* A, int ia, int ja, const int* descA,
                          double* w, std::complex<double>* Z, int iz, int jz, const int* descZ) {
  return cscalapack_pzheev(jobz, uplo, n, complex_cast(A), ia, ja, descA, w, complex_cast(Z), iz, jz, descZ);
}

} // end of anonymous namespace

template<typename MATRIX, typename VECTOR>
int psyev(char jobz, char uplo, MATRIX& a, VECTOR& w, MATRIX& z) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR>>::value, "");

  const int* descA = a.get_mapping().get_blacs_descriptor().data();
  const int* descZ = z.get_mapping().get_blacs_descriptor().data();
  return psyev_dispatch(jobz, uplo, a.get_m_global(), a.get_array_pointer(), 0, 0, descA,
                        storage(w), z.get_array_pointer(), 0, 0, descZ);
}

template<typename MATRIX, typename VECTOR>
int psyev(char jobz, char uplo, MATRIX& a, VECTOR& w, MATRIX& z, VECTOR& work) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR>>::value, "");

  const int* descA = a.get_mapping().get_blacs_descriptor().data();
  const int* descZ = z.get_mapping().get_blacs_descriptor().data();
  return psyev_dispatch(jobz, uplo, a.get_m_global(), a.get_array_pointer(), 0, 0, descA,
                        storage(w), z.get_array_pointer(), 0, 0, descZ, storage(work), work.size());
}

// eigenvalues & eigenvectors (without jobz)
template<typename MATRIX, typename VECTOR>
int psyev(char uplo, MATRIX& a, VECTOR& w, MATRIX& z) {
  return psyev('V', uplo, a, w, z);
}

// only eigenvalues (without jobz)
template<typename MATRIX, typename VECTOR>
int psyev(char uplo, MATRIX& a, VECTOR& w) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR>>::value, "");

  const int* descA = a.get_mapping().get_blacs_descriptor().data();
  return psyev_dispatch('N', uplo, a.get_m_global(), a.get_array_pointer(), 0, 0, descA,
                        storage(w), NULL, 0, 0, NULL);
}

} // end namespace scalapack
} // end namespace rokko

#endif // ROKKO_SCALAPACK_PSYEV_HPP


<|start_filename|>rokko/cmatrix.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_CMATRIX_H
#define ROKKO_CMATRIX_H

#include <stdlib.h>
#include <stdio.h>
#include <complex.h>
#undef I

#define vec_ptr(vec) &(vec)[0]
#define mat_ptr(mat) &(mat)[0][0]
#define mat_elem(mat, i, j) (mat)[j][i]

#ifdef __cplusplus
extern "C" {
#endif

/*********
  vectors
**********/

/* allocate vector of int */
static inline int *alloc_ivector(int n) {
  int *vec;
  vec = (int*)calloc(n, sizeof(int));
  if (vec == NULL) {
    fprintf(stderr, "Error: allocation failed in alloc_ivector\n");
    exit(1);
  }
  return vec;
}

/* allocate vector of float */
static inline float *alloc_svector(int n) {
  float *vec;
  vec = (float*)calloc(n, sizeof(float));
  if (vec == NULL) {
    fprintf(stderr, "Error: allocation failed in alloc_svector\n");
    exit(1);
  }
  return vec;
}

/* allocate vector of double */
static inline double *alloc_dvector(int n) {
  double *vec;
  vec = (double*)calloc(n, sizeof(double));
  if (vec == NULL) {
    fprintf(stderr, "Error: allocation failed in alloc_dvector\n");
    exit(1);
  }
  return vec;
}

/* allocate vector of float complex */
static inline float complex *alloc_cvector(int n) {
  float complex *vec;
  vec = (float complex*)calloc(n, sizeof(float complex));
  if (vec == NULL) {
    fprintf(stderr, "Error: allocation failed in alloc_cvector\n");
    exit(1);
  }
  return vec;
}

/* allocate vector of double complex */
static inline double complex *alloc_zvector(int n) {
  double complex *vec;
  vec = (double complex*)calloc(n, sizeof(double complex));
  if (vec == NULL) {
    fprintf(stderr, "Error: allocation failed in alloc_zvector\n");
    exit(1);
  }
  return vec;
}

/* deallocate vector of int */
static inline void free_ivector(int *vec) {
  free(vec);
  vec = NULL;
}

/* deallocate vector of float */
static inline void free_svector(float *vec) {
  free(vec);
  vec = NULL;
}

/* deallocate vector of double */
static inline void free_dvector(double *vec) {
  free(vec);
  vec = NULL;
}

/* deallocate vector of float complex */
static inline void free_cvector(float complex *vec) {
  free(vec);
  vec = NULL;
}

/* deallocate vector of double complex */
static inline void free_zvector(double complex *vec) {
  free(vec);
  vec = NULL;
}

/* print out vector of int */
static inline void fprintf_ivector(FILE *fp, const char* fmt, int n, int *vec) {
  int i;
  fprintf(fp, "%d\n", n);
  for (i = 0; i < n; ++i) fprintf(fp, fmt, vec[i]);
  fprintf(fp, "\n");
}
static inline void fprint_ivector(FILE *fp, int n, int *vec) {
  fprintf_ivector(fp, "%d ", n, vec);
}

/* print out vector of float */
static inline void fprintf_svector(FILE *fp, const char* fmt, int n, float *vec) {
  int i;
  fprintf(fp, "%d\n", n);
  for (i = 0; i < n; ++i) fprintf(fp, fmt, vec[i]);
  fprintf(fp, "\n");
}
static inline void fprint_svector(FILE *fp, int n, float *vec) {
  fprintf_svector(fp, "%e ", n, vec);
}

/* print out vector of double */
static inline void fprintf_dvector(FILE *fp, const char* fmt, int n, double *vec) {
  int i;
  fprintf(fp, "%d\n", n);
  for (i = 0; i < n; ++i) fprintf(fp, fmt, vec[i]);
  fprintf(fp, "\n");
}
static inline void fprint_dvector(FILE *fp, int n, double *vec) {
  fprintf_dvector(fp, "%20.14e ", n, vec);
}

/* print out vector of float complex */
static inline void fprintf_cvector(FILE *fp, const char* fmt, int n, float complex *vec) {
  int i;
  fprintf(fp, "%d\n", n);
  for (i = 0; i < n; ++i) fprintf(fp, fmt, crealf(vec[i]), cimagf(vec[i]));
  fprintf(fp, "\n");
}
static inline void fprint_cvector(FILE *fp, int n, float complex *vec) {
  fprintf_cvector(fp, "(%e,%e) ", n, vec);
}

/* print out vector of double complex */
static inline void fprintf_zvector(FILE *fp, const char* fmt, int n, double complex *vec) {
  int i;
  fprintf(fp, "%d\n", n);
  for (i = 0; i < n; ++i) fprintf(fp, fmt, creal(vec[i]), cimag(vec[i]));
  fprintf(fp, "\n");
}
static inline void fprint_zvector(FILE *fp, int n, double complex *vec) {
  fprintf_zvector(fp, "(%20.14e,%20.14e) ", n, vec);
}

/* read vector of int from file */
static inline void read_ivector(FILE *fp, int *n, int **vec) {
  int i;
  fscanf(fp, "%d", n);
  *vec = alloc_ivector(*n);
  for (i = 0; i < *n; ++i) fscanf(fp, "%d", &(*vec)[i]);
}

/* read vector of float from file */
static inline void read_svector(FILE *fp, int *n, float **vec) {
  int i;
  fscanf(fp, "%d", n);
  *vec = alloc_svector(*n);
  for (i = 0; i < *n; ++i) fscanf(fp, "%e", &(*vec)[i]);
}

/* read vector of double from file */
static inline void read_dvector(FILE *fp, int *n, double **vec) {
  int i;
  fscanf(fp, "%d", n);
  *vec = alloc_dvector(*n);
  for (i = 0; i < *n; ++i) fscanf(fp, "%le", &(*vec)[i]);
}

/* read vector of float complex from file */
static inline void read_cvector(FILE *fp, int *n, float complex **vec) {
  int i;
  float v_re, v_im;
  fscanf(fp, "%d", n);
  *vec = alloc_cvector(*n);
  for (i = 0; i < *n; ++i) {
    fscanf(fp, "(%e,%e)%*c", &v_re, &v_im);
    (*vec)[i] = v_re + _Complex_I * v_im;
  }
}

/* read vector of double from file */
static inline void read_zvector(FILE *fp, int *n, double complex **vec) {
  int i;
  double v_re, v_im;
  fscanf(fp, "%d", n);
  *vec = alloc_zvector(*n);
  for (i = 0; i < *n; ++i) {
    fscanf(fp, "(%le,%le)%*c", &v_re, &v_im);
    (*vec)[i] = v_re + _Complex_I * v_im;
  }
}

/**********
  matrices
***********/

/* allocate m x n column-major matrix of float */
static inline float **alloc_smatrix(int m, int n) {
  int i;
  float **mat;
  mat = (float**)malloc((size_t)(n * sizeof(float*)));
  if (mat == NULL) {
    fprintf(stderr, "Error: allocation failed in alloc_smatrix\n");
    exit(1);
  }
  mat[0] = (float*)malloc((size_t)(m * n * sizeof(float)));
  if (mat[0] == NULL) {
    fprintf(stderr, "Error: allocation failed in alloc_smatrix\n");
    exit(1);
  }
  for (i = 1; i < n; ++i) mat[i] = mat[i-1] + m;
  return mat;
}

/* allocate m x n row-major matrix of float */
static inline float **alloc_smatrix_r(int m, int n) { return alloc_smatrix(n, m); }

/* allocate m x n column-major matrix of double */
static inline double **alloc_dmatrix(int m, int n) {
  int i;
  double **mat;
  mat = (double**)malloc((size_t)(n * sizeof(double*)));
  if (mat == NULL) {
    fprintf(stderr, "Error: allocation failed in alloc_dmatrix\n");
    exit(1);
  }
  mat[0] = (double*)calloc(m * n, sizeof(double));
  if (mat[0] == NULL) {
    fprintf(stderr, "Error: allocation failed in alloc_dmatrix\n");
    exit(1);
  }
  for (i = 1; i < n; ++i) mat[i] = mat[i-1] + m;
  return mat;
}

/* allocate m x n row-major matrix of double */
static inline double **alloc_dmatrix_r(int m, int n) { return alloc_dmatrix(n, m); }

/* allocate m x n column-major matrix of float complex */
static inline float complex **alloc_cmatrix(int m, int n) {
  int i;
  float complex **mat;
  mat = (float complex**)malloc((size_t)(n * sizeof(float complex*)));
  if (mat == NULL) {
    fprintf(stderr, "Error: allocation failed in alloc_cmatrix\n");
    exit(1);
  }
  mat[0] = (float complex*)malloc((size_t)(m * n * sizeof(float complex)));
  if (mat[0] == NULL) {
    fprintf(stderr, "Error: allocation failed in alloc_cmatrix\n");
    exit(1);
  }
  for (i = 1; i < n; ++i) mat[i] = mat[i-1] + m;
  return mat;
}

/* allocate m x n row-major matrix of float complex */
static inline float complex **alloc_cmatrix_r(int m, int n) { return alloc_cmatrix(n, m); }

/* allocate m x n column-major matrix of double complex */
static inline double complex **alloc_zmatrix(int m, int n) {
  int i;
  double complex **mat;
  mat = (double complex**)malloc((size_t)(n * sizeof(double complex*)));
  if (mat == NULL) {
    fprintf(stderr, "Error: allocation failed in alloc_zmatrix\n");
    exit(1);
  }
  mat[0] = (double complex*)calloc(m * n, sizeof(double complex));
  if (mat[0] == NULL) {
    fprintf(stderr, "Error: allocation failed in alloc_zmatrix\n");
    exit(1);
  }
  for (i = 1; i < n; ++i) mat[i] = mat[i-1] + m;
  return mat;
}

/* allocate m x n row-major matrix of double complex */
static inline double complex **alloc_zmatrix_r(int m, int n) { return alloc_zmatrix(n, m); }

/* deallocate matrix of float */
static inline void free_smatrix(float **mat) {
  free(mat[0]);
  free(mat);
  mat = NULL;
}

/* deallocate matrix of double */
static inline void free_dmatrix(double **mat) {
  free(mat[0]);
  free(mat);
  mat = NULL;
}

/* deallocate matrix of float complex */
static inline void free_cmatrix(float complex **mat) {
  free(mat[0]);
  free(mat);
  mat = NULL;
}

/* deallocate matrix of double complex */
static inline void free_zmatrix(double complex **mat) {
  free(mat[0]);
  free(mat);
  mat = NULL;
}

/* print out column-major matrix of float */
static inline void fprint_smatrixf(FILE *fp, const char *fmt, int m, int n, float **mat) {
  int i, j;
  fprintf(fp, "%d %d\n", m, n);
  for (i = 0; i < m; ++i) {
    for (j = 0; j < n; ++j) fprintf(fp, fmt, mat_elem(mat, i, j));
    fprintf(fp, "\n");
  }
}
static inline void fprint_smatrix(FILE *fp, int m, int n, float **mat) {
  fprint_smatrixf(fp, "%e ", m, n, mat);
}

/* print out row-major matrix of float */
static inline void fprint_smatrixf_r(FILE *fp, const char *fmt, int m, int n, float **mat) {
  int i, j;
  fprintf(fp, "%d %d\n", m, n);
  for (i = 0; i < m; ++i) {
    for (j = 0; j < n; ++j) fprintf(fp, fmt, mat[i][j]);
    fprintf(fp, "\n");
  }
}
static inline void fprint_smatrix_r(FILE *fp, int m, int n, float **mat) {
  fprint_smatrixf_r(fp, "%e ", m, n, mat);
}

/* print out column-major matrix of double */
static inline void fprint_dmatrixf(FILE *fp, const char *fmt, int m, int n, double **mat) {
  int i, j;
  fprintf(fp, "%d %d\n", m, n);
  for (i = 0; i < m; ++i) {
    for (j = 0; j < n; ++j) fprintf(fp, fmt, mat_elem(mat, i, j));
    fprintf(fp, "\n");
  }
}
static inline void fprint_dmatrix(FILE *fp, int m, int n, double **mat) {
  fprint_dmatrixf(fp, "%20.14e ", m, n, mat);
}
/* print out row-major matrix of double */
static inline void fprint_dmatrixf_r(FILE *fp, const char *fmt, int m, int n, double **mat) {
  int i, j;
  fprintf(fp, "%d %d\n", m, n);
  for (i = 0; i < m; ++i) {
    for (j = 0; j < n; ++j) fprintf(fp, fmt, mat[i][j]);
    fprintf(fp, "\n");
  }
}
static inline void fprint_dmatrix_r(FILE *fp, int m, int n, double **mat) {
  fprint_dmatrixf_r(fp, "%20.14e ", m, n, mat);
}

/* print out column-major matrix of float complex */
static inline void fprint_cmatrixf(FILE *fp, const char *fmt, int m, int n, float complex **mat) {
  int i, j;
  fprintf(fp, "%d %d\n", m, n);
  for (i = 0; i < m; ++i) {
    for (j = 0; j < n; ++j)
      fprintf(fp, fmt, crealf(mat_elem(mat, i, j)), cimagf(mat_elem(mat, i, j)));
    fprintf(fp, "\n");
  }
}
static inline void fprint_cmatrix(FILE *fp, int m, int n, float complex **mat) {
  fprint_cmatrixf(fp, "(%e,%e) ", m, n, mat);
}

/* print out row-major matrix of float complex */
static inline void fprint_cmatrixf_r(FILE *fp, const char *fmt, int m, int n, float complex **mat) {
  int i, j;
  fprintf(fp, "%d %d\n", m, n);
  for (i = 0; i < m; ++i) {
    for (j = 0; j < n; ++j)
      fprintf(fp, fmt, crealf(mat[i][j]), cimagf(mat[i][j]));
    fprintf(fp, "\n");
  }
}
static inline void fprint_cmatrix_r(FILE *fp, int m, int n, float complex **mat) {
  fprint_cmatrixf_r(fp, "(%e,%e) ", m, n, mat);
}

/* print out column-major matrix of double complex */
static inline void fprint_zmatrixf(FILE *fp, const char *fmt, int m, int n, double complex **mat) {
  int i, j;
  fprintf(fp, "%d %d\n", m, n);
  for (i = 0; i < m; ++i) {
    for (j = 0; j < n; ++j)
      fprintf(fp, fmt, creal(mat_elem(mat, i, j)), cimag(mat_elem(mat, i, j)));
    fprintf(fp, "\n");
  }
}
static inline void fprint_zmatrix(FILE *fp, int m, int n, double complex **mat) {
  fprint_zmatrixf(fp, "(%20.14e,%20.14e) ", m, n, mat);
}

/* print out row-major matrix of double complex */
static inline void fprint_zmatrixf_r(FILE *fp, const char *fmt, int m, int n, double complex **mat) {
  int i, j;
  fprintf(fp, "%d %d\n", m, n);
  for (i = 0; i < m; ++i) {
    for (j = 0; j < n; ++j)
      fprintf(fp, fmt, creal(mat[i][j]), cimag(mat[i][j]));
    fprintf(fp, "\n");
  }
}
static inline void fprint_zmatrix_r(FILE *fp, int m, int n, double complex **mat) {
  fprint_zmatrixf_r(fp, "(%20.14e,%20.14e) ", m, n, mat);
}

/* read column-major matrix of float from file */
static inline void read_smatrix(FILE *fp, int *m, int *n, float ***mat) {
  int i, j;
  fscanf(fp, "%d", m);
  fscanf(fp, "%d", n);
  *mat = alloc_smatrix(*m, *n);
  for (i = 0; i < *m; ++i) {
    for (j = 0; j < *n; ++j) fscanf(fp, "%e", &mat_elem(*mat, i, j));
  }
}

/* read row-major matrix of float from file */
static inline void read_smatrix_r(FILE *fp, int *m, int *n, float ***mat) {
  int i, j;
  fscanf(fp, "%d", m);
  fscanf(fp, "%d", n);
  *mat = alloc_smatrix_r(*m, *n);
  for (i = 0; i < *m; ++i) {
    for (j = 0; j < *n; ++j) fscanf(fp, "%e", &(*mat)[i][j]);
  }
}

/* read column-major matrix of double from file */
static inline void read_dmatrix(FILE *fp, int *m, int *n, double ***mat) {
  int i, j;
  fscanf(fp, "%d", m);
  fscanf(fp, "%d", n);
  *mat = alloc_dmatrix(*m, *n);
  for (i = 0; i < *m; ++i) {
    for (j = 0; j < *n; ++j) fscanf(fp, "%le", &mat_elem(*mat, i, j));
  }
}

/* read row-major matrix of double from file */
static inline void read_dmatrix_r(FILE *fp, int *m, int *n, double ***mat) {
  int i, j;
  fscanf(fp, "%d", m);
  fscanf(fp, "%d", n);
  *mat = alloc_dmatrix_r(*m, *n);
  for (i = 0; i < *m; ++i) {
    for (j = 0; j < *n; ++j) fscanf(fp, "%le", &(*mat)[i][j]);
  }
}

/* read column-major matrix of float complex from file */
static inline void read_cmatrix(FILE *fp, int *m, int *n, float complex ***mat) {
  int i, j;
  float v_re, v_im;
  fscanf(fp, "%d", m);
  fscanf(fp, "%d", n);
  *mat = alloc_cmatrix(*m, *n);
  for (i = 0; i < *m; ++i) {
    for (j = 0; j < *n; ++j) {
      fscanf(fp, "(%e,%e)%*c", &v_re, &v_im);
      mat_elem(*mat, i, j) = v_re + _Complex_I * v_im;
    }
  }
}

/* read row-major matrix of float complex from file */
static inline void read_cmatrix_r(FILE *fp, int *m, int *n, float complex ***mat) {
  int i, j;
  float v_re, v_im;
  fscanf(fp, "%d", m);
  fscanf(fp, "%d", n);
  *mat = alloc_cmatrix_r(*m, *n);
  for (i = 0; i < *m; ++i) {
    for (j = 0; j < *n; ++j) {
      fscanf(fp, "(%e,%e)%*c", &v_re, &v_im);
      (*mat)[i][j] = v_re + _Complex_I * v_im;
    }
  }
}

/* read column-major matrix of double complex from file */
static inline void read_zmatrix(FILE *fp, int *m, int *n, double complex ***mat) {
  int i, j;
  double v_re, v_im;
  fscanf(fp, "%d", m);
  fscanf(fp, "%d", n);
  *mat = alloc_zmatrix(*m, *n);
  for (i = 0; i < *m; ++i) {
    for (j = 0; j < *n; ++j) {
      fscanf(fp, "(%le,%le)%*c", &v_re, &v_im);
      mat_elem(*mat, i, j) = v_re + _Complex_I * v_im;
    }
  }
}

/* read row-major matrix of double complex from file */
static inline void read_zmatrix_r(FILE *fp, int *m, int *n, double complex ***mat) {
  int i, j;
  double v_re, v_im;
  fscanf(fp, "%d", m);
  fscanf(fp, "%d", n);
  *mat = alloc_zmatrix_r(*m, *n);
  for (i = 0; i < *m; ++i) {
    for (j = 0; j < *n; ++j) {
      fscanf(fp, "(%le,%le)%*c", &v_re, &v_im);
      (*mat)[i][j] = v_re + _Complex_I * v_im;
    }
  }
}

#ifdef __cplusplus
}
#endif

#endif


<|start_filename|>rokko/utility/pyrokko_matrix_123.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_MATRIX_123_HPP
#define PYROKKO_MATRIX_123_HPP

#include <rokko/utility/matrix123.hpp>

#include <rokko/pyrokko_distributed_matrix.hpp>

namespace rokko {

static void pyrokko_generate_matrix_123(wrap_distributed_matrix& mat) {
  if (mat.is_major_col())
    generate_matrix_123(mat.col_ver());
  else
    generate_matrix_123(mat.row_ver());
}

} // namespace rokko

#endif // PYROKKO_MATRIX_123_HPP


<|start_filename|>rokko/lapack/geqrf.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_GEQRF_HPP
#define ROKKO_LAPACK_GEQRF_HPP

#include <complex>
#ifdef I
# undef I
#endif
#include <stdexcept>
#include <boost/type_traits/is_same.hpp>
#include <lapacke.h>
#undef I
#include <rokko/traits/value_t.hpp>
#include "complex_cast.hpp"

namespace rokko {
namespace lapack {

namespace {

template<typename T> struct geqrf_dispatch;
  
template<>
struct geqrf_dispatch<float> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int geqrf(int matrix_layout, lapack_int m, lapack_int n,
                          MATRIX& a, VECTOR& tau) {
    return LAPACKE_sgeqrf(matrix_layout, m, n, storage(a), ld(a), storage(tau));
  }
  template<typename MATRIX, typename VECTOR>
  static lapack_int geqrf(int matrix_layout, lapack_int m, lapack_int n,
                          MATRIX& a, VECTOR& tau, VECTOR& work) {
    return LAPACKE_sgeqrf(matrix_layout, m, n, storage(a), ld(a), storage(tau),
                          storage(work), size(work));
  }
};

template<>
struct geqrf_dispatch<double> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int geqrf(int matrix_layout, lapack_int m, lapack_int n,
                          MATRIX& a, VECTOR& tau) {
    return LAPACKE_dgeqrf(matrix_layout, m, n, storage(a), ld(a), storage(tau));
  }
  template<typename MATRIX, typename VECTOR>
  static lapack_int geqrf(int matrix_layout, lapack_int m, lapack_int n,
                          MATRIX& a, VECTOR& tau, VECTOR& work) {
    return LAPACKE_dgeqrf(matrix_layout, m, n, storage(a), ld(a), storage(tau),
                          storage(work), size(work));
  }
};

template<>
struct geqrf_dispatch<std::complex<float>> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int geqrf(int matrix_layout, lapack_int m, lapack_int n,
                          MATRIX& a, VECTOR& tau) {
    return LAPACKE_cgeqrf(matrix_layout, m, n, complex_cast(storage(a)), ld(a),
                          complex_cast(storage(tau)));
  }
  template<typename MATRIX, typename VECTOR>
  static lapack_int geqrf(int matrix_layout, lapack_int m, lapack_int n,
                          MATRIX& a, VECTOR& tau, VECTOR& work) {
    return LAPACKE_cgeqrf(matrix_layout, m, n, complex_cast(storage(a)), ld(a),
                          complex_cast(storage(tau)), complex_cast(storage(work)),
                          size(work));
  }
};

template<>
struct geqrf_dispatch<std::complex<double>> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int geqrf(int matrix_layout, lapack_int m, lapack_int n,
                          MATRIX& a, VECTOR& tau) {
    return LAPACKE_zgeqrf(matrix_layout, m, n, complex_cast(storage(a)), ld(a),
                          complex_cast(storage(tau)));
  }
  template<typename MATRIX, typename VECTOR>
  static lapack_int geqrf(int matrix_layout, lapack_int m, lapack_int n,
                          MATRIX& a, VECTOR& tau, VECTOR& work) {
    return LAPACKE_zgeqrf(matrix_layout, m, n, complex_cast(storage(a)), ld(a),
                          complex_cast(storage(tau)), complex_cast(storage(work)),
                          size(work));
  }
};

}
  
template<typename MATRIX, typename VECTOR>
lapack_int geqrf(MATRIX& a, VECTOR& tau) {
  static_assert(std::is_same<value_t<MATRIX>, value_t<VECTOR>>::value, "");
  lapack_int m = rows(a);
  lapack_int n = cols(a);
  lapack_int r = std::min(m, n);
  if (size(tau) != r)
    throw std::invalid_argument("vector tau size mismatch");
  return geqrf_dispatch<value_t<MATRIX>>
    ::geqrf((is_col_major(a) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR), m, n, a, tau);
}

template<typename MATRIX, typename VECTOR>
lapack_int geqrf(MATRIX& a, VECTOR& tau, VECTOR& work) {
  static_assert(std::is_same<value_t<MATRIX>, value_t<VECTOR>>::value, "");
  lapack_int m = rows(a);
  lapack_int n = cols(a);
  lapack_int r = std::min(m, n);
  if (size(tau) != r)
    throw std::invalid_argument("vector tau size mismatch");
  if (size(work) < std::max(1, n))
    throw std::invalid_argument("vector work size mismatch");
  return geqrf_dispatch<value_t<MATRIX>>
    ::geqrf((is_col_major(a) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR), m, n, a, tau, work);
}

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_GEQRF_HPP


<|start_filename|>rokko/scalapack/diagonalize_psyevd.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_DIAGONALIZE_PSYEVD_HPP
#define ROKKO_SCALAPACK_DIAGONALIZE_PSYEVD_HPP

#include <rokko/distributed_matrix.hpp>
#include <rokko/parameters.hpp>
#include <rokko/cscalapack.h>
#include <rokko/lapack/diagonalize_get_parameters.hpp>
#include <rokko/utility/timer.hpp>

#include <mpi.h>

namespace rokko {

namespace scalapack {

// eigenvalues & eigenvectors
template<typename T, typename VEC>
parameters diagonalize_psyevd(distributed_matrix<T, rokko::matrix_col_major>& mat,
			       VEC& eigvals, distributed_matrix<T, rokko::matrix_col_major>& eigvecs,
			       parameters const& params) {
  parameters params_out;
  const char uplow = lapack::get_matrix_part(params);
  int info = psyevd(uplow, mat, eigvals, eigvecs);

  params_out.set("info", info);
  if (info) {
    std::cerr << "error at pdsyevd function. info=" << info << std::endl;
  }
  if ((mat.get_myrank() == 0) && params.get_bool("verbose")) {
    lapack::print_verbose("syevd", 'V', uplow);
  }
  return params_out;
}

template<typename T, typename VEC>
parameters diagonalize_psyevd(distributed_matrix<T, rokko::matrix_row_major>& mat,
			       VEC& eigvals, distributed_matrix<T, rokko::matrix_row_major>& eigvecs,
			       parameters const& params) {
  throw std::invalid_argument("scalapack::diagonalize_psyevd() : scalapack doesn't support matrix_row_major.  Use scalapack with matrix_col_major.");
}

} // namespace scalapack
} // namespace rokko

#endif // ROKKO_SCALAPACK_DIAGONALIZE_PSYEVD_HPP


<|start_filename|>rokko/cpblas.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_CPBLAS_H
#define ROKKO_CPBLAS_H

#include <rokko/pblas/pblas_interface.h>

/* PvCOPY */

#define CPBLAS_PCOPY_DECL(NAMES, NAMEL, TYPE) \
void cpblas_ ## NAMES (int N, const TYPE * X, int IX, int JX, const int* DESCX, int INCX, TYPE * Y, int IY, int JY, const int* DESCY, int INCY);

#ifdef __cplusplus
extern "C" {
#endif

CPBLAS_PCOPY_DECL(pscopy, PSCOPY, float);
CPBLAS_PCOPY_DECL(pdcopy, PDCOPY, double);
CPBLAS_PCOPY_DECL(pccopy, PCCOPY, lapack_complex_float);
CPBLAS_PCOPY_DECL(pzcopy, PZCOPY, lapack_complex_double);

#ifdef __cplusplus
}
#endif

#undef CPBLAS_PCOPY_DECL

/* PvDOT, PvDOTU, PvDOTC */

#define CPBLAS_PDOT_DECL(NAMES, NAMEL, TYPE) \
TYPE cpblas_ ## NAMES (int N, const TYPE * X, int IX, int JX, const int* DESCX, int INCX, const TYPE * Y, int IY, int JY, const int* DESCY, int INCY); \
void cpblas_ ## NAMES ## _sub (int N, TYPE * DOT, const TYPE * X, int IX, int JX, const int* DESCX, int INCX, const TYPE * Y, int IY, int JY, const int* DESCY, int INCY);

#ifdef __cplusplus
extern "C" {
#endif

CPBLAS_PDOT_DECL(psdot, PSDOT, float);
CPBLAS_PDOT_DECL(pddot, PDDOT, double);
CPBLAS_PDOT_DECL(pcdotu, PCDOTU, lapack_complex_float);
CPBLAS_PDOT_DECL(pzdotu, PZDOTU, lapack_complex_double);
CPBLAS_PDOT_DECL(pcdotc, PCDOTC, lapack_complex_float);
CPBLAS_PDOT_DECL(pzdotc, PZDOTC, lapack_complex_double);

#ifdef __cplusplus
}
#endif

#undef CPBLAS_PDOT_DECL

/* PvGEMV */

#define CPBLAS_PGEMV_DECL(NAMES, NAMEL, TYPE) \
void cpblas_ ## NAMES (char TRANS, int M, int N, TYPE ALPHA, const TYPE * A, int IA, int JA, const int* DESCA, const TYPE * X, int IX, int JX, const int* DESCX, int INCX, TYPE BETA, TYPE * Y, int IY, int JY, const int* DESCY, int INCY);

#ifdef __cplusplus
extern "C" {
#endif

CPBLAS_PGEMV_DECL(psgemv, PSGEMV, float);
CPBLAS_PGEMV_DECL(pdgemv, PDGEMV, double);
CPBLAS_PGEMV_DECL(pcgemv, PCGEMV, lapack_complex_float);
CPBLAS_PGEMV_DECL(pzgemv, PZGEMV, lapack_complex_double);

#ifdef __cplusplus
}
#endif

#undef CPBLAS_PGEMV_DECL

/* PvGEMM */

#define CPBLAS_PGEMM_DECL(NAMES, NAMEL, TYPE) \
void cpblas_ ## NAMES (char TRANSA, char TRANSB, int M, int N, int K, TYPE ALPHA, const TYPE * A, int IA, int JA, const int* DESCA, const TYPE * B, int IB, int JB, const int* DESCB, TYPE BETA, TYPE * C, int IC, int JC, const int* DESCC);

#ifdef __cplusplus
extern "C" {
#endif

CPBLAS_PGEMM_DECL(psgemm, PSGEMM, float);
CPBLAS_PGEMM_DECL(pdgemm, PDGEMM, double);
CPBLAS_PGEMM_DECL(pcgemm, PCGEMM, lapack_complex_float);
CPBLAS_PGEMM_DECL(pzgemm, PZGEMM, lapack_complex_double);

#ifdef __cplusplus
}
#endif

#undef CPBLAS_PGEMM_DECL

#endif // ROKKO_CPBLAS_H


<|start_filename|>example/c/dense/gev_fixedB_mpi_c.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2016 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <mpi.h>
#include <rokko/rokko.h>
#include <rokko/dense.h>

#include <stdio.h>
#include <stdlib.h>

#include "gev_fixedB_mpi.h"
#include "gev_fixedB_mpi.hpp"

using matrix_major = rokko::matrix_col_major;

void diagonalize_fixedB_c(struct rokko_parallel_dense_ev solver_in, struct rokko_distributed_matrix A_in, struct rokko_distributed_matrix B_in,
			  struct rokko_eigen_vector eigval_in, struct rokko_distributed_matrix eigvec_in, double /* tol */) {
  rokko::parallel_dense_ev& solver = *(static_cast<rokko::parallel_dense_ev*>(solver_in.ptr));
  rokko::distributed_matrix<double, matrix_major>& A = *(static_cast<rokko::distributed_matrix<double,matrix_major>*>(A_in.ptr));
  rokko::distributed_matrix<double, matrix_major>& B = *(static_cast<rokko::distributed_matrix<double,matrix_major>*>(B_in.ptr));
  rokko::distributed_matrix<double, matrix_major>& eigvec = *(static_cast<rokko::distributed_matrix<double,matrix_major>*>(eigvec_in.ptr));
  Eigen::VectorXd& eigval = *(static_cast<Eigen::VectorXd*>(eigval_in.ptr));

  rokko::mapping_bc<matrix_major> map = A.get_mapping();
  rokko::distributed_matrix<double, matrix_major> tmp(map), Binvroot(map), mat(map);

  diagonalize_fixedB(solver, A, B, eigval, eigvec);
}

void set_A_B_c(struct rokko_eigen_matrix locA_in, struct rokko_eigen_matrix locB_in) {
  Eigen::MatrixXd& locA = *(static_cast<Eigen::MatrixXd*>(locA_in.ptr));
  Eigen::MatrixXd& locB = *(static_cast<Eigen::MatrixXd*>(locB_in.ptr));
  set_A_B(locA, locB);
}


<|start_filename|>rokko/matrix_major.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_MATRIX_MAJOR_H
#define ROKKO_MATRIX_MAJOR_H

#ifdef __cplusplus
extern "C" {
#endif

enum {
  rokko_matrix_col_major = 3, rokko_matrix_row_major = 4
};

#ifdef __cplusplus
}
#endif

#endif /* ROKKO_MATRIX_MAJOR_H */


<|start_filename|>test/sparse/distributed_crs_symmetric_matrix_extract.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/various_mpi_comm.hpp>

#include <gtest/gtest.h>

constexpr double eps = 1e-8;

int global_argc;
char** global_argv;

void run_test(std::string const& library, MPI_Comm comm) {
  constexpr int dim = 8;
  std::vector<std::vector<int>> cols = {{0, 4}, {3}, {5}, {1, 7}, {0, 5, 6}, {2, 4}, {4, 7}, {3, 6}};
  std::vector<std::vector<double>> values = {{7.1, 2.8}, {6.4}, {0.5}, {6.4, 3.5}, {2.8, 0.2, 1.4}, {0.5, 0.2}, {1.4, 4.3}, {3.5, 4.3}};

  int num_entries_per_row = std::max_element(cols.cbegin(), cols.cend(),
                                              [] (auto const& a, auto const& b) {
                                                return a.size() < b.size();
                                              })->size();

  std::cout << "library = " << library << std::endl;
  rokko::parallel_sparse_ev solver(library);
  if (comm != MPI_COMM_NULL) {
    auto map = solver.default_mapping(dim, rokko::mpi_comm{comm});
    rokko::distributed_crs_matrix mat(map, num_entries_per_row);
    // storing
    for (int row = map.start_row(); row < map.end_row(); ++row) {
      mat.insert(row, cols[row], values[row]);
    }
    mat.complete();
    // checking
    std::vector<int> cols_check;
    std::vector<double> values_check;
    for (int row = map.start_row(); row < map.end_row(); ++row) {
      mat.extract(row, cols_check, values_check);
      for (int i=0; i<cols_check.size(); ++i) {
        ASSERT_EQ(cols_check[i], cols[row][i]);
        ASSERT_EQ(values_check[i], values[row][i]);
      }
    }
  }
  solver.finalize();
}

TEST(laplacian_crs, eigenvalue) {
  for(auto library : rokko::parallel_sparse_ev::solvers()) {
    run_test(library, MPI_COMM_WORLD);
    run_test(library, create_even_odd_comm_by_split());
    run_test(library, create_even_odd_comm());
    run_test(library, create_even_comm());  // MPI_COMM_NULL for odd rank number
  }
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>rokko/blas/util.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_BLAS_UTIL_HPP
#define ROKKO_BLAS_UTIL_HPP

#include <cblas.h>

namespace rokko {
namespace blas {
namespace util {

template<typename MATRIX>
int op_rows(CBLAS_TRANSPOSE trans, MATRIX const& a) {
  return (trans == CblasNoTrans) ? rows(a) : cols(a);
}
  
template<typename MATRIX>
int op_cols(CBLAS_TRANSPOSE trans, MATRIX const& a) {
  return (trans == CblasNoTrans) ? cols(a) : rows(a);
}
  
} // namespace util
} // namespace blas
} // namespace rokko

#endif // ROKKO_BLAS_UTIL_HPP


<|start_filename|>3rd-party/cblas/testing/cblas_test.h<|end_filename|>
/*
 * cblas_test.h
 * Written by <NAME>
 */
#ifndef CBLAS_TEST_H
#define CBLAS_TEST_H
#include "cblas.h"

#define  TRUE           1
#define  PASSED         1
#define  TEST_ROW_MJR	1

#define  FALSE          0
#define  FAILED         0
#define  TEST_COL_MJR	0

#define  INVALID       -1
#define  UNDEFINED     -1

typedef struct { float real; float imag; } CBLAS_TEST_COMPLEX;
typedef struct { double real; double imag; } CBLAS_TEST_ZOMPLEX;

#include "cblas_mangling.h"

#define F77_xerbla     BLAS_GLOBAL(xerbla, XERBLA)
/*
 * Level 1 BLAS
 */
#define F77_srotg      BLAS_GLOBAL(srotgtest,  SROTG)
#define F77_srotmg     BLAS_GLOBAL(srotmgtest, SROTMG)
#define F77_srot       BLAS_GLOBAL(srottest,   SROT)
#define F77_srotm      BLAS_GLOBAL(srotmtest,  SROTM)
#define F77_drotg      BLAS_GLOBAL(drotgtest,  DROTG)
#define F77_drotmg     BLAS_GLOBAL(drotmgtest, DROTMG)
#define F77_drot       BLAS_GLOBAL(drottest,   DROT)
#define F77_drotm      BLAS_GLOBAL(drotmtest,  DROTM)
#define F77_sswap      BLAS_GLOBAL(sswaptest,  SSWAP)
#define F77_scopy      BLAS_GLOBAL(scopytest,  SCOPY)
#define F77_saxpy      BLAS_GLOBAL(saxpytest,  SAXPY)
#define F77_isamax     BLAS_GLOBAL(isamaxtest, ISAMAX)
#define F77_dswap      BLAS_GLOBAL(dswaptest,  DSWAP)
#define F77_dcopy      BLAS_GLOBAL(dcopytest,  DCOPY)
#define F77_daxpy      BLAS_GLOBAL(daxpytest,  DAXPY)
#define F77_idamax     BLAS_GLOBAL(idamaxtest, IDAMAX)
#define F77_cswap      BLAS_GLOBAL(cswaptest,  CSWAP)
#define F77_ccopy      BLAS_GLOBAL(ccopytest,  CCOPY)
#define F77_caxpy      BLAS_GLOBAL(caxpytest,  CAXPY)
#define F77_icamax     BLAS_GLOBAL(icamaxtest, ICAMAX)
#define F77_zswap      BLAS_GLOBAL(zswaptest,  ZSWAP)
#define F77_zcopy      BLAS_GLOBAL(zcopytest,  ZCOPY)
#define F77_zaxpy      BLAS_GLOBAL(zaxpytest,  ZAXPY)
#define F77_izamax     BLAS_GLOBAL(izamaxtest, IZAMAX)
#define F77_sdot       BLAS_GLOBAL(sdottest,   SDOT)
#define F77_ddot       BLAS_GLOBAL(ddottest,   DDOT)
#define F77_dsdot      BLAS_GLOBAL(dsdottest,  DSDOT)
#define F77_sscal      BLAS_GLOBAL(sscaltest,  SSCAL)
#define F77_dscal      BLAS_GLOBAL(dscaltest,  DSCAL)
#define F77_cscal      BLAS_GLOBAL(cscaltest,  CSCAL)
#define F77_zscal      BLAS_GLOBAL(zscaltest,  ZSCAL)
#define F77_csscal     BLAS_GLOBAL(csscaltest, CSSCAL)
#define F77_zdscal     BLAS_GLOBAL(zdscaltest, ZDSCAL)
#define F77_cdotu      BLAS_GLOBAL(cdotutest,  CDOTU)
#define F77_cdotc      BLAS_GLOBAL(cdotctest,  CDOTC)
#define F77_zdotu      BLAS_GLOBAL(zdotutest,  ZDOTU)
#define F77_zdotc      BLAS_GLOBAL(zdotctest,  ZDOTC)
#define F77_snrm2      BLAS_GLOBAL(snrm2test,  SNRM2)
#define F77_sasum      BLAS_GLOBAL(sasumtest,  SASUM)
#define F77_dnrm2      BLAS_GLOBAL(dnrm2test,  DNRM2)
#define F77_dasum      BLAS_GLOBAL(dasumtest,  DASUM)
#define F77_scnrm2     BLAS_GLOBAL(scnrm2test, SCNRM2)
#define F77_scasum     BLAS_GLOBAL(scasumtest, SCASUM)
#define F77_dznrm2     BLAS_GLOBAL(dznrm2test, DZNRM2)
#define F77_dzasum     BLAS_GLOBAL(dzasumtest, DZASUM)
#define F77_sdsdot     BLAS_GLOBAL(sdsdottest, SDSDOT)
/*
 * Level 2 BLAS
 */
#define F77_s2chke     BLAS_GLOBAL(cs2chke, CS2CHKE)
#define F77_d2chke     BLAS_GLOBAL(cd2chke, CD2CHKE)
#define F77_c2chke     BLAS_GLOBAL(cc2chke, CC2CHKE)
#define F77_z2chke     BLAS_GLOBAL(cz2chke, CZ2CHKE)
#define F77_ssymv      BLAS_GLOBAL(cssymv,  CSSYMV)
#define F77_ssbmv      BLAS_GLOBAL(cssbmv,  CSSBMV)
#define F77_sspmv      BLAS_GLOBAL(csspmv,  CSSPMV)
#define F77_sger       BLAS_GLOBAL(csger,   CSGER)
#define F77_ssyr       BLAS_GLOBAL(cssyr,   CSSYR)
#define F77_sspr       BLAS_GLOBAL(csspr,   CSSPR)
#define F77_ssyr2      BLAS_GLOBAL(cssyr2,  CSSYR2)
#define F77_sspr2      BLAS_GLOBAL(csspr2,  CSSPR2)
#define F77_dsymv      BLAS_GLOBAL(cdsymv,  CDSYMV)
#define F77_dsbmv      BLAS_GLOBAL(cdsbmv,  CDSBMV)
#define F77_dspmv      BLAS_GLOBAL(cdspmv,  CDSPMV)
#define F77_dger       BLAS_GLOBAL(cdger,   CDGER)
#define F77_dsyr       BLAS_GLOBAL(cdsyr,   CDSYR)
#define F77_dspr       BLAS_GLOBAL(cdspr,   CDSPR)
#define F77_dsyr2      BLAS_GLOBAL(cdsyr2,  CDSYR2)
#define F77_dspr2      BLAS_GLOBAL(cdspr2,  CDSPR2)
#define F77_chemv      BLAS_GLOBAL(cchemv,  CCHEMV)
#define F77_chbmv      BLAS_GLOBAL(cchbmv,  CCHBMV)
#define F77_chpmv      BLAS_GLOBAL(cchpmv,  CCHPMV)
#define F77_cgeru      BLAS_GLOBAL(ccgeru,  CCGERU)
#define F77_cgerc      BLAS_GLOBAL(ccgerc,  CCGERC)
#define F77_cher       BLAS_GLOBAL(ccher,   CCHER)
#define F77_chpr       BLAS_GLOBAL(cchpr,   CCHPR)
#define F77_cher2      BLAS_GLOBAL(ccher2,  CCHER2)
#define F77_chpr2      BLAS_GLOBAL(cchpr2,  CCHPR2)
#define F77_zhemv      BLAS_GLOBAL(czhemv,  CZHEMV)
#define F77_zhbmv      BLAS_GLOBAL(czhbmv,  CZHBMV)
#define F77_zhpmv      BLAS_GLOBAL(czhpmv,  CZHPMV)
#define F77_zgeru      BLAS_GLOBAL(czgeru,  CZGERU)
#define F77_zgerc      BLAS_GLOBAL(czgerc,  CZGERC)
#define F77_zher       BLAS_GLOBAL(czher,   CZHER)
#define F77_zhpr       BLAS_GLOBAL(czhpr,   CZHPR)
#define F77_zher2      BLAS_GLOBAL(czher2,  CZHER2)
#define F77_zhpr2      BLAS_GLOBAL(czhpr2,  CZHPR2)
#define F77_sgemv      BLAS_GLOBAL(csgemv,  CSGEMV)
#define F77_sgbmv      BLAS_GLOBAL(csgbmv,  CSGBMV)
#define F77_strmv      BLAS_GLOBAL(cstrmv,  CSTRMV)
#define F77_stbmv      BLAS_GLOBAL(cstbmv,  CSTBMV)
#define F77_stpmv      BLAS_GLOBAL(cstpmv,  CSTPMV)
#define F77_strsv      BLAS_GLOBAL(cstrsv,  CSTRSV)
#define F77_stbsv      BLAS_GLOBAL(cstbsv,  CSTBSV)
#define F77_stpsv      BLAS_GLOBAL(cstpsv,  CSTPSV)
#define F77_dgemv      BLAS_GLOBAL(cdgemv,  CDGEMV)
#define F77_dgbmv      BLAS_GLOBAL(cdgbmv,  CDGBMV)
#define F77_dtrmv      BLAS_GLOBAL(cdtrmv,  CDTRMV)
#define F77_dtbmv      BLAS_GLOBAL(cdtbmv,  CDTBMV)
#define F77_dtpmv      BLAS_GLOBAL(cdtpmv,  CDTPMV)
#define F77_dtrsv      BLAS_GLOBAL(cdtrsv,  CDTRSV)
#define F77_dtbsv      BLAS_GLOBAL(cdtbsv,  CDTBSV)
#define F77_dtpsv      BLAS_GLOBAL(cdtpsv,  CDTPSV)
#define F77_cgemv      BLAS_GLOBAL(ccgemv,  CCGEMV)
#define F77_cgbmv      BLAS_GLOBAL(ccgbmv,  CCGBMV)
#define F77_ctrmv      BLAS_GLOBAL(cctrmv,  CCTRMV)
#define F77_ctbmv      BLAS_GLOBAL(cctbmv,  CCTBMV)
#define F77_ctpmv      BLAS_GLOBAL(cctpmv,  CCTPMV)
#define F77_ctrsv      BLAS_GLOBAL(cctrsv,  CCTRSV)
#define F77_ctbsv      BLAS_GLOBAL(cctbsv,  CCTBSV)
#define F77_ctpsv      BLAS_GLOBAL(cctpsv,  CCTPSV)
#define F77_zgemv      BLAS_GLOBAL(czgemv,  CZGEMV)
#define F77_zgbmv      BLAS_GLOBAL(czgbmv,  CZGBMV)
#define F77_ztrmv      BLAS_GLOBAL(cztrmv,  CZTRMV)
#define F77_ztbmv      BLAS_GLOBAL(cztbmv,  CZTBMV)
#define F77_ztpmv      BLAS_GLOBAL(cztpmv,  CZTPMV)
#define F77_ztrsv      BLAS_GLOBAL(cztrsv,  CZTRSV)
#define F77_ztbsv      BLAS_GLOBAL(cztbsv,  CZTBSV)
#define F77_ztpsv      BLAS_GLOBAL(cztpsv,  CZTPSV)
/*
 * Level 3 BLAS
 */
#define F77_s3chke     BLAS_GLOBAL(cs3chke, CS3CHKE)
#define F77_d3chke     BLAS_GLOBAL(cd3chke, CD3CHKE)
#define F77_c3chke     BLAS_GLOBAL(cc3chke, CC3CHKE)
#define F77_z3chke     BLAS_GLOBAL(cz3chke, CZ3CHKE)
#define F77_chemm      BLAS_GLOBAL(cchemm,  CCHEMM)
#define F77_cherk      BLAS_GLOBAL(ccherk,  CCHERK)
#define F77_cher2k     BLAS_GLOBAL(ccher2k, CCHER2K)
#define F77_zhemm      BLAS_GLOBAL(czhemm,  CZHEMM)
#define F77_zherk      BLAS_GLOBAL(czherk,  CZHERK)
#define F77_zher2k     BLAS_GLOBAL(czher2k, CZHER2K)
#define F77_sgemm      BLAS_GLOBAL(csgemm,  CSGEMM)
#define F77_ssymm      BLAS_GLOBAL(cssymm,  CSSYMM)
#define F77_ssyrk      BLAS_GLOBAL(cssyrk,  CSSYRK)
#define F77_ssyr2k     BLAS_GLOBAL(cssyr2k, CSSYR2K)
#define F77_strmm      BLAS_GLOBAL(cstrmm,  CSTRMM)
#define F77_strsm      BLAS_GLOBAL(cstrsm,  CSTRSM)
#define F77_dgemm      BLAS_GLOBAL(cdgemm,  CDGEMM)
#define F77_dsymm      BLAS_GLOBAL(cdsymm,  CDSYMM)
#define F77_dsyrk      BLAS_GLOBAL(cdsyrk,  CDSYRK)
#define F77_dsyr2k     BLAS_GLOBAL(cdsyr2k, CDSYR2K)
#define F77_dtrmm      BLAS_GLOBAL(cdtrmm,  CDTRMM)
#define F77_dtrsm      BLAS_GLOBAL(cdtrsm,  CDTRSM)
#define F77_cgemm      BLAS_GLOBAL(ccgemm,  CCGEMM)
#define F77_csymm      BLAS_GLOBAL(ccsymm,  CCSYMM)
#define F77_csyrk      BLAS_GLOBAL(ccsyrk,  CCSYRK)
#define F77_csyr2k     BLAS_GLOBAL(ccsyr2k, CCSYR2K)
#define F77_ctrmm      BLAS_GLOBAL(cctrmm,  CCTRMM)
#define F77_ctrsm      BLAS_GLOBAL(cctrsm,  CCTRSM)
#define F77_zgemm      BLAS_GLOBAL(czgemm,  CZGEMM)
#define F77_zsymm      BLAS_GLOBAL(czsymm,  CZSYMM)
#define F77_zsyrk      BLAS_GLOBAL(czsyrk,  CZSYRK)
#define F77_zsyr2k     BLAS_GLOBAL(czsyr2k, CZSYR2K)
#define F77_ztrmm      BLAS_GLOBAL(cztrmm,  CZTRMM)
#define F77_ztrsm      BLAS_GLOBAL(cztrsm,  CZTRSM)

void get_transpose_type(char *type, enum CBLAS_TRANSPOSE *trans);
void get_uplo_type(char *type, enum CBLAS_UPLO *uplo);
void get_diag_type(char *type, enum CBLAS_DIAG *diag);
void get_side_type(char *type, enum CBLAS_SIDE *side);

#endif /* CBLAS_TEST_H */


<|start_filename|>example/c/dense/frank_block_mpi.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2016 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <mpi.h>
#include <rokko/rokko.h>
#include <rokko/utility/frank_matrix.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
  int dim = 10;
  struct rokko_parallel_dense_ev solver;
  struct rokko_grid grid;
  struct rokko_mapping_bc map;
  struct rokko_distributed_matrix mat, Z;
  struct rokko_eigen_vector w;
  struct rokko_parameters params;
  char *library_routine, *library, *routine;

  int provided, myrank, nprocs, i;

  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
  MPI_Comm_size(MPI_COMM_WORLD, &nprocs);

  if (argc >= 2) library_routine = argv[1];
  else library_routine = rokko_parallel_dense_ev_default_solver();
  if (argc >= 3) dim = atoi(argv[2]);
  rokko_split_solver_name(library_routine, &library, &routine);

  if (myrank == 0) {
    printf("library = %s\n", library);
    printf("routine = %s\n", routine);
    printf("dimension = %d\n", dim);
  }
  
  rokko_parallel_dense_ev_construct(&solver, library, argc, argv);
  rokko_grid_construct(&grid, MPI_COMM_WORLD, rokko_grid_row_major);
  rokko_mapping_bc_construct_block_size(&map, dim, 1, grid);
  rokko_distributed_matrix_construct(&mat, map);
  rokko_distributed_matrix_construct(&Z, map);
  rokko_eigen_vector_construct(&w, dim);

  /* generate frank matrix */
  rokko_frank_matrix_generate_distributed_matrix(mat);
  rokko_distributed_matrix_print(mat);
  
  rokko_parameters_construct(&params);
  rokko_parameters_set_string(params, "routine", routine);
  rokko_parallel_dense_ev_diagonalize(solver, mat, w, Z, params);

  if (myrank == 0) {
    printf("Computed Eigenvalues =\n");
    for (i = 0; i < dim; ++i)
      printf("%30.20f\n", rokko_eigen_vector_get(w, i));
  }

  rokko_distributed_matrix_destruct(&mat);
  rokko_distributed_matrix_destruct(&Z);
  rokko_eigen_vector_destruct(&w);
  rokko_parallel_dense_ev_destruct(&solver);
  rokko_mapping_bc_destruct(&map);
  rokko_grid_destruct(&grid);

  MPI_Finalize();
  return 0;
}


<|start_filename|>example/fortran/dense/generate_matrix/matrix012.f90<|end_filename|>
!*****************************************************************************
!
! Rokko: Integrated Interface for libraries of eigenvalue decomposition
!
! Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
!
! 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)
!
!*****************************************************************************

program matrix012
  use rokko
  implicit none
  integer :: dim
  type(rokko_eigen_matrix) :: mat

  dim = 10
  print *,"dimension = ", dim

  call rokko_construct(mat, dim, dim, rokko_matrix_col_major)

  call rokko_matrix012_generate(mat)
  call rokko_print(mat)

  call rokko_destruct(mat)

end program matrix012


<|start_filename|>test/grid/grid_matrix_all_shapes_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/grid.hpp>
#include <rokko/traits/grid2matrix_major.hpp>
#include <rokko/utility/matrix012.hpp>

#include <gtest/gtest.h>


template<typename GRID_MAJOR>
void run_test(GRID_MAJOR, std::array<int,2> size) {
  constexpr int eigen_major = rokko::eigen3_major<GRID_MAJOR>;
  rokko::grid g(MPI_COMM_WORLD, size, GRID_MAJOR{});
  ASSERT_TRUE(g.get_comm() == MPI_COMM_WORLD);
  ASSERT_EQ(g.get_nprow() * g.get_npcol(), g.get_nprocs());

  const int lld = (eigen_major == Eigen::RowMajor) ? g.get_npcol() : g.get_nprow();
  ASSERT_EQ(rokko::matrix012::get_index<eigen_major>(lld, g.get_myrow(), g.get_mycol()), g.get_myrank());
}

TEST(grid_matrix, any_shpae) {
  int nprocs, myrank;
  MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
  MPI_Comm_rank(MPI_COMM_WORLD, &myrank);

  for (int nprow=1; nprow<=nprocs; ++nprow) {
    if (nprocs % nprow == 0) {
      const int npcol = nprocs / nprow;
      if (myrank == 0)
        std::cout << "nprow=" << nprow << " npcol=" << npcol << std::endl;
      run_test(rokko::grid_row_major, {nprow,npcol});
      run_test(rokko::grid_col_major, {nprow,npcol});
    }
  }
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  MPI_Init(&argc, &argv);
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>rokko/scalapack/psyevd.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_PSYEVD_HPP
#define ROKKO_SCALAPACK_PSYEVD_HPP

#include <rokko/cscalapack.h>
#include <rokko/lapack/complex_cast.hpp>
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>

namespace rokko {
namespace scalapack {

using rokko::lapack::storage;
using rokko::lapack::complex_cast;

namespace {

inline int psyevd_dispatch(char jobz, char uplo, int n, float* A, int ia, int ja, const int* descA,
                           float* w, float* Z, int iz, int jz, const int* descZ,
                           float* work, int lwork, int* iwork, int liwork) {
  return cscalapack_pssyevd_work(jobz, uplo, n, A, ia, ja, descA, w, Z, iz, jz, descZ,
                                 work, lwork, iwork, liwork);
}

inline int psyevd_dispatch(char jobz, char uplo, int n, float* A, int ia, int ja, const int* descA,
                           float* w, float* Z, int iz, int jz, const int* descZ) {
  return cscalapack_pssyevd(jobz, uplo, n, A, ia, ja, descA, w, Z, iz, jz, descZ);
}

inline int psyevd_dispatch(char jobz, char uplo, int n, double* A, int ia, int ja, const int* descA,
                           double* w, double* Z, int iz, int jz, const int* descZ,
                           double* work, int lwork, int* iwork, int liwork) {
  return cscalapack_pdsyevd_work(jobz, uplo, n, A, ia, ja, descA, w, Z, iz, jz, descZ,
                                 work, lwork, iwork, liwork);
}

inline int psyevd_dispatch(char jobz, char uplo, int n, double* A, int ia, int ja, const int* descA,
                           double* w, double* Z, int iz, int jz, const int* descZ) {
  return cscalapack_pdsyevd(jobz, uplo, n, A, ia, ja, descA, w, Z, iz, jz, descZ);
}

inline int psyevd_dispatch(char jobz, char uplo, int n, std::complex<float>* A, int ia, int ja, const int* descA,
                           float* w, std::complex<float>* Z, int iz, int jz, const int* descZ) {
  return cscalapack_pcheevd(jobz, uplo, n, complex_cast(A), ia, ja, descA, w, complex_cast(Z), iz, jz, descZ);
}

inline int psyevd_dispatch(char jobz, char uplo, int n, std::complex<double>* A, int ia, int ja, const int* descA,
                           double* w, std::complex<double>* Z, int iz, int jz, const int* descZ) {
  return cscalapack_pzheevd(jobz, uplo, n, complex_cast(A), ia, ja, descA, w, complex_cast(Z), iz, jz, descZ);
}

} // end of anonymous namespace

template<typename MATRIX, typename VECTOR>
int psyevd(char jobz, char uplo, MATRIX& a, VECTOR& w, MATRIX& z) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR>>::value, "");

  const int* descA = a.get_mapping().get_blacs_descriptor().data();
  const int* descZ = z.get_mapping().get_blacs_descriptor().data();
  return psyevd_dispatch(jobz, uplo, a.get_m_global(), a.get_array_pointer(), 0, 0, descA,
                        storage(w), z.get_array_pointer(), 0, 0, descZ);
}

template<typename MATRIX, typename VECTOR0, typename VECTOR1>
int psyevd(char jobz, char uplo, MATRIX& a, VECTOR0& w, MATRIX& z, VECTOR0& work, VECTOR1& iwork) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR0>>::value, "");

  const int* descA = a.get_mapping().get_blacs_descriptor().data();
  const int* descZ = z.get_mapping().get_blacs_descriptor().data();
  return psyevd_dispatch(jobz, uplo, a.get_m_global(), a.get_array_pointer(), 0, 0, descA,
                         storage(w), z.get_array_pointer(), 0, 0, descZ,
                         storage(work), work.size(), storage(iwork), iwork.size());
}

// eigenvalues & eigenvectors (without jobz)
template<typename MATRIX, typename VECTOR>
int psyevd(char uplo, MATRIX& a, VECTOR& w, MATRIX& z) {
  return psyevd('V', uplo, a, w, z);
}

} // end namespace scalapack
} // end namespace rokko

#endif // ROKKO_SCALAPACK_PSYEVD_HPP


<|start_filename|>rokko/scalapack/psyevd_work.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <rokko/scalapack/scalapack_interface.h>

#define CSCALAPACK_PSYEVD_WORK_IMPL(NAMES, NAMEL, TYPE, TYPE_REAL) \
int cscalapack_ ## NAMES ## _work(char jobz, char uplo, int n, \
                                  TYPE* A, int ia, int ja, const int* descA, \
                                  TYPE_REAL* w, TYPE* Z, int iz, int jz, const int* descZ, \
                                  TYPE* work, int lwork, int* iwork, int liwork) { \
  int ia_f = ia + 1; \
  int ja_f = ja + 1; \
  int iz_f = iz + 1; \
  int jz_f = jz + 1; \
  int info; \
  ROKKO_GLOBAL(NAMES, NAMEL) (&jobz, &uplo, &n, A, &ia_f, &ja_f, descA, w, Z, &iz_f, &jz_f, descZ, \
                              work, &lwork, iwork, &liwork, &info); \
  return info; \
}

CSCALAPACK_PSYEVD_WORK_IMPL(pssyevd, PSSYEVD, float, float)
CSCALAPACK_PSYEVD_WORK_IMPL(pdsyevd, PDSYEVD, double, double)
CSCALAPACK_PSYEVD_WORK_IMPL(pcheevd, PCHEEVD, lapack_complex_float, float)
CSCALAPACK_PSYEVD_WORK_IMPL(pzheevd, PZHEEVD, lapack_complex_double, double)

#undef CSCALAPACK_PSYEVD_WORK_IMPL


<|start_filename|>rokko/utility/sort_eigenpairs.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_SORT_EIGENPAIRS_HPP
#define ROKKO_UTILITY_SORT_EIGENPAIRS_HPP

#include <vector>
#include <utility>
#include <algorithm>
#include <rokko/eigen3.hpp>

namespace {

template<typename T>
struct less {
  bool operator()(std::pair<T, int> const& lhs, std::pair<T, int> const& rhs) const {
    return lhs < rhs;
  }
};

template<typename T>
struct more {
  bool operator()(std::pair<T, int> const& lhs, std::pair<T, int> const& rhs) const {
  return lhs > rhs;
  }
};

} // end of unnamed namespace

namespace rokko {

// sort eigenvalues and eigenvectors
template<typename T, int SIZE, int ROWS, int COLS, int MATRIX_MAJOR>
void sort_eigenpairs(const Eigen::Vector<T, SIZE>& eigval,
                     const Eigen::Matrix<T,ROWS,COLS,MATRIX_MAJOR>& eigvec,
                     Eigen::Vector<T, SIZE>& eigval_sorted,
                     Eigen::Matrix<T,ROWS,COLS,MATRIX_MAJOR>& eigvec_sorted,
                     bool ascending = true) {
  int dim = eigval.size();
  std::vector<std::pair<T, std::size_t>> entries;
  entries.reserve(dim);
  for (int i = 0; i < dim; ++i) {
    entries.emplace_back(std::make_pair(eigval(i), i));
  }
  if (ascending)
    std::sort(entries.begin(), entries.end(), ::less<T>());
  else
    std::sort(entries.begin(), entries.end(), ::more<T>());

  if (eigval_sorted.size() != dim) eigval_sorted.resize(dim);
  if (MATRIX_MAJOR == Eigen::ColMajor) {
    if (eigvec_sorted.cols() != dim) eigvec_sorted.resize(Eigen::NoChange, dim);
    for (int i = 0; i < dim; ++i) {
      eigval_sorted(i) = entries[i].first;
      eigvec_sorted.col(i) = eigvec.col(entries[i].second);
    }
  } else {
    if (eigvec_sorted.rows() != dim) eigvec_sorted.resize(dim, Eigen::NoChange);
    for (int i = 0; i < dim; ++i) {
      eigval_sorted(i) = entries[i].first;
      eigvec_sorted.row(i) = eigvec.row(entries[i].second);
    }
  }
}

} // namespace rokko

#endif // ROKKO_UTILITY_SORT_EIGENPAIRS_HPP


<|start_filename|>rokko/parameters.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_PARAMETERS_HPP
#define ROKKO_PARAMETERS_HPP

#include <iostream>
#include <list>
#include <map>
#include <string>
#include <boost/any.hpp>

#include <stdexcept>

namespace rokko {

class parameters {
private:
  using map_type = std::map<std::string, boost::any>;
  using mapped_type = map_type::mapped_type;
public:
  using key_type = map_type::key_type;
  using value_type = map_type::value_type;

  parameters() = default;
  parameters(parameters const& map_in) : map_(map_in.get_map()) {}
  ~parameters() = default;
  
  void clear() { map_.clear(); }
  void clear(key_type const& key) { map_.erase(map_.find(key)); }
  // set "value" for "key"
  template<typename T>
  void set(key_type const& key, T const& value) {
    map_[key] = value;
  }
  void set(key_type const& key, const char *value) {
    map_[key] = std::string(value);
  }
  // returns if parameter with "key" is defined or not
  bool defined(key_type const& key) const {return (map_.find(key) != map_.cend()); }
  // returns list of keys
  std::list<key_type> keys() const {
    std::list<key_type> keys;
    for(auto const& p : map_) { keys.emplace_back(p.first); }
    return keys;
  }
  // returns value of parameter in type T
  template<typename T>
  T get(key_type const& key) const {
    if (type(key) != typeid(T)) {
      //std::cout << "type(key)=" << type(key).name() << " typeid(T)=" << typeid(T).name() << std::endl;
      throw std::invalid_argument("parameters::get() : type given as template parameter is not correct.");
    }
    return boost::any_cast<T>(map_.find(key)->second);
  }
  const std::type_info& type(key_type const& key) const { return map_.find(key)->second.type(); }
  // return parameter as string
  std::string get_string(key_type const& key) const {
    if (type(key) == typeid(std::string)) {
      return get<std::string>(key);
    }
    if (type(key) == typeid(const char*)) {
      return std::string(get<const char*>(key));
    }
    if (type(key) == typeid(int)) {
      return std::to_string(get<int>(key));
    }
    if (type(key) == typeid(double)) {
      return std::to_string(get<double>(key));
    }
    if (type(key) == typeid(bool)) {
      return get<bool>(key) ? "true" : "false";
    }
    if (type(key) == typeid(char)) {
      return std::string{get<char>(key)};
    }
    else {
      throw std::invalid_argument("parameters::get_string() : value type given as template parameter must be char*, string, int, or double.");
    }
  }
  bool get_bool(key_type const& key) const {
    if (defined(key)) {
      if (type(key) == typeid(bool)) {
        return get<bool>(key);
      }
      else {
        throw std::invalid_argument("parameters::get_bool() : the key \"" + key + "\" is not bool type");
      }
    }
    return false;
  }
  std::map<std::string, boost::any>const& get_map() const { return map_; }
  
private:
  std::map<std::string, boost::any> map_;
};


//void get_2string(rokko::parameters const& params, std::string const& key, char keyword_char, std::string const& keyword_str) {
//  if (params.type(key) == typeid(const char*)) {
//    letter = *(params.get<const char*>(key));
//  } else if (params.type(key) == typeid(const char*)) {
//    letter = params.get<char>(key);    
//  }
//}

template <typename T>
bool get_key(rokko::parameters const& params, std::string const& key, T& value) {
  if (params.defined(key)) {
    if (params.type(key) == typeid(T)) {
      value = params.get<T>(key);
      return true;
    }
  }
  return false;
}


} // namespace rokko

#endif // ROKKO_PARAMETERS_HPP


<|start_filename|>rokko/lapack/diagonalize_sygv.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_DIAGONALIZE_SYGV_HPP
#define ROKKO_LAPACK_DIAGONALIZE_SYGV_HPP

#include <rokko/parameters.hpp>
#include <rokko/eigen3.hpp>
#include <rokko/utility/timer.hpp>
#include <rokko/lapack.hpp>
#include <rokko/lapack/diagonalize_get_parameters.hpp>

namespace rokko {
namespace lapack {

// only eigenvalues
template<typename T, int MATRIX_MAJOR, typename VEC>
parameters diagonalize_sygv(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mata, Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& matb,
			     VEC& eigvals,
			     parameters const& params) {
  parameters params_out;
  const char jobz = 'N';  // only eigenvalues
  const char uplow = get_matrix_part(params);

  constexpr int itype = 1;
  int info = sygv(itype, jobz, uplow, mata, matb, eigvals);

  if (info) {
    std::cerr << "error at sygv function. info=" << info << std::endl;
  }
  if (params.get_bool("verbose")) {
    print_verbose("sygv", jobz, uplow);
  }

  return params_out;
}

// eigenvalues / eigenvectors
template<typename T, int MATRIX_MAJOR, typename VEC>
parameters diagonalize_sygv(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& mata, Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& matb,
			     VEC& eigvals,
			     Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>& eigvecs,
			     parameters const& params) {
  parameters params_out;
  const char jobz = 'V';  // eigenvalues / eigenvectors
  const char uplow = get_matrix_part(params);

  constexpr int itype = 1;
  int info = sygv(itype, jobz, uplow, mata, matb, eigvals);

  eigvecs = mata;
  if (info) {
    std::cerr << "error at sygv function. info=" << info << std::endl;
  }
  if (params.get_bool("verbose")) {
    print_verbose("sygv", jobz, uplow);
  }

  return params_out;
}

} // namespace lapack
} // namespace rokko

#endif // ROKKO_LAPACK_DIAGONALIZE_SYGV_HPP


<|start_filename|>rokko/solver_name_c.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/solver_name.h>
#include <rokko/utility/solver_name.hpp>
#include <rokko/copy_string.hpp>

void rokko_split_solver_name(char* str, char** library_ptr, char** routine_ptr) {
  std::string tmp_library, tmp_routine;
  rokko::split_solver_name(str, tmp_library, tmp_routine); 
  *library_ptr = copy_string(tmp_library);
  *routine_ptr = copy_string(tmp_routine);
}


<|start_filename|>rokko/original/lanczos_tridiagonalization.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_ORIGINAL_LANCZOS_TRIDIAGONALIZATION_HPP
#define ROKKO_ORIGINAL_LANCZOS_TRIDIAGONALIZATION_HPP

#include <rokko/mpi/reduction.hpp>

namespace rokko {

namespace original {

class lanczos {
public:
  template<typename VEC, typename MAT>
  static void tridiagonalization(const rokko::distributed_mfree& mat, VEC& alpha, VEC& beta, MAT& u) {
    constexpr double eps_lanczos = 1e-8;

    const int dim = mat.get_dim();
    MPI_Comm comm = mat.get_comm();
    Eigen::VectorXd tmp(dim), y(dim);

    u.col(0).setRandom();
    u.col(0) /= sqrt(rokko::all_reduce(u.col(0).squaredNorm(), comm));

    y.setZero();
    mat.multiply(u.col(0).data(), y.data());
    alpha(0) = rokko::all_reduce(y.dot(u.col(0)), comm);
    tmp = y - alpha(0) * u.col(0);
    for (int i=1; i<dim; ++i) {
      beta(i-1) = sqrt(rokko::all_reduce(tmp.squaredNorm(), comm));
      if (beta(i-1) < eps_lanczos)  throw std::runtime_error("beta is too small");
      u.col(i) = tmp / beta(i-1);

      y.setZero();
      mat.multiply(u.col(i).data(), y.data());
      alpha(i) = rokko::all_reduce(y.dot(u.col(i)), comm);
      tmp = y - alpha(i) * u.col(i) - beta(i-1) * u.col(i-1);
    }
  }
};

} // namespace original

} // namespace rokko

#endif // ROKKO_ORIGINAL_LANCZOS_TRIDIAGONALIZATION_HPP


<|start_filename|>rokko/scalapack/diagonalize_psyev.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_DIAGONALIZE_PSYEV_HPP
#define ROKKO_SCALAPACK_DIAGONALIZE_PSYEV_HPP

#include <rokko/distributed_matrix.hpp>
#include <rokko/parameters.hpp>
#include <rokko/scalapack.hpp>
#include <rokko/lapack/diagonalize_get_parameters.hpp>
#include <rokko/utility/timer.hpp>

namespace rokko {
namespace scalapack {

// eigenvalues & eigenvectors
template<typename T, typename VEC>
parameters diagonalize_psyev(distributed_matrix<T, rokko::matrix_col_major>& mat,
			      VEC& eigvals, distributed_matrix<T, rokko::matrix_col_major>& eigvecs,
			      parameters const& params) {
  parameters params_out;
  const char uplow = lapack::get_matrix_part(params);
  int info = psyev(uplow, mat, eigvals, eigvecs);
  params_out.set("info", info);
  if (info) {
    std::cerr << "error at pdsyev function. info=" << info << std::endl;
  }
  if ((mat.get_myrank() == 0) && params.get_bool("verbose")) {
    lapack::print_verbose("syev", 'V', uplow);
  }
  return params_out;
}

template<typename T, typename VEC>
parameters diagonalize_psyev(distributed_matrix<T, rokko::matrix_row_major>& mat,
			      VEC& eigvals, distributed_matrix<T, rokko::matrix_row_major>& eigvecs,
			      parameters const& params) {
  throw std::invalid_argument("scalapack::diagonalize_psyev() : scalapack doesn't support matrix_row_major.  Use scalapack with matrix_col_major.");
}

// only eigenvalues
template<typename T, typename VEC>
parameters diagonalize_psyev(distributed_matrix<T, rokko::matrix_col_major>& mat,
			      VEC& eigvals,
			      parameters const& params) {
  parameters params_out;
  const char uplow = lapack::get_matrix_part(params);
  int info = psyev(uplow, mat, eigvals);
  params_out.set("info", info);
  if (info) {
    std::cerr << "error at pdsyev function. info=" << info << std::endl;
  }
  if ((mat.get_myrank() == 0) && params.get_bool("verbose")) {
    lapack::print_verbose("syev", 'N', uplow);
  }
  return params_out;
}

template<typename T, typename VEC>
parameters diagonalize_psyev(distributed_matrix<T, rokko::matrix_row_major>& mat,
			      VEC& eigvals,
			      parameters const& params) {
  throw std::invalid_argument("scalapack::diagonalize_psyev() : scalapack doesn't support matrix_row_major.  Use scalapack with matrix_col_major.");
}

} // namespace scalapack
} // namespace rokko

#endif // ROKKO_SCALAPACK_DIAGONALIZE_PSYEV_HPP


<|start_filename|>rokko/utility/frank_matrix.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_FRANK_MATRIX_HPP
#define ROKKO_UTILITY_FRANK_MATRIX_HPP

#include <cmath>
#include <stdexcept>
#include <rokko/config.h>
#include <rokko/eigen3.hpp>
#if defined(ROKKO_HAVE_PARALLEL_DENSE_SOLVER)
# include <rokko/distributed_matrix.hpp>
#endif

namespace rokko {

class frank_matrix {
public:
  template<typename T, int ROWS, int COLS>
  static void generate(Eigen::Matrix<T,ROWS,COLS,Eigen::ColMajor>& mat) {
    if (mat.rows() != mat.cols())
      throw std::invalid_argument("frank_matrix::generate() : non-square matrix");
    const int n = mat.rows();
    for(int j = 0; j < mat.cols(); ++j) {
      for(int i = 0; i < mat.rows(); ++i) {
        mat(i,j) = n - std::max(i, j);
      }
    }
  }

  template<typename T, int ROWS, int COLS>
  static void generate(Eigen::Matrix<T,ROWS,COLS,Eigen::RowMajor>& mat) {
    if (mat.rows() != mat.cols())
      throw std::invalid_argument("frank_matrix::generate() : non-square matrix");
    const int n = mat.rows();
    for(int i = 0; i < mat.rows(); ++i) {
      for(int j = 0; j < mat.cols(); ++j) {
        mat(i,j) = n - std::max(i, j);
      }
    }
  }

#if defined(ROKKO_HAVE_PARALLEL_DENSE_SOLVER)
  template<typename T>
  static void generate(rokko::distributed_matrix<T, matrix_col_major>& mat) {
    auto const& map = mat.get_mapping();
    if (map.get_m_global() != map.get_n_global())
      throw std::invalid_argument("frank_matrix::generate() : non-square matrix");

    for(int local_j = 0; local_j < map.get_n_local(); ++local_j) {
      int global_j = map.translate_l2g_col(local_j);
      for(int local_i = 0; local_i < map.get_m_local(); ++local_i) {
        int global_i = map.translate_l2g_row(local_i);
        mat.set_local(local_i, local_j, map.get_m_global() - std::max(global_i, global_j));
      }
    }
  }

  template<typename T>
  static void generate(rokko::distributed_matrix<T, matrix_row_major>& mat) {
    auto const& map = mat.get_mapping();
     if (map.get_m_global() != map.get_n_global())
      throw std::invalid_argument("frank_matrix::generate() : non-square matrix");

     for(int local_i = 0; local_i < map.get_m_local(); ++local_i) {
      int global_i = map.translate_l2g_row(local_i);
      for(int local_j = 0; local_j < map.get_n_local(); ++local_j) {
        int global_j = map.translate_l2g_col(local_j);
        mat.set_local(local_i, local_j, map.get_m_global() - std::max(global_i, global_j));
      }
    }
  }

  // another (slower) implementation using set_global function
  template<typename T>
  static void generate_global(rokko::distributed_matrix<T, matrix_col_major>& mat) {
    auto const& map = mat.get_mapping();
    if (map.m_global() != map.n_global())
      throw std::invalid_argument("frank_matrix::generate() : non-square matrix");

    for(int global_j=0; global_j<map.n_global(); ++global_j) {
      for(int global_i=0; global_i<map.m_global(); ++global_i) {
        mat.set_global(global_i, global_j, map.m_global() - std::max(global_i, global_j) );
      }
    }
  }

  template<typename T>
  static void generate_global(rokko::distributed_matrix<T, matrix_row_major>& mat) {
    auto const& map = mat.get_mapping();
    if (map.m_global() != map.n_global())
      throw std::invalid_argument("frank_matrix::generate() : non-square matrix");

    for(int global_i=0; global_i<map.m_global(); ++global_i) {
      for(int global_j=0; global_j<map.n_global(); ++global_j) {
        mat.set_global(global_i, global_j, map.m_global() - std::max(global_i, global_j) );
      }
    }
  }
#endif

  // calculate k-th smallest eigenvalue of dim-dimensional Frank matrix (k=0...dim-1)
  static double eigenvalue(int dim, int k) {
    return 1 / (2 * (1 - std::cos(M_PI * (2 * k + 1) / (2 * dim + 1))));
  }
};

} // namespace rokko

#endif // ROKKO_UTILITY_FRANK_MATRIX_HPP


<|start_filename|>rokko/scalapack/psyev_work.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <rokko/scalapack/scalapack_interface.h>

#define CSCALAPACK_PSYEV_WORK_IMPL(NAMES, NAMEL, TYPE, TYPE_REAL) \
int cscalapack_ ## NAMES ## _work(char jobz, char uplo, int n, \
                                  TYPE* A, int ia, int ja, const int* descA, \
                                  TYPE_REAL* w, TYPE* Z, int iz, int jz, const int* descZ, \
                                  TYPE* work, int lwork) { \
  int ia_f = ia + 1; \
  int ja_f = ja + 1; \
  int iz_f = iz + 1; \
  int jz_f = jz + 1; \
  int info; \
  ROKKO_GLOBAL(NAMES, NAMEL) (&jobz, &uplo, &n, A, &ia_f, &ja_f, descA, w, Z, &iz_f, &jz_f, descZ, \
                              work, &lwork, &info); \
  return info; \
}

CSCALAPACK_PSYEV_WORK_IMPL(pssyev, PSSYEV, float, float)
CSCALAPACK_PSYEV_WORK_IMPL(pdsyev, PDSYEV, double, double)
CSCALAPACK_PSYEV_WORK_IMPL(pcheev, PCHEEV, lapack_complex_float, float)
CSCALAPACK_PSYEV_WORK_IMPL(pzheev, PZHEEV, lapack_complex_double, double)

#undef CSCALAPACK_PSYEV_WORK_IMPL


<|start_filename|>example/fortran/dense/generate_matrix/minij_set_elem.f90<|end_filename|>
!*****************************************************************************
!
! Rokko: Integrated Interface for libraries of eigenvalue decomposition
!
! Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
!
! 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)
!
!*****************************************************************************

program generate_minij_matrix
  use rokko
  implicit none
  integer :: dim
  type(rokko_eigen_matrix) :: mat

  integer :: i, j

  dim = 10
  print *,"dimension = ", dim

  call rokko_construct(mat, dim, dim, rokko_matrix_col_major)

  ! generate minij matrix
  do i = 1, dim
     do j = 1, dim
        call rokko_set_elem(mat, i, j, dble(min(i,j)))
     enddo
  enddo
  call rokko_print(mat)

  call rokko_destruct(mat)

end program generate_minij_matrix


<|start_filename|>test/grid/grid_mpi_1proc.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/grid.hpp>

#include <gtest/gtest.h>

void run_test(rokko::grid const& g) {
  ASSERT_TRUE(g.get_comm() == MPI_COMM_WORLD);
  // The following tests should be run in single MPI process.
  ASSERT_EQ(g.get_nprocs(), 1);
  ASSERT_EQ(g.get_nprow(), 1);
  ASSERT_EQ(g.get_npcol(), 1);
  ASSERT_EQ(g.get_myrank(), 0);
  ASSERT_EQ(g.get_myrow(), 0);
  ASSERT_EQ(g.get_mycol(), 0);
  ASSERT_EQ(g.calculate_grid_row(g.get_myrank()), 0);
  ASSERT_EQ(g.calculate_grid_col(g.get_myrank()), 0);
}

TEST(grid, grid_1process) {
  MPI_Comm comm = MPI_COMM_WORLD;
  {
    rokko::grid g(comm); // default should be row-major
    ASSERT_TRUE(g.is_row_major());
    ASSERT_FALSE(g.is_col_major());
    run_test(g);
  }
  {
    rokko::grid g(comm, rokko::grid_row_major);
    ASSERT_TRUE(g.is_row_major());
    ASSERT_FALSE(g.is_col_major());
    run_test(g);
  }
  {
    rokko::grid g(comm, rokko::grid_col_major);
    ASSERT_FALSE(g.is_row_major());
    ASSERT_TRUE(g.is_col_major());
    run_test(g);
  }
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  MPI_Init(&argc, &argv);
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>rokko/scalapack/pstebz.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_PSTEBZ_HPP
#define ROKKO_SCALAPACK_PSTEBZ_HPP

#include <lapacke.h>
#include <rokko/cscalapack.h>
#include <rokko/eigen3.hpp>
#include <rokko/lapack/storage.hpp>
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>

namespace rokko {
namespace scalapack {

using rokko::lapack::storage;

namespace {

inline int pstebz_dispatch(int ictxt, char range, char order, int n,
                           double vl, double vu, int il, int iu,
                           double abstol, const double* d, const double* e, int& m, int& nsplit,
                           double* w, int* iblock, int* isplit) {
  return cscalapack_pdstebz(ictxt, range, order, n,
                            vl, vu, il, iu,
                            abstol, d, e, &m, &nsplit,
                            w, iblock, isplit);
}

} // end of anonymous namespace

template<typename T, typename VECTOR, typename VECTOR_INT>
int pstebz(int ictxt, char range, char order,
           T vl, T vu, int il, int iu,
           T abstol, const VECTOR& d, const VECTOR& e, int& m, int& nsplit,
           VECTOR& w, VECTOR_INT& iblock, VECTOR_INT& isplit) {
  static_assert(std::is_same<value_t<VECTOR>, T>::value, "");
  lapack_int n = size(d);

  return pstebz_dispatch(ictxt, range, order, n,
                         vl, vu, il, iu,
                         abstol, storage(d), storage(e), m, nsplit,
                         storage(w), storage(iblock), storage(isplit));
}

} // end namespace scalapack
} // end namespace rokko

#endif // ROKKO_SCALAPACK_PSTEBZ_HPP


<|start_filename|>rokko/scalapack/diagonalize_psyevr.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_DIAGONALIZE_PSYEVR_HPP
#define ROKKO_SCALAPACK_DIAGONALIZE_PSYEVR_HPP

#include <rokko/distributed_matrix.hpp>
#include <rokko/parameters.hpp>
#include <rokko/cscalapack.h>
#include <rokko/lapack/diagonalize_get_parameters.hpp>
#include <rokko/scalapack/psyevr.hpp>
#include <rokko/utility/timer.hpp>

#include <mpi.h>

namespace rokko {

namespace scalapack {

// eigenvalues & eigenvectors
template<typename T, typename VEC>
parameters diagonalize_psyevr(distributed_matrix<T, rokko::matrix_col_major>& mat,
			VEC& eigvals, distributed_matrix<T, rokko::matrix_col_major>& eigvecs,
			parameters const& params) {
  parameters params_out;
  const char uplow = lapack::get_matrix_part(params);
  real_t<T> vl = 0, vu = 0;
  int il = 0, iu = 0;
  const char range = lapack::get_eigenvalues_range(params, vu, vl, iu, il);

  int m, nz;
  int info = psyevr(range, uplow, mat,
                    vl, vu, il, iu, m, nz,
                    eigvals, eigvecs);
  if (info) {
    std::cerr << "error at pdsyevr function. info=" << info << std::endl;
  }
  params_out.set("info", info);
  params_out.set("m", m);
  params_out.set("nz", nz);
  if ((mat.get_myrank() == 0) && params.get_bool("verbose")) {
    lapack::print_verbose("syevr", 'V', range, uplow, vl, vu, il, iu, params_out);
  }
  return params_out;
}

template<typename T, typename VEC>
parameters diagonalize_psyevr(distributed_matrix<T, rokko::matrix_row_major>& mat,
			VEC& eigvals, distributed_matrix<T, rokko::matrix_row_major>& eigvecs,
			parameters const& params) {
  throw std::invalid_argument("scalapack::diagonalize_psyevr() : scalapack doesn't support matrix_row_major.  Use scalapack with matrix_col_major.");
}

// only eigenvalues
template<typename T, typename VEC>
parameters diagonalize_psyevr(distributed_matrix<T, rokko::matrix_col_major>& mat,
			       VEC& eigvals,
			       parameters const& params) {
  parameters params_out;
  const char uplow = lapack::get_matrix_part(params);
  real_t<T> vl = 0, vu = 0;
  int il = 0, iu = 0;
  const char range = lapack::get_eigenvalues_range(params, vu, vl, iu, il);
  int m, nz;
  int info = psyevr(range, uplow, mat,
                    vl, vu, il, iu, m, nz,
                    eigvals);

  if (info) {
    std::cerr << "error at pdsyevr function. info=" << info << std::endl;
  }
  params_out.set("info", info);
  params_out.set("m", m);
  params_out.set("nz", nz);
  if ((mat.get_myrank() == 0) && params.get_bool("verbose")) {
    lapack::print_verbose("syevr", 'N', range, uplow, vl, vu, il, iu, params_out);
  }
  return params_out;
}

template<typename T, typename VEC>
parameters diagonalize_psyevr(distributed_matrix<T, rokko::matrix_row_major>& mat,
			       VEC& eigvals,
			       parameters const& params) {
  throw std::invalid_argument("scalapack::diagonalize_psyevr() : scalapack doesn't support matrix_row_major.  Use scalapack with matrix_col_major.");
}

} // namespace scalapack
} // namespace rokko

#endif // ROKKO_SCALAPACK_DIAGONALIZE_PSYEVR_HPP


<|start_filename|>rokko/scalapack/pstedc.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cscalapack.h>
#include <stdlib.h>
#include <rokko/scalapack/scalapack_interface.h>

#define CSCALAPACK_PSTEDC_IMPL(NAMES, NAMEL, TYPE) \
int cscalapack_## NAMES (char compz, int n, TYPE* d, TYPE* e, \
                         TYPE* Q, int iq, int jq, const int* descQ) { \
  /* call for querying optimal size of work array */ \
  int lwork = -1; \
  int liwork = -1; \
  TYPE work_query[1]; \
  int iwork_query[1]; \
  int info; \
  info = cscalapack_## NAMES ##_work(compz, n, d, e, \
                                     Q, iq, jq, descQ, \
                                     work_query, lwork, iwork_query, liwork); \
  if (info) return info; \
  \
  /* allocate work arrays */ \
  lwork = (int)work_query[0]; \
  TYPE* work = (TYPE*)malloc( sizeof(TYPE) * lwork ); \
  liwork = iwork_query[0]; \
  int* iwork = (int*)malloc( sizeof(int) * liwork ); \
  if (work == NULL || iwork == NULL) return 1; \
  \
  /* call for computation */ \
  info = cscalapack_## NAMES ##_work(compz, n, d, e, \
                                     Q, iq, jq, descQ, \
                                     work, lwork, iwork, liwork);   \
  free(work); \
  free(iwork); \
  return info; \
}

CSCALAPACK_PSTEDC_IMPL(psstedc, PSSTEDC, float)
CSCALAPACK_PSTEDC_IMPL(pdstedc, PDSTEDC, double)

#undef CSCALAPACK_PSTEDC_IMPL


<|start_filename|>rokko/pblas.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2017 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_PBLAS_HPP
#define ROKKO_PBLAS_HPP

#include <rokko/cpblas.h>
#include <rokko/lapack/complex_cast.hpp>

using rokko::lapack::complex_cast;

namespace rokko {
namespace pblas {

// pcopy

namespace {

#define PBLAS_PCOPY_IMPL(NAMES, TYPE)                                   \
inline void pcopy_dispatch(int n, const TYPE * x, int ix, int jx, const int* descx, int incx, TYPE * y, int iy, int jy, const int* descy, int incy) { cpblas_ ## NAMES (n, complex_cast(x), ix, jx, descx, incx, complex_cast(y), iy, jy, descy, incy); }
    
PBLAS_PCOPY_IMPL(pscopy, float);
PBLAS_PCOPY_IMPL(pdcopy, double);
PBLAS_PCOPY_IMPL(pccopy, std::complex<float>);
PBLAS_PCOPY_IMPL(pzcopy, std::complex<double>);

#undef PBLAS_PCOPY_IMPL

}

template<typename MATRIX>
void pcopy(int n, const MATRIX& x, int ix, int jx, int incx, MATRIX& y, int iy, int jy, int incy) {
  const int* descx = x.get_mapping().get_blacs_descriptor();
  const int* descy = y.get_mapping().get_blacs_descriptor();
  pcopy_dispatch(n, x.get_array_pointer(), ix, jx, descx, incx,
                 y.get_array_pointer(), iy, jy, descy, incy);
}

// pdot, pdotu, pdotc

namespace {
    
#define PBLAS_PDOT_IMPL(NAMEX, NAMES, TYPE) \
inline TYPE NAMEX ## _dispatch (int n, const TYPE * x, int ix, int jx, const int* descx, int incx, const TYPE * y, int iy, int jy, const int* descy, int incy) { \
  TYPE dot; \
  cpblas_ ## NAMES ## _sub (n, complex_cast(&dot), complex_cast(x), ix, jx, descx, incx, complex_cast(y), iy, jy, descy, incy); \
  return dot; \
}

PBLAS_PDOT_IMPL(pdot, psdot, float);
PBLAS_PDOT_IMPL(pdot, pddot, double);
PBLAS_PDOT_IMPL(pdot, pcdotc, std::complex<float>);
PBLAS_PDOT_IMPL(pdot, pzdotc, std::complex<double>);
PBLAS_PDOT_IMPL(pdotu, pcdotu, std::complex<float>);
PBLAS_PDOT_IMPL(pdotu, pzdotu, std::complex<double>);
PBLAS_PDOT_IMPL(pdotc, psdot, float);
PBLAS_PDOT_IMPL(pdotc, pddot, double);
PBLAS_PDOT_IMPL(pdotc, pcdotc, std::complex<float>);
PBLAS_PDOT_IMPL(pdotc, pzdotc, std::complex<double>);

#undef PBLAS_PDOT_IMPL

}
  
template<typename VECTOR>
typename VECTOR::value_type pdot(int n, const VECTOR& x, int ix, int jx, int incx,
                                 const VECTOR& y, int iy, int jy, int incy) {
  const int* descx = x.get_mapping().get_blacs_descriptor().data();
  const int* descy = y.get_mapping().get_blacs_descriptor().data();
  return pdot_dispatch(n, x.get_array_pointer(), ix, jx, descx, incx,
                       y.get_array_pointer(), iy, jy, descy, incy);
}

template<typename VECTOR>
typename VECTOR::value_type pdotc(int n, const VECTOR& x, int ix, int jx, int incx,
                                 const VECTOR& y, int iy, int jy, int incy) {
  const int* descx = x.get_mapping().get_blacs_descriptor().data();
  const int* descy = y.get_mapping().get_blacs_descriptor().data();
  return pdotc_dispatch(n, x.get_array_pointer(), ix, jx, descx, incx,
                        y.get_array_pointer(), iy, jy, descy, incy);
}

template<typename VECTOR>
typename VECTOR::value_type pdotu(int n, const VECTOR& x, int ix, int jx, int incx,
                                 const VECTOR& y, int iy, int jy, int incy) {
  const int* descx = x.get_mapping().get_blacs_descriptor().data();
  const int* descy = y.get_mapping().get_blacs_descriptor().data();
  return pdotu_dispatch(n, x.get_array_pointer(), ix, jx, descx, incx,
                        y.get_array_pointer(), iy, jy, descy, incy);
}

// pgemv

namespace {
    
#define PBLAS_PGEMV_IMPL(NAMES, TYPE) \
inline void pgemv_dispatch(char trans, int m, int n, TYPE alpha, const TYPE* a, int ia, int ja, const int* desca, const TYPE* x, int ix, int jx, const int* descx, int incx, TYPE beta, TYPE * y, int iy, int jy, const int* descy, int incy) { \
  cpblas_ ## NAMES (trans, m, n, complex_cast(alpha), complex_cast(a), ia, ja, desca, complex_cast(x), ix, jx, descx, incx, complex_cast(beta), complex_cast(y), iy, jy, descy, incy); \
}

PBLAS_PGEMV_IMPL(psgemv, float);
PBLAS_PGEMV_IMPL(pdgemv, double);
PBLAS_PGEMV_IMPL(pcgemv, std::complex<float>);
PBLAS_PGEMV_IMPL(pzgemv, std::complex<double>);

#undef PBLAS_PGEMV_IMPL

}
  
template<typename MATRIX, typename VECTOR, typename T>
void pgemv(char trans, T alpha, const MATRIX& a, const VECTOR& x, int incx,
           T beta, VECTOR& y, int incy) {
  const int* desca = a.get_mapping().get_blacs_descriptor().data();
  const int* descx = x.get_mapping().get_blacs_descriptor().data();
  const int* descy = y.get_mapping().get_blacs_descriptor().data();
  pgemv_dispatch(trans, a.get_m_global(), a.get_n_global(), alpha,
                 a.get_array_pointer(), 0, 0, desca,
                 x.get_array_pointer(), 0, 0, descx, incx, beta,
                 y.get_array_pointer(), 0, 0, descy, incy);
}

// pgemm

namespace {
    
#define PBLAS_PGEMM_IMPL(NAMES, TYPE) \
inline void pgemm_dispatch(char transa, char transb, int m, int n, int k, TYPE alpha, const TYPE* a, int ia, int ja, const int* desca, const TYPE* b, int ib, int jb, const int* descb, TYPE beta, TYPE* c, int ic, int jc, const int* descc) { \
  cpblas_ ## NAMES (transa, transb, m, n, k, complex_cast(alpha), complex_cast(a), ia, ja, desca, complex_cast(b), ib, jb, descb, complex_cast(beta), complex_cast(c), ic, jc, descc); \
}

PBLAS_PGEMM_IMPL(psgemm, float);
PBLAS_PGEMM_IMPL(pdgemm, double);
PBLAS_PGEMM_IMPL(pcgemm, std::complex<float>);
PBLAS_PGEMM_IMPL(pzgemm, std::complex<double>);

#undef PBLAS_PGEMM_IMPL

}
  
template<typename MATRIX, typename T>
void pgemm(char transa, char transb, T alpha, const MATRIX& a, const MATRIX& b,
           T beta, MATRIX& c) {
  const int* desca = a.get_mapping().get_blacs_descriptor().data();
  const int* descb = b.get_mapping().get_blacs_descriptor().data();
  const int* descc = c.get_mapping().get_blacs_descriptor().data();
  pgemm_dispatch(transa, transb, a.get_m_global(), b.get_n_global(), a.get_n_global(), alpha,
                 a.get_array_pointer(), 0, 0, desca,
                 b.get_array_pointer(), 0, 0, descb, beta,
                 c.get_array_pointer(), 0, 0, descc);
}

} // namespace pblas
} // namespace rokko

#endif // ROKKO_PBLAS_HPP


<|start_filename|>rokko/eigen_matrix.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_EIGEN_MATRIX_H
#define ROKKO_EIGEN_MATRIX_H

#include <rokko/matrix_major.h>

#ifdef __cplusplus
extern "C" {
#endif

struct rokko_eigen_matrix {
  void* ptr;
  int major;
};

void rokko_eigen_matrix_construct(struct rokko_eigen_matrix* matrix, int dim1, int dim2,
  int matrix_major);
void rokko_eigen_matrix_construct_array_sizes(struct rokko_eigen_matrix* matrix,
                                              int dim1, int dim2, double* ptr, int matrix_major);
void rokko_eigen_matrix_destruct(struct rokko_eigen_matrix* matrix);
void rokko_eigen_matrix_print(struct rokko_eigen_matrix matrix);
void rokko_eigen_matrix_generate_function(struct rokko_eigen_matrix matrix,
  double (*func)(int i, int j));
void rokko_eigen_matrix_generate_function_p(struct rokko_eigen_matrix matrix,
  double (*func)(const int* i, const int* j));
void rokko_eigen_matrix_generate_function1(struct rokko_eigen_matrix matrix,
  double (*func)(int i, int j));
void rokko_eigen_matrix_generate_function1_p(struct rokko_eigen_matrix matrix,
  double (*func)(const int* i, const int* j));
void rokko_eigen_matrix_set(struct rokko_eigen_matrix matrix,
  int i, int j, double value);
void rokko_eigen_matrix_set1(struct rokko_eigen_matrix matrix,
  int i, int j, double value);
double rokko_eigen_matrix_get(struct rokko_eigen_matrix matrix,
  int i, int j);
double rokko_eigen_matrix_get1(struct rokko_eigen_matrix matrix,
  int i, int j);
int rokko_eigen_matrix_get_m(struct rokko_eigen_matrix matrix);
int rokko_eigen_matrix_get_n(struct rokko_eigen_matrix matrix);
double* rokko_eigen_matrix_get_array_pointer(struct rokko_eigen_matrix matrix);

#ifdef __cplusplus
}
#endif

#endif /* ROKKO_EIGEN_MATRIX_H */


<|start_filename|>test/sparse/heisenberg_mfree_output_market_through_crs.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/heisenberg_hamiltonian_mfree.hpp>
#include <rokko/utility/output_matrix_market.hpp>

#include <sstream>

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

TEST(heisenberg_mfree, output_market_through_crs) {
  std::string library(rokko::parallel_sparse_ev::default_solver());
  if (global_argc >= 2) library = global_argv[1];

  int L = (global_argc >= 3) ? std::stoi(global_argv[2]) : 4;
  int dim = 1 << L;
  std::vector<std::pair<int, int>> lattice;
  for (int i = 0; i < L; ++i) lattice.emplace_back(std::make_pair(i, (i+1) % L));

  rokko::heisenberg_mfree op(L, lattice);
  std::ostringstream os_direct, os_crs;

  rokko::output_matrix_market(op, os_direct);

  rokko::parallel_sparse_ev solver(library);
  auto map = solver.default_mapping(dim, rokko::mpi_comm{op.get_comm()});
  const int num_entries_per_row = lattice.size() + 1;
  rokko::distributed_crs_matrix mat(map, num_entries_per_row);
  rokko::output_matrix_market(op, os_crs);

  ASSERT_TRUE(os_direct.str() == os_crs.str());

  solver.finalize();
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>example/c/dense/helmert.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.h>
#include <rokko/utility/helmert_matrix.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
  int dim = 10;
  struct rokko_serial_dense_ev solver;
  struct rokko_eigen_matrix mat, Z;
  struct rokko_eigen_vector diag, w;
  struct rokko_parameters params;
  double *diag_ptr;
  char *library_routine, *library, *routine;
  int i;
  
  if (argc >= 2) library_routine = argv[1];
  else library_routine = rokko_serial_dense_ev_default_solver();
  if (argc >= 3) dim = atoi(argv[2]);
  rokko_split_solver_name(library_routine, &library, &routine);
  rokko_serial_dense_ev_construct(&solver, library, argc, argv);

  printf("library = %s\n", library);
  printf("routine = %s\n", routine);
  printf("dimension = %d\n", dim);
  
  rokko_eigen_matrix_construct(&mat, dim, dim, rokko_matrix_col_major);
  rokko_eigen_matrix_construct(&Z, dim, dim, rokko_matrix_col_major);
  rokko_eigen_vector_construct(&w, dim);
  rokko_parameters_construct(&params);
  rokko_parameters_set_string(params, "routine", routine);
  
  /* generate matrix whose eigenvectors are helmert matrix */
  rokko_helmert_matrix_generate_eigen_matrix(mat);
  rokko_eigen_vector_construct(&diag, dim);
  diag_ptr = rokko_eigen_vector_get_array_pointer(diag);
  for (i=0; i<dim; ++i)
    diag_ptr[i] = i + 1;
  rokko_helmert_matrix_generate_for_given_eigenvalues_eigen_matrix(mat, diag);
  rokko_eigen_matrix_print(mat);

  rokko_serial_dense_ev_diagonalize_params(solver, mat, w, Z, params);

  printf("Computed Eigenvalues =\n");
  for (i = 0; i < dim; ++i)
    printf("%30.20f\n", rokko_eigen_vector_get(w, i));

  rokko_parameters_destruct(&params);
  rokko_eigen_matrix_destruct(&mat);
  rokko_eigen_matrix_destruct(&Z);
  rokko_eigen_vector_destruct(&w);
  rokko_serial_dense_ev_destruct(&solver);

  return 0;
}


<|start_filename|>rokko/solver.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SOLVER_HPP
#define ROKKO_SOLVER_HPP

#include <rokko/config.h>
#include <rokko/serial_dense_ev.hpp>
#ifdef ROKKO_HAVE_PARALLEL_DENSE_SOLVER
# include <rokko/parallel_dense_ev.hpp>
#endif
#ifdef ROKKO_HAVE_PARALLEL_SPARSE_SOLVER
# include <rokko/parallel_sparse_ev.hpp>
#endif

#endif // ROKKO_SOLVER_HPP


<|start_filename|>rokko/lapack/hegvx.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_HEGVX_HPP
#define ROKKO_LAPACK_HEGVX_HPP

#include <complex>
#include <lapacke.h>
#undef I
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>
#include "complex_cast.hpp"
#include <rokko/lapack/storage.hpp>
#include <rokko/alias_template_function.hpp>

namespace rokko {
namespace lapack {

namespace {

template<typename T> struct hegvx_dispatch;

template<>
struct hegvx_dispatch<float> {
  template<typename MATRIX, typename VECTOR, typename VECTOR_INT>
  static lapack_int hegvx(int matrix_layout, lapack_int itype, char jobz, char uplo, lapack_int n,
                          MATRIX& a, MATRIX& b,
                          float vl, float vu, lapack_int il, lapack_int iu, float abstol,
                          lapack_int& m, VECTOR& w, VECTOR_INT& ifail) {
  return LAPACKE_ssygvx(matrix_layout, itype, jobz, uplo, n, storage(a), ld(a), storage(b), ld(b), vl, vu, il, iu, abstol, &m, storage(w), storage(ifail));
  }
};

template<>
struct hegvx_dispatch<double> {
  template<typename MATRIX, typename VECTOR, typename VECTOR_INT>
  static lapack_int hegvx(int matrix_layout, lapack_int itype, char jobz, char uplo, lapack_int n,
                          MATRIX& a, MATRIX& b,
                          double vl, double vu, lapack_int il, lapack_int iu, double abstol,
                          lapack_int& m, VECTOR& w, VECTOR_INT& ifail) {
    return LAPACKE_dsygvx(matrix_layout, itype, jobz, uplo, n, storage(a), ld(a), storage(b), ld(b), vl, vu, il, iu, abstol, &m, storage(w), storage(ifail));
  }
};

template<>
struct hegvx_dispatch<std::complex<float>> {
  template<typename MATRIX, typename VECTOR, typename VECTOR_INT>
  static lapack_int hegvx(int matrix_layout, lapack_int itype, char jobz, char uplo, lapack_int n,
                          MATRIX& a, MATRIX& b,
                          float vl, float vu, lapack_int il, lapack_int iu, float abstol,
                          lapack_int& m, VECTOR& w, VECTOR_INT& ifail) {
    return LAPACKE_chegvx(matrix_layout, itype, jobz, uplo, n, storage(a), ld(a), storage(b), ld(b), vl, vu, il, iu, abstol, &m, storage(w), storage(ifail));
  }
};

template<>
struct hegvx_dispatch<std::complex<double>> {
  template<typename MATRIX, typename VECTOR, typename VECTOR_INT>
  static lapack_int hegvx(int matrix_layout, lapack_int itype, char jobz, char uplo, lapack_int n,
                          MATRIX& a, MATRIX& b,
                          double vl, double vu, lapack_int il, lapack_int iu, double abstol,
                          lapack_int& m, VECTOR& w, VECTOR_INT& ifail) {
    return LAPACKE_zhegvx(matrix_layout, itype, jobz, uplo, n, storage(a), ld(a), storage(b), ld(b), vl, vu, il, iu, abstol, &m, storage(w), storage(ifail));
  }
};

} // end of anonymous namespace

template<typename MATRIX, typename VECTOR, typename VECTOR_INT>
lapack_int hegvx(lapack_int itype, char jobz, char uplo,
                 MATRIX& a, MATRIX& b,
                 double vl, double vu, lapack_int il, lapack_int iu, double abstol,
                 lapack_int& m, VECTOR& w, VECTOR_INT& ifail) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR>>::value, "");
  lapack_int n = rows(a);
  if (rows(a) != cols(a))
    throw std::invalid_argument("matrix A size mismatch");
  //if (size(w) != n)
  //  throw std::invalid_argument("vector w size mismatch");
  return hegvx_dispatch<value_t<MATRIX>>::
    hegvx((is_col_major(a) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR), itype, jobz, uplo, n, a, b, w, vl, vu, il, iu, abstol, m, w, ifail);
 }

ALIAS_TEMPLATE_FUNCTION(sygvx, hegvx);

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_HEGVX_HPP


<|start_filename|>rokko/pblas/pdotc.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/cpblas.h>

#define CPBLAS_PDOTC_IMPL(NAMES, NAMEL, TYPE) \
TYPE cpblas_ ## NAMES (int n, const TYPE * x, int ix, int jx, const int* descx, int incx, const TYPE * y, int iy, int jy, const int* descy, int incy) { \
  int ix_f = ix + 1; \
  int jx_f = jx + 1; \
  int iy_f = iy + 1; \
  int jy_f = jy + 1; \
  TYPE dotc; \
  ROKKO_GLOBAL(NAMES, NAMEL) (&n, &dotc, x, &ix_f, &jx_f, descx, &incx, y, &iy_f, &jy_f, descy, &incy); \
  return dotc; \
} \
void cpblas_ ## NAMES ## _sub (int n, TYPE * dotc, const TYPE * x, int ix, int jx, const int* descx, int incx, const TYPE * y, int iy, int jy, const int* descy, int incy) { \
  int ix_f = ix + 1; \
  int jx_f = jx + 1; \
  int iy_f = iy + 1; \
  int jy_f = jy + 1; \
  ROKKO_GLOBAL(NAMES, NAMEL) (&n, dotc, x, &ix_f, &jx_f, descx, &incx, y, &iy_f, &jy_f, descy, &incy); \
}

CPBLAS_PDOTC_IMPL(pcdotc, PCDOTC, lapack_complex_float);
CPBLAS_PDOTC_IMPL(pzdotc, PZDOTC, lapack_complex_double);

#undef CPBLAS_PDOTC_IMPL


<|start_filename|>test/generate_matrix/eigen_matrix.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2013-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/eigen3.hpp>

#include <gtest/gtest.h>

TEST(eigen_matrix, 123) {

  // M = 1 4 7
  //     2 5 8
  //     3 6 9
  //
  // a = 5
  // 
  // u = 1
  //     2
  //     3
  //
  // v = 4
  //     5
  //     6
  // 
  // w = au + Mv = 37
  //               87
  //              137

  int dim = 3;
  Eigen::MatrixXd M(dim,dim);
  M << 1,2,3,4,5,6,7,8,9;
  std::cout << M << std::endl;
  double a = 5.0;
  Eigen::VectorXd u(dim);
  u << 1,2,3;
  Eigen::VectorXd v(dim);
  v << 4,5,6;

  Eigen::VectorXd w = a*u+M*v;
  std::cout << w << std::endl;
  ASSERT_EQ(w[0], 37.);
  ASSERT_EQ(w[1], 87.);
  ASSERT_EQ(w[2], 137.);

  // u^t M = 30 36 42
  ASSERT_EQ( (u.transpose()*M.col(0)), 30.);
  ASSERT_EQ( (u.transpose()*M.col(1)), 36.);
  ASSERT_EQ( (u.transpose()*M.col(2)), 42.);
}

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}


<|start_filename|>example/lapack/gesvd.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2017 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <rokko/blas.hpp>
#include <rokko/lapack/gesvd.hpp>
#include <rokko/lapack/lange.hpp>
#include <rokko/eigen3.hpp>
#include <iostream>
#include <stdexcept>

int main(int argc, char** argv) {
  constexpr double eps = 1e-10;
  int m = 3;
  int n = 5;
  if (argc > 2) {
    m = std::stoi(argv[1]);
    n = std::stoi(argv[2]);
  }
  int r = std::min(m, n);
  
  // generate matrix
  Eigen::MatrixXd a(m, n);
  for (int j = 0; j < n; ++j) {
    for (int i = 0; i < m; ++i) {
      a(i, j) = n - std::max(i, j);
    }
  }
  std::cout << "Matrix A: " << std::endl << a << std::endl;

  // singular value decomposition
  Eigen::VectorXd s(r);
  Eigen::MatrixXd u(m, r), vt(r, n);
  Eigen::MatrixXd t = a;
  Eigen::VectorXd superb(r-1);
  int info = rokko::lapack::gesvd('S', 'S', t, s, u, vt, superb);
  if (info) throw std::runtime_error("Error: gesvd failed");
  std::cout << "Matrix U: " << std::endl << u << std::endl;
  std::cout << "Singular values: " << std::endl << s << std::endl;
  std::cout << "Matrix Vt: " << std::endl << vt << std::endl;

  // orthogonality check
  Eigen::MatrixXd check1 = u.adjoint() * u - Eigen::MatrixXd::Identity(r, r);
  double norm1 = rokko::lapack::lange('F', check1);
  std::cout << "|| U^t U - I || = " << norm1 << std::endl;
  if (norm1 > eps) throw std::runtime_error("Error: orthogonality check");

  Eigen::MatrixXd check2 = vt * vt.adjoint() - Eigen::MatrixXd::Identity(r, r);
  double norm2 = rokko::lapack::lange('F', check2);
  std::cout << "|| V^t V - I || = " << norm2 << std::endl;
  if (norm2 > eps) throw std::runtime_error("Error: orthogonality check");

  // solution check
  Eigen::MatrixXd check3 = u.adjoint() * a * vt.adjoint();
  for (int i = 0; i < r; ++i) check3(i, i) -= s(i);
  double norm3 = rokko::lapack::lange('F', check3);
  std::cout << "|| U^t A V - diag(S) || = " << norm3 << std::endl;
  if (norm3 > eps) throw std::runtime_error("Error: solution check");

  return 0;
}


<|start_filename|>rokko/ceigenexa.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_CEIGENEXA_H
#define ROKKO_CEIGENEXA_H

#include <mpi.h>

#ifdef __cplusplus
extern "C" {
#endif

void ceigenexa_init(void);
void ceigenexa_init1(MPI_Comm comm);
void ceigenexa_init2(MPI_Comm comm, char grid_major);

void ceigenexa_free(void);
void ceigenexa_free1(int flag);

// int ceigenexa_get_optdim(int n_min, int n_unroll, int delta_L1, int delta_L2);

void ceigenexa_get_matdims(int nprow, int npcol, int n, int* nx, int* ny);

void ceigenexa_get_procs(int* procs, int* x_procs, int* y_procs);

void ceigenexa_get_id(int* id, int* x_id, int* y_id);

int ceigenexa_loop_start(int istart, int nnod, int inod);

int ceigenexa_loop_end(int iend, int nnod, int inod);

int ceigenexa_translate_l2g(int ictr, int nnod, int inod);

int ceigenexa_translate_g2l(int ictr, int nnod, int inod);
  
void ceigenexa_eigen_s(int n, int nvec, double* a, int lda, double* w, double* z, int ldz,
                       int m_forward, int m_backword, char mode);

void ceigenexa_eigen_sx(int n, int nvec, double* a, int lda, double* w, double* z, int ldz,
                        int m_forward, int m_backword, char mode);

#ifdef __cplusplus
}
#endif

#endif // ROKKO_EIGENEXA_WRAP_H


<|start_filename|>rokko/scalapack/diagonalize_qr.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_SCALAPACK_DIAGONALIZE_QR_HPP
#define ROKKO_SCALAPACK_DIAGONALIZE_QR_HPP

#include <rokko/distributed_matrix.hpp>
#include <rokko/parameters.hpp>
#include <rokko/cscalapack.h>
#include <rokko/lapack/diagonalize_get_parameters.hpp>
#include <rokko/scalapack/diagonalize_psyevx.hpp>
#include <rokko/utility/timer.hpp>

#include <mpi.h>

namespace rokko {
namespace scalapack {

// qr (pdsyevx) eigenvalues & eigenvectors
template<typename T, typename MATRIX_MAJOR, typename VEC>
parameters diagonalize_qr(distributed_matrix<T, MATRIX_MAJOR>& mat,
			       VEC& eigvals, distributed_matrix<T, MATRIX_MAJOR>& eigvecs,
			       parameters params) {
  if (params.defined("abstol")) {
    real_t<T> abstol = params.get<real_t<T>>("abstol");
    if (abstol > 0) {
      params.set("abstol", - abstol);
    }
  }
  parameters params_out = diagonalize_psyevx(mat, eigvals, eigvecs, params);

  if (params.get_bool("verbose")) {
    std::cout << "finished pdsyevx (qr)" << std::endl;
  }

  return params_out;
}

// qr (pdsyevx) only eigenvalues
template<typename T, typename MATRIX_MAJOR, typename VEC>
parameters diagonalize_qr(distributed_matrix<T, MATRIX_MAJOR>& mat,
			       VEC& eigvals,
			       parameters params) {
  if (params.defined("abstol")) {
    real_t<T> abstol = params.get<real_t<T>>("abstol");
    if (abstol > 0) {
      params.set("abstol", - abstol);
    }
  }
  parameters params_out = diagonalize_psyevx(mat, eigvals, params);

  if (params.get_bool("verbose")) {
    std::cout << "finished pdsyevx (qr)" << std::endl;
  }

  return params_out;
}

} // namespace scalapack
} // namespace rokko

#endif // ROKKO_SCALAPACK_DIAGONALIZE_QR_HPP


<|start_filename|>test/lapack/syev.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2017 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <gtest/gtest.h>
#include <rokko/eigen3.hpp>
#include <rokko/lapack.hpp>

constexpr double eps = 1e-10;
constexpr double eps_float = 1e-4;

TEST(syev, dsyev) {
  int n = 32;

  // generate matrix
  Eigen::MatrixXd a = Eigen::MatrixXd::Random(n, n);
  a += a.transpose().eval();
  
  // diagonalization
  Eigen::MatrixXd u = a;
  Eigen::VectorXd w(n);
  int info = rokko::lapack::syev('V', 'U', u, w);
  EXPECT_EQ(0, info);

  // orthogonality check
  Eigen::MatrixXd check1 = u.adjoint() * u - Eigen::MatrixXd::Identity(n, n);
  double norm1 = rokko::lapack::lange('F', check1);
  EXPECT_NEAR(0.0, norm1, eps);

  // eigenvalue check
  Eigen::MatrixXd check2 = u.adjoint() * a * u;
  for (int i = 0; i < n; ++i) check2(i, i) -= w(i);
  double norm2 = rokko::lapack::lange('F', check2);
  EXPECT_NEAR(0.0, norm2, eps);
}

TEST(syev, ssyev) {
  int n = 32;

  // generate matrix
  Eigen::MatrixXf a = Eigen::MatrixXf::Random(n, n);
  a += a.transpose().eval();
  
  // diagonalization
  Eigen::MatrixXf u = a;
  Eigen::VectorXf w(n);
  int info = rokko::lapack::syev('V', 'U', u, w);
  EXPECT_EQ(0, info);

  // orthogonality check
  Eigen::MatrixXf check1 = u.adjoint() * u - Eigen::MatrixXf::Identity(n, n);
  float norm1 = rokko::lapack::lange('F', check1);
  EXPECT_NEAR(0.0, norm1, eps_float);

  // eigenvalue check
  Eigen::MatrixXf check2 = u.adjoint() * a * u;
  for (int i = 0; i < n; ++i) check2(i, i) -= w(i);
  float norm2 = rokko::lapack::lange('F', check2);
  EXPECT_NEAR(0.0, norm2, eps_float);
}


<|start_filename|>example/scalapack/pssyevd_f.f90<|end_filename|>
!*****************************************************************************
!
! Rokko: Integrated Interface for libraries of eigenvalue decomposition
!
! Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
!
! 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)
!
!*****************************************************************************

program main
  use mpi
  implicit none
  integer, parameter :: n = 8, nb = 1
  integer :: provided, ierr, myrank, nprocs
  integer :: icontxt, npcol, nprow, desc(9)
  integer :: i, j, info
  real(4), allocatable :: a(:, :), z(:,:), w(:)
  integer :: lwork, liwork
  real(4), allocatable :: work(:)
  integer, allocatable :: iwork(:)

  call MPI_init_thread(MPI_THREAD_MULTIPLE, provided, ierr)
  call MPI_comm_rank(MPI_COMM_WORLD, myrank, ierr)
  call MPI_comm_size(MPI_COMM_WORLD, nprocs, ierr)
  nprow = int(sqrt(1. * nprocs + 0.5))
  npcol = int(1. * nprocs / nprow)
  if (myrank == 0) then
     print *, "n =", n
     print *, "nprocs =", nprocs
     print *, "nprow =", nprow
     print *, "npcol =", npcol
     if ((nprocs /= nprow * npcol) .or. (mod(n, nprow) /= 0) .or. &
          (mod(n, npcol) /= 0)) then
        print *, "incompatible matrix size and number of processes"
        call MPI_Abort(MPI_COMM_WORLD, 127, ierr)
     end if
  end if
  call BLACS_get(0, 0, icontxt)
  call BLACS_gridinit(icontxt, 'R', nprow, npcol)

  call descinit(desc, n, n, nb, nb, 0, 0, icontxt, n/nprow, info)
  allocate(a(n/nprow, n/npcol), z(n/nprow, n/npcol), w(n))
  do j = 1, n
     do i = 1, n
        call pselset(a, i, j, desc, real(min(i, j)))
     end do
  end do

  lwork = -1
  liwork = 1
  allocate(work(1), iwork(1))
  call pssyevd('V', 'U', n, a, 1, 1, desc, w, z, 1, 1, desc, work, lwork, iwork, liwork, info)
  lwork = int(work(1))
  liwork = iwork(1)
  deallocate(work, iwork)
  allocate(work(lwork), iwork(liwork))

  call pssyevd('V', 'U', n, a, 1, 1, desc, w, z, 1, 1, desc, work, lwork, iwork, liwork, info)
  if (myrank == 0) then
     print *, "eigenvalues:", w(:)
  end if

  deallocate(a, z, w, work, iwork)
  call BLACS_gridexit(icontxt)
  call MPI_finalize(ierr)
end program main


<|start_filename|>test/blas/gemv.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <gtest/gtest.h>
#include <rokko/eigen3.hpp>
#include <rokko/blas.hpp>

constexpr double eps = 1e-12;

TEST(GemvTest, GemvTest) {
  std::size_t n = 16;
  Eigen::MatrixXd a = Eigen::MatrixXd::Random(n, n);
  Eigen::VectorXd x = Eigen::VectorXd::Random(n);
  Eigen::VectorXd y = Eigen::VectorXd::Random(n);
  Eigen::VectorXd yr = y;
  double alpha = 2.3;
  double beta = 0.5;
  rokko::blas::gemv(CblasNoTrans, alpha, a, x, 1, beta, yr, 1);

  Eigen::VectorXd yc(n);
  for (std::size_t i = 0; i < n; ++i) {
    yc(i) = beta * y(i);
    for (std::size_t j = 0; j < n; ++j) {
      yc(i) += alpha * a(i, j) * x(j);
    }
    EXPECT_NEAR(yc(i), yr(i), eps);
  }
}


<|start_filename|>test/factory/register_products.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/factory.hpp>
#include <iostream>
#include <string>
#include <rokko/utility/macro_join.hpp>

class test_base {
public:
  virtual ~test_base() = default;
  virtual void print() = 0;
};

template<typename SOLVER>
class test_wrapper : public test_base {
  using solver_type = SOLVER;

public:
  test_wrapper() = default;
  virtual ~test_wrapper() = default;
  void print() {
    solver_impl_.print();
  }

private:
  solver_type solver_impl_;
};

class test1 {
public:
  test1() = default;
  ~test1() = default;
  void print() {
    std::cout << "print_test1" << std::endl;
  }
};

class test2 {
public:
  test2() = default;
  ~test2() = default;
  void print() {
    std::cout << "print_test2" << std::endl;
  }
};


using test_factory = rokko::factory<test_base>;

template<>
test_factory *test_factory::instance_ = nullptr;

#define ROKKO_REGISTER_TEST(solver, name, priority) \
namespace { namespace ROKKO_JOIN(register, __LINE__) { \
struct register_caller { \
  using factory = rokko::factory<test_base>; \
  using product = test_wrapper<solver>; \
  register_caller() { factory::instance()->register_creator<product>(name, priority); } \
} caller; \
} }

ROKKO_REGISTER_TEST(test1, "test1", 10)
ROKKO_REGISTER_TEST(test2, "test2", 20)

int main() {
  test_factory::product_pointer_type solver_impl = test_factory::instance()->make_product("test2");
  solver_impl->print();
  std::cerr << "product_names:" << std::endl;
  for(auto name : test_factory::instance()->product_names()) {
    std::cerr << name << std::endl;
  }
  std::cerr << "default_product_name = " << test_factory::instance()->default_product_name() << std::endl;
}


<|start_filename|>rokko/utility/pyrokko_generate_matrix.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef PYROKKO_GENERATE_MATRIX_HPP
#define PYROKKO_GENERATE_MATRIX_HPP

#include <rokko/eigen3.hpp>

namespace rokko {

template<int MATRIX_MAJOR>
void pyrokko_generate(Eigen::Ref<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,MATRIX_MAJOR>> mat, std::function<double(int, int)> const& func) {
  for(int i = 0; i < mat.rows(); ++i) {
    for(int j = 0; j < mat.cols(); ++j) {
      mat(i, j) = func(i, j);
    }
  }
}

} // namespace rokko

#endif // PYROKKO_GENERATE_MATRIX_HPP


<|start_filename|>tutorial/titpack/01_lapack_cxx/sample-05.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

// C++ version of TITPACK Ver.2 by <NAME>

/************* Sample main program #5 *****************
* 1d Heisenberg antiferromagnet with 16 spins
* Eigenvector of an excited state by inv1
******************************************************/

#include "titpack.hpp"

int main() {
  std::cout.precision(10);

  // lattice structure
  int n = 16;
  int ibond = n;
  std::vector<int> ipair;
  for (int i = 0; i < ibond; ++i) {
    ipair.emplace_back(i);
    ipair.emplace_back((i + 1) % n);
  }

  // Hamiltonian parameters
  std::vector<double> bondwt(ibond, -1);
  std::vector<double> zrtio(ibond, 1);

  // table of configurations
  std::vector<int> list1;
  std::vector<std::pair<int, int>> list2;
  int idim = sz(n, 0, list1, list2);
  // You may alternatively use szdy or sztn for faster processing
  //   int idim = szdy(n, 0, list1, list2);
  // or
  //   int idim = sztn(n, 0, list1, list2);

  // Eigenvalues
  int nvec = 1;
  matrix_type v(idim, 2);
  std::vector<double> E, alpha, beta;
  matrix_type coeff;
  matrix_type wk;
  matrix_type x;
  for (int k = 0; k < 2; ++k) {
    int iv = 20 + (idim / 2) * k;
    int itr = lnc1(n, ipair, bondwt, zrtio, nvec, iv, E, alpha, beta, coeff, wk, list1, list2);
    
    std::cout << "# " << k << " [Eigenvalues]\n";
    for (int i = 0; i < 4; ++i) std::cout << '\t' << E[i];
    std::cout << std::endl;

    lncv1(n, ipair, bondwt, zrtio, nvec, iv, alpha, beta, coeff, x, itr, wk, list1, list2);
    for (int i = 0; i < idim; ++i) v(i, k) = x(i, 0);
  }
  
  // Degeneracy check
  std::vector<double> norm;
  int idgn = orthg(v, norm, 2);
  std::cout << " [Degeneracy] : " << idgn << "   Norm : " << norm[0] << '\t' << norm[1] << std::endl;
}


<|start_filename|>rokko/traits/grid2matrix_major.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_TRAITS_GRID2MATRIX_MAJOR_HPP
#define ROKKO_TRAITS_GRID2MATRIX_MAJOR_HPP

#include <rokko/eigen3.hpp>
#include <rokko/matrix_major.hpp>
#include <rokko/eigen3/matrix_major.hpp>

namespace rokko {

namespace detail {

template<>
struct eigen3_matrix_major<rokko::grid_row_major_t> {
  static constexpr int value = Eigen::RowMajor;
};

template<>
struct eigen3_matrix_major<rokko::grid_col_major_t> {
  static constexpr int value = Eigen::ColMajor;
};

} // namespace detail

} // namespace rokko

#endif // ROKKO_TRAITS_GRID2MATRIX_MAJOR_HPP


<|start_filename|>test/generate_matrix/rank_number.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/distributed_matrix.hpp>
#include <rokko/collective.hpp>

#include <algorithm>
#include <gtest/gtest.h>

int global_argc;
char** global_argv;

template <typename MATRIX_MAJOR, typename GRID_MAJOR>
void run_test(std::array<int,2> const& global_size, std::array<int,2> const& block_size, GRID_MAJOR) {
  rokko::grid g(MPI_COMM_WORLD, GRID_MAJOR{});
  const auto grid_size = g.get_size();
  const int myrank = g.get_myrank();
  constexpr int root_proc = 0;
  rokko::mapping_bc<MATRIX_MAJOR> map(global_size, block_size, g);
  rokko::distributed_matrix<double, MATRIX_MAJOR> mat(map);

  for (int local_i=0; local_i<map.get_m_local(); ++local_i) {
    for (int local_j=0; local_j<map.get_n_local(); ++local_j) {
      mat.set_local(local_i, local_j, myrank);
    }
  }

  auto global_size_proc = (myrank == root_proc) ? global_size : std::array<int,2>({0,0});
  using eigen_matrix = Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,rokko::eigen3_major<MATRIX_MAJOR>>;
  eigen_matrix mat_loc(global_size_proc[0], global_size_proc[1]);
  rokko::gather(mat, mat_loc, root_proc);

  if (myrank == root_proc) {
    for (int i=0; i<global_size[0]; i += block_size[0]) {
      const int i_block = i / block_size[0];
      const int ip = i_block % grid_size[0];
      const int block0 = std::min(global_size[0] - i, block_size[0]);
      for (int j=0; j<global_size[1]; j += block_size[1]) {
        const int j_block = j / block_size[1];
        const int jp = j_block % grid_size[1];
        const int block1 = std::min(global_size[1] - j, block_size[1]);
        const int rank = g.calculate_rank_form_coords(ip, jp);
        ASSERT_TRUE(mat_loc.block(i, j, block0, block1) == eigen_matrix::Constant(block0, block1, rank));
      }
    }
  }
}

template <typename MATRIX_MAJOR>
void test_both_grid_major(std::array<int,2> const& global_size, std::array<int,2> const& block_size) {
  run_test<MATRIX_MAJOR>(global_size, block_size, rokko::grid_row_major);
  run_test<MATRIX_MAJOR>(global_size, block_size, rokko::grid_col_major);
}

TEST(generate_matrix, rank_number) {
  test_both_grid_major<rokko::matrix_col_major>({20,8}, {4,3});
  test_both_grid_major<rokko::matrix_col_major>({8,20}, {4,3});
  test_both_grid_major<rokko::matrix_col_major>({5,7}, {9,12});
  test_both_grid_major<rokko::matrix_col_major>({7,9}, {9,5});
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>rokko/distributed_mfree.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_DISTRIBUTED_MFREE_HPP
#define ROKKO_DISTRIBUTED_MFREE_HPP

#include <rokko/mapping_1d.hpp>
#include <rokko/mapping_1d_common.hpp>
#include <rokko/skel/mapping_1d.hpp>
#include <rokko/eigen3.hpp>

namespace rokko {

class distributed_mfree : virtual public detail::mapping_1d_common {
public:
  distributed_mfree() = default;
  virtual ~distributed_mfree() = default;

  virtual void multiply(const double *const x, double *const y) const = 0;
  virtual void fill_diagonal(double* x) const {  // optional
    throw std::runtime_error("distributed_mfree : fill_diagonal is not implemented");
  }
  virtual int get_local_offset() const = 0;
  virtual MPI_Comm get_comm() const = 0;
};

class distributed_mfree_default : virtual public distributed_mfree, public skel::mapping_1d {
public:
  distributed_mfree_default() = default;
  distributed_mfree_default(int dim) : distributed_mfree_default(dim, rokko::mpi_comm{MPI_COMM_WORLD}) {}
  distributed_mfree_default(int dim, rokko::mpi_comm const& mpi_comm) : skel::mapping_1d(dim, mpi_comm) {}
  distributed_mfree_default(int dim, int num_local_rows, rokko::mpi_comm const& mpi_comm) : skel::mapping_1d(dim, num_local_rows, mpi_comm) {}
  distributed_mfree_default(skel::mapping_1d const& map) : skel::mapping_1d(map) {}

  virtual ~distributed_mfree_default() = default;

  int get_local_offset() const override { return start_row(); }

  MPI_Comm get_comm() const override { return get_mpi_comm().get_comm(); }
};

using MapVec = Eigen::Map<Eigen::Vector<double>>;
using ConstMapVec = const Eigen::Map<const Eigen::Vector<double>>;

class distributed_mfree_holder : public rokko::distributed_mfree_default {
public:
  distributed_mfree_holder(std::function<void(const double *const, double *const)> const& multiply_in, rokko::skel::mapping_1d const& map)
    : multiply_(multiply_in), rokko::distributed_mfree_default(map) {}

  // For function pointer
  distributed_mfree_holder(void (*multiply_in)(const double *const, double *const), rokko::skel::mapping_1d const& map)
    : distributed_mfree_holder(std::function<void(const double *const, double *const)>(multiply_in), map) {}

  // For C binding
  distributed_mfree_holder(std::function<void(const double *const, double *const, void*)> const& multiply_in, void* vars, rokko::skel::mapping_1d const& map)
    : distributed_mfree_holder([multiply_in, vars](const double *const x, double *const y) {
        multiply_in(x, y, vars);
      },
      map) {}

  // For Fortran binding
  distributed_mfree_holder(std::function<void(const int*, const double *const, double *const)> const& multiply_in, rokko::skel::mapping_1d const& map)
    : distributed_mfree_holder([this, multiply_in](const double *const x, double *const y) {
        int num_local_rows = get_num_local_rows();
        multiply_in(&num_local_rows, x, y);
      },
      map) {}

  // Use Eigen3 for Python binding
  distributed_mfree_holder(std::function<void(ConstMapVec,MapVec)> const& multiply_in, rokko::skel::mapping_1d const& map)
    : multiply_([this, multiply_in](const double *const x, double *const y) {
        const int num_local_rows = get_num_local_rows();
        ConstMapVec  X(x, num_local_rows);
        MapVec  Y(y, num_local_rows);
        multiply_in(X, Y);
      }), rokko::distributed_mfree_default(map) {}

  ~distributed_mfree_holder() = default;

  void multiply(const double *const x, double *const y) const override {
    multiply_(x, y);
  }

private:
  std::function<void(const double *const, double *const)> multiply_;
};

} // end namespace rokko

#endif // ROKKO_DISTRIBUTED_MFREE_HPP


<|start_filename|>rokko/dense.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2016 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_DENSE_H
#define ROKKO_DENSE_H

#include <rokko/config.h>

#include <rokko/serial_dense.h>

#if defined(ROKKO_HAVE_PARALLEL_DENSE_SOLVER)
#include <rokko/parallel_dense.h>
#endif /* defined(ROKKO_HAVE_PARALLEL_DENSE_SOLVER) */

#endif /* ROKKO_DENSE_H */


<|start_filename|>rokko/eigen_matrix_c.cpp<|end_filename|>
/*****************************************************************************
 *
 * Rokko: Integrated Interface for libraries of eigenvalue decomposition
 *
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
 *
 * 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)
 *
 *****************************************************************************/

#include <rokko/eigen_matrix.h>
#include <rokko/eigen3.hpp>
#include <rokko/eigen3/generate_matrix.hpp>

void rokko_eigen_matrix_construct(rokko_eigen_matrix* matrix, int dim1, int dim2,
				      int matrix_major) {
  if (matrix_major == rokko_matrix_col_major)
    matrix->ptr = new Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>(dim1, dim2);
  else
    matrix->ptr = new Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>(dim1, dim2);
  matrix->major = matrix_major;
}

void rokko_eigen_matrix_construct_array_sizes(struct rokko_eigen_matrix* matrix,
                                              int dim1, int dim2, double* ptr, int matrix_major) {
  if (matrix_major == rokko_matrix_col_major) {
    matrix->ptr = new Eigen::Map<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>>(ptr, dim1, dim2);
  } else {
    matrix->ptr = new Eigen::Map<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>>(ptr, dim1, dim2);
  }
  matrix->major = matrix_major;
}

void rokko_eigen_matrix_destruct(rokko_eigen_matrix* matrix) {
  if (matrix->major == rokko_matrix_col_major)
    delete static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(matrix->ptr);
  else
    delete static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(matrix->ptr);
  matrix->ptr = nullptr;
}

void rokko_eigen_matrix_print(rokko_eigen_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    std::cout << *static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(matrix.ptr) << std::endl;
  else
    std::cout << *static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(matrix.ptr) << std::endl;
}

void rokko_eigen_matrix_generate_function(struct rokko_eigen_matrix matrix,
					      double (*func)(int i, int j)) {
  if (matrix.major == rokko_matrix_col_major)
    rokko::generate(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(matrix.ptr), func);
  else
    rokko::generate(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(matrix.ptr), func);
}

void rokko_eigen_matrix_generate_function_p(struct rokko_eigen_matrix matrix,
					      double (*func)(const int* i, const int* j)) {

  const auto g = [&func](int i, int j) { return func(&i, &j); };

  if (matrix.major == rokko_matrix_col_major)
    rokko::generate(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(matrix.ptr), g);
  else
    rokko::generate(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(matrix.ptr), g);
}

void rokko_eigen_matrix_generate_function1(struct rokko_eigen_matrix matrix,
					      double (*func)(int i, int j)) {
  const auto g = [&func](int i, int j) { return func(i+1, j+1); };

  if (matrix.major == rokko_matrix_col_major)
    rokko::generate(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(matrix.ptr), g);
  else
    rokko::generate(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(matrix.ptr), g);
}

void rokko_eigen_matrix_generate_function1_p(struct rokko_eigen_matrix matrix,
					      double (*func)(const int* i, const int* j)) {
  const auto g = [&func](int i, int j) {
    const int i1 = i+1, j1 = j+1;
    return func(&i1, &j1);
  };

  if (matrix.major == rokko_matrix_col_major)
    rokko::generate(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(matrix.ptr), g);
  else
    rokko::generate(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(matrix.ptr), g);
}

double rokko_eigen_matrix_get(struct rokko_eigen_matrix matrix, int i, int j) {
  if (matrix.major == rokko_matrix_col_major)
    return (*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(matrix.ptr))(i, j);
  else
    return (*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(matrix.ptr))(i, j);
}

double rokko_eigen_matrix_get1(struct rokko_eigen_matrix matrix, int i, int j) {
  if (matrix.major == rokko_matrix_col_major)
    return (*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(matrix.ptr))(i-1, j-1);
  else
    return (*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(matrix.ptr))(i-1, j-1);
}

void rokko_eigen_matrix_set(struct rokko_eigen_matrix matrix, int i, int j, double value) {
  if (matrix.major == rokko_matrix_col_major)
    (*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(matrix.ptr))(i, j) = value;
  else
    (*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(matrix.ptr))(i, j) = value;
}

void rokko_eigen_matrix_set1(struct rokko_eigen_matrix matrix, int i, int j, double value) {
  if (matrix.major == rokko_matrix_col_major)
    (*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(matrix.ptr))(i-1, j-1) = value;
  else
    (*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(matrix.ptr))(i-1, j-1) = value;
}

int rokko_eigen_matrix_get_m(struct rokko_eigen_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(matrix.ptr)->rows();
  else
    return static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(matrix.ptr)->rows();
}

int rokko_eigen_matrix_get_n(struct rokko_eigen_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    return static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(matrix.ptr)->cols();
  else
    return static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(matrix.ptr)->cols();
}

bool rokko_eigen_matrix_is_row_major(struct rokko_eigen_matrix matrix) {
  return matrix.major == rokko_matrix_row_major;
}

bool rokko_eigen_matrix_is_col_major(struct rokko_eigen_matrix matrix) {
  return matrix.major == rokko_matrix_col_major;
}

double* rokko_eigen_matrix_get_array_pointer(struct rokko_eigen_matrix matrix) {
  if (matrix.major == rokko_matrix_col_major)
    return storage(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>*>(matrix.ptr));
  else
    return storage(*static_cast<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>*>(matrix.ptr));
}


<|start_filename|>rokko/parallel_sparse_ev_c.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2016 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/parallel_sparse_ev.h>
#include <rokko/parallel_sparse_ev.hpp>
#include <rokko/copy_string.hpp>

void rokko_parallel_sparse_ev_construct(struct rokko_parallel_sparse_ev* solver, const char* solver_name, int argc, char** argv) {
  solver->ptr = new rokko::parallel_sparse_ev(std::string(solver_name));
  static_cast<rokko::parallel_sparse_ev*>(solver->ptr)->initialize(argc, argv);
}

void rokko_parallel_sparse_ev_construct_f(rokko_parallel_sparse_ev* solver, const char* solver_name) {
  int argc = 0;
  char** argv;
  rokko_parallel_sparse_ev_construct(solver, solver_name, argc, argv);
}

void rokko_parallel_sparse_ev_destruct(rokko_parallel_sparse_ev* solver) {
  rokko::parallel_sparse_ev* ptr = static_cast<rokko::parallel_sparse_ev*>(solver->ptr);
  ptr->finalize();
  delete ptr;
  solver->ptr = nullptr;
}


struct rokko_parameters rokko_parallel_sparse_ev_diagonalize_distributed_crs_matrix(struct rokko_parallel_sparse_ev solver,
										    struct rokko_distributed_crs_matrix mat,
										    struct rokko_parameters params) {
  struct rokko_parameters params_out;
  rokko_parameters_construct(&params_out);
  *static_cast<rokko::parameters*>(params_out.ptr) = static_cast<rokko::parallel_sparse_ev*>(solver.ptr)->diagonalize(*static_cast<rokko::distributed_crs_matrix*>(mat.ptr),
														      *static_cast<rokko::parameters*>(params.ptr));
  return params_out;
}

struct rokko_parameters rokko_parallel_sparse_ev_diagonalize_distributed_mfree(struct rokko_parallel_sparse_ev solver,
									       struct rokko_distributed_mfree mat,
									       struct rokko_parameters params) {
  struct rokko_parameters params_out;
  rokko_parameters_construct(&params_out);
  *static_cast<rokko::parameters*>(params_out.ptr) = static_cast<rokko::parallel_sparse_ev*>(solver.ptr)->diagonalize(*static_cast<rokko::distributed_mfree_holder*>(mat.ptr),
														       *static_cast<rokko::parameters*>(params.ptr));
  return params_out;
}

// Fortran binding
void rokko_parallel_sparse_ev_diagonalize_distributed_crs_matrix_f(struct rokko_parallel_sparse_ev* solver,
								   struct rokko_distributed_crs_matrix* mat,
								   struct rokko_parameters* params, struct rokko_parameters* params_out) {
  rokko_parameters_construct(params_out);
  *static_cast<rokko::parameters*>(params_out->ptr) = static_cast<rokko::parallel_sparse_ev*>(solver->ptr)->diagonalize(*static_cast<rokko::distributed_crs_matrix*>(mat->ptr),
															*static_cast<rokko::parameters*>(params->ptr));
}

void rokko_parallel_sparse_ev_diagonalize_distributed_crs_matrix_noreturn_f(struct rokko_parallel_sparse_ev* solver,
									    struct rokko_distributed_crs_matrix* mat,
									    struct rokko_parameters* params) {
  static_cast<rokko::parallel_sparse_ev*>(solver->ptr)->diagonalize(*static_cast<rokko::distributed_crs_matrix*>(mat->ptr),
								    *static_cast<rokko::parameters*>(params->ptr));
}

void rokko_parallel_sparse_ev_diagonalize_distributed_mfree_f(struct rokko_parallel_sparse_ev* solver,
							      struct rokko_distributed_mfree* mat,
							      struct rokko_parameters* params, struct rokko_parameters* params_out) {
  rokko_parameters_construct(params_out);
  *static_cast<rokko::parameters*>(params_out->ptr) = static_cast<rokko::parallel_sparse_ev*>(solver->ptr)->diagonalize(*static_cast<rokko::distributed_mfree_holder*>(mat->ptr),
															*static_cast<rokko::parameters*>(params->ptr));
}

void rokko_parallel_sparse_ev_diagonalize_distributed_mfree_noreturn_f(struct rokko_parallel_sparse_ev* solver,
								       struct rokko_distributed_mfree* mat,
								       struct rokko_parameters* params) {
  static_cast<rokko::parallel_sparse_ev*>(solver->ptr)->diagonalize(*static_cast<rokko::distributed_mfree_holder*>(mat->ptr),
								    *static_cast<rokko::parameters*>(params->ptr));
}


double rokko_parallel_sparse_ev_eigenvalue(struct rokko_parallel_sparse_ev solver, int i) {
  return static_cast<rokko::parallel_sparse_ev*>(solver.ptr)->eigenvalue(i);
}

void rokko_parallel_sparse_ev_eigenvector(struct rokko_parallel_sparse_ev solver, int i, double* vec) {
  return static_cast<rokko::parallel_sparse_ev*>(solver.ptr)->eigenvector(i, vec);
}

int rokko_parallel_sparse_ev_num_conv(struct rokko_parallel_sparse_ev solver) {
  return static_cast<rokko::parallel_sparse_ev*>(solver.ptr)->get_num_conv();
}

struct rokko_mapping_1d rokko_parallel_sparse_ev_default_mapping(struct rokko_parallel_sparse_ev solver, int dim, MPI_Comm comm) {
  struct rokko_mapping_1d map;
  map.ptr = new rokko::mapping_1d(static_cast<rokko::parallel_sparse_ev*>(solver.ptr)->default_mapping(dim, rokko::mpi_comm{comm}));
  return map;
}

void rokko_parallel_sparse_ev_default_mapping_f(struct rokko_parallel_sparse_ev solver, int dim, int comm_f, struct rokko_mapping_1d* map) {
  MPI_Comm comm = MPI_Comm_f2c(comm_f);
  map->ptr = new rokko::mapping_1d(static_cast<rokko::parallel_sparse_ev*>(solver.ptr)->default_mapping(dim, rokko::mpi_comm{comm}));
}

int rokko_parallel_sparse_ev_num_solvers() {
  return rokko::parallel_sparse_ev::solvers().size();
}

char** rokko_parallel_sparse_ev_solvers() {
  std::vector<std::string> solvers = rokko::parallel_sparse_ev::solvers();
  char **solvers_c = (char**)malloc((size_t)(solvers.size() * sizeof(char*)));
  for (int i = 0; i < solvers.size(); ++i) {
    solvers_c[i] = copy_string(solvers[i]);
  }
  return solvers_c;
}

const char* rokko_parallel_sparse_ev_default_solver() {
  return rokko::parallel_sparse_ev::default_solver().c_str();
}


<|start_filename|>example/scalapack/pdstebz_f.f90<|end_filename|>
program main
  use mpi
  implicit none
  integer, parameter :: n = 8, nb = 1
  integer :: provided, ierr, myrank, nprocs
  integer :: icontxt, npcol, nprow
  integer :: info
  double precision, allocatable :: d(:), e(:), w(:)
  integer :: lwork, liwork
  double precision, allocatable :: work(:)
  integer, allocatable :: iwork(:)
  integer :: il, iu, m, nsplit
  double precision :: vl, vu, abstol
  integer, allocatable :: isplit(:), iblock(:)

  call MPI_init_thread(MPI_THREAD_MULTIPLE, provided, ierr)
  call MPI_comm_rank(MPI_COMM_WORLD, myrank, ierr)
  call MPI_comm_size(MPI_COMM_WORLD, nprocs, ierr)
  nprow = int(sqrt(1. * nprocs + 0.5))
  npcol = int(1. * nprocs / nprow)
  if (myrank == 0) then
     print *, "n =", n
     print *, "nprocs =", nprocs
     print *, "nprow =", nprow
     print *, "npcol =", npcol
     if ((nprocs /= nprow * npcol) .or. (mod(n, nprow) /= 0) .or. &
          (mod(n, npcol) /= 0)) then
        print *, "incompatible matrix size and number of processes"
        call MPI_Abort(MPI_COMM_WORLD, 127, ierr)
     end if
  end if
  call BLACS_get(0, 0, icontxt)
  call BLACS_gridinit(icontxt, 'R', nprow, npcol)  ! not used explicitly, but needed for pdstebz. If you remove it, segmentation fault occurs.

  allocate(d(n), e(n))
  call generate_laplacian(n, d, e)

  allocate(w(n))

  abstol = 0d0
  lwork = -1
  liwork = -1
  allocate(work(1), iwork(1))
  allocate(isplit(n))
  allocate(iblock(n))

  call pdstebz(icontxt, 'A', 'E', n, &
       & vl, vu, il, iu, &
       & abstol, d, e, m, nsplit, &
       & w, iblock, isplit, &
       & work, lwork, iwork, liwork, &
       & info)
  lwork = int(work(1))
  liwork = iwork(1)
  deallocate(work, iwork)
  allocate(work(lwork), iwork(liwork))

  call pdstebz(icontxt, 'A', 'E', n, &
       & vl, vu, il, iu, &
       & abstol, d, e, m, nsplit, &
       & w, iblock, isplit, &
       & work, lwork, iwork, liwork, &
       & info)

  call mpi_barrier(mpi_comm_world, ierr)
  if (myrank == 0) then
     print *, "eigenvalues:", w(:)
  end if

  deallocate(isplit, iblock)
  deallocate(d, e, w, work, iwork)
  call BLACS_gridexit(icontxt)
  call MPI_finalize(ierr)

contains

  subroutine generate_laplacian(n, d, e)
    implicit none
    integer, intent(in) :: n
    double precision, intent(out) :: d(:), e(:)
    integer :: i

    d(1) = 1d0;
    do i = 2, n
       d(i) = 2d0
    enddo
    do i = 1, n-1
       e(i) = -1d0
    enddo
  end subroutine generate_laplacian

end program main


<|start_filename|>tutorial/titpack/02_refactored_cxx/sample-05.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2014 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

// C++ version of TITPACK Ver.2 by <NAME>

/************* Sample main program #5 *****************
* 1d Heisenberg antiferromagnet with 16 spins
* Eigenvector of an excited state by inv1
******************************************************/

#include "titpack.hpp"
#include "options.hpp"

int main(int argc, char** argv) {
  std::cout.precision(10);
  options opt(argc, argv, 16);
  if (!opt.valid) std::abort();

  // lattice structure
  int n = opt.N;
  int ibond = n;
  std::vector<int> ipair;
  for (int i = 0; i < ibond; ++i) {
    ipair.emplace_back(i);
    ipair.emplace_back((i + 1) % n);
  }

  // Hamiltonian parameters
  std::vector<double> bondwt(ibond, -1);
  std::vector<double> zrtio(ibond, 1);

  // table of configurations and Hamiltonian operator
  subspace ss(n, 0);
  hamiltonian hop(ss, ipair, bondwt, zrtio);

  // Eigenvalues
  int nvec = 1;
  matrix_type v(ss.dimension(), 2);
  std::vector<double> E, alpha, beta;
  matrix_type coeff;
  matrix_type wk;
  matrix_type x;
  for (int k = 0; k < 2; ++k) {
    int iv = 20 + (ss.dimension() / 2) * k;
    int itr = lnc1(hop, nvec, iv, E, alpha, beta, coeff, wk);
    
    std::cout << "# " << k << " [Eigenvalues]\n";
    for (int i = 0; i < 4; ++i) std::cout << '\t' << E[i];
    std::cout << std::endl;

    lncv1(hop, nvec, iv, alpha, beta, coeff, x, itr, wk);
    for (int i = 0; i < ss.dimension(); ++i) v(i, k) = x(i, 0);
  }
  
  // Degeneracy check
  std::vector<double> norm;
  int idgn = orthg(v, norm, 2);
  std::cout << " [Degeneracy] : " << idgn << "   Norm : " << norm[0] << '\t' << norm[1] << std::endl;
}


<|start_filename|>rokko/Cblacs.h<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_CBLACS_H
#define ROKKO_CBLACS_H

#include "mpi.h"

#ifdef __cplusplus
extern "C" {
#endif
  
MPI_Comm Cblacs2sys_handle(int BlacsCtxt);

void Cblacs_barrier(int ConTxt, char *scope);

void Cblacs_exit(int NotDone);

void Cblacs_get(int ConTxt, int what, int *val);

void Cblacs_gridexit(int ConTxt);

void Cblacs_gridinfo(int ConTxt, int *nprow, int *npcol, int *myrow, int *mycol);

void Cblacs_gridinit(int *ConTxt, char *order, int nprow, int npcol);

void Cblacs_gridmap(int *ConTxt, int *usermap, int ldup, int nprow0, int npcol0);

void Cfree_blacs_system_handle(int ISysCtxt);

int Csys2blacs_handle(MPI_Comm SysCtxt);

#ifdef __cplusplus
} // extern "C"
#endif

#endif // ROKKO_CBLACS_H


<|start_filename|>test/mapping_1d/sizes_skel.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2020 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/skel/mapping_1d.hpp>

#include <gtest/gtest.h>

int global_argc;
char** global_argv;

int start_row_by_sum(rokko::skel::mapping_1d const& map) {
  int index = 0;
  for (int proc=0; proc<map.get_mpi_comm().get_myrank(); ++proc)
    index += map.calculate_num_local_rows(proc);
  return index;
}

int dim_by_sum(rokko::skel::mapping_1d const& map) {
  int sum = 0;
  for (int proc=0; proc<map.get_mpi_comm().get_nprocs(); ++proc)
    sum += map.calculate_num_local_rows(proc);
  return sum;
}

TEST(mapping_1d, skel) {
  constexpr int dim = 100;
  rokko::skel::mapping_1d map(dim);

  ASSERT_EQ(map.start_row(), start_row_by_sum(map));
  ASSERT_EQ(dim_by_sum(map), dim);

  const int end_proc = map.get_mpi_comm().get_nprocs() - 1;
  if (map.get_mpi_comm().get_myrank() == end_proc)
    ASSERT_EQ(map.end_row(), dim);
}

int main(int argc, char** argv) {
  int result = 0;
  ::testing::InitGoogleTest(&argc, argv);
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  global_argc = argc;
  global_argv = argv;
  result = RUN_ALL_TESTS();
  MPI_Finalize();
  return result;
}


<|start_filename|>example/eigenexa/eigen_s_c.c<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 by <NAME> <<EMAIL>>
*
* 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)
*
*****************************************************************************/

#include <mpi.h>
#include <stdio.h>
#include <rokko/ceigenexa.h>
#include <rokko/cmatrix.h>

int imin(int x, int y) { return (x < y) ? x : y; }

int main(int argc, char** argv) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  int myrank;
  MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
  ceigenexa_init();

  int n = 8;
  if (argc > 1) n = atoi(argv[1]);

  int nprocs, npcol, nprow;
  ceigenexa_get_procs(&nprocs, &npcol, &nprow);
  if (myrank == 0) {
    printf("n = %d\n", n);
    printf("nprocs = %d\n", nprocs);
    printf("nprow = %d\n", nprow);
    printf("npcol = %d\n", npcol);
  }
  int inod, x_inod, y_inod;
  ceigenexa_get_id(&inod, &x_inod, &y_inod);

  int nm, ny;
  ceigenexa_get_matdims(nprow, npcol, n, &nm, &ny);
  double **a = alloc_dmatrix(nm, ny);
  double **z = alloc_dmatrix(nm, ny);
  double *w = alloc_dvector(n);

  int jloop_sta = ceigenexa_loop_start(0, nprow, y_inod);
  int jloop_end = ceigenexa_loop_end(n, nprow, y_inod);
  int iloop_sta = ceigenexa_loop_start(0, npcol, x_inod);
  int iloop_end = ceigenexa_loop_end(n, npcol, x_inod);
  for (int jl = jloop_sta; jl < jloop_end; ++jl) {
    int j = ceigenexa_translate_l2g(jl, nprow, y_inod);
    for (int il = iloop_sta; il < iloop_end; ++il) {
      int i = ceigenexa_translate_l2g(il, npcol, x_inod);
      mat_elem(a, il, jl) = imin(i, j) + 1;
    }
  }

  ceigenexa_eigen_s(n, n, mat_ptr(a), nm, vec_ptr(w), mat_ptr(z), nm, 48, 128, 'A');
  if (myrank == 0) {
    printf("eigenvalues: ");
    fprint_dvector(stdout, n, vec_ptr(w));
  }

  free_dmatrix(a);
  free_dmatrix(z);
  free_dvector(w);
  ceigenexa_free();
  MPI_Finalize();
}


<|start_filename|>example/cxx/dense/generate_matrix/minij_by_function_mpi.cpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2019 Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/mapping_bc.hpp>
#include <rokko/collective.hpp>
#include <rokko/utility/solver_name.hpp>
#include <rokko/utility/minij_matrix.hpp>
#include <iostream>

using matrix_major = rokko::matrix_col_major;

int main(int argc, char *argv[]) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
  MPI_Comm comm = MPI_COMM_WORLD;
  std::string library_routine(rokko::parallel_dense_ev::default_solver());
  std::string library, routine;
  int dim = 10;
  if (argc >= 2) library_routine = argv[1];
  if (argc >= 3) dim = std::stoi(argv[2]);
  rokko::split_solver_name(library_routine, library, routine);

  rokko::grid g(comm);
  int myrank = g.get_myrank();

  auto f = [](int global_i, int global_j) {
    return static_cast<double>(std::min(global_i, global_j) + 1);
  };

  std::cout.precision(5);

  rokko::parallel_dense_ev solver(library);
  solver.initialize(argc, argv);
  if (myrank == 0)
    std::cout << "Eigenvalue decomposition of minij matrix" << std::endl
	      << "library:routine = " << library_routine << std::endl
              << "num_procs = " << g.get_nprocs() << std::endl
              #ifdef _OPENMP
              << "num_threads per process = " << omp_get_max_threads() << std::endl
              #endif
	      << "routine = " << routine << std::endl
              << "dimension = " << dim << std::endl;

  rokko::mapping_bc<matrix_major> map = solver.default_mapping(dim, g);
  rokko::distributed_matrix<double, matrix_major> mat(map);
  mat.generate(f);

  solver.finalize();
  MPI_Finalize();
}


<|start_filename|>rokko/lapack/gesvd.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_LAPACK_GESVD_HPP
#define ROKKO_LAPACK_GESVD_HPP

#include <complex>
#ifdef I
# undef I
#endif
#include <stdexcept>
#include <lapacke.h>
#undef I
#include <rokko/traits/real_t.hpp>
#include <rokko/traits/value_t.hpp>
#include "complex_cast.hpp"

namespace rokko {
namespace lapack {

namespace {

template<typename T> struct gesvd_dispatch;
  
template<>
struct gesvd_dispatch<float> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int gesvd(int matrix_layout, char jobu, char jobvt,
                          lapack_int m, lapack_int n, MATRIX& a, VECTOR& s,
                          MATRIX& u, MATRIX& vt, VECTOR& work) {
    if (size(work) == std::min(m, n) - 1)
      return LAPACKE_sgesvd(matrix_layout, jobu, jobvt, m, n, 
                            storage(a), ld(a), storage(s), storage(u), ld(u),
                            storage(vt), ld(vt), storage(work));
    else
      return LAPACKE_sgesvd_work(matrix_layout, jobu, jobvt, m, n, 
                                 storage(a), ld(a), storage(s), storage(u), ld(u),
                                 storage(vt), ld(vt), storage(work), size(work));
  }
};
  
template<>
struct gesvd_dispatch<double> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int gesvd(int matrix_layout, char jobu, char jobvt,
                          lapack_int m, lapack_int n, MATRIX& a, VECTOR& s,
                          MATRIX& u, MATRIX& vt, VECTOR& work) {
    if (size(work) == std::min(m, n) - 1)
      return LAPACKE_dgesvd(matrix_layout, jobu, jobvt, m, n, 
                            storage(a), ld(a), storage(s), storage(u), ld(u),
                            storage(vt), ld(vt), storage(work));
    else
      return LAPACKE_dgesvd_work(matrix_layout, jobu, jobvt, m, n, 
                                 storage(a), ld(a), storage(s), storage(u), ld(u),
                                 storage(vt), ld(vt), storage(work), size(work));
  }
};
  
template<>
struct gesvd_dispatch<std::complex<float>> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int gesvd(int matrix_layout, char jobu, char jobvt,
                          lapack_int m, lapack_int n, MATRIX& a, VECTOR& s,
                          MATRIX& u, MATRIX& vt, VECTOR& superb) {
    if (size(superb) != std::min(m, n) - 1)
      throw std::invalid_argument("vector superb size mismatch");
    return LAPACKE_cgesvd(matrix_layout, jobu, jobvt, m, n, 
                          complex_cast(storage(a)), ld(a), storage(s),
                          complex_cast(storage(u)), ld(u),
                          complex_cast(storage(vt)), ld(vt), storage(superb));
  }
  template<typename MATRIX, typename VECTOR0, typename VECTOR1>
  static lapack_int gesvd_work(int matrix_layout, char jobu, char jobvt,
                               lapack_int m, lapack_int n, MATRIX& a, VECTOR0& s,
                               MATRIX& u, MATRIX& vt, VECTOR1& work, VECTOR0& rwork) {
    return LAPACKE_cgesvd(matrix_layout, jobu, jobvt, m, n, 
                          complex_cast(storage(a)), ld(a), storage(s),
                          complex_cast(storage(u)), ld(u),
                          complex_cast(storage(vt)), ld(vt),
                          complex_cast(storage(work)), size(work), storage(rwork));
  }
};
  
template<>
struct gesvd_dispatch<std::complex<double>> {
  template<typename MATRIX, typename VECTOR>
  static lapack_int gesvd(int matrix_layout, char jobu, char jobvt,
                          lapack_int m, lapack_int n, MATRIX& a, VECTOR& s,
                          MATRIX& u, MATRIX& vt, VECTOR& superb) {
    if (size(superb) != std::min(m, n) - 1)
      throw std::invalid_argument("vector superb size mismatch");
    return LAPACKE_zgesvd(matrix_layout, jobu, jobvt, m, n, 
                          complex_cast(storage(a)), ld(a), storage(s),
                          complex_cast(storage(u)), ld(u),
                          complex_cast(storage(vt)), ld(vt), storage(superb));
  }
  template<typename MATRIX, typename VECTOR0, typename VECTOR1>
  static lapack_int gesvd_work(int matrix_layout, char jobu, char jobvt,
                               lapack_int m, lapack_int n, MATRIX& a, VECTOR0& s,
                               MATRIX& u, MATRIX& vt, VECTOR1& work, VECTOR0& rwork) {
    return LAPACKE_zgesvd(matrix_layout, jobu, jobvt, m, n, 
                          complex_cast(storage(a)), ld(a), storage(s),
                          complex_cast(storage(u)), ld(u),
                          complex_cast(storage(vt)), ld(vt),
                          complex_cast(storage(work)), size(work), storage(rwork));
  }
};
  
}
  
template<typename MATRIX, typename VECTOR>
lapack_int gesvd(char jobu, char jobvt, MATRIX& a, VECTOR& s, MATRIX& u, MATRIX& vt,
                 VECTOR& work) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR>>::value, "");
  lapack_int m = rows(a);
  lapack_int n = cols(a);
  lapack_int r = std::min(m, n);
  if (size(s) != r)
    throw std::invalid_argument("vector S size mismatch");
  if (jobu == 'A' && (rows(u) != m || cols(u) != m))
    throw std::invalid_argument("matrix U size mismatch");
  if (jobu == 'S' && (rows(u) != m || cols(u) != r))
    throw std::invalid_argument("matrix U size mismatch");
  if (jobvt == 'A' && (rows(vt) != n || cols(vt) != n))
    throw std::invalid_argument("matrix Vt size mismatch");
  if (jobvt == 'S' && (rows(vt) != r || cols(vt) != n))
    throw std::invalid_argument("matrix Vt size mismatch");
  return gesvd_dispatch<value_t<MATRIX>>
    ::gesvd((is_col_major(a) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR),
            jobu, jobvt, m, n, a, s, u, vt, work);
}

template<typename MATRIX, typename VECTOR0, typename VECTOR1>
lapack_int gesvd(char jobu, char jobvt, MATRIX& a, VECTOR0& s, MATRIX& u, MATRIX& vt,
                 VECTOR1& work, VECTOR0& rwork) {
  static_assert(std::is_same<real_t<MATRIX>, value_t<VECTOR0>>::value, "");
  static_assert(std::is_same<value_t<MATRIX>, value_t<VECTOR1>>::value, "");
  lapack_int m = rows(a);
  lapack_int n = cols(a);
  lapack_int r = std::min(m, n);
  if (size(s) != r)
    throw std::invalid_argument("vector S size mismatch");
  if (jobu == 'A' && (rows(u) != m || cols(u) != m))
    throw std::invalid_argument("matrix U size mismatch");
  if (jobu == 'S' && (rows(u) != m || cols(u) != r))
    throw std::invalid_argument("matrix U size mismatch");
  if (jobvt == 'A' && (rows(vt) != n || cols(vt) != n))
    throw std::invalid_argument("matrix Vt size mismatch");
  if (jobvt == 'S' && (rows(vt) != r || cols(vt) != n))
    throw std::invalid_argument("matrix Vt size mismatch");
  if (size(rwork) < 5 * r)
    throw std::invalid_argument("matrix rwork size mismatch");
  return gesvd_dispatch<value_t<MATRIX>>
    ::gesvd_work((is_col_major(a) ? LAPACK_COL_MAJOR : LAPACK_ROW_MAJOR),
                 jobu, jobvt, m, n, a, s, u, vt, work, rwork);
}

} // end namespace lapack
} // end namespace rokko

#endif // ROKKO_LAPACK_GESVD_HPP


<|start_filename|>rokko/distributed_crs_matrix.hpp<|end_filename|>
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2016 by Rokko Developers https://github.com/t-sakashita/rokko
*
* 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)
*
*****************************************************************************/

#ifndef ROKKO_DISTRIBUTED_CRS_MATRIX_HPP
#define ROKKO_DISTRIBUTED_CRS_MATRIX_HPP

#include <rokko/mapping_1d.hpp>
#include <rokko/utility/tuple_to_array.hpp>
#include <rokko/utility/macro_join.hpp>
#include <vector>

namespace rokko {
namespace detail {

class ps_crs_base {
public:
  virtual ~ps_crs_base() = default;
  virtual void insert(int row, std::vector<int> const& cols, std::vector<double> const& values) = 0;
  virtual void insert(int row, int col_size, int const*const cols, double const*const values) = 0;
  virtual void complete() = 0;
  virtual void extract(int row, std::vector<int>& cols, std::vector<double>& values) const = 0;
  virtual int get_dim() const = 0;
  virtual int get_num_local_rows() const = 0;
  virtual int start_row() const = 0;
  virtual int end_row() const = 0;
  virtual int get_nnz() const = 0;
  virtual void print() const = 0;
  virtual void output_matrix_market(std::ostream& os = std::cout) const = 0;
  virtual const ps_mapping_1d_base& get_map() const = 0;
};

using ps_crs_factory = factory<ps_crs_base,rokko::mapping_1d const&,int>;

} // end namespace detail

class distributed_crs_matrix {
public:
  explicit distributed_crs_matrix(rokko::mapping_1d const& map, int num_entries_per_row)
    : solver_name_(map.get_solver_name()), crs_impl_(detail::ps_crs_factory::instance()->make_product(solver_name_, map, num_entries_per_row)) {}

  std::string get_solver_name() const { return solver_name_; }
  void insert(int row, std::vector<int> const& cols, std::vector<double> const& values) const {
    crs_impl_->insert(row, cols, values);
  }
  template <std::size_t N>
  void insert(int row, std::array<int,N> const& cols, std::array<double,N> const& values) const {
    assert(cols.size() == values.size());
    crs_impl_->insert(row, cols.size(), cols.data(), values.data());
  }
  void insert(int row, int col_size, int const*const cols, double const*const values) const {
    crs_impl_->insert(row, col_size, cols, values);
  }
  void complete() const {
    crs_impl_->complete();
  }
  void extract(int row, std::vector<int>& cols, std::vector<double>& values) const {
    crs_impl_->extract(row, cols, values);
  }
  int get_dim() const {
    return crs_impl_->get_dim();
  }
  int get_num_local_rows() const {
    return crs_impl_->get_num_local_rows();
  }
  int start_row() const {
    return crs_impl_->start_row();
  }
  int end_row() const {
    return crs_impl_->end_row();
  }
  int get_nnz() const {
    return crs_impl_->get_nnz();
  }
  void print() const {
    crs_impl_->print();
  }
  const detail::ps_mapping_1d_base& get_map() const {
    return crs_impl_->get_map();
  }
  void output_matrix_market(std::ostream& os = std::cout) const {
    const auto& comm = get_map().get_mpi_comm();
    constexpr int root_proc = 0;
    std::vector<int> cols;
    std::vector<double> values;

    const int nnz = get_nnz();
    if (comm.get_myrank() == root_proc) {
      os << "%%MatrixMarket matrix coordinate real general" << std::endl
         << get_dim() << " " << get_dim() << " " << nnz << std::endl;
    }
    comm.barrier();
    for (int global_row=0; global_row<get_dim(); ++global_row) {
      if ((global_row >= start_row()) && (global_row < end_row())) {
        extract(global_row, cols, values);
        for (int i=0; i<cols.size(); ++i) {
          os << global_row + 1 << " " << cols[i] + 1 << " " << values[i] << std::endl;
        }
      }
      comm.barrier();
    }
  }
  const detail::ps_crs_factory::product_pointer_type get_ptr() const { return crs_impl_; }

private:
  std::string solver_name_;
  detail::ps_crs_factory::product_pointer_type crs_impl_;
};

} // end namespace rokko

#define ROKKO_REGISTER_PARALLEL_SPARSE_CRS(crs, name, priority) \
namespace { namespace ROKKO_JOIN(register, __LINE__) { \
struct register_caller { \
  using factory = rokko::detail::ps_crs_factory;   \
  using product = crs; \
  register_caller() { factory::instance()->register_creator<product>(name, priority); } \
} caller; \
} }

#endif // ROKKO_DISTRIBUTED_CRS_MATRIX_HPP
