From 257abf0674e7cf81e43c674d7b92a69c67ab7f00 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 15 Sep 2016 16:25:21 +0200 Subject: upgraded XCode project --- ripser.xcodeproj/project.pbxproj | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ripser.xcodeproj/project.pbxproj b/ripser.xcodeproj/project.pbxproj index 04bc3a6..2aa6179 100644 --- a/ripser.xcodeproj/project.pbxproj +++ b/ripser.xcodeproj/project.pbxproj @@ -88,7 +88,7 @@ 551018401BD63CB300990BFF /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0700; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "ulrich-bauer.org"; TargetAttributes = { 551018471BD63CB300990BFF = { @@ -138,8 +138,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; @@ -181,8 +183,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; -- cgit v1.2.3 From 09ad67d33adeb7443685214954c7b447a94ebdc2 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 15 Sep 2016 16:25:39 +0200 Subject: added first version of sparse distance matrix --- ripser.cpp | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/ripser.cpp b/ripser.cpp index 5568f32..b2226fc 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -294,6 +294,27 @@ public: size_t size() const { return rows.size(); } }; +class sparse_distance_matrix { +public: + std::vector> neighbors; + + template + sparse_distance_matrix(const DistanceMatrix& mat, value_t threshold) + : neighbors(mat.size()) + { + + for (index_t i = 1; i < size(); ++i) + for (index_t j = 0; j < size(); ++j) + if (mat(i, j) <= threshold) + neighbors[i].push_back(diameter_index_t(mat(i, j), j)); + } + + value_t operator()(const index_t i, const index_t j) const; + + size_t size() const { return neighbors.size(); } +}; + + template <> void compressed_distance_matrix::init_rows() { value_t* pointer = &distances[0]; for (index_t i = 1; i < size(); ++i) { @@ -468,6 +489,11 @@ void assemble_columns_to_reduce(std::vector& columns_to_reduce index_t n, value_t threshold, const binomial_coeff_table& binomial_coeff) { index_t num_simplices = binomial_coeff(n, dim + 2); + // iterate over all (previous) columns_to_reduce + // find cofaces, additional vertices + // if additional vertex is larger than all current ones: append to columns_to_reduce + + columns_to_reduce.clear(); #ifdef INDICATE_PROGRESS @@ -584,6 +610,9 @@ void compute_pairs(std::vector& columns_to_reduce, hash_map Date: Fri, 16 Sep 2016 14:47:38 +0200 Subject: intermediate commit --- ripser.cpp | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/ripser.cpp b/ripser.cpp index b2226fc..a477ce6 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -315,6 +315,87 @@ public: }; +template +class set_intersection_enumerator { +public: + InputIteratorCollection first, last; + + set_intersection_enumerator (InputIteratorCollection _first, InputIteratorCollection _last) : first(_first), last(_last) {} + +// template +// set_intersection_enumerator (InputCollection _set) : first(_first), last(_last) {} + + bool has_next() { + for (auto &it0 = first[0], end0 = last[0]; it0 != end0; ++it0) { + auto x = *it0; + for (size_t idx = 1; idx < first.size(); ++idx) { + auto &it = first[idx], end = last[idx]; + while (*it < x) if (++it == end) return false; + if (*it > x) goto continue_outer; + } + return true; + continue_outer: ; + } + return false; + } + + // only valid after has_next() has been called + decltype(*first[0]) next() { + return *first[0]++; + } +}; + + +class simplex_coboundary_enumerator_sparse { +private: + index_t idx, modified_idx, v, k; + const binomial_coeff_table& binomial_coeff; + const sparse_distance_matrix& sparse_dist; + std::vector vertices; + + std::vector::const_reverse_iterator> ii, ee; + set_intersection_enumerator v_intersection; + +public: + simplex_coboundary_enumerator_sparse(index_t _idx, index_t _dim, index_t _n, const binomial_coeff_table& _binomial_coeff, sparse_distance_matrix& _sparse_dist) + : idx(_idx), modified_idx(_idx), v(_n - 1), k(_dim + 1), binomial_coeff(_binomial_coeff), sparse_dist(_sparse_dist), v_intersection(ii, ee) + { + get_simplex_vertices(idx, _dim, _n, _binomial_coeff, std::back_inserter(vertices)); + + for (auto v: vertices) { + ii.push_back(sparse_dist.neighbors[v].rbegin()); + ee.push_back(sparse_dist.neighbors[v].rend()); + } + + vertices.push_back(-1); + + } + + bool has_next() { + return v_intersection.has_next(); + } + + std::pair next() { + + auto v = v_intersection.has_next(); + + while (k > 0 && vertices[k - 1] > v) { + vertices[k] = vertices[k - 1]; + --k; + } + + vertices[k] = v; + + //... + auto result = std::make_pair(make_entry(modified_idx + binomial_coeff(v, k + 1), k & 1 ? -1 : 1), v); + + + return result; + } +}; + + + template <> void compressed_distance_matrix::init_rows() { value_t* pointer = &distances[0]; for (index_t i = 1; i < size(); ++i) { -- cgit v1.2.3 From 01f16a612b8d30a1cc7dc000a5e7d79f00238b2d Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Fri, 16 Sep 2016 19:57:59 +0200 Subject: sparse coboundary enumerator (untested) --- ripser.cpp | 72 ++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 28c8b3c..2a62170 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -94,30 +94,36 @@ std::vector multiplicative_inverse_vector(const coefficient_t m) return inverse; } +void get_next_vertex(index_t& v, const index_t idx, const index_t k, const binomial_coeff_table& binomial_coeff) { + + if (binomial_coeff(v, k) > idx) { + index_t count = v; + while (count > 0) { + index_t i = v; + index_t step = count >> 1; + i -= step; + if (binomial_coeff(i, k) > idx) { + v = --i; + count -= step + 1; + } else + count = step; + } + } + assert(binomial_coeff(v, k) <= idx); + assert(binomial_coeff(v + 1, k) > idx); +} + + template -OutputIterator get_simplex_vertices(index_t idx, const index_t dim, index_t n, +OutputIterator get_simplex_vertices(index_t idx, const index_t dim, index_t v, const binomial_coeff_table& binomial_coeff, OutputIterator out) { - --n; + --v; for (index_t k = dim + 1; k > 0; --k) { - if (binomial_coeff(n, k) > idx) { - index_t count = n; - while (count > 0) { - index_t i = n; - index_t step = count >> 1; - i -= step; - if (binomial_coeff(i, k) > idx) { - n = --i; - count -= step + 1; - } else - count = step; - } - } - assert(binomial_coeff(n, k) <= idx); - assert(binomial_coeff(n + 1, k) > idx); + get_next_vertex(v, idx, k, binomial_coeff); - *out++ = n; - idx -= binomial_coeff(n, k); + *out++ = v; + idx -= binomial_coeff(v, k); } return out; @@ -349,7 +355,7 @@ public: class simplex_coboundary_enumerator_sparse { private: - index_t idx, modified_idx, v, k; + index_t idx_below, idx_above, v, k, w; const binomial_coeff_table& binomial_coeff; const sparse_distance_matrix& sparse_dist; std::vector vertices; @@ -359,16 +365,14 @@ private: public: simplex_coboundary_enumerator_sparse(index_t _idx, index_t _dim, index_t _n, const binomial_coeff_table& _binomial_coeff, sparse_distance_matrix& _sparse_dist) - : idx(_idx), modified_idx(_idx), v(_n - 1), k(_dim + 1), binomial_coeff(_binomial_coeff), sparse_dist(_sparse_dist), v_intersection(ii, ee) + : idx_below(_idx), idx_above(0), v(_n - 1), k(_dim + 1), w(_n - 1), binomial_coeff(_binomial_coeff), sparse_dist(_sparse_dist), v_intersection(ii, ee) { - get_simplex_vertices(idx, _dim, _n, _binomial_coeff, std::back_inserter(vertices)); + get_simplex_vertices(idx_below, _dim, _n, _binomial_coeff, std::back_inserter(vertices)); for (auto v: vertices) { ii.push_back(sparse_dist.neighbors[v].rbegin()); ee.push_back(sparse_dist.neighbors[v].rend()); } - - vertices.push_back(-1); } @@ -378,17 +382,19 @@ public: std::pair next() { - auto v = v_intersection.has_next(); - - while (k > 0 && vertices[k - 1] > v) { - vertices[k] = vertices[k - 1]; - --k; - } + index_t v = get_index(v_intersection.next()); + + while (w > v && idx_below > 0) { + get_next_vertex(w, idx_below, k, binomial_coeff); - vertices[k] = v; + idx_below -= binomial_coeff(w, k); + idx_above += binomial_coeff(w, k + 1); - //... - auto result = std::make_pair(make_entry(modified_idx + binomial_coeff(v, k + 1), k & 1 ? -1 : 1), v); + --k; + assert(k != -1); + } + + auto result = std::make_pair(make_entry(idx_above + binomial_coeff(v, k + 1) + idx_below, k & 1 ? -1 : 1), v); return result; -- cgit v1.2.3 From 5d356d18ab38d85c255927419a45ff6736e1595d Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Fri, 16 Sep 2016 21:14:04 +0200 Subject: sparse coboundary enumerator --- ripser.cpp | 50 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 2a62170..85e94f6 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -310,9 +310,9 @@ public: : neighbors(mat.size()) { - for (index_t i = 1; i < size(); ++i) + for (index_t i = 0; i < size(); ++i) for (index_t j = 0; j < size(); ++j) - if (mat(i, j) <= threshold) + if (i != j && mat(i, j) <= threshold) neighbors[i].push_back(diameter_index_t(mat(i, j), j)); } @@ -322,23 +322,42 @@ public: }; -template +template +struct second_argument_greater { + bool operator()(const T &lhs, const T &rhs) const + { + return lhs.second > rhs.second; + } +}; + +template +struct second_argument_equal_to { + bool operator()(const T &lhs, const T &rhs) const + { + return lhs.second == rhs.second; + } +}; + +template class set_intersection_enumerator { public: - InputIteratorCollection first, last; - - set_intersection_enumerator (InputIteratorCollection _first, InputIteratorCollection _last) : first(_first), last(_last) {} + InputIteratorCollection &first, &last; + Compare comp; + Equal equal; + + set_intersection_enumerator (InputIteratorCollection& _first, InputIteratorCollection& _last) : first(_first), last(_last) {} // template // set_intersection_enumerator (InputCollection _set) : first(_first), last(_last) {} bool has_next() { - for (auto &it0 = first[0], end0 = last[0]; it0 != end0; ++it0) { + for (auto &it0 = first[0], &end0 = last[0]; it0 != end0; ++it0) { auto x = *it0; for (size_t idx = 1; idx < first.size(); ++idx) { auto &it = first[idx], end = last[idx]; - while (*it < x) if (++it == end) return false; - if (*it > x) goto continue_outer; + while (comp(*it, x)) if (++it == end) return false; + auto y = *it; + if (!equal(y, x)) goto continue_outer; } return true; continue_outer: ; @@ -361,7 +380,7 @@ private: std::vector vertices; std::vector::const_reverse_iterator> ii, ee; - set_intersection_enumerator v_intersection; + set_intersection_enumerator, second_argument_equal_to> v_intersection; public: simplex_coboundary_enumerator_sparse(index_t _idx, index_t _dim, index_t _n, const binomial_coeff_table& _binomial_coeff, sparse_distance_matrix& _sparse_dist) @@ -373,7 +392,8 @@ public: ii.push_back(sparse_dist.neighbors[v].rbegin()); ee.push_back(sparse_dist.neighbors[v].rend()); } - + + get_next_vertex(w, idx_below, k, binomial_coeff); } bool has_next() { @@ -384,13 +404,17 @@ public: index_t v = get_index(v_intersection.next()); + + while (w > v && idx_below > 0) { - get_next_vertex(w, idx_below, k, binomial_coeff); - idx_below -= binomial_coeff(w, k); idx_above += binomial_coeff(w, k + 1); --k; + + get_next_vertex(w, idx_below, k, binomial_coeff); + + assert(k != -1); } -- cgit v1.2.3 From 29b383df930009dfe43d9629bc666d18345a96ac Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Fri, 16 Sep 2016 21:38:57 +0200 Subject: sparse coboundary enumerator --- ripser.cpp | 29 +++++------------------------ 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 85e94f6..820a3d3 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -94,7 +94,7 @@ std::vector multiplicative_inverse_vector(const coefficient_t m) return inverse; } -void get_next_vertex(index_t& v, const index_t idx, const index_t k, const binomial_coeff_table& binomial_coeff) { +index_t get_next_vertex(index_t& v, const index_t idx, const index_t k, const binomial_coeff_table& binomial_coeff) { if (binomial_coeff(v, k) > idx) { index_t count = v; @@ -111,6 +111,8 @@ void get_next_vertex(index_t& v, const index_t idx, const index_t k, const binom } assert(binomial_coeff(v, k) <= idx); assert(binomial_coeff(v + 1, k) > idx); + + return v; } @@ -321,7 +323,6 @@ public: size_t size() const { return neighbors.size(); } }; - template struct second_argument_greater { bool operator()(const T &lhs, const T &rhs) const @@ -347,9 +348,6 @@ public: set_intersection_enumerator (InputIteratorCollection& _first, InputIteratorCollection& _last) : first(_first), last(_last) {} -// template -// set_intersection_enumerator (InputCollection _set) : first(_first), last(_last) {} - bool has_next() { for (auto &it0 = first[0], &end0 = last[0]; it0 != end0; ++it0) { auto x = *it0; @@ -371,7 +369,6 @@ public: } }; - class simplex_coboundary_enumerator_sparse { private: index_t idx_below, idx_above, v, k, w; @@ -392,8 +389,6 @@ public: ii.push_back(sparse_dist.neighbors[v].rbegin()); ee.push_back(sparse_dist.neighbors[v].rend()); } - - get_next_vertex(w, idx_below, k, binomial_coeff); } bool has_next() { @@ -401,32 +396,18 @@ public: } std::pair next() { - index_t v = get_index(v_intersection.next()); - - - while (w > v && idx_below > 0) { + while (k > 0 && get_next_vertex(w, idx_below, k, binomial_coeff) > v) { idx_below -= binomial_coeff(w, k); idx_above += binomial_coeff(w, k + 1); - --k; - - get_next_vertex(w, idx_below, k, binomial_coeff); - - - assert(k != -1); } - auto result = std::make_pair(make_entry(idx_above + binomial_coeff(v, k + 1) + idx_below, k & 1 ? -1 : 1), v); - - - return result; + return std::make_pair(make_entry(idx_above + binomial_coeff(v, k + 1) + idx_below, k & 1 ? -1 : 1), v); } }; - - template <> void compressed_distance_matrix::init_rows() { value_t* pointer = &distances[0]; for (index_t i = 1; i < size(); ++i) { -- cgit v1.2.3 From 5794ba59f5621c6ec70ffa75a938d61c9342d4e3 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Mon, 19 Sep 2016 10:02:02 +0200 Subject: restructured coboundary enumerator --- ripser.cpp | 292 ++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 181 insertions(+), 111 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 208ebb0..80b00d3 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -111,11 +111,10 @@ index_t get_next_vertex(index_t& v, const index_t idx, const index_t k, const bi } assert(binomial_coeff(v, k) <= idx); assert(binomial_coeff(v + 1, k) > idx); - + return v; } - template OutputIterator get_simplex_vertices(index_t idx, const index_t dim, index_t v, const binomial_coeff_table& binomial_coeff, OutputIterator out) { @@ -246,14 +245,26 @@ public: } }; -class simplex_coboundary_enumerator { +template class simplex_coboundary_enumerator { private: index_t idx_below, idx_above, v, k; + + std::vector vertices; + + const diameter_entry_t simplex; + + const coefficient_t modulus; + const DistanceMatrix& dist; const binomial_coeff_table& binomial_coeff; public: - simplex_coboundary_enumerator(index_t _idx, index_t _dim, index_t _n, const binomial_coeff_table& _binomial_coeff) - : idx_below(_idx), idx_above(0), v(_n - 1), k(_dim + 1), binomial_coeff(_binomial_coeff) {} + simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, index_t _n, + const coefficient_t _modulus, const DistanceMatrix& _dist, + const binomial_coeff_table& _binomial_coeff) + : simplex(_simplex), idx_below(get_index(_simplex)), idx_above(0), v(_n - 1), k(_dim + 1), modulus(_modulus), + binomial_coeff(_binomial_coeff), dist(_dist), vertices(_dim + 1) { + get_simplex_vertices(get_index(_simplex), _dim, _n, binomial_coeff, vertices.begin()); + } bool has_next() { while ((v != -1) && (binomial_coeff(v, k) <= idx_below)) { @@ -267,8 +278,16 @@ public: return v != -1; } - std::pair next() { - auto result = std::make_pair(make_entry(idx_above + binomial_coeff(v, k + 1) + idx_below, k & 1 ? -1 : 1), v); + std::pair next() { + + value_t coface_diameter = get_diameter(simplex); + for (index_t w : vertices) { coface_diameter = std::max(coface_diameter, dist(v, w)); } + + coefficient_t coface_coefficient = (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; + + auto result = std::make_pair( + make_diameter_entry(coface_diameter, idx_above + binomial_coeff(v, k + 1) + idx_below, coface_coefficient), + v); --v; return result; } @@ -308,14 +327,11 @@ public: std::vector> neighbors; template - sparse_distance_matrix(const DistanceMatrix& mat, value_t threshold) - : neighbors(mat.size()) - { + sparse_distance_matrix(const DistanceMatrix& mat, value_t threshold) : neighbors(mat.size()) { for (index_t i = 0; i < size(); ++i) for (index_t j = 0; j < size(); ++j) - if (i != j && mat(i, j) <= threshold) - neighbors[i].push_back(diameter_index_t(mat(i, j), j)); + if (i != j && mat(i, j) <= threshold) neighbors[i].push_back(diameter_index_t(mat(i, j), j)); } value_t operator()(const index_t i, const index_t j) const; @@ -323,88 +339,107 @@ public: size_t size() const { return neighbors.size(); } }; -template -struct second_argument_greater { - bool operator()(const T &lhs, const T &rhs) const - { - return lhs.second > rhs.second; - } +template struct second_argument_greater { + bool operator()(const T& lhs, const T& rhs) const { return lhs.second > rhs.second; } }; -template -struct second_argument_equal_to { - bool operator()(const T &lhs, const T &rhs) const - { - return lhs.second == rhs.second; - } +template struct second_argument_equal_to { + bool operator()(const T& lhs, const T& rhs) const { return lhs.second == rhs.second; } }; -template +template class set_intersection_enumerator { public: - InputIteratorCollection &first, &last; + InputIteratorCollection &ii, ⅇ Compare comp; Equal equal; - - set_intersection_enumerator (InputIteratorCollection& _first, InputIteratorCollection& _last) : first(_first), last(_last) {} - - bool has_next() { - for (auto &it0 = first[0], &end0 = last[0]; it0 != end0; ++it0) { - auto x = *it0; - for (size_t idx = 1; idx < first.size(); ++idx) { - auto &it = first[idx], end = last[idx]; - while (comp(*it, x)) if (++it == end) return false; + Representative rep; + + set_intersection_enumerator(InputIteratorCollection& _first, InputIteratorCollection& _last) + : ii(_first), ee(_last) {} + + bool has_next() { + for (auto &it0 = ii[0], &end0 = ee[0]; it0 != end0; ++it0) { + auto x = *it0; + for (size_t idx = 1; idx < ii.size(); ++idx) { + auto &it = ii[idx], end = ee[idx]; + while (comp(*it, x)) + if (++it == end) return false; auto y = *it; - if (!equal(y, x)) goto continue_outer; - } - return true; - continue_outer: ; - } - return false; - } - - // only valid after has_next() has been called - decltype(*first[0]) next() { - return *first[0]++; - } + if (!equal(y, x)) + goto continue_outer; + else + x = rep(x, y); + } + return true; + continue_outer:; + } + return false; + } + + // only valid after has_next() has been called + decltype(*ii[0]) next() { return *ii[0]++; } }; class simplex_coboundary_enumerator_sparse { private: - index_t idx_below, idx_above, v, k, w; + index_t idx_below, idx_above, v, k, max_vertex_below; const binomial_coeff_table& binomial_coeff; - const sparse_distance_matrix& sparse_dist; - std::vector vertices; - - std::vector::const_reverse_iterator> ii, ee; - set_intersection_enumerator, second_argument_equal_to> v_intersection; + const sparse_distance_matrix& sparse_dist; + std::vector vertices; + + const value_t simplex_diameter; + + std::vector::const_reverse_iterator> ii, ee; + + diameter_index_t x; public: - simplex_coboundary_enumerator_sparse(index_t _idx, index_t _dim, index_t _n, const binomial_coeff_table& _binomial_coeff, sparse_distance_matrix& _sparse_dist) - : idx_below(_idx), idx_above(0), v(_n - 1), k(_dim + 1), w(_n - 1), binomial_coeff(_binomial_coeff), sparse_dist(_sparse_dist), v_intersection(ii, ee) - { - get_simplex_vertices(idx_below, _dim, _n, _binomial_coeff, std::back_inserter(vertices)); - - for (auto v: vertices) { - ii.push_back(sparse_dist.neighbors[v].rbegin()); - ee.push_back(sparse_dist.neighbors[v].rend()); - } - } + simplex_coboundary_enumerator_sparse(diameter_index_t _simplex, index_t _dim, index_t _n, + const binomial_coeff_table& _binomial_coeff, + const sparse_distance_matrix& _sparse_dist) + : simplex_diameter(get_diameter(_simplex)), idx_below(get_index(_simplex)), idx_above(0), v(_n - 1), + k(_dim + 1), max_vertex_below(_n - 1), binomial_coeff(_binomial_coeff), sparse_dist(_sparse_dist) { + get_simplex_vertices(idx_below, _dim, _n, _binomial_coeff, std::back_inserter(vertices)); + + for (auto v : vertices) { + ii.push_back(sparse_dist.neighbors[v].rbegin()); + ee.push_back(sparse_dist.neighbors[v].rend()); + } + } bool has_next() { - return v_intersection.has_next(); + for (auto &it0 = ii[0], &end0 = ee[0]; it0 != end0; ++it0) { + x = *it0; + for (size_t idx = 1; idx < ii.size(); ++idx) { + auto &it = ii[idx], end = ee[idx]; + while (get_index(*it) > get_index(x)) + if (++it == end) return false; + auto y = *it; + if (get_index(y) != get_index(x)) + goto continue_outer; + else + x = std::min(x, y, greater_diameter_or_smaller_index()); + } + return true; + continue_outer:; + } + return false; } - std::pair next() { - index_t v = get_index(v_intersection.next()); - - while (k > 0 && get_next_vertex(w, idx_below, k, binomial_coeff) > v) { - idx_below -= binomial_coeff(w, k); - idx_above += binomial_coeff(w, k + 1); + std::pair next() { + index_t covertex = get_index(x); + + while (k > 0 && get_next_vertex(max_vertex_below, idx_below, k, binomial_coeff) > covertex) { + idx_below -= binomial_coeff(max_vertex_below, k); + idx_above += binomial_coeff(max_vertex_below, k + 1); --k; } - - return std::make_pair(make_entry(idx_above + binomial_coeff(v, k + 1) + idx_below, k & 1 ? -1 : 1), v); + + return std::make_pair(make_diameter_entry(get_diameter(x), + idx_above + binomial_coeff(covertex, k + 1) + idx_below, + k & 1 ? -1 : 1), + covertex); } }; @@ -582,10 +617,60 @@ void assemble_columns_to_reduce(std::vector& columns_to_reduce index_t n, value_t threshold, const binomial_coeff_table& binomial_coeff) { index_t num_simplices = binomial_coeff(n, dim + 2); - // iterate over all (previous) columns_to_reduce - // find cofaces, additional vertices - // if additional vertex is larger than all current ones: append to columns_to_reduce + columns_to_reduce.clear(); + +#ifdef INDICATE_PROGRESS + std::cout << "\033[K" + << "assembling " << num_simplices << " columns" << std::flush << "\r"; +#endif + + for (index_t index = 0; index < num_simplices; ++index) { + if (pivot_column_index.find(index) == pivot_column_index.end()) { + value_t diameter = comp.diameter(index); + if (diameter <= threshold) columns_to_reduce.push_back(std::make_pair(diameter, index)); + } + } + +#ifdef INDICATE_PROGRESS + std::cout << "\033[K" + << "sorting " << num_simplices << " columns" << std::flush << "\r"; +#endif + std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), + greater_diameter_or_smaller_index()); +#ifdef INDICATE_PROGRESS + std::cout << "\033[K"; +#endif +} + +template +void assemble_columns_to_reduce_sparse(std::vector& columns_to_reduce, + hash_map& pivot_column_index, const Comparator& comp, + index_t dim, index_t n, value_t threshold, + const binomial_coeff_table& binomial_coeff, + const sparse_distance_matrix& sparse_dist) { + index_t num_simplices = binomial_coeff(n, dim + 2); + + // iterate over all (previous) columns_to_reduce + // find cofaces, additional vertices + // if additional vertex is larger than all current ones: append to columns_to_reduce + + std::vector previous_columns_to_reduce; + previous_columns_to_reduce.swap(columns_to_reduce); + for (diameter_index_t simplex : previous_columns_to_reduce) { + // coface_entries.clear(); + simplex_coboundary_enumerator_sparse cofaces(simplex, dim, n, binomial_coeff, sparse_dist); + + while (cofaces.has_next()) { + auto coface_descriptor = cofaces.next(); + auto coface = coface_descriptor.first; + index_t covertex = get_index(coface_descriptor.second); + index_t coface_index = get_index(coface); + value_t coface_diameter = get_diameter(coface_descriptor.first); + // for (index_t v : vertices) { coface_diameter = std::max(coface_diameter, dist(v, covertex)); } + assert(comp.diameter(coface_index) == coface_diameter); + } + } columns_to_reduce.clear(); @@ -615,9 +700,9 @@ void assemble_columns_to_reduce(std::vector& columns_to_reduce template void compute_pairs(std::vector& columns_to_reduce, hash_map& pivot_column_index, - const DistanceMatrix& dist, const ComparatorCofaces& comp, const Comparator& comp_prev, index_t dim, - index_t n, value_t threshold, coefficient_t modulus, - const std::vector& multiplicative_inverse, + index_t dim, index_t n, value_t threshold, coefficient_t modulus, + const std::vector& multiplicative_inverse, const DistanceMatrix& dist, + const ComparatorCofaces& comp, const Comparator& comp_prev, const binomial_coeff_table& binomial_coeff) { #ifdef PRINT_PERSISTENCE_PAIRS @@ -682,51 +767,36 @@ void compute_pairs(std::vector& columns_to_reduce, hash_map cofaces(simplex, dim, n, modulus, dist, binomial_coeff); + while (cofaces.has_next()) { - auto coface_descriptor = cofaces.next(); - entry_t coface = coface_descriptor.first; - index_t covertex = coface_descriptor.second; - index_t coface_index = get_index(coface); - value_t coface_diameter = get_diameter(simplex); - for (index_t v : vertices) { coface_diameter = std::max(coface_diameter, dist(v, covertex)); } - assert(comp.diameter(coface_index) == coface_diameter); - - if (coface_diameter <= threshold) { - coefficient_t coface_coefficient = - (get_coefficient(coface) + modulus) * simplex_coefficient % modulus; - assert(coface_coefficient >= 0); - - diameter_entry_t coface_entry = - make_diameter_entry(coface_diameter, coface_index, coface_coefficient); - coface_entries.push_back(coface_entry); - - if (might_be_apparent_pair && (get_diameter(simplex) == coface_diameter)) { - if (pivot_column_index.find(coface_index) == pivot_column_index.end()) { - pivot = coface_entry; + diameter_entry_t coface = cofaces.next().first; + assert(comp.diameter(get_index(coface)) == get_diameter(coface)); + + if (get_diameter(coface) <= threshold) { + coface_entries.push_back(coface); + + if (might_be_apparent_pair && (get_diameter(simplex) == get_diameter(coface))) { + if (pivot_column_index.find(get_index(coface)) == pivot_column_index.end()) { + pivot = coface; goto found_persistence_pair; } might_be_apparent_pair = false; @@ -1064,8 +1134,8 @@ int main(int argc, char** argv) { hash_map pivot_column_index; pivot_column_index.reserve(columns_to_reduce.size()); - compute_pairs(columns_to_reduce, pivot_column_index, dist, comp, comp_prev, dim, n, threshold, modulus, - multiplicative_inverse, binomial_coeff); + compute_pairs(columns_to_reduce, pivot_column_index, dim, n, threshold, modulus, multiplicative_inverse, dist, + comp, comp_prev, binomial_coeff); if (dim < dim_max) { assemble_columns_to_reduce(columns_to_reduce, pivot_column_index, comp, dim, n, threshold, binomial_coeff); -- cgit v1.2.3 From 51b07afc8e3d68d2c8dac8ef2916672ecffd9bfa Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Mon, 19 Sep 2016 18:05:09 +0200 Subject: cleanup --- ripser.cpp | 112 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 55 insertions(+), 57 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 80b00d3..c2213df 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -178,7 +178,11 @@ template struct smaller_index { bool operator()(const Entry& a, const Entry& b) { return get_index(a) < get_index(b); } }; -typedef std::pair diameter_index_t; +class diameter_index_t: public std::pair { +public: + diameter_index_t() : std::pair() {} + diameter_index_t(std::pair p) : std::pair(p) {} +}; value_t get_diameter(diameter_index_t i) { return i.first; } index_t get_index(diameter_index_t i) { return i.second; } @@ -187,6 +191,12 @@ public: diameter_entry_t(std::pair p) : std::pair(p) {} diameter_entry_t(entry_t e) : std::pair(0, e) {} diameter_entry_t() : diameter_entry_t(0) {} + diameter_entry_t(value_t _diameter, index_t _index, coefficient_t _coefficient) + : std::pair(_diameter, make_entry(_index, _coefficient)) {} + diameter_entry_t(diameter_index_t _diameter_index, coefficient_t _coefficient) + : std::pair(get_diameter(_diameter_index), + make_entry(get_index(_diameter_index), _coefficient)) {} + diameter_entry_t(diameter_index_t _diameter_index) : diameter_entry_t(_diameter_index, 1) {} }; const entry_t& get_entry(const diameter_entry_t& p) { return p.second; } @@ -195,12 +205,6 @@ const index_t get_index(const diameter_entry_t& p) { return get_index(get_entry( const coefficient_t get_coefficient(const diameter_entry_t& p) { return get_coefficient(get_entry(p)); } const value_t& get_diameter(const diameter_entry_t& p) { return p.first; } void set_coefficient(diameter_entry_t& p, const coefficient_t c) { set_coefficient(get_entry(p), c); } -diameter_entry_t make_diameter_entry(value_t _diameter, index_t _index, coefficient_t _coefficient) { - return std::make_pair(_diameter, make_entry(_index, _coefficient)); -} -diameter_entry_t make_diameter_entry(diameter_index_t _diameter_index, coefficient_t _coefficient) { - return std::make_pair(get_diameter(_diameter_index), make_entry(get_index(_diameter_index), _coefficient)); -} template struct greater_diameter_or_smaller_index { bool operator()(const Entry& a, const Entry& b) { @@ -278,18 +282,16 @@ public: return v != -1; } - std::pair next() { + index_t next_index() { return idx_above + binomial_coeff(v--, k + 1) + idx_below; } + + diameter_entry_t next() { value_t coface_diameter = get_diameter(simplex); for (index_t w : vertices) { coface_diameter = std::max(coface_diameter, dist(v, w)); } coefficient_t coface_coefficient = (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; - auto result = std::make_pair( - make_diameter_entry(coface_diameter, idx_above + binomial_coeff(v, k + 1) + idx_below, coface_coefficient), - v); - --v; - return result; + return diameter_entry_t(coface_diameter, idx_above + binomial_coeff(v, k + 1) + idx_below, coface_coefficient); } }; @@ -388,18 +390,20 @@ private: const sparse_distance_matrix& sparse_dist; std::vector vertices; - const value_t simplex_diameter; + const diameter_entry_t simplex; std::vector::const_reverse_iterator> ii, ee; diameter_index_t x; + const coefficient_t modulus; + public: - simplex_coboundary_enumerator_sparse(diameter_index_t _simplex, index_t _dim, index_t _n, - const binomial_coeff_table& _binomial_coeff, - const sparse_distance_matrix& _sparse_dist) - : simplex_diameter(get_diameter(_simplex)), idx_below(get_index(_simplex)), idx_above(0), v(_n - 1), - k(_dim + 1), max_vertex_below(_n - 1), binomial_coeff(_binomial_coeff), sparse_dist(_sparse_dist) { + simplex_coboundary_enumerator_sparse(const diameter_entry_t _simplex, index_t _dim, index_t _n, + const coefficient_t _modulus, const sparse_distance_matrix& _sparse_dist, + const binomial_coeff_table& _binomial_coeff) + : simplex(_simplex), idx_below(get_index(_simplex)), idx_above(0), v(_n - 1), k(_dim + 1), + max_vertex_below(_n - 1), modulus(_modulus), sparse_dist(_sparse_dist), binomial_coeff(_binomial_coeff) { get_simplex_vertices(idx_below, _dim, _n, _binomial_coeff, std::back_inserter(vertices)); for (auto v : vertices) { @@ -427,19 +431,21 @@ public: return false; } - std::pair next() { - index_t covertex = get_index(x); + diameter_entry_t next() { - while (k > 0 && get_next_vertex(max_vertex_below, idx_below, k, binomial_coeff) > covertex) { + while (k > 0 && get_next_vertex(max_vertex_below, idx_below, k, binomial_coeff) > get_index(x)) { idx_below -= binomial_coeff(max_vertex_below, k); idx_above += binomial_coeff(max_vertex_below, k + 1); --k; } - return std::make_pair(make_diameter_entry(get_diameter(x), - idx_above + binomial_coeff(covertex, k + 1) + idx_below, - k & 1 ? -1 : 1), - covertex); + value_t coface_diameter = std::max(get_diameter(simplex), get_diameter(x)); + + coefficient_t coface_coefficient = (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; + + return diameter_entry_t(get_diameter(x), + idx_above + binomial_coeff(get_index(x), k + 1) + idx_below, + k & 1 ? -1 : 1); } }; @@ -646,10 +652,9 @@ void assemble_columns_to_reduce(std::vector& columns_to_reduce template void assemble_columns_to_reduce_sparse(std::vector& columns_to_reduce, hash_map& pivot_column_index, const Comparator& comp, - index_t dim, index_t n, value_t threshold, - const binomial_coeff_table& binomial_coeff, - const sparse_distance_matrix& sparse_dist) { - index_t num_simplices = binomial_coeff(n, dim + 2); + index_t dim, index_t n, value_t threshold, const coefficient_t modulus, + const sparse_distance_matrix& sparse_dist, + const binomial_coeff_table& binomial_coeff) { // iterate over all (previous) columns_to_reduce // find cofaces, additional vertices @@ -659,16 +664,12 @@ void assemble_columns_to_reduce_sparse(std::vector& columns_to previous_columns_to_reduce.swap(columns_to_reduce); for (diameter_index_t simplex : previous_columns_to_reduce) { // coface_entries.clear(); - simplex_coboundary_enumerator_sparse cofaces(simplex, dim, n, binomial_coeff, sparse_dist); + simplex_coboundary_enumerator_sparse cofaces(simplex, dim, n, modulus, sparse_dist, binomial_coeff); while (cofaces.has_next()) { - auto coface_descriptor = cofaces.next(); - auto coface = coface_descriptor.first; - index_t covertex = get_index(coface_descriptor.second); - index_t coface_index = get_index(coface); - value_t coface_diameter = get_diameter(coface_descriptor.first); - // for (index_t v : vertices) { coface_diameter = std::max(coface_diameter, dist(v, covertex)); } - assert(comp.diameter(coface_index) == coface_diameter); + auto coface = cofaces.next(); + + columns_to_reduce.push_back(std::make_pair(get_diameter(coface), get_index(coface))); } } @@ -679,12 +680,12 @@ void assemble_columns_to_reduce_sparse(std::vector& columns_to << "assembling " << num_simplices << " columns" << std::flush << "\r"; #endif - for (index_t index = 0; index < num_simplices; ++index) { - if (pivot_column_index.find(index) == pivot_column_index.end()) { - value_t diameter = comp.diameter(index); - if (diameter <= threshold) columns_to_reduce.push_back(std::make_pair(diameter, index)); - } - } +// for (index_t index = 0; index < num_simplices; ++index) { +// if (pivot_column_index.find(index) == pivot_column_index.end()) { +// value_t diameter = comp.diameter(index); +// if (diameter <= threshold) columns_to_reduce.push_back(std::make_pair(diameter, index)); +// } +// } #ifdef INDICATE_PROGRESS std::cout << "\033[K" @@ -745,15 +746,15 @@ void compute_pairs(std::vector& columns_to_reduce, hash_map& columns_to_reduce, hash_map cofaces(simplex, dim, n, modulus, dist, binomial_coeff); while (cofaces.has_next()) { - diameter_entry_t coface = cofaces.next().first; + diameter_entry_t coface = cofaces.next(); assert(comp.diameter(get_index(coface)) == get_diameter(coface)); if (get_diameter(coface) <= threshold) { @@ -848,20 +849,17 @@ void compute_pairs(std::vector& columns_to_reduce, hash_map 0); -#else - const coefficient_t coefficient = 1; + set_coefficient(e, inverse * get_coefficient(e) % modulus); + assert(get_coefficient(e) > 0); #endif - reduction_matrix.push_back(make_diameter_entry(get_diameter(e), index, coefficient)); + reduction_matrix.push_back(e); } #else #ifdef USE_COEFFICIENTS reduction_coefficients.pop_back(); - reduction_coefficients.push_back(make_diameter_entry(column_to_reduce, inverse)); + reduction_coefficients.push_back(diameter_entry_t(column_to_reduce, inverse)); #endif #endif break; @@ -1097,7 +1095,7 @@ int main(int argc, char** argv) { rips_filtration_comparator comp(dist, 1, binomial_coeff); for (index_t index = binomial_coeff(n, 2); index-- > 0;) { value_t diameter = comp.diameter(index); - if (diameter <= threshold) edges.push_back(diameter_index_t(diameter, index)); + if (diameter <= threshold) edges.push_back(std::make_pair(diameter, index)); } std::sort(edges.rbegin(), edges.rend(), greater_diameter_or_smaller_index()); -- cgit v1.2.3 From ad46246d05aaef70d523b96d483e5a6407404cb1 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Mon, 19 Sep 2016 18:22:37 +0200 Subject: small bugs fixed --- ripser.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index c2213df..1405865 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -291,7 +291,7 @@ public: coefficient_t coface_coefficient = (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; - return diameter_entry_t(coface_diameter, idx_above + binomial_coeff(v, k + 1) + idx_below, coface_coefficient); + return diameter_entry_t(coface_diameter, idx_above + binomial_coeff(v--, k + 1) + idx_below, coface_coefficient); } }; @@ -443,9 +443,9 @@ public: coefficient_t coface_coefficient = (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; - return diameter_entry_t(get_diameter(x), + return diameter_entry_t(coface_diameter, idx_above + binomial_coeff(get_index(x), k + 1) + idx_below, - k & 1 ? -1 : 1); + coface_coefficient); } }; -- cgit v1.2.3 From 42a60a47c9bf12c5249fdea9b354fe352170950f Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Tue, 20 Sep 2016 09:35:45 +0200 Subject: bug fix in sparse coboundary enumerator --- ripser.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ripser.cpp b/ripser.cpp index 1405865..e16679c 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -333,7 +333,7 @@ public: for (index_t i = 0; i < size(); ++i) for (index_t j = 0; j < size(); ++j) - if (i != j && mat(i, j) <= threshold) neighbors[i].push_back(diameter_index_t(mat(i, j), j)); + if (i != j && mat(i, j) <= threshold) neighbors[i].push_back(std::make_pair(mat(i, j), j)); } value_t operator()(const index_t i, const index_t j) const; @@ -432,6 +432,7 @@ public: } diameter_entry_t next() { + ++ii[0]; while (k > 0 && get_next_vertex(max_vertex_below, idx_below, k, binomial_coeff) > get_index(x)) { idx_below -= binomial_coeff(max_vertex_below, k); -- cgit v1.2.3 From ab9fadd86b09a34e159fa12bdf0ab285ca252c3f Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Tue, 20 Sep 2016 11:08:59 +0200 Subject: fixes to sparse cobounrady computation --- ripser.cpp | 44 +++++++++++++++++++++++++--------------- ripser.xcodeproj/project.pbxproj | 11 +++++----- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index e16679c..5bbfe5c 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -168,7 +168,7 @@ typedef index_t entry_t; const index_t get_index(entry_t i) { return i; } index_t get_coefficient(entry_t i) { return 1; } entry_t make_entry(index_t _index, coefficient_t _value) { return entry_t(_index); } -void set_coefficient(index_t& e, const coefficient_t c) { e = c; } +void set_coefficient(index_t& e, const coefficient_t c) { } #endif @@ -336,8 +336,6 @@ public: if (i != j && mat(i, j) <= threshold) neighbors[i].push_back(std::make_pair(mat(i, j), j)); } - value_t operator()(const index_t i, const index_t j) const; - size_t size() const { return neighbors.size(); } }; @@ -383,7 +381,8 @@ public: decltype(*ii[0]) next() { return *ii[0]++; } }; -class simplex_coboundary_enumerator_sparse { +template<> +class simplex_coboundary_enumerator { private: index_t idx_below, idx_above, v, k, max_vertex_below; const binomial_coeff_table& binomial_coeff; @@ -399,7 +398,7 @@ private: const coefficient_t modulus; public: - simplex_coboundary_enumerator_sparse(const diameter_entry_t _simplex, index_t _dim, index_t _n, + simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, index_t _n, const coefficient_t _modulus, const sparse_distance_matrix& _sparse_dist, const binomial_coeff_table& _binomial_coeff) : simplex(_simplex), idx_below(get_index(_simplex)), idx_above(0), v(_n - 1), k(_dim + 1), @@ -661,11 +660,19 @@ void assemble_columns_to_reduce_sparse(std::vector& columns_to // find cofaces, additional vertices // if additional vertex is larger than all current ones: append to columns_to_reduce +#ifdef INDICATE_PROGRESS + std::cout << "\033[K" + << "assembling columns" << std::flush << "\r"; +#endif + std::vector previous_columns_to_reduce; previous_columns_to_reduce.swap(columns_to_reduce); + + columns_to_reduce.clear(); + for (diameter_index_t simplex : previous_columns_to_reduce) { // coface_entries.clear(); - simplex_coboundary_enumerator_sparse cofaces(simplex, dim, n, modulus, sparse_dist, binomial_coeff); + simplex_coboundary_enumerator cofaces(simplex, dim, n, modulus, sparse_dist, binomial_coeff); while (cofaces.has_next()) { auto coface = cofaces.next(); @@ -674,12 +681,6 @@ void assemble_columns_to_reduce_sparse(std::vector& columns_to } } - columns_to_reduce.clear(); - -#ifdef INDICATE_PROGRESS - std::cout << "\033[K" - << "assembling " << num_simplices << " columns" << std::flush << "\r"; -#endif // for (index_t index = 0; index < num_simplices; ++index) { // if (pivot_column_index.find(index) == pivot_column_index.end()) { @@ -690,7 +691,7 @@ void assemble_columns_to_reduce_sparse(std::vector& columns_to #ifdef INDICATE_PROGRESS std::cout << "\033[K" - << "sorting " << num_simplices << " columns" << std::flush << "\r"; + << "sorting " << columns_to_reduce.size() << " columns" << std::flush << "\r"; #endif std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), @@ -700,10 +701,12 @@ void assemble_columns_to_reduce_sparse(std::vector& columns_to #endif } -template +template void compute_pairs(std::vector& columns_to_reduce, hash_map& pivot_column_index, index_t dim, index_t n, value_t threshold, coefficient_t modulus, const std::vector& multiplicative_inverse, const DistanceMatrix& dist, +// const FullDistanceMatrix& dist_full, const ComparatorCofaces& comp, const Comparator& comp_prev, const binomial_coeff_table& binomial_coeff) { @@ -783,15 +786,22 @@ void compute_pairs(std::vector& columns_to_reduce, hash_map cofaces(simplex, dim, n, modulus, dist, binomial_coeff); +// simplex_coboundary_enumerator cofaces_full(simplex, dim, n, modulus, dist_full, binomial_coeff); while (cofaces.has_next()) { +// assert(cofaces_full.has_next()); diameter_entry_t coface = cofaces.next(); - assert(comp.diameter(get_index(coface)) == get_diameter(coface)); +// , coface_full = cofaces_full.next(); +// value_t diameter = comp.diameter(get_index(coface)); +// assert(comp.diameter(get_index(coface)) == get_diameter(coface)); if (get_diameter(coface) <= threshold) { coface_entries.push_back(coface); @@ -1083,6 +1093,8 @@ int main(int argc, char** argv) { auto value_range = std::minmax_element(dist.distances.begin(), dist.distances.end()); std::cout << "value range: [" << *value_range.first << "," << *value_range.second << "]" << std::endl; + sparse_distance_matrix sparse_dist(dist, threshold); + dim_max = std::min(dim_max, n - 2); binomial_coeff_table binomial_coeff(n, dim_max + 2); @@ -1133,7 +1145,7 @@ int main(int argc, char** argv) { hash_map pivot_column_index; pivot_column_index.reserve(columns_to_reduce.size()); - compute_pairs(columns_to_reduce, pivot_column_index, dim, n, threshold, modulus, multiplicative_inverse, dist, + compute_pairs(columns_to_reduce, pivot_column_index, dim, n, threshold, modulus, multiplicative_inverse, sparse_dist, //dist, comp, comp_prev, binomial_coeff); if (dim < dim_max) { diff --git a/ripser.xcodeproj/project.pbxproj b/ripser.xcodeproj/project.pbxproj index 2aa6179..24c7d8b 100644 --- a/ripser.xcodeproj/project.pbxproj +++ b/ripser.xcodeproj/project.pbxproj @@ -129,7 +129,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -148,7 +148,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_C_LANGUAGE_STANDARD = c11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; @@ -174,7 +174,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -193,7 +193,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_C_LANGUAGE_STANDARD = c11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; @@ -216,7 +216,8 @@ _FILE_FORMAT_DISTANCE_MATRIX, _FILE_FORMAT_LOWER_DISTANCE_MATRIX, _FILE_FORMAT_POINT_CLOUD, - USE_COEFFICIENTS, + _USE_COEFFICIENTS, + INDICATE_PROGRESS, ); PRODUCT_NAME = "$(TARGET_NAME)"; }; -- cgit v1.2.3 From c6d9d81dc7f445a0bcbcc7e943b514edad448389 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Tue, 20 Sep 2016 13:36:51 +0200 Subject: finished first version of sparse matrix support --- ripser.cpp | 96 +++++++++++++++++++++++--------------------------------------- 1 file changed, 35 insertions(+), 61 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 5bbfe5c..9f4e5e5 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -347,39 +347,6 @@ template struct second_argument_equal_to { bool operator()(const T& lhs, const T& rhs) const { return lhs.second == rhs.second; } }; -template -class set_intersection_enumerator { -public: - InputIteratorCollection &ii, ⅇ - Compare comp; - Equal equal; - Representative rep; - - set_intersection_enumerator(InputIteratorCollection& _first, InputIteratorCollection& _last) - : ii(_first), ee(_last) {} - - bool has_next() { - for (auto &it0 = ii[0], &end0 = ee[0]; it0 != end0; ++it0) { - auto x = *it0; - for (size_t idx = 1; idx < ii.size(); ++idx) { - auto &it = ii[idx], end = ee[idx]; - while (comp(*it, x)) - if (++it == end) return false; - auto y = *it; - if (!equal(y, x)) - goto continue_outer; - else - x = rep(x, y); - } - return true; - continue_outer:; - } - return false; - } - - // only valid after has_next() has been called - decltype(*ii[0]) next() { return *ii[0]++; } -}; template<> class simplex_coboundary_enumerator { @@ -411,7 +378,7 @@ public: } } - bool has_next() { + bool has_next(bool all_cofaces = true) { for (auto &it0 = ii[0], &end0 = ee[0]; it0 != end0; ++it0) { x = *it0; for (size_t idx = 1; idx < ii.size(); ++idx) { @@ -424,7 +391,7 @@ public: else x = std::min(x, y, greater_diameter_or_smaller_index()); } - return true; + return all_cofaces || !(k > 0 && get_next_vertex(max_vertex_below, idx_below, k, binomial_coeff) > get_index(x)); continue_outer:; } return false; @@ -634,6 +601,11 @@ void assemble_columns_to_reduce(std::vector& columns_to_reduce if (pivot_column_index.find(index) == pivot_column_index.end()) { value_t diameter = comp.diameter(index); if (diameter <= threshold) columns_to_reduce.push_back(std::make_pair(diameter, index)); +#ifdef INDICATE_PROGRESS + if ((index + 1) % 1000 == 0) + std::cout << "\033[K" + << "assembled " << columns_to_reduce.size() << " out of " << (index + 1) << "/" << num_simplices << " columns" << std::flush << "\r"; +#endif } } @@ -649,11 +621,15 @@ void assemble_columns_to_reduce(std::vector& columns_to_reduce #endif } + + template -void assemble_columns_to_reduce_sparse(std::vector& columns_to_reduce, - hash_map& pivot_column_index, const Comparator& comp, +void assemble_columns_to_reduce(std::vector& simplices, + std::vector& columns_to_reduce, + hash_map& pivot_column_index, + const sparse_distance_matrix& sparse_dist, + const Comparator& comp, index_t dim, index_t n, value_t threshold, const coefficient_t modulus, - const sparse_distance_matrix& sparse_dist, const binomial_coeff_table& binomial_coeff) { // iterate over all (previous) columns_to_reduce @@ -665,30 +641,26 @@ void assemble_columns_to_reduce_sparse(std::vector& columns_to << "assembling columns" << std::flush << "\r"; #endif - std::vector previous_columns_to_reduce; - previous_columns_to_reduce.swap(columns_to_reduce); - columns_to_reduce.clear(); + + std::vector next_simplices; - for (diameter_index_t simplex : previous_columns_to_reduce) { + for (diameter_index_t simplex : simplices) { // coface_entries.clear(); - simplex_coboundary_enumerator cofaces(simplex, dim, n, modulus, sparse_dist, binomial_coeff); + simplex_coboundary_enumerator cofaces(simplex, dim, n, modulus, sparse_dist, binomial_coeff); - while (cofaces.has_next()) { + while (cofaces.has_next(false)) { auto coface = cofaces.next(); + + next_simplices.push_back(std::make_pair(get_diameter(coface), get_index(coface))); - columns_to_reduce.push_back(std::make_pair(get_diameter(coface), get_index(coface))); + if (pivot_column_index.find(get_index(coface)) == pivot_column_index.end()) + columns_to_reduce.push_back(std::make_pair(get_diameter(coface), get_index(coface))); } } - - -// for (index_t index = 0; index < num_simplices; ++index) { -// if (pivot_column_index.find(index) == pivot_column_index.end()) { -// value_t diameter = comp.diameter(index); -// if (diameter <= threshold) columns_to_reduce.push_back(std::make_pair(diameter, index)); -// } -// } - + + simplices.swap(next_simplices); + #ifdef INDICATE_PROGRESS std::cout << "\033[K" << "sorting " << columns_to_reduce.size() << " columns" << std::flush << "\r"; @@ -1102,14 +1074,16 @@ int main(int argc, char** argv) { std::vector columns_to_reduce; + std::vector simplices , &edges = simplices; + rips_filtration_comparator comp(dist, 1, binomial_coeff); + for (index_t index = binomial_coeff(n, 2); index-- > 0;) { + value_t diameter = comp.diameter(index); + if (diameter <= threshold) edges.push_back(std::make_pair(diameter, index)); + } + { union_find dset(n); - std::vector edges; - rips_filtration_comparator comp(dist, 1, binomial_coeff); - for (index_t index = binomial_coeff(n, 2); index-- > 0;) { - value_t diameter = comp.diameter(index); - if (diameter <= threshold) edges.push_back(std::make_pair(diameter, index)); - } + std::sort(edges.rbegin(), edges.rend(), greater_diameter_or_smaller_index()); #ifdef PRINT_PERSISTENCE_PAIRS @@ -1149,7 +1123,7 @@ int main(int argc, char** argv) { comp, comp_prev, binomial_coeff); if (dim < dim_max) { - assemble_columns_to_reduce(columns_to_reduce, pivot_column_index, comp, dim, n, threshold, binomial_coeff); + assemble_columns_to_reduce(simplices, columns_to_reduce, pivot_column_index, sparse_dist, comp, dim, n, threshold, modulus, binomial_coeff); } } } -- cgit v1.2.3 From f31f1d94bc2367c27e306562c2f0492d2f0e87ab Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 22 Sep 2016 13:53:04 +0200 Subject: cleaned up comments --- ripser.cpp | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 9f4e5e5..713c70b 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -632,10 +632,6 @@ void assemble_columns_to_reduce(std::vector& simplices, index_t dim, index_t n, value_t threshold, const coefficient_t modulus, const binomial_coeff_table& binomial_coeff) { - // iterate over all (previous) columns_to_reduce - // find cofaces, additional vertices - // if additional vertex is larger than all current ones: append to columns_to_reduce - #ifdef INDICATE_PROGRESS std::cout << "\033[K" << "assembling columns" << std::flush << "\r"; @@ -646,7 +642,6 @@ void assemble_columns_to_reduce(std::vector& simplices, std::vector next_simplices; for (diameter_index_t simplex : simplices) { - // coface_entries.clear(); simplex_coboundary_enumerator cofaces(simplex, dim, n, modulus, sparse_dist, binomial_coeff); while (cofaces.has_next(false)) { @@ -673,12 +668,11 @@ void assemble_columns_to_reduce(std::vector& simplices, #endif } -template void compute_pairs(std::vector& columns_to_reduce, hash_map& pivot_column_index, index_t dim, index_t n, value_t threshold, coefficient_t modulus, const std::vector& multiplicative_inverse, const DistanceMatrix& dist, -// const FullDistanceMatrix& dist_full, const ComparatorCofaces& comp, const Comparator& comp_prev, const binomial_coeff_table& binomial_coeff) { @@ -758,22 +752,14 @@ void compute_pairs(std::vector& columns_to_reduce, hash_map cofaces(simplex, dim, n, modulus, dist, binomial_coeff); -// simplex_coboundary_enumerator cofaces_full(simplex, dim, n, modulus, dist_full, binomial_coeff); while (cofaces.has_next()) { -// assert(cofaces_full.has_next()); diameter_entry_t coface = cofaces.next(); -// , coface_full = cofaces_full.next(); -// value_t diameter = comp.diameter(get_index(coface)); -// assert(comp.diameter(get_index(coface)) == get_diameter(coface)); if (get_diameter(coface) <= threshold) { coface_entries.push_back(coface); @@ -1119,7 +1105,7 @@ int main(int argc, char** argv) { hash_map pivot_column_index; pivot_column_index.reserve(columns_to_reduce.size()); - compute_pairs(columns_to_reduce, pivot_column_index, dim, n, threshold, modulus, multiplicative_inverse, sparse_dist, //dist, + compute_pairs(columns_to_reduce, pivot_column_index, dim, n, threshold, modulus, multiplicative_inverse, sparse_dist, comp, comp_prev, binomial_coeff); if (dim < dim_max) { -- cgit v1.2.3 From 5adf0472e278034d155395cb8a95c017b30f0acb Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 29 Sep 2016 18:16:54 +0200 Subject: rearranged reduction columns code --- ripser.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index ec73f6d..4067018 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -685,7 +685,7 @@ void compute_pairs(std::vector& columns_to_reduce, hash_map reduction_matrix; + compressed_sparse_matrix reduction_coefficients; #else #ifdef USE_COEFFICIENTS std::vector reduction_coefficients; @@ -723,9 +723,9 @@ void compute_pairs(std::vector& columns_to_reduce, hash_map& columns_to_reduce, hash_map& columns_to_reduce, hash_map& columns_to_reduce, hash_map 0); #endif - reduction_matrix.push_back(e); + reduction_coefficients.push_back(e); } #else #ifdef USE_COEFFICIENTS -- cgit v1.2.3 From 43d28e6cea16062d0cefaf16979d07837cc788d6 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 29 Sep 2016 23:02:29 +0200 Subject: removed comparator --- ripser.cpp | 88 +++----------------------------------------------------------- 1 file changed, 3 insertions(+), 85 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 713c70b..f5384e9 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -213,42 +213,6 @@ template struct greater_diameter_or_smaller_index { } }; -template class rips_filtration_comparator { -public: - const DistanceMatrix& dist; - const index_t dim; - -private: - mutable std::vector vertices; - const binomial_coeff_table& binomial_coeff; - -public: - rips_filtration_comparator(const DistanceMatrix& _dist, const index_t _dim, - const binomial_coeff_table& _binomial_coeff) - : dist(_dist), dim(_dim), vertices(_dim + 1), binomial_coeff(_binomial_coeff){}; - - value_t diameter(const index_t index) const { - value_t diam = 0; - get_simplex_vertices(index, dim, dist.size(), binomial_coeff, vertices.begin()); - - for (index_t i = 0; i <= dim; ++i) - for (index_t j = 0; j < i; ++j) { diam = std::max(diam, dist(vertices[i], vertices[j])); } - return diam; - } - - bool operator()(const index_t a, const index_t b) const { - assert(a < binomial_coeff(dist.size(), dim + 1)); - assert(b < binomial_coeff(dist.size(), dim + 1)); - - return greater_diameter_or_smaller_index()(diameter_index_t(diameter(a), a), - diameter_index_t(diameter(b), b)); - } - - template bool operator()(const Entry& a, const Entry& b) const { - return operator()(get_index(a), get_index(b)); - } -}; - template class simplex_coboundary_enumerator { private: index_t idx_below, idx_above, v, k; @@ -584,51 +548,10 @@ template void push_entry(Heap& column, index_t i, coefficient_t column.push(std::make_pair(diameter, e)); } -template -void assemble_columns_to_reduce(std::vector& columns_to_reduce, - hash_map& pivot_column_index, const Comparator& comp, index_t dim, - index_t n, value_t threshold, const binomial_coeff_table& binomial_coeff) { - index_t num_simplices = binomial_coeff(n, dim + 2); - - columns_to_reduce.clear(); - -#ifdef INDICATE_PROGRESS - std::cout << "\033[K" - << "assembling " << num_simplices << " columns" << std::flush << "\r"; -#endif - - for (index_t index = 0; index < num_simplices; ++index) { - if (pivot_column_index.find(index) == pivot_column_index.end()) { - value_t diameter = comp.diameter(index); - if (diameter <= threshold) columns_to_reduce.push_back(std::make_pair(diameter, index)); -#ifdef INDICATE_PROGRESS - if ((index + 1) % 1000 == 0) - std::cout << "\033[K" - << "assembled " << columns_to_reduce.size() << " out of " << (index + 1) << "/" << num_simplices << " columns" << std::flush << "\r"; -#endif - } - } - -#ifdef INDICATE_PROGRESS - std::cout << "\033[K" - << "sorting " << num_simplices << " columns" << std::flush << "\r"; -#endif - - std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), - greater_diameter_or_smaller_index()); -#ifdef INDICATE_PROGRESS - std::cout << "\033[K"; -#endif -} - - - -template void assemble_columns_to_reduce(std::vector& simplices, std::vector& columns_to_reduce, hash_map& pivot_column_index, const sparse_distance_matrix& sparse_dist, - const Comparator& comp, index_t dim, index_t n, value_t threshold, const coefficient_t modulus, const binomial_coeff_table& binomial_coeff) { @@ -668,12 +591,10 @@ void assemble_columns_to_reduce(std::vector& simplices, #endif } -template +template void compute_pairs(std::vector& columns_to_reduce, hash_map& pivot_column_index, index_t dim, index_t n, value_t threshold, coefficient_t modulus, const std::vector& multiplicative_inverse, const DistanceMatrix& dist, - const ComparatorCofaces& comp, const Comparator& comp_prev, const binomial_coeff_table& binomial_coeff) { #ifdef PRINT_PERSISTENCE_PAIRS @@ -1099,17 +1020,14 @@ int main(int argc, char** argv) { } for (index_t dim = 1; dim <= dim_max; ++dim) { - rips_filtration_comparator comp(dist, dim + 1, binomial_coeff); - rips_filtration_comparator comp_prev(dist, dim, binomial_coeff); - hash_map pivot_column_index; pivot_column_index.reserve(columns_to_reduce.size()); compute_pairs(columns_to_reduce, pivot_column_index, dim, n, threshold, modulus, multiplicative_inverse, sparse_dist, - comp, comp_prev, binomial_coeff); + binomial_coeff); if (dim < dim_max) { - assemble_columns_to_reduce(simplices, columns_to_reduce, pivot_column_index, sparse_dist, comp, dim, n, threshold, modulus, binomial_coeff); + assemble_columns_to_reduce(simplices, columns_to_reduce, pivot_column_index, sparse_dist, dim, n, threshold, modulus, binomial_coeff); } } } -- cgit v1.2.3 From 77deb431e86bab1b4d3716909fc061ac52f692f1 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 29 Sep 2016 23:03:12 +0200 Subject: sparse graph support for dim 0 --- ripser.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index f5384e9..561f7bf 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -982,17 +982,22 @@ int main(int argc, char** argv) { std::vector columns_to_reduce; std::vector simplices , &edges = simplices; - rips_filtration_comparator comp(dist, 1, binomial_coeff); - for (index_t index = binomial_coeff(n, 2); index-- > 0;) { - value_t diameter = comp.diameter(index); - if (diameter <= threshold) edges.push_back(std::make_pair(diameter, index)); + + for (index_t i = 0; i < n; ++i) { + simplex_coboundary_enumerator cofaces(i, 0, n, modulus, sparse_dist, binomial_coeff); + + while (cofaces.has_next(false)) { + auto coface = cofaces.next(); + value_t diameter = get_diameter(coface); + if (diameter <= threshold) edges.push_back(std::make_pair(diameter, get_index(coface))); + } + + std::sort(edges.rbegin(), edges.rend(), greater_diameter_or_smaller_index()); } { union_find dset(n); - std::sort(edges.rbegin(), edges.rend(), greater_diameter_or_smaller_index()); - #ifdef PRINT_PERSISTENCE_PAIRS std::cout << "persistence intervals in dim 0:" << std::endl; #endif -- cgit v1.2.3 From 7cd0e22d554207e420d4dcedbe7e753bac64c3c3 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Fri, 30 Sep 2016 18:43:48 +0200 Subject: pretty-print --- ripser.cpp | 90 +++++++++++++++++++++++++++++--------------------------------- 1 file changed, 42 insertions(+), 48 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 6faa9c4..3effc85 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -18,7 +18,6 @@ with this program. If not, see . */ - //#define ASSEMBLE_REDUCTION_MATRIX //#define USE_COEFFICIENTS @@ -167,7 +166,7 @@ typedef index_t entry_t; const index_t get_index(entry_t i) { return i; } index_t get_coefficient(entry_t i) { return 1; } entry_t make_entry(index_t _index, coefficient_t _value) { return entry_t(_index); } -void set_coefficient(index_t& e, const coefficient_t c) { } +void set_coefficient(index_t& e, const coefficient_t c) {} #endif @@ -177,7 +176,7 @@ template struct smaller_index { bool operator()(const Entry& a, const Entry& b) { return get_index(a) < get_index(b); } }; -class diameter_index_t: public std::pair { +class diameter_index_t : public std::pair { public: diameter_index_t() : std::pair() {} diameter_index_t(std::pair p) : std::pair(p) {} @@ -284,7 +283,8 @@ public: value_t coface_diameter = get_diameter(simplex); for (index_t w : vertices) coface_diameter = std::max(coface_diameter, dist(v, w)); coefficient_t coface_coefficient = (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; - return diameter_entry_t(coface_diameter, idx_above + binomial_coeff(v--, k + 1) + idx_below, coface_coefficient); + return diameter_entry_t(coface_diameter, idx_above + binomial_coeff(v--, k + 1) + idx_below, + coface_coefficient); } }; @@ -340,9 +340,7 @@ template struct second_argument_equal_to { bool operator()(const T& lhs, const T& rhs) const { return lhs.second == rhs.second; } }; - -template<> -class simplex_coboundary_enumerator { +template <> class simplex_coboundary_enumerator { private: index_t idx_below, idx_above, v, k, max_vertex_below; const binomial_coeff_table& binomial_coeff; @@ -359,8 +357,8 @@ private: public: simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, index_t _n, - const coefficient_t _modulus, const sparse_distance_matrix& _sparse_dist, - const binomial_coeff_table& _binomial_coeff) + const coefficient_t _modulus, const sparse_distance_matrix& _sparse_dist, + const binomial_coeff_table& _binomial_coeff) : simplex(_simplex), idx_below(get_index(_simplex)), idx_above(0), v(_n - 1), k(_dim + 1), max_vertex_below(_n - 1), modulus(_modulus), sparse_dist(_sparse_dist), binomial_coeff(_binomial_coeff) { get_simplex_vertices(idx_below, _dim, _n, _binomial_coeff, std::back_inserter(vertices)); @@ -384,7 +382,8 @@ public: else x = std::min(x, y, greater_diameter_or_smaller_index()); } - return all_cofaces || !(k > 0 && get_next_vertex(max_vertex_below, idx_below, k, binomial_coeff) > get_index(x)); + return all_cofaces || + !(k > 0 && get_next_vertex(max_vertex_below, idx_below, k, binomial_coeff) > get_index(x)); continue_outer:; } return false; @@ -403,9 +402,8 @@ public: coefficient_t coface_coefficient = (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; - return diameter_entry_t(coface_diameter, - idx_above + binomial_coeff(get_index(x), k + 1) + idx_below, - coface_coefficient); + return diameter_entry_t(coface_diameter, idx_above + binomial_coeff(get_index(x), k + 1) + idx_below, + coface_coefficient); } }; @@ -595,9 +593,10 @@ void assemble_columns_to_reduce(std::vector& columns_to_reduce value_t diameter = comp.diameter(index); if (diameter <= threshold) columns_to_reduce.push_back(std::make_pair(diameter, index)); #ifdef INDICATE_PROGRESS - if ((index + 1) % 1000 == 0) - std::cout << "\033[K" - << "assembled " << columns_to_reduce.size() << " out of " << (index + 1) << "/" << num_simplices << " columns" << std::flush << "\r"; + if ((index + 1) % 1000 == 0) + std::cout << "\033[K" + << "assembled " << columns_to_reduce.size() << " out of " << (index + 1) << "/" + << num_simplices << " columns" << std::flush << "\r"; #endif } } @@ -614,16 +613,13 @@ void assemble_columns_to_reduce(std::vector& columns_to_reduce #endif } - - template void assemble_columns_to_reduce(std::vector& simplices, - std::vector& columns_to_reduce, - hash_map& pivot_column_index, - const sparse_distance_matrix& sparse_dist, - const Comparator& comp, - index_t dim, index_t n, value_t threshold, const coefficient_t modulus, - const binomial_coeff_table& binomial_coeff) { + std::vector& columns_to_reduce, + hash_map& pivot_column_index, + const sparse_distance_matrix& sparse_dist, const Comparator& comp, index_t dim, + index_t n, value_t threshold, const coefficient_t modulus, + const binomial_coeff_table& binomial_coeff) { #ifdef INDICATE_PROGRESS std::cout << "\033[K" @@ -631,24 +627,25 @@ void assemble_columns_to_reduce(std::vector& simplices, #endif columns_to_reduce.clear(); - + std::vector next_simplices; for (diameter_index_t simplex : simplices) { - simplex_coboundary_enumerator cofaces(simplex, dim, n, modulus, sparse_dist, binomial_coeff); + simplex_coboundary_enumerator cofaces(simplex, dim, n, modulus, sparse_dist, + binomial_coeff); while (cofaces.has_next(false)) { auto coface = cofaces.next(); - + next_simplices.push_back(std::make_pair(get_diameter(coface), get_index(coface))); - + if (pivot_column_index.find(get_index(coface)) == pivot_column_index.end()) columns_to_reduce.push_back(std::make_pair(get_diameter(coface), get_index(coface))); } } - + simplices.swap(next_simplices); - + #ifdef INDICATE_PROGRESS std::cout << "\033[K" << "sorting " << columns_to_reduce.size() << " columns" << std::flush << "\r"; @@ -661,12 +658,10 @@ void assemble_columns_to_reduce(std::vector& simplices, #endif } -template +template void compute_pairs(std::vector& columns_to_reduce, hash_map& pivot_column_index, index_t dim, index_t n, value_t threshold, coefficient_t modulus, - const std::vector& multiplicative_inverse, - const DistanceMatrix& dist, + const std::vector& multiplicative_inverse, const DistanceMatrix& dist, const ComparatorCofaces& comp, const Comparator& comp_prev, const binomial_coeff_table& binomial_coeff) { @@ -736,8 +731,7 @@ void compute_pairs(std::vector& columns_to_reduce, hash_map columns_to_reduce; - std::vector simplices , &edges = simplices; - rips_filtration_comparator comp(dist, 1, binomial_coeff); - for (index_t index = binomial_coeff(n, 2); index-- > 0;) { - value_t diameter = comp.diameter(index); - if (diameter <= threshold) edges.push_back(std::make_pair(diameter, index)); - } - + std::vector simplices, &edges = simplices; + rips_filtration_comparator comp(dist, 1, binomial_coeff); + for (index_t index = binomial_coeff(n, 2); index-- > 0;) { + value_t diameter = comp.diameter(index); + if (diameter <= threshold) edges.push_back(std::make_pair(diameter, index)); + } + { union_find dset(n); @@ -1071,8 +1065,7 @@ int main(int argc, char** argv) { if (u != v) { #ifdef PRINT_PERSISTENCE_PAIRS - if (get_diameter(e) > 0) - std::cout << " [0," << get_diameter(e) << ")" << std::endl; + if (get_diameter(e) > 0) std::cout << " [0," << get_diameter(e) << ")" << std::endl; #endif dset.link(u, v); } else @@ -1093,11 +1086,12 @@ int main(int argc, char** argv) { hash_map pivot_column_index; pivot_column_index.reserve(columns_to_reduce.size()); - compute_pairs(columns_to_reduce, pivot_column_index, dim, n, threshold, modulus, multiplicative_inverse, sparse_dist, - comp, comp_prev, binomial_coeff); + compute_pairs(columns_to_reduce, pivot_column_index, dim, n, threshold, modulus, multiplicative_inverse, + sparse_dist, comp, comp_prev, binomial_coeff); if (dim < dim_max) { - assemble_columns_to_reduce(simplices, columns_to_reduce, pivot_column_index, sparse_dist, comp, dim, n, threshold, modulus, binomial_coeff); + assemble_columns_to_reduce(simplices, columns_to_reduce, pivot_column_index, sparse_dist, comp, dim, n, + threshold, modulus, binomial_coeff); } } } -- cgit v1.2.3 From 7f2d16e1054529bed4d04c00a6fd7a7c33fdd458 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Fri, 30 Sep 2016 22:03:08 +0200 Subject: fixed build problems --- ripser.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index b183b3d..36a477a 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -180,6 +180,7 @@ class diameter_index_t : public std::pair { public: diameter_index_t() : std::pair() {} diameter_index_t(std::pair p) : std::pair(p) {} + diameter_index_t(index_t i) : std::pair(0, i) {} }; value_t get_diameter(diameter_index_t i) { return i.first; } index_t get_index(diameter_index_t i) { return i.second; } @@ -187,8 +188,6 @@ index_t get_index(diameter_index_t i) { return i.second; } class diameter_entry_t : public std::pair { public: diameter_entry_t(std::pair p) : std::pair(p) {} - diameter_entry_t(entry_t e) : std::pair(0, e) {} - diameter_entry_t() : diameter_entry_t(0) {} diameter_entry_t(value_t _diameter, index_t _index, coefficient_t _coefficient) : std::pair(_diameter, make_entry(_index, _coefficient)) {} diameter_entry_t(diameter_index_t _diameter_index, coefficient_t _coefficient) @@ -968,7 +967,7 @@ int main(int argc, char** argv) { std::vector simplices, &edges = simplices; for (index_t i = 0; i < n; ++i) { - simplex_coboundary_enumerator cofaces(i, 0, n, modulus, sparse_dist, binomial_coeff); + simplex_coboundary_enumerator cofaces(diameter_index_t(i), 0, n, modulus, sparse_dist, binomial_coeff); while (cofaces.has_next(false)) { auto coface = cofaces.next(); -- cgit v1.2.3 From 370d31554bf52353cfc2af542242faf621066588 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Mon, 7 Nov 2016 10:55:29 +0100 Subject: javaplex benchmarks --- benchmarks/benchmarks.txt | 1 + benchmarks/javaplex.txt | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 benchmarks/javaplex.txt diff --git a/benchmarks/benchmarks.txt b/benchmarks/benchmarks.txt index c5fc91f..bb34d08 100644 --- a/benchmarks/benchmarks.txt +++ b/benchmarks/benchmarks.txt @@ -8,3 +8,4 @@ c++ -std=c++11 ripser.cpp -o ripser -Ofast -D NDEBUG -D FILE_FORMAT_DIPHA -D PRINT_PERSISTENCE_PAIRS && /usr/bin/time -l ./ripser --dim 2 ~/Bitbucket/phat-paper/benchmark/dipha/sphere_3_192.complex +/usr/bin/time -l java -Xmx16G -cp Bitbucket/phat-paper/benchmark:Source/javaplex/dist/javaplex-4.2.1.jar RipsFiltration ~/Bitbucket/phat-paper/benchmark/point\ cloud/sphere_3_192_points.dat 2 3 \ No newline at end of file diff --git a/benchmarks/javaplex.txt b/benchmarks/javaplex.txt new file mode 100644 index 0000000..a39e804 --- /dev/null +++ b/benchmarks/javaplex.txt @@ -0,0 +1,19 @@ +geometry74:~ uli$ /usr/bin/time -l java -Xmx16G -cp Bitbucket/phat-paper/benchmark:Source/javaplex/dist/javaplex-4.2.1.jar RipsFiltration ~/Bitbucket/phat-paper/benchmark/point\ cloud/sphere_3_192_points.dat 2 3 +Constructing Rips filtration in 425.57800000000003 s +Computing persistence (default) in 2848.477 s + 3275.48 real 3900.79 user 36.35 sys +12636958720 maximum resident set size + 0 average shared memory size + 0 average unshared data size + 0 average unshared stack size + 4791446 page reclaims + 2 page faults + 0 swaps + 5 block input operations + 5 block output operations + 0 messages sent + 0 messages received + 5 signals received + 9 voluntary context switches + 9898205 involuntary context switches + -- cgit v1.2.3 From 0e3bd6152519cce4a55c104aa00478aeaf23dfb9 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Wed, 9 Nov 2016 23:58:52 +0100 Subject: initialize edges from lower distance matrix --- ripser.cpp | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 36a477a..3ebf2e3 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -965,19 +965,19 @@ int main(int argc, char** argv) { std::vector columns_to_reduce; std::vector simplices, &edges = simplices; - - for (index_t i = 0; i < n; ++i) { - simplex_coboundary_enumerator cofaces(diameter_index_t(i), 0, n, modulus, sparse_dist, binomial_coeff); - - while (cofaces.has_next(false)) { - auto coface = cofaces.next(); - value_t diameter = get_diameter(coface); - if (diameter <= threshold) edges.push_back(std::make_pair(diameter, get_index(coface))); - } - - std::sort(edges.rbegin(), edges.rend(), greater_diameter_or_smaller_index()); + + std::chrono::time_point start, end; + long elapsed_time; + + start = std::chrono::system_clock::now(); + + for (index_t e = 0; e < dist.distances.size(); ++e) { + value_t diameter = dist.distances[e]; + if (diameter <= threshold) edges.push_back(std::make_pair(diameter, e)); } - + + std::sort(edges.rbegin(), edges.rend(), greater_diameter_or_smaller_index()); + { union_find dset(n); @@ -1019,4 +1019,9 @@ int main(int argc, char** argv) { threshold, modulus, binomial_coeff); } } + + end = std::chrono::system_clock::now(); + elapsed_time = std::chrono::duration_cast(end - start).count(); + std::cout << "Computed Rips persistence in " << elapsed_time << " ms.\n"; + } -- cgit v1.2.3 From 9213750960682a4bd3d4291467818395f124355c Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 10 Nov 2016 00:25:10 +0100 Subject: more timing --- ripser.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 3ebf2e3..d984904 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -946,8 +946,14 @@ int main(int argc, char** argv) { exit(-1); } + std::chrono::time_point start; + + start = std::chrono::system_clock::now(); + compressed_lower_distance_matrix dist = read_file(filename ? file_stream : std::cin, format); + std::cout << "Reading file in " << std::chrono::duration_cast(std::chrono::system_clock::now() - start).count() / 1000. << " s.\n"; + index_t n = dist.size(); std::cout << "distance matrix with " << n << " points" << std::endl; @@ -955,7 +961,12 @@ int main(int argc, char** argv) { auto value_range = std::minmax_element(dist.distances.begin(), dist.distances.end()); std::cout << "value range: [" << *value_range.first << "," << *value_range.second << "]" << std::endl; + start = std::chrono::system_clock::now(); + sparse_distance_matrix sparse_dist(dist, threshold); + + std::cout << "Building sparse distance matrix in " << std::chrono::duration_cast(std::chrono::system_clock::now() - start).count() / 1000. << " s.\n"; + dim_max = std::min(dim_max, n - 2); @@ -966,8 +977,6 @@ int main(int argc, char** argv) { std::vector simplices, &edges = simplices; - std::chrono::time_point start, end; - long elapsed_time; start = std::chrono::system_clock::now(); @@ -1020,8 +1029,7 @@ int main(int argc, char** argv) { } } - end = std::chrono::system_clock::now(); - elapsed_time = std::chrono::duration_cast(end - start).count(); - std::cout << "Computed Rips persistence in " << elapsed_time << " ms.\n"; + std::cout << "Computing Rips persistence in " << std::chrono::duration_cast(std::chrono::system_clock::now() - start).count() / 1000. << " s.\n"; + } -- cgit v1.2.3 From 5c55dd581f101b68941150ab803cb79eef6a79e0 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 10 Nov 2016 08:43:53 +0100 Subject: renamed variable --- ripser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ripser.cpp b/ripser.cpp index 9d57fa9..8bd5a83 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -619,7 +619,7 @@ void compute_pairs(std::vector& columns_to_reduce, hash_map Date: Thu, 10 Nov 2016 18:21:18 +0100 Subject: Ripser binary file format --- ripser.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ripser.cpp b/ripser.cpp index 8bd5a83..3e4cf1f 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -686,7 +686,7 @@ void compute_pairs(std::vector& columns_to_reduce, hash_map T read(std::istream& s) { T result; @@ -787,6 +787,12 @@ compressed_lower_distance_matrix read_dipha(std::istream& input_stream) { return compressed_lower_distance_matrix(std::move(distances)); } +compressed_lower_distance_matrix read_ripser(std::istream& input_stream) { + std::vector distances; + while (!input_stream.eof()) distances.push_back(read(input_stream)); + return compressed_lower_distance_matrix(std::move(distances)); +} + compressed_lower_distance_matrix read_file(std::istream& input_stream, file_format format) { switch (format) { case LOWER_DISTANCE_MATRIX: @@ -799,6 +805,8 @@ compressed_lower_distance_matrix read_file(std::istream& input_stream, file_form return read_point_cloud(input_stream); case DIPHA: return read_dipha(input_stream); + case RIPSER: + return read_ripser(input_stream); } } @@ -816,6 +824,7 @@ void print_usage_and_exit(int exit_code) { << " distance (full distance matrix)" << std::endl << " point-cloud (point cloud in Euclidean space)" << std::endl << " dipha (distance matrix in DIPHA file format)" << std::endl + << " ripser (distance matrix in Ripser binary file format)" << std::endl << " --dim compute persistent homology up to dimension " << std::endl << " --threshold compute Rips complexes up to diameter " << std::endl #ifdef USE_COEFFICIENTS @@ -867,6 +876,8 @@ int main(int argc, char** argv) { format = POINT_CLOUD; else if (parameter == "dipha") format = DIPHA; + else if (parameter == "ripser") + format = RIPSER; else print_usage_and_exit(-1); #ifdef USE_COEFFICIENTS -- cgit v1.2.3 From 5cfc80f27c19e2db52373a155b8dbf1ff627ac26 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Tue, 22 Nov 2016 17:18:54 -0500 Subject: coeff reduction in makefile --- Makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 73e09fb..893d776 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ build: ripser -all: ripser ripser-coeff ripser-reduction ripser-debug +all: ripser ripser-coeff ripser-reduction ripser-coeff-reduction ripser-debug ripser: ripser.cpp @@ -13,9 +13,12 @@ ripser-coeff: ripser.cpp ripser-reduction: ripser.cpp c++ -std=c++11 ripser.cpp -o ripser-reduction -Ofast -D NDEBUG -D ASSEMBLE_REDUCTION_MATRIX +ripser-coeff-reduction: ripser.cpp + c++ -std=c++11 ripser.cpp -o ripser-coeff-reduction -Ofast -D NDEBUG -D USE_COEFFICIENTS -D ASSEMBLE_REDUCTION_MATRIX + ripser-debug: ripser.cpp c++ -std=c++11 ripser.cpp -o ripser-debug -g clean: - rm -f ripser ripser-coeff ripser-reduction ripser-debug + rm -f ripser ripser-coeff ripser-reduction ripser-coeff-reduction ripser-debug -- cgit v1.2.3 From c0574ec97f6d413b597447636a39b550cb55ee5d Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Tue, 22 Nov 2016 17:19:27 -0500 Subject: don’t store diagonal in reduction matrix when not using coefficients MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ripser.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 3e4cf1f..022b5fe 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -548,7 +548,7 @@ void compute_pairs(std::vector& columns_to_reduce, hash_map, smaller_index> + std::priority_queue, greater_diameter_or_smaller_index> reduction_column; #endif @@ -574,20 +574,25 @@ void compute_pairs(std::vector& columns_to_reduce, hash_map coeffs(0); + coeffs.push_back(columns_to_reduce[j]); + for (auto it = reduction_coefficients.cbegin(j); it != reduction_coefficients.cend(j); ++it) coeffs.push_back(*it); + auto coeffs_begin = coeffs.begin(), coeffs_end = coeffs.end(); +#endif #else #ifdef USE_COEFFICIENTS auto coeffs_begin = &reduction_coefficients[j], coeffs_end = &reduction_coefficients[j] + 1; @@ -661,7 +666,12 @@ void compute_pairs(std::vector& columns_to_reduce, hash_map Date: Tue, 22 Nov 2016 18:26:01 -0500 Subject: moved attribute packed --- ripser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 022b5fe..8f6ec89 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -136,13 +136,13 @@ std::vector vertices_of_simplex(const index_t simplex_index, const inde } #ifdef USE_COEFFICIENTS -struct entry_t { +struct __attribute__((packed)) entry_t { index_t index : 8 * (sizeof(index_t) - sizeof(coefficient_t)); coefficient_t coefficient; entry_t(index_t _index, coefficient_t _coefficient) : index(_index), coefficient(_coefficient) {} entry_t(index_t _index) : index(_index), coefficient(1) {} entry_t() : index(0), coefficient(1) {} -} __attribute__((packed)); +}; static_assert(sizeof(entry_t) == sizeof(index_t), "size of entry_t is not the same as index_t"); -- cgit v1.2.3 From 6f36a1288f8de8c9cddc8b90ca8256935291ce28 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Sat, 26 Nov 2016 17:20:41 -0500 Subject: code reorganization --- ripser.cpp | 433 ++++++++++++++++++++++++++++--------------------------------- 1 file changed, 198 insertions(+), 235 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 8f6ec89..dc6b1bd 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -47,8 +47,6 @@ template class hash_map : public std::unordered_map #endif typedef float value_t; -// typedef uint16_t value_t; - typedef int64_t index_t; typedef int16_t coefficient_t; @@ -74,8 +72,7 @@ public: } index_t operator()(index_t n, index_t k) const { - assert(n <= n_max); - assert(k <= k_max); + assert(n <= n_max && k <= k_max); return B[n][k]; } }; @@ -111,8 +108,7 @@ index_t get_next_vertex(index_t& v, const index_t idx, const index_t k, const bi count = step; } } - assert(binomial_coeff(v, k) <= idx); - assert(binomial_coeff(v + 1, k) > idx); + assert(binomial_coeff(v, k) <= idx && binomial_coeff(v + 1, k) > idx); return v; } @@ -128,13 +124,6 @@ OutputIterator get_simplex_vertices(index_t idx, const index_t dim, index_t v, return out; } -std::vector vertices_of_simplex(const index_t simplex_index, const index_t dim, const index_t n, - const binomial_coeff_table& binomial_coeff) { - std::vector vertices; - get_simplex_vertices(simplex_index, dim, n, binomial_coeff, std::back_inserter(vertices)); - return vertices; -} - #ifdef USE_COEFFICIENTS struct __attribute__((packed)) entry_t { index_t index : 8 * (sizeof(index_t) - sizeof(coefficient_t)); @@ -172,10 +161,6 @@ void set_coefficient(index_t& e, const coefficient_t c) {} const entry_t& get_entry(const entry_t& e) { return e; } -template struct smaller_index { - bool operator()(const Entry& a, const Entry& b) { return get_index(a) < get_index(b); } -}; - class diameter_index_t : public std::pair { public: diameter_index_t() : std::pair() {} @@ -211,42 +196,6 @@ template struct greater_diameter_or_smaller_index { } }; -template class rips_filtration_comparator { -public: - const DistanceMatrix& dist; - const index_t dim; - -private: - mutable std::vector vertices; - const binomial_coeff_table& binomial_coeff; - -public: - rips_filtration_comparator(const DistanceMatrix& _dist, const index_t _dim, - const binomial_coeff_table& _binomial_coeff) - : dist(_dist), dim(_dim), vertices(_dim + 1), binomial_coeff(_binomial_coeff){}; - - value_t diameter(const index_t index) const { - value_t diam = 0; - get_simplex_vertices(index, dim, dist.size(), binomial_coeff, vertices.begin()); - - for (index_t i = 0; i <= dim; ++i) - for (index_t j = 0; j < i; ++j) { diam = std::max(diam, dist(vertices[i], vertices[j])); } - return diam; - } - - bool operator()(const index_t a, const index_t b) const { - assert(a < binomial_coeff(dist.size(), dim + 1)); - assert(b < binomial_coeff(dist.size(), dim + 1)); - - return greater_diameter_or_smaller_index()(diameter_index_t(diameter(a), a), - diameter_index_t(diameter(b), b)); - } - - template bool operator()(const Entry& a, const Entry& b) const { - return operator()(get_index(a), get_index(b)); - } -}; - template class simplex_coboundary_enumerator { private: index_t idx_below, idx_above, v, k; @@ -269,7 +218,6 @@ public: while ((v != -1) && (binomial_coeff(v, k) <= idx_below)) { idx_below -= binomial_coeff(v, k); idx_above += binomial_coeff(v, k + 1); - --v; --k; assert(k != -1); @@ -485,216 +433,289 @@ template void push_entry(Heap& column, index_t i, coefficient_t column.push(std::make_pair(diameter, e)); } -template -void assemble_columns_to_reduce(std::vector& columns_to_reduce, - hash_map& pivot_column_index, const Comparator& comp, index_t dim, - index_t n, value_t threshold, const binomial_coeff_table& binomial_coeff) { - index_t num_simplices = binomial_coeff(n, dim + 2); +class ripser { + index_t dim_max, n; + value_t threshold; + const binomial_coeff_table binomial_coeff; + std::vector multiplicative_inverse; + coefficient_t modulus; + compressed_lower_distance_matrix dist; + mutable std::vector vertices; + +public: + ripser(compressed_lower_distance_matrix&& _dist, index_t _dim_max, value_t _threshold, coefficient_t _modulus) + : dist(_dist), n(_dist.size()), dim_max(std::min(_dim_max, index_t(_dist.size() - 2))), threshold(_threshold), + modulus(_modulus), binomial_coeff(n, dim_max + 2), + multiplicative_inverse(multiplicative_inverse_vector(_modulus)) {} + + value_t compute_diameter(const index_t index, index_t dim) const { + value_t diam = 0; + + vertices.clear(); + get_simplex_vertices(index, dim, dist.size(), binomial_coeff, std::back_inserter(vertices)); - columns_to_reduce.clear(); + for (index_t i = 0; i <= dim; ++i) + for (index_t j = 0; j < i; ++j) { diam = std::max(diam, dist(vertices[i], vertices[j])); } + return diam; + } + + void assemble_columns_to_reduce(std::vector& columns_to_reduce, + hash_map& pivot_column_index, index_t dim) { + index_t num_simplices = binomial_coeff(n, dim + 1); + + columns_to_reduce.clear(); #ifdef INDICATE_PROGRESS - std::cout << "\033[K" - << "assembling " << num_simplices << " columns" << std::flush << "\r"; + std::cout << "\033[K" + << "assembling " << num_simplices << " columns" << std::flush << "\r"; #endif - for (index_t index = 0; index < num_simplices; ++index) { - if (pivot_column_index.find(index) == pivot_column_index.end()) { - value_t diameter = comp.diameter(index); - if (diameter <= threshold) columns_to_reduce.push_back(std::make_pair(diameter, index)); + for (index_t index = 0; index < num_simplices; ++index) { + if (pivot_column_index.find(index) == pivot_column_index.end()) { + value_t diameter = compute_diameter(index, dim); + if (diameter <= threshold) columns_to_reduce.push_back(std::make_pair(diameter, index)); #ifdef INDICATE_PROGRESS - if ((index + 1) % 1000 == 0) - std::cout << "\033[K" - << "assembled " << columns_to_reduce.size() << " out of " << (index + 1) << "/" - << num_simplices << " columns" << std::flush << "\r"; + if ((index + 1) % 1000 == 0) + std::cout << "\033[K" + << "assembled " << columns_to_reduce.size() << " out of " << (index + 1) << "/" + << num_simplices << " columns" << std::flush << "\r"; #endif + } } - } #ifdef INDICATE_PROGRESS - std::cout << "\033[K" - << "sorting " << num_simplices << " columns" << std::flush << "\r"; + std::cout << "\033[K" + << "sorting " << num_simplices << " columns" << std::flush << "\r"; #endif - std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), - greater_diameter_or_smaller_index()); + std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), + greater_diameter_or_smaller_index()); #ifdef INDICATE_PROGRESS - std::cout << "\033[K"; + std::cout << "\033[K"; #endif -} + } -template -void compute_pairs(std::vector& columns_to_reduce, hash_map& pivot_column_index, - index_t dim, index_t n, value_t threshold, coefficient_t modulus, - const std::vector& multiplicative_inverse, const DistanceMatrix& dist, - const ComparatorCofaces& comp, const Comparator& comp_prev, - const binomial_coeff_table& binomial_coeff) { + void compute_pairs(std::vector& columns_to_reduce, hash_map& pivot_column_index, + index_t dim) { #ifdef PRINT_PERSISTENCE_PAIRS - std::cout << "persistence intervals in dim " << dim << ":" << std::endl; + std::cout << "persistence intervals in dim " << dim << ":" << std::endl; #endif #ifdef ASSEMBLE_REDUCTION_MATRIX - compressed_sparse_matrix reduction_coefficients; + compressed_sparse_matrix reduction_coefficients; #else #ifdef USE_COEFFICIENTS - std::vector reduction_coefficients; + std::vector reduction_coefficients; #endif #endif - std::vector coface_entries; + std::vector coface_entries; - for (index_t i = 0; i < columns_to_reduce.size(); ++i) { - auto column_to_reduce = columns_to_reduce[i]; + for (index_t i = 0; i < columns_to_reduce.size(); ++i) { + auto column_to_reduce = columns_to_reduce[i]; #ifdef ASSEMBLE_REDUCTION_MATRIX - std::priority_queue, greater_diameter_or_smaller_index> - reduction_column; + std::priority_queue, + greater_diameter_or_smaller_index> + reduction_column; #endif - std::priority_queue, - greater_diameter_or_smaller_index> - working_coboundary; + std::priority_queue, + greater_diameter_or_smaller_index> + working_coboundary; - value_t diameter = get_diameter(column_to_reduce); + value_t diameter = get_diameter(column_to_reduce); #ifdef INDICATE_PROGRESS - if ((i + 1) % 1000 == 0) - std::cout << "\033[K" - << "reducing column " << i + 1 << "/" << columns_to_reduce.size() << " (diameter " << diameter - << ")" << std::flush << "\r"; + if ((i + 1) % 1000 == 0) + std::cout << "\033[K" + << "reducing column " << i + 1 << "/" << columns_to_reduce.size() << " (diameter " << diameter + << ")" << std::flush << "\r"; #endif - index_t j = i; + index_t j = i; - // start with a dummy pivot entry with coefficient -1 in order to initialize - // working_coboundary with the coboundary of the simplex with index column_to_reduce - diameter_entry_t pivot(0, -1, -1 + modulus); + // start with a dummy pivot entry with coefficient -1 in order to initialize + // working_coboundary with the coboundary of the simplex with index column_to_reduce + diameter_entry_t pivot(0, -1, -1 + modulus); #ifdef ASSEMBLE_REDUCTION_MATRIX - // initialize reduction_coefficients as identity matrix - reduction_coefficients.append_column(); + // initialize reduction_coefficients as identity matrix + reduction_coefficients.append_column(); #endif #ifdef USE_COEFFICIENTS - reduction_coefficients.push_back(diameter_entry_t(column_to_reduce, 1)); + reduction_coefficients.push_back(diameter_entry_t(column_to_reduce, 1)); #endif - - bool might_be_apparent_pair = (i == j); - do { - const coefficient_t factor = modulus - get_coefficient(pivot); + bool might_be_apparent_pair = (i == j); + + do { + const coefficient_t factor = modulus - get_coefficient(pivot); #ifdef ASSEMBLE_REDUCTION_MATRIX #ifdef USE_COEFFICIENTS - auto coeffs_begin = reduction_coefficients.cbegin(j), coeffs_end = reduction_coefficients.cend(j); + auto coeffs_begin = reduction_coefficients.cbegin(j), coeffs_end = reduction_coefficients.cend(j); #else - std::vector coeffs(0); - coeffs.push_back(columns_to_reduce[j]); - for (auto it = reduction_coefficients.cbegin(j); it != reduction_coefficients.cend(j); ++it) coeffs.push_back(*it); - auto coeffs_begin = coeffs.begin(), coeffs_end = coeffs.end(); + std::vector coeffs(0); + coeffs.push_back(columns_to_reduce[j]); + for (auto it = reduction_coefficients.cbegin(j); it != reduction_coefficients.cend(j); ++it) + coeffs.push_back(*it); + auto coeffs_begin = coeffs.begin(), coeffs_end = coeffs.end(); #endif #else #ifdef USE_COEFFICIENTS - auto coeffs_begin = &reduction_coefficients[j], coeffs_end = &reduction_coefficients[j] + 1; + auto coeffs_begin = &reduction_coefficients[j], coeffs_end = &reduction_coefficients[j] + 1; #else - auto coeffs_begin = &columns_to_reduce[j], coeffs_end = &columns_to_reduce[j] + 1; + auto coeffs_begin = &columns_to_reduce[j], coeffs_end = &columns_to_reduce[j] + 1; #endif #endif - for (auto it = coeffs_begin; it != coeffs_end; ++it) { - diameter_entry_t simplex = *it; - set_coefficient(simplex, get_coefficient(simplex) * factor % modulus); + for (auto it = coeffs_begin; it != coeffs_end; ++it) { + diameter_entry_t simplex = *it; + set_coefficient(simplex, get_coefficient(simplex) * factor % modulus); #ifdef ASSEMBLE_REDUCTION_MATRIX - reduction_column.push(simplex); -#endif - - coface_entries.clear(); - simplex_coboundary_enumerator cofaces(simplex, dim, n, modulus, dist, binomial_coeff); - while (cofaces.has_next()) { - diameter_entry_t coface = cofaces.next(); - if (get_diameter(coface) <= threshold) { - coface_entries.push_back(coface); - if (might_be_apparent_pair && (get_diameter(simplex) == get_diameter(coface))) { - if (pivot_column_index.find(get_index(coface)) == pivot_column_index.end()) { - pivot = coface; - goto found_persistence_pair; + reduction_column.push(simplex); +#endif + + coface_entries.clear(); + simplex_coboundary_enumerator cofaces(simplex, dim, n, modulus, dist, + binomial_coeff); + while (cofaces.has_next()) { + diameter_entry_t coface = cofaces.next(); + if (get_diameter(coface) <= threshold) { + coface_entries.push_back(coface); + if (might_be_apparent_pair && (get_diameter(simplex) == get_diameter(coface))) { + if (pivot_column_index.find(get_index(coface)) == pivot_column_index.end()) { + pivot = coface; + goto found_persistence_pair; + } + might_be_apparent_pair = false; } - might_be_apparent_pair = false; } } + for (auto coface : coface_entries) working_coboundary.push(coface); } - for (auto coface : coface_entries) working_coboundary.push(coface); - } - pivot = get_pivot(working_coboundary, modulus); + pivot = get_pivot(working_coboundary, modulus); - if (get_index(pivot) != -1) { - auto pair = pivot_column_index.find(get_index(pivot)); + if (get_index(pivot) != -1) { + auto pair = pivot_column_index.find(get_index(pivot)); - if (pair != pivot_column_index.end()) { - j = pair->second; - continue; - } - } else { + if (pair != pivot_column_index.end()) { + j = pair->second; + continue; + } + } else { #ifdef PRINT_PERSISTENCE_PAIRS #ifdef INDICATE_PROGRESS - std::cout << "\033[K"; + std::cout << "\033[K"; #endif - std::cout << " [" << diameter << ", )" << std::endl << std::flush; + std::cout << " [" << diameter << ", )" << std::endl << std::flush; #endif - break; - } + break; + } - found_persistence_pair: + found_persistence_pair: #ifdef PRINT_PERSISTENCE_PAIRS - value_t death = get_diameter(pivot); - if (diameter != death) { + value_t death = get_diameter(pivot); + if (diameter != death) { #ifdef INDICATE_PROGRESS - std::cout << "\033[K"; + std::cout << "\033[K"; #endif - std::cout << " [" << diameter << "," << death << ")" << std::endl << std::flush; - } + std::cout << " [" << diameter << "," << death << ")" << std::endl << std::flush; + } #endif - pivot_column_index.insert(std::make_pair(get_index(pivot), i)); + pivot_column_index.insert(std::make_pair(get_index(pivot), i)); #ifdef USE_COEFFICIENTS - const coefficient_t inverse = multiplicative_inverse[get_coefficient(pivot)]; + const coefficient_t inverse = multiplicative_inverse[get_coefficient(pivot)]; #endif #ifdef ASSEMBLE_REDUCTION_MATRIX - // replace current column of reduction_coefficients (with a single diagonal 1 entry) - // by reduction_column (possibly with a different entry on the diagonal) +// replace current column of reduction_coefficients (with a single diagonal 1 entry) +// by reduction_column (possibly with a different entry on the diagonal) #ifdef USE_COEFFICIENTS - reduction_coefficients.pop_back(); + reduction_coefficients.pop_back(); #else - pop_pivot(reduction_column, modulus); + pop_pivot(reduction_column, modulus); #endif - - while (true) { - diameter_entry_t e = pop_pivot(reduction_column, modulus); - if (get_index(e) == -1) break; + + while (true) { + diameter_entry_t e = pop_pivot(reduction_column, modulus); + if (get_index(e) == -1) break; #ifdef USE_COEFFICIENTS - set_coefficient(e, inverse * get_coefficient(e) % modulus); - assert(get_coefficient(e) > 0); + set_coefficient(e, inverse * get_coefficient(e) % modulus); + assert(get_coefficient(e) > 0); #endif - reduction_coefficients.push_back(e); - } + reduction_coefficients.push_back(e); + } #else #ifdef USE_COEFFICIENTS - reduction_coefficients.pop_back(); - reduction_coefficients.push_back(diameter_entry_t(column_to_reduce, inverse)); + reduction_coefficients.pop_back(); + reduction_coefficients.push_back(diameter_entry_t(column_to_reduce, inverse)); #endif #endif - break; - } while (true); - } + break; + } while (true); + } #ifdef INDICATE_PROGRESS - std::cout << "\033[K"; + std::cout << "\033[K"; #endif -} + } + + void compute_barcodes() { + + std::vector columns_to_reduce; + + { + union_find dset(n); + std::vector edges; + for (index_t index = binomial_coeff(n, 2); index-- > 0;) { + value_t diameter = compute_diameter(index, 1); + if (diameter <= threshold) edges.push_back(std::make_pair(diameter, index)); + } + std::sort(edges.rbegin(), edges.rend(), greater_diameter_or_smaller_index()); + +#ifdef PRINT_PERSISTENCE_PAIRS + std::cout << "persistence intervals in dim 0:" << std::endl; +#endif + + std::vector vertices_of_edge(2); + for (auto e : edges) { + vertices_of_edge.clear(); + get_simplex_vertices(get_index(e), 1, n, binomial_coeff, std::back_inserter(vertices_of_edge)); + index_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]); + + if (u != v) { +#ifdef PRINT_PERSISTENCE_PAIRS + if (get_diameter(e) > 0) std::cout << " [0," << get_diameter(e) << ")" << std::endl; +#endif + dset.link(u, v); + } else + columns_to_reduce.push_back(e); + } + std::reverse(columns_to_reduce.begin(), columns_to_reduce.end()); + +#ifdef PRINT_PERSISTENCE_PAIRS + for (index_t i = 0; i < n; ++i) + if (dset.find(i) == i) std::cout << " [0, )" << std::endl << std::flush; +#endif + } + + for (index_t dim = 1; dim <= dim_max; ++dim) { + hash_map pivot_column_index; + pivot_column_index.reserve(columns_to_reduce.size()); + + compute_pairs(columns_to_reduce, pivot_column_index, dim); + + if (dim < dim_max) { assemble_columns_to_reduce(columns_to_reduce, pivot_column_index, dim + 1); } + } + } +}; enum file_format { LOWER_DISTANCE_MATRIX, UPPER_DISTANCE_MATRIX, DISTANCE_MATRIX, POINT_CLOUD, DIPHA, RIPSER }; @@ -911,68 +932,10 @@ int main(int argc, char** argv) { compressed_lower_distance_matrix dist = read_file(filename ? file_stream : std::cin, format); - index_t n = dist.size(); - - std::cout << "distance matrix with " << n << " points" << std::endl; + std::cout << "distance matrix with " << dist.size() << " points" << std::endl; auto value_range = std::minmax_element(dist.distances.begin(), dist.distances.end()); std::cout << "value range: [" << *value_range.first << "," << *value_range.second << "]" << std::endl; - dim_max = std::min(dim_max, n - 2); - - binomial_coeff_table binomial_coeff(n, dim_max + 2); - std::vector multiplicative_inverse(multiplicative_inverse_vector(modulus)); - - std::vector columns_to_reduce; - - { - union_find dset(n); - std::vector edges; - rips_filtration_comparator comp(dist, 1, binomial_coeff); - for (index_t index = binomial_coeff(n, 2); index-- > 0;) { - value_t diameter = comp.diameter(index); - if (diameter <= threshold) edges.push_back(std::make_pair(diameter, index)); - } - std::sort(edges.rbegin(), edges.rend(), greater_diameter_or_smaller_index()); - -#ifdef PRINT_PERSISTENCE_PAIRS - std::cout << "persistence intervals in dim 0:" << std::endl; -#endif - - std::vector vertices_of_edge(2); - for (auto e : edges) { - vertices_of_edge.clear(); - get_simplex_vertices(get_index(e), 1, n, binomial_coeff, std::back_inserter(vertices_of_edge)); - index_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]); - - if (u != v) { -#ifdef PRINT_PERSISTENCE_PAIRS - if (get_diameter(e) > 0) std::cout << " [0," << get_diameter(e) << ")" << std::endl; -#endif - dset.link(u, v); - } else - columns_to_reduce.push_back(e); - } - std::reverse(columns_to_reduce.begin(), columns_to_reduce.end()); - -#ifdef PRINT_PERSISTENCE_PAIRS - for (index_t i = 0; i < n; ++i) - if (dset.find(i) == i) std::cout << " [0, )" << std::endl << std::flush; -#endif - } - - for (index_t dim = 1; dim <= dim_max; ++dim) { - rips_filtration_comparator comp(dist, dim + 1, binomial_coeff); - rips_filtration_comparator comp_prev(dist, dim, binomial_coeff); - - hash_map pivot_column_index; - pivot_column_index.reserve(columns_to_reduce.size()); - - compute_pairs(columns_to_reduce, pivot_column_index, dim, n, threshold, modulus, multiplicative_inverse, dist, - comp, comp_prev, binomial_coeff); - - if (dim < dim_max) { - assemble_columns_to_reduce(columns_to_reduce, pivot_column_index, comp, dim, n, threshold, binomial_coeff); - } - } + ripser(std::move(dist), dim_max, threshold, modulus).compute_barcodes(); } -- cgit v1.2.3 From f177efa1b4ceac3cc72a3702ebc1dd508559dcd5 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Sat, 26 Nov 2016 17:20:59 -0500 Subject: more code reorganization --- ripser.cpp | 145 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 71 insertions(+), 74 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index dc6b1bd..6209730 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -94,35 +94,6 @@ std::vector multiplicative_inverse_vector(const coefficient_t m) return inverse; } -index_t get_next_vertex(index_t& v, const index_t idx, const index_t k, const binomial_coeff_table& binomial_coeff) { - if (binomial_coeff(v, k) > idx) { - index_t count = v; - while (count > 0) { - index_t i = v; - index_t step = count >> 1; - i -= step; - if (binomial_coeff(i, k) > idx) { - v = --i; - count -= step + 1; - } else - count = step; - } - } - assert(binomial_coeff(v, k) <= idx && binomial_coeff(v + 1, k) > idx); - return v; -} - -template -OutputIterator get_simplex_vertices(index_t idx, const index_t dim, index_t v, - const binomial_coeff_table& binomial_coeff, OutputIterator out) { - --v; - for (index_t k = dim + 1; k > 0; --k) { - get_next_vertex(v, idx, k, binomial_coeff); - *out++ = v; - idx -= binomial_coeff(v, k); - } - return out; -} #ifdef USE_COEFFICIENTS struct __attribute__((packed)) entry_t { @@ -196,46 +167,6 @@ template struct greater_diameter_or_smaller_index { } }; -template class simplex_coboundary_enumerator { -private: - index_t idx_below, idx_above, v, k; - std::vector vertices; - const diameter_entry_t simplex; - const coefficient_t modulus; - const DistanceMatrix& dist; - const binomial_coeff_table& binomial_coeff; - -public: - simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, index_t _n, - const coefficient_t _modulus, const DistanceMatrix& _dist, - const binomial_coeff_table& _binomial_coeff) - : simplex(_simplex), idx_below(get_index(_simplex)), idx_above(0), v(_n - 1), k(_dim + 1), modulus(_modulus), - binomial_coeff(_binomial_coeff), dist(_dist), vertices(_dim + 1) { - get_simplex_vertices(get_index(_simplex), _dim, _n, binomial_coeff, vertices.begin()); - } - - bool has_next() { - while ((v != -1) && (binomial_coeff(v, k) <= idx_below)) { - idx_below -= binomial_coeff(v, k); - idx_above += binomial_coeff(v, k + 1); - --v; - --k; - assert(k != -1); - } - return v != -1; - } - - index_t next_index() { return idx_above + binomial_coeff(v--, k + 1) + idx_below; } - - diameter_entry_t next() { - value_t coface_diameter = get_diameter(simplex); - for (index_t w : vertices) coface_diameter = std::max(coface_diameter, dist(v, w)); - coefficient_t coface_coefficient = (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; - return diameter_entry_t(coface_diameter, idx_above + binomial_coeff(v--, k + 1) + idx_below, - coface_coefficient); - } -}; - enum compressed_matrix_layout { LOWER_TRIANGULAR, UPPER_TRIANGULAR }; template class compressed_distance_matrix { @@ -447,17 +378,84 @@ public: : dist(_dist), n(_dist.size()), dim_max(std::min(_dim_max, index_t(_dist.size() - 2))), threshold(_threshold), modulus(_modulus), binomial_coeff(n, dim_max + 2), multiplicative_inverse(multiplicative_inverse_vector(_modulus)) {} - + + index_t get_next_vertex(index_t& v, const index_t idx, const index_t k) const { + if (binomial_coeff(v, k) > idx) { + index_t count = v; + while (count > 0) { + index_t i = v; + index_t step = count >> 1; + i -= step; + if (binomial_coeff(i, k) > idx) { + v = --i; + count -= step + 1; + } else + count = step; + } + } + assert(binomial_coeff(v, k) <= idx && binomial_coeff(v + 1, k) > idx); + return v; + } + + template + OutputIterator get_simplex_vertices(index_t idx, const index_t dim, index_t v, + OutputIterator out) const { + --v; + for (index_t k = dim + 1; k > 0; --k) { + get_next_vertex(v, idx, k); + *out++ = v; + idx -= binomial_coeff(v, k); + } + return out; + } + value_t compute_diameter(const index_t index, index_t dim) const { value_t diam = 0; vertices.clear(); - get_simplex_vertices(index, dim, dist.size(), binomial_coeff, std::back_inserter(vertices)); + get_simplex_vertices(index, dim, dist.size(), std::back_inserter(vertices)); for (index_t i = 0; i <= dim; ++i) for (index_t j = 0; j < i; ++j) { diam = std::max(diam, dist(vertices[i], vertices[j])); } return diam; } + + class simplex_coboundary_enumerator { + private: + index_t idx_below, idx_above, v, k; + std::vector vertices; + const diameter_entry_t simplex; + const coefficient_t modulus; + const compressed_lower_distance_matrix& dist; + const binomial_coeff_table& binomial_coeff; + + public: + simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, const ripser& parent) + : simplex(_simplex), idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), k(_dim + 1), modulus(parent.modulus), + binomial_coeff(parent.binomial_coeff), dist(parent.dist), vertices(_dim + 1) { + parent.get_simplex_vertices(get_index(_simplex), _dim, parent.n, vertices.begin()); + } + + bool has_next() { + while ((v != -1) && (binomial_coeff(v, k) <= idx_below)) { + idx_below -= binomial_coeff(v, k); + idx_above += binomial_coeff(v, k + 1); + --v; + --k; + assert(k != -1); + } + return v != -1; + } + + diameter_entry_t next() { + value_t coface_diameter = get_diameter(simplex); + for (index_t w : vertices) coface_diameter = std::max(coface_diameter, dist(v, w)); + index_t coface_index = idx_above + binomial_coeff(v--, k + 1) + idx_below; + coefficient_t coface_coefficient = (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; + return diameter_entry_t(coface_diameter, coface_index, coface_coefficient); + } + }; + void assemble_columns_to_reduce(std::vector& columns_to_reduce, hash_map& pivot_column_index, index_t dim) { @@ -580,8 +578,7 @@ public: #endif coface_entries.clear(); - simplex_coboundary_enumerator cofaces(simplex, dim, n, modulus, dist, - binomial_coeff); + simplex_coboundary_enumerator cofaces(simplex, dim, *this); while (cofaces.has_next()) { diameter_entry_t coface = cofaces.next(); if (get_diameter(coface) <= threshold) { @@ -687,7 +684,7 @@ public: std::vector vertices_of_edge(2); for (auto e : edges) { vertices_of_edge.clear(); - get_simplex_vertices(get_index(e), 1, n, binomial_coeff, std::back_inserter(vertices_of_edge)); + get_simplex_vertices(get_index(e), 1, n, std::back_inserter(vertices_of_edge)); index_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]); if (u != v) { -- cgit v1.2.3 From eb8c26dc3bad09678290c58d3637cb8336a37704 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Sat, 26 Nov 2016 18:16:27 -0500 Subject: cleanup binomial coefficients --- ripser.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 6209730..72e784c 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -52,27 +52,20 @@ typedef int16_t coefficient_t; class binomial_coeff_table { std::vector> B; - index_t n_max, k_max; - public: - binomial_coeff_table(index_t n, index_t k) { - n_max = n; - k_max = k; - - B.resize(n + 1); + binomial_coeff_table(index_t n, index_t k) : B(n + 1) { for (index_t i = 0; i <= n; i++) { B[i].resize(k + 1); - for (index_t j = 0; j <= std::min(i, k); j++) { + for (index_t j = 0; j <= std::min(i, k); j++) if (j == 0 || j == i) B[i][j] = 1; else B[i][j] = B[i - 1][j - 1] + B[i - 1][j]; - } } } index_t operator()(index_t n, index_t k) const { - assert(n <= n_max && k <= k_max); + assert(n < B.size() && k < B[n].size()); return B[n][k]; } }; -- cgit v1.2.3 From 8521d24c4584a6eb1149a604309ffa987862414f Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Mon, 28 Nov 2016 14:13:46 -0500 Subject: allow for negative edge filtration values --- ripser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 72e784c..efa672e 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -403,7 +403,7 @@ public: } value_t compute_diameter(const index_t index, index_t dim) const { - value_t diam = 0; + value_t diam = -std::numeric_limits::infinity(); vertices.clear(); get_simplex_vertices(index, dim, dist.size(), std::back_inserter(vertices)); @@ -682,7 +682,7 @@ public: if (u != v) { #ifdef PRINT_PERSISTENCE_PAIRS - if (get_diameter(e) > 0) std::cout << " [0," << get_diameter(e) << ")" << std::endl; + if (get_diameter(e) != 0) std::cout << " [0," << get_diameter(e) << ")" << std::endl; #endif dset.link(u, v); } else -- cgit v1.2.3 From c9596839245779792ddf7c8235ab96feecc8aeb8 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Wed, 30 Nov 2016 14:42:47 -0500 Subject: fix for missing constructor of diameter_entry_t --- ripser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ripser.cpp b/ripser.cpp index efa672e..403516b 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -548,7 +548,7 @@ public: #ifdef USE_COEFFICIENTS auto coeffs_begin = reduction_coefficients.cbegin(j), coeffs_end = reduction_coefficients.cend(j); #else - std::vector coeffs(0); + std::vector coeffs; coeffs.push_back(columns_to_reduce[j]); for (auto it = reduction_coefficients.cbegin(j); it != reduction_coefficients.cend(j); ++it) coeffs.push_back(*it); -- cgit v1.2.3 From c86c7fc1620363b4a78699c88644d5d8c6051379 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Wed, 30 Nov 2016 17:46:00 -0500 Subject: cleanup --- ripser.cpp | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 270f8b9..a66e8e6 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -137,6 +137,8 @@ index_t get_index(diameter_index_t i) { return i.second; } class diameter_entry_t : public std::pair { public: diameter_entry_t(std::pair p) : std::pair(p) {} + diameter_entry_t(entry_t e) : std::pair(0, e) {} + diameter_entry_t() : diameter_entry_t(0) {} diameter_entry_t(value_t _diameter, index_t _index, coefficient_t _coefficient) : std::pair(_diameter, make_entry(_index, _coefficient)) {} diameter_entry_t(diameter_index_t _diameter_index, coefficient_t _coefficient) @@ -203,14 +205,6 @@ public: size_t size() const { return neighbors.size(); } }; -template struct second_argument_greater { - bool operator()(const T& lhs, const T& rhs) const { return lhs.second > rhs.second; } -}; - -template struct second_argument_equal_to { - bool operator()(const T& lhs, const T& rhs) const { return lhs.second == rhs.second; } -}; - template <> void compressed_distance_matrix::init_rows() { value_t* pointer = &distances[0]; for (index_t i = 1; i < size(); ++i) { @@ -494,16 +488,16 @@ public: return out; } -// value_t compute_diameter(const index_t index, index_t dim) const { -// value_t diam = -std::numeric_limits::infinity(); -// -// vertices.clear(); -// get_simplex_vertices(index, dim, sparse_dist.size(), std::back_inserter(vertices)); -// -// for (index_t i = 0; i <= dim; ++i) -// for (index_t j = 0; j < i; ++j) { diam = std::max(diam, sparse_dist(vertices[i], vertices[j])); } -// return diam; -// } + value_t compute_diameter(const index_t index, index_t dim) const { + value_t diam = -std::numeric_limits::infinity(); + + vertices.clear(); + get_simplex_vertices(index, dim, sparse_dist.size(), std::back_inserter(vertices)); + + for (index_t i = 0; i <= dim; ++i) + for (index_t j = 0; j < i; ++j) { diam = std::max(diam, dist(vertices[i], vertices[j])); } + return diam; + } void assemble_columns_to_reduce(std::vector& simplices, std::vector& columns_to_reduce, -- cgit v1.2.3 From 117088b16d9abe1ca18a909568bd71e377782ff4 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Wed, 30 Nov 2016 18:22:01 -0500 Subject: speedup coboundary enumeration --- ripser.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index a66e8e6..aa2d438 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -381,7 +381,10 @@ class ripser { coefficient_t modulus; compressed_lower_distance_matrix dist; sparse_distance_matrix sparse_dist; + mutable std::vector vertices; + mutable std::vector::const_reverse_iterator> ii; + mutable std::vector::const_reverse_iterator> ee; public: ripser(compressed_lower_distance_matrix&& _dist,sparse_distance_matrix&& _sparse_dist, index_t _dim_max, value_t _threshold, coefficient_t _modulus) @@ -400,9 +403,11 @@ public: const sparse_distance_matrix& sparse_dist; const binomial_coeff_table& binomial_coeff; - std::vector vertices; + std::vector& vertices; - std::vector::const_reverse_iterator> ii, ee; + std::vector::const_reverse_iterator>& ii; + std::vector::const_reverse_iterator>& ee; + diameter_index_t x; @@ -410,7 +415,12 @@ public: public: simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, const ripser& _parent) : parent(_parent), simplex(_simplex), idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), k(_dim + 1), - max_vertex_below(parent.n - 1), modulus(parent.modulus), sparse_dist(parent.sparse_dist), binomial_coeff(parent.binomial_coeff) { + max_vertex_below(parent.n - 1), modulus(parent.modulus), sparse_dist(parent.sparse_dist), binomial_coeff(parent.binomial_coeff), vertices(parent.vertices), ii(parent.ii), ee(parent.ee) { + + ii.clear(); + ee.clear(); + vertices.clear(); + parent.get_simplex_vertices(idx_below, _dim, parent.n, std::back_inserter(vertices)); for (auto v : vertices) { -- cgit v1.2.3 From 63c3ae66f90bbf4ef295433b02d8dd10072bcf6d Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Wed, 30 Nov 2016 19:23:17 -0500 Subject: use only sparse distance matrix --- ripser.cpp | 156 +++++++++++++++++++++++++++---------------------------------- 1 file changed, 68 insertions(+), 88 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index aa2d438..01e587b 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -52,6 +52,7 @@ typedef int16_t coefficient_t; class binomial_coeff_table { std::vector> B; + public: binomial_coeff_table(index_t n, index_t k) : B(n + 1) { for (index_t i = 0; i <= n; i++) { @@ -87,7 +88,6 @@ std::vector multiplicative_inverse_vector(const coefficient_t m) return inverse; } - #ifdef USE_COEFFICIENTS struct __attribute__((packed)) entry_t { index_t index : 8 * (sizeof(index_t) - sizeof(coefficient_t)); @@ -379,22 +379,20 @@ class ripser { const binomial_coeff_table binomial_coeff; std::vector multiplicative_inverse; coefficient_t modulus; - compressed_lower_distance_matrix dist; sparse_distance_matrix sparse_dist; - + mutable std::vector vertices; mutable std::vector::const_reverse_iterator> ii; mutable std::vector::const_reverse_iterator> ee; public: - ripser(compressed_lower_distance_matrix&& _dist,sparse_distance_matrix&& _sparse_dist, index_t _dim_max, value_t _threshold, coefficient_t _modulus) - : dist(_dist), sparse_dist(_sparse_dist), n(_sparse_dist.size()), dim_max(std::min(_dim_max, index_t(_sparse_dist.size() - 2))), threshold(_threshold), - modulus(_modulus), binomial_coeff(n, dim_max + 2), - multiplicative_inverse(multiplicative_inverse_vector(_modulus)) {} - + ripser(sparse_distance_matrix&& _sparse_dist, index_t _dim_max, value_t _threshold, coefficient_t _modulus) + : sparse_dist(_sparse_dist), n(_sparse_dist.size()), + dim_max(std::min(_dim_max, index_t(_sparse_dist.size() - 2))), threshold(_threshold), modulus(_modulus), + binomial_coeff(n, dim_max + 2), multiplicative_inverse(multiplicative_inverse_vector(_modulus)) {} + class simplex_coboundary_enumerator { private: - const ripser& parent; index_t idx_below, idx_above, v, k, max_vertex_below; @@ -404,31 +402,28 @@ public: const binomial_coeff_table& binomial_coeff; std::vector& vertices; - std::vector::const_reverse_iterator>& ii; std::vector::const_reverse_iterator>& ee; - - diameter_index_t x; - - + public: simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, const ripser& _parent) - : parent(_parent), simplex(_simplex), idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), k(_dim + 1), - max_vertex_below(parent.n - 1), modulus(parent.modulus), sparse_dist(parent.sparse_dist), binomial_coeff(parent.binomial_coeff), vertices(parent.vertices), ii(parent.ii), ee(parent.ee) { - + : parent(_parent), simplex(_simplex), idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), + k(_dim + 1), max_vertex_below(parent.n - 1), modulus(parent.modulus), sparse_dist(parent.sparse_dist), + binomial_coeff(parent.binomial_coeff), vertices(parent.vertices), ii(parent.ii), ee(parent.ee) { + ii.clear(); ee.clear(); vertices.clear(); - + parent.get_simplex_vertices(idx_below, _dim, parent.n, std::back_inserter(vertices)); - + for (auto v : vertices) { ii.push_back(sparse_dist.neighbors[v].rbegin()); ee.push_back(sparse_dist.neighbors[v].rend()); } } - + bool has_next(bool all_cofaces = true) { for (auto &it0 = ii[0], &end0 = ee[0]; it0 != end0; ++it0) { x = *it0; @@ -440,34 +435,32 @@ public: if (get_index(y) != get_index(x)) goto continue_outer; else - x = std::min(x, y, greater_diameter_or_smaller_index()); + x = std::max(x, y); } - return all_cofaces || - !(k > 0 && parent.get_next_vertex(max_vertex_below, idx_below, k) > get_index(x)); + return all_cofaces || !(k > 0 && parent.get_next_vertex(max_vertex_below, idx_below, k) > get_index(x)); continue_outer:; } return false; } - + diameter_entry_t next() { ++ii[0]; - + while (k > 0 && parent.get_next_vertex(max_vertex_below, idx_below, k) > get_index(x)) { idx_below -= binomial_coeff(max_vertex_below, k); idx_above += binomial_coeff(max_vertex_below, k + 1); --k; } - + value_t coface_diameter = std::max(get_diameter(simplex), get_diameter(x)); - + coefficient_t coface_coefficient = (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; - + return diameter_entry_t(coface_diameter, idx_above + binomial_coeff(get_index(x), k + 1) + idx_below, - coface_coefficient); + coface_coefficient); } }; - index_t get_next_vertex(index_t& v, const index_t idx, const index_t k) const { if (binomial_coeff(v, k) > idx) { index_t count = v; @@ -485,10 +478,11 @@ public: assert(binomial_coeff(v, k) <= idx && binomial_coeff(v + 1, k) > idx); return v; } - + + index_t get_edge_index(const index_t i, const index_t j) const { return binomial_coeff(i, 2) + j; } + template - OutputIterator get_simplex_vertices(index_t idx, const index_t dim, index_t v, - OutputIterator out) const { + OutputIterator get_simplex_vertices(index_t idx, const index_t dim, index_t v, OutputIterator out) const { --v; for (index_t k = dim + 1; k > 0; --k) { get_next_vertex(v, idx, k); @@ -497,57 +491,46 @@ public: } return out; } - - value_t compute_diameter(const index_t index, index_t dim) const { - value_t diam = -std::numeric_limits::infinity(); - vertices.clear(); - get_simplex_vertices(index, dim, sparse_dist.size(), std::back_inserter(vertices)); - - for (index_t i = 0; i <= dim; ++i) - for (index_t j = 0; j < i; ++j) { diam = std::max(diam, dist(vertices[i], vertices[j])); } - return diam; - } - -void assemble_columns_to_reduce(std::vector& simplices, - std::vector& columns_to_reduce, - hash_map& pivot_column_index, index_t dim) { + void assemble_columns_to_reduce(std::vector& simplices, + std::vector& columns_to_reduce, + hash_map& pivot_column_index, index_t dim) { #ifdef INDICATE_PROGRESS - std::cout << "\033[K" - << "assembling columns" << std::flush << "\r"; + std::cout << "\033[K" + << "assembling columns" << std::flush << "\r"; #endif - columns_to_reduce.clear(); + columns_to_reduce.clear(); - std::vector next_simplices; + std::vector next_simplices; - for (diameter_index_t simplex : simplices) { - simplex_coboundary_enumerator cofaces(simplex, dim, *this); + for (diameter_index_t simplex : simplices) { + simplex_coboundary_enumerator cofaces(simplex, dim, *this); - while (cofaces.has_next(false)) { - auto coface = cofaces.next(); + while (cofaces.has_next(false)) { + auto coface = cofaces.next(); - next_simplices.push_back(std::make_pair(get_diameter(coface), get_index(coface))); + next_simplices.push_back(std::make_pair(get_diameter(coface), get_index(coface))); - if (pivot_column_index.find(get_index(coface)) == pivot_column_index.end()) - columns_to_reduce.push_back(std::make_pair(get_diameter(coface), get_index(coface))); + if (pivot_column_index.find(get_index(coface)) == pivot_column_index.end()) + columns_to_reduce.push_back(std::make_pair(get_diameter(coface), get_index(coface))); + } } - } - simplices.swap(next_simplices); + simplices.swap(next_simplices); #ifdef INDICATE_PROGRESS - std::cout << "\033[K" - << "sorting " << columns_to_reduce.size() << " columns" << std::flush << "\r"; + std::cout << "\033[K" + << "sorting " << columns_to_reduce.size() << " columns" << std::flush << "\r"; #endif - std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), - greater_diameter_or_smaller_index()); + std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), + greater_diameter_or_smaller_index()); #ifdef INDICATE_PROGRESS - std::cout << "\033[K"; + std::cout << "\033[K"; #endif -} + } void compute_pairs(std::vector& columns_to_reduce, hash_map& pivot_column_index, index_t dim) { @@ -723,29 +706,30 @@ void assemble_columns_to_reduce(std::vector& simplices, void compute_barcodes() { std::vector columns_to_reduce; - + std::vector simplices, &edges = simplices; - - for (index_t e = 0; e < dist.distances.size(); ++e) { - value_t diameter = dist.distances[e]; - if (diameter <= threshold) edges.push_back(std::make_pair(diameter, e)); - } - + + for (index_t i = 0; i < n; ++i) + for (auto n : sparse_dist.neighbors[i]) { + index_t j = get_index(n); + if (i > j) edges.push_back(std::make_pair(get_diameter(n), get_edge_index(i, j))); + } + std::sort(edges.rbegin(), edges.rend(), greater_diameter_or_smaller_index()); - + { union_find dset(n); - + #ifdef PRINT_PERSISTENCE_PAIRS std::cout << "persistence intervals in dim 0:" << std::endl; #endif - + std::vector vertices_of_edge(2); for (auto e : edges) { vertices_of_edge.clear(); get_simplex_vertices(get_index(e), 1, n, std::back_inserter(vertices_of_edge)); index_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]); - + if (u != v) { #ifdef PRINT_PERSISTENCE_PAIRS if (get_diameter(e) > 0) std::cout << " [0," << get_diameter(e) << ")" << std::endl; @@ -755,24 +739,21 @@ void assemble_columns_to_reduce(std::vector& simplices, columns_to_reduce.push_back(e); } std::reverse(columns_to_reduce.begin(), columns_to_reduce.end()); - + #ifdef PRINT_PERSISTENCE_PAIRS for (index_t i = 0; i < n; ++i) if (dset.find(i) == i) std::cout << " [0, )" << std::endl << std::flush; #endif } - + for (index_t dim = 1; dim <= dim_max; ++dim) { hash_map pivot_column_index; pivot_column_index.reserve(columns_to_reduce.size()); - + compute_pairs(columns_to_reduce, pivot_column_index, dim); - - if (dim < dim_max) { - assemble_columns_to_reduce(simplices, columns_to_reduce, pivot_column_index, dim); - } + + if (dim < dim_max) { assemble_columns_to_reduce(simplices, columns_to_reduce, pivot_column_index, dim); } } - } }; @@ -995,9 +976,8 @@ int main(int argc, char** argv) { auto value_range = std::minmax_element(dist.distances.begin(), dist.distances.end()); std::cout << "value range: [" << *value_range.first << "," << *value_range.second << "]" << std::endl; - + sparse_distance_matrix sparse_dist(dist, threshold); - - ripser(std::move(dist), std::move(sparse_dist), dim_max, threshold, modulus).compute_barcodes(); + ripser(std::move(sparse_dist), dim_max, threshold, modulus).compute_barcodes(); } -- cgit v1.2.3 From d32402d37998dd0d2c24be8e5a139ebc525a0a56 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Mon, 5 Dec 2016 10:51:16 +0100 Subject: fixed move constructor --- ripser.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 403516b..aad196d 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -170,7 +170,7 @@ public: void init_rows(); compressed_distance_matrix(std::vector&& _distances) - : distances(_distances), rows((1 + std::sqrt(1 + 8 * distances.size())) / 2) { + : distances(std::move(_distances)), rows((1 + std::sqrt(1 + 8 * distances.size())) / 2) { assert(distances.size() == size() * (size() - 1) / 2); init_rows(); } @@ -222,7 +222,7 @@ class euclidean_distance_matrix { public: std::vector> points; - euclidean_distance_matrix(std::vector>&& _points) : points(_points) {} + euclidean_distance_matrix(std::vector>&& _points) : points(std::move(_points)) {} value_t operator()(const index_t i, const index_t j) const { return std::sqrt(std::inner_product(points[i].begin(), points[i].end(), points[j].begin(), value_t(), @@ -358,17 +358,17 @@ template void push_entry(Heap& column, index_t i, coefficient_t } class ripser { + compressed_lower_distance_matrix dist; index_t dim_max, n; value_t threshold; + coefficient_t modulus; const binomial_coeff_table binomial_coeff; std::vector multiplicative_inverse; - coefficient_t modulus; - compressed_lower_distance_matrix dist; mutable std::vector vertices; public: ripser(compressed_lower_distance_matrix&& _dist, index_t _dim_max, value_t _threshold, coefficient_t _modulus) - : dist(_dist), n(_dist.size()), dim_max(std::min(_dim_max, index_t(_dist.size() - 2))), threshold(_threshold), + : dist(std::move(_dist)), dim_max(std::min(_dim_max, index_t(dist.size() - 2))), n(dist.size()), threshold(_threshold), modulus(_modulus), binomial_coeff(n, dim_max + 2), multiplicative_inverse(multiplicative_inverse_vector(_modulus)) {} -- cgit v1.2.3 From 8b42fb2a7885b0e371ff6b0e1bbe31332ae63adb Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Sat, 17 Dec 2016 14:05:20 +0100 Subject: cleanup compressed distance matrix access --- ripser.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index aad196d..0f9d02f 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -206,13 +206,11 @@ template <> void compressed_distance_matrix::init_rows() { } template <> value_t compressed_distance_matrix::operator()(index_t i, index_t j) const { - if (i > j) std::swap(i, j); - return i == j ? 0 : rows[i][j]; + return i == j ? 0 : i > j ? rows[j][i] : rows[i][j]; } template <> value_t compressed_distance_matrix::operator()(index_t i, index_t j) const { - if (i > j) std::swap(i, j); - return i == j ? 0 : rows[j][i]; + return i == j ? 0 : i < j ? rows[j][i] : rows[i][j]; } typedef compressed_distance_matrix compressed_lower_distance_matrix; -- cgit v1.2.3 From f1af637b5d3552472e63a6715ea073540871bf65 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Wed, 28 Dec 2016 14:32:21 +0100 Subject: code cleanup --- ripser.cpp | 126 ++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 66 insertions(+), 60 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 01e587b..ec06d05 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -24,6 +24,8 @@ with this program. If not, see . //#define INDICATE_PROGRESS #define PRINT_PERSISTENCE_PAIRS +#define SPARSE_DISTANCE_MATRIX + //#define USE_GOOGLE_HASHMAP #include @@ -52,7 +54,6 @@ typedef int16_t coefficient_t; class binomial_coeff_table { std::vector> B; - public: binomial_coeff_table(index_t n, index_t k) : B(n + 1) { for (index_t i = 0; i <= n; i++) { @@ -129,7 +130,6 @@ class diameter_index_t : public std::pair { public: diameter_index_t() : std::pair() {} diameter_index_t(std::pair p) : std::pair(p) {} - diameter_index_t(index_t i) : std::pair(0, i) {} }; value_t get_diameter(diameter_index_t i) { return i.first; } index_t get_index(diameter_index_t i) { return i.second; } @@ -379,51 +379,88 @@ class ripser { const binomial_coeff_table binomial_coeff; std::vector multiplicative_inverse; coefficient_t modulus; +#ifdef SPARSE_DISTANCE_MATRIX sparse_distance_matrix sparse_dist; - +#else + compressed_lower_distance_matrix dist; +#endif mutable std::vector vertices; +#ifdef SPARSE_DISTANCE_MATRIX mutable std::vector::const_reverse_iterator> ii; mutable std::vector::const_reverse_iterator> ee; - +#endif + public: ripser(sparse_distance_matrix&& _sparse_dist, index_t _dim_max, value_t _threshold, coefficient_t _modulus) : sparse_dist(_sparse_dist), n(_sparse_dist.size()), dim_max(std::min(_dim_max, index_t(_sparse_dist.size() - 2))), threshold(_threshold), modulus(_modulus), binomial_coeff(n, dim_max + 2), multiplicative_inverse(multiplicative_inverse_vector(_modulus)) {} + index_t get_next_vertex(index_t& v, const index_t idx, const index_t k) const { + if (binomial_coeff(v, k) > idx) { + index_t count = v; + while (count > 0) { + index_t i = v; + index_t step = count >> 1; + i -= step; + if (binomial_coeff(i, k) > idx) { + v = --i; + count -= step + 1; + } else + count = step; + } + } + assert(binomial_coeff(v, k) <= idx && binomial_coeff(v + 1, k) > idx); + return v; + } + + index_t get_edge_index(const index_t i, const index_t j) const { return binomial_coeff(i, 2) + j; } + + template + OutputIterator get_simplex_vertices(index_t idx, const index_t dim, index_t v, + OutputIterator out) const { + --v; + for (index_t k = dim + 1; k > 0; --k) { + get_next_vertex(v, idx, k); + *out++ = v; + idx -= binomial_coeff(v, k); + } + return out; + } + class simplex_coboundary_enumerator { private: const ripser& parent; - + index_t idx_below, idx_above, v, k, max_vertex_below; const diameter_entry_t simplex; const coefficient_t modulus; const sparse_distance_matrix& sparse_dist; const binomial_coeff_table& binomial_coeff; - + std::vector& vertices; std::vector::const_reverse_iterator>& ii; std::vector::const_reverse_iterator>& ee; diameter_index_t x; - + public: simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, const ripser& _parent) - : parent(_parent), simplex(_simplex), idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), - k(_dim + 1), max_vertex_below(parent.n - 1), modulus(parent.modulus), sparse_dist(parent.sparse_dist), - binomial_coeff(parent.binomial_coeff), vertices(parent.vertices), ii(parent.ii), ee(parent.ee) { - + : parent(_parent), simplex(_simplex), idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), + k(_dim + 1), max_vertex_below(parent.n - 1), modulus(parent.modulus), sparse_dist(parent.sparse_dist), + binomial_coeff(parent.binomial_coeff), vertices(parent.vertices), ii(parent.ii), ee(parent.ee) { + ii.clear(); ee.clear(); vertices.clear(); - + parent.get_simplex_vertices(idx_below, _dim, parent.n, std::back_inserter(vertices)); - + for (auto v : vertices) { ii.push_back(sparse_dist.neighbors[v].rbegin()); ee.push_back(sparse_dist.neighbors[v].rend()); } } - + bool has_next(bool all_cofaces = true) { for (auto &it0 = ii[0], &end0 = ee[0]; it0 != end0; ++it0) { x = *it0; @@ -442,55 +479,25 @@ public: } return false; } - + diameter_entry_t next() { ++ii[0]; - + while (k > 0 && parent.get_next_vertex(max_vertex_below, idx_below, k) > get_index(x)) { idx_below -= binomial_coeff(max_vertex_below, k); idx_above += binomial_coeff(max_vertex_below, k + 1); --k; } - + value_t coface_diameter = std::max(get_diameter(simplex), get_diameter(x)); - + coefficient_t coface_coefficient = (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; - + return diameter_entry_t(coface_diameter, idx_above + binomial_coeff(get_index(x), k + 1) + idx_below, - coface_coefficient); + coface_coefficient); } }; - index_t get_next_vertex(index_t& v, const index_t idx, const index_t k) const { - if (binomial_coeff(v, k) > idx) { - index_t count = v; - while (count > 0) { - index_t i = v; - index_t step = count >> 1; - i -= step; - if (binomial_coeff(i, k) > idx) { - v = --i; - count -= step + 1; - } else - count = step; - } - } - assert(binomial_coeff(v, k) <= idx && binomial_coeff(v + 1, k) > idx); - return v; - } - - index_t get_edge_index(const index_t i, const index_t j) const { return binomial_coeff(i, 2) + j; } - - template - OutputIterator get_simplex_vertices(index_t idx, const index_t dim, index_t v, OutputIterator out) const { - --v; - for (index_t k = dim + 1; k > 0; --k) { - get_next_vertex(v, idx, k); - *out++ = v; - idx -= binomial_coeff(v, k); - } - return out; - } void assemble_columns_to_reduce(std::vector& simplices, std::vector& columns_to_reduce, @@ -707,18 +714,17 @@ public: std::vector columns_to_reduce; - std::vector simplices, &edges = simplices; - - for (index_t i = 0; i < n; ++i) - for (auto n : sparse_dist.neighbors[i]) { - index_t j = get_index(n); - if (i > j) edges.push_back(std::make_pair(get_diameter(n), get_edge_index(i, j))); - } - - std::sort(edges.rbegin(), edges.rend(), greater_diameter_or_smaller_index()); - + std::vector simplices; + { union_find dset(n); + std::vector &edges = simplices; + for (index_t i = 0; i < n; ++i) + for (auto n : sparse_dist.neighbors[i]) { + index_t j = get_index(n); + if (i > j) edges.push_back(std::make_pair(get_diameter(n), get_edge_index(i, j))); + } + std::sort(edges.rbegin(), edges.rend(), greater_diameter_or_smaller_index()); #ifdef PRINT_PERSISTENCE_PAIRS std::cout << "persistence intervals in dim 0:" << std::endl; -- cgit v1.2.3 From 31d0819c553fabbb25192797b250967216d699d3 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 29 Dec 2016 16:12:38 +0100 Subject: more code cleanup --- ripser.cpp | 317 +++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 224 insertions(+), 93 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index ec06d05..d0674f9 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -221,14 +221,12 @@ template <> void compressed_distance_matrix::init_rows() { } } -template <> value_t compressed_distance_matrix::operator()(index_t i, index_t j) const { - if (i > j) std::swap(i, j); - return i == j ? 0 : rows[i][j]; +template <> value_t compressed_distance_matrix::operator()(const index_t i, const index_t j) const { + return i == j ? 0 : i > j ? rows[j][i] : rows[i][j]; } -template <> value_t compressed_distance_matrix::operator()(index_t i, index_t j) const { - if (i > j) std::swap(i, j); - return i == j ? 0 : rows[j][i]; +template <> value_t compressed_distance_matrix::operator()(const index_t i, const index_t j) const { + return i == j ? 0 : i > j ? rows[i][j] : rows[j][i]; } typedef compressed_distance_matrix compressed_lower_distance_matrix; @@ -373,28 +371,22 @@ template void push_entry(Heap& column, index_t i, coefficient_t column.push(std::make_pair(diameter, e)); } -class ripser { - index_t dim_max, n; +template class ripser { + DistanceMatrix dist; + index_t n, dim_max; value_t threshold; const binomial_coeff_table binomial_coeff; std::vector multiplicative_inverse; coefficient_t modulus; -#ifdef SPARSE_DISTANCE_MATRIX - sparse_distance_matrix sparse_dist; -#else - compressed_lower_distance_matrix dist; -#endif mutable std::vector vertices; -#ifdef SPARSE_DISTANCE_MATRIX - mutable std::vector::const_reverse_iterator> ii; - mutable std::vector::const_reverse_iterator> ee; -#endif - + mutable std::vector::const_reverse_iterator> neighbor_it; + mutable std::vector::const_reverse_iterator> neighbor_end; + public: - ripser(sparse_distance_matrix&& _sparse_dist, index_t _dim_max, value_t _threshold, coefficient_t _modulus) - : sparse_dist(_sparse_dist), n(_sparse_dist.size()), - dim_max(std::min(_dim_max, index_t(_sparse_dist.size() - 2))), threshold(_threshold), modulus(_modulus), - binomial_coeff(n, dim_max + 2), multiplicative_inverse(multiplicative_inverse_vector(_modulus)) {} + ripser(DistanceMatrix&& _dist, index_t _dim_max, value_t _threshold, coefficient_t _modulus) + : dist(std::move(_dist)), n(dist.size()), dim_max(std::min(_dim_max, index_t(dist.size() - 2))), + threshold(_threshold), modulus(_modulus), binomial_coeff(n, dim_max + 2), + multiplicative_inverse(multiplicative_inverse_vector(_modulus)) {} index_t get_next_vertex(index_t& v, const index_t idx, const index_t k) const { if (binomial_coeff(v, k) > idx) { @@ -417,8 +409,7 @@ public: index_t get_edge_index(const index_t i, const index_t j) const { return binomial_coeff(i, 2) + j; } template - OutputIterator get_simplex_vertices(index_t idx, const index_t dim, index_t v, - OutputIterator out) const { + OutputIterator get_simplex_vertices(index_t idx, const index_t dim, index_t v, OutputIterator out) const { --v; for (index_t k = dim + 1; k > 0; --k) { get_next_vertex(v, idx, k); @@ -427,45 +418,92 @@ public: } return out; } - + + value_t compute_diameter(const index_t index, index_t dim) const { + value_t diam = -std::numeric_limits::infinity(); + + vertices.clear(); + get_simplex_vertices(index, dim, dist.size(), std::back_inserter(vertices)); + + for (index_t i = 0; i <= dim; ++i) + for (index_t j = 0; j < i; ++j) { diam = std::max(diam, dist(vertices[i], vertices[j])); } + return diam; + } + class simplex_coboundary_enumerator { + private: + index_t idx_below, idx_above, v, k; + std::vector vertices; + const diameter_entry_t simplex; + const coefficient_t modulus; + const compressed_lower_distance_matrix& dist; + const binomial_coeff_table& binomial_coeff; + + public: + simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, const ripser& parent) + : simplex(_simplex), idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), k(_dim + 1), + modulus(parent.modulus), binomial_coeff(parent.binomial_coeff), dist(parent.dist), vertices(_dim + 1) { + parent.get_simplex_vertices(get_index(_simplex), _dim, parent.n, vertices.begin()); + } + + bool has_next() { + while ((v != -1) && (binomial_coeff(v, k) <= idx_below)) { + idx_below -= binomial_coeff(v, k); + idx_above += binomial_coeff(v, k + 1); + --v; + --k; + assert(k != -1); + } + return v != -1; + } + + diameter_entry_t next() { + value_t coface_diameter = get_diameter(simplex); + for (index_t w : vertices) coface_diameter = std::max(coface_diameter, dist(v, w)); + index_t coface_index = idx_above + binomial_coeff(v--, k + 1) + idx_below; + coefficient_t coface_coefficient = (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; + return diameter_entry_t(coface_diameter, coface_index, coface_coefficient); + } + }; + + class simplex_sparse_coboundary_enumerator { private: const ripser& parent; - + index_t idx_below, idx_above, v, k, max_vertex_below; const diameter_entry_t simplex; const coefficient_t modulus; - const sparse_distance_matrix& sparse_dist; + const DistanceMatrix& dist; const binomial_coeff_table& binomial_coeff; - + std::vector& vertices; - std::vector::const_reverse_iterator>& ii; - std::vector::const_reverse_iterator>& ee; + std::vector::const_reverse_iterator>& neighbor_it; + std::vector::const_reverse_iterator>& neighbor_end; diameter_index_t x; - + public: - simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, const ripser& _parent) - : parent(_parent), simplex(_simplex), idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), - k(_dim + 1), max_vertex_below(parent.n - 1), modulus(parent.modulus), sparse_dist(parent.sparse_dist), - binomial_coeff(parent.binomial_coeff), vertices(parent.vertices), ii(parent.ii), ee(parent.ee) { - - ii.clear(); - ee.clear(); + simplex_sparse_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, const ripser& _parent) + : parent(_parent), simplex(_simplex), idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), + k(_dim + 1), max_vertex_below(parent.n - 1), modulus(parent.modulus), dist(parent.dist), + binomial_coeff(parent.binomial_coeff), vertices(parent.vertices), neighbor_it(parent.neighbor_it), neighbor_end(parent.neighbor_end) { + + neighbor_it.clear(); + neighbor_end.clear(); vertices.clear(); - + parent.get_simplex_vertices(idx_below, _dim, parent.n, std::back_inserter(vertices)); - + for (auto v : vertices) { - ii.push_back(sparse_dist.neighbors[v].rbegin()); - ee.push_back(sparse_dist.neighbors[v].rend()); + neighbor_it.push_back(dist.neighbors[v].rbegin()); + neighbor_end.push_back(dist.neighbors[v].rend()); } } - + bool has_next(bool all_cofaces = true) { - for (auto &it0 = ii[0], &end0 = ee[0]; it0 != end0; ++it0) { + for (auto &it0 = neighbor_it[0], &end0 = neighbor_end[0]; it0 != end0; ++it0) { x = *it0; - for (size_t idx = 1; idx < ii.size(); ++idx) { - auto &it = ii[idx], end = ee[idx]; + for (size_t idx = 1; idx < neighbor_it.size(); ++idx) { + auto &it = neighbor_it[idx], end = neighbor_end[idx]; while (get_index(*it) > get_index(x)) if (++it == end) return false; auto y = *it; @@ -479,41 +517,77 @@ public: } return false; } - + diameter_entry_t next() { - ++ii[0]; - + ++neighbor_it[0]; + while (k > 0 && parent.get_next_vertex(max_vertex_below, idx_below, k) > get_index(x)) { idx_below -= binomial_coeff(max_vertex_below, k); idx_above += binomial_coeff(max_vertex_below, k + 1); --k; } - + value_t coface_diameter = std::max(get_diameter(simplex), get_diameter(x)); - + coefficient_t coface_coefficient = (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; - + return diameter_entry_t(coface_diameter, idx_above + binomial_coeff(get_index(x), k + 1) + idx_below, - coface_coefficient); + coface_coefficient); } }; - - void assemble_columns_to_reduce(std::vector& simplices, - std::vector& columns_to_reduce, + void assemble_columns_to_reduce(std::vector& columns_to_reduce, hash_map& pivot_column_index, index_t dim) { + index_t num_simplices = binomial_coeff(n, dim + 1); + + columns_to_reduce.clear(); + +#ifdef INDICATE_PROGRESS + std::cout << "\033[K" + << "assembling " << num_simplices << " columns" << std::flush << "\r"; +#endif + + for (index_t index = 0; index < num_simplices; ++index) { + if (pivot_column_index.find(index) == pivot_column_index.end()) { + value_t diameter = compute_diameter(index, dim); + if (diameter <= threshold) columns_to_reduce.push_back(std::make_pair(diameter, index)); +#ifdef INDICATE_PROGRESS + if ((index + 1) % 1000 == 0) + std::cout << "\033[K" + << "assembled " << columns_to_reduce.size() << " out of " << (index + 1) << "/" + << num_simplices << " columns" << std::flush << "\r"; +#endif + } + } + +#ifdef INDICATE_PROGRESS + std::cout << "\033[K" + << "sorting " << num_simplices << " columns" << std::flush << "\r"; +#endif + + std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), + greater_diameter_or_smaller_index()); +#ifdef INDICATE_PROGRESS + std::cout << "\033[K"; +#endif + } + + void assemble_sparse_columns_to_reduce(std::vector& simplices, + std::vector& columns_to_reduce, + hash_map& pivot_column_index, index_t dim) { #ifdef INDICATE_PROGRESS std::cout << "\033[K" << "assembling columns" << std::flush << "\r"; #endif + --dim; columns_to_reduce.clear(); std::vector next_simplices; for (diameter_index_t simplex : simplices) { - simplex_coboundary_enumerator cofaces(simplex, dim, *this); + simplex_sparse_coboundary_enumerator cofaces(simplex, dim, *this); while (cofaces.has_next(false)) { auto coface = cofaces.next(); @@ -539,6 +613,7 @@ public: #endif } + template void compute_pairs(std::vector& columns_to_reduce, hash_map& pivot_column_index, index_t dim) { @@ -624,7 +699,7 @@ public: #endif coface_entries.clear(); - simplex_coboundary_enumerator cofaces(simplex, dim, *this); + BoundaryEnumerator cofaces(simplex, dim, *this); while (cofaces.has_next()) { diameter_entry_t coface = cofaces.next(); if (get_diameter(coface) <= threshold) { @@ -710,58 +785,111 @@ public: #endif } - void compute_barcodes() { + void compute_barcodes(); +}; - std::vector columns_to_reduce; +template <> void ripser::compute_barcodes() { - std::vector simplices; - - { - union_find dset(n); - std::vector &edges = simplices; - for (index_t i = 0; i < n; ++i) - for (auto n : sparse_dist.neighbors[i]) { - index_t j = get_index(n); - if (i > j) edges.push_back(std::make_pair(get_diameter(n), get_edge_index(i, j))); - } - std::sort(edges.rbegin(), edges.rend(), greater_diameter_or_smaller_index()); + std::vector columns_to_reduce; + + { + union_find dset(n); + std::vector edges; + for (index_t index = binomial_coeff(n, 2); index-- > 0;) { + value_t diameter = compute_diameter(index, 1); + if (diameter <= threshold) edges.push_back(std::make_pair(diameter, index)); + } + std::sort(edges.rbegin(), edges.rend(), greater_diameter_or_smaller_index()); #ifdef PRINT_PERSISTENCE_PAIRS - std::cout << "persistence intervals in dim 0:" << std::endl; + std::cout << "persistence intervals in dim 0:" << std::endl; #endif - std::vector vertices_of_edge(2); - for (auto e : edges) { - vertices_of_edge.clear(); - get_simplex_vertices(get_index(e), 1, n, std::back_inserter(vertices_of_edge)); - index_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]); + std::vector vertices_of_edge(2); + for (auto e : edges) { + vertices_of_edge.clear(); + get_simplex_vertices(get_index(e), 1, n, std::back_inserter(vertices_of_edge)); + index_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]); - if (u != v) { + if (u != v) { #ifdef PRINT_PERSISTENCE_PAIRS - if (get_diameter(e) > 0) std::cout << " [0," << get_diameter(e) << ")" << std::endl; + if (get_diameter(e) != 0) std::cout << " [0," << get_diameter(e) << ")" << std::endl; #endif - dset.link(u, v); - } else - columns_to_reduce.push_back(e); + dset.link(u, v); + } else + columns_to_reduce.push_back(e); + } + std::reverse(columns_to_reduce.begin(), columns_to_reduce.end()); + +#ifdef PRINT_PERSISTENCE_PAIRS + for (index_t i = 0; i < n; ++i) + if (dset.find(i) == i) std::cout << " [0, )" << std::endl << std::flush; +#endif + } + + for (index_t dim = 1; dim <= dim_max; ++dim) { + hash_map pivot_column_index; + pivot_column_index.reserve(columns_to_reduce.size()); + + compute_pairs(columns_to_reduce, pivot_column_index, dim); + + if (dim < dim_max) { assemble_columns_to_reduce(columns_to_reduce, pivot_column_index, dim + 1); } + } +} + +template <> void ripser::compute_barcodes() { + + std::vector columns_to_reduce; + + std::vector simplices; + + { + union_find dset(n); + std::vector& edges = simplices; + for (index_t i = 0; i < n; ++i) + for (auto n : dist.neighbors[i]) { + index_t j = get_index(n); + if (i > j) edges.push_back(std::make_pair(get_diameter(n), get_edge_index(i, j))); } - std::reverse(columns_to_reduce.begin(), columns_to_reduce.end()); + std::sort(edges.rbegin(), edges.rend(), greater_diameter_or_smaller_index()); + +#ifdef PRINT_PERSISTENCE_PAIRS + std::cout << "persistence intervals in dim 0:" << std::endl; +#endif + + std::vector vertices_of_edge(2); + for (auto e : edges) { + vertices_of_edge.clear(); + get_simplex_vertices(get_index(e), 1, n, std::back_inserter(vertices_of_edge)); + index_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]); + if (u != v) { #ifdef PRINT_PERSISTENCE_PAIRS - for (index_t i = 0; i < n; ++i) - if (dset.find(i) == i) std::cout << " [0, )" << std::endl << std::flush; + if (get_diameter(e) != 0) std::cout << " [0," << get_diameter(e) << ")" << std::endl; #endif + dset.link(u, v); + } else + columns_to_reduce.push_back(e); } + std::reverse(columns_to_reduce.begin(), columns_to_reduce.end()); + +#ifdef PRINT_PERSISTENCE_PAIRS + for (index_t i = 0; i < n; ++i) + if (dset.find(i) == i) std::cout << " [0, )" << std::endl << std::flush; +#endif + } - for (index_t dim = 1; dim <= dim_max; ++dim) { - hash_map pivot_column_index; - pivot_column_index.reserve(columns_to_reduce.size()); + for (index_t dim = 1; dim <= dim_max; ++dim) { + hash_map pivot_column_index; + pivot_column_index.reserve(columns_to_reduce.size()); - compute_pairs(columns_to_reduce, pivot_column_index, dim); + compute_pairs(columns_to_reduce, pivot_column_index, dim); - if (dim < dim_max) { assemble_columns_to_reduce(simplices, columns_to_reduce, pivot_column_index, dim); } + if (dim < dim_max) { + assemble_sparse_columns_to_reduce(simplices, columns_to_reduce, pivot_column_index, dim + 1); } } -}; +} enum file_format { LOWER_DISTANCE_MATRIX, UPPER_DISTANCE_MATRIX, DISTANCE_MATRIX, POINT_CLOUD, DIPHA, RIPSER }; @@ -983,7 +1111,10 @@ int main(int argc, char** argv) { auto value_range = std::minmax_element(dist.distances.begin(), dist.distances.end()); std::cout << "value range: [" << *value_range.first << "," << *value_range.second << "]" << std::endl; - sparse_distance_matrix sparse_dist(dist, threshold); - ripser(std::move(sparse_dist), dim_max, threshold, modulus).compute_barcodes(); +#ifdef SPARSE_DISTANCE_MATRIX + ripser(std::move(dist), dim_max, threshold, modulus).compute_barcodes(); +#else + ripser(sparse_distance_matrix(dist, threshold), dim_max, threshold, modulus).compute_barcodes(); +#endif } -- cgit v1.2.3 From 2158b4a884d1239ede305b7ce91c9f9beeb0668b Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 29 Dec 2016 16:23:53 +0100 Subject: reordered initializers --- ripser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 0f9d02f..052c07d 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -422,8 +422,8 @@ public: public: simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, const ripser& parent) - : simplex(_simplex), idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), k(_dim + 1), modulus(parent.modulus), - binomial_coeff(parent.binomial_coeff), dist(parent.dist), vertices(_dim + 1) { + : idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), k(_dim + 1), vertices(_dim + 1), simplex(_simplex), modulus(parent.modulus), dist(parent.dist), + binomial_coeff(parent.binomial_coeff) { parent.get_simplex_vertices(get_index(_simplex), _dim, parent.n, vertices.begin()); } -- cgit v1.2.3 From 11dfa016218793929b6a8b7f8c93a3669f3229d5 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 29 Dec 2016 17:52:49 +0100 Subject: code reformatting --- .clang-format | 2 +- ripser.cpp | 469 ++++++++++++++++++++++++++++++++-------------------------- 2 files changed, 259 insertions(+), 212 deletions(-) diff --git a/.clang-format b/.clang-format index 598d7c2..1975b19 100644 --- a/.clang-format +++ b/.clang-format @@ -1,7 +1,7 @@ BasedOnStyle: LLVM IndentWidth: 4 TabWidth: 4 -ColumnLimit: 120 +ColumnLimit: 100 AccessModifierOffset: -4 AllowShortIfStatementsOnASingleLine: true AllowShortLoopsOnASingleLine: true diff --git a/ripser.cpp b/ripser.cpp index 052c07d..02bfac9 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -52,6 +52,7 @@ typedef int16_t coefficient_t; class binomial_coeff_table { std::vector> B; + public: binomial_coeff_table(index_t n, index_t k) : B(n + 1) { for (index_t i = 0; i <= n; i++) { @@ -87,19 +88,21 @@ std::vector multiplicative_inverse_vector(const coefficient_t m) return inverse; } - #ifdef USE_COEFFICIENTS struct __attribute__((packed)) entry_t { index_t index : 8 * (sizeof(index_t) - sizeof(coefficient_t)); coefficient_t coefficient; - entry_t(index_t _index, coefficient_t _coefficient) : index(_index), coefficient(_coefficient) {} + entry_t(index_t _index, coefficient_t _coefficient) + : index(_index), coefficient(_coefficient) {} entry_t(index_t _index) : index(_index), coefficient(1) {} entry_t() : index(0), coefficient(1) {} }; static_assert(sizeof(entry_t) == sizeof(index_t), "size of entry_t is not the same as index_t"); -entry_t make_entry(index_t _index, coefficient_t _coefficient) { return entry_t(_index, _coefficient); } +entry_t make_entry(index_t _index, coefficient_t _coefficient) { + return entry_t(_index, _coefficient); +} index_t get_index(entry_t e) { return e.index; } index_t get_coefficient(entry_t e) { return e.coefficient; } void set_coefficient(entry_t& e, const coefficient_t c) { e.coefficient = c; } @@ -149,9 +152,13 @@ public: const entry_t& get_entry(const diameter_entry_t& p) { return p.second; } entry_t& get_entry(diameter_entry_t& p) { return p.second; } const index_t get_index(const diameter_entry_t& p) { return get_index(get_entry(p)); } -const coefficient_t get_coefficient(const diameter_entry_t& p) { return get_coefficient(get_entry(p)); } +const coefficient_t get_coefficient(const diameter_entry_t& p) { + return get_coefficient(get_entry(p)); +} const value_t& get_diameter(const diameter_entry_t& p) { return p.first; } -void set_coefficient(diameter_entry_t& p, const coefficient_t c) { set_coefficient(get_entry(p), c); } +void set_coefficient(diameter_entry_t& p, const coefficient_t c) { + set_coefficient(get_entry(p), c); +} template struct greater_diameter_or_smaller_index { bool operator()(const Entry& a, const Entry& b) { @@ -205,11 +212,13 @@ template <> void compressed_distance_matrix::init_rows() { } } -template <> value_t compressed_distance_matrix::operator()(index_t i, index_t j) const { +template <> +value_t compressed_distance_matrix::operator()(index_t i, index_t j) const { return i == j ? 0 : i > j ? rows[j][i] : rows[i][j]; } -template <> value_t compressed_distance_matrix::operator()(index_t i, index_t j) const { +template <> +value_t compressed_distance_matrix::operator()(index_t i, index_t j) const { return i == j ? 0 : i < j ? rows[j][i] : rows[i][j]; } @@ -220,12 +229,13 @@ class euclidean_distance_matrix { public: std::vector> points; - euclidean_distance_matrix(std::vector>&& _points) : points(std::move(_points)) {} + euclidean_distance_matrix(std::vector>&& _points) + : points(std::move(_points)) {} value_t operator()(const index_t i, const index_t j) const { - return std::sqrt(std::inner_product(points[i].begin(), points[i].end(), points[j].begin(), value_t(), - std::plus(), - [](value_t u, value_t v) { return (u - v) * (u - v); })); + return std::sqrt(std::inner_product( + points[i].begin(), points[i].end(), points[j].begin(), value_t(), std::plus(), + [](value_t u, value_t v) { return (u - v) * (u - v); })); } size_t size() const { return points.size(); } @@ -350,7 +360,8 @@ public: } }; -template void push_entry(Heap& column, index_t i, coefficient_t c, value_t diameter) { +template +void push_entry(Heap& column, index_t i, coefficient_t c, value_t diameter) { entry_t e = make_entry(i, c); column.push(std::make_pair(diameter, e)); } @@ -365,11 +376,12 @@ class ripser { mutable std::vector vertices; public: - ripser(compressed_lower_distance_matrix&& _dist, index_t _dim_max, value_t _threshold, coefficient_t _modulus) - : dist(std::move(_dist)), dim_max(std::min(_dim_max, index_t(dist.size() - 2))), n(dist.size()), threshold(_threshold), - modulus(_modulus), binomial_coeff(n, dim_max + 2), + ripser(compressed_lower_distance_matrix&& _dist, index_t _dim_max, value_t _threshold, + coefficient_t _modulus) + : dist(std::move(_dist)), dim_max(std::min(_dim_max, index_t(dist.size() - 2))), + n(dist.size()), threshold(_threshold), modulus(_modulus), binomial_coeff(n, dim_max + 2), multiplicative_inverse(multiplicative_inverse_vector(_modulus)) {} - + index_t get_next_vertex(index_t& v, const index_t idx, const index_t k) const { if (binomial_coeff(v, k) > idx) { index_t count = v; @@ -387,10 +399,10 @@ public: assert(binomial_coeff(v, k) <= idx && binomial_coeff(v + 1, k) > idx); return v; } - + template OutputIterator get_simplex_vertices(index_t idx, const index_t dim, index_t v, - OutputIterator out) const { + OutputIterator out) const { --v; for (index_t k = dim + 1; k > 0; --k) { get_next_vertex(v, idx, k); @@ -399,7 +411,7 @@ public: } return out; } - + value_t compute_diameter(const index_t index, index_t dim) const { value_t diam = -std::numeric_limits::infinity(); @@ -407,10 +419,12 @@ public: get_simplex_vertices(index, dim, dist.size(), std::back_inserter(vertices)); for (index_t i = 0; i <= dim; ++i) - for (index_t j = 0; j < i; ++j) { diam = std::max(diam, dist(vertices[i], vertices[j])); } + for (index_t j = 0; j < i; ++j) { + diam = std::max(diam, dist(vertices[i], vertices[j])); + } return diam; } - + class simplex_coboundary_enumerator { private: index_t idx_below, idx_above, v, k; @@ -419,14 +433,16 @@ public: const coefficient_t modulus; const compressed_lower_distance_matrix& dist; const binomial_coeff_table& binomial_coeff; - + public: - simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, const ripser& parent) - : idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), k(_dim + 1), vertices(_dim + 1), simplex(_simplex), modulus(parent.modulus), dist(parent.dist), - binomial_coeff(parent.binomial_coeff) { + simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, + const ripser& parent) + : idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), k(_dim + 1), + vertices(_dim + 1), simplex(_simplex), modulus(parent.modulus), dist(parent.dist), + binomial_coeff(parent.binomial_coeff) { parent.get_simplex_vertices(get_index(_simplex), _dim, parent.n, vertices.begin()); } - + bool has_next() { while ((v != -1) && (binomial_coeff(v, k) <= idx_below)) { idx_below -= binomial_coeff(v, k); @@ -437,276 +453,248 @@ public: } return v != -1; } - + diameter_entry_t next() { value_t coface_diameter = get_diameter(simplex); for (index_t w : vertices) coface_diameter = std::max(coface_diameter, dist(v, w)); index_t coface_index = idx_above + binomial_coeff(v--, k + 1) + idx_below; - coefficient_t coface_coefficient = (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; + coefficient_t coface_coefficient = + (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; return diameter_entry_t(coface_diameter, coface_index, coface_coefficient); } }; - void assemble_columns_to_reduce(std::vector& columns_to_reduce, - hash_map& pivot_column_index, index_t dim) { - index_t num_simplices = binomial_coeff(n, dim + 1); + hash_map& pivot_column_index, index_t dim); + + void compute_pairs(std::vector& columns_to_reduce, + hash_map& pivot_column_index, index_t dim); + + void compute_barcodes(); +}; - columns_to_reduce.clear(); +void ripser::assemble_columns_to_reduce(std::vector& columns_to_reduce, + hash_map& pivot_column_index, + index_t dim) { + index_t num_simplices = binomial_coeff(n, dim + 1); + + columns_to_reduce.clear(); #ifdef INDICATE_PROGRESS - std::cout << "\033[K" - << "assembling " << num_simplices << " columns" << std::flush << "\r"; + std::cout << "\033[K" + << "assembling " << num_simplices << " columns" << std::flush << "\r"; #endif - for (index_t index = 0; index < num_simplices; ++index) { - if (pivot_column_index.find(index) == pivot_column_index.end()) { - value_t diameter = compute_diameter(index, dim); - if (diameter <= threshold) columns_to_reduce.push_back(std::make_pair(diameter, index)); + for (index_t index = 0; index < num_simplices; ++index) { + if (pivot_column_index.find(index) == pivot_column_index.end()) { + value_t diameter = compute_diameter(index, dim); + if (diameter <= threshold) columns_to_reduce.push_back(std::make_pair(diameter, index)); #ifdef INDICATE_PROGRESS - if ((index + 1) % 1000 == 0) - std::cout << "\033[K" - << "assembled " << columns_to_reduce.size() << " out of " << (index + 1) << "/" - << num_simplices << " columns" << std::flush << "\r"; + if ((index + 1) % 1000 == 0) + std::cout << "\033[K" + << "assembled " << columns_to_reduce.size() << " out of " << (index + 1) + << "/" << num_simplices << " columns" << std::flush << "\r"; #endif - } } + } #ifdef INDICATE_PROGRESS - std::cout << "\033[K" - << "sorting " << num_simplices << " columns" << std::flush << "\r"; + std::cout << "\033[K" + << "sorting " << num_simplices << " columns" << std::flush << "\r"; #endif - std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), - greater_diameter_or_smaller_index()); + std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), + greater_diameter_or_smaller_index()); #ifdef INDICATE_PROGRESS - std::cout << "\033[K"; + std::cout << "\033[K"; #endif - } +} - void compute_pairs(std::vector& columns_to_reduce, hash_map& pivot_column_index, - index_t dim) { +void ripser::compute_pairs(std::vector& columns_to_reduce, + hash_map& pivot_column_index, index_t dim) { #ifdef PRINT_PERSISTENCE_PAIRS - std::cout << "persistence intervals in dim " << dim << ":" << std::endl; + std::cout << "persistence intervals in dim " << dim << ":" << std::endl; #endif #ifdef ASSEMBLE_REDUCTION_MATRIX - compressed_sparse_matrix reduction_coefficients; + compressed_sparse_matrix reduction_coefficients; #else #ifdef USE_COEFFICIENTS - std::vector reduction_coefficients; + std::vector reduction_coefficients; #endif #endif - std::vector coface_entries; + std::vector coface_entries; - for (index_t i = 0; i < columns_to_reduce.size(); ++i) { - auto column_to_reduce = columns_to_reduce[i]; + for (index_t i = 0; i < columns_to_reduce.size(); ++i) { + auto column_to_reduce = columns_to_reduce[i]; #ifdef ASSEMBLE_REDUCTION_MATRIX - std::priority_queue, - greater_diameter_or_smaller_index> - reduction_column; + std::priority_queue, + greater_diameter_or_smaller_index> + reduction_column; #endif - std::priority_queue, - greater_diameter_or_smaller_index> - working_coboundary; + std::priority_queue, + greater_diameter_or_smaller_index> + working_coboundary; - value_t diameter = get_diameter(column_to_reduce); + value_t diameter = get_diameter(column_to_reduce); #ifdef INDICATE_PROGRESS - if ((i + 1) % 1000 == 0) - std::cout << "\033[K" - << "reducing column " << i + 1 << "/" << columns_to_reduce.size() << " (diameter " << diameter - << ")" << std::flush << "\r"; + if ((i + 1) % 1000 == 0) + std::cout << "\033[K" + << "reducing column " << i + 1 << "/" << columns_to_reduce.size() + << " (diameter " << diameter << ")" << std::flush << "\r"; #endif - index_t j = i; + index_t j = i; - // start with a dummy pivot entry with coefficient -1 in order to initialize - // working_coboundary with the coboundary of the simplex with index column_to_reduce - diameter_entry_t pivot(0, -1, -1 + modulus); + // start with a dummy pivot entry with coefficient -1 in order to initialize + // working_coboundary with the coboundary of the simplex with index column_to_reduce + diameter_entry_t pivot(0, -1, -1 + modulus); #ifdef ASSEMBLE_REDUCTION_MATRIX - // initialize reduction_coefficients as identity matrix - reduction_coefficients.append_column(); + // initialize reduction_coefficients as identity matrix + reduction_coefficients.append_column(); #endif #ifdef USE_COEFFICIENTS - reduction_coefficients.push_back(diameter_entry_t(column_to_reduce, 1)); + reduction_coefficients.push_back(diameter_entry_t(column_to_reduce, 1)); #endif - bool might_be_apparent_pair = (i == j); + bool might_be_apparent_pair = (i == j); - do { - const coefficient_t factor = modulus - get_coefficient(pivot); + do { + const coefficient_t factor = modulus - get_coefficient(pivot); #ifdef ASSEMBLE_REDUCTION_MATRIX #ifdef USE_COEFFICIENTS - auto coeffs_begin = reduction_coefficients.cbegin(j), coeffs_end = reduction_coefficients.cend(j); + auto coeffs_begin = reduction_coefficients.cbegin(j), + coeffs_end = reduction_coefficients.cend(j); #else - std::vector coeffs; - coeffs.push_back(columns_to_reduce[j]); - for (auto it = reduction_coefficients.cbegin(j); it != reduction_coefficients.cend(j); ++it) - coeffs.push_back(*it); - auto coeffs_begin = coeffs.begin(), coeffs_end = coeffs.end(); + std::vector coeffs; + coeffs.push_back(columns_to_reduce[j]); + for (auto it = reduction_coefficients.cbegin(j); it != reduction_coefficients.cend(j); + ++it) + coeffs.push_back(*it); + auto coeffs_begin = coeffs.begin(), coeffs_end = coeffs.end(); #endif #else #ifdef USE_COEFFICIENTS - auto coeffs_begin = &reduction_coefficients[j], coeffs_end = &reduction_coefficients[j] + 1; + auto coeffs_begin = &reduction_coefficients[j], + coeffs_end = &reduction_coefficients[j] + 1; #else - auto coeffs_begin = &columns_to_reduce[j], coeffs_end = &columns_to_reduce[j] + 1; + auto coeffs_begin = &columns_to_reduce[j], coeffs_end = &columns_to_reduce[j] + 1; #endif #endif - for (auto it = coeffs_begin; it != coeffs_end; ++it) { - diameter_entry_t simplex = *it; - set_coefficient(simplex, get_coefficient(simplex) * factor % modulus); + for (auto it = coeffs_begin; it != coeffs_end; ++it) { + diameter_entry_t simplex = *it; + set_coefficient(simplex, get_coefficient(simplex) * factor % modulus); #ifdef ASSEMBLE_REDUCTION_MATRIX - reduction_column.push(simplex); -#endif - - coface_entries.clear(); - simplex_coboundary_enumerator cofaces(simplex, dim, *this); - while (cofaces.has_next()) { - diameter_entry_t coface = cofaces.next(); - if (get_diameter(coface) <= threshold) { - coface_entries.push_back(coface); - if (might_be_apparent_pair && (get_diameter(simplex) == get_diameter(coface))) { - if (pivot_column_index.find(get_index(coface)) == pivot_column_index.end()) { - pivot = coface; - goto found_persistence_pair; - } - might_be_apparent_pair = false; + reduction_column.push(simplex); +#endif + + coface_entries.clear(); + simplex_coboundary_enumerator cofaces(simplex, dim, *this); + while (cofaces.has_next()) { + diameter_entry_t coface = cofaces.next(); + if (get_diameter(coface) <= threshold) { + coface_entries.push_back(coface); + if (might_be_apparent_pair && + (get_diameter(simplex) == get_diameter(coface))) { + if (pivot_column_index.find(get_index(coface)) == + pivot_column_index.end()) { + pivot = coface; + goto found_persistence_pair; } + might_be_apparent_pair = false; } } - for (auto coface : coface_entries) working_coboundary.push(coface); } + for (auto coface : coface_entries) working_coboundary.push(coface); + } - pivot = get_pivot(working_coboundary, modulus); + pivot = get_pivot(working_coboundary, modulus); - if (get_index(pivot) != -1) { - auto pair = pivot_column_index.find(get_index(pivot)); + if (get_index(pivot) != -1) { + auto pair = pivot_column_index.find(get_index(pivot)); - if (pair != pivot_column_index.end()) { - j = pair->second; - continue; - } - } else { + if (pair != pivot_column_index.end()) { + j = pair->second; + continue; + } + } else { #ifdef PRINT_PERSISTENCE_PAIRS #ifdef INDICATE_PROGRESS - std::cout << "\033[K"; + std::cout << "\033[K"; #endif - std::cout << " [" << diameter << ", )" << std::endl << std::flush; + std::cout << " [" << diameter << ", )" << std::endl << std::flush; #endif - break; - } + break; + } - found_persistence_pair: + found_persistence_pair: #ifdef PRINT_PERSISTENCE_PAIRS - value_t death = get_diameter(pivot); - if (diameter != death) { + value_t death = get_diameter(pivot); + if (diameter != death) { #ifdef INDICATE_PROGRESS - std::cout << "\033[K"; + std::cout << "\033[K"; #endif - std::cout << " [" << diameter << "," << death << ")" << std::endl << std::flush; - } + std::cout << " [" << diameter << "," << death << ")" << std::endl << std::flush; + } #endif - pivot_column_index.insert(std::make_pair(get_index(pivot), i)); + pivot_column_index.insert(std::make_pair(get_index(pivot), i)); #ifdef USE_COEFFICIENTS - const coefficient_t inverse = multiplicative_inverse[get_coefficient(pivot)]; + const coefficient_t inverse = multiplicative_inverse[get_coefficient(pivot)]; #endif #ifdef ASSEMBLE_REDUCTION_MATRIX // replace current column of reduction_coefficients (with a single diagonal 1 entry) // by reduction_column (possibly with a different entry on the diagonal) #ifdef USE_COEFFICIENTS - reduction_coefficients.pop_back(); + reduction_coefficients.pop_back(); #else - pop_pivot(reduction_column, modulus); + pop_pivot(reduction_column, modulus); #endif - while (true) { - diameter_entry_t e = pop_pivot(reduction_column, modulus); - if (get_index(e) == -1) break; + while (true) { + diameter_entry_t e = pop_pivot(reduction_column, modulus); + if (get_index(e) == -1) break; #ifdef USE_COEFFICIENTS - set_coefficient(e, inverse * get_coefficient(e) % modulus); - assert(get_coefficient(e) > 0); + set_coefficient(e, inverse * get_coefficient(e) % modulus); + assert(get_coefficient(e) > 0); #endif - reduction_coefficients.push_back(e); - } + reduction_coefficients.push_back(e); + } #else #ifdef USE_COEFFICIENTS - reduction_coefficients.pop_back(); - reduction_coefficients.push_back(diameter_entry_t(column_to_reduce, inverse)); + reduction_coefficients.pop_back(); + reduction_coefficients.push_back(diameter_entry_t(column_to_reduce, inverse)); #endif #endif - break; - } while (true); - } - -#ifdef INDICATE_PROGRESS - std::cout << "\033[K"; -#endif + break; + } while (true); } - void compute_barcodes() { - - std::vector columns_to_reduce; - - { - union_find dset(n); - std::vector edges; - for (index_t index = binomial_coeff(n, 2); index-- > 0;) { - value_t diameter = compute_diameter(index, 1); - if (diameter <= threshold) edges.push_back(std::make_pair(diameter, index)); - } - std::sort(edges.rbegin(), edges.rend(), greater_diameter_or_smaller_index()); - -#ifdef PRINT_PERSISTENCE_PAIRS - std::cout << "persistence intervals in dim 0:" << std::endl; -#endif - - std::vector vertices_of_edge(2); - for (auto e : edges) { - vertices_of_edge.clear(); - get_simplex_vertices(get_index(e), 1, n, std::back_inserter(vertices_of_edge)); - index_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]); - - if (u != v) { -#ifdef PRINT_PERSISTENCE_PAIRS - if (get_diameter(e) != 0) std::cout << " [0," << get_diameter(e) << ")" << std::endl; -#endif - dset.link(u, v); - } else - columns_to_reduce.push_back(e); - } - std::reverse(columns_to_reduce.begin(), columns_to_reduce.end()); - -#ifdef PRINT_PERSISTENCE_PAIRS - for (index_t i = 0; i < n; ++i) - if (dset.find(i) == i) std::cout << " [0, )" << std::endl << std::flush; +#ifdef INDICATE_PROGRESS + std::cout << "\033[K"; #endif - } - - for (index_t dim = 1; dim <= dim_max; ++dim) { - hash_map pivot_column_index; - pivot_column_index.reserve(columns_to_reduce.size()); - - compute_pairs(columns_to_reduce, pivot_column_index, dim); +} - if (dim < dim_max) { assemble_columns_to_reduce(columns_to_reduce, pivot_column_index, dim + 1); } - } - } +enum file_format { + LOWER_DISTANCE_MATRIX, + UPPER_DISTANCE_MATRIX, + DISTANCE_MATRIX, + POINT_CLOUD, + DIPHA, + RIPSER }; -enum file_format { LOWER_DISTANCE_MATRIX, UPPER_DISTANCE_MATRIX, DISTANCE_MATRIX, POINT_CLOUD, DIPHA, RIPSER }; - template T read(std::istream& s) { T result; s.read(reinterpret_cast(&result), sizeof(T)); @@ -733,7 +721,8 @@ compressed_lower_distance_matrix read_point_cloud(std::istream& input_stream) { index_t n = eucl_dist.size(); - std::cout << "point cloud with " << n << " points in dimension " << eucl_dist.points.front().size() << std::endl; + std::cout << "point cloud with " << n << " points in dimension " + << eucl_dist.points.front().size() << std::endl; std::vector distances; @@ -830,26 +819,30 @@ compressed_lower_distance_matrix read_file(std::istream& input_stream, file_form } void print_usage_and_exit(int exit_code) { - std::cerr << "Usage: " - << "ripser " - << "[options] [filename]" << std::endl - << std::endl - << "Options:" << std::endl - << std::endl - << " --help print this screen" << std::endl - << " --format use the specified file format for the input. Options are:" << std::endl - << " lower-distance (lower triangular distance matrix; default)" << std::endl - << " upper-distance (upper triangular distance matrix)" << std::endl - << " distance (full distance matrix)" << std::endl - << " point-cloud (point cloud in Euclidean space)" << std::endl - << " dipha (distance matrix in DIPHA file format)" << std::endl - << " ripser (distance matrix in Ripser binary file format)" << std::endl - << " --dim compute persistent homology up to dimension " << std::endl - << " --threshold compute Rips complexes up to diameter " << std::endl + std::cerr + << "Usage: " + << "ripser " + << "[options] [filename]" << std::endl + << std::endl + << "Options:" << std::endl + << std::endl + << " --help print this screen" << std::endl + << " --format use the specified file format for the input. Options are:" + << std::endl + << " lower-distance (lower triangular distance matrix; default)" + << std::endl + << " upper-distance (upper triangular distance matrix)" << std::endl + << " distance (full distance matrix)" << std::endl + << " point-cloud (point cloud in Euclidean space)" << std::endl + << " dipha (distance matrix in DIPHA file format)" << std::endl + << " ripser (distance matrix in Ripser binary file format)" + << std::endl + << " --dim compute persistent homology up to dimension " << std::endl + << " --threshold compute Rips complexes up to diameter " << std::endl #ifdef USE_COEFFICIENTS - << " --modulus

compute homology with coefficients in the prime field Z/

Z" + << " --modulus

compute homology with coefficients in the prime field Z/

Z" #endif - << std::endl; + << std::endl; exit(exit_code); } @@ -923,7 +916,61 @@ int main(int argc, char** argv) { std::cout << "distance matrix with " << dist.size() << " points" << std::endl; auto value_range = std::minmax_element(dist.distances.begin(), dist.distances.end()); - std::cout << "value range: [" << *value_range.first << "," << *value_range.second << "]" << std::endl; + std::cout << "value range: [" << *value_range.first << "," << *value_range.second << "]" + << std::endl; ripser(std::move(dist), dim_max, threshold, modulus).compute_barcodes(); } + +void ripser::compute_barcodes() { + + std::vector columns_to_reduce; + + { + union_find dset(n); + std::vector edges; + for (index_t index = binomial_coeff(n, 2); index-- > 0;) { + value_t diameter = compute_diameter(index, 1); + if (diameter <= threshold) edges.push_back(std::make_pair(diameter, index)); + } + std::sort(edges.rbegin(), edges.rend(), + greater_diameter_or_smaller_index()); + +#ifdef PRINT_PERSISTENCE_PAIRS + std::cout << "persistence intervals in dim 0:" << std::endl; +#endif + + std::vector vertices_of_edge(2); + for (auto e : edges) { + vertices_of_edge.clear(); + get_simplex_vertices(get_index(e), 1, n, std::back_inserter(vertices_of_edge)); + index_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]); + + if (u != v) { +#ifdef PRINT_PERSISTENCE_PAIRS + if (get_diameter(e) != 0) + std::cout << " [0," << get_diameter(e) << ")" << std::endl; +#endif + dset.link(u, v); + } else + columns_to_reduce.push_back(e); + } + std::reverse(columns_to_reduce.begin(), columns_to_reduce.end()); + +#ifdef PRINT_PERSISTENCE_PAIRS + for (index_t i = 0; i < n; ++i) + if (dset.find(i) == i) std::cout << " [0, )" << std::endl << std::flush; +#endif + } + + for (index_t dim = 1; dim <= dim_max; ++dim) { + hash_map pivot_column_index; + pivot_column_index.reserve(columns_to_reduce.size()); + + compute_pairs(columns_to_reduce, pivot_column_index, dim); + + if (dim < dim_max) { + assemble_columns_to_reduce(columns_to_reduce, pivot_column_index, dim + 1); + } + } +} -- cgit v1.2.3 From 2bed1bcf7f3d654b0f8332e003bb3ec602b84681 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 29 Dec 2016 17:59:03 +0100 Subject: code reformatting --- ripser.cpp | 247 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 121 insertions(+), 126 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 02bfac9..e17bc6a 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -464,227 +464,222 @@ public: } }; - void assemble_columns_to_reduce(std::vector& columns_to_reduce, - hash_map& pivot_column_index, index_t dim); - - void compute_pairs(std::vector& columns_to_reduce, - hash_map& pivot_column_index, index_t dim); - void compute_barcodes(); -}; -void ripser::assemble_columns_to_reduce(std::vector& columns_to_reduce, - hash_map& pivot_column_index, - index_t dim) { - index_t num_simplices = binomial_coeff(n, dim + 1); + void assemble_columns_to_reduce(std::vector& columns_to_reduce, + hash_map& pivot_column_index, index_t dim) { + index_t num_simplices = binomial_coeff(n, dim + 1); - columns_to_reduce.clear(); + columns_to_reduce.clear(); #ifdef INDICATE_PROGRESS - std::cout << "\033[K" - << "assembling " << num_simplices << " columns" << std::flush << "\r"; + std::cout << "\033[K" + << "assembling " << num_simplices << " columns" << std::flush << "\r"; #endif - for (index_t index = 0; index < num_simplices; ++index) { - if (pivot_column_index.find(index) == pivot_column_index.end()) { - value_t diameter = compute_diameter(index, dim); - if (diameter <= threshold) columns_to_reduce.push_back(std::make_pair(diameter, index)); + for (index_t index = 0; index < num_simplices; ++index) { + if (pivot_column_index.find(index) == pivot_column_index.end()) { + value_t diameter = compute_diameter(index, dim); + if (diameter <= threshold) + columns_to_reduce.push_back(std::make_pair(diameter, index)); #ifdef INDICATE_PROGRESS - if ((index + 1) % 1000 == 0) - std::cout << "\033[K" - << "assembled " << columns_to_reduce.size() << " out of " << (index + 1) - << "/" << num_simplices << " columns" << std::flush << "\r"; + if ((index + 1) % 1000 == 0) + std::cout << "\033[K" + << "assembled " << columns_to_reduce.size() << " out of " + << (index + 1) << "/" << num_simplices << " columns" << std::flush + << "\r"; #endif + } } - } #ifdef INDICATE_PROGRESS - std::cout << "\033[K" - << "sorting " << num_simplices << " columns" << std::flush << "\r"; + std::cout << "\033[K" + << "sorting " << num_simplices << " columns" << std::flush << "\r"; #endif - std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), - greater_diameter_or_smaller_index()); + std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), + greater_diameter_or_smaller_index()); #ifdef INDICATE_PROGRESS - std::cout << "\033[K"; + std::cout << "\033[K"; #endif -} + } -void ripser::compute_pairs(std::vector& columns_to_reduce, - hash_map& pivot_column_index, index_t dim) { + void compute_pairs(std::vector& columns_to_reduce, + hash_map& pivot_column_index, index_t dim) { #ifdef PRINT_PERSISTENCE_PAIRS - std::cout << "persistence intervals in dim " << dim << ":" << std::endl; + std::cout << "persistence intervals in dim " << dim << ":" << std::endl; #endif #ifdef ASSEMBLE_REDUCTION_MATRIX - compressed_sparse_matrix reduction_coefficients; + compressed_sparse_matrix reduction_coefficients; #else #ifdef USE_COEFFICIENTS - std::vector reduction_coefficients; + std::vector reduction_coefficients; #endif #endif - std::vector coface_entries; + std::vector coface_entries; - for (index_t i = 0; i < columns_to_reduce.size(); ++i) { - auto column_to_reduce = columns_to_reduce[i]; + for (index_t i = 0; i < columns_to_reduce.size(); ++i) { + auto column_to_reduce = columns_to_reduce[i]; #ifdef ASSEMBLE_REDUCTION_MATRIX - std::priority_queue, - greater_diameter_or_smaller_index> - reduction_column; + std::priority_queue, + greater_diameter_or_smaller_index> + reduction_column; #endif - std::priority_queue, - greater_diameter_or_smaller_index> - working_coboundary; + std::priority_queue, + greater_diameter_or_smaller_index> + working_coboundary; - value_t diameter = get_diameter(column_to_reduce); + value_t diameter = get_diameter(column_to_reduce); #ifdef INDICATE_PROGRESS - if ((i + 1) % 1000 == 0) - std::cout << "\033[K" - << "reducing column " << i + 1 << "/" << columns_to_reduce.size() - << " (diameter " << diameter << ")" << std::flush << "\r"; + if ((i + 1) % 1000 == 0) + std::cout << "\033[K" + << "reducing column " << i + 1 << "/" << columns_to_reduce.size() + << " (diameter " << diameter << ")" << std::flush << "\r"; #endif - index_t j = i; + index_t j = i; - // start with a dummy pivot entry with coefficient -1 in order to initialize - // working_coboundary with the coboundary of the simplex with index column_to_reduce - diameter_entry_t pivot(0, -1, -1 + modulus); + // start with a dummy pivot entry with coefficient -1 in order to initialize + // working_coboundary with the coboundary of the simplex with index column_to_reduce + diameter_entry_t pivot(0, -1, -1 + modulus); #ifdef ASSEMBLE_REDUCTION_MATRIX - // initialize reduction_coefficients as identity matrix - reduction_coefficients.append_column(); + // initialize reduction_coefficients as identity matrix + reduction_coefficients.append_column(); #endif #ifdef USE_COEFFICIENTS - reduction_coefficients.push_back(diameter_entry_t(column_to_reduce, 1)); + reduction_coefficients.push_back(diameter_entry_t(column_to_reduce, 1)); #endif - bool might_be_apparent_pair = (i == j); + bool might_be_apparent_pair = (i == j); - do { - const coefficient_t factor = modulus - get_coefficient(pivot); + do { + const coefficient_t factor = modulus - get_coefficient(pivot); #ifdef ASSEMBLE_REDUCTION_MATRIX #ifdef USE_COEFFICIENTS - auto coeffs_begin = reduction_coefficients.cbegin(j), - coeffs_end = reduction_coefficients.cend(j); + auto coeffs_begin = reduction_coefficients.cbegin(j), + coeffs_end = reduction_coefficients.cend(j); #else - std::vector coeffs; - coeffs.push_back(columns_to_reduce[j]); - for (auto it = reduction_coefficients.cbegin(j); it != reduction_coefficients.cend(j); - ++it) - coeffs.push_back(*it); - auto coeffs_begin = coeffs.begin(), coeffs_end = coeffs.end(); + std::vector coeffs; + coeffs.push_back(columns_to_reduce[j]); + for (auto it = reduction_coefficients.cbegin(j); + it != reduction_coefficients.cend(j); ++it) + coeffs.push_back(*it); + auto coeffs_begin = coeffs.begin(), coeffs_end = coeffs.end(); #endif #else #ifdef USE_COEFFICIENTS - auto coeffs_begin = &reduction_coefficients[j], - coeffs_end = &reduction_coefficients[j] + 1; + auto coeffs_begin = &reduction_coefficients[j], + coeffs_end = &reduction_coefficients[j] + 1; #else - auto coeffs_begin = &columns_to_reduce[j], coeffs_end = &columns_to_reduce[j] + 1; + auto coeffs_begin = &columns_to_reduce[j], coeffs_end = &columns_to_reduce[j] + 1; #endif #endif - for (auto it = coeffs_begin; it != coeffs_end; ++it) { - diameter_entry_t simplex = *it; - set_coefficient(simplex, get_coefficient(simplex) * factor % modulus); + for (auto it = coeffs_begin; it != coeffs_end; ++it) { + diameter_entry_t simplex = *it; + set_coefficient(simplex, get_coefficient(simplex) * factor % modulus); #ifdef ASSEMBLE_REDUCTION_MATRIX - reduction_column.push(simplex); -#endif - - coface_entries.clear(); - simplex_coboundary_enumerator cofaces(simplex, dim, *this); - while (cofaces.has_next()) { - diameter_entry_t coface = cofaces.next(); - if (get_diameter(coface) <= threshold) { - coface_entries.push_back(coface); - if (might_be_apparent_pair && - (get_diameter(simplex) == get_diameter(coface))) { - if (pivot_column_index.find(get_index(coface)) == - pivot_column_index.end()) { - pivot = coface; - goto found_persistence_pair; + reduction_column.push(simplex); +#endif + + coface_entries.clear(); + simplex_coboundary_enumerator cofaces(simplex, dim, *this); + while (cofaces.has_next()) { + diameter_entry_t coface = cofaces.next(); + if (get_diameter(coface) <= threshold) { + coface_entries.push_back(coface); + if (might_be_apparent_pair && + (get_diameter(simplex) == get_diameter(coface))) { + if (pivot_column_index.find(get_index(coface)) == + pivot_column_index.end()) { + pivot = coface; + goto found_persistence_pair; + } + might_be_apparent_pair = false; } - might_be_apparent_pair = false; } } + for (auto coface : coface_entries) working_coboundary.push(coface); } - for (auto coface : coface_entries) working_coboundary.push(coface); - } - pivot = get_pivot(working_coboundary, modulus); + pivot = get_pivot(working_coboundary, modulus); - if (get_index(pivot) != -1) { - auto pair = pivot_column_index.find(get_index(pivot)); + if (get_index(pivot) != -1) { + auto pair = pivot_column_index.find(get_index(pivot)); - if (pair != pivot_column_index.end()) { - j = pair->second; - continue; - } - } else { + if (pair != pivot_column_index.end()) { + j = pair->second; + continue; + } + } else { #ifdef PRINT_PERSISTENCE_PAIRS #ifdef INDICATE_PROGRESS - std::cout << "\033[K"; + std::cout << "\033[K"; #endif - std::cout << " [" << diameter << ", )" << std::endl << std::flush; + std::cout << " [" << diameter << ", )" << std::endl << std::flush; #endif - break; - } + break; + } - found_persistence_pair: + found_persistence_pair: #ifdef PRINT_PERSISTENCE_PAIRS - value_t death = get_diameter(pivot); - if (diameter != death) { + value_t death = get_diameter(pivot); + if (diameter != death) { #ifdef INDICATE_PROGRESS - std::cout << "\033[K"; + std::cout << "\033[K"; #endif - std::cout << " [" << diameter << "," << death << ")" << std::endl << std::flush; - } + std::cout << " [" << diameter << "," << death << ")" << std::endl << std::flush; + } #endif - pivot_column_index.insert(std::make_pair(get_index(pivot), i)); + pivot_column_index.insert(std::make_pair(get_index(pivot), i)); #ifdef USE_COEFFICIENTS - const coefficient_t inverse = multiplicative_inverse[get_coefficient(pivot)]; + const coefficient_t inverse = multiplicative_inverse[get_coefficient(pivot)]; #endif #ifdef ASSEMBLE_REDUCTION_MATRIX // replace current column of reduction_coefficients (with a single diagonal 1 entry) // by reduction_column (possibly with a different entry on the diagonal) #ifdef USE_COEFFICIENTS - reduction_coefficients.pop_back(); + reduction_coefficients.pop_back(); #else - pop_pivot(reduction_column, modulus); + pop_pivot(reduction_column, modulus); #endif - while (true) { - diameter_entry_t e = pop_pivot(reduction_column, modulus); - if (get_index(e) == -1) break; + while (true) { + diameter_entry_t e = pop_pivot(reduction_column, modulus); + if (get_index(e) == -1) break; #ifdef USE_COEFFICIENTS - set_coefficient(e, inverse * get_coefficient(e) % modulus); - assert(get_coefficient(e) > 0); + set_coefficient(e, inverse * get_coefficient(e) % modulus); + assert(get_coefficient(e) > 0); #endif - reduction_coefficients.push_back(e); - } + reduction_coefficients.push_back(e); + } #else #ifdef USE_COEFFICIENTS - reduction_coefficients.pop_back(); - reduction_coefficients.push_back(diameter_entry_t(column_to_reduce, inverse)); + reduction_coefficients.pop_back(); + reduction_coefficients.push_back(diameter_entry_t(column_to_reduce, inverse)); #endif #endif - break; - } while (true); - } + break; + } while (true); + } #ifdef INDICATE_PROGRESS - std::cout << "\033[K"; + std::cout << "\033[K"; #endif -} + } +}; enum file_format { LOWER_DISTANCE_MATRIX, -- cgit v1.2.3 From b945df6609d9198c34a982e70dee0773ee630897 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 29 Dec 2016 19:26:55 +0100 Subject: reordered initializers --- ripser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 49ff6a8..3054441 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -508,8 +508,8 @@ public: public: simplex_sparse_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, const ripser& _parent) - : parent(_parent), simplex(_simplex), idx_below(get_index(_simplex)), idx_above(0), - v(parent.n - 1), k(_dim + 1), max_vertex_below(parent.n - 1), modulus(parent.modulus), + : parent(_parent), idx_below(get_index(_simplex)), idx_above(0), + v(parent.n - 1), k(_dim + 1), max_vertex_below(parent.n - 1), simplex(_simplex), modulus(parent.modulus), dist(parent.dist), binomial_coeff(parent.binomial_coeff), vertices(parent.vertices), neighbor_it(parent.neighbor_it), neighbor_end(parent.neighbor_end) { -- cgit v1.2.3 From 2989ecd1047fcae2b8fead4b8fca1a4608342576 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 29 Dec 2016 23:07:00 +0100 Subject: use sparse distance matrix when threshold is given --- ripser.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 3054441..4ac5033 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -24,8 +24,6 @@ with this program. If not, see . //#define INDICATE_PROGRESS #define PRINT_PERSISTENCE_PAIRS -#define SPARSE_DISTANCE_MATRIX - //#define USE_GOOGLE_HASHMAP #include @@ -1063,14 +1061,14 @@ int main(int argc, char** argv) { std::cout << "value range: [" << *value_range.first << "," << *value_range.second << "]" << std::endl; -#ifdef SPARSE_DISTANCE_MATRIX - ripser(std::move(dist), dim_max, threshold, modulus) - .compute_barcodes(); -#else - ripser(sparse_distance_matrix(dist, threshold), dim_max, threshold, - modulus) - .compute_barcodes(); -#endif + if (threshold == std::numeric_limits::max()) + ripser(std::move(dist), dim_max, threshold, modulus) + .compute_barcodes(); + else + ripser(sparse_distance_matrix(dist, threshold), dim_max, threshold, + modulus) + .compute_barcodes(); + } template <> void ripser::compute_barcodes() { -- cgit v1.2.3 From 82b1e5ec6c9ee4aedc7c3e6701c0dec9f66bd56f Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Sat, 7 Jan 2017 00:24:40 +0100 Subject: constructors fixed --- ripser.cpp | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index e17bc6a..53fa4fa 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -103,8 +103,8 @@ static_assert(sizeof(entry_t) == sizeof(index_t), "size of entry_t is not the sa entry_t make_entry(index_t _index, coefficient_t _coefficient) { return entry_t(_index, _coefficient); } -index_t get_index(entry_t e) { return e.index; } -index_t get_coefficient(entry_t e) { return e.coefficient; } +index_t get_index(const entry_t& e) { return e.index; } +index_t get_coefficient(const entry_t& e) { return e.coefficient; } void set_coefficient(entry_t& e, const coefficient_t c) { e.coefficient = c; } bool operator==(const entry_t& e1, const entry_t& e2) { @@ -119,10 +119,10 @@ std::ostream& operator<<(std::ostream& stream, const entry_t& e) { #else typedef index_t entry_t; -const index_t get_index(entry_t i) { return i; } -index_t get_coefficient(entry_t i) { return 1; } +const index_t get_index(const entry_t& i) { return i; } +index_t get_coefficient(const entry_t& i) { return 1; } entry_t make_entry(index_t _index, coefficient_t _value) { return entry_t(_index); } -void set_coefficient(index_t& e, const coefficient_t c) {} +void set_coefficient(entry_t& e, const coefficient_t c) {} #endif @@ -131,22 +131,22 @@ const entry_t& get_entry(const entry_t& e) { return e; } class diameter_index_t : public std::pair { public: diameter_index_t() : std::pair() {} - diameter_index_t(std::pair p) : std::pair(p) {} + diameter_index_t(std::pair&& p) : std::pair(std::move(p)) {} }; -value_t get_diameter(diameter_index_t i) { return i.first; } -index_t get_index(diameter_index_t i) { return i.second; } +value_t get_diameter(const diameter_index_t& i) { return i.first; } +index_t get_index(const diameter_index_t& i) { return i.second; } class diameter_entry_t : public std::pair { public: diameter_entry_t(std::pair p) : std::pair(p) {} - diameter_entry_t(entry_t e) : std::pair(0, e) {} - diameter_entry_t() : diameter_entry_t(0) {} + diameter_entry_t(entry_t&& e) : std::pair(0, std::move(e)) {} + diameter_entry_t() : diameter_entry_t(entry_t()) {} diameter_entry_t(value_t _diameter, index_t _index, coefficient_t _coefficient) : std::pair(_diameter, make_entry(_index, _coefficient)) {} - diameter_entry_t(diameter_index_t _diameter_index, coefficient_t _coefficient) + diameter_entry_t(const diameter_index_t& _diameter_index, coefficient_t _coefficient) : std::pair(get_diameter(_diameter_index), make_entry(get_index(_diameter_index), _coefficient)) {} - diameter_entry_t(diameter_index_t _diameter_index) : diameter_entry_t(_diameter_index, 1) {} + diameter_entry_t(const diameter_index_t& _diameter_index) : diameter_entry_t(_diameter_index, 1) {} }; const entry_t& get_entry(const diameter_entry_t& p) { return p.second; } @@ -230,9 +230,15 @@ public: std::vector> points; euclidean_distance_matrix(std::vector>&& _points) - : points(std::move(_points)) {} + : points(std::move(_points)) { + for (auto p: points) { + assert(p.size() == points.front().size()); + } + } value_t operator()(const index_t i, const index_t j) const { + assert(i < points.size()); + assert(j < points.size()); return std::sqrt(std::inner_product( points[i].begin(), points[i].end(), points[j].begin(), value_t(), std::plus(), [](value_t u, value_t v) { return (u - v) * (u - v); })); @@ -537,7 +543,7 @@ public: value_t diameter = get_diameter(column_to_reduce); #ifdef INDICATE_PROGRESS - if ((i + 1) % 1000 == 0) + //if ((i + 1) % 1000 == 0) std::cout << "\033[K" << "reducing column " << i + 1 << "/" << columns_to_reduce.size() << " (diameter " << diameter << ")" << std::flush << "\r"; -- cgit v1.2.3 From 31a18897fb52e4e98faed5562e6b97da1e024b4c Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Sat, 7 Jan 2017 00:31:25 +0100 Subject: move --- ripser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 701ba35..fbbd345 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -1071,8 +1071,8 @@ int main(int argc, char** argv) { ripser(std::move(dist), dim_max, threshold, modulus) .compute_barcodes(); else - ripser(sparse_distance_matrix(dist, threshold), dim_max, threshold, - modulus) + ripser(sparse_distance_matrix(std::move(dist), threshold), dim_max, + threshold, modulus) .compute_barcodes(); } -- cgit v1.2.3 From 0dc8dc9c9dd444951928dcf6c59967f9f617f488 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Mon, 9 Jan 2017 11:56:45 +0100 Subject: benchmark H^1 --- benchmarks/sphere_3_192/run_benchmarks.sh | 4 ++++ benchmarks/sphere_3_192/run_dionysus.sh | 1 + benchmarks/sphere_3_192/run_dipha.sh | 1 + benchmarks/sphere_3_192/run_gudhi.sh | 1 + benchmarks/sphere_3_192/run_ripser.sh | 1 + 5 files changed, 8 insertions(+) create mode 100644 benchmarks/sphere_3_192/run_benchmarks.sh create mode 100644 benchmarks/sphere_3_192/run_dionysus.sh create mode 100644 benchmarks/sphere_3_192/run_dipha.sh create mode 100644 benchmarks/sphere_3_192/run_gudhi.sh create mode 100644 benchmarks/sphere_3_192/run_ripser.sh diff --git a/benchmarks/sphere_3_192/run_benchmarks.sh b/benchmarks/sphere_3_192/run_benchmarks.sh new file mode 100644 index 0000000..14cac6c --- /dev/null +++ b/benchmarks/sphere_3_192/run_benchmarks.sh @@ -0,0 +1,4 @@ +. run_dionysus.sh +. run_dipha.sh +. run_gudhi.sh +. run_ripser.sh diff --git a/benchmarks/sphere_3_192/run_dionysus.sh b/benchmarks/sphere_3_192/run_dionysus.sh new file mode 100644 index 0000000..1e5c7d3 --- /dev/null +++ b/benchmarks/sphere_3_192/run_dionysus.sh @@ -0,0 +1 @@ +/usr/bin/time -l ~/Source/Dionysus/examples/cohomology/rips-pairwise-cohomology -s2 -p2 ~/Bitbucket/phat-paper/benchmark/point\ cloud/sphere_3_192_points.dat 2>&1 | tee dionysus.out.txt diff --git a/benchmarks/sphere_3_192/run_dipha.sh b/benchmarks/sphere_3_192/run_dipha.sh new file mode 100644 index 0000000..312bcd7 --- /dev/null +++ b/benchmarks/sphere_3_192/run_dipha.sh @@ -0,0 +1 @@ +/usr/bin/time -l ~/Bitbucket/dipha/dipha --benchmark --upper_dim 2 --dual ~/Bitbucket/phat-paper/benchmark/dipha/sphere_3_192.complex /dev/null 2>&1 | tee dipha.out.txt diff --git a/benchmarks/sphere_3_192/run_gudhi.sh b/benchmarks/sphere_3_192/run_gudhi.sh new file mode 100644 index 0000000..a4c6c51 --- /dev/null +++ b/benchmarks/sphere_3_192/run_gudhi.sh @@ -0,0 +1 @@ +/usr/bin/time -l ~/Source/Gudhi_library_1.3.1/example/Persistent_cohomology/rips_persistence -d2 -p2 ~/Bitbucket/phat-paper/benchmark/point\ cloud/sphere_3_192_points.dat -o/dev/null 2>&1 | tee gudhi.out.txt diff --git a/benchmarks/sphere_3_192/run_ripser.sh b/benchmarks/sphere_3_192/run_ripser.sh new file mode 100644 index 0000000..209c410 --- /dev/null +++ b/benchmarks/sphere_3_192/run_ripser.sh @@ -0,0 +1 @@ +/usr/bin/time -l ~/Bitbucket/ripser/ripser ~/Bitbucket/ripser/examples/sphere_3_192.lower_distance_matrix 2>&1 | tee ripser.out.txt -- cgit v1.2.3 From 3c3f3e74e26a1534202cf0235956c8a7924085ed Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Wed, 11 Jan 2017 13:16:58 +0100 Subject: gudhi benchmark output --- benchmarks/sphere_3_192/run_gudhi.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/sphere_3_192/run_gudhi.sh b/benchmarks/sphere_3_192/run_gudhi.sh index a4c6c51..80ae403 100644 --- a/benchmarks/sphere_3_192/run_gudhi.sh +++ b/benchmarks/sphere_3_192/run_gudhi.sh @@ -1 +1 @@ -/usr/bin/time -l ~/Source/Gudhi_library_1.3.1/example/Persistent_cohomology/rips_persistence -d2 -p2 ~/Bitbucket/phat-paper/benchmark/point\ cloud/sphere_3_192_points.dat -o/dev/null 2>&1 | tee gudhi.out.txt +/usr/bin/time -l ~/Source/Gudhi_library_1.3.1/example/Persistent_cohomology/rips_persistence -d2 -p2 ~/Bitbucket/phat-paper/benchmark/point\ cloud/sphere_3_192_points.dat 2>&1 | tee gudhi.out.txt -- cgit v1.2.3 From f84042ed1b0b1de7f66e57d9a516cf60736af91a Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Wed, 11 Jan 2017 13:22:21 +0100 Subject: benchmark results --- benchmarks/sphere_3_192/dionysus.out.txt | 27 ++++ benchmarks/sphere_3_192/dipha.out.txt | 55 +++++++ benchmarks/sphere_3_192/gudhi.out.txt | 262 ++++++++++++++++++++++++++++++ benchmarks/sphere_3_192/ripser.out.txt | 264 +++++++++++++++++++++++++++++++ 4 files changed, 608 insertions(+) create mode 100644 benchmarks/sphere_3_192/dionysus.out.txt create mode 100644 benchmarks/sphere_3_192/dipha.out.txt create mode 100644 benchmarks/sphere_3_192/gudhi.out.txt create mode 100644 benchmarks/sphere_3_192/ripser.out.txt diff --git a/benchmarks/sphere_3_192/dionysus.out.txt b/benchmarks/sphere_3_192/dionysus.out.txt new file mode 100644 index 0000000..3191f98 --- /dev/null +++ b/benchmarks/sphere_3_192/dionysus.out.txt @@ -0,0 +1,27 @@ +Boundary matrix: +Cocycles: *.ccl +Vertices: +Diagram: +Simplex vector generated, size: 1179808 + +0% 10 20 30 40 50 60 70 80 90 100% +|----|----|----|----|----|----|----|----|----|----| +*************************************************** +Rips timer : Elapsed time [4.39] seconds +Persistence timer : Elapsed time [2.55] seconds +Total timer : Elapsed time [7.88] seconds + 7.99 real 7.88 user 0.08 sys + 141664256 maximum resident set size + 0 average shared memory size + 0 average unshared data size + 0 average unshared stack size + 34606 page reclaims + 0 page faults + 0 swaps + 0 block input operations + 0 block output operations + 0 messages sent + 0 messages received + 0 signals received + 0 voluntary context switches + 2629 involuntary context switches diff --git a/benchmarks/sphere_3_192/dipha.out.txt b/benchmarks/sphere_3_192/dipha.out.txt new file mode 100644 index 0000000..bae5fc7 --- /dev/null +++ b/benchmarks/sphere_3_192/dipha.out.txt @@ -0,0 +1,55 @@ + +Input filename: +/Users/uli/Bitbucket/phat-paper/benchmark/dipha/sphere_3_192.complex + +upper_dim: 2 + +Number of processes used: +1 + +Detailed information for rank 0: + time prior mem peak mem bytes recv + 0.0s 3 MB 4 MB 0 MB complex.load_binary( input_filename, upper_dim ); + +Number of cells in input: +1179808 + 0.2s 4 MB 40 MB 0 MB get_filtration_to_cell_map( complex, dualize, filtration_to_cell_map ); + 0.1s 40 MB 127 MB 18 MB get_cell_to_filtration_map( complex.get_num_cells(), filtration_to_cell_map, cell_to_filtration_map ); + 0.0s 154 MB 156 MB 0 MB generate_unreduced_columns( complex, filtration_to_cell_map, cell_to_filtration_map, cur_dim, dualize, unreduced_columns ); + 0.0s 153 MB 156 MB 0 MB reduction_kernel( complex.get_num_cells(), unreduced_columns, reduced_columns ); + 0.3s 151 MB 165 MB 53 MB generate_unreduced_columns( complex, filtration_to_cell_map, cell_to_filtration_map, cur_dim, dualize, unreduced_columns ); + 0.1s 136 MB 169 MB 0 MB reduction_kernel( complex.get_num_cells(), unreduced_columns, reduced_columns ); + 0.1s 167 MB 169 MB 1 MB dipha::outputs::save_persistence_diagram( output_filename, complex, filtration_to_cell_map, reduced_columns, dualize, upper_dim ); + +Overall running time in seconds: +0.9 + +Reduction kernel running time in seconds: +0.1 + +Overall peak mem in GB of all ranks: +0.2 + +Individual peak mem in GB of per rank: +0.2 + +Maximal communication traffic (without sorting) in GB between any pair of nodes: +0.1 + +Total communication traffic (without sorting) in GB between all pairs of nodes: +0.1 + 0.94 real 0.75 user 0.16 sys + 177598464 maximum resident set size + 0 average shared memory size + 0 average unshared data size + 0 average unshared stack size + 78159 page reclaims + 0 page faults + 0 swaps + 0 block input operations + 0 block output operations + 0 messages sent + 0 messages received + 0 signals received + 5 voluntary context switches + 333 involuntary context switches diff --git a/benchmarks/sphere_3_192/gudhi.out.txt b/benchmarks/sphere_3_192/gudhi.out.txt new file mode 100644 index 0000000..1a0cddf --- /dev/null +++ b/benchmarks/sphere_3_192/gudhi.out.txt @@ -0,0 +1,262 @@ +The complex contains 1179808 simplices + and has dimension 2 +2 0 0 inf +2 1 0.316534 0.682559 +2 1 0.304761 0.647803 +2 0 0 0.332695 +2 0 0 0.323964 +2 0 0 0.319493 +2 0 0 0.316023 +2 1 0.34298 0.65758 +2 0 0 0.304062 +2 0 0 0.297933 +2 0 0 0.297053 +2 0 0 0.293466 +2 1 0.347806 0.638039 +2 0 0 0.289189 +2 0 0 0.288591 +2 0 0 0.287316 +2 0 0 0.285416 +2 0 0 0.283881 +2 0 0 0.283562 +2 0 0 0.282169 +2 0 0 0.280629 +2 0 0 0.277582 +2 0 0 0.277191 +2 0 0 0.276431 +2 0 0 0.274611 +2 0 0 0.270996 +2 0 0 0.268806 +2 0 0 0.266635 +2 0 0 0.266592 +2 0 0 0.264483 +2 0 0 0.264334 +2 0 0 0.257997 +2 0 0 0.25725 +2 0 0 0.253227 +2 0 0 0.253163 +2 0 0 0.249345 +2 0 0 0.249339 +2 0 0 0.248879 +2 0 0 0.247042 +2 0 0 0.246491 +2 0 0 0.24509 +2 0 0 0.24348 +2 0 0 0.240632 +2 0 0 0.23879 +2 0 0 0.237571 +2 0 0 0.234969 +2 0 0 0.234112 +2 0 0 0.231675 +2 0 0 0.231179 +2 1 0.35058 0.580726 +2 0 0 0.228917 +2 0 0 0.2286 +2 0 0 0.227933 +2 0 0 0.227524 +2 0 0 0.223232 +2 0 0 0.218561 +2 0 0 0.218526 +2 0 0 0.215759 +2 0 0 0.214018 +2 1 0.347388 0.559978 +2 0 0 0.210372 +2 0 0 0.208851 +2 0 0 0.208063 +2 0 0 0.207714 +2 0 0 0.207261 +2 0 0 0.207016 +2 0 0 0.205389 +2 0 0 0.204544 +2 0 0 0.204208 +2 0 0 0.203812 +2 0 0 0.202564 +2 0 0 0.201961 +2 0 0 0.199673 +2 0 0 0.197377 +2 0 0 0.195722 +2 0 0 0.193804 +2 0 0 0.193791 +2 0 0 0.192733 +2 0 0 0.192406 +2 0 0 0.192356 +2 0 0 0.191661 +2 0 0 0.190642 +2 1 0.352356 0.541947 +2 0 0 0.189106 +2 0 0 0.184757 +2 0 0 0.18428 +2 0 0 0.179609 +2 1 0.301986 0.478334 +2 0 0 0.176306 +2 0 0 0.175016 +2 0 0 0.17493 +2 0 0 0.174172 +2 0 0 0.173684 +2 0 0 0.173586 +2 0 0 0.173412 +2 0 0 0.168587 +2 0 0 0.167455 +2 0 0 0.165907 +2 0 0 0.165592 +2 0 0 0.165494 +2 0 0 0.165314 +2 0 0 0.165202 +2 0 0 0.164815 +2 0 0 0.164809 +2 0 0 0.162464 +2 1 0.322683 0.482958 +2 0 0 0.159282 +2 0 0 0.158413 +2 0 0 0.157373 +2 0 0 0.157293 +2 0 0 0.157251 +2 0 0 0.1569 +2 0 0 0.15587 +2 0 0 0.154095 +2 0 0 0.15244 +2 0 0 0.151643 +2 0 0 0.150747 +2 0 0 0.149226 +2 0 0 0.149017 +2 0 0 0.148506 +2 0 0 0.147427 +2 0 0 0.147289 +2 0 0 0.147203 +2 0 0 0.145725 +2 0 0 0.145018 +2 0 0 0.143151 +2 0 0 0.143085 +2 0 0 0.142834 +2 0 0 0.142537 +2 0 0 0.142152 +2 0 0 0.141823 +2 0 0 0.138674 +2 1 0.377729 0.514046 +2 0 0 0.135402 +2 0 0 0.134886 +2 0 0 0.133722 +2 0 0 0.133525 +2 0 0 0.133033 +2 0 0 0.131638 +2 0 0 0.131438 +2 0 0 0.129741 +2 0 0 0.127864 +2 0 0 0.127383 +2 0 0 0.126595 +2 0 0 0.124774 +2 1 0.339394 0.463666 +2 0 0 0.123527 +2 0 0 0.122089 +2 0 0 0.121955 +2 0 0 0.119187 +2 1 0.2576 0.373749 +2 0 0 0.115939 +2 1 0.370051 0.483155 +2 0 0 0.111798 +2 0 0 0.111131 +2 0 0 0.109526 +2 0 0 0.108768 +2 1 0.386278 0.4922 +2 1 0.443911 0.54761 +2 1 0.374531 0.477153 +2 1 0.354747 0.454956 +2 0 0 0.0994522 +2 1 0.318032 0.417462 +2 0 0 0.0988752 +2 0 0 0.0970981 +2 0 0 0.0959033 +2 0 0 0.0884133 +2 0 0 0.0870489 +2 0 0 0.0857401 +2 0 0 0.084341 +2 0 0 0.0831521 +2 0 0 0.0831358 +2 0 0 0.0814685 +2 0 0 0.0802451 +2 0 0 0.0800348 +2 0 0 0.0792212 +2 0 0 0.0782455 +2 0 0 0.076909 +2 0 0 0.0753955 +2 1 0.324159 0.399094 +2 0 0 0.0746054 +2 0 0 0.0743236 +2 0 0 0.0741239 +2 1 0.413789 0.487379 +2 0 0 0.0728647 +2 0 0 0.0714516 +2 0 0 0.0702075 +2 0 0 0.0692368 +2 1 0.409968 0.478461 +2 0 0 0.0672609 +2 0 0 0.0651112 +2 0 0 0.0637053 +2 0 0 0.0633425 +2 1 0.298341 0.360737 +2 0 0 0.0623736 +2 1 0.309419 0.37151 +2 1 0.411549 0.471715 +2 0 0 0.0593071 +2 0 0 0.057488 +2 1 0.377019 0.434385 +2 1 0.329066 0.386148 +2 0 0 0.0560443 +2 0 0 0.0559886 +2 0 0 0.0522132 +2 0 0 0.0515157 +2 1 0.412572 0.46308 +2 0 0 0.0496187 +2 0 0 0.048826 +2 0 0 0.0487061 +2 1 0.240869 0.288747 +2 0 0 0.0471186 +2 1 0.531636 0.578093 +2 1 0.530723 0.576869 +2 1 0.33364 0.3797 +2 1 0.431628 0.477277 +2 0 0 0.0433426 +2 1 0.344005 0.387193 +2 1 0.463389 0.505345 +2 1 0.361715 0.403181 +2 1 0.381084 0.421374 +2 1 0.253337 0.292286 +2 0 0 0.0387451 +2 0 0 0.037954 +2 1 0.377147 0.414788 +2 1 0.308779 0.346297 +2 1 0.317521 0.349622 +2 0 0 0.0311057 +2 1 0.331259 0.356381 +2 1 0.279016 0.301331 +2 0 0 0.0217315 +2 1 0.350913 0.369543 +2 1 0.324571 0.343083 +2 0 0 0.0173134 +2 1 0.33392 0.35111 +2 1 0.542696 0.558863 +2 1 0.33836 0.350411 +2 1 0.29997 0.311993 +2 0 0 0.0120098 +2 1 0.189652 0.197515 +2 0 0 0.00391946 +2 0 0 0.0036753 +2 1 0.445398 0.448892 +2 1 0.24546 0.248903 +2 1 0.301045 0.303943 +2 1 0.309336 0.310216 + 0.59 real 0.56 user 0.02 sys + 69210112 maximum resident set size + 0 average shared memory size + 0 average unshared data size + 0 average unshared stack size + 16916 page reclaims + 0 page faults + 0 swaps + 0 block input operations + 0 block output operations + 0 messages sent + 0 messages received + 0 signals received + 10 voluntary context switches + 125 involuntary context switches diff --git a/benchmarks/sphere_3_192/ripser.out.txt b/benchmarks/sphere_3_192/ripser.out.txt new file mode 100644 index 0000000..bc741ae --- /dev/null +++ b/benchmarks/sphere_3_192/ripser.out.txt @@ -0,0 +1,264 @@ +distance matrix with 192 points +value range: [0.00367531,2] +persistence intervals in dim 0: + [0,0.00367531) + [0,0.00391946) + [0,0.0120098) + [0,0.0173134) + [0,0.0217315) + [0,0.0311057) + [0,0.037954) + [0,0.0387451) + [0,0.0433426) + [0,0.0471186) + [0,0.0487061) + [0,0.048826) + [0,0.0496187) + [0,0.0515157) + [0,0.0522132) + [0,0.0559886) + [0,0.0560443) + [0,0.057488) + [0,0.0593071) + [0,0.0623736) + [0,0.0633425) + [0,0.0637053) + [0,0.0651112) + [0,0.0672609) + [0,0.0692368) + [0,0.0702075) + [0,0.0714516) + [0,0.0728647) + [0,0.0741239) + [0,0.0743236) + [0,0.0746054) + [0,0.0753955) + [0,0.076909) + [0,0.0782455) + [0,0.0792212) + [0,0.0800348) + [0,0.0802451) + [0,0.0814685) + [0,0.0831358) + [0,0.0831521) + [0,0.084341) + [0,0.0857401) + [0,0.0870489) + [0,0.0884133) + [0,0.0959033) + [0,0.0970981) + [0,0.0988752) + [0,0.0994522) + [0,0.108768) + [0,0.109526) + [0,0.111131) + [0,0.111798) + [0,0.115939) + [0,0.119187) + [0,0.121955) + [0,0.122089) + [0,0.123527) + [0,0.124774) + [0,0.126595) + [0,0.127383) + [0,0.127864) + [0,0.129741) + [0,0.131438) + [0,0.131638) + [0,0.133033) + [0,0.133525) + [0,0.133722) + [0,0.134886) + [0,0.135402) + [0,0.138674) + [0,0.141823) + [0,0.142152) + [0,0.142537) + [0,0.142834) + [0,0.143085) + [0,0.143151) + [0,0.145018) + [0,0.145725) + [0,0.147203) + [0,0.147289) + [0,0.147427) + [0,0.148506) + [0,0.149017) + [0,0.149226) + [0,0.150747) + [0,0.151643) + [0,0.15244) + [0,0.154095) + [0,0.15587) + [0,0.1569) + [0,0.157251) + [0,0.157293) + [0,0.157373) + [0,0.158413) + [0,0.159282) + [0,0.162464) + [0,0.164809) + [0,0.164815) + [0,0.165202) + [0,0.165314) + [0,0.165494) + [0,0.165592) + [0,0.165907) + [0,0.167455) + [0,0.168587) + [0,0.173412) + [0,0.173586) + [0,0.173684) + [0,0.174172) + [0,0.17493) + [0,0.175016) + [0,0.176306) + [0,0.179609) + [0,0.18428) + [0,0.184757) + [0,0.189106) + [0,0.190642) + [0,0.191661) + [0,0.192356) + [0,0.192406) + [0,0.192733) + [0,0.193791) + [0,0.193804) + [0,0.195722) + [0,0.197377) + [0,0.199673) + [0,0.201961) + [0,0.202564) + [0,0.203812) + [0,0.204208) + [0,0.204544) + [0,0.205389) + [0,0.207016) + [0,0.207261) + [0,0.207714) + [0,0.208063) + [0,0.208851) + [0,0.210372) + [0,0.214018) + [0,0.215759) + [0,0.218526) + [0,0.218561) + [0,0.223232) + [0,0.227524) + [0,0.227933) + [0,0.2286) + [0,0.228917) + [0,0.231179) + [0,0.231675) + [0,0.234112) + [0,0.234969) + [0,0.237571) + [0,0.23879) + [0,0.240632) + [0,0.24348) + [0,0.24509) + [0,0.246491) + [0,0.247042) + [0,0.248879) + [0,0.249339) + [0,0.249345) + [0,0.253163) + [0,0.253227) + [0,0.25725) + [0,0.257997) + [0,0.264334) + [0,0.264483) + [0,0.266592) + [0,0.266635) + [0,0.268806) + [0,0.270996) + [0,0.274611) + [0,0.276431) + [0,0.277191) + [0,0.277582) + [0,0.280629) + [0,0.282169) + [0,0.283562) + [0,0.283881) + [0,0.285416) + [0,0.287316) + [0,0.288591) + [0,0.289189) + [0,0.293466) + [0,0.297053) + [0,0.297933) + [0,0.304062) + [0,0.316023) + [0,0.319493) + [0,0.323964) + [0,0.332695) + [0, ) +persistence intervals in dim 1: + [0.542696,0.558863) + [0.531636,0.578093) + [0.530723,0.576869) + [0.463389,0.505345) + [0.445398,0.448892) + [0.443911,0.54761) + [0.431628,0.477277) + [0.413789,0.487379) + [0.412572,0.46308) + [0.411549,0.471715) + [0.409968,0.478461) + [0.386278,0.4922) + [0.381084,0.421374) + [0.377729,0.514046) + [0.377147,0.414788) + [0.377019,0.434385) + [0.374531,0.477153) + [0.370051,0.483155) + [0.361715,0.403181) + [0.354747,0.454956) + [0.352356,0.541947) + [0.350913,0.369543) + [0.35058,0.580726) + [0.347806,0.638039) + [0.347388,0.559978) + [0.344005,0.387193) + [0.34298,0.65758) + [0.339394,0.463666) + [0.33836,0.350411) + [0.33392,0.35111) + [0.33364,0.3797) + [0.331259,0.356381) + [0.329066,0.386148) + [0.324571,0.343083) + [0.324159,0.399094) + [0.322683,0.482958) + [0.318032,0.417462) + [0.317521,0.349622) + [0.316534,0.682559) + [0.309419,0.37151) + [0.309336,0.310216) + [0.308779,0.346297) + [0.304761,0.647803) + [0.301986,0.478334) + [0.301045,0.303943) + [0.29997,0.311993) + [0.298341,0.360737) + [0.279016,0.301331) + [0.2576,0.373749) + [0.253337,0.292286) + [0.24546,0.248903) + [0.240869,0.288747) + [0.189652,0.197515) + 0.03 real 0.03 user 0.00 sys + 3276800 maximum resident set size + 0 average shared memory size + 0 average unshared data size + 0 average unshared stack size + 819 page reclaims + 0 page faults + 0 swaps + 0 block input operations + 0 block output operations + 0 messages sent + 0 messages received + 0 signals received + 7 voluntary context switches + 119 involuntary context switches -- cgit v1.2.3 From eb8a0a7d92c1b3260ff33e8f213b7369dd038d0b Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Wed, 22 Feb 2017 12:55:07 +0100 Subject: typo in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0c5a2e6..4aae03d 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ The input is given either in a file whose name is passed as an argument, or thro - `--format`: use the specified file format for the input. The following formats are supported: - `lower-distance` (default if no format is specified): lower triangular distance matrix; a comma (or whitespace, or other non-numerical character) separated list of the distance matrix entries below the diagonal, sorted lexicographically by row index, then column index - `upper-distance`: upper triangular distance matrix; similar to the previous, but for the entries above the diagonal; suitable for output from the MATLAB functions `pdist` or `seqpdist`, exported to a CSV file - - `distances`: full distance matrix; similar to the above, but for all entries of the distance matrix + - `distance`: full distance matrix; similar to the above, but for all entries of the distance matrix - `dipha`: DIPHA distance matrix as described on the [DIPHA] website - `point-cloud`: point cloud; a comma (or whitespace, or other non-numerical character) separated list of coordinates of the points in some Euclidean space, one point per line - `--dim k`: compute persistent homology up to dimension *k* -- cgit v1.2.3 From a5ada276181dadded36a8cb19d83466d1f098278 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Mon, 20 Mar 2017 15:45:21 +0100 Subject: updated benchmark --- benchmarks/sphere_3_192/dionysus.dim_1.out.txt | 27 +++ benchmarks/sphere_3_192/dionysus.dim_2.out.txt | 27 +++ benchmarks/sphere_3_192/dipha.dim_1.out.txt | 55 +++++ benchmarks/sphere_3_192/dipha.dim_2.out.txt | 57 ++++++ benchmarks/sphere_3_192/gudhi.dim_1.out.txt | 262 ++++++++++++++++++++++++ benchmarks/sphere_3_192/gudhi.dim_2.out.txt | 263 ++++++++++++++++++++++++ benchmarks/sphere_3_192/ripser.dim_1.out.txt | 264 ++++++++++++++++++++++++ benchmarks/sphere_3_192/ripser.dim_2.out.txt | 266 +++++++++++++++++++++++++ benchmarks/sphere_3_192/run_dionysus.sh | 4 +- benchmarks/sphere_3_192/run_dipha.sh | 4 +- benchmarks/sphere_3_192/run_gudhi.sh | 4 +- benchmarks/sphere_3_192/run_ripser.sh | 4 +- 12 files changed, 1233 insertions(+), 4 deletions(-) create mode 100644 benchmarks/sphere_3_192/dionysus.dim_1.out.txt create mode 100644 benchmarks/sphere_3_192/dionysus.dim_2.out.txt create mode 100644 benchmarks/sphere_3_192/dipha.dim_1.out.txt create mode 100644 benchmarks/sphere_3_192/dipha.dim_2.out.txt create mode 100644 benchmarks/sphere_3_192/gudhi.dim_1.out.txt create mode 100644 benchmarks/sphere_3_192/gudhi.dim_2.out.txt create mode 100644 benchmarks/sphere_3_192/ripser.dim_1.out.txt create mode 100644 benchmarks/sphere_3_192/ripser.dim_2.out.txt diff --git a/benchmarks/sphere_3_192/dionysus.dim_1.out.txt b/benchmarks/sphere_3_192/dionysus.dim_1.out.txt new file mode 100644 index 0000000..0e8cd4d --- /dev/null +++ b/benchmarks/sphere_3_192/dionysus.dim_1.out.txt @@ -0,0 +1,27 @@ +Boundary matrix: +Cocycles: *.ccl +Vertices: +Diagram: +Simplex vector generated, size: 1179808 + +0% 10 20 30 40 50 60 70 80 90 100% +|----|----|----|----|----|----|----|----|----|----| +*************************************************** +Rips timer : Elapsed time [4.19] seconds +Persistence timer : Elapsed time [2.38] seconds +Total timer : Elapsed time [7.45] seconds + 7.54 real 7.46 user 0.06 sys + 142344192 maximum resident set size + 0 average shared memory size + 0 average unshared data size + 0 average unshared stack size + 34700 page reclaims + 72 page faults + 0 swaps + 5 block input operations + 0 block output operations + 0 messages sent + 0 messages received + 0 signals received + 7 voluntary context switches + 212 involuntary context switches diff --git a/benchmarks/sphere_3_192/dionysus.dim_2.out.txt b/benchmarks/sphere_3_192/dionysus.dim_2.out.txt new file mode 100644 index 0000000..3495e23 --- /dev/null +++ b/benchmarks/sphere_3_192/dionysus.dim_2.out.txt @@ -0,0 +1,27 @@ +Boundary matrix: +Cocycles: *.ccl +Vertices: +Diagram: +Simplex vector generated, size: 56050288 + +0% 10 20 30 40 50 60 70 80 90 100% +|----|----|----|----|----|----|----|----|----|----| +*************************************************** +Rips timer : Elapsed time [256.35] seconds +Persistence timer : Elapsed time [205.61] seconds +Total timer : Elapsed time [528.91] seconds + 532.99 real 527.96 user 4.95 sys +3376783360 maximum resident set size + 0 average shared memory size + 0 average unshared data size + 0 average unshared stack size + 1430837 page reclaims + 0 page faults + 0 swaps + 0 block input operations + 0 block output operations + 0 messages sent + 0 messages received + 0 signals received + 0 voluntary context switches + 17326 involuntary context switches diff --git a/benchmarks/sphere_3_192/dipha.dim_1.out.txt b/benchmarks/sphere_3_192/dipha.dim_1.out.txt new file mode 100644 index 0000000..133977f --- /dev/null +++ b/benchmarks/sphere_3_192/dipha.dim_1.out.txt @@ -0,0 +1,55 @@ + +Input filename: +/Users/uli/Bitbucket/phat-paper/benchmark/dipha/sphere_3_192.complex + +upper_dim: 2 + +Number of processes used: +1 + +Detailed information for rank 0: + time prior mem peak mem bytes recv + 0.0s 3 MB 4 MB 0 MB complex.load_binary( input_filename, upper_dim ); + +Number of cells in input: +1179808 + 0.2s 4 MB 40 MB 0 MB get_filtration_to_cell_map( complex, dualize, filtration_to_cell_map ); + 0.1s 40 MB 127 MB 18 MB get_cell_to_filtration_map( complex.get_num_cells(), filtration_to_cell_map, cell_to_filtration_map ); + 0.0s 154 MB 156 MB 0 MB generate_unreduced_columns( complex, filtration_to_cell_map, cell_to_filtration_map, cur_dim, dualize, unreduced_columns ); + 0.0s 153 MB 156 MB 0 MB reduction_kernel( complex.get_num_cells(), unreduced_columns, reduced_columns ); + 0.3s 150 MB 165 MB 53 MB generate_unreduced_columns( complex, filtration_to_cell_map, cell_to_filtration_map, cur_dim, dualize, unreduced_columns ); + 0.1s 136 MB 169 MB 0 MB reduction_kernel( complex.get_num_cells(), unreduced_columns, reduced_columns ); + 0.1s 167 MB 169 MB 1 MB dipha::outputs::save_persistence_diagram( output_filename, complex, filtration_to_cell_map, reduced_columns, dualize, upper_dim ); + +Overall running time in seconds: +0.8 + +Reduction kernel running time in seconds: +0.1 + +Overall peak mem in GB of all ranks: +0.2 + +Individual peak mem in GB of per rank: +0.2 + +Maximal communication traffic (without sorting) in GB between any pair of nodes: +0.1 + +Total communication traffic (without sorting) in GB between all pairs of nodes: +0.1 + 0.90 real 0.71 user 0.15 sys + 177610752 maximum resident set size + 0 average shared memory size + 0 average unshared data size + 0 average unshared stack size + 78019 page reclaims + 164 page faults + 0 swaps + 10 block input operations + 8 block output operations + 0 messages sent + 0 messages received + 0 signals received + 48 voluntary context switches + 367 involuntary context switches diff --git a/benchmarks/sphere_3_192/dipha.dim_2.out.txt b/benchmarks/sphere_3_192/dipha.dim_2.out.txt new file mode 100644 index 0000000..1a7b30b --- /dev/null +++ b/benchmarks/sphere_3_192/dipha.dim_2.out.txt @@ -0,0 +1,57 @@ + +Input filename: +/Users/uli/Bitbucket/phat-paper/benchmark/dipha/sphere_3_192.complex + +upper_dim: 3 + +Number of processes used: +1 + +Detailed information for rank 0: + time prior mem peak mem bytes recv + 0.0s 3 MB 4 MB 0 MB complex.load_binary( input_filename, upper_dim ); + +Number of cells in input: +56050288 + 12.3s 4 MB 1714 MB 0 MB get_filtration_to_cell_map( complex, dualize, filtration_to_cell_map ); + 5.5s 431 MB 4416 MB 855 MB get_cell_to_filtration_map( complex.get_num_cells(), filtration_to_cell_map, cell_to_filtration_map ); + 0.3s 2278 MB 4416 MB 0 MB generate_unreduced_columns( complex, filtration_to_cell_map, cell_to_filtration_map, cur_dim, dualize, unreduced_columns ); + 0.0s 2279 MB 4416 MB 0 MB reduction_kernel( complex.get_num_cells(), unreduced_columns, reduced_columns ); + 0.6s 2279 MB 4416 MB 53 MB generate_unreduced_columns( complex, filtration_to_cell_map, cell_to_filtration_map, cur_dim, dualize, unreduced_columns ); + 0.0s 2240 MB 4416 MB 0 MB reduction_kernel( complex.get_num_cells(), unreduced_columns, reduced_columns ); + 18.7s 2252 MB 5285 MB 3349 MB generate_unreduced_columns( complex, filtration_to_cell_map, cell_to_filtration_map, cur_dim, dualize, unreduced_columns ); + 5.9s 3930 MB 5715 MB 0 MB reduction_kernel( complex.get_num_cells(), unreduced_columns, reduced_columns ); + 6.8s 3716 MB 5715 MB 106 MB dipha::outputs::save_persistence_diagram( output_filename, complex, filtration_to_cell_map, reduced_columns, dualize, upper_dim ); + +Overall running time in seconds: +50.9 + +Reduction kernel running time in seconds: +5.9 + +Overall peak mem in GB of all ranks: +5.6 + +Individual peak mem in GB of per rank: +5.6 + +Maximal communication traffic (without sorting) in GB between any pair of nodes: +4.3 + +Total communication traffic (without sorting) in GB between all pairs of nodes: +4.3 + 50.97 real 42.99 user 7.93 sys +5993607168 maximum resident set size + 0 average shared memory size + 0 average unshared data size + 0 average unshared stack size + 5448458 page reclaims + 0 page faults + 0 swaps + 0 block input operations + 6 block output operations + 0 messages sent + 0 messages received + 0 signals received + 6 voluntary context switches + 6625 involuntary context switches diff --git a/benchmarks/sphere_3_192/gudhi.dim_1.out.txt b/benchmarks/sphere_3_192/gudhi.dim_1.out.txt new file mode 100644 index 0000000..94e7f6e --- /dev/null +++ b/benchmarks/sphere_3_192/gudhi.dim_1.out.txt @@ -0,0 +1,262 @@ +The complex contains 1179808 simplices + and has dimension 2 +2 0 0 inf +2 1 0.316534 0.682559 +2 1 0.304761 0.647803 +2 0 0 0.332695 +2 0 0 0.323964 +2 0 0 0.319493 +2 0 0 0.316023 +2 1 0.34298 0.65758 +2 0 0 0.304062 +2 0 0 0.297933 +2 0 0 0.297053 +2 0 0 0.293466 +2 1 0.347806 0.638039 +2 0 0 0.289189 +2 0 0 0.288591 +2 0 0 0.287316 +2 0 0 0.285416 +2 0 0 0.283881 +2 0 0 0.283562 +2 0 0 0.282169 +2 0 0 0.280629 +2 0 0 0.277582 +2 0 0 0.277191 +2 0 0 0.276431 +2 0 0 0.274611 +2 0 0 0.270996 +2 0 0 0.268806 +2 0 0 0.266635 +2 0 0 0.266592 +2 0 0 0.264483 +2 0 0 0.264334 +2 0 0 0.257997 +2 0 0 0.25725 +2 0 0 0.253227 +2 0 0 0.253163 +2 0 0 0.249345 +2 0 0 0.249339 +2 0 0 0.248879 +2 0 0 0.247042 +2 0 0 0.246491 +2 0 0 0.24509 +2 0 0 0.24348 +2 0 0 0.240632 +2 0 0 0.23879 +2 0 0 0.237571 +2 0 0 0.234969 +2 0 0 0.234112 +2 0 0 0.231675 +2 0 0 0.231179 +2 1 0.35058 0.580726 +2 0 0 0.228917 +2 0 0 0.2286 +2 0 0 0.227933 +2 0 0 0.227524 +2 0 0 0.223232 +2 0 0 0.218561 +2 0 0 0.218526 +2 0 0 0.215759 +2 0 0 0.214018 +2 1 0.347388 0.559978 +2 0 0 0.210372 +2 0 0 0.208851 +2 0 0 0.208063 +2 0 0 0.207714 +2 0 0 0.207261 +2 0 0 0.207016 +2 0 0 0.205389 +2 0 0 0.204544 +2 0 0 0.204208 +2 0 0 0.203812 +2 0 0 0.202564 +2 0 0 0.201961 +2 0 0 0.199673 +2 0 0 0.197377 +2 0 0 0.195722 +2 0 0 0.193804 +2 0 0 0.193791 +2 0 0 0.192733 +2 0 0 0.192406 +2 0 0 0.192356 +2 0 0 0.191661 +2 0 0 0.190642 +2 1 0.352356 0.541947 +2 0 0 0.189106 +2 0 0 0.184757 +2 0 0 0.18428 +2 0 0 0.179609 +2 1 0.301986 0.478334 +2 0 0 0.176306 +2 0 0 0.175016 +2 0 0 0.17493 +2 0 0 0.174172 +2 0 0 0.173684 +2 0 0 0.173586 +2 0 0 0.173412 +2 0 0 0.168587 +2 0 0 0.167455 +2 0 0 0.165907 +2 0 0 0.165592 +2 0 0 0.165494 +2 0 0 0.165314 +2 0 0 0.165202 +2 0 0 0.164815 +2 0 0 0.164809 +2 0 0 0.162464 +2 1 0.322683 0.482958 +2 0 0 0.159282 +2 0 0 0.158413 +2 0 0 0.157373 +2 0 0 0.157293 +2 0 0 0.157251 +2 0 0 0.1569 +2 0 0 0.15587 +2 0 0 0.154095 +2 0 0 0.15244 +2 0 0 0.151643 +2 0 0 0.150747 +2 0 0 0.149226 +2 0 0 0.149017 +2 0 0 0.148506 +2 0 0 0.147427 +2 0 0 0.147289 +2 0 0 0.147203 +2 0 0 0.145725 +2 0 0 0.145018 +2 0 0 0.143151 +2 0 0 0.143085 +2 0 0 0.142834 +2 0 0 0.142537 +2 0 0 0.142152 +2 0 0 0.141823 +2 0 0 0.138674 +2 1 0.377729 0.514046 +2 0 0 0.135402 +2 0 0 0.134886 +2 0 0 0.133722 +2 0 0 0.133525 +2 0 0 0.133033 +2 0 0 0.131638 +2 0 0 0.131438 +2 0 0 0.129741 +2 0 0 0.127864 +2 0 0 0.127383 +2 0 0 0.126595 +2 0 0 0.124774 +2 1 0.339394 0.463666 +2 0 0 0.123527 +2 0 0 0.122089 +2 0 0 0.121955 +2 0 0 0.119187 +2 1 0.2576 0.373749 +2 0 0 0.115939 +2 1 0.370051 0.483155 +2 0 0 0.111798 +2 0 0 0.111131 +2 0 0 0.109526 +2 0 0 0.108768 +2 1 0.386278 0.4922 +2 1 0.443911 0.54761 +2 1 0.374531 0.477153 +2 1 0.354747 0.454956 +2 0 0 0.0994522 +2 1 0.318032 0.417462 +2 0 0 0.0988752 +2 0 0 0.0970981 +2 0 0 0.0959033 +2 0 0 0.0884133 +2 0 0 0.0870489 +2 0 0 0.0857401 +2 0 0 0.084341 +2 0 0 0.0831521 +2 0 0 0.0831358 +2 0 0 0.0814685 +2 0 0 0.0802451 +2 0 0 0.0800348 +2 0 0 0.0792212 +2 0 0 0.0782455 +2 0 0 0.076909 +2 0 0 0.0753955 +2 1 0.324159 0.399094 +2 0 0 0.0746054 +2 0 0 0.0743236 +2 0 0 0.0741239 +2 1 0.413789 0.487379 +2 0 0 0.0728647 +2 0 0 0.0714516 +2 0 0 0.0702075 +2 0 0 0.0692368 +2 1 0.409968 0.478461 +2 0 0 0.0672609 +2 0 0 0.0651112 +2 0 0 0.0637053 +2 0 0 0.0633425 +2 1 0.298341 0.360737 +2 0 0 0.0623736 +2 1 0.309419 0.37151 +2 1 0.411549 0.471715 +2 0 0 0.0593071 +2 0 0 0.057488 +2 1 0.377019 0.434385 +2 1 0.329066 0.386148 +2 0 0 0.0560443 +2 0 0 0.0559886 +2 0 0 0.0522132 +2 0 0 0.0515157 +2 1 0.412572 0.46308 +2 0 0 0.0496187 +2 0 0 0.048826 +2 0 0 0.0487061 +2 1 0.240869 0.288747 +2 0 0 0.0471186 +2 1 0.531636 0.578093 +2 1 0.530723 0.576869 +2 1 0.33364 0.3797 +2 1 0.431628 0.477277 +2 0 0 0.0433426 +2 1 0.344005 0.387193 +2 1 0.463389 0.505345 +2 1 0.361715 0.403181 +2 1 0.381084 0.421374 +2 1 0.253337 0.292286 +2 0 0 0.0387451 +2 0 0 0.037954 +2 1 0.377147 0.414788 +2 1 0.308779 0.346297 +2 1 0.317521 0.349622 +2 0 0 0.0311057 +2 1 0.331259 0.356381 +2 1 0.279016 0.301331 +2 0 0 0.0217315 +2 1 0.350913 0.369543 +2 1 0.324571 0.343083 +2 0 0 0.0173134 +2 1 0.33392 0.35111 +2 1 0.542696 0.558863 +2 1 0.33836 0.350411 +2 1 0.29997 0.311993 +2 0 0 0.0120098 +2 1 0.189652 0.197515 +2 0 0 0.00391946 +2 0 0 0.0036753 +2 1 0.445398 0.448892 +2 1 0.24546 0.248903 +2 1 0.301045 0.303943 +2 1 0.309336 0.310216 + 0.56 real 0.52 user 0.02 sys + 69439488 maximum resident set size + 0 average shared memory size + 0 average unshared data size + 0 average unshared stack size + 16943 page reclaims + 29 page faults + 0 swaps + 2 block input operations + 0 block output operations + 0 messages sent + 0 messages received + 0 signals received + 10 voluntary context switches + 73 involuntary context switches diff --git a/benchmarks/sphere_3_192/gudhi.dim_2.out.txt b/benchmarks/sphere_3_192/gudhi.dim_2.out.txt new file mode 100644 index 0000000..36740c8 --- /dev/null +++ b/benchmarks/sphere_3_192/gudhi.dim_2.out.txt @@ -0,0 +1,263 @@ +The complex contains 56050288 simplices + and has dimension 3 +2 0 0 inf +2 2 0.720484 1.65562 +2 1 0.316534 0.682559 +2 1 0.304761 0.647803 +2 0 0 0.332695 +2 0 0 0.323964 +2 0 0 0.319493 +2 0 0 0.316023 +2 1 0.34298 0.65758 +2 0 0 0.304062 +2 0 0 0.297933 +2 0 0 0.297053 +2 0 0 0.293466 +2 1 0.347806 0.638039 +2 0 0 0.289189 +2 0 0 0.288591 +2 0 0 0.287316 +2 0 0 0.285416 +2 0 0 0.283881 +2 0 0 0.283562 +2 0 0 0.282169 +2 0 0 0.280629 +2 0 0 0.277582 +2 0 0 0.277191 +2 0 0 0.276431 +2 0 0 0.274611 +2 0 0 0.270996 +2 0 0 0.268806 +2 0 0 0.266635 +2 0 0 0.266592 +2 0 0 0.264483 +2 0 0 0.264334 +2 0 0 0.257997 +2 0 0 0.25725 +2 0 0 0.253227 +2 0 0 0.253163 +2 0 0 0.249345 +2 0 0 0.249339 +2 0 0 0.248879 +2 0 0 0.247042 +2 0 0 0.246491 +2 0 0 0.24509 +2 0 0 0.24348 +2 0 0 0.240632 +2 0 0 0.23879 +2 0 0 0.237571 +2 0 0 0.234969 +2 0 0 0.234112 +2 0 0 0.231675 +2 0 0 0.231179 +2 1 0.35058 0.580726 +2 0 0 0.228917 +2 0 0 0.2286 +2 0 0 0.227933 +2 0 0 0.227524 +2 0 0 0.223232 +2 0 0 0.218561 +2 0 0 0.218526 +2 0 0 0.215759 +2 0 0 0.214018 +2 1 0.347388 0.559978 +2 0 0 0.210372 +2 0 0 0.208851 +2 0 0 0.208063 +2 0 0 0.207714 +2 0 0 0.207261 +2 0 0 0.207016 +2 0 0 0.205389 +2 0 0 0.204544 +2 0 0 0.204208 +2 0 0 0.203812 +2 0 0 0.202564 +2 0 0 0.201961 +2 0 0 0.199673 +2 0 0 0.197377 +2 0 0 0.195722 +2 0 0 0.193804 +2 0 0 0.193791 +2 0 0 0.192733 +2 0 0 0.192406 +2 0 0 0.192356 +2 0 0 0.191661 +2 0 0 0.190642 +2 1 0.352356 0.541947 +2 0 0 0.189106 +2 0 0 0.184757 +2 0 0 0.18428 +2 0 0 0.179609 +2 1 0.301986 0.478334 +2 0 0 0.176306 +2 0 0 0.175016 +2 0 0 0.17493 +2 0 0 0.174172 +2 0 0 0.173684 +2 0 0 0.173586 +2 0 0 0.173412 +2 0 0 0.168587 +2 0 0 0.167455 +2 0 0 0.165907 +2 0 0 0.165592 +2 0 0 0.165494 +2 0 0 0.165314 +2 0 0 0.165202 +2 0 0 0.164815 +2 0 0 0.164809 +2 0 0 0.162464 +2 1 0.322683 0.482958 +2 0 0 0.159282 +2 0 0 0.158413 +2 0 0 0.157373 +2 0 0 0.157293 +2 0 0 0.157251 +2 0 0 0.1569 +2 0 0 0.15587 +2 0 0 0.154095 +2 0 0 0.15244 +2 0 0 0.151643 +2 0 0 0.150747 +2 0 0 0.149226 +2 0 0 0.149017 +2 0 0 0.148506 +2 0 0 0.147427 +2 0 0 0.147289 +2 0 0 0.147203 +2 0 0 0.145725 +2 0 0 0.145018 +2 0 0 0.143151 +2 0 0 0.143085 +2 0 0 0.142834 +2 0 0 0.142537 +2 0 0 0.142152 +2 0 0 0.141823 +2 0 0 0.138674 +2 1 0.377729 0.514046 +2 0 0 0.135402 +2 0 0 0.134886 +2 0 0 0.133722 +2 0 0 0.133525 +2 0 0 0.133033 +2 0 0 0.131638 +2 0 0 0.131438 +2 0 0 0.129741 +2 0 0 0.127864 +2 0 0 0.127383 +2 0 0 0.126595 +2 0 0 0.124774 +2 1 0.339394 0.463666 +2 0 0 0.123527 +2 0 0 0.122089 +2 0 0 0.121955 +2 0 0 0.119187 +2 1 0.2576 0.373749 +2 0 0 0.115939 +2 1 0.370051 0.483155 +2 0 0 0.111798 +2 0 0 0.111131 +2 0 0 0.109526 +2 0 0 0.108768 +2 1 0.386278 0.4922 +2 1 0.443911 0.54761 +2 1 0.374531 0.477153 +2 1 0.354747 0.454956 +2 0 0 0.0994522 +2 1 0.318032 0.417462 +2 0 0 0.0988752 +2 0 0 0.0970981 +2 0 0 0.0959033 +2 0 0 0.0884133 +2 0 0 0.0870489 +2 0 0 0.0857401 +2 0 0 0.084341 +2 0 0 0.0831521 +2 0 0 0.0831358 +2 0 0 0.0814685 +2 0 0 0.0802451 +2 0 0 0.0800348 +2 0 0 0.0792212 +2 0 0 0.0782455 +2 0 0 0.076909 +2 0 0 0.0753955 +2 1 0.324159 0.399094 +2 0 0 0.0746054 +2 0 0 0.0743236 +2 0 0 0.0741239 +2 1 0.413789 0.487379 +2 0 0 0.0728647 +2 0 0 0.0714516 +2 0 0 0.0702075 +2 0 0 0.0692368 +2 1 0.409968 0.478461 +2 0 0 0.0672609 +2 0 0 0.0651112 +2 0 0 0.0637053 +2 0 0 0.0633425 +2 1 0.298341 0.360737 +2 0 0 0.0623736 +2 1 0.309419 0.37151 +2 1 0.411549 0.471715 +2 0 0 0.0593071 +2 0 0 0.057488 +2 1 0.377019 0.434385 +2 1 0.329066 0.386148 +2 0 0 0.0560443 +2 0 0 0.0559886 +2 0 0 0.0522132 +2 0 0 0.0515157 +2 1 0.412572 0.46308 +2 0 0 0.0496187 +2 0 0 0.048826 +2 0 0 0.0487061 +2 1 0.240869 0.288747 +2 0 0 0.0471186 +2 1 0.531636 0.578093 +2 1 0.530723 0.576869 +2 1 0.33364 0.3797 +2 1 0.431628 0.477277 +2 0 0 0.0433426 +2 1 0.344005 0.387193 +2 1 0.463389 0.505345 +2 1 0.361715 0.403181 +2 1 0.381084 0.421374 +2 1 0.253337 0.292286 +2 0 0 0.0387451 +2 0 0 0.037954 +2 1 0.377147 0.414788 +2 1 0.308779 0.346297 +2 1 0.317521 0.349622 +2 0 0 0.0311057 +2 1 0.331259 0.356381 +2 1 0.279016 0.301331 +2 0 0 0.0217315 +2 1 0.350913 0.369543 +2 1 0.324571 0.343083 +2 0 0 0.0173134 +2 1 0.33392 0.35111 +2 1 0.542696 0.558863 +2 1 0.33836 0.350411 +2 1 0.29997 0.311993 +2 0 0 0.0120098 +2 1 0.189652 0.197515 +2 0 0 0.00391946 +2 0 0 0.0036753 +2 1 0.445398 0.448892 +2 1 0.24546 0.248903 +2 1 0.301045 0.303943 +2 1 0.309336 0.310216 + 75.58 real 74.18 user 1.35 sys +2911698944 maximum resident set size + 0 average shared memory size + 0 average unshared data size + 0 average unshared stack size + 820365 page reclaims + 0 page faults + 0 swaps + 0 block input operations + 0 block output operations + 0 messages sent + 0 messages received + 0 signals received + 11 voluntary context switches + 9107 involuntary context switches diff --git a/benchmarks/sphere_3_192/ripser.dim_1.out.txt b/benchmarks/sphere_3_192/ripser.dim_1.out.txt new file mode 100644 index 0000000..f7f631f --- /dev/null +++ b/benchmarks/sphere_3_192/ripser.dim_1.out.txt @@ -0,0 +1,264 @@ +distance matrix with 192 points +value range: [0.00367531,2] +persistence intervals in dim 0: + [0,0.00367531) + [0,0.00391946) + [0,0.0120098) + [0,0.0173134) + [0,0.0217315) + [0,0.0311057) + [0,0.037954) + [0,0.0387451) + [0,0.0433426) + [0,0.0471186) + [0,0.0487061) + [0,0.048826) + [0,0.0496187) + [0,0.0515157) + [0,0.0522132) + [0,0.0559886) + [0,0.0560443) + [0,0.057488) + [0,0.0593071) + [0,0.0623736) + [0,0.0633425) + [0,0.0637053) + [0,0.0651112) + [0,0.0672609) + [0,0.0692368) + [0,0.0702075) + [0,0.0714516) + [0,0.0728647) + [0,0.0741239) + [0,0.0743236) + [0,0.0746054) + [0,0.0753955) + [0,0.076909) + [0,0.0782455) + [0,0.0792212) + [0,0.0800348) + [0,0.0802451) + [0,0.0814685) + [0,0.0831358) + [0,0.0831521) + [0,0.084341) + [0,0.0857401) + [0,0.0870489) + [0,0.0884133) + [0,0.0959033) + [0,0.0970981) + [0,0.0988752) + [0,0.0994522) + [0,0.108768) + [0,0.109526) + [0,0.111131) + [0,0.111798) + [0,0.115939) + [0,0.119187) + [0,0.121955) + [0,0.122089) + [0,0.123527) + [0,0.124774) + [0,0.126595) + [0,0.127383) + [0,0.127864) + [0,0.129741) + [0,0.131438) + [0,0.131638) + [0,0.133033) + [0,0.133525) + [0,0.133722) + [0,0.134886) + [0,0.135402) + [0,0.138674) + [0,0.141823) + [0,0.142152) + [0,0.142537) + [0,0.142834) + [0,0.143085) + [0,0.143151) + [0,0.145018) + [0,0.145725) + [0,0.147203) + [0,0.147289) + [0,0.147427) + [0,0.148506) + [0,0.149017) + [0,0.149226) + [0,0.150747) + [0,0.151643) + [0,0.15244) + [0,0.154095) + [0,0.15587) + [0,0.1569) + [0,0.157251) + [0,0.157293) + [0,0.157373) + [0,0.158413) + [0,0.159282) + [0,0.162464) + [0,0.164809) + [0,0.164815) + [0,0.165202) + [0,0.165314) + [0,0.165494) + [0,0.165592) + [0,0.165907) + [0,0.167455) + [0,0.168587) + [0,0.173412) + [0,0.173586) + [0,0.173684) + [0,0.174172) + [0,0.17493) + [0,0.175016) + [0,0.176306) + [0,0.179609) + [0,0.18428) + [0,0.184757) + [0,0.189106) + [0,0.190642) + [0,0.191661) + [0,0.192356) + [0,0.192406) + [0,0.192733) + [0,0.193791) + [0,0.193804) + [0,0.195722) + [0,0.197377) + [0,0.199673) + [0,0.201961) + [0,0.202564) + [0,0.203812) + [0,0.204208) + [0,0.204544) + [0,0.205389) + [0,0.207016) + [0,0.207261) + [0,0.207714) + [0,0.208063) + [0,0.208851) + [0,0.210372) + [0,0.214018) + [0,0.215759) + [0,0.218526) + [0,0.218561) + [0,0.223232) + [0,0.227524) + [0,0.227933) + [0,0.2286) + [0,0.228917) + [0,0.231179) + [0,0.231675) + [0,0.234112) + [0,0.234969) + [0,0.237571) + [0,0.23879) + [0,0.240632) + [0,0.24348) + [0,0.24509) + [0,0.246491) + [0,0.247042) + [0,0.248879) + [0,0.249339) + [0,0.249345) + [0,0.253163) + [0,0.253227) + [0,0.25725) + [0,0.257997) + [0,0.264334) + [0,0.264483) + [0,0.266592) + [0,0.266635) + [0,0.268806) + [0,0.270996) + [0,0.274611) + [0,0.276431) + [0,0.277191) + [0,0.277582) + [0,0.280629) + [0,0.282169) + [0,0.283562) + [0,0.283881) + [0,0.285416) + [0,0.287316) + [0,0.288591) + [0,0.289189) + [0,0.293466) + [0,0.297053) + [0,0.297933) + [0,0.304062) + [0,0.316023) + [0,0.319493) + [0,0.323964) + [0,0.332695) + [0, ) +persistence intervals in dim 1: + [0.542696,0.558863) + [0.531636,0.578093) + [0.530723,0.576869) + [0.463389,0.505345) + [0.445398,0.448892) + [0.443911,0.54761) + [0.431628,0.477277) + [0.413789,0.487379) + [0.412572,0.46308) + [0.411549,0.471715) + [0.409968,0.478461) + [0.386278,0.4922) + [0.381084,0.421374) + [0.377729,0.514046) + [0.377147,0.414788) + [0.377019,0.434385) + [0.374531,0.477153) + [0.370051,0.483155) + [0.361715,0.403181) + [0.354747,0.454956) + [0.352356,0.541947) + [0.350913,0.369543) + [0.35058,0.580726) + [0.347806,0.638039) + [0.347388,0.559978) + [0.344005,0.387193) + [0.34298,0.65758) + [0.339394,0.463666) + [0.33836,0.350411) + [0.33392,0.35111) + [0.33364,0.3797) + [0.331259,0.356381) + [0.329066,0.386148) + [0.324571,0.343083) + [0.324159,0.399094) + [0.322683,0.482958) + [0.318032,0.417462) + [0.317521,0.349622) + [0.316534,0.682559) + [0.309419,0.37151) + [0.309336,0.310216) + [0.308779,0.346297) + [0.304761,0.647803) + [0.301986,0.478334) + [0.301045,0.303943) + [0.29997,0.311993) + [0.298341,0.360737) + [0.279016,0.301331) + [0.2576,0.373749) + [0.253337,0.292286) + [0.24546,0.248903) + [0.240869,0.288747) + [0.189652,0.197515) + 0.03 real 0.02 user 0.00 sys + 3379200 maximum resident set size + 0 average shared memory size + 0 average unshared data size + 0 average unshared stack size + 844 page reclaims + 0 page faults + 0 swaps + 0 block input operations + 0 block output operations + 0 messages sent + 0 messages received + 0 signals received + 4 voluntary context switches + 21 involuntary context switches diff --git a/benchmarks/sphere_3_192/ripser.dim_2.out.txt b/benchmarks/sphere_3_192/ripser.dim_2.out.txt new file mode 100644 index 0000000..b3283e7 --- /dev/null +++ b/benchmarks/sphere_3_192/ripser.dim_2.out.txt @@ -0,0 +1,266 @@ +distance matrix with 192 points +value range: [0.00367531,2] +persistence intervals in dim 0: + [0,0.00367531) + [0,0.00391946) + [0,0.0120098) + [0,0.0173134) + [0,0.0217315) + [0,0.0311057) + [0,0.037954) + [0,0.0387451) + [0,0.0433426) + [0,0.0471186) + [0,0.0487061) + [0,0.048826) + [0,0.0496187) + [0,0.0515157) + [0,0.0522132) + [0,0.0559886) + [0,0.0560443) + [0,0.057488) + [0,0.0593071) + [0,0.0623736) + [0,0.0633425) + [0,0.0637053) + [0,0.0651112) + [0,0.0672609) + [0,0.0692368) + [0,0.0702075) + [0,0.0714516) + [0,0.0728647) + [0,0.0741239) + [0,0.0743236) + [0,0.0746054) + [0,0.0753955) + [0,0.076909) + [0,0.0782455) + [0,0.0792212) + [0,0.0800348) + [0,0.0802451) + [0,0.0814685) + [0,0.0831358) + [0,0.0831521) + [0,0.084341) + [0,0.0857401) + [0,0.0870489) + [0,0.0884133) + [0,0.0959033) + [0,0.0970981) + [0,0.0988752) + [0,0.0994522) + [0,0.108768) + [0,0.109526) + [0,0.111131) + [0,0.111798) + [0,0.115939) + [0,0.119187) + [0,0.121955) + [0,0.122089) + [0,0.123527) + [0,0.124774) + [0,0.126595) + [0,0.127383) + [0,0.127864) + [0,0.129741) + [0,0.131438) + [0,0.131638) + [0,0.133033) + [0,0.133525) + [0,0.133722) + [0,0.134886) + [0,0.135402) + [0,0.138674) + [0,0.141823) + [0,0.142152) + [0,0.142537) + [0,0.142834) + [0,0.143085) + [0,0.143151) + [0,0.145018) + [0,0.145725) + [0,0.147203) + [0,0.147289) + [0,0.147427) + [0,0.148506) + [0,0.149017) + [0,0.149226) + [0,0.150747) + [0,0.151643) + [0,0.15244) + [0,0.154095) + [0,0.15587) + [0,0.1569) + [0,0.157251) + [0,0.157293) + [0,0.157373) + [0,0.158413) + [0,0.159282) + [0,0.162464) + [0,0.164809) + [0,0.164815) + [0,0.165202) + [0,0.165314) + [0,0.165494) + [0,0.165592) + [0,0.165907) + [0,0.167455) + [0,0.168587) + [0,0.173412) + [0,0.173586) + [0,0.173684) + [0,0.174172) + [0,0.17493) + [0,0.175016) + [0,0.176306) + [0,0.179609) + [0,0.18428) + [0,0.184757) + [0,0.189106) + [0,0.190642) + [0,0.191661) + [0,0.192356) + [0,0.192406) + [0,0.192733) + [0,0.193791) + [0,0.193804) + [0,0.195722) + [0,0.197377) + [0,0.199673) + [0,0.201961) + [0,0.202564) + [0,0.203812) + [0,0.204208) + [0,0.204544) + [0,0.205389) + [0,0.207016) + [0,0.207261) + [0,0.207714) + [0,0.208063) + [0,0.208851) + [0,0.210372) + [0,0.214018) + [0,0.215759) + [0,0.218526) + [0,0.218561) + [0,0.223232) + [0,0.227524) + [0,0.227933) + [0,0.2286) + [0,0.228917) + [0,0.231179) + [0,0.231675) + [0,0.234112) + [0,0.234969) + [0,0.237571) + [0,0.23879) + [0,0.240632) + [0,0.24348) + [0,0.24509) + [0,0.246491) + [0,0.247042) + [0,0.248879) + [0,0.249339) + [0,0.249345) + [0,0.253163) + [0,0.253227) + [0,0.25725) + [0,0.257997) + [0,0.264334) + [0,0.264483) + [0,0.266592) + [0,0.266635) + [0,0.268806) + [0,0.270996) + [0,0.274611) + [0,0.276431) + [0,0.277191) + [0,0.277582) + [0,0.280629) + [0,0.282169) + [0,0.283562) + [0,0.283881) + [0,0.285416) + [0,0.287316) + [0,0.288591) + [0,0.289189) + [0,0.293466) + [0,0.297053) + [0,0.297933) + [0,0.304062) + [0,0.316023) + [0,0.319493) + [0,0.323964) + [0,0.332695) + [0, ) +persistence intervals in dim 1: + [0.542696,0.558863) + [0.531636,0.578093) + [0.530723,0.576869) + [0.463389,0.505345) + [0.445398,0.448892) + [0.443911,0.54761) + [0.431628,0.477277) + [0.413789,0.487379) + [0.412572,0.46308) + [0.411549,0.471715) + [0.409968,0.478461) + [0.386278,0.4922) + [0.381084,0.421374) + [0.377729,0.514046) + [0.377147,0.414788) + [0.377019,0.434385) + [0.374531,0.477153) + [0.370051,0.483155) + [0.361715,0.403181) + [0.354747,0.454956) + [0.352356,0.541947) + [0.350913,0.369543) + [0.35058,0.580726) + [0.347806,0.638039) + [0.347388,0.559978) + [0.344005,0.387193) + [0.34298,0.65758) + [0.339394,0.463666) + [0.33836,0.350411) + [0.33392,0.35111) + [0.33364,0.3797) + [0.331259,0.356381) + [0.329066,0.386148) + [0.324571,0.343083) + [0.324159,0.399094) + [0.322683,0.482958) + [0.318032,0.417462) + [0.317521,0.349622) + [0.316534,0.682559) + [0.309419,0.37151) + [0.309336,0.310216) + [0.308779,0.346297) + [0.304761,0.647803) + [0.301986,0.478334) + [0.301045,0.303943) + [0.29997,0.311993) + [0.298341,0.360737) + [0.279016,0.301331) + [0.2576,0.373749) + [0.253337,0.292286) + [0.24546,0.248903) + [0.240869,0.288747) + [0.189652,0.197515) +persistence intervals in dim 2: + [0.720484,1.65562) + 1.17 real 1.08 user 0.08 sys + 182210560 maximum resident set size + 0 average shared memory size + 0 average unshared data size + 0 average unshared stack size + 44505 page reclaims + 0 page faults + 0 swaps + 0 block input operations + 0 block output operations + 0 messages sent + 0 messages received + 0 signals received + 2 voluntary context switches + 69 involuntary context switches diff --git a/benchmarks/sphere_3_192/run_dionysus.sh b/benchmarks/sphere_3_192/run_dionysus.sh index 1e5c7d3..7af804f 100644 --- a/benchmarks/sphere_3_192/run_dionysus.sh +++ b/benchmarks/sphere_3_192/run_dionysus.sh @@ -1 +1,3 @@ -/usr/bin/time -l ~/Source/Dionysus/examples/cohomology/rips-pairwise-cohomology -s2 -p2 ~/Bitbucket/phat-paper/benchmark/point\ cloud/sphere_3_192_points.dat 2>&1 | tee dionysus.out.txt +/usr/bin/time -l ~/Source/Dionysus/examples/cohomology/rips-pairwise-cohomology -s2 -p2 ~/Bitbucket/phat-paper/benchmark/point\ cloud/sphere_3_192_points.dat 2>&1 | tee dionysus.dim_1.out.txt +/usr/bin/time -l ~/Source/Dionysus/examples/cohomology/rips-pairwise-cohomology -s3 -p2 ~/Bitbucket/phat-paper/benchmark/point\ cloud/sphere_3_192_points.dat 2>&1 | tee dionysus.dim_2.out.txt + diff --git a/benchmarks/sphere_3_192/run_dipha.sh b/benchmarks/sphere_3_192/run_dipha.sh index 312bcd7..b700a1a 100644 --- a/benchmarks/sphere_3_192/run_dipha.sh +++ b/benchmarks/sphere_3_192/run_dipha.sh @@ -1 +1,3 @@ -/usr/bin/time -l ~/Bitbucket/dipha/dipha --benchmark --upper_dim 2 --dual ~/Bitbucket/phat-paper/benchmark/dipha/sphere_3_192.complex /dev/null 2>&1 | tee dipha.out.txt +/usr/bin/time -l ~/Bitbucket/dipha/dipha --benchmark --upper_dim 2 --dual ~/Bitbucket/phat-paper/benchmark/dipha/sphere_3_192.complex /dev/null 2>&1 | tee dipha.dim_1.out.txt +/usr/bin/time -l ~/Bitbucket/dipha/dipha --benchmark --upper_dim 3 --dual ~/Bitbucket/phat-paper/benchmark/dipha/sphere_3_192.complex /dev/null 2>&1 | tee dipha.dim_2.out.txt + diff --git a/benchmarks/sphere_3_192/run_gudhi.sh b/benchmarks/sphere_3_192/run_gudhi.sh index 80ae403..7e39da9 100644 --- a/benchmarks/sphere_3_192/run_gudhi.sh +++ b/benchmarks/sphere_3_192/run_gudhi.sh @@ -1 +1,3 @@ -/usr/bin/time -l ~/Source/Gudhi_library_1.3.1/example/Persistent_cohomology/rips_persistence -d2 -p2 ~/Bitbucket/phat-paper/benchmark/point\ cloud/sphere_3_192_points.dat 2>&1 | tee gudhi.out.txt +/usr/bin/time -l ~/Source/Gudhi_library_1.3.1/example/Persistent_cohomology/rips_persistence -d2 -p2 ~/Bitbucket/phat-paper/benchmark/point\ cloud/sphere_3_192_points.dat 2>&1 | tee gudhi.dim_1.out.txt +/usr/bin/time -l ~/Source/Gudhi_library_1.3.1/example/Persistent_cohomology/rips_persistence -d3 -p2 ~/Bitbucket/phat-paper/benchmark/point\ cloud/sphere_3_192_points.dat 2>&1 | tee gudhi.dim_2.out.txt + diff --git a/benchmarks/sphere_3_192/run_ripser.sh b/benchmarks/sphere_3_192/run_ripser.sh index 209c410..4cc1c3d 100644 --- a/benchmarks/sphere_3_192/run_ripser.sh +++ b/benchmarks/sphere_3_192/run_ripser.sh @@ -1 +1,3 @@ -/usr/bin/time -l ~/Bitbucket/ripser/ripser ~/Bitbucket/ripser/examples/sphere_3_192.lower_distance_matrix 2>&1 | tee ripser.out.txt +/usr/bin/time -l ~/Bitbucket/ripser/ripser ~/Bitbucket/ripser/examples/sphere_3_192.lower_distance_matrix 2>&1 | tee ripser.dim_1.out.txt +/usr/bin/time -l ~/Bitbucket/ripser/ripser ~/Bitbucket/ripser/examples/sphere_3_192.lower_distance_matrix --dim 2 2>&1 | tee ripser.dim_2.out.txt + -- cgit v1.2.3 From 92536895274a4632eaff452c56227caa2e3e0e66 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Mon, 20 Mar 2017 16:07:33 +0100 Subject: benchmark using sparsehash --- Makefile | 10 +++++----- benchmarks/sphere_3_192/ripser.dim_1.out.txt | 10 +++++----- benchmarks/sphere_3_192/ripser.dim_2.out.txt | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index 893d776..90543db 100644 --- a/Makefile +++ b/Makefile @@ -5,19 +5,19 @@ all: ripser ripser-coeff ripser-reduction ripser-coeff-reduction ripser-debug ripser: ripser.cpp - c++ -std=c++11 ripser.cpp -o ripser -Ofast -D NDEBUG + c++ -std=c++11 ripser.cpp -o ripser -Ofast -D NDEBUG -D USE_GOOGLE_HASHMAP ripser-coeff: ripser.cpp - c++ -std=c++11 ripser.cpp -o ripser-coeff -Ofast -D NDEBUG -D USE_COEFFICIENTS + c++ -std=c++11 ripser.cpp -o ripser-coeff -Ofast -D NDEBUG -D USE_GOOGLE_HASHMAP -D USE_COEFFICIENTS ripser-reduction: ripser.cpp - c++ -std=c++11 ripser.cpp -o ripser-reduction -Ofast -D NDEBUG -D ASSEMBLE_REDUCTION_MATRIX + c++ -std=c++11 ripser.cpp -o ripser-reduction -Ofast -D NDEBUG -D USE_GOOGLE_HASHMAP -D ASSEMBLE_REDUCTION_MATRIX ripser-coeff-reduction: ripser.cpp - c++ -std=c++11 ripser.cpp -o ripser-coeff-reduction -Ofast -D NDEBUG -D USE_COEFFICIENTS -D ASSEMBLE_REDUCTION_MATRIX + c++ -std=c++11 ripser.cpp -o ripser-coeff-reduction -Ofast -D NDEBUG -D USE_GOOGLE_HASHMAP -D USE_COEFFICIENTS -D ASSEMBLE_REDUCTION_MATRIX ripser-debug: ripser.cpp - c++ -std=c++11 ripser.cpp -o ripser-debug -g + c++ -std=c++11 ripser.cpp -o ripser-debug -g -D USE_GOOGLE_HASHMAP clean: diff --git a/benchmarks/sphere_3_192/ripser.dim_1.out.txt b/benchmarks/sphere_3_192/ripser.dim_1.out.txt index f7f631f..4ef9cb2 100644 --- a/benchmarks/sphere_3_192/ripser.dim_1.out.txt +++ b/benchmarks/sphere_3_192/ripser.dim_1.out.txt @@ -247,12 +247,12 @@ persistence intervals in dim 1: [0.24546,0.248903) [0.240869,0.288747) [0.189652,0.197515) - 0.03 real 0.02 user 0.00 sys - 3379200 maximum resident set size + 0.02 real 0.02 user 0.00 sys + 2682880 maximum resident set size 0 average shared memory size 0 average unshared data size 0 average unshared stack size - 844 page reclaims + 674 page reclaims 0 page faults 0 swaps 0 block input operations @@ -260,5 +260,5 @@ persistence intervals in dim 1: 0 messages sent 0 messages received 0 signals received - 4 voluntary context switches - 21 involuntary context switches + 5 voluntary context switches + 4 involuntary context switches diff --git a/benchmarks/sphere_3_192/ripser.dim_2.out.txt b/benchmarks/sphere_3_192/ripser.dim_2.out.txt index b3283e7..7ba2de6 100644 --- a/benchmarks/sphere_3_192/ripser.dim_2.out.txt +++ b/benchmarks/sphere_3_192/ripser.dim_2.out.txt @@ -249,12 +249,12 @@ persistence intervals in dim 1: [0.189652,0.197515) persistence intervals in dim 2: [0.720484,1.65562) - 1.17 real 1.08 user 0.08 sys - 182210560 maximum resident set size + 1.17 real 1.10 user 0.06 sys + 151293952 maximum resident set size 0 average shared memory size 0 average unshared data size 0 average unshared stack size - 44505 page reclaims + 36957 page reclaims 0 page faults 0 swaps 0 block input operations @@ -263,4 +263,4 @@ persistence intervals in dim 2: 0 messages received 0 signals received 2 voluntary context switches - 69 involuntary context switches + 49 involuntary context switches -- cgit v1.2.3 From d898ef27044bc7f10da478d16581915e95edc2c9 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 30 Mar 2017 08:36:40 +0200 Subject: progress indicator --- ripser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 53fa4fa..d3aa615 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -489,7 +489,7 @@ public: if (diameter <= threshold) columns_to_reduce.push_back(std::make_pair(diameter, index)); #ifdef INDICATE_PROGRESS - if ((index + 1) % 1000 == 0) + if ((index + 1) % 1000000 == 0) std::cout << "\033[K" << "assembled " << columns_to_reduce.size() << " out of " << (index + 1) << "/" << num_simplices << " columns" << std::flush @@ -543,7 +543,7 @@ public: value_t diameter = get_diameter(column_to_reduce); #ifdef INDICATE_PROGRESS - //if ((i + 1) % 1000 == 0) + if ((i + 1) % 1000000 == 0) std::cout << "\033[K" << "reducing column " << i + 1 << "/" << columns_to_reduce.size() << " (diameter " << diameter << ")" << std::flush << "\r"; -- cgit v1.2.3 From ad8ae0cfc24300996505fe1a2bd6795fbc6a2ed1 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Wed, 14 Jun 2017 09:42:03 +0200 Subject: remove google hashmap again (typically slower computation, only slightly less memory) --- Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 90543db..893d776 100644 --- a/Makefile +++ b/Makefile @@ -5,19 +5,19 @@ all: ripser ripser-coeff ripser-reduction ripser-coeff-reduction ripser-debug ripser: ripser.cpp - c++ -std=c++11 ripser.cpp -o ripser -Ofast -D NDEBUG -D USE_GOOGLE_HASHMAP + c++ -std=c++11 ripser.cpp -o ripser -Ofast -D NDEBUG ripser-coeff: ripser.cpp - c++ -std=c++11 ripser.cpp -o ripser-coeff -Ofast -D NDEBUG -D USE_GOOGLE_HASHMAP -D USE_COEFFICIENTS + c++ -std=c++11 ripser.cpp -o ripser-coeff -Ofast -D NDEBUG -D USE_COEFFICIENTS ripser-reduction: ripser.cpp - c++ -std=c++11 ripser.cpp -o ripser-reduction -Ofast -D NDEBUG -D USE_GOOGLE_HASHMAP -D ASSEMBLE_REDUCTION_MATRIX + c++ -std=c++11 ripser.cpp -o ripser-reduction -Ofast -D NDEBUG -D ASSEMBLE_REDUCTION_MATRIX ripser-coeff-reduction: ripser.cpp - c++ -std=c++11 ripser.cpp -o ripser-coeff-reduction -Ofast -D NDEBUG -D USE_GOOGLE_HASHMAP -D USE_COEFFICIENTS -D ASSEMBLE_REDUCTION_MATRIX + c++ -std=c++11 ripser.cpp -o ripser-coeff-reduction -Ofast -D NDEBUG -D USE_COEFFICIENTS -D ASSEMBLE_REDUCTION_MATRIX ripser-debug: ripser.cpp - c++ -std=c++11 ripser.cpp -o ripser-debug -g -D USE_GOOGLE_HASHMAP + c++ -std=c++11 ripser.cpp -o ripser-debug -g clean: -- cgit v1.2.3 From 0969baa58afd624a32fa73a1a7993d2d256bfa6d Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 24 Aug 2017 12:34:45 +0200 Subject: limits and thresholds for sparse distance matrices --- ripser.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index d3aa615..fceba33 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -855,7 +855,7 @@ int main(int argc, char** argv) { file_format format = DISTANCE_MATRIX; index_t dim_max = 1; - value_t threshold = std::numeric_limits::max(); + value_t threshold = std::numeric_limits::infinity(); #ifdef USE_COEFFICIENTS coefficient_t modulus = 2; @@ -917,7 +917,19 @@ int main(int argc, char** argv) { std::cout << "distance matrix with " << dist.size() << " points" << std::endl; auto value_range = std::minmax_element(dist.distances.begin(), dist.distances.end()); - std::cout << "value range: [" << *value_range.first << "," << *value_range.second << "]" + + value_t min = std::numeric_limits::infinity(), max = -std::numeric_limits::infinity(); + + for (auto d: dist.distances) { + if (d != std::numeric_limits::infinity() ) { + min = std::min(min, d); + max = std::max(max, d); + } else { + threshold = std::min(threshold, std::numeric_limits::max()); + } + } + + std::cout << "value range: [" << min << "," << max << "]" << std::endl; ripser(std::move(dist), dim_max, threshold, modulus).compute_barcodes(); -- cgit v1.2.3 From 02e1d32f8c19a92b91dab3fc2520a6f4a98640f1 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 24 Aug 2017 12:36:23 +0200 Subject: threshold for sparse distance matrix --- ripser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ripser.cpp b/ripser.cpp index 2f5a01a..74f9224 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -1079,7 +1079,7 @@ int main(int argc, char** argv) { std::cout << "value range: [" << min << "," << max << "]" << std::endl; - if (threshold == std::numeric_limits::max()) + if (threshold == std::numeric_limits::infinity()) ripser(std::move(dist), dim_max, threshold, modulus) .compute_barcodes(); else -- cgit v1.2.3 From b6b8b14a129107fc5bd70c999d551a6c9632881d Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Sat, 26 Aug 2017 08:19:09 +0200 Subject: filter by persistence ratio --- ripser.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 74f9224..2f41b05 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -394,6 +394,7 @@ template class ripser { DistanceMatrix dist; index_t n, dim_max; value_t threshold; + float ratio; coefficient_t modulus; const binomial_coeff_table binomial_coeff; std::vector multiplicative_inverse; @@ -402,10 +403,10 @@ template class ripser { mutable std::vector::const_reverse_iterator> neighbor_end; public: - ripser(DistanceMatrix&& _dist, index_t _dim_max, value_t _threshold, coefficient_t _modulus) + ripser(DistanceMatrix&& _dist, index_t _dim_max, value_t _threshold, float _ratio, coefficient_t _modulus) : dist(std::move(_dist)), n(dist.size()), dim_max(std::min(_dim_max, index_t(dist.size() - 2))), threshold(_threshold), - modulus(_modulus), binomial_coeff(n, dim_max + 2), + ratio(_ratio), modulus(_modulus), binomial_coeff(n, dim_max + 2), multiplicative_inverse(multiplicative_inverse_vector(_modulus)) {} index_t get_next_vertex(index_t& v, const index_t idx, const index_t k) const { @@ -781,7 +782,7 @@ public: found_persistence_pair: #ifdef PRINT_PERSISTENCE_PAIRS value_t death = get_diameter(pivot); - if (diameter != death) { + if ((float)death/diameter > ratio) { #ifdef INDICATE_PROGRESS std::cout << "\033[K"; #endif @@ -1003,6 +1004,9 @@ int main(int argc, char** argv) { index_t dim_max = 1; value_t threshold = std::numeric_limits::infinity(); + + float ratio = 1; + #ifdef USE_COEFFICIENTS coefficient_t modulus = 2; @@ -1024,6 +1028,11 @@ int main(int argc, char** argv) { size_t next_pos; threshold = std::stof(parameter, &next_pos); if (next_pos != parameter.size()) print_usage_and_exit(-1); + } else if (arg == "--ratio") { + std::string parameter = std::string(argv[++i]); + size_t next_pos; + ratio = std::stof(parameter, &next_pos); + if (next_pos != parameter.size()) print_usage_and_exit(-1); } else if (arg == "--format") { std::string parameter = std::string(argv[++i]); if (parameter == "lower-distance") @@ -1080,11 +1089,11 @@ int main(int argc, char** argv) { << std::endl; if (threshold == std::numeric_limits::infinity()) - ripser(std::move(dist), dim_max, threshold, modulus) + ripser(std::move(dist), dim_max, threshold, ratio, modulus) .compute_barcodes(); else ripser(sparse_distance_matrix(std::move(dist), threshold), dim_max, - threshold, modulus) + threshold, ratio, modulus) .compute_barcodes(); } -- cgit v1.2.3 From 991d4e17c873d64d2ad3c262dbcdaea59157ed50 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Fri, 1 Sep 2017 13:41:59 +0200 Subject: clarified code setting coefficient for column addition --- ripser.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index fceba33..49a1840 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -550,10 +550,13 @@ public: #endif index_t j = i; + + diameter_entry_t pivot; - // start with a dummy pivot entry with coefficient -1 in order to initialize + + // start with coefficient 1 in order to initialize // working_coboundary with the coboundary of the simplex with index column_to_reduce - diameter_entry_t pivot(0, -1, -1 + modulus); + coefficient_t factor = 1; #ifdef ASSEMBLE_REDUCTION_MATRIX // initialize reduction_coefficients as identity matrix @@ -566,7 +569,6 @@ public: bool might_be_apparent_pair = (i == j); do { - const coefficient_t factor = modulus - get_coefficient(pivot); #ifdef ASSEMBLE_REDUCTION_MATRIX #ifdef USE_COEFFICIENTS @@ -624,6 +626,7 @@ public: if (pair != pivot_column_index.end()) { j = pair->second; + factor = modulus - get_coefficient(pivot); continue; } } else { -- cgit v1.2.3 From eb10fdad464f3346663fa0ca6cde9aabd7cdbc14 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Fri, 1 Sep 2017 18:07:38 +0200 Subject: renamed some variables --- ripser.cpp | 74 +++++++++++++++++++++++++++++++------------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 49a1840..ec5d288 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -518,22 +518,22 @@ public: #endif #ifdef ASSEMBLE_REDUCTION_MATRIX - compressed_sparse_matrix reduction_coefficients; + compressed_sparse_matrix reduction_matrix; #else #ifdef USE_COEFFICIENTS - std::vector reduction_coefficients; + std::vector reduction_matrix; #endif #endif std::vector coface_entries; - for (index_t i = 0; i < columns_to_reduce.size(); ++i) { - auto column_to_reduce = columns_to_reduce[i]; + for (index_t index_column_to_reduce = 0; index_column_to_reduce < columns_to_reduce.size(); ++index_column_to_reduce) { + auto column_to_reduce = columns_to_reduce[index_column_to_reduce]; #ifdef ASSEMBLE_REDUCTION_MATRIX std::priority_queue, greater_diameter_or_smaller_index> - reduction_column; + working_reduction_column; #endif std::priority_queue, @@ -543,60 +543,60 @@ public: value_t diameter = get_diameter(column_to_reduce); #ifdef INDICATE_PROGRESS - if ((i + 1) % 1000000 == 0) + if ((index_column_to_reduce + 1) % 1000000 == 0) std::cout << "\033[K" - << "reducing column " << i + 1 << "/" << columns_to_reduce.size() + << "reducing column " << index_column_to_reduce + 1 << "/" << columns_to_reduce.size() << " (diameter " << diameter << ")" << std::flush << "\r"; #endif - index_t j = i; + index_t index_column_to_add = index_column_to_reduce; diameter_entry_t pivot; - // start with coefficient 1 in order to initialize - // working_coboundary with the coboundary of the simplex with index column_to_reduce - coefficient_t factor = 1; + // start with factor 1 in order to initialize working_coboundary + // with the coboundary of the simplex with index column_to_reduce + coefficient_t factor_column_to_add = 1; #ifdef ASSEMBLE_REDUCTION_MATRIX - // initialize reduction_coefficients as identity matrix - reduction_coefficients.append_column(); + // initialize reduction_matrix as identity matrix + reduction_matrix.append_column(); #endif #ifdef USE_COEFFICIENTS - reduction_coefficients.push_back(diameter_entry_t(column_to_reduce, 1)); + reduction_matrix.push_back(diameter_entry_t(column_to_reduce, 1)); #endif - bool might_be_apparent_pair = (i == j); + bool might_be_apparent_pair = (index_column_to_reduce == index_column_to_add); do { #ifdef ASSEMBLE_REDUCTION_MATRIX #ifdef USE_COEFFICIENTS - auto coeffs_begin = reduction_coefficients.cbegin(j), - coeffs_end = reduction_coefficients.cend(j); + auto reduction_column_begin = reduction_matrix.cbegin(index_column_to_add), + reduction_column_end = reduction_matrix.cend(index_column_to_add); #else std::vector coeffs; - coeffs.push_back(columns_to_reduce[j]); - for (auto it = reduction_coefficients.cbegin(j); - it != reduction_coefficients.cend(j); ++it) + coeffs.push_back(columns_to_reduce[index_column_to_add]); + for (auto it = reduction_matrix.cbegin(index_column_to_add); + it != reduction_matrix.cend(index_column_to_add); ++it) coeffs.push_back(*it); - auto coeffs_begin = coeffs.begin(), coeffs_end = coeffs.end(); + auto reduction_column_begin = coeffs.begin(), reduction_column_end = coeffs.end(); #endif #else #ifdef USE_COEFFICIENTS - auto coeffs_begin = &reduction_coefficients[j], - coeffs_end = &reduction_coefficients[j] + 1; + auto reduction_column_begin = &reduction_matrix[index_column_to_add], + reduction_column_end = &reduction_matrix[index_column_to_add] + 1; #else - auto coeffs_begin = &columns_to_reduce[j], coeffs_end = &columns_to_reduce[j] + 1; + auto reduction_column_begin = &columns_to_reduce[index_column_to_add], reduction_column_end = &columns_to_reduce[index_column_to_add] + 1; #endif #endif - for (auto it = coeffs_begin; it != coeffs_end; ++it) { + for (auto it = reduction_column_begin; it != reduction_column_end; ++it) { diameter_entry_t simplex = *it; - set_coefficient(simplex, get_coefficient(simplex) * factor % modulus); + set_coefficient(simplex, get_coefficient(simplex) * factor_column_to_add % modulus); #ifdef ASSEMBLE_REDUCTION_MATRIX - reduction_column.push(simplex); + working_reduction_column.push(simplex); #endif coface_entries.clear(); @@ -625,8 +625,8 @@ public: auto pair = pivot_column_index.find(get_index(pivot)); if (pair != pivot_column_index.end()) { - j = pair->second; - factor = modulus - get_coefficient(pivot); + index_column_to_add = pair->second; + factor_column_to_add = modulus - get_coefficient(pivot); continue; } } else { @@ -650,34 +650,34 @@ public: } #endif - pivot_column_index.insert(std::make_pair(get_index(pivot), i)); + pivot_column_index.insert(std::make_pair(get_index(pivot), index_column_to_reduce)); #ifdef USE_COEFFICIENTS const coefficient_t inverse = multiplicative_inverse[get_coefficient(pivot)]; #endif #ifdef ASSEMBLE_REDUCTION_MATRIX -// replace current column of reduction_coefficients (with a single diagonal 1 entry) +// replace current column of reduction_matrix (with a single diagonal 1 entry) // by reduction_column (possibly with a different entry on the diagonal) #ifdef USE_COEFFICIENTS - reduction_coefficients.pop_back(); + reduction_matrix.pop_back(); #else - pop_pivot(reduction_column, modulus); + pop_pivot(working_reduction_column, modulus); #endif while (true) { - diameter_entry_t e = pop_pivot(reduction_column, modulus); + diameter_entry_t e = pop_pivot(working_reduction_column, modulus); if (get_index(e) == -1) break; #ifdef USE_COEFFICIENTS set_coefficient(e, inverse * get_coefficient(e) % modulus); assert(get_coefficient(e) > 0); #endif - reduction_coefficients.push_back(e); + reduction_matrix.push_back(e); } #else #ifdef USE_COEFFICIENTS - reduction_coefficients.pop_back(); - reduction_coefficients.push_back(diameter_entry_t(column_to_reduce, inverse)); + reduction_matrix.pop_back(); + reduction_matrix.push_back(diameter_entry_t(column_to_reduce, inverse)); #endif #endif break; -- cgit v1.2.3 From fa4391b17f9aa2e2cedbf8ce855be2a55b7d5b60 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Wed, 13 Sep 2017 16:51:33 +0200 Subject: add Eirene benchmark --- benchmarks/sphere_3_192/eirene.dim_1.out.txt | 173 +++++++++++++++++++++++++++ benchmarks/sphere_3_192/eirene.dim_2.out.txt | 173 +++++++++++++++++++++++++++ benchmarks/sphere_3_192/run_eirene.sh | 7 ++ 3 files changed, 353 insertions(+) create mode 100644 benchmarks/sphere_3_192/eirene.dim_1.out.txt create mode 100644 benchmarks/sphere_3_192/eirene.dim_2.out.txt create mode 100644 benchmarks/sphere_3_192/run_eirene.sh diff --git a/benchmarks/sphere_3_192/eirene.dim_1.out.txt b/benchmarks/sphere_3_192/eirene.dim_1.out.txt new file mode 100644 index 0000000..3f205e1 --- /dev/null +++ b/benchmarks/sphere_3_192/eirene.dim_1.out.txt @@ -0,0 +1,173 @@ + + +Eirene Library for Homological Algebra +Copyright (C) 2016, 2017 Gregory Henselman +www.gregoryhenselman.org + +Eirene is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Eirene is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Eirene. If not, see . + + +WELCOME TO EIRENE! +v0.3.5 + +Please help us document Eirene's recent work! Bibtex entries and +contact information for teaching and outreach can be found at the +Eirene homepage, http://gregoryhenselman.org/eirene. + + +Please Note: MultivariateStats.jl may not be installed. This package is required for +some operations pertaining to multidimensional scaling, but is not required. +To install, enter the following at the Julia prompt: + +Pkg.add("MultivariateStats") +using MultivariateStats + + +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in __persistF2#19__ at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in __persistF2#19__ at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in __persistF2#19__ at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in __persistF2#19__ at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in __persistF2#19__ at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in __persistF2#19__ at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in ezlabel at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in ezlabel at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in ezlabel at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in ezlabel at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +Constructed Morse boundary operator, columns indexed by cells of dimension 1 +elapsed time: 5.240448941 seconds +Constructed Morse boundary operator, columns indexed by cells of dimension 1 +Constructed Morse boundary operator, columns indexed by cells of dimension 2 +Constructed Morse boundary operator, columns indexed by cells of dimension 3 +elapsed time: 2.614149242 seconds + 22.13 real 21.22 user 1.07 sys + 632369152 maximum resident set size + 0 average shared memory size + 0 average unshared data size + 0 average unshared stack size + 263754 page reclaims + 0 page faults + 0 swaps + 59 block input operations + 0 block output operations + 0 messages sent + 0 messages received + 5 signals received + 120 voluntary context switches + 165216 involuntary context switches diff --git a/benchmarks/sphere_3_192/eirene.dim_2.out.txt b/benchmarks/sphere_3_192/eirene.dim_2.out.txt new file mode 100644 index 0000000..acfb3db --- /dev/null +++ b/benchmarks/sphere_3_192/eirene.dim_2.out.txt @@ -0,0 +1,173 @@ + + +Eirene Library for Homological Algebra +Copyright (C) 2016, 2017 Gregory Henselman +www.gregoryhenselman.org + +Eirene is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Eirene is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Eirene. If not, see . + + +WELCOME TO EIRENE! +v0.3.5 + +Please help us document Eirene's recent work! Bibtex entries and +contact information for teaching and outreach can be found at the +Eirene homepage, http://gregoryhenselman.org/eirene. + + +Please Note: MultivariateStats.jl may not be installed. This package is required for +some operations pertaining to multidimensional scaling, but is not required. +To install, enter the following at the Julia prompt: + +Pkg.add("MultivariateStats") +using MultivariateStats + + +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in __persistF2#19__ at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in __persistF2#19__ at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in __persistF2#19__ at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in __persistF2#19__ at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in __persistF2#19__ at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in __persistF2#19__ at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in ezlabel at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in ezlabel at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in ezlabel at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +WARNING: Base.String is deprecated, use AbstractString instead. + likely near no file:0 +in ezlabel at /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl +Constructed Morse boundary operator, columns indexed by cells of dimension 1 +elapsed time: 5.023364429 seconds +Constructed Morse boundary operator, columns indexed by cells of dimension 1 +Constructed Morse boundary operator, columns indexed by cells of dimension 2 +Constructed Morse boundary operator, columns indexed by cells of dimension 3 +elapsed time: 13.676510239 seconds + 33.14 real 30.90 user 2.37 sys +1508073472 maximum resident set size + 0 average shared memory size + 0 average unshared data size + 0 average unshared stack size + 810601 page reclaims + 0 page faults + 0 swaps + 0 block input operations + 0 block output operations + 0 messages sent + 0 messages received + 5 signals received + 46 voluntary context switches + 195015 involuntary context switches diff --git a/benchmarks/sphere_3_192/run_eirene.sh b/benchmarks/sphere_3_192/run_eirene.sh new file mode 100644 index 0000000..4d76795 --- /dev/null +++ b/benchmarks/sphere_3_192/run_eirene.sh @@ -0,0 +1,7 @@ +/usr/bin/time -l julia --load /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl --eval \ +'p = readdlm("/Users/uli/Bitbucket/phat-paper/benchmark/point cloud/sphere_3_192_points.dat"); eirene(p, rowsare="points", bettimax=0); eirene(p, rowsare="points", bettimax=1);' \ +2>&1 | tee eirene.dim_1.out.txt + +/usr/bin/time -l julia --load /Users/uli/Source/Eirene0_3_5/Eirene0_3_5.jl --eval \ +'p = readdlm("/Users/uli/Bitbucket/phat-paper/benchmark/point cloud/sphere_3_192_points.dat"); eirene(p, rowsare="points", bettimax=0); eirene(p, rowsare="points", bettimax=2);' \ +2>&1 | tee eirene.dim_2.out.txt -- cgit v1.2.3 From bebf8d1c30f887de46bc1f6089464fa8e0d80081 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Fri, 22 Sep 2017 10:50:03 +0200 Subject: removed old value range computation --- ripser.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index ec5d288..555bde4 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -919,8 +919,6 @@ int main(int argc, char** argv) { std::cout << "distance matrix with " << dist.size() << " points" << std::endl; - auto value_range = std::minmax_element(dist.distances.begin(), dist.distances.end()); - value_t min = std::numeric_limits::infinity(), max = -std::numeric_limits::infinity(); for (auto d: dist.distances) { -- cgit v1.2.3 From 922acb40aec110347ac17da391ce5ae2b5da57db Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Sun, 24 Sep 2017 18:19:44 +0200 Subject: consolidated code for sparse and dense distance matrices --- ripser.cpp | 593 +++++++++++++++++++++++++++++-------------------------------- 1 file changed, 283 insertions(+), 310 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 2f41b05..1cb1d79 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -456,201 +456,12 @@ public: return diam; } - class simplex_coboundary_enumerator { - private: - index_t idx_below, idx_above, v, k; - std::vector vertices; - const diameter_entry_t simplex; - const coefficient_t modulus; - const compressed_lower_distance_matrix& dist; - const binomial_coeff_table& binomial_coeff; - - public: - simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, - const ripser& parent) - : idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), k(_dim + 1), - vertices(_dim + 1), simplex(_simplex), modulus(parent.modulus), dist(parent.dist), - binomial_coeff(parent.binomial_coeff) { - parent.get_simplex_vertices(get_index(_simplex), _dim, parent.n, vertices.begin()); - } - - bool has_next() { - while ((v != -1) && (binomial_coeff(v, k) <= idx_below)) { - idx_below -= binomial_coeff(v, k); - idx_above += binomial_coeff(v, k + 1); - --v; - --k; - assert(k != -1); - } - return v != -1; - } - - diameter_entry_t next() { - value_t coface_diameter = get_diameter(simplex); - for (index_t w : vertices) coface_diameter = std::max(coface_diameter, dist(v, w)); - index_t coface_index = idx_above + binomial_coeff(v--, k + 1) + idx_below; - coefficient_t coface_coefficient = - (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; - return diameter_entry_t(coface_diameter, coface_index, coface_coefficient); - } - }; - - class simplex_sparse_coboundary_enumerator { - private: - const ripser& parent; - - index_t idx_below, idx_above, v, k, max_vertex_below; - const diameter_entry_t simplex; - const coefficient_t modulus; - const DistanceMatrix& dist; - const binomial_coeff_table& binomial_coeff; - - std::vector& vertices; - std::vector::const_reverse_iterator>& neighbor_it; - std::vector::const_reverse_iterator>& neighbor_end; - diameter_index_t x; - - public: - simplex_sparse_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, - const ripser& _parent) - : parent(_parent), idx_below(get_index(_simplex)), idx_above(0), - v(parent.n - 1), k(_dim + 1), max_vertex_below(parent.n - 1), simplex(_simplex), modulus(parent.modulus), - dist(parent.dist), binomial_coeff(parent.binomial_coeff), vertices(parent.vertices), - neighbor_it(parent.neighbor_it), neighbor_end(parent.neighbor_end) { - - neighbor_it.clear(); - neighbor_end.clear(); - vertices.clear(); - - parent.get_simplex_vertices(idx_below, _dim, parent.n, std::back_inserter(vertices)); - - for (auto v : vertices) { - neighbor_it.push_back(dist.neighbors[v].rbegin()); - neighbor_end.push_back(dist.neighbors[v].rend()); - } - } - - bool has_next(bool all_cofaces = true) { - for (auto &it0 = neighbor_it[0], &end0 = neighbor_end[0]; it0 != end0; ++it0) { - x = *it0; - for (size_t idx = 1; idx < neighbor_it.size(); ++idx) { - auto &it = neighbor_it[idx], end = neighbor_end[idx]; - while (get_index(*it) > get_index(x)) - if (++it == end) return false; - auto y = *it; - if (get_index(y) != get_index(x)) - goto continue_outer; - else - x = std::max(x, y); - } - return all_cofaces || - !(k > 0 && - parent.get_next_vertex(max_vertex_below, idx_below, k) > get_index(x)); - continue_outer:; - } - return false; - } - - diameter_entry_t next() { - ++neighbor_it[0]; - - while (k > 0 && parent.get_next_vertex(max_vertex_below, idx_below, k) > get_index(x)) { - idx_below -= binomial_coeff(max_vertex_below, k); - idx_above += binomial_coeff(max_vertex_below, k + 1); - --k; - } - - value_t coface_diameter = std::max(get_diameter(simplex), get_diameter(x)); - - coefficient_t coface_coefficient = - (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; - - return diameter_entry_t(coface_diameter, - idx_above + binomial_coeff(get_index(x), k + 1) + idx_below, - coface_coefficient); - } - }; - - void assemble_columns_to_reduce(std::vector& columns_to_reduce, - hash_map& pivot_column_index, index_t dim) { - index_t num_simplices = binomial_coeff(n, dim + 1); - - columns_to_reduce.clear(); - -#ifdef INDICATE_PROGRESS - std::cout << "\033[K" - << "assembling " << num_simplices << " columns" << std::flush << "\r"; -#endif - - for (index_t index = 0; index < num_simplices; ++index) { - if (pivot_column_index.find(index) == pivot_column_index.end()) { - value_t diameter = compute_diameter(index, dim); - if (diameter <= threshold) - columns_to_reduce.push_back(std::make_pair(diameter, index)); -#ifdef INDICATE_PROGRESS - if ((index + 1) % 1000000 == 0) - std::cout << "\033[K" - << "assembled " << columns_to_reduce.size() << " out of " - << (index + 1) << "/" << num_simplices << " columns" << std::flush - << "\r"; -#endif - } - } - -#ifdef INDICATE_PROGRESS - std::cout << "\033[K" - << "sorting " << num_simplices << " columns" << std::flush << "\r"; -#endif - - std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), - greater_diameter_or_smaller_index()); -#ifdef INDICATE_PROGRESS - std::cout << "\033[K"; -#endif - } - - void assemble_sparse_columns_to_reduce(std::vector& simplices, - std::vector& columns_to_reduce, - hash_map& pivot_column_index, - index_t dim) { - -#ifdef INDICATE_PROGRESS - std::cout << "\033[K" - << "assembling columns" << std::flush << "\r"; -#endif - - --dim; - columns_to_reduce.clear(); - - std::vector next_simplices; - - for (diameter_index_t simplex : simplices) { - simplex_sparse_coboundary_enumerator cofaces(simplex, dim, *this); - - while (cofaces.has_next(false)) { - auto coface = cofaces.next(); - - next_simplices.push_back(std::make_pair(get_diameter(coface), get_index(coface))); - - if (pivot_column_index.find(get_index(coface)) == pivot_column_index.end()) - columns_to_reduce.push_back( - std::make_pair(get_diameter(coface), get_index(coface))); - } - } - - simplices.swap(next_simplices); - -#ifdef INDICATE_PROGRESS - std::cout << "\033[K" - << "sorting " << columns_to_reduce.size() << " columns" << std::flush << "\r"; -#endif + class simplex_coboundary_enumerator; - std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), - greater_diameter_or_smaller_index()); -#ifdef INDICATE_PROGRESS - std::cout << "\033[K"; -#endif - } + void assemble_columns_to_reduce(std::vector& simplices, + std::vector& columns_to_reduce, + hash_map& pivot_column_index, + index_t dim); template void compute_pairs(std::vector& columns_to_reduce, @@ -829,11 +640,286 @@ public: #endif } - void compute_barcodes(); + std::vector get_edges(); + + void compute_barcodes() { + + std::vector columns_to_reduce; + + std::vector simplices; + + { + union_find dset(n); + std::vector& edges = simplices; + + edges = get_edges(); + + std::sort(edges.rbegin(), edges.rend(), + greater_diameter_or_smaller_index()); + +#ifdef PRINT_PERSISTENCE_PAIRS + std::cout << "persistence intervals in dim 0:" << std::endl; +#endif + + std::vector vertices_of_edge(2); + for (auto e : edges) { + vertices_of_edge.clear(); + get_simplex_vertices(get_index(e), 1, n, std::back_inserter(vertices_of_edge)); + index_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]); + + if (u != v) { +#ifdef PRINT_PERSISTENCE_PAIRS + if (get_diameter(e) != 0) + std::cout << " [0," << get_diameter(e) << ")" << std::endl; +#endif + dset.link(u, v); + } else + columns_to_reduce.push_back(e); + } + std::reverse(columns_to_reduce.begin(), columns_to_reduce.end()); + +#ifdef PRINT_PERSISTENCE_PAIRS + for (index_t i = 0; i < n; ++i) + if (dset.find(i) == i) std::cout << " [0, )" << std::endl << std::flush; +#endif + } + + for (index_t dim = 1; dim <= dim_max; ++dim) { + hash_map pivot_column_index; + pivot_column_index.reserve(columns_to_reduce.size()); + + compute_pairs(columns_to_reduce, pivot_column_index, + dim); + + if (dim < dim_max) { + assemble_columns_to_reduce(simplices, columns_to_reduce, pivot_column_index, + dim + 1); + } + } + } }; -template <> void ripser::compute_barcodes(); -template <> void ripser::compute_barcodes(); + +template <> +class ripser::simplex_coboundary_enumerator { +private: + index_t idx_below, idx_above, v, k; + std::vector vertices; + const diameter_entry_t simplex; + const coefficient_t modulus; + const compressed_lower_distance_matrix& dist; + const binomial_coeff_table& binomial_coeff; + +public: + simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, + const ripser& parent) + : idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), k(_dim + 1), + vertices(_dim + 1), simplex(_simplex), modulus(parent.modulus), dist(parent.dist), + binomial_coeff(parent.binomial_coeff) { + parent.get_simplex_vertices(get_index(_simplex), _dim, parent.n, vertices.begin()); + } + + bool has_next() { + while ((v != -1) && (binomial_coeff(v, k) <= idx_below)) { + idx_below -= binomial_coeff(v, k); + idx_above += binomial_coeff(v, k + 1); + --v; + --k; + assert(k != -1); + } + return v != -1; + } + + diameter_entry_t next() { + value_t coface_diameter = get_diameter(simplex); + for (index_t w : vertices) coface_diameter = std::max(coface_diameter, dist(v, w)); + index_t coface_index = idx_above + binomial_coeff(v--, k + 1) + idx_below; + coefficient_t coface_coefficient = + (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; + return diameter_entry_t(coface_diameter, coface_index, coface_coefficient); + } +}; + +template <> +class ripser::simplex_coboundary_enumerator { +private: + const ripser& parent; + + index_t idx_below, idx_above, v, k, max_vertex_below; + const diameter_entry_t simplex; + const coefficient_t modulus; + const sparse_distance_matrix& dist; + const binomial_coeff_table& binomial_coeff; + + std::vector& vertices; + std::vector::const_reverse_iterator>& neighbor_it; + std::vector::const_reverse_iterator>& neighbor_end; + diameter_index_t x; + +public: + simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, + const ripser& _parent) + : parent(_parent), idx_below(get_index(_simplex)), idx_above(0), + v(parent.n - 1), k(_dim + 1), max_vertex_below(parent.n - 1), simplex(_simplex), modulus(parent.modulus), + dist(parent.dist), binomial_coeff(parent.binomial_coeff), vertices(parent.vertices), + neighbor_it(parent.neighbor_it), neighbor_end(parent.neighbor_end) { + + neighbor_it.clear(); + neighbor_end.clear(); + vertices.clear(); + + parent.get_simplex_vertices(idx_below, _dim, parent.n, std::back_inserter(vertices)); + + for (auto v : vertices) { + neighbor_it.push_back(dist.neighbors[v].rbegin()); + neighbor_end.push_back(dist.neighbors[v].rend()); + } + } + + bool has_next(bool all_cofaces = true) { + for (auto &it0 = neighbor_it[0], &end0 = neighbor_end[0]; it0 != end0; ++it0) { + x = *it0; + for (size_t idx = 1; idx < neighbor_it.size(); ++idx) { + auto &it = neighbor_it[idx], end = neighbor_end[idx]; + while (get_index(*it) > get_index(x)) + if (++it == end) return false; + auto y = *it; + if (get_index(y) != get_index(x)) + goto continue_outer; + else + x = std::max(x, y); + } + return all_cofaces || + !(k > 0 && + parent.get_next_vertex(max_vertex_below, idx_below, k) > get_index(x)); + continue_outer:; + } + return false; + } + + diameter_entry_t next() { + ++neighbor_it[0]; + + while (k > 0 && parent.get_next_vertex(max_vertex_below, idx_below, k) > get_index(x)) { + idx_below -= binomial_coeff(max_vertex_below, k); + idx_above += binomial_coeff(max_vertex_below, k + 1); + --k; + } + + value_t coface_diameter = std::max(get_diameter(simplex), get_diameter(x)); + + coefficient_t coface_coefficient = + (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; + + return diameter_entry_t(coface_diameter, + idx_above + binomial_coeff(get_index(x), k + 1) + idx_below, + coface_coefficient); + } +}; + + +template <> std::vector ripser::get_edges() { + std::vector edges; + for (index_t index = binomial_coeff(n, 2); index-- > 0;) { + value_t diameter = compute_diameter(index, 1); + if (diameter <= threshold) edges.push_back(std::make_pair(diameter, index)); + } + return edges; +} + +template <> std::vector ripser::get_edges() { + std::vector edges; + for (index_t i = 0; i < n; ++i) + for (auto n : dist.neighbors[i]) { + index_t j = get_index(n); + if (i > j) edges.push_back(std::make_pair(get_diameter(n), get_edge_index(i, j))); + } + return edges; +} + +template <> void ripser:: +assemble_columns_to_reduce(std::vector& simplices, + std::vector& columns_to_reduce, + hash_map& pivot_column_index, index_t dim) { + index_t num_simplices = binomial_coeff(n, dim + 1); + + columns_to_reduce.clear(); + +#ifdef INDICATE_PROGRESS + std::cout << "\033[K" + << "assembling " << num_simplices << " columns" << std::flush << "\r"; +#endif + + for (index_t index = 0; index < num_simplices; ++index) { + if (pivot_column_index.find(index) == pivot_column_index.end()) { + value_t diameter = compute_diameter(index, dim); + if (diameter <= threshold) + columns_to_reduce.push_back(std::make_pair(diameter, index)); +#ifdef INDICATE_PROGRESS + if ((index + 1) % 1000000 == 0) + std::cout << "\033[K" + << "assembled " << columns_to_reduce.size() << " out of " + << (index + 1) << "/" << num_simplices << " columns" << std::flush + << "\r"; +#endif + } + } + +#ifdef INDICATE_PROGRESS + std::cout << "\033[K" + << "sorting " << num_simplices << " columns" << std::flush << "\r"; +#endif + + std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), + greater_diameter_or_smaller_index()); +#ifdef INDICATE_PROGRESS + std::cout << "\033[K"; +#endif +} + +template <> void ripser:: +assemble_columns_to_reduce(std::vector& simplices, + std::vector& columns_to_reduce, + hash_map& pivot_column_index, + index_t dim) { + +#ifdef INDICATE_PROGRESS + std::cout << "\033[K" + << "assembling columns" << std::flush << "\r"; +#endif + + --dim; + columns_to_reduce.clear(); + + std::vector next_simplices; + + for (diameter_index_t simplex : simplices) { + simplex_coboundary_enumerator cofaces(simplex, dim, *this); + + while (cofaces.has_next(false)) { + auto coface = cofaces.next(); + + next_simplices.push_back(std::make_pair(get_diameter(coface), get_index(coface))); + + if (pivot_column_index.find(get_index(coface)) == pivot_column_index.end()) + columns_to_reduce.push_back( + std::make_pair(get_diameter(coface), get_index(coface))); + } + } + + simplices.swap(next_simplices); + +#ifdef INDICATE_PROGRESS + std::cout << "\033[K" + << "sorting " << columns_to_reduce.size() << " columns" << std::flush << "\r"; +#endif + + std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), + greater_diameter_or_smaller_index()); +#ifdef INDICATE_PROGRESS + std::cout << "\033[K"; +#endif +} enum file_format { LOWER_DISTANCE_MATRIX, @@ -1072,8 +1158,6 @@ int main(int argc, char** argv) { std::cout << "distance matrix with " << dist.size() << " points" << std::endl; - auto value_range = std::minmax_element(dist.distances.begin(), dist.distances.end()); - value_t min = std::numeric_limits::infinity(), max = -std::numeric_limits::infinity(); for (auto d: dist.distances) { @@ -1097,114 +1181,3 @@ int main(int argc, char** argv) { .compute_barcodes(); } - -template <> void ripser::compute_barcodes() { - - std::vector columns_to_reduce; - - { - union_find dset(n); - std::vector edges; - for (index_t index = binomial_coeff(n, 2); index-- > 0;) { - value_t diameter = compute_diameter(index, 1); - if (diameter <= threshold) edges.push_back(std::make_pair(diameter, index)); - } - std::sort(edges.rbegin(), edges.rend(), - greater_diameter_or_smaller_index()); - -#ifdef PRINT_PERSISTENCE_PAIRS - std::cout << "persistence intervals in dim 0:" << std::endl; -#endif - - std::vector vertices_of_edge(2); - for (auto e : edges) { - vertices_of_edge.clear(); - get_simplex_vertices(get_index(e), 1, n, std::back_inserter(vertices_of_edge)); - index_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]); - - if (u != v) { -#ifdef PRINT_PERSISTENCE_PAIRS - if (get_diameter(e) != 0) - std::cout << " [0," << get_diameter(e) << ")" << std::endl; -#endif - dset.link(u, v); - } else - columns_to_reduce.push_back(e); - } - std::reverse(columns_to_reduce.begin(), columns_to_reduce.end()); - -#ifdef PRINT_PERSISTENCE_PAIRS - for (index_t i = 0; i < n; ++i) - if (dset.find(i) == i) std::cout << " [0, )" << std::endl << std::flush; -#endif - } - - for (index_t dim = 1; dim <= dim_max; ++dim) { - hash_map pivot_column_index; - pivot_column_index.reserve(columns_to_reduce.size()); - - compute_pairs(columns_to_reduce, pivot_column_index, dim); - - if (dim < dim_max) { - assemble_columns_to_reduce(columns_to_reduce, pivot_column_index, dim + 1); - } - } -} - -template <> void ripser::compute_barcodes() { - - std::vector columns_to_reduce; - - std::vector simplices; - - { - union_find dset(n); - std::vector& edges = simplices; - for (index_t i = 0; i < n; ++i) - for (auto n : dist.neighbors[i]) { - index_t j = get_index(n); - if (i > j) edges.push_back(std::make_pair(get_diameter(n), get_edge_index(i, j))); - } - std::sort(edges.rbegin(), edges.rend(), - greater_diameter_or_smaller_index()); - -#ifdef PRINT_PERSISTENCE_PAIRS - std::cout << "persistence intervals in dim 0:" << std::endl; -#endif - - std::vector vertices_of_edge(2); - for (auto e : edges) { - vertices_of_edge.clear(); - get_simplex_vertices(get_index(e), 1, n, std::back_inserter(vertices_of_edge)); - index_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]); - - if (u != v) { -#ifdef PRINT_PERSISTENCE_PAIRS - if (get_diameter(e) != 0) - std::cout << " [0," << get_diameter(e) << ")" << std::endl; -#endif - dset.link(u, v); - } else - columns_to_reduce.push_back(e); - } - std::reverse(columns_to_reduce.begin(), columns_to_reduce.end()); - -#ifdef PRINT_PERSISTENCE_PAIRS - for (index_t i = 0; i < n; ++i) - if (dset.find(i) == i) std::cout << " [0, )" << std::endl << std::flush; -#endif - } - - for (index_t dim = 1; dim <= dim_max; ++dim) { - hash_map pivot_column_index; - pivot_column_index.reserve(columns_to_reduce.size()); - - compute_pairs(columns_to_reduce, pivot_column_index, - dim); - - if (dim < dim_max) { - assemble_sparse_columns_to_reduce(simplices, columns_to_reduce, pivot_column_index, - dim + 1); - } - } -} -- cgit v1.2.3 From 12bda394bdf6d2c610600b246b500908f88e4d10 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Sun, 24 Sep 2017 18:59:04 +0200 Subject: extracted dim 0 computation --- ripser.cpp | 80 +++++++++++++++++++++++++++++++------------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 1cb1d79..688df6a 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -462,6 +462,42 @@ public: std::vector& columns_to_reduce, hash_map& pivot_column_index, index_t dim); + + void compute_dim_0_pairs(std::vector& edges, + std::vector& columns_to_reduce) { + union_find dset(n); + + edges = get_edges(); + + std::sort(edges.rbegin(), edges.rend(), + greater_diameter_or_smaller_index()); + +#ifdef PRINT_PERSISTENCE_PAIRS + std::cout << "persistence intervals in dim 0:" << std::endl; +#endif + + std::vector vertices_of_edge(2); + for (auto e : edges) { + vertices_of_edge.clear(); + get_simplex_vertices(get_index(e), 1, n, std::back_inserter(vertices_of_edge)); + index_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]); + + if (u != v) { +#ifdef PRINT_PERSISTENCE_PAIRS + if (get_diameter(e) != 0) + std::cout << " [0," << get_diameter(e) << ")" << std::endl; +#endif + dset.link(u, v); + } else + columns_to_reduce.push_back(e); + } + std::reverse(columns_to_reduce.begin(), columns_to_reduce.end()); + +#ifdef PRINT_PERSISTENCE_PAIRS + for (index_t i = 0; i < n; ++i) + if (dset.find(i) == i) std::cout << " [0, )" << std::endl << std::flush; +#endif + } template void compute_pairs(std::vector& columns_to_reduce, @@ -644,56 +680,20 @@ public: void compute_barcodes() { - std::vector columns_to_reduce; + std::vector simplices, columns_to_reduce; - std::vector simplices; - - { - union_find dset(n); - std::vector& edges = simplices; - - edges = get_edges(); - - std::sort(edges.rbegin(), edges.rend(), - greater_diameter_or_smaller_index()); - -#ifdef PRINT_PERSISTENCE_PAIRS - std::cout << "persistence intervals in dim 0:" << std::endl; -#endif - - std::vector vertices_of_edge(2); - for (auto e : edges) { - vertices_of_edge.clear(); - get_simplex_vertices(get_index(e), 1, n, std::back_inserter(vertices_of_edge)); - index_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]); - - if (u != v) { -#ifdef PRINT_PERSISTENCE_PAIRS - if (get_diameter(e) != 0) - std::cout << " [0," << get_diameter(e) << ")" << std::endl; -#endif - dset.link(u, v); - } else - columns_to_reduce.push_back(e); - } - std::reverse(columns_to_reduce.begin(), columns_to_reduce.end()); - -#ifdef PRINT_PERSISTENCE_PAIRS - for (index_t i = 0; i < n; ++i) - if (dset.find(i) == i) std::cout << " [0, )" << std::endl << std::flush; -#endif - } + compute_dim_0_pairs(simplices, columns_to_reduce); for (index_t dim = 1; dim <= dim_max; ++dim) { hash_map pivot_column_index; pivot_column_index.reserve(columns_to_reduce.size()); compute_pairs(columns_to_reduce, pivot_column_index, - dim); + dim); if (dim < dim_max) { assemble_columns_to_reduce(simplices, columns_to_reduce, pivot_column_index, - dim + 1); + dim + 1); } } } -- cgit v1.2.3 From 740992e73b581c646f0f381789264f2504e76e8b Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Sun, 24 Sep 2017 19:16:08 +0200 Subject: use sparse distance matrix only when threshold is below maximum value --- ripser.cpp | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 688df6a..5acc32e 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -1089,10 +1089,9 @@ int main(int argc, char** argv) { file_format format = DISTANCE_MATRIX; index_t dim_max = 1; - value_t threshold = std::numeric_limits::infinity(); - - float ratio = 1; + value_t threshold = std::numeric_limits::max(); + float ratio = 1; #ifdef USE_COEFFICIENTS coefficient_t modulus = 2; @@ -1156,28 +1155,30 @@ int main(int argc, char** argv) { compressed_lower_distance_matrix dist = read_file(filename ? file_stream : std::cin, format); - std::cout << "distance matrix with " << dist.size() << " points" << std::endl; + value_t min = std::numeric_limits::infinity(), + max = -std::numeric_limits::infinity(), max_finite = max; + int num_edges = 0; - value_t min = std::numeric_limits::infinity(), max = -std::numeric_limits::infinity(); - - for (auto d: dist.distances) { - if (d != std::numeric_limits::infinity() ) { - min = std::min(min, d); - max = std::max(max, d); - } else { - threshold = std::min(threshold, std::numeric_limits::max()); - } + for (auto d : dist.distances) { + min = std::min(min, d); + max = std::max(max, d); + max_finite = d != std::numeric_limits::infinity() ? std::max(max, d) : max_finite; + if (d <= threshold) ++num_edges; } - - std::cout << "value range: [" << min << "," << max << "]" - << std::endl; - if (threshold == std::numeric_limits::infinity()) - ripser(std::move(dist), dim_max, threshold, ratio, modulus) - .compute_barcodes(); - else + std::cout << "value range: [" << min << "," << max_finite << "]" << std::endl; + + if (threshold >= max) { + std::cout << "distance matrix with " << dist.size() << " points" << std::endl; + ripser(std::move(dist), dim_max, threshold, ratio, + modulus) + .compute_barcodes(); + } else { + std::cout << "sparse distance matrix with " << dist.size() << " points and " << num_edges + << " entries" << std::endl; + ripser(sparse_distance_matrix(std::move(dist), threshold), dim_max, threshold, ratio, modulus) - .compute_barcodes(); - + .compute_barcodes(); + } } -- cgit v1.2.3 From a962f06a93df50941c813d187730b849b8fd84d6 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Sun, 24 Sep 2017 19:16:35 +0200 Subject: pretty-print --- ripser.cpp | 190 +++++++++++++++++++++++++++++-------------------------------- 1 file changed, 91 insertions(+), 99 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 5acc32e..70a092a 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -146,7 +146,8 @@ public: diameter_entry_t(const diameter_index_t& _diameter_index, coefficient_t _coefficient) : std::pair(get_diameter(_diameter_index), make_entry(get_index(_diameter_index), _coefficient)) {} - diameter_entry_t(const diameter_index_t& _diameter_index) : diameter_entry_t(_diameter_index, 1) {} + diameter_entry_t(const diameter_index_t& _diameter_index) + : diameter_entry_t(_diameter_index, 1) {} }; const entry_t& get_entry(const diameter_entry_t& p) { return p.second; } @@ -249,10 +250,8 @@ public: euclidean_distance_matrix(std::vector>&& _points) : points(std::move(_points)) { - for (auto p: points) { - assert(p.size() == points.front().size()); - } - } + for (auto p : points) { assert(p.size() == points.front().size()); } + } value_t operator()(const index_t i, const index_t j) const { assert(i < points.size()); @@ -403,7 +402,8 @@ template class ripser { mutable std::vector::const_reverse_iterator> neighbor_end; public: - ripser(DistanceMatrix&& _dist, index_t _dim_max, value_t _threshold, float _ratio, coefficient_t _modulus) + ripser(DistanceMatrix&& _dist, index_t _dim_max, value_t _threshold, float _ratio, + coefficient_t _modulus) : dist(std::move(_dist)), n(dist.size()), dim_max(std::min(_dim_max, index_t(dist.size() - 2))), threshold(_threshold), ratio(_ratio), modulus(_modulus), binomial_coeff(n, dim_max + 2), @@ -459,29 +459,28 @@ public: class simplex_coboundary_enumerator; void assemble_columns_to_reduce(std::vector& simplices, - std::vector& columns_to_reduce, - hash_map& pivot_column_index, - index_t dim); - + std::vector& columns_to_reduce, + hash_map& pivot_column_index, index_t dim); + void compute_dim_0_pairs(std::vector& edges, - std::vector& columns_to_reduce) { + std::vector& columns_to_reduce) { union_find dset(n); - + edges = get_edges(); - + std::sort(edges.rbegin(), edges.rend(), - greater_diameter_or_smaller_index()); - + greater_diameter_or_smaller_index()); + #ifdef PRINT_PERSISTENCE_PAIRS std::cout << "persistence intervals in dim 0:" << std::endl; #endif - + std::vector vertices_of_edge(2); for (auto e : edges) { vertices_of_edge.clear(); get_simplex_vertices(get_index(e), 1, n, std::back_inserter(vertices_of_edge)); index_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]); - + if (u != v) { #ifdef PRINT_PERSISTENCE_PAIRS if (get_diameter(e) != 0) @@ -492,7 +491,7 @@ public: columns_to_reduce.push_back(e); } std::reverse(columns_to_reduce.begin(), columns_to_reduce.end()); - + #ifdef PRINT_PERSISTENCE_PAIRS for (index_t i = 0; i < n; ++i) if (dset.find(i) == i) std::cout << " [0, )" << std::endl << std::flush; @@ -629,7 +628,7 @@ public: found_persistence_pair: #ifdef PRINT_PERSISTENCE_PAIRS value_t death = get_diameter(pivot); - if ((float)death/diameter > ratio) { + if ((float)death / diameter > ratio) { #ifdef INDICATE_PROGRESS std::cout << "\033[K"; #endif @@ -677,31 +676,29 @@ public: } std::vector get_edges(); - + void compute_barcodes() { - + std::vector simplices, columns_to_reduce; - + compute_dim_0_pairs(simplices, columns_to_reduce); - + for (index_t dim = 1; dim <= dim_max; ++dim) { hash_map pivot_column_index; pivot_column_index.reserve(columns_to_reduce.size()); - + compute_pairs(columns_to_reduce, pivot_column_index, - dim); - + dim); + if (dim < dim_max) { assemble_columns_to_reduce(simplices, columns_to_reduce, pivot_column_index, - dim + 1); + dim + 1); } } } }; - -template <> -class ripser::simplex_coboundary_enumerator { +template <> class ripser::simplex_coboundary_enumerator { private: index_t idx_below, idx_above, v, k; std::vector vertices; @@ -709,16 +706,16 @@ private: const coefficient_t modulus; const compressed_lower_distance_matrix& dist; const binomial_coeff_table& binomial_coeff; - + public: simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, - const ripser& parent) - : idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), k(_dim + 1), - vertices(_dim + 1), simplex(_simplex), modulus(parent.modulus), dist(parent.dist), - binomial_coeff(parent.binomial_coeff) { + const ripser& parent) + : idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), k(_dim + 1), + vertices(_dim + 1), simplex(_simplex), modulus(parent.modulus), dist(parent.dist), + binomial_coeff(parent.binomial_coeff) { parent.get_simplex_vertices(get_index(_simplex), _dim, parent.n, vertices.begin()); } - + bool has_next() { while ((v != -1) && (binomial_coeff(v, k) <= idx_below)) { idx_below -= binomial_coeff(v, k); @@ -729,53 +726,52 @@ public: } return v != -1; } - + diameter_entry_t next() { value_t coface_diameter = get_diameter(simplex); for (index_t w : vertices) coface_diameter = std::max(coface_diameter, dist(v, w)); index_t coface_index = idx_above + binomial_coeff(v--, k + 1) + idx_below; coefficient_t coface_coefficient = - (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; + (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; return diameter_entry_t(coface_diameter, coface_index, coface_coefficient); } }; -template <> -class ripser::simplex_coboundary_enumerator { +template <> class ripser::simplex_coboundary_enumerator { private: const ripser& parent; - + index_t idx_below, idx_above, v, k, max_vertex_below; const diameter_entry_t simplex; const coefficient_t modulus; const sparse_distance_matrix& dist; const binomial_coeff_table& binomial_coeff; - + std::vector& vertices; std::vector::const_reverse_iterator>& neighbor_it; std::vector::const_reverse_iterator>& neighbor_end; diameter_index_t x; - + public: simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, - const ripser& _parent) - : parent(_parent), idx_below(get_index(_simplex)), idx_above(0), - v(parent.n - 1), k(_dim + 1), max_vertex_below(parent.n - 1), simplex(_simplex), modulus(parent.modulus), - dist(parent.dist), binomial_coeff(parent.binomial_coeff), vertices(parent.vertices), - neighbor_it(parent.neighbor_it), neighbor_end(parent.neighbor_end) { - + const ripser& _parent) + : parent(_parent), idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), + k(_dim + 1), max_vertex_below(parent.n - 1), simplex(_simplex), modulus(parent.modulus), + dist(parent.dist), binomial_coeff(parent.binomial_coeff), vertices(parent.vertices), + neighbor_it(parent.neighbor_it), neighbor_end(parent.neighbor_end) { + neighbor_it.clear(); neighbor_end.clear(); vertices.clear(); - + parent.get_simplex_vertices(idx_below, _dim, parent.n, std::back_inserter(vertices)); - + for (auto v : vertices) { neighbor_it.push_back(dist.neighbors[v].rbegin()); neighbor_end.push_back(dist.neighbors[v].rend()); } } - + bool has_next(bool all_cofaces = true) { for (auto &it0 = neighbor_it[0], &end0 = neighbor_end[0]; it0 != end0; ++it0) { x = *it0; @@ -790,34 +786,33 @@ public: x = std::max(x, y); } return all_cofaces || - !(k > 0 && - parent.get_next_vertex(max_vertex_below, idx_below, k) > get_index(x)); + !(k > 0 && + parent.get_next_vertex(max_vertex_below, idx_below, k) > get_index(x)); continue_outer:; } return false; } - + diameter_entry_t next() { ++neighbor_it[0]; - + while (k > 0 && parent.get_next_vertex(max_vertex_below, idx_below, k) > get_index(x)) { idx_below -= binomial_coeff(max_vertex_below, k); idx_above += binomial_coeff(max_vertex_below, k + 1); --k; } - + value_t coface_diameter = std::max(get_diameter(simplex), get_diameter(x)); - + coefficient_t coface_coefficient = - (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; - + (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; + return diameter_entry_t(coface_diameter, - idx_above + binomial_coeff(get_index(x), k + 1) + idx_below, - coface_coefficient); + idx_above + binomial_coeff(get_index(x), k + 1) + idx_below, + coface_coefficient); } }; - template <> std::vector ripser::get_edges() { std::vector edges; for (index_t index = binomial_coeff(n, 2); index-- > 0;) { @@ -837,85 +832,82 @@ template <> std::vector ripser::get_ed return edges; } -template <> void ripser:: -assemble_columns_to_reduce(std::vector& simplices, - std::vector& columns_to_reduce, - hash_map& pivot_column_index, index_t dim) { +template <> +void ripser::assemble_columns_to_reduce( + std::vector& simplices, std::vector& columns_to_reduce, + hash_map& pivot_column_index, index_t dim) { index_t num_simplices = binomial_coeff(n, dim + 1); - + columns_to_reduce.clear(); - + #ifdef INDICATE_PROGRESS std::cout << "\033[K" - << "assembling " << num_simplices << " columns" << std::flush << "\r"; + << "assembling " << num_simplices << " columns" << std::flush << "\r"; #endif - + for (index_t index = 0; index < num_simplices; ++index) { if (pivot_column_index.find(index) == pivot_column_index.end()) { value_t diameter = compute_diameter(index, dim); - if (diameter <= threshold) - columns_to_reduce.push_back(std::make_pair(diameter, index)); + if (diameter <= threshold) columns_to_reduce.push_back(std::make_pair(diameter, index)); #ifdef INDICATE_PROGRESS if ((index + 1) % 1000000 == 0) std::cout << "\033[K" - << "assembled " << columns_to_reduce.size() << " out of " - << (index + 1) << "/" << num_simplices << " columns" << std::flush - << "\r"; + << "assembled " << columns_to_reduce.size() << " out of " << (index + 1) + << "/" << num_simplices << " columns" << std::flush << "\r"; #endif } } - + #ifdef INDICATE_PROGRESS std::cout << "\033[K" - << "sorting " << num_simplices << " columns" << std::flush << "\r"; + << "sorting " << num_simplices << " columns" << std::flush << "\r"; #endif - + std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), - greater_diameter_or_smaller_index()); + greater_diameter_or_smaller_index()); #ifdef INDICATE_PROGRESS std::cout << "\033[K"; #endif } -template <> void ripser:: -assemble_columns_to_reduce(std::vector& simplices, - std::vector& columns_to_reduce, - hash_map& pivot_column_index, - index_t dim) { - +template <> +void ripser::assemble_columns_to_reduce( + std::vector& simplices, std::vector& columns_to_reduce, + hash_map& pivot_column_index, index_t dim) { + #ifdef INDICATE_PROGRESS std::cout << "\033[K" - << "assembling columns" << std::flush << "\r"; + << "assembling columns" << std::flush << "\r"; #endif - + --dim; columns_to_reduce.clear(); - + std::vector next_simplices; - + for (diameter_index_t simplex : simplices) { simplex_coboundary_enumerator cofaces(simplex, dim, *this); - + while (cofaces.has_next(false)) { auto coface = cofaces.next(); - + next_simplices.push_back(std::make_pair(get_diameter(coface), get_index(coface))); - + if (pivot_column_index.find(get_index(coface)) == pivot_column_index.end()) columns_to_reduce.push_back( - std::make_pair(get_diameter(coface), get_index(coface))); + std::make_pair(get_diameter(coface), get_index(coface))); } } - + simplices.swap(next_simplices); - + #ifdef INDICATE_PROGRESS std::cout << "\033[K" - << "sorting " << columns_to_reduce.size() << " columns" << std::flush << "\r"; + << "sorting " << columns_to_reduce.size() << " columns" << std::flush << "\r"; #endif - + std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), - greater_diameter_or_smaller_index()); + greater_diameter_or_smaller_index()); #ifdef INDICATE_PROGRESS std::cout << "\033[K"; #endif -- cgit v1.2.3 From a1db43fc46443e1010c81bb04d161907ea852cb2 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Wed, 25 Oct 2017 23:01:54 +0200 Subject: code cleanup --- ripser.cpp | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 555bde4..6bd725e 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -128,19 +128,14 @@ void set_coefficient(entry_t& e, const coefficient_t c) {} const entry_t& get_entry(const entry_t& e) { return e; } -class diameter_index_t : public std::pair { -public: - diameter_index_t() : std::pair() {} - diameter_index_t(std::pair&& p) : std::pair(std::move(p)) {} -}; +typedef std::pair diameter_index_t; value_t get_diameter(const diameter_index_t& i) { return i.first; } index_t get_index(const diameter_index_t& i) { return i.second; } class diameter_entry_t : public std::pair { public: - diameter_entry_t(std::pair p) : std::pair(p) {} - diameter_entry_t(entry_t&& e) : std::pair(0, std::move(e)) {} - diameter_entry_t() : diameter_entry_t(entry_t()) {} + diameter_entry_t() {} + diameter_entry_t(const entry_t& e) : std::pair(0, e) {} diameter_entry_t(value_t _diameter, index_t _index, coefficient_t _coefficient) : std::pair(_diameter, make_entry(_index, _coefficient)) {} diameter_entry_t(const diameter_index_t& _diameter_index, coefficient_t _coefficient) @@ -366,12 +361,6 @@ public: } }; -template -void push_entry(Heap& column, index_t i, coefficient_t c, value_t diameter) { - entry_t e = make_entry(i, c); - column.push(std::make_pair(diameter, e)); -} - class ripser { compressed_lower_distance_matrix dist; index_t dim_max, n; -- cgit v1.2.3 From 9eae733cca3ac379ca447d5abb7289cc37bbeafc Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 26 Oct 2017 00:25:46 +0200 Subject: extracted add_coboundary_and_get_pivot method --- ripser.cpp | 116 +++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 66 insertions(+), 50 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 6bd725e..9085ec2 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -141,7 +141,8 @@ public: diameter_entry_t(const diameter_index_t& _diameter_index, coefficient_t _coefficient) : std::pair(get_diameter(_diameter_index), make_entry(get_index(_diameter_index), _coefficient)) {} - diameter_entry_t(const diameter_index_t& _diameter_index) : diameter_entry_t(_diameter_index, 1) {} + diameter_entry_t(const diameter_index_t& _diameter_index) + : diameter_entry_t(_diameter_index, 1) {} }; const entry_t& get_entry(const diameter_entry_t& p) { return p.second; } @@ -226,10 +227,8 @@ public: euclidean_distance_matrix(std::vector>&& _points) : points(std::move(_points)) { - for (auto p: points) { - assert(p.size() == points.front().size()); - } - } + for (auto p : points) { assert(p.size() == points.front().size()); } + } value_t operator()(const index_t i, const index_t j) const { assert(i < points.size()); @@ -369,6 +368,7 @@ class ripser { const binomial_coeff_table binomial_coeff; std::vector multiplicative_inverse; mutable std::vector vertices; + mutable std::vector coface_entries; public: ripser(compressed_lower_distance_matrix&& _dist, index_t _dim_max, value_t _threshold, @@ -499,6 +499,44 @@ public: #endif } + template + diameter_entry_t add_coboundary_and_get_pivot(Iterator column_begin, Iterator column_end, + coefficient_t factor_column_to_add, +#ifdef ASSEMBLE_REDUCTION_MATRIX + Column& working_reduction_column, +#endif + Column& working_coboundary, const index_t& dim, + hash_map& pivot_column_index, + bool& might_be_apparent_pair) { + for (auto it = column_begin; it != column_end; ++it) { + diameter_entry_t simplex = *it; + set_coefficient(simplex, get_coefficient(simplex) * factor_column_to_add % modulus); + +#ifdef ASSEMBLE_REDUCTION_MATRIX + working_reduction_column.push(simplex); +#endif + + coface_entries.clear(); + simplex_coboundary_enumerator cofaces(simplex, dim, *this); + while (cofaces.has_next()) { + diameter_entry_t coface = cofaces.next(); + if (get_diameter(coface) <= threshold) { + coface_entries.push_back(coface); + if (might_be_apparent_pair && (get_diameter(simplex) == get_diameter(coface))) { + if (pivot_column_index.find(get_index(coface)) == + pivot_column_index.end()) { + return coface; + } + might_be_apparent_pair = false; + } + } + } + for (auto coface : coface_entries) working_coboundary.push(coface); + } + + return get_pivot(working_coboundary, modulus); + } + void compute_pairs(std::vector& columns_to_reduce, hash_map& pivot_column_index, index_t dim) { @@ -516,7 +554,8 @@ public: std::vector coface_entries; - for (index_t index_column_to_reduce = 0; index_column_to_reduce < columns_to_reduce.size(); ++index_column_to_reduce) { + for (index_t index_column_to_reduce = 0; index_column_to_reduce < columns_to_reduce.size(); + ++index_column_to_reduce) { auto column_to_reduce = columns_to_reduce[index_column_to_reduce]; #ifdef ASSEMBLE_REDUCTION_MATRIX @@ -534,14 +573,14 @@ public: #ifdef INDICATE_PROGRESS if ((index_column_to_reduce + 1) % 1000000 == 0) std::cout << "\033[K" - << "reducing column " << index_column_to_reduce + 1 << "/" << columns_to_reduce.size() - << " (diameter " << diameter << ")" << std::flush << "\r"; + << "reducing column " << index_column_to_reduce + 1 << "/" + << columns_to_reduce.size() << " (diameter " << diameter << ")" + << std::flush << "\r"; #endif index_t index_column_to_add = index_column_to_reduce; - - diameter_entry_t pivot; + diameter_entry_t pivot; // start with factor 1 in order to initialize working_coboundary // with the coboundary of the simplex with index column_to_reduce @@ -557,8 +596,7 @@ public: bool might_be_apparent_pair = (index_column_to_reduce == index_column_to_add); - do { - + while (true) { #ifdef ASSEMBLE_REDUCTION_MATRIX #ifdef USE_COEFFICIENTS auto reduction_column_begin = reduction_matrix.cbegin(index_column_to_add), @@ -576,39 +614,18 @@ public: auto reduction_column_begin = &reduction_matrix[index_column_to_add], reduction_column_end = &reduction_matrix[index_column_to_add] + 1; #else - auto reduction_column_begin = &columns_to_reduce[index_column_to_add], reduction_column_end = &columns_to_reduce[index_column_to_add] + 1; + auto reduction_column_begin = &columns_to_reduce[index_column_to_add], + reduction_column_end = &columns_to_reduce[index_column_to_add] + 1; #endif #endif - for (auto it = reduction_column_begin; it != reduction_column_end; ++it) { - diameter_entry_t simplex = *it; - set_coefficient(simplex, get_coefficient(simplex) * factor_column_to_add % modulus); - + pivot = add_coboundary_and_get_pivot(reduction_column_begin, reduction_column_end, + factor_column_to_add, #ifdef ASSEMBLE_REDUCTION_MATRIX - working_reduction_column.push(simplex); -#endif - - coface_entries.clear(); - simplex_coboundary_enumerator cofaces(simplex, dim, *this); - while (cofaces.has_next()) { - diameter_entry_t coface = cofaces.next(); - if (get_diameter(coface) <= threshold) { - coface_entries.push_back(coface); - if (might_be_apparent_pair && - (get_diameter(simplex) == get_diameter(coface))) { - if (pivot_column_index.find(get_index(coface)) == - pivot_column_index.end()) { - pivot = coface; - goto found_persistence_pair; - } - might_be_apparent_pair = false; - } - } - } - for (auto coface : coface_entries) working_coboundary.push(coface); - } - - pivot = get_pivot(working_coboundary, modulus); + working_reduction_column, +#endif + working_coboundary, dim, pivot_column_index, + might_be_apparent_pair); if (get_index(pivot) != -1) { auto pair = pivot_column_index.find(get_index(pivot)); @@ -628,7 +645,6 @@ public: break; } - found_persistence_pair: #ifdef PRINT_PERSISTENCE_PAIRS value_t death = get_diameter(pivot); if (diameter != death) { @@ -670,7 +686,7 @@ public: #endif #endif break; - } while (true); + } } #ifdef INDICATE_PROGRESS @@ -908,19 +924,19 @@ int main(int argc, char** argv) { std::cout << "distance matrix with " << dist.size() << " points" << std::endl; - value_t min = std::numeric_limits::infinity(), max = -std::numeric_limits::infinity(); - - for (auto d: dist.distances) { - if (d != std::numeric_limits::infinity() ) { + value_t min = std::numeric_limits::infinity(), + max = -std::numeric_limits::infinity(); + + for (auto d : dist.distances) { + if (d != std::numeric_limits::infinity()) { min = std::min(min, d); max = std::max(max, d); } else { threshold = std::min(threshold, std::numeric_limits::max()); } } - - std::cout << "value range: [" << min << "," << max << "]" - << std::endl; + + std::cout << "value range: [" << min << "," << max << "]" << std::endl; ripser(std::move(dist), dim_max, threshold, modulus).compute_barcodes(); } -- cgit v1.2.3 From 0ed8c7932825572e49fa5abd50f2338cb66d7fd0 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Wed, 24 Jan 2018 15:16:34 +0100 Subject: simplified control flow --- ripser.cpp | 76 ++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 9085ec2..bc97752 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -619,13 +619,12 @@ public: #endif #endif - pivot = add_coboundary_and_get_pivot(reduction_column_begin, reduction_column_end, - factor_column_to_add, + pivot = add_coboundary_and_get_pivot( + reduction_column_begin, reduction_column_end, factor_column_to_add, #ifdef ASSEMBLE_REDUCTION_MATRIX - working_reduction_column, + working_reduction_column, #endif - working_coboundary, dim, pivot_column_index, - might_be_apparent_pair); + working_coboundary, dim, pivot_column_index, might_be_apparent_pair); if (get_index(pivot) != -1) { auto pair = pivot_column_index.find(get_index(pivot)); @@ -633,59 +632,58 @@ public: if (pair != pivot_column_index.end()) { index_column_to_add = pair->second; factor_column_to_add = modulus - get_coefficient(pivot); - continue; - } - } else { + } else { #ifdef PRINT_PERSISTENCE_PAIRS + value_t death = get_diameter(pivot); + if (diameter != death) { #ifdef INDICATE_PROGRESS - std::cout << "\033[K"; -#endif - std::cout << " [" << diameter << ", )" << std::endl << std::flush; + std::cout << "\033[K"; #endif - break; - } - -#ifdef PRINT_PERSISTENCE_PAIRS - value_t death = get_diameter(pivot); - if (diameter != death) { -#ifdef INDICATE_PROGRESS - std::cout << "\033[K"; -#endif - std::cout << " [" << diameter << "," << death << ")" << std::endl << std::flush; - } + std::cout << " [" << diameter << "," << death << ")" << std::endl + << std::flush; + } #endif - - pivot_column_index.insert(std::make_pair(get_index(pivot), index_column_to_reduce)); + pivot_column_index.insert( + std::make_pair(get_index(pivot), index_column_to_reduce)); #ifdef USE_COEFFICIENTS - const coefficient_t inverse = multiplicative_inverse[get_coefficient(pivot)]; + const coefficient_t inverse = + multiplicative_inverse[get_coefficient(pivot)]; #endif #ifdef ASSEMBLE_REDUCTION_MATRIX -// replace current column of reduction_matrix (with a single diagonal 1 entry) -// by reduction_column (possibly with a different entry on the diagonal) + // replace current column of reduction_matrix (with a single diagonal 1 + // entry) by reduction_column (possibly with a different entry on the + // diagonal) #ifdef USE_COEFFICIENTS - reduction_matrix.pop_back(); + reduction_matrix.pop_back(); #else - pop_pivot(working_reduction_column, modulus); + pop_pivot(working_reduction_column, modulus); #endif - while (true) { - diameter_entry_t e = pop_pivot(working_reduction_column, modulus); - if (get_index(e) == -1) break; + while (true) { + diameter_entry_t e = pop_pivot(working_reduction_column, modulus); + if (get_index(e) == -1) break; #ifdef USE_COEFFICIENTS - set_coefficient(e, inverse * get_coefficient(e) % modulus); - assert(get_coefficient(e) > 0); + set_coefficient(e, inverse * get_coefficient(e) % modulus); + assert(get_coefficient(e) > 0); #endif - reduction_matrix.push_back(e); - } + reduction_matrix.push_back(e); + } #else #ifdef USE_COEFFICIENTS - reduction_matrix.pop_back(); - reduction_matrix.push_back(diameter_entry_t(column_to_reduce, inverse)); + reduction_matrix.pop_back(); + reduction_matrix.push_back(diameter_entry_t(column_to_reduce, inverse)); #endif #endif - break; + break; + } + } else { +#ifdef PRINT_PERSISTENCE_PAIRS + std::cout << " [" << diameter << ", )" << std::endl << std::flush; +#endif + break; + } } } -- cgit v1.2.3 From 23a262f1b59eacd7a3ef01589101e64290cd7128 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 15 Feb 2018 11:00:13 +0100 Subject: threshold at enclosing radius --- ripser.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 70a092a..7858c55 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -785,9 +785,8 @@ public: else x = std::max(x, y); } - return all_cofaces || - !(k > 0 && - parent.get_next_vertex(max_vertex_below, idx_below, k) > get_index(x)); + return all_cofaces || !(k > 0 && parent.get_next_vertex(max_vertex_below, idx_below, + k) > get_index(x)); continue_outer:; } return false; @@ -1151,6 +1150,15 @@ int main(int argc, char** argv) { max = -std::numeric_limits::infinity(), max_finite = max; int num_edges = 0; + value_t enclosing_radius = std::numeric_limits::infinity(); + for (index_t i = 0; i < dist.size(); ++i) { + value_t r_i = -std::numeric_limits::infinity(); + for (index_t j = 0; j < dist.size(); ++j) r_i = std::max(r_i, dist(i, j)); + enclosing_radius = std::min(enclosing_radius, r_i); + } + + if (threshold == std::numeric_limits::max()) threshold = enclosing_radius; + for (auto d : dist.distances) { min = std::min(min, d); max = std::max(max, d); -- cgit v1.2.3 From 7d662086064455d2b409d3b5651a7ce009b0a6d4 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Sun, 29 Apr 2018 21:49:25 +0200 Subject: xcode project update --- ripser.xcodeproj/project.pbxproj | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ripser.xcodeproj/project.pbxproj b/ripser.xcodeproj/project.pbxproj index 24c7d8b..b5f6881 100644 --- a/ripser.xcodeproj/project.pbxproj +++ b/ripser.xcodeproj/project.pbxproj @@ -88,7 +88,7 @@ 551018401BD63CB300990BFF /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0800; + LastUpgradeCheck = 0910; ORGANIZATIONNAME = "ulrich-bauer.org"; TargetAttributes = { 551018471BD63CB300990BFF = { @@ -133,14 +133,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -178,14 +184,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; -- cgit v1.2.3 From e10038a0fbd1bf2f8c9eec129b2d523d95a4ad0f Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Wed, 16 May 2018 09:25:46 +0200 Subject: simplify union-find --- ripser.cpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 6bd725e..bd1a7db 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -252,23 +252,16 @@ public: } index_t find(index_t x) { - index_t y = x, z = parent[y]; - while (z != y) { - y = z; - z = parent[y]; - } - y = parent[x]; - while (z != y) { - parent[x] = z; - x = y; - y = parent[x]; + index_t y = x, z; + while ((z = parent[y]) != y) y = z; + while ((z = parent[x]) != y) { + parent[x] = y; + x = z; } return z; } void link(index_t x, index_t y) { - x = find(x); - y = find(y); - if (x == y) return; + if ((x = find(x)) == (y = find(y))) return; if (rank[x] > rank[y]) parent[y] = x; else { -- cgit v1.2.3 From 932cc3028fcde38e6e4d6588f1f7bde76a344eb3 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Sat, 19 May 2018 12:58:37 -0400 Subject: consolidation of branches --- ripser.cpp | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index bd1a7db..8f2d509 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -208,12 +208,14 @@ template <> void compressed_distance_matrix::init_rows() { } template <> -value_t compressed_distance_matrix::operator()(index_t i, index_t j) const { +value_t compressed_distance_matrix::operator()(const index_t i, + const index_t j) const { return i == j ? 0 : i > j ? rows[j][i] : rows[i][j]; } template <> -value_t compressed_distance_matrix::operator()(index_t i, index_t j) const { +value_t compressed_distance_matrix::operator()(const index_t i, + const index_t j) const { return i == j ? 0 : i < j ? rows[j][i] : rows[i][j]; } @@ -226,10 +228,8 @@ public: euclidean_distance_matrix(std::vector>&& _points) : points(std::move(_points)) { - for (auto p: points) { - assert(p.size() == points.front().size()); - } - } + for (auto p : points) { assert(p.size() == points.front().size()); } + } value_t operator()(const index_t i, const index_t j) const { assert(i < points.size()); @@ -356,18 +356,20 @@ public: class ripser { compressed_lower_distance_matrix dist; - index_t dim_max, n; + index_t n, dim_max; value_t threshold; + float ratio; coefficient_t modulus; const binomial_coeff_table binomial_coeff; std::vector multiplicative_inverse; mutable std::vector vertices; public: - ripser(compressed_lower_distance_matrix&& _dist, index_t _dim_max, value_t _threshold, + ripser(compressed_lower_distance_matrix&& _dist, index_t _dim_max, value_t _threshold, float _ratio, coefficient_t _modulus) - : dist(std::move(_dist)), dim_max(std::min(_dim_max, index_t(dist.size() - 2))), - n(dist.size()), threshold(_threshold), modulus(_modulus), binomial_coeff(n, dim_max + 2), + : dist(std::move(_dist)), n(dist.size()), + dim_max(std::min(_dim_max, index_t(dist.size() - 2))), threshold(_threshold), + ratio(_ratio), modulus(_modulus), binomial_coeff(n, dim_max + 2), multiplicative_inverse(multiplicative_inverse_vector(_modulus)) {} index_t get_next_vertex(index_t& v, const index_t idx, const index_t k) const { @@ -624,7 +626,7 @@ public: found_persistence_pair: #ifdef PRINT_PERSISTENCE_PAIRS value_t death = get_diameter(pivot); - if (diameter != death) { + if (death > diameter * ratio) { #ifdef INDICATE_PROGRESS std::cout << "\033[K"; #endif @@ -842,6 +844,8 @@ int main(int argc, char** argv) { index_t dim_max = 1; value_t threshold = std::numeric_limits::infinity(); + float ratio = 1; + #ifdef USE_COEFFICIENTS coefficient_t modulus = 2; #else @@ -862,6 +866,11 @@ int main(int argc, char** argv) { size_t next_pos; threshold = std::stof(parameter, &next_pos); if (next_pos != parameter.size()) print_usage_and_exit(-1); + } else if (arg == "--ratio") { + std::string parameter = std::string(argv[++i]); + size_t next_pos; + ratio = std::stof(parameter, &next_pos); + if (next_pos != parameter.size()) print_usage_and_exit(-1); } else if (arg == "--format") { std::string parameter = std::string(argv[++i]); if (parameter == "lower-distance") @@ -915,7 +924,7 @@ int main(int argc, char** argv) { std::cout << "value range: [" << min << "," << max << "]" << std::endl; - ripser(std::move(dist), dim_max, threshold, modulus).compute_barcodes(); + ripser(std::move(dist), dim_max, threshold, ratio, modulus).compute_barcodes(); } void ripser::compute_barcodes() { -- cgit v1.2.3 From ff4b0cc4012e1cdc8ebe0ae5cdc613352b9f8bac Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Sat, 19 May 2018 14:17:27 -0400 Subject: consolidation of branches --- ripser.cpp | 447 +++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 244 insertions(+), 203 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 8f2d509..9e291ca 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -141,7 +141,8 @@ public: diameter_entry_t(const diameter_index_t& _diameter_index, coefficient_t _coefficient) : std::pair(get_diameter(_diameter_index), make_entry(get_index(_diameter_index), _coefficient)) {} - diameter_entry_t(const diameter_index_t& _diameter_index) : diameter_entry_t(_diameter_index, 1) {} + diameter_entry_t(const diameter_index_t& _diameter_index) + : diameter_entry_t(_diameter_index, 1) {} }; const entry_t& get_entry(const diameter_entry_t& p) { return p.second; } @@ -354,8 +355,8 @@ public: } }; -class ripser { - compressed_lower_distance_matrix dist; +template class ripser { + DistanceMatrix dist; index_t n, dim_max; value_t threshold; float ratio; @@ -363,9 +364,10 @@ class ripser { const binomial_coeff_table binomial_coeff; std::vector multiplicative_inverse; mutable std::vector vertices; + mutable std::vector coface_entries; public: - ripser(compressed_lower_distance_matrix&& _dist, index_t _dim_max, value_t _threshold, float _ratio, + ripser(DistanceMatrix&& _dist, index_t _dim_max, value_t _threshold, float _ratio, coefficient_t _modulus) : dist(std::move(_dist)), n(dist.size()), dim_max(std::min(_dim_max, index_t(dist.size() - 2))), threshold(_threshold), @@ -415,83 +417,84 @@ public: return diam; } - class simplex_coboundary_enumerator { - private: - index_t idx_below, idx_above, v, k; - std::vector vertices; - const diameter_entry_t simplex; - const coefficient_t modulus; - const compressed_lower_distance_matrix& dist; - const binomial_coeff_table& binomial_coeff; - - public: - simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, - const ripser& parent) - : idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), k(_dim + 1), - vertices(_dim + 1), simplex(_simplex), modulus(parent.modulus), dist(parent.dist), - binomial_coeff(parent.binomial_coeff) { - parent.get_simplex_vertices(get_index(_simplex), _dim, parent.n, vertices.begin()); - } + class simplex_coboundary_enumerator; - bool has_next() { - while ((v != -1) && (binomial_coeff(v, k) <= idx_below)) { - idx_below -= binomial_coeff(v, k); - idx_above += binomial_coeff(v, k + 1); - --v; - --k; - assert(k != -1); - } - return v != -1; - } - - diameter_entry_t next() { - value_t coface_diameter = get_diameter(simplex); - for (index_t w : vertices) coface_diameter = std::max(coface_diameter, dist(v, w)); - index_t coface_index = idx_above + binomial_coeff(v--, k + 1) + idx_below; - coefficient_t coface_coefficient = - (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; - return diameter_entry_t(coface_diameter, coface_index, coface_coefficient); - } - }; + void assemble_columns_to_reduce(std::vector& simplices, + std::vector& columns_to_reduce, + hash_map& pivot_column_index, index_t dim); - void compute_barcodes(); + void compute_dim_0_pairs(std::vector& edges, + std::vector& columns_to_reduce) { + union_find dset(n); - void assemble_columns_to_reduce(std::vector& columns_to_reduce, - hash_map& pivot_column_index, index_t dim) { - index_t num_simplices = binomial_coeff(n, dim + 1); + edges = get_edges(); - columns_to_reduce.clear(); + std::sort(edges.rbegin(), edges.rend(), + greater_diameter_or_smaller_index()); -#ifdef INDICATE_PROGRESS - std::cout << "\033[K" - << "assembling " << num_simplices << " columns" << std::flush << "\r"; +#ifdef PRINT_PERSISTENCE_PAIRS + std::cout << "persistence intervals in dim 0:" << std::endl; #endif - for (index_t index = 0; index < num_simplices; ++index) { - if (pivot_column_index.find(index) == pivot_column_index.end()) { - value_t diameter = compute_diameter(index, dim); - if (diameter <= threshold) - columns_to_reduce.push_back(std::make_pair(diameter, index)); -#ifdef INDICATE_PROGRESS - if ((index + 1) % 1000000 == 0) - std::cout << "\033[K" - << "assembled " << columns_to_reduce.size() << " out of " - << (index + 1) << "/" << num_simplices << " columns" << std::flush - << "\r"; + std::vector vertices_of_edge(2); + for (auto e : edges) { + vertices_of_edge.clear(); + get_simplex_vertices(get_index(e), 1, n, std::back_inserter(vertices_of_edge)); + index_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]); + + if (u != v) { +#ifdef PRINT_PERSISTENCE_PAIRS + if (get_diameter(e) != 0) + std::cout << " [0," << get_diameter(e) << ")" << std::endl; #endif - } + dset.link(u, v); + } else + columns_to_reduce.push_back(e); } + std::reverse(columns_to_reduce.begin(), columns_to_reduce.end()); -#ifdef INDICATE_PROGRESS - std::cout << "\033[K" - << "sorting " << num_simplices << " columns" << std::flush << "\r"; +#ifdef PRINT_PERSISTENCE_PAIRS + for (index_t i = 0; i < n; ++i) + if (dset.find(i) == i) std::cout << " [0, )" << std::endl << std::flush; #endif + } - std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), - greater_diameter_or_smaller_index()); -#ifdef INDICATE_PROGRESS - std::cout << "\033[K"; + template + diameter_entry_t add_coboundary_and_get_pivot(Iterator column_begin, Iterator column_end, + coefficient_t factor_column_to_add, +#ifdef ASSEMBLE_REDUCTION_MATRIX + Column& working_reduction_column, #endif + Column& working_coboundary, const index_t& dim, + hash_map& pivot_column_index, + bool& might_be_apparent_pair) { + for (auto it = column_begin; it != column_end; ++it) { + diameter_entry_t simplex = *it; + set_coefficient(simplex, get_coefficient(simplex) * factor_column_to_add % modulus); + +#ifdef ASSEMBLE_REDUCTION_MATRIX + working_reduction_column.push(simplex); +#endif + + coface_entries.clear(); + simplex_coboundary_enumerator cofaces(simplex, dim, *this); + while (cofaces.has_next()) { + diameter_entry_t coface = cofaces.next(); + if (get_diameter(coface) <= threshold) { + coface_entries.push_back(coface); + if (might_be_apparent_pair && (get_diameter(simplex) == get_diameter(coface))) { + if (pivot_column_index.find(get_index(coface)) == + pivot_column_index.end()) { + return coface; + } + might_be_apparent_pair = false; + } + } + } + for (auto coface : coface_entries) working_coboundary.push(coface); + } + + return get_pivot(working_coboundary, modulus); } void compute_pairs(std::vector& columns_to_reduce, @@ -511,7 +514,8 @@ public: std::vector coface_entries; - for (index_t index_column_to_reduce = 0; index_column_to_reduce < columns_to_reduce.size(); ++index_column_to_reduce) { + for (index_t index_column_to_reduce = 0; index_column_to_reduce < columns_to_reduce.size(); + ++index_column_to_reduce) { auto column_to_reduce = columns_to_reduce[index_column_to_reduce]; #ifdef ASSEMBLE_REDUCTION_MATRIX @@ -529,14 +533,14 @@ public: #ifdef INDICATE_PROGRESS if ((index_column_to_reduce + 1) % 1000000 == 0) std::cout << "\033[K" - << "reducing column " << index_column_to_reduce + 1 << "/" << columns_to_reduce.size() - << " (diameter " << diameter << ")" << std::flush << "\r"; + << "reducing column " << index_column_to_reduce + 1 << "/" + << columns_to_reduce.size() << " (diameter " << diameter << ")" + << std::flush << "\r"; #endif index_t index_column_to_add = index_column_to_reduce; - - diameter_entry_t pivot; + diameter_entry_t pivot; // start with factor 1 in order to initialize working_coboundary // with the coboundary of the simplex with index column_to_reduce @@ -552,8 +556,7 @@ public: bool might_be_apparent_pair = (index_column_to_reduce == index_column_to_add); - do { - + while (true) { #ifdef ASSEMBLE_REDUCTION_MATRIX #ifdef USE_COEFFICIENTS auto reduction_column_begin = reduction_matrix.cbegin(index_column_to_add), @@ -571,39 +574,17 @@ public: auto reduction_column_begin = &reduction_matrix[index_column_to_add], reduction_column_end = &reduction_matrix[index_column_to_add] + 1; #else - auto reduction_column_begin = &columns_to_reduce[index_column_to_add], reduction_column_end = &columns_to_reduce[index_column_to_add] + 1; + auto reduction_column_begin = &columns_to_reduce[index_column_to_add], + reduction_column_end = &columns_to_reduce[index_column_to_add] + 1; #endif #endif - for (auto it = reduction_column_begin; it != reduction_column_end; ++it) { - diameter_entry_t simplex = *it; - set_coefficient(simplex, get_coefficient(simplex) * factor_column_to_add % modulus); - + pivot = add_coboundary_and_get_pivot( + reduction_column_begin, reduction_column_end, factor_column_to_add, #ifdef ASSEMBLE_REDUCTION_MATRIX - working_reduction_column.push(simplex); -#endif - - coface_entries.clear(); - simplex_coboundary_enumerator cofaces(simplex, dim, *this); - while (cofaces.has_next()) { - diameter_entry_t coface = cofaces.next(); - if (get_diameter(coface) <= threshold) { - coface_entries.push_back(coface); - if (might_be_apparent_pair && - (get_diameter(simplex) == get_diameter(coface))) { - if (pivot_column_index.find(get_index(coface)) == - pivot_column_index.end()) { - pivot = coface; - goto found_persistence_pair; - } - might_be_apparent_pair = false; - } - } - } - for (auto coface : coface_entries) working_coboundary.push(coface); - } - - pivot = get_pivot(working_coboundary, modulus); + working_reduction_column, +#endif + working_coboundary, dim, pivot_column_index, might_be_apparent_pair); if (get_index(pivot) != -1) { auto pair = pivot_column_index.find(get_index(pivot)); @@ -611,69 +592,174 @@ public: if (pair != pivot_column_index.end()) { index_column_to_add = pair->second; factor_column_to_add = modulus - get_coefficient(pivot); - continue; - } - } else { + } else { #ifdef PRINT_PERSISTENCE_PAIRS + value_t death = get_diameter(pivot); + if (diameter != death) { #ifdef INDICATE_PROGRESS - std::cout << "\033[K"; -#endif - std::cout << " [" << diameter << ", )" << std::endl << std::flush; + std::cout << "\033[K"; #endif - break; - } - - found_persistence_pair: -#ifdef PRINT_PERSISTENCE_PAIRS - value_t death = get_diameter(pivot); - if (death > diameter * ratio) { -#ifdef INDICATE_PROGRESS - std::cout << "\033[K"; -#endif - std::cout << " [" << diameter << "," << death << ")" << std::endl << std::flush; - } + std::cout << " [" << diameter << "," << death << ")" << std::endl + << std::flush; + } #endif - - pivot_column_index.insert(std::make_pair(get_index(pivot), index_column_to_reduce)); + pivot_column_index.insert( + std::make_pair(get_index(pivot), index_column_to_reduce)); #ifdef USE_COEFFICIENTS - const coefficient_t inverse = multiplicative_inverse[get_coefficient(pivot)]; + const coefficient_t inverse = + multiplicative_inverse[get_coefficient(pivot)]; #endif #ifdef ASSEMBLE_REDUCTION_MATRIX -// replace current column of reduction_matrix (with a single diagonal 1 entry) -// by reduction_column (possibly with a different entry on the diagonal) + // replace current column of reduction_matrix (with a single diagonal 1 + // entry) by reduction_column (possibly with a different entry on the + // diagonal) #ifdef USE_COEFFICIENTS - reduction_matrix.pop_back(); + reduction_matrix.pop_back(); #else - pop_pivot(working_reduction_column, modulus); + pop_pivot(working_reduction_column, modulus); #endif - while (true) { - diameter_entry_t e = pop_pivot(working_reduction_column, modulus); - if (get_index(e) == -1) break; + while (true) { + diameter_entry_t e = pop_pivot(working_reduction_column, modulus); + if (get_index(e) == -1) break; #ifdef USE_COEFFICIENTS - set_coefficient(e, inverse * get_coefficient(e) % modulus); - assert(get_coefficient(e) > 0); + set_coefficient(e, inverse * get_coefficient(e) % modulus); + assert(get_coefficient(e) > 0); #endif - reduction_matrix.push_back(e); - } + reduction_matrix.push_back(e); + } #else #ifdef USE_COEFFICIENTS - reduction_matrix.pop_back(); - reduction_matrix.push_back(diameter_entry_t(column_to_reduce, inverse)); + reduction_matrix.pop_back(); + reduction_matrix.push_back(diameter_entry_t(column_to_reduce, inverse)); #endif #endif - break; - } while (true); + break; + } + } else { +#ifdef PRINT_PERSISTENCE_PAIRS + std::cout << " [" << diameter << ", )" << std::endl << std::flush; +#endif + break; + } + } } #ifdef INDICATE_PROGRESS std::cout << "\033[K"; #endif } + + std::vector get_edges(); + + void compute_barcodes() { + + std::vector simplices, columns_to_reduce; + + compute_dim_0_pairs(simplices, columns_to_reduce); + + for (index_t dim = 1; dim <= dim_max; ++dim) { + hash_map pivot_column_index; + pivot_column_index.reserve(columns_to_reduce.size()); + + compute_pairs(columns_to_reduce, pivot_column_index, dim); + + if (dim < dim_max) { + assemble_columns_to_reduce(simplices, columns_to_reduce, pivot_column_index, + dim + 1); + } + } + } +}; + +template <> class ripser::simplex_coboundary_enumerator { +private: + index_t idx_below, idx_above, v, k; + std::vector vertices; + const diameter_entry_t simplex; + const coefficient_t modulus; + const compressed_lower_distance_matrix& dist; + const binomial_coeff_table& binomial_coeff; + +public: + simplex_coboundary_enumerator(const diameter_entry_t _simplex, index_t _dim, + const ripser& parent) + : idx_below(get_index(_simplex)), idx_above(0), v(parent.n - 1), k(_dim + 1), + vertices(_dim + 1), simplex(_simplex), modulus(parent.modulus), dist(parent.dist), + binomial_coeff(parent.binomial_coeff) { + parent.get_simplex_vertices(get_index(_simplex), _dim, parent.n, vertices.begin()); + } + + bool has_next() { + while ((v != -1) && (binomial_coeff(v, k) <= idx_below)) { + idx_below -= binomial_coeff(v, k); + idx_above += binomial_coeff(v, k + 1); + --v; + --k; + assert(k != -1); + } + return v != -1; + } + + diameter_entry_t next() { + value_t coface_diameter = get_diameter(simplex); + for (index_t w : vertices) coface_diameter = std::max(coface_diameter, dist(v, w)); + index_t coface_index = idx_above + binomial_coeff(v--, k + 1) + idx_below; + coefficient_t coface_coefficient = + (k & 1 ? -1 + modulus : 1) * get_coefficient(simplex) % modulus; + return diameter_entry_t(coface_diameter, coface_index, coface_coefficient); + } }; +template <> std::vector ripser::get_edges() { + std::vector edges; + for (index_t index = binomial_coeff(n, 2); index-- > 0;) { + value_t diameter = compute_diameter(index, 1); + if (diameter <= threshold) edges.push_back(std::make_pair(diameter, index)); + } + return edges; +} + +template <> +void ripser::assemble_columns_to_reduce( + std::vector& simplices, std::vector& columns_to_reduce, + hash_map& pivot_column_index, index_t dim) { + index_t num_simplices = binomial_coeff(n, dim + 1); + + columns_to_reduce.clear(); + +#ifdef INDICATE_PROGRESS + std::cout << "\033[K" + << "assembling " << num_simplices << " columns" << std::flush << "\r"; +#endif + + for (index_t index = 0; index < num_simplices; ++index) { + if (pivot_column_index.find(index) == pivot_column_index.end()) { + value_t diameter = compute_diameter(index, dim); + if (diameter <= threshold) columns_to_reduce.push_back(std::make_pair(diameter, index)); +#ifdef INDICATE_PROGRESS + if ((index + 1) % 1000000 == 0) + std::cout << "\033[K" + << "assembled " << columns_to_reduce.size() << " out of " << (index + 1) + << "/" << num_simplices << " columns" << std::flush << "\r"; +#endif + } + } + +#ifdef INDICATE_PROGRESS + std::cout << "\033[K" + << "sorting " << num_simplices << " columns" << std::flush << "\r"; +#endif + + std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), + greater_diameter_or_smaller_index()); +#ifdef INDICATE_PROGRESS + std::cout << "\033[K"; +#endif +} + enum file_format { LOWER_DISTANCE_MATRIX, UPPER_DISTANCE_MATRIX, @@ -908,74 +994,29 @@ int main(int argc, char** argv) { compressed_lower_distance_matrix dist = read_file(filename ? file_stream : std::cin, format); - std::cout << "distance matrix with " << dist.size() << " points" << std::endl; + value_t min = std::numeric_limits::infinity(), + max = -std::numeric_limits::infinity(), max_finite = max; + int num_edges = 0; - value_t min = std::numeric_limits::infinity(), max = -std::numeric_limits::infinity(); - - for (auto d: dist.distances) { - if (d != std::numeric_limits::infinity() ) { - min = std::min(min, d); - max = std::max(max, d); - } else { - threshold = std::min(threshold, std::numeric_limits::max()); - } + value_t enclosing_radius = std::numeric_limits::infinity(); + for (index_t i = 0; i < dist.size(); ++i) { + value_t r_i = -std::numeric_limits::infinity(); + for (index_t j = 0; j < dist.size(); ++j) r_i = std::max(r_i, dist(i, j)); + enclosing_radius = std::min(enclosing_radius, r_i); } - - std::cout << "value range: [" << min << "," << max << "]" - << std::endl; - - ripser(std::move(dist), dim_max, threshold, ratio, modulus).compute_barcodes(); -} - -void ripser::compute_barcodes() { - - std::vector columns_to_reduce; - - { - union_find dset(n); - std::vector edges; - for (index_t index = binomial_coeff(n, 2); index-- > 0;) { - value_t diameter = compute_diameter(index, 1); - if (diameter <= threshold) edges.push_back(std::make_pair(diameter, index)); - } - std::sort(edges.rbegin(), edges.rend(), - greater_diameter_or_smaller_index()); - -#ifdef PRINT_PERSISTENCE_PAIRS - std::cout << "persistence intervals in dim 0:" << std::endl; -#endif - std::vector vertices_of_edge(2); - for (auto e : edges) { - vertices_of_edge.clear(); - get_simplex_vertices(get_index(e), 1, n, std::back_inserter(vertices_of_edge)); - index_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]); + if (threshold == std::numeric_limits::max()) threshold = enclosing_radius; - if (u != v) { -#ifdef PRINT_PERSISTENCE_PAIRS - if (get_diameter(e) != 0) - std::cout << " [0," << get_diameter(e) << ")" << std::endl; -#endif - dset.link(u, v); - } else - columns_to_reduce.push_back(e); - } - std::reverse(columns_to_reduce.begin(), columns_to_reduce.end()); - -#ifdef PRINT_PERSISTENCE_PAIRS - for (index_t i = 0; i < n; ++i) - if (dset.find(i) == i) std::cout << " [0, )" << std::endl << std::flush; -#endif + for (auto d : dist.distances) { + min = std::min(min, d); + max = std::max(max, d); + max_finite = d != std::numeric_limits::infinity() ? std::max(max, d) : max_finite; + if (d <= threshold) ++num_edges; } - for (index_t dim = 1; dim <= dim_max; ++dim) { - hash_map pivot_column_index; - pivot_column_index.reserve(columns_to_reduce.size()); + std::cout << "value range: [" << min << "," << max_finite << "]" << std::endl; - compute_pairs(columns_to_reduce, pivot_column_index, dim); - - if (dim < dim_max) { - assemble_columns_to_reduce(columns_to_reduce, pivot_column_index, dim + 1); - } - } + std::cout << "distance matrix with " << dist.size() << " points" << std::endl; + ripser(std::move(dist), dim_max, threshold, ratio, modulus) + .compute_barcodes(); } -- cgit v1.2.3 From 535c4115f73fcf052d6206f12fce9d714c716c05 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Sat, 19 May 2018 14:26:22 -0400 Subject: consolidation of branches --- ripser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ripser.cpp b/ripser.cpp index 9e291ca..9e2aa90 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -928,7 +928,7 @@ int main(int argc, char** argv) { file_format format = DISTANCE_MATRIX; index_t dim_max = 1; - value_t threshold = std::numeric_limits::infinity(); + value_t threshold = std::numeric_limits::max(); float ratio = 1; -- cgit v1.2.3 From a1154088fd2d47320f56839b1c7a0ed87ae35ade Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Sat, 19 May 2018 16:00:48 -0400 Subject: untemplated dev --- ripser.cpp | 89 +++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 48 insertions(+), 41 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index 9e2aa90..69c8355 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -355,8 +355,8 @@ public: } }; -template class ripser { - DistanceMatrix dist; +class ripser { + compressed_lower_distance_matrix dist; index_t n, dim_max; value_t threshold; float ratio; @@ -367,8 +367,8 @@ template class ripser { mutable std::vector coface_entries; public: - ripser(DistanceMatrix&& _dist, index_t _dim_max, value_t _threshold, float _ratio, - coefficient_t _modulus) + ripser(compressed_lower_distance_matrix&& _dist, index_t _dim_max, value_t _threshold, + float _ratio, coefficient_t _modulus) : dist(std::move(_dist)), n(dist.size()), dim_max(std::min(_dim_max, index_t(dist.size() - 2))), threshold(_threshold), ratio(_ratio), modulus(_modulus), binomial_coeff(n, dim_max + 2), @@ -467,35 +467,7 @@ public: #endif Column& working_coboundary, const index_t& dim, hash_map& pivot_column_index, - bool& might_be_apparent_pair) { - for (auto it = column_begin; it != column_end; ++it) { - diameter_entry_t simplex = *it; - set_coefficient(simplex, get_coefficient(simplex) * factor_column_to_add % modulus); - -#ifdef ASSEMBLE_REDUCTION_MATRIX - working_reduction_column.push(simplex); -#endif - - coface_entries.clear(); - simplex_coboundary_enumerator cofaces(simplex, dim, *this); - while (cofaces.has_next()) { - diameter_entry_t coface = cofaces.next(); - if (get_diameter(coface) <= threshold) { - coface_entries.push_back(coface); - if (might_be_apparent_pair && (get_diameter(simplex) == get_diameter(coface))) { - if (pivot_column_index.find(get_index(coface)) == - pivot_column_index.end()) { - return coface; - } - might_be_apparent_pair = false; - } - } - } - for (auto coface : coface_entries) working_coboundary.push(coface); - } - - return get_pivot(working_coboundary, modulus); - } + bool& might_be_apparent_pair); void compute_pairs(std::vector& columns_to_reduce, hash_map& pivot_column_index, index_t dim) { @@ -674,7 +646,7 @@ public: } }; -template <> class ripser::simplex_coboundary_enumerator { +class ripser::simplex_coboundary_enumerator { private: index_t idx_below, idx_above, v, k; std::vector vertices; @@ -713,7 +685,43 @@ public: } }; -template <> std::vector ripser::get_edges() { +template +diameter_entry_t ripser::add_coboundary_and_get_pivot( + Iterator column_begin, Iterator column_end, coefficient_t factor_column_to_add, +#ifdef ASSEMBLE_REDUCTION_MATRIX + Column& working_reduction_column, +#endif + Column& working_coboundary, const index_t& dim, hash_map& pivot_column_index, + bool& might_be_apparent_pair) { + for (auto it = column_begin; it != column_end; ++it) { + diameter_entry_t simplex = *it; + set_coefficient(simplex, get_coefficient(simplex) * factor_column_to_add % modulus); + +#ifdef ASSEMBLE_REDUCTION_MATRIX + working_reduction_column.push(simplex); +#endif + + coface_entries.clear(); + simplex_coboundary_enumerator cofaces(simplex, dim, *this); + while (cofaces.has_next()) { + diameter_entry_t coface = cofaces.next(); + if (get_diameter(coface) <= threshold) { + coface_entries.push_back(coface); + if (might_be_apparent_pair && (get_diameter(simplex) == get_diameter(coface))) { + if (pivot_column_index.find(get_index(coface)) == pivot_column_index.end()) { + return coface; + } + might_be_apparent_pair = false; + } + } + } + for (auto coface : coface_entries) working_coboundary.push(coface); + } + + return get_pivot(working_coboundary, modulus); +} + +std::vector ripser::get_edges() { std::vector edges; for (index_t index = binomial_coeff(n, 2); index-- > 0;) { value_t diameter = compute_diameter(index, 1); @@ -722,10 +730,10 @@ template <> std::vector ripser -void ripser::assemble_columns_to_reduce( - std::vector& simplices, std::vector& columns_to_reduce, - hash_map& pivot_column_index, index_t dim) { +void ripser::assemble_columns_to_reduce(std::vector& simplices, + std::vector& columns_to_reduce, + hash_map& pivot_column_index, + index_t dim) { index_t num_simplices = binomial_coeff(n, dim + 1); columns_to_reduce.clear(); @@ -1017,6 +1025,5 @@ int main(int argc, char** argv) { std::cout << "value range: [" << min << "," << max_finite << "]" << std::endl; std::cout << "distance matrix with " << dist.size() << " points" << std::endl; - ripser(std::move(dist), dim_max, threshold, ratio, modulus) - .compute_barcodes(); + ripser(std::move(dist), dim_max, threshold, ratio, modulus).compute_barcodes(); } -- cgit v1.2.3 From 38dc1f43136afe004e71d0076b9fa3919e7f68a5 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 24 May 2018 15:47:20 -0400 Subject: using ratio --- ripser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ripser.cpp b/ripser.cpp index 69c8355..2eacd63 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -567,7 +567,7 @@ public: } else { #ifdef PRINT_PERSISTENCE_PAIRS value_t death = get_diameter(pivot); - if (diameter != death) { + if (death > diameter * ratio) { #ifdef INDICATE_PROGRESS std::cout << "\033[K"; #endif -- cgit v1.2.3 From 5a3afe81d365917ec64d2af7bf43d28df4b3b55c Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 12 Jul 2018 22:04:34 +0200 Subject: only compute enclosing radius when thresholding --- ripser.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/ripser.cpp b/ripser.cpp index d534f49..f012591 100644 --- a/ripser.cpp +++ b/ripser.cpp @@ -1157,14 +1157,16 @@ int main(int argc, char** argv) { max = -std::numeric_limits::infinity(), max_finite = max; int num_edges = 0; - value_t enclosing_radius = std::numeric_limits::infinity(); - for (index_t i = 0; i < dist.size(); ++i) { - value_t r_i = -std::numeric_limits::infinity(); - for (index_t j = 0; j < dist.size(); ++j) r_i = std::max(r_i, dist(i, j)); - enclosing_radius = std::min(enclosing_radius, r_i); - } + if (threshold == std::numeric_limits::max()) { + value_t enclosing_radius = std::numeric_limits::infinity(); + for (index_t i = 0; i < dist.size(); ++i) { + value_t r_i = -std::numeric_limits::infinity(); + for (index_t j = 0; j < dist.size(); ++j) r_i = std::max(r_i, dist(i, j)); + enclosing_radius = std::min(enclosing_radius, r_i); + } - if (threshold == std::numeric_limits::max()) threshold = enclosing_radius; + threshold = enclosing_radius; + } for (auto d : dist.distances) { min = std::min(min, d); @@ -1182,7 +1184,7 @@ int main(int argc, char** argv) { .compute_barcodes(); } else { std::cout << "sparse distance matrix with " << dist.size() << " points and " << num_edges - << " entries" << std::endl; + << "/" << (dist.size()*dist.size()-1)/2 << " entries" << std::endl; ripser(sparse_distance_matrix(std::move(dist), threshold), dim_max, threshold, ratio, modulus) -- cgit v1.2.3 From f0f5cad546e7d396c2402cd709cd9e68587aafcb Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 12 Jul 2018 22:04:44 +0200 Subject: updated readme --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 4aae03d..73bbe59 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ # Ripser -Copyright © 2015–2016 [Ulrich Bauer]. +Copyright © 2015–2018 [Ulrich Bauer]. ### Description Ripser is a lean C++ code for the computation of Vietoris–Rips persistence barcodes. It can do just this one thing, but does it extremely well. -To see a live demo of Ripser's capabilities, go to [live.ripser.org]. The computation happens inside the browser (using [PNaCl] on Chrome and JavaScript via [Emscripten] on other browsers). +To see a live demo of Ripser's capabilities, go to [live.ripser.org]. The computation happens inside the browser (using [PNaCl] on Chrome and JavaScript via [Emscripten] on other browsers). The main features of Ripser: @@ -26,13 +26,14 @@ Input formats currently supported by Ripser: - [DIPHA] distance matrix data - point cloud data -Ripser's efficiency is based on a few important concepts and principles: +Ripser's efficiency is based on a few important concepts and principles, building on key previous and concurrent developments by other researchers in computational topology: - - Compute persistent *co*homology + - Compute persistent *co*homology (as suggested by [Vin de Silva, Dmitriy Morozov, and Mikael Vejdemo-Johansson](https://doi.org/10.1088/0266-5611/27/12/124003)) - Don't compute information that is never needed - (for the experts: employ the *clearing* optimization, aka *persistence with a twist*) - - Don't store information that can be readily recomputed - - Take obvious shortcuts (*apparent persistence pairs*) + (for the experts: employ the *clearing* optimization, aka *persistence with a twist*, as suggested by [Chao Chen and Michael Kerber](http://www.geometrie.tugraz.at/kerber/kerber_papers/ck-phcwat-11.pdf)) + - Don't store information that can be readily recomputed (in particular, the boundary matrix and the reduced boundary matrix) + - Take computational shortcuts (*apparent* and *emergent persistence pairs*) + - If no threshold is specified, choose the *enclosing radius* as the threshold, from which on homology is guaranteed to be trivial (as suggested by [Greg Henselman-Petrusek](https://github.com/Eetion/Eirene.jl)) ### Version -- cgit v1.2.3 From 22017ba657b7068fed2f1ff4f2d76413aa8fa1e7 Mon Sep 17 00:00:00 2001 From: Ulrich Bauer Date: Thu, 12 Jul 2018 22:13:54 +0200 Subject: xcode project update --- ripser.xcodeproj/project.pbxproj | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ripser.xcodeproj/project.pbxproj b/ripser.xcodeproj/project.pbxproj index b5f6881..60bb47a 100644 --- a/ripser.xcodeproj/project.pbxproj +++ b/ripser.xcodeproj/project.pbxproj @@ -88,7 +88,7 @@ 551018401BD63CB300990BFF /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0910; + LastUpgradeCheck = 0940; ORGANIZATIONNAME = "ulrich-bauer.org"; TargetAttributes = { 551018471BD63CB300990BFF = { @@ -129,7 +129,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LANGUAGE_STANDARD = "c++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -137,12 +137,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -180,7 +182,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LANGUAGE_STANDARD = "c++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -188,12 +190,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; -- cgit v1.2.3