diff --git a/src/algebra/BiCGStab.hpp b/src/algebra/BiCGStab.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4faf83a054572821d07aa7d29fc08779c3ce8734
--- /dev/null
+++ b/src/algebra/BiCGStab.hpp
@@ -0,0 +1,82 @@
+#ifndef BICG_STAB_HPP
+#define BICG_STAB_HPP
+
+#include <iostream>
+
+class BiCGStab
+{
+ public:
+  template <typename VectorType, typename MatrixType, typename PreconditionerType>
+  BiCGStab(const VectorType& b,
+           const MatrixType& A,
+           [[maybe_unused]] const PreconditionerType& P,
+           VectorType& x,
+           const size_t max_iter,
+           const double epsilon = 1e-6)
+  {
+    std::cout << "- bi-conjugate gradient stabilized\n";
+    std::cout << "  epsilon = " << epsilon << '\n';
+    std::cout << "  maximum number of iterations: " << max_iter << '\n';
+
+    VectorType r_k_1{b.size()};
+
+    r_k_1 = b - A * x;
+
+    double residu = std::sqrt((r_k_1, r_k_1));   // Norm(r_k_1);
+
+    if (residu != 0) {
+      double resid0 = residu;
+
+      VectorType rTilda_0 = copy(r_k_1);
+      VectorType p_k      = copy(r_k_1);
+
+      VectorType s_k{x.size()};
+
+      VectorType Ap_k{x.size()};
+      VectorType As_k{x.size()};
+
+      VectorType r_k{x.size()};
+
+      std::cout << "   initial residu: " << resid0 << '\n';
+      for (size_t i = 1; i <= max_iter; ++i) {
+        std::cout << "  - iteration: " << std::setw(6) << i << "\tresidu: " << residu / resid0
+                  << "\tabsolute: " << residu << '\n';
+
+        Ap_k = A * p_k;
+
+        const double alpha_k = (r_k_1, rTilda_0) / (Ap_k, rTilda_0);
+
+        s_k  = r_k_1 - alpha_k * Ap_k;
+        As_k = A * s_k;
+
+        const double w_k = (As_k, s_k) / (As_k, As_k);
+
+        x += alpha_k * p_k + w_k * s_k;
+        r_k = s_k - w_k * As_k;
+
+        const double beta_k = (r_k, rTilda_0) / (r_k_1, rTilda_0) * (alpha_k / w_k);
+
+        p_k -= w_k * Ap_k;
+        p_k *= beta_k;
+        p_k += r_k;
+
+        if ((residu = std::sqrt((r_k, r_k))) / resid0 < epsilon) {
+          break;
+        }
+
+        r_k_1 = r_k;
+      }
+
+      if (residu / resid0 > epsilon) {
+        std::cout << "  bi_conjugate gradient stabilized: *NOT CONVERGED*\n";
+        std::cout << "  - epsilon:          " << epsilon << '\n';
+        std::cout << "  - relative residu : " << residu / resid0 << '\n';
+        std::cout << "  - absolute residu : " << residu << '\n';
+      }
+    }
+
+    std::cout << "- bi-conjugate gradient stabilized: done\n";
+  }
+};
+
+#endif   // BICG_STAB_HPP
diff --git a/src/algebra/PCG.hpp b/src/algebra/PCG.hpp
index 357ab3a1d1275d6f79ceb82627e28f0003f06edd..2a979af2be8ad89c4ae3049f71b5d0b28af1a161 100644
--- a/src/algebra/PCG.hpp
+++ b/src/algebra/PCG.hpp
@@ -38,7 +38,7 @@ struct PCG
 
         cg -= h;
 
-        g = copy(cg);   // C.computes(cg, g);
+        g = copy(cg);   // TODO: precond: g = g/C
 
         gcg = (g, cg);
 
@@ -55,8 +55,7 @@ struct PCG
       double ro = gcg / hAh;
       cg -= ro * b;
 
