+ //torusp.compute_diagrams();
+ //torusp.interpret_reduction(std::cout);
+ //torusp.interpret_persistence(std::cout);
+ //std::cout << std::endl;
+ //std::cout << std::endl;
+ }
+
+ void test_betti_numbers() {
+ pers ringp(oring);
+ ringp.compute_diagrams();
+
+ TEST_ASSERT(ringp.get_persistence_diagram(-1).betti() == 0);
+ TEST_ASSERT(ringp.get_persistence_diagram(0).betti() == 0);
+ TEST_ASSERT(ringp.get_persistence_diagram(1).betti() == 1);
+ TEST_ASSERT(ringp.get_persistence_diagram(2).betti() == 0);
+ TEST_ASSERT(ringp.get_persistence_diagram(3).betti() == 0);
+ for (unsigned d=0; d < 3; ++d)
+ TEST_ASSERT(ringp.get_persistence_diagram(d).persistent_betti(oring.size()-1, oring.size()-1) ==
+ ringp.get_persistence_diagram(d).betti());
+
+
+ pers torusp(otorus);
+ torusp.compute_diagrams();
+
+ TEST_ASSERT(torusp.get_persistence_diagram(-1).betti() == 0);
+ TEST_ASSERT(torusp.get_persistence_diagram(0).betti() == 0);
+ TEST_ASSERT(torusp.get_persistence_diagram(1).betti() == 2);
+ TEST_ASSERT(torusp.get_persistence_diagram(2).betti() == 1);
+ TEST_ASSERT(torusp.get_persistence_diagram(3).betti() == 0);
+ for (unsigned d=0; d < 3; ++d)
+ TEST_ASSERT(torusp.get_persistence_diagram(d).persistent_betti(otorus.size()-1, otorus.size()-1) ==
+ torusp.get_persistence_diagram(d).betti());
+
+ // Torus was made from ring. Hence, persistent betti numbers must correspond to betti numbers of ring.
+ for (unsigned d=0; d < 3; ++d)
+ TEST_ASSERT(torusp.get_persistence_diagram(d).persistent_betti(oring.size()-1, oring.size()-1) ==
+ ringp.get_persistence_diagram(d).betti());
+
+
+ pers ballp(oball);
+ ballp.compute_diagrams();
+
+ //std::cout << std::endl;
+ //ballp.interpret_reduction(std::cout);
+ //std::cout << std::endl;
+
+ TEST_ASSERT(ballp.get_persistence_diagram(-1).betti() == 0);
+ TEST_ASSERT(ballp.get_persistence_diagram(0).betti() == 0);
+ TEST_ASSERT(ballp.get_persistence_diagram(1).betti() == 0);
+ TEST_ASSERT(ballp.get_persistence_diagram(2).betti() == 0);
+ TEST_ASSERT(ballp.get_persistence_diagram(3).betti() == 0);
+ for (unsigned d=0; d < 3; ++d)
+ TEST_ASSERT(ballp.get_persistence_diagram(d).persistent_betti(oball.size()-1, oball.size()-1) ==
+ ballp.get_persistence_diagram(d).betti());
+
+ // Before we inserted the two tetrahedra and the interior triangle, we had a sphere.
+ TEST_ASSERT(ballp.get_persistence_diagram(-1).persistent_betti(oball.size()-4, oball.size()-4) == 0);
+ TEST_ASSERT(ballp.get_persistence_diagram(0).persistent_betti(oball.size()-4, oball.size()-4) == 0);
+ TEST_ASSERT(ballp.get_persistence_diagram(1).persistent_betti(oball.size()-4, oball.size()-4) == 0);
+ TEST_ASSERT(ballp.get_persistence_diagram(2).persistent_betti(oball.size()-4, oball.size()-4) == 1);
+ TEST_ASSERT(ballp.get_persistence_diagram(3).persistent_betti(oball.size()-4, oball.size()-4) == 0);
+
+ // Before we inserted the two tetrahedra, we had a double-sphere.
+ TEST_ASSERT(ballp.get_persistence_diagram(-1).persistent_betti(oball.size()-3, oball.size()-3) == 0);
+ TEST_ASSERT(ballp.get_persistence_diagram(0).persistent_betti(oball.size()-3, oball.size()-3) == 0);
+ TEST_ASSERT(ballp.get_persistence_diagram(1).persistent_betti(oball.size()-3, oball.size()-3) == 0);
+ TEST_ASSERT(ballp.get_persistence_diagram(2).persistent_betti(oball.size()-3, oball.size()-3) == 2);
+ TEST_ASSERT(ballp.get_persistence_diagram(3).persistent_betti(oball.size()-3, oball.size()-3) == 0);
+ }
+
+ void test_lowestones() {
+ test_lowestones_impl(oring);
+ test_lowestones_impl(otorus);
+ test_lowestones_impl(oball);
+ }
+
+ void test_lowestones_impl(const scomplex::simplex_order& so) {
+ pers p(so);
+ p.compute_matrices();
+ const lom &lowestones = p.get_lowestones_matrix();
+
+ // Check that lowestones contains every column-index only once,
+ // except the zeros.
+ lom cpy = lowestones;
+ sort(cpy.begin(), cpy.end());
+ lom::iterator it = cpy.begin();
+ // Skip the zeros
+ while (it != cpy.end() && *it == 0)
+ ++it;
+ // From now on, no column index appears twice
+ for (; it+1 != cpy.end(); ++it)
+ TEST_ASSERT(*it < *(it+1));
+
+ for (unsigned r=0; r < lowestones.size(); ++r) {
+ // If (r,c) is a one then
+ // (i) a cycle dies with c --> row c is zero
+ // (ii) a cycle is born with r --> column r is zero
+ //Hence
+ // (i) the column r is a zero-column
+ // (i) the row c is a zero-column
+
+ const uint32_t c = lowestones[r];
+ if (c > 0) {
+ TEST_ASSERT(p.get_reduced_boundary_matrix().get(r,c) == true);
+ TEST_ASSERT(p.get_reduced_boundary_matrix().get_column(r).size() == 0);
+ TEST_ASSERT(lowestones[c] == 0);
+ }
+ }
+ }
+
+ void test_diagram() {
+ test_diagram_impl(oring);
+ test_diagram_impl(otorus);
+ test_diagram_impl(oball);
+ }
+
+ void test_diagram_impl(const scomplex::simplex_order& so) {
+ pers p(so);
+ p.compute_diagrams();
+
+ // Even Jesus died after his birth. Homology classes are nothing better.
+ for (int d=-1; d <= 3; ++d) {
+ const pers::diagram &dia = p.get_persistence_diagram(d);
+ for (unsigned i=0; i < dia.births.size(); ++i)
+ if (dia.births[i].death > 0)
+ assert(dia.births[i].birth < dia.births[i].death);
+ }
+