summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorROUVREAU Vincent <vincent.rouvreau@inria.fr>2020-03-19 10:19:07 +0100
committerROUVREAU Vincent <vincent.rouvreau@inria.fr>2020-03-19 10:19:07 +0100
commit0dbb5fd9a2096ba830c77954429ab49202228728 (patch)
tree580ae894e739a4df59deb0108ed954e99d03a6c8
parent4010a8da315d500e023d8a1f5b70a9eab3da629c (diff)
Add utilities
-rw-r--r--src/Collapse/utilities/CMakeLists.txt21
-rw-r--r--src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp181
-rw-r--r--src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp192
3 files changed, 394 insertions, 0 deletions
diff --git a/src/Collapse/utilities/CMakeLists.txt b/src/Collapse/utilities/CMakeLists.txt
new file mode 100644
index 00000000..bc241bf2
--- /dev/null
+++ b/src/Collapse/utilities/CMakeLists.txt
@@ -0,0 +1,21 @@
+project(Collapse_utilities)
+
+# From a point cloud
+add_executable ( point_cloud_edge_collapse_rips_persistence point_cloud_edge_collapse_rips_persistence.cpp )
+target_link_libraries(point_cloud_edge_collapse_rips_persistence Boost::program_options)
+
+if (TBB_FOUND)
+ target_link_libraries(point_cloud_edge_collapse_rips_persistence ${TBB_LIBRARIES})
+endif()
+add_test(NAME point_cloud_edge_collapse_rips_persistence COMMAND $<TARGET_FILE:point_cloud_edge_collapse_rips_persistence>
+ "-i" "${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off" "-e" "1e40" "-o" "result.pers")
+
+# From a distance matrix
+add_executable ( distance_matrix_edge_collapse_rips_persistence distance_matrix_edge_collapse_rips_persistence.cpp )
+target_link_libraries(distance_matrix_edge_collapse_rips_persistence Boost::program_options)
+
+if (TBB_FOUND)
+ target_link_libraries(distance_matrix_edge_collapse_rips_persistence ${TBB_LIBRARIES})
+endif()
+#add_test(NAME distance_matrix_edge_collapse_rips_persistence COMMAND $<TARGET_FILE:distance_matrix_edge_collapse_rips_persistence>
+# "-m" "f" "-i" "${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off" "-e" "1e40")
diff --git a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp
new file mode 100644
index 00000000..a2bc1c93
--- /dev/null
+++ b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp
@@ -0,0 +1,181 @@
+#include <gudhi/FlagComplexSpMatrix.h>
+#include <gudhi/Rips_complex.h>
+#include <gudhi/Simplex_tree.h>
+#include <gudhi/Persistent_cohomology.h>
+#include <gudhi/Rips_edge_list.h>
+#include <gudhi/distance_functions.h>
+#include <gudhi/reader_utils.h>
+#include <gudhi/Points_off_io.h>
+
+#include <CGAL/Epick_d.h>
+
+#include <boost/program_options.hpp>
+
+// Types definition
+using Point = CGAL::Epick_d<CGAL::Dynamic_dimension_tag>::Point_d;
+using Vector_of_points = std::vector<Point>;
+
+using Simplex_tree = Gudhi::Simplex_tree<Gudhi::Simplex_tree_options_fast_persistence>;
+using Filtration_value = double;
+using Rips_complex = Gudhi::rips_complex::Rips_complex<Filtration_value>;
+using Rips_edge_list = Gudhi::rips_edge_list::Rips_edge_list<Filtration_value>;
+using Field_Zp = Gudhi::persistent_cohomology::Field_Zp;
+using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology<Simplex_tree, Field_Zp>;
+using Distance_matrix = std::vector<std::vector<Filtration_value>>;
+
+void program_options(int argc, char* const argv[], double& min_persistence, double& end_thresold,
+ int& dimension, int& dim_max, std::string& in_file_name, std::string& out_file_name) {
+ namespace po = boost::program_options;
+ po::options_description visible("Allowed options", 100);
+ visible.add_options()
+ ("help,h", "produce help message")
+ ("min_persistence,m", po::value<double>(&min_persistence)->default_value(0.1),
+ "Minimum persistence interval length")
+ ("end_thresold,e", po::value<double>(&end_thresold)->default_value(1),
+ "Final threshold for rips complex.")
+ ("dimensions,D", po::value<int>(&dimension)->default_value(2),
+ "Dimension of the manifold.")
+ ("dim_max,k ", po::value<int>(&dim_max)->default_value(2),
+ "Maximum allowed dimension of the Rips complex.")
+ ("input_file_name,i", po::value<std::string>(&in_file_name),
+ "The input file.")
+ ("out_file_name,o", po::value<std::string>(&out_file_name),
+ "The output file.");
+
+ po::options_description all;
+ all.add(visible);
+ po::variables_map vm;
+ po::store(po::command_line_parser(argc, argv).options(all).run(), vm);
+ po::notify(vm);
+ if (vm.count("help")) {
+ std::cout << std::endl;
+ std::cout << "Computes rips complexes of different threshold values, to 'end_thresold' from a n random uniform "
+ "point_vector on a selected manifold, . \n";
+ std::cout << "Strongly collapses all the rips complexes and output the results in out_file. \n";
+ std::cout << "The experiments are repeted 'repete' num of times for each threshold value. \n";
+ std::cout << "type -m for manifold options, 's' for uni sphere, 'b' for unit ball, 'f' for file. \n";
+ std::cout << "type -i 'filename' for Input file option for exported point sample. \n";
+ std::cout << std::endl << std::endl;
+ std::cout << "Usage: " << argv[0] << " [options]" << std::endl << std::endl;
+ std::cout << visible << std::endl;
+ std::abort();
+ }
+}
+
+class filt_edge_to_dist_matrix {
+ public:
+ template <class Distance_matrix, class Filtered_sorted_edge_list>
+ filt_edge_to_dist_matrix(Distance_matrix& distance_mat, Filtered_sorted_edge_list& edge_filt,
+ std::size_t number_of_points) {
+ double inf = std::numeric_limits<double>::max();
+ doubleVector distances;
+ std::pair<std::size_t, std::size_t> e;
+ for (std::size_t indx = 0; indx < number_of_points; indx++) {
+ for (std::size_t j = 0; j <= indx; j++) {
+ if (j == indx)
+ distances.push_back(0);
+ else
+ distances.push_back(inf);
+ }
+ distance_mat.push_back(distances);
+ distances.clear();
+ }
+
+ for (auto edIt = edge_filt.begin(); edIt != edge_filt.end(); edIt++) {
+ e = std::minmax(std::get<1>(*edIt), std::get<2>(*edIt));
+ distance_mat.at(std::get<1>(e)).at(std::get<0>(e)) = std::get<0>(*edIt);
+ }
+ }
+};
+
+int main(int argc, char* const argv[]) {
+ auto the_begin = std::chrono::high_resolution_clock::now();
+ std::string out_file_name;
+ std::string in_file_name;
+ std::size_t number_of_points;
+
+ typedef size_t Vertex_handle;
+ typedef std::vector<std::tuple<Filtration_value, Vertex_handle, Vertex_handle>> Filtered_sorted_edge_list;
+
+ int dimension;
+ double end_threshold;
+ double min_persistence;
+ int dim_max = 2;
+
+ program_options(argc, argv, min_persistence, end_threshold, dimension, dim_max, in_file_name,
+ out_file_name);
+
+ std::cout << "The current input values to run the program is: " << std::endl;
+ std::cout << "min_persistence, end_threshold, dimension, max_complex_dimension, in_file_name, out_file_name"
+ << std::endl;
+ std::cout << min_persistence << ", " << end_threshold << ", " << dimension << ", " << dim_max
+ << ", " << in_file_name << ", " << out_file_name << std::endl;
+
+ Map map_empty;
+
+ Distance_matrix distances;
+ Distance_matrix sparse_distances;
+
+ distances = Gudhi::read_lower_triangular_matrix_from_csv_file<Filtration_value>(in_file_name);
+ number_of_points = distances.size();
+ std::cout << "Read the distance matrix succesfully, of size: " << number_of_points << std::endl;
+
+
+ std::cout << "Successfully read " << number_of_points << " point_vector.\n";
+
+ std::cout << "Point Set Generated." << std::endl;
+
+ Filtered_sorted_edge_list edge_t;
+ std::cout << "Computing the one-skeleton for threshold: " << end_threshold << std::endl;
+
+ Rips_edge_list Rips_edge_list_from_file(distances, end_threshold);
+ Rips_edge_list_from_file.create_edges(edge_t);
+ std::cout<< "Sorted edge list computed" << std::endl;
+ std::cout << "Total number of edges before collapse are: " << edge_t.size() << std::endl;
+
+ if (edge_t.size() <= 0) {
+ std::cerr << "Total number of egdes are zero." << std::endl;
+ exit(-1);
+ }
+
+ // Now we will perform filtered edge collapse to sparsify the edge list edge_t.
+ std::cout << "Filtered edge collapse begins" << std::endl;
+ FlagComplexSpMatrix mat_filt_edge_coll(number_of_points, edge_t);
+ std::cout << "Matrix instansiated" << std::endl;
+ Filtered_sorted_edge_list collapse_edges;
+ collapse_edges = mat_filt_edge_coll.filtered_edge_collapse();
+ filt_edge_to_dist_matrix(sparse_distances, collapse_edges, number_of_points);
+ std::cout << "Total number of vertices after collapse in the sparse matrix are: " << mat_filt_edge_coll.num_vertices()
+ << std::endl;
+
+ Rips_complex rips_complex_after_collapse(sparse_distances, end_threshold);
+
+ Simplex_tree stree;
+ rips_complex_after_collapse.create_complex(stree, dim_max);
+
+ std::cout << "The complex contains " << stree.num_simplices() << " simplices after collapse. \n";
+ std::cout << " and has dimension " << stree.dimension() << " \n";
+
+ // Sort the simplices in the order of the filtration
+ stree.initialize_filtration();
+ // Compute the persistence diagram of the complex
+ Persistent_cohomology pcoh(stree);
+ // initializes the coefficient field for homology
+ pcoh.init_coefficients(3);
+
+ pcoh.compute_persistent_cohomology(min_persistence);
+ if (out_file_name.empty()) {
+ pcoh.output_diagram();
+ } else {
+ std::ofstream out(out_file_name);
+ pcoh.output_diagram(out);
+ out.close();
+ }
+
+ auto the_end = std::chrono::high_resolution_clock::now();
+
+ std::cout << "Total computation time : " << std::chrono::duration<double, std::milli>(the_end - the_begin).count()
+ << " ms\n"
+ << std::endl;
+ return 0;
+}
diff --git a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp
new file mode 100644
index 00000000..abd4e862
--- /dev/null
+++ b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp
@@ -0,0 +1,192 @@
+#include <gudhi/FlagComplexSpMatrix.h>
+#include <gudhi/Rips_complex.h>
+#include <gudhi/Simplex_tree.h>
+#include <gudhi/Persistent_cohomology.h>
+#include <gudhi/Rips_edge_list.h>
+#include <gudhi/distance_functions.h>
+#include <gudhi/reader_utils.h>
+#include <gudhi/Points_off_io.h>
+
+#include <CGAL/Epick_d.h>
+
+#include <boost/program_options.hpp>
+
+// Types definition
+using Point = CGAL::Epick_d<CGAL::Dynamic_dimension_tag>::Point_d;
+using Vector_of_points = std::vector<Point>;
+
+using Simplex_tree = Gudhi::Simplex_tree<Gudhi::Simplex_tree_options_fast_persistence>;
+using Filtration_value = double;
+using Rips_complex = Gudhi::rips_complex::Rips_complex<Filtration_value>;
+using Rips_edge_list = Gudhi::rips_edge_list::Rips_edge_list<Filtration_value>;
+using Field_Zp = Gudhi::persistent_cohomology::Field_Zp;
+using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology<Simplex_tree, Field_Zp>;
+using Distance_matrix = std::vector<std::vector<Filtration_value>>;
+
+void program_options(int argc, char* const argv[], double& min_persistence, double& end_thresold,
+ int& dimension, int& dim_max, std::string& in_file_name, std::string& out_file_name) {
+ namespace po = boost::program_options;
+ po::options_description visible("Allowed options", 100);
+ visible.add_options()
+ ("help,h", "produce help message")
+ ("min_persistence,m", po::value<double>(&min_persistence)->default_value(0.1),
+ "Minimum persistence interval length")
+ ("end_thresold,e", po::value<double>(&end_thresold)->default_value(1),
+ "Final threshold for rips complex.")
+ ("dimensions,D", po::value<int>(&dimension)->default_value(2),
+ "Dimension of the manifold.")
+ ("dim_max,k ", po::value<int>(&dim_max)->default_value(2),
+ "Maximum allowed dimension of the Rips complex.")
+ ("input_file_name,i", po::value<std::string>(&in_file_name),
+ "The input file.")
+ ("out_file_name,o", po::value<std::string>(&out_file_name),
+ "The output file.");
+
+ po::options_description all;
+ all.add(visible);
+ po::variables_map vm;
+ po::store(po::command_line_parser(argc, argv).options(all).run(), vm);
+ po::notify(vm);
+ if (vm.count("help")) {
+ std::cout << std::endl;
+ std::cout << "Computes rips complexes of different threshold values, to 'end_thresold' from a n random uniform "
+ "point_vector on a selected manifold, . \n";
+ std::cout << "Strongly collapses all the rips complexes and output the results in out_file. \n";
+ std::cout << "The experiments are repeted 'repete' num of times for each threshold value. \n";
+ std::cout << "type -m for manifold options, 's' for uni sphere, 'b' for unit ball, 'f' for file. \n";
+ std::cout << "type -i 'filename' for Input file option for exported point sample. \n";
+ std::cout << std::endl << std::endl;
+ std::cout << "Usage: " << argv[0] << " [options]" << std::endl << std::endl;
+ std::cout << visible << std::endl;
+ std::abort();
+ }
+}
+
+class filt_edge_to_dist_matrix {
+ public:
+ template <class Distance_matrix, class Filtered_sorted_edge_list>
+ filt_edge_to_dist_matrix(Distance_matrix& distance_mat, Filtered_sorted_edge_list& edge_filt,
+ std::size_t number_of_points) {
+ double inf = std::numeric_limits<double>::max();
+ doubleVector distances;
+ std::pair<std::size_t, std::size_t> e;
+ for (std::size_t indx = 0; indx < number_of_points; indx++) {
+ for (std::size_t j = 0; j <= indx; j++) {
+ if (j == indx)
+ distances.push_back(0);
+ else
+ distances.push_back(inf);
+ }
+ distance_mat.push_back(distances);
+ distances.clear();
+ }
+
+ for (auto edIt = edge_filt.begin(); edIt != edge_filt.end(); edIt++) {
+ e = std::minmax(std::get<1>(*edIt), std::get<2>(*edIt));
+ distance_mat.at(std::get<1>(e)).at(std::get<0>(e)) = std::get<0>(*edIt);
+ }
+ }
+};
+
+int main(int argc, char* const argv[]) {
+ auto the_begin = std::chrono::high_resolution_clock::now();
+ std::string out_file_name;
+ std::string in_file_name;
+ std::size_t number_of_points;
+
+ typedef size_t Vertex_handle;
+ typedef std::vector<std::tuple<Filtration_value, Vertex_handle, Vertex_handle>> Filtered_sorted_edge_list;
+
+ int dimension;
+ double end_threshold;
+ double min_persistence;
+ int dim_max = 2;
+
+ program_options(argc, argv, min_persistence, end_threshold, dimension, dim_max, in_file_name,
+ out_file_name);
+
+ std::cout << "The current input values to run the program is: " << std::endl;
+ std::cout << "min_persistence, end_threshold, dimension, max_complex_dimension, in_file_name, out_file_name"
+ << std::endl;
+ std::cout << min_persistence << ", " << end_threshold << ", " << dimension << ", " << dim_max
+ << ", " << in_file_name << ", " << out_file_name << std::endl;
+
+ Map map_empty;
+
+ Distance_matrix distances;
+ Distance_matrix sparse_distances;
+
+ Gudhi::Points_off_reader<Point> off_reader(in_file_name);
+ if (!off_reader.is_valid()) {
+ std::cerr << "Unable to read file " << in_file_name << "\n";
+ exit(-1); // ----- >>
+ }
+
+ Vector_of_points point_vector = off_reader.get_point_cloud();
+ if (point_vector.size() <= 0) {
+ std::cerr << "Empty point cloud." << std::endl;
+ exit(-1); // ----- >>
+ }
+
+ dimension = point_vector[0].dimension();
+ number_of_points = point_vector.size();
+ std::cout << "Successfully read " << number_of_points << " point_vector.\n";
+ std::cout << "Ambient dimension is " << dimension << ".\n";
+
+ std::cout << "Point Set Generated." << std::endl;
+
+ Filtered_sorted_edge_list edge_t;
+ std::cout << "Computing the one-skeleton for threshold: " << end_threshold << std::endl;
+
+ Rips_edge_list Rips_edge_list_from_file(point_vector, end_threshold, Gudhi::Euclidean_distance());
+ Rips_edge_list_from_file.create_edges(edge_t);
+ std::cout << "Sorted edge list computed" << std::endl;
+ std::cout << "Total number of edges before collapse are: " << edge_t.size() << std::endl;
+
+ if (edge_t.size() <= 0) {
+ std::cerr << "Total number of egdes are zero." << std::endl;
+ exit(-1);
+ }
+
+ // Now we will perform filtered edge collapse to sparsify the edge list edge_t.
+ std::cout << "Filtered edge collapse begins" << std::endl;
+ FlagComplexSpMatrix mat_filt_edge_coll(number_of_points, edge_t);
+ std::cout << "Matrix instansiated" << std::endl;
+ Filtered_sorted_edge_list collapse_edges;
+ collapse_edges = mat_filt_edge_coll.filtered_edge_collapse();
+ filt_edge_to_dist_matrix(sparse_distances, collapse_edges, number_of_points);
+ std::cout << "Total number of vertices after collapse in the sparse matrix are: " << mat_filt_edge_coll.num_vertices()
+ << std::endl;
+
+ // Rips_complex rips_complex_before_collapse(distances, end_threshold);
+ Rips_complex rips_complex_after_collapse(sparse_distances, end_threshold);
+
+ Simplex_tree stree;
+ rips_complex_after_collapse.create_complex(stree, dim_max);
+
+ std::cout << "The complex contains " << stree.num_simplices() << " simplices after collapse. \n";
+ std::cout << " and has dimension " << stree.dimension() << " \n";
+
+ // Sort the simplices in the order of the filtration
+ stree.initialize_filtration();
+ // Compute the persistence diagram of the complex
+ Persistent_cohomology pcoh(stree);
+ // initializes the coefficient field for homology
+ pcoh.init_coefficients(3);
+
+ pcoh.compute_persistent_cohomology(min_persistence);
+ if (out_file_name.empty()) {
+ pcoh.output_diagram();
+ } else {
+ std::ofstream out(out_file_name);
+ pcoh.output_diagram(out);
+ out.close();
+ }
+
+ auto the_end = std::chrono::high_resolution_clock::now();
+
+ std::cout << "Total computation time : " << std::chrono::duration<double, std::milli>(the_end - the_begin).count()
+ << " ms\n"
+ << std::endl;
+ return 0;
+}