diff --git a/modules/base/src/CMakeLists.txt b/modules/base/src/CMakeLists.txt
index b30a8312b937c84425ce039f0332faed98e73c98..ecdc389dbea1db9239f5aa92dc4152554938005d 100644
--- a/modules/base/src/CMakeLists.txt
+++ b/modules/base/src/CMakeLists.txt
@@ -28,6 +28,7 @@ platform.hh
 string_ref.hh
 pod_vector.hh
 fixed_string.hh
+tri_matrix.hh
 )
 
 module(NAME base SOURCES ${OST_BASE_SOURCES} 
diff --git a/modules/base/src/tri_matrix.hh b/modules/base/src/tri_matrix.hh
new file mode 100644
index 0000000000000000000000000000000000000000..21545ffdafb03c2ae99885f42296b8c790d8eafc
--- /dev/null
+++ b/modules/base/src/tri_matrix.hh
@@ -0,0 +1,61 @@
+#ifndef OST_TRI_MATRIX_HH
+#define OST_TRI_MATRIX_HH
+
+#include <vector>
+#include <cassert>
+#include <ost/module_config.hh>
+
+
+namespace ost {
+
+/// \brief triangular matrix template
+template <typename T>
+class TEMPLATE_EXPORT TriMatrix {
+public:
+  TriMatrix(int n, const T& def_val=T()):
+    data_((n*(n+1))/2, def_val), n_(n)
+  { }
+  
+  void Set(int i, int j, const T& sim)
+  {
+    data_[this->GetIndex(i, j)]=sim;
+  }
+  
+  const T& Get(int i, int j) const
+  {
+    return data_[this->GetIndex(i, j)];
+  }
+  
+  T& operator()(int i, int j)
+  {
+    return data_[this->GetIndex(i, j)];
+  }
+  
+  const T& operator()(int i, int j) const
+  {
+    return data_[this->GetIndex(i, j)];
+  }  
+  
+  int GetSize() const 
+  {
+    return n_;
+  }
+  std::vector<T>& Data()
+  {
+    return data_;
+  }
+private:
+  int GetIndex(int i, int j) const {
+    assert(i<n_);
+    assert(j<n_);
+    if (j>i) 
+      std::swap(j, i);
+    return ((2*n_-j+1)*j)/2+i-j;
+  }
+  std::vector<T> data_;
+  int n_;
+};
+
+}
+
+#endif