From d18ef465b79fe53b103bb05d75d7f71b37792276 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Tue, 18 Oct 2022 16:50:12 +0200 Subject: added possibility of negative values in persistance diagram --- .../include/gudhi/Persistence_graph.h | 57 +++++++--- .../test/bottleneck_unit_test.cpp | 120 +++++++++++++++++---- .../example/example_spatial_searching.cpp | 4 +- src/Spatial_searching/test/test_Kd_tree_search.cpp | 4 +- 4 files changed, 144 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/Bottleneck_distance/include/gudhi/Persistence_graph.h b/src/Bottleneck_distance/include/gudhi/Persistence_graph.h index 33f03b9c..9b663cc2 100644 --- a/src/Bottleneck_distance/include/gudhi/Persistence_graph.h +++ b/src/Bottleneck_distance/include/gudhi/Persistence_graph.h @@ -20,6 +20,7 @@ #include #include #include // for numeric_limits +#include namespace Gudhi { @@ -70,27 +71,51 @@ Persistence_graph::Persistence_graph(const Persistence_diagram1 &diag1, : u(), v(), b_alive(0.) { std::vector u_alive; std::vector v_alive; + std::vector u_nalive; + std::vector v_nalive; + int u_inf = 0; + int v_inf = 0; + double inf = std::numeric_limits::infinity(); + double neginf = -1 * inf; + for (auto it = std::begin(diag1); it != std::end(diag1); ++it) { - if (std::get<1>(*it) == std::numeric_limits::infinity()) - u_alive.push_back(std::get<0>(*it)); - else if (std::get<1>(*it) - std::get<0>(*it) > e) - u.push_back(Internal_point(std::get<0>(*it), std::get<1>(*it), u.size())); + if (std::get<0>(*it) != inf && std::get<1>(*it) != neginf){ + if (std::get<0>(*it) == neginf && std::get<1>(*it) == inf) + u_inf++; + else if (std::get<0>(*it) == neginf) + u_nalive.push_back(std::get<1>(*it)); + else if (std::get<1>(*it) == inf) + u_alive.push_back(std::get<0>(*it)); + else if (std::get<1>(*it) - std::get<0>(*it) > e) + u.push_back(Internal_point(std::get<0>(*it), std::get<1>(*it), u.size())); + } } for (auto it = std::begin(diag2); it != std::end(diag2); ++it) { - if (std::get<1>(*it) == std::numeric_limits::infinity()) - v_alive.push_back(std::get<0>(*it)); - else if (std::get<1>(*it) - std::get<0>(*it) > e) - v.push_back(Internal_point(std::get<0>(*it), std::get<1>(*it), v.size())); + if (std::get<0>(*it) != inf && std::get<1>(*it) != neginf){ + if (std::get<0>(*it) == neginf && std::get<1>(*it) == inf) + v_inf++; + else if (std::get<0>(*it) == neginf) + v_nalive.push_back(std::get<1>(*it)); + else if (std::get<1>(*it) == inf) + v_alive.push_back(std::get<0>(*it)); + else if (std::get<1>(*it) - std::get<0>(*it) > e) + v.push_back(Internal_point(std::get<0>(*it), std::get<1>(*it), v.size())); + } } if (u.size() < v.size()) swap(u, v); - std::sort(u_alive.begin(), u_alive.end()); - std::sort(v_alive.begin(), v_alive.end()); - if (u_alive.size() != v_alive.size()) { + + if (u_alive.size() != v_alive.size() || u_nalive.size() != v_nalive.size() || u_inf != v_inf) { b_alive = std::numeric_limits::infinity(); } else { + std::sort(u_alive.begin(), u_alive.end()); + std::sort(v_alive.begin(), v_alive.end()); + std::sort(u_nalive.begin(), u_nalive.end()); + std::sort(v_nalive.begin(), v_nalive.end()); for (auto it_u = u_alive.cbegin(), it_v = v_alive.cbegin(); it_u != u_alive.cend(); ++it_u, ++it_v) b_alive = (std::max)(b_alive, std::fabs(*it_u - *it_v)); + for (auto it_u = u_nalive.cbegin(), it_v = v_nalive.cbegin(); it_u != u_nalive.cend(); ++it_u, ++it_v) + b_alive = (std::max)(b_alive, std::fabs(*it_u - *it_v)); } } @@ -114,7 +139,7 @@ inline int Persistence_graph::corresponding_point_in_v(int u_point_index) const inline double Persistence_graph::distance(int u_point_index, int v_point_index) const { if (on_the_u_diagonal(u_point_index) && on_the_v_diagonal(v_point_index)) - return 0.; + return 0.; Internal_point p_u = get_u_point(u_point_index); Internal_point p_v = get_v_point(v_point_index); return (std::max)(std::fabs(p_u.x() - p_v.x()), std::fabs(p_u.y() - p_v.y())); @@ -132,9 +157,9 @@ inline std::vector Persistence_graph::sorted_distances() const { std::vector distances; distances.push_back(0.); // for empty diagrams for (int u_point_index = 0; u_point_index < size(); ++u_point_index) { - distances.push_back(distance(u_point_index, corresponding_point_in_v(u_point_index))); - for (int v_point_index = 0; v_point_index < size(); ++v_point_index) - distances.push_back(distance(u_point_index, v_point_index)); + distances.push_back(distance(u_point_index, corresponding_point_in_v(u_point_index))); + for (int v_point_index = 0; v_point_index < size(); ++v_point_index) + distances.push_back(distance(u_point_index, v_point_index)); } #ifdef GUDHI_USE_TBB tbb::parallel_sort(distances.begin(), distances.end()); @@ -146,7 +171,7 @@ inline std::vector Persistence_graph::sorted_distances() const { inline Internal_point Persistence_graph::get_u_point(int u_point_index) const { if (!on_the_u_diagonal(u_point_index)) - return u.at(u_point_index); + return u.at(u_point_index); Internal_point projector = v.at(corresponding_point_in_v(u_point_index)); double m = (projector.x() + projector.y()) / 2.; return Internal_point(m, m, u_point_index); diff --git a/src/Bottleneck_distance/test/bottleneck_unit_test.cpp b/src/Bottleneck_distance/test/bottleneck_unit_test.cpp index 44141baa..79ee9c2c 100644 --- a/src/Bottleneck_distance/test/bottleneck_unit_test.cpp +++ b/src/Bottleneck_distance/test/bottleneck_unit_test.cpp @@ -31,14 +31,14 @@ std::vector< std::pair > v1, v2; BOOST_AUTO_TEST_CASE(persistence_graph) { // Random construction for (int i = 0; i < n1; i++) { - double a = unif(re); - double b = unif(re); - v1.emplace_back(std::min(a, b), std::max(a, b)); + double a = unif(re); + double b = unif(re); + v1.emplace_back(std::min(a, b), std::max(a, b)); } for (int i = 0; i < n2; i++) { - double a = unif(re); - double b = unif(re); - v2.emplace_back(std::min(a, b), std::max(a, b)); + double a = unif(re); + double b = unif(re); + v2.emplace_back(std::min(a, b), std::max(a, b)); } Persistence_graph g(v1, v2, 0.); std::vector d(g.sorted_distances()); @@ -84,14 +84,14 @@ BOOST_AUTO_TEST_CASE(neighbors_finder) { Persistence_graph g(v1, v2, 0.); Neighbors_finder nf(g, 1.); for (int v_point_index = 1; v_point_index < ((n2 + n1)*9 / 10); v_point_index += 2) - nf.add(v_point_index); + nf.add(v_point_index); // int v_point_index_1 = nf.pull_near(n2 / 2); BOOST_CHECK((v_point_index_1 == -1) || (g.distance(n2 / 2, v_point_index_1) <= 1.)); std::vector l = nf.pull_all_near(n2 / 2); bool v = true; for (auto it = l.cbegin(); it != l.cend(); ++it) - v = v && (g.distance(n2 / 2, *it) > 1.); + v = v && (g.distance(n2 / 2, *it) > 1.); BOOST_CHECK(v); int v_point_index_2 = nf.pull_near(n2 / 2); BOOST_CHECK(v_point_index_2 == -1); @@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(layered_neighbors_finder) { Persistence_graph g(v1, v2, 0.); Layered_neighbors_finder lnf(g, 1.); for (int v_point_index = 1; v_point_index < ((n2 + n1)*9 / 10); v_point_index += 2) - lnf.add(v_point_index, v_point_index % 7); + lnf.add(v_point_index, v_point_index % 7); // int v_point_index_1 = lnf.pull_near(n2 / 2, 6); BOOST_CHECK((v_point_index_1 == -1) || (g.distance(n2 / 2, v_point_index_1) <= 1.)); @@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(graph_matching) { m1.set_r(0.); int e = 0; while (m1.multi_augment()) - ++e; + ++e; BOOST_CHECK(e > 0); BOOST_CHECK(e <= 2 * sqrt(2 * (n1 + n2))); Graph_matching m2 = m1; @@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(graph_matching) { m2.set_r(upper_bound); e = 0; while (m2.multi_augment()) - ++e; + ++e; BOOST_CHECK(e <= 2 * sqrt(2 * (n1 + n2))); BOOST_CHECK(m2.perfect()); BOOST_CHECK(!m1.perfect()); @@ -139,16 +139,16 @@ BOOST_AUTO_TEST_CASE(global) { std::default_random_engine re; std::vector< std::pair > v1, v2; for (int i = 0; i < n1; i++) { - double a = unif1(re); - double b = unif1(re); - double x = unif2(re); - double y = unif2(re); - v1.emplace_back(std::min(a, b), std::max(a, b)); - v2.emplace_back(std::min(a, b) + std::min(x, y), std::max(a, b) + std::max(x, y)); - if (i % 5 == 0) - v1.emplace_back(std::min(a, b), std::min(a, b) + x); - if (i % 3 == 0) - v2.emplace_back(std::max(a, b), std::max(a, b) + y); + double a = unif1(re); + double b = unif1(re); + double x = unif2(re); + double y = unif2(re); + v1.emplace_back(std::min(a, b), std::max(a, b)); + v2.emplace_back(std::min(a, b) + std::min(x, y), std::max(a, b) + std::max(x, y)); + if (i % 5 == 0) + v1.emplace_back(std::min(a, b), std::min(a, b) + x); + if (i % 3 == 0) + v2.emplace_back(std::max(a, b), std::max(a, b) + y); } BOOST_CHECK(bottleneck_distance(v1, v2, 0.) <= upper_bound / 100.); BOOST_CHECK(bottleneck_distance(v1, v2, upper_bound / 10000.) <= upper_bound / 100. + upper_bound / 10000.); @@ -159,3 +159,81 @@ BOOST_AUTO_TEST_CASE(global) { BOOST_CHECK(bottleneck_distance(empty, empty) == 0); BOOST_CHECK(bottleneck_distance(empty, one) == 1); } + +BOOST_AUTO_TEST_CASE(neg_global) { + std::uniform_real_distribution unif1(0., upper_bound); + std::uniform_real_distribution unif2(upper_bound / 10000., upper_bound / 100.); + std::default_random_engine re; + std::vector< std::pair > v1, v2; + for (int i = 0; i < n1; i++) { + double a = std::log(unif1(re)); + double b = std::log(unif1(re)); + double x = std::log(unif2(re)); + double y = std::log(unif2(re)); + v1.emplace_back(std::min(a, b), std::max(a, b)); + v2.emplace_back(std::min(a, b) + std::min(x, y), std::max(a, b) + std::max(x, y)); + if (i % 5 == 0) + v1.emplace_back(std::min(a, b), std::min(a, b) + x); + if (i % 3 == 0) + v2.emplace_back(std::max(a, b), std::max(a, b) + y); + } + BOOST_CHECK(bottleneck_distance(v1, v2, 0.) <= upper_bound / 100.); + BOOST_CHECK(bottleneck_distance(v1, v2, upper_bound / 10000.) <= upper_bound / 100. + upper_bound / 10000.); + BOOST_CHECK(std::abs(bottleneck_distance(v1, v2, 0.) - bottleneck_distance(v1, v2, upper_bound / 10000.)) <= upper_bound / 10000.); + + std::vector< std::pair > empty; + std::vector< std::pair > one = {{8, 10}}; + BOOST_CHECK(bottleneck_distance(empty, empty) == 0); + BOOST_CHECK(bottleneck_distance(empty, one) == 1); +} + +BOOST_AUTO_TEST_CASE(bottleneck_simple_test) { + std::vector< std::pair > v1, v2; + double inf = std::numeric_limits::infinity(); + double neginf = -1 * inf; + double b; + + v1.emplace_back(9.6, 14.); + v2.emplace_back(9.5, 14.1); + + b = Gudhi::persistence_diagram::bottleneck_distance(v1, v2, 0.); + BOOST_CHECK(b > 0.09 && b < 0.11); + + v1.emplace_back(-34.974, -34.2); + + b = Gudhi::persistence_diagram::bottleneck_distance(v1, v2, 0.); + BOOST_CHECK(b > 0.386 && b < 0.388); + + v1.emplace_back(neginf, 3.7); + + b = Gudhi::persistence_diagram::bottleneck_distance(v1, v2, 0.); + BOOST_CHECK_EQUAL(b, inf); + + v2.emplace_back(neginf, 4.45); + + b = Gudhi::persistence_diagram::bottleneck_distance(v1, v2, 0.); + BOOST_CHECK(b > 0.74 && b < 0.76); + + v1.emplace_back(-60.6, 52.1); + v2.emplace_back(-61.5, 53.); + + b = Gudhi::persistence_diagram::bottleneck_distance(v1, v2, 0.); + BOOST_CHECK(b > 0.89 && b < 0.91); + + v1.emplace_back(3., inf); + v2.emplace_back(3.2, inf); + + b = Gudhi::persistence_diagram::bottleneck_distance(v1, v2, 0.); + BOOST_CHECK(b > 0.89 && b < 0.91); + + v1.emplace_back(neginf, inf); + v2.emplace_back(neginf, inf); + + b = Gudhi::persistence_diagram::bottleneck_distance(v1, v2, 0.); + BOOST_CHECK(b > 0.89 && b < 0.91); + + v2.emplace_back(6, inf); + + b = Gudhi::persistence_diagram::bottleneck_distance(v1, v2, 0.); + BOOST_CHECK_EQUAL(b, inf); +} diff --git a/src/Spatial_searching/example/example_spatial_searching.cpp b/src/Spatial_searching/example/example_spatial_searching.cpp index 8f9151fc..09c2dabf 100644 --- a/src/Spatial_searching/example/example_spatial_searching.cpp +++ b/src/Spatial_searching/example/example_spatial_searching.cpp @@ -25,7 +25,7 @@ int main(void) { // 10-nearest neighbor query std::clog << "10 nearest neighbors from points[20]:\n"; auto knn_range = points_ds.k_nearest_neighbors(points[20], 10, true); - for (auto const& nghb : knn_range) + for (auto const nghb : knn_range) std::clog << nghb.first << " (sq. dist. = " << nghb.second << ")\n"; // Incremental nearest neighbor query @@ -38,7 +38,7 @@ int main(void) { // 10-furthest neighbor query std::clog << "10 furthest neighbors from points[20]:\n"; auto kfn_range = points_ds.k_furthest_neighbors(points[20], 10, true); - for (auto const& nghb : kfn_range) + for (auto const nghb : kfn_range) std::clog << nghb.first << " (sq. dist. = " << nghb.second << ")\n"; // Incremental furthest neighbor query diff --git a/src/Spatial_searching/test/test_Kd_tree_search.cpp b/src/Spatial_searching/test/test_Kd_tree_search.cpp index d6c6fba3..e9acfaa7 100644 --- a/src/Spatial_searching/test/test_Kd_tree_search.cpp +++ b/src/Spatial_searching/test/test_Kd_tree_search.cpp @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(test_Kd_tree_search) { std::vector knn_result; FT last_dist = -1.; - for (auto const& nghb : kns_range) { + for (auto const nghb : kns_range) { BOOST_CHECK(nghb.second > last_dist); knn_result.push_back(nghb.second); last_dist = nghb.second; @@ -76,7 +76,7 @@ BOOST_AUTO_TEST_CASE(test_Kd_tree_search) { std::vector kfn_result; last_dist = kfn_range.begin()->second; - for (auto const& nghb : kfn_range) { + for (auto const nghb : kfn_range) { BOOST_CHECK(nghb.second <= last_dist); kfn_result.push_back(nghb.second); last_dist = nghb.second; -- cgit v1.2.3 From ff59ebb1a3417701a9282783adeb254af14b856c Mon Sep 17 00:00:00 2001 From: hschreiber Date: Tue, 18 Oct 2022 17:31:34 +0200 Subject: syntax correction --- src/Bottleneck_distance/include/gudhi/Persistence_graph.h | 2 +- src/Bottleneck_distance/test/bottleneck_unit_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/Bottleneck_distance/include/gudhi/Persistence_graph.h b/src/Bottleneck_distance/include/gudhi/Persistence_graph.h index 9b663cc2..de989e1b 100644 --- a/src/Bottleneck_distance/include/gudhi/Persistence_graph.h +++ b/src/Bottleneck_distance/include/gudhi/Persistence_graph.h @@ -76,7 +76,7 @@ Persistence_graph::Persistence_graph(const Persistence_diagram1 &diag1, int u_inf = 0; int v_inf = 0; double inf = std::numeric_limits::infinity(); - double neginf = -1 * inf; + double neginf = -inf; for (auto it = std::begin(diag1); it != std::end(diag1); ++it) { if (std::get<0>(*it) != inf && std::get<1>(*it) != neginf){ diff --git a/src/Bottleneck_distance/test/bottleneck_unit_test.cpp b/src/Bottleneck_distance/test/bottleneck_unit_test.cpp index 79ee9c2c..38ed89a8 100644 --- a/src/Bottleneck_distance/test/bottleneck_unit_test.cpp +++ b/src/Bottleneck_distance/test/bottleneck_unit_test.cpp @@ -190,7 +190,7 @@ BOOST_AUTO_TEST_CASE(neg_global) { BOOST_AUTO_TEST_CASE(bottleneck_simple_test) { std::vector< std::pair > v1, v2; double inf = std::numeric_limits::infinity(); - double neginf = -1 * inf; + double neginf = -inf; double b; v1.emplace_back(9.6, 14.); -- cgit v1.2.3 From 475a20c0645b079aaf204fd47398b7bb278fb490 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Wed, 19 Oct 2022 11:52:41 +0200 Subject: correction of indentation --- .../include/gudhi/Persistence_graph.h | 72 +++++++++++----------- .../test/bottleneck_unit_test.cpp | 62 +++++++++---------- 2 files changed, 67 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/Bottleneck_distance/include/gudhi/Persistence_graph.h b/src/Bottleneck_distance/include/gudhi/Persistence_graph.h index de989e1b..c1e10f8e 100644 --- a/src/Bottleneck_distance/include/gudhi/Persistence_graph.h +++ b/src/Bottleneck_distance/include/gudhi/Persistence_graph.h @@ -32,7 +32,7 @@ namespace persistence_diagram { * \ingroup bottleneck_distance */ class Persistence_graph { - public: +public: /** \internal \brief Constructor taking 2 PersistenceDiagrams (concept) as parameters. */ template Persistence_graph(const Persistence_diagram1& diag1, const Persistence_diagram2& diag2, double e); @@ -59,7 +59,7 @@ class Persistence_graph { /** \internal \brief Returns the corresponding internal point */ Internal_point get_v_point(int v_point_index) const; - private: +private: std::vector u; std::vector v; double b_alive; @@ -68,7 +68,7 @@ class Persistence_graph { template Persistence_graph::Persistence_graph(const Persistence_diagram1 &diag1, const Persistence_diagram2 &diag2, double e) - : u(), v(), b_alive(0.) { + : u(), v(), b_alive(0.) { std::vector u_alive; std::vector v_alive; std::vector u_nalive; @@ -79,28 +79,28 @@ Persistence_graph::Persistence_graph(const Persistence_diagram1 &diag1, double neginf = -inf; for (auto it = std::begin(diag1); it != std::end(diag1); ++it) { - if (std::get<0>(*it) != inf && std::get<1>(*it) != neginf){ - if (std::get<0>(*it) == neginf && std::get<1>(*it) == inf) - u_inf++; - else if (std::get<0>(*it) == neginf) - u_nalive.push_back(std::get<1>(*it)); - else if (std::get<1>(*it) == inf) - u_alive.push_back(std::get<0>(*it)); - else if (std::get<1>(*it) - std::get<0>(*it) > e) - u.push_back(Internal_point(std::get<0>(*it), std::get<1>(*it), u.size())); - } + if (std::get<0>(*it) != inf && std::get<1>(*it) != neginf){ + if (std::get<0>(*it) == neginf && std::get<1>(*it) == inf) + u_inf++; + else if (std::get<0>(*it) == neginf) + u_nalive.push_back(std::get<1>(*it)); + else if (std::get<1>(*it) == inf) + u_alive.push_back(std::get<0>(*it)); + else if (std::get<1>(*it) - std::get<0>(*it) > e) + u.push_back(Internal_point(std::get<0>(*it), std::get<1>(*it), u.size())); + } } for (auto it = std::begin(diag2); it != std::end(diag2); ++it) { - if (std::get<0>(*it) != inf && std::get<1>(*it) != neginf){ - if (std::get<0>(*it) == neginf && std::get<1>(*it) == inf) - v_inf++; - else if (std::get<0>(*it) == neginf) - v_nalive.push_back(std::get<1>(*it)); - else if (std::get<1>(*it) == inf) - v_alive.push_back(std::get<0>(*it)); - else if (std::get<1>(*it) - std::get<0>(*it) > e) - v.push_back(Internal_point(std::get<0>(*it), std::get<1>(*it), v.size())); - } + if (std::get<0>(*it) != inf && std::get<1>(*it) != neginf){ + if (std::get<0>(*it) == neginf && std::get<1>(*it) == inf) + v_inf++; + else if (std::get<0>(*it) == neginf) + v_nalive.push_back(std::get<1>(*it)); + else if (std::get<1>(*it) == inf) + v_alive.push_back(std::get<0>(*it)); + else if (std::get<1>(*it) - std::get<0>(*it) > e) + v.push_back(Internal_point(std::get<0>(*it), std::get<1>(*it), v.size())); + } } if (u.size() < v.size()) swap(u, v); @@ -108,14 +108,14 @@ Persistence_graph::Persistence_graph(const Persistence_diagram1 &diag1, if (u_alive.size() != v_alive.size() || u_nalive.size() != v_nalive.size() || u_inf != v_inf) { b_alive = std::numeric_limits::infinity(); } else { - std::sort(u_alive.begin(), u_alive.end()); - std::sort(v_alive.begin(), v_alive.end()); - std::sort(u_nalive.begin(), u_nalive.end()); - std::sort(v_nalive.begin(), v_nalive.end()); + std::sort(u_alive.begin(), u_alive.end()); + std::sort(v_alive.begin(), v_alive.end()); + std::sort(u_nalive.begin(), u_nalive.end()); + std::sort(v_nalive.begin(), v_nalive.end()); for (auto it_u = u_alive.cbegin(), it_v = v_alive.cbegin(); it_u != u_alive.cend(); ++it_u, ++it_v) b_alive = (std::max)(b_alive, std::fabs(*it_u - *it_v)); - for (auto it_u = u_nalive.cbegin(), it_v = v_nalive.cbegin(); it_u != u_nalive.cend(); ++it_u, ++it_v) - b_alive = (std::max)(b_alive, std::fabs(*it_u - *it_v)); + for (auto it_u = u_nalive.cbegin(), it_v = v_nalive.cbegin(); it_u != u_nalive.cend(); ++it_u, ++it_v) + b_alive = (std::max)(b_alive, std::fabs(*it_u - *it_v)); } } @@ -129,17 +129,17 @@ inline bool Persistence_graph::on_the_v_diagonal(int v_point_index) const { inline int Persistence_graph::corresponding_point_in_u(int v_point_index) const { return on_the_v_diagonal(v_point_index) ? - v_point_index - static_cast (v.size()) : v_point_index + static_cast (u.size()); + v_point_index - static_cast (v.size()) : v_point_index + static_cast (u.size()); } inline int Persistence_graph::corresponding_point_in_v(int u_point_index) const { return on_the_u_diagonal(u_point_index) ? - u_point_index - static_cast (u.size()) : u_point_index + static_cast (v.size()); + u_point_index - static_cast (u.size()) : u_point_index + static_cast (v.size()); } inline double Persistence_graph::distance(int u_point_index, int v_point_index) const { if (on_the_u_diagonal(u_point_index) && on_the_v_diagonal(v_point_index)) - return 0.; + return 0.; Internal_point p_u = get_u_point(u_point_index); Internal_point p_v = get_v_point(v_point_index); return (std::max)(std::fabs(p_u.x() - p_v.x()), std::fabs(p_u.y() - p_v.y())); @@ -157,9 +157,9 @@ inline std::vector Persistence_graph::sorted_distances() const { std::vector distances; distances.push_back(0.); // for empty diagrams for (int u_point_index = 0; u_point_index < size(); ++u_point_index) { - distances.push_back(distance(u_point_index, corresponding_point_in_v(u_point_index))); - for (int v_point_index = 0; v_point_index < size(); ++v_point_index) - distances.push_back(distance(u_point_index, v_point_index)); + distances.push_back(distance(u_point_index, corresponding_point_in_v(u_point_index))); + for (int v_point_index = 0; v_point_index < size(); ++v_point_index) + distances.push_back(distance(u_point_index, v_point_index)); } #ifdef GUDHI_USE_TBB tbb::parallel_sort(distances.begin(), distances.end()); @@ -171,7 +171,7 @@ inline std::vector Persistence_graph::sorted_distances() const { inline Internal_point Persistence_graph::get_u_point(int u_point_index) const { if (!on_the_u_diagonal(u_point_index)) - return u.at(u_point_index); + return u.at(u_point_index); Internal_point projector = v.at(corresponding_point_in_v(u_point_index)); double m = (projector.x() + projector.y()) / 2.; return Internal_point(m, m, u_point_index); diff --git a/src/Bottleneck_distance/test/bottleneck_unit_test.cpp b/src/Bottleneck_distance/test/bottleneck_unit_test.cpp index 38ed89a8..9872f20c 100644 --- a/src/Bottleneck_distance/test/bottleneck_unit_test.cpp +++ b/src/Bottleneck_distance/test/bottleneck_unit_test.cpp @@ -31,14 +31,14 @@ std::vector< std::pair > v1, v2; BOOST_AUTO_TEST_CASE(persistence_graph) { // Random construction for (int i = 0; i < n1; i++) { - double a = unif(re); - double b = unif(re); - v1.emplace_back(std::min(a, b), std::max(a, b)); + double a = unif(re); + double b = unif(re); + v1.emplace_back(std::min(a, b), std::max(a, b)); } for (int i = 0; i < n2; i++) { - double a = unif(re); - double b = unif(re); - v2.emplace_back(std::min(a, b), std::max(a, b)); + double a = unif(re); + double b = unif(re); + v2.emplace_back(std::min(a, b), std::max(a, b)); } Persistence_graph g(v1, v2, 0.); std::vector d(g.sorted_distances()); @@ -84,14 +84,14 @@ BOOST_AUTO_TEST_CASE(neighbors_finder) { Persistence_graph g(v1, v2, 0.); Neighbors_finder nf(g, 1.); for (int v_point_index = 1; v_point_index < ((n2 + n1)*9 / 10); v_point_index += 2) - nf.add(v_point_index); + nf.add(v_point_index); // int v_point_index_1 = nf.pull_near(n2 / 2); BOOST_CHECK((v_point_index_1 == -1) || (g.distance(n2 / 2, v_point_index_1) <= 1.)); std::vector l = nf.pull_all_near(n2 / 2); bool v = true; for (auto it = l.cbegin(); it != l.cend(); ++it) - v = v && (g.distance(n2 / 2, *it) > 1.); + v = v && (g.distance(n2 / 2, *it) > 1.); BOOST_CHECK(v); int v_point_index_2 = nf.pull_near(n2 / 2); BOOST_CHECK(v_point_index_2 == -1); @@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(layered_neighbors_finder) { Persistence_graph g(v1, v2, 0.); Layered_neighbors_finder lnf(g, 1.); for (int v_point_index = 1; v_point_index < ((n2 + n1)*9 / 10); v_point_index += 2) - lnf.add(v_point_index, v_point_index % 7); + lnf.add(v_point_index, v_point_index % 7); // int v_point_index_1 = lnf.pull_near(n2 / 2, 6); BOOST_CHECK((v_point_index_1 == -1) || (g.distance(n2 / 2, v_point_index_1) <= 1.)); @@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(graph_matching) { m1.set_r(0.); int e = 0; while (m1.multi_augment()) - ++e; + ++e; BOOST_CHECK(e > 0); BOOST_CHECK(e <= 2 * sqrt(2 * (n1 + n2))); Graph_matching m2 = m1; @@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(graph_matching) { m2.set_r(upper_bound); e = 0; while (m2.multi_augment()) - ++e; + ++e; BOOST_CHECK(e <= 2 * sqrt(2 * (n1 + n2))); BOOST_CHECK(m2.perfect()); BOOST_CHECK(!m1.perfect()); @@ -139,16 +139,16 @@ BOOST_AUTO_TEST_CASE(global) { std::default_random_engine re; std::vector< std::pair > v1, v2; for (int i = 0; i < n1; i++) { - double a = unif1(re); - double b = unif1(re); - double x = unif2(re); - double y = unif2(re); - v1.emplace_back(std::min(a, b), std::max(a, b)); - v2.emplace_back(std::min(a, b) + std::min(x, y), std::max(a, b) + std::max(x, y)); - if (i % 5 == 0) - v1.emplace_back(std::min(a, b), std::min(a, b) + x); - if (i % 3 == 0) - v2.emplace_back(std::max(a, b), std::max(a, b) + y); + double a = unif1(re); + double b = unif1(re); + double x = unif2(re); + double y = unif2(re); + v1.emplace_back(std::min(a, b), std::max(a, b)); + v2.emplace_back(std::min(a, b) + std::min(x, y), std::max(a, b) + std::max(x, y)); + if (i % 5 == 0) + v1.emplace_back(std::min(a, b), std::min(a, b) + x); + if (i % 3 == 0) + v2.emplace_back(std::max(a, b), std::max(a, b) + y); } BOOST_CHECK(bottleneck_distance(v1, v2, 0.) <= upper_bound / 100.); BOOST_CHECK(bottleneck_distance(v1, v2, upper_bound / 10000.) <= upper_bound / 100. + upper_bound / 10000.); @@ -166,16 +166,16 @@ BOOST_AUTO_TEST_CASE(neg_global) { std::default_random_engine re; std::vector< std::pair > v1, v2; for (int i = 0; i < n1; i++) { - double a = std::log(unif1(re)); - double b = std::log(unif1(re)); - double x = std::log(unif2(re)); - double y = std::log(unif2(re)); - v1.emplace_back(std::min(a, b), std::max(a, b)); - v2.emplace_back(std::min(a, b) + std::min(x, y), std::max(a, b) + std::max(x, y)); - if (i % 5 == 0) - v1.emplace_back(std::min(a, b), std::min(a, b) + x); - if (i % 3 == 0) - v2.emplace_back(std::max(a, b), std::max(a, b) + y); + double a = std::log(unif1(re)); + double b = std::log(unif1(re)); + double x = std::log(unif2(re)); + double y = std::log(unif2(re)); + v1.emplace_back(std::min(a, b), std::max(a, b)); + v2.emplace_back(std::min(a, b) + std::min(x, y), std::max(a, b) + std::max(x, y)); + if (i % 5 == 0) + v1.emplace_back(std::min(a, b), std::min(a, b) + x); + if (i % 3 == 0) + v2.emplace_back(std::max(a, b), std::max(a, b) + y); } BOOST_CHECK(bottleneck_distance(v1, v2, 0.) <= upper_bound / 100.); BOOST_CHECK(bottleneck_distance(v1, v2, upper_bound / 10000.) <= upper_bound / 100. + upper_bound / 10000.); -- cgit v1.2.3 From 26d7bcc518f3bdc9b0d8f854f2879ed9c219e440 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 3 Nov 2022 14:56:34 +0100 Subject: Translate n_jobs to workers for SciPy --- src/python/gudhi/point_cloud/knn.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/python/gudhi/point_cloud/knn.py b/src/python/gudhi/point_cloud/knn.py index de5844f9..7dc83817 100644 --- a/src/python/gudhi/point_cloud/knn.py +++ b/src/python/gudhi/point_cloud/knn.py @@ -314,7 +314,9 @@ class KNearestNeighbors: return None if self.params["implementation"] == "ckdtree": - qargs = {key: val for key, val in self.params.items() if key in {"p", "eps", "n_jobs"}} + qargs = {key: val for key, val in self.params.items() if key in {"p", "eps"}} + # SciPy renamed n_jobs to workers + qargs["workers"] = self.params.get("workers") or self.params.get("n_jobs") or 1 distances, neighbors = self.kdtree.query(X, k=self.k, **qargs) if k == 1: # SciPy decided to squeeze the last dimension for k=1 -- cgit v1.2.3 From 95330fb658db4184813d8720c52da5e25bcdd38c Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 4 Nov 2022 11:01:43 +0100 Subject: Mention SciPy version in the doc --- src/python/doc/installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/python/doc/installation.rst b/src/python/doc/installation.rst index b704f778..276ac4e2 100644 --- a/src/python/doc/installation.rst +++ b/src/python/doc/installation.rst @@ -391,7 +391,7 @@ The :doc:`persistence graphical tools ` and mathematics, science, and engineering. :class:`~gudhi.point_cloud.knn.KNearestNeighbors` can use the Python package -`SciPy `_ as a backend if explicitly requested. +`SciPy `_ :math:`\geq` 1.6.0 as a backend if explicitly requested. TensorFlow ---------- -- cgit v1.2.3 From 454ef5370d5a188cd303c497ed473df9aac81708 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 4 Nov 2022 23:02:56 +0100 Subject: Use fetch_spiral_2d in the doc --- src/python/doc/clustering.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/python/doc/clustering.rst b/src/python/doc/clustering.rst index c5a57d3c..62422682 100644 --- a/src/python/doc/clustering.rst +++ b/src/python/doc/clustering.rst @@ -17,9 +17,8 @@ As a by-product, we produce the persistence diagram of the merge tree of the ini :include-source: import gudhi - f = open(gudhi.__root_source_dir__ + '/data/points/spiral_2d.csv', 'r') - import numpy as np - data = np.loadtxt(f) + from gudhi.datasets.remote import fetch_spiral_2d + data = fetch_spiral_2d() import matplotlib.pyplot as plt plt.scatter(data[:,0],data[:,1],marker='.',s=1) plt.show() -- cgit v1.2.3 From 4246261962f5b3f37cf4e845ff192da2be023834 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 4 Nov 2022 23:39:46 +0100 Subject: Remove the deprecated std::iterator --- .../include/gudhi/Bitmap_cubical_complex.h | 16 ++++++++++++++-- .../include/gudhi/Bitmap_cubical_complex_base.h | 16 ++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex.h b/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex.h index 4a6af3a4..ae7e6ed3 100644 --- a/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex.h +++ b/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex.h @@ -241,10 +241,16 @@ class Bitmap_cubical_complex : public T { **/ class Filtration_simplex_range; - class Filtration_simplex_iterator : std::iterator { + class Filtration_simplex_iterator { // Iterator over all simplices of the complex in the order of the indexing scheme. // 'value_type' must be 'Simplex_handle'. public: + typedef std::input_iterator_tag iterator_category; + typedef Simplex_handle value_type; + typedef std::ptrdiff_t difference_type; + typedef value_type* pointer; + typedef value_type& reference; + Filtration_simplex_iterator(Bitmap_cubical_complex* b) : b(b), position(0) {} Filtration_simplex_iterator() : b(NULL), position(0) {} @@ -386,10 +392,16 @@ class Bitmap_cubical_complex : public T { **/ class Skeleton_simplex_range; - class Skeleton_simplex_iterator : std::iterator { + class Skeleton_simplex_iterator { // Iterator over all simplices of the complex in the order of the indexing scheme. // 'value_type' must be 'Simplex_handle'. public: + typedef std::input_iterator_tag iterator_category; + typedef Simplex_handle value_type; + typedef std::ptrdiff_t difference_type; + typedef value_type* pointer; + typedef value_type& reference; + Skeleton_simplex_iterator(Bitmap_cubical_complex* b, std::size_t d) : b(b), dimension(d) { if (globalDbg) { std::clog << "Skeleton_simplex_iterator ( Bitmap_cubical_complex* b , std::size_t d )\n"; diff --git a/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex_base.h b/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex_base.h index bafe7981..253e4a54 100644 --- a/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex_base.h +++ b/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex_base.h @@ -251,8 +251,14 @@ class Bitmap_cubical_complex_base { * @brief Iterator through all cells in the complex (in order they appear in the structure -- i.e. * in lexicographical order). **/ - class All_cells_iterator : std::iterator { + class All_cells_iterator { public: + typedef std::input_iterator_tag iterator_category; + typedef T value_type; + typedef std::ptrdiff_t difference_type; + typedef value_type* pointer; + typedef value_type& reference; + All_cells_iterator() { this->counter = 0; } All_cells_iterator operator++() { @@ -355,8 +361,14 @@ class Bitmap_cubical_complex_base { * @brief Iterator through top dimensional cells of the complex. The cells appear in order they are stored * in the structure (i.e. in lexicographical order) **/ - class Top_dimensional_cells_iterator : std::iterator { + class Top_dimensional_cells_iterator { public: + typedef std::input_iterator_tag iterator_category; + typedef T value_type; + typedef std::ptrdiff_t difference_type; + typedef value_type* pointer; + typedef value_type& reference; + Top_dimensional_cells_iterator(Bitmap_cubical_complex_base& b) : b(b) { this->counter = std::vector(b.dimension()); // std::fill( this->counter.begin() , this->counter.end() , 0 ); -- cgit v1.2.3 From f5af745c4f671f477365115bedf17d167b8d07a5 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 4 Nov 2022 23:46:45 +0100 Subject: Fix bogus traits. Not great, but less broken. --- src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex.h | 4 ++-- .../include/gudhi/Bitmap_cubical_complex_base.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex.h b/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex.h index ae7e6ed3..29fabc6c 100644 --- a/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex.h +++ b/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex.h @@ -249,7 +249,7 @@ class Bitmap_cubical_complex : public T { typedef Simplex_handle value_type; typedef std::ptrdiff_t difference_type; typedef value_type* pointer; - typedef value_type& reference; + typedef value_type reference; Filtration_simplex_iterator(Bitmap_cubical_complex* b) : b(b), position(0) {} @@ -400,7 +400,7 @@ class Bitmap_cubical_complex : public T { typedef Simplex_handle value_type; typedef std::ptrdiff_t difference_type; typedef value_type* pointer; - typedef value_type& reference; + typedef value_type reference; Skeleton_simplex_iterator(Bitmap_cubical_complex* b, std::size_t d) : b(b), dimension(d) { if (globalDbg) { diff --git a/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex_base.h b/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex_base.h index 253e4a54..2bf62f9b 100644 --- a/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex_base.h +++ b/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex_base.h @@ -254,10 +254,10 @@ class Bitmap_cubical_complex_base { class All_cells_iterator { public: typedef std::input_iterator_tag iterator_category; - typedef T value_type; + typedef std::size_t value_type; typedef std::ptrdiff_t difference_type; typedef value_type* pointer; - typedef value_type& reference; + typedef value_type reference; All_cells_iterator() { this->counter = 0; } @@ -364,10 +364,10 @@ class Bitmap_cubical_complex_base { class Top_dimensional_cells_iterator { public: typedef std::input_iterator_tag iterator_category; - typedef T value_type; + typedef std::size_t value_type; typedef std::ptrdiff_t difference_type; typedef value_type* pointer; - typedef value_type& reference; + typedef value_type reference; Top_dimensional_cells_iterator(Bitmap_cubical_complex_base& b) : b(b) { this->counter = std::vector(b.dimension()); -- cgit v1.2.3 From 8804aa1580c500ed927d65c25e8b78700725338e Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Tue, 8 Nov 2022 22:26:36 +0100 Subject: Clarify doc of RipsComplex.__init__ --- src/python/gudhi/rips_complex.pyx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/python/gudhi/rips_complex.pyx b/src/python/gudhi/rips_complex.pyx index c3470292..a0924cd6 100644 --- a/src/python/gudhi/rips_complex.pyx +++ b/src/python/gudhi/rips_complex.pyx @@ -45,20 +45,19 @@ cdef class RipsComplex: max_edge_length=float('inf'), sparse=None): """RipsComplex constructor. - :param max_edge_length: Rips value. - :type max_edge_length: float - :param points: A list of points in d-Dimension. - :type points: list of list of float + :type points: List[List[float]] Or :param distance_matrix: A distance matrix (full square or lower triangular). - :type points: list of list of float + :type distance_matrix: List[List[float]] And in both cases + :param max_edge_length: Rips value. + :type max_edge_length: float :param sparse: If this is not None, it switches to building a sparse Rips and represents the approximation parameter epsilon. :type sparse: float -- cgit v1.2.3 From 7c17408897a95a1f74626e8ff0ec8101ac4f92fd Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Tue, 8 Nov 2022 22:36:16 +0100 Subject: Reject positional arguments in RipsComplex.__init__ --- .github/next_release.md | 3 +++ src/python/gudhi/rips_complex.pyx | 4 ++-- src/python/test/test_simplex_generators.py | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/.github/next_release.md b/.github/next_release.md index 81599b2c..d5fcef1c 100644 --- a/.github/next_release.md +++ b/.github/next_release.md @@ -9,6 +9,9 @@ Below is a list of changes made since GUDHI 3.6.0: - [Module](link) - ... +- [Rips complex](https://gudhi.inria.fr/python/latest/rips_complex_user.html) + - Construction now rejects positional arguments, you need to specify `points=X`. + - Installation - c++17 is the new minimal standard to compile the library. This implies Visual Studio minimal version is now 2017. diff --git a/src/python/gudhi/rips_complex.pyx b/src/python/gudhi/rips_complex.pyx index a0924cd6..d748f91e 100644 --- a/src/python/gudhi/rips_complex.pyx +++ b/src/python/gudhi/rips_complex.pyx @@ -41,7 +41,7 @@ cdef class RipsComplex: cdef Rips_complex_interface thisref # Fake constructor that does nothing but documenting the constructor - def __init__(self, points=None, distance_matrix=None, + def __init__(self, *, points=None, distance_matrix=None, max_edge_length=float('inf'), sparse=None): """RipsComplex constructor. @@ -64,7 +64,7 @@ cdef class RipsComplex: """ # The real cython constructor - def __cinit__(self, points=None, distance_matrix=None, + def __cinit__(self, *, points=None, distance_matrix=None, max_edge_length=float('inf'), sparse=None): if sparse is not None: if distance_matrix is not None: diff --git a/src/python/test/test_simplex_generators.py b/src/python/test/test_simplex_generators.py index 8a9b4844..c567d4c1 100755 --- a/src/python/test/test_simplex_generators.py +++ b/src/python/test/test_simplex_generators.py @@ -14,7 +14,7 @@ import numpy as np def test_flag_generators(): pts = np.array([[0, 0], [0, 1.01], [1, 0], [1.02, 1.03], [100, 0], [100, 3.01], [103, 0], [103.02, 3.03]]) - r = gudhi.RipsComplex(pts, max_edge_length=4) + r = gudhi.RipsComplex(points=pts, max_edge_length=4) st = r.create_simplex_tree(max_dimension=50) st.persistence() g = st.flag_persistence_generators() -- cgit v1.2.3 From ad1123c3c7cfddc1c15e9933b96af08ef3398b3c Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 9 Nov 2022 17:46:39 +0100 Subject: New write_points_to_off_file --- src/python/CMakeLists.txt | 4 +- src/python/doc/installation.rst | 4 +- src/python/doc/point_cloud.rst | 5 ++ src/python/gudhi/off_reader.pyx | 41 -------------- src/python/gudhi/off_utils.pyx | 57 ++++++++++++++++++++ src/python/test/test_subsampling.py | 103 ++++++++---------------------------- 6 files changed, 88 insertions(+), 126 deletions(-) delete mode 100644 src/python/gudhi/off_reader.pyx create mode 100644 src/python/gudhi/off_utils.pyx (limited to 'src') diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index 8f8df138..35ddb778 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -53,7 +53,7 @@ if(PYTHONINTERP_FOUND) set(GUDHI_PYTHON_MODULES_EXTRA "${GUDHI_PYTHON_MODULES_EXTRA}'datasets', ") # Cython modules - set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'off_reader', ") + set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'off_utils', ") set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'simplex_tree', ") set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'rips_complex', ") set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'cubical_complex', ") @@ -152,7 +152,7 @@ if(PYTHONINTERP_FOUND) set(GUDHI_PYTHON_EXTRA_COMPILE_ARGS "${GUDHI_PYTHON_EXTRA_COMPILE_ARGS}'-DCGAL_EIGEN3_ENABLED', ") endif (EIGEN3_FOUND) - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'off_reader', ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'off_utils', ") set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'simplex_tree', ") set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'rips_complex', ") set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'cubical_complex', ") diff --git a/src/python/doc/installation.rst b/src/python/doc/installation.rst index 276ac4e2..5491542f 100644 --- a/src/python/doc/installation.rst +++ b/src/python/doc/installation.rst @@ -150,7 +150,7 @@ You shall have something like: Cython version 0.29.25 Numpy version 1.21.4 Boost version 1.77.0 - + Installed modules are: off_reader;simplex_tree;rips_complex;cubical_complex;periodic_cubical_complex; + + Installed modules are: off_utils;simplex_tree;rips_complex;cubical_complex;periodic_cubical_complex; persistence_graphical_tools;reader_utils;witness_complex;strong_witness_complex; + Missing modules are: bottleneck;nerve_gic;subsampling;tangential_complex;alpha_complex;euclidean_witness_complex; euclidean_strong_witness_complex; @@ -188,7 +188,7 @@ A complete configuration would be : GMPXX_LIBRARIES = /usr/lib/x86_64-linux-gnu/libgmpxx.so MPFR_LIBRARIES = /usr/lib/x86_64-linux-gnu/libmpfr.so TBB version 9107 found and used - + Installed modules are: bottleneck;off_reader;simplex_tree;rips_complex;cubical_complex;periodic_cubical_complex; + + Installed modules are: bottleneck;off_utils;simplex_tree;rips_complex;cubical_complex;periodic_cubical_complex; persistence_graphical_tools;reader_utils;witness_complex;strong_witness_complex;nerve_gic;subsampling; tangential_complex;alpha_complex;euclidean_witness_complex;euclidean_strong_witness_complex; + Missing modules are: diff --git a/src/python/doc/point_cloud.rst b/src/python/doc/point_cloud.rst index ffd8f85b..473b303f 100644 --- a/src/python/doc/point_cloud.rst +++ b/src/python/doc/point_cloud.rst @@ -13,6 +13,11 @@ File Readers .. autofunction:: gudhi.read_lower_triangular_matrix_from_csv_file +File Writers +------------ + +.. autofunction:: gudhi.write_points_to_off_file + Subsampling ----------- diff --git a/src/python/gudhi/off_reader.pyx b/src/python/gudhi/off_reader.pyx deleted file mode 100644 index a3200704..00000000 --- a/src/python/gudhi/off_reader.pyx +++ /dev/null @@ -1,41 +0,0 @@ -# This file is part of the Gudhi Library - https://gudhi.inria.fr/ - -# which is released under MIT. -# See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full -# license details. -# Author(s): Vincent Rouvreau -# -# Copyright (C) 2016 Inria -# -# Modification(s): -# - YYYY/MM Author: Description of the modification - -from __future__ import print_function -from cython cimport numeric -from libcpp.vector cimport vector -from libcpp.string cimport string -import errno -import os - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 Inria" -__license__ = "MIT" - -cdef extern from "Off_reader_interface.h" namespace "Gudhi": - vector[vector[double]] read_points_from_OFF_file(string off_file) - -def read_points_from_off_file(off_file=''): - """Read points from OFF file. - - :param off_file: An OFF file style name. - :type off_file: string - - :returns: The point set. - :rtype: List[List[float]] - """ - if off_file: - if os.path.isfile(off_file): - return read_points_from_OFF_file(off_file.encode('utf-8')) - else: - raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), - off_file) - diff --git a/src/python/gudhi/off_utils.pyx b/src/python/gudhi/off_utils.pyx new file mode 100644 index 00000000..155575d5 --- /dev/null +++ b/src/python/gudhi/off_utils.pyx @@ -0,0 +1,57 @@ +# This file is part of the Gudhi Library - https://gudhi.inria.fr/ - +# which is released under MIT. +# See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full +# license details. +# Author(s): Vincent Rouvreau +# +# Copyright (C) 2016 Inria +# +# Modification(s): +# - YYYY/MM Author: Description of the modification + +from __future__ import print_function +from cython cimport numeric +from libcpp.vector cimport vector +from libcpp.string cimport string +cimport cython +import errno +import os +import numpy as np + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "MIT" + +cdef extern from "Off_reader_interface.h" namespace "Gudhi": + vector[vector[double]] read_points_from_OFF_file(string off_file) + +def read_points_from_off_file(off_file=''): + """Read points from OFF file. + + :param off_file: An OFF file style name. + :type off_file: string + + :returns: The point set. + :rtype: List[List[float]] + """ + if off_file: + if os.path.isfile(off_file): + return read_points_from_OFF_file(off_file.encode('utf-8')) + else: + raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), + off_file) + +@cython.embedsignature(True) +def write_points_to_off_file(fname, points): + """Write points to an OFF file. + + A simple wrapper for `numpy.savetxt`. + + :param fname: Name of the OFF file. + :type fname: str or file handle + :param points: Point coordinates. + :type points: numpy array of shape (n, dim) + """ + points = np.array(points, copy=False) + assert len(points.shape) == 2 + np.savetxt(fname, points, header='nOFF\n{} {} 0 0'.format(points.shape[1], points.shape[0]), comments='') diff --git a/src/python/test/test_subsampling.py b/src/python/test/test_subsampling.py index 3431f372..c1cb4e3f 100755 --- a/src/python/test/test_subsampling.py +++ b/src/python/test/test_subsampling.py @@ -16,17 +16,9 @@ __license__ = "MIT" def test_write_off_file_for_tests(): - file = open("subsample.off", "w") - file.write("nOFF\n") - file.write("2 7 0 0\n") - file.write("1.0 1.0\n") - file.write("7.0 0.0\n") - file.write("4.0 6.0\n") - file.write("9.0 6.0\n") - file.write("0.0 14.0\n") - file.write("2.0 19.0\n") - file.write("9.0 17.0\n") - file.close() + gudhi.write_points_to_off_file( + "subsample.off", [[1.0, 1.0], [7.0, 0.0], [4.0, 6.0], [9.0, 6.0], [0.0, 14.0], [2.0, 19.0], [9.0, 17.0]] + ) def test_simple_choose_n_farthest_points_with_a_starting_point(): @@ -34,54 +26,29 @@ def test_simple_choose_n_farthest_points_with_a_starting_point(): i = 0 for point in point_set: # The iteration starts with the given starting point - sub_set = gudhi.choose_n_farthest_points( - points=point_set, nb_points=1, starting_point=i - ) + sub_set = gudhi.choose_n_farthest_points(points=point_set, nb_points=1, starting_point=i) assert sub_set[0] == point_set[i] i = i + 1 # The iteration finds then the farthest - sub_set = gudhi.choose_n_farthest_points( - points=point_set, nb_points=2, starting_point=1 - ) + sub_set = gudhi.choose_n_farthest_points(points=point_set, nb_points=2, starting_point=1) assert sub_set[1] == point_set[3] - sub_set = gudhi.choose_n_farthest_points( - points=point_set, nb_points=2, starting_point=3 - ) + sub_set = gudhi.choose_n_farthest_points(points=point_set, nb_points=2, starting_point=3) assert sub_set[1] == point_set[1] - sub_set = gudhi.choose_n_farthest_points( - points=point_set, nb_points=2, starting_point=0 - ) + sub_set = gudhi.choose_n_farthest_points(points=point_set, nb_points=2, starting_point=0) assert sub_set[1] == point_set[2] - sub_set = gudhi.choose_n_farthest_points( - points=point_set, nb_points=2, starting_point=2 - ) + sub_set = gudhi.choose_n_farthest_points(points=point_set, nb_points=2, starting_point=2) assert sub_set[1] == point_set[0] # Test the limits - assert ( - gudhi.choose_n_farthest_points(points=[], nb_points=0, starting_point=0) == [] - ) - assert ( - gudhi.choose_n_farthest_points(points=[], nb_points=1, starting_point=0) == [] - ) - assert ( - gudhi.choose_n_farthest_points(points=[], nb_points=0, starting_point=1) == [] - ) - assert ( - gudhi.choose_n_farthest_points(points=[], nb_points=1, starting_point=1) == [] - ) + assert gudhi.choose_n_farthest_points(points=[], nb_points=0, starting_point=0) == [] + assert gudhi.choose_n_farthest_points(points=[], nb_points=1, starting_point=0) == [] + assert gudhi.choose_n_farthest_points(points=[], nb_points=0, starting_point=1) == [] + assert gudhi.choose_n_farthest_points(points=[], nb_points=1, starting_point=1) == [] # From off file test for i in range(0, 7): - assert ( - len( - gudhi.choose_n_farthest_points( - off_file="subsample.off", nb_points=i, starting_point=i - ) - ) - == i - ) + assert len(gudhi.choose_n_farthest_points(off_file="subsample.off", nb_points=i, starting_point=i)) == i def test_simple_choose_n_farthest_points_randomed(): @@ -104,10 +71,7 @@ def test_simple_choose_n_farthest_points_randomed(): # From off file test for i in range(0, 7): - assert ( - len(gudhi.choose_n_farthest_points(off_file="subsample.off", nb_points=i)) - == i - ) + assert len(gudhi.choose_n_farthest_points(off_file="subsample.off", nb_points=i)) == i def test_simple_pick_n_random_points(): @@ -130,9 +94,7 @@ def test_simple_pick_n_random_points(): # From off file test for i in range(0, 7): - assert ( - len(gudhi.pick_n_random_points(off_file="subsample.off", nb_points=i)) == i - ) + assert len(gudhi.pick_n_random_points(off_file="subsample.off", nb_points=i)) == i def test_simple_sparsify_points(): @@ -152,31 +114,10 @@ def test_simple_sparsify_points(): ] assert gudhi.sparsify_point_set(points=point_set, min_squared_dist=2.001) == [[0, 1]] - assert ( - len(gudhi.sparsify_point_set(off_file="subsample.off", min_squared_dist=0.0)) - == 7 - ) - assert ( - len(gudhi.sparsify_point_set(off_file="subsample.off", min_squared_dist=30.0)) - == 5 - ) - assert ( - len(gudhi.sparsify_point_set(off_file="subsample.off", min_squared_dist=40.1)) - == 4 - ) - assert ( - len(gudhi.sparsify_point_set(off_file="subsample.off", min_squared_dist=89.9)) - == 3 - ) - assert ( - len(gudhi.sparsify_point_set(off_file="subsample.off", min_squared_dist=100.0)) - == 2 - ) - assert ( - len(gudhi.sparsify_point_set(off_file="subsample.off", min_squared_dist=324.9)) - == 2 - ) - assert ( - len(gudhi.sparsify_point_set(off_file="subsample.off", min_squared_dist=325.01)) - == 1 - ) + assert len(gudhi.sparsify_point_set(off_file="subsample.off", min_squared_dist=0.0)) == 7 + assert len(gudhi.sparsify_point_set(off_file="subsample.off", min_squared_dist=30.0)) == 5 + assert len(gudhi.sparsify_point_set(off_file="subsample.off", min_squared_dist=40.1)) == 4 + assert len(gudhi.sparsify_point_set(off_file="subsample.off", min_squared_dist=89.9)) == 3 + assert len(gudhi.sparsify_point_set(off_file="subsample.off", min_squared_dist=100.0)) == 2 + assert len(gudhi.sparsify_point_set(off_file="subsample.off", min_squared_dist=324.9)) == 2 + assert len(gudhi.sparsify_point_set(off_file="subsample.off", min_squared_dist=325.01)) == 1 -- cgit v1.2.3 From 4118bcb622c624130e768d9116a7e147a5e45c68 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 11 Nov 2022 18:00:42 +0100 Subject: Link to OFF format --- src/python/gudhi/off_utils.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/python/gudhi/off_utils.pyx b/src/python/gudhi/off_utils.pyx index 155575d5..a8142791 100644 --- a/src/python/gudhi/off_utils.pyx +++ b/src/python/gudhi/off_utils.pyx @@ -26,7 +26,7 @@ cdef extern from "Off_reader_interface.h" namespace "Gudhi": vector[vector[double]] read_points_from_OFF_file(string off_file) def read_points_from_off_file(off_file=''): - """Read points from OFF file. + """Read points from an `OFF file `_. :param off_file: An OFF file style name. :type off_file: string @@ -43,7 +43,7 @@ def read_points_from_off_file(off_file=''): @cython.embedsignature(True) def write_points_to_off_file(fname, points): - """Write points to an OFF file. + """Write points to an `OFF file `_. A simple wrapper for `numpy.savetxt`. -- cgit v1.2.3 From 2d5039b7eeb16116ab859076aa0a93f092250d88 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 11 Nov 2022 18:59:42 +0100 Subject: Special case for writing 3d OFF --- src/python/CMakeLists.txt | 1 + src/python/gudhi/off_utils.pyx | 7 ++++++- src/python/test/test_off.py | 21 +++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/python/test/test_off.py (limited to 'src') diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index 35ddb778..32ec13bd 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -546,6 +546,7 @@ if(PYTHONINTERP_FOUND) # Reader utils add_gudhi_py_test(test_reader_utils) + add_gudhi_py_test(test_off) # Wasserstein if(OT_FOUND) diff --git a/src/python/gudhi/off_utils.pyx b/src/python/gudhi/off_utils.pyx index a8142791..9276c7b0 100644 --- a/src/python/gudhi/off_utils.pyx +++ b/src/python/gudhi/off_utils.pyx @@ -54,4 +54,9 @@ def write_points_to_off_file(fname, points): """ points = np.array(points, copy=False) assert len(points.shape) == 2 - np.savetxt(fname, points, header='nOFF\n{} {} 0 0'.format(points.shape[1], points.shape[0]), comments='') + dim = points.shape[1] + if dim == 3: + head = 'OFF\n{} 0 0'.format(points.shape[0]) + else: + head = 'nOFF\n{} {} 0 0'.format(dim, points.shape[0]) + np.savetxt(fname, points, header=head, comments='') diff --git a/src/python/test/test_off.py b/src/python/test/test_off.py new file mode 100644 index 00000000..69bfa1f9 --- /dev/null +++ b/src/python/test/test_off.py @@ -0,0 +1,21 @@ +""" This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + Author(s): Marc Glisse + + Copyright (C) 2022 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +import gudhi as gd +import numpy as np +import pytest + + +def test_off_rw(): + for dim in range(2, 6): + X = np.random.rand(123, dim) + gd.write_points_to_off_file('rand.off', X) + Y = gd.read_points_from_off_file('rand.off') + assert Y == pytest.approx(X) -- cgit v1.2.3 From f4f930169fbf2db2707d69b334cfe5b941c64350 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 11 Nov 2022 19:03:54 +0100 Subject: black --- src/python/test/test_off.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/python/test/test_off.py b/src/python/test/test_off.py index 69bfa1f9..aea1941b 100644 --- a/src/python/test/test_off.py +++ b/src/python/test/test_off.py @@ -16,6 +16,6 @@ import pytest def test_off_rw(): for dim in range(2, 6): X = np.random.rand(123, dim) - gd.write_points_to_off_file('rand.off', X) - Y = gd.read_points_from_off_file('rand.off') + gd.write_points_to_off_file("rand.off", X) + Y = gd.read_points_from_off_file("rand.off") assert Y == pytest.approx(X) -- cgit v1.2.3 From 1e71120bdacb6f5ec4c90fb4c1365f76ecea7ff9 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Sat, 12 Nov 2022 17:22:07 +0100 Subject: Handle QGLViewer >= 2.7.0 --- src/GudhUI/view/Viewer.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/GudhUI/view/Viewer.cpp b/src/GudhUI/view/Viewer.cpp index 6b17c833..2c00f86f 100644 --- a/src/GudhUI/view/Viewer.cpp +++ b/src/GudhUI/view/Viewer.cpp @@ -31,7 +31,11 @@ void Viewer::set_bounding_box(const Point_3 & lower_left, const Point_3 & upper_ } void Viewer::update_GL() { +#if QGLVIEWER_VERSION >= 0x020700 + this->update(); +#else this->updateGL(); +#endif } void Viewer::init_scene() { -- cgit v1.2.3