diff --git a/src/algebra/CRSMatrix.hpp b/src/algebra/CRSMatrix.hpp
index 1c6b4f689cbe231f09f3b11ab1f400739d183d4d..010ebd95d037212db2d0fb55adcf85e9bc76b04c 100644
--- a/src/algebra/CRSMatrix.hpp
+++ b/src/algebra/CRSMatrix.hpp
@@ -9,23 +9,27 @@
 
 #include <iostream>
 
+template <typename DataType = double, typename IndexType = size_t>
 class FlexibleMatrix
 {
  public:
+  using data_type  = DataType;
+  using index_type = IndexType;
+
   class FlexibleRow
   {
     friend class FlexibleMatrix;
-    std::map<uint64_t, double> m_id_value_map;
+    std::map<IndexType, DataType> m_id_value_map;
 
    public:
-    const double& operator[](const size_t& j) const
+    const DataType& operator[](const IndexType& j) const
     {
       auto i_value = m_id_value_map.find(j);
       Assert(i_value != m_id_value_map.end());
       return i_value->second;
     }
 
-    double& operator[](const size_t& j)
+    DataType& operator[](const IndexType& j)
     {
       auto i_value = m_id_value_map.find(j);
       if (i_value != m_id_value_map.end()) {
@@ -54,25 +58,25 @@ class FlexibleMatrix
 
  public:
   FlexibleRow&
-  row(const size_t i)
+  row(const IndexType i)
   {
     return m_row_array[i];
   }
 
   const FlexibleRow&
-  row(const size_t i) const
+  row(const IndexType i) const
   {
     return m_row_array[i];
   }
 
-  double&
-  operator()(const size_t& i, const size_t& j)
+  DataType&
+  operator()(const IndexType& i, const IndexType& j)
   {
     return m_row_array[i][j];
   }
 
-  const double&
-  operator()(const size_t& i, const size_t& j) const
+  const DataType&
+  operator()(const IndexType& i, const IndexType& j) const
   {
     return m_row_array[i][j];
   }
@@ -80,7 +84,7 @@ class FlexibleMatrix
   friend std::ostream&
   operator<<(std::ostream& os, const FlexibleMatrix& M)
   {
-    for (size_t i = 0; i < M.m_row_array.size(); ++i) {
+    for (IndexType i = 0; i < M.m_row_array.size(); ++i) {
       os << i << " |" << M.m_row_array[i] << '\n';
     }
     return os;
@@ -89,8 +93,8 @@ class FlexibleMatrix
   auto
   graphVector() const
   {
-    std::vector<std::vector<uint64_t>> graph_vector(m_row_array.size());
-    for (size_t i_row = 0; i_row < m_row_array.size(); ++i_row) {
+    std::vector<std::vector<IndexType>> graph_vector(m_row_array.size());
+    for (IndexType i_row = 0; i_row < m_row_array.size(); ++i_row) {
       const FlexibleRow& row = m_row_array[i_row];
       for (auto [id, value] : row.m_id_value_map) {
         graph_vector[i_row].push_back(id);
@@ -99,18 +103,18 @@ class FlexibleMatrix
     return graph_vector;
   }
 
-  Array<double>
+  Array<DataType>
   valueArray() const
   {
-    size_t size = 0;
-    for (size_t i_row = 0; i_row < m_row_array.size(); ++i_row) {
+    IndexType size = 0;
+    for (IndexType i_row = 0; i_row < m_row_array.size(); ++i_row) {
       size += m_row_array[i_row].m_id_value_map.size();
     }
 
-    Array<double> values(size);
+    Array<DataType> values(size);
 
-    size_t cpt = 0;
-    for (size_t i_row = 0; i_row < m_row_array.size(); ++i_row) {
+    IndexType cpt = 0;
+    for (IndexType i_row = 0; i_row < m_row_array.size(); ++i_row) {
       const FlexibleRow& row = m_row_array[i_row];
       for (auto [id, value] : row.m_id_value_map) {
         values[cpt++] = value;
@@ -119,31 +123,32 @@ class FlexibleMatrix
     return values;
   }
 
-  FlexibleMatrix(size_t nb_row) : m_row_array{nb_row} {}
+  FlexibleMatrix(IndexType nb_row) : m_row_array{nb_row} {}
 
   ~FlexibleMatrix() = default;
 };
 
+template <typename DataType = double, typename IndexType = size_t>
 class CRSMatrix
 {
  private:
-  using HostMatrix = Kokkos::StaticCrsGraph<unsigned int, Kokkos::HostSpace>;
+  using HostMatrix = Kokkos::StaticCrsGraph<IndexType, Kokkos::HostSpace>;
 
   HostMatrix m_host_matrix;
-  Array<double> m_values;
+  Array<DataType> m_values;
 
  public:
-  Vector<double> operator*(const Vector<double>& x) const
+  Vector<DataType> operator*(const Vector<DataType>& x) const
   {
-    Vector<double> Ax{m_host_matrix.numRows()};
+    Vector<DataType> Ax{m_host_matrix.numRows()};
     auto host_row_map = m_host_matrix.row_map;
 
     parallel_for(
-      m_host_matrix.numRows(), PUGS_LAMBDA(const size_t& i_row) {
+      m_host_matrix.numRows(), PUGS_LAMBDA(const IndexType& i_row) {
         const auto row_begin = host_row_map(i_row);
         const auto row_end   = host_row_map(i_row + 1);
-        double sum{0};
-        for (size_t j = row_begin; j < row_end; ++j) {
+        DataType sum{0};
+        for (IndexType j = row_begin; j < row_end; ++j) {
           sum += m_values[j] * x[m_host_matrix.entries(j)];
         }
         Ax[i_row] = sum;
@@ -156,11 +161,11 @@ class CRSMatrix
   operator<<(std::ostream& os, const CRSMatrix& M)
   {
     auto host_row_map = M.m_host_matrix.row_map;
-    for (size_t i_row = 0; i_row < M.m_host_matrix.numRows(); ++i_row) {
+    for (IndexType i_row = 0; i_row < M.m_host_matrix.numRows(); ++i_row) {
       const auto& row_begin = host_row_map(i_row);
       const auto& row_end   = host_row_map(i_row + 1);
       os << i_row << " #";
-      for (size_t j = row_begin; j < row_end; ++j) {
+      for (IndexType j = row_begin; j < row_end; ++j) {
         os << ' ' << M.m_host_matrix.entries(j) << ':' << M.m_values[j];
       }
       os << '\n';
@@ -168,7 +173,7 @@ class CRSMatrix
     return os;
   }
 
-  CRSMatrix(const FlexibleMatrix& M)
+  CRSMatrix(const FlexibleMatrix<DataType, IndexType>& M)
   {
     m_host_matrix = Kokkos::create_staticcrsgraph<HostMatrix>("connectivity_matrix", M.graphVector());
     m_values      = M.valueArray();
diff --git a/src/algebra/Vector.hpp b/src/algebra/Vector.hpp
index 5f6cff9415ff431123070ac5f2363adb328365df..3a21d2a534517427fae8fd1afead63baf7bf40e3 100644
--- a/src/algebra/Vector.hpp
+++ b/src/algebra/Vector.hpp
@@ -101,6 +101,32 @@ class Vector
     return *this;
   }
 
+  PUGS_INLINE
+  Vector
+  operator+(const Vector& y)
+  {
+    Assert(this->size() == y.size());
+    Vector sum{y.size()};
+
+    parallel_for(
+      this->size(), PUGS_LAMBDA(const index_type& i) { sum.m_values[i] = m_values[i] + y.m_values[i]; });
+
+    return sum;
+  }
+
+  PUGS_INLINE
+  Vector
+  operator-(const Vector& y)
+  {
+    Assert(this->size() == y.size());
+    Vector sum{y.size()};
+
+    parallel_for(
+      this->size(), PUGS_LAMBDA(const index_type& i) { sum.m_values[i] = m_values[i] - y.m_values[i]; });
+
+    return sum;
+  }
+
   PUGS_INLINE
   DataType& operator[](const index_type& i) const noexcept(NO_ASSERT)
   {
diff --git a/src/main.cpp b/src/main.cpp
index 760164fcf200da6f1f70183ba572d26fdea8b38e..3647754351565d38353ebfabc878aadfeed73292 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -70,8 +70,12 @@ main(int argc, char* argv[])
       Vector<double> u{x.size()};
       u = 0;
 
-      PCG{Ax, A, A, u, 9, 1e-4};
-      std::cout << "u=" << u << '\n';
+      PCG{Ax, A, A, u, static_cast<size_t>(-1), 1e-12};
+      std::cout << "u=\n" << u << '\n';
+
+      std::cout << "L2 Error = " << std::sqrt((x - u, x - u)) << '\n';
+      std::cout << "L2 Norm  = " << std::sqrt((x, x)) << '\n';
+      std::cout << "L2 RelEr = " << std::sqrt((x - u, x - u)) / std::sqrt((x, x)) << '\n';
     }
 
     Kokkos::finalize();