diff --git a/src/algebra/Eigen3Utils.hpp b/src/algebra/Eigen3Utils.hpp
index 14434fe940878366171fc7b264e1aa50419124ab..5224a4b0bb10dc252b0f299cc9cbbbfe9fa87712 100644
--- a/src/algebra/Eigen3Utils.hpp
+++ b/src/algebra/Eigen3Utils.hpp
@@ -14,10 +14,11 @@
 class Eigen3DenseMatrixEmbedder
 {
  public:
-  using MatrixType = Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>;
+  using Eigen3MatrixType    = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
+  using Eigen3MapMatrixType = Eigen::Map<const Eigen3MatrixType>;
 
  private:
-  MatrixType m_eigen_matrix;
+  Eigen3MapMatrixType m_eigen_matrix;
 
   Eigen3DenseMatrixEmbedder(const size_t nb_rows, const size_t nb_columns, const double* A)
     : m_eigen_matrix{A, int(nb_rows), int(nb_columns)}
@@ -39,14 +40,14 @@ class Eigen3DenseMatrixEmbedder
   }
 
   PUGS_INLINE
-  MatrixType&
+  Eigen3MapMatrixType&
   matrix()
   {
     return m_eigen_matrix;
   }
 
   PUGS_INLINE
-  const MatrixType&
+  const Eigen3MapMatrixType&
   matrix() const
   {
     return m_eigen_matrix;
@@ -66,10 +67,11 @@ class Eigen3DenseMatrixEmbedder
 class Eigen3SparseMatrixEmbedder
 {
  public:
-  using MatrixType = Eigen::Map<const Eigen::SparseMatrix<double, Eigen::RowMajor>>;
+  using Eigen3MatrixType    = Eigen::SparseMatrix<double, Eigen::RowMajor>;
+  using Eigen3MapMatrixType = Eigen::Map<const Eigen3MatrixType>;
 
  private:
-  MatrixType m_eigen_matrix;
+  Eigen3MapMatrixType m_eigen_matrix;
 
  public:
   PUGS_INLINE
@@ -87,14 +89,14 @@ class Eigen3SparseMatrixEmbedder
   }
 
   PUGS_INLINE
-  MatrixType&
+  Eigen3MapMatrixType&
   matrix()
   {
     return m_eigen_matrix;
   }
 
   PUGS_INLINE
-  const MatrixType&
+  const Eigen3MapMatrixType&
   matrix() const
   {
     return m_eigen_matrix;
diff --git a/src/algebra/LinearSolver.cpp b/src/algebra/LinearSolver.cpp
index 7504ced5f7390e3d69c4587c0d2dbf1f1b153517..1ebb59663405883aac2405979ff60bdb7ccb3e7e 100644
--- a/src/algebra/LinearSolver.cpp
+++ b/src/algebra/LinearSolver.cpp
@@ -3,8 +3,13 @@
 
 #include <algebra/BiCGStab.hpp>
 #include <algebra/CG.hpp>
+#include <algebra/Eigen3Utils.hpp>
 #include <algebra/PETScUtils.hpp>
 
+#ifdef PUGS_HAS_EIGEN3
+#include <eigen3/unsupported/Eigen/IterativeSolvers>
+#endif   // PUGS_HAS_EIGEN3
+
 #ifdef PUGS_HAS_PETSC
 #include <petsc.h>
 #endif   // PUGS_HAS_PETSC
@@ -69,15 +74,12 @@ struct LinearSolver::Internals
   {
     switch (method) {
     case LSMethod::cg:
-#warning clean-up
-      // case LSMethod::bicgstab:
-      // case LSMethod::bicgstab2:
-      // case LSMethod::gmres:
-      // case LSMethod::lu:
-      // case LSMethod::cholesky:
-      {
-        break;
-      }
+    case LSMethod::bicgstab:
+    case LSMethod::gmres:
+    case LSMethod::lu:
+    case LSMethod::cholesky: {
+      break;
+    }
       // LCOV_EXCL_START
     default: {
       throw NormalError(name(method) + " is not an Eigen3 linear solver!");
@@ -124,14 +126,11 @@ struct LinearSolver::Internals
   {
     switch (precond) {
     case LSPrecond::none:
-#warning clean-up
-      // case LSPrecond::amg:
-      // case LSPrecond::diagonal:
-      // case LSPrecond::incomplete_cholesky:
-      // case LSPrecond::incomplete_LU:
-      {
-        break;
-      }
+    case LSPrecond::diagonal:
+    case LSPrecond::incomplete_cholesky:
+    case LSPrecond::incomplete_LU: {
+      break;
+    }
       // LCOV_EXCL_START
     default: {
       throw NormalError(name(precond) + " is not an Eigen3 preconditioner!");
@@ -215,6 +214,163 @@ struct LinearSolver::Internals
     }
   }
 
+#ifdef PUGS_HAS_EIGEN3
+  template <typename PreconditionerType,
+            typename Eigen3MatrixEmbedderType,
+            typename SolutionVectorType,
+            typename RHSVectorType>
+  static void
+  _preconditionedEigen3SolveLocalSystem(const Eigen3MatrixEmbedderType& eigen3_A,
+                                        SolutionVectorType& x,
+                                        const RHSVectorType& b,
+                                        const LinearSolverOptions& options)
+  {
+    Eigen::Map<Eigen::VectorX<double>> eigen3_x{(x.size() > 0) ? (&x[0]) : nullptr, static_cast<int>(x.size())};
+    Eigen::Map<const Eigen::VectorX<double>> eigen3_b{(b.size() > 0) ? (&b[0]) : nullptr, static_cast<int>(b.size())};
+
+    using Eigen3MatrixType = typename Eigen3MatrixEmbedderType::Eigen3MatrixType;
+
+    switch (options.method()) {
+    case LSMethod::bicgstab: {
+      Eigen::BiCGSTAB<Eigen3MatrixType, PreconditionerType> solver;
+      solver.compute(eigen3_A.matrix());
+      solver.setMaxIterations(options.maximumIteration());
+      solver.setTolerance(options.epsilon());
+      eigen3_x = solver.solve(eigen3_b);
+      break;
+    }
+    case LSMethod::cg: {
+      Eigen::ConjugateGradient<Eigen3MatrixType, Eigen::Lower | Eigen::Upper, PreconditionerType> solver;
+      solver.compute(eigen3_A.matrix());
+      solver.setMaxIterations(options.maximumIteration());
+      solver.setTolerance(options.epsilon());
+      eigen3_x = solver.solve(eigen3_b);
+      break;
+    }
+    case LSMethod::gmres: {
+      Eigen::GMRES<Eigen3MatrixType, PreconditionerType> solver;
+      solver.compute(eigen3_A.matrix());
+      solver.setMaxIterations(options.maximumIteration());
+      solver.setTolerance(options.epsilon());
+      eigen3_x = solver.solve(eigen3_b);
+      break;
+    }
+    case LSMethod::lu: {
+      if constexpr (std::is_same_v<Eigen3MatrixEmbedderType, Eigen3DenseMatrixEmbedder>) {
+        Eigen::FullPivLU<Eigen3MatrixType> solver;
+        solver.compute(eigen3_A.matrix());
+        eigen3_x = solver.solve(eigen3_b);
+      } else {
+        Eigen::SparseLU<Eigen3MatrixType> solver;
+        solver.compute(eigen3_A.matrix());
+        eigen3_x = solver.solve(eigen3_b);
+      }
+      break;
+    }
+    case LSMethod::cholesky: {
+      if constexpr (std::is_same_v<Eigen3MatrixEmbedderType, Eigen3DenseMatrixEmbedder>) {
+        Eigen::LLT<Eigen3MatrixType> solver;
+        solver.compute(eigen3_A.matrix());
+        eigen3_x = solver.solve(eigen3_b);
+      } else {
+        Eigen::SimplicialLLT<Eigen3MatrixType> solver;
+        solver.compute(eigen3_A.matrix());
+        eigen3_x = solver.solve(eigen3_b);
+      }
+      break;
+    }
+      // LCOV_EXCL_START
+    default: {
+      throw UnexpectedError("unexpected method: " + name(options.method()));
+    }
+      // LCOV_EXCL_STOP
+    }
+  }
+
+  template <typename Eigen3MatrixEmbedderType, typename SolutionVectorType, typename RHSVectorType>
+  static void
+  _eigen3SolveLocalSystem(const Eigen3MatrixEmbedderType& eigen3_A,
+                          SolutionVectorType& x,
+                          const RHSVectorType& b,
+                          const LinearSolverOptions& options)
+  {
+    switch (options.precond()) {
+    case LSPrecond::none: {
+      _preconditionedEigen3SolveLocalSystem<Eigen::IdentityPreconditioner, Eigen3MatrixEmbedderType, SolutionVectorType,
+                                            RHSVectorType>(eigen3_A, x, b, options);
+      break;
+    }
+    case LSPrecond::diagonal: {
+      _preconditionedEigen3SolveLocalSystem<Eigen::DiagonalPreconditioner<double>, Eigen3MatrixEmbedderType,
+                                            SolutionVectorType, RHSVectorType>(eigen3_A, x, b, options);
+      break;
+    }
+    case LSPrecond::incomplete_cholesky: {
+      if constexpr (std::is_same_v<Eigen3SparseMatrixEmbedder, Eigen3MatrixEmbedderType>) {
+        _preconditionedEigen3SolveLocalSystem<Eigen::IncompleteCholesky<double>, Eigen3MatrixEmbedderType,
+                                              SolutionVectorType, RHSVectorType>(eigen3_A, x, b, options);
+      } else {
+        throw NormalError("incomplete cholesky is not available for dense matrices in Eigen3");
+      }
+      break;
+    }
+    case LSPrecond::incomplete_LU: {
+      if constexpr (std::is_same_v<Eigen3SparseMatrixEmbedder, Eigen3MatrixEmbedderType>) {
+        _preconditionedEigen3SolveLocalSystem<Eigen::IncompleteLUT<double>, Eigen3MatrixEmbedderType,
+                                              SolutionVectorType, RHSVectorType>(eigen3_A, x, b, options);
+      } else {
+        throw NormalError("incomplete LU is not available for dense matrices in Eigen3");
+      }
+      break;
+    }
+      // LCOV_EXCL_START
+    default: {
+      throw UnexpectedError("unexpected preconditioner: " + name(options.precond()));
+    }
+      // LCOV_EXCL_STOP
+    }
+  }
+
+  template <typename DataType, typename SolutionVectorType, typename RHSVectorType>
+  static void
+  eigen3SolveLocalSystem(const CRSMatrix<DataType>& A,
+                         SolutionVectorType& x,
+                         const RHSVectorType& b,
+                         const LinearSolverOptions& options)
+  {
+    Assert((x.size() == b.size()) and (x.size() - A.numberOfColumns() == 0) and A.isSquare());
+
+    Eigen3SparseMatrixEmbedder eigen3_A{A};
+    _eigen3SolveLocalSystem(eigen3_A, x, b, options);
+  }
+
+  template <typename DataType, typename SolutionVectorType, typename RHSVectorType>
+  static void
+  eigen3SolveLocalSystem(const SmallMatrix<DataType>& A,
+                         SolutionVectorType& x,
+                         const RHSVectorType& b,
+                         const LinearSolverOptions& options)
+  {
+    Assert((x.size() == b.size()) and (x.size() - A.numberOfColumns() == 0) and A.isSquare());
+
+    Eigen3DenseMatrixEmbedder eigen3_A{A};
+    _eigen3SolveLocalSystem(eigen3_A, x, b, options);
+  }
+
+#else   // PUGS_HAS_EIGEN3
+
+  // LCOV_EXCL_START
+  template <typename MatrixType, typename SolutionVectorType, typename RHSVectorType>
+  static void
+  eigen3SolveLocalSystem(const MatrixType&, SolutionVectorType&, const RHSVectorType&, const LinearSolverOptions&)
+  {
+    checkHasLibrary(LSLibrary::eigen3);
+    throw UnexpectedError("unexpected situation should not reach this point!");
+  }
+  // LCOV_EXCL_STOP
+
+#endif   // PUGS_HAS_EIGEN3
+
 #ifdef PUGS_HAS_PETSC
   static int
   petscMonitor(KSP, int i, double residu, void*)
@@ -357,6 +513,13 @@ struct LinearSolver::Internals
       break;
     }
       // LCOV_EXCL_START
+    case LSLibrary::eigen3: {
+      // not covered since if Eigen3 is not linked this point is
+      // unreachable: LinearSolver throws an exception at construction
+      // in this case.
+      eigen3SolveLocalSystem(A, x, b, options);
+      break;
+    }
     case LSLibrary::petsc: {
       // not covered since if PETSc is not linked this point is
       // unreachable: LinearSolver throws an exception at construction
diff --git a/tests/test_LinearSolver.cpp b/tests/test_LinearSolver.cpp
index 01c71cbea82041747ee137ca76d15a17de89c170..4d01df2f0605e2bd141c1de3d95f28776f3178a0 100644
--- a/tests/test_LinearSolver.cpp
+++ b/tests/test_LinearSolver.cpp
@@ -167,9 +167,6 @@ TEST_CASE("LinearSolver", "[algebra]")
         options.method() = LSMethod::bicgstab;
         REQUIRE_NOTHROW(linear_solver.checkOptions(options));
 
-        options.method() = LSMethod::bicgstab2;
-        REQUIRE_NOTHROW(linear_solver.checkOptions(options));
-
         options.method() = LSMethod::lu;
         REQUIRE_NOTHROW(linear_solver.checkOptions(options));
 
@@ -196,9 +193,6 @@ TEST_CASE("LinearSolver", "[algebra]")
 
         options.precond() = LSPrecond::incomplete_cholesky;
         REQUIRE_NOTHROW(linear_solver.checkOptions(options));
-
-        options.precond() = LSPrecond::amg;
-        REQUIRE_NOTHROW(linear_solver.checkOptions(options));
       }
     }
 
@@ -302,48 +296,44 @@ TEST_CASE("LinearSolver", "[algebra]")
               Vector error = x - x_exact;
               REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
             }
-#warning test all options
-            // SECTION("CG Diagonal")
-            // {
-            //   options.precond() = LSPrecond::diagonal;
 
-            //   Vector<double> x{5};
-            //   x = zero;
+            SECTION("CG Diagonal")
+            {
+              options.precond() = LSPrecond::diagonal;
 
-            //   LinearSolver solver{options};
+              Vector<double> x{5};
+              x = zero;
 
-            //   solver.solveLocalSystem(A, x, b);
-            //   Vector error = x - x_exact;
-            //   REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
-            // }
+              LinearSolver solver{options};
 
-            // SECTION("CG ICholesky")
-            // {
-            //   options.precond() = LSPrecond::incomplete_cholesky;
+              solver.solveLocalSystem(A, x, b);
+              Vector error = x - x_exact;
+              REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+            }
 
-            //   Vector<double> x{5};
-            //   x = zero;
+            SECTION("CG ICholesky")
+            {
+              options.precond() = LSPrecond::incomplete_cholesky;
 
-            //   LinearSolver solver{options};
+              Vector<double> x{5};
+              x = zero;
 
-            //   solver.solveLocalSystem(A, x, b);
-            //   Vector error = x - x_exact;
-            //   REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
-            // }
+              LinearSolver solver{options};
 
-            // SECTION("CG AMG")
-            // {
-            //   options.precond() = LSPrecond::amg;
+              solver.solveLocalSystem(A, x, b);
+              Vector error = x - x_exact;
+              REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+            }
 
-            //   Vector<double> x{5};
-            //   x = zero;
+            SECTION("CG AMG")
+            {
+              options.precond() = LSPrecond::amg;
 
-            //   LinearSolver solver{options};
+              Vector<double> x{5};
+              x = zero;
 
-            //   solver.solveLocalSystem(A, x, b);
-            //   Vector error = x - x_exact;
-            //   REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
-            // }
+              REQUIRE_THROWS_WITH(LinearSolver{options}, "error: AMG is not an Eigen3 preconditioner!");
+            }
           }
 
           SECTION("Cholesky")
@@ -706,170 +696,186 @@ TEST_CASE("LinearSolver", "[algebra]")
           }
 #endif   // PUGS_HAS_PETSC
         }
