diff --git a/src/algebra/CRSMatrix.hpp b/src/algebra/CRSMatrix.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..112ceae31b326998cbdd9ef6f044e086afa05ede
--- /dev/null
+++ b/src/algebra/CRSMatrix.hpp
@@ -0,0 +1,158 @@
+#ifndef CRS_MATRIX_HPP
+#define CRS_MATRIX_HPP
+
+#include <Array.hpp>
+#include <Kokkos_StaticCrsGraph.hpp>
+#include <PugsAssert.hpp>
+
+#include <iostream>
+
+class FlexibleMatrix
+{
+ public:
+  class FlexibleRow
+  {
+    friend class FlexibleMatrix;
+    std::map<uint64_t, double> m_id_value_map;
+
+   public:
+    const double& operator[](const size_t& 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)
+    {
+      auto i_value = m_id_value_map.find(j);
+      if (i_value != m_id_value_map.end()) {
+        return i_value->second;
+      } else {
+        auto [i_inserted, success] = m_id_value_map.insert(std::make_pair(j, 0));
+        Assert(success);
+        return i_inserted->second;
+      }
+    }
+
+    friend std::ostream&
+    operator<<(std::ostream& os, const FlexibleRow& row)
+    {
+      for (auto [j, value] : row.m_id_value_map) {
+        os << ' ' << j << ':' << value;
+      }
+      return os;
+    }
+
+    FlexibleRow() = default;
+  };
+
+ private:
+  Array<FlexibleRow> m_row_array;
+
+ public:
+  FlexibleRow&
+  row(const size_t i)
+  {
+    return m_row_array[i];
+  }
+
+  const FlexibleRow&
+  row(const size_t i) const
+  {
+    return m_row_array[i];
+  }
+
+  double&
+  operator()(const size_t& i, const size_t& j)
+  {
+    return m_row_array[i][j];
+  }
+
+  const double&
+  operator()(const size_t& i, const size_t& j) const
+  {
+    return m_row_array[i][j];
+  }
+
+  friend std::ostream&
+  operator<<(std::ostream& os, const FlexibleMatrix& M)
+  {
+    for (size_t i = 0; i < M.m_row_array.size(); ++i) {
+      os << i << " |" << M.m_row_array[i] << '\n';
+    }
+    return os;
+  }
+
+  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) {
+      const FlexibleRow& row = m_row_array[i_row];
+      for (auto [id, value] : row.m_id_value_map) {
+        graph_vector[i_row].push_back(id);
+      }
+    }
+    return graph_vector;
+  }
+
+  Array<double>
+  valueArray() const
+  {
+    size_t size = 0;
+    for (size_t 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);
+
+    size_t cpt = 0;
+    for (size_t 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;
+      }
+    }
+    return values;
+  }
+
+  FlexibleMatrix(size_t nb_row) : m_row_array{nb_row} {}
+
+  ~FlexibleMatrix() = default;
+};
+
+class CRSMatrix
+{
+ private:
+  using HostMatrix = Kokkos::StaticCrsGraph<unsigned int, Kokkos::HostSpace>;
+
+  HostMatrix m_host_matrix;
+  Array<double> m_values;
+
+ public:
+  friend std::ostream&
+  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) {
+      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) {
+        os << ' ' << M.m_host_matrix.entries(j) << ':' << M.m_values[j];
+      }
+      os << '\n';
+    }
+    return os;
+  }
+
+  CRSMatrix(const FlexibleMatrix& M)
+  {
+    m_host_matrix = Kokkos::create_staticcrsgraph<HostMatrix>("connectivity_matrix", M.graphVector());
+    m_values      = M.valueArray();
+  }
+  ~CRSMatrix() = default;
+};
+
+#endif   // CRS_MATRIX_HPP
diff --git a/src/main.cpp b/src/main.cpp
index 93ff1e39f0d3ad18c556d141f91754dcc1d4c211..00de1f4cc9007433e8d8e69766439a74c871f262 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -24,6 +24,8 @@
 
 #include <SynchronizerManager.hpp>
 
+#include <CRSMatrix.hpp>
+
 #include <iostream>
 
 #include <limits>
@@ -33,6 +35,31 @@
 int
 main(int argc, char* argv[])
 {
+  if (argc == 1) {
+    std::cout << "-- Testing linear algebra --\n";
+    Kokkos::initialize({4, -1, -1, true});
+
+    {
+      size_t matrix_size = 10;
+      FlexibleMatrix F(matrix_size);
+
+      for (size_t i = 0; i < matrix_size; ++i) {
+        F(i, i) = 2;
+        if (i + 1 < matrix_size) {
+          F(i, i + 1) = 1;
+        }
+      }
+      std::cout << F << '\n';
+
+      CRSMatrix M{F};
+
+      std::cout << M << '\n';
+    }
+
+    Kokkos::finalize();
+    return 0;
+  }
+
   std::string filename = initialize(argc, argv);
 
   std::regex gmsh_regex("(.*).msh");