std::pair<unsigned int, Real>
EigenSparseLinearSolver<T>::solve (SparseMatrix<T> &matrix_in,
                                   NumericVector<T> &solution_in,
                                   NumericVector<T> &rhs_in,
                                   const double tol,
                                   const unsigned int m_its)
{
  START_LOG("solve()", "EigenSparseLinearSolver");
  this->init ();

  // Make sure the data passed in are really Eigen types
  EigenSparseMatrix<T>& matrix   = libmesh_cast_ref<EigenSparseMatrix<T>&>(matrix_in);
  EigenSparseVector<T>& solution = libmesh_cast_ref<EigenSparseVector<T>&>(solution_in);
  EigenSparseVector<T>& rhs      = libmesh_cast_ref<EigenSparseVector<T>&>(rhs_in);

  // Close the matrix and vectors in case this wasn't already done.
  matrix.close();
  solution.close();
  rhs.close();

  std::pair<unsigned int, Real> retval(0,0.);

  // Solve the linear system
  switch (this->_solver_type)
    {
      // Conjugate-Gradient
    case CG:
      {
        Eigen::ConjugateGradient<EigenSM> solver (matrix._mat);
        solver.setMaxIterations(m_its);
        solver.setTolerance(tol);
        solution._vec = solver.solveWithGuess(rhs._vec,solution._vec);
        libMesh::out << "#iterations: " << solver.iterations() << std::endl;
        libMesh::out << "estimated error: " << solver.error() << std::endl;
        retval = std::make_pair(solver.iterations(), solver.error());
        break;
      }

      // Bi-Conjugate Gradient Stabilized
    case BICGSTAB:
      {
        Eigen::BiCGSTAB<EigenSM> solver (matrix._mat);
        solver.setMaxIterations(m_its);
        solver.setTolerance(tol);
        solution._vec = solver.solveWithGuess(rhs._vec,solution._vec);
        libMesh::out << "#iterations: " << solver.iterations() << std::endl;
        libMesh::out << "estimated error: " << solver.error() << std::endl;
        retval = std::make_pair(solver.iterations(), solver.error());
        break;
      }

      //   // Generalized Minimum Residual
      // case GMRES:
      //   {
      // libmesh_not_implemented();
      // break;
      //   }

      // Unknown solver, use BICGSTAB
    default:
      {
        libMesh::err << "ERROR:  Unsupported Eigen Solver: "
                     << Utility::enum_to_string(this->_solver_type) << std::endl
                     << "Continuing with BICGSTAB" << std::endl;

        this->_solver_type = BICGSTAB;

        STOP_LOG("solve()", "EigenSparseLinearSolver");

        return this->solve (matrix,
                            solution,
                            rhs,
                            tol,
                            m_its);
      }
    }

  STOP_LOG("solve()", "EigenSparseLinearSolver");
  return retval;
}