-      }
-    }
-  }
 
-  SECTION("Dense Matrices")
-  {
-    SECTION("check linear solvers")
-    {
-      SECTION("symmetric system")
-      {
-        SmallMatrix<double> A{5};
-        A = zero;
+        SECTION("Eigen3")
+        {
+#ifdef PUGS_HAS_EIGEN3
 
-        A(0, 0) = 2;
-        A(0, 1) = -1;
+          SECTION("BICGStab")
+          {
+            LinearSolverOptions options;
+            options.library() = LSLibrary::eigen3;
+            options.method()  = LSMethod::bicgstab;
+            options.precond() = LSPrecond::none;
+            options.verbose() = true;
 
-        A(1, 0) = -1;
-        A(1, 1) = 2;
-        A(1, 2) = -1;
+            SECTION("BICGStab no preconditioner")
+            {
+              options.precond() = LSPrecond::none;
 
-        A(2, 1) = -1;
-        A(2, 2) = 2;
-        A(2, 3) = -1;
+              Vector<double> x{5};
+              x = zero;
 
-        A(3, 2) = -1;
-        A(3, 3) = 2;
-        A(3, 4) = -1;
+              LinearSolver solver{options};
 
-        A(4, 3) = -1;
-        A(4, 4) = 2;
+              solver.solveLocalSystem(A, x, b);
+              Vector error = x - x_exact;
+              REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+            }
 
-        SmallVector<const double> x_exact = [] {
-          SmallVector<double> y{5};
-          y[0] = 1;
-          y[1] = 3;
-          y[2] = 2;
-          y[3] = 4;
-          y[4] = 5;
-          return y;
-        }();
+            SECTION("BICGStab Diagonal")
+            {
+              options.precond() = LSPrecond::diagonal;
 
-        SmallVector<double> b = A * x_exact;
+              Vector<double> x{5};
+              x = zero;
 
-        SECTION("builtin")
-        {
-          SECTION("CG no preconditioner")
-          {
-            LinearSolverOptions options;
-            options.library() = LSLibrary::builtin;
-            options.method()  = LSMethod::cg;
-            options.precond() = LSPrecond::none;
+              LinearSolver solver{options};
 
-            SmallVector<double> x{5};
-            x = zero;
+              solver.solveLocalSystem(A, x, b);
+              Vector error = x - x_exact;
+              REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+            }
 
-            LinearSolver solver{options};
+            SECTION("BICGStab ILU")
+            {
+              options.precond() = LSPrecond::incomplete_LU;
 
-            solver.solveLocalSystem(A, x, b);
-            SmallVector error = x - x_exact;
-            REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
-          }
-        }
+              Vector<double> x{5};
+              x = zero;
 
-        SECTION("PETSc")
-        {
-#ifdef PUGS_HAS_PETSC
+              LinearSolver solver{options};
 
-          SECTION("CG")
+              solver.solveLocalSystem(A, x, b);
+              Vector error = x - x_exact;
+              REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+            }
+          }
+
+          SECTION("BICGStab2")
           {
             LinearSolverOptions options;
             options.library() = LSLibrary::petsc;
-            options.method()  = LSMethod::cg;
+            options.method()  = LSMethod::bicgstab2;
             options.precond() = LSPrecond::none;
-            options.verbose() = true;
 
-            SECTION("CG no preconditioner")
+            SECTION("BICGStab2 no preconditioner")
             {
               options.precond() = LSPrecond::none;
 
-              SmallVector<double> x{5};
+              Vector<double> x{5};
               x = zero;
 
               LinearSolver solver{options};
 
               solver.solveLocalSystem(A, x, b);
-              SmallVector error = x - x_exact;
+              Vector error = x - x_exact;
               REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
             }
 
-            SECTION("CG Diagonal")
+            SECTION("BICGStab2 Diagonal")
             {
               options.precond() = LSPrecond::diagonal;
 
-              SmallVector<double> x{5};
+              Vector<double> x{5};
               x = zero;
 
               LinearSolver solver{options};
 
               solver.solveLocalSystem(A, x, b);
-              SmallVector error = x - x_exact;
+              Vector error = x - x_exact;
               REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
             }
+          }
 
-            SECTION("CG ICholesky")
+          SECTION("GMRES")
+          {
+            LinearSolverOptions options;
+            options.library() = LSLibrary::petsc;
+            options.method()  = LSMethod::gmres;
+            options.precond() = LSPrecond::none;
+
+            SECTION("GMRES no preconditioner")
             {
-              options.precond() = LSPrecond::incomplete_cholesky;
+              options.precond() = LSPrecond::none;
 
-              SmallVector<double> x{5};
+              Vector<double> x{5};
               x = zero;
 
               LinearSolver solver{options};
 
               solver.solveLocalSystem(A, x, b);
-              SmallVector error = x - x_exact;
+              Vector error = x - x_exact;
               REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
             }
 
-            SECTION("CG AMG")
+            SECTION("GMRES Diagonal")
             {
-              options.precond() = LSPrecond::amg;
+              options.precond() = LSPrecond::diagonal;
 
-              SmallVector<double> x{5};
+              Vector<double> x{5};
               x = zero;
 
               LinearSolver solver{options};
 
               solver.solveLocalSystem(A, x, b);
-              SmallVector error = x - x_exact;
+              Vector error = x - x_exact;
+              REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+            }
+
+            SECTION("GMRES ILU")
+            {
+              options.precond() = LSPrecond::incomplete_LU;
+
+              Vector<double> x{5};
+              x = zero;
+
+              LinearSolver solver{options};
+
+              solver.solveLocalSystem(A, x, b);
+              Vector error = x - x_exact;
               REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
             }
           }
 
-          SECTION("Cholesky")
+          SECTION("LU")
           {
             LinearSolverOptions options;
             options.library() = LSLibrary::petsc;
-            options.method()  = LSMethod::cholesky;
+            options.method()  = LSMethod::lu;
             options.precond() = LSPrecond::none;
 
-            SmallVector<double> x{5};
+            Vector<double> x{5};
             x = zero;
 
             LinearSolver solver{options};
 
             solver.solveLocalSystem(A, x, b);
-            SmallVector error = x - x_exact;
+            Vector error = x - x_exact;
             REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
           }
 
-#else    // PUGS_HAS_PETSC
-          SECTION("PETSc not linked")
+#else    // PUGS_HAS_EIGEN3
+          SECTION("Eigen3 not linked")
           {
             LinearSolverOptions options;
             options.library() = LSLibrary::petsc;
             options.method()  = LSMethod::cg;
             options.precond() = LSPrecond::none;
 
-            REQUIRE_THROWS_WITH(LinearSolver{options}, "error: PETSc is not linked to pugs. Cannot use it!");
+            REQUIRE_THROWS_WITH(LinearSolver{options}, "error: Eigen3 is not linked to pugs. Cannot use it!");
           }
-#endif   // PUGS_HAS_PETSC
+#endif   // PUGS_HAS_EIGEN3
         }
       }
+    }
+  }
 
-      SECTION("none symmetric system")
+  SECTION("Dense Matrices")
+  {
+    SECTION("check linear solvers")
+    {
+      SECTION("symmetric system")
       {
         SmallMatrix<double> A{5};
         A = zero;
@@ -877,20 +883,20 @@ TEST_CASE("LinearSolver", "[algebra]")
         A(0, 0) = 2;
         A(0, 1) = -1;
 
-        A(1, 0) = -0.2;
+        A(1, 0) = -1;
         A(1, 1) = 2;
         A(1, 2) = -1;
 
         A(2, 1) = -1;
-        A(2, 2) = 4;
-        A(2, 3) = -2;
+        A(2, 2) = 2;
+        A(2, 3) = -1;
 
         A(3, 2) = -1;
         A(3, 3) = 2;
-        A(3, 4) = -0.1;
+        A(3, 4) = -1;
 
-        A(4, 3) = 1;
-        A(4, 4) = 3;
+        A(4, 3) = -1;
+        A(4, 4) = 2;
 
         SmallVector<const double> x_exact = [] {
           SmallVector<double> y{5};
@@ -906,11 +912,11 @@ TEST_CASE("LinearSolver", "[algebra]")
 
         SECTION("builtin")
         {
-          SECTION("BICGStab no preconditioner")
+          SECTION("CG no preconditioner")
           {
             LinearSolverOptions options;
             options.library() = LSLibrary::builtin;
-            options.method()  = LSMethod::bicgstab;
+            options.method()  = LSMethod::cg;
             options.precond() = LSPrecond::none;
 
             SmallVector<double> x{5};
@@ -928,15 +934,15 @@ TEST_CASE("LinearSolver", "[algebra]")
         {
 #ifdef PUGS_HAS_EIGEN3
 
-          SECTION("BICGStab")
+          SECTION("CG")
           {
             LinearSolverOptions options;
             options.library() = LSLibrary::eigen3;
-            options.method()  = LSMethod::bicgstab;
+            options.method()  = LSMethod::cg;
             options.precond() = LSPrecond::none;
             options.verbose() = true;
 
-            SECTION("BICGStab no preconditioner")
+            SECTION("CG no preconditioner")
             {
               options.precond() = LSPrecond::none;
 
@@ -950,7 +956,7 @@ TEST_CASE("LinearSolver", "[algebra]")
               REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
             }
 
-            SECTION("BICGStab Diagonal")
+            SECTION("CG Diagonal")
             {
               options.precond() = LSPrecond::diagonal;
 
@@ -964,45 +970,75 @@ TEST_CASE("LinearSolver", "[algebra]")
               REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
             }
 
-            SECTION("BICGStab ILU")
+            SECTION("CG ICholesky")
             {
-              options.precond() = LSPrecond::incomplete_LU;
+              options.precond() = LSPrecond::incomplete_cholesky;
 
               SmallVector<double> x{5};
               x = zero;
 
               LinearSolver solver{options};
 
-              solver.solveLocalSystem(A, x, b);
-              SmallVector error = x - x_exact;
-              REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+              REQUIRE_THROWS_WITH(solver.solveLocalSystem(A, x, b),
+                                  "error: incomplete cholesky is not available for dense matrices in Eigen3");
+            }
+
+            SECTION("CG AMG")
+            {
+              options.precond() = LSPrecond::amg;
+
+              SmallVector<double> x{5};
+              x = zero;
+
+              REQUIRE_THROWS_WITH(LinearSolver{options}, "error: AMG is not an Eigen3 preconditioner!");
             }
           }
 
-          SECTION("BICGStab2")
+          SECTION("Cholesky")
           {
             LinearSolverOptions options;
-            options.library() = LSLibrary::petsc;
-            options.method()  = LSMethod::bicgstab2;
+            options.library() = LSLibrary::eigen3;
+            options.method()  = LSMethod::cholesky;
             options.precond() = LSPrecond::none;
 
-            SECTION("BICGStab2 no preconditioner")
-            {
-              options.precond() = LSPrecond::none;
+            SmallVector<double> x{5};
+            x = zero;
 
-              SmallVector<double> x{5};
-              x = zero;
+            LinearSolver solver{options};
 
-              LinearSolver solver{options};
+            solver.solveLocalSystem(A, x, b);
+            SmallVector error = x - x_exact;
+            REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+          }
 
-              solver.solveLocalSystem(A, x, b);
-              SmallVector error = x - x_exact;
-              REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
-            }
+#else    // PUGS_HAS_EIGEN3
+          SECTION("Eigen3 not linked")
+          {
+            LinearSolverOptions options;
+            options.library() = LSLibrary::eigen3;
+            options.method()  = LSMethod::cg;
+            options.precond() = LSPrecond::none;
 
-            SECTION("BICGStab2 Diagonal")
+            REQUIRE_THROWS_WITH(LinearSolver{options}, "error: Eigen3 is not linked to pugs. Cannot use it!");
+          }
+#endif   // PUGS_HAS_EIGEN3
+        }
+
+        SECTION("PETSc")
+        {
+#ifdef PUGS_HAS_PETSC
+
+          SECTION("CG")
+          {
+            LinearSolverOptions options;
+            options.library() = LSLibrary::petsc;
+            options.method()  = LSMethod::cg;
+            options.precond() = LSPrecond::none;
+            options.verbose() = true;
+
+            SECTION("CG no preconditioner")
             {
-              options.precond() = LSPrecond::diagonal;
+              options.precond() = LSPrecond::none;
 
               SmallVector<double> x{5};
               x = zero;
@@ -1013,18 +1049,10 @@ TEST_CASE("LinearSolver", "[algebra]")
               SmallVector error = x - x_exact;
               REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
             }
-          }
 
-          SECTION("GMRES")
-          {
-            LinearSolverOptions options;
-            options.library() = LSLibrary::petsc;
-            options.method()  = LSMethod::gmres;
-            options.precond() = LSPrecond::none;
-
-            SECTION("GMRES no preconditioner")
+            SECTION("CG Diagonal")
             {
-              options.precond() = LSPrecond::none;
+              options.precond() = LSPrecond::diagonal;
 
               SmallVector<double> x{5};
               x = zero;
@@ -1036,9 +1064,9 @@ TEST_CASE("LinearSolver", "[algebra]")
               REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
             }
 
-            SECTION("GMRES Diagonal")
+            SECTION("CG ICholesky")
             {
-              options.precond() = LSPrecond::diagonal;
+              options.precond() = LSPrecond::incomplete_cholesky;
 
               SmallVector<double> x{5};
               x = zero;
@@ -1050,9 +1078,9 @@ TEST_CASE("LinearSolver", "[algebra]")
               REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
             }
 
-            SECTION("GMRES ILU")
+            SECTION("CG AMG")
             {
-              options.precond() = LSPrecond::incomplete_LU;
+              options.precond() = LSPrecond::amg;
 
               SmallVector<double> x{5};
               x = zero;
@@ -1065,11 +1093,11 @@ TEST_CASE("LinearSolver", "[algebra]")
             }
           }
 
-          SECTION("LU")
+          SECTION("Cholesky")
           {
             LinearSolverOptions options;
             options.library() = LSLibrary::petsc;
-            options.method()  = LSMethod::lu;
+            options.method()  = LSMethod::cholesky;
             options.precond() = LSPrecond::none;
 
             SmallVector<double> x{5};
@@ -1082,33 +1110,64 @@ TEST_CASE("LinearSolver", "[algebra]")
             REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
           }
 
-#else    // PUGS_HAS_EIGEN3
-          SECTION("Eigen3 not linked")
+#else    // PUGS_HAS_PETSC
+          SECTION("PETSc not linked")
           {
             LinearSolverOptions options;
             options.library() = LSLibrary::petsc;
             options.method()  = LSMethod::cg;
             options.precond() = LSPrecond::none;
 
-            REQUIRE_THROWS_WITH(LinearSolver{options}, "error: Eigen3 is not linked to pugs. Cannot use it!");
+            REQUIRE_THROWS_WITH(LinearSolver{options}, "error: PETSc is not linked to pugs. Cannot use it!");
           }
-#endif   // PUGS_HAS_EIGEN3
+#endif   // PUGS_HAS_PETSC
         }
+      }
 
-        SECTION("PETSc")
+      SECTION("none symmetric system")
+      {
+        SECTION("Dense matrix")
         {
-#ifdef PUGS_HAS_PETSC
+          SmallMatrix<double> A{5};
+          A = zero;
 
-          SECTION("BICGStab")
-          {
-            LinearSolverOptions options;
-            options.library() = LSLibrary::petsc;
-            options.method()  = LSMethod::bicgstab;
-            options.precond() = LSPrecond::none;
-            options.verbose() = true;
+          A(0, 0) = 2;
+          A(0, 1) = -1;
+
+          A(1, 0) = -0.2;
+          A(1, 1) = 2;
+          A(1, 2) = -1;
+
+          A(2, 1) = -1;
+          A(2, 2) = 4;
+          A(2, 3) = -2;
+
+          A(3, 2) = -1;
+          A(3, 3) = 2;
+          A(3, 4) = -0.1;
+
+          A(4, 3) = 1;
+          A(4, 4) = 3;
 
+          SmallVector<const double> x_exact = [] {
+            SmallVector<double> y{5};
+            y[0] = 1;
+            y[1] = 3;
+            y[2] = 2;
+            y[3] = 4;
+            y[4] = 5;
+            return y;
+          }();
+
+          SmallVector<double> b = A * x_exact;
+
+          SECTION("builtin")
+          {
             SECTION("BICGStab no preconditioner")
             {
+              LinearSolverOptions options;
+              options.library() = LSLibrary::builtin;
+              options.method()  = LSMethod::bicgstab;
               options.precond() = LSPrecond::none;
 
               SmallVector<double> x{5};
@@ -1120,60 +1179,135 @@ TEST_CASE("LinearSolver", "[algebra]")
               SmallVector error = x - x_exact;
               REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
             }
+          }
 
-            SECTION("BICGStab Diagonal")
+          SECTION("Eigen3")
+          {
+#ifdef PUGS_HAS_EIGEN3
+
+            SECTION("BICGStab")
             {
-              options.precond() = LSPrecond::diagonal;
+              LinearSolverOptions options;
+              options.library() = LSLibrary::eigen3;
+              options.method()  = LSMethod::bicgstab;
+              options.precond() = LSPrecond::none;
+              options.verbose() = true;
 
-              SmallVector<double> x{5};
-              x = zero;
+              SECTION("BICGStab no preconditioner")
+              {
+                options.precond() = LSPrecond::none;
 
-              LinearSolver solver{options};
+                SmallVector<double> x{5};
+                x = zero;
 
-              solver.solveLocalSystem(A, x, b);
-              SmallVector error = x - x_exact;
-              REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+                LinearSolver solver{options};
+
+                solver.solveLocalSystem(A, x, b);
+                SmallVector error = x - x_exact;
+                REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+              }
+
+              SECTION("BICGStab Diagonal")
+              {
+                options.precond() = LSPrecond::diagonal;
+
+                SmallVector<double> x{5};
+                x = zero;
+
+                LinearSolver solver{options};
+
+                solver.solveLocalSystem(A, x, b);
+                SmallVector error = x - x_exact;
+                REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+              }
+
+              SECTION("BICGStab ILU")
+              {
+                options.precond() = LSPrecond::incomplete_LU;
+
+                SmallVector<double> x{5};
+                x = zero;
+
+                LinearSolver solver{options};
+
+                REQUIRE_THROWS_WITH(solver.solveLocalSystem(A, x, b),
+                                    "error: incomplete LU is not available for dense matrices in Eigen3");
+              }
             }
 
-            SECTION("BICGStab ILU")
+            SECTION("BICGStab2")
             {
-              options.precond() = LSPrecond::incomplete_LU;
+              LinearSolverOptions options;
+              options.library() = LSLibrary::eigen3;
+              options.method()  = LSMethod::bicgstab2;
+              options.precond() = LSPrecond::none;
 
-              SmallVector<double> x{5};
-              x = zero;
+              SECTION("BICGStab2 no preconditioner")
+              {
+                options.precond() = LSPrecond::none;
 
-              LinearSolver solver{options};
+                SmallVector<double> x{5};
+                x = zero;
 
-              solver.solveLocalSystem(A, x, b);
-              SmallVector error = x - x_exact;
-              REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+                REQUIRE_THROWS_WITH(LinearSolver{options}, "error: BICGStab2 is not an Eigen3 linear solver!");
+              }
             }
-          }
-
-          SECTION("BICGStab2")
-          {
-            LinearSolverOptions options;
-            options.library() = LSLibrary::petsc;
-            options.method()  = LSMethod::bicgstab2;
-            options.precond() = LSPrecond::none;
 
-            SECTION("BICGStab2 no preconditioner")
+            SECTION("GMRES")
             {
+              LinearSolverOptions options;
+              options.library() = LSLibrary::eigen3;
+              options.method()  = LSMethod::gmres;
               options.precond() = LSPrecond::none;
 
-              SmallVector<double> x{5};
-              x = zero;
+              SECTION("GMRES no preconditioner")
+              {
+                options.precond() = LSPrecond::none;
 
-              LinearSolver solver{options};
+                SmallVector<double> x{5};
+                x = zero;
 
-              solver.solveLocalSystem(A, x, b);
-              SmallVector error = x - x_exact;
-              REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+                LinearSolver solver{options};
+
+                solver.solveLocalSystem(A, x, b);
+                SmallVector error = x - x_exact;
+                REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+              }
+
+              SECTION("GMRES Diagonal")
+              {
+                options.precond() = LSPrecond::diagonal;
+
+                SmallVector<double> x{5};
+                x = zero;
+
+                LinearSolver solver{options};
+
+                solver.solveLocalSystem(A, x, b);
+                SmallVector error = x - x_exact;
+                REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+              }
+
+              SECTION("GMRES ILU")
+              {
+                options.precond() = LSPrecond::incomplete_LU;
+
+                SmallVector<double> x{5};
+                x = zero;
+
+                LinearSolver solver{options};
+
+                REQUIRE_THROWS_WITH(solver.solveLocalSystem(A, x, b),
+                                    "error: incomplete LU is not available for dense matrices in Eigen3");
+              }
             }
 
-            SECTION("BICGStab2 Diagonal")
+            SECTION("LU")
             {
-              options.precond() = LSPrecond::diagonal;
+              LinearSolverOptions options;
+              options.library() = LSLibrary::eigen3;
+              options.method()  = LSMethod::lu;
+              options.precond() = LSPrecond::none;
 
               SmallVector<double> x{5};
               x = zero;
@@ -1184,46 +1318,167 @@ TEST_CASE("LinearSolver", "[algebra]")
               SmallVector error = x - x_exact;
               REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
             }
+
+#else    // PUGS_HAS_EIGEN3
+            SECTION("Eigen3 not linked")
+            {
+              LinearSolverOptions options;
+              options.library() = LSLibrary::eigen3;
+              options.method()  = LSMethod::cg;
+              options.precond() = LSPrecond::none;
+
+              REQUIRE_THROWS_WITH(LinearSolver{options}, "error: Eigen3 is not linked to pugs. Cannot use it!");
+            }
+#endif   // PUGS_HAS_EIGEN3
           }
 
-          SECTION("GMRES")
+          SECTION("PETSc")
           {
-            LinearSolverOptions options;
-            options.library() = LSLibrary::petsc;
-            options.method()  = LSMethod::gmres;
-            options.precond() = LSPrecond::none;
+#ifdef PUGS_HAS_PETSC
 
-            SECTION("GMRES no preconditioner")
+            SECTION("BICGStab")
             {
+              LinearSolverOptions options;
+              options.library() = LSLibrary::petsc;
+              options.method()  = LSMethod::bicgstab;
               options.precond() = LSPrecond::none;
+              options.verbose() = true;
 
-              SmallVector<double> x{5};
-              x = zero;
+              SECTION("BICGStab no preconditioner")
+              {
+                options.precond() = LSPrecond::none;
 
-              LinearSolver solver{options};
+                SmallVector<double> x{5};
+                x = zero;
 
-              solver.solveLocalSystem(A, x, b);
-              SmallVector error = x - x_exact;
-              REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+                LinearSolver solver{options};
+
+                solver.solveLocalSystem(A, x, b);
+                SmallVector error = x - x_exact;
+                REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+              }
+
+              SECTION("BICGStab Diagonal")
+              {
+                options.precond() = LSPrecond::diagonal;
+
+                SmallVector<double> x{5};
+                x = zero;
+
+                LinearSolver solver{options};
+
+                solver.solveLocalSystem(A, x, b);
+                SmallVector error = x - x_exact;
+                REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+              }
+
+              SECTION("BICGStab ILU")
+              {
+                options.precond() = LSPrecond::incomplete_LU;
+
+                SmallVector<double> x{5};
+                x = zero;
+
+                LinearSolver solver{options};
+
+                solver.solveLocalSystem(A, x, b);
+                SmallVector error = x - x_exact;
+                REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+              }
             }
 
-            SECTION("GMRES Diagonal")
+            SECTION("BICGStab2")
             {
-              options.precond() = LSPrecond::diagonal;
+              LinearSolverOptions options;
+              options.library() = LSLibrary::petsc;
+              options.method()  = LSMethod::bicgstab2;
+              options.precond() = LSPrecond::none;
 
-              SmallVector<double> x{5};
-              x = zero;
+              SECTION("BICGStab2 no preconditioner")
+              {
+                options.precond() = LSPrecond::none;
 
-              LinearSolver solver{options};
+                SmallVector<double> x{5};
+                x = zero;
 
-              solver.solveLocalSystem(A, x, b);
-              SmallVector error = x - x_exact;
-              REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+                LinearSolver solver{options};
+
+                solver.solveLocalSystem(A, x, b);
+                SmallVector error = x - x_exact;
+                REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+              }
+
+              SECTION("BICGStab2 Diagonal")
+              {
+                options.precond() = LSPrecond::diagonal;
+
+                SmallVector<double> x{5};
+                x = zero;
+
+                LinearSolver solver{options};
+
+                solver.solveLocalSystem(A, x, b);
+                SmallVector error = x - x_exact;
+                REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+              }
             }
 
-            SECTION("GMRES ILU")
+            SECTION("GMRES")
             {
-              options.precond() = LSPrecond::incomplete_LU;
+              LinearSolverOptions options;
+              options.library() = LSLibrary::petsc;
+              options.method()  = LSMethod::gmres;
+              options.precond() = LSPrecond::none;
+
+              SECTION("GMRES no preconditioner")
+              {
+                options.precond() = LSPrecond::none;
+
+                SmallVector<double> x{5};
+                x = zero;
+
+                LinearSolver solver{options};
+
+                solver.solveLocalSystem(A, x, b);
+                SmallVector error = x - x_exact;
+                REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+              }
+
+              SECTION("GMRES Diagonal")
+              {
+                options.precond() = LSPrecond::diagonal;
+
+                SmallVector<double> x{5};
+                x = zero;
+
+                LinearSolver solver{options};
+
+                solver.solveLocalSystem(A, x, b);
+                SmallVector error = x - x_exact;
+                REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+              }
+
+              SECTION("GMRES ILU")
+              {
+                options.precond() = LSPrecond::incomplete_LU;
+
+                SmallVector<double> x{5};
+                x = zero;
+
+                LinearSolver solver{options};
+
+                solver.solveLocalSystem(A, x, b);
+                SmallVector error = x - x_exact;
+                REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
+              }
+            }
+
+            SECTION("LU")
+            {
+              LinearSolverOptions options;
+              options.library() = LSLibrary::petsc;
+              options.method()  = LSMethod::lu;
+              options.precond() = LSPrecond::none;
 
               SmallVector<double> x{5};
               x = zero;
@@ -1234,36 +1489,19 @@ TEST_CASE("LinearSolver", "[algebra]")
               SmallVector error = x - x_exact;
               REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
             }
-          }
-
-          SECTION("LU")
-          {
-            LinearSolverOptions options;
-            options.library() = LSLibrary::petsc;
-            options.method()  = LSMethod::lu;
-            options.precond() = LSPrecond::none;
-
-            SmallVector<double> x{5};
-            x = zero;
-
-            LinearSolver solver{options};
-
-            solver.solveLocalSystem(A, x, b);
-            SmallVector error = x - x_exact;
-            REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact)));
-          }
 
 #else    // PUGS_HAS_PETSC
-          SECTION("PETSc not linked")
-          {
-            LinearSolverOptions options;
-            options.library() = LSLibrary::petsc;
-            options.method()  = LSMethod::cg;
-            options.precond() = LSPrecond::none;
+            SECTION("PETSc not linked")
+            {
+              LinearSolverOptions options;
+              options.library() = LSLibrary::petsc;
+              options.method()  = LSMethod::cg;
+              options.precond() = LSPrecond::none;
 
-            REQUIRE_THROWS_WITH(LinearSolver{options}, "error: PETSc is not linked to pugs. Cannot use it!");
-          }
+              REQUIRE_THROWS_WITH(LinearSolver{options}, "error: PETSc is not linked to pugs. Cannot use it!");
+            }
 #endif   // PUGS_HAS_PETSC
+          }
         }
       }
     }