/// return the extremal eigenvalues of Ax=cBx
std::pair<double, double>
generalized_extreme_eigenvalues(const Eigen::SparseMatrix<double> &Ain,
                                const Eigen::SparseMatrix<double> &Bin) {
  assert(Ain.rows() == Ain.cols());
  assert(Ain.rows() == Ain.cols());
  assert(Ain.rows() == Bin.rows());
  assert(Ain.isCompressed());
  assert(Bin.isCompressed());
  const int N = static_cast<int>(Ain.rows());

  /* mkl_sparse_d_gv input parameters */
  char which =
      'S';     /* Which eigenvalues to calculate. ('L' - largest (algebraic)
                  eigenvalues, 'S' - smallest (algebraic) eigenvalues) */
  int pm[128]; /* This array is used to pass various parameters to Extended
                  Eigensolver Extensions routines. */
  int k0 = 1;  /* Desired number of max/min eigenvalues */

  /* mkl_sparse_d_gv output parameters */
  int k;             /* Number of eigenvalues found (might be less than k0). */
  double E_small[3]; /* Eigenvalues */
  double E_large[3]; /* Eigenvalues */
  double X[3];       /* Eigenvectors */
  double res[3];     /* Residual */

  /* Local variables */
  int compute_vectors = 0; /* Flag to compute eigenvectors */
  int tol = 7;             /* Tolerance */

  /* Sparse BLAS IE variables */
  sparse_status_t status;

  ConvertToMklResult A = to_mkl(Ain, status); // TODO: check A.status;
  ConvertToMklResult B = to_mkl(Bin, status); // TODO: check B.status;

  /* Step 2. Call mkl_sparse_ee_init to define default input values */
  mkl_sparse_ee_init(pm);

  pm[1] = tol; /* Set tolerance */
  pm[6] = compute_vectors;

  /* Step 3. Solve the standard Ax = ex eigenvalue problem. */
  which = 'S';
  const int infoS = mkl_sparse_d_gv(&which, pm, A.matrix, A.descr, B.matrix,
                                    B.descr, k0, &k, E_small, X, res);
  assert(infoS == 0);

  which = 'L';
  const int infoL = mkl_sparse_d_gv(&which, pm, A.matrix, A.descr, B.matrix,
                                    B.descr, k0, &k, E_large, X, res);
  assert(infoL == 0);

  mkl_sparse_destroy(A.matrix);
  mkl_sparse_destroy(B.matrix);

  return {E_small[0], E_large[0]}; // todo: return the right thing
}
ColCompressedMatrix convert_from_Eigen(const Eigen::SparseMatrix<double> &m)
{
	assert(m.rows() == m.cols());
	assert(m.isCompressed());
	return ColCompressedMatrix(m.rows, m.nonZeros(), 
		m.valuePtr(), m.outerIndexPtr(), m.innerIndexPtr());
}