Add tests for matrix reduction of complex examples
authorStefan Huber <shuber@sthu.org>
Mon, 11 Nov 2013 16:02:42 +0000 (17:02 +0100)
committerStefan Huber <shuber@sthu.org>
Tue, 12 Nov 2013 14:32:57 +0000 (15:32 +0100)
- Move matrix_reduction() to a persistence class.
- Add persistence test suite.
- Add a few helper functions to boolean_matrix classes.

include/libstick-0.1/booleanmatrix.h
include/libstick-0.1/matrixreduction.h [deleted file]
include/libstick-0.1/persistence.h [new file with mode: 0644]
include/libstick-0.1/simplicialcomplex.h
tests/main.cc
tests/persistence.h [new file with mode: 0644]
tests/simplicialcomplex.h

index 774aeb73095c6abb2738d49d9f6d8ad63f88ddbc..1fb4dd28f6d98e02d70cabb6372e62ddf6d9180a 100644 (file)
@@ -25,11 +25,13 @@ class boolean_colmatrix_base {
         typedef std::vector<index_type> column_type;
         typedef D derived;
 
+    protected:
         /** Create a matrix with 'width' columns, initalized with zero entries. */
         boolean_colmatrix_base(size_t width) :
             cols(width) {
         }
 
+    public:
         /** Get height resp. width of the matrix. */
         size_t width() const {
             return cols.size();
@@ -47,6 +49,12 @@ class boolean_colmatrix_base {
             get_derived()->_set(r, c, value);
         }
 
+        /** For each of the 'count'-many (row-index, column-pair) pair in 'indices', set the specific value. */
+        void set_all(index_type indices[][2], size_t count, bool value) {
+            for (unsigned i=0; i < count; ++i)
+                set(indices[i][0], indices[i][1], value);
+        }
+
         /** Get the c-th column. */
         const column_type& get_column(index_type c) const {
             assert(c < width());
@@ -73,6 +81,24 @@ class boolean_colmatrix_base {
             return !(*this == m);
         }
 
+        /** Print index pairs of the 1s as { {r, c}, {r, c}, {r, c} } */
+        void print_indexpairs(std::ostream &os) const {
+            bool first=true;
+
+            os << "{";
+            for (unsigned c=0; c < width(); ++c) {
+                const column_type &col = get_column(c);
+                for (typename column_type::const_iterator it = col.begin(); it != col.end(); ++it) {
+                    if (first)
+                        first = false;
+                    else
+                        os << ",";
+                    os << " {" << *it << ", " << c << "}";
+                }
+            }
+            os << " }";
+        }
+
     protected:
         /** Set the matrix entry at row 'r' and column 'c'. */
         void _set(index_type r, index_type c, bool value) {
@@ -148,12 +174,14 @@ class boolean_rowmatrix_base {
         typedef std::vector<index_type> row_type;
         typedef D derived;
 
+    protected:
         /** Create a matrix with 'height' rows, initalized with zero entries.
          * */
         boolean_rowmatrix_base(size_t height) :
             rows(height) {
         }
 
+    public:
         /** Get height resp. width of the matrix. */
         size_t height() const {
             return rows.size();
@@ -171,6 +199,12 @@ class boolean_rowmatrix_base {
             get_derived()->_set(r, c, value);
         }
 
+        /** For each of the 'count'-many (row-index, column-pair) pair in 'indices', set the specific value. */
+        void set_all(index_type indices[][2], size_t count, bool value) {
+            for (unsigned i=0; i < count; ++i)
+                set(indices[i][0], indices[i][1], value);
+        }
+
         /** Get the r-th row. */
         const row_type& get_row(index_type r) const {
             assert(r < height());
@@ -301,6 +335,11 @@ class boolean_colrowmatrix : public boolean_colmatrix_base<IT, boolean_colrowmat
             colbase::set(r, c, value);
         }
 
+        /** For each of the 'count'-many (row-index, column-pair) pair in 'indices', set the specific value. */
+        void set_all(index_type indices[][2], size_t count, bool value) {
+            colbase::set_all(indices, count, value);
+        }
+
         /** Get the matrix entry at row 'r' and column 'c'. */
         bool get(index_type r, index_type c) const {
             assert(colbase::get(r, c) == rowbase::get(r, c));
@@ -320,7 +359,7 @@ class boolean_colrowmatrix : public boolean_colmatrix_base<IT, boolean_colrowmat
 
         /** Multiply with matrix b from the right */
         template<class D>
-        boolean_colrowmatrix<IT> operator*(const boolean_colmatrix_base<IT, D> &b) {
+        boolean_colrowmatrix<IT> operator*(const boolean_colmatrix_base<IT, D> &b) const {
             boolean_colrowmatrix<IT> c(size());
             multiply_matrix(c, *this, b);
             return c;
@@ -353,14 +392,14 @@ size_t count_set_intersection (InputIterator1 first1, InputIterator1 last1, Inpu
 }
 
 /** Multiply a*b and save the product in 'result'. It is assumed that 'result' is intially empty and has appropriate size. */
-template<class IT, class D, class RT>
-void multiply_matrix(RT &result, const boolean_rowmatrix_base<IT, D> &a, const boolean_colmatrix_base<IT, D> &b) {
+template<class IT, class D1, class D2, class RT>
+void multiply_matrix(RT &result, const boolean_rowmatrix_base<IT, D1> &a, const boolean_colmatrix_base<IT, D2> &b) {
     assert(a.height() == b.width());
 
     for (unsigned r=0; r < a.height(); ++r) {
-        const typename boolean_rowmatrix_base<IT, D>::row_type &row = a.get_row(r);
+        const typename boolean_rowmatrix_base<IT, D1>::row_type &row = a.get_row(r);
         for (unsigned c=0; c < b.width(); ++c) {
-            const typename boolean_colmatrix_base<IT, D>::column_type &col = b.get_column(c);
+            const typename boolean_colmatrix_base<IT, D2>::column_type &col = b.get_column(c);
             if (count_set_intersection(row.begin(), row.end(), col.begin(), col.end()) % 2 == 1)
                 result.set(r, c, true);
         }
@@ -377,7 +416,24 @@ MT create_unit_matrix(size_t size) {
 
 template<class IT>
 std::ostream& operator<<(std::ostream &os, const boolean_colrowmatrix<IT> &mat) {
+
+    os << " ";
+    for (unsigned c=0; c < mat.size(); ++c) {
+        const unsigned d = (c % 10);
+        if (d > 0)
+            os << d;
+        else
+            os << " ";
+    }
+    os << std::endl;
+
     for (unsigned r=0; r < mat.size(); ++r) {
+        const unsigned d = (r % 10);
+        if (d > 0)
+            os << d;
+        else
+            os << " ";
+
         for (unsigned c=0; c < mat.size(); ++c)
             os << (mat.get(r,c) ? "X" : ".");
 
diff --git a/include/libstick-0.1/matrixreduction.h b/include/libstick-0.1/matrixreduction.h
deleted file mode 100644 (file)
index d9624cc..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef matrixreduction_h_aPeinoXeiFeethuz
-#define matrixreduction_h_aPeinoXeiFeethuz
-
-#include <iostream>
-
-#include "booleanmatrix.h"
-
-
-namespace libstick {
-
-/** Takes the boundary matrix b and transforms it inplace into a reduced matrix
- * b. The matrix v is required to be a unit matrix having the same dimensions
- * as b. It is maintained in order to leave the product b*inverse(v) as an
- * invariant.  Hence, the resulting b is equal to the product of the boundary
- * matrix times v. */
-template<class IT, class D>
-void reduce_boundary_matrix(boolean_colrowmatrix<IT> &b, boolean_colmatrix_base<IT, D> &v) {
-    assert(b.size() == v.width());
-
-    // Make every column reduced, i.e., it is a zero-column or contains only one 1.
-    for (unsigned c=0; c < b.size(); ++c) {
-        const typename boolean_colrowmatrix<IT>::colbase::column_type &col = b.get_column(c);
-        if (col.size() == 0)
-            continue;
-
-        // The column is not a zero-column, take the lowest 1, and reduce the other columns at the row
-        IT r = col.back();
-        assert(b.get(r, c));
-
-        // Get a copy of the r-th row
-        typename boolean_colrowmatrix<IT>::rowbase::row_type row(b.get_row(r).size());
-        copy(b.get_row(r).begin(), b.get_row(r).end(), row.begin());
-        assert(row.size() >= 1);
-
-        // Get rid of 1s at that row right of column c.
-        typename boolean_colrowmatrix<IT>::row_type::const_iterator it = lower_bound(row.begin(), row.end(), c);
-        for(; it != row.end(); ++it) {
-            if (*it <= c)
-                continue;
-
-            assert(b.get(r, *it));
-            b.add_column(*it, col);
-            v.add_column(*it, v.get_column(c));
-            assert(!b.get(r, *it));
-        }
-    }
-}
-
-}
-
-#endif
diff --git a/include/libstick-0.1/persistence.h b/include/libstick-0.1/persistence.h
new file mode 100644 (file)
index 0000000..937a4cc
--- /dev/null
@@ -0,0 +1,201 @@
+#ifndef persistence_h_aPeinoXeiFeethuz
+#define persistence_h_aPeinoXeiFeethuz
+
+#include <iostream>
+#include <ostream>
+#include <vector>
+
+#include "simplicialcomplex.h"
+#include "booleanmatrix.h"
+
+
+namespace libstick {
+
+
+template<class T>
+std::ostream& operator<<(std::ostream &, const std::vector<T> &);
+
+
+/** Persistence computers various persistent homology information on a
+ * simplex_order of a simplicial_complex. */
+template<int MAXDIM, class IT, class VT>
+class persistence {
+
+    public:
+        typedef typename simplicial_complex<MAXDIM, IT, VT>::simplex_order simplex_order;
+        typedef typename simplex_order::boundary_matrix boundary_matrix;
+        typedef boolean_colmatrix<IT> transformation_matrix;
+
+        /** A point in a diagram comprises birth- and death-index. These are the
+         * indices of the simplices of 'order' that give birth and death to the
+         * class. */
+        struct diagram_point {
+            IT birth;
+            IT death;
+        };
+
+
+    public:
+        /** Create a new peristence object on the given simplex_order */
+        persistence(const simplex_order &order) :
+            order(order),
+            bm(0),
+            rbm(0),
+            tm(0)
+        {
+            reset();
+        }
+
+        /** Reset all results gained from 'order'. */
+        void reset() {
+            done_matrices = false;
+        }
+
+        /** Get boundary matrix 'bm' of 'order', compute reduces boundary
+         * matrix 'rbm', and the transformation matrix 'tm' such that rbm = bm *
+         * tm. */
+        void compute_matrices() {
+            if (done_matrices)
+                return;
+            done_matrices = true;
+
+            bm = order.get_boundary_matrix();
+            rbm = bm;
+            tm = create_unit_matrix<transformation_matrix>(bm.size());
+            reduce_boundary_matrix(rbm, tm);
+
+            assert(rbm == bm * tm);
+        }
+
+        /** Get the boundary matrix of 'order'. */
+        const boundary_matrix& get_boundary_matrix() {
+            compute_matrices();
+            return bm;
+        }
+
+        /** Get the reduced boundary matrix of 'order'. */
+        const boundary_matrix& get_reduced_boundary_matrix() {
+            compute_matrices();
+            return rbm;
+        }
+
+        /** Get the transformation matrix of 'order', which transforms the
+         * boundary matrix to the reduced boundary matrix, when multiplied from
+         * the right. */
+        const transformation_matrix& get_transformation_matrix() {
+            compute_matrices();
+            return tm;
+        }
+
+
+        /** Print the sequence of births and deaths of cycles (homology classes). */
+        void interpret_reduction(std::ostream &os) {
+            compute_matrices();
+            for (unsigned c=0; c < bm.size(); ++c) {
+                os << c << ". inserting ";
+
+                switch (bm.get_column(c).size()) {
+                    case 0:
+                        os << "dummy vertex of dim -1";
+                        break;
+                    case 1:
+                        os << "vertex";
+                        break;
+                    case 2:
+                        os << "edge";
+                        break;
+                    case 3:
+                        os << "triangle";
+                        break;
+                    case 4:
+                        os << "tetrahedron";
+                        break;
+                    default:
+                        os << "simplex";
+                        break;
+                }
+
+                os << std::endl;
+                os << "  boundary: " << bm.get_column(c) << std::endl;
+
+                typename boolean_colrowmatrix<IT>::colbase::column_type col = rbm.get_column(c);
+                if (col.size() == 0) {
+                    os << "  \033[1;32mbirth\033[0;m of a cycle: " << tm.get_column(c) << std::endl;
+                } else {
+                    os << "  \033[1;31mdeath\033[0;m of a cycle: " << rbm.get_column(c) << std::endl;
+                    os << "  boundary of: " << tm.get_column(c) << std::endl;
+                }
+                os << std::endl;
+            }
+        }
+
+    private:
+
+        /** The underlying simplex order of this diagram. */
+        const simplex_order &order;
+
+        bool done_matrices;
+
+        boundary_matrix bm;
+        boundary_matrix rbm;
+        transformation_matrix tm;
+};
+
+
+/** Takes the boundary matrix b and transforms it inplace into a reduced matrix
+ * b. The matrix v is required to be a unit matrix having the same dimensions
+ * as b. It is maintained in order to leave the product b*inverse(v) as an
+ * invariant.  Hence, the resulting b is equal to the product of the boundary
+ * matrix times v. */
+template<class IT, class D>
+void reduce_boundary_matrix(boolean_colrowmatrix<IT> &b, boolean_colmatrix_base<IT, D> &v) {
+    assert(b.size() == v.width());
+
+    // Make every column reduced, i.e., it is a zero-column or contains only one 1.
+    for (unsigned c=0; c < b.size(); ++c) {
+        const typename boolean_colrowmatrix<IT>::colbase::column_type &col = b.get_column(c);
+        if (col.size() == 0)
+            continue;
+
+        // The column is not a zero-column, take the lowest 1, and reduce the other columns at the row
+        IT r = col.back();
+        assert(b.get(r, c));
+
+        // Get a copy of the r-th row
+        typename boolean_colrowmatrix<IT>::rowbase::row_type row(b.get_row(r).size());
+        copy(b.get_row(r).begin(), b.get_row(r).end(), row.begin());
+        assert(row.size() >= 1);
+
+        // Get rid of 1s at that row right of column c.
+        typename boolean_colrowmatrix<IT>::row_type::const_iterator it = lower_bound(row.begin(), row.end(), c);
+        for(; it != row.end(); ++it) {
+            if (*it <= c)
+                continue;
+
+            assert(b.get(r, *it));
+            b.add_column(*it, col);
+            v.add_column(*it, v.get_column(c));
+            assert(!b.get(r, *it));
+        }
+    }
+}
+
+template<class T>
+std::ostream& operator<<(std::ostream& os, const std::vector<T> &vec) {
+    os << "[";
+
+    typename std::vector<T>::const_iterator it = vec.begin();
+    while ( it != vec.end()) {
+        os << *it;
+        if (++it != vec.end())
+            os << " ";
+    }
+
+    os << "]";
+    return os;
+}
+
+
+} // namespace libstick
+
+#endif
index 47a88c64907cb29054cb6d22d78c49df9e0bb08b..707fd4f3240ae7fe71c4c90e7a4d1ab25926689e 100644 (file)
@@ -223,6 +223,12 @@ class simplicial_complex {
             simplices.push_back(s);
         }
 
+        /** Add an array of simplices */
+        void add_simplices(Simplex* sarray, size_t count) {
+            for (unsigned i=0; i < count; ++i)
+                add_simplex(sarray[i]);
+        }
+
         /** Return true iff for each simplex i with dimension dim it holds that
          * the faces of i are contained in the complex and have dimension dim-1. */
         bool is_complex() const {
index ef4977e8eb9110a80f69939a54516188eef54078..0b3dd996f1af959242a3b2efa6374e821c79b339 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "booleanmatrix.h"
 #include "simplicialcomplex.h"
+#include "persistence.h"
 
 using namespace std;
 
@@ -15,6 +16,7 @@ int main(int argc, char* argv[]) {
 
     ts.add(auto_ptr<Test::Suite>(new boolean_matrix_TestSuite));
     ts.add(auto_ptr<Test::Suite>(new simplicial_complex_TestSuite));
+    ts.add(auto_ptr<Test::Suite>(new persistence_TestSuite));
 
     Test::TextOutput output(Test::TextOutput::Verbose);
     return ts.run(output);
diff --git a/tests/persistence.h b/tests/persistence.h
new file mode 100644 (file)
index 0000000..55774dd
--- /dev/null
@@ -0,0 +1,217 @@
+#ifndef persistence_h_Fahlaewahgaebaqu
+#define persistence_h_Fahlaewahgaebaqu
+
+#include <cpptest.h>
+#include <cpptest-suite.h>
+
+#include <libstick-0.1/persistence.h>
+
+using namespace libstick;
+
+
+class persistence_TestSuite: public Test::Suite {
+
+    private:
+        typedef simplicial_complex<3, uint32_t, double> scomplex;
+        typedef persistence<3, uint32_t, double> pers;
+        typedef pers::boundary_matrix bm;
+        typedef pers::transformation_matrix tm;
+
+        bool setupcalled;
+        scomplex ball, ring, torus;
+        scomplex::simplex_order oball, oring, otorus;
+
+    public:
+        persistence_TestSuite() :
+            setupcalled(false),
+            oball(ball),
+            oring(ring),
+            otorus(torus)
+            {
+            TEST_ADD(persistence_TestSuite::test_matrix_reduction);
+        }
+
+    protected:
+        virtual void setup() {
+            if (setupcalled)
+                return;
+            setupcalled = true;
+
+            //   7 ------------------------------------- 8
+            //    \                                     /
+            //     \    4 ------------------------- 5  /
+            //      \    \                         /  /
+            //       \    \      1 ------- 2      /  /
+            //        \    \      \       /      /  /
+            //         \    \      \     /      /  /
+            //          \    \      \   /      /  /
+            //           \    \      \ /      /  /
+            //            \    \      3      /  /
+            //             \    \           /  /
+            //              \    \         /  /
+            //               \    \       /  /
+            //                \    \     /  /
+            //                 \    \   /  /
+            //                  \    \ /  /
+            //                   \    6  /
+            //                    \     /
+            //                     \   /
+            //                      \ /
+            //                       9
+
+            scomplex::Simplex ssring[] = {
+                // dimension, faces, value...
+                /*  1 */ {0, {},           1},
+                /*  2 */ {0, {},           2},
+                /*  3 */ {0, {},           3},
+                /*  4 */ {0, {},           4},
+                /*  5 */ {0, {},           5},
+                /*  6 */ {0, {},           6},
+                /*  7 */ {1, {2, 3},       6.01},
+                /*  8 */ {1, {3, 1},       6.02},
+                /*  9 */ {1, {1, 2},       6.03},
+                /* 10 */ {1, {4, 5},       6.04},
+                /* 11 */ {1, {5, 6},       6.05},
+                /* 12 */ {1, {6, 4},       6.06},
+                /* 13 */ {1, {1, 4},       6.07},
+                /* 14 */ {1, {1, 5},       6.08},
+                /* 15 */ {2, {13, 14, 10}, 6.0801},
+                /* 16 */ {1, {3, 6},       6.09},
+                /* 17 */ {1, {2, 5},       6.10},
+                /* 18 */ {1, {2, 6},       6.11},
+                /* 19 */ {2, {9, 14, 17},  6.1101},
+                /* 20 */ {2, {7, 16, 18},  6.1102},
+                /* 21 */ {2, {11, 17, 18}, 6.1103},
+                /* 22 */ {1, {1, 6},       6.12},
+                /* 23 */ {2, {12, 13, 22}, 6.1201},
+                /* 24 */ {2, {8, 16, 22},  6.1202}
+            };
+            const size_t cntssring = sizeof(ssring)/sizeof(scomplex::Simplex);
+            ring.add_simplices(ssring, cntssring);
+            oring.reset();
+
+            scomplex::Simplex sstorus[] = {
+                // dimension, faces, value...
+                /* 25 */ {0, {},           7},
+                /* 26 */ {0, {},           8},
+                /* 27 */ {0, {},           9},
+                /* 28 */ {1, {25, 26},     9.01},
+                /* 29 */ {1, {26, 27},     9.02},
+                /* 30 */ {1, {25, 27},     9.03},
+                /* 31 */ {1, {25, 1},      9.04},
+                /* 32 */ {1, {26, 1},      9.05},
+                /* 33 */ {2, {28, 31, 32}, 9.0501},
+                /* 34 */ {1, {27, 1},      9.06},
+                /* 35 */ {2, {30, 31, 34}, 9.0601},
+                /* 36 */ {1, {27, 3},      9.07},
+                /* 37 */ {2, {36, 34, 8},  9.0701},
+                /* 38 */ {1, {27, 2},      9.08},
+                /* 39 */ {1, {26, 2},      9.09},
+                /* 40 */ {2, {9, 32, 39},  9.0901},
+                /* 41 */ {2, {29, 38, 39}, 9.0902},
+                /* 42 */ {2, {7, 38, 36},  9.0903},
+                /* 43 */ {1, {4, 25},      9.10},
+                /* 44 */ {1, {5, 26},      9.11},
+                /* 45 */ {1, {6, 27},      9.12},
+                /* 46 */ {1, {4, 26},      9.13},
+                /* 47 */ {1, {4, 27},      9.14},
+                /* 48 */ {1, {5, 27},      9.15},
+                /* 49 */ {2, {43, 47, 30}, 9.1501},
+                /* 50 */ {2, {12, 45, 47}, 9.1502},
+                /* 51 */ {2, {29, 44, 48}, 9.1503},
+                /* 52 */ {2, {48, 11, 45}, 9.1504},
+                /* 53 */ {2, {10, 46, 44}, 9.1505},
+                /* 54 */ {2, {43, 46, 28}, 9.1506},
+            };
+            const size_t cntsstorus = sizeof(sstorus)/sizeof(scomplex::Simplex);
+            torus = ring;
+            torus.add_simplices(sstorus, cntsstorus);
+            otorus.reset();
+
+            scomplex::Simplex ssball[] = {
+                // dimension, faces, value...
+                {0, {},                1},
+                {0, {},                2},
+                {0, {},                3},
+                {0, {},                4},
+                {0, {},                5},
+                {1, {1, 2},            6},
+                {1, {2, 3},            7},
+                {1, {3, 4},            8},
+                {1, {4, 1},            9},
+                {1, {1, 5},           10},
+                {1, {2, 5},           11},
+                {1, {3, 5},           12},
+                {1, {4, 5},           13},
+                {2, {6, 10, 11},      14},
+                {2, {7, 11, 12},      15},
+                {2, {8, 12, 13},      16},
+                {2, {9, 13, 10},      17},
+                {1, {1, 3},           18},
+                {2, {18, 6, 7},       19},
+                {2, {18, 8, 9},       20},
+                {2, {18, 10, 12},     21},
+                {3, {21, 14, 15, 19}, 22},
+                {3, {21, 16, 17, 20}, 23},
+            };
+            const size_t cntssball = sizeof(ssball)/sizeof(scomplex::Simplex);
+            ball.add_simplices(ssball, cntssball);
+            oball.reset();
+        }
+
+        virtual void tear_down() {
+        }
+
+        void test_matrix_reduction() {
+            pers ringp(oring);
+            const bm &ringbm = ringp.get_boundary_matrix();
+            const bm &ringrbm = ringp.get_reduced_boundary_matrix();
+            const tm &ringtm = ringp.get_transformation_matrix();
+            TEST_ASSERT(ringrbm == ringbm * ringtm);
+
+            pers torusp(otorus);
+            const bm &torusbm = torusp.get_boundary_matrix();
+            const bm &torusrbm = torusp.get_reduced_boundary_matrix();
+            const tm &torustm = torusp.get_transformation_matrix();
+            TEST_ASSERT(torusrbm == torusbm * torustm);
+
+            uint32_t torusrbme_coords[][2] = {
+                    {0, 1}, {2, 7}, {3, 7}, {1, 8}, {2, 8}, {4, 10}, {5, 10}, {4, 11}, {6, 11}, {1, 13},
+                    {4, 13}, {10, 15}, {13, 15}, {14, 15}, {9, 19}, {10, 19}, {13, 19}, {17, 19}, {7, 20},
+                    {16, 20}, {18, 20}, {7, 21}, {9, 21}, {10, 21}, {11, 21}, {13, 21}, {16, 21}, {12, 23},
+                    {13, 23}, {22, 23}, {7, 24}, {8, 24}, {9, 24}, {10, 24}, {11, 24}, {12, 24}, {25, 28},
+                    {26, 28}, {25, 29}, {27, 29}, {1, 31}, {25, 31}, {28, 33}, {31, 33}, {32, 33}, {30, 35},
+                    {31, 35}, {34, 35}, {8, 37}, {30, 37}, {31, 37}, {36, 37}, {9, 40}, {28, 40}, {31, 40},
+                    {39, 40}, {9, 41}, {28, 41}, {29, 41}, {31, 41}, {38, 41}, {7, 42}, {8, 42}, {9, 42},
+                    {28, 42}, {29, 42}, {30, 42}, {7, 49}, {8, 49}, {9, 49}, {28, 49}, {29, 49}, {43, 49},
+                    {47, 49}, {10, 50}, {11, 50}, {28, 50}, {29, 50}, {43, 50}, {45, 50}, {29, 51}, {44, 51},
+                    {48, 51}, {10, 52}, {28, 52}, {43, 52}, {44, 52}, {28, 53}, {43, 53}, {46, 53 }
+            };
+            bm torusrbme(torusbm.size());
+            torusrbme.set_all(torusrbme_coords, sizeof(torusrbme_coords)/(2*sizeof(uint32_t)), true);
+            TEST_ASSERT(torusrbme == torusrbm);
+
+
+            pers ballp(oball);
+            const bm &ballbm = ballp.get_boundary_matrix();
+            const bm &ballrbm = ballp.get_reduced_boundary_matrix();
+            const tm &balltm = ballp.get_transformation_matrix();
+            TEST_ASSERT(ballrbm == ballbm * balltm);
+
+            uint32_t ballrbme_coords[][2] = {
+                    {0, 1}, {1, 6}, {2, 6}, {1, 7}, {3, 7}, {1, 8}, {4, 8}, {1, 10}, {5, 10}, {6, 14},
+                    {10, 14}, {11, 14}, {6, 15}, {7, 15}, {10, 15}, {12, 15}, {6, 16}, {7, 16}, {8, 16},
+                    {10, 16}, {13, 16}, {6, 17}, {7, 17}, {8, 17}, {9, 17}, {6, 19}, {7, 19}, {18, 19},
+                    {14, 22}, {15, 22}, {19, 22}, {21, 22}, {14, 23}, {15, 23}, {16, 23}, {17, 23}, {19, 23},
+                    {20, 23 }
+            };
+            bm ballrbme(ballrbm.size());
+            ballrbme.set_all(ballrbme_coords, sizeof(ballrbme_coords)/(2*sizeof(uint32_t)), true);
+            TEST_ASSERT(ballrbme == ballrbm);
+
+            //std::cout << std::endl;
+            //ballp.interpret_reduction(std::cout);
+        }
+};
+
+#endif
index 373688351dea1f172c49a93c600d4e4388c63c28..6e63f54f9baaf2c0827f0eb136fd82026d5b9662 100644 (file)
@@ -5,7 +5,6 @@
 #include <cpptest-suite.h>
 
 #include <libstick-0.1/simplicialcomplex.h>
-#include <libstick-0.1/matrixreduction.h>
 
 using namespace libstick;
 
@@ -13,7 +12,7 @@ using namespace libstick;
 class simplicial_complex_TestSuite: public Test::Suite {
 
     private:
-        typedef simplicial_complex<2, uint32_t, double> scomplex;
+        typedef simplicial_complex<3, uint32_t, double> scomplex;
         typedef scomplex::simplex_order::boundary_matrix bm;
 
         bool setupcalled;
@@ -33,7 +32,6 @@ class simplicial_complex_TestSuite: public Test::Suite {
             TEST_ADD(simplicial_complex_TestSuite::test_is_order_filtration);
             TEST_ADD(simplicial_complex_TestSuite::test_is_order_monotone);
             TEST_ADD(simplicial_complex_TestSuite::test_boundary_matrix);
-            TEST_ADD(simplicial_complex_TestSuite::test_matrix_reduction);
         }
 
     protected:
@@ -42,8 +40,7 @@ class simplicial_complex_TestSuite: public Test::Suite {
                 return;
             setupcalled = true;
 
-            const unsigned num = 11;
-            scomplex::Simplex ss[num] = {
+            scomplex::Simplex ss[] = {
                 // dimension, faces, value...
                 {0, {}, 1},
                 {0, {}, 2},
@@ -57,6 +54,8 @@ class simplicial_complex_TestSuite: public Test::Suite {
                 {2, {7, 8, 9}, 10},
                 {2, {5, 6, 9}, 11}
             };
+            const size_t cntss = sizeof(ss)/sizeof(scomplex::Simplex);
+            c1.add_simplices(ss, cntss);
 
             //  This is o1        This is o2         This is o3(b)
             //  (value = index)   (values)           (values)
@@ -73,10 +72,6 @@ class simplicial_complex_TestSuite: public Test::Suite {
             //  |          \|    |          \|     |          \|
             //  4 ----7---- 3    4 ----7---- 3     4 ----7---- 3
 
-            // Build the complex
-            for (unsigned i=0; i<num; ++i)
-                c1.add_simplex(ss[i]);
-
             c2 = c1;
             c2.simplices[6].value = 12;
 
@@ -122,50 +117,21 @@ class simplicial_complex_TestSuite: public Test::Suite {
         void test_boundary_matrix() {
             bm mat1 = o1.get_boundary_matrix();
             bm mat1e(c1.size());
-            mat1e.set(0, 1, true);
-            mat1e.set(0, 2, true);
-            mat1e.set(0, 3, true);
-            mat1e.set(0, 4, true);
-            mat1e.set(1, 5, true);
-            mat1e.set(2, 5, true);
-            mat1e.set(2, 6, true);
-            mat1e.set(3, 6, true);
-            mat1e.set(3, 7, true);
-            mat1e.set(4, 7, true);
-            mat1e.set(4, 8, true);
-            mat1e.set(1, 8, true);
-            mat1e.set(1, 9, true);
-            mat1e.set(3, 9, true);
-            mat1e.set(7, 10, true);
-            mat1e.set(8, 10, true);
-            mat1e.set(9, 10, true);
-            mat1e.set(5, 11, true);
-            mat1e.set(6, 11, true);
-            mat1e.set(9, 11, true);
+            uint32_t mat1e_coords[][2] = {
+                    {0, 1}, {0, 2}, {0, 3}, {0, 4}, {1, 5}, {2, 5}, {2, 6}, {3, 6}, {3, 7}, {4, 7}, {1, 8}, {4, 8},
+                    {1, 9}, {3, 9}, {7, 10}, {8, 10}, {9, 10}, {5, 11}, {6, 11}, {9, 11}
+            };
+            mat1e.set_all(mat1e_coords, sizeof(mat1e_coords)/(2*sizeof(uint32_t)), true);
             TEST_ASSERT(mat1 == mat1e);
 
+
             bm mat3b = o3b.get_boundary_matrix();
             bm mat3be(c1.size());
-            mat3be.set(0, 1, true);
-            mat3be.set(0, 2, true);
-            mat3be.set(0, 3, true);
-            mat3be.set(0, 4, true);
-            mat3be.set(1, 5, true);
-            mat3be.set(2, 5, true);
-            mat3be.set(3, 6, true);
-            mat3be.set(4, 6, true);
-            mat3be.set(4, 7, true);
-            mat3be.set(1, 7, true);
-            mat3be.set(1, 8, true);
-            mat3be.set(3, 8, true);
-            mat3be.set(6, 9, true);
-            mat3be.set(7, 9, true);
-            mat3be.set(8, 9, true);
-            mat3be.set(2, 10, true);
-            mat3be.set(3, 10, true);
-            mat3be.set(5, 11, true);
-            mat3be.set(8, 11, true);
-            mat3be.set(10, 11, true);
+            uint32_t mat3be_coords[][2] = {
+                    {0, 1}, {0, 2}, {0, 3}, {0, 4}, {1, 5}, {2, 5}, {3, 6}, {4, 6}, {1, 7}, {4, 7}, {1, 8}, {3, 8},
+                    {6, 9}, {7, 9}, {8, 9}, {2, 10}, {3, 10}, {5, 11}, {8, 11}, {10, 11}
+            };
+            mat3be.set_all(mat3be_coords, sizeof(mat3be_coords)/(2*sizeof(uint32_t)), true);
             TEST_ASSERT(mat3b == mat3be);
 
             //std::cout << mat3b << std::endl << std::endl;
@@ -173,20 +139,6 @@ class simplicial_complex_TestSuite: public Test::Suite {
             //std::cout << ((bm::colbase) mat3b) << std::endl << std::endl;
             //std::cout << ((bm::rowbase) mat3b) << std::endl << std::endl;
         }
-
-        void test_matrix_reduction() {
-            bm b = o3b.get_boundary_matrix();
-            bm v = create_unit_matrix<bm>(b.size());
-
-            bm b_orig = b;
-            reduce_boundary_matrix(b, v);
-            TEST_ASSERT(b == b_orig*v);
-
-            //std::cout << std::endl << "after reduce: " << std::endl;
-            //std::cout << std::endl << b << std::endl;
-            //std::cout << std::endl << v << std::endl;
-            //std::cout << std::endl << (b_orig*v) << std::endl;
-        }
 };
 
 #endif