summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Witness_complex/example/CMakeLists.txt8
-rw-r--r--src/Witness_complex/example/Landmark_choice_random_knn.h142
-rw-r--r--src/Witness_complex/example/Landmark_choice_sparsification.h230
-rw-r--r--src/Witness_complex/example/a0_persistence.cpp632
-rw-r--r--src/Witness_complex/example/bench_rwit.cpp616
-rw-r--r--src/Witness_complex/example/color-picker.cpp37
-rw-r--r--src/Witness_complex/example/generators.h8
-rw-r--r--src/Witness_complex/example/off_writer.h11
-rw-r--r--src/Witness_complex/example/output.h305
-rw-r--r--src/Witness_complex/example/output_tikz.h178
-rw-r--r--src/Witness_complex/example/relaxed_delaunay.cpp180
-rw-r--r--src/Witness_complex/example/relaxed_witness_complex_sphere.cpp461
-rw-r--r--src/Witness_complex/example/relaxed_witness_persistence.cpp122
-rw-r--r--src/Witness_complex/example/strange_sphere.cpp219
-rw-r--r--src/Witness_complex/include/gudhi/A0_complex.h337
-rw-r--r--src/Witness_complex/include/gudhi/Dim_list_iterator.h155
-rw-r--r--src/Witness_complex/include/gudhi/Dim_lists.h195
-rw-r--r--src/Witness_complex/include/gudhi/Good_links.h72
-rw-r--r--src/Witness_complex/include/gudhi/Relaxed_witness_complex.h131
-rw-r--r--src/Witness_complex/include/gudhi/Strange_witness_complex.h232
-rw-r--r--src/Witness_complex/include/gudhi/Strong_relaxed_witness_complex.h337
-rw-r--r--src/Witness_complex/include/gudhi/Weak_relaxed_witness_complex.h379
22 files changed, 4907 insertions, 80 deletions
diff --git a/src/Witness_complex/example/CMakeLists.txt b/src/Witness_complex/example/CMakeLists.txt
index 9b874261..80396392 100644
--- a/src/Witness_complex/example/CMakeLists.txt
+++ b/src/Witness_complex/example/CMakeLists.txt
@@ -38,6 +38,14 @@ if(CGAL_FOUND)
add_executable ( relaxed_witness_persistence relaxed_witness_persistence.cpp )
target_link_libraries(relaxed_witness_persistence ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY})
add_test( relaxed_witness_persistence_10 ${CMAKE_CURRENT_BINARY_DIR}/relaxed_witness_persistence 10)
+ add_executable ( a0_persistence a0_persistence.cpp )
+ target_link_libraries(a0_persistence ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY})
+ add_test( a0_persistence_10 ${CMAKE_CURRENT_BINARY_DIR}/a0_persistence 10)
+ add_executable ( bench_rwit bench_rwit.cpp )
+
+ add_executable ( relaxed_delaunay relaxed_delaunay.cpp )
+ target_link_libraries(relaxed_delaunay ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY})
+ add_test( relaxed_delaunay_10 ${CMAKE_CURRENT_BINARY_DIR}/relaxed_delaunay 10)
else()
message(WARNING "Eigen3 not found. Version 3.1.0 is required for witness_complex_sphere example.")
endif()
diff --git a/src/Witness_complex/example/Landmark_choice_random_knn.h b/src/Witness_complex/example/Landmark_choice_random_knn.h
new file mode 100644
index 00000000..3797b4c5
--- /dev/null
+++ b/src/Witness_complex/example/Landmark_choice_random_knn.h
@@ -0,0 +1,142 @@
+/* This file is part of the Gudhi Library. The Gudhi library
+ * (Geometric Understanding in Higher Dimensions) is a generic C++
+ * library for computational topology.
+ *
+ * Author(s): Siargey Kachanovich
+ *
+ * Copyright (C) 2015 INRIA Sophia Antipolis-Méditerranée (France)
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LANDMARK_CHOICE_BY_RANDOM_KNN_H_
+#define LANDMARK_CHOICE_BY_RANDOM_KNN_H_
+
+#include <utility> // for pair<>
+#include <vector>
+#include <cstddef> // for ptrdiff_t type
+
+//#include <CGAL/Cartesian_d.h>
+#include <CGAL/Search_traits.h>
+#include <CGAL/Search_traits_adapter.h>
+//#include <CGAL/property_map.h>
+#include <CGAL/Epick_d.h>
+#include <CGAL/Orthogonal_incremental_neighbor_search.h>
+#include <CGAL/Orthogonal_k_neighbor_search.h>
+#include <CGAL/Kd_tree.h>
+#include <CGAL/Euclidean_distance.h>
+//#include <CGAL/Kernel_d/Vector_d.h>
+#include <CGAL/Random.h>
+
+
+namespace Gudhi {
+
+namespace witness_complex {
+
+typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> K;
+typedef K::FT FT;
+typedef K::Point_d Point_d;
+typedef CGAL::Search_traits< FT,
+ Point_d,
+ typename K::Cartesian_const_iterator_d,
+ typename K::Construct_cartesian_const_iterator_d > Traits_base;
+typedef CGAL::Euclidean_distance<Traits_base> Euclidean_distance;
+typedef CGAL::Search_traits_adapter< std::ptrdiff_t,
+ Point_d*,
+ Traits_base> STraits;
+typedef CGAL::Distance_adapter< std::ptrdiff_t,
+ Point_d*,
+ Euclidean_distance > Distance_adapter;
+typedef CGAL::Orthogonal_incremental_neighbor_search< STraits,
+ Distance_adapter > Neighbor_search;
+ typedef CGAL::Orthogonal_k_neighbor_search< STraits > Neighbor_search2;
+typedef Neighbor_search::Tree Tree;
+
+
+ /** \brief Landmark choice strategy by taking random vertices for landmarks.
+ * \details It chooses nbL distinct landmarks from a random access range `points`
+ * and outputs a matrix {witness}*{closest landmarks} in knn.
+ */
+ template <typename KNearestNeighbours,
+ typename Point_random_access_range,
+ typename Distance_matrix>
+ void landmark_choice_by_random_knn(Point_random_access_range const & points,
+ int nbL,
+ FT alpha,
+ unsigned limD,
+ KNearestNeighbours & knn,
+ Distance_matrix & distances) {
+ int nbP = points.end() - points.begin();
+ assert(nbP >= nbL);
+ std::vector<Point_d> landmarks;
+ std::vector<int> landmarks_ind;
+ Point_d p;
+ int chosen_landmark;
+ CGAL::Random rand;
+ // TODO(SK) Consider using rand_r(...) instead of rand(...) for improved thread safety
+ int current_number_of_landmarks = 0; // counter for landmarks
+ for (; current_number_of_landmarks != nbL; current_number_of_landmarks++) {
+ do chosen_landmark = rand.get_int(0,nbP);
+ while (std::find(landmarks_ind.begin(), landmarks_ind.end(), chosen_landmark) != landmarks_ind.end());
+ p = points[chosen_landmark];
+ landmarks.push_back(p);
+ landmarks_ind.push_back(chosen_landmark);
+ }
+ // std::cout << "Choice finished!" << std::endl;
+
+ //int dim = points.begin()->size();
+ knn = KNearestNeighbours(nbP);
+ distances = Distance_matrix(nbP);
+ STraits traits(&(landmarks[0]));
+ CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance> adapter(&(landmarks[0]));
+ Euclidean_distance ed;
+ Tree landmark_tree(boost::counting_iterator<std::ptrdiff_t>(0),
+ boost::counting_iterator<std::ptrdiff_t>(nbL),
+ typename Tree::Splitter(),
+ traits);
+ for (int points_i = 0; points_i < nbP; points_i++) {
+ Point_d const & w = points[points_i];
+ Neighbor_search search(landmark_tree,
+ w,
+ FT(0),
+ true,
+ adapter);
+ Neighbor_search::iterator search_it = search.begin();
+ // Neighbor_search2 search(landmark_tree,
+ // w, limD+1,
+ // FT(0),
+ // true,
+ // adapter);
+ // Neighbor_search2::iterator search_it = search.begin();
+
+ while (knn[points_i].size() < limD) {
+ distances[points_i].push_back(sqrt(search_it->second));
+ knn[points_i].push_back((search_it++)->first);
+ }
+ FT dtow = distances[points_i][limD-1];
+
+ if (alpha != 0)
+ while (search_it != search.end() && search_it->second < dtow + alpha) {
+ distances[points_i].push_back(sqrt(search_it->second));
+ knn[points_i].push_back((search_it++)->first);
+ }
+ std::cout << "k = " << knn[points_i].size() << std::endl;
+ }
+ }
+
+} // namespace witness_complex
+
+} // namespace Gudhi
+
+#endif // LANDMARK_CHOICE_BY_RANDOM_POINT_H_
diff --git a/src/Witness_complex/example/Landmark_choice_sparsification.h b/src/Witness_complex/example/Landmark_choice_sparsification.h
new file mode 100644
index 00000000..1052b0c4
--- /dev/null
+++ b/src/Witness_complex/example/Landmark_choice_sparsification.h
@@ -0,0 +1,230 @@
+/* This file is part of the Gudhi Library. The Gudhi library
+ * (Geometric Understanding in Higher Dimensions) is a generic C++
+ * library for computational topology.
+ *
+ * Author(s): Siargey Kachanovich
+ *
+ * Copyright (C) 2015 INRIA Sophia Antipolis-Méditerranée (France)
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LANDMARK_CHOICE_BY_SPARSIFICATION_H_
+#define LANDMARK_CHOICE_BY_SPARSIFICATION_H_
+
+#include <utility> // for pair<>
+#include <vector>
+#include <cstddef> // for ptrdiff_t type
+#include <algorithm>
+
+//#include <CGAL/Cartesian_d.h>
+#include <CGAL/Search_traits.h>
+#include <CGAL/Search_traits_adapter.h>
+//#include <CGAL/property_map.h>
+#include <CGAL/Epick_d.h>
+#include <CGAL/Orthogonal_incremental_neighbor_search.h>
+#include <CGAL/Orthogonal_k_neighbor_search.h>
+#include <CGAL/Kd_tree.h>
+#include <CGAL/Euclidean_distance.h>
+//#include <CGAL/Kernel_d/Vector_d.h>
+#include <CGAL/Random.h>
+#include <CGAL/Fuzzy_sphere.h>
+
+namespace Gudhi {
+
+namespace witness_complex {
+
+ typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> K;
+ typedef K::FT FT;
+ typedef K::Point_d Point_d;
+ typedef CGAL::Search_traits< FT,
+ Point_d,
+ typename K::Cartesian_const_iterator_d,
+ typename K::Construct_cartesian_const_iterator_d > Traits_base;
+ typedef CGAL::Euclidean_distance<Traits_base> Euclidean_distance;
+ typedef CGAL::Search_traits_adapter< std::ptrdiff_t,
+ Point_d*,
+ Traits_base> STraits;
+ typedef CGAL::Distance_adapter< std::ptrdiff_t,
+ Point_d*,
+ Euclidean_distance > Distance_adapter;
+ typedef CGAL::Orthogonal_incremental_neighbor_search< STraits,
+ Distance_adapter > Neighbor_search;
+ typedef CGAL::Orthogonal_k_neighbor_search< STraits > Neighbor_search2;
+ typedef Neighbor_search::Tree Tree;
+ typedef CGAL::Fuzzy_sphere<STraits> Fuzzy_sphere;
+
+ /** \brief Landmark selection function by as a sub-epsilon-net of the
+ * given set of points.
+ */
+ template <typename Point_random_access_range>
+ void landmark_choice_by_sparsification(Point_random_access_range & points,
+ unsigned nbL,
+ FT mu_epsilon,
+ Point_random_access_range & landmarks)
+ {
+ int nbP = points.end() - points.begin();
+ assert(nbP >= nbL);
+ CGAL::Random rand;
+ // TODO(SK) Consider using rand_r(...) instead of rand(...) for improved thread safety
+ STraits points_traits(&(points[0]));
+ CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance> points_adapter(&(points[0]));
+ std::vector<bool> dropped_points(nbP, false);
+
+ Tree witness_tree(boost::counting_iterator<std::ptrdiff_t>(0),
+ boost::counting_iterator<std::ptrdiff_t>(nbP),
+ typename Tree::Splitter(),
+ points_traits);
+
+ for (int points_i = 0; points_i < nbP; points_i++) {
+ if (dropped_points[points_i])
+ continue;
+ Point_d & w = points[points_i];
+ Fuzzy_sphere fs(w, mu_epsilon, 0, points_traits);
+ std::vector<int> close_neighbors;
+ witness_tree.search(std::insert_iterator<std::vector<int>>(close_neighbors,close_neighbors.begin()),fs);
+ for (int i: close_neighbors)
+ dropped_points[i] = true;
+ }
+
+ for (int points_i = 0; points_i < nbP; points_i++) {
+ if (dropped_points[points_i])
+ landmarks.push_back(points[points_i]);
+ }
+
+ if (nbL < landmarks.size()) {
+ std::random_shuffle(landmarks.begin(), landmarks.end());
+ landmarks.resize(nbL);
+ }
+ }
+
+
+
+
+ /** \brief Landmark choice strategy by taking random vertices for landmarks.
+ * \details It chooses nbL distinct landmarks from a random access range `points`
+ * and outputs a matrix {witness}*{closest landmarks} in knn.
+ */
+ template <typename KNearestNeighbours,
+ typename Point_random_access_range,
+ typename Distance_matrix>
+ void build_distance_matrix(Point_random_access_range const & points,
+ Point_random_access_range & landmarks,
+ FT alpha,
+ unsigned limD,
+ KNearestNeighbours & knn,
+ Distance_matrix & distances)
+ {
+ int nbP = points.end() - points.begin();
+ knn = KNearestNeighbours(nbP);
+ distances = Distance_matrix(nbP);
+ STraits traits(&(landmarks[0]));
+ CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance> adapter(&(landmarks[0]));
+ Euclidean_distance ed;
+ Tree landmark_tree(boost::counting_iterator<std::ptrdiff_t>(0),
+ boost::counting_iterator<std::ptrdiff_t>(landmarks.size()),
+ typename Tree::Splitter(),
+ traits);
+ for (int points_i = 0; points_i < nbP; points_i++) {
+ Point_d const & w = points[points_i];
+ Neighbor_search search(landmark_tree,
+ w,
+ FT(0),
+ true,
+ adapter);
+ Neighbor_search::iterator search_it = search.begin();
+ // Neighbor_search2 search(landmark_tree,
+ // w, limD+1,
+ // FT(0),
+ // true,
+ // adapter);
+ // Neighbor_search2::iterator search_it = search.begin();
+
+ while (knn[points_i].size() <= limD) {
+ distances[points_i].push_back(search_it->second); //!sq_dist
+ knn[points_i].push_back((search_it++)->first);
+ }
+ FT dtow = distances[points_i][limD];
+
+ while (search_it != search.end() && search_it->second < dtow + alpha) {
+ distances[points_i].push_back(search_it->second);
+ knn[points_i].push_back((search_it++)->first);
+ }
+ //std::cout << "k = " << knn[points_i].size() << std::endl;
+ }
+ }
+
+ /*
+ template <typename Kernel, typename Point_container>
+ std::vector<typename Point_container::value_type>
+ sparsify_point_set(const Kernel &k,
+ Point_container const& input_pts,
+ typename Kernel::FT min_squared_dist)
+ {
+ typedef typename CGAL::Tangential_complex_::Point_cloud_data_structure<Kernel, Point_container> Points_ds;
+ typedef typename Points_ds::INS_iterator INS_iterator;
+ typedef typename Points_ds::INS_range INS_range;
+
+ typename Kernel::Squared_distance_d sqdist = k.squared_distance_d_object();
+
+ // Create the output container
+ std::vector<typename Point_container::value_type> output;
+
+ Points_ds points_ds(input_pts);
+
+ std::vector<bool> dropped_points(input_pts.size(), false);
+
+ // Parse the input points, and add them if they are not too close to
+ // the other points
+ std::size_t pt_idx = 0;
+ for (typename Point_container::const_iterator it_pt = input_pts.begin() ;
+ it_pt != input_pts.end();
+ ++it_pt, ++pt_idx)
+ {
+ if (dropped_points[pt_idx])
+ continue;
+
+ output.push_back(*it_pt);
+
+ INS_range ins_range = points_ds.query_incremental_ANN(*it_pt);
+
+ // If another point Q is closer that min_squared_dist, mark Q to be dropped
+ for (INS_iterator nn_it = ins_range.begin() ;
+ nn_it != ins_range.end() ;
+ ++nn_it)
+ {
+ std::size_t neighbor_point_idx = nn_it->first;
+ // If the neighbor is too close, we drop the neighbor
+ if (nn_it->second < min_squared_dist)
+ {
+ // N.B.: If neighbor_point_idx < pt_idx,
+ // dropped_points[neighbor_point_idx] is already true but adding a
+ // test doesn't make things faster, so why bother?
+ dropped_points[neighbor_point_idx] = true;
+ }
+ else
+ break;
+ }
+ }
+
+ return output;
+}
+ */
+
+
+} // namespace witness_complex
+
+} // namespace Gudhi
+
+#endif // LANDMARK_CHOICE_BY_RANDOM_POINT_H_
diff --git a/src/Witness_complex/example/a0_persistence.cpp b/src/Witness_complex/example/a0_persistence.cpp
new file mode 100644
index 00000000..295c7115
--- /dev/null
+++ b/src/Witness_complex/example/a0_persistence.cpp
@@ -0,0 +1,632 @@
+/* This file is part of the Gudhi Library. The Gudhi library
+ * (Geometric Understanding in Higher Dimensions) is a generic C++
+ * library for computational topology.
+ *
+ * Author(s): Siargey Kachanovich
+ *
+ * Copyright (C) 2016 INRIA Sophia Antipolis-Méditerranée (France)
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gudhi/Simplex_tree.h>
+#include <gudhi/A0_complex.h>
+#include <gudhi/Relaxed_witness_complex.h>
+#include <gudhi/Dim_lists.h>
+#include <gudhi/reader_utils.h>
+#include <gudhi/Persistent_cohomology.h>
+#include "Landmark_choice_random_knn.h"
+#include "Landmark_choice_sparsification.h"
+
+#include <iostream>
+#include <fstream>
+#include <ctime>
+#include <utility>
+#include <algorithm>
+#include <set>
+#include <queue>
+#include <iterator>
+#include <string>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/iterator/zip_iterator.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/range/iterator_range.hpp>
+
+#include "generators.h"
+#include "output.h"
+#include "output_tikz.h"
+
+using namespace Gudhi;
+using namespace Gudhi::witness_complex;
+using namespace Gudhi::persistent_cohomology;
+
+typedef std::vector<Point_d> Point_Vector;
+typedef A0_complex< Simplex_tree<> > A0Complex;
+typedef Simplex_tree<>::Simplex_handle Simplex_handle;
+
+typedef A0_complex< Simplex_tree<> > SRWit;
+typedef Relaxed_witness_complex< Simplex_tree<> > WRWit;
+
+/**
+ * \brief Customized version of read_points
+ * which takes into account a possible nbP first line
+ *
+ */
+inline void
+read_points_cust(std::string file_name, std::vector< std::vector< double > > & points) {
+ std::ifstream in_file(file_name.c_str(), std::ios::in);
+ if (!in_file.is_open()) {
+ std::cerr << "Unable to open file " << file_name << std::endl;
+ return;
+ }
+ std::string line;
+ double x;
+ while (getline(in_file, line)) {
+ std::vector< double > point;
+ std::istringstream iss(line);
+ while (iss >> x) {
+ point.push_back(x);
+ }
+ if (point.size() != 1)
+ points.push_back(point);
+ }
+ in_file.close();
+}
+
+void output_experiment_information(char * const file_name)
+{
+ std::cout << "Enter a valid experiment number. Usage: "
+ << file_name << " exp_no options\n";
+ std::cout << "Experiment description:\n"
+ << "0 nbP nbL dim alpha limD mu_epsilon: "
+ << "Build persistence diagram on relaxed witness complex "
+ << "built from a point cloud on (dim-1)-dimensional sphere "
+ << "consisting of nbP witnesses and nbL landmarks. "
+ << "The maximal relaxation is alpha and the limit on simplicial complex "
+ << "dimension is limD.\n";
+ std::cout << "1 file_name nbL alpha limD: "
+ << "Build persistence diagram on relaxed witness complex "
+ << "build from a point cloud stored in a file and nbL landmarks. "
+ << "The maximal relaxation is alpha and the limit on simplicial complex dimension is limD\n";
+}
+
+void rw_experiment(Point_Vector & point_vector, int nbL, FT alpha2, int limD, FT mu_epsilon = 0.1)
+{
+ clock_t start, end;
+ Simplex_tree<> simplex_tree;
+
+ // Choose landmarks
+ std::vector<std::vector< int > > knn;
+ std::vector<std::vector< FT > > distances;
+ start = clock();
+ //Gudhi::witness_complex::landmark_choice_by_random_knn(point_vector, nbL, alpha, limD, knn, distances);
+
+ std::vector<Point_d> landmarks;
+ Gudhi::witness_complex::landmark_choice_by_sparsification(point_vector, nbL, mu_epsilon, landmarks);
+ Gudhi::witness_complex::build_distance_matrix(point_vector, // aka witnesses
+ landmarks, // aka landmarks
+ alpha2,
+ limD,
+ knn,
+ distances);
+ end = clock();
+ double time = static_cast<double>(end - start) / CLOCKS_PER_SEC;
+ std::cout << "Choice of " << nbL << " landmarks took "
+ << time << " s. \n";
+ // Compute witness complex
+ start = clock();
+ A0Complex rw(distances,
+ knn,
+ simplex_tree,
+ nbL,
+ alpha2,
+ limD);
+ end = clock();
+ time = static_cast<double>(end - start) / CLOCKS_PER_SEC;
+ std::cout << "Witness complex for " << nbL << " landmarks took "
+ << time << " s. \n";
+ std::cout << "The complex contains " << simplex_tree.num_simplices() << " simplices \n";
+ //std::cout << simplex_tree << "\n";
+
+ // Compute the persistence diagram of the complex
+ simplex_tree.set_dimension(limD);
+ persistent_cohomology::Persistent_cohomology< Simplex_tree<>, Field_Zp > pcoh(simplex_tree, true);
+ int p = 3;
+ pcoh.init_coefficients( p ); //initilizes the coefficient field for homology
+ start = clock();
+ pcoh.compute_persistent_cohomology( alpha2/10 );
+ end = clock();
+ time = static_cast<double>(end - start) / CLOCKS_PER_SEC;
+ std::cout << "Persistence diagram took "
+ << time << " s. \n";
+ pcoh.output_diagram();
+
+ int chi = 0;
+ for (auto sh: simplex_tree.complex_simplex_range())
+ chi += 1-2*(simplex_tree.dimension(sh)%2);
+ std::cout << "Euler characteristic is " << chi << std::endl;
+
+ // Gudhi::witness_complex::Dim_lists<Simplex_tree<>> simplices(simplex_tree, limD);
+
+ // simplices.collapse();
+ // simplices.output_simplices();
+
+ // Simplex_tree<> collapsed_tree;
+ // for (auto sh: simplices) {
+ // std::vector<int> vertices;
+ // for (int v: collapsed_tree.simplex_vertex_range(sh))
+ // vertices.push_back(v);
+ // collapsed_tree.insert_simplex(vertices);
+ // }
+ std::vector<int> landmarks_ind(nbL);
+ for (unsigned i = 0; i != distances.size(); ++i) {
+ if (distances[i][0] == 0)
+ landmarks_ind[knn[i][0]] = i;
+ }
+ //write_witness_mesh(point_vector, landmarks_ind, simplex_tree, simplices, false, true);
+ write_witness_mesh(point_vector, landmarks_ind, simplex_tree, simplex_tree.complex_simplex_range(), false, true, "witness_before_collapse.mesh");
+
+ // collapsed_tree.set_dimension(limD);
+ // persistent_cohomology::Persistent_cohomology< Simplex_tree<>, Field_Zp > pcoh2(collapsed_tree, true);
+ // pcoh2.init_coefficients( p ); //initilizes the coefficient field for homology
+ // pcoh2.compute_persistent_cohomology( alpha2/10 );
+ // pcoh2.output_diagram();
+
+ // chi = 0;
+ // for (auto sh: simplices)
+ // chi += 1-2*(simplex_tree.dimension(sh)%2);
+ // std::cout << "Euler characteristic is " << chi << std::endl;
+ // write_witness_mesh(point_vector, landmarks_ind, collapsed_tree, collapsed_tree.complex_simplex_range(), false, true, "witness_after_collapse.mesh");
+}
+
+void rips_experiment(Point_Vector & points, double threshold, int dim_max)
+{
+ typedef std::vector<double> Point_t;
+ typedef Simplex_tree<Simplex_tree_options_fast_persistence> ST;
+ clock_t start, end;
+ ST st;
+
+ // Compute the proximity graph of the points
+ start = clock();
+ Graph_t prox_graph = compute_proximity_graph(points, threshold
+ , euclidean_distance<Point_t>);
+ // Construct the Rips complex in a Simplex Tree
+ // insert the proximity graph in the simplex tree
+ st.insert_graph(prox_graph);
+ // expand the graph until dimension dim_max
+ st.expansion(dim_max);
+ end = clock();
+
+ double time = static_cast<double>(end - start) / CLOCKS_PER_SEC;
+ std::cout << "Rips complex took "
+ << time << " s. \n";
+ std::cout << "The complex contains " << st.num_simplices() << " simplices \n";
+ //std::cout << " and has dimension " << st.dimension() << " \n";
+
+ // Sort the simplices in the order of the filtration
+ st.initialize_filtration();
+
+ // Compute the persistence diagram of the complex
+ persistent_cohomology::Persistent_cohomology<ST, Field_Zp > pcoh(st);
+ // initializes the coefficient field for homology
+ int p = 3;
+ double min_persistence = -1; //threshold/5;
+ pcoh.init_coefficients(p);
+ pcoh.compute_persistent_cohomology(min_persistence);
+ pcoh.output_diagram();
+}
+
+
+int experiment0 (int argc, char * const argv[])
+{
+ if (argc != 8) {
+ std::cerr << "Usage: " << argv[0]
+ << " 0 nbP nbL dim alpha limD mu_epsilon\n";
+ return 0;
+ }
+ /*
+ boost::filesystem::path p;
+ for (; argc > 2; --argc, ++argv)
+ p /= argv[1];
+ */
+
+ int nbP = atoi(argv[2]);
+ int nbL = atoi(argv[3]);
+ int dim = atoi(argv[4]);
+ double alpha = atof(argv[5]);
+ int limD = atoi(argv[6]);
+ double mu_epsilon = atof(argv[7]);
+
+ // Read the point file
+ Point_Vector point_vector;
+ generate_points_sphere(point_vector, nbP, dim);
+ std::cout << "Successfully generated " << point_vector.size() << " points.\n";
+ std::cout << "Ambient dimension is " << point_vector[0].size() << ".\n";
+
+ rw_experiment(point_vector, nbL, alpha, limD);
+ return 0;
+}
+
+// int experiment1 (int argc, char * const argv[])
+// {
+// if (argc != 3) {
+// std::cerr << "Usage: " << argv[0]
+// << " 1 file_name\n";
+// return 0;
+// }
+// /*
+// boost::filesystem::path p;
+// for (; argc > 2; --argc, ++argv)
+// p /= argv[1];
+// */
+
+// std::string file_name = argv[2];
+
+// // Read the point file
+// Point_Vector point_vector;
+// read_points_cust(file_name, point_vector);
+// std::cout << "The file contains " << point_vector.size() << " points.\n";
+// std::cout << "Ambient dimension is " << point_vector[0].size() << ".\n";
+
+// bool ok = false;
+// int nbL, limD;
+// double alpha;
+// while (!ok) {
+// std::cout << "Relaxed witness complex: parameters nbL, alpha, limD.\n";
+// std::cout << "Enter nbL: ";
+// std::cin >> nbL;
+// std::cout << "Enter alpha: ";
+// std::cin >> alpha;
+// std::cout << "Enter limD: ";
+// std::cin >> limD;
+// std::cout << "Start relaxed witness complex...\n";
+// rw_experiment(point_vector, nbL, alpha, limD);
+// std::cout << "Is the result correct? [y/n]: ";
+// char answer;
+// std::cin >> answer;
+// switch (answer) {
+// case 'n':
+// ok = false; break;
+// default :
+// ok = true; break;
+// }
+// }
+// // ok = false;
+// // while (!ok) {
+// // std::cout << "Rips complex: parameters threshold, limD.\n";
+// // std::cout << "Enter threshold: ";
+// // std::cin >> alpha;
+// // std::cout << "Enter limD: ";
+// // std::cin >> limD;
+// // std::cout << "Start Rips complex...\n";
+// // rips_experiment(point_vector, alpha, limD);
+// // std::cout << "Is the result correct? [y/n]: ";
+// // char answer;
+// // std::cin >> answer;
+// // switch (answer) {
+// // case 'n':
+// // ok = false; break;
+// // default :
+// // ok = true; break;
+// // }
+// // }
+// return 0;
+// }
+
+int experiment1 (int argc, char * const argv[])
+{
+ if (argc != 8) {
+ std::cerr << "Usage: " << argv[0]
+ << " 1 file_name nbL alpha mu_epsilon limD experiment_name\n";
+ return 0;
+ }
+ /*
+ boost::filesystem::path p;
+ for (; argc > 2; --argc, ++argv)
+ p /= argv[1];
+ */
+
+ std::string file_name = argv[2];
+ int nbL = atoi(argv[3]), limD = atoi(argv[6]);
+ double alpha2 = atof(argv[4]), mu_epsilon = atof(argv[5]);
+ std::string experiment_name = argv[7];
+
+ // Read the point file
+ Point_Vector point_vector;
+ read_points_cust(file_name, point_vector);
+ std::cout << "The file contains " << point_vector.size() << " points.\n";
+ std::cout << "Ambient dimension is " << point_vector[0].size() << ".\n";
+
+ Simplex_tree<> simplex_tree;
+ std::vector<std::vector< int > > knn;
+ std::vector<std::vector< FT > > distances;
+ std::vector<Point_d> landmarks;
+ Gudhi::witness_complex::landmark_choice_by_sparsification(point_vector, nbL, mu_epsilon, landmarks);
+ Gudhi::witness_complex::build_distance_matrix(point_vector, // aka witnesses
+ landmarks, // aka landmarks
+ alpha2,
+ limD,
+ knn,
+ distances);
+
+ rw_experiment(point_vector, nbL, alpha2, limD, mu_epsilon);
+
+ // ok = false;
+ // while (!ok) {
+ // std::cout << "Rips complex: parameters threshold, limD.\n";
+ // std::cout << "Enter threshold: ";
+ // std::cin >> alpha;
+ // std::cout << "Enter limD: ";
+ // std::cin >> limD;
+ // std::cout << "Start Rips complex...\n";
+ // rips_experiment(point_vector, alpha, limD);
+ // std::cout << "Is the result correct? [y/n]: ";
+ // char answer;
+ // std::cin >> answer;
+ // switch (answer) {
+ // case 'n':
+ // ok = false; break;
+ // default :
+ // ok = true; break;
+ // }
+ // }
+ return 0;
+}
+
+
+/********************************************************************************************
+ * Length of the good interval experiment
+ *******************************************************************************************/
+
+struct Pers_endpoint {
+ double alpha;
+ bool start;
+ int dim;
+ Pers_endpoint(double alpha_, bool start_, int dim_)
+ : alpha(alpha_), start(start_), dim(dim_)
+ {}
+};
+
+/*
+struct less_than_key {
+ inline bool operator() (const MyStruct& struct1, const MyStruct& struct2) {
+ return (struct1.key < struct2.key);
+ }
+};
+*/
+
+double good_interval_length(const std::vector<int> & desired_homology, Simplex_tree<> & simplex_tree, double alpha2)
+{
+ int nbL = simplex_tree.num_vertices();
+ int p = 3;
+ persistent_cohomology::Persistent_cohomology< Simplex_tree<>, Field_Zp > pcoh(simplex_tree, true);
+ pcoh.init_coefficients( p ); //initilizes the coefficient field for homology
+ pcoh.compute_persistent_cohomology( -1 );
+ std::ofstream out_stream("pers_diag.tmp");
+ pcoh.output_diagram(out_stream);
+ out_stream.close();
+ std::ifstream in_stream("pers_diag.tmp", std::ios::in);
+ std::string line;
+ std::vector<Pers_endpoint> pers_endpoints;
+ while (getline(in_stream, line)) {
+ int p, dim;
+ double alpha_start, alpha_end;
+ std::istringstream iss(line);
+ iss >> p >> dim >> alpha_start >> alpha_end;
+ if (alpha_start != alpha_end) {
+ if (alpha_end < alpha_start)
+ alpha_end = alpha2;
+ pers_endpoints.push_back(Pers_endpoint(alpha_start, true, dim));
+ pers_endpoints.push_back(Pers_endpoint(alpha_end, false, dim));
+ }
+ }
+ std::cout << "Pers_endpoints.size = " << pers_endpoints.size() << std::endl;
+ in_stream.close();
+ std::sort(pers_endpoints.begin(),
+ pers_endpoints.end(),
+ [](const Pers_endpoint & p1, const Pers_endpoint & p2){
+ return p1.alpha < p2.alpha;}
+ );
+ write_barcodes("pers_diag.tmp", alpha2);
+ /*
+ for (auto p: pers_endpoints) {
+ std::cout << p.alpha << " " << p.dim << " " << p.start << "\n";
+ }
+ */
+ std::vector<int> current_homology(nbL-1,0);
+ current_homology[0] = 1; // for the compulsary "0 0 inf" entry
+ double good_start = 0, good_end = 0;
+ double sum_intervals = 0;
+ int num_pieces = 0;
+ bool interval_in_process = (desired_homology == current_homology);
+ for (auto p: pers_endpoints) {
+ /*
+ std::cout << "Treating " << p.alpha << " " << p.dim << " " << p.start
+ << " [";
+ for (int v: current_homology)
+ std::cout << v << " ";
+ std::cout << "]\n";
+ */
+ if (p.start)
+ current_homology[p.dim]++;
+ else
+ current_homology[p.dim]--;
+ if (interval_in_process) {
+ good_end = p.alpha;
+ sum_intervals += good_end - good_start;
+ std::cout << "good_start = " << good_start
+ << ", good_end = " << good_end << "\n";
+
+ Gudhi::witness_complex::Dim_lists<Simplex_tree<>> simplices(simplex_tree, nbL-1, (good_end - good_start)/2);
+ simplices.collapse();
+ simplices.output_simplices();
+ interval_in_process = false;
+ //break;
+ }
+ else if (desired_homology == current_homology) {
+ interval_in_process = true;
+ good_start = p.alpha;
+ num_pieces++;
+ }
+ }
+ std::cout << "Number of good homology intervals: " << num_pieces << "\n";
+ return sum_intervals;
+}
+
+void run_comparison(std::vector<std::vector< int > > const & knn,
+ std::vector<std::vector< FT > > const & distances,
+ unsigned nbL,
+ double alpha2,
+ std::vector<int>& desired_homology)
+{
+ clock_t start, end;
+ Simplex_tree<> simplex_tree;
+
+ start = clock();
+ SRWit srwit(distances,
+ knn,
+ simplex_tree,
+ nbL,
+ alpha2,
+ nbL-1);
+ end = clock();
+ std::cout << "SRWit.size = " << simplex_tree.num_simplices() << std::endl;
+ simplex_tree.set_dimension(nbL-1);
+
+ std::cout << "Good homology interval length for SRWit is "
+ << good_interval_length(desired_homology, simplex_tree, alpha2) << "\n";
+ std::cout << "Time: " << static_cast<double>(end - start) / CLOCKS_PER_SEC << " s. \n";
+
+ /*
+ Simplex_tree<> simplex_tree2;
+ start = clock();
+ WRWit wrwit(distances,
+ knn,
+ simplex_tree2,
+ nbL,
+ alpha2,
+ nbL-1);
+ end = clock();
+ std::cout << "WRWit.size = " << simplex_tree2.num_simplices() << std::endl;
+ simplex_tree.set_dimension(nbL-1);
+
+ std::cout << "Good homology interval length for WRWit is "
+ << good_interval_length(desired_homology, simplex_tree2, alpha2) << "\n";
+ std::cout << "Time: " << static_cast<double>(end - start) / CLOCKS_PER_SEC << " s. \n";
+ */
+}
+
+int experiment2(int argc, char * const argv[])
+{
+ for (unsigned d = 2; d < 2; d++) {
+ // Sphere S^d
+ Point_Vector point_vector;
+ unsigned N = 1;
+ double alpha2 = 2.4 - 0.4*d;
+ switch (d) {
+ case 1: alpha2 = 2.2; break;
+ case 2: alpha2 = 1.8; break;
+ case 3: alpha2 = 1.5; break;
+ case 4: alpha2 = 1.4; break;
+ default: alpha2 = 1.4; break;
+ }
+ std::cout << "alpha2 = " << alpha2 << "\n";
+ unsigned nbL = 20;
+ std::vector<int> desired_homology(nbL-1,0);
+ desired_homology[0] = 1; desired_homology[d] = 1;
+
+
+ for (unsigned i = 1; i <= N; ++i) {
+ unsigned nbW = 1000*i;//, nbL = 20;
+ double mu_epsilon = 1/sqrt(nbL);
+ std::cout << "Running test S"<< d <<", |W|=" << nbW << ", |L|=" << nbL << std::endl;
+ generate_points_sphere(point_vector, i*1000, d+1);
+ std::vector<Point_d> landmarks;
+ Gudhi::witness_complex::landmark_choice_by_sparsification(point_vector, nbL, mu_epsilon, landmarks);
+
+ std::vector<std::vector< int > > knn;
+ std::vector<std::vector< FT > > distances;
+
+ std::cout << "|L| after sparsification: " << landmarks.size() << "\n";
+ Gudhi::witness_complex::build_distance_matrix(point_vector, // aka witnesses
+ landmarks, // aka landmarks
+ alpha2,
+ nbL-1,
+ knn,
+ distances);
+ run_comparison(knn, distances, nbL, alpha2, desired_homology);
+ }
+ }
+ {
+ // SO(3)
+ Point_Vector point_vector;
+ double alpha2 = 0.6;
+ std::cout << "alpha2 = " << alpha2 << "\n";
+ unsigned nbL = 150;
+ std::vector<int> desired_homology(nbL-1,0);
+ desired_homology[0] = 1; desired_homology[1] = 1; desired_homology[2] = 1; //Kl
+ // desired_homology[0] = 1; desired_homology[3] = 1; //SO3
+
+ double mu_epsilon = 1/sqrt(nbL);
+ if (argc < 3) std::cerr << "No file name indicated!\n";
+ read_points_cust(argv[2], point_vector);
+ int nbW = point_vector.size();
+ std::cout << "Running test SO(3), |W|=" << nbW << ", |L|=" << nbL << std::endl;
+ std::vector<Point_d> landmarks;
+ Gudhi::witness_complex::landmark_choice_by_sparsification(point_vector, nbL, mu_epsilon, landmarks);
+
+ std::vector<std::vector< int > > knn;
+ std::vector<std::vector< FT > > distances;
+
+ std::cout << "|L| after sparsification: " << landmarks.size() << "\n";
+ Gudhi::witness_complex::build_distance_matrix(point_vector, // aka witnesses
+ landmarks, // aka landmarks
+ alpha2,
+ nbL-1,
+ knn,
+ distances);
+ run_comparison(knn, distances, nbL, alpha2, desired_homology);
+ }
+ return 0;
+}
+
+int experiment3(int argc, char * const argv[])
+{
+ // COLLAPSES EXPERIMENT
+
+ return 0;
+}
+
+int main (int argc, char * const argv[])
+{
+ if (argc == 1) {
+ output_experiment_information(argv[0]);
+ return 1;
+ }
+ switch (atoi(argv[1])) {
+ case 0 :
+ return experiment0(argc, argv);
+ break;
+ case 1 :
+ return experiment1(argc, argv);
+ break;
+ case 2 :
+ return experiment2(argc, argv);
+ break;
+ default :
+ output_experiment_information(argv[0]);
+ return 1;
+ }
+}
diff --git a/src/Witness_complex/example/bench_rwit.cpp b/src/Witness_complex/example/bench_rwit.cpp
new file mode 100644
index 00000000..f83f9f42
--- /dev/null
+++ b/src/Witness_complex/example/bench_rwit.cpp
@@ -0,0 +1,616 @@
+/* This file is part of the Gudhi Library. The Gudhi library
+ * (Geometric Understanding in Higher Dimensions) is a generic C++
+ * library for computational topology.
+ *
+ * Author(s): Siargey Kachanovich
+ *
+ * Copyright (C) 2016 INRIA Sophia Antipolis-Méditerranée (France)
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gudhi/Simplex_tree.h>
+#include <gudhi/A0_complex.h>
+#include <gudhi/Relaxed_witness_complex.h>
+#include <gudhi/Dim_lists.h>
+#include <gudhi/reader_utils.h>
+#include <gudhi/Persistent_cohomology.h>
+#include "Landmark_choice_random_knn.h"
+#include "Landmark_choice_sparsification.h"
+
+#include <iostream>
+#include <fstream>
+#include <ctime>
+#include <utility>
+#include <algorithm>
+#include <set>
+#include <queue>
+#include <iterator>
+#include <string>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/iterator/zip_iterator.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/range/iterator_range.hpp>
+
+#include "generators.h"
+#include "output.h"
+#include "output_tikz.h"
+
+using namespace Gudhi;
+using namespace Gudhi::witness_complex;
+using namespace Gudhi::persistent_cohomology;
+
+typedef std::vector<Point_d> Point_Vector;
+typedef Simplex_tree<Simplex_tree_options_fast_persistence> STree;
+//typedef Simplex_tree<> STree;
+typedef A0_complex< STree> A0Complex;
+typedef STree::Simplex_handle Simplex_handle;
+
+typedef A0_complex< STree > SRWit;
+typedef Relaxed_witness_complex< STree > WRWit;
+
+/**
+ * \brief Customized version of read_points
+ * which takes into account a possible nbP first line
+ *
+ */
+inline void
+read_points_cust(std::string file_name, std::vector< std::vector< double > > & points) {
+ std::ifstream in_file(file_name.c_str(), std::ios::in);
+ if (!in_file.is_open()) {
+ std::cerr << "Unable to open file " << file_name << std::endl;
+ return;
+ }
+ std::string line;
+ double x;
+ while (getline(in_file, line)) {
+ std::vector< double > point;
+ std::istringstream iss(line);
+ while (iss >> x) {
+ point.push_back(x);
+ }
+ if (point.size() != 1)
+ points.push_back(point);
+ }
+ in_file.close();
+}
+
+void rips(Point_Vector & points, double alpha2, int dim_max, STree& st)
+{
+ Graph_t prox_graph = compute_proximity_graph(points, sqrt(alpha2)
+ , euclidean_distance<std::vector<FT> >);
+ // Construct the Rips complex in a Simplex Tree
+ // insert the proximity graph in the simplex tree
+ st.insert_graph(prox_graph);
+ // expand the graph until dimension dim_max
+ st.expansion(dim_max);
+}
+
+void output_experiment_information(char * const file_name)
+{
+ std::cout << "Enter a valid experiment number. Usage: "
+ << file_name << " exp_no options\n";
+ std::cout << "Experiment description:\n"
+ << "0 nbP nbL dim alpha limD mu_epsilon: "
+ << "Build persistence diagram on relaxed witness complex "
+ << "built from a point cloud on (dim-1)-dimensional sphere "
+ << "consisting of nbP witnesses and nbL landmarks. "
+ << "The maximal relaxation is alpha and the limit on simplicial complex "
+ << "dimension is limD.\n";
+ std::cout << "1 file_name nbL alpha limD: "
+ << "Build persistence diagram on relaxed witness complex "
+ << "build from a point cloud stored in a file and nbL landmarks. "
+ << "The maximal relaxation is alpha and the limit on simplicial complex dimension is limD\n";
+}
+
+void rw_experiment(Point_Vector & point_vector, int nbL, FT alpha2, int limD, FT mu_epsilon = 0.1,
+ std::string mesh_filename = "witness")
+{
+ clock_t start, end;
+ STree simplex_tree;
+
+ // Choose landmarks
+ std::vector<std::vector< int > > knn;
+ std::vector<std::vector< FT > > distances;
+ start = clock();
+ //Gudhi::witness_complex::landmark_choice_by_random_knn(point_vector, nbL, alpha, limD, knn, distances);
+
+ std::vector<Point_d> landmarks;
+ Gudhi::witness_complex::landmark_choice_by_sparsification(point_vector, nbL, mu_epsilon, landmarks);
+ Gudhi::witness_complex::build_distance_matrix(point_vector, // aka witnesses
+ landmarks, // aka landmarks
+ alpha2,
+ limD,
+ knn,
+ distances);
+ end = clock();
+ double time = static_cast<double>(end - start) / CLOCKS_PER_SEC;
+ std::cout << "Choice of " << nbL << " landmarks took "
+ << time << " s. \n";
+ // Compute witness complex
+ start = clock();
+ A0Complex rw(distances,
+ knn,
+ simplex_tree,
+ nbL,
+ alpha2,
+ limD);
+ end = clock();
+ time = static_cast<double>(end - start) / CLOCKS_PER_SEC;
+ std::cout << "Witness complex for " << nbL << " landmarks took "
+ << time << " s. \n";
+ std::cout << "The complex contains " << simplex_tree.num_simplices() << " simplices \n";
+ //std::cout << simplex_tree << "\n";
+
+ // Compute the persistence diagram of the complex
+ simplex_tree.set_dimension(limD);
+ persistent_cohomology::Persistent_cohomology< STree, Field_Zp > pcoh(simplex_tree, true);
+ int p = 3;
+ pcoh.init_coefficients( p ); //initilizes the coefficient field for homology
+ start = clock();
+ pcoh.compute_persistent_cohomology( alpha2/10 );
+ end = clock();
+ time = static_cast<double>(end - start) / CLOCKS_PER_SEC;
+ std::cout << "Persistence diagram took "
+ << time << " s. \n";
+ pcoh.output_diagram();
+
+ int chi = 0;
+ for (auto sh: simplex_tree.complex_simplex_range())
+ chi += 1-2*(simplex_tree.dimension(sh)%2);
+ std::cout << "Euler characteristic is " << chi << std::endl;
+
+ Gudhi::witness_complex::Dim_lists<STree> simplices(simplex_tree, limD);
+
+ // std::vector<Simplex_handle> simplices;
+ simplices.collapse();
+ simplices.output_simplices();
+
+ STree collapsed_tree;
+ for (auto sh: simplices) {
+ std::vector<int> vertices;
+ for (int v: collapsed_tree.simplex_vertex_range(sh))
+ vertices.push_back(v);
+ collapsed_tree.insert_simplex(vertices);
+ }
+ std::vector<int> landmarks_ind(nbL);
+ for (unsigned i = 0; i != distances.size(); ++i) {
+ if (distances[i][0] == 0)
+ landmarks_ind[knn[i][0]] = i;
+ }
+ //write_witness_mesh(point_vector, landmarks_ind, simplex_tree, simplices, false, true);
+ write_witness_mesh(point_vector, landmarks_ind, simplex_tree, simplex_tree.complex_simplex_range(), false, true, mesh_filename+"_before_collapse.mesh");
+
+ collapsed_tree.set_dimension(limD);
+ persistent_cohomology::Persistent_cohomology< STree, Field_Zp > pcoh2(collapsed_tree, true);
+ pcoh2.init_coefficients( p ); //initilizes the coefficient field for homology
+ pcoh2.compute_persistent_cohomology( alpha2/10 );
+ pcoh2.output_diagram();
+
+ chi = 0;
+ for (auto sh: simplices)
+ chi += 1-2*(simplex_tree.dimension(sh)%2);
+ std::cout << "Euler characteristic is " << chi << std::endl;
+ write_witness_mesh(point_vector, landmarks_ind, collapsed_tree, collapsed_tree.complex_simplex_range(), false, true, mesh_filename+"_after_collapse.mesh");
+}
+
+void rips_experiment(Point_Vector & points, double threshold, int dim_max)
+{
+ typedef STree ST;
+ clock_t start, end;
+ ST st;
+
+ // Compute the proximity graph of the points
+ start = clock();
+ rips(points, threshold, dim_max, st);
+ end = clock();
+
+ double time = static_cast<double>(end - start) / CLOCKS_PER_SEC;
+ std::cout << "Rips complex took "
+ << time << " s. \n";
+ std::cout << "The complex contains " << st.num_simplices() << " simplices \n";
+ //std::cout << " and has dimension " << st.dimension() << " \n";
+
+ // Sort the simplices in the order of the filtration
+ st.initialize_filtration();
+
+ // Compute the persistence diagram of the complex
+ persistent_cohomology::Persistent_cohomology<ST, Field_Zp > pcoh(st);
+ // initializes the coefficient field for homology
+ int p = 3;
+ double min_persistence = -1; //threshold/5;
+ pcoh.init_coefficients(p);
+ pcoh.compute_persistent_cohomology(min_persistence);
+ pcoh.output_diagram();
+}
+
+
+int experiment0 (int argc, char * const argv[])
+{
+ if (argc != 8) {
+ std::cerr << "Usage: " << argv[0]
+ << " 0 nbP nbL dim alpha limD mu_epsilon\n";
+ return 0;
+ }
+ /*
+ boost::filesystem::path p;
+ for (; argc > 2; --argc, ++argv)
+ p /= argv[1];
+ */
+
+ int nbP = atoi(argv[2]);
+ int nbL = atoi(argv[3]);
+ int dim = atoi(argv[4]);
+ double alpha = atof(argv[5]);
+ int limD = atoi(argv[6]);
+ double mu_epsilon = atof(argv[7]);
+
+ // Read the point file
+ Point_Vector point_vector;
+ generate_points_sphere(point_vector, nbP, dim);
+ std::cout << "Successfully generated " << point_vector.size() << " points.\n";
+ std::cout << "Ambient dimension is " << point_vector[0].size() << ".\n";
+
+ rw_experiment(point_vector, nbL, alpha, limD);
+ return 0;
+}
+
+int experiment1 (int argc, char * const argv[])
+{
+ if (argc != 8) {
+ std::cerr << "Usage: " << argv[0]
+ << " 1 file_name nbL alpha mu_epsilon limD experiment_name\n";
+ return 0;
+ }
+ /*
+ boost::filesystem::path p;
+ for (; argc > 2; --argc, ++argv)
+ p /= argv[1];
+ */
+
+ std::string file_name = argv[2];
+ int nbL = atoi(argv[3]), limD = atoi(argv[6]);
+ double alpha2 = atof(argv[4]), mu_epsilon = atof(argv[5]);
+ std::string experiment_name = argv[7];
+
+ // Read the point file
+ Point_Vector point_vector;
+ read_points_cust(file_name, point_vector);
+ std::cout << "The file contains " << point_vector.size() << " points.\n";
+ std::cout << "Ambient dimension is " << point_vector[0].size() << ".\n";
+
+ STree simplex_tree;
+ std::vector<std::vector< int > > knn;
+ std::vector<std::vector< FT > > distances;
+ std::vector<Point_d> landmarks;
+ Gudhi::witness_complex::landmark_choice_by_sparsification(point_vector, nbL, mu_epsilon, landmarks);
+ Gudhi::witness_complex::build_distance_matrix(point_vector, // aka witnesses
+ landmarks, // aka landmarks
+ alpha2,
+ limD,
+ knn,
+ distances);
+ WRWit rw(distances,
+ knn,
+ simplex_tree,
+ nbL,
+ 0,
+ limD);
+ std::vector<int> landmarks_ind(nbL);
+ for (unsigned i = 0; i != distances.size(); ++i) {
+ if (distances[i][0] == 0)
+ landmarks_ind[knn[i][0]] = i;
+ }
+
+ write_witness_mesh(point_vector, landmarks_ind, simplex_tree, simplex_tree.complex_simplex_range(), false, true, experiment_name+"_witness_complex.mesh");
+
+ int chi = 0;
+ for (auto sh: simplex_tree.complex_simplex_range())
+ chi += 1-2*(simplex_tree.dimension(sh)%2);
+ std::cout << "Euler characteristic is " << chi << std::endl;
+
+ rw_experiment(point_vector, nbL, alpha2, limD, mu_epsilon, experiment_name);
+
+ // ok = false;
+ // while (!ok) {
+ // std::cout << "Rips complex: parameters threshold, limD.\n";
+ // std::cout << "Enter threshold: ";
+ // std::cin >> alpha;
+ // std::cout << "Enter limD: ";
+ // std::cin >> limD;
+ // std::cout << "Start Rips complex...\n";
+ // rips_experiment(point_vector, alpha, limD);
+ // std::cout << "Is the result correct? [y/n]: ";
+ // char answer;
+ // std::cin >> answer;
+ // switch (answer) {
+ // case 'n':
+ // ok = false; break;
+ // default :
+ // ok = true; break;
+ // }
+ // }
+ return 0;
+}
+
+/********************************************************************************************
+ * Length of the good interval experiment
+ *******************************************************************************************/
+
+struct Pers_endpoint {
+ double alpha;
+ bool start;
+ int dim;
+ Pers_endpoint(double alpha_, bool start_, int dim_)
+ : alpha(alpha_), start(start_), dim(dim_)
+ {}
+};
+
+/*
+struct less_than_key {
+ inline bool operator() (const MyStruct& struct1, const MyStruct& struct2) {
+ return (struct1.key < struct2.key);
+ }
+};
+*/
+
+double good_interval_length(const std::vector<int> & desired_homology, STree & simplex_tree, double alpha2)
+{
+ int nbL = simplex_tree.num_vertices();
+ int p = 3;
+ persistent_cohomology::Persistent_cohomology< STree, Field_Zp > pcoh(simplex_tree, true);
+ pcoh.init_coefficients( p ); //initilizes the coefficient field for homology
+ pcoh.compute_persistent_cohomology( -1 );
+ std::ofstream out_stream("pers_diag.tmp");
+ pcoh.output_diagram(out_stream);
+ out_stream.close();
+ std::ifstream in_stream("pers_diag.tmp", std::ios::in);
+ std::string line;
+ std::vector<Pers_endpoint> pers_endpoints;
+ while (getline(in_stream, line)) {
+ int p, dim;
+ double alpha_start, alpha_end;
+ std::istringstream iss(line);
+ iss >> p >> dim >> alpha_start >> alpha_end;
+ if (alpha_start != alpha_end) {
+ if (alpha_end < alpha_start)
+ alpha_end = alpha2;
+ pers_endpoints.push_back(Pers_endpoint(alpha_start, true, dim));
+ pers_endpoints.push_back(Pers_endpoint(alpha_end, false, dim));
+ }
+ }
+ std::cout << "Pers_endpoints.size = " << pers_endpoints.size() << std::endl;
+ in_stream.close();
+ std::sort(pers_endpoints.begin(),
+ pers_endpoints.end(),
+ [](const Pers_endpoint & p1, const Pers_endpoint & p2){
+ return p1.alpha < p2.alpha;}
+ );
+ write_barcodes("pers_diag.tmp", alpha2);
+ /*
+ for (auto p: pers_endpoints) {
+ std::cout << p.alpha << " " << p.dim << " " << p.start << "\n";
+ }
+ */
+ std::vector<int> current_homology(nbL-1,0);
+ current_homology[0] = 1; // for the compulsary "0 0 inf" entry
+ double good_start = 0, good_end = 0;
+ double sum_intervals = 0;
+ int num_pieces = 0;
+ bool interval_in_process = (desired_homology == current_homology);
+ for (auto p: pers_endpoints) {
+ /*
+ std::cout << "Treating " << p.alpha << " " << p.dim << " " << p.start
+ << " [";
+ for (int v: current_homology)
+ std::cout << v << " ";
+ std::cout << "]\n";
+ */
+ if (p.start)
+ current_homology[p.dim]++;
+ else
+ current_homology[p.dim]--;
+ if (interval_in_process) {
+ good_end = p.alpha;
+ sum_intervals += good_end - good_start;
+ std::cout << "good_start = " << good_start
+ << ", good_end = " << good_end << "\n";
+
+ Gudhi::witness_complex::Dim_lists<STree> simplices(simplex_tree, nbL-1, (good_end - good_start)/2);
+ //simplices.collapse();
+ //simplices.output_simplices();
+ interval_in_process = false;
+ //break;
+ }
+ else if (desired_homology == current_homology) {
+ interval_in_process = true;
+ good_start = p.alpha;
+ num_pieces++;
+ }
+ }
+ std::cout << "Number of good homology intervals: " << num_pieces << "\n";
+ return sum_intervals;
+}
+
+
+
+void run_comparison(std::vector<std::vector< int > > const & knn,
+ std::vector<std::vector< FT > > const & distances,
+ Point_Vector & points,
+ unsigned nbL,
+ double alpha2,
+ std::vector<int>& desired_homology)
+{
+ clock_t start, end;
+ STree simplex_tree;
+
+ alpha2 = 0.55;
+ std::cout << "alpha2 = " << alpha2 << "\n";
+ start = clock();
+ SRWit srwit(distances,
+ knn,
+ simplex_tree,
+ nbL,
+ alpha2,
+ nbL-1);
+ end = clock();
+ std::cout << "SRWit.size = " << simplex_tree.num_simplices() << std::endl;
+ simplex_tree.set_dimension(nbL-1);
+
+ std::cout << "Good homology interval length for SRWit is "
+ << good_interval_length(desired_homology, simplex_tree, alpha2) << "\n";
+ std::cout << "Time: " << static_cast<double>(end - start) / CLOCKS_PER_SEC << " s. \n";
+
+ STree simplex_tree2;
+ alpha2 = 0.35;
+ std::cout << "alpha2 = " << alpha2 << "\n";
+ start = clock();
+ WRWit wrwit(distances,
+ knn,
+ simplex_tree2,
+ nbL,
+ alpha2,
+ nbL-1);
+ end = clock();
+ std::cout << "WRWit.size = " << simplex_tree2.num_simplices() << std::endl;
+ simplex_tree.set_dimension(nbL-1);
+
+ std::cout << "Good homology interval length for WRWit is "
+ << good_interval_length(desired_homology, simplex_tree2, alpha2) << "\n";
+ std::cout << "Time: " << static_cast<double>(end - start) / CLOCKS_PER_SEC << " s. \n";
+
+ STree simplex_tree3;
+ std::cout << "Enter alpha2 for Rips: ";
+ std::cin >> alpha2;
+ std::cout << "\n";
+ std::cout << "points.size() = " << points.size() << "\n";
+ start = clock();
+ rips(points,
+ 0.2,
+ nbL-1,
+ simplex_tree3);
+ end = clock();
+ std::cout << "Rips.size = " << simplex_tree3.num_simplices() << std::endl;
+ simplex_tree.set_dimension(nbL-1);
+
+ std::cout << "Good homology interval length for WRWit is "
+ << good_interval_length(desired_homology, simplex_tree3, alpha2) << "\n";
+ std::cout << "Time: " << static_cast<double>(end - start) / CLOCKS_PER_SEC << " s. \n";
+}
+
+int experiment2(int argc, char * const argv[])
+{
+ for (unsigned d = 3; d < 4; d++) {
+ // Sphere S^d
+ Point_Vector point_vector;
+ unsigned N = 1;
+ double alpha2 = 2.4 - 0.4*d;
+ switch (d) {
+ case 1: alpha2 = 2.2; break;
+ case 2: alpha2 = 1.7; break;
+ case 3: alpha2 = 1.5; break;
+ case 4: alpha2 = 1.4; break;
+ default: alpha2 = 1.4; break;
+ }
+ std::cout << "alpha2 = " << alpha2 << "\n";
+ unsigned nbL = 20;
+ std::vector<int> desired_homology(nbL-1,0);
+ desired_homology[0] = 1; desired_homology[d] = 1;
+
+
+ for (unsigned i = 1; i <= N; ++i) {
+ unsigned nbW = 1000*i;//, nbL = 20;
+ double mu_epsilon = 1/sqrt(nbL);
+ std::cout << "Running test S"<< d <<", |W|=" << nbW << ", |L|=" << nbL << std::endl;
+ generate_points_sphere(point_vector, i*1000, d+1);
+ std::vector<Point_d> landmarks;
+ Gudhi::witness_complex::landmark_choice_by_sparsification(point_vector, nbL, mu_epsilon, landmarks);
+
+ std::vector<std::vector< int > > knn;
+ std::vector<std::vector< FT > > distances;
+
+ std::cout << "|L| after sparsification: " << landmarks.size() << "\n";
+ Gudhi::witness_complex::build_distance_matrix(point_vector, // aka witnesses
+ landmarks, // aka landmarks
+ alpha2,
+ nbL-1,
+ knn,
+ distances);
+ run_comparison(knn, distances, point_vector, nbL, alpha2, desired_homology);
+ }
+ }
+ /*
+ {
+ // SO(3)
+ Point_Vector point_vector;
+ double alpha2 = 0.6;
+ std::cout << "alpha2 = " << alpha2 << "\n";
+ unsigned nbL = 150;
+ std::vector<int> desired_homology(nbL-1,0);
+ desired_homology[0] = 1; desired_homology[1] = 1; desired_homology[2] = 1; //Kl
+ // desired_homology[0] = 1; desired_homology[3] = 1; //SO3
+
+ double mu_epsilon = 1/sqrt(nbL);
+ if (argc < 3) std::cerr << "No file name indicated!\n";
+ read_points_cust(argv[2], point_vector);
+ int nbW = point_vector.size();
+ std::cout << "Running test SO(3), |W|=" << nbW << ", |L|=" << nbL << std::endl;
+ std::vector<Point_d> landmarks;
+ Gudhi::witness_complex::landmark_choice_by_sparsification(point_vector, nbL, mu_epsilon, landmarks);
+
+ std::vector<std::vector< int > > knn;
+ std::vector<std::vector< FT > > distances;
+
+ std::cout << "|L| after sparsification: " << landmarks.size() << "\n";
+ Gudhi::witness_complex::build_distance_matrix(point_vector, // aka witnesses
+ landmarks, // aka landmarks
+ alpha2,
+ nbL-1,
+ knn,
+ distances);
+ run_comparison(knn, distances, point_vector, nbL, alpha2, desired_homology);
+ }
+ */
+ return 0;
+}
+
+int experiment3(int argc, char * const argv[])
+{
+ // COLLAPSES EXPERIMENT
+
+ return 0;
+}
+
+int main (int argc, char * const argv[])
+{
+ if (argc == 1) {
+ output_experiment_information(argv[0]);
+ return 1;
+ }
+ switch (atoi(argv[1])) {
+ case 0 :
+ return experiment0(argc, argv);
+ break;
+ case 1 :
+ return experiment1(argc, argv);
+ break;
+ case 2 :
+ return experiment2(argc, argv);
+ break;
+ default :
+ output_experiment_information(argv[0]);
+ return 1;
+ }
+}
diff --git a/src/Witness_complex/example/color-picker.cpp b/src/Witness_complex/example/color-picker.cpp
new file mode 100644
index 00000000..fcea033e
--- /dev/null
+++ b/src/Witness_complex/example/color-picker.cpp
@@ -0,0 +1,37 @@
+#include <iostream>
+#include <assert.h>
+
+struct Color {
+ double r, g, b;
+ Color() : r(0), g(0), b(0) { }
+ Color(double r_, double g_, double b_)
+ : r(r_), g(g_), b(b_) { }
+};
+
+// Convert a double in [0,1] to a color
+template< typename ColorType >
+void double_to_color(double t, ColorType & color) {
+ assert(t >= 0 && t <= 1);
+ double s = 1.0/6;
+ if (t >= 0 && t <= s)
+ color = ColorType(1, 6*t, 0);
+ else if (t > s && t <= 2*s)
+ color = ColorType(1-6*(t-s), 1, 0);
+ else if (t > 2*s && t <= 3*s)
+ color = ColorType(0, 1, 6*(t-2*s));
+ else if (t > 3*s && t <= 4*s)
+ color = ColorType(0, 1-6*(t-3*s), 1);
+ else if (t > 4*s && t <= 5*s)
+ color = ColorType(6*(t-4*s), 0, 1);
+ else
+ color = ColorType(1, 0, 1-6*(t-5*s));
+}
+
+int main (int argc, char * const argv[]) {
+ double number_to_convert = 0;
+ std::cout << "Enter a real number in [0,1]: ";
+ std::cin >> number_to_convert;
+ Color color;
+ double_to_color(number_to_convert, color);
+ std::cout << "The corresponding color in rgb is: (" << color.r << ", " << color.g << ", " << color.b << ")\n";
+}
diff --git a/src/Witness_complex/example/generators.h b/src/Witness_complex/example/generators.h
index ac445261..23915546 100644
--- a/src/Witness_complex/example/generators.h
+++ b/src/Witness_complex/example/generators.h
@@ -144,4 +144,12 @@ void generate_points_sphere(Point_Vector& W, int nbP, int dim) {
W.push_back(*rp++);
}
+/** \brief Generate nbP points on a d-torus
+ *
+ */
+void generate_points_torus(Point_Vector& W, int nbP, int dim) {
+ CGAL::Random_points_on_sphere_d<Point_d> rp(2, 1);
+
+}
+
#endif // EXAMPLE_WITNESS_COMPLEX_GENERATORS_H_
diff --git a/src/Witness_complex/example/off_writer.h b/src/Witness_complex/example/off_writer.h
new file mode 100644
index 00000000..8cafe9e2
--- /dev/null
+++ b/src/Witness_complex/example/off_writer.h
@@ -0,0 +1,11 @@
+#ifndef OFF_WRITER_H_
+#define OFF_WRITER_H_
+
+
+class Off_Writer {
+
+private:
+
+}
+
+#endif
diff --git a/src/Witness_complex/example/output.h b/src/Witness_complex/example/output.h
new file mode 100644
index 00000000..0e74387a
--- /dev/null
+++ b/src/Witness_complex/example/output.h
@@ -0,0 +1,305 @@
+#ifndef OUTPUT_H
+#define OUTPUT_H
+
+#include <fstream>
+#include <vector>
+#include <string>
+
+#include <gudhi/Simplex_tree.h>
+
+#include <CGAL/Epick_d.h>
+#include <CGAL/Delaunay_triangulation.h>
+
+//typename Gudhi::Witness_complex<> Witness_complex;
+
+typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> K;
+typedef K::Point_d Point_d;
+typedef std::vector<Point_d> Point_Vector;
+typedef CGAL::Delaunay_triangulation<K> Delaunay_triangulation;
+
+/** \brief Write the table of the nearest landmarks to each witness
+ * to a file.
+ */
+template <class Value>
+void write_wl( std::string file_name, std::vector< std::vector <Value> > & WL)
+{
+ std::ofstream ofs (file_name, std::ofstream::out);
+ for (auto w : WL)
+ {
+ for (auto l: w)
+ ofs << l << " ";
+ ofs << "\n";
+ }
+ ofs.close();
+}
+
+/** \brief Write the coordinates of points in points to a file.
+ *
+ */
+void write_points( std::string file_name, std::vector< Point_d > & points)
+{
+ std::ofstream ofs (file_name, std::ofstream::out);
+ for (auto w : points)
+ {
+ for (auto it = w.cartesian_begin(); it != w.cartesian_end(); ++it)
+ ofs << *it << " ";
+ ofs << "\n";
+ }
+ ofs.close();
+}
+
+/** Write edges of a witness complex in a file.
+ * The format of an edge is coordinates of u \n coordinates of v \n\n\n
+ * This format is compatible with gnuplot
+ */
+template< typename STree >
+void write_edges(std::string file_name, STree& witness_complex, Point_Vector& landmarks)
+{
+ std::ofstream ofs (file_name, std::ofstream::out);
+ for (auto u: witness_complex.complex_vertex_range())
+ for (auto v: witness_complex.complex_vertex_range())
+ {
+ std::vector<int> edge = {u,v};
+ if (u < v && witness_complex.find(edge) != witness_complex.null_simplex())
+ {
+ for (auto it = landmarks[u].cartesian_begin(); it != landmarks[u].cartesian_end(); ++it)
+ ofs << *it << " ";
+ ofs << "\n";
+ for (auto it = landmarks[v].cartesian_begin(); it != landmarks[v].cartesian_end(); ++it)
+ ofs << *it << " ";
+ ofs << "\n\n\n";
+ }
+ }
+ ofs.close();
+}
+
+/** \brief Write triangles (tetrahedra in 3d) of a witness
+ * complex in a file, compatible with medit.
+ * l_is_v = landmark is vertex
+ */
+template <typename SimplexHandleRange,
+ typename STree >
+void write_witness_mesh(Point_Vector& W, std::vector<int>& landmarks_ind, STree& st, SimplexHandleRange const & shr, bool is2d, bool l_is_v, std::string file_name = "witness.mesh")
+{
+ std::ofstream ofs (file_name, std::ofstream::out);
+ if (is2d)
+ ofs << "MeshVersionFormatted 1\nDimension 2\n";
+ else
+ ofs << "MeshVersionFormatted 1\nDimension 3\n";
+
+ if (!l_is_v)
+ ofs << "Vertices\n" << W.size() << "\n";
+ else
+ ofs << "Vertices\n" << landmarks_ind.size() << "\n";
+
+ if (l_is_v)
+ for (auto p_it : landmarks_ind) {
+ for (auto coord = W[p_it].cartesian_begin(); coord != W[p_it].cartesian_end() && coord != W[p_it].cartesian_begin()+3 ; ++coord)
+ ofs << *coord << " ";
+ ofs << "508\n";
+ }
+ else
+ for (auto p_it : W) {
+ for (auto coord = p_it.cartesian_begin(); coord != p_it.cartesian_end() && coord != p_it.cartesian_begin()+3 ; ++coord)
+ ofs << *coord << " ";
+ ofs << "508\n";
+ }
+
+ // int num_triangles = W.size(), num_tetrahedra = 0;
+ int num_edges = 0, num_triangles = 0, num_tetrahedra = 0;
+ if (!l_is_v) {
+ for (auto sh_it : shr)
+ if (st.dimension(sh_it) == 1)
+ num_edges++;
+ else if (st.dimension(sh_it) == 2)
+ num_triangles++;
+ else if (st.dimension(sh_it) == 3)
+ num_tetrahedra++;
+ ofs << "Edges " << num_edges << "\n";
+ for (auto sh_it : shr) {
+ if (st.dimension(sh_it) == 1) {
+ for (auto v_it : st.simplex_vertex_range(sh_it))
+ ofs << landmarks_ind[v_it]+1 << " ";
+ ofs << "200\n";
+ }
+ }
+ ofs << "Triangles " << num_triangles << "\n";
+ for (unsigned i = 0; i < W.size(); ++i)
+ ofs << i << " " << i << " " << i << " " << "508\n";
+ for (auto sh_it : shr)
+ {
+ if (st.dimension(sh_it) == 2) {
+ for (auto v_it : st.simplex_vertex_range(sh_it))
+ ofs << landmarks_ind[v_it]+1 << " ";
+ ofs << "508\n";
+ }
+ }
+ ofs << "Tetrahedra " << num_tetrahedra << "\n";
+ for (auto sh_it : shr)
+ {
+ if (st.dimension(sh_it) == 3) {
+ for (auto v_it : st.simplex_vertex_range(sh_it))
+ ofs << landmarks_ind[v_it]+1 << " ";
+ ofs << "250\n";
+ }
+ }
+ }
+ else {
+ for (auto sh_it : shr)
+ if (st.dimension(sh_it) == 1)
+ num_edges++;
+ else if (st.dimension(sh_it) == 2)
+ num_triangles++;
+ else if (st.dimension(sh_it) == 3)
+ num_tetrahedra++;
+ ofs << "Edges " << num_edges << "\n";
+ for (auto sh_it : shr) {
+ if (st.dimension(sh_it) == 1) {
+ for (auto v_it : st.simplex_vertex_range(sh_it))
+ ofs << v_it+1 << " ";
+ ofs << "200\n";
+ }
+ }
+ ofs << "Triangles " << num_triangles << "\n";
+ for (auto sh_it : shr)
+ {
+ if (st.dimension(sh_it) == 2) {
+ for (auto v_it : st.simplex_vertex_range(sh_it))
+ ofs << v_it+1 << " ";
+ ofs << "508\n";
+ }
+ }
+ ofs << "Tetrahedra " << num_tetrahedra << "\n";
+ for (auto sh_it : shr)
+ {
+ if (st.dimension(sh_it) == 3) {
+ for (auto v_it : st.simplex_vertex_range(sh_it))
+ ofs << v_it+1 << " ";
+ ofs << "250\n";
+ }
+ }
+ }
+
+ ofs << "End\n";
+ /*
+ else
+ {
+ ofs << "Tetrahedra " << t.number_of_finite_full_cells()+1 << "\n";
+ for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
+ {
+ if (t.is_infinite(fc_it))
+ continue;
+ for (auto vh_it = fc_it->vertices_begin(); vh_it != fc_it->vertices_end(); ++vh_it)
+ ofs << index_of_vertex[*vh_it] << " ";
+ ofs << "508\n";
+ }
+ ofs << nbV << " " << nbV << " " << nbV << " " << nbV << " " << 208 << "\n";
+ ofs << "End\n";
+ }
+ */
+ ofs.close();
+}
+
+void write_witness_mesh(Point_Vector& W, std::vector<int>& landmarks_ind, Gudhi::Simplex_tree<>& st, bool is2d, bool l_is_v, std::string file_name = "witness.mesh")
+{
+ write_witness_mesh(W, landmarks_ind, st, st.complex_simplex_range(), is2d, l_is_v, file_name);
+}
+
+/** \brief Write triangles (tetrahedra in 3d) of a Delaunay
+ * triangulation in a file, compatible with medit.
+ */
+void write_delaunay_mesh(Delaunay_triangulation& t, const Point_d& p, bool is2d)
+{
+ std::ofstream ofs ("delaunay.mesh", std::ofstream::out);
+ int nbV = t.number_of_vertices()+1;
+ if (is2d)
+ ofs << "MeshVersionFormatted 1\nDimension 2\n";
+ else
+ ofs << "MeshVersionFormatted 1\nDimension 3\n";
+ ofs << "Vertices\n" << nbV << "\n";
+ int ind = 1; //index of a vertex
+ std::map<Delaunay_triangulation::Vertex_handle, int> index_of_vertex;
+ for (auto v_it = t.vertices_begin(); v_it != t.vertices_end(); ++v_it)
+ {
+ if (t.is_infinite(v_it))
+ continue;
+ // Add maximum 3 coordinates
+ for (auto coord = v_it->point().cartesian_begin(); coord != v_it->point().cartesian_end() && coord != v_it->point().cartesian_begin()+3; ++coord)
+ ofs << *coord << " ";
+ ofs << "508\n";
+ index_of_vertex[v_it] = ind++;
+ }
+ for (auto coord = p.cartesian_begin(); coord != p.cartesian_end(); ++coord)
+ ofs << *coord << " ";
+ ofs << "208\n";
+ if (is2d)
+ {
+ ofs << "Triangles " << t.number_of_finite_full_cells()+1 << "\n";
+ for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
+ {
+ if (t.is_infinite(fc_it))
+ continue;
+ for (auto vh_it = fc_it->vertices_begin(); vh_it != fc_it->vertices_end(); ++vh_it)
+ ofs << index_of_vertex[*vh_it] << " ";
+ ofs << "508\n";
+ }
+ ofs << nbV << " " << nbV << " " << nbV << " " << 208 << "\n";
+ ofs << "End\n";
+ }
+ else if (p.size() == 3)
+ {
+ ofs << "Tetrahedra " << t.number_of_finite_full_cells()+1 << "\n";
+ for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
+ {
+ if (t.is_infinite(fc_it))
+ continue;
+ for (auto vh_it = fc_it->vertices_begin(); vh_it != fc_it->vertices_end(); ++vh_it)
+ ofs << index_of_vertex[*vh_it] << " ";
+ ofs << "508\n";
+ }
+ ofs << nbV << " " << nbV << " " << nbV << " " << nbV << " " << 208 << "\n";
+ ofs << "End\n";
+ }
+ else if (p.size() == 4)
+ {
+ ofs << "Tetrahedra " << 5*(t.number_of_finite_full_cells())+1 << "\n";
+ for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
+ {
+ if (t.is_infinite(fc_it))
+ continue;
+ for (auto vh_it = fc_it->vertices_begin(); vh_it != fc_it->vertices_end(); ++vh_it)
+ {
+ for (auto vh_it2 = fc_it->vertices_begin(); vh_it2 != fc_it->vertices_end(); ++vh_it2)
+ if (vh_it != vh_it2)
+ ofs << index_of_vertex[*vh_it2] << " ";
+ ofs << "508\n";
+ }
+ }
+ ofs << nbV << " " << nbV << " " << nbV << " " << nbV << " " << 208 << "\n";
+ ofs << "End\n";
+ }
+ ofs.close();
+}
+
+///////////////////////////////////////////////////////////////////////
+// PRINT VECTOR
+///////////////////////////////////////////////////////////////////////
+
+template <typename T>
+void print_vector(std::vector<T> v)
+{
+ std::cout << "[";
+ if (!v.empty())
+ {
+ std::cout << *(v.begin());
+ for (auto it = v.begin()+1; it != v.end(); ++it)
+ {
+ std::cout << ",";
+ std::cout << *it;
+ }
+ }
+ std::cout << "]";
+}
+
+
+#endif
diff --git a/src/Witness_complex/example/output_tikz.h b/src/Witness_complex/example/output_tikz.h
new file mode 100644
index 00000000..281c65b7
--- /dev/null
+++ b/src/Witness_complex/example/output_tikz.h
@@ -0,0 +1,178 @@
+#ifndef OUTPUT_TIKZ_H
+#define OUTPUT_TIKZ_H
+
+#include <vector>
+#include <string>
+#include <algorithm>
+#include <fstream>
+#include <cmath>
+
+typedef double FT;
+
+
+//////////////////AUX/////////////////////
+
+void write_preamble(std::ofstream& ofs)
+{
+ ofs << "\\documentclass{standalone}\n"
+ << "\\usepackage{tikz}\n\n"
+ << "\\begin{document}\n"
+ << "\\begin{tikzpicture}\n";
+}
+
+void write_end(std::ofstream& ofs)
+{
+ ofs << "\\end{tikzpicture}\n"
+ << "\\end{document}";
+}
+
+
+/////////////////MAIN//////////////////////
+
+void write_tikz_plot(std::vector<FT> data, std::string filename)
+{
+ int n = data.size();
+ FT vmax = *(std::max_element(data.begin(), data.end()));
+ //std::cout << std::log10(vmax) << " " << std::floor(std::log10(vmax));
+
+ FT order10 = pow(10,std::floor(std::log10(vmax)));
+ int digit = std::floor( vmax / order10) + 1;
+ if (digit == 4 || digit == 6) digit = 5;
+ if (digit > 6) digit = 10;
+ FT plot_max = digit*order10;
+ std::cout << plot_max << " " << vmax;
+ FT hstep = 10.0/(n-1);
+ FT wstep = 10.0 / plot_max;
+
+ std::cout << "(eps_max-eps_min)/(N-48) = " << (vmax-*data.begin())/(data.size()-48) << "\n";
+ std::ofstream ofs(filename, std::ofstream::out);
+
+ ofs <<
+ "\\documentclass{standalone}\n" <<
+ "\\usepackage[utf8]{inputenc}\n" <<
+ "\\usepackage{amsmath}\n" <<
+ "\\usepackage{tikz}\n\n" <<
+ "\\begin{document}\n" <<
+ "\\begin{tikzpicture}\n";
+
+ ofs << "\\draw[->] (0,0) -- (0,11);" << std::endl <<
+ "\\draw[->] (0,0) -- (11,0);" << std::endl <<
+ "\\foreach \\i in {1,...,10}" << std::endl <<
+ "\\draw (0,\\i) -- (-0.05,\\i);" << std::endl <<
+ "\\foreach \\i in {1,...,10}" << std::endl <<
+ "\\draw (\\i,0) -- (\\i,-0.05);" << std::endl << std::endl <<
+
+ "\\foreach \\i in {1,...,10}" << std::endl <<
+ "\\draw[dashed] (-0.05,\\i) -- (11,\\i);" << std::endl << std::endl <<
+
+ "\\node at (-0.5,11) {$*$}; " << std::endl <<
+ "\\node at (11,-0.5) {$*$}; " << std::endl <<
+ "\\node at (-0.5,-0.5) {0}; " << std::endl <<
+ "\\node at (-0.5,10) {" << plot_max << "}; " << std::endl <<
+ "%\\node at (10,-0.5) {2}; " << std::endl;
+
+ ofs << "\\draw[red] (0," << wstep*data[0] << ")";
+ for (int i = 1; i < n; ++i)
+ ofs << " -- (" << hstep*i << "," << wstep*data[i] << ")";
+ ofs << ";\n";
+
+ ofs <<
+ "\\end{tikzpicture}\n" <<
+ "\\end{document}";
+
+ ofs.close();
+}
+
+
+// A little script to make a tikz histogram of epsilon distribution
+// Returns the average epsilon
+void write_histogram(std::vector<double> histo, std::string file_name = "histogram.tikz", std::string xaxis = "$\\epsilon/\\epsilon_{max}$", std::string yaxis = "$\\epsilon$", FT max_x = 1)
+{
+ int n = histo.size();
+
+ std::ofstream ofs (file_name, std::ofstream::out);
+ FT barwidth = 20.0/n;
+ FT max_value = *(std::max_element(histo.begin(), histo.end()));
+ std::cout << max_value << std::endl;
+ FT ten_power = pow(10, ceil(log10(max_value)));
+ FT max_histo = ten_power;
+ if (max_value/ten_power > 1) {
+ if (max_value/ten_power < 2)
+ max_histo = 0.2*ten_power;
+ else if (max_value/ten_power < 5)
+ max_histo = 0.5*ten_power;
+ }
+ std::cout << ceil(log10(max_value)) << std::endl << max_histo << std::endl;
+ FT unitht = max_histo/10.0;
+ write_preamble(ofs);
+
+ ofs << "\\draw[->] (0,0) -- (0,11);\n" <<
+ "\\draw[->] (0,0) -- (21,0);\n" <<
+ "\\foreach \\i in {1,...,10}\n" <<
+ "\\draw (0,\\i) -- (-0.1,\\i);\n" <<
+ "\\foreach \\i in {1,...,20}\n" <<
+ "\\draw (\\i,0) -- (\\i,-0.1);\n" <<
+
+ "\\node at (-1,11) {" << yaxis << "};\n" <<
+ "\\node at (22,-1) {" << xaxis << "};\n" <<
+ "\\node at (-0.5,-0.5) {0};\n" <<
+ "\\node at (-0.5,10) {" << max_histo << "};\n" <<
+ "\\node at (20,-0.5) {" << max_x << "};\n";
+
+ for (int i = 0; i < n; ++i)
+ ofs << "\\draw (" << barwidth*i << "," << histo[i]/unitht << ") -- ("
+ << barwidth*(i+1) << "," << histo[i]/unitht << ") -- ("
+ << barwidth*(i+1) << ",0) -- (" << barwidth*i << ",0) -- cycle;\n";
+
+ write_end(ofs);
+ ofs.close();
+}
+
+struct Pers_interval {
+ double alpha_start, alpha_end;
+ int dim;
+ Pers_interval(double alpha_start_, double alpha_end_, int dim_)
+ : alpha_start(alpha_start_), alpha_end(alpha_end_), dim(dim_)
+ {}
+};
+
+void write_barcodes(std::string in_file, double alpha2, std::string out_file = "barcodes.tikz.tex")
+{
+ std::ifstream ifs(in_file, std::ios::in);
+ std::string line;
+ std::vector<Pers_interval> pers_intervals;
+ while (getline(ifs, line)) {
+ int p, dim;
+ double alpha_start, alpha_end;
+ std::istringstream iss(line);
+ iss >> p >> dim >> alpha_start >> alpha_end;
+ if (alpha_start != alpha_end) {
+ if (alpha_end < alpha_start)
+ alpha_end = alpha2;
+ pers_intervals.push_back(Pers_interval(alpha_start, alpha_end, dim));
+ }
+ }
+ ifs.close();
+ std::ofstream ofs (out_file, std::ofstream::out);
+ write_preamble(ofs);
+ double barwidth = 0.01;
+ int i = 0;
+ for (auto interval: pers_intervals) {
+ std::string color = "black";
+ switch (interval.dim) {
+ case 0: color = "orange"; break;
+ case 1: color = "red"; break;
+ case 2: color = "blue"; break;
+ case 3: color = "green"; break;
+ case 4: color = "yellow"; break;
+ default: color = "orange"; break;
+ }
+ ofs << "\\fill[" << color << "] (" << interval.alpha_start << "," << barwidth*i << ") rectangle ("
+ << interval.alpha_end << "," << barwidth*(i+1) <<");\n";
+ i++;
+ }
+ write_end(ofs);
+ ofs.close();
+}
+
+#endif
diff --git a/src/Witness_complex/example/relaxed_delaunay.cpp b/src/Witness_complex/example/relaxed_delaunay.cpp
new file mode 100644
index 00000000..b0190446
--- /dev/null
+++ b/src/Witness_complex/example/relaxed_delaunay.cpp
@@ -0,0 +1,180 @@
+/* This file is part of the Gudhi Library. The Gudhi library
+ * (Geometric Understanding in Higher Dimensions) is a generic C++
+ * library for computational topology.
+ *
+ * Author(s): Siargey Kachanovich
+ *
+ * Copyright (C) 2016 INRIA Sophia Antipolis-Méditerranée (France)
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gudhi/Simplex_tree.h>
+#include <gudhi/Relaxed_witness_complex.h>
+#include <gudhi/Dim_lists.h>
+#include <gudhi/reader_utils.h>
+#include <gudhi/Persistent_cohomology.h>
+#include "Landmark_choice_random_knn.h"
+#include "Landmark_choice_sparsification.h"
+
+#include <iostream>
+#include <fstream>
+#include <ctime>
+#include <utility>
+#include <algorithm>
+#include <set>
+#include <queue>
+#include <iterator>
+#include <string>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/iterator/zip_iterator.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/range/iterator_range.hpp>
+
+#include <CGAL/Epick_d.h>
+#include <CGAL/Delaunay_triangulation.h>
+//#include <CGAL/Sphere_d.h>
+
+#include "generators.h"
+#include "output.h"
+
+using namespace Gudhi;
+using namespace Gudhi::witness_complex;
+using namespace Gudhi::persistent_cohomology;
+
+typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> K;
+typedef K::Point_d Point_d;
+typedef K::Sphere_d Sphere_d;
+typedef CGAL::Delaunay_triangulation<K> Delaunay_triangulation;
+
+typedef std::vector<Point_d> Point_Vector;
+typedef Relaxed_witness_complex< Simplex_tree<> > RelaxedWitnessComplex;
+typedef Simplex_tree<>::Simplex_handle Simplex_handle;
+
+
+
+/**
+ * \brief Customized version of read_points
+ * which takes into account a possible nbP first line
+ *
+ */
+inline void
+read_points_cust(std::string file_name, std::vector< std::vector< double > > & points) {
+ std::ifstream in_file(file_name.c_str(), std::ios::in);
+ if (!in_file.is_open()) {
+ std::cerr << "Unable to open file " << file_name << std::endl;
+ return;
+ }
+ std::string line;
+ double x;
+ while (getline(in_file, line)) {
+ std::vector< double > point;
+ std::istringstream iss(line);
+ while (iss >> x) {
+ point.push_back(x);
+ }
+ if (point.size() != 1)
+ points.push_back(point);
+ }
+ in_file.close();
+}
+
+int main (int argc, char * const argv[])
+{
+ if (argc != 4) {
+ std::cerr << "Usage: " << argv[0]
+ << " 1 file_name alpha limD\n";
+ return 0;
+ }
+ std::string file_name = argv[1];
+ double alpha2 = atof(argv[2]);
+ int limD = atoi(argv[3]);
+
+ // Read points
+ Point_Vector point_vector;
+ read_points_cust(file_name, point_vector);
+ generate_points_random_box(point_vector, 200, 2);
+ write_points(file_name, point_vector);
+
+ std::cout << "The file contains " << point_vector.size() << " points.\n";
+ std::cout << "Ambient dimension is " << point_vector[0].size() << ".\n";
+
+ // 1. Compute Delaunay centers
+ Delaunay_triangulation delaunay(point_vector[0].size());
+ delaunay.insert(point_vector.begin(), point_vector.end());
+ Point_Vector del_centers;
+ for (auto f_it = delaunay.full_cells_begin(); f_it != delaunay.full_cells_end(); ++f_it) {
+ if (delaunay.is_infinite(f_it))
+ continue;
+ Point_Vector vertices;
+ for (auto v_it = f_it->vertices_begin(); v_it != f_it->vertices_end(); ++v_it)
+ vertices.push_back((*v_it)->point());
+ Sphere_d sphere(vertices.begin(), vertices.end());
+ del_centers.push_back(sphere.center());
+ }
+ std::cout << "Delaunay center count: " << del_centers.size() << ".\n";
+
+ // 2. Build Relaxed Witness Complex
+ std::vector<std::vector<int>> knn;
+ std::vector<std::vector<double>> distances;
+ Gudhi::witness_complex::build_distance_matrix(del_centers, // aka witnesses
+ point_vector, // aka landmarks
+ alpha2,
+ limD,
+ knn,
+ distances);
+
+ write_wl("wl_distances.txt", distances);
+ Simplex_tree<> simplex_tree;
+ Gudhi::witness_complex::Relaxed_witness_complex<Simplex_tree<>> rwc(distances,
+ knn,
+ simplex_tree,
+ point_vector.size(),
+ alpha2,
+ limD);
+ std::vector<int> dim_simplices(limD+1);
+ for (auto sh: simplex_tree.complex_simplex_range()) {
+ dim_simplices[simplex_tree.dimension(sh)]++;
+ }
+ for (unsigned i =0; i != dim_simplices.size(); ++i)
+ std::cout << "dim[" << i << "]: " << dim_simplices[i] << " simplices.\n";
+
+ std::vector<int> landmarks_ind;
+ for (unsigned i = 0; i < point_vector.size(); ++i)
+ landmarks_ind.push_back(i);
+ write_witness_mesh(point_vector, landmarks_ind, simplex_tree, simplex_tree.complex_simplex_range(), true, true, "relaxed_delaunay.mesh");
+
+ // 3. Check if the thing is Relaxed Delaunay
+ for (auto sh: simplex_tree.complex_simplex_range()) {
+ Point_Vector vertices;
+ for (auto v: simplex_tree.simplex_vertex_range(sh))
+ vertices.push_back(point_vector[v]);
+ Sphere_d sphere(vertices.begin(), vertices.end());
+ Point_d center = sphere.center();
+ double r2 = sphere.squared_radius();
+ typename K::Squared_distance_d dist2;
+ std::vector<int> v_inds;
+ for (auto v: simplex_tree.simplex_vertex_range(sh))
+ v_inds.push_back(v);
+ auto range_begin = std::begin(v_inds);
+ auto range_end = std::end(v_inds);
+ if (simplex_tree.dimension(sh) == (int)point_vector[0].size())
+ for (auto v: simplex_tree.complex_vertex_range())
+ if (std::find(range_begin, range_end, v) == range_end) {
+ if (dist2(point_vector[v], center) < r2 - alpha2)
+ std::cout << "WARNING! The vertex " << point_vector[v] << " is inside the (r2-alpha2)-ball (" << center << ", " << r2 << ") distance is " << dist2(point_vector[v], center) << "\n";
+ }
+ }
+}
diff --git a/src/Witness_complex/example/relaxed_witness_complex_sphere.cpp b/src/Witness_complex/example/relaxed_witness_complex_sphere.cpp
new file mode 100644
index 00000000..067321ce
--- /dev/null
+++ b/src/Witness_complex/example/relaxed_witness_complex_sphere.cpp
@@ -0,0 +1,461 @@
+/* This file is part of the Gudhi Library. The Gudhi library
+ * (Geometric Understanding in Higher Dimensions) is a generic C++
+ * library for computational topology.
+ *
+ * Author(s): Siargey Kachanovich
+ *
+ * Copyright (C) 2015 INRIA Sophia Antipolis-Méditerranée (France)
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <iostream>
+#include <fstream>
+#include <ctime>
+#include <utility>
+#include <algorithm>
+#include <set>
+#include <queue>
+#include <iterator>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+//#include <stdlib.h>
+
+//#include "gudhi/graph_simplicial_complex.h"
+#include "gudhi/Relaxed_witness_complex.h"
+#include "gudhi/reader_utils.h"
+#include "gudhi/Collapse/Collapse.h"
+//#include <boost/filesystem.hpp>
+
+//#include <CGAL/Delaunay_triangulation.h>
+#include <CGAL/Cartesian_d.h>
+#include <CGAL/Search_traits.h>
+#include <CGAL/Search_traits_adapter.h>
+#include <CGAL/property_map.h>
+#include <CGAL/Epick_d.h>
+#include <CGAL/Orthogonal_incremental_neighbor_search.h>
+#include <CGAL/Kd_tree.h>
+#include <CGAL/Euclidean_distance.h>
+
+#include <CGAL/Kernel_d/Vector_d.h>
+#include <CGAL/point_generators_d.h>
+#include <CGAL/constructions_d.h>
+#include <CGAL/Fuzzy_sphere.h>
+#include <CGAL/Random.h>
+
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/iterator/zip_iterator.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/range/iterator_range.hpp>
+
+using namespace Gudhi;
+//using namespace boost::filesystem;
+
+typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> K;
+typedef K::FT FT;
+typedef K::Point_d Point_d;
+typedef CGAL::Search_traits<
+ FT, Point_d,
+ typename K::Cartesian_const_iterator_d,
+ typename K::Construct_cartesian_const_iterator_d> Traits_base;
+typedef CGAL::Euclidean_distance<Traits_base> Euclidean_distance;
+
+typedef std::vector< Vertex_handle > typeVectorVertex;
+
+//typedef std::pair<typeVectorVertex, Filtration_value> typeSimplex;
+//typedef std::pair< Simplex_tree<>::Simplex_handle, bool > typePairSimplexBool;
+
+typedef CGAL::Search_traits_adapter<
+ std::ptrdiff_t, Point_d*, Traits_base> STraits;
+//typedef K TreeTraits;
+//typedef CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance > Euclidean_adapter;
+//typedef CGAL::Kd_tree<STraits> Kd_tree;
+typedef CGAL::Orthogonal_incremental_neighbor_search<STraits, CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance>> Neighbor_search;
+typedef Neighbor_search::Tree Tree;
+typedef Neighbor_search::Distance Distance;
+typedef Neighbor_search::iterator KNS_iterator;
+typedef Neighbor_search::iterator KNS_range;
+typedef boost::container::flat_map<int, int> Point_etiquette_map;
+typedef CGAL::Kd_tree<STraits> Tree2;
+
+typedef CGAL::Fuzzy_sphere<STraits> Fuzzy_sphere;
+
+typedef std::vector<Point_d> Point_Vector;
+
+//typedef K::Equal_d Equal_d;
+typedef CGAL::Random_points_in_cube_d<Point_d> Random_cube_iterator;
+typedef CGAL::Random_points_in_ball_d<Point_d> Random_point_iterator;
+
+bool toric=false;
+
+/**
+ * \brief Customized version of read_points
+ * which takes into account a possible nbP first line
+ *
+ */
+inline void
+read_points_cust ( std::string file_name , Point_Vector & points)
+{
+ std::ifstream in_file (file_name.c_str(),std::ios::in);
+ if(!in_file.is_open())
+ {
+ std::cerr << "Unable to open file " << file_name << std::endl;
+ return;
+ }
+ std::string line;
+ double x;
+ while( getline ( in_file , line ) )
+ {
+ std::vector< double > point;
+ std::istringstream iss( line );
+ while(iss >> x) { point.push_back(x); }
+ Point_d p(point.begin(), point.end());
+ if (point.size() != 1)
+ points.push_back(p);
+ }
+ in_file.close();
+}
+
+
+void generate_points_sphere(Point_Vector& W, int nbP, int dim)
+{
+ CGAL::Random_points_on_sphere_d<Point_d> rp(dim,1);
+ for (int i = 0; i < nbP; i++)
+ W.push_back(*rp++);
+}
+
+
+void write_wl( std::string file_name, std::vector< std::vector <int> > & WL)
+{
+ std::ofstream ofs (file_name, std::ofstream::out);
+ for (auto w : WL)
+ {
+ for (auto l: w)
+ ofs << l << " ";
+ ofs << "\n";
+ }
+ ofs.close();
+}
+
+void write_rl( std::string file_name, std::vector< std::vector <std::vector<int>::iterator> > & rl)
+{
+ std::ofstream ofs (file_name, std::ofstream::out);
+ for (auto w : rl)
+ {
+ for (auto l: w)
+ ofs << *l << " ";
+ ofs << "\n";
+ }
+ ofs.close();
+}
+
+std::vector<Point_d> convert_to_torus(std::vector< Point_d>& points)
+{
+ std::vector< Point_d > points_torus;
+ for (auto p: points)
+ {
+ FT theta = M_PI*p[0];
+ FT phi = M_PI*p[1];
+ std::vector<FT> p_torus;
+ p_torus.push_back((1+0.2*cos(theta))*cos(phi));
+ p_torus.push_back((1+0.2*cos(theta))*sin(phi));
+ p_torus.push_back(0.2*sin(theta));
+ points_torus.push_back(Point_d(p_torus));
+ }
+ return points_torus;
+}
+
+
+void write_points_torus( std::string file_name, std::vector< Point_d > & points)
+{
+ std::ofstream ofs (file_name, std::ofstream::out);
+ std::vector<Point_d> points_torus = convert_to_torus(points);
+ for (auto w : points_torus)
+ {
+ for (auto it = w.cartesian_begin(); it != w.cartesian_end(); ++it)
+ ofs << *it << " ";
+ ofs << "\n";
+ }
+ ofs.close();
+}
+
+
+void write_points( std::string file_name, std::vector< Point_d > & points)
+{
+ if (toric) write_points_torus(file_name, points);
+ else
+ {
+ std::ofstream ofs (file_name, std::ofstream::out);
+ for (auto w : points)
+ {
+ for (auto it = w.cartesian_begin(); it != w.cartesian_end(); ++it)
+ ofs << *it << " ";
+ ofs << "\n";
+ }
+ ofs.close();
+ }
+}
+
+
+void write_edges_torus(std::string file_name, Witness_complex<>& witness_complex, Point_Vector& landmarks)
+{
+ std::ofstream ofs (file_name, std::ofstream::out);
+ Point_Vector l_torus = convert_to_torus(landmarks);
+ for (auto u: witness_complex.complex_vertex_range())
+ for (auto v: witness_complex.complex_vertex_range())
+ {
+ typeVectorVertex edge = {u,v};
+ if (u < v && witness_complex.find(edge) != witness_complex.null_simplex())
+ {
+ for (auto it = l_torus[u].cartesian_begin(); it != l_torus[u].cartesian_end(); ++it)
+ ofs << *it << " ";
+ ofs << "\n";
+ for (auto it = l_torus[v].cartesian_begin(); it != l_torus[v].cartesian_end(); ++it)
+ ofs << *it << " ";
+ ofs << "\n\n\n";
+ }
+ }
+ ofs.close();
+}
+
+void write_edges(std::string file_name, Witness_complex<>& witness_complex, Point_Vector& landmarks)
+{
+ std::ofstream ofs (file_name, std::ofstream::out);
+ if (toric) write_edges_torus(file_name, witness_complex, landmarks);
+ else
+ {
+ for (auto u: witness_complex.complex_vertex_range())
+ for (auto v: witness_complex.complex_vertex_range())
+ {
+ typeVectorVertex edge = {u,v};
+ if (u < v && witness_complex.find(edge) != witness_complex.null_simplex())
+ {
+ for (auto it = landmarks[u].cartesian_begin(); it != landmarks[u].cartesian_end(); ++it)
+ ofs << *it << " ";
+ ofs << "\n";
+ for (auto it = landmarks[v].cartesian_begin(); it != landmarks[v].cartesian_end(); ++it)
+ ofs << *it << " ";
+ ofs << "\n\n\n";
+ }
+ }
+ ofs.close();
+ }
+}
+
+
+/** Function that chooses landmarks from W and place it in the kd-tree L.
+ * Note: nbL hould be removed if the code moves to Witness_complex
+ */
+void landmark_choice(Point_Vector &W, int nbP, int nbL, Point_Vector& landmarks, std::vector<int>& landmarks_ind)
+{
+ std::cout << "Enter landmark choice to kd tree\n";
+ //std::vector<Point_d> landmarks;
+ int chosen_landmark;
+ //std::pair<Point_etiquette_map::iterator,bool> res = std::make_pair(L_i.begin(),false);
+ Point_d* p;
+ CGAL::Random rand;
+ for (int i = 0; i < nbL; i++)
+ {
+ // while (!res.second)
+ // {
+ do chosen_landmark = rand.get_int(0,nbP);
+ while (std::find(landmarks_ind.begin(), landmarks_ind.end(), chosen_landmark) != landmarks_ind.end());
+ //rand++;
+ //std::cout << "Chose " << chosen_landmark << std::endl;
+ p = &W[chosen_landmark];
+ //L_i.emplace(chosen_landmark,i);
+ // }
+ landmarks.push_back(*p);
+ landmarks_ind.push_back(chosen_landmark);
+ //std::cout << "Added landmark " << chosen_landmark << std::endl;
+ }
+ }
+
+
+void landmarks_to_witness_complex(Point_Vector &W, Point_Vector& landmarks, std::vector<int>& landmarks_ind, FT alpha)
+{
+ //********************Preface: origin point
+ unsigned D = W[0].size();
+ std::vector<FT> orig_vector;
+ for (unsigned i = 0; i < D; i++)
+ orig_vector.push_back(0);
+ Point_d origin(orig_vector);
+ //Distance dist;
+ //dist.transformed_distance(0,1);
+ //******************** Constructing a WL matrix
+ int nbP = W.size();
+ int nbL = landmarks.size();
+ STraits traits(&(landmarks[0]));
+ Euclidean_distance ed;
+ std::vector< std::vector <int> > WL(nbP);
+ std::vector< std::vector< typename std::vector<int>::iterator > > ope_limits(nbP);
+ Tree L(boost::counting_iterator<std::ptrdiff_t>(0),
+ boost::counting_iterator<std::ptrdiff_t>(nbL),
+ typename Tree::Splitter(),
+ traits);
+
+ std::cout << "Enter (D+1) nearest landmarks\n";
+ //std::cout << "Size of the tree is " << L.size() << std::endl;
+ for (int i = 0; i < nbP; i++)
+ {
+ //std::cout << "Entered witness number " << i << std::endl;
+ Point_d& w = W[i];
+ std::queue< typename std::vector<int>::iterator > ope_queue; // queue of points at (1+epsilon) distance to current landmark
+ Neighbor_search search(L, w, FT(0), true, CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance>(&(landmarks[0])));
+ Neighbor_search::iterator search_it = search.begin();
+
+ //Incremental search and filling WL
+ while (WL[i].size() < D)
+ WL[i].push_back((search_it++)->first);
+ FT dtow = ed.transformed_distance(w, landmarks[WL[i][D-1]]);
+ while (search_it->second < dtow + alpha)
+ WL[i].push_back((search_it++)->first);
+
+ //Filling the (1+epsilon)-limits table
+ for (std::vector<int>::iterator wl_it = WL[i].begin(); wl_it != WL[i].end(); ++wl_it)
+ {
+ ope_queue.push(wl_it);
+ FT d_to_curr_l = ed.transformed_distance(w, landmarks[*wl_it]);
+ //std::cout << "d_to_curr_l=" << d_to_curr_l << std::endl;
+ //std::cout << "d_to_front+alpha=" << d_to_curr_l << std::endl;
+ while (d_to_curr_l > alpha + ed.transformed_distance(w, landmarks[*(ope_queue.front())]))
+ {
+ ope_limits[i].push_back(wl_it);
+ ope_queue.pop();
+ }
+ }
+ while (ope_queue.size() > 0)
+ {
+ ope_limits[i].push_back(WL[i].end());
+ ope_queue.pop();
+ }
+ //std::cout << "Safely constructed a point\n";
+ ////Search D+1 nearest neighbours from the tree of landmarks L
+ /*
+ if (w[0]>0.95)
+ std::cout << i << std::endl;
+ */
+ //K_neighbor_search search(L, w, D, FT(0), true,
+ // CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance>(&(landmarks[0])) );
+ //std::cout << "Safely found nearest landmarks\n";
+ /*
+ for(K_neighbor_search::iterator it = search.begin(); it != search.end(); ++it)
+ {
+ //std::cout << "Entered KNN_it with point at distance " << it->second << "\n";
+ //Point_etiquette_map::iterator itm = L_i.find(it->first);
+ //assert(itm != L_i.end());
+ //std::cout << "Entered KNN_it with point at distance " << it->second << "\n";
+ WL[i].push_back(it->first);
+ //std::cout << "ITFIRST " << it->first << std::endl;
+ //std::cout << i << " " << it->first << ": " << it->second << std::endl;
+ }
+ */
+ }
+ //std::cout << "\n";
+
+ //std::string out_file = "wl_result";
+ write_wl("wl_result",WL);
+ write_rl("rl_result",ope_limits);
+
+ //******************** Constructng a witness complex
+ std::cout << "Entered witness complex construction\n";
+ Witness_complex<> witnessComplex;
+ witnessComplex.setNbL(nbL);
+ witnessComplex.relaxed_witness_complex(WL, ope_limits);
+ char buffer[100];
+ int i = sprintf(buffer,"stree_result.txt");
+
+ if (i >= 0)
+ {
+ std::string out_file = (std::string)buffer;
+ std::ofstream ofs (out_file, std::ofstream::out);
+ witnessComplex.st_to_file(ofs);
+ ofs.close();
+ }
+ write_edges("landmarks/edges", witnessComplex, landmarks);
+ std::cout << Distance().transformed_distance(Point_d(std::vector<double>({0.1,0.1})), Point_d(std::vector<double>({1.9,1.9}))) << std::endl;
+}
+
+
+int main (int argc, char * const argv[])
+{
+
+ if (argc != 5)
+ {
+ std::cerr << "Usage: " << argv[0]
+ << " nbP nbL dim alpha\n";
+ return 0;
+ }
+ /*
+ boost::filesystem::path p;
+ for (; argc > 2; --argc, ++argv)
+ p /= argv[1];
+ */
+
+ int nbP = atoi(argv[1]);
+ int nbL = atoi(argv[2]);
+ int dim = atoi(argv[3]);
+ double alpha = atof(argv[4]);
+ //clock_t start, end;
+ //Construct the Simplex Tree
+ Witness_complex<> witnessComplex;
+
+ std::cout << "Let the carnage begin!\n";
+ Point_Vector point_vector;
+ //read_points_cust(file_name, point_vector);
+ generate_points_sphere(point_vector, nbP, dim);
+ /*
+ for (auto &p: point_vector)
+ {
+ assert(std::count(point_vector.begin(),point_vector.end(),p) == 1);
+ }
+ */
+ //std::cout << "Successfully read the points\n";
+ //witnessComplex.setNbL(nbL);
+ Point_Vector L;
+ std::vector<int> chosen_landmarks;
+ landmark_choice(point_vector, nbP, nbL, L, chosen_landmarks);
+ //start = clock();
+
+ write_points("landmarks/initial_pointset",point_vector);
+ write_points("landmarks/initial_landmarks",L);
+
+ landmarks_to_witness_complex(point_vector, L, chosen_landmarks, alpha);
+ //end = clock();
+
+ /*
+ std::cout << "Landmark choice took "
+ << (double)(end-start)/CLOCKS_PER_SEC << " s. \n";
+ start = clock();
+ witnessComplex.witness_complex(WL);
+ //
+ end = clock();
+ std::cout << "Howdy world! The process took "
+ << (double)(end-start)/CLOCKS_PER_SEC << " s. \n";
+ */
+
+ /*
+ out_file = "output/"+file_name+"_"+argv[2]+".stree";
+ std::ofstream ofs (out_file, std::ofstream::out);
+ witnessComplex.st_to_file(ofs);
+ ofs.close();
+
+ out_file = "output/"+file_name+"_"+argv[2]+".badlinks";
+ std::ofstream ofs2(out_file, std::ofstream::out);
+ witnessComplex.write_bad_links(ofs2);
+ ofs2.close();
+ */
+}
diff --git a/src/Witness_complex/example/relaxed_witness_persistence.cpp b/src/Witness_complex/example/relaxed_witness_persistence.cpp
index b8e4866f..b4837594 100644
--- a/src/Witness_complex/example/relaxed_witness_persistence.cpp
+++ b/src/Witness_complex/example/relaxed_witness_persistence.cpp
@@ -4,7 +4,7 @@
*
* Author(s): Siargey Kachanovich
*
- * Copyright (C) 2015 INRIA Sophia Antipolis-Méditerranée (France)
+ * Copyright (C) 2016 INRIA Sophia Antipolis-Méditerranée (France)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,9 +22,11 @@
#include <gudhi/Simplex_tree.h>
#include <gudhi/Relaxed_witness_complex.h>
+#include <gudhi/Dim_lists.h>
#include <gudhi/reader_utils.h>
#include <gudhi/Persistent_cohomology.h>
#include "Landmark_choice_random_knn.h"
+#include "Landmark_choice_sparsification.h"
#include <iostream>
#include <fstream>
@@ -34,6 +36,7 @@
#include <set>
#include <queue>
#include <iterator>
+#include <string>
#include <boost/tuple/tuple.hpp>
#include <boost/iterator/zip_iterator.hpp>
@@ -49,6 +52,7 @@ using namespace Gudhi::persistent_cohomology;
typedef std::vector<Point_d> Point_Vector;
typedef Relaxed_witness_complex< Simplex_tree<> > RelaxedWitnessComplex;
+typedef Simplex_tree<>::Simplex_handle Simplex_handle;
/**
* \brief Customized version of read_points
@@ -81,7 +85,7 @@ void output_experiment_information(char * const file_name)
std::cout << "Enter a valid experiment number. Usage: "
<< file_name << " exp_no options\n";
std::cout << "Experiment description:\n"
- << "0 nbP nbL dim alpha limD: "
+ << "0 nbP nbL dim alpha limD mu_epsilon: "
<< "Build persistence diagram on relaxed witness complex "
<< "built from a point cloud on (dim-1)-dimensional sphere "
<< "consisting of nbP witnesses and nbL landmarks. "
@@ -93,7 +97,7 @@ void output_experiment_information(char * const file_name)
<< "The maximal relaxation is alpha and the limit on simplicial complex dimension is limD\n";
}
-void rw_experiment(Point_Vector & point_vector, int nbL, FT alpha, int limD)
+void rw_experiment(Point_Vector & point_vector, int nbL, FT alpha, int limD, FT mu_epsilon = 0.1)
{
clock_t start, end;
Simplex_tree<> simplex_tree;
@@ -102,81 +106,60 @@ void rw_experiment(Point_Vector & point_vector, int nbL, FT alpha, int limD)
std::vector<std::vector< int > > knn;
std::vector<std::vector< FT > > distances;
start = clock();
- Gudhi::witness_complex::landmark_choice_by_random_knn(point_vector, nbL, alpha, limD, knn, distances);
+ //Gudhi::witness_complex::landmark_choice_by_random_knn(point_vector, nbL, alpha, limD, knn, distances);
+ std::vector<Point_d> landmarks;
+ Gudhi::witness_complex::landmark_choice_by_sparsification(point_vector, nbL, mu_epsilon, landmarks);
+ Gudhi::witness_complex::build_distance_matrix(point_vector, // aka witnesses
+ landmarks, // aka landmarks
+ alpha,
+ limD,
+ knn,
+ distances);
end = clock();
double time = static_cast<double>(end - start) / CLOCKS_PER_SEC;
std::cout << "Choice of " << nbL << " landmarks took "
<< time << " s. \n";
// Compute witness complex
start = clock();
- RelaxedWitnessComplex(distances,
- knn,
- simplex_tree,
- nbL,
- alpha,
- limD);
+ RelaxedWitnessComplex rw(distances,
+ knn,
+ simplex_tree,
+ nbL,
+ alpha,
+ limD);
end = clock();
time = static_cast<double>(end - start) / CLOCKS_PER_SEC;
- std::cout << "Witness complex for " << nbL << " landmarks took "
+ std::cout << "Relaxed witness complex for " << nbL << " landmarks took "
<< time << " s. \n";
std::cout << "The complex contains " << simplex_tree.num_simplices() << " simplices \n";
// std::cout << simplex_tree << "\n";
// Compute the persistence diagram of the complex
- persistent_cohomology::Persistent_cohomology< Simplex_tree<>, Field_Zp > pcoh(simplex_tree, false);
+ simplex_tree.set_dimension(limD);
+ persistent_cohomology::Persistent_cohomology< Simplex_tree<>, Field_Zp > pcoh(simplex_tree, true);
int p = 3;
pcoh.init_coefficients( p ); //initilizes the coefficient field for homology
start = clock();
- pcoh.compute_persistent_cohomology( alpha/5 );
+ pcoh.compute_persistent_cohomology( alpha/1000 );
end = clock();
time = static_cast<double>(end - start) / CLOCKS_PER_SEC;
std::cout << "Persistence diagram took "
<< time << " s. \n";
pcoh.output_diagram();
-}
-
-void rips_experiment(Point_Vector & points, double threshold, int dim_max)
-{
- typedef std::vector<double> Point_t;
- typedef Simplex_tree<Simplex_tree_options_fast_persistence> ST;
- clock_t start, end;
- ST st;
-
- // Compute the proximity graph of the points
- start = clock();
- Graph_t prox_graph = compute_proximity_graph(points, threshold
- , euclidean_distance<Point_t>);
- // Construct the Rips complex in a Simplex Tree
- // insert the proximity graph in the simplex tree
- st.insert_graph(prox_graph);
- // expand the graph until dimension dim_max
- st.expansion(dim_max);
- end = clock();
-
- double time = static_cast<double>(end - start) / CLOCKS_PER_SEC;
- std::cout << "Rips complex took "
- << time << " s. \n";
- std::cout << "The complex contains " << st.num_simplices() << " simplices \n";
- //std::cout << " and has dimension " << st.dimension() << " \n";
- // Sort the simplices in the order of the filtration
- st.initialize_filtration();
+ int chi = 0;
+ for (auto sh: simplex_tree.complex_simplex_range())
+ chi += 1-2*(simplex_tree.dimension(sh)%2);
+ std::cout << "Euler characteristic is " << chi << std::endl;
- // Compute the persistence diagram of the complex
- persistent_cohomology::Persistent_cohomology<ST, Field_Zp > pcoh(st);
- // initializes the coefficient field for homology
- int p = 3;
- double min_persistence = threshold/5;
- pcoh.init_coefficients(p);
- pcoh.compute_persistent_cohomology(min_persistence);
- pcoh.output_diagram();
}
+
int experiment0 (int argc, char * const argv[])
{
- if (argc != 7) {
+ if (argc != 8) {
std::cerr << "Usage: " << argv[0]
- << " 0 nbP nbL dim alpha limD\n";
+ << " 0 nbP nbL dim alpha limD mu_epsilon\n";
return 0;
}
/*
@@ -190,6 +173,7 @@ int experiment0 (int argc, char * const argv[])
int dim = atoi(argv[4]);
double alpha = atof(argv[5]);
int limD = atoi(argv[6]);
+ double mu_epsilon = atof(argv[7]);
// Read the point file
Point_Vector point_vector;
@@ -244,25 +228,25 @@ int experiment1 (int argc, char * const argv[])
ok = true; break;
}
}
- ok = false;
- while (!ok) {
- std::cout << "Rips complex: parameters threshold, limD.\n";
- std::cout << "Enter threshold: ";
- std::cin >> alpha;
- std::cout << "Enter limD: ";
- std::cin >> limD;
- std::cout << "Start Rips complex...\n";
- rips_experiment(point_vector, alpha, limD);
- std::cout << "Is the result correct? [y/n]: ";
- char answer;
- std::cin >> answer;
- switch (answer) {
- case 'n':
- ok = false; break;
- default :
- ok = true; break;
- }
- }
+ // ok = false;
+ // while (!ok) {
+ // std::cout << "Rips complex: parameters threshold, limD.\n";
+ // std::cout << "Enter threshold: ";
+ // std::cin >> alpha;
+ // std::cout << "Enter limD: ";
+ // std::cin >> limD;
+ // std::cout << "Start Rips complex...\n";
+ // rips_experiment(point_vector, alpha, limD);
+ // std::cout << "Is the result correct? [y/n]: ";
+ // char answer;
+ // std::cin >> answer;
+ // switch (answer) {
+ // case 'n':
+ // ok = false; break;
+ // default :
+ // ok = true; break;
+ // }
+ // }
}
int main (int argc, char * const argv[])
diff --git a/src/Witness_complex/example/strange_sphere.cpp b/src/Witness_complex/example/strange_sphere.cpp
new file mode 100644
index 00000000..9188bd8e
--- /dev/null
+++ b/src/Witness_complex/example/strange_sphere.cpp
@@ -0,0 +1,219 @@
+/* This file is part of the Gudhi Library. The Gudhi library
+ * (Geometric Understanding in Higher Dimensions) is a generic C++
+ * library for computational topology.
+ *
+ * Author(s): Siargey Kachanovich
+ *
+ * Copyright (C) 2015 INRIA Sophia Antipolis-Méditerranée (France)
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#define BOOST_PARAMETER_MAX_ARITY 12
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <gudhi/Simplex_tree.h>
+#include <gudhi/Strange_witness_complex.h>
+#include <gudhi/Landmark_choice_by_random_point.h>
+#include <gudhi/reader_utils.h>
+#include "output.h"
+
+#include <iostream>
+#include <fstream>
+#include <ctime>
+#include <utility>
+#include <string>
+#include <vector>
+
+#include <CGAL/Cartesian_d.h>
+#include <CGAL/Search_traits.h>
+#include <CGAL/Search_traits_adapter.h>
+#include <CGAL/property_map.h>
+#include <CGAL/Epick_d.h>
+#include <CGAL/Orthogonal_incremental_neighbor_search.h>
+#include <CGAL/Kd_tree.h>
+#include <CGAL/Euclidean_distance.h>
+
+#include <CGAL/Kernel_d/Vector_d.h>
+#include <CGAL/point_generators_d.h>
+#include <CGAL/constructions_d.h>
+#include <CGAL/Fuzzy_sphere.h>
+#include <CGAL/Random.h>
+
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/iterator/zip_iterator.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/range/iterator_range.hpp>
+
+
+#include "generators.h"
+
+using namespace Gudhi;
+using namespace Gudhi::witness_complex;
+
+typedef std::vector< Vertex_handle > typeVectorVertex;
+typedef Strange_witness_complex< Simplex_tree<> > WitnessComplex;
+
+typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> K;
+typedef K::FT FT;
+typedef K::Point_d Point_d;
+typedef CGAL::Search_traits<
+ FT, Point_d,
+ typename K::Cartesian_const_iterator_d,
+ typename K::Construct_cartesian_const_iterator_d> Traits_base;
+typedef CGAL::Euclidean_distance<Traits_base> Euclidean_distance;
+
+typedef CGAL::Search_traits_adapter<
+ std::ptrdiff_t, Point_d*, Traits_base> STraits;
+typedef CGAL::Orthogonal_incremental_neighbor_search<STraits, CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance>> Neighbor_search;
+typedef Neighbor_search::Tree Tree;
+typedef Neighbor_search::Distance Distance;
+typedef Neighbor_search::iterator KNS_iterator;
+typedef Neighbor_search::iterator KNS_range;
+typedef boost::container::flat_map<int, int> Point_etiquette_map;
+typedef CGAL::Kd_tree<STraits> Tree2;
+typedef CGAL::Fuzzy_sphere<STraits> Fuzzy_sphere;
+typedef std::vector<Point_d> Point_Vector;
+
+/** Function that chooses landmarks from W and place it in the kd-tree L.
+ * Note: nbL hould be removed if the code moves to Witness_complex
+ */
+void landmark_choice(Point_Vector &W, int nbP, int nbL, Point_Vector& landmarks, std::vector<int>& landmarks_ind)
+{
+ std::cout << "Enter landmark choice to kd tree\n";
+ //std::vector<Point_d> landmarks;
+ int chosen_landmark;
+ //std::pair<Point_etiquette_map::iterator,bool> res = std::make_pair(L_i.begin(),false);
+ Point_d* p;
+ CGAL::Random rand;
+ for (int i = 0; i < nbL; i++)
+ {
+ // while (!res.second)
+ // {
+ do chosen_landmark = rand.get_int(0,nbP);
+ while (std::find(landmarks_ind.begin(), landmarks_ind.end(), chosen_landmark) != landmarks_ind.end());
+ //rand++;
+ //std::cout << "Chose " << chosen_landmark << std::endl;
+ p = &W[chosen_landmark];
+ //L_i.emplace(chosen_landmark,i);
+ // }
+ landmarks.push_back(*p);
+ landmarks_ind.push_back(chosen_landmark);
+ //std::cout << "Added landmark " << chosen_landmark << std::endl;
+ }
+ }
+
+void landmarks_to_witness_complex(Point_Vector &W, int nbL)
+{
+ //********************Preface: origin point
+ unsigned D = W[0].size();
+ std::vector<FT> orig_vector;
+ for (unsigned i = 0; i < D; i++)
+ orig_vector.push_back(0);
+ Point_d origin(orig_vector);
+ //Distance dist;
+ //dist.transformed_distance(0,1);
+ //******************** Constructing a WL matrix
+ int nbP = W.size();
+ Point_Vector landmarks;
+ std::vector<int> landmarks_ind;
+ landmark_choice(W, nbP, nbL, landmarks, landmarks_ind);
+
+
+ STraits traits(&(landmarks[0]));
+ Euclidean_distance ed;
+ std::vector< std::vector <int> > WL(nbP);
+ std::vector< std::vector< typename std::vector<int>::iterator > > ope_limits(nbP);
+ Tree L(boost::counting_iterator<std::ptrdiff_t>(0),
+ boost::counting_iterator<std::ptrdiff_t>(nbL),
+ typename Tree::Splitter(),
+ traits);
+
+ std::cout << "Enter (D+1) nearest landmarks\n";
+ //std::cout << "Size of the tree is " << L.size() << std::endl;
+ for (int i = 0; i < nbP; i++) {
+ //std::cout << "Entered witness number " << i << std::endl;
+ Point_d& w = W[i];
+ std::queue< typename std::vector<int>::iterator > ope_queue; // queue of points at (1+epsilon) distance to current landmark
+ Neighbor_search search(L, w, FT(0), true, CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance>(&(landmarks[0])));
+ Neighbor_search::iterator search_it = search.begin();
+
+ //Incremental search and filling WL
+ while (WL[i].size() < D)
+ WL[i].push_back((search_it++)->first);
+ }
+ write_wl("WL.txt", WL); //!
+ //******************** Constructng a witness complex
+ std::cout << "Entered witness complex construction\n";
+
+ Simplex_tree<> simplex_tree;
+ WitnessComplex(WL, simplex_tree, nbL, W[0].size()-1);
+ //std::cout << simplex_tree << "\n"; //!
+ write_witness_mesh(W, landmarks_ind, simplex_tree, false, true);
+}
+
+
+
+/** Write a gnuplot readable file.
+ * Data range is a random access range of pairs (arg, value)
+ */
+template < typename Data_range >
+void write_data(Data_range & data, std::string filename) {
+ std::ofstream ofs(filename, std::ofstream::out);
+ for (auto entry : data)
+ ofs << entry.first << ", " << entry.second << "\n";
+ ofs.close();
+}
+
+
+
+int main(int argc, char * const argv[]) {
+ if (argc != 4) {
+ std::cerr << "Usage: " << argv[0]
+ << " nbP nbL dim\n";
+ return 0;
+ }
+
+ int nbP = atoi(argv[1]);
+ int nbL = atoi(argv[2]);
+ int dim = atoi(argv[3]);
+ clock_t start, end;
+
+ // Construct the Simplex Tree
+ Simplex_tree<> simplex_tree;
+
+ std::vector< std::pair<int, double> > l_time;
+
+ // Read the point file
+ Point_Vector point_vector;
+ generate_points_sphere(point_vector, nbP, dim);
+ std::cout << "Successfully generated " << point_vector.size() << " points.\n";
+ std::cout << "Ambient dimension is " << point_vector[0].size() << ".\n";
+
+ // Choose landmarks
+ start = clock();
+ std::vector<std::vector< int > > knn;
+
+ landmarks_to_witness_complex(point_vector, nbL);
+
+ end = clock();
+ double time = static_cast<double>(end - start) / CLOCKS_PER_SEC;
+ std::cout << "Witness complex for " << nbL << " landmarks took "
+ << time << " s. \n";
+ l_time.push_back(std::make_pair(nbP, time));
+ //write_data(l_time, "w_time.dat");
+}
diff --git a/src/Witness_complex/include/gudhi/A0_complex.h b/src/Witness_complex/include/gudhi/A0_complex.h
new file mode 100644
index 00000000..2018e1c8
--- /dev/null
+++ b/src/Witness_complex/include/gudhi/A0_complex.h
@@ -0,0 +1,337 @@
+/* This file is part of the Gudhi Library. The Gudhi library
+ * (Geometric Understanding in Higher Dimensions) is a generic C++
+ * library for computational topology.
+ *
+ * Author(s): Siargey Kachanovich
+ *
+ * Copyright (C) 2015 INRIA Sophia Antipolis-Méditerranée (France)
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef A0_COMPLEX_H_
+#define A0_COMPLEX_H_
+
+#include <boost/container/flat_map.hpp>
+#include <boost/iterator/transform_iterator.hpp>
+#include <algorithm>
+#include <utility>
+#include "gudhi/reader_utils.h"
+#include "gudhi/distance_functions.h"
+#include "gudhi/Simplex_tree.h"
+#include <vector>
+#include <list>
+#include <set>
+#include <queue>
+#include <limits>
+#include <math.h>
+#include <ctime>
+#include <iostream>
+
+// Needed for nearest neighbours
+#include <CGAL/Cartesian_d.h>
+#include <CGAL/Search_traits.h>
+#include <CGAL/Search_traits_adapter.h>
+#include <CGAL/property_map.h>
+#include <CGAL/Epick_d.h>
+#include <CGAL/Orthogonal_k_neighbor_search.h>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/iterator/zip_iterator.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/range/iterator_range.hpp>
+
+// Needed for the adjacency graph in bad link search
+#include <boost/graph/graph_traits.hpp>
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/graph/connected_components.hpp>
+
+namespace Gudhi {
+
+namespace witness_complex {
+
+ /** \addtogroup simplex_tree
+ * Witness complex is a simplicial complex defined on two sets of points in \f$\mathbf{R}^D\f$:
+ * \f$W\f$ set of witnesses and \f$L \subseteq W\f$ set of landmarks. The simplices are based on points in \f$L\f$
+ * and a simplex belongs to the witness complex if and only if it is witnessed (there exists a point \f$w \in W\f$ such that
+ * w is closer to the vertices of this simplex than others) and all of its faces are witnessed as well.
+ */
+template< class Simplicial_complex >
+class A0_complex {
+
+private:
+ struct Active_witness {
+ int witness_id;
+ int landmark_id;
+
+ Active_witness(int witness_id_, int landmark_id_)
+ : witness_id(witness_id_),
+ landmark_id(landmark_id_) { }
+ };
+
+private:
+ typedef typename Simplicial_complex::Simplex_handle Simplex_handle;
+ typedef typename Simplicial_complex::Vertex_handle Vertex_handle;
+ typedef typename Simplicial_complex::Filtration_value FT;
+
+ typedef std::vector< double > Point_t;
+ typedef std::vector< Point_t > Point_Vector;
+
+ // typedef typename Simplicial_complex::Filtration_value Filtration_value;
+ typedef std::vector< Vertex_handle > typeVectorVertex;
+ typedef std::pair< typeVectorVertex, Filtration_value> typeSimplex;
+ typedef std::pair< Simplex_handle, bool > typePairSimplexBool;
+
+ typedef int Witness_id;
+ typedef int Landmark_id;
+ typedef std::list< Vertex_handle > ActiveWitnessList;
+
+ private:
+ int nbL; // Number of landmarks
+ Simplicial_complex& sc; // Simplicial complex
+
+ public:
+ /** @name Constructor
+ */
+
+ //@{
+
+ /**
+ * \brief Iterative construction of the relaxed witness complex.
+ * \details The witness complex is written in sc_ basing on a matrix knn
+ * of k nearest neighbours of the form {witnesses}x{landmarks} and
+ * and a matrix distances of distances to these landmarks from witnesses.
+ * The parameter alpha defines relaxation and
+ * limD defines the
+ *
+ * The line lengths in one given matrix can differ,
+ * however both matrices have the same corresponding line lengths.
+ *
+ * The type KNearestNeighbors can be seen as
+ * Witness_range<Closest_landmark_range<Vertex_handle>>, where
+ * Witness_range and Closest_landmark_range are random access ranges.
+ *
+ * Constructor takes into account at most (dim+1)
+ * first landmarks from each landmark range to construct simplices.
+ *
+ * Landmarks are supposed to be in [0,nbL_-1]
+ */
+
+ template< typename KNearestNeighbours >
+ A0_complex(std::vector< std::vector<double> > const & distances,
+ KNearestNeighbours const & knn,
+ Simplicial_complex & sc_,
+ int nbL_,
+ double alpha2,
+ unsigned limD) : nbL(nbL_), sc(sc_) {
+ int nbW = knn.size();
+ typeVectorVertex vv;
+ //int counter = 0;
+ /* The list of still useful witnesses
+ * it will diminuish in the course of iterations
+ */
+ ActiveWitnessList active_w;// = new ActiveWitnessList();
+ for (int i = 0; i != nbL; ++i) {
+ // initial fill of 0-dimensional simplices
+ // by doing it we don't assume that landmarks are necessarily witnesses themselves anymore
+ //counter++;
+ vv = {i};
+ sc.insert_simplex(vv, Filtration_value(0.0));
+ /* TODO Error if not inserted : normally no need here though*/
+ }
+ for (int i=0; i != nbW; ++i) {
+ // int i_end = limD+1;
+ // if (knn[i].size() < limD+1)
+ // i_end = knn[i].size();
+ // double dist_wL = *(distances[i].begin());
+ // while (distances[i][i_end] > dist_wL + alpha2)
+ // i_end--;
+ // add_all_witnessed_faces(distances[i].begin(),
+ // knn[i].begin(),
+ // knn[i].begin() + i_end + 1);
+ unsigned j_end = 0;
+ while (j_end < distances[i].size() && j_end <= limD && distances[i][j_end] <= distances[i][0] + alpha2) {
+ std::vector<int> simplex;
+ for (unsigned j = 0; j <= j_end; ++j)
+ simplex.push_back(knn[i][j]);
+ assert(distances[i][j_end] - distances[i][0] >= 0);
+ sc.insert_simplex_and_subfaces(simplex, distances[i][j_end] - distances[i][0]);
+ j_end++;
+ }
+ }
+ sc.set_dimension(limD);
+ }
+
+ //@}
+
+private:
+ /* \brief Adds recursively all the faces of a certain dimension dim witnessed by the same witness
+ * Iterator is needed to know until how far we can take landmarks to form simplexes
+ * simplex is the prefix of the simplexes to insert
+ * The output value indicates if the witness rests active or not
+ */
+ void add_all_witnessed_faces(std::vector<double>::const_iterator curr_d,
+ std::vector<int>::const_iterator curr_l,
+ std::vector<int>::const_iterator end)
+ {
+ std::vector<int> simplex;
+ std::vector<int>::const_iterator l_end = curr_l;
+ for (; l_end != end; ++l_end) {
+ std::vector<int>::const_iterator l_it = curr_l;
+ std::vector<double>::const_iterator d_it = curr_d;
+ simplex = {};
+ for (; l_it != l_end; ++l_it, ++d_it)
+ simplex.push_back(*l_it);
+ sc.insert_simplex_and_subfaces(simplex, *(d_it--) - *curr_d);
+ }
+ }
+
+ /** \brief Check if the facets of the k-dimensional simplex witnessed
+ * by witness witness_id are already in the complex.
+ * inserted_vertex is the handle of the (k+1)-th vertex witnessed by witness_id
+ */
+ bool all_faces_in(std::vector<int>& simplex, double* filtration_value)
+ {
+ std::vector< int > facet;
+ for (std::vector<int>::iterator not_it = simplex.begin(); not_it != simplex.end(); ++not_it)
+ {
+ facet.clear();
+ for (std::vector<int>::iterator it = simplex.begin(); it != simplex.end(); ++it)
+ if (it != not_it)
+ facet.push_back(*it);
+ Simplex_handle facet_sh = sc.find(facet);
+ if (facet_sh == sc.null_simplex())
+ return false;
+ else if (sc.filtration(facet_sh) > *filtration_value)
+ *filtration_value = sc.filtration(facet_sh);
+ }
+ return true;
+ }
+
+ bool is_face(Simplex_handle face, Simplex_handle coface)
+ {
+ // vertex range is sorted in decreasing order
+ auto fvr = sc.simplex_vertex_range(face);
+ auto cfvr = sc.simplex_vertex_range(coface);
+ auto fv_it = fvr.begin();
+ auto cfv_it = cfvr.begin();
+ while (fv_it != fvr.end() && cfv_it != cfvr.end()) {
+ if (*fv_it < *cfv_it)
+ ++cfv_it;
+ else if (*fv_it == *cfv_it) {
+ ++cfv_it;
+ ++fv_it;
+ }
+ else
+ return false;
+
+ }
+ return (fv_it == fvr.end());
+ }
+
+ // void erase_simplex(Simplex_handle sh)
+ // {
+ // auto siblings = sc.self_siblings(sh);
+ // auto oncles = siblings->oncles();
+ // int prev_vertex = siblings->parent();
+ // siblings->members().erase(sh->first);
+ // if (siblings->members().empty()) {
+ // typename typedef Simplicial_complex::Siblings Siblings;
+ // oncles->members().find(prev_vertex)->second.assign_children(new Siblings(oncles, prev_vertex));
+ // assert(!sc.has_children(oncles->members().find(prev_vertex)));
+ // //delete siblings;
+ // }
+
+ // }
+
+ void elementary_collapse(Simplex_handle face_sh, Simplex_handle coface_sh)
+ {
+ erase_simplex(coface_sh);
+ erase_simplex(face_sh);
+ }
+
+public:
+ // void collapse(std::vector<Simplex_handle>& simplices)
+ // {
+ // // Get a vector of simplex handles ordered by filtration value
+ // std::cout << sc << std::endl;
+ // //std::vector<Simplex_handle> simplices;
+ // for (Simplex_handle sh: sc.filtration_simplex_range())
+ // simplices.push_back(sh);
+ // // std::sort(simplices.begin(),
+ // // simplices.end(),
+ // // [&](Simplex_handle sh1, Simplex_handle sh2)
+ // // { double f1 = sc.filtration(sh1), f2 = sc.filtration(sh2);
+ // // return (f1 > f2) || (f1 >= f2 && sc.dimension(sh1) > sc.dimension(sh2)); });
+ // // Double iteration
+ // auto face_it = simplices.rbegin();
+ // while (face_it != simplices.rend() && sc.filtration(*face_it) != 0) {
+ // int coface_count = 0;
+ // auto reduced_coface = simplices.rbegin();
+ // for (auto coface_it = simplices.rbegin(); coface_it != simplices.rend() && sc.filtration(*coface_it) != 0; ++coface_it)
+ // if (face_it != coface_it && is_face(*face_it, *coface_it)) {
+ // coface_count++;
+ // if (coface_count == 1)
+ // reduced_coface = coface_it;
+ // else
+ // break;
+ // }
+ // if (coface_count == 1) {
+ // std::cout << "Erase ( ";
+ // for (auto v: sc.simplex_vertex_range(*(--reduced_coface.base())))
+ // std::cout << v << " ";
+
+ // simplices.erase(--(reduced_coface.base()));
+ // //elementary_collapse(*face_it, *reduced_coface);
+ // std::cout << ") and then ( ";
+ // for (auto v: sc.simplex_vertex_range(*(--face_it.base())))
+ // std::cout << v << " ";
+ // std::cout << ")\n";
+ // simplices.erase(--((face_it++).base()));
+ // //face_it = simplices.rbegin();
+ // //std::cout << "Size of vector: " << simplices.size() << "\n";
+ // }
+ // else
+ // face_it++;
+ // }
+ // sc.initialize_filtration();
+ // //std::cout << sc << std::endl;
+ // }
+
+ template <class Dim_lists>
+ void collapse(Dim_lists& dim_lists)
+ {
+ dim_lists.collapse();
+ }
+
+private:
+
+ /** Collapse recursively boundary faces of the given simplex
+ * if its filtration is bigger than alpha_lim.
+ */
+ void rec_boundary_collapse(Simplex_handle sh, FT alpha_lim)
+ {
+ for (Simplex_handle face_it : sc.boundary_simplex_range()) {
+
+ }
+
+ }
+
+}; //class Relaxed_witness_complex
+
+} // namespace witness_complex
+
+} // namespace Gudhi
+
+#endif
diff --git a/src/Witness_complex/include/gudhi/Dim_list_iterator.h b/src/Witness_complex/include/gudhi/Dim_list_iterator.h
new file mode 100644
index 00000000..3f23e8c9
--- /dev/null
+++ b/src/Witness_complex/include/gudhi/Dim_list_iterator.h
@@ -0,0 +1,155 @@
+/* This file is part of the Gudhi Library. The Gudhi library
+ * (Geometric Understanding in Higher Dimensions) is a generic C++
+ * library for computational topology.
+ *
+ * Author(s): Siargey Kachanovich
+ *
+ * Copyright (C) 2015 INRIA Sophia Antipolis-Méditerranée (France)
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DIM_LISTS_ITERATOR_H_
+#define DIM_LISTS_ITERATOR_H_
+
+#include <boost/container/flat_map.hpp>
+#include <boost/iterator/transform_iterator.hpp>
+#include <algorithm>
+#include <utility>
+#include "gudhi/reader_utils.h"
+#include "gudhi/distance_functions.h"
+#include "gudhi/Simplex_tree.h"
+#include <vector>
+#include <list>
+#include <set>
+#include <queue>
+#include <limits>
+#include <math.h>
+#include <ctime>
+#include <iostream>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/iterator/zip_iterator.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/range/iterator_range.hpp>
+
+// Needed for the adjacency graph in bad link search
+#include <boost/graph/graph_traits.hpp>
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/graph/connected_components.hpp>
+
+namespace Gudhi {
+
+namespace witness_complex {
+
+ /** \addtogroup simplex_tree
+ * Witness complex is a simplicial complex defined on two sets of points in \f$\mathbf{R}^D\f$:
+ * \f$W\f$ set of witnesses and \f$L \subseteq W\f$ set of landmarks. The simplices are based on points in \f$L\f$
+ * and a simplex belongs to the witness complex if and only if it is witnessed (there exists a point \f$w \in W\f$ such that
+ * w is closer to the vertices of this simplex than others) and all of its faces are witnessed as well.
+ */
+template< class Simplex_handle >
+class Dim_lists_iterator {
+
+private:
+
+ typedef typename std::list<Simplex_handle>::iterator List_iterator;
+ typedef typename std::vector<std::list<Simplex_handle>>::reverse_iterator Vector_iterator;
+ typedef typename Gudhi::witness_complex::Dim_lists_iterator<Simplex_handle> Iterator;
+
+
+ List_iterator sh_;
+ Vector_iterator curr_list_;
+ typename std::vector<std::list<Simplex_handle>>& table_;
+
+public:
+
+ Dim_lists_iterator(List_iterator sh,
+ Vector_iterator curr_list,
+ typename std::vector<std::list<Simplex_handle>>& table)
+ : sh_(sh), curr_list_(curr_list), table_(table)
+ {
+ }
+
+ Simplex_handle operator*()
+ {
+ return *sh_;
+ }
+
+ Iterator operator++()
+ {
+ increment();
+ return (*this);
+ }
+
+ Iterator operator++(int)
+ {
+ Iterator prev_it(sh_, curr_list_, table_);
+ increment();
+ return prev_it;
+ }
+
+ Iterator dim_begin()
+ {
+ return Iterator(curr_list_->begin(), curr_list_, table_);
+ }
+
+ Iterator dim_end()
+ {
+ return Iterator(curr_list_->end(), curr_list_, table_);
+ }
+
+ Iterator dimp1_begin()
+ {
+ return Iterator((curr_list_-1)->begin(), curr_list_-1, table_);
+ }
+
+ Iterator dimp1_end()
+ {
+ return Iterator((curr_list_-1)->end(), curr_list_-1, table_);
+ }
+
+ bool operator==(const Iterator& it2) const
+ {
+ return (sh_ == it2.sh_);
+ }
+
+ bool operator!=(const Iterator& it2) const
+ {
+ return (sh_ != it2.sh_);
+ }
+
+ void remove_incr()
+ {
+
+ }
+
+private:
+
+ void increment()
+ {
+ if (++sh_ == curr_list_->end())
+ if (++curr_list_ != table_.rend())
+ sh_ = curr_list_->begin();
+ // The iterator of the end of the table is the end of the last list
+ }
+
+
+}; //class Dim_lists_iterator
+
+} // namespace witness_complex
+
+} // namespace Gudhi
+
+#endif
diff --git a/src/Witness_complex/include/gudhi/Dim_lists.h b/src/Witness_complex/include/gudhi/Dim_lists.h
new file mode 100644
index 00000000..1d1b03c3
--- /dev/null
+++ b/src/Witness_complex/include/gudhi/Dim_lists.h
@@ -0,0 +1,195 @@
+/* This file is part of the Gudhi Library. The Gudhi library
+ * (Geometric Understanding in Higher Dimensions) is a generic C++
+ * library for computational topology.
+ *
+ * Author(s): Siargey Kachanovich
+ *
+ * Copyright (C) 2015 INRIA Sophia Antipolis-Méditerranée (France)
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DIM_LISTS_H_
+#define DIM_LISTS_H_
+
+#include <boost/container/flat_map.hpp>
+#include <boost/iterator/transform_iterator.hpp>
+#include <algorithm>
+#include <utility>
+#include "gudhi/reader_utils.h"
+#include "gudhi/distance_functions.h"
+#include <gudhi/Dim_list_iterator.h>
+#include <vector>
+#include <list>
+#include <set>
+#include <queue>
+#include <limits>
+#include <math.h>
+#include <ctime>
+#include <iostream>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/iterator/zip_iterator.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/range/iterator_range.hpp>
+
+// Needed for the adjacency graph in bad link search
+#include <boost/graph/graph_traits.hpp>
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/graph/connected_components.hpp>
+
+namespace Gudhi {
+
+namespace witness_complex {
+
+ /** \addtogroup simplex_tree
+ * Witness complex is a simplicial complex defined on two sets of points in \f$\mathbf{R}^D\f$:
+ * \f$W\f$ set of witnesses and \f$L \subseteq W\f$ set of landmarks. The simplices are based on points in \f$L\f$
+ * and a simplex belongs to the witness complex if and only if it is witnessed (there exists a point \f$w \in W\f$ such that
+ * w is closer to the vertices of this simplex than others) and all of its faces are witnessed as well.
+ */
+template< class Simplicial_complex >
+class Dim_lists {
+
+private:
+
+ typedef typename Simplicial_complex::Simplex_handle Simplex_handle;
+ typedef typename Gudhi::witness_complex::Dim_lists_iterator<Simplex_handle> Iterator;
+
+ std::vector<std::list<Simplex_handle>> table_;
+ Simplicial_complex& sc_;
+
+public:
+
+ Dim_lists(Simplicial_complex & sc, int dim, double alpha_max = 100)
+ : sc_(sc)
+ {
+ table_ = std::vector<std::list<Simplex_handle>>(dim+1);
+ for (auto sh: sc.filtration_simplex_range()) {
+ if (sc_.filtration(sh) < alpha_max)
+ table_[sc.dimension(sh)].push_front(sh);
+ }
+ auto t_it = table_.rbegin();
+ while (t_it->empty()) {
+ t_it++;
+ table_.pop_back();
+ }
+ }
+
+ Iterator begin()
+ {
+ return Iterator(table_.rbegin()->begin(), table_.rbegin(), table_);
+ }
+
+ Iterator end()
+ {
+ return Iterator(table_[0].end(), table_.rend(), table_);
+ }
+
+ unsigned size()
+ {
+ unsigned curr_size = 0;
+ for (auto l: table_)
+ curr_size += l.size();
+ return curr_size;
+ }
+
+ bool is_face(Simplex_handle face, Simplex_handle coface)
+ {
+ // vertex range is sorted in decreasing order
+ auto fvr = sc_.simplex_vertex_range(face);
+ auto cfvr = sc_.simplex_vertex_range(coface);
+ auto fv_it = fvr.begin();
+ auto cfv_it = cfvr.begin();
+ while (fv_it != fvr.end() && cfv_it != cfvr.end()) {
+ if (*fv_it < *cfv_it)
+ ++cfv_it;
+ else if (*fv_it == *cfv_it) {
+ ++cfv_it;
+ ++fv_it;
+ }
+ else
+ return false;
+
+ }
+ return (fv_it == fvr.end());
+ }
+
+ void output_simplices() {
+ std::cout << "Size of vector: " << size() << std::endl;
+ for (auto line_it = table_.rbegin(); line_it != table_.rend(); ++line_it)
+ for (auto sh: *line_it) {
+ std::cout << sc_.dimension(sh) << " ";
+ for (auto v : sc_.simplex_vertex_range(sh))
+ std::cout << v << " ";
+ std::cout << sc_.filtration(sh) << "\n";
+ }
+ }
+
+ void collapse()
+ {
+ auto coface_list_it = table_.rbegin();
+ auto face_list_it = table_.rbegin()+1;
+ for ( ;
+ face_list_it != table_.rend();
+ ++face_list_it) {
+ auto face_it = face_list_it->begin();
+ while (face_it != face_list_it->end() && sc_.filtration(*face_it) != 0) {
+ int coface_count = 0;
+ auto reduced_coface = coface_list_it->begin();
+ for (auto coface_it = coface_list_it->begin(); coface_it != coface_list_it->end() && sc_.filtration(*coface_it) != 0; ++coface_it)
+ if (is_face(*face_it, *coface_it)) {
+ coface_count++;
+ if (coface_count == 1)
+ reduced_coface = coface_it;
+ else
+ break;
+ }
+ if (coface_count == 1) {
+ /*
+ std::cout << "Erase ( ";
+ for (auto v: sc_.simplex_vertex_range(*reduced_coface))
+ std::cout << v << " ";
+ */
+ coface_list_it->erase(reduced_coface);
+ /*
+ std::cout << ") and then ( ";
+ for (auto v: sc_.simplex_vertex_range(*face_it))
+ std::cout << v << " ";
+ std::cout << ")\n";
+ */
+ face_list_it->erase(face_it);
+ face_it = face_list_it->begin();
+ }
+ else
+ face_it++;
+ }
+ if ((coface_list_it++)->empty())
+ table_.pop_back();
+ }
+ }
+
+ bool is_pseudomanifold()
+ {
+
+ return true;
+ }
+
+}; //class Dim_lists
+
+} // namespace witness_complex
+
+} // namespace Gudhi
+
+#endif
diff --git a/src/Witness_complex/include/gudhi/Good_links.h b/src/Witness_complex/include/gudhi/Good_links.h
new file mode 100644
index 00000000..a011c032
--- /dev/null
+++ b/src/Witness_complex/include/gudhi/Good_links.h
@@ -0,0 +1,72 @@
+/* This file is part of the Gudhi Library. The Gudhi library
+ * (Geometric Understanding in Higher Dimensions) is a generic C++
+ * library for computational topology.
+ *
+ * Author(s): Siargey Kachanovich
+ *
+ * Copyright (C) 2015 INRIA Sophia Antipolis-Méditerranée (France)
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GOOD_LINKS_H_
+#define GOOD_LINKS_H_
+
+#include <boost/container/flat_map.hpp>
+#include <boost/iterator/transform_iterator.hpp>
+#include <algorithm>
+#include <utility>
+#include "gudhi/reader_utils.h"
+#include "gudhi/distance_functions.h"
+#include <gudhi/Dim_list_iterator.h>
+#include <vector>
+#include <list>
+#include <set>
+#include <queue>
+#include <limits>
+#include <math.h>
+#include <ctime>
+#include <iostream>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/iterator/zip_iterator.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/range/iterator_range.hpp>
+
+// Needed for the adjacency graph in bad link search
+#include <boost/graph/graph_traits.hpp>
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/graph/connected_components.hpp>
+
+namespace Gudhi {
+
+namespace witness_complex {
+
+ /** \addtogroup simplex_tree
+ * Witness complex is a simplicial complex defined on two sets of points in \f$\mathbf{R}^D\f$:
+ * \f$W\f$ set of witnesses and \f$L \subseteq W\f$ set of landmarks. The simplices are based on points in \f$L\f$
+ * and a simplex belongs to the witness complex if and only if it is witnessed (there exists a point \f$w \in W\f$ such that
+ * w is closer to the vertices of this simplex than others) and all of its faces are witnessed as well.
+ */
+template< class Simplicial_complex >
+bool good_links(Simplicial_complex& sc_)
+{
+
+}
+
+} // namespace witness_complex
+
+} // namespace Gudhi
+
+#endif
diff --git a/src/Witness_complex/include/gudhi/Relaxed_witness_complex.h b/src/Witness_complex/include/gudhi/Relaxed_witness_complex.h
index 04dc37d4..2971149a 100644
--- a/src/Witness_complex/include/gudhi/Relaxed_witness_complex.h
+++ b/src/Witness_complex/include/gudhi/Relaxed_witness_complex.h
@@ -83,6 +83,7 @@ private:
private:
typedef typename Simplicial_complex::Simplex_handle Simplex_handle;
typedef typename Simplicial_complex::Vertex_handle Vertex_handle;
+ typedef typename Simplicial_complex::Filtration_value FT;
typedef std::vector< double > Point_t;
typedef std::vector< Point_t > Point_Vector;
@@ -197,7 +198,7 @@ private:
std::vector<int>::const_iterator l_it = curr_l;
std::vector<double>::const_iterator d_it = curr_d;
if (dim > 0)
- for (; *d_it - alpha < norelax_dist && l_it != end; ++l_it, ++d_it) {
+ for (; *d_it - alpha <= norelax_dist && l_it != end; ++l_it, ++d_it) {
simplex.push_back(*l_it);
if (sc.find(simplex) != sc.null_simplex())
will_be_active = add_all_faces_of_dimension(dim-1,
@@ -209,7 +210,7 @@ private:
end) || will_be_active;
simplex.pop_back();
// If norelax_dist is infinity, change to first omitted distance
- if (*d_it < norelax_dist)
+ if (*d_it <= norelax_dist)
norelax_dist = *d_it;
will_be_active = add_all_faces_of_dimension(dim-1,
alpha,
@@ -220,17 +221,16 @@ private:
end) || will_be_active;
}
else if (dim == 0)
- for (; *d_it - alpha < norelax_dist && l_it != end; ++l_it, ++d_it) {
+ for (; *d_it - alpha <= norelax_dist && l_it != end; ++l_it, ++d_it) {
simplex.push_back(*l_it);
double filtration_value = 0;
// if norelax_dist is infinite, relaxation is 0.
if (*d_it > norelax_dist)
filtration_value = *d_it - norelax_dist;
- if (all_faces_in(simplex, &filtration_value))
- {
- will_be_active = true;
- sc.insert_simplex(simplex, filtration_value);
- }
+ if (all_faces_in(simplex, &filtration_value)) {
+ will_be_active = true;
+ sc.insert_simplex(simplex, filtration_value);
+ }
simplex.pop_back();
// If norelax_dist is infinity, change to first omitted distance
if (*d_it < norelax_dist)
@@ -260,11 +260,120 @@ private:
}
return true;
}
-
-}; //class Witness_complex
+
+ bool is_face(Simplex_handle face, Simplex_handle coface)
+ {
+ // vertex range is sorted in decreasing order
+ auto fvr = sc.simplex_vertex_range(face);
+ auto cfvr = sc.simplex_vertex_range(coface);
+ auto fv_it = fvr.begin();
+ auto cfv_it = cfvr.begin();
+ while (fv_it != fvr.end() && cfv_it != cfvr.end()) {
+ if (*fv_it < *cfv_it)
+ ++cfv_it;
+ else if (*fv_it == *cfv_it) {
+ ++cfv_it;
+ ++fv_it;
+ }
+ else
+ return false;
+
+ }
+ return (fv_it == fvr.end());
+ }
+
+ // void erase_simplex(Simplex_handle sh)
+ // {
+ // auto siblings = sc.self_siblings(sh);
+ // auto oncles = siblings->oncles();
+ // int prev_vertex = siblings->parent();
+ // siblings->members().erase(sh->first);
+ // if (siblings->members().empty()) {
+ // typename typedef Simplicial_complex::Siblings Siblings;
+ // oncles->members().find(prev_vertex)->second.assign_children(new Siblings(oncles, prev_vertex));
+ // assert(!sc.has_children(oncles->members().find(prev_vertex)));
+ // //delete siblings;
+ // }
+
+ // }
+
+ void elementary_collapse(Simplex_handle face_sh, Simplex_handle coface_sh)
+ {
+ erase_simplex(coface_sh);
+ erase_simplex(face_sh);
+ }
+
+public:
+ // void collapse(std::vector<Simplex_handle>& simplices)
+ // {
+ // // Get a vector of simplex handles ordered by filtration value
+ // std::cout << sc << std::endl;
+ // //std::vector<Simplex_handle> simplices;
+ // for (Simplex_handle sh: sc.filtration_simplex_range())
+ // simplices.push_back(sh);
+ // // std::sort(simplices.begin(),
+ // // simplices.end(),
+ // // [&](Simplex_handle sh1, Simplex_handle sh2)
+ // // { double f1 = sc.filtration(sh1), f2 = sc.filtration(sh2);
+ // // return (f1 > f2) || (f1 >= f2 && sc.dimension(sh1) > sc.dimension(sh2)); });
+ // // Double iteration
+ // auto face_it = simplices.rbegin();
+ // while (face_it != simplices.rend() && sc.filtration(*face_it) != 0) {
+ // int coface_count = 0;
+ // auto reduced_coface = simplices.rbegin();
+ // for (auto coface_it = simplices.rbegin(); coface_it != simplices.rend() && sc.filtration(*coface_it) != 0; ++coface_it)
+ // if (face_it != coface_it && is_face(*face_it, *coface_it)) {
+ // coface_count++;
+ // if (coface_count == 1)
+ // reduced_coface = coface_it;
+ // else
+ // break;
+ // }
+ // if (coface_count == 1) {
+ // std::cout << "Erase ( ";
+ // for (auto v: sc.simplex_vertex_range(*(--reduced_coface.base())))
+ // std::cout << v << " ";
+
+ // simplices.erase(--(reduced_coface.base()));
+ // //elementary_collapse(*face_it, *reduced_coface);
+ // std::cout << ") and then ( ";
+ // for (auto v: sc.simplex_vertex_range(*(--face_it.base())))
+ // std::cout << v << " ";
+ // std::cout << ")\n";
+ // simplices.erase(--((face_it++).base()));
+ // //face_it = simplices.rbegin();
+ // //std::cout << "Size of vector: " << simplices.size() << "\n";
+ // }
+ // else
+ // face_it++;
+ // }
+ // sc.initialize_filtration();
+ // //std::cout << sc << std::endl;
+ // }
+
+ template <class Dim_lists>
+ void collapse(Dim_lists& dim_lists)
+ {
+ dim_lists.collapse();
+ }
+
+private:
+
+ /** Collapse recursively boundary faces of the given simplex
+ * if its filtration is bigger than alpha_lim.
+ */
+ void rec_boundary_collapse(Simplex_handle sh, FT alpha_lim)
+ {
+ for (Simplex_handle face_it : sc.boundary_simplex_range()) {
+
+ }
+
+ }
+
+}; //class Relaxed_witness_complex
} // namespace witness_complex
-} // namespace Guhdi
+} // namespace Gudhi
#endif
diff --git a/src/Witness_complex/include/gudhi/Strange_witness_complex.h b/src/Witness_complex/include/gudhi/Strange_witness_complex.h
new file mode 100644
index 00000000..c1c2912b
--- /dev/null
+++ b/src/Witness_complex/include/gudhi/Strange_witness_complex.h
@@ -0,0 +1,232 @@
+/* This file is part of the Gudhi Library. The Gudhi library
+ * (Geometric Understanding in Higher Dimensions) is a generic C++
+ * library for computational topology.
+ *
+ * Author(s): Siargey Kachanovich
+ *
+ * Copyright (C) 2015 INRIA Sophia Antipolis-Méditerranée (France)
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef WITNESS_COMPLEX_H_
+#define WITNESS_COMPLEX_H_
+
+// Needed for the adjacency graph in bad link search
+#include <boost/graph/graph_traits.hpp>
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/graph/connected_components.hpp>
+
+#include <boost/container/flat_map.hpp>
+#include <boost/iterator/transform_iterator.hpp>
+
+#include <gudhi/distance_functions.h>
+
+#include <algorithm>
+#include <utility>
+#include <vector>
+#include <list>
+#include <set>
+#include <queue>
+#include <limits>
+#include <ctime>
+#include <iostream>
+
+namespace Gudhi {
+
+namespace witness_complex {
+
+/**
+ \class Witness_complex
+ \brief Constructs the witness complex for the given set of witnesses and landmarks.
+ \ingroup witness_complex
+ */
+template< class Simplicial_complex>
+class Strange_witness_complex {
+ private:
+ struct Active_witness {
+ int witness_id;
+ int landmark_id;
+
+ Active_witness(int witness_id_, int landmark_id_)
+ : witness_id(witness_id_),
+ landmark_id(landmark_id_) { }
+ };
+
+ private:
+ typedef typename Simplicial_complex::Simplex_handle Simplex_handle;
+ typedef typename Simplicial_complex::Vertex_handle Vertex_handle;
+
+ typedef std::vector< double > Point_t;
+ typedef std::vector< Point_t > Point_Vector;
+
+ // typedef typename Simplicial_complex::Filtration_value Filtration_value;
+ typedef std::vector< Vertex_handle > typeVectorVertex;
+ typedef std::pair< typeVectorVertex, Filtration_value> typeSimplex;
+ typedef std::pair< Simplex_handle, bool > typePairSimplexBool;
+
+ typedef int Witness_id;
+ typedef int Landmark_id;
+ typedef std::list< Vertex_handle > ActiveWitnessList;
+
+ private:
+ int nbL; // Number of landmarks
+ Simplicial_complex& sc; // Simplicial complex
+
+ public:
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ /** @name Constructor
+ */
+
+ //@{
+
+ // Witness_range<Closest_landmark_range<Vertex_handle>>
+
+ /**
+ * \brief Iterative construction of the witness complex.
+ * \details The witness complex is written in sc_ basing on a matrix knn of
+ * nearest neighbours of the form {witnesses}x{landmarks}.
+ *
+ * The type KNearestNeighbors can be seen as
+ * Witness_range<Closest_landmark_range<Vertex_handle>>, where
+ * Witness_range and Closest_landmark_range are random access ranges.
+ *
+ * Constructor takes into account at most (dim+1)
+ * first landmarks from each landmark range to construct simplices.
+ *
+ * Landmarks are supposed to be in [0,nbL_-1]
+ */
+ template< typename KNearestNeighbors >
+ Strange_witness_complex(KNearestNeighbors const & knn,
+ Simplicial_complex & sc_,
+ int nbL_,
+ int dim) : nbL(nbL_), sc(sc_) {
+ // Construction of the active witness list
+ int nbW = knn.size();
+ typeVectorVertex vv;
+ int counter = 0;
+ /* The list of still useful witnesses
+ * it will diminuish in the course of iterations
+ */
+ for (int i = 0; i != nbL; ++i) {
+ // initial fill of 0-dimensional simplices
+ // by doing it we don't assume that landmarks are necessarily witnesses themselves anymore
+ counter++;
+ vv = {i};
+ sc.insert_simplex(vv);
+ // TODO(SK) Error if not inserted : normally no need here though
+ }
+ for (int i = 0; i != nbW; ++i) {
+ std::vector<int> simplex;
+ simplex.reserve(dim+1);
+ for (int j = 0; j <= dim; j++)
+ simplex.push_back(knn[i][j]);
+ sc.insert_simplex_and_subfaces(simplex);
+ }
+ }
+
+ //@}
+
+ private:
+ /** \brief Check if the facets of the k-dimensional simplex witnessed
+ * by witness witness_id are already in the complex.
+ * inserted_vertex is the handle of the (k+1)-th vertex witnessed by witness_id
+ */
+ template <typename KNearestNeighbors>
+ bool all_faces_in(KNearestNeighbors const &knn, int witness_id, int k) {
+ // std::cout << "All face in with the landmark " << inserted_vertex << std::endl;
+ std::vector< Vertex_handle > facet;
+ // Vertex_handle curr_vh = curr_sh->first;
+ // CHECK ALL THE FACETS
+ for (int i = 0; i != k + 1; ++i) {
+ facet = {};
+ for (int j = 0; j != k + 1; ++j) {
+ if (j != i) {
+ facet.push_back(knn[witness_id][j]);
+ }
+ } // endfor
+ if (sc.find(facet) == sc.null_simplex())
+ return false;
+ // std::cout << "++++ finished loop safely\n";
+ } // endfor
+ return true;
+ }
+
+ template <typename T>
+ static void print_vector(const std::vector<T>& v) {
+ std::cout << "[";
+ if (!v.empty()) {
+ std::cout << *(v.begin());
+ for (auto it = v.begin() + 1; it != v.end(); ++it) {
+ std::cout << ",";
+ std::cout << *it;
+ }
+ }
+ std::cout << "]";
+ }
+
+ public:
+ /**
+ * \brief Verification if every simplex in the complex is witnessed by witnesses in knn.
+ * \param print_output =true will print the witnesses for each simplex
+ * \remark Added for debugging purposes.
+ */
+ template< class KNearestNeighbors >
+ bool is_witness_complex(KNearestNeighbors const & knn, bool print_output) {
+ // bool final_result = true;
+ for (Simplex_handle sh : sc.complex_simplex_range()) {
+ bool is_witnessed = false;
+ typeVectorVertex simplex;
+ int nbV = 0; // number of verticed in the simplex
+ for (int v : sc.simplex_vertex_range(sh))
+ simplex.push_back(v);
+ nbV = simplex.size();
+ for (typeVectorVertex w : knn) {
+ bool has_vertices = true;
+ for (int v : simplex)
+ if (std::find(w.begin(), w.begin() + nbV, v) == w.begin() + nbV) {
+ has_vertices = false;
+ // break;
+ }
+ if (has_vertices) {
+ is_witnessed = true;
+ if (print_output) {
+ std::cout << "The simplex ";
+ print_vector(simplex);
+ std::cout << " is witnessed by the witness ";
+ print_vector(w);
+ std::cout << std::endl;
+ }
+ break;
+ }
+ }
+ if (!is_witnessed) {
+ if (print_output) {
+ std::cout << "The following simplex is not witnessed ";
+ print_vector(simplex);
+ std::cout << std::endl;
+ }
+ assert(is_witnessed);
+ return false;
+ }
+ }
+ return true;
+ }
+};
+
+} // namespace witness_complex
+
+} // namespace Gudhi
+
+#endif // WITNESS_COMPLEX_H_
diff --git a/src/Witness_complex/include/gudhi/Strong_relaxed_witness_complex.h b/src/Witness_complex/include/gudhi/Strong_relaxed_witness_complex.h
new file mode 100644
index 00000000..ee863a42
--- /dev/null
+++ b/src/Witness_complex/include/gudhi/Strong_relaxed_witness_complex.h
@@ -0,0 +1,337 @@
+/* This file is part of the Gudhi Library. The Gudhi library
+ * (Geometric Understanding in Higher Dimensions) is a generic C++
+ * library for computational topology.
+ *
+ * Author(s): Siargey Kachanovich
+ *
+ * Copyright (C) 2015 INRIA Sophia Antipolis-Méditerranée (France)
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef STRONG_RELAXED_WITNESS_COMPLEX_H_
+#define STRONG_RELAXED_WITNESS_COMPLEX_H_
+
+#include <boost/container/flat_map.hpp>
+#include <boost/iterator/transform_iterator.hpp>
+#include <algorithm>
+#include <utility>
+#include "gudhi/reader_utils.h"
+#include "gudhi/distance_functions.h"
+#include "gudhi/Simplex_tree.h"
+#include <vector>
+#include <list>
+#include <set>
+#include <queue>
+#include <limits>
+#include <math.h>
+#include <ctime>
+#include <iostream>
+
+// Needed for nearest neighbours
+#include <CGAL/Cartesian_d.h>
+#include <CGAL/Search_traits.h>
+#include <CGAL/Search_traits_adapter.h>
+#include <CGAL/property_map.h>
+#include <CGAL/Epick_d.h>
+#include <CGAL/Orthogonal_k_neighbor_search.h>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/iterator/zip_iterator.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/range/iterator_range.hpp>
+
+// Needed for the adjacency graph in bad link search
+#include <boost/graph/graph_traits.hpp>
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/graph/connected_components.hpp>
+
+namespace Gudhi {
+
+namespace witness_complex {
+
+ /** \addtogroup simplex_tree
+ * Witness complex is a simplicial complex defined on two sets of points in \f$\mathbf{R}^D\f$:
+ * \f$W\f$ set of witnesses and \f$L \subseteq W\f$ set of landmarks. The simplices are based on points in \f$L\f$
+ * and a simplex belongs to the witness complex if and only if it is witnessed (there exists a point \f$w \in W\f$ such that
+ * w is closer to the vertices of this simplex than others) and all of its faces are witnessed as well.
+ */
+template< class Simplicial_complex >
+class Strong_relaxed_witness_complex {
+
+private:
+ struct Active_witness {
+ int witness_id;
+ int landmark_id;
+
+ Active_witness(int witness_id_, int landmark_id_)
+ : witness_id(witness_id_),
+ landmark_id(landmark_id_) { }
+ };
+
+private:
+ typedef typename Simplicial_complex::Simplex_handle Simplex_handle;
+ typedef typename Simplicial_complex::Vertex_handle Vertex_handle;
+ typedef typename Simplicial_complex::Filtration_value FT;
+
+ typedef std::vector< double > Point_t;
+ typedef std::vector< Point_t > Point_Vector;
+
+ // typedef typename Simplicial_complex::Filtration_value Filtration_value;
+ typedef std::vector< Vertex_handle > typeVectorVertex;
+ typedef std::pair< typeVectorVertex, Filtration_value> typeSimplex;
+ typedef std::pair< Simplex_handle, bool > typePairSimplexBool;
+
+ typedef int Witness_id;
+ typedef int Landmark_id;
+ typedef std::list< Vertex_handle > ActiveWitnessList;
+
+ private:
+ int nbL; // Number of landmarks
+ Simplicial_complex& sc; // Simplicial complex
+
+ public:
+ /** @name Constructor
+ */
+
+ //@{
+
+ /**
+ * \brief Iterative construction of the relaxed witness complex.
+ * \details The witness complex is written in sc_ basing on a matrix knn
+ * of k nearest neighbours of the form {witnesses}x{landmarks} and
+ * and a matrix distances of distances to these landmarks from witnesses.
+ * The parameter alpha defines relaxation and
+ * limD defines the
+ *
+ * The line lengths in one given matrix can differ,
+ * however both matrices have the same corresponding line lengths.
+ *
+ * The type KNearestNeighbors can be seen as
+ * Witness_range<Closest_landmark_range<Vertex_handle>>, where
+ * Witness_range and Closest_landmark_range are random access ranges.
+ *
+ * Constructor takes into account at most (dim+1)
+ * first landmarks from each landmark range to construct simplices.
+ *
+ * Landmarks are supposed to be in [0,nbL_-1]
+ */
+
+ template< typename KNearestNeighbours >
+ Strong_relaxed_witness_complex(std::vector< std::vector<double> > const & distances,
+ KNearestNeighbours const & knn,
+ Simplicial_complex & sc_,
+ int nbL_,
+ double alpha2,
+ unsigned limD) : nbL(nbL_), sc(sc_) {
+ int nbW = knn.size();
+ typeVectorVertex vv;
+ //int counter = 0;
+ /* The list of still useful witnesses
+ * it will diminuish in the course of iterations
+ */
+ ActiveWitnessList active_w;// = new ActiveWitnessList();
+ for (int i = 0; i != nbL; ++i) {
+ // initial fill of 0-dimensional simplices
+ // by doing it we don't assume that landmarks are necessarily witnesses themselves anymore
+ //counter++;
+ vv = {i};
+ sc.insert_simplex(vv, Filtration_value(0.0));
+ /* TODO Error if not inserted : normally no need here though*/
+ }
+ for (int i=0; i != nbW; ++i) {
+ // int i_end = limD+1;
+ // if (knn[i].size() < limD+1)
+ // i_end = knn[i].size();
+ // double dist_wL = *(distances[i].begin());
+ // while (distances[i][i_end] > dist_wL + alpha2)
+ // i_end--;
+ // add_all_witnessed_faces(distances[i].begin(),
+ // knn[i].begin(),
+ // knn[i].begin() + i_end + 1);
+ unsigned j_end = 0;
+ while (j_end < distances[i].size() && j_end <= limD && distances[i][j_end] <= distances[i][0] + alpha2) {
+ std::vector<int> simplex;
+ for (unsigned j = 0; j <= j_end; ++j)
+ simplex.push_back(knn[i][j]);
+ assert(distances[i][j_end] - distances[i][0] >= 0);
+ sc.insert_simplex_and_subfaces(simplex, distances[i][j_end] - distances[i][0]);
+ j_end++;
+ }
+ }
+ sc.set_dimension(limD);
+ }
+
+ //@}
+
+private:
+ /* \brief Adds recursively all the faces of a certain dimension dim witnessed by the same witness
+ * Iterator is needed to know until how far we can take landmarks to form simplexes
+ * simplex is the prefix of the simplexes to insert
+ * The output value indicates if the witness rests active or not
+ */
+ void add_all_witnessed_faces(std::vector<double>::const_iterator curr_d,
+ std::vector<int>::const_iterator curr_l,
+ std::vector<int>::const_iterator end)
+ {
+ std::vector<int> simplex;
+ std::vector<int>::const_iterator l_end = curr_l;
+ for (; l_end != end; ++l_end) {
+ std::vector<int>::const_iterator l_it = curr_l;
+ std::vector<double>::const_iterator d_it = curr_d;
+ simplex = {};
+ for (; l_it != l_end; ++l_it, ++d_it)
+ simplex.push_back(*l_it);
+ sc.insert_simplex_and_subfaces(simplex, *(d_it--) - *curr_d);
+ }
+ }
+
+ /** \brief Check if the facets of the k-dimensional simplex witnessed
+ * by witness witness_id are already in the complex.
+ * inserted_vertex is the handle of the (k+1)-th vertex witnessed by witness_id
+ */
+ bool all_faces_in(std::vector<int>& simplex, double* filtration_value)
+ {
+ std::vector< int > facet;
+ for (std::vector<int>::iterator not_it = simplex.begin(); not_it != simplex.end(); ++not_it)
+ {
+ facet.clear();
+ for (std::vector<int>::iterator it = simplex.begin(); it != simplex.end(); ++it)
+ if (it != not_it)
+ facet.push_back(*it);
+ Simplex_handle facet_sh = sc.find(facet);
+ if (facet_sh == sc.null_simplex())
+ return false;
+ else if (sc.filtration(facet_sh) > *filtration_value)
+ *filtration_value = sc.filtration(facet_sh);
+ }
+ return true;
+ }
+
+ bool is_face(Simplex_handle face, Simplex_handle coface)
+ {
+ // vertex range is sorted in decreasing order
+ auto fvr = sc.simplex_vertex_range(face);
+ auto cfvr = sc.simplex_vertex_range(coface);
+ auto fv_it = fvr.begin();
+ auto cfv_it = cfvr.begin();
+ while (fv_it != fvr.end() && cfv_it != cfvr.end()) {
+ if (*fv_it < *cfv_it)
+ ++cfv_it;
+ else if (*fv_it == *cfv_it) {
+ ++cfv_it;
+ ++fv_it;
+ }
+ else
+ return false;
+
+ }
+ return (fv_it == fvr.end());
+ }
+
+ // void erase_simplex(Simplex_handle sh)
+ // {
+ // auto siblings = sc.self_siblings(sh);
+ // auto oncles = siblings->oncles();
+ // int prev_vertex = siblings->parent();
+ // siblings->members().erase(sh->first);
+ // if (siblings->members().empty()) {
+ // typename typedef Simplicial_complex::Siblings Siblings;
+ // oncles->members().find(prev_vertex)->second.assign_children(new Siblings(oncles, prev_vertex));
+ // assert(!sc.has_children(oncles->members().find(prev_vertex)));
+ // //delete siblings;
+ // }
+
+ // }
+
+ void elementary_collapse(Simplex_handle face_sh, Simplex_handle coface_sh)
+ {
+ erase_simplex(coface_sh);
+ erase_simplex(face_sh);
+ }
+
+public:
+ // void collapse(std::vector<Simplex_handle>& simplices)
+ // {
+ // // Get a vector of simplex handles ordered by filtration value
+ // std::cout << sc << std::endl;
+ // //std::vector<Simplex_handle> simplices;
+ // for (Simplex_handle sh: sc.filtration_simplex_range())
+ // simplices.push_back(sh);
+ // // std::sort(simplices.begin(),
+ // // simplices.end(),
+ // // [&](Simplex_handle sh1, Simplex_handle sh2)
+ // // { double f1 = sc.filtration(sh1), f2 = sc.filtration(sh2);
+ // // return (f1 > f2) || (f1 >= f2 && sc.dimension(sh1) > sc.dimension(sh2)); });
+ // // Double iteration
+ // auto face_it = simplices.rbegin();
+ // while (face_it != simplices.rend() && sc.filtration(*face_it) != 0) {
+ // int coface_count = 0;
+ // auto reduced_coface = simplices.rbegin();
+ // for (auto coface_it = simplices.rbegin(); coface_it != simplices.rend() && sc.filtration(*coface_it) != 0; ++coface_it)
+ // if (face_it != coface_it && is_face(*face_it, *coface_it)) {
+ // coface_count++;
+ // if (coface_count == 1)
+ // reduced_coface = coface_it;
+ // else
+ // break;
+ // }
+ // if (coface_count == 1) {
+ // std::cout << "Erase ( ";
+ // for (auto v: sc.simplex_vertex_range(*(--reduced_coface.base())))
+ // std::cout << v << " ";
+
+ // simplices.erase(--(reduced_coface.base()));
+ // //elementary_collapse(*face_it, *reduced_coface);
+ // std::cout << ") and then ( ";
+ // for (auto v: sc.simplex_vertex_range(*(--face_it.base())))
+ // std::cout << v << " ";
+ // std::cout << ")\n";
+ // simplices.erase(--((face_it++).base()));
+ // //face_it = simplices.rbegin();
+ // //std::cout << "Size of vector: " << simplices.size() << "\n";
+ // }
+ // else
+ // face_it++;
+ // }
+ // sc.initialize_filtration();
+ // //std::cout << sc << std::endl;
+ // }
+
+ template <class Dim_lists>
+ void collapse(Dim_lists& dim_lists)
+ {
+ dim_lists.collapse();
+ }
+
+private:
+
+ /** Collapse recursively boundary faces of the given simplex
+ * if its filtration is bigger than alpha_lim.
+ */
+ void rec_boundary_collapse(Simplex_handle sh, FT alpha_lim)
+ {
+ for (Simplex_handle face_it : sc.boundary_simplex_range()) {
+
+ }
+
+ }
+
+}; //class Strong_relaxed_witness_complex
+
+} // namespace witness_complex
+
+} // namespace Gudhi
+
+#endif
diff --git a/src/Witness_complex/include/gudhi/Weak_relaxed_witness_complex.h b/src/Witness_complex/include/gudhi/Weak_relaxed_witness_complex.h
new file mode 100644
index 00000000..a1aedd8e
--- /dev/null
+++ b/src/Witness_complex/include/gudhi/Weak_relaxed_witness_complex.h
@@ -0,0 +1,379 @@
+/* This file is part of the Gudhi Library. The Gudhi library
+ * (Geometric Understanding in Higher Dimensions) is a generic C++
+ * library for computational topology.
+ *
+ * Author(s): Siargey Kachanovich
+ *
+ * Copyright (C) 2015 INRIA Sophia Antipolis-Méditerranée (France)
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef WEAK_RELAXED_WITNESS_COMPLEX_H_
+#define WEAK_RELAXED_WITNESS_COMPLEX_H_
+
+#include <boost/container/flat_map.hpp>
+#include <boost/iterator/transform_iterator.hpp>
+#include <algorithm>
+#include <utility>
+#include "gudhi/reader_utils.h"
+#include "gudhi/distance_functions.h"
+#include "gudhi/Simplex_tree.h"
+#include <vector>
+#include <list>
+#include <set>
+#include <queue>
+#include <limits>
+#include <math.h>
+#include <ctime>
+#include <iostream>
+
+// Needed for nearest neighbours
+#include <CGAL/Cartesian_d.h>
+#include <CGAL/Search_traits.h>
+#include <CGAL/Search_traits_adapter.h>
+#include <CGAL/property_map.h>
+#include <CGAL/Epick_d.h>
+#include <CGAL/Orthogonal_k_neighbor_search.h>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/iterator/zip_iterator.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/range/iterator_range.hpp>
+
+// Needed for the adjacency graph in bad link search
+#include <boost/graph/graph_traits.hpp>
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/graph/connected_components.hpp>
+
+namespace Gudhi {
+
+namespace witness_complex {
+
+ /** \addtogroup simplex_tree
+ * Witness complex is a simplicial complex defined on two sets of points in \f$\mathbf{R}^D\f$:
+ * \f$W\f$ set of witnesses and \f$L \subseteq W\f$ set of landmarks. The simplices are based on points in \f$L\f$
+ * and a simplex belongs to the witness complex if and only if it is witnessed (there exists a point \f$w \in W\f$ such that
+ * w is closer to the vertices of this simplex than others) and all of its faces are witnessed as well.
+ */
+template< class Simplicial_complex >
+class Weak_relaxed_witness_complex {
+
+private:
+ struct Active_witness {
+ int witness_id;
+ int landmark_id;
+
+ Active_witness(int witness_id_, int landmark_id_)
+ : witness_id(witness_id_),
+ landmark_id(landmark_id_) { }
+ };
+
+private:
+ typedef typename Simplicial_complex::Simplex_handle Simplex_handle;
+ typedef typename Simplicial_complex::Vertex_handle Vertex_handle;
+ typedef typename Simplicial_complex::Filtration_value FT;
+
+ typedef std::vector< double > Point_t;
+ typedef std::vector< Point_t > Point_Vector;
+
+ // typedef typename Simplicial_complex::Filtration_value Filtration_value;
+ typedef std::vector< Vertex_handle > typeVectorVertex;
+ typedef std::pair< typeVectorVertex, Filtration_value> typeSimplex;
+ typedef std::pair< Simplex_handle, bool > typePairSimplexBool;
+
+ typedef int Witness_id;
+ typedef int Landmark_id;
+ typedef std::list< Vertex_handle > ActiveWitnessList;
+
+ private:
+ int nbL; // Number of landmarks
+ Simplicial_complex& sc; // Simplicial complex
+
+ public:
+ /** @name Constructor
+ */
+
+ //@{
+
+ /**
+ * \brief Iterative construction of the relaxed witness complex.
+ * \details The witness complex is written in sc_ basing on a matrix knn
+ * of k nearest neighbours of the form {witnesses}x{landmarks} and
+ * and a matrix distances of distances to these landmarks from witnesses.
+ * The parameter alpha defines relaxation and
+ * limD defines the
+ *
+ * The line lengths in one given matrix can differ,
+ * however both matrices have the same corresponding line lengths.
+ *
+ * The type KNearestNeighbors can be seen as
+ * Witness_range<Closest_landmark_range<Vertex_handle>>, where
+ * Witness_range and Closest_landmark_range are random access ranges.
+ *
+ * Constructor takes into account at most (dim+1)
+ * first landmarks from each landmark range to construct simplices.
+ *
+ * Landmarks are supposed to be in [0,nbL_-1]
+ */
+
+ template< typename KNearestNeighbours >
+ Weak_relaxed_witness_complex(std::vector< std::vector<double> > const & distances,
+ KNearestNeighbours const & knn,
+ Simplicial_complex & sc_,
+ int nbL_,
+ double alpha,
+ int limD) : nbL(nbL_), sc(sc_) {
+ int nbW = knn.size();
+ typeVectorVertex vv;
+ //int counter = 0;
+ /* The list of still useful witnesses
+ * it will diminuish in the course of iterations
+ */
+ ActiveWitnessList active_w;// = new ActiveWitnessList();
+ for (int i = 0; i != nbL; ++i) {
+ // initial fill of 0-dimensional simplices
+ // by doing it we don't assume that landmarks are necessarily witnesses themselves anymore
+ //counter++;
+ vv = {i};
+ sc.insert_simplex(vv, Filtration_value(0.0));
+ /* TODO Error if not inserted : normally no need here though*/
+ }
+ int k = 1; /* current dimension in iterative construction */
+ for (int i=0; i != nbW; ++i)
+ active_w.push_back(i);
+ while (!active_w.empty() && k <= limD && k < nbL )
+ {
+ typename ActiveWitnessList::iterator aw_it = active_w.begin();
+ while (aw_it != active_w.end())
+ {
+ std::vector<int> simplex;
+ bool ok = add_all_faces_of_dimension(k,
+ alpha,
+ std::numeric_limits<double>::infinity(),
+ distances[*aw_it].begin(),
+ knn[*aw_it].begin(),
+ simplex,
+ knn[*aw_it].end());
+ if (!ok)
+ active_w.erase(aw_it++); //First increase the iterator and then erase the previous element
+ else
+ aw_it++;
+ }
+ k++;
+ }
+ sc.set_dimension(limD);
+ }
+
+ //@}
+
+private:
+ /* \brief Adds recursively all the faces of a certain dimension dim witnessed by the same witness
+ * Iterator is needed to know until how far we can take landmarks to form simplexes
+ * simplex is the prefix of the simplexes to insert
+ * The output value indicates if the witness rests active or not
+ */
+ bool add_all_faces_of_dimension(int dim,
+ double alpha,
+ double norelax_dist,
+ std::vector<double>::const_iterator curr_d,
+ std::vector<int>::const_iterator curr_l,
+ std::vector<int>& simplex,
+ std::vector<int>::const_iterator end)
+ {
+ if (curr_l == end)
+ return false;
+ bool will_be_active = false;
+ std::vector<int>::const_iterator l_it = curr_l;
+ std::vector<double>::const_iterator d_it = curr_d;
+ if (dim > 0)
+ for (; *d_it - alpha <= norelax_dist && l_it != end; ++l_it, ++d_it) {
+ simplex.push_back(*l_it);
+ if (sc.find(simplex) != sc.null_simplex())
+ will_be_active = add_all_faces_of_dimension(dim-1,
+ alpha,
+ norelax_dist,
+ d_it+1,
+ l_it+1,
+ simplex,
+ end) || will_be_active;
+ simplex.pop_back();
+ // If norelax_dist is infinity, change to first omitted distance
+ if (*d_it <= norelax_dist)
+ norelax_dist = *d_it;
+ will_be_active = add_all_faces_of_dimension(dim-1,
+ alpha,
+ norelax_dist,
+ d_it+1,
+ l_it+1,
+ simplex,
+ end) || will_be_active;
+ }
+ else if (dim == 0)
+ for (; *d_it - alpha <= norelax_dist && l_it != end; ++l_it, ++d_it) {
+ simplex.push_back(*l_it);
+ double filtration_value = 0;
+ // if norelax_dist is infinite, relaxation is 0.
+ if (*d_it > norelax_dist)
+ filtration_value = *d_it - norelax_dist;
+ if (all_faces_in(simplex, &filtration_value)) {
+ will_be_active = true;
+ sc.insert_simplex(simplex, filtration_value);
+ }
+ simplex.pop_back();
+ // If norelax_dist is infinity, change to first omitted distance
+ if (*d_it < norelax_dist)
+ norelax_dist = *d_it;
+ }
+ return will_be_active;
+ }
+
+ /** \brief Check if the facets of the k-dimensional simplex witnessed
+ * by witness witness_id are already in the complex.
+ * inserted_vertex is the handle of the (k+1)-th vertex witnessed by witness_id
+ */
+ bool all_faces_in(std::vector<int>& simplex, double* filtration_value)
+ {
+ std::vector< int > facet;
+ for (std::vector<int>::iterator not_it = simplex.begin(); not_it != simplex.end(); ++not_it)
+ {
+ facet.clear();
+ for (std::vector<int>::iterator it = simplex.begin(); it != simplex.end(); ++it)
+ if (it != not_it)
+ facet.push_back(*it);
+ Simplex_handle facet_sh = sc.find(facet);
+ if (facet_sh == sc.null_simplex())
+ return false;
+ else if (sc.filtration(facet_sh) > *filtration_value)
+ *filtration_value = sc.filtration(facet_sh);
+ }
+ return true;
+ }
+
+ bool is_face(Simplex_handle face, Simplex_handle coface)
+ {
+ // vertex range is sorted in decreasing order
+ auto fvr = sc.simplex_vertex_range(face);
+ auto cfvr = sc.simplex_vertex_range(coface);
+ auto fv_it = fvr.begin();
+ auto cfv_it = cfvr.begin();
+ while (fv_it != fvr.end() && cfv_it != cfvr.end()) {
+ if (*fv_it < *cfv_it)
+ ++cfv_it;
+ else if (*fv_it == *cfv_it) {
+ ++cfv_it;
+ ++fv_it;
+ }
+ else
+ return false;
+
+ }
+ return (fv_it == fvr.end());
+ }
+
+ // void erase_simplex(Simplex_handle sh)
+ // {
+ // auto siblings = sc.self_siblings(sh);
+ // auto oncles = siblings->oncles();
+ // int prev_vertex = siblings->parent();
+ // siblings->members().erase(sh->first);
+ // if (siblings->members().empty()) {
+ // typename typedef Simplicial_complex::Siblings Siblings;
+ // oncles->members().find(prev_vertex)->second.assign_children(new Siblings(oncles, prev_vertex));
+ // assert(!sc.has_children(oncles->members().find(prev_vertex)));
+ // //delete siblings;
+ // }
+
+ // }
+
+ void elementary_collapse(Simplex_handle face_sh, Simplex_handle coface_sh)
+ {
+ erase_simplex(coface_sh);
+ erase_simplex(face_sh);
+ }
+
+public:
+ // void collapse(std::vector<Simplex_handle>& simplices)
+ // {
+ // // Get a vector of simplex handles ordered by filtration value
+ // std::cout << sc << std::endl;
+ // //std::vector<Simplex_handle> simplices;
+ // for (Simplex_handle sh: sc.filtration_simplex_range())
+ // simplices.push_back(sh);
+ // // std::sort(simplices.begin(),
+ // // simplices.end(),
+ // // [&](Simplex_handle sh1, Simplex_handle sh2)
+ // // { double f1 = sc.filtration(sh1), f2 = sc.filtration(sh2);
+ // // return (f1 > f2) || (f1 >= f2 && sc.dimension(sh1) > sc.dimension(sh2)); });
+ // // Double iteration
+ // auto face_it = simplices.rbegin();
+ // while (face_it != simplices.rend() && sc.filtration(*face_it) != 0) {
+ // int coface_count = 0;
+ // auto reduced_coface = simplices.rbegin();
+ // for (auto coface_it = simplices.rbegin(); coface_it != simplices.rend() && sc.filtration(*coface_it) != 0; ++coface_it)
+ // if (face_it != coface_it && is_face(*face_it, *coface_it)) {
+ // coface_count++;
+ // if (coface_count == 1)
+ // reduced_coface = coface_it;
+ // else
+ // break;
+ // }
+ // if (coface_count == 1) {
+ // std::cout << "Erase ( ";
+ // for (auto v: sc.simplex_vertex_range(*(--reduced_coface.base())))
+ // std::cout << v << " ";
+
+ // simplices.erase(--(reduced_coface.base()));
+ // //elementary_collapse(*face_it, *reduced_coface);
+ // std::cout << ") and then ( ";
+ // for (auto v: sc.simplex_vertex_range(*(--face_it.base())))
+ // std::cout << v << " ";
+ // std::cout << ")\n";
+ // simplices.erase(--((face_it++).base()));
+ // //face_it = simplices.rbegin();
+ // //std::cout << "Size of vector: " << simplices.size() << "\n";
+ // }
+ // else
+ // face_it++;
+ // }
+ // sc.initialize_filtration();
+ // //std::cout << sc << std::endl;
+ // }
+
+ template <class Dim_lists>
+ void collapse(Dim_lists& dim_lists)
+ {
+ dim_lists.collapse();
+ }
+
+private:
+
+ /** Collapse recursively boundary faces of the given simplex
+ * if its filtration is bigger than alpha_lim.
+ */
+ void rec_boundary_collapse(Simplex_handle sh, FT alpha_lim)
+ {
+ for (Simplex_handle face_it : sc.boundary_simplex_range()) {
+
+ }
+
+ }
+
+}; //class Weak_relaxed_witness_complex
+
+} // namespace witness_complex
+
+} // namespace Gudhi
+
+#endif