summaryrefslogtreecommitdiff
path: root/src/Subsampling
diff options
context:
space:
mode:
Diffstat (limited to 'src/Subsampling')
-rw-r--r--src/Subsampling/example/CMakeLists.txt1
-rw-r--r--src/Subsampling/example/example_custom_kernel.cpp63
-rw-r--r--src/Subsampling/include/gudhi/choose_n_farthest_points.h53
-rw-r--r--src/Subsampling/include/gudhi/pick_n_random_points.h4
-rw-r--r--src/Subsampling/include/gudhi/sparsify_point_set.h2
-rw-r--r--src/Subsampling/test/test_choose_n_farthest_points.cpp55
6 files changed, 162 insertions, 16 deletions
diff --git a/src/Subsampling/example/CMakeLists.txt b/src/Subsampling/example/CMakeLists.txt
index 54349f0c..0fd3335c 100644
--- a/src/Subsampling/example/CMakeLists.txt
+++ b/src/Subsampling/example/CMakeLists.txt
@@ -6,6 +6,7 @@ if(CGAL_FOUND)
if (EIGEN3_FOUND)
add_executable(Subsampling_example_pick_n_random_points example_pick_n_random_points.cpp)
add_executable(Subsampling_example_choose_n_farthest_points example_choose_n_farthest_points.cpp)
+ add_executable(Subsampling_example_custom_kernel example_custom_kernel.cpp)
add_executable(Subsampling_example_sparsify_point_set example_sparsify_point_set.cpp)
target_link_libraries(Subsampling_example_sparsify_point_set ${CGAL_LIBRARY})
diff --git a/src/Subsampling/example/example_custom_kernel.cpp b/src/Subsampling/example/example_custom_kernel.cpp
new file mode 100644
index 00000000..25b5bf6c
--- /dev/null
+++ b/src/Subsampling/example/example_custom_kernel.cpp
@@ -0,0 +1,63 @@
+#include <gudhi/choose_n_farthest_points.h>
+
+#include <CGAL/Epick_d.h>
+#include <CGAL/Random.h>
+
+#include <vector>
+#include <iterator>
+
+
+/* The class Kernel contains a distance function defined on the set of points {0, 1, 2, 3}
+ * and computes a distance according to the matrix:
+ * 0 1 2 4
+ * 1 0 4 2
+ * 2 4 0 1
+ * 4 2 1 0
+ */
+class Kernel {
+ public:
+ typedef double FT;
+ typedef unsigned Point_d;
+
+ // Class Squared_distance_d
+ class Squared_distance_d {
+ private:
+ std::vector<std::vector<FT>> matrix_;
+
+ public:
+ Squared_distance_d() {
+ matrix_.push_back(std::vector<FT>({0, 1, 2, 4}));
+ matrix_.push_back(std::vector<FT>({1, 0, 4, 2}));
+ matrix_.push_back(std::vector<FT>({2, 4, 0, 1}));
+ matrix_.push_back(std::vector<FT>({4, 2, 1, 0}));
+ }
+
+ FT operator()(Point_d p1, Point_d p2) {
+ return matrix_[p1][p2];
+ }
+ };
+
+ // Constructor
+ Kernel() {}
+
+ // Object of type Squared_distance_d
+ Squared_distance_d squared_distance_d_object() const {
+ return Squared_distance_d();
+ }
+};
+
+int main(void) {
+ typedef Kernel K;
+ typedef typename K::Point_d Point_d;
+
+ K k;
+ std::vector<Point_d> points = {0, 1, 2, 3};
+ std::vector<Point_d> results;
+
+ Gudhi::subsampling::choose_n_farthest_points(k, points, 2, std::back_inserter(results));
+ std::cout << "Before sparsification: " << points.size() << " points.\n";
+ std::cout << "After sparsification: " << results.size() << " points.\n";
+ std::cout << "Result table: {" << results[0] << "," << results[1] << "}\n";
+
+ return 0;
+}
diff --git a/src/Subsampling/include/gudhi/choose_n_farthest_points.h b/src/Subsampling/include/gudhi/choose_n_farthest_points.h
index 40c7808d..5e908090 100644
--- a/src/Subsampling/include/gudhi/choose_n_farthest_points.h
+++ b/src/Subsampling/include/gudhi/choose_n_farthest_points.h
@@ -48,22 +48,40 @@ namespace subsampling {
* \brief Subsample by a greedy strategy of iteratively adding the farthest point from the
* current chosen point set to the subsampling.
* The iteration starts with the landmark `starting point`.
+ * \tparam Kernel must provide a type Kernel::Squared_distance_d which is a model of the
+ * concept <a target="_blank"
+ * href="http://doc.cgal.org/latest/Kernel_d/classKernel__d_1_1Squared__distance__d.html">Kernel_d::Squared_distance_d</a>
+ * concept.
+ * It must also contain a public member 'squared_distance_d_object' of this type.
+ * \tparam Point_range Range whose value type is Kernel::Point_d. It must provide random-access
+ * via `operator[]` and the points should be stored contiguously in memory.
+ * \tparam OutputIterator Output iterator whose value type is Kernel::Point_d.
* \details It chooses `final_size` points from a random access range `input_pts` and
* outputs it in the output iterator `output_it`.
+ * @param[in] k A kernel object.
+ * @param[in] input_pts Const reference to the input points.
+ * @param[in] final_size The size of the subsample to compute.
+ * @param[in] starting_point The seed in the farthest point algorithm.
+ * @param[out] output_it The output iterator.
*
*/
template < typename Kernel,
-typename Point_container,
+typename Point_range,
typename OutputIterator>
void choose_n_farthest_points(Kernel const &k,
- Point_container const &input_pts,
+ Point_range const &input_pts,
std::size_t final_size,
std::size_t starting_point,
OutputIterator output_it) {
- typename Kernel::Squared_distance_d sqdist = k.squared_distance_d_object();
-
std::size_t nb_points = boost::size(input_pts);
- assert(nb_points >= final_size);
+ if (final_size > nb_points)
+ final_size = nb_points;
+
+ // Tests to the limit
+ if (final_size < 1)
+ return;
+
+ typename Kernel::Squared_distance_d sqdist = k.squared_distance_d_object();
std::size_t current_number_of_landmarks = 0; // counter for landmarks
const double infty = std::numeric_limits<double>::infinity(); // infinity (see next entry)
@@ -96,22 +114,39 @@ void choose_n_farthest_points(Kernel const &k,
* \brief Subsample by a greedy strategy of iteratively adding the farthest point from the
* current chosen point set to the subsampling.
* The iteration starts with a random landmark.
+ * \tparam Kernel must provide a type Kernel::Squared_distance_d which is a model of the
+ * concept <a target="_blank"
+ * href="http://doc.cgal.org/latest/Kernel_d/classKernel__d_1_1Squared__distance__d.html">Kernel_d::Squared_distance_d</a>
+ * concept.
+ * It must also contain a public member 'squared_distance_d_object' of this type.
+ * \tparam Point_range Range whose value type is Kernel::Point_d. It must provide random-access
+ * via `operator[]` and the points should be stored contiguously in memory.
+ * \tparam OutputIterator Output iterator whose value type is Kernel::Point_d.
* \details It chooses `final_size` points from a random access range `input_pts` and
* outputs it in the output iterator `output_it`.
+ * @param[in] k A kernel object.
+ * @param[in] input_pts Const reference to the input points.
+ * @param[in] final_size The size of the subsample to compute.
+ * @param[out] output_it The output iterator.
*
*/
template < typename Kernel,
-typename Point_container,
+typename Point_range,
typename OutputIterator>
void choose_n_farthest_points(Kernel const& k,
- Point_container const &input_pts,
+ Point_range const &input_pts,
unsigned final_size,
OutputIterator output_it) {
+ // Tests to the limit
+ if ((final_size < 1) || (input_pts.size() == 0))
+ return;
+
// Choose randomly the first landmark
std::random_device rd;
std::mt19937 gen(rd());
- std::uniform_int_distribution<> dis(1, 6);
- int starting_point = dis(gen);
+ std::uniform_int_distribution<> dis(0, (input_pts.size() - 1));
+ std::size_t starting_point = dis(gen);
+
choose_n_farthest_points(k, input_pts, final_size, starting_point, output_it);
}
diff --git a/src/Subsampling/include/gudhi/pick_n_random_points.h b/src/Subsampling/include/gudhi/pick_n_random_points.h
index e89b2b2d..f0e3f1f1 100644
--- a/src/Subsampling/include/gudhi/pick_n_random_points.h
+++ b/src/Subsampling/include/gudhi/pick_n_random_points.h
@@ -57,7 +57,9 @@ void pick_n_random_points(Point_container const &points,
#endif
std::size_t nbP = boost::size(points);
- assert(nbP >= final_size);
+ if (final_size > nbP)
+ final_size = nbP;
+
std::vector<int> landmarks(nbP);
std::iota(landmarks.begin(), landmarks.end(), 0);
diff --git a/src/Subsampling/include/gudhi/sparsify_point_set.h b/src/Subsampling/include/gudhi/sparsify_point_set.h
index 7ff11b4c..507f8c79 100644
--- a/src/Subsampling/include/gudhi/sparsify_point_set.h
+++ b/src/Subsampling/include/gudhi/sparsify_point_set.h
@@ -64,8 +64,6 @@ sparsify_point_set(
typedef typename Gudhi::spatial_searching::Kd_tree_search<
Kernel, Point_range> Points_ds;
- typename Kernel::Squared_distance_d sqdist = k.squared_distance_d_object();
-
#ifdef GUDHI_SUBSAMPLING_PROFILING
Gudhi::Clock t;
#endif
diff --git a/src/Subsampling/test/test_choose_n_farthest_points.cpp b/src/Subsampling/test/test_choose_n_farthest_points.cpp
index d064899a..0bc0dff4 100644
--- a/src/Subsampling/test/test_choose_n_farthest_points.cpp
+++ b/src/Subsampling/test/test_choose_n_farthest_points.cpp
@@ -39,18 +39,65 @@ typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> K;
typedef typename K::FT FT;
typedef typename K::Point_d Point_d;
-BOOST_AUTO_TEST_CASE(test_choose_farthest_point) {
+typedef boost::mpl::list<CGAL::Epick_d<CGAL::Dynamic_dimension_tag>, CGAL::Epick_d<CGAL::Dimension_tag<4>>> list_of_tested_kernels;
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(test_choose_farthest_point, Kernel, list_of_tested_kernels) {
+ typedef typename Kernel::FT FT;
+ typedef typename Kernel::Point_d Point_d;
std::vector< Point_d > points, landmarks;
// Add grid points (625 points)
for (FT i = 0; i < 5; i += 1.0)
for (FT j = 0; j < 5; j += 1.0)
for (FT k = 0; k < 5; k += 1.0)
- for (FT l = 0; l < 5; l += 1.0)
- points.push_back(Point_d(std::vector<FT>({i, j, k, l})));
+ for (FT l = 0; l < 5; l += 1.0) {
+ std::vector<FT> point({i, j, k, l});
+ points.push_back(Point_d(point.begin(), point.end()));
+ }
landmarks.clear();
- K k;
+ Kernel k;
Gudhi::subsampling::choose_n_farthest_points(k, points, 100, std::back_inserter(landmarks));
BOOST_CHECK(landmarks.size() == 100);
+ for (auto landmark : landmarks)
+ {
+ // Check all landmarks are in points
+ BOOST_CHECK(std::find (points.begin(), points.end(), landmark) != points.end());
+ }
+}
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(test_choose_farthest_point_limits, Kernel, list_of_tested_kernels) {
+ typedef typename Kernel::FT FT;
+ typedef typename Kernel::Point_d Point_d;
+ std::vector< Point_d > points, landmarks;
+ landmarks.clear();
+ Kernel k;
+ // Choose -1 farthest points in an empty point cloud
+ Gudhi::subsampling::choose_n_farthest_points(k, points, -1, std::back_inserter(landmarks));
+ BOOST_CHECK(landmarks.size() == 0);
+ landmarks.clear();
+ // Choose 0 farthest points in an empty point cloud
+ Gudhi::subsampling::choose_n_farthest_points(k, points, 0, std::back_inserter(landmarks));
+ BOOST_CHECK(landmarks.size() == 0);
+ landmarks.clear();
+ // Choose 1 farthest points in an empty point cloud
+ Gudhi::subsampling::choose_n_farthest_points(k, points, 1, std::back_inserter(landmarks));
+ BOOST_CHECK(landmarks.size() == 0);
+ landmarks.clear();
+
+ std::vector<FT> point({0.0, 0.0, 0.0, 0.0});
+ points.push_back(Point_d(point.begin(), point.end()));
+ // Choose -1 farthest points in an empty point cloud
+ Gudhi::subsampling::choose_n_farthest_points(k, points, -1, std::back_inserter(landmarks));
+ BOOST_CHECK(landmarks.size() == 1);
+ landmarks.clear();
+ // Choose 0 farthest points in a one point cloud
+ Gudhi::subsampling::choose_n_farthest_points(k, points, 0, std::back_inserter(landmarks));
+ BOOST_CHECK(landmarks.size() == 0);
+ landmarks.clear();
+ // Choose 1 farthest points in a one point cloud
+ Gudhi::subsampling::choose_n_farthest_points(k, points, 1, std::back_inserter(landmarks));
+ BOOST_CHECK(landmarks.size() == 1);
+ landmarks.clear();
+
}