-      // VectorType b2 = b;
-      // C.computes(b2, b);
+      // TODO: precond: b <- b/C
 
       x += ro * h;
       g -= ro * b;
diff --git a/src/algebra/Vector.hpp b/src/algebra/Vector.hpp
index 3a21d2a534517427fae8fd1afead63baf7bf40e3..d9537f0e488f39bedf8849c299f06221e62a7dc9 100644
--- a/src/algebra/Vector.hpp
+++ b/src/algebra/Vector.hpp
@@ -103,7 +103,7 @@ class Vector
 
   PUGS_INLINE
   Vector
-  operator+(const Vector& y)
+  operator+(const Vector& y) const
   {
     Assert(this->size() == y.size());
     Vector sum{y.size()};
@@ -116,7 +116,7 @@ class Vector
 
   PUGS_INLINE
   Vector
-  operator-(const Vector& y)
+  operator-(const Vector& y) const
   {
     Assert(this->size() == y.size());
     Vector sum{y.size()};
diff --git a/src/main.cpp b/src/main.cpp
index 3647754351565d38353ebfabc878aadfeed73292..c2f6b3a32d2d869611c753e69d501c2c29dbb225 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -24,6 +24,7 @@
 
 #include <SynchronizerManager.hpp>
 
+#include <BiCGStab.hpp>
 #include <CRSMatrix.hpp>
 #include <PCG.hpp>
 
@@ -41,41 +42,70 @@ main(int argc, char* argv[])
     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) = 4;
-        if (i + 1 < matrix_size) {
-          F(i, i + 1) = -1;
-          F(i + 1, i) = -1;
+      {   // PCG simple test
+        size_t matrix_size = 10;
+        FlexibleMatrix F(matrix_size);
+
+        for (size_t i = 0; i < matrix_size; ++i) {
+          F(i, i) = 4;
+          if (i + 1 < matrix_size) {
+            F(i, i + 1) = -1;
+            F(i + 1, i) = -1;
+          }
         }
-      }
-      std::cout << F << '\n';
 
-      CRSMatrix A{F};
+        CRSMatrix A{F};
+
+        Vector<double> x{10};
+        for (size_t i = 0; i < x.size(); ++i) {
+          x[i] = 2 * i + 1;
+        }
+
+        Vector<double> Ax = A * x;
+
+        Vector<double> u{x.size()};
+        u = 0;
 
-      std::cout << A << '\n';
+        PCG{Ax, A, A, u, 100, 1e-12};
 
-      Vector<double> x{10};
-      for (size_t i = 0; i < x.size(); ++i) {
-        x[i] = 2 * i + 1;
+        std::cout << "== PCG report ==\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';
+        std::cout << "================\n";
       }
 
-      std::cout << "x=\n" << x << '\n';
+      {   // BiCGStab simple test
+        size_t matrix_size = 10;
+        FlexibleMatrix F(matrix_size);
 
-      Vector<double> Ax = A * x;
-      std::cout << "Ax=\n" << Ax << '\n';
+        for (size_t i = 0; i < matrix_size; ++i) {
+          F(i, i) = 4;
+          if (i + 1 < matrix_size) {
+            F(i, i + 1) = -1;
+            F(i + 1, i) = -0.3;
+          }
+        }
+
+        CRSMatrix A{F};
 
-      Vector<double> u{x.size()};
-      u = 0;
+        Vector<double> x{10};
+        for (size_t i = 0; i < x.size(); ++i) {
+          x[i] = 2 * i + 1;
+        }
+
+        Vector<double> Ax = A * x;
+        Vector<double> u{x.size()};
+        u = 0;
 
-      PCG{Ax, A, A, u, static_cast<size_t>(-1), 1e-12};
-      std::cout << "u=\n" << u << '\n';
+        BiCGStab{Ax, A, A, u, 100, 1e-12};
 
-      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';
+        std::cout << "== BiCGStab report ==\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';
+        std::cout << "=====================\n";
+      }
     }
 
     Kokkos::finalize();