summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt42
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/Simplex_tree/include/gudhi/Simplex_tree.h1
-rw-r--r--src/Witness_complex/example/CMakeLists.txt101
-rw-r--r--src/Witness_complex/example/Torus_distance.h209
-rw-r--r--src/Witness_complex/example/protected_sets/output_tikz.h67
-rw-r--r--src/Witness_complex/example/protected_sets/protected_sets.h597
-rw-r--r--src/Witness_complex/example/protected_sets/protected_sets_paper.cpp610
-rw-r--r--src/Witness_complex/example/protected_sets/protected_sets_paper.h917
-rw-r--r--src/Witness_complex/example/protected_sets/protected_sets_paper2.h1384
-rw-r--r--src/Witness_complex/example/relaxed_witness_complex_sphere.cpp461
-rw-r--r--src/Witness_complex/example/simple_witness_complex.cpp54
-rw-r--r--src/Witness_complex/example/witness_complex_cube.cpp590
-rw-r--r--src/Witness_complex/example/witness_complex_cubic_systems.cpp547
-rw-r--r--src/Witness_complex/example/witness_complex_epsilon.cpp55
-rw-r--r--src/Witness_complex/example/witness_complex_flat_torus.cpp851
-rw-r--r--src/Witness_complex/example/witness_complex_from_file.cpp156
-rw-r--r--src/Witness_complex/example/witness_complex_from_off.cpp184
-rw-r--r--src/Witness_complex/example/witness_complex_from_wl_matrix.cpp148
-rw-r--r--src/Witness_complex/example/witness_complex_knn_landmarks.cpp210
-rw-r--r--src/Witness_complex/example/witness_complex_perturbations.cpp462
-rw-r--r--src/Witness_complex/example/witness_complex_protected_delaunay.cpp604
-rw-r--r--src/Witness_complex/example/witness_complex_sphere.cpp457
-rw-r--r--src/Witness_complex/include/gudhi/Relaxed_witness_complex.h886
-rw-r--r--src/Witness_complex/include/gudhi/Witness_complex.h1111
25 files changed, 10690 insertions, 15 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 02e0c614..57cb14d4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,7 +14,7 @@ if(MSVC)
# Turn off some VC++ warnings
SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267 /wd4668 /wd4311 /wd4800 /wd4820 /wd4503 /wd4244 /wd4345 /wd4996 /wd4396 /wd4018")
else()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -std=c++11 -Wall -Wpedantic -Wsign-compare")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -std=c++11 -Wall -Wsign-compare")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -ggdb -O0")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
endif()
@@ -24,24 +24,36 @@ set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost)
-find_package(GMP)
-if(GMP_FOUND)
- find_package(GMPXX)
-endif()
+#find_package(GMP)
+#if(GMP_FOUND)
+ #find_package(GMPXX)
+#endif()
find_package(CGAL)
# Required programs for unitary tests purpose
-FIND_PROGRAM( GCOVR_PATH gcovr )
-if (GCOVR_PATH)
- message("gcovr found in ${GCOVR_PATH}")
+FIND_PROGRAM( LCOV_PATH lcov )
+if (LCOV_PATH)
+ message("lcov found in ${LCOV_PATH}")
endif()
-# Required programs for unitary tests purpose
-FIND_PROGRAM( GPROF_PATH gprof )
-if (GPROF_PATH)
- message("gprof found in ${GPROF_PATH}")
+
+FIND_PROGRAM( PYTHON_PATH python )
+if (PYTHON_PATH)
+ message("python found in ${PYTHON_PATH}")
endif()
+# Function to add_test cpplint on each header file of the Gudhi module
+function(cpplint_add_tests the_directory)
+ if (PYTHON_PATH)
+ # Cpplint tests on coding style
+ file(GLOB files "${the_directory}/*.h" "${the_directory}/*/*.h")
+ foreach(filename ${files})
+ message(${filename})
+ add_test("${filename}.cpplint" ${CMAKE_SOURCE_DIR}/scripts/check_google_style.sh ${filename} ${CMAKE_SOURCE_DIR}/scripts/cpplint.py)
+ endforeach()
+ endif()
+endfunction(cpplint_add_tests)
+
if(NOT Boost_FOUND)
message(FATAL_ERROR "NOTICE: This demo requires Boost and will not be compiled.")
@@ -64,6 +76,7 @@ else()
include_directories(src/Persistent_cohomology/include/)
include_directories(src/Simplex_tree/include/)
include_directories(src/Skeleton_blocker/include/)
+ include_directories(src/Witness_complex/include/)
add_subdirectory(src/Simplex_tree/test)
add_subdirectory(src/Simplex_tree/example)
@@ -73,14 +86,13 @@ else()
add_subdirectory(src/Skeleton_blocker/example)
add_subdirectory(src/Contraction/example)
add_subdirectory(src/Hasse_complex/example)
+ add_subdirectory(src/Witness_complex/test)
+ add_subdirectory(src/Witness_complex/example)
add_subdirectory(src/Alpha_shapes/example)
add_subdirectory(src/Alpha_shapes/test)
add_subdirectory(src/Bottleneck/example)
add_subdirectory(src/Bottleneck/test)
- # GudhUI
- add_subdirectory(src/GudhUI)
-
# data points generator
add_subdirectory(data/points/generator)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3be05c4f..70fc9a45 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -44,6 +44,7 @@ else()
add_subdirectory(example/Skeleton_blocker)
add_subdirectory(example/Contraction)
add_subdirectory(example/Hasse_complex)
+ add_subdirectort(example/Witness_complex)
add_subdirectory(example/Alpha_shapes)
add_subdirectory(example/Bottleneck)
diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h
index 9d0cf755..5d3753ca 100644
--- a/src/Simplex_tree/include/gudhi/Simplex_tree.h
+++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h
@@ -35,6 +35,7 @@
#include <algorithm>
#include <utility>
#include <vector>
+#include <iostream>
namespace Gudhi {
diff --git a/src/Witness_complex/example/CMakeLists.txt b/src/Witness_complex/example/CMakeLists.txt
new file mode 100644
index 00000000..ff372d16
--- /dev/null
+++ b/src/Witness_complex/example/CMakeLists.txt
@@ -0,0 +1,101 @@
+cmake_minimum_required(VERSION 2.6)
+project(GUDHIWitnessComplex)
+
+# A simple example
+ add_executable ( simple_witness_complex simple_witness_complex.cpp )
+ add_test(simple_witness_complex ${CMAKE_CURRENT_BINARY_DIR}/simple_witness_complex)
+
+ add_executable( witness_complex_from_file witness_complex_from_file.cpp )
+ #target_link_libraries(witness_complex_from_file ${EIGEN3_LIBRARIES} ${CGAL_LIBRARY})
+ add_test( witness_complex_from_bunny &{CMAKE_CURRENT_BINARY_DIR}/witness_complex_from_file ${CMAKE_SOURCE_DIR}/data/points/bunny_5000 100)
+
+ add_executable( witness_complex_from_off witness_complex_from_off.cpp )
+
+ add_executable( witness_complex_from_wl_matrix witness_complex_from_wl_matrix.cpp )
+
+
+# An example with Simplex-tree using CGAL alpha_shapes_3
+
+#find_package(Eigen3 3.1.0)
+#if(GMP_FOUND AND CGAL_FOUND)
+# message("CGAL_lib = ${CGAL_LIBRARIES_DIR}")
+# message("GMP_LIBRARIES = ${GMP_LIBRARIES}")
+# message(STATUS "Eigen3 version: ${EIGEN3_VERSION}.")
+# #message("EIGEN3_LIBRARIES = ${EIGEN3_LIBRARIES}")
+# INCLUDE_DIRECTORIES(${EIGEN3_INCLUDE_DIRS})
+# INCLUDE_DIRECTORIES(${GMP_INCLUDE_DIR})
+# INCLUDE_DIRECTORIES(${CGAL_INCLUDE_DIRS})
+# add_executable (witness_complex_knn_landmarks witness_complex_knn_landmarks.cpp )
+# target_link_libraries(witness_complex_knn_landmarks ${EIGEN3_LIBRARIES} ${CGAL_LIBRARY})
+# add_test(witness_complex_knn_landmarks ${CMAKE_CURRENT_BINARY_DIR}/witness_complex_knn_landmarks ${CMAKE_SOURCE_DIR}/data/points/bunny_5000 100)
+#endif()
+
+# need CGAL 4.6
+# cmake -DCGAL_DIR=~/workspace/CGAL-4.6-beta1 ../../..
+if(CGAL_FOUND)
+ if (NOT CGAL_VERSION VERSION_LESS 4.6.0)
+ message(STATUS "CGAL version: ${CGAL_VERSION}.")
+
+ include( ${CGAL_USE_FILE} )
+
+ find_package(Eigen3 3.1.0)
+ if (EIGEN3_FOUND)
+ message(STATUS "Eigen3 version: ${EIGEN3_VERSION}.")
+ include( ${EIGEN3_USE_FILE} )
+ message(STATUS "Eigen3 use file: ${EIGEN3_USE_FILE}.")
+ include_directories (BEFORE "../../include")
+
+ add_executable ( witness_complex_knn_landmarks witness_complex_knn_landmarks.cpp )
+ target_link_libraries(witness_complex_knn_landmarks ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY})
+ add_test(witness_complex_knn_landmarks ${CMAKE_CURRENT_BINARY_DIR}/witness_complex_knn_landmarks ${CMAKE_SOURCE_DIR}/data/points/bunny_5000 100)
+ #add_executable ( witness_complex_perturbations witness_complex_perturbations.cpp )
+ #target_link_libraries(witness_complex_perturbations ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY})
+ #add_test(witness_complex_perturbations ${CMAKE_CURRENT_BINARY_DIR}/witness_complex_perturbations ${CMAKE_SOURCE_DIR}/data/points/bunny_5000 100)
+ else()
+ message(WARNING "Eigen3 not found. Version 3.1.0 is required for Alpha shapes feature.")
+ endif()
+ else()
+ message(WARNING "CGAL version: ${CGAL_VERSION} is too old to compile Alpha shapes feature. Version 4.6.0 is required.")
+ endif ()
+endif()
+if(CGAL_FOUND)
+ if (NOT CGAL_VERSION VERSION_LESS 4.6.0)
+ message(STATUS "CGAL version: ${CGAL_VERSION}.")
+
+ include( ${CGAL_USE_FILE} )
+
+ find_package(Eigen3 3.1.0)
+ if (EIGEN3_FOUND)
+ message(STATUS "Eigen3 version: ${EIGEN3_VERSION}.")
+ include( ${EIGEN3_USE_FILE} )
+ include_directories (BEFORE "../../include")
+ add_executable ( witness_complex_perturbations witness_complex_perturbations.cpp )
+ target_link_libraries(witness_complex_perturbations ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY})
+ add_test(witness_complex_perturbations ${CMAKE_CURRENT_BINARY_DIR}/witness_complex_perturbations ${CMAKE_SOURCE_DIR}/data/points/bunny_5000 100)
+ add_executable ( witness_complex_flat_torus witness_complex_flat_torus.cpp )
+ target_link_libraries(witness_complex_flat_torus ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY})
+ add_test(witness_complex_flat_torus ${CMAKE_CURRENT_BINARY_DIR}/witness_complex_flat_torus ${CMAKE_SOURCE_DIR}/data/points/bunny_5000 100)
+ add_executable ( witness_complex_sphere witness_complex_sphere.cpp )
+ target_link_libraries(witness_complex_sphere ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY})
+ add_test(witness_complex_sphere ${CMAKE_CURRENT_BINARY_DIR}/witness_complex_sphere ${CMAKE_SOURCE_DIR}/data/points/bunny_5000 100)
+ add_executable ( relaxed_witness_complex_sphere relaxed_witness_complex_sphere.cpp )
+ add_test(witness_complex_sphere ${CMAKE_CURRENT_BINARY_DIR}/witness_complex_sphere ${CMAKE_SOURCE_DIR}/data/points/bunny_5000 100)
+ add_executable ( witness_complex_protected_delaunay witness_complex_protected_delaunay.cpp )
+ target_link_libraries(witness_complex_protected_delaunay ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY})
+ add_test(witness_complex_protected_delaunay ${CMAKE_CURRENT_BINARY_DIR}/witness_complex_protected_delaunay ${CMAKE_SOURCE_DIR}/data/points/bunny_5000 100)
+ add_executable ( witness_complex_cubic_systems witness_complex_cubic_systems.cpp )
+ target_link_libraries(witness_complex_cubic_systems ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY})
+ add_test(witness_complex_cubic_systems ${CMAKE_CURRENT_BINARY_DIR}/witness_complex_cubic_systems ${CMAKE_SOURCE_DIR}/data/points/bunny_5000 100)
+ add_executable ( witness_complex_cube witness_complex_cube.cpp )
+ target_link_libraries(witness_complex_cube ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY})
+ add_test(witness_complex_cube ${CMAKE_CURRENT_BINARY_DIR}/witness_complex_cube ${CMAKE_SOURCE_DIR}/data/points/bunny_5000 100)
+ add_executable ( witness_complex_epsilon witness_complex_epsilon.cpp )
+ target_link_libraries(witness_complex_epsilon ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY})
+ add_test(witness_complex_epsilon ${CMAKE_CURRENT_BINARY_DIR}/witness_complex_epsilon ${CMAKE_SOURCE_DIR}/data/points/bunny_5000 100)
+ else()
+ message(WARNING "Eigen3 not found. Version 3.1.0 is required for Alpha shapes feature.")
+ endif()
+ else()
+ message(WARNING "CGAL version: ${CGAL_VERSION} is too old to compile Alpha shapes feature. Version 4.6.0 is required.")
+ endif ()
+endif()
diff --git a/src/Witness_complex/example/Torus_distance.h b/src/Witness_complex/example/Torus_distance.h
new file mode 100644
index 00000000..5ae127df
--- /dev/null
+++ b/src/Witness_complex/example/Torus_distance.h
@@ -0,0 +1,209 @@
+#ifndef GUDHI_TORUS_DISTANCE_H_
+#define GUDHI_TORUS_DISTANCE_H_
+
+#include <math.h>
+
+#include <CGAL/Search_traits.h>
+#include <CGAL/Search_traits_adapter.h>
+#include <CGAL/Epick_d.h>
+
+typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> K;
+typedef K::Point_d Point_d;
+typedef K::FT FT;
+typedef CGAL::Search_traits<
+ FT, Point_d,
+ typename K::Cartesian_const_iterator_d,
+ typename K::Construct_cartesian_const_iterator_d> Traits_base;
+
+/**
+ * \brief Class of distance in a flat torus in dimension D
+ *
+ */
+class Torus_distance {
+
+public:
+ typedef K::FT FT;
+ typedef K::Point_d Point_d;
+ typedef Point_d Query_item;
+ typedef typename CGAL::Dynamic_dimension_tag D;
+
+ double box_length = 2;
+
+ FT transformed_distance(Query_item q, Point_d p) const
+ {
+ FT distance = FT(0);
+ FT coord = FT(0);
+ //std::cout << "Hello skitty!\n";
+ typename K::Construct_cartesian_const_iterator_d construct_it=Traits_base().construct_cartesian_const_iterator_d_object();
+ typename K::Cartesian_const_iterator_d qit = construct_it(q),
+ qe = construct_it(q,1), pit = construct_it(p);
+ for(; qit != qe; qit++, pit++)
+ {
+ coord = sqrt(((*qit)-(*pit))*((*qit)-(*pit)));
+ if (coord*coord <= (box_length-coord)*(box_length-coord))
+ distance += coord*coord;
+ else
+ distance += (box_length-coord)*(box_length-coord);
+ }
+ return distance;
+ }
+
+ FT min_distance_to_rectangle(const Query_item& q,
+ const CGAL::Kd_tree_rectangle<FT,D>& r) const {
+ FT distance = FT(0);
+ FT dist1, dist2;
+ typename K::Construct_cartesian_const_iterator_d construct_it=Traits_base().construct_cartesian_const_iterator_d_object();
+ typename K::Cartesian_const_iterator_d qit = construct_it(q),
+ qe = construct_it(q,1);
+ for(unsigned int i = 0;qit != qe; i++, qit++)
+ {
+ if((*qit) < r.min_coord(i))
+ {
+ dist1 = (r.min_coord(i)-(*qit));
+ dist2 = (box_length - r.max_coord(i)+(*qit));
+ if (dist1 < dist2)
+ distance += dist1*dist1;
+ else
+ distance += dist2*dist2;
+ }
+ else if ((*qit) > r.max_coord(i))
+ {
+ dist1 = (box_length - (*qit)+r.min_coord(i));
+ dist2 = ((*qit) - r.max_coord(i));
+ if (dist1 < dist2)
+ distance += dist1*dist1;
+ else
+ distance += dist2*dist2;
+ }
+ }
+ return distance;
+ }
+
+ FT min_distance_to_rectangle(const Query_item& q,
+ const CGAL::Kd_tree_rectangle<FT,D>& r,
+ std::vector<FT>& dists) const {
+ FT distance = FT(0);
+ FT dist1, dist2;
+ typename K::Construct_cartesian_const_iterator_d construct_it=Traits_base().construct_cartesian_const_iterator_d_object();
+ typename K::Cartesian_const_iterator_d qit = construct_it(q),
+ qe = construct_it(q,1);
+ //std::cout << r.max_coord(0) << std::endl;
+ for(unsigned int i = 0;qit != qe; i++, qit++)
+ {
+ if((*qit) < r.min_coord(i))
+ {
+ dist1 = (r.min_coord(i)-(*qit));
+ dist2 = (box_length - r.max_coord(i)+(*qit));
+ if (dist1 < dist2)
+ {
+ dists[i] = dist1;
+ distance += dist1*dist1;
+ }
+ else
+ {
+ dists[i] = dist2;
+ distance += dist2*dist2;
+ //std::cout << "Good stuff1\n";
+ }
+ }
+ else if ((*qit) > r.max_coord(i))
+ {
+ dist1 = (box_length - (*qit)+r.min_coord(i));
+ dist2 = ((*qit) - r.max_coord(i));
+ if (dist1 < dist2)
+ {
+ dists[i] = dist1;
+ distance += dist1*dist1;
+ //std::cout << "Good stuff2\n";
+ }
+ else
+ {
+ dists[i] = dist2;
+ distance += dist2*dist2;
+ }
+ }
+ };
+ return distance;
+ }
+
+ FT max_distance_to_rectangle(const Query_item& q,
+ const CGAL::Kd_tree_rectangle<FT,D>& r) const {
+ FT distance=FT(0);
+ typename K::Construct_cartesian_const_iterator_d construct_it=Traits_base().construct_cartesian_const_iterator_d_object();
+ typename K::Cartesian_const_iterator_d qit = construct_it(q),
+ qe = construct_it(q,1);
+ for(unsigned int i = 0;qit != qe; i++, qit++)
+ {
+ if (box_length <= (r.min_coord(i)+r.max_coord(i)))
+ if ((r.max_coord(i)+r.min_coord(i)-box_length)/FT(2.0) <= (*qit) &&
+ (*qit) <= (r.min_coord(i)+r.max_coord(i))/FT(2.0))
+ distance += (r.max_coord(i)-(*qit))*(r.max_coord(i)-(*qit));
+ else
+ distance += ((*qit)-r.min_coord(i))*((*qit)-r.min_coord(i));
+ else
+ if ((box_length-r.max_coord(i)-r.min_coord(i))/FT(2.0) <= (*qit) ||
+ (*qit) <= (r.min_coord(i)+r.max_coord(i))/FT(2.0))
+ distance += (r.max_coord(i)-(*qit))*(r.max_coord(i)-(*qit));
+ else
+ distance += ((*qit)-r.min_coord(i))*((*qit)-r.min_coord(i));
+ }
+ return distance;
+ }
+
+
+ FT max_distance_to_rectangle(const Query_item& q,
+ const CGAL::Kd_tree_rectangle<FT,D>& r,
+ std::vector<FT>& dists) const {
+ FT distance=FT(0);
+ typename K::Construct_cartesian_const_iterator_d construct_it=Traits_base().construct_cartesian_const_iterator_d_object();
+ typename K::Cartesian_const_iterator_d qit = construct_it(q),
+ qe = construct_it(q,1);
+ for(unsigned int i = 0;qit != qe; i++, qit++)
+ {
+ if (box_length <= (r.min_coord(i)+r.max_coord(i)))
+ if ((r.max_coord(i)+r.min_coord(i)-box_length)/FT(2.0) <= (*qit) &&
+ (*qit) <= (r.min_coord(i)+r.max_coord(i))/FT(2.0))
+ {
+ dists[i] = r.max_coord(i)-(*qit);
+ distance += (r.max_coord(i)-(*qit))*(r.max_coord(i)-(*qit));
+ }
+ else
+ {
+ dists[i] = sqrt(((*qit)-r.min_coord(i))*((*qit)-r.min_coord(i)));
+ distance += ((*qit)-r.min_coord(i))*((*qit)-r.min_coord(i));
+ }
+ else
+ if ((box_length-r.max_coord(i)-r.min_coord(i))/FT(2.0) <= (*qit) ||
+ (*qit) <= (r.min_coord(i)+r.max_coord(i))/FT(2.0))
+ {
+ dists[i] = sqrt((r.max_coord(i)-(*qit))*(r.max_coord(i)-(*qit)));
+ distance += (r.max_coord(i)-(*qit))*(r.max_coord(i)-(*qit));
+
+ }
+ else
+ {
+ dists[i] = (*qit)-r.min_coord(i);
+ distance += ((*qit)-r.min_coord(i))*((*qit)-r.min_coord(i));
+ }
+ }
+ return distance;
+ }
+
+ inline FT new_distance(FT dist, FT old_off, FT new_off,
+ int ) const {
+
+ FT new_dist = dist + (new_off*new_off - old_off*old_off);
+ return new_dist;
+ }
+
+ inline FT transformed_distance(FT d) const {
+ return d*d;
+ }
+
+ inline FT inverse_of_transformed_distance(FT d) const {
+ return sqrt(d);
+ }
+
+};
+
+#endif
diff --git a/src/Witness_complex/example/protected_sets/output_tikz.h b/src/Witness_complex/example/protected_sets/output_tikz.h
new file mode 100644
index 00000000..edfd9a5f
--- /dev/null
+++ b/src/Witness_complex/example/protected_sets/output_tikz.h
@@ -0,0 +1,67 @@
+#ifndef OUTPUT_TIKZ_H
+#define OUTPUT_TIKZ_H
+
+#include <vector>
+#include <string>
+#include <algorithm>
+#include <fstream>
+#include <cmath>
+
+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();
+
+
+
+}
+
+#endif
diff --git a/src/Witness_complex/example/protected_sets/protected_sets.h b/src/Witness_complex/example/protected_sets/protected_sets.h
new file mode 100644
index 00000000..ec627808
--- /dev/null
+++ b/src/Witness_complex/example/protected_sets/protected_sets.h
@@ -0,0 +1,597 @@
+#ifndef PROTECTED_SETS_H
+#define PROTECTED_SETS_H
+
+#include <algorithm>
+#include <CGAL/Cartesian_d.h>
+#include <CGAL/Epick_d.h>
+#include <CGAL/Euclidean_distance.h>
+#include <CGAL/Kernel_d/Sphere_d.h>
+#include <CGAL/Kernel_d/Hyperplane_d.h>
+#include <CGAL/Kernel_d/Vector_d.h>
+
+#include <CGAL/point_generators_d.h>
+#include <CGAL/constructions_d.h>
+
+
+typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> K;
+typedef K::Point_d Point_d;
+typedef K::Vector_d Vector_d;
+typedef K::Oriented_side_d Oriented_side_d;
+typedef K::Has_on_positive_side_d Has_on_positive_side_d;
+typedef K::Sphere_d Sphere_d;
+typedef K::Hyperplane_d Hyperplane_d;
+
+typedef CGAL::Delaunay_triangulation<K> Delaunay_triangulation;
+typedef Delaunay_triangulation::Facet Facet;
+typedef Delaunay_triangulation::Vertex_handle Delaunay_vertex;
+typedef Delaunay_triangulation::Full_cell_handle Full_cell_handle;
+
+typedef std::vector<Point_d> Point_Vector;
+typedef CGAL::Euclidean_distance<Traits_base> Euclidean_distance;
+
+FT _sfty = pow(10,-14);
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+// AUXILLARY FUNCTIONS
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/** Insert a point in Delaunay triangulation. If you are working in a flat torus, the procedure adds all the 3^d copies in adjacent cubes as well
+ *
+ * W is the initial point vector
+ * chosen_landmark is the index of the chosen point in W
+ * landmarks_ind is the vector of indices of already chosen points in W
+ * delaunay is the Delaunay triangulation
+ * landmark_count is the current number of chosen vertices
+ * torus is true iff you are working on a flat torus [-1,1]^d
+ * OUT: Vertex handle to the newly inserted point
+ */
+Delaunay_vertex insert_delaunay_landmark_with_copies(Point_Vector& W, int chosen_landmark, std::vector<int>& landmarks_ind, Delaunay_triangulation& delaunay, int& landmark_count, bool torus)
+{
+ if (!torus)
+ {
+ Delaunay_vertex v =delaunay.insert(W[chosen_landmark]);
+ landmarks_ind.push_back(chosen_landmark);
+ landmark_count++;
+ return v;
+ }
+ else
+ {
+ int D = W[0].size();
+ int nb_cells = pow(3, D);
+ Delaunay_vertex v;
+ for (int i = 0; i < nb_cells; ++i)
+ {
+ std::vector<FT> point;
+ int cell_i = i;
+ for (int l = 0; l < D; ++l)
+ {
+ point.push_back(W[chosen_landmark][l] + 2.0*(cell_i%3-1));
+ cell_i /= 3;
+ }
+ v = delaunay.insert(point);
+ }
+ landmarks_ind.push_back(chosen_landmark);
+ landmark_count++;
+ return v;
+ }
+}
+
+/** Small check if the vertex v is in the full cell fc
+ */
+
+bool vertex_is_in_full_cell(Delaunay_triangulation::Vertex_handle v, Full_cell_handle fc)
+{
+ for (auto v_it = fc->vertices_begin(); v_it != fc->vertices_end(); ++v_it)
+ if (*v_it == v)
+ return true;
+ return false;
+}
+
+/** Fill chosen point vector from indices with copies if you are working on a flat torus
+ *
+ * IN: W is the point vector
+ * OUT: landmarks is the output vector
+ * IN: landmarks_ind is the vector of indices
+ * IN: torus is true iff you are working on a flat torus [-1,1]^d
+ */
+
+void fill_landmarks(Point_Vector& W, Point_Vector& landmarks, std::vector<int>& landmarks_ind, bool torus)
+{
+ if (!torus)
+ for (unsigned j = 0; j < landmarks_ind.size(); ++j)
+ landmarks.push_back(W[landmarks_ind[j]]);
+ else
+ {
+ int D = W[0].size();
+ int nb_cells = pow(3, D);
+ int nbL = landmarks_ind.size();
+ // Fill landmarks
+ for (int i = 0; i < nb_cells-1; ++i)
+ for (int j = 0; j < nbL; ++j)
+ {
+ int cell_i = i;
+ Point_d point;
+ for (int l = 0; l < D; ++l)
+ {
+ point.push_back(W[landmarks_ind[j]][l] + 2.0*(cell_i-1));
+ cell_i /= 3;
+ }
+ landmarks.push_back(point);
+ }
+ }
+}
+
+/** Fill a vector of all simplices in the Delaunay triangulation giving integer indices to vertices
+ *
+ * IN: t is the Delaunay triangulation
+ * OUT: full_cells is the output vector
+ */
+
+void fill_full_cell_vector(Delaunay_triangulation& t, std::vector<std::vector<int>>& full_cells)
+{
+ // Store vertex indices in a map
+ int ind = 0; //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;
+ else
+ index_of_vertex[v_it] = ind++;
+ // Write full cells as vectors in full_cells
+ for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
+ {
+ if (t.is_infinite(fc_it))
+ continue;
+ Point_Vector vertices;
+ for (auto fc_v_it = fc_it->vertices_begin(); fc_v_it != fc_it->vertices_end(); ++fc_v_it)
+ vertices.push_back((*fc_v_it)->point());
+ Sphere_d cs( vertices.begin(), vertices.end());
+ Point_d csc = cs.center();
+ bool in_cube = true;
+ for (auto xi = csc.cartesian_begin(); xi != csc.cartesian_end(); ++xi)
+ if (*xi > 1.0 || *xi < -1.0)
+ {
+ in_cube = false; break;
+ }
+ if (!in_cube)
+ continue;
+ std::vector<int> cell;
+ for (auto v_it = fc_it->vertices_begin(); v_it != fc_it->vertices_end(); ++v_it)
+ cell.push_back(index_of_vertex[*v_it]);
+ full_cells.push_back(cell);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// IS VIOLATED TEST
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/** Check if a newly created cell is protected from old vertices
+ *
+ * t is the Delaunay triangulation
+ * vertices is the vector containing the point to insert and a facet f in t
+ * v1 is the vertex of t, such that f and v1 form a simplex
+ * v2 is the vertex of t, such that f and v2 form another simplex
+ * delta is the protection constant
+ * power_protection is true iff the delta-power protection is used
+ */
+
+bool new_cell_is_violated(Delaunay_triangulation& t, std::vector<Point_d>& vertices, const Delaunay_vertex& v1, const Delaunay_vertex v2, FT delta, bool power_protection, FT theta0)
+{
+ assert(vertices.size() == vertices[0].size() ||
+ vertices.size() == vertices[0].size() + 1); //simplex size = d | d+1
+ assert(v1 != v2);
+ if (vertices.size() == vertices[0].size() + 1)
+ // FINITE CASE
+ {
+ Sphere_d cs(vertices.begin(), vertices.end());
+ Point_d center_cs = cs.center();
+ FT r = sqrt(Euclidean_distance().transformed_distance(center_cs, vertices[0]));
+ /*
+ for (auto v_it = t.vertices_begin(); v_it != t.vertices_end(); ++v_it)
+ if (!t.is_infinite(v_it))
+ {
+ //CGAL::Oriented_side side = Oriented_side_d()(cs, (v_it)->point());
+ if (std::find(vertices.begin(), vertices.end(), v_it->point()) == vertices.end())
+ {
+ FT dist2 = Euclidean_distance().transformed_distance(center_cs, (v_it)->point());
+ if (!power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= (r+delta)*(r+delta))
+ return true;
+ if (power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= r*r+delta*delta)
+ return true;
+ }
+ }
+ */
+ // Check if the simplex is thick enough
+ Hyperplane_d tau_h(vertices.begin()+1, vertices.end());
+ Vector_d orth_tau = tau_h.orthogonal_vector();
+ /*
+ p_s1 = Vector_d(*(vertices.begin()), *(vertices.begin()+1));
+ */
+ //std::cout << "||orth_tau|| = " << sqrt(orth_tau.squared_length()) << "\n";
+ FT orth_length = sqrt(orth_tau.squared_length());
+ K::Cartesian_const_iterator_d o_it, p_it, s_it, c_it;
+ // Compute the altitude
+ FT h = 0;
+ for (o_it = orth_tau.cartesian_begin(),
+ p_it = vertices.begin()->cartesian_begin(),
+ s_it = (vertices.begin()+1)->cartesian_begin();
+ o_it != orth_tau.cartesian_end();
+ ++o_it, ++p_it, ++s_it)
+ h += (*o_it)*(*p_it - *s_it)/orth_length;
+ h = fabs(h);
+ // Is the center inside the box?
+ bool inside_the_box = true;
+ for (c_it = center_cs.cartesian_begin(); c_it != center_cs.cartesian_end(); ++c_it)
+ if (*c_it > 1.0 || *c_it < -1.0)
+ {
+ inside_the_box = false; break;
+ }
+ if (inside_the_box && h/r < theta0)
+ return true;
+ if (!t.is_infinite(v1))
+ {
+ FT dist2 = Euclidean_distance().transformed_distance(center_cs, v1->point());
+ if (!power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= (r+delta)*(r+delta))
+ return true;
+ if (power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= r*r+delta*delta)
+ return true;
+ }
+ if (!t.is_infinite(v2))
+ {
+ FT dist2 = Euclidean_distance().transformed_distance(center_cs, v2->point());
+ if (!power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= (r+delta)*(r+delta))
+ return true;
+ if (power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= r*r+delta*delta)
+ return true;
+ }
+ }
+ else
+ // INFINITE CASE
+ {
+ Delaunay_triangulation::Vertex_iterator v = t.vertices_begin();
+ while (t.is_infinite(v) || std::find(vertices.begin(), vertices.end(), v->point()) == vertices.end())
+ v++;
+ Hyperplane_d facet_plane(vertices.begin(), vertices.end(), v->point(), CGAL::ON_POSITIVE_SIDE);
+ Vector_d orth_v = facet_plane.orthogonal_vector();
+ /*
+ for (auto v_it = t.vertices_begin(); v_it != t.vertices_end(); ++v_it)
+ if (!t.is_infinite(v_it))
+ if (std::find(vertices.begin(), vertices.end(), v_it->point()) == vertices.end())
+ {
+ std::vector<FT> coords;
+ Point_d p = v_it->point();
+ auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
+ for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
+ coords.push_back((*p_i) - (*orth_i) * delta / sqrt(orth_v.squared_length()));
+ Point_d p_delta = Point_d(coords);
+ bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p);
+ bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
+ if (!p_is_inside && p_delta_is_inside)
+ return true;
+ }
+ */
+ if (!t.is_infinite(v1))
+ {
+ std::vector<FT> coords;
+ Point_d p = v1->point();
+ auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
+ for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
+ coords.push_back((*p_i) - (*orth_i) * delta / sqrt(orth_v.squared_length()));
+ Point_d p_delta = Point_d(coords);
+ bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p);
+ bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
+ if (!power_protection && !p_is_inside && p_delta_is_inside)
+ return true;
+ }
+ if (!t.is_infinite(v2))
+ {
+ std::vector<FT> coords;
+ Point_d p = v2->point();
+ auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
+ for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
+ coords.push_back((*p_i) - (*orth_i) * delta / sqrt(orth_v.squared_length()));
+ Point_d p_delta = Point_d(coords);
+ bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p);
+ bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
+ if (!power_protection && !p_is_inside && p_delta_is_inside)
+ return true;
+ }
+ }
+ return false;
+}
+
+/** Auxillary recursive function to check if the point p violates the protection of the cell c and
+ * if there is a violation of an eventual new cell
+ *
+ * p is the point to insert
+ * t is the current triangulation
+ * c is the current cell (simplex)
+ * parent_cell is the parent cell (simplex)
+ * index is the index of the facet between c and parent_cell from parent_cell's point of view
+ * D is the dimension of the triangulation
+ * delta is the protection constant
+ * marked_cells is the vector of all visited cells containing p in their circumscribed ball
+ * power_protection is true iff you are working with delta-power protection
+ *
+ * OUT: true iff inserting p hasn't produced any violation so far
+ */
+
+bool is_violating_protection(Point_d& p, Delaunay_triangulation& t, Full_cell_handle c, Full_cell_handle parent_cell, int index, int D, FT delta, std::vector<Full_cell_handle>& marked_cells, bool power_protection, FT theta0)
+{
+ Euclidean_distance ed;
+ std::vector<Point_d> vertices;
+ if (!t.is_infinite(c))
+ {
+ // if the cell is finite, we look if the protection is violated
+ for (auto v_it = c->vertices_begin(); v_it != c->vertices_end(); ++v_it)
+ vertices.push_back((*v_it)->point());
+ Sphere_d cs( vertices.begin(), vertices.end());
+ Point_d center_cs = cs.center();
+ FT r = sqrt(ed.transformed_distance(center_cs, vertices[0]));
+ FT dist2 = ed.transformed_distance(center_cs, p);
+ // if the new point is inside the protection ball of a non conflicting simplex
+ if (!power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= (r+delta)*(r+delta))
+ return true;
+ if (power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= r*r+delta*delta)
+ return true;
+ // if the new point is inside the circumscribing ball : continue violation searching on neighbours
+ //if (dist2 < r*r)
+ //if (dist2 < (5*r+delta)*(5*r+delta))
+ if (dist2 < r*r)
+ {
+ c->tds_data().mark_visited();
+ marked_cells.push_back(c);
+ for (int i = 0; i < D+1; ++i)
+ {
+ Full_cell_handle next_c = c->neighbor(i);
+ if (next_c->tds_data().is_clear() &&
+ is_violating_protection(p, t, next_c, c, i, D, delta, marked_cells, power_protection, theta0))
+ return true;
+ }
+ }
+ // if the new point is outside the protection sphere
+ else
+ {
+ // facet f is on the border of the conflict zone : check protection of simplex {p,f}
+ // the new simplex is guaranteed to be finite
+ vertices.clear(); vertices.push_back(p);
+ for (int i = 0; i < D+1; ++i)
+ if (i != index)
+ vertices.push_back(parent_cell->vertex(i)->point());
+ Delaunay_vertex vertex_to_check = t.infinite_vertex();
+ for (auto vh_it = c->vertices_begin(); vh_it != c->vertices_end(); ++vh_it)
+ if (!vertex_is_in_full_cell(*vh_it, parent_cell))
+ {
+ vertex_to_check = *vh_it; break;
+ }
+ if (new_cell_is_violated(t, vertices, vertex_to_check, parent_cell->vertex(index), delta, power_protection, theta0))
+ //if (new_cell_is_violated(t, vertices, vertex_to_check->point(), delta))
+ return true;
+ }
+ }
+ else
+ {
+ // Inside of the convex hull is + side. Outside is - side.
+ for (auto vh_it = c->vertices_begin(); vh_it != c->vertices_end(); ++vh_it)
+ if (!t.is_infinite(*vh_it))
+ vertices.push_back((*vh_it)->point());
+ Delaunay_triangulation::Vertex_iterator v_it = t.vertices_begin();
+ while (t.is_infinite(v_it) || vertex_is_in_full_cell(v_it, c))
+ v_it++;
+ Hyperplane_d facet_plane(vertices.begin(), vertices.end(), v_it->point(), CGAL::ON_POSITIVE_SIDE);
+ //CGAL::Oriented_side outside = Oriented_side_d()(facet_plane, v_it->point());
+ Vector_d orth_v = facet_plane.orthogonal_vector();
+ std::vector<FT> coords;
+ auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
+ for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
+ coords.push_back((*p_i) - (*orth_i) * delta / sqrt(orth_v.squared_length()));
+ Point_d p_delta = Point_d(coords);
+ bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p) && (Oriented_side_d()(facet_plane, p) != CGAL::ZERO);
+ bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
+
+ // If we work with power protection, we just ignore any conflicts
+ if (!power_protection && !p_is_inside && p_delta_is_inside)
+ return true;
+ //if the cell is infinite we look at the neighbours regardless
+ if (p_is_inside)
+ {
+ c->tds_data().mark_visited();
+ marked_cells.push_back(c);
+ for (int i = 0; i < D+1; ++i)
+ {
+ Full_cell_handle next_c = c->neighbor(i);
+ if (next_c->tds_data().is_clear() &&
+ is_violating_protection(p, t, next_c, c, i, D, delta, marked_cells, power_protection, theta0))
+ return true;
+ }
+ }
+ else
+ {
+ // facet f is on the border of the conflict zone : check protection of simplex {p,f}
+ // the new simplex is finite if the parent cell is finite
+ vertices.clear(); vertices.push_back(p);
+ for (int i = 0; i < D+1; ++i)
+ if (i != index)
+ if (!t.is_infinite(parent_cell->vertex(i)))
+ vertices.push_back(parent_cell->vertex(i)->point());
+ Delaunay_vertex vertex_to_check = t.infinite_vertex();
+ for (auto vh_it = c->vertices_begin(); vh_it != c->vertices_end(); ++vh_it)
+ if (!vertex_is_in_full_cell(*vh_it, parent_cell))
+ {
+ vertex_to_check = *vh_it; break;
+ }
+ if (new_cell_is_violated(t, vertices, vertex_to_check, parent_cell->vertex(index), delta, power_protection, theta0))
+ //if (new_cell_is_violated(t, vertices, vertex_to_check->point(), delta))
+ return true;
+ }
+ }
+ //c->tds_data().clear_visited();
+ //marked_cells.pop_back();
+ return false;
+}
+
+/** Checks if inserting the point p in t will make conflicts
+ *
+ * p is the point to insert
+ * t is the current triangulation
+ * D is the dimension of triangulation
+ * delta is the protection constant
+ * power_protection is true iff you are working with delta-power protection
+ * OUT: true iff inserting p produces a violation of delta-protection.
+ */
+
+bool is_violating_protection(Point_d& p, Delaunay_triangulation& t, int D, FT delta, bool power_protection, FT theta0)
+{
+ Euclidean_distance ed;
+ Delaunay_triangulation::Vertex_handle v;
+ Delaunay_triangulation::Face f(t.current_dimension());
+ Delaunay_triangulation::Facet ft;
+ Delaunay_triangulation::Full_cell_handle c;
+ Delaunay_triangulation::Locate_type lt;
+ std::vector<Full_cell_handle> marked_cells;
+ c = t.locate(p, lt, f, ft, v);
+ bool violation_existing_cells = is_violating_protection(p, t, c, c, 0, D, delta, marked_cells, power_protection, theta0);
+ for (Full_cell_handle fc : marked_cells)
+ fc->tds_data().clear();
+ return violation_existing_cells;
+}
+
+///////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////
+//!!!!!!!!!!!!! THE INTERFACE FOR LANDMARK CHOICE IS BELOW !!!!!!!!!!//
+///////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////
+// LANDMARK CHOICE PROCEDURE
+///////////////////////////////////////////////////////////////////////
+
+/** Procedure to compute a maximal protected subset from a point cloud. All OUTs should be empty at call.
+ *
+ * IN: W is the initial point cloud having type Epick_d<Dynamic_dimension_tag>::Point_d
+ * IN: nbP is the size of W
+ * OUT: landmarks is the output vector for the points
+ * OUT: landmarks_ind is the output vector for the indices of the selected points in W
+ * IN: delta is the constant of protection
+ * OUT: full_cells is the output vector of the simplices in the final Delaunay triangulation
+ * IN: torus is true iff you are working on a flat torus [-1,1]^d
+ */
+
+void landmark_choice_protected_delaunay(Point_Vector& W, int nbP, Point_Vector& landmarks, std::vector<int>& landmarks_ind, FT delta, std::vector<std::vector<int>>& full_cells, bool torus, bool power_protection, FT theta0)
+{
+ bool return_ = true;
+ unsigned D = W[0].size();
+ Torus_distance td;
+ Euclidean_distance ed;
+ Delaunay_triangulation t(D);
+ CGAL::Random rand;
+ int landmark_count = 0;
+ std::list<int> index_list;
+ // shuffle the list of indexes (via a vector)
+ {
+ std::vector<int> temp_vector;
+ for (int i = 0; i < nbP; ++i)
+ temp_vector.push_back(i);
+ unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
+ std::shuffle(temp_vector.begin(), temp_vector.end(), std::default_random_engine(seed));
+ //CGAL::spatial_sort(temp_vector.begin(), temp_vector.end());
+ for (std::vector<int>::iterator it = temp_vector.begin(); it != temp_vector.end(); ++it)
+ index_list.push_front(*it);
+ }
+ if (!torus)
+ for (unsigned pos1 = 0; pos1 < D+1; ++pos1)
+ {
+ std::vector<FT> point;
+ for (unsigned i = 0; i < pos1; ++i)
+ point.push_back(-1);
+ if (pos1 != D)
+ point.push_back(1);
+ for (unsigned i = pos1+1; i < D; ++i)
+ point.push_back(0);
+ assert(point.size() == D);
+ W[index_list.front()] = Point_d(point);
+ insert_delaunay_landmark_with_copies(W, index_list.front(), landmarks_ind, t, landmark_count, torus);
+ index_list.pop_front();
+ }
+ else if (D == 2)
+ {
+ for (int i = 0; i < 4; ++i)
+ for (int j = 0; j < 2; ++j)
+ {
+ W[index_list.front()] = Point_d(std::vector<FT>{i*0.5, j*1.0});
+ insert_delaunay_landmark_with_copies(W, index_list.front(), landmarks_ind, t, landmark_count, torus);
+ index_list.pop_front();
+ W[index_list.front()] = Point_d(std::vector<FT>{0.25+i*0.5, 0.5+j});
+ insert_delaunay_landmark_with_copies(W, index_list.front(), landmarks_ind, t, landmark_count, torus);
+ index_list.pop_front();
+ }
+ }
+ else
+ std::cout << "No torus starter available for dim>2\n";
+ std::list<int>::iterator list_it = index_list.begin();
+ while (list_it != index_list.end())
+ {
+ if (!is_violating_protection(W[*list_it], t, D, delta, power_protection, theta0))
+ {
+ // If no conflicts then insert in every copy of T^3
+
+ insert_delaunay_landmark_with_copies(W, *list_it, landmarks_ind, t, landmark_count, torus);
+ if (return_)
+ {
+ index_list.erase(list_it);
+ list_it = index_list.begin();
+ }
+ else
+ index_list.erase(list_it++);
+ /*
+ // PIECE OF CODE FOR DEBUGGING PURPOSES
+
+ Delaunay_vertex inserted_v = insert_delaunay_landmark_with_copies(W, *list_it, landmarks_ind, t, landmark_count);
+ if (triangulation_is_protected(t, delta))
+ {
+ index_list.erase(list_it);
+ list_it = index_list.begin();
+ }
+ else
+ { //THAT'S WHERE SOMETHING'S WRONG
+ t.remove(inserted_v);
+ landmarks_ind.pop_back();
+ landmark_count--;
+ write_delaunay_mesh(t, W[*list_it], is2d);
+ is_violating_protection(W[*list_it], t_old, D, delta); //Called for encore
+ }
+ */
+ //std::cout << "index_list_size() = " << index_list.size() << "\n";
+ }
+ else
+ {
+ list_it++;
+ //std::cout << "!!!!!WARNING!!!!! A POINT HAS BEEN OMITTED!!!\n";
+ }
+ //if (list_it != index_list.end())
+ // write_delaunay_mesh(t, W[*list_it], is2d);
+ }
+ fill_landmarks(W, landmarks, landmarks_ind, torus);
+ fill_full_cell_vector(t, full_cells);
+ /*
+ if (triangulation_is_protected(t, delta))
+ std::cout << "Triangulation is ok\n";
+ else
+ {
+ std::cout << "Triangulation is BAD!! T_T しくしく!\n";
+ }
+ */
+ //write_delaunay_mesh(t, W[0], is2d);
+ //std::cout << t << std::endl;
+}
+
+#endif
diff --git a/src/Witness_complex/example/protected_sets/protected_sets_paper.cpp b/src/Witness_complex/example/protected_sets/protected_sets_paper.cpp
new file mode 100644
index 00000000..f3df3f1e
--- /dev/null
+++ b/src/Witness_complex/example/protected_sets/protected_sets_paper.cpp
@@ -0,0 +1,610 @@
+#ifndef PROTECTED_SETS_H
+#define PROTECTED_SETS_H
+
+#include <algorithm>
+#include <CGAL/Cartesian_d.h>
+#include <CGAL/Epick_d.h>
+#include <CGAL/Euclidean_distance.h>
+#include <CGAL/Kernel_d/Sphere_d.h>
+#include <CGAL/Kernel_d/Hyperplane_d.h>
+#include <CGAL/Kernel_d/Vector_d.h>
+
+typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> K;
+typedef K::Point_d Point_d;
+typedef K::Vector_d Vector_d;
+typedef K::Oriented_side_d Oriented_side_d;
+typedef K::Has_on_positive_side_d Has_on_positive_side_d;
+typedef K::Sphere_d Sphere_d;
+typedef K::Hyperplane_d Hyperplane_d;
+
+typedef CGAL::Delaunay_triangulation<K> Delaunay_triangulation;
+typedef Delaunay_triangulation::Facet Facet;
+typedef Delaunay_triangulation::Vertex_handle Delaunay_vertex;
+typedef Delaunay_triangulation::Full_cell_handle Full_cell_handle;
+
+typedef std::vector<Point_d> Point_Vector;
+typedef CGAL::Euclidean_distance<Traits_base> Euclidean_distance;
+
+FT _sfty = pow(10,-14);
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+// AUXILLARY FUNCTIONS
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/** Insert a point in Delaunay triangulation. If you are working in a flat torus, the procedure adds all the 3^d copies in adjacent cubes as well
+ *
+ * W is the initial point vector
+ * chosen_landmark is the index of the chosen point in W
+ * landmarks_ind is the vector of indices of already chosen points in W
+ * delaunay is the Delaunay triangulation
+ * landmark_count is the current number of chosen vertices
+ * torus is true iff you are working on a flat torus [-1,1]^d
+ * OUT: Vertex handle to the newly inserted point
+ */
+Delaunay_vertex insert_delaunay_landmark_with_copies(Point_d& p, Delaunay_triangulation& delaunay, int& landmark_count, bool torus)
+{
+ if (!torus)
+ {
+ Delaunay_vertex v =delaunay.insert(p);
+ landmark_count++;
+ return v;
+ }
+ else
+ {
+ int D = W[0].size();
+ int nb_cells = pow(3, D);
+ Delaunay_vertex v;
+ for (int i = 0; i < nb_cells; ++i)
+ {
+ std::vector<FT> point;
+ int cell_i = i;
+ for (int l = 0; l < D; ++l)
+ {
+ point.push_back(p[l] + 2.0*(cell_i%3-1));
+ cell_i /= 3;
+ }
+ v = delaunay.insert(point);
+ }
+ landmark_count++;
+ return v;
+ }
+}
+
+/** Small check if the vertex v is in the full cell fc
+ */
+
+bool vertex_is_in_full_cell(Delaunay_triangulation::Vertex_handle v, Full_cell_handle fc)
+{
+ for (auto v_it = fc->vertices_begin(); v_it != fc->vertices_end(); ++v_it)
+ if (*v_it == v)
+ return true;
+ return false;
+}
+
+/** Fill chosen point vector from indices with copies if you are working on a flat torus
+ *
+ * IN: W is the point vector
+ * OUT: landmarks is the output vector
+ * IN: landmarks_ind is the vector of indices
+ * IN: torus is true iff you are working on a flat torus [-1,1]^d
+ */
+
+void fill_landmarks(Point_Vector& W, Point_Vector& landmarks, std::vector<int>& landmarks_ind, bool torus)
+{
+ if (!torus)
+ for (unsigned j = 0; j < landmarks_ind.size(); ++j)
+ landmarks.push_back(W[landmarks_ind[j]]);
+ else
+ {
+ int D = W[0].size();
+ int nb_cells = pow(3, D);
+ int nbL = landmarks_ind.size();
+ // Fill landmarks
+ for (int i = 0; i < nb_cells-1; ++i)
+ for (int j = 0; j < nbL; ++j)
+ {
+ int cell_i = i;
+ Point_d point;
+ for (int l = 0; l < D; ++l)
+ {
+ point.push_back(W[landmarks_ind[j]][l] + 2.0*(cell_i-1));
+ cell_i /= 3;
+ }
+ landmarks.push_back(point);
+ }
+ }
+}
+
+/** Fill a vector of all simplices in the Delaunay triangulation giving integer indices to vertices
+ *
+ * IN: t is the Delaunay triangulation
+ * OUT: full_cells is the output vector
+ */
+
+void fill_full_cell_vector(Delaunay_triangulation& t, std::vector<std::vector<int>>& full_cells)
+{
+ // Store vertex indices in a map
+ int ind = 0; //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;
+ else
+ index_of_vertex[v_it] = ind++;
+ // Write full cells as vectors in full_cells
+ for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
+ {
+ if (t.is_infinite(fc_it))
+ continue;
+ Point_Vector vertices;
+ for (auto fc_v_it = fc_it->vertices_begin(); fc_v_it != fc_it->vertices_end(); ++fc_v_it)
+ vertices.push_back((*fc_v_it)->point());
+ Sphere_d cs( vertices.begin(), vertices.end());
+ Point_d csc = cs.center();
+ bool in_cube = true;
+ for (auto xi = csc.cartesian_begin(); xi != csc.cartesian_end(); ++xi)
+ if (*xi > 1.0 || *xi < -1.0)
+ {
+ in_cube = false; break;
+ }
+ if (!in_cube)
+ continue;
+ std::vector<int> cell;
+ for (auto v_it = fc_it->vertices_begin(); v_it != fc_it->vertices_end(); ++v_it)
+ cell.push_back(index_of_vertex[*v_it]);
+ full_cells.push_back(cell);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// IS VIOLATED TEST
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/** Check if a newly created cell is protected from old vertices
+ *
+ * t is the Delaunay triangulation
+ * vertices is the vector containing the point to insert and a facet f in t
+ * v1 is the vertex of t, such that f and v1 form a simplex
+ * v2 is the vertex of t, such that f and v2 form another simplex
+ * delta is the protection constant
+ * power_protection is true iff the delta-power protection is used
+ */
+
+bool new_cell_is_violated(Delaunay_triangulation& t, std::vector<Point_d>& vertices, const Delaunay_vertex& v1, const Delaunay_vertex v2, FT delta, bool power_protection, FT theta0)
+{
+ assert(vertices.size() == vertices[0].size() ||
+ vertices.size() == vertices[0].size() + 1); //simplex size = d | d+1
+ assert(v1 != v2);
+ if (vertices.size() == vertices[0].size() + 1)
+ // FINITE CASE
+ {
+ Sphere_d cs(vertices.begin(), vertices.end());
+ Point_d center_cs = cs.center();
+ FT r = sqrt(Euclidean_distance().transformed_distance(center_cs, vertices[0]));
+ /*
+ for (auto v_it = t.vertices_begin(); v_it != t.vertices_end(); ++v_it)
+ if (!t.is_infinite(v_it))
+ {
+ //CGAL::Oriented_side side = Oriented_side_d()(cs, (v_it)->point());
+ if (std::find(vertices.begin(), vertices.end(), v_it->point()) == vertices.end())
+ {
+ FT dist2 = Euclidean_distance().transformed_distance(center_cs, (v_it)->point());
+ if (!power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= (r+delta)*(r+delta))
+ return true;
+ if (power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= r*r+delta*delta)
+ return true;
+ }
+ }
+ */
+ // Check if the simplex is thick enough
+ Hyperplane_d tau_h(vertices.begin()+1, vertices.end());
+ Vector_d orth_tau = tau_h.orthogonal_vector();
+ /*
+ p_s1 = Vector_d(*(vertices.begin()), *(vertices.begin()+1));
+ */
+ //std::cout << "||orth_tau|| = " << sqrt(orth_tau.squared_length()) << "\n";
+ FT orth_length = sqrt(orth_tau.squared_length());
+ K::Cartesian_const_iterator_d o_it, p_it, s_it, c_it;
+ // Compute the altitude
+ FT h = 0;
+ for (o_it = orth_tau.cartesian_begin(),
+ p_it = vertices.begin()->cartesian_begin(),
+ s_it = (vertices.begin()+1)->cartesian_begin();
+ o_it != orth_tau.cartesian_end();
+ ++o_it, ++p_it, ++s_it)
+ h += (*o_it)*(*p_it - *s_it)/orth_length;
+ h = fabs(h);
+ // Is the center inside the box?
+ bool inside_the_box = true;
+ for (c_it = center_cs.cartesian_begin(); c_it != center_cs.cartesian_end(); ++c_it)
+ if (*c_it > 1.0 || *c_it < -1.0)
+ {
+ inside_the_box = false; break;
+ }
+ if (inside_the_box && h/r < theta0)
+ return true;
+ if (!t.is_infinite(v1))
+ {
+ FT dist2 = Euclidean_distance().transformed_distance(center_cs, v1->point());
+ if (!power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= (r+delta)*(r+delta))
+ return true;
+ if (power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= r*r+delta*delta)
+ return true;
+ }
+ if (!t.is_infinite(v2))
+ {
+ FT dist2 = Euclidean_distance().transformed_distance(center_cs, v2->point());
+ if (!power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= (r+delta)*(r+delta))
+ return true;
+ if (power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= r*r+delta*delta)
+ return true;
+ }
+ }
+ else
+ // INFINITE CASE
+ {
+ Delaunay_triangulation::Vertex_iterator v = t.vertices_begin();
+ while (t.is_infinite(v) || std::find(vertices.begin(), vertices.end(), v->point()) == vertices.end())
+ v++;
+ Hyperplane_d facet_plane(vertices.begin(), vertices.end(), v->point(), CGAL::ON_POSITIVE_SIDE);
+ Vector_d orth_v = facet_plane.orthogonal_vector();
+ /*
+ for (auto v_it = t.vertices_begin(); v_it != t.vertices_end(); ++v_it)
+ if (!t.is_infinite(v_it))
+ if (std::find(vertices.begin(), vertices.end(), v_it->point()) == vertices.end())
+ {
+ std::vector<FT> coords;
+ Point_d p = v_it->point();
+ auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
+ for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
+ coords.push_back((*p_i) - (*orth_i) * delta / sqrt(orth_v.squared_length()));
+ Point_d p_delta = Point_d(coords);
+ bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p);
+ bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
+ if (!p_is_inside && p_delta_is_inside)
+ return true;
+ }
+ */
+ if (!t.is_infinite(v1))
+ {
+ std::vector<FT> coords;
+ Point_d p = v1->point();
+ auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
+ for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
+ coords.push_back((*p_i) - (*orth_i) * delta / sqrt(orth_v.squared_length()));
+ Point_d p_delta = Point_d(coords);
+ bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p);
+ bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
+ if (!power_protection && !p_is_inside && p_delta_is_inside)
+ return true;
+ }
+ if (!t.is_infinite(v2))
+ {
+ std::vector<FT> coords;
+ Point_d p = v2->point();
+ auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
+ for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
+ coords.push_back((*p_i) - (*orth_i) * delta / sqrt(orth_v.squared_length()));
+ Point_d p_delta = Point_d(coords);
+ bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p);
+ bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
+ if (!power_protection && !p_is_inside && p_delta_is_inside)
+ return true;
+ }
+ }
+ return false;
+}
+
+/** Auxillary recursive function to check if the point p violates the protection of the cell c and
+ * if there is a violation of an eventual new cell
+ *
+ * p is the point to insert
+ * t is the current triangulation
+ * c is the current cell (simplex)
+ * parent_cell is the parent cell (simplex)
+ * index is the index of the facet between c and parent_cell from parent_cell's point of view
+ * D is the dimension of the triangulation
+ * delta is the protection constant
+ * marked_cells is the vector of all visited cells containing p in their circumscribed ball
+ * power_protection is true iff you are working with delta-power protection
+ *
+ * OUT: true iff inserting p hasn't produced any violation so far
+ */
+
+bool is_violating_protection(Point_d& p, Delaunay_triangulation& t, Full_cell_handle c, Full_cell_handle parent_cell, int index, int D, FT delta, std::vector<Full_cell_handle>& marked_cells, bool power_protection, FT theta0)
+{
+ Euclidean_distance ed;
+ std::vector<Point_d> vertices;
+ if (!t.is_infinite(c))
+ {
+ // if the cell is finite, we look if the protection is violated
+ for (auto v_it = c->vertices_begin(); v_it != c->vertices_end(); ++v_it)
+ vertices.push_back((*v_it)->point());
+ Sphere_d cs( vertices.begin(), vertices.end());
+ Point_d center_cs = cs.center();
+ FT r = sqrt(ed.transformed_distance(center_cs, vertices[0]));
+ FT dist2 = ed.transformed_distance(center_cs, p);
+ // if the new point is inside the protection ball of a non conflicting simplex
+ if (!power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= (r+delta)*(r+delta))
+ return true;
+ if (power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= r*r+delta*delta)
+ return true;
+ // if the new point is inside the circumscribing ball : continue violation searching on neighbours
+ //if (dist2 < r*r)
+ //if (dist2 < (5*r+delta)*(5*r+delta))
+ if (dist2 < r*r)
+ {
+ c->tds_data().mark_visited();
+ marked_cells.push_back(c);
+ for (int i = 0; i < D+1; ++i)
+ {
+ Full_cell_handle next_c = c->neighbor(i);
+ if (next_c->tds_data().is_clear() &&
+ is_violating_protection(p, t, next_c, c, i, D, delta, marked_cells, power_protection, theta0))
+ return true;
+ }
+ }
+ // if the new point is outside the protection sphere
+ else
+ {
+ // facet f is on the border of the conflict zone : check protection of simplex {p,f}
+ // the new simplex is guaranteed to be finite
+ vertices.clear(); vertices.push_back(p);
+ for (int i = 0; i < D+1; ++i)
+ if (i != index)
+ vertices.push_back(parent_cell->vertex(i)->point());
+ Delaunay_vertex vertex_to_check = t.infinite_vertex();
+ for (auto vh_it = c->vertices_begin(); vh_it != c->vertices_end(); ++vh_it)
+ if (!vertex_is_in_full_cell(*vh_it, parent_cell))
+ {
+ vertex_to_check = *vh_it; break;
+ }
+ if (new_cell_is_violated(t, vertices, vertex_to_check, parent_cell->vertex(index), delta, power_protection, theta0))
+ //if (new_cell_is_violated(t, vertices, vertex_to_check->point(), delta))
+ return true;
+ }
+ }
+ else
+ {
+ // Inside of the convex hull is + side. Outside is - side.
+ for (auto vh_it = c->vertices_begin(); vh_it != c->vertices_end(); ++vh_it)
+ if (!t.is_infinite(*vh_it))
+ vertices.push_back((*vh_it)->point());
+ Delaunay_triangulation::Vertex_iterator v_it = t.vertices_begin();
+ while (t.is_infinite(v_it) || vertex_is_in_full_cell(v_it, c))
+ v_it++;
+ Hyperplane_d facet_plane(vertices.begin(), vertices.end(), v_it->point(), CGAL::ON_POSITIVE_SIDE);
+ //CGAL::Oriented_side outside = Oriented_side_d()(facet_plane, v_it->point());
+ Vector_d orth_v = facet_plane.orthogonal_vector();
+ std::vector<FT> coords;
+ auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
+ for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
+ coords.push_back((*p_i) - (*orth_i) * delta / sqrt(orth_v.squared_length()));
+ Point_d p_delta = Point_d(coords);
+ bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p) && (Oriented_side_d()(facet_plane, p) != CGAL::ZERO);
+ bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
+
+ // If we work with power protection, we just ignore any conflicts
+ if (!power_protection && !p_is_inside && p_delta_is_inside)
+ return true;
+ //if the cell is infinite we look at the neighbours regardless
+ if (p_is_inside)
+ {
+ c->tds_data().mark_visited();
+ marked_cells.push_back(c);
+ for (int i = 0; i < D+1; ++i)
+ {
+ Full_cell_handle next_c = c->neighbor(i);
+ if (next_c->tds_data().is_clear() &&
+ is_violating_protection(p, t, next_c, c, i, D, delta, marked_cells, power_protection, theta0))
+ return true;
+ }
+ }
+ else
+ {
+ // facet f is on the border of the conflict zone : check protection of simplex {p,f}
+ // the new simplex is finite if the parent cell is finite
+ vertices.clear(); vertices.push_back(p);
+ for (int i = 0; i < D+1; ++i)
+ if (i != index)
+ if (!t.is_infinite(parent_cell->vertex(i)))
+ vertices.push_back(parent_cell->vertex(i)->point());
+ Delaunay_vertex vertex_to_check = t.infinite_vertex();
+ for (auto vh_it = c->vertices_begin(); vh_it != c->vertices_end(); ++vh_it)
+ if (!vertex_is_in_full_cell(*vh_it, parent_cell))
+ {
+ vertex_to_check = *vh_it; break;
+ }
+ if (new_cell_is_violated(t, vertices, vertex_to_check, parent_cell->vertex(index), delta, power_protection, theta0))
+ //if (new_cell_is_violated(t, vertices, vertex_to_check->point(), delta))
+ return true;
+ }
+ }
+ //c->tds_data().clear_visited();
+ //marked_cells.pop_back();
+ return false;
+}
+
+/** Checks if inserting the point p in t will make conflicts
+ *
+ * p is the point to insert
+ * t is the current triangulation
+ * D is the dimension of triangulation
+ * delta is the protection constant
+ * power_protection is true iff you are working with delta-power protection
+ * OUT: true iff inserting p produces a violation of delta-protection.
+ */
+
+bool is_violating_protection(Point_d& p, Delaunay_triangulation& t, int D, FT delta, bool power_protection, FT theta0)
+{
+ Euclidean_distance ed;
+ Delaunay_triangulation::Vertex_handle v;
+ Delaunay_triangulation::Face f(t.current_dimension());
+ Delaunay_triangulation::Facet ft;
+ Delaunay_triangulation::Full_cell_handle c;
+ Delaunay_triangulation::Locate_type lt;
+ std::vector<Full_cell_handle> marked_cells;
+ c = t.locate(p, lt, f, ft, v);
+ bool violation_existing_cells = is_violating_protection(p, t, c, c, 0, D, delta, marked_cells, power_protection, theta0);
+ for (Full_cell_handle fc : marked_cells)
+ fc->tds_data().clear();
+ return violation_existing_cells;
+}
+
+//////////////////////////////////////////////////////////////////////
+// INITIALIZATION
+//////////////////////////////////////////////////////////////////////
+
+void initialize(Search_Tree& W, Delaunay& t, int D, int width, bool torus)
+{
+ if (!torus)
+ std::cout << "Non-toric case is not supported\n";
+ else
+ {
+ if (D == 2)
+ {
+ FT stepx = 2.0/width;
+ FT stepy = sqrt(3)/width;
+ for (int i = 0; i < width; ++i)
+ for (int j = 0; j < floor(2*width/sqrt(3)); ++j)
+ {
+ insert_delaunay_landmark_with_copies(Point_d(step*i,))
+ }
+ }
+ else (D == 3)
+ {
+
+ }
+ else std::cout << "T^d with d>3 not supported";
+ }
+}
+
+///////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////
+//!!!!!!!!!!!!! THE INTERFACE FOR LANDMARK CHOICE IS BELOW !!!!!!!!!!//
+///////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////
+// LANDMARK CHOICE PROCEDURE AS IN PAPER
+///////////////////////////////////////////////////////////////////////
+
+/** Procedure to compute a maximal protected subset from a point cloud. All OUTs should be empty at call.
+ *
+ * IN: W is the initial point cloud having type Epick_d<Dynamic_dimension_tag>::Point_d
+ * IN: nbP is the size of W
+ * OUT: landmarks is the output vector for the points
+ * OUT: landmarks_ind is the output vector for the indices of the selected points in W
+ * IN: delta is the constant of protection
+ * OUT: full_cells is the output vector of the simplices in the final Delaunay triangulation
+ * IN: torus is true iff you are working on a flat torus [-1,1]^d
+ */
+
+template<class Search_Tree>
+void protected_delaunay_refinement(Search_Tree& W, int nbP, Point_Vector& landmarks, FT delta, bool torus, bool power_protection, FT theta0)
+{
+ bool return_ = true;
+ unsigned D = W[0].size();
+ Torus_distance td;
+ Euclidean_distance ed;
+ Delaunay_triangulation t(D);
+ CGAL::Random rand;
+ int landmark_count = 0;
+ //std::list<int> index_list;
+ // shuffle the list of indexes (via a vector)
+ // {
+ // std::vector<int> temp_vector;
+ // for (int i = 0; i < nbP; ++i)
+ // temp_vector.push_back(i);
+ // unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
+ // std::shuffle(temp_vector.begin(), temp_vector.end(), std::default_random_engine(seed));
+ // //CGAL::spatial_sort(temp_vector.begin(), temp_vector.end());
+ // for (std::vector<int>::iterator it = temp_vector.begin(); it != temp_vector.end(); ++it)
+ // index_list.push_front(*it);
+ // }
+ if (torus)
+ if (D == 2)
+ // \T^2
+ {
+ for (int i = 0; i < 4; ++i)
+ for (int j = 0; j < 2; ++j)
+ {
+ W[index_list.front()] = Point_d(std::vector<FT>{i*0.5, j*1.0});
+ insert_delaunay_landmark_with_copies(W, index_list.front(), landmarks_ind, t, landmark_count, torus);
+ index_list.pop_front();
+ W[index_list.front()] = Point_d(std::vector<FT>{0.25+i*0.5, 0.5+j});
+ insert_delaunay_landmark_with_copies(W, index_list.front(), landmarks_ind, t, landmark_count, torus);
+ index_list.pop_front();
+ }
+ }
+ else if (D == 3)
+ {
+
+ }
+ //std::cout << "No torus starter available for dim>2\n";
+ std::list<int>::iterator list_it = index_list.begin();
+ while (list_it != index_list.end())
+ {
+ if (!is_violating_protection(W[*list_it], t, D, delta, power_protection, theta0))
+ {
+ // If no conflicts then insert in every copy of T^3
+
+ insert_delaunay_landmark_with_copies(W, *list_it, landmarks_ind, t, landmark_count, torus);
+ if (return_)
+ {
+ index_list.erase(list_it);
+ list_it = index_list.begin();
+ }
+ else
+ index_list.erase(list_it++);
+ /*
+ // PIECE OF CODE FOR DEBUGGING PURPOSES
+
+ Delaunay_vertex inserted_v = insert_delaunay_landmark_with_copies(W, *list_it, landmarks_ind, t, landmark_count);
+ if (triangulation_is_protected(t, delta))
+ {
+ index_list.erase(list_it);
+ list_it = index_list.begin();
+ }
+ else
+ { //THAT'S WHERE SOMETHING'S WRONG
+ t.remove(inserted_v);
+ landmarks_ind.pop_back();
+ landmark_count--;
+ write_delaunay_mesh(t, W[*list_it], is2d);
+ is_violating_protection(W[*list_it], t_old, D, delta); //Called for encore
+ }
+ */
+ //std::cout << "index_list_size() = " << index_list.size() << "\n";
+ }
+ else
+ {
+ list_it++;
+ //std::cout << "!!!!!WARNING!!!!! A POINT HAS BEEN OMITTED!!!\n";
+ }
+ //if (list_it != index_list.end())
+ // write_delaunay_mesh(t, W[*list_it], is2d);
+ }
+ fill_landmarks(W, landmarks, landmarks_ind, torus);
+ fill_full_cell_vector(t, full_cells);
+ /*
+ if (triangulation_is_protected(t, delta))
+ std::cout << "Triangulation is ok\n";
+ else
+ {
+ std::cout << "Triangulation is BAD!! T_T しくしく!\n";
+ }
+ */
+ //write_delaunay_mesh(t, W[0], is2d);
+ //std::cout << t << std::endl;
+}
+
+#endif
diff --git a/src/Witness_complex/example/protected_sets/protected_sets_paper.h b/src/Witness_complex/example/protected_sets/protected_sets_paper.h
new file mode 100644
index 00000000..61fcc75b
--- /dev/null
+++ b/src/Witness_complex/example/protected_sets/protected_sets_paper.h
@@ -0,0 +1,917 @@
+#ifndef PROTECTED_SETS_H
+#define PROTECTED_SETS_H
+
+#include <algorithm>
+#include <CGAL/Cartesian_d.h>
+#include <CGAL/Epick_d.h>
+#include <CGAL/Euclidean_distance.h>
+#include <CGAL/Kernel_d/Sphere_d.h>
+#include <CGAL/Kernel_d/Hyperplane_d.h>
+#include <CGAL/Kernel_d/Vector_d.h>
+
+#include <CGAL/Orthogonal_k_neighbor_search.h>
+#include <CGAL/Kd_tree.h>
+#include <CGAL/Fuzzy_sphere.h>
+
+#include <boost/heap/fibonacci_heap.hpp>
+#include <boost/heap/policies.hpp>
+
+#include "output_tikz.h"
+
+typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> K;
+typedef K::Point_d Point_d;
+typedef K::Line_d Line_d;
+typedef K::Vector_d Vector_d;
+typedef K::Oriented_side_d Oriented_side_d;
+typedef K::Has_on_positive_side_d Has_on_positive_side_d;
+typedef K::Sphere_d Sphere_d;
+typedef K::Hyperplane_d Hyperplane_d;
+
+typedef CGAL::Delaunay_triangulation<K> Delaunay_triangulation;
+typedef Delaunay_triangulation::Facet Facet;
+typedef Delaunay_triangulation::Vertex_handle Delaunay_vertex;
+typedef Delaunay_triangulation::Full_cell_handle Full_cell_handle;
+
+typedef std::vector<Point_d> Point_Vector;
+typedef CGAL::Euclidean_distance<Traits_base> Euclidean_distance;
+
+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_k_neighbor_search<STraits, CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance>> K_neighbor_search;
+typedef K_neighbor_search::Tree Tree;
+typedef K_neighbor_search::Distance Distance;
+typedef K_neighbor_search::iterator KNS_iterator;
+typedef K_neighbor_search::iterator KNS_range;
+typedef CGAL::Fuzzy_sphere<STraits> Fuzzy_sphere;
+
+
+FT _sfty = pow(10,-14);
+
+bool experiment1, experiment2 = false;
+
+/* Experiment 1: epsilon as function on time **********************/
+std::vector<FT> eps_vector;
+
+/* Experiment 2: R/epsilon on delta *******************************/
+std::vector<FT> epsratio_vector;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+// AUXILLARY FUNCTIONS
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/** Insert a point in Delaunay triangulation. If you are working in a flat torus, the procedure adds all the 3^d copies in adjacent cubes as well
+ *
+ * W is the initial point vector
+ * chosen_landmark is the index of the chosen point in W
+ * landmarks_ind is the vector of indices of already chosen points in W
+ * delaunay is the Delaunay triangulation
+ * landmark_count is the current number of chosen vertices
+ * torus is true iff you are working on a flat torus [-1,1]^d
+ * OUT: Vertex handle to the newly inserted point
+ */
+Delaunay_vertex insert_delaunay_landmark_with_copies(Point_Vector& W, int chosen_landmark, std::vector<int>& landmarks_ind, Delaunay_triangulation& delaunay, int& landmark_count, bool torus)
+{
+ if (!torus)
+ {
+ Delaunay_vertex v =delaunay.insert(W[chosen_landmark]);
+ landmarks_ind.push_back(chosen_landmark);
+ landmark_count++;
+ return v;
+ }
+ else
+ {
+ int D = W[0].size();
+ int nb_cells = pow(3, D);
+ Delaunay_vertex v;
+ for (int i = 0; i < nb_cells; ++i)
+ {
+ std::vector<FT> point;
+ int cell_i = i;
+ for (int l = 0; l < D; ++l)
+ {
+ point.push_back(W[chosen_landmark][l] + 2.0*(cell_i%3-1));
+ cell_i /= 3;
+ }
+ if (i == nb_cells/2)
+ v = delaunay.insert(point); //v = center point
+ else
+ delaunay.insert(point);
+ }
+ landmarks_ind.push_back(chosen_landmark);
+ landmark_count++;
+ return v;
+ }
+}
+
+/** Small check if the vertex v is in the full cell fc
+ */
+
+bool vertex_is_in_full_cell(Delaunay_triangulation::Vertex_handle v, Full_cell_handle fc)
+{
+ for (auto v_it = fc->vertices_begin(); v_it != fc->vertices_end(); ++v_it)
+ if (*v_it == v)
+ return true;
+ return false;
+}
+
+/** Fill chosen point vector from indices with copies if you are working on a flat torus
+ *
+ * IN: W is the point vector
+ * OUT: landmarks is the output vector
+ * IN: landmarks_ind is the vector of indices
+ * IN: torus is true iff you are working on a flat torus [-1,1]^d
+ */
+
+void fill_landmarks(Point_Vector& W, Point_Vector& landmarks, std::vector<int>& landmarks_ind, bool torus)
+{
+ if (!torus)
+ for (unsigned j = 0; j < landmarks_ind.size(); ++j)
+ landmarks.push_back(W[landmarks_ind[j]]);
+ else
+ {
+ int D = W[0].size();
+ int nb_cells = pow(3, D);
+ int nbL = landmarks_ind.size();
+ // Fill landmarks
+ for (int i = 0; i < nb_cells-1; ++i)
+ for (int j = 0; j < nbL; ++j)
+ {
+ int cell_i = i;
+ Point_d point;
+ for (int l = 0; l < D; ++l)
+ {
+ point.push_back(W[landmarks_ind[j]][l] + 2.0*(cell_i-1));
+ cell_i /= 3;
+ }
+ landmarks.push_back(point);
+ }
+ }
+}
+
+/** Fill a vector of all simplices in the Delaunay triangulation giving integer indices to vertices
+ *
+ * IN: t is the Delaunay triangulation
+ * OUT: full_cells is the output vector
+ */
+
+void fill_full_cell_vector(Delaunay_triangulation& t, std::vector<std::vector<int>>& full_cells)
+{
+ // Store vertex indices in a map
+ int ind = 0; //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;
+ else
+ index_of_vertex[v_it] = ind++;
+ // Write full cells as vectors in full_cells
+ for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
+ {
+ if (t.is_infinite(fc_it))
+ continue;
+ Point_Vector vertices;
+ for (auto fc_v_it = fc_it->vertices_begin(); fc_v_it != fc_it->vertices_end(); ++fc_v_it)
+ vertices.push_back((*fc_v_it)->point());
+ Sphere_d cs( vertices.begin(), vertices.end());
+ Point_d csc = cs.center();
+ bool in_cube = true;
+ for (auto xi = csc.cartesian_begin(); xi != csc.cartesian_end(); ++xi)
+ if (*xi > 1.0 || *xi < -1.0)
+ {
+ in_cube = false; break;
+ }
+ if (!in_cube)
+ continue;
+ std::vector<int> cell;
+ for (auto v_it = fc_it->vertices_begin(); v_it != fc_it->vertices_end(); ++v_it)
+ cell.push_back(index_of_vertex[*v_it]);
+ full_cells.push_back(cell);
+ }
+}
+
+bool sphere_intersects_cube(Point_d& c, FT r)
+{
+ bool in_cube = true;
+ // int i = 0, D = p.size();
+ for (auto xi = c.cartesian_begin(); xi != c.cartesian_end(); ++xi)
+ // if ((*xi < 1.0 || *xi > -1.0) &&
+ // (*xi-r < 1.0 || *xi-r > -1.0) &&
+ // (*xi+r < 1.0 || *xi+r > -1.0))
+
+ if ((*xi-r < -1.0 && *xi+r < -1.0) ||
+ (*xi-r > 1.0 && *xi+r > 1.0 ))
+ {
+ in_cube = false; break;
+ }
+ return in_cube;
+}
+
+/** Recursive function for checking if the simplex is good,
+ * meaning it does not contain a k-face, which is not theta0^(k-1) thick
+ */
+
+bool is_theta0_good(std::vector<Point_d>& vertices, FT theta0)
+{
+ if (theta0 > 1)
+ {
+ std::cout << "Warning! theta0 is set > 1\n";
+ return false;
+ }
+ int D = vertices.size()-1;
+ if (D <= 1)
+ return true; // Edges are always good
+ //******** Circumscribed sphere
+ Euclidean_distance ed;
+ Sphere_d cs(vertices.begin(), vertices.end());
+ FT r = sqrt(cs.squared_radius());
+ for (std::vector<Point_d>::iterator v_it = vertices.begin(); v_it != vertices.end(); ++v_it)
+ {
+ std::vector<Point_d> facet;
+ for (std::vector<Point_d>::iterator f_it = vertices.begin(); f_it != vertices.end(); ++f_it)
+ if (f_it != v_it)
+ facet.push_back(*f_it);
+ // Compute the altitude
+
+ if (vertices[0].size() == 3 && D == 2)
+ {
+ //Vector_d l = facet[0] - facet[1];
+ FT orth_length2 = ed.transformed_distance(facet[0],facet[1]);
+ K::Cartesian_const_iterator_d l_it, p_it, s_it, c_it;
+ FT h = 0;
+ // Scalar product = <sp,l>
+ FT scalar = 0;
+ for (p_it = v_it->cartesian_begin(),
+ s_it = facet[0].cartesian_begin(),
+ l_it = facet[1].cartesian_begin();
+ p_it != v_it->cartesian_end();
+ ++l_it, ++p_it, ++s_it)
+ scalar += (*l_it - *s_it)*(*p_it - *s_it);
+ // Gram-Schmidt for one vector
+ for (p_it = v_it->cartesian_begin(),
+ s_it = facet[0].cartesian_begin(),
+ l_it = facet[1].cartesian_begin();
+ p_it != v_it->cartesian_end();
+ ++l_it, ++p_it, ++s_it)
+ {
+ FT hx = (*p_it - *s_it) - scalar*(*l_it - *s_it)/orth_length2;
+ h += hx*hx;
+ }
+ h = sqrt(h);
+
+ if (h/(2*r) < pow(theta0, D-1))
+ return false;
+ if (!is_theta0_good(facet, theta0))
+ return false;
+ }
+ else
+ {
+ Hyperplane_d tau_h(facet.begin(), facet.end(), *v_it);
+ Vector_d orth_tau = tau_h.orthogonal_vector();
+ FT orth_length = sqrt(orth_tau.squared_length());
+ K::Cartesian_const_iterator_d o_it, p_it, s_it, c_it;
+ FT h = 0;
+ for (o_it = orth_tau.cartesian_begin(),
+ p_it = v_it->cartesian_begin(),
+ s_it = (facet.begin())->cartesian_begin();
+ o_it != orth_tau.cartesian_end();
+ ++o_it, ++p_it, ++s_it)
+ h += (*o_it)*(*p_it - *s_it)/orth_length;
+ h = fabs(h);
+ if (h/(2*r) < pow(theta0, D-1))
+ return false;
+ if (!is_theta0_good(facet, theta0))
+ return false;
+ }
+ }
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// IS VIOLATED TEST
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/** Check if a newly created cell is protected from old vertices
+ *
+ * t is the Delaunay triangulation
+ * vertices is the vector containing the point to insert and a facet f in t
+ * v1 is the vertex of t, such that f and v1 form a simplex
+ * v2 is the vertex of t, such that f and v2 form another simplex
+ * delta is the protection constant
+ * power_protection is true iff the delta-power protection is used
+ */
+
+bool new_cell_is_violated(Delaunay_triangulation& t, std::vector<Point_d>& vertices, const Delaunay_vertex& v1, const Delaunay_vertex v2, FT delta, bool power_protection, FT theta0)
+{
+ assert(vertices.size() == vertices[0].size() ||
+ vertices.size() == vertices[0].size() + 1); //simplex size = d | d+1
+ assert(v1 != v2);
+ if (vertices.size() == vertices[0].size() + 1)
+ // FINITE CASE
+ {
+ Sphere_d cs(vertices.begin(), vertices.end());
+ Point_d center_cs = cs.center();
+ FT r = sqrt(Euclidean_distance().transformed_distance(center_cs, vertices[0]));
+ /*
+ for (auto v_it = t.vertices_begin(); v_it != t.vertices_end(); ++v_it)
+ if (!t.is_infinite(v_it))
+ {
+ //CGAL::Oriented_side side = Oriented_side_d()(cs, (v_it)->point());
+ if (std::find(vertices.begin(), vertices.end(), v_it->point()) == vertices.end())
+ {
+ FT dist2 = Euclidean_distance().transformed_distance(center_cs, (v_it)->point());
+ if (!power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= (r+delta)*(r+delta))
+ return true;
+ if (power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= r*r+delta*delta)
+ return true;
+ }
+ }
+ */
+ // Check if the simplex is theta0-good
+ if (!is_theta0_good(vertices, theta0))
+ return true;
+ // Is the center inside the box? (only Euclidean case)
+ // if (!torus)
+ // {
+ // bool inside_the_box = true;
+ // for (c_it = center_cs.cartesian_begin(); c_it != center_cs.cartesian_end(); ++c_it)
+ // if (*c_it > 1.0 || *c_it < -1.0)
+ // {
+ // inside_the_box = false; break;
+ // }
+ // if (inside_the_box && h/r < theta0)
+ // return true;
+ // }
+ // Check the two vertices (if not infinite)
+ if (!t.is_infinite(v1))
+ {
+ FT dist2 = Euclidean_distance().transformed_distance(center_cs, v1->point());
+ if (!power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= (r+delta)*(r+delta))
+ return true;
+ if (power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= r*r+delta*delta)
+ return true;
+ }
+ if (!t.is_infinite(v2))
+ {
+ FT dist2 = Euclidean_distance().transformed_distance(center_cs, v2->point());
+ if (!power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= (r+delta)*(r+delta))
+ return true;
+ if (power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= r*r+delta*delta)
+ return true;
+ }
+ }
+ else
+ // INFINITE CASE
+ {
+ Delaunay_triangulation::Vertex_iterator v = t.vertices_begin();
+ while (t.is_infinite(v) || std::find(vertices.begin(), vertices.end(), v->point()) == vertices.end())
+ v++;
+ Hyperplane_d facet_plane(vertices.begin(), vertices.end(), v->point(), CGAL::ON_POSITIVE_SIDE);
+ Vector_d orth_v = facet_plane.orthogonal_vector();
+ /*
+ for (auto v_it = t.vertices_begin(); v_it != t.vertices_end(); ++v_it)
+ if (!t.is_infinite(v_it))
+ if (std::find(vertices.begin(), vertices.end(), v_it->point()) == vertices.end())
+ {
+ std::vector<FT> coords;
+ Point_d p = v_it->point();
+ auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
+ for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
+ coords.push_back((*p_i) - (*orth_i) * delta / sqrt(orth_v.squared_length()));
+ Point_d p_delta = Point_d(coords);
+ bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p);
+ bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
+ if (!p_is_inside && p_delta_is_inside)
+ return true;
+ }
+ */
+ if (!t.is_infinite(v1))
+ {
+ std::vector<FT> coords;
+ Point_d p = v1->point();
+ auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
+ for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
+ coords.push_back((*p_i) - (*orth_i) * delta / sqrt(orth_v.squared_length()));
+ Point_d p_delta = Point_d(coords);
+ bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p);
+ bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
+ if (!power_protection && !p_is_inside && p_delta_is_inside)
+ return true;
+ }
+ if (!t.is_infinite(v2))
+ {
+ std::vector<FT> coords;
+ Point_d p = v2->point();
+ auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
+ for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
+ coords.push_back((*p_i) - (*orth_i) * delta / sqrt(orth_v.squared_length()));
+ Point_d p_delta = Point_d(coords);
+ bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p);
+ bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
+ if (!power_protection && !p_is_inside && p_delta_is_inside)
+ return true;
+ }
+ }
+ return false;
+}
+
+/** Auxillary recursive function to check if the point p violates the protection of the cell c and
+ * if there is a violation of an eventual new cell
+ *
+ * p is the point to insert
+ * t is the current triangulation
+ * c is the current cell (simplex)
+ * parent_cell is the parent cell (simplex)
+ * index is the index of the facet between c and parent_cell from parent_cell's point of view
+ * D is the dimension of the triangulation
+ * delta is the protection constant
+ * marked_cells is the vector of all visited cells containing p in their circumscribed ball
+ * power_protection is true iff you are working with delta-power protection
+ *
+ * OUT: true iff inserting p hasn't produced any violation so far
+ */
+
+bool is_violating_protection(Point_d& p, Delaunay_triangulation& t, Full_cell_handle c, Full_cell_handle parent_cell, int index, int D, FT delta, std::vector<Full_cell_handle>& marked_cells, bool power_protection, FT theta0)
+{
+ Euclidean_distance ed;
+ std::vector<Point_d> vertices;
+ if (!t.is_infinite(c))
+ {
+ // if the cell is finite, we look if the protection is violated
+ for (auto v_it = c->vertices_begin(); v_it != c->vertices_end(); ++v_it)
+ vertices.push_back((*v_it)->point());
+ Sphere_d cs( vertices.begin(), vertices.end());
+ Point_d center_cs = cs.center();
+ FT r = sqrt(ed.transformed_distance(center_cs, vertices[0]));
+ FT dist2 = ed.transformed_distance(center_cs, p);
+ // if the new point is inside the protection ball of a non conflicting simplex
+ if (!power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= (r+delta)*(r+delta))
+ return true;
+ if (power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= r*r+delta*delta)
+ return true;
+ // if the new point is inside the circumscribing ball : continue violation searching on neighbours
+ //if (dist2 < r*r)
+ //if (dist2 < (5*r+delta)*(5*r+delta))
+ if (dist2 < r*r)
+ {
+ c->tds_data().mark_visited();
+ marked_cells.push_back(c);
+ for (int i = 0; i < D+1; ++i)
+ {
+ Full_cell_handle next_c = c->neighbor(i);
+ if (next_c->tds_data().is_clear() &&
+ is_violating_protection(p, t, next_c, c, i, D, delta, marked_cells, power_protection, theta0))
+ return true;
+ }
+ }
+ // if the new point is outside the protection sphere
+ else
+ {
+ // facet f is on the border of the conflict zone : check protection of simplex {p,f}
+ // the new simplex is guaranteed to be finite
+ vertices.clear(); vertices.push_back(p);
+ for (int i = 0; i < D+1; ++i)
+ if (i != index)
+ vertices.push_back(parent_cell->vertex(i)->point());
+ Delaunay_vertex vertex_to_check = t.infinite_vertex();
+ for (auto vh_it = c->vertices_begin(); vh_it != c->vertices_end(); ++vh_it)
+ if (!vertex_is_in_full_cell(*vh_it, parent_cell))
+ {
+ vertex_to_check = *vh_it; break;
+ }
+ if (new_cell_is_violated(t, vertices, vertex_to_check, parent_cell->vertex(index), delta, power_protection, theta0))
+ //if (new_cell_is_violated(t, vertices, vertex_to_check->point(), delta))
+ return true;
+ }
+ }
+ else
+ {
+ // Inside of the convex hull is + side. Outside is - side.
+ for (auto vh_it = c->vertices_begin(); vh_it != c->vertices_end(); ++vh_it)
+ if (!t.is_infinite(*vh_it))
+ vertices.push_back((*vh_it)->point());
+ Delaunay_triangulation::Vertex_iterator v_it = t.vertices_begin();
+ while (t.is_infinite(v_it) || vertex_is_in_full_cell(v_it, c))
+ v_it++;
+ Hyperplane_d facet_plane(vertices.begin(), vertices.end(), v_it->point(), CGAL::ON_POSITIVE_SIDE);
+ //CGAL::Oriented_side outside = Oriented_side_d()(facet_plane, v_it->point());
+ Vector_d orth_v = facet_plane.orthogonal_vector();
+ std::vector<FT> coords;
+ auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
+ for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
+ coords.push_back((*p_i) - (*orth_i) * delta / sqrt(orth_v.squared_length()));
+ Point_d p_delta = Point_d(coords);
+ bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p) && (Oriented_side_d()(facet_plane, p) != CGAL::ZERO);
+ bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
+
+ // If we work with power protection, we just ignore any conflicts
+ if (!power_protection && !p_is_inside && p_delta_is_inside)
+ return true;
+ //if the cell is infinite we look at the neighbours regardless
+ if (p_is_inside)
+ {
+ c->tds_data().mark_visited();
+ marked_cells.push_back(c);
+ for (int i = 0; i < D+1; ++i)
+ {
+ Full_cell_handle next_c = c->neighbor(i);
+ if (next_c->tds_data().is_clear() &&
+ is_violating_protection(p, t, next_c, c, i, D, delta, marked_cells, power_protection, theta0))
+ return true;
+ }
+ }
+ else
+ {
+ // facet f is on the border of the conflict zone : check protection of simplex {p,f}
+ // the new simplex is finite if the parent cell is finite
+ vertices.clear(); vertices.push_back(p);
+ for (int i = 0; i < D+1; ++i)
+ if (i != index)
+ if (!t.is_infinite(parent_cell->vertex(i)))
+ vertices.push_back(parent_cell->vertex(i)->point());
+ Delaunay_vertex vertex_to_check = t.infinite_vertex();
+ for (auto vh_it = c->vertices_begin(); vh_it != c->vertices_end(); ++vh_it)
+ if (!vertex_is_in_full_cell(*vh_it, parent_cell))
+ {
+ vertex_to_check = *vh_it; break;
+ }
+ if (new_cell_is_violated(t, vertices, vertex_to_check, parent_cell->vertex(index), delta, power_protection, theta0))
+ //if (new_cell_is_violated(t, vertices, vertex_to_check->point(), delta))
+ return true;
+ }
+ }
+ //c->tds_data().clear_visited();
+ //marked_cells.pop_back();
+ return false;
+}
+
+/** Checks if inserting the point p in t will make conflicts
+ *
+ * p is the point to insert
+ * t is the current triangulation
+ * D is the dimension of triangulation
+ * delta is the protection constant
+ * power_protection is true iff you are working with delta-power protection
+ * OUT: true iff inserting p produces a violation of delta-protection.
+ */
+
+bool is_violating_protection(Point_d& p, Delaunay_triangulation& t, int D, FT delta, bool power_protection, FT theta0)
+{
+ Euclidean_distance ed;
+ Delaunay_triangulation::Vertex_handle v;
+ Delaunay_triangulation::Face f(t.current_dimension());
+ Delaunay_triangulation::Facet ft;
+ Delaunay_triangulation::Full_cell_handle c;
+ Delaunay_triangulation::Locate_type lt;
+ std::vector<Full_cell_handle> marked_cells;
+ //c = t.locate(p, lt, f, ft, v);
+ c = t.locate(p);
+ bool violation_existing_cells = is_violating_protection(p, t, c, c, 0, D, delta, marked_cells, power_protection, theta0);
+ for (Full_cell_handle fc : marked_cells)
+ fc->tds_data().clear();
+ return violation_existing_cells;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+// INITIALIZATION
+////////////////////////////////////////////////////////////////////////
+
+// Query for a sphere near a cite in all copies of a torus
+// OUT points_inside
+void torus_search(Tree& treeW, int D, Point_d cite, FT r, std::vector<int>& points_inside)
+{
+ int nb_cells = pow(3, D);
+ Delaunay_vertex v;
+ for (int i = 0; i < nb_cells; ++i)
+ {
+ std::vector<FT> cite_copy;
+ int cell_i = i;
+ for (int l = 0; l < D; ++l)
+ {
+ cite_copy.push_back(cite[l] + 2.0*(cell_i%3-1));
+ cell_i /= 3;
+ }
+ Fuzzy_sphere fs(cite_copy, r, 0, treeW.traits());
+ treeW.search(std::insert_iterator<std::vector<int>>(points_inside, points_inside.end()), fs);
+ }
+}
+
+
+void initialize_torus(Point_Vector& W, Tree& treeW, Delaunay_triangulation& t, FT epsilon, std::vector<int>& landmarks_ind, int& landmark_count)
+{
+ int D = W[0].size();
+ if (D == 2)
+ {
+ int xw = 6, yw = 4;
+ // Triangular lattice close to regular triangles h=0.866a ~ 0.875a : 48p
+ for (int i = 0; i < xw; ++i)
+ for (int j = 0; j < yw; ++j)
+ {
+ Point_d cite1(std::vector<FT>{2.0/xw*i, 1.0/yw*j});
+ std::vector<int> points_inside;
+ torus_search(treeW, D, cite1, epsilon, points_inside);
+ assert(points_inside.size() > 0);
+ insert_delaunay_landmark_with_copies(W, *(points_inside.begin()),
+ landmarks_ind, t, landmark_count, true);
+ Point_d cite2(std::vector<FT>{2.0/xw*(i+0.5), 1.0/yw*(j+0.5)});
+ points_inside.clear();
+ torus_search(treeW, D, cite2, epsilon, points_inside);
+ assert(points_inside.size() > 0);
+ insert_delaunay_landmark_with_copies(W, *(points_inside.begin()),
+ landmarks_ind, t, landmark_count, true);
+ }
+ }
+ else if (D == 3)
+ {
+ int wd = 3;
+ // Body-centered cubic lattice : 54p
+ for (int i = 0; i < wd; ++i)
+ for (int j = 0; j < wd; ++j)
+ for (int k = 0; k < wd; ++k)
+ {
+ Point_d cite1(std::vector<FT>{2.0/wd*i, 2.0/wd*j, 2.0/wd*k});
+ std::vector<int> points_inside;
+ torus_search(treeW, D, cite1, epsilon, points_inside);
+ assert(points_inside.size() > 0);
+ insert_delaunay_landmark_with_copies(W, *(points_inside.begin()),
+ landmarks_ind, t, landmark_count, true);
+ Point_d cite2(std::vector<FT>{2.0/wd*(i+0.5), 2.0/wd*(j+0.5), 2.0/wd*(k+0.5)});
+ points_inside.clear();
+ torus_search(treeW, D, cite2, epsilon, points_inside);
+ assert(points_inside.size() > 0);
+ insert_delaunay_landmark_with_copies(W, *(points_inside.begin()),
+ landmarks_ind, t, landmark_count, true);
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////
+//!!!!!!!!!!!!! THE INTERFACE FOR LANDMARK CHOICE IS BELOW !!!!!!!!!!//
+///////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////
+
+// Struct for R_max_heap elements
+
+struct R_max_handle
+{
+ FT value;
+ Point_d center;
+
+ R_max_handle(FT value_, Point_d c): value(value_), center(c)
+ {}
+};
+
+struct R_max_compare
+{
+ bool operator()(const R_max_handle& rmh1, const R_max_handle& rmh2) const
+ {
+ return rmh1.value < rmh2.value;
+ }
+};
+
+// typedef boost::heap::fibonacci_heap<R_max_handle, boost::heap::compare<R_max_compare>> Heap;
+
+// void make_heap(Delaunay_triangulation& t, Heap& R_max_heap)
+// {
+// R_max_heap.clear();
+// for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
+// {
+// if (t.is_infinite(fc_it))
+// continue;
+// Point_Vector vertices;
+// for (auto fc_v_it = fc_it->vertices_begin(); fc_v_it != fc_it->vertices_end(); ++fc_v_it)
+// vertices.push_back((*fc_v_it)->point());
+// Sphere_d cs( vertices.begin(), vertices.end());
+// Point_d csc = cs.center();
+// FT r = sqrt(cs.squared_radius());
+// // A ball is in the heap, if it intersects the cube
+// bool accepted = sphere_intersects_cube(csc, sqrt(r));
+// if (!accepted)
+// continue;
+// R_max_heap.push(R_max_handle(r, fc_it, csc));
+// }
+// }
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+// SAMPLING RADIUS
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+R_max_handle sampling_radius(Delaunay_triangulation& t)
+{
+ FT epsilon2 = 0;
+ Point_d final_center;
+ Point_d control_point;
+ for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
+ {
+ if (t.is_infinite(fc_it))
+ continue;
+ Point_Vector vertices;
+ for (auto fc_v_it = fc_it->vertices_begin(); fc_v_it != fc_it->vertices_end(); ++fc_v_it)
+ vertices.push_back((*fc_v_it)->point());
+ Sphere_d cs( vertices.begin(), vertices.end());
+ Point_d csc = cs.center();
+ bool in_cube = true;
+ for (auto xi = csc.cartesian_begin(); xi != csc.cartesian_end(); ++xi)
+ if (*xi > 1.0 || *xi < -1.0)
+ {
+ in_cube = false; break;
+ }
+ if (!in_cube)
+ continue;
+ FT r2 = Euclidean_distance().transformed_distance(cs.center(), *(vertices.begin()));
+ if (epsilon2 < r2)
+ {
+ epsilon2 = r2;
+ final_center = csc;
+ control_point = (*vertices.begin());
+ }
+ }
+ return R_max_handle(sqrt(epsilon2), final_center);
+}
+
+///////////////////////////////////////////////////////////////////////
+// LANDMARK CHOICE PROCEDURE
+///////////////////////////////////////////////////////////////////////
+
+/** Procedure to compute a maximal protected subset from a point cloud. All OUTs should be empty at call.
+ *
+ * IN: W is the initial point cloud having type Epick_d<Dynamic_dimension_tag>::Point_d
+ * IN: nbP is the size of W
+ * OUT: landmarks is the output vector for the points
+ * OUT: landmarks_ind is the output vector for the indices of the selected points in W
+ * IN: delta is the constant of protection
+ * OUT: full_cells is the output vector of the simplices in the final Delaunay triangulation
+ * IN: torus is true iff you are working on a flat torus [-1,1]^d
+ */
+
+void protected_delaunay(Point_Vector& W,
+ //Point_Vector& landmarks,
+ std::vector<int>& landmarks_ind,
+ FT delta,
+ FT epsilon,
+ FT alpha,
+ FT theta0,
+ //std::vector<std::vector<int>>& full_cells,
+ bool torus,
+ bool power_protection
+ )
+{
+ //bool return_ = true;
+ unsigned D = W[0].size();
+ int nbP = W.size();
+ Torus_distance td;
+ Euclidean_distance ed;
+ Delaunay_triangulation t(D);
+ CGAL::Random rand;
+ int landmark_count = 0;
+ std::list<int> index_list;
+ //****************** Kd Tree W
+ STraits traits(&(W[0]));
+ Tree treeW(boost::counting_iterator<std::ptrdiff_t>(0),
+ boost::counting_iterator<std::ptrdiff_t>(nbP),
+ typename Tree::Splitter(),
+ traits);
+ // shuffle the list of indexes (via a vector)
+ {
+ std::vector<int> temp_vector;
+ for (int i = 0; i < nbP; ++i)
+ temp_vector.push_back(i);
+ unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
+ std::shuffle(temp_vector.begin(), temp_vector.end(), std::default_random_engine(seed));
+ //CGAL::spatial_sort(temp_vector.begin(), temp_vector.end());
+ for (std::vector<int>::iterator it = temp_vector.begin(); it != temp_vector.end(); ++it)
+ index_list.push_front(*it);
+ }
+ //******************** Initialize point set
+ if (!torus)
+ for (unsigned pos1 = 0; pos1 < D+1; ++pos1)
+ {
+ std::vector<FT> point;
+ for (unsigned i = 0; i < pos1; ++i)
+ point.push_back(-1);
+ if (pos1 != D)
+ point.push_back(1);
+ for (unsigned i = pos1+1; i < D; ++i)
+ point.push_back(0);
+ assert(point.size() == D);
+ W[index_list.front()] = Point_d(point);
+ insert_delaunay_landmark_with_copies(W, index_list.front(), landmarks_ind, t, landmark_count, torus);
+ index_list.pop_front();
+ }
+ else
+ initialize_torus(W, treeW, t, epsilon, landmarks_ind, landmark_count);
+ //std::cout << "Size of treeW: " << treeW.size() << "\n";
+ //std::cout << "Size of t: " << t.number_of_vertices() << "\n";
+ //******************* Initialize heap for R_max
+ //Heap R_max_heap;
+ //make_heap(t, R_max_heap);
+
+
+ R_max_handle rh = sampling_radius(t);
+ FT epsilon0 = rh.value;
+ if (experiment1) eps_vector.push_back(pow(1/rh.value,D));
+ //******************** Iterative algorithm
+ std::vector<int> candidate_points;
+ torus_search(treeW, D,
+ rh.center,
+ alpha*rh.value,
+ candidate_points);
+ std::list<int>::iterator list_it;
+ std::vector<int>::iterator cp_it = candidate_points.begin();
+ while (cp_it != candidate_points.end())
+ {
+ if (!is_violating_protection(W[*cp_it], t, D, delta, power_protection, theta0))
+ {
+ insert_delaunay_landmark_with_copies(W, *cp_it, landmarks_ind, t, landmark_count, torus);
+ //make_heap(t, R_max_heap);
+ rh = sampling_radius(t);
+ if (experiment1) eps_vector.push_back(pow(1/rh.value,D));
+ //std::cout << "rhvalue = " << rh.value << "\n";
+ //std::cout << "D = " <<
+ candidate_points.clear();
+ torus_search(treeW, D,
+ rh.center,
+ alpha*rh.value,
+ candidate_points);
+ /*
+ // PIECE OF CODE FOR DEBUGGING PURPOSES
+
+ Delaunay_vertex inserted_v = insert_delaunay_landmark_with_copies(W, *list_it, landmarks_ind, t, landmark_count);
+ if (triangulation_is_protected(t, delta))
+ {
+ index_list.erase(list_it);
+ list_it = index_list.begin();
+ }
+ else
+ { //THAT'S WHERE SOMETHING'S WRONG
+ t.remove(inserted_v);
+ landmarks_ind.pop_back();
+ landmark_count--;
+ write_delaunay_mesh(t, W[*list_it], is2d);
+ is_violating_protection(W[*list_it], t_old, D, delta); //Called for encore
+ }
+ */
+ //std::cout << "index_list_size() = " << index_list.size() << "\n";
+ }
+ else
+ {
+ cp_it++;
+ //std::cout << "!!!!!WARNING!!!!! A POINT HAS BEEN OMITTED!!!\n";
+ }
+ //if (list_it != index_list.end())
+ // write_delaunay_mesh(t, W[*list_it], is2d);
+ }
+ if (experiment2) epsratio_vector.push_back(rh.value/epsilon0);
+ std::cout << "The iteration ended when cp_count = " << candidate_points.size() << "\n";
+ std::cout << "alphaRmax = " << alpha*rh.value << "\n";
+ std::cout << "epsilon' = " << rh.value << "\n";
+ std::cout << "nbL = " << landmarks_ind.size() << "\n";
+ //fill_landmarks(W, landmarks, landmarks_ind, torus);
+ //fill_full_cell_vector(t, full_cells);
+ /*
+ if (triangulation_is_protected(t, delta))
+ std::cout << "Triangulation is ok\n";
+ else
+ {
+ std::cout << "Triangulation is BAD!! T_T しくしく!\n";
+ }
+ */
+ //write_delaunay_mesh(t, W[0], is2d);
+ //std::cout << t << std::endl;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Series of experiments
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void start_experiments(Point_Vector& W, FT theta0, std::vector<int>& landmarks_ind, FT epsilon)
+{
+ // Experiment 1
+ experiment1 = true;
+ protected_delaunay(W, landmarks_ind, 0.1*epsilon, epsilon, 0.5, 0, true, true);
+ write_tikz_plot(eps_vector,"epstime.tikz");
+ experiment1 = false;
+
+ // Experiment 2
+ // experiment2 = true;
+ // for (FT delta = 0; delta < epsilon; delta += 0.1*epsilon)
+ // protected_delaunay(W, landmarks_ind, delta, epsilon, 0.5, 0, true, true);
+ // write_tikz_plot(epsratio_vector,"epsratio_delta.tikz");
+ // experiment2 = false;
+
+}
+
+#endif
diff --git a/src/Witness_complex/example/protected_sets/protected_sets_paper2.h b/src/Witness_complex/example/protected_sets/protected_sets_paper2.h
new file mode 100644
index 00000000..04b5e3bc
--- /dev/null
+++ b/src/Witness_complex/example/protected_sets/protected_sets_paper2.h
@@ -0,0 +1,1384 @@
+#ifndef PROTECTED_SETS_H
+#define PROTECTED_SETS_H
+
+#include <algorithm>
+#include <CGAL/Cartesian_d.h>
+#include <CGAL/Epick_d.h>
+#include <CGAL/Euclidean_distance.h>
+#include <CGAL/Kernel_d/Sphere_d.h>
+#include <CGAL/Kernel_d/Hyperplane_d.h>
+#include <CGAL/Kernel_d/Vector_d.h>
+
+#include <CGAL/Orthogonal_k_neighbor_search.h>
+#include <CGAL/Kd_tree.h>
+#include <CGAL/Fuzzy_sphere.h>
+
+#include <boost/heap/fibonacci_heap.hpp>
+#include <boost/heap/policies.hpp>
+
+#include "output_tikz.h"
+#include "../output.h"
+#include "../generators.h"
+
+#include <CGAL/point_generators_d.h>
+
+
+typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> K;
+typedef K::Point_d Point_d;
+typedef K::Line_d Line_d;
+typedef K::Vector_d Vector_d;
+typedef K::Oriented_side_d Oriented_side_d;
+typedef K::Has_on_positive_side_d Has_on_positive_side_d;
+typedef K::Sphere_d Sphere_d;
+typedef K::Hyperplane_d Hyperplane_d;
+
+typedef CGAL::Delaunay_triangulation<K> Delaunay_triangulation;
+typedef Delaunay_triangulation::Facet Facet;
+typedef Delaunay_triangulation::Vertex_handle Delaunay_vertex;
+typedef Delaunay_triangulation::Full_cell_handle Full_cell_handle;
+
+typedef std::vector<Point_d> Point_Vector;
+typedef CGAL::Euclidean_distance<Traits_base> Euclidean_distance;
+
+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_k_neighbor_search<STraits, CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance>> K_neighbor_search;
+typedef K_neighbor_search::Tree Tree;
+typedef K_neighbor_search::Distance Distance;
+typedef K_neighbor_search::iterator KNS_iterator;
+typedef K_neighbor_search::iterator KNS_range;
+typedef CGAL::Fuzzy_sphere<STraits> Fuzzy_sphere;
+
+typedef CGAL::Random_points_in_ball_d<Point_d> Random_point_iterator;
+
+
+FT _sfty = pow(10,-14);
+
+bool experiment1, experiment2, experiment3, experiment5 = false;
+
+/* Experiment 1: epsilon as function on time **********************/
+std::vector<FT> eps_vector;
+
+/* Experiment 2: R/epsilon on alpha *******************************/
+std::vector<FT> epsratio_vector;
+std::vector<FT> epsslope_vector;
+
+/* Experiment 3: theta on delta ***********************************/
+std::vector<FT> thetamin_vector; FT curr_theta;
+std::vector<FT> gammamin_vector;
+
+/* Statistical data ***********************************************/
+int refused_case1, refused_case2, refused_bad, refused_centers1, refused_centers2;
+
+void initialize_statistics()
+{
+ refused_case1 = 0;
+ refused_case2 = 0;
+ refused_bad = 0;
+ refused_centers1 = 0;
+ refused_centers2 = 0;
+}
+
+void print_statistics()
+{
+ std::cout << " * Old simplex not protected: " << refused_case1 << "\n";
+ std::cout << " * New simplex not protected: " << refused_case2 << "\n";
+ std::cout << " * New simplex not good: " << refused_bad << "\n";
+ std::cout << " * New-old centers too close: " << refused_centers1 << "\n";
+ std::cout << " * New-new centers too close: " << refused_centers2 << "\n";
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+// AUXILLARY FUNCTIONS
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/** Insert a point in Delaunay triangulation. If you are working in a flat torus, the procedure adds all the 3^d copies in adjacent cubes as well
+ *
+ * W is the initial point vector
+ * chosen_landmark is the index of the chosen point in W
+ * landmarks_ind is the vector of indices of already chosen points in W
+ * delaunay is the Delaunay triangulation
+ * landmark_count is the current number of chosen vertices
+ * torus is true iff you are working on a flat torus [-1,1]^d
+ * OUT: Vertex handle to the newly inserted point
+ */
+Delaunay_vertex insert_delaunay_landmark_with_copies(Point_Vector& W, int chosen_landmark, std::vector<int>& landmarks_ind, Delaunay_triangulation& delaunay, int& landmark_count, bool torus)
+{
+ if (!torus)
+ {
+ Delaunay_vertex v =delaunay.insert(W[chosen_landmark]);
+ landmarks_ind.push_back(chosen_landmark);
+ landmark_count++;
+ return v;
+ }
+ else
+ {
+ int D = W[0].size();
+ int nb_cells = pow(3, D);
+ Delaunay_vertex v;
+ for (int i = 0; i < nb_cells; ++i)
+ {
+ std::vector<FT> point;
+ int cell_i = i;
+ for (int l = 0; l < D; ++l)
+ {
+ point.push_back(W[chosen_landmark][l] + 2.0*(cell_i%3-1));
+ cell_i /= 3;
+ }
+ if (i == nb_cells/2)
+ v = delaunay.insert(point); //v = center point
+ else
+ delaunay.insert(point);
+ }
+ landmarks_ind.push_back(chosen_landmark);
+ landmark_count++;
+ return v;
+ }
+}
+
+/** Small check if the vertex v is in the full cell fc
+ */
+
+bool vertex_is_in_full_cell(Delaunay_triangulation::Vertex_handle v, Full_cell_handle fc)
+{
+ for (auto v_it = fc->vertices_begin(); v_it != fc->vertices_end(); ++v_it)
+ if (*v_it == v)
+ return true;
+ return false;
+}
+
+/** Fill chosen point vector from indices with copies if you are working on a flat torus
+ *
+ * IN: W is the point vector
+ * OUT: landmarks is the output vector
+ * IN: landmarks_ind is the vector of indices
+ * IN: torus is true iff you are working on a flat torus [-1,1]^d
+ */
+
+void fill_landmarks(Point_Vector& W, Point_Vector& landmarks, std::vector<int>& landmarks_ind, bool torus)
+{
+ if (!torus)
+ for (unsigned j = 0; j < landmarks_ind.size(); ++j)
+ landmarks.push_back(W[landmarks_ind[j]]);
+ else
+ {
+ int D = W[0].size();
+ int nb_cells = pow(3, D);
+ int nbL = landmarks_ind.size();
+ // Fill landmarks
+ for (int i = 0; i < nb_cells-1; ++i)
+ for (int j = 0; j < nbL; ++j)
+ {
+ int cell_i = i;
+ Point_d point;
+ for (int l = 0; l < D; ++l)
+ {
+ point.push_back(W[landmarks_ind[j]][l] + 2.0*(cell_i-1));
+ cell_i /= 3;
+ }
+ landmarks.push_back(point);
+ }
+ }
+}
+
+/** Fill a vector of all simplices in the Delaunay triangulation giving integer indices to vertices
+ *
+ * IN: t is the Delaunay triangulation
+ * OUT: full_cells is the output vector
+ */
+
+void fill_full_cell_vector(Delaunay_triangulation& t, std::vector<std::vector<int>>& full_cells)
+{
+ // Store vertex indices in a map
+ int ind = 0; //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;
+ else
+ index_of_vertex[v_it] = ind++;
+ // Write full cells as vectors in full_cells
+ for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
+ {
+ if (t.is_infinite(fc_it))
+ continue;
+ Point_Vector vertices;
+ for (auto fc_v_it = fc_it->vertices_begin(); fc_v_it != fc_it->vertices_end(); ++fc_v_it)
+ vertices.push_back((*fc_v_it)->point());
+ Sphere_d cs( vertices.begin(), vertices.end());
+ Point_d csc = cs.center();
+ bool in_cube = true;
+ for (auto xi = csc.cartesian_begin(); xi != csc.cartesian_end(); ++xi)
+ if (*xi > 1.0 || *xi < -1.0)
+ {
+ in_cube = false; break;
+ }
+ if (!in_cube)
+ continue;
+ std::vector<int> cell;
+ for (auto v_it = fc_it->vertices_begin(); v_it != fc_it->vertices_end(); ++v_it)
+ cell.push_back(index_of_vertex[*v_it]);
+ full_cells.push_back(cell);
+ }
+}
+
+bool sphere_intersects_cube(Point_d& c, FT r)
+{
+ bool in_cube = true;
+ // int i = 0, D = p.size();
+ for (auto xi = c.cartesian_begin(); xi != c.cartesian_end(); ++xi)
+ // if ((*xi < 1.0 || *xi > -1.0) &&
+ // (*xi-r < 1.0 || *xi-r > -1.0) &&
+ // (*xi+r < 1.0 || *xi+r > -1.0))
+
+ if ((*xi-r < -1.0 && *xi+r < -1.0) ||
+ (*xi-r > 1.0 && *xi+r > 1.0 ))
+ {
+ in_cube = false; break;
+ }
+ return in_cube;
+}
+
+/** Recursive function for checking if the simplex is good,
+ * meaning it does not contain a k-face, which is not theta0^(k-1) thick
+ */
+
+bool is_theta0_good(std::vector<Point_d>& vertices, FT theta0)
+{
+ if (theta0 > 1)
+ {
+ std::cout << "Warning! theta0 is set > 1\n";
+ return false;
+ }
+ int D = vertices.size()-1;
+ if (D <= 1)
+ return true; // Edges are always good
+ //******** Circumscribed sphere
+ Euclidean_distance ed;
+ Sphere_d cs(vertices.begin(), vertices.end());
+ FT r = sqrt(cs.squared_radius());
+ for (std::vector<Point_d>::iterator v_it = vertices.begin(); v_it != vertices.end(); ++v_it)
+ {
+ std::vector<Point_d> facet;
+ for (std::vector<Point_d>::iterator f_it = vertices.begin(); f_it != vertices.end(); ++f_it)
+ if (f_it != v_it)
+ facet.push_back(*f_it);
+ // Compute the altitude
+
+ if (vertices[0].size() == 3 && D == 2)
+ {
+ //Vector_d l = facet[0] - facet[1];
+ FT orth_length2 = ed.transformed_distance(facet[0],facet[1]);
+ K::Cartesian_const_iterator_d l_it, p_it, s_it, c_it;
+ FT h = 0;
+ // Scalar product = <sp,l>
+ FT scalar = 0;
+ for (p_it = v_it->cartesian_begin(),
+ s_it = facet[0].cartesian_begin(),
+ l_it = facet[1].cartesian_begin();
+ p_it != v_it->cartesian_end();
+ ++l_it, ++p_it, ++s_it)
+ scalar += (*l_it - *s_it)*(*p_it - *s_it);
+ // Gram-Schmidt for one vector
+ for (p_it = v_it->cartesian_begin(),
+ s_it = facet[0].cartesian_begin(),
+ l_it = facet[1].cartesian_begin();
+ p_it != v_it->cartesian_end();
+ ++l_it, ++p_it, ++s_it)
+ {
+ FT hx = (*p_it - *s_it) - scalar*(*l_it - *s_it)/orth_length2;
+ h += hx*hx;
+ }
+ h = sqrt(h);
+
+ if (h/(2*r) < pow(theta0, D-1))
+ return false;
+ if (!is_theta0_good(facet, theta0))
+ return false;
+ }
+ else
+ {
+ Hyperplane_d tau_h(facet.begin(), facet.end(), *v_it);
+ Vector_d orth_tau = tau_h.orthogonal_vector();
+ FT orth_length = sqrt(orth_tau.squared_length());
+ K::Cartesian_const_iterator_d o_it, p_it, s_it, c_it;
+ FT h = 0;
+ for (o_it = orth_tau.cartesian_begin(),
+ p_it = v_it->cartesian_begin(),
+ s_it = (facet.begin())->cartesian_begin();
+ o_it != orth_tau.cartesian_end();
+ ++o_it, ++p_it, ++s_it)
+ h += (*o_it)*(*p_it - *s_it)/orth_length;
+ h = fabs(h);
+ if (experiment3 && thetamin_vector[thetamin_vector.size()-1] > pow(h/(2*r), 1.0/(D-1)))
+ {
+ thetamin_vector[thetamin_vector.size()-1] = pow(h/(2*r), 1.0/(D-1));
+ //std::cout << "theta=" << h/(2*r) << ", ";
+ }
+ if (h/(2*r) < pow(theta0, D-1))
+ return false;
+ if (!is_theta0_good(facet, theta0))
+ return false;
+ }
+ }
+ return true;
+}
+
+/** Recursive function for checking the goodness of a simplex,
+ * meaning it does not contain a k-face, which is not theta0^(k-1) thick
+ */
+
+FT theta(std::vector<Point_d>& vertices)
+{
+ FT curr_value = 1.0;
+ int D = vertices.size()-1;
+ if (D <= 1)
+ return 1; // Edges are always good
+ //******** Circumscribed sphere
+ Euclidean_distance ed;
+ Sphere_d cs(vertices.begin(), vertices.end());
+ FT r = sqrt(cs.squared_radius());
+ for (std::vector<Point_d>::iterator v_it = vertices.begin(); v_it != vertices.end(); ++v_it)
+ {
+ std::vector<Point_d> facet;
+ for (std::vector<Point_d>::iterator f_it = vertices.begin(); f_it != vertices.end(); ++f_it)
+ if (f_it != v_it)
+ facet.push_back(*f_it);
+ // Compute the altitude
+ curr_value = std::min(curr_value, theta(facet)); // Check the corresponding facet
+ if (vertices[0].size() == 3 && D == 2)
+ {
+ //Vector_d l = facet[0] - facet[1];
+ FT orth_length2 = ed.transformed_distance(facet[0],facet[1]);
+ K::Cartesian_const_iterator_d l_it, p_it, s_it, c_it;
+ FT h = 0;
+ // Scalar product = <sp,l>
+ FT scalar = 0;
+ for (p_it = v_it->cartesian_begin(),
+ s_it = facet[0].cartesian_begin(),
+ l_it = facet[1].cartesian_begin();
+ p_it != v_it->cartesian_end();
+ ++l_it, ++p_it, ++s_it)
+ scalar += (*l_it - *s_it)*(*p_it - *s_it);
+ // Gram-Schmidt for one vector
+ for (p_it = v_it->cartesian_begin(),
+ s_it = facet[0].cartesian_begin(),
+ l_it = facet[1].cartesian_begin();
+ p_it != v_it->cartesian_end();
+ ++l_it, ++p_it, ++s_it)
+ {
+ FT hx = (*p_it - *s_it) - scalar*(*l_it - *s_it)/orth_length2;
+ h += hx*hx;
+ }
+ h = sqrt(h);
+ curr_value = std::min(curr_value, std::pow(h/(2*r), 1.0/(D-1)));
+ }
+ else
+ {
+ Hyperplane_d tau_h(facet.begin(), facet.end(), *v_it);
+ Vector_d orth_tau = tau_h.orthogonal_vector();
+ FT orth_length = sqrt(orth_tau.squared_length());
+ K::Cartesian_const_iterator_d o_it, p_it, s_it, c_it;
+ FT h = 0;
+ for (o_it = orth_tau.cartesian_begin(),
+ p_it = v_it->cartesian_begin(),
+ s_it = (facet.begin())->cartesian_begin();
+ o_it != orth_tau.cartesian_end();
+ ++o_it, ++p_it, ++s_it)
+ h += (*o_it)*(*p_it - *s_it)/orth_length;
+ h = fabs(h);
+ curr_value = std::min(curr_value, pow(h/(2*r), 1.0/(D-1)));
+ }
+ }
+ return curr_value;
+}
+
+// Doubling in a way 1->2->5->10
+void double_round(int& i)
+{
+ FT order10 = pow(10,std::floor(std::log10(i)));
+ int digit = std::floor( i / order10);
+ std::cout << digit;
+ if (digit == 1)
+ i *= 2;
+ else if (digit == 2)
+ i = 5*i/2;
+ else if (digit == 5)
+ i *= 2;
+ else
+ std::cout << "digit not correct. digit = " << digit << std::endl;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// IS VIOLATED TEST
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/** Check if a newly created cell is protected from old vertices
+ *
+ * t is the Delaunay triangulation
+ * vertices is the vector containing the point to insert and a facet f in t
+ * v1 is the vertex of t, such that f and v1 form a simplex
+ * v2 is the vertex of t, such that f and v2 form another simplex
+ * delta is the protection constant
+ * power_protection is true iff the delta-power protection is used
+ */
+
+bool new_cell_is_violated(Delaunay_triangulation& t, std::vector<Point_d>& vertices, const Delaunay_vertex& v1, const Delaunay_vertex v2, FT delta0, bool power_protection, FT theta0, FT gamma0)
+{
+ assert(vertices.size() == vertices[0].size() ||
+ vertices.size() == vertices[0].size() + 1); //simplex size = d | d+1
+ assert(v1 != v2);
+ if (vertices.size() == vertices[0].size() + 1)
+ // FINITE CASE
+ {
+ Sphere_d cs(vertices.begin(), vertices.end());
+ Point_d center_cs = cs.center();
+ FT r = sqrt(Euclidean_distance().transformed_distance(center_cs, vertices[0]));
+ /*
+ for (auto v_it = t.vertices_begin(); v_it != t.vertices_end(); ++v_it)
+ if (!t.is_infinite(v_it))
+ {
+ //CGAL::Oriented_side side = Oriented_side_d()(cs, (v_it)->point());
+ if (std::find(vertices.begin(), vertices.end(), v_it->point()) == vertices.end())
+ {
+ FT dist2 = Euclidean_distance().transformed_distance(center_cs, (v_it)->point());
+ if (!power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= (r+delta)*(r+delta))
+ return true;
+ if (power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= r*r+delta*delta)
+ return true;
+ }
+ }
+ */
+ // Is the center inside the box? (only Euclidean case)
+ // if (!torus)
+ // {
+ // bool inside_the_box = true;
+ // for (c_it = center_cs.cartesian_begin(); c_it != center_cs.cartesian_end(); ++c_it)
+ // if (*c_it > 1.0 || *c_it < -1.0)
+ // {
+ // inside_the_box = false; break;
+ // }
+ // if (inside_the_box && h/r < theta0)
+ // return true;
+ // }
+ // Check the two vertices (if not infinite)
+ if (!t.is_infinite(v1))
+ {
+ FT dist2 = Euclidean_distance().transformed_distance(center_cs, v1->point());
+ if (!power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= (r+r*delta0)*(r+r*delta0))
+ { refused_case2++; return true;}
+ if (power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= r*r+r*r*delta0*delta0)
+ { refused_case2++; return true;}
+ // Check if the centers are not too close
+ std::vector<Point_d> sigma(vertices);
+ sigma[0] = v1->point();
+ Sphere_d cs_sigma(sigma.begin(), sigma.end());
+ Point_d csc_sigma = cs_sigma.center();
+ FT r_sigma = sqrt(cs_sigma.squared_radius());
+ FT dcc = sqrt(Euclidean_distance().transformed_distance(center_cs, csc_sigma));
+ if (experiment3 && dcc/r < gammamin_vector[gammamin_vector.size()-1])
+ gammamin_vector[gammamin_vector.size()-1] = dcc/r;
+ if (experiment3 && dcc/r_sigma < gammamin_vector[gammamin_vector.size()-1])
+ gammamin_vector[gammamin_vector.size()-1] = dcc/r_sigma;
+ if (dcc < r*gamma0 || dcc < r_sigma*gamma0)
+ { refused_centers1++; return true; }
+ }
+ if (!t.is_infinite(v2))
+ {
+ FT dist2 = Euclidean_distance().transformed_distance(center_cs, v2->point());
+ if (!power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= (r+r*delta0)*(r+r*delta0))
+ { refused_case2++; return true;}
+ if (power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= r*r+r*r*delta0*delta0)
+ { refused_case2++; return true;}
+ // Check if the centers are not too close
+ std::vector<Point_d> sigma(vertices);
+ sigma[0] = v2->point();
+ Sphere_d cs_sigma(sigma.begin(), sigma.end());
+ Point_d csc_sigma = cs_sigma.center();
+ FT r_sigma = sqrt(cs_sigma.squared_radius());
+ FT dcc = sqrt(Euclidean_distance().transformed_distance(center_cs, csc_sigma));
+ if (experiment3 && dcc/r < gammamin_vector[gammamin_vector.size()-1])
+ gammamin_vector[gammamin_vector.size()-1] = dcc/r;
+ if (experiment3 && dcc/r_sigma < gammamin_vector[gammamin_vector.size()-1])
+ gammamin_vector[gammamin_vector.size()-1] = dcc/r_sigma;
+ if (dcc < r*gamma0 || dcc < r_sigma*gamma0)
+ { refused_centers1++; return true; }
+ }
+ // Check if the simplex is theta0-good
+ if (!is_theta0_good(vertices, theta0))
+ { refused_bad++; return true;}
+
+ }
+ else
+ // INFINITE CASE
+ {
+ Delaunay_triangulation::Vertex_iterator v = t.vertices_begin();
+ while (t.is_infinite(v) || std::find(vertices.begin(), vertices.end(), v->point()) == vertices.end())
+ v++;
+ Hyperplane_d facet_plane(vertices.begin(), vertices.end(), v->point(), CGAL::ON_POSITIVE_SIDE);
+ Vector_d orth_v = facet_plane.orthogonal_vector();
+ /*
+ for (auto v_it = t.vertices_begin(); v_it != t.vertices_end(); ++v_it)
+ if (!t.is_infinite(v_it))
+ if (std::find(vertices.begin(), vertices.end(), v_it->point()) == vertices.end())
+ {
+ std::vector<FT> coords;
+ Point_d p = v_it->point();
+ auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
+ for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
+ coords.push_back((*p_i) - (*orth_i) * delta / sqrt(orth_v.squared_length()));
+ Point_d p_delta = Point_d(coords);
+ bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p);
+ bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
+ if (!p_is_inside && p_delta_is_inside)
+ return true;
+ }
+ */
+ if (!t.is_infinite(v1))
+ {
+ std::vector<FT> coords;
+ Point_d p = v1->point();
+ auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
+ for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
+ coords.push_back((*p_i) - (*orth_i) * delta0 / sqrt(orth_v.squared_length()));
+ Point_d p_delta = Point_d(coords);
+ bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p);
+ bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
+ if (!power_protection && !p_is_inside && p_delta_is_inside)
+ return true;
+ }
+ if (!t.is_infinite(v2))
+ {
+ std::vector<FT> coords;
+ Point_d p = v2->point();
+ auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
+ for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
+ coords.push_back((*p_i) - (*orth_i) * delta0 / sqrt(orth_v.squared_length()));
+ Point_d p_delta = Point_d(coords);
+ bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p);
+ bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
+ if (!power_protection && !p_is_inside && p_delta_is_inside)
+ return true;
+ }
+ }
+ return false;
+}
+
+/** Auxillary recursive function to check if the point p violates the protection of the cell c and
+ * if there is a violation of an eventual new cell
+ *
+ * p is the point to insert
+ * t is the current triangulation
+ * c is the current cell (simplex)
+ * parent_cell is the parent cell (simplex)
+ * index is the index of the facet between c and parent_cell from parent_cell's point of view
+ * D is the dimension of the triangulation
+ * delta is the protection constant
+ * marked_cells is the vector of all visited cells containing p in their circumscribed ball
+ * power_protection is true iff you are working with delta-power protection
+ *
+ * OUT: true iff inserting p hasn't produced any violation so far
+ */
+
+bool is_violating_protection(Point_d& p, Delaunay_triangulation& t, Full_cell_handle c, Full_cell_handle parent_cell, int index, int D, FT delta0, std::vector<Full_cell_handle>& marked_cells, bool power_protection, FT theta0, FT gamma0)
+{
+ Euclidean_distance ed;
+ std::vector<Point_d> vertices;
+ if (!t.is_infinite(c))
+ {
+ // if the cell is finite, we look if the protection is violated
+ for (auto v_it = c->vertices_begin(); v_it != c->vertices_end(); ++v_it)
+ vertices.push_back((*v_it)->point());
+ Sphere_d cs( vertices.begin(), vertices.end());
+ Point_d center_cs = cs.center();
+ FT r = sqrt(ed.transformed_distance(center_cs, vertices[0]));
+ FT dist2 = ed.transformed_distance(center_cs, p);
+ // if the new point is inside the protection ball of a non conflicting simplex
+ if (!power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= (r+r*delta0)*(r+r*delta0))
+ { refused_case1++; return true;}
+ if (power_protection)
+ if (dist2 >= r*r-_sfty && dist2 <= r*r+delta0*delta0*r*r)
+ { refused_case1++; return true;}
+ // if the new point is inside the circumscribing ball : continue violation searching on neighbours
+ //if (dist2 < r*r)
+ //if (dist2 < (5*r+delta)*(5*r+delta))
+ if (dist2 < r*r)
+ {
+ c->tds_data().mark_visited();
+ marked_cells.push_back(c);
+ for (int i = 0; i < D+1; ++i)
+ {
+ Full_cell_handle next_c = c->neighbor(i);
+ if (next_c->tds_data().is_clear() &&
+ is_violating_protection(p, t, next_c, c, i, D, delta0, marked_cells, power_protection, theta0, gamma0))
+ return true;
+ }
+ }
+ // if the new point is outside the protection sphere
+ else
+ {
+ // facet f is on the border of the conflict zone : check protection of simplex {p,f}
+ // the new simplex is guaranteed to be finite
+ vertices.clear(); vertices.push_back(p);
+ for (int i = 0; i < D+1; ++i)
+ if (i != index)
+ vertices.push_back(parent_cell->vertex(i)->point());
+ Delaunay_vertex vertex_to_check = t.infinite_vertex();
+ for (auto vh_it = c->vertices_begin(); vh_it != c->vertices_end(); ++vh_it)
+ if (!vertex_is_in_full_cell(*vh_it, parent_cell))
+ {
+ vertex_to_check = *vh_it; break;
+ }
+ if (new_cell_is_violated(t, vertices, vertex_to_check, parent_cell->vertex(index), delta0, power_protection, theta0, gamma0))
+ //if (new_cell_is_violated(t, vertices, vertex_to_check->point(), delta))
+ return true;
+ }
+ }
+ else
+ {
+ // Inside of the convex hull is + side. Outside is - side.
+ for (auto vh_it = c->vertices_begin(); vh_it != c->vertices_end(); ++vh_it)
+ if (!t.is_infinite(*vh_it))
+ vertices.push_back((*vh_it)->point());
+ Delaunay_triangulation::Vertex_iterator v_it = t.vertices_begin();
+ while (t.is_infinite(v_it) || vertex_is_in_full_cell(v_it, c))
+ v_it++;
+ Hyperplane_d facet_plane(vertices.begin(), vertices.end(), v_it->point(), CGAL::ON_POSITIVE_SIDE);
+ //CGAL::Oriented_side outside = Oriented_side_d()(facet_plane, v_it->point());
+ Vector_d orth_v = facet_plane.orthogonal_vector();
+ std::vector<FT> coords;
+ auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
+ for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
+ coords.push_back((*p_i) - (*orth_i) * delta0 / sqrt(orth_v.squared_length()));
+ Point_d p_delta = Point_d(coords);
+ bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p) && (Oriented_side_d()(facet_plane, p) != CGAL::ZERO);
+ bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
+
+ // If we work with power protection, we just ignore any conflicts
+ if (!power_protection && !p_is_inside && p_delta_is_inside)
+ return true;
+ //if the cell is infinite we look at the neighbours regardless
+ if (p_is_inside)
+ {
+ c->tds_data().mark_visited();
+ marked_cells.push_back(c);
+ for (int i = 0; i < D+1; ++i)
+ {
+ Full_cell_handle next_c = c->neighbor(i);
+ if (next_c->tds_data().is_clear() &&
+ is_violating_protection(p, t, next_c, c, i, D, delta0, marked_cells, power_protection, theta0, gamma0))
+ return true;
+ }
+ }
+ else
+ {
+ // facet f is on the border of the conflict zone : check protection of simplex {p,f}
+ // the new simplex is finite if the parent cell is finite
+ vertices.clear(); vertices.push_back(p);
+ for (int i = 0; i < D+1; ++i)
+ if (i != index)
+ if (!t.is_infinite(parent_cell->vertex(i)))
+ vertices.push_back(parent_cell->vertex(i)->point());
+ Delaunay_vertex vertex_to_check = t.infinite_vertex();
+ for (auto vh_it = c->vertices_begin(); vh_it != c->vertices_end(); ++vh_it)
+ if (!vertex_is_in_full_cell(*vh_it, parent_cell))
+ {
+ vertex_to_check = *vh_it; break;
+ }
+ if (new_cell_is_violated(t, vertices, vertex_to_check, parent_cell->vertex(index), delta0, power_protection, theta0, gamma0))
+ //if (new_cell_is_violated(t, vertices, vertex_to_check->point(), delta))
+ return true;
+ }
+ }
+ //c->tds_data().clear_visited();
+ //marked_cells.pop_back();
+ return false;
+}
+
+/** Checks if inserting the point p in t will make conflicts
+ *
+ * p is the point to insert
+ * t is the current triangulation
+ * D is the dimension of triangulation
+ * delta is the protection constant
+ * power_protection is true iff you are working with delta-power protection
+ * OUT: true iff inserting p produces a violation of delta-protection.
+ */
+
+bool is_violating_protection(Point_d& p, Delaunay_triangulation& t, int D, FT delta0, bool power_protection, FT theta0, FT gamma0)
+{
+ Euclidean_distance ed;
+ Delaunay_triangulation::Vertex_handle v;
+ Delaunay_triangulation::Face f(t.current_dimension());
+ Delaunay_triangulation::Facet ft;
+ Delaunay_triangulation::Full_cell_handle c;
+ Delaunay_triangulation::Locate_type lt;
+ std::vector<Full_cell_handle> marked_cells;
+ //c = t.locate(p, lt, f, ft, v);
+ c = t.locate(p);
+ bool violation_existing_cells = is_violating_protection(p, t, c, c, 0, D, delta0, marked_cells, power_protection, theta0, gamma0);
+ for (Full_cell_handle fc : marked_cells)
+ fc->tds_data().clear();
+ return violation_existing_cells;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+// INITIALIZATION
+////////////////////////////////////////////////////////////////////////
+
+// Query for a sphere near a cite in all copies of a torus
+// OUT points_inside
+void torus_search(Tree& treeW, int D, Point_d cite, FT r, std::vector<int>& points_inside)
+{
+ int nb_cells = pow(3, D);
+ Delaunay_vertex v;
+ for (int i = 0; i < nb_cells; ++i)
+ {
+ std::vector<FT> cite_copy;
+ int cell_i = i;
+ for (int l = 0; l < D; ++l)
+ {
+ cite_copy.push_back(cite[l] + 2.0*(cell_i%3-1));
+ cell_i /= 3;
+ }
+ Fuzzy_sphere fs(cite_copy, r, 0, treeW.traits());
+ treeW.search(std::insert_iterator<std::vector<int>>(points_inside, points_inside.end()), fs);
+ }
+}
+
+
+void initialize_torus(Point_Vector& W, Tree& treeW, Delaunay_triangulation& t, FT epsilon, std::vector<int>& landmarks_ind, int& landmark_count, std::vector<bool>& point_taken)
+{
+ initialize_statistics();
+ int D = W[0].size();
+ if (D == 2)
+ {
+ int xw = 6, yw = 4;
+ // Triangular lattice close to regular triangles h=0.866a ~ 0.875a : 48p
+ for (int i = 0; i < xw; ++i)
+ for (int j = 0; j < yw; ++j)
+ {
+ Point_d cite1(std::vector<FT>{2.0/xw*i, 2.0/yw*j});
+ std::vector<int> points_inside;
+ torus_search(treeW, D, cite1, epsilon, points_inside);
+ //std::cout << "i=" << i << ", j=" << j << " "; print_vector(points_inside); std::cout << "\n";
+ std::vector<int>::iterator p_it = points_inside.begin();
+ while (p_it != points_inside.end() && point_taken[*p_it])
+ ++p_it;
+ assert(p_it != points_inside.end());
+ //W[*p_it] = cite1; // debug purpose
+ insert_delaunay_landmark_with_copies(W, *p_it,
+ landmarks_ind, t, landmark_count, true);
+ point_taken[*p_it] = true;
+
+ Point_d cite2(std::vector<FT>{2.0/xw*(i+0.5), 2.0/yw*(j+0.5)});
+ points_inside.clear();
+ torus_search(treeW, D, cite2, epsilon, points_inside);
+ //std::cout << "i=" << i << ", j=" << j << " "; print_vector(points_inside); std::cout << "\n";
+ p_it = points_inside.begin();
+ while (p_it != points_inside.end() && point_taken[*p_it])
+ ++p_it;
+ assert(p_it != points_inside.end());
+ //W[*p_it] = cite2; // debug purpose
+ insert_delaunay_landmark_with_copies(W, *p_it,
+ landmarks_ind, t, landmark_count, true);
+ point_taken[*p_it] = true;
+ }
+ }
+ else if (D == 3)
+ {
+ int wd = 3;
+ // Body-centered cubic lattice : 54p
+ for (int i = 0; i < wd; ++i)
+ for (int j = 0; j < wd; ++j)
+ for (int k = 0; k < wd; ++k)
+ {
+ Point_d cite1(std::vector<FT>{2.0/wd*i, 2.0/wd*j, 2.0/wd*k});
+ std::vector<int> points_inside;
+ torus_search(treeW, D, cite1, epsilon, points_inside);
+ std::vector<int>::iterator p_it = points_inside.begin();
+ while (p_it != points_inside.end() && point_taken[*p_it])
+ ++p_it;
+ assert(p_it != points_inside.end());
+ insert_delaunay_landmark_with_copies(W, *(points_inside.begin()),
+ landmarks_ind, t, landmark_count, true);
+ point_taken[*p_it] = true;
+
+ Point_d cite2(std::vector<FT>{2.0/wd*(i+0.5), 2.0/wd*(j+0.5), 2.0/wd*(k+0.5)});
+ points_inside.clear();
+ torus_search(treeW, D, cite2, epsilon, points_inside);
+ p_it = points_inside.begin();
+ while (p_it != points_inside.end() && point_taken[*p_it])
+ ++p_it;
+ assert(p_it != points_inside.end());
+ insert_delaunay_landmark_with_copies(W, *(points_inside.begin()),
+ landmarks_ind, t, landmark_count, true);
+ point_taken[*p_it] = true;
+ }
+ }
+ //write_mesh
+}
+
+///////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////
+//!!!!!!!!!!!!! THE INTERFACE FOR LANDMARK CHOICE IS BELOW !!!!!!!!!!//
+///////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////
+
+// Struct for R_max_heap elements
+
+struct R_max_handle
+{
+ FT value;
+ Point_d center;
+
+ R_max_handle(FT value_, Point_d c): value(value_), center(c)
+ {}
+};
+
+struct R_max_compare
+{
+ bool operator()(const R_max_handle& rmh1, const R_max_handle& rmh2) const
+ {
+ return rmh1.value < rmh2.value;
+ }
+};
+
+// typedef boost::heap::fibonacci_heap<R_max_handle, boost::heap::compare<R_max_compare>> Heap;
+
+// void make_heap(Delaunay_triangulation& t, Heap& R_max_heap)
+// {
+// R_max_heap.clear();
+// for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
+// {
+// if (t.is_infinite(fc_it))
+// continue;
+// Point_Vector vertices;
+// for (auto fc_v_it = fc_it->vertices_begin(); fc_v_it != fc_it->vertices_end(); ++fc_v_it)
+// vertices.push_back((*fc_v_it)->point());
+// Sphere_d cs( vertices.begin(), vertices.end());
+// Point_d csc = cs.center();
+// FT r = sqrt(cs.squared_radius());
+// // A ball is in the heap, if it intersects the cube
+// bool accepted = sphere_intersects_cube(csc, sqrt(r));
+// if (!accepted)
+// continue;
+// R_max_heap.push(R_max_handle(r, fc_it, csc));
+// }
+// }
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+// SAMPLING RADIUS
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+R_max_handle sampling_radius(Delaunay_triangulation& t)
+{
+ FT epsilon2 = 0;
+ Point_d final_center;
+ Point_d control_point;
+ for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
+ {
+ if (t.is_infinite(fc_it))
+ continue;
+ Point_Vector vertices;
+ for (auto fc_v_it = fc_it->vertices_begin(); fc_v_it != fc_it->vertices_end(); ++fc_v_it)
+ vertices.push_back((*fc_v_it)->point());
+ Sphere_d cs( vertices.begin(), vertices.end());
+ Point_d csc = cs.center();
+ bool in_cube = true;
+ for (auto xi = csc.cartesian_begin(); xi != csc.cartesian_end(); ++xi)
+ if (*xi > 1.0 || *xi < -1.0)
+ {
+ in_cube = false; break;
+ }
+ if (!in_cube)
+ continue;
+ FT r2 = Euclidean_distance().transformed_distance(cs.center(), *(vertices.begin()));
+ if (epsilon2 < r2)
+ {
+ epsilon2 = r2;
+ final_center = csc;
+ control_point = (*vertices.begin());
+ }
+ }
+ return R_max_handle(sqrt(epsilon2), final_center);
+}
+
+FT sampling_fatness(Delaunay_triangulation& t)
+{
+ FT curr_theta = 1.0;
+ for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
+ {
+ if (t.is_infinite(fc_it))
+ continue;
+ Point_Vector vertices;
+ for (auto fc_v_it = fc_it->vertices_begin(); fc_v_it != fc_it->vertices_end(); ++fc_v_it)
+ vertices.push_back((*fc_v_it)->point());
+ Sphere_d cs( vertices.begin(), vertices.end());
+ Point_d csc = cs.center();
+ bool in_cube = true;
+ for (auto xi = csc.cartesian_begin(); xi != csc.cartesian_end(); ++xi)
+ if (*xi > 1.0 || *xi < -1.0)
+ {
+ in_cube = false; break;
+ }
+ if (!in_cube)
+ continue;
+ FT theta_f = theta(vertices);
+ curr_theta = std::min(curr_theta, theta_f);
+ //std::cout << "theta(sigma) = " << theta_f << "\n";
+ }
+ return curr_theta;
+}
+
+// Generate an epsilon sample for a given epsilon
+void generate_epsilon_sample_torus(Point_Vector& W, FT epsilon, int dim, Delaunay_triangulation& t)
+{
+ W.clear();
+ t.clear();
+ int point_count = 0;
+ std::vector<int> point_ind;
+ // std::vector<FT> coords;
+ FT curr_eps = 2*dim;
+ // Initialize
+ // for (int i = 0; i < dim; ++i)
+ // coords.push_back(-1);
+ // R_max_handle rmh(2*sqrt(dim), Point_d(coords));
+ // int N = dim; std::floor(std::pow(1/epsilon,dim));
+ // std::cout << N << "\n";
+ typedef CGAL::Random_points_in_cube_d<Point_d> Random_cube_iterator;
+ Random_cube_iterator rp(dim, 1.0);
+ W.push_back(*rp++);
+ insert_delaunay_landmark_with_copies(W, W.size()-1, point_ind, t, point_count, true);
+ curr_eps = sampling_radius(t).value;
+ while (curr_eps > epsilon)
+ {
+
+ W.push_back(*rp++);
+ insert_delaunay_landmark_with_copies(W, W.size()-1, point_ind, t, point_count, true);
+
+ Point_d c = sampling_radius(t).center;
+ W.push_back(c);
+ insert_delaunay_landmark_with_copies(W, W.size()-1, point_ind, t, point_count, true);
+ curr_eps = sampling_radius(t).value;
+
+ std::cout << "curr_eps = " << curr_eps << "\n";
+ }
+ // Iterate and insert in a torus
+ // while (rmh.value > epsilon)
+ // {
+ // W.push_back(rmh.center);
+ // insert_delaunay_landmark_with_copies(W, W.size()-1, point_ind, t, point_count, true);
+ // rmh = sampling_radius(t);
+ // //std::cout << rmh.value;
+ // }
+}
+
+///////////////////////////////////////////////////////////////////////
+// LANDMARK CHOICE PROCEDURE
+///////////////////////////////////////////////////////////////////////
+
+/** Procedure to compute a maximal protected subset from a point cloud. All OUTs should be empty at call.
+ *
+ * IN: W is the initial point cloud having type Epick_d<Dynamic_dimension_tag>::Point_d
+ * IN: nbP is the size of W
+ * OUT: landmarks is the output vector for the points
+ * OUT: landmarks_ind is the output vector for the indices of the selected points in W
+ * IN: delta is the constant of protection
+ * OUT: full_cells is the output vector of the simplices in the final Delaunay triangulation
+ * IN: torus is true iff you are working on a flat torus [-1,1]^d
+ */
+
+void protected_delaunay(Point_Vector& W,
+ //Point_Vector& landmarks,
+ std::vector<int>& landmarks_ind,
+ FT alpha,
+ FT epsilon,
+ FT delta0,
+ FT theta0,
+ FT gamma0,
+ //std::vector<std::vector<int>>& full_cells,
+ bool torus,
+ bool power_protection
+ )
+{
+ //bool return_ = true;
+ unsigned D = W[0].size();
+ int nbP = W.size();
+ //FT beta = 1/(1-alpha);
+ //FT Ad = pow((4*alpha + 8*beta)/alpha, D);
+ //FT theta0 = 1/Ad;
+ //FT delta0 = pow(1/Ad,D);
+ Torus_distance td;
+ Euclidean_distance ed;
+ Delaunay_triangulation t(D);
+ std::vector<bool> point_taken(nbP,false);
+ CGAL::Random rand;
+ int landmark_count = 0;
+ std::list<int> index_list;
+ //****************** Kd Tree W
+ STraits traits(&(W[0]));
+ Tree treeW(boost::counting_iterator<std::ptrdiff_t>(0),
+ boost::counting_iterator<std::ptrdiff_t>(nbP),
+ typename Tree::Splitter(),
+ traits);
+ // shuffle the list of indexes (via a vector)
+ {
+ std::vector<int> temp_vector;
+ for (int i = 0; i < nbP; ++i)
+ temp_vector.push_back(i);
+ unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
+ std::shuffle(temp_vector.begin(), temp_vector.end(), std::default_random_engine(seed));
+ //CGAL::spatial_sort(temp_vector.begin(), temp_vector.end());
+ for (std::vector<int>::iterator it = temp_vector.begin(); it != temp_vector.end(); ++it)
+ index_list.push_front(*it);
+ }
+ //******************** Initialize point set
+ if (!torus)
+ for (unsigned pos1 = 0; pos1 < D+1; ++pos1)
+ {
+ std::vector<FT> point;
+ for (unsigned i = 0; i < pos1; ++i)
+ point.push_back(-1);
+ if (pos1 != D)
+ point.push_back(1);
+ for (unsigned i = pos1+1; i < D; ++i)
+ point.push_back(0);
+ assert(point.size() == D);
+ W[index_list.front()] = Point_d(point);
+ insert_delaunay_landmark_with_copies(W, index_list.front(), landmarks_ind, t, landmark_count, torus);
+ index_list.pop_front();
+ }
+ else
+ initialize_torus(W, treeW, t, epsilon, landmarks_ind, landmark_count, point_taken);
+ //std::cout << "Size of treeW: " << treeW.size() << "\n";
+ //std::cout << "Size of t: " << t.number_of_vertices() << "\n";
+ //******************* Initialize heap for R_max
+ //Heap R_max_heap;
+ //make_heap(t, R_max_heap);
+
+
+ R_max_handle rh = sampling_radius(t);
+ FT epsilon0 = rh.value;
+ if (experiment1) eps_vector.push_back(pow(1/rh.value,D));
+ //******************** Iterative algorithm
+ std::vector<int> candidate_points;
+ torus_search(treeW, D,
+ rh.center,
+ alpha*rh.value,
+ candidate_points);
+ std::list<int>::iterator list_it;
+ std::vector<int>::iterator cp_it = candidate_points.begin();
+ while (cp_it != candidate_points.end())
+ {
+ if (!point_taken[*cp_it] && !is_violating_protection(W[*cp_it], t, D, delta0, power_protection, theta0, gamma0))
+ {
+ Delaunay_vertex v = insert_delaunay_landmark_with_copies(W, *cp_it, landmarks_ind, t, landmark_count, torus);
+ {
+ // Simple check if the new cells don't have centers too close one to another
+ std::vector<Full_cell_handle> inc_cells;
+ std::back_insert_iterator<std::vector<Full_cell_handle>> out(inc_cells);
+ t.tds().incident_full_cells(v, out);
+
+ std::vector<Sphere_d> spheres;
+ for (auto i_it = inc_cells.begin(); i_it != inc_cells.end(); ++i_it)
+ {
+ std::vector<Point_d> vertices;
+ for (auto v_it = (*i_it)->vertices_begin(); v_it != (*i_it)->vertices_end(); ++v_it)
+ vertices.push_back((*v_it)->point());
+ spheres.push_back(Sphere_d(vertices.begin(), vertices.end()));
+ }
+ for (auto s_it = spheres.begin(); s_it != spheres.end(); ++s_it)
+ for (auto t_it = s_it+1; t_it != spheres.end(); ++t_it)
+ {
+ FT ddc2 = ed.transformed_distance(s_it->center(),t_it->center());
+ if (ddc2 < gamma0*gamma0*s_it->squared_radius() ||
+ ddc2 < gamma0*gamma0*t_it->squared_radius())
+ { refused_centers2++; }
+ }
+ }
+
+ //std::cout << *cp_it << ",\n";
+ //make_heap(t, R_max_heap);
+ point_taken[*cp_it] = true;
+ rh = sampling_radius(t);
+ if (experiment1) eps_vector.push_back(pow(1/rh.value,D));
+ //std::cout << "rhvalue = " << rh.value << "\n";
+ //std::cout << "D = " <<
+ candidate_points.clear();
+ torus_search(treeW, D,
+ rh.center,
+ alpha*rh.value,
+ candidate_points);
+ cp_it = candidate_points.begin();
+ /*
+ // PIECE OF CODE FOR DEBUGGING PURPOSES
+
+ Delaunay_vertex inserted_v = insert_delaunay_landmark_with_copies(W, *list_it, landmarks_ind, t, landmark_count);
+ if (triangulation_is_protected(t, delta))
+ {
+ index_list.erase(list_it);
+ list_it = index_list.begin();
+ }
+ else
+ { //THAT'S WHERE SOMETHING'S WRONG
+ t.remove(inserted_v);
+ landmarks_ind.pop_back();
+ landmark_count--;
+ write_delaunay_mesh(t, W[*list_it], is2d);
+ is_violating_protection(W[*list_it], t_old, D, delta); //Called for encore
+ }
+ */
+ //std::cout << "index_list_size() = " << index_list.size() << "\n";
+ }
+ else
+ {
+ cp_it++;
+ //std::cout << "!!!!!WARNING!!!!! A POINT HAS BEEN OMITTED!!!\n";
+ }
+ //if (list_it != index_list.end())
+ // write_delaunay_mesh(t, W[*list_it], is2d);
+ }
+
+ if (experiment2) epsratio_vector.push_back(rh.value/epsilon0);
+ if (experiment2) epsslope_vector.push_back( (pow(1/rh.value,D)-pow(1/epsilon0,D))/(landmarks_ind.size() - 48) );
+ std::cout << "The iteration ended when cp_count = " << candidate_points.size() << "\n";
+ std::cout << "alphaRmax = " << alpha*rh.value << "\n";
+ std::cout << "epsilon' = " << rh.value << "\n";
+ std::cout << "nbL = " << landmarks_ind.size() << "\n";
+ print_statistics();
+ //print_vector(landmarks_ind); std::cout << std::endl;
+ //std::sort(landmarks_ind.begin(), landmarks_ind.end());
+ print_vector(landmarks_ind); std::cout << std::endl;
+ if (experiment3) thetamin_vector[thetamin_vector.size()-1] = sampling_fatness(t);
+ std::cout << "theta = " << sampling_fatness(t) << "\n";
+ //fill_landmarks(W, landmarks, landmarks_ind, torus);
+ //fill_full_cell_vector(t, full_cells);
+ /*
+ if (triangulation_is_protected(t, delta))
+ std::cout << "Triangulation is ok\n";
+ else
+ {
+ std::cout << "Triangulation is BAD!! T_T しくしく!\n";
+ }
+ */
+ write_delaunay_mesh(t, W[0], true);
+ //std::cout << t << std::endl;
+}
+
+void run_experiment5(Point_Vector& W,
+ int D,
+ FT alpha,
+ FT epsilon,
+ FT delta0,
+ FT theta0,
+ FT gamma0,
+ //std::vector<std::vector<int>>& full_cells,
+ bool torus,
+ bool power_protection
+ )
+{
+ // INITIALIZATION
+ Delaunay_triangulation t(D);
+ std::vector<int> landmarks_ind;
+ int landmark_count = 0;
+ initialize_statistics();
+ if (D == 2)
+ {
+ int xw = 6, yw = 4;
+ // Triangular lattice close to regular triangles h=0.866a ~ 0.875a : 48p
+ for (int i = 0; i < xw; ++i)
+ for (int j = 0; j < yw; ++j)
+ {
+ Point_d cite1(std::vector<FT>{2.0/xw*i, 2.0/yw*j});
+ W.push_back(cite1); // debug purpose
+ insert_delaunay_landmark_with_copies(W, W.size()-1,
+ landmarks_ind, t, landmark_count, true);
+
+ Point_d cite2(std::vector<FT>{2.0/xw*(i+0.5), 2.0/yw*(j+0.5)});
+ W.push_back(cite2); // debug purpose
+ insert_delaunay_landmark_with_copies(W, W.size()-1,
+ landmarks_ind, t, landmark_count, true);
+ }
+ }
+ else if (D == 3)
+ {
+ int wd = 3;
+ // Body-centered cubic lattice : 54p
+ for (int i = 0; i < wd; ++i)
+ for (int j = 0; j < wd; ++j)
+ for (int k = 0; k < wd; ++k)
+ {
+ Point_d cite1(std::vector<FT>{2.0/wd*i, 2.0/wd*j, 2.0/wd*k});
+ W.push_back(cite1); // debug purpose
+ insert_delaunay_landmark_with_copies(W, W.size()-1,
+ landmarks_ind, t, landmark_count, true);
+
+ Point_d cite2(std::vector<FT>{2.0/wd*(i+0.5), 2.0/wd*(j+0.5), 2.0/wd*(k+0.5)});
+ W.push_back(cite2); // debug purpose
+ insert_delaunay_landmark_with_copies(W, W.size()-1,
+ landmarks_ind, t, landmark_count, true);
+ }
+ }
+
+ // ITERATIONS
+ R_max_handle rh = sampling_radius(t);
+ Point_d rp = *(Random_point_iterator(D, alpha*rh.value));
+ int death_count = 0;
+ std::cout << "death count " << death_count << " rp = " << rp << "\n";
+ while (death_count < 100)
+ {
+ std::vector<FT> coords;
+ for (auto c_it = rh.center.cartesian_begin(),
+ r_it = rp.cartesian_begin();
+ c_it != rh.center.cartesian_end();
+ ++c_it, ++r_it)
+ coords.push_back(*c_it + *r_it);
+ Point_d new_p(coords);
+ if (!is_violating_protection(new_p, t, D, delta0, power_protection, theta0, gamma0))
+ {
+ W.push_back(new_p);
+ insert_delaunay_landmark_with_copies(W, W.size()-1, landmarks_ind, t, landmark_count, torus);
+ rh = sampling_radius(t);
+ rp = *(Random_point_iterator(D, alpha*rh.value));
+ death_count = 0;
+ std::cout << "death count " << death_count << " rp = " << rp << "\n";
+ }
+ else
+ {
+ rp = *(Random_point_iterator(D, alpha*rh.value));
+ death_count++;
+ std::cout << "death count " << death_count << " rp = " << rp << "\n";
+ }
+ //Point_d new_p = (*rp++) + Vector_d;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Series of experiments
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void start_experiments(Point_Vector& W, FT alpha, std::vector<int>& landmarks_ind, FT epsilon)
+{
+ int experiment_no = 1;
+ FT delta0 = 0.1;
+ FT theta0 = 0.1;
+ FT gamma0 = 0.01;
+ std::string suffix;
+ //std::cout << "ようこそジプシー我が神秘の部屋へ:\n";
+ while (experiment_no != 0)
+ {
+ std::cout << "Enter experiment no (0 to exit): ";
+ std::cin >> experiment_no;
+ switch (experiment_no)
+ {
+ case 1:
+ // Experiment 1
+ experiment1 = true;
+ eps_vector = {};
+ std::cout << "Enter delta0: "; std::cin >> delta0;
+ std::cout << "Enter theta0: "; std::cin >> theta0;
+ std::cout << "Enter gamma0: "; std::cin >> gamma0;
+ protected_delaunay(W, landmarks_ind, alpha, epsilon, delta0, theta0, gamma0, true, true);
+ write_tikz_plot(eps_vector,"epstime.tikz");
+ experiment1 = false;
+ break;
+
+ case 2:
+ // Experiment 2
+ suffix = "";
+ experiment2 = true;
+ epsratio_vector = {0};
+ epsslope_vector = {0};
+ std::cout << "File name suffix: ";
+ std::cin >> suffix;
+ for (FT alpha = 0.01; alpha < 0.999; alpha += 0.01)
+ {
+ landmarks_ind.clear();
+ std::cout << "Test for alpha = " << alpha << "\n";
+ protected_delaunay(W, landmarks_ind, alpha, epsilon, delta0, theta0, gamma0, true, true);
+ }
+ write_tikz_plot(epsratio_vector,"epsratio_alpha." + suffix + ".tex");
+ write_tikz_plot(epsslope_vector,"epsslope_alpha." + suffix + ".tex");
+ experiment2 = false;
+ break;
+
+ case 3:
+ // Experiment 3
+ experiment3 = true;
+ thetamin_vector = {};
+ gammamin_vector = {};
+ theta0 = 0;
+ gamma0 = 0;
+ for (FT delta0 = 0; delta0 < 0.999; delta0 += 0.05)
+ {
+ landmarks_ind.clear();
+ thetamin_vector.push_back(1.0); //0.7489 fatness of the initialization
+ gammamin_vector.push_back(10);
+ std::cout << "Test for delta0 = " << delta0 << "\n";
+ protected_delaunay(W, landmarks_ind, alpha, epsilon, delta0, theta0, gamma0, true, true);
+ }
+ write_tikz_plot(thetamin_vector,"thetamin_delta.tex");
+ write_tikz_plot(gammamin_vector,"gammamin_delta.tex");
+ experiment3 = false;
+ break;
+
+ // case 4:
+ // // Experiment 4
+ // {
+ // int dim;
+ // std::cout << "Enter dimension: ";
+ // std::cin >> dim;
+ // Delaunay_triangulation t(dim);
+ // // for (FT eps = 0.7; eps < 1.1; eps += 0.1)
+ // // {
+ // // generate_epsilon_sample_torus(W, eps, dim, t);
+ // // for (auto v_it = t.vertices_begin(); v_it != t.vertices_end(); ++v_it)
+ // // {
+ // // if (t.is_infinite(v_it))
+ // // continue;
+ // // bool in_cube = true;
+ // // for (auto xi = v_it->cartesian_begin(); xi != v_it->cartesian_end(); ++xi)
+ // // if (*xi > 1.0 || *xi < -1.0)
+ // // {
+ // // in_cube = false; break;
+ // // }
+ // // if (!in_cube)
+ // // continue;
+ // // for (auto t.tds().incident_full_cells())
+ // // }
+ // // std::cout << "eps = " << eps << ", real epsilon = " << sampling_radius(t).value << "\n";
+ // // }
+ // // }
+ // break;
+
+
+ case 5:
+ // Experiment 5
+ experiment5 = true;
+ // std::cout << "Enter dimension: ";
+ // std::cin >> dim;
+
+ landmarks_ind.clear();
+ W.clear();
+ run_experiment5(W, alpha, epsilon, delta0, theta0, gamma0, true, true);
+ experiment5 = false;
+ break;
+ }
+
+ }
+
+}
+
+#endif
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/simple_witness_complex.cpp b/src/Witness_complex/example/simple_witness_complex.cpp
new file mode 100644
index 00000000..43921c4e
--- /dev/null
+++ b/src/Witness_complex/example/simple_witness_complex.cpp
@@ -0,0 +1,54 @@
+/* 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): Vincent Rouvreau
+ *
+ * Copyright (C) 2014 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 <ctime>
+//#include "gudhi/graph_simplicial_complex.h"
+#include "gudhi/Witness_complex.h"
+
+using namespace Gudhi;
+
+typedef std::vector< Vertex_handle > typeVectorVertex;
+//typedef std::pair<typeVectorVertex, Filtration_value> typeSimplex;
+//typedef std::pair< Simplex_tree<>::Simplex_handle, bool > typePairSimplexBool;
+
+int main (int argc, char * const argv[])
+{
+ Witness_complex<> witnessComplex = Witness_complex<>();
+ std::vector< typeVectorVertex > KNN;
+ typeVectorVertex witness0 = {1,0,5,2,6,3,4}; KNN.push_back(witness0 );
+ typeVectorVertex witness1 = {2,6,4,5,0,1,3}; KNN.push_back(witness1 );
+ typeVectorVertex witness2 = {3,4,2,1,5,6,0}; KNN.push_back(witness2 );
+ typeVectorVertex witness3 = {4,2,1,3,5,6,0}; KNN.push_back(witness3 );
+ typeVectorVertex witness4 = {5,1,6,0,2,3,4}; KNN.push_back(witness4 );
+ typeVectorVertex witness5 = {6,0,5,2,1,3,4}; KNN.push_back(witness5 );
+ typeVectorVertex witness6 = {0,5,6,1,2,3,4}; KNN.push_back(witness6 );
+ typeVectorVertex witness7 = {2,6,4,5,3,1,0}; KNN.push_back(witness7 );
+ typeVectorVertex witness8 = {1,2,5,4,3,6,0}; KNN.push_back(witness8 );
+ typeVectorVertex witness9 = {3,4,0,6,5,1,2}; KNN.push_back(witness9 );
+ typeVectorVertex witness10 = {5,0,1,3,6,2,4}; KNN.push_back(witness10);
+ typeVectorVertex witness11 = {5,6,1,0,2,3,4}; KNN.push_back(witness11);
+ typeVectorVertex witness12 = {1,6,0,5,2,3,4}; KNN.push_back(witness12);
+ std::cout << "Let the carnage begin!\n";
+ witnessComplex.witness_complex(KNN);
+ std::cout << "Howdy world!\n";
+}
diff --git a/src/Witness_complex/example/witness_complex_cube.cpp b/src/Witness_complex/example/witness_complex_cube.cpp
new file mode 100644
index 00000000..e448c55d
--- /dev/null
+++ b/src/Witness_complex/example/witness_complex_cube.cpp
@@ -0,0 +1,590 @@
+/* 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/>.
+ */
+
+// Avoiding the max arity issue with CGAL
+#ifndef BOOST_PARAMETER_MAX_ARITY
+# define BOOST_PARAMETER_MAX_ARITY 12
+#endif
+
+#include <iostream>
+#include <fstream>
+#include <ctime>
+#include <utility>
+#include <algorithm>
+#include <set>
+#include <iterator>
+#include <chrono>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+//#include <stdlib.h>
+
+//#include "gudhi/graph_simplicial_complex.h"
+#include "gudhi/Witness_complex.h"
+#include "gudhi/reader_utils.h"
+#include "Torus_distance.h"
+#include "generators.h"
+#include "output.h"
+//#include "protected_sets/protected_sets.h"
+#include "protected_sets/protected_sets_paper2.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_k_neighbor_search.h>
+#include <CGAL/Kd_tree.h>
+#include <CGAL/Euclidean_distance.h>
+#include <CGAL/Kernel_d/Sphere_d.h>
+#include <CGAL/Kernel_d/Hyperplane_d.h>
+#include <CGAL/enum.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 <CGAL/Timer.h>
+#include <CGAL/Delaunay_triangulation.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::Point_d Point_d;
+typedef K::Vector_d Vector_d;
+typedef K::Oriented_side_d Oriented_side_d;
+typedef K::Has_on_positive_side_d Has_on_positive_side_d;
+
+//typedef CGAL::Point_d<K> Point_d;
+typedef K::FT FT;
+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_k_neighbor_search<STraits, CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance>> K_neighbor_search;
+typedef K_neighbor_search::Tree Tree;
+typedef K_neighbor_search::Distance Distance;
+typedef K_neighbor_search::iterator KNS_iterator;
+typedef K_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<CGAL::Point_d<CGAL::Cartesian_d<FT> > > Random_cube_iterator;
+
+typedef CGAL::Delaunay_triangulation<K> Delaunay_triangulation;
+typedef Delaunay_triangulation::Facet Facet;
+typedef Delaunay_triangulation::Vertex_handle Delaunay_vertex;
+typedef Delaunay_triangulation::Full_cell_handle Full_cell_handle;
+//typedef CGAL::Sphere_d<K> Sphere_d;
+typedef K::Sphere_d Sphere_d;
+typedef K::Hyperplane_d Hyperplane_d;
+
+/*//////////////////////////////////////
+ * GLOBAL VARIABLES ********************
+ *//////////////////////////////////////
+
+//NA bool toric=false;
+bool power_protection = true;
+bool grid_points = true;
+bool is2d = true;
+//FT _sfty = pow(10,-14);
+bool torus = false;
+
+
+bool triangulation_is_protected(Delaunay_triangulation& t, FT delta)
+{
+ std::cout << "Start protection verification\n";
+ Euclidean_distance ed;
+ // Fill the map Vertices -> Numbers
+ std::map<Delaunay_triangulation::Vertex_handle, int> index_of_vertex;
+ int ind = 0;
+ for (auto v_it = t.vertices_begin(); v_it != t.vertices_end(); ++v_it)
+ {
+ if (t.is_infinite(v_it))
+ continue;
+ index_of_vertex[v_it] = ind++;
+ }
+ for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
+ if (!t.is_infinite(fc_it))
+ {
+ std::vector<Point_d> vertices;
+ for (auto fc_v_it = fc_it->vertices_begin(); fc_v_it != fc_it->vertices_end(); ++fc_v_it)
+ vertices.push_back((*fc_v_it)->point());
+ Sphere_d cs( vertices.begin(), vertices.end());
+ Point_d center_cs = cs.center();
+ FT r = sqrt(ed.transformed_distance(center_cs, fc_it->vertex(0)->point()));
+ for (auto v_it = t.vertices_begin(); v_it != t.vertices_end(); ++v_it)
+ if (!t.is_infinite(v_it))
+ //check if vertex belongs to the face
+ if (!vertex_is_in_full_cell(v_it, fc_it))
+ {
+ FT dist2 = ed.transformed_distance(center_cs, v_it->point());
+ //if the new point is inside the protection ball of a non conflicting simplex
+ //std::cout << "Dist^2 = " << dist2 << " (r+delta)*(r+delta) = " << (r+delta)*(r+delta) << " r^2 = " << r*r <<"\n";
+ if (!power_protection)
+ if (dist2 <= (r+delta)*(r+delta) && dist2 >= r*r)
+ {
+ write_delaunay_mesh(t, v_it->point(), is2d);
+ // Output the problems
+ std::cout << "Problematic vertex " << index_of_vertex[v_it] << " ";
+ std::cout << "Problematic cell ";
+ for (auto vh_it = fc_it->vertices_begin(); vh_it != fc_it->vertices_end(); ++vh_it)
+ if (!t.is_infinite(*vh_it))
+ std::cout << index_of_vertex[*vh_it] << " ";
+ std::cout << "\n";
+ std::cout << "r^2 = " << r*r << ", d^2 = " << dist2 << ", (r+delta)^2 = " << (r+delta)*(r+delta) << "\n";
+ return false;
+ }
+ if (power_protection)
+ if (dist2 <= r*r+delta*delta && dist2 >= r*r)
+ {
+ write_delaunay_mesh(t, v_it->point(), is2d);
+ std::cout << "Problematic vertex " << *v_it << " ";
+ std::cout << "Problematic cell " << *fc_it << "\n";
+ std::cout << "r^2 = " << r*r << ", d^2 = " << dist2 << ", r^2+delta^2 = " << r*r+delta*delta << "\n";
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+// SAMPLING RADIUS
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+FT sampling_radius(Delaunay_triangulation& t, FT epsilon0)
+{
+ FT epsilon2 = 0;
+ Point_d control_point;
+ for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
+ {
+ if (t.is_infinite(fc_it))
+ continue;
+ Point_Vector vertices;
+ for (auto fc_v_it = fc_it->vertices_begin(); fc_v_it != fc_it->vertices_end(); ++fc_v_it)
+ vertices.push_back((*fc_v_it)->point());
+ Sphere_d cs( vertices.begin(), vertices.end());
+ Point_d csc = cs.center();
+ bool in_cube = true;
+ for (auto xi = csc.cartesian_begin(); xi != csc.cartesian_end(); ++xi)
+ if (*xi > 1.0 || *xi < -1.0)
+ {
+ in_cube = false; break;
+ }
+ if (!in_cube)
+ continue;
+ FT r2 = Euclidean_distance().transformed_distance(cs.center(), *(vertices.begin()));
+ if (epsilon2 < r2)
+ {
+ epsilon2 = r2;
+ control_point = (*vertices.begin());
+ }
+ }
+ if (epsilon2 < epsilon0*epsilon0)
+ {
+ std::cout << "ACHTUNG! E' < E\n";
+ std::cout << "eps = " << epsilon0 << " eps' = " << sqrt(epsilon2) << "\n";
+ write_delaunay_mesh(t, control_point, is2d);
+ }
+ return sqrt(epsilon2);
+}
+
+FT point_sampling_radius_by_delaunay(Point_Vector& points, FT epsilon0)
+{
+ Delaunay_triangulation t(points[0].size());
+ t.insert(points.begin(), points.end());
+ return sampling_radius(t, epsilon0);
+}
+
+// A little script to make a tikz histogram of epsilon distribution
+// Returns the average epsilon
+FT epsilon_histogram(Delaunay_triangulation& t, int n)
+{
+ FT epsilon_max = 0; //sampling_radius(t,0);
+ FT sum_epsilon = 0;
+ int count_simplices = 0;
+ std::vector<int> histo(n+1, 0);
+ for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
+ {
+ if (t.is_infinite(fc_it))
+ continue;
+ Point_Vector vertices;
+ for (auto fc_v_it = fc_it->vertices_begin(); fc_v_it != fc_it->vertices_end(); ++fc_v_it)
+ vertices.push_back((*fc_v_it)->point());
+ Sphere_d cs( vertices.begin(), vertices.end());
+ Point_d csc = cs.center();
+ bool in_cube = true;
+ for (auto xi = csc.cartesian_begin(); xi != csc.cartesian_end(); ++xi)
+ if (*xi > 1.0 || *xi < -1.0)
+ {
+ in_cube = false; break;
+ }
+ if (!in_cube)
+ continue;
+ FT r = sqrt(Euclidean_distance().transformed_distance(cs.center(), *(vertices.begin())));
+ if (r > epsilon_max)
+ epsilon_max = r;
+ sum_epsilon += r;
+ count_simplices++;
+ histo[floor(r/epsilon_max*n)]++;
+ }
+ std::ofstream ofs ("histogram.tikz", std::ofstream::out);
+ FT barwidth = 20.0/n;
+ int 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 < 2)
+ max_histo = 0.2*ten_power;
+ 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;
+
+ 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) {$\\epsilon$};\n" <<
+ "\\node at (22,-1) {$\\epsilon/\\epsilon_{max}$};\n" <<
+ "\\node at (-0.5,-0.5) {0};\n" <<
+ "\\node at (-0.5,10) {" << max_histo << "};\n" <<
+ "\\node at (20,-0.5) {1};\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";
+
+ ofs.close();
+
+ //return sum_epsilon/count_simplices;
+ return epsilon_max;
+}
+
+FT epsilon_histogram_by_delaunay(Point_Vector& points, int n)
+{
+ Delaunay_triangulation t(points[0].size());
+ t.insert(points.begin(), points.end());
+ return epsilon_histogram(t, n);
+}
+
+
+int landmark_perturbation(Point_Vector &W, int nbL, Point_Vector& landmarks, std::vector<int>& landmarks_ind, std::vector<std::vector<int>>& full_cells)
+{
+ //******************** Preface: origin point
+ int D = W[0].size();
+ std::vector<FT> orig_vector;
+ for (int i=0; i<D; i++)
+ orig_vector.push_back(0);
+ Point_d origin(orig_vector);
+
+ //******************** Constructing a WL matrix
+ int nbP = W.size();
+ Euclidean_distance ed;
+ FT lambda = ed.transformed_distance(landmarks[0],landmarks[1]);
+ std::vector<Point_d> landmarks_ext;
+ int nb_cells = 1;
+ for (int i = 0; i < D; ++i)
+ nb_cells *= 3;
+ for (int i = 0; i < nb_cells; ++i)
+ for (int k = 0; k < nbL; ++k)
+ {
+ std::vector<double> point;
+ int cell_i = i;
+ for (int l = 0; l < D; ++l)
+ {
+ point.push_back(landmarks[k][l] + 2.0*((cell_i%3)-1.0));
+ cell_i /= 3;
+ }
+ landmarks_ext.push_back(point);
+ }
+ write_points("landmarks/initial_landmarks",landmarks_ext);
+ STraits traits(&(landmarks_ext[0]));
+ std::vector< std::vector <int> > WL(nbP);
+
+ //********************** Neighbor search in a Kd tree
+ Tree L(boost::counting_iterator<std::ptrdiff_t>(0),
+ boost::counting_iterator<std::ptrdiff_t>(nb_cells*nbL),
+ typename Tree::Splitter(),
+ traits);
+ std::cout << "Enter (D+1) nearest landmarks\n";
+ for (int i = 0; i < nbP; i++)
+ {
+ Point_d& w = W[i];
+ ////Search D+1 nearest neighbours from the tree of landmarks L
+ K_neighbor_search search(L, w, D+1, FT(0), true,
+ CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance>(&(landmarks_ext[0])) );
+ for(K_neighbor_search::iterator it = search.begin(); it != search.end(); ++it)
+ {
+ if (std::find(WL[i].begin(), WL[i].end(), (it->first)%nbL) == WL[i].end())
+ WL[i].push_back((it->first)%nbL);
+ }
+ if (i == landmarks_ind[WL[i][0]])
+ {
+ FT dist = ed.transformed_distance(W[i], landmarks[WL[i][1]]);
+ if (dist < lambda)
+ lambda = dist;
+ }
+ }
+ std::string out_file = "wl_result";
+ //write_wl(out_file,WL);
+
+ //******************** Constructng a witness complex
+ std::cout << "Entered witness complex construction\n";
+ Witness_complex<> witnessComplex;
+ witnessComplex.setNbL(nbL);
+ witnessComplex.witness_complex(WL);
+
+ //******************** Verifying if all full cells are in the complex
+
+ int in=0, not_in=0;
+ for (auto cell : full_cells)
+ {
+ //print_vector(cell);
+ if (witnessComplex.find(cell) != witnessComplex.null_simplex())
+ in++;
+ else
+ not_in++;
+ }
+ std::cout << "Out of all the cells in Delaunay triangulation:\n" << in << " are in the witness complex\n" <<
+ not_in << " are not.\n";
+
+ //******************** Making a set of bad link landmarks
+
+ std::cout << "Entered bad links\n";
+ std::set< int > perturbL;
+ int count_badlinks = 0;
+ //std::cout << "Bad links around ";
+ std::vector< int > count_bad(D);
+ std::vector< int > count_good(D);
+ for (auto u: witnessComplex.complex_vertex_range())
+ {
+ if (!witnessComplex.has_good_link(u, count_bad, count_good))
+ {
+ count_badlinks++;
+ Point_d& l = landmarks[u];
+ Fuzzy_sphere fs(l, sqrt(lambda)*3, 0, traits);
+ std::vector<int> curr_perturb;
+ L.search(std::insert_iterator<std::vector<int>>(curr_perturb,curr_perturb.begin()),fs);
+ for (int i: curr_perturb)
+ perturbL.insert(i%nbL);
+ }
+ }
+ for (unsigned int i = 0; i != count_good.size(); i++)
+ if (count_good[i] != 0)
+ std::cout << "count_good[" << i << "] = " << count_good[i] << std::endl;
+ for (unsigned int i = 0; i != count_bad.size(); i++)
+ if (count_bad[i] != 0)
+ std::cout << "count_bad[" << i << "] = " << count_bad[i] << std::endl;
+ std::cout << "\nBad links total: " << count_badlinks << " Points to perturb: " << perturbL.size() << std::endl;
+
+ //*********************** Perturb bad link landmarks
+ /*
+ for (auto u: perturbL)
+ {
+ Random_point_iterator rp(D,sqrt(lambda)/8);
+ std::vector<FT> point;
+ for (int i = 0; i < D; i++)
+ {
+ while (K().squared_distance_d_object()(*rp,origin) < lambda/256)
+ rp++;
+ FT coord = landmarks[u][i] + (*rp)[i];
+ if (coord > 1)
+ point.push_back(coord-1);
+ else if (coord < -1)
+ point.push_back(coord+1);
+ else
+ point.push_back(coord);
+ }
+ landmarks[u] = Point_d(point);
+ }
+ std::cout << "lambda=" << lambda << std::endl;
+ */
+ 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);
+ /*
+ return count_badlinks;
+ */
+ return 0;
+}
+
+int main (int argc, char * const argv[])
+{
+ power_protection = true;//false;
+ grid_points = false;//true;
+ torus = true;
+
+ if (argc != 4)
+ {
+ std::cerr << "Usage: " << argv[0]
+ << " nbP dim delta\n";
+ return 0;
+ }
+ int nbP = atoi(argv[1]);
+ int dim = atoi(argv[2]);
+ double theta0 = atof(argv[3]);
+ //double delta = atof(argv[3]);
+
+ is2d = (dim == 2);
+
+ std::cout << "Let the carnage begin!\n";
+ Point_Vector point_vector;
+ if (grid_points)
+ {
+ generate_points_grid(point_vector, (int)pow(nbP, 1.0/dim), dim, torus);
+ nbP = (int)pow((int)pow(nbP, 1.0/dim), dim);
+ }
+ else
+ generate_points_random_box(point_vector, nbP, dim);
+ FT epsilon = point_sampling_radius_by_delaunay(point_vector, 0);
+ //FT epsilon = epsilon_histogram_by_delaunay(point_vector,50);
+ std::cout << "Initial epsilon = " << epsilon << std::endl;
+ Point_Vector L;
+ std::vector<int> chosen_landmarks;
+ //write_points("landmarks/initial_pointset",point_vector);
+ //write_points("landmarks/initial_landmarks",L);
+ CGAL::Timer timer;
+
+ int n = 1;
+ std::vector<FT> values(n,0);
+ std::vector<FT> time(n,0);
+
+ //FT step = 0.001;
+ //FT delta = 0.01*epsilon;
+ //FT alpha = 0.5;
+ //FT step = atof(argv[3]);
+
+ start_experiments(point_vector, theta0, chosen_landmarks, epsilon);
+
+ // for (int i = 0; i < n; i++)
+ // //for (int i = 0; bl > 0; i++)
+ // {
+ // //std::cout << "========== Start iteration " << i << "== curr_min(" << curr_min << ")========\n";
+ // //double delta = pow(10, -(1.0*i)/2);
+ // //delta = step*i*epsilon;
+ // //theta0 = step*i;
+ // std::cout << "delta/epsilon = " << delta/epsilon << std::endl;
+ // std::cout << "theta0 = " << theta0 << std::endl;
+ // // Averaging the result
+ // int sum_values = 0;
+ // int nb_iterations = 1;
+ // std::vector<std::vector<int>> full_cells;
+ // for (int i = 0; i < nb_iterations; ++i)
+ // {
+ // //L = {};
+ // chosen_landmarks = {};
+ // //full_cells = {};
+ // //timer.start();
+ // //protected_delaunay(point_vector, nbP, L, chosen_landmarks, delta, epsilon, alpha, theta0, full_cells, torus, power_protection);
+ // protected_delaunay(point_vector, chosen_landmarks, delta, epsilon, alpha, theta0, torus, power_protection);
+ // //timer.stop();
+ // sum_values += chosen_landmarks.size();
+ // }
+ // //FT epsilon2 = point_sampling_radius_by_delaunay(L, epsilon);
+ // //std::cout << "Final epsilon = " << epsilon2 << ". Ratio = " << epsilon2/epsilon << std::endl;
+ // //write_points("landmarks/initial_landmarks",L);
+ // //std::cout << "delta/epsilon' = " << delta/epsilon2 << std::endl;
+ // FT nbL = (sum_values*1.0)/nb_iterations;
+ // //values[i] = pow((1.0*nbL)/nbP, -1.0/dim);
+ // values[i] = (1.0*nbL)/nbP;
+ // std::cout << "Number of landmarks = " << nbL << ", time= " << timer.time() << "s"<< std::endl;
+ // //landmark_perturbation(point_vector, nbL, L, chosen_landmarks, full_cells);
+ // time[i] = timer.time();
+ // timer.reset();
+ // //write_points("landmarks/landmarks0",L);
+ // }
+
+ // // OUTPUT A PLOT
+ // FT hstep = 20.0/(n-1);
+ // FT wstep = 10.0;
+
+ // std::ofstream ofs("N'Nplot.tikz", std::ofstream::out);
+ // ofs << "\\draw[red] (0," << wstep*values[0] << ")";
+ // for (int i = 1; i < n; ++i)
+ // ofs << " -- (" << hstep*i << "," << wstep*values[i] << ")";
+ // ofs << ";\n";
+ // ofs.close();
+ /*
+ wstep = 0.1;
+ ofs = std::ofstream("time.tikz", std::ofstream::out);
+ ofs << "\\draw[red] (0," << wstep*time[0] << ")";
+ for (int i = 1; i < n; ++i)
+ ofs << " -- (" << hstep*i << "," << wstep*time[i] << ")";
+ ofs << ";\n";
+ ofs.close();
+
+
+ std::vector<std::vector<int>> full_cells;
+ timer.start();
+ landmark_choice_protected_delaunay(point_vector, nbP, L, chosen_landmarks, delta, full_cells);
+ timer.stop();
+ FT epsilon2 = point_sampling_radius_by_delaunay(L);
+ std::cout << "Final epsilon = " << epsilon2 << ". Ratio = " << epsilon/epsilon2 << std::endl;
+ write_points("landmarks/initial_landmarks",L);
+ int nbL = chosen_landmarks.size();
+ std::cout << "Number of landmarks = " << nbL << ", time= " << timer.time() << "s"<< std::endl;
+ //landmark_perturbation(point_vector, nbL, L, chosen_landmarks, full_cells);
+ timer.reset();
+ */
+}
diff --git a/src/Witness_complex/example/witness_complex_cubic_systems.cpp b/src/Witness_complex/example/witness_complex_cubic_systems.cpp
new file mode 100644
index 00000000..2f4ee1cb
--- /dev/null
+++ b/src/Witness_complex/example/witness_complex_cubic_systems.cpp
@@ -0,0 +1,547 @@
+/* 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 <iterator>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+//#include "gudhi/graph_simplicial_complex.h"
+#include "gudhi/Witness_complex.h"
+#include "gudhi/reader_utils.h"
+#include "Torus_distance.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_k_neighbor_search.h>
+#include <CGAL/Kd_tree.h>
+#include <CGAL/Euclidean_distance.h>
+#include <CGAL/Kernel_d/Sphere_d.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 <CGAL/Delaunay_triangulation.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::Point_d Point_d;
+//typedef CGAL::Cartesian_d<double> K;
+//typedef CGAL::Point_d<K> Point_d;
+typedef K::FT FT;
+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_k_neighbor_search<STraits, CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance>> K_neighbor_search;
+typedef K_neighbor_search::Tree Tree;
+typedef K_neighbor_search::Distance Distance;
+typedef K_neighbor_search::iterator KNS_iterator;
+typedef K_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<CGAL::Point_d<CGAL::Cartesian_d<FT> > > Random_cube_iterator;
+typedef CGAL::Random_points_in_cube_d<Point_d> Random_cube_iterator;
+typedef CGAL::Random_points_in_ball_d<Point_d> Random_point_iterator;
+
+typedef CGAL::Delaunay_triangulation<K> Delaunay_triangulation;
+typedef Delaunay_triangulation::Facet Facet;
+typedef CGAL::Sphere_d<K> Sphere_d;
+
+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_random_box(Point_Vector& W, int nbP, int dim)
+{
+ /*
+ Random_cube_iterator rp(dim, 1);
+ for (int i = 0; i < nbP; i++)
+ {
+ std::vector<double> point;
+ for (auto it = rp->cartesian_begin(); it != rp->cartesian_end(); ++it)
+ point.push_back(*it);
+ W.push_back(Point_d(point));
+ rp++;
+ }
+ */
+ Random_cube_iterator rp(dim, 1.0);
+ 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_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();
+}
+
+void write_edges(std::string file_name, Witness_complex<>& 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())
+ {
+ 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";
+ int chosen_landmark;
+ 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::count(landmarks_ind.begin(),landmarks_ind.end(),chosen_landmark)!=0);
+ //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 aux_fill_grid(Point_Vector& W, int& width, Point_Vector& landmarks, std::vector<int>& landmarks_ind, std::vector<bool> & curr_pattern)
+{
+ int D = W[0].size();
+ int nb_points = 1;
+ for (int i = 0; i < D; ++i)
+ nb_points *= width;
+ for (int i = 0; i < nb_points; ++i)
+ {
+ std::vector<double> point;
+ int cell_i = i;
+ for (int l = 0; l < D; ++l)
+ {
+ if (curr_pattern[l])
+ point.push_back(-1.0+(2.0/width)*(cell_i%width)+(1.0/width));
+ else
+ point.push_back(-1.0+(2.0/width)*(cell_i%width));
+ cell_i /= width;
+ }
+ landmarks.push_back(Point_d(point));
+ landmarks_ind.push_back(0);//landmarks_ind.push_back(W.size());
+ //std::cout << "Added point " << W.size() << std::endl;;
+ //W.push_back(Point_d(point));
+ }
+}
+
+void aux_put_halves(Point_Vector& W, int& width, Point_Vector& landmarks, std::vector<int>& landmarks_ind, std::vector<bool>& curr_pattern, std::vector<bool>::iterator curr_pattern_it, std::vector<bool>::iterator bool_it, std::vector<bool>::iterator bool_end)
+{
+ if (curr_pattern_it != curr_pattern.end())
+ {
+ if (bool_it != bool_end)
+ {
+ *curr_pattern_it = false;
+ aux_put_halves(W, width, landmarks, landmarks_ind, curr_pattern, curr_pattern_it+1, bool_it, bool_end);
+ *curr_pattern_it = true;
+ aux_put_halves(W, width, landmarks, landmarks_ind, curr_pattern, curr_pattern_it+1, bool_it+1, bool_end);
+ }
+ }
+ else
+ if (*bool_it)
+ {
+ std::cout << "Filling the pattern ";
+ for (bool b: curr_pattern)
+ if (b) std::cout << '1';
+ else std::cout << '0';
+ std::cout << "\n";
+ aux_fill_grid(W, width, landmarks, landmarks_ind, curr_pattern);
+ }
+}
+
+void landmark_choice_cs(Point_Vector& W, int width, Point_Vector& landmarks, std::vector<int>& landmarks_ind, std::vector<bool>& face_centers)
+{
+ std::cout << "Enter landmark choice to kd tree\n";
+ //int chosen_landmark;
+ CGAL::Random rand;
+ //To speed things up check the last true in the code and put it as the finishing condition
+ unsigned last_true = face_centers.size()-1;
+ while (!face_centers[last_true] && last_true != 0)
+ last_true--;
+ //Recursive procedure to understand where we put +1/2 in centers' coordinates
+ std::vector<bool> curr_pattern(W[0].size(), false);
+ aux_put_halves(W, width, landmarks, landmarks_ind, curr_pattern, curr_pattern.begin(), face_centers.begin(), face_centers.begin()+(last_true+1));
+ std::cout << "The number of landmarks is: " << landmarks.size() << std::endl;
+
+ }
+
+int landmark_perturbation(Point_Vector &W, Point_Vector& landmarks, std::vector<int>& landmarks_ind)
+{
+ //******************** Preface: origin point
+ int D = W[0].size();
+ std::vector<FT> orig_vector;
+ for (int i=0; i<D; i++)
+ orig_vector.push_back(0);
+ Point_d origin(orig_vector);
+
+ //******************** Constructing a WL matrix
+ int nbP = W.size();
+ int nbL = landmarks.size();
+ Euclidean_distance ed;
+ FT lambda = ed.transformed_distance(landmarks[0],landmarks[1]);
+ std::vector<Point_d> landmarks_ext;
+ int nb_cells = 1;
+ for (int i = 0; i < D; ++i)
+ nb_cells *= 3;
+ for (int i = 0; i < nb_cells; ++i)
+ for (int k = 0; k < nbL; ++k)
+ {
+ std::vector<double> point;
+ int cell_i = i;
+ for (int l = 0; l < D; ++l)
+ {
+ point.push_back(landmarks[k][l] + 2.0*((cell_i%3)-1.0));
+ cell_i /= 3;
+ }
+ landmarks_ext.push_back(point);
+ }
+ write_points("landmarks/initial_landmarks",landmarks_ext);
+ STraits traits(&(landmarks_ext[0]));
+ std::vector< std::vector <int> > WL(nbP);
+
+ //********************** Neighbor search in a Kd tree
+ Tree L(boost::counting_iterator<std::ptrdiff_t>(0),
+ boost::counting_iterator<std::ptrdiff_t>(nb_cells*nbL),
+ typename Tree::Splitter(),
+ traits);
+ std::cout << "Enter (D+1) nearest landmarks\n";
+ for (int i = 0; i < nbP; i++)
+ {
+ Point_d& w = W[i];
+ ////Search D+1 nearest neighbours from the tree of landmarks L
+ K_neighbor_search search(L, w, D+1, FT(0), true,
+ CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance>(&(landmarks_ext[0])) );
+ for(K_neighbor_search::iterator it = search.begin(); it != search.end(); ++it)
+ {
+ if (std::find(WL[i].begin(), WL[i].end(), (it->first)%nbL) == WL[i].end())
+ WL[i].push_back((it->first)%nbL);
+ }
+ if (i == landmarks_ind[WL[i][0]])
+ {
+ FT dist = ed.transformed_distance(W[i], landmarks[WL[i][1]]);
+ if (dist < lambda)
+ lambda = dist;
+ }
+ }
+ std::string out_file = "wl_result";
+ write_wl(out_file,WL);
+
+ //******************** Constructng a witness complex
+ std::cout << "Entered witness complex construction\n";
+ Witness_complex<> witnessComplex;
+ witnessComplex.setNbL(nbL);
+ witnessComplex.witness_complex(WL);
+
+ //******************** Making a set of bad link landmarks
+ std::cout << "Entered bad links\n";
+ std::set< int > perturbL;
+ int count_badlinks = 0;
+ //std::cout << "Bad links around ";
+ std::vector< int > count_bad(D);
+ std::vector< int > count_good(D);
+ for (auto u: witnessComplex.complex_vertex_range())
+ {
+ if (!witnessComplex.has_good_link(u, count_bad, count_good, D))
+ {
+ count_badlinks++;
+ Point_d& l = landmarks[u];
+ Fuzzy_sphere fs(l, sqrt(lambda)*3, 0, traits);
+ std::vector<int> curr_perturb;
+ L.search(std::insert_iterator<std::vector<int>>(curr_perturb,curr_perturb.begin()),fs);
+ for (int i: curr_perturb)
+ perturbL.insert(i%nbL);
+ }
+ }
+ for (unsigned int i = 0; i != count_good.size(); i++)
+ if (count_good[i] != 0)
+ std::cout << "count_good[" << i << "] = " << count_good[i] << std::endl;
+ for (unsigned int i = 0; i != count_bad.size(); i++)
+ if (count_bad[i] != 0)
+ std::cout << "count_bad[" << i << "] = " << count_bad[i] << std::endl;
+ std::cout << "\nBad links total: " << count_badlinks << " Points to perturb: " << perturbL.size() << std::endl;
+
+ //*********************** Perturb bad link landmarks
+ for (auto u: perturbL)
+ {
+ Random_point_iterator rp(D,sqrt(lambda)/8);
+ std::vector<FT> point;
+ for (int i = 0; i < D; i++)
+ {
+ while (K().squared_distance_d_object()(*rp,origin) < lambda/256)
+ rp++;
+ FT coord = landmarks[u][i] + (*rp)[i];
+ if (coord > 1)
+ point.push_back(coord-1);
+ else if (coord < -1)
+ point.push_back(coord+1);
+ else
+ point.push_back(coord);
+ }
+ landmarks[u] = Point_d(point);
+ }
+ std::cout << "lambda=" << lambda << std::endl;
+ 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);
+ return count_badlinks;
+}
+
+void exaustive_search(Point_Vector& W, int width)
+{
+ int D = W[0].size()+1;
+ int nb_points = pow(2,D);
+ std::vector<bool> face_centers(D, false);
+ int bl = 0; //Bad links
+ std::vector<std::vector<bool>> good_patterns;
+ for (int i = 0; i < nb_points; ++i)
+ {
+ int cell_i = i;
+ for (int l = 0; l < D; ++l)
+ {
+ if (cell_i%2 == 0)
+ face_centers[l] = false;
+ else
+ face_centers[l] = true;
+ cell_i /= 2;
+ }
+ std::cout << "**Current pattern ";
+ for (bool b: face_centers)
+ if (b) std::cout << '1';
+ else std::cout << '0';
+ std::cout << "\n";
+ Point_Vector landmarks;
+ std::vector<int> landmarks_ind;
+ Point_Vector W_copy(W);
+ landmark_choice_cs(W_copy, width, landmarks, landmarks_ind, face_centers);
+ if (landmarks.size() != 0)
+ {
+ bl = landmark_perturbation(W_copy, landmarks, landmarks_ind);
+ if ((1.0*bl)/landmarks.size() < 0.5)
+ good_patterns.push_back(face_centers);
+ }
+ }
+ std::cout << "The following patterns worked: ";
+ for (std::vector<bool> pattern : good_patterns)
+ {
+ std::cout << "[";
+ for (bool b: pattern)
+ if (b) std::cout << '1';
+ else std::cout << '0';
+ std::cout << "] ";
+ }
+ std::cout << "\n";
+}
+
+int main (int argc, char * const argv[])
+{
+ unsigned nbP = atoi(argv[1]);
+ unsigned width = atoi(argv[2]);
+ unsigned dim = atoi(argv[3]);
+ std::string code = (std::string) argv[4];
+ bool e_option = false;
+ int c;
+ if (argc != 5)
+ {
+ std::cerr << "Usage: " << argv[0]
+ << "witness_complex_cubic_systems nbP width dim code || witness_complex_systems -e nbP width dim\n"
+ << "where nbP stands for the number of witnesses, width for the width of the grid, dim for dimension "
+ << "and code is a sequence of (dim+1) symbols 0 and 1 representing if we take the centers of k-dimensional faces of the cubic system depending if it is 0 or 1."
+ << "-e stands for the 'exaustive' option";
+ return 0;
+ }
+ while ((c = getopt (argc, argv, "e::")) != -1)
+ switch(c)
+ {
+ case 'e' :
+ e_option = true;
+ nbP = atoi(argv[2]);
+ width = atoi(argv[3]);
+ dim = atoi(argv[4]);
+ break;
+ default :
+ nbP = atoi(argv[1]);
+ width = atoi(argv[2]);
+ dim = atoi(argv[3]);
+ code = (std::string) argv[4];
+ }
+ Point_Vector point_vector;
+ generate_points_random_box(point_vector, nbP, dim);
+
+ // Exaustive search
+ if (e_option)
+ {
+ std::cout << "Start exaustive search!\n";
+ exaustive_search(point_vector, width);
+ return 0;
+ }
+ // Search with a specific cubic system
+ std::vector<bool> face_centers;
+ if (code.size() != dim+1)
+ {
+ std::cerr << "The code should contain (dim+1) symbols";
+ return 1;
+ }
+ for (char c: code)
+ if (c == '0')
+ face_centers.push_back(false);
+ else
+ face_centers.push_back(true);
+ std::cout << "Let the carnage begin!\n";
+ Point_Vector L;
+ std::vector<int> chosen_landmarks;
+
+ landmark_choice_cs(point_vector, width, L, chosen_landmarks, face_centers);
+
+ int nbL = width; //!!!!!!!!!!!!!
+ int bl = nbL, curr_min = bl;
+ write_points("landmarks/initial_pointset",point_vector);
+ //write_points("landmarks/initial_landmarks",L);
+ //for (int i = 0; i < 1; i++)
+ for (int i = 0; bl > 0; i++)
+ {
+ std::cout << "========== Start iteration " << i << "== curr_min(" << curr_min << ")========\n";
+ bl=landmark_perturbation(point_vector, L, chosen_landmarks);
+ if (bl < curr_min)
+ curr_min=bl;
+ write_points("landmarks/landmarks0",L);
+ }
+
+}
diff --git a/src/Witness_complex/example/witness_complex_epsilon.cpp b/src/Witness_complex/example/witness_complex_epsilon.cpp
new file mode 100644
index 00000000..7f8b985f
--- /dev/null
+++ b/src/Witness_complex/example/witness_complex_epsilon.cpp
@@ -0,0 +1,55 @@
+/* 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 <vector>
+
+#include <CGAL/Epick_d.h>
+#include <CGAL/enum.h>
+
+typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> K;
+typedef K::Point_d Point_d;
+typedef K::FT FT;
+typedef K::Hyperplane_d Hyperplane_d;
+typedef K::Has_on_positive_side_d Has_on_positive_side_d;
+
+int main ()
+{
+ std::vector<Point_d> vertices;
+ Point_d v1(std::vector<FT>({-1,1}));
+ Point_d v2(std::vector<FT>({1,-1}));
+ vertices.push_back(v1);
+ vertices.push_back(v2);
+ Point_d p(std::vector<FT>({-1,-1}));
+ Hyperplane_d hp(vertices.begin(), vertices.end());
+ //Hyperplane_d hp(vertices.begin(), vertices.end(), p, CGAL::ON_POSITIVE_SIDE);
+ if (Has_on_positive_side_d()(hp, p))
+ std::cout << "OK\n";
+ else
+ std::cout << "NOK\n";
+ CGAL::Oriented_side side_p = K::Oriented_side_d()(hp, p);
+ if (side_p == CGAL::ZERO)
+ std::cout << "Point (-1,-1) is on the line passing through (-1,1) and (1,-1)";
+ CGAL::Oriented_side side_v2 = K::Oriented_side_d()(hp, v2);
+ if (side_v2 != CGAL::ZERO)
+ std::cout << "Point (1,-1) is not on the line passing through (-1,1) and (1,-1)";
+}
diff --git a/src/Witness_complex/example/witness_complex_flat_torus.cpp b/src/Witness_complex/example/witness_complex_flat_torus.cpp
new file mode 100644
index 00000000..49383154
--- /dev/null
+++ b/src/Witness_complex/example/witness_complex_flat_torus.cpp
@@ -0,0 +1,851 @@
+/* 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 <iterator>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+//#include <stdlib.h>
+
+//#include "gudhi/graph_simplicial_complex.h"
+#include "gudhi/Witness_complex.h"
+#include "gudhi/reader_utils.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_k_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::Point_d Point_d;
+//typedef CGAL::Cartesian_d<double> K;
+//typedef CGAL::Point_d<K> Point_d;
+typedef K::FT FT;
+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;
+
+/**
+ * \brief Class of distance in a flat torus in dimension D
+ *
+ */
+//class Torus_distance : public Euclidean_distance {
+/*
+ class Torus_distance {
+
+public:
+ typedef K::FT FT;
+ typedef K::Point_d Point_d;
+ typedef Point_d Query_item;
+ typedef typename CGAL::Dynamic_dimension_tag D;
+
+ double box_length = 2;
+
+ FT transformed_distance(Query_item q, Point_d p) const
+ {
+ FT distance = FT(0);
+ FT coord = FT(0);
+ //std::cout << "Hello skitty!\n";
+ typename K::Construct_cartesian_const_iterator_d construct_it=Traits_base().construct_cartesian_const_iterator_d_object();
+ typename K::Cartesian_const_iterator_d qit = construct_it(q),
+ qe = construct_it(q,1), pit = construct_it(p);
+ for(; qit != qe; qit++, pit++)
+ {
+ coord = sqrt(((*qit)-(*pit))*((*qit)-(*pit)));
+ if (coord*coord <= (box_length-coord)*(box_length-coord))
+ distance += coord*coord;
+ else
+ distance += (box_length-coord)*(box_length-coord);
+ }
+ return distance;
+ }
+
+ FT min_distance_to_rectangle(const Query_item& q,
+ const CGAL::Kd_tree_rectangle<FT,D>& r) const {
+ FT distance = FT(0);
+ FT dist1, dist2;
+ typename K::Construct_cartesian_const_iterator_d construct_it=Traits_base().construct_cartesian_const_iterator_d_object();
+ typename K::Cartesian_const_iterator_d qit = construct_it(q),
+ qe = construct_it(q,1);
+ for(unsigned int i = 0;qit != qe; i++, qit++)
+ {
+ if((*qit) < r.min_coord(i))
+ {
+ dist1 = (r.min_coord(i)-(*qit));
+ dist2 = (box_length - r.max_coord(i)+(*qit));
+ if (dist1 < dist2)
+ distance += dist1*dist1;
+ else
+ distance += dist2*dist2;
+ }
+ else if ((*qit) > r.max_coord(i))
+ {
+ dist1 = (box_length - (*qit)+r.min_coord(i));
+ dist2 = ((*qit) - r.max_coord(i));
+ if (dist1 < dist2)
+ distance += dist1*dist1;
+ else
+ distance += dist2*dist2;
+ }
+ }
+ return distance;
+ }
+
+ FT min_distance_to_rectangle(const Query_item& q,
+ const CGAL::Kd_tree_rectangle<FT,D>& r,
+ std::vector<FT>& dists) const {
+ FT distance = FT(0);
+ FT dist1, dist2;
+ typename K::Construct_cartesian_const_iterator_d construct_it=Traits_base().construct_cartesian_const_iterator_d_object();
+ typename K::Cartesian_const_iterator_d qit = construct_it(q),
+ qe = construct_it(q,1);
+ //std::cout << r.max_coord(0) << std::endl;
+ for(unsigned int i = 0;qit != qe; i++, qit++)
+ {
+ if((*qit) < r.min_coord(i))
+ {
+ dist1 = (r.min_coord(i)-(*qit));
+ dist2 = (box_length - r.max_coord(i)+(*qit));
+ if (dist1 < dist2)
+ {
+ dists[i] = dist1;
+ distance += dist1*dist1;
+ }
+ else
+ {
+ dists[i] = dist2;
+ distance += dist2*dist2;
+ //std::cout << "Good stuff1\n";
+ }
+ }
+ else if ((*qit) > r.max_coord(i))
+ {
+ dist1 = (box_length - (*qit)+r.min_coord(i));
+ dist2 = ((*qit) - r.max_coord(i));
+ if (dist1 < dist2)
+ {
+ dists[i] = dist1;
+ distance += dist1*dist1;
+ //std::cout << "Good stuff2\n";
+ }
+ else
+ {
+ dists[i] = dist2;
+ distance += dist2*dist2;
+ }
+ }
+ };
+ return distance;
+ }
+
+ FT max_distance_to_rectangle(const Query_item& q,
+ const CGAL::Kd_tree_rectangle<FT,D>& r) const {
+ FT distance=FT(0);
+ typename K::Construct_cartesian_const_iterator_d construct_it=Traits_base().construct_cartesian_const_iterator_d_object();
+ typename K::Cartesian_const_iterator_d qit = construct_it(q),
+ qe = construct_it(q,1);
+ for(unsigned int i = 0;qit != qe; i++, qit++)
+ {
+ if (box_length <= (r.min_coord(i)+r.max_coord(i)))
+ if ((r.max_coord(i)+r.min_coord(i)-box_length)/FT(2.0) <= (*qit) &&
+ (*qit) <= (r.min_coord(i)+r.max_coord(i))/FT(2.0))
+ distance += (r.max_coord(i)-(*qit))*(r.max_coord(i)-(*qit));
+ else
+ distance += ((*qit)-r.min_coord(i))*((*qit)-r.min_coord(i));
+ else
+ if ((box_length-r.max_coord(i)-r.min_coord(i))/FT(2.0) <= (*qit) ||
+ (*qit) <= (r.min_coord(i)+r.max_coord(i))/FT(2.0))
+ distance += (r.max_coord(i)-(*qit))*(r.max_coord(i)-(*qit));
+ else
+ distance += ((*qit)-r.min_coord(i))*((*qit)-r.min_coord(i));
+ }
+ return distance;
+ }
+
+
+ FT max_distance_to_rectangle(const Query_item& q,
+ const CGAL::Kd_tree_rectangle<FT,D>& r,
+ std::vector<FT>& dists) const {
+ FT distance=FT(0);
+ typename K::Construct_cartesian_const_iterator_d construct_it=Traits_base().construct_cartesian_const_iterator_d_object();
+ typename K::Cartesian_const_iterator_d qit = construct_it(q),
+ qe = construct_it(q,1);
+ for(unsigned int i = 0;qit != qe; i++, qit++)
+ {
+ if (box_length <= (r.min_coord(i)+r.max_coord(i)))
+ if ((r.max_coord(i)+r.min_coord(i)-box_length)/FT(2.0) <= (*qit) &&
+ (*qit) <= (r.min_coord(i)+r.max_coord(i))/FT(2.0))
+ {
+ dists[i] = r.max_coord(i)-(*qit);
+ distance += (r.max_coord(i)-(*qit))*(r.max_coord(i)-(*qit));
+ }
+ else
+ {
+ dists[i] = sqrt(((*qit)-r.min_coord(i))*((*qit)-r.min_coord(i)));
+ distance += ((*qit)-r.min_coord(i))*((*qit)-r.min_coord(i));
+ }
+ else
+ if ((box_length-r.max_coord(i)-r.min_coord(i))/FT(2.0) <= (*qit) ||
+ (*qit) <= (r.min_coord(i)+r.max_coord(i))/FT(2.0))
+ {
+ dists[i] = sqrt((r.max_coord(i)-(*qit))*(r.max_coord(i)-(*qit)));
+ distance += (r.max_coord(i)-(*qit))*(r.max_coord(i)-(*qit));
+
+ }
+ else
+ {
+ dists[i] = (*qit)-r.min_coord(i);
+ distance += ((*qit)-r.min_coord(i))*((*qit)-r.min_coord(i));
+ }
+ }
+ return distance;
+ }
+
+ inline FT new_distance(FT dist, FT old_off, FT new_off,
+ int ) const {
+
+ FT new_dist = dist + (new_off*new_off - old_off*old_off);
+ return new_dist;
+ }
+
+ inline FT transformed_distance(FT d) const {
+ return d*d;
+ }
+
+ inline FT inverse_of_transformed_distance(FT d) const {
+ return sqrt(d);
+ }
+
+};
+*/
+
+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_k_neighbor_search<STraits, CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance>> K_neighbor_search;
+typedef K_neighbor_search::Tree Tree;
+typedef K_neighbor_search::Distance Distance;
+typedef K_neighbor_search::iterator KNS_iterator;
+typedef K_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<CGAL::Point_d<CGAL::Cartesian_d<FT> > > Random_cube_iterator;
+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_grid(Point_Vector& W, int width, int D)
+{
+ int nb_points = 1;
+ for (int i = 0; i < D; ++i)
+ nb_points *= width;
+ for (int i = 0; i < nb_points; ++i)
+ {
+ std::vector<double> point;
+ int cell_i = i;
+ for (int l = 0; l < D; ++l)
+ {
+ point.push_back((2.0/width)*(cell_i%width));
+ cell_i /= width;
+ }
+ W.push_back(point);
+ }
+}
+
+void generate_points_random_box(Point_Vector& W, int nbP, int dim)
+{
+ /*
+ Random_cube_iterator rp(dim, 1);
+ for (int i = 0; i < nbP; i++)
+ {
+ std::vector<double> point;
+ for (auto it = rp->cartesian_begin(); it != rp->cartesian_end(); ++it)
+ point.push_back(*it);
+ W.push_back(Point_d(point));
+ rp++;
+ }
+ */
+ Random_cube_iterator rp(dim, 1.0);
+ for (int i = 0; i < nbP; i++)
+ {
+ W.push_back(*rp++);
+ }
+}
+
+/* NOT TORUS RELATED
+ */
+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 read_points_to_tree (std::string file_name, Tree& tree)
+{
+ //I assume here that tree is empty
+ 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> coords;
+ std::istringstream iss( line );
+ while(iss >> x) { coords.push_back(x); }
+ if (coords.size() != 1)
+ {
+ Point_d point(coords.begin(), coords.end());
+ tree.insert(point);
+ }
+ }
+ in_file.close();
+}
+*/
+
+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();
+}
+
+
+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";
+ int chosen_landmark;
+ 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;
+ }
+ }
+
+/** \brief Choose landmarks on a body-central cubic system
+ */
+void landmark_choice_bcc(Point_Vector &W, int nbP, int width, Point_Vector& landmarks, std::vector<int>& landmarks_ind)
+{
+ int D = W[0].size();
+ int nb_points = 1;
+ for (int i = 0; i < D; ++i)
+ nb_points *= width;
+ for (int i = 0; i < nb_points; ++i)
+ {
+ std::vector<double> point;
+ std::vector<double> cpoint;
+ int cell_i = i;
+ for (int l = 0; l < D; ++l)
+ {
+ point.push_back(-1.0+(2.0/width)*(cell_i%width));
+ cpoint.push_back(-1.0+(2.0/width)*(cell_i%width)+(1.0/width));
+ cell_i /= width;
+ }
+ landmarks.push_back(point);
+ landmarks.push_back(cpoint);
+ landmarks_ind.push_back(2*i);
+ landmarks_ind.push_back(2*i+1);
+ }
+ std::cout << "The number of landmarks is: " << landmarks.size() << std::endl;
+}
+
+
+int landmark_perturbation(Point_Vector &W, Point_Vector& landmarks, std::vector<int>& landmarks_ind)
+{
+ //********************Preface: origin point
+ int D = W[0].size();
+ std::vector<FT> orig_vector;
+ for (int 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();
+ //Point_Vector landmarks_ = landmarks;
+ Euclidean_distance ed;
+ //Equal_d ed;
+ //Point_d p1(std::vector<FT>({0.8,0.8})), p2(std::vector<FT>({0.1,0.1}));
+ FT lambda = ed.transformed_distance(landmarks[0],landmarks[1]);
+ //std::cout << "Lambda=" << lambda << std::endl;
+ //FT lambda = 0.1;//Euclidean_distance();
+ std::vector<Point_d> landmarks_ext;
+ int nb_cells = 1;
+ for (int i = 0; i < D; ++i)
+ nb_cells *= 3;
+ for (int i = 0; i < nb_cells; ++i)
+ for (int k = 0; k < nbL; ++k)
+ {
+ std::vector<double> point;
+ int cell_i = i;
+ for (int l = 0; l < D; ++l)
+ {
+ point.push_back(landmarks[k][l] + 2.0*((cell_i%3)-1.0));
+ cell_i /= 3;
+ }
+ landmarks_ext.push_back(point);
+ }
+ write_points("landmarks/initial_landmarks",landmarks_ext);
+ STraits traits(&(landmarks_ext[0]));
+ std::vector< std::vector <int> > WL(nbP);
+ Tree L(boost::counting_iterator<std::ptrdiff_t>(0),
+ boost::counting_iterator<std::ptrdiff_t>(nb_cells*nbL),
+ typename Tree::Splitter(),
+ traits);
+ /*Tree2 L2(boost::counting_iterator<std::ptrdiff_t>(0),
+ boost::counting_iterator<std::ptrdiff_t>(nbL),
+ typename Tree::Splitter(),
+ STraits(&(landmarks[0])));
+ */
+ 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::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+1, FT(0), true,
+ //CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance>(&(landmarks[0])) );
+ CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance>(&(landmarks_ext[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";
+ if (std::find(WL[i].begin(), WL[i].end(), (it->first)%nbL) == WL[i].end())
+ WL[i].push_back((it->first)%nbL);
+ //std::cout << "ITFIRST " << it->first << std::endl;
+ //std::cout << i << " " << it->first << ": " << it->second << std::endl;
+ }
+ if (i == landmarks_ind[WL[i][0]])
+ {
+ //std::cout << "'";
+ FT dist = ed.transformed_distance(W[i], landmarks[WL[i][1]]);
+ if (dist < lambda)
+ lambda = dist;
+ }
+ }
+ //std::cout << "\n";
+
+ std::string out_file = "wl_result";
+ write_wl(out_file,WL);
+
+ //******************** Constructng a witness complex
+ std::cout << "Entered witness complex construction\n";
+ Witness_complex<> witnessComplex;
+ witnessComplex.setNbL(nbL);
+ witnessComplex.witness_complex(WL);
+ /*
+ if (witnessComplex.is_witness_complex(WL))
+ std::cout << "!!YES. IT IS A WITNESS COMPLEX!!\n";
+ else
+ std::cout << "??NO. IT IS NOT A WITNESS COMPLEX??\n";
+ */
+ //******************** Making a set of bad link landmarks
+ std::cout << "Entered bad links\n";
+ std::set< int > perturbL;
+ int count_badlinks = 0;
+ //std::cout << "Bad links around ";
+ std::vector< int > count_bad(D);
+ std::vector< int > count_good(D);
+ for (auto u: witnessComplex.complex_vertex_range())
+ {
+ //std::cout << "Vertex " << u << " ";
+ if (!witnessComplex.has_good_link(u, count_bad, count_good))
+ {
+ //std::cout << "Landmark " << u << " start!" << std::endl;
+ //perturbL.insert(u);
+ count_badlinks++;
+ //std::cout << u << " ";
+ Point_d& l = landmarks[u];
+ Fuzzy_sphere fs(l, sqrt(lambda), 0, traits);
+ std::vector<int> curr_perturb;
+ L.search(std::insert_iterator<std::vector<int>>(curr_perturb,curr_perturb.begin()),fs);
+ for (int i: curr_perturb)
+ perturbL.insert(i%nbL);
+ //L.search(std::inserter(perturbL,perturbL.begin()),fs);
+ //L.search(std::ostream_iterator<int>(std::cout,"\n"),fs);
+ //std::cout << "PerturbL size is " << perturbL.size() << std::endl;
+ }
+ }
+ for (unsigned int i = 0; i != count_good.size(); i++)
+ if (count_good[i] != 0)
+ std::cout << "count_good[" << i << "] = " << count_good[i] << std::endl;
+ for (unsigned int i = 0; i != count_bad.size(); i++)
+ if (count_bad[i] != 0)
+ std::cout << "count_bad[" << i << "] = " << count_bad[i] << std::endl;
+ std::cout << "\nBad links total: " << count_badlinks << " Points to perturb: " << perturbL.size() << std::endl;
+ //std::cout << "landmark[0][0] before" << landmarks[0][0] << std::endl;
+ //*********************** Perturb bad link landmarks
+
+ for (auto u: perturbL)
+ {
+ Random_point_iterator rp(D,sqrt(lambda)/8);
+ //std::cout << landmarks[u] << std::endl;
+
+ std::vector<FT> point;
+ for (int i = 0; i < D; i++)
+ {
+ while (K().squared_distance_d_object()(*rp,origin) < lambda/256)
+ rp++;
+ //FT coord = W[landmarks_ind[u]][i] + (*rp)[i];
+ FT coord = landmarks[u][i] + (*rp)[i];
+ if (coord > 1)
+ point.push_back(coord-1);
+ else if (coord < -1)
+ point.push_back(coord+1);
+ else
+ point.push_back(coord);
+ }
+ landmarks[u] = Point_d(point);
+ //std::cout << landmarks[u] << std::endl;
+ }
+
+ //std::cout << "landmark[0][0] after" << landmarks[0][0] << std::endl;
+ std::cout << "lambda=" << lambda << std::endl;
+
+ //std::cout << "WL size" << WL.size() << std::endl;
+ /*
+ std::cout << "L:" << std::endl;
+ for (int i = 0; i < landmarks.size(); i++)
+ std::cout << landmarks[i] << std::endl;
+ */
+
+ 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();
+ }
+ /*
+ i = sprintf(buffer,"badlinks.txt");
+ if (i >= 0)
+ {
+ std::string out_file = (std::string)buffer;
+ std::ofstream ofs (out_file, std::ofstream::out);
+ witnessComplex.write_bad_links(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;
+ return count_badlinks;
+}
+
+
+int main (int argc, char * const argv[])
+{
+
+ if (argc != 4)
+ {
+ std::cerr << "Usage: " << argv[0]
+ << " nbP nbL dim\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]);
+ //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_random_box(point_vector, nbP, dim);
+ generate_points_grid(point_vector, (int)pow(nbP, 1.0/dim), dim);
+ //nbP = (int)(pow((int)pow(nbP, 1.0/dim), 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);
+ // witnessComplex.witness_complex_from_points(point_vector);
+ //int nbP = point_vector.size();
+ //std::vector<std::vector< int > > WL(nbP);
+ //std::set<int> L;
+ Point_Vector L;
+ std::vector<int> chosen_landmarks;
+ //Point_etiquette_map L_i;
+ //start = clock();
+ //witnessComplex.landmark_choice_by_furthest_points(point_vector, point_vector.size(), WL);
+ bool ok=false;
+ while (!ok)
+ {
+ ok = true;
+ L = {};
+ chosen_landmarks = {};
+ landmark_choice(point_vector, nbP, nbL, L, chosen_landmarks);
+
+ //int width = (int)pow(nbL, 1.0/dim); landmark_choice_bcc(point_vector, nbP, width, L, chosen_landmarks);
+ for (auto i: chosen_landmarks)
+ {
+ ok = ok && (std::count(chosen_landmarks.begin(),chosen_landmarks.end(),i) == 1);
+ if (!ok) break;
+ }
+
+ }
+ int bl = nbL, curr_min = bl;
+ write_points("landmarks/initial_pointset",point_vector);
+ //write_points("landmarks/initial_landmarks",L);
+ for (int i = 0; i < 1; i++)
+ //for (int i = 0; bl > 0; i++)
+ {
+ std::cout << "========== Start iteration " << i << "== curr_min(" << curr_min << ")========\n";
+ bl=landmark_perturbation(point_vector, L, chosen_landmarks);
+ if (bl < curr_min)
+ curr_min=bl;
+ write_points("landmarks/landmarks0",L);
+ }
+ //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/witness_complex_from_file.cpp b/src/Witness_complex/example/witness_complex_from_file.cpp
new file mode 100644
index 00000000..70c81528
--- /dev/null
+++ b/src/Witness_complex/example/witness_complex_from_file.cpp
@@ -0,0 +1,156 @@
+/* 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 <sys/types.h>
+#include <sys/stat.h>
+//#include <stdlib.h>
+
+//#include "gudhi/graph_simplicial_complex.h"
+#include "gudhi/Witness_complex.h"
+#include "gudhi/reader_utils.h"
+//#include <boost/filesystem.hpp>
+
+using namespace Gudhi;
+//using namespace boost::filesystem;
+
+typedef std::vector< Vertex_handle > typeVectorVertex;
+typedef std::vector< std::vector <double> > Point_Vector;
+//typedef std::pair<typeVectorVertex, Filtration_value> typeSimplex;
+//typedef std::pair< Simplex_tree<>::Simplex_handle, bool > typePairSimplexBool;
+
+
+/**
+ * \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 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();
+}
+
+int main (int argc, char * const argv[])
+{
+ if (argc != 3)
+ {
+ std::cerr << "Usage: " << argv[0]
+ << " path_to_point_file nbL \n";
+ return 0;
+ }
+ /*
+ boost::filesystem::path p;
+
+ for (; argc > 2; --argc, ++argv)
+ p /= argv[1];
+ */
+ std::string file_name = argv[1];
+ int nbL = atoi(argv[2]);
+
+ 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);
+ //std::cout << "Successfully read the points\n";
+ witnessComplex.setNbL(nbL);
+ // witnessComplex.witness_complex_from_points(point_vector);
+ std::vector<std::vector< int > > WL;
+ std::set<int> L;
+ start = clock();
+ //witnessComplex.landmark_choice_by_furthest_points(point_vector, point_vector.size(), WL);
+ witnessComplex.landmark_choice_by_random_points(point_vector, point_vector.size(), L);
+ witnessComplex.nearest_landmarks(point_vector,L,WL);
+ end = clock();
+ std::cout << "Landmark choice for " << nbL << " landmarks took "
+ << (double)(end-start)/CLOCKS_PER_SEC << " s. \n";
+ // Write the WL matrix in a file
+ mkdir("output", S_IRWXU);
+ const size_t last_slash_idx = file_name.find_last_of("/");
+ if (std::string::npos != last_slash_idx)
+ {
+ file_name.erase(0, last_slash_idx + 1);
+ }
+ std::string out_file = "output/"+file_name+"_"+argv[2]+".wl";
+ write_wl(out_file,WL);
+ start = clock();
+ witnessComplex.witness_complex(WL);
+ //
+ end = clock();
+ std::cout << "Howdy world! The process took "
+ << (double)(end-start)/CLOCKS_PER_SEC << " s. \n";
+ /*
+ char buffer[100];
+ int i = sprintf(buffer,"%s_%s_result.txt",argv[1],argv[2]);
+ 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();
+ }
+ */
+
+ 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/witness_complex_from_off.cpp b/src/Witness_complex/example/witness_complex_from_off.cpp
new file mode 100644
index 00000000..948f09a8
--- /dev/null
+++ b/src/Witness_complex/example/witness_complex_from_off.cpp
@@ -0,0 +1,184 @@
+/* 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 <sys/types.h>
+#include <sys/stat.h>
+
+//#include <stdlib.h>
+
+//#include "gudhi/graph_simplicial_complex.h"
+#include "gudhi/Witness_complex.h"
+#include "gudhi/reader_utils.h"
+
+using namespace Gudhi;
+
+typedef std::vector< Vertex_handle > typeVectorVertex;
+typedef std::vector< std::vector <double> > Point_Vector;
+//typedef std::pair<typeVectorVertex, Filtration_value> typeSimplex;
+//typedef std::pair< Simplex_tree<>::Simplex_handle, bool > typePairSimplexBool;
+
+
+/**
+ * \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();
+}
+
+/**
+ * \brief Rock age method of reading off file
+ *
+ */
+inline void
+off_reader_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;
+ // Line OFF. No need in it
+ if (!getline(in_file, line))
+ {
+ std::cerr << "No line OFF\n";
+ return;
+ }
+ // Line with 3 numbers. No need
+ if (!getline(in_file, line))
+ {
+ std::cerr << "No line with 3 numbers\n";
+ return;
+ }
+ // Reading points
+ while( getline ( in_file , line ) )
+ {
+ std::vector< double > point;
+ std::istringstream iss( line );
+ while(iss >> x) { point.push_back(x); }
+ points.push_back(point);
+ }
+ in_file.close();
+}
+
+int main (int argc, char * const argv[])
+{
+ if (argc != 3)
+ {
+ std::cerr << "Usage: " << argv[0]
+ << " path_to_point_file nbL \n";
+ return 0;
+ }
+ std::string file_name = argv[1];
+ int nbL = atoi(argv[2]);
+
+ clock_t start, end;
+ //Construct the Simplex Tree
+ Witness_complex<> witnessComplex;
+
+ /*
+ std::cout << "Let the carnage begin!\n";
+ start = clock();
+ Point_Vector point_vector;
+ off_reader_cust(file_name, point_vector);
+ std::cout << "Successfully read the points\n";
+ witnessComplex.setNbL(nbL);
+ witnessComplex.witness_complex_from_points(point_vector);
+ end = clock();
+ std::cout << "Howdy world! The process took "
+ << (double)(end-start)/CLOCKS_PER_SEC << " s. \n";
+ char buffer[100];
+ int i = sprintf(buffer,"%s_%s_result.txt",argv[1],argv[2]);
+ 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();
+ }
+ */
+ std::cout << "Let the carnage begin!\n";
+ Point_Vector point_vector;
+ off_reader_cust(file_name, point_vector);
+ //std::cout << "Successfully read the points\n";
+ witnessComplex.setNbL(nbL);
+ // witnessComplex.witness_complex_from_points(point_vector);
+ std::vector<std::vector< int > > WL;
+ std::set<int> L;
+ start = clock();
+ //witnessComplex.landmark_choice_by_furthest_points(point_vector, point_vector.size(), WL);
+ witnessComplex.landmark_choice_by_random_points(point_vector, point_vector.size(), L);
+ witnessComplex.nearest_landmarks(point_vector,L,WL);
+ end = clock();
+ std::cout << "Landmark choice took "
+ << (double)(end-start)/CLOCKS_PER_SEC << " s. \n";
+ // Write the WL matrix in a file
+ mkdir("output", S_IRWXU);
+ const size_t last_slash_idx = file_name.find_last_of("/");
+ if (std::string::npos != last_slash_idx)
+ {
+ file_name.erase(0, last_slash_idx + 1);
+ }
+ std::string out_file = "output/"+file_name+"_"+argv[2]+".wl";
+ //write_wl(out_file,WL);
+ 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/witness_complex_from_wl_matrix.cpp b/src/Witness_complex/example/witness_complex_from_wl_matrix.cpp
new file mode 100644
index 00000000..614bb945
--- /dev/null
+++ b/src/Witness_complex/example/witness_complex_from_wl_matrix.cpp
@@ -0,0 +1,148 @@
+/* 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 <sys/types.h>
+#include <sys/stat.h>
+//#include <stdlib.h>
+
+//#include "gudhi/graph_simplicial_complex.h"
+#include "gudhi/Witness_complex.h"
+#include "gudhi/reader_utils.h"
+//#include <boost/filesystem.hpp>
+
+using namespace Gudhi;
+//using namespace boost::filesystem;
+
+typedef std::vector< Vertex_handle > typeVectorVertex;
+typedef std::vector< std::vector <double> > Point_Vector;
+//typedef std::pair<typeVectorVertex, Filtration_value> typeSimplex;
+//typedef std::pair< Simplex_tree<>::Simplex_handle, bool > typePairSimplexBool;
+
+
+/**
+ * \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 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 read_wl( std::string file_name, std::vector< std::vector <int> > & WL)
+{
+ 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;
+ int x;
+ while( getline ( in_file , line ) )
+ {
+ std::vector< int > witness;
+ std::istringstream iss( line );
+ while(iss >> x) { witness.push_back(x); }
+ WL.push_back(witness);
+ }
+ in_file.close();
+
+}
+
+int main (int argc, char * const argv[])
+{
+ if (argc != 2)
+ {
+ std::cerr << "Usage: " << argv[0]
+ << " path_to_point_file \n";
+ return 0;
+ }
+ /*
+ boost::filesystem::path p;
+
+ for (; argc > 2; --argc, ++argv)
+ p /= argv[1];
+ */
+ std::string file_name = argv[1];
+ //int nbL = atoi(argv[2]);
+
+ 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);
+ //std::cout << "Successfully read the points\n";
+ // witnessComplex.witness_complex_from_points(point_vector);
+ std::vector<std::vector< int > > WL;
+ read_wl(file_name,WL);
+ witnessComplex.setNbL(WL[0].size());
+ // Write the WL matrix in a file
+ std::string out_file;
+ write_wl(out_file,WL);
+ 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();
+
+}
diff --git a/src/Witness_complex/example/witness_complex_knn_landmarks.cpp b/src/Witness_complex/example/witness_complex_knn_landmarks.cpp
new file mode 100644
index 00000000..c45bc0c1
--- /dev/null
+++ b/src/Witness_complex/example/witness_complex_knn_landmarks.cpp
@@ -0,0 +1,210 @@
+/* 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 <sys/types.h>
+#include <sys/stat.h>
+//#include <stdlib.h>
+
+//#include "gudhi/graph_simplicial_complex.h"
+#include "gudhi/Witness_complex.h"
+#include "gudhi/reader_utils.h"
+#include "generators.h"
+#include "output.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_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>
+
+using namespace Gudhi;
+//using namespace boost::filesystem;
+
+typedef std::vector< Vertex_handle > typeVectorVertex;
+
+//typedef std::pair<typeVectorVertex, Filtration_value> typeSimplex;
+//typedef std::pair< Simplex_tree<>::Simplex_handle, bool > typePairSimplexBool;
+
+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::Search_traits_adapter<
+ std::ptrdiff_t, Point_d*, Traits_base> STraits;
+//typedef K TreeTraits;
+typedef CGAL::Orthogonal_k_neighbor_search<STraits> K_neighbor_search;
+typedef K_neighbor_search::Tree Tree;
+typedef K_neighbor_search::Distance Distance;
+typedef K_neighbor_search::iterator KNS_iterator;
+typedef K_neighbor_search::iterator KNS_range;
+typedef boost::container::flat_map<int, int> Point_etiquette_map;
+
+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_to_tree(Point_Vector &W, int nbP, Point_etiquette_map &L_i, int nbL, std::vector< std::vector <int> > &WL)
+{
+ 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;
+ srand(24660);
+ for (int i = 0; i < nbL; i++)
+ {
+ // while (!res.second)
+ // {
+ chosen_landmark = rand()%nbP;
+ p = &W[chosen_landmark];
+ //L_i.emplace(chosen_landmark,i);
+ // }
+ landmarks.push_back(*p);
+ //std::cout << "Added landmark " << chosen_landmark << std::endl;
+ }
+ Tree L(boost::counting_iterator<std::ptrdiff_t>(0),
+ boost::counting_iterator<std::ptrdiff_t>(nbL),
+ typename Tree::Splitter(),
+ STraits((Point_d*)&(landmarks[0])));
+ /*}
+
+
+void d_nearest_landmarks(Point_Vector &W, Tree &L, Point_etiquette_map &L_i, std::vector< std::vector <int> > &WL)
+{*/
+ std::cout << "Enter (D+1) nearest landmarks\n";
+ std::cout << "Size of the tree is " << L.size() << std::endl;
+//int nbP = W.size();
+ int D = W[0].size();
+ for (int i = 0; i < nbP; i++)
+ {
+ //std::cout << "Entered witness number " << i << std::endl;
+ Point_d& w = W[i];
+ //std::cout << "Safely constructed a point\n";
+ //Search D+1 nearest neighbours from the tree of landmarks L
+ K_neighbor_search search(L, w, D+1, FT(0), true,
+ CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,CGAL::Euclidean_distance<Traits_base>>((Point_d*)&(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 << i << " " << it->first << ": " << it->second << std::endl;
+ }
+ }
+}
+
+int main (int argc, char * const argv[])
+{
+ if (argc != 3)
+ {
+ std::cerr << "Usage: " << argv[0]
+ << " path_to_point_file nbL \n";
+ return 0;
+ }
+ /*
+ boost::filesystem::path p;
+
+ for (; argc > 2; --argc, ++argv)
+ p /= argv[1];
+ */
+ std::string file_name = argv[1];
+ int nbL = atoi(argv[2]);
+
+ 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);
+ //std::cout << "Successfully read the points\n";
+ witnessComplex.setNbL(nbL);
+ // witnessComplex.witness_complex_from_points(point_vector);
+ int nbP = point_vector.size();
+ std::vector<std::vector< int > > WL(nbP);
+ //std::set<int> L;
+ Tree L;
+ Point_etiquette_map L_i;
+ start = clock();
+ //witnessComplex.landmark_choice_by_furthest_points(point_vector, point_vector.size(), WL);
+ landmark_choice_to_tree(point_vector, nbP, L_i, nbL, WL);
+ //d_nearest_landmarks(point_vector, L, L_i, WL);
+ end = clock();
+ std::cout << "Landmark choice took "
+ << (double)(end-start)/CLOCKS_PER_SEC << " s. \n";
+ // Write the WL matrix in a file
+ mkdir("output", S_IRWXU);
+ const size_t last_slash_idx = file_name.find_last_of("/");
+ if (std::string::npos != last_slash_idx)
+ {
+ file_name.erase(0, last_slash_idx + 1);
+ }
+ std::string out_file = "output/"+file_name+"_"+argv[2]+".wl";
+ write_wl(out_file,WL);
+ start = clock();
+ witnessComplex.witness_complex(WL);
+ //
+ end = clock();
+ std::cout << "Howdy world! The process took "
+ << (double)(end-start)/CLOCKS_PER_SEC << " s. \n";
+ /*
+ char buffer[100];
+ int i = sprintf(buffer,"%s_%s_result.txt",argv[1],argv[2]);
+ 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();
+ }
+ */
+
+ 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/witness_complex_perturbations.cpp b/src/Witness_complex/example/witness_complex_perturbations.cpp
new file mode 100644
index 00000000..f78bcdab
--- /dev/null
+++ b/src/Witness_complex/example/witness_complex_perturbations.cpp
@@ -0,0 +1,462 @@
+/* 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 <set>
+#include <iterator>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+//#include <stdlib.h>
+
+//#include "gudhi/graph_simplicial_complex.h"
+#include "gudhi/Witness_complex.h"
+#include "gudhi/reader_utils.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_k_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/Origin.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 std::vector< Vertex_handle > typeVectorVertex;
+
+//typedef std::pair<typeVectorVertex, Filtration_value> typeSimplex;
+//typedef std::pair< Simplex_tree<>::Simplex_handle, bool > typePairSimplexBool;
+
+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::Search_traits_adapter<
+ std::ptrdiff_t, Point_d*, Traits_base> STraits;
+//typedef K TreeTraits;
+typedef CGAL::Orthogonal_k_neighbor_search<STraits> K_neighbor_search;
+typedef K_neighbor_search::Tree Tree;
+typedef K_neighbor_search::Distance Distance;
+typedef K_neighbor_search::iterator KNS_iterator;
+typedef K_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 CGAL::Euclidean_distance<Traits_base> Euclidean_distance;
+//typedef K::Equal_d Equal_d;
+typedef CGAL::Random_points_in_ball_d<Point_d> Random_point_iterator;
+/**
+ * \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 read_points_to_tree (std::string file_name, Tree& tree)
+{
+ //I assume here that tree is empty
+ 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> coords;
+ std::istringstream iss( line );
+ while(iss >> x) { coords.push_back(x); }
+ if (coords.size() != 1)
+ {
+ Point_d point(coords.begin(), coords.end());
+ tree.insert(point);
+ }
+ }
+ in_file.close();
+}
+*/
+
+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_points( std::string file_name, std::vector< Point_d > & WL)
+{
+ std::ofstream ofs (file_name, std::ofstream::out);
+ for (auto w : WL)
+ {
+ for (auto it = w.cartesian_begin(); it != w.cartesian_end(); ++it)
+ ofs << *it << " ";
+ ofs << "\n";
+ }
+ ofs.close();
+}
+
+void write_edges_gnuplot(std::string file_name, Witness_complex<>& 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())
+ {
+ 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;
+ srand(24660);
+ for (int i = 0; i < nbL; i++)
+ {
+ // while (!res.second)
+ // {
+ chosen_landmark = rand()%nbP;
+ 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 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 = 0;
+ //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.uniform_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;
+ }
+ }
+
+
+int landmark_perturbation(Point_Vector &W, Point_Vector& landmarks, std::vector<int>& landmarks_ind)
+{
+ //******************** Constructing a WL matrix
+ int nbP = W.size();
+ int nbL = landmarks.size();
+ //Point_Vector landmarks_ = landmarks;
+ Euclidean_distance ed;
+ //Equal_d ed;
+ FT lambda = ed.transformed_distance(landmarks[0],landmarks[1]);
+ //FT lambda = 0.1;//Euclidean_distance();
+ std::vector< std::vector <int> > WL(nbP);
+ Tree L(boost::counting_iterator<std::ptrdiff_t>(0),
+ boost::counting_iterator<std::ptrdiff_t>(nbL),
+ typename Tree::Splitter(),
+ STraits(&(landmarks[0])));
+ /*Tree2 L2(boost::counting_iterator<std::ptrdiff_t>(0),
+ boost::counting_iterator<std::ptrdiff_t>(nbL),
+ typename Tree::Splitter(),
+ STraits(&(landmarks[0])));
+ */
+ std::cout << "Enter (D+1) nearest landmarks\n";
+ //std::cout << "Size of the tree is " << L.size() << std::endl;
+ int D = W[0].size();
+ clock_t start, end;
+ start = clock();
+ for (int i = 0; i < nbP; i++)
+ {
+ //std::cout << "Entered witness number " << i << std::endl;
+ Point_d& w = W[i];
+ //std::cout << "Safely constructed a point\n";
+ ////Search D+1 nearest neighbours from the tree of landmarks L
+ K_neighbor_search search(L, w, D+1, FT(0), true,
+ CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,CGAL::Euclidean_distance<Traits_base>>(&(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;
+ }
+ if (i == landmarks_ind[WL[i][0]])
+ {
+ //std::cout << "'";
+ FT dist = ed.transformed_distance(W[i], landmarks[WL[i][1]]);
+ if (dist < lambda)
+ lambda = dist;
+ }
+ //std::cout << "\nBad links total: " << count_badlinks << " Points to perturb: " << perturbL.size() << std::endl;
+ }
+ //std::cout << "\n";
+ end = clock();
+ std::cout << "WL matrix construction on " << nbL << " landmarks took " << (double)(end-start)/CLOCKS_PER_SEC << "s.\n";
+
+
+ std::string out_file = "wl_result";
+ //write_wl(out_file,WL);
+
+ //******************** Constructng a witness complex
+ std::cout << "Entered witness complex construction\n";
+ Witness_complex<> witnessComplex;
+ witnessComplex.setNbL(nbL);
+ start = clock();
+ witnessComplex.witness_complex(WL);
+ end = clock();
+ std::cout << "Witness complex construction on " << nbL << " landmarks took " << (double)(end-start)/CLOCKS_PER_SEC << "s.\n";
+ //******************** Making a set of bad link landmarks
+ std::cout << "Entered bad links\n";
+ std::set< int > perturbL;
+ int count_badlinks = 0;
+ std::vector< int > count_bad(D);
+ std::vector< int > count_good(D);
+ //std::cout << "Bad links around ";
+ for (auto u: witnessComplex.complex_vertex_range())
+ if (!witnessComplex.has_good_link(u, count_bad, count_good))
+ {
+ //std::cout << "Landmark " << u << " start!" << std::endl;
+ //perturbL.insert(u);
+ count_badlinks++;
+ //std::cout << u << " ";
+ Point_d& l = landmarks[u];
+ Fuzzy_sphere fs(l, sqrt(lambda)*2, 0, STraits(&(landmarks[0])));
+ L.search(std::insert_iterator<std::set<int>>(perturbL,perturbL.begin()),fs);
+ //L.search(std::inserter(perturbL,perturbL.begin()),fs);
+ //L.search(std::ostream_iterator<int>(std::cout,"\n"),fs);
+ //std::cout << "PerturbL size is " << perturbL.size() << std::endl;
+ }
+ for (unsigned int i = 0; i != count_good.size(); i++)
+ if (count_good[i] != 0)
+ std::cout << "count_good[" << i << "] = " << count_good[i] << std::endl;
+ for (unsigned int i = 0; i != count_bad.size(); i++)
+ if (count_bad[i] != 0)
+ std::cout << "count_bad[" << i << "] = " << count_bad[i] << std::endl;
+ std::cout << "Bad links total: " << count_badlinks << " Points to perturb: " << perturbL.size() << std::endl;
+ //std::cout << "landmark[0][0] before" << landmarks[0][0] << std::endl;
+ //*********************** Perturb bad link landmarks
+
+ for (auto u: perturbL)
+ {
+ Random_point_iterator rp(D,sqrt(lambda)/4);
+ //std::cout << landmarks[u] << std::endl;
+
+ std::vector<FT> point;
+ for (int i = 0; i < D; i++)
+ {
+ point.push_back(W[landmarks_ind[u]][i] + (*rp)[i]);
+ }
+ landmarks[u] = Point_d(point);
+ //std::cout << landmarks[u] << std::endl;
+ }
+
+ //std::cout << "landmark[0][0] after" << landmarks[0][0] << std::endl;
+ std::cout << "lambda=" << lambda << std::endl;
+ // Write the WL matrix in a file
+
+ /*
+ 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();
+ }
+ */
+ //witnessComplex.write_badlinks("badlinks");
+ //write_edges_gnuplot("landmarks/edges", witnessComplex, landmarks);
+ return count_badlinks;
+}
+
+
+int main (int argc, char * const argv[])
+{
+ if (argc != 3)
+ {
+ std::cerr << "Usage: " << argv[0]
+ << " path_to_point_file nbL \n";
+ return 0;
+ }
+ /*
+ boost::filesystem::path p;
+
+ for (; argc > 2; --argc, ++argv)
+ p /= argv[1];
+ */
+ std::string file_name = argv[1];
+ int nbL = atoi(argv[2]);
+
+ //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);
+ //std::cout << "Successfully read the points\n";
+ //witnessComplex.setNbL(nbL);
+ // witnessComplex.witness_complex_from_points(point_vector);
+ int nbP = point_vector.size();
+ //std::vector<std::vector< int > > WL(nbP);
+ //std::set<int> L;
+ Point_Vector L;
+ std::vector<int> chosen_landmarks;
+ //Point_etiquette_map L_i;
+ //start = clock();
+ //witnessComplex.landmark_choice_by_furthest_points(point_vector, point_vector.size(), WL);
+ landmark_choice(point_vector, nbP, nbL, L, chosen_landmarks);
+ int bl = 1;
+
+ mkdir("landmarks", S_IRWXU);
+ const size_t last_slash_idx = file_name.find_last_of("/");
+ if (std::string::npos != last_slash_idx)
+ {
+ file_name.erase(0, last_slash_idx + 1);
+ }
+ write_points("landmarks/initial_pointset",point_vector);
+ //write_points("landmarks/initial_landmarks",L);
+ //for (int i = 0; bl != 0; i++)
+ for (int i = 0; i < 1; i++)
+ {
+ std::cout << "========== Start iteration " << i << " ========\n";
+ bl = landmark_perturbation(point_vector, L, chosen_landmarks);
+ std::ostringstream os(std::ostringstream::ate);;
+ os << "landmarks/landmarks0";
+ write_points(os.str(),L);
+ }
+ //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/witness_complex_protected_delaunay.cpp b/src/Witness_complex/example/witness_complex_protected_delaunay.cpp
new file mode 100644
index 00000000..77a167a5
--- /dev/null
+++ b/src/Witness_complex/example/witness_complex_protected_delaunay.cpp
@@ -0,0 +1,604 @@
+/* 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 <iterator>
+#include <chrono>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+//#include <stdlib.h>
+
+//#include "gudhi/graph_simplicial_complex.h"
+#include "gudhi/Witness_complex.h"
+#include "gudhi/reader_utils.h"
+#include "Torus_distance.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_k_neighbor_search.h>
+#include <CGAL/Kd_tree.h>
+#include <CGAL/Euclidean_distance.h>
+#include <CGAL/Kernel_d/Sphere_d.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 <CGAL/Delaunay_triangulation.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::Point_d Point_d;
+//typedef CGAL::Cartesian_d<double> K;
+//typedef CGAL::Point_d<K> Point_d;
+typedef K::FT FT;
+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_k_neighbor_search<STraits, CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance>> K_neighbor_search;
+typedef K_neighbor_search::Tree Tree;
+typedef K_neighbor_search::Distance Distance;
+typedef K_neighbor_search::iterator KNS_iterator;
+typedef K_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<CGAL::Point_d<CGAL::Cartesian_d<FT> > > Random_cube_iterator;
+typedef CGAL::Random_points_in_cube_d<Point_d> Random_cube_iterator;
+typedef CGAL::Random_points_in_ball_d<Point_d> Random_point_iterator;
+
+typedef CGAL::Delaunay_triangulation<K> Delaunay_triangulation;
+typedef Delaunay_triangulation::Facet Facet;
+typedef CGAL::Sphere_d<K> Sphere_d;
+
+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_grid(Point_Vector& W, int width, int D)
+{
+ int nb_points = 1;
+ for (int i = 0; i < D; ++i)
+ nb_points *= width;
+ for (int i = 0; i < nb_points; ++i)
+ {
+ std::vector<double> point;
+ int cell_i = i;
+ for (int l = 0; l < D; ++l)
+ {
+ point.push_back(0.01*(cell_i%width));
+ cell_i /= width;
+ }
+ W.push_back(point);
+ }
+}
+
+void generate_points_random_box(Point_Vector& W, int nbP, int dim)
+{
+ /*
+ Random_cube_iterator rp(dim, 1);
+ for (int i = 0; i < nbP; i++)
+ {
+ std::vector<double> point;
+ for (auto it = rp->cartesian_begin(); it != rp->cartesian_end(); ++it)
+ point.push_back(*it);
+ W.push_back(Point_d(point));
+ rp++;
+ }
+ */
+ Random_cube_iterator rp(dim, 1.0);
+ 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_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();
+}
+
+void write_edges(std::string file_name, Witness_complex<>& 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())
+ {
+ 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";
+ int chosen_landmark;
+ 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::count(landmarks_ind.begin(),landmarks_ind.end(),chosen_landmark)!=0);
+ //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 insert_delaunay_landmark_with_copies(Point_Vector& W, int chosen_landmark, std::vector<int>& landmarks_ind, Delaunay_triangulation& delaunay, int& landmark_count)
+{
+ int D = W[0].size();
+ int nb_cells = pow(3, D);
+ for (int i = 0; i < nb_cells; ++i)
+ {
+ std::vector<FT> point;
+ int cell_i = i;
+ for (int l = 0; l < D; ++l)
+ {
+ point.push_back(W[chosen_landmark][l] + 2.0*(cell_i%3-1));
+ cell_i /= 3;
+ }
+ delaunay.insert(point);
+ }
+ landmarks_ind.push_back(chosen_landmark);
+ landmark_count++;
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+// OLD CODE VVVVVVVV
+////////////////////////////////////////////////////////////////////////
+
+
+/*
+bool is_violating_protection(Point_d& p, Delaunay_triangulation& t, int D, FT delta)
+{
+ Euclidean_distance ed;
+ Delaunay_triangulation::Vertex_handle v;
+ Delaunay_triangulation::Face f(t.current_dimension());
+ Delaunay_triangulation::Facet ft;
+ Delaunay_triangulation::Full_cell_handle c;
+ Delaunay_triangulation::Locate_type lt;
+ c = t.locate(p, lt, f, ft, v);
+ for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
+ if (!t.is_infinite(fc_it))
+ {
+ std::vector<Point_d> vertices;
+ for (auto v_it = fc_it->vertices_begin(); v_it != fc_it->vertices_end(); ++v_it)
+ vertices.push_back((*v_it)->point());
+ Sphere_d cs(D, vertices.begin(), vertices.end());
+ Point_d center_cs = cs.center();
+ FT r = sqrt(ed.transformed_distance(center_cs, fc_it->vertex(1)->point()));
+ FT dist2 = ed.transformed_distance(center_cs, p);
+ //if the new point is inside the protection ball of a non conflicting simplex
+ if (dist2 >= r*r && dist2 <= (r+delta)*(r+delta))
+ return true;
+ }
+ return false;
+}
+
+bool triangulation_is_protected(Delaunay_triangulation& t, FT delta)
+{
+ Euclidean_distance ed;
+ int D = t.current_dimension();
+ for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
+ if (!t.is_infinite(fc_it))
+ for (auto v_it = t.vertices_begin(); v_it != t.vertices_end(); ++v_it)
+ {
+ //check if vertex belongs to the face
+ bool belongs = false;
+ for (auto fc_v_it = fc_it->vertices_begin(); fc_v_it != fc_it->vertices_end(); ++fc_v_it)
+ if (v_it == *fc_v_it)
+ {
+ belongs = true;
+ break;
+ }
+ if (!belongs)
+ {
+ std::vector<Point_d> vertices;
+ for (auto fc_v_it = fc_it->vertices_begin(); fc_v_it != fc_it->vertices_end(); ++fc_v_it)
+ vertices.push_back((*fc_v_it)->point());
+ Sphere_d cs(D, vertices.begin(), vertices.end());
+ Point_d center_cs = cs.center();
+ FT r = sqrt(ed.transformed_distance(center_cs, fc_it->vertex(1)->point()));
+ FT dist2 = ed.transformed_distance(center_cs, v_it->point());
+ //if the new point is inside the protection ball of a non conflicting simplex
+ if (dist2 <= (r+delta)*(r+delta))
+ return false;
+ }
+ }
+ return true;
+}
+
+void fill_landmark_copies(Point_Vector& W, Point_Vector& landmarks, std::vector<int>& landmarks_ind)
+{
+ int D = W[0].size();
+ int nb_cells = pow(3, D);
+ int nbL = landmarks_ind.size();
+ // Fill landmarks
+ for (int i = 0; i < nb_cells-1; ++i)
+ for (int j = 0; j < nbL; ++j)
+ {
+ int cell_i = i;
+ Point_d point;
+ for (int l = 0; l < D; ++l)
+ {
+ point.push_back(W[landmarks_ind[j]][l] + 2.0*(cell_i-1));
+ cell_i /= 3;
+ }
+ landmarks.push_back(point);
+ }
+}
+
+void landmark_choice_by_delaunay(Point_Vector& W, int nbP, int nbL, Point_Vector& landmarks, std::vector<int>& landmarks_ind, FT delta)
+{
+ int D = W[0].size();
+ Delaunay_triangulation t(D);
+ CGAL::Random rand;
+ int chosen_landmark;
+ int landmark_count = 0;
+ for (int i = 0; i <= D+1; ++i)
+ {
+ do chosen_landmark = rand.get_int(0,nbP);
+ while (std::count(landmarks_ind.begin(),landmarks_ind.end(),chosen_landmark)!=0);
+ insert_delaunay_landmark_with_copies(W, chosen_landmark, landmarks_ind, t, landmark_count);
+ }
+ while (landmark_count < nbL)
+ {
+ do chosen_landmark = rand.get_int(0,nbP);
+ while (std::count(landmarks_ind.begin(),landmarks_ind.end(),chosen_landmark)!=0);
+ // If no conflicts then insert in every copy of T^3
+ if (!is_violating_protection(W[chosen_landmark], t, D, delta))
+ insert_delaunay_landmark_with_copies(W, chosen_landmark, landmarks_ind, t, landmark_count);
+ }
+ fill_landmark_copies(W, landmarks, landmarks_ind);
+}
+
+
+void landmark_choice_protected_delaunay(Point_Vector& W, int nbP, Point_Vector& landmarks, std::vector<int>& landmarks_ind, FT delta)
+{
+ int D = W[0].size();
+ Torus_distance td;
+ Euclidean_distance ed;
+ Delaunay_triangulation t(D);
+ CGAL::Random rand;
+ int landmark_count = 0;
+ std::list<int> index_list;
+ // shuffle the list of indexes (via a vector)
+ {
+ std::vector<int> temp_vector;
+ for (int i = 0; i < nbP; ++i)
+ temp_vector.push_back(i);
+ unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
+ std::shuffle(temp_vector.begin(), temp_vector.end(), std::default_random_engine(seed));
+ for (std::vector<int>::iterator it = temp_vector.begin(); it != temp_vector.end(); ++it)
+ index_list.push_front(*it);
+ }
+ // add the first D+1 vertices to form one non-empty cell
+ for (int i = 0; i <= D+1; ++i)
+ {
+ insert_delaunay_landmark_with_copies(W, index_list.front(), landmarks_ind, t, landmark_count);
+ index_list.pop_front();
+ }
+ // add other vertices if they don't violate protection
+ std::list<int>::iterator list_it = index_list.begin();
+ while (list_it != index_list.end())
+ if (!is_violating_protection(W[*list_it], t, D, delta))
+ {
+ // If no conflicts then insert in every copy of T^3
+ insert_delaunay_landmark_with_copies(W, *list_it, landmarks_ind, t, landmark_count);
+ index_list.erase(list_it);
+ list_it = index_list.begin();
+ }
+ else
+ list_it++;
+ fill_landmark_copies(W, landmarks, landmarks_ind);
+}
+
+
+int landmark_perturbation(Point_Vector &W, int nbL, Point_Vector& landmarks, std::vector<int>& landmarks_ind)
+{
+ //******************** Preface: origin point
+ int D = W[0].size();
+ std::vector<FT> orig_vector;
+ for (int i=0; i<D; i++)
+ orig_vector.push_back(0);
+ Point_d origin(orig_vector);
+
+ //******************** Constructing a WL matrix
+ int nbP = W.size();
+ Euclidean_distance ed;
+ FT lambda = ed.transformed_distance(landmarks[0],landmarks[1]);
+ std::vector<Point_d> landmarks_ext;
+ int nb_cells = 1;
+ for (int i = 0; i < D; ++i)
+ nb_cells *= 3;
+ for (int i = 0; i < nb_cells; ++i)
+ for (int k = 0; k < nbL; ++k)
+ {
+ std::vector<double> point;
+ int cell_i = i;
+ for (int l = 0; l < D; ++l)
+ {
+ point.push_back(landmarks[k][l] + 2.0*((cell_i%3)-1.0));
+ cell_i /= 3;
+ }
+ landmarks_ext.push_back(point);
+ }
+ write_points("landmarks/initial_landmarks",landmarks_ext);
+ STraits traits(&(landmarks_ext[0]));
+ std::vector< std::vector <int> > WL(nbP);
+
+ //********************** Neighbor search in a Kd tree
+ Tree L(boost::counting_iterator<std::ptrdiff_t>(0),
+ boost::counting_iterator<std::ptrdiff_t>(nb_cells*nbL),
+ typename Tree::Splitter(),
+ traits);
+ std::cout << "Enter (D+1) nearest landmarks\n";
+ for (int i = 0; i < nbP; i++)
+ {
+ Point_d& w = W[i];
+ ////Search D+1 nearest neighbours from the tree of landmarks L
+ K_neighbor_search search(L, w, D+1, FT(0), true,
+ CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance>(&(landmarks_ext[0])) );
+ for(K_neighbor_search::iterator it = search.begin(); it != search.end(); ++it)
+ {
+ if (std::find(WL[i].begin(), WL[i].end(), (it->first)%nbL) == WL[i].end())
+ WL[i].push_back((it->first)%nbL);
+ }
+ if (i == landmarks_ind[WL[i][0]])
+ {
+ FT dist = ed.transformed_distance(W[i], landmarks[WL[i][1]]);
+ if (dist < lambda)
+ lambda = dist;
+ }
+ }
+ std::string out_file = "wl_result";
+ write_wl(out_file,WL);
+
+ //******************** Constructng a witness complex
+ std::cout << "Entered witness complex construction\n";
+ Witness_complex<> witnessComplex;
+ witnessComplex.setNbL(nbL);
+ witnessComplex.witness_complex(WL);
+
+ //******************** Making a set of bad link landmarks
+ std::cout << "Entered bad links\n";
+ std::set< int > perturbL;
+ int count_badlinks = 0;
+ //std::cout << "Bad links around ";
+ std::vector< int > count_bad(D);
+ std::vector< int > count_good(D);
+ for (auto u: witnessComplex.complex_vertex_range())
+ {
+ if (!witnessComplex.has_good_link(u, count_bad, count_good))
+ {
+ count_badlinks++;
+ Point_d& l = landmarks[u];
+ Fuzzy_sphere fs(l, sqrt(lambda)*3, 0, traits);
+ std::vector<int> curr_perturb;
+ L.search(std::insert_iterator<std::vector<int>>(curr_perturb,curr_perturb.begin()),fs);
+ for (int i: curr_perturb)
+ perturbL.insert(i%nbL);
+ }
+ }
+ for (unsigned int i = 0; i != count_good.size(); i++)
+ if (count_good[i] != 0)
+ std::cout << "count_good[" << i << "] = " << count_good[i] << std::endl;
+ for (unsigned int i = 0; i != count_bad.size(); i++)
+ if (count_bad[i] != 0)
+ std::cout << "count_bad[" << i << "] = " << count_bad[i] << std::endl;
+ std::cout << "\nBad links total: " << count_badlinks << " Points to perturb: " << perturbL.size() << std::endl;
+
+ //*********************** Perturb bad link landmarks
+ for (auto u: perturbL)
+ {
+ Random_point_iterator rp(D,sqrt(lambda)/8);
+ std::vector<FT> point;
+ for (int i = 0; i < D; i++)
+ {
+ while (K().squared_distance_d_object()(*rp,origin) < lambda/256)
+ rp++;
+ FT coord = landmarks[u][i] + (*rp)[i];
+ if (coord > 1)
+ point.push_back(coord-1);
+ else if (coord < -1)
+ point.push_back(coord+1);
+ else
+ point.push_back(coord);
+ }
+ landmarks[u] = Point_d(point);
+ }
+ std::cout << "lambda=" << lambda << std::endl;
+ 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);
+ return count_badlinks;
+}
+
+
+int main (int argc, char * const argv[])
+{
+ if (argc != 5)
+ {
+ std::cerr << "Usage: " << argv[0]
+ << " nbP nbL dim delta\n";
+ return 0;
+ }
+ int nbP = atoi(argv[1]);
+ int nbL = atoi(argv[2]);
+ int dim = atoi(argv[3]);
+ FT delta = atof(argv[4]);
+
+ std::cout << "Let the carnage begin!\n";
+ Point_Vector point_vector;
+ generate_points_random_box(point_vector, nbP, dim);
+ Point_Vector L;
+ std::vector<int> chosen_landmarks;
+ bool ok=false;
+ while (!ok)
+ {
+ ok = true;
+ L = {};
+ chosen_landmarks = {};
+ //landmark_choice_by_delaunay(point_vector, nbP, nbL, L, chosen_landmarks, delta);
+ landmark_choice_protected_delaunay(point_vector, nbP, L, chosen_landmarks, delta);
+ nbL = chosen_landmarks.size();
+ std::cout << "Number of landmarks is " << nbL << std::endl;
+ //int width = (int)pow(nbL, 1.0/dim); landmark_choice_bcc(point_vector, nbP, width, L, chosen_landmarks);
+ for (auto i: chosen_landmarks)
+ {
+ ok = ok && (std::count(chosen_landmarks.begin(),chosen_landmarks.end(),i) == 1);
+ if (!ok) break;
+ }
+
+ }
+ int bl = nbL, curr_min = bl;
+ write_points("landmarks/initial_pointset",point_vector);
+ //write_points("landmarks/initial_landmarks",L);
+ //for (int i = 0; i < 1; i++)
+ for (int i = 0; bl > 0; i++)
+ {
+ std::cout << "========== Start iteration " << i << "== curr_min(" << curr_min << ")========\n";
+ bl=landmark_perturbation(point_vector, nbL, L, chosen_landmarks);
+ if (bl < curr_min)
+ curr_min=bl;
+ write_points("landmarks/landmarks0",L);
+ }
+
+}
+*/
diff --git a/src/Witness_complex/example/witness_complex_sphere.cpp b/src/Witness_complex/example/witness_complex_sphere.cpp
new file mode 100644
index 00000000..bf3015fa
--- /dev/null
+++ b/src/Witness_complex/example/witness_complex_sphere.cpp
@@ -0,0 +1,457 @@
+/* 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 <iterator>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+//#include <stdlib.h>
+
+//#include "gudhi/graph_simplicial_complex.h"
+#include "gudhi/Witness_complex.h"
+#include "gudhi/reader_utils.h"
+#include "generators.h"
+#include "output.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_k_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_k_neighbor_search<STraits, CGAL::Distance_adapter<std::ptrdiff_t,Point_d*,Euclidean_distance>> K_neighbor_search;
+typedef K_neighbor_search::Tree Tree;
+typedef K_neighbor_search::Distance Distance;
+typedef K_neighbor_search::iterator KNS_iterator;
+typedef K_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;
+
+bool toric=false;
+
+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;
+}
+
+/** 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;
+ }
+ }
+
+/** \brief A test with 600cell, the generalisation of icosaedre in 4d
+ */
+void landmark_choice_600cell(Point_Vector&W, int nbP, int nbL, Point_Vector& landmarks, std::vector<int>& landmarks_ind)
+{
+ assert(W[0].size() == 4); //4-dimensionality required
+ FT phi = (1+sqrt(5))/2;
+ FT phi_1 = FT(1)/phi;
+ std::vector<FT> p;
+ // 16 vertices
+ for (FT a = -0.5; a < 1; a += 1)
+ for (FT b = -0.5; b < 1; b += 1)
+ for (FT c = -0.5; c < 1; c += 1)
+ for (FT d = -0.5; d < 1; d += 1)
+ landmarks.push_back(Point_d(std::vector<FT>({a,b,c,d})));
+ // 8 vertices
+ for (FT a = -0.5; a < 1; a += 1)
+ {
+ landmarks.push_back(Point_d(std::vector<FT>({a,0,0,0})));
+ landmarks.push_back(Point_d(std::vector<FT>({0,a,0,0})));
+ landmarks.push_back(Point_d(std::vector<FT>({0,0,a,0})));
+ landmarks.push_back(Point_d(std::vector<FT>({0,0,0,a})));
+ }
+ // 96 vertices
+ for (FT a = -phi/2; a < phi; a += phi)
+ for (FT b = -0.5; b < 1; b += 1)
+ for (FT c = -phi_1/2; c < phi_1; c += phi_1)
+ {
+ landmarks.push_back(Point_d(std::vector<FT>({a,b,c,0})));
+ landmarks.push_back(Point_d(std::vector<FT>({b,a,0,c})));
+ landmarks.push_back(Point_d(std::vector<FT>({c,0,a,b})));
+ landmarks.push_back(Point_d(std::vector<FT>({0,c,b,a})));
+ landmarks.push_back(Point_d(std::vector<FT>({a,c,0,b})));
+ landmarks.push_back(Point_d(std::vector<FT>({a,0,b,c})));
+ landmarks.push_back(Point_d(std::vector<FT>({c,b,0,a})));
+ landmarks.push_back(Point_d(std::vector<FT>({0,b,a,c})));
+ landmarks.push_back(Point_d(std::vector<FT>({b,0,c,a})));
+ landmarks.push_back(Point_d(std::vector<FT>({0,a,c,b})));
+ landmarks.push_back(Point_d(std::vector<FT>({b,c,a,0})));
+ landmarks.push_back(Point_d(std::vector<FT>({c,a,b,0})));
+ }
+ for (int i = 0; i < 120; ++i)
+ landmarks_ind.push_back(i);
+}
+
+int landmark_perturbation(Point_Vector &W, Point_Vector& landmarks, std::vector<int>& landmarks_ind)
+{
+ //********************Preface: origin point
+ clock_t start, end;
+ int D = W[0].size();
+ std::vector<FT> orig_vector;
+ for (int 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();
+ Euclidean_distance ed;
+ FT lambda = ed.transformed_distance(landmarks[0],landmarks[1]);
+ //std::cout << "Lambda=" << lambda << std::endl;
+ //FT lambda = 0.1;//Euclidean_distance();
+ STraits traits(&(landmarks[0]));
+ std::vector< std::vector <int> > WL(nbP);
+ Tree L(boost::counting_iterator<std::ptrdiff_t>(0),
+ boost::counting_iterator<std::ptrdiff_t>(nbL),
+ typename Tree::Splitter(),
+ traits);
+ /*Tree2 L2(boost::counting_iterator<std::ptrdiff_t>(0),
+ boost::counting_iterator<std::ptrdiff_t>(nbL),
+ typename Tree::Splitter(),
+ STraits(&(landmarks[0])));
+ */
+ std::cout << "Enter (D+1) nearest landmarks\n";
+ //std::cout << "Size of the tree is " << L.size() << std::endl;
+ start = clock();
+ for (int i = 0; i < nbP; i++)
+ {
+ //std::cout << "Entered witness number " << i << std::endl;
+ Point_d& w = W[i];
+ //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])) );
+ 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;
+ }
+ if (i == landmarks_ind[WL[i][0]])
+ {
+ //std::cout << "'";
+ FT dist = ed.transformed_distance(W[i], landmarks[WL[i][1]]);
+ if (dist < lambda)
+ lambda = dist;
+ }
+ }
+ //std::cout << "\n";
+ end = clock();
+ std::cout << "Landmark choice for " << nbL << " landmarks took "
+ << (double)(end-start)/CLOCKS_PER_SEC << " s. \n";
+ std::string out_file = "wl_result";
+ write_wl(out_file,WL);
+
+ //******************** Constructng a witness complex
+ std::cout << "Entered witness complex construction\n";
+ Witness_complex<> witnessComplex;
+ witnessComplex.setNbL(nbL);
+ start = clock();
+ witnessComplex.witness_complex(WL);
+ //
+ end = clock();
+ std::cout << "Howdy world! The process took "
+ << (double)(end-start)/CLOCKS_PER_SEC << " s. \n";
+ //witnessComplex.witness_complex(WL);
+ /*
+ if (witnessComplex.is_witness_complex(WL))
+ std::cout << "!!YES. IT IS A WITNESS COMPLEX!!\n";
+ else
+ std::cout << "??NO. IT IS NOT A WITNESS COMPLEX??\n";
+ */
+ //******************** Making a set of bad link landmarks
+ std::cout << "Entered bad links\n";
+ std::set< int > perturbL;
+ int count_badlinks = 0;
+ //std::cout << "Bad links around ";
+ std::vector< int > count_bad(D);
+ std::vector< int > count_good(D);
+ for (auto u: witnessComplex.complex_vertex_range())
+ if (!witnessComplex.has_good_link(u, count_bad, count_good))
+ {
+ //std::cout << "Landmark " << u << " start!" << std::endl;
+ //perturbL.insert(u);
+ count_badlinks++;
+ //std::cout << u << " ";
+ Point_d& l = landmarks[u];
+ Fuzzy_sphere fs(l, sqrt(lambda), 0, traits);
+ std::vector<int> curr_perturb;
+ L.search(std::insert_iterator<std::vector<int>>(curr_perturb,curr_perturb.begin()),fs);
+ for (int i: curr_perturb)
+ perturbL.insert(i%nbL);
+ //L.search(std::inserter(perturbL,perturbL.begin()),fs);
+ //L.search(std::ostream_iterator<int>(std::cout,"\n"),fs);
+ //std::cout << "PerturbL size is " << perturbL.size() << std::endl;
+ }
+ for (unsigned int i = 0; i != count_good.size(); i++)
+ if (count_good[i] != 0)
+ std::cout << "count_good[" << i << "] = " << count_good[i] << std::endl;
+ for (unsigned int i = 0; i != count_bad.size(); i++)
+ if (count_bad[i] != 0)
+ std::cout << "count_bad[" << i << "] = " << count_bad[i] << std::endl;
+ std::cout << "\nBad links total: " << count_badlinks << " Points to perturb: " << perturbL.size() << std::endl;
+ //std::cout << "landmark[0][0] before" << landmarks[0][0] << std::endl;
+ //*********************** Perturb bad link landmarks
+
+ for (auto u: perturbL)
+ {
+ Random_point_iterator rp(D,sqrt(lambda)/8*nbL/count_badlinks);
+ //std::cout << landmarks[u] << std::endl;
+
+ std::vector<FT> point;
+ for (int i = 0; i < D; i++)
+ {
+ while (K().squared_distance_d_object()(*rp,origin) < lambda/256)
+ rp++;
+ FT coord = W[landmarks_ind[u]][i] + (*rp)[i];
+ //FT coord = landmarks[u][i] + (*rp)[i];
+ if (coord > 1)
+ point.push_back(coord-1);
+ else if (coord < -1)
+ point.push_back(coord+1);
+ else
+ point.push_back(coord);
+ }
+ landmarks[u] = Point_d(point);
+ //std::cout << landmarks[u] << std::endl;
+ }
+
+ //std::cout << "landmark[0][0] after" << landmarks[0][0] << std::endl;
+ std::cout << "lambda=" << lambda << std::endl;
+
+ //std::cout << "WL size" << WL.size() << std::endl;
+ /*
+ std::cout << "L:" << std::endl;
+ for (int i = 0; i < landmarks.size(); i++)
+ std::cout << landmarks[i] << std::endl;
+ */
+
+ 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;
+ return count_badlinks;
+}
+
+
+int main (int argc, char * const argv[])
+{
+
+ if (argc != 4)
+ {
+ std::cerr << "Usage: " << argv[0]
+ << " nbP nbL dim\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]);
+ //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);
+ // witnessComplex.witness_complex_from_points(point_vector);
+ //int nbP = point_vector.size();
+ //std::vector<std::vector< int > > WL(nbP);
+ //std::set<int> L;
+ Point_Vector L;
+ std::vector<int> chosen_landmarks;
+ //Point_etiquette_map L_i;
+ //start = clock();
+ //witnessComplex.landmark_choice_by_furthest_points(point_vector, point_vector.size(), WL);
+ bool ok=false;
+ while (!ok)
+ {
+ ok = true;
+ L = {};
+ chosen_landmarks = {};
+ landmark_choice(point_vector, nbP, nbL, L, chosen_landmarks);
+ //landmark_choice_600cell(point_vector, nbP, nbL, L, chosen_landmarks);
+ /*
+ for (auto i: chosen_landmarks)
+ {
+ ok = ok && (std::count(chosen_landmarks.begin(),chosen_landmarks.end(),i) == 1);
+ if (!ok) break;
+ }
+ */
+ }
+ int bl = nbL, curr_min = bl;
+ //write_points("landmarks/initial_pointset",point_vector);
+ //write_points("landmarks/initial_landmarks",L);
+
+ for (int i = 0; bl > 0; i++)
+ //for (int i = 0; i < 1; i++)
+ {
+ std::cout << "========== Start iteration " << i << "== curr_min(" << curr_min << ")========\n";
+ bl=landmark_perturbation(point_vector, L, chosen_landmarks);
+ if (bl < curr_min)
+ curr_min=bl;
+ //write_points("landmarks/landmarks0",L);
+ }
+ //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/include/gudhi/Relaxed_witness_complex.h b/src/Witness_complex/include/gudhi/Relaxed_witness_complex.h
new file mode 100644
index 00000000..c869628f
--- /dev/null
+++ b/src/Witness_complex/include/gudhi/Relaxed_witness_complex.h
@@ -0,0 +1,886 @@
+/* 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 GUDHI_RELAXED_WITNESS_COMPLEX_H_
+#define GUDHI_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 {
+
+
+ /** \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<typename FiltrationValue = double,
+ typename SimplexKey = int,
+ typename VertexHandle = int>
+ class Witness_complex: public Simplex_tree<> {
+
+ private:
+
+ struct Active_witness {
+ int witness_id;
+ int landmark_id;
+ Simplex_handle simplex_handle;
+
+ Active_witness(int witness_id_, int landmark_id_, Simplex_handle simplex_handle_)
+ : witness_id(witness_id_),
+ landmark_id(landmark_id_),
+ simplex_handle(simplex_handle_)
+ {}
+ };
+
+
+
+
+ public:
+
+
+ /** \brief Type for the vertex handle.
+ *
+ * Must be a signed integer type. It admits a total order <. */
+ typedef VertexHandle Vertex_handle;
+
+ /* Type of node in the simplex tree. */
+ typedef Simplex_tree_node_explicit_storage<Simplex_tree> Node;
+ /* Type of dictionary Vertex_handle -> Node for traversing the simplex tree. */
+ typedef typename boost::container::flat_map<Vertex_handle, Node> Dictionary;
+ typedef typename Dictionary::iterator Simplex_handle;
+
+ typedef std::vector< double > Point_t;
+ typedef std::vector< Point_t > Point_Vector;
+
+ typedef std::vector< Vertex_handle > typeVectorVertex;
+ typedef std::pair< typeVectorVertex, Filtration_value> typeSimplex;
+ typedef std::pair< Simplex_tree<>::Simplex_handle, bool > typePairSimplexBool;
+
+ typedef int Witness_id;
+ typedef int Landmark_id;
+ typedef std::list< Vertex_handle > ActiveWitnessList;
+
+ private:
+ /** Number of landmarks
+ */
+ int nbL;
+ /** Desired density
+ */
+ double density;
+
+ public:
+
+ /** \brief Set number of landmarks to nbL_
+ */
+ void setNbL(int nbL_)
+ {
+ nbL = nbL_;
+ }
+
+ /** \brief Set density to density_
+ */
+ void setDensity(double density_)
+ {
+ density = density_;
+ }
+
+ /**
+ * /brief Iterative construction of the relaxed witness complex basing on a matrix of k nearest neighbours of the form {witnesses}x{landmarks} and (1+epsilon)-limit table {witnesses}*{landmarks} consisting of iterators of k nearest neighbor matrix.
+ * The line lengths can differ, however both matrices have the same corresponding line lengths.
+ */
+
+ template< typename KNearestNeighbours, typename OPELimits >
+ void relaxed_witness_complex(KNearestNeighbours & knn, OPELimits & rl)
+ //void witness_complex(std::vector< std::vector< Vertex_handle > > & knn)
+ {
+ std::cout << "**Start the procedure witness_complex" << std::endl;
+ //Construction of the active witness list
+ int nbW = knn.size();
+ //int nbL = knn.at(0).size();
+ typeVectorVertex vv;
+ //typeSimplex simplex;
+ //typePairSimplexBool returnValue;
+ //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};
+ 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 */
+ //std::cout << "Successfully added landmarks" << std::endl;
+ // PRINT2
+ //print_sc(root()); std::cout << std::endl;
+ for (int i=0; i != nbW; ++i)
+ active_w.push_back(i);
+ /*
+ int u,v; // two extremities of an edge
+ if (nbL > 1) // if the supposed dimension of the complex is >0
+ {
+ for (int i=0; i != nbW; ++i)
+ {
+ // initial fill of active witnesses list
+ u = knn[i][0];
+ v = knn[i][1];
+ vv = {u,v};
+ this->insert_simplex(vv,Filtration_value(0.0));
+ //print_sc(root()); std::cout << std::endl;
+ //std::cout << "Added edges" << std::endl;
+ }
+ //print_sc(root());
+
+ }
+ */
+ std::cout << "k=0, active witnesses: " << active_w.size() << std::endl;
+ //std::cout << "Successfully added edges" << std::endl;
+ //count_good = {0,0};
+ //count_bad = {0,0};
+ while (!active_w.empty() && k < nbL )
+ {
+ //count_good.push_back(0);
+ //count_bad.push_back(0);
+ //std::cout << "Started the step k=" << k << std::endl;
+ 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, knn[*aw_it].begin(), rl[*aw_it].begin(), simplex, knn[*aw_it].end(), knn[*aw_it].end());
+ if (!ok)
+ active_w.erase(aw_it++); //First increase the iterator and then erase the previous element
+ else
+ aw_it++;
+ }
+ std::cout << "k=" << k << ", active witnesses: " << active_w.size() << std::endl;
+ k++;
+ }
+ //print_sc(root()); std::cout << std::endl;
+ }
+
+ /* \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, std::vector<int>::iterator curr_l, typename std::vector< std::vector<int>::iterator >::iterator curr_until, std::vector<int>& simplex, std::vector<int>::iterator until, std::vector<int>::iterator end)
+ {
+ /*
+ std::ofstream ofs ("stree_result.txt", std::ofstream::out);
+ st_to_file(ofs);
+ ofs.close();
+ */
+ //print_sc(root());
+ bool will_be_active = false;
+ if (dim > 0)
+ for (std::vector<int>::iterator it = curr_l; it != until && it != end; ++it, ++curr_until)
+ {
+ simplex.push_back(*it);
+ if (find(simplex) != null_simplex())
+ will_be_active = will_be_active || add_all_faces_of_dimension(dim-1, it+1, curr_until+1, simplex, until, end);
+ simplex.pop_back();
+ if (until == end)
+ until = *curr_until;
+ }
+ else if (dim == 0)
+ for (std::vector<int>::iterator it = curr_l; it != until && it != end; ++it, ++curr_until)
+ {
+ simplex.push_back(*it);
+ if (all_faces_in(simplex))
+ {
+ will_be_active = true;
+ insert_simplex(simplex, 0.0);
+ }
+ simplex.pop_back();
+ if (until == end)
+ until = *curr_until;
+ }
+ return will_be_active;
+ }
+
+ /** \brief Construction of witness complex from points given explicitly
+ * nbL must be set to the right value of landmarks for strategies
+ * FURTHEST_POINT_STRATEGY and RANDOM_POINT_STRATEGY and
+ * density must be set to the right value for DENSITY_STRATEGY
+ */
+ // void witness_complex_from_points(Point_Vector point_vector)
+ // {
+ // std::vector<std::vector< int > > WL;
+ // landmark_choice_by_random_points(point_vector, point_vector.size(), WL);
+ // witness_complex(WL);
+ // }
+
+private:
+
+ /** \brief Print functions
+ */
+ void print_sc(Siblings * sibl)
+ {
+ if (sibl == NULL)
+ std::cout << "&";
+ else
+ print_children(sibl->members_);
+ }
+
+ void print_children(Dictionary map)
+ {
+ std::cout << "(";
+ if (!map.empty())
+ {
+ std::cout << map.begin()->first;
+ if (has_children(map.begin()))
+ print_sc(map.begin()->second.children());
+ typename Dictionary::iterator it;
+ for (it = map.begin()+1; it != map.end(); ++it)
+ {
+ std::cout << "," << it->first;
+ if (has_children(it))
+ print_sc(it->second.children());
+ }
+ }
+ std::cout << ")";
+ }
+
+ public:
+ /** \brief Print functions
+ */
+
+ void st_to_file(std::ofstream& out_file)
+ {
+ sc_to_file(out_file, root());
+ }
+
+ private:
+ void sc_to_file(std::ofstream& out_file, Siblings * sibl)
+ {
+ assert(sibl);
+ children_to_file(out_file, sibl->members_);
+ }
+
+ void children_to_file(std::ofstream& out_file, Dictionary& map)
+ {
+ out_file << "(" << std::flush;
+ if (!map.empty())
+ {
+ out_file << map.begin()->first << std::flush;
+ if (has_children(map.begin()))
+ sc_to_file(out_file, map.begin()->second.children());
+ typename Dictionary::iterator it;
+ for (it = map.begin()+1; it != map.end(); ++it)
+ {
+ out_file << "," << it->first << std::flush;
+ if (has_children(it))
+ sc_to_file(out_file, it->second.children());
+ }
+ }
+ out_file << ")" << std::flush;
+ }
+
+
+ /** \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)
+ {
+ //std::cout << "All face in with the landmark " << inserted_vertex << std::endl;
+ std::vector< VertexHandle > facet;
+ //VertexHandle curr_vh = curr_sh->first;
+ // CHECK ALL THE FACETS
+ for (std::vector<int>::iterator not_it = simplex.begin(); not_it != simplex.end(); ++not_it)
+ {
+ facet.clear();
+ //facet = {};
+ for (std::vector<int>::iterator it = simplex.begin(); it != simplex.end(); ++it)
+ if (it != not_it)
+ facet.push_back(*it);
+ if (find(facet) == null_simplex())
+ return false;
+ } //endfor
+ return true;
+ }
+
+ 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 << "]";
+ }
+
+ template <typename T>
+ void print_vvector(std::vector< std::vector <T> > vv)
+ {
+ std::cout << "[";
+ if (!vv.empty())
+ {
+ print_vector(*(vv.begin()));
+ for (auto it = vv.begin()+1; it != vv.end(); ++it)
+ {
+ std::cout << ",";
+ print_vector(*it);
+ }
+ }
+ std::cout << "]\n";
+ }
+
+ public:
+/**
+ * \brief Landmark choice strategy by iteratively adding the landmark the furthest from the
+ * current landmark set
+ * \arg W is the vector of points which will be the witnesses
+ * \arg nbP is the number of witnesses
+ * \arg nbL is the number of landmarks
+ * \arg WL is the matrix of the nearest landmarks with respect to witnesses (output)
+ */
+
+ template <typename KNearestNeighbours>
+ void landmark_choice_by_furthest_points(Point_Vector &W, int nbP, KNearestNeighbours &WL)
+ {
+ //std::cout << "Enter landmark_choice_by_furthest_points "<< std::endl;
+ //std::cout << "W="; print_vvector(W);
+ //double density = 5.;
+ Point_Vector wit_land_dist(nbP,std::vector<double>()); // distance matrix witness x landmarks
+ typeVectorVertex chosen_landmarks; // landmark list
+
+ WL = KNearestNeighbours(nbP,std::vector<int>());
+ int current_number_of_landmarks=0; // counter for landmarks
+ double curr_max_dist = 0; // used for defining the furhest point from L
+ double curr_dist; // used to stock the distance from the current point to L
+ double infty = std::numeric_limits<double>::infinity(); // infinity (see next entry)
+ std::vector< double > dist_to_L(nbP,infty); // vector of current distances to L from points
+ // double mindist = infty;
+ int curr_max_w=0; // the point currently furthest from L
+ int j;
+ int temp_swap_int;
+ double temp_swap_double;
+
+ //CHOICE OF THE FIRST LANDMARK
+ std::cout << "Enter the first landmark stage\n";
+ srand(354698);
+ int rand_int = rand()% nbP;
+ curr_max_w = rand_int; //For testing purposes a pseudo-random number is used here
+
+ for (current_number_of_landmarks = 0; current_number_of_landmarks != nbL; current_number_of_landmarks++)
+ {
+ //curr_max_w at this point is the next landmark
+ chosen_landmarks.push_back(curr_max_w);
+ //std::cout << "**********Entered loop with current number of landmarks = " << current_number_of_landmarks << std::endl;
+ //std::cout << "WL="; print_vvector(WL);
+ //std::cout << "WLD="; print_vvector(wit_land_dist);
+ //std::cout << "landmarks="; print_vector(chosen_landmarks); std::cout << std::endl;
+ for (auto v: WL)
+ v.push_back(current_number_of_landmarks);
+ for (int i = 0; i < nbP; ++i)
+ {
+ // iteration on points in W. update of distance vectors
+
+ //std::cout << "In the loop with i=" << i << " and landmark=" << chosen_landmarks[current_number_of_landmarks] << std::endl;
+ //std::cout << "W[i]="; print_vector(W[i]); std::cout << " W[landmark]="; print_vector(W[chosen_landmarks[current_number_of_landmarks]]); std::cout << std::endl;
+ curr_dist = euclidean_distance(W[i],W[chosen_landmarks[current_number_of_landmarks]]);
+ //std::cout << "The problem is not in distance function\n";
+ wit_land_dist[i].push_back(curr_dist);
+ WL[i].push_back(current_number_of_landmarks);
+ //std::cout << "Push't back\n";
+ if (curr_dist < dist_to_L[i])
+ dist_to_L[i] = curr_dist;
+ j = current_number_of_landmarks;
+ //std::cout << "First half complete\n";
+ while (j > 0 && wit_land_dist[i][j-1] > wit_land_dist[i][j])
+ {
+ // sort the closest landmark vector for every witness
+ temp_swap_int = WL[i][j];
+ WL[i][j] = WL[i][j-1];
+ WL[i][j-1] = temp_swap_int;
+ temp_swap_double = wit_land_dist[i][j];
+ wit_land_dist[i][j] = wit_land_dist[i][j-1];
+ wit_land_dist[i][j-1] = temp_swap_double;
+ --j;
+ }
+ //std::cout << "result WL="; print_vvector(WL);
+ //std::cout << "result WLD="; print_vvector(wit_land_dist);
+ //std::cout << "result distL="; print_vector(dist_to_L); std::cout << std::endl;
+ //std::cout << "End loop\n";
+ }
+ //std::cout << "Distance to landmarks="; print_vector(dist_to_L); std::cout << std::endl;
+ curr_max_dist = 0;
+ for (int i = 0; i < nbP; ++i) {
+ if (dist_to_L[i] > curr_max_dist)
+ {
+ curr_max_dist = dist_to_L[i];
+ curr_max_w = i;
+ }
+ }
+ //std::cout << "Chose " << curr_max_w << " as new landmark\n";
+ }
+ //std::cout << endl;
+ }
+
+ /** \brief Landmark choice strategy by taking random vertices for landmarks.
+ *
+ */
+
+ // template <typename KNearestNeighbours>
+ // void landmark_choice_by_random_points(Point_Vector &W, int nbP, KNearestNeighbours &WL)
+ // {
+ // std::cout << "Enter landmark_choice_by_random_points "<< std::endl;
+ // //std::cout << "W="; print_vvector(W);
+ // std::unordered_set< int > chosen_landmarks; // landmark set
+
+ // Point_Vector wit_land_dist(nbP,std::vector<double>()); // distance matrix witness x landmarks
+
+ // WL = KNearestNeighbours(nbP,std::vector<int>());
+ // int current_number_of_landmarks=0; // counter for landmarks
+
+ // srand(24660);
+ // int chosen_landmark = rand()%nbP;
+ // double curr_dist;
+
+ // //int j;
+ // //int temp_swap_int;
+ // //double temp_swap_double;
+
+
+ // for (current_number_of_landmarks = 0; current_number_of_landmarks != nbL; current_number_of_landmarks++)
+ // {
+ // while (chosen_landmarks.find(chosen_landmark) != chosen_landmarks.end())
+ // {
+ // srand((int)clock());
+ // chosen_landmark = rand()% nbP;
+ // //std::cout << chosen_landmark << "\n";
+ // }
+ // chosen_landmarks.insert(chosen_landmark);
+ // //std::cout << "**********Entered loop with current number of landmarks = " << current_number_of_landmarks << std::endl;
+ // //std::cout << "WL="; print_vvector(WL);
+ // //std::cout << "WLD="; print_vvector(wit_land_dist);
+ // //std::cout << "landmarks="; print_vector(chosen_landmarks); std::cout << std::endl;
+ // for (auto v: WL)
+ // v.push_back(current_number_of_landmarks);
+ // for (int i = 0; i < nbP; ++i)
+ // {
+ // // iteration on points in W. update of distance vectors
+
+ // //std::cout << "In the loop with i=" << i << " and landmark=" << chosen_landmarks[current_number_of_landmarks] << std::endl;
+ // //std::cout << "W[i]="; print_vector(W[i]); std::cout << " W[landmark]="; print_vector(W[chosen_landmarks[current_number_of_landmarks]]); std::cout << std::endl;
+ // curr_dist = euclidean_distance(W[i],W[chosen_landmark]);
+ // //std::cout << "The problem is not in distance function\n";
+ // wit_land_dist[i].push_back(curr_dist);
+ // WL[i].push_back(current_number_of_landmarks);
+ // //std::cout << "Push't back\n";
+ // //j = current_number_of_landmarks;
+ // //std::cout << "First half complete\n";
+ // //std::cout << "result WL="; print_vvector(WL);
+ // //std::cout << "result WLD="; print_vvector(wit_land_dist);
+ // //std::cout << "End loop\n";
+ // }
+ // }
+ // for (int i = 0; i < nbP; i++)
+ // {
+ // sort(WL[i].begin(), WL[i].end(), [&](int j1, int j2){return wit_land_dist[i][j1] < wit_land_dist[i][j2];});
+ // }
+ // //std::cout << endl;
+ // }
+
+ /** \brief Landmark choice strategy by taking random vertices for landmarks.
+ *
+ */
+
+ // template <typename KNearestNeighbours>
+ void landmark_choice_by_random_points(Point_Vector &W, int nbP, std::set<int> &L)
+ {
+ std::cout << "Enter landmark_choice_by_random_points "<< std::endl;
+ //std::cout << "W="; print_vvector(W);
+ //std::unordered_set< int > chosen_landmarks; // landmark set
+
+ //Point_Vector wit_land_dist(nbP,std::vector<double>()); // distance matrix witness x landmarks
+
+ //WL = KNearestNeighbours(nbP,std::vector<int>());
+ int current_number_of_landmarks=0; // counter for landmarks
+
+ srand(24660);
+ int chosen_landmark = rand()%nbP;
+ //double curr_dist;
+ //int j;
+ //int temp_swap_int;
+ //double temp_swap_double;
+ for (current_number_of_landmarks = 0; current_number_of_landmarks != nbL; current_number_of_landmarks++)
+ {
+ while (L.find(chosen_landmark) != L.end())
+ {
+ srand((int)clock());
+ chosen_landmark = rand()% nbP;
+ //std::cout << chosen_landmark << "\n";
+ }
+ L.insert(chosen_landmark);
+ //std::cout << "**********Entered loop with current number of landmarks = " << current_number_of_landmarks << std::endl;
+ //std::cout << "WL="; print_vvector(WL);
+ //std::cout << "WLD="; print_vvector(wit_land_dist);
+ //std::cout << "landmarks="; print_vector(chosen_landmarks); std::cout << std::endl;
+ // for (auto v: WL)
+ // v.push_back(current_number_of_landmarks);
+ // for (int i = 0; i < nbP; ++i)
+ // {
+ // // iteration on points in W. update of distance vectors
+
+ // //std::cout << "In the loop with i=" << i << " and landmark=" << chosen_landmarks[current_number_of_landmarks] << std::endl;
+ // //std::cout << "W[i]="; print_vector(W[i]); std::cout << " W[landmark]="; print_vector(W[chosen_landmarks[current_number_of_landmarks]]); std::cout << std::endl;
+ // curr_dist = euclidean_distance(W[i],W[chosen_landmark]);
+ // //std::cout << "The problem is not in distance function\n";
+ // wit_land_dist[i].push_back(curr_dist);
+ // WL[i].push_back(current_number_of_landmarks);
+ // //std::cout << "Push't back\n";
+ // //j = current_number_of_landmarks;
+ // //std::cout << "First half complete\n";
+ // //std::cout << "result WL="; print_vvector(WL);
+ // //std::cout << "result WLD="; print_vvector(wit_land_dist);
+ // //std::cout << "End loop\n";
+ // }
+ }
+ // for (int i = 0; i < nbP; i++)
+ // {
+ // sort(WL[i].begin(), WL[i].end(), [&](int j1, int j2){return wit_land_dist[i][j1] < wit_land_dist[i][j2];});
+ // }
+ //std::cout << endl;
+ }
+
+
+ /** \brief Construct the matrix |W|x(D+1) of D+1 closest landmarks
+ * where W is the set of witnesses and D is the ambient dimension
+ */
+ template <typename KNearestNeighbours>
+ void nearest_landmarks(Point_Vector &W, std::set<int> &L, KNearestNeighbours &WL)
+ {
+ int D = W[0].size();
+ int nbP = W.size();
+ WL = KNearestNeighbours(nbP,std::vector<int>());
+ typedef std::pair<double,int> dist_i;
+ typedef bool (*comp)(dist_i,dist_i);
+ for (int W_i = 0; W_i < nbP; W_i++)
+ {
+ //std::cout << "<<<<<<<<<<<<<<" << W_i <<"\n";
+ std::priority_queue<dist_i, std::vector<dist_i>, comp> l_heap([&](dist_i j1, dist_i j2){return j1.first > j2.first;});
+ std::set<int>::iterator L_it;
+ int L_i;
+ for (L_it = L.begin(), L_i=0; L_it != L.end(); L_it++, L_i++)
+ {
+ dist_i dist = std::make_pair(euclidean_distance(W[W_i],W[*L_it]), L_i);
+ l_heap.push(dist);
+ }
+ for (int i = 0; i < D+1; i++)
+ {
+ dist_i dist = l_heap.top();
+ WL[W_i].push_back(dist.second);
+ //WL[W_i].insert(WL[W_i].begin(),dist.second);
+ //std::cout << dist.first << " " << dist.second << std::endl;
+ l_heap.pop();
+ }
+ }
+ }
+
+ /** \brief Search and output links around vertices that are not pseudomanifolds
+ *
+ */
+ void write_bad_links(std::ofstream& out_file)
+ {
+ out_file << "Bad links list\n";
+ std::cout << "Entered write_bad_links\n";
+ //typeVectorVertex testv = {9,15,17};
+ //int count = 0;
+ for (auto v: complex_vertex_range())
+ {
+ //std::cout << "Vertex " << v << ":\n";
+ std::vector< Vertex_handle > link_vertices;
+ // Fill link_vertices
+ for (auto u: complex_vertex_range())
+ {
+ typeVectorVertex edge = {u,v};
+ if (u != v && find(edge) != null_simplex())
+ link_vertices.push_back(u);
+ }
+ /*
+ print_vector(link_vertices);
+ std::cout << "\n";
+ */
+ // Find the dimension
+ typeVectorVertex empty_simplex = {};
+ int d = link_dim(link_vertices, link_vertices.begin(),-1, empty_simplex);
+ //std::cout << " dim " << d << "\n";
+ //Siblings* curr_sibl = root();
+ if (link_is_pseudomanifold(link_vertices,d))
+ count_good[d]++;
+ //out_file << "Bad link at " << v << "\n";
+ }
+ //out_file << "Number of bad links: " << count << "/" << root()->size();
+ //std::cout << "Number of bad links: " << count << "/" << root()->size() << std::endl;
+ nc = nbL;
+ for (unsigned int i = 0; i != count_good.size(); i++)
+ {
+ out_file << "count_good[" << i << "] = " << count_good[i] << std::endl;
+ nc -= count_good[i];
+ if (count_good[i] != 0)
+ std::cout << "count_good[" << i << "] = " << count_good[i] << std::endl;
+ }
+ for (unsigned int i = 0; i != count_bad.size(); i++)
+ {
+ out_file << "count_bad[" << i << "] = " << count_bad[i] << std::endl;
+ nc -= count_bad[i];
+ if (count_bad[i] != 0)
+ std::cout << "count_bad[" << i << "] = " << count_bad[i] << std::endl;
+ }
+ std::cout << "not_connected = " << nc << std::endl;
+ }
+
+ private:
+
+ std::vector<int> count_good;
+ std::vector<int> count_bad;
+ int nc;
+
+ int link_dim(std::vector< Vertex_handle >& link_vertices,
+ typename std::vector< Vertex_handle >::iterator curr_v,
+ int curr_d,
+ typeVectorVertex& curr_simplex)
+ {
+ //std::cout << "Entered link_dim for " << *(curr_v-1) << "\n";
+ Simplex_handle sh;
+ int final_d = curr_d;
+ typename std::vector< Vertex_handle >::iterator it;
+ for (it = curr_v; it != link_vertices.end(); ++it)
+ {
+ curr_simplex.push_back(*it);
+ /*
+ std::cout << "Searching for ";
+ print_vector(curr_simplex);
+ std::cout << " curr_dim " << curr_d << " final_dim " << final_d;
+ */
+ sh = find(curr_simplex);
+ if (sh != null_simplex())
+ {
+ //std::cout << " -> " << *it << "\n";
+ int d = link_dim(link_vertices, it+1, curr_d+1, curr_simplex);
+ if (d > final_d)
+ final_d = d;
+ }
+ /*
+ else
+ std::cout << "\n";
+ */
+ curr_simplex.pop_back();
+ }
+ return final_d;
+ }
+
+ // color is false is a (d-1)-dim face, true is a d-dim face
+ //typedef bool Color;
+ // graph is an adjacency list
+ typedef typename boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> Adj_graph;
+ // map that gives to a certain simplex its node in graph and its dimension
+ //typedef std::pair<boost::vecS,Color> Reference;
+ typedef boost::graph_traits<Adj_graph>::vertex_descriptor Vertex_t;
+ typedef boost::graph_traits<Adj_graph>::edge_descriptor Edge_t;
+
+ typedef boost::container::flat_map<Simplex_handle, Vertex_t> Graph_map;
+
+ /* \brief Verifies if the simplices formed by vertices given by link_vertices
+ * form a pseudomanifold.
+ * The idea is to make a bipartite graph, where vertices are the d- and (d-1)-dimensional
+ * faces and edges represent adjacency between them.
+ */
+ bool link_is_pseudomanifold(std::vector< Vertex_handle >& link_vertices,
+ int dimension)
+ {
+ Adj_graph adj_graph;
+ Graph_map d_map, f_map; // d_map = map for d-dimensional simplices
+ // f_map = map for its facets
+ typeVectorVertex empty_vector = {};
+ add_vertices(link_vertices,
+ link_vertices.begin(),
+ adj_graph,
+ d_map,
+ f_map,
+ empty_vector,
+ 0, dimension);
+ //std::cout << "DMAP_SIZE: " << d_map.size() << "\n";
+ //std::cout << "FMAP_SIZE: " << f_map.size() << "\n";
+ add_edges(adj_graph, d_map, f_map);
+ for (auto f_map_it : f_map)
+ {
+ //std::cout << "Degree of " << f_map_it.first->first << " is " << boost::out_degree(f_map_it.second, adj_graph) << "\n";
+ if (boost::out_degree(f_map_it.second, adj_graph) != 2)
+ {
+ count_bad[dimension]++;
+ return false;
+ }
+ }
+ // At this point I know that all (d-1)-simplices are adjacent to exactly 2 d-simplices
+ // What is left is to check the connexity
+ std::vector<int> components(boost::num_vertices(adj_graph));
+ return (boost::connected_components(adj_graph, &components[0]) == 1);
+ }
+
+ void add_vertices(typeVectorVertex& link_vertices,
+ typename typeVectorVertex::iterator curr_v,
+ Adj_graph& adj_graph,
+ Graph_map& d_map,
+ Graph_map& f_map,
+ typeVectorVertex& curr_simplex,
+ int curr_d,
+ int dimension)
+ {
+ Simplex_handle sh;
+ Vertex_t vert;
+ typename typeVectorVertex::iterator it;
+ std::pair<typename Graph_map::iterator,bool> resPair;
+ //typename Graph_map::iterator resPair;
+ //Add vertices
+ //std::cout << "Entered add vertices\n";
+ for (it = curr_v; it != link_vertices.end(); ++it)
+ {
+ curr_simplex.push_back(*it);
+ /*
+ std::cout << "Searching for ";
+ print_vector(curr_simplex);
+ std::cout << " curr_dim " << curr_d << " d " << dimension << "";
+ */
+ sh = find(curr_simplex);
+ if (sh != null_simplex())
+ {
+ //std::cout << " added\n";
+ if (curr_d == dimension)
+ {
+ vert = boost::add_vertex(adj_graph);
+ resPair = d_map.emplace(sh,vert);
+ }
+ else
+ {
+ if (curr_d == dimension-1)
+ {
+ vert = boost::add_vertex(adj_graph);
+ resPair = f_map.emplace(sh,vert);
+ }
+ add_vertices(link_vertices,
+ it+1,
+ adj_graph,
+ d_map,
+ f_map,
+ curr_simplex,
+ curr_d+1, dimension);
+ }
+ }
+ /*
+ else
+ std::cout << "\n";
+ */
+ curr_simplex.pop_back();
+ }
+ }
+
+ void add_edges(Adj_graph& adj_graph,
+ Graph_map& d_map,
+ Graph_map& f_map)
+ {
+ Simplex_handle sh;
+ // Add edges
+ //std::cout << "Entered add edges:\n";
+ typename Graph_map::iterator map_it;
+ for (auto d_map_pair : d_map)
+ {
+ //std::cout << "*";
+ sh = d_map_pair.first;
+ Vertex_t d_vert = d_map_pair.second;
+ for (auto facet_sh : boundary_simplex_range(sh))
+ //for (auto f_map_it : f_map)
+ {
+ //std::cout << "'";
+ map_it = f_map.find(facet_sh);
+ //We must have all the facets in the graph at this point
+ assert(map_it != f_map.end());
+ Vertex_t f_vert = map_it->second;
+ //std::cout << "Added edge " << sh->first << "-" << map_it->first->first << "\n";
+ boost::add_edge(d_vert,f_vert,adj_graph);
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////
+ //***********COLLAPSES**************************************************************************//
+ //////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+
+}; //class Witness_complex
+
+
+
+} // namespace Guhdi
+
+#endif
diff --git a/src/Witness_complex/include/gudhi/Witness_complex.h b/src/Witness_complex/include/gudhi/Witness_complex.h
new file mode 100644
index 00000000..201d6525
--- /dev/null
+++ b/src/Witness_complex/include/gudhi/Witness_complex.h
@@ -0,0 +1,1111 @@
+/* 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 GUDHI_WITNESS_COMPLEX_H_
+#define GUDHI_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/Delaunay_triangulation.h>
+//#include <CGAL/Epick_d.h>
+//#include <CGAL/K_neighbor_search.h>
+//#include <CGAL/Search_traits_d.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>
+
+namespace Gudhi {
+
+
+ /** \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<typename FiltrationValue = double,
+ typename SimplexKey = int,
+ typename VertexHandle = int>
+ class Witness_complex: public Simplex_tree<> {
+
+ private:
+
+ struct Active_witness {
+ int witness_id;
+ int landmark_id;
+ Simplex_handle simplex_handle;
+
+ Active_witness(int witness_id_, int landmark_id_, Simplex_handle simplex_handle_)
+ : witness_id(witness_id_),
+ landmark_id(landmark_id_),
+ simplex_handle(simplex_handle_)
+ {}
+ };
+
+
+
+
+ public:
+
+
+ /** \brief Type for the vertex handle.
+ *
+ * Must be a signed integer type. It admits a total order <. */
+ typedef VertexHandle Vertex_handle;
+
+ /* Type of node in the simplex tree. */
+ typedef Simplex_tree_node_explicit_storage<Simplex_tree> Node;
+ /* Type of dictionary Vertex_handle -> Node for traversing the simplex tree. */
+ typedef typename boost::container::flat_map<Vertex_handle, Node> Dictionary;
+ typedef typename Dictionary::iterator Simplex_handle;
+
+ typedef std::vector< double > Point_t;
+ typedef std::vector< Point_t > Point_Vector;
+
+ typedef std::vector< Vertex_handle > typeVectorVertex;
+ typedef std::pair< typeVectorVertex, Filtration_value> typeSimplex;
+ typedef std::pair< Simplex_tree<>::Simplex_handle, bool > typePairSimplexBool;
+
+ typedef int Witness_id;
+ typedef int Landmark_id;
+ typedef std::list< Vertex_handle > ActiveWitnessList;
+
+ private:
+ /** Number of landmarks
+ */
+ int nbL;
+ /** Desired density
+ */
+ double density;
+
+ public:
+
+ /** \brief Set number of landmarks to nbL_
+ */
+ void setNbL(int nbL_)
+ {
+ nbL = nbL_;
+ }
+
+ /** \brief Set density to density_
+ */
+ void setDensity(double density_)
+ {
+ density = density_;
+ }
+
+ /**
+ * /brief Iterative construction of the witness complex basing on a matrix of k nearest neighbours of the form {witnesses}x{landmarks}.
+ * Landmarks are supposed to be in [0,nbL-1]
+ */
+
+ template< typename KNearestNeighbours >
+ void witness_complex(KNearestNeighbours & knn)
+ //void witness_complex(std::vector< std::vector< Vertex_handle > > & knn)
+ {
+ std::cout << "**Start the procedure witness_complex" << std::endl;
+ //Construction of the active witness list
+ int nbW = knn.size();
+ //int nbL = knn.at(0).size();
+ typeVectorVertex vv;
+ typeSimplex simplex;
+ typePairSimplexBool returnValue;
+ 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};
+ returnValue = 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 */
+ //std::cout << "Successfully added landmarks" << std::endl;
+ // PRINT2
+ //print_sc(root()); std::cout << std::endl;
+ /*
+ int u,v; // two extremities of an edge
+ int count = 0;
+ if (nbL > 1) // if the supposed dimension of the complex is >0
+ {
+ for (int i=0; i != nbW; ++i)
+ {
+ // initial fill of active witnesses list
+ u = knn[i][0];
+ v = knn[i][1];
+ vv = {u,v};
+ returnValue = this->insert_simplex(vv,Filtration_value(0.0));
+ if (returnValue.second)
+ count++;
+ //print_sc(root()); std::cout << std::endl;
+ //std::cout << "Added edges" << std::endl;
+ }
+ std::cout << "The number of edges = " << count << std::endl;
+ count = 0;
+ //print_sc(root());
+ for (int i=0; i != nbW; ++i)
+ {
+ // initial fill of active witnesses list
+ u = knn[i][0];
+ v = knn[i][1];
+ if ( u > v)
+ {
+ u = v;
+ v = knn[i][0];
+ knn[i][0] = knn[i][1];
+ knn[i][1] = v;
+ }
+ Simplex_handle sh;
+ vv = {u,v};
+ //if (u==v) std::cout << "Bazzinga!\n";
+ sh = (root()->find(u))->second.children()->find(v);
+ active_w.push_back(i);
+ }
+ }
+ */
+ for (int i=0; i != nbW; ++i)
+ active_w.push_back(i);
+ std::cout << "k=0, active witnesses: " << active_w.size() << std::endl;
+ //std::cout << "Successfully added edges" << std::endl;
+ count_good = {0};
+ count_bad = {0};
+ int D = knn[0].size();
+ while (!active_w.empty() && k < D )
+ {
+ count_good.push_back(0);
+ count_bad.push_back(0);
+ //std::cout << "Started the step k=" << k << std::endl;
+ typename ActiveWitnessList::iterator it = active_w.begin();
+ while (it != active_w.end())
+ {
+ typeVectorVertex simplex_vector;
+ /* THE INSERTION: Checking if all the subfaces are in the simplex tree*/
+ bool ok = all_faces_in(knn, *it, k);
+ if (ok)
+ {
+ for (int i = 0; i != k+1; ++i)
+ simplex_vector.push_back(knn[*it][i]);
+ returnValue = insert_simplex(simplex_vector,0.0);
+ it++;
+ }
+ else
+ active_w.erase(it++); //First increase the iterator and then erase the previous element
+ }
+ std::cout << "k=" << k << ", active witnesses: " << active_w.size() << std::endl;
+ //std::cout << "** k=" << k << ", num_simplices: " <<count << std::endl;
+ k++;
+ }
+ //print_sc(root()); std::cout << std::endl;
+ }
+
+ /** \brief Construction of witness complex from points given explicitly
+ * nbL must be set to the right value of landmarks for strategies
+ * FURTHEST_POINT_STRATEGY and RANDOM_POINT_STRATEGY and
+ * density must be set to the right value for DENSITY_STRATEGY
+ */
+ // void witness_complex_from_points(Point_Vector point_vector)
+ // {
+ // std::vector<std::vector< int > > WL;
+ // landmark_choice_by_random_points(point_vector, point_vector.size(), WL);
+ // witness_complex(WL);
+ // }
+
+private:
+
+ /** \brief Print functions
+ */
+ void print_sc(Siblings * sibl)
+ {
+ if (sibl == NULL)
+ std::cout << "&";
+ else
+ print_children(sibl->members_);
+ }
+
+ void print_children(Dictionary map)
+ {
+ std::cout << "(";
+ if (!map.empty())
+ {
+ std::cout << map.begin()->first;
+ if (has_children(map.begin()))
+ print_sc(map.begin()->second.children());
+ typename Dictionary::iterator it;
+ for (it = map.begin()+1; it != map.end(); ++it)
+ {
+ std::cout << "," << it->first;
+ if (has_children(it))
+ print_sc(it->second.children());
+ }
+ }
+ std::cout << ")";
+ }
+
+ public:
+ /** \brief Print functions
+ */
+
+ void st_to_file(std::ofstream& out_file)
+ {
+ sc_to_file(out_file, root());
+ }
+
+ private:
+ void sc_to_file(std::ofstream& out_file, Siblings * sibl)
+ {
+ assert(sibl);
+ children_to_file(out_file, sibl->members_);
+ }
+
+ void children_to_file(std::ofstream& out_file, Dictionary& map)
+ {
+ out_file << "(" << std::flush;
+ if (!map.empty())
+ {
+ out_file << map.begin()->first << std::flush;
+ if (has_children(map.begin()))
+ sc_to_file(out_file, map.begin()->second.children());
+ typename Dictionary::iterator it;
+ for (it = map.begin()+1; it != map.end(); ++it)
+ {
+ out_file << "," << it->first << std::flush;
+ if (has_children(it))
+ sc_to_file(out_file, it->second.children());
+ }
+ }
+ out_file << ")" << std::flush;
+ }
+
+
+ /** \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 KNearestNeighbours>
+ bool all_faces_in(KNearestNeighbours &knn, int witness_id, int k)
+ {
+ //std::cout << "All face in with the landmark " << inserted_vertex << std::endl;
+ std::vector< VertexHandle > facet;
+ //VertexHandle 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 (find(facet) == null_simplex())
+ return false;
+ //std::cout << "++++ finished loop safely\n";
+ } //endfor
+ return true;
+ }
+
+ 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 << "]";
+ }
+
+ template <typename T>
+ void print_vvector(std::vector< std::vector <T> > vv)
+ {
+ std::cout << "[";
+ if (!vv.empty())
+ {
+ print_vector(*(vv.begin()));
+ for (auto it = vv.begin()+1; it != vv.end(); ++it)
+ {
+ std::cout << ",";
+ print_vector(*it);
+ }
+ }
+ std::cout << "]\n";
+ }
+
+ public:
+/**
+ * \brief Landmark choice strategy by iteratively adding the landmark the furthest from the
+ * current landmark set
+ * \arg W is the vector of points which will be the witnesses
+ * \arg nbP is the number of witnesses
+ * \arg nbL is the number of landmarks
+ * \arg WL is the matrix of the nearest landmarks with respect to witnesses (output)
+ */
+
+ template <typename KNearestNeighbours>
+ void landmark_choice_by_furthest_points(Point_Vector &W, int nbP, KNearestNeighbours &WL)
+ {
+ //std::cout << "Enter landmark_choice_by_furthest_points "<< std::endl;
+ //std::cout << "W="; print_vvector(W);
+ //double density = 5.;
+ Point_Vector wit_land_dist(nbP,std::vector<double>()); // distance matrix witness x landmarks
+ typeVectorVertex chosen_landmarks; // landmark list
+
+ WL = KNearestNeighbours(nbP,std::vector<int>());
+ int current_number_of_landmarks=0; // counter for landmarks
+ double curr_max_dist = 0; // used for defining the furhest point from L
+ double curr_dist; // used to stock the distance from the current point to L
+ double infty = std::numeric_limits<double>::infinity(); // infinity (see next entry)
+ std::vector< double > dist_to_L(nbP,infty); // vector of current distances to L from points
+ // double mindist = infty;
+ int curr_max_w=0; // the point currently furthest from L
+ int j;
+ int temp_swap_int;
+ double temp_swap_double;
+
+ //CHOICE OF THE FIRST LANDMARK
+ std::cout << "Enter the first landmark stage\n";
+ srand(354698);
+ int rand_int = rand()% nbP;
+ curr_max_w = rand_int; //For testing purposes a pseudo-random number is used here
+
+ for (current_number_of_landmarks = 0; current_number_of_landmarks != nbL; current_number_of_landmarks++)
+ {
+ //curr_max_w at this point is the next landmark
+ chosen_landmarks.push_back(curr_max_w);
+ //std::cout << "**********Entered loop with current number of landmarks = " << current_number_of_landmarks << std::endl;
+ //std::cout << "WL="; print_vvector(WL);
+ //std::cout << "WLD="; print_vvector(wit_land_dist);
+ //std::cout << "landmarks="; print_vector(chosen_landmarks); std::cout << std::endl;
+ for (auto v: WL)
+ v.push_back(current_number_of_landmarks);
+ for (int i = 0; i < nbP; ++i)
+ {
+ // iteration on points in W. update of distance vectors
+
+ //std::cout << "In the loop with i=" << i << " and landmark=" << chosen_landmarks[current_number_of_landmarks] << std::endl;
+ //std::cout << "W[i]="; print_vector(W[i]); std::cout << " W[landmark]="; print_vector(W[chosen_landmarks[current_number_of_landmarks]]); std::cout << std::endl;
+ curr_dist = euclidean_distance(W[i],W[chosen_landmarks[current_number_of_landmarks]]);
+ //std::cout << "The problem is not in distance function\n";
+ wit_land_dist[i].push_back(curr_dist);
+ WL[i].push_back(current_number_of_landmarks);
+ //std::cout << "Push't back\n";
+ if (curr_dist < dist_to_L[i])
+ dist_to_L[i] = curr_dist;
+ j = current_number_of_landmarks;
+ //std::cout << "First half complete\n";
+ while (j > 0 && wit_land_dist[i][j-1] > wit_land_dist[i][j])
+ {
+ // sort the closest landmark vector for every witness
+ temp_swap_int = WL[i][j];
+ WL[i][j] = WL[i][j-1];
+ WL[i][j-1] = temp_swap_int;
+ temp_swap_double = wit_land_dist[i][j];
+ wit_land_dist[i][j] = wit_land_dist[i][j-1];
+ wit_land_dist[i][j-1] = temp_swap_double;
+ --j;
+ }
+ //std::cout << "result WL="; print_vvector(WL);
+ //std::cout << "result WLD="; print_vvector(wit_land_dist);
+ //std::cout << "result distL="; print_vector(dist_to_L); std::cout << std::endl;
+ //std::cout << "End loop\n";
+ }
+ //std::cout << "Distance to landmarks="; print_vector(dist_to_L); std::cout << std::endl;
+ curr_max_dist = 0;
+ for (int i = 0; i < nbP; ++i) {
+ if (dist_to_L[i] > curr_max_dist)
+ {
+ curr_max_dist = dist_to_L[i];
+ curr_max_w = i;
+ }
+ }
+ //std::cout << "Chose " << curr_max_w << " as new landmark\n";
+ }
+ //std::cout << endl;
+ }
+
+ /** \brief Landmark choice strategy by taking random vertices for landmarks.
+ *
+ */
+
+ // template <typename KNearestNeighbours>
+ // void landmark_choice_by_random_points(Point_Vector &W, int nbP, KNearestNeighbours &WL)
+ // {
+ // std::cout << "Enter landmark_choice_by_random_points "<< std::endl;
+ // //std::cout << "W="; print_vvector(W);
+ // std::unordered_set< int > chosen_landmarks; // landmark set
+
+ // Point_Vector wit_land_dist(nbP,std::vector<double>()); // distance matrix witness x landmarks
+
+ // WL = KNearestNeighbours(nbP,std::vector<int>());
+ // int current_number_of_landmarks=0; // counter for landmarks
+
+ // srand(24660);
+ // int chosen_landmark = rand()%nbP;
+ // double curr_dist;
+
+ // //int j;
+ // //int temp_swap_int;
+ // //double temp_swap_double;
+
+
+ // for (current_number_of_landmarks = 0; current_number_of_landmarks != nbL; current_number_of_landmarks++)
+ // {
+ // while (chosen_landmarks.find(chosen_landmark) != chosen_landmarks.end())
+ // {
+ // srand((int)clock());
+ // chosen_landmark = rand()% nbP;
+ // //std::cout << chosen_landmark << "\n";
+ // }
+ // chosen_landmarks.insert(chosen_landmark);
+ // //std::cout << "**********Entered loop with current number of landmarks = " << current_number_of_landmarks << std::endl;
+ // //std::cout << "WL="; print_vvector(WL);
+ // //std::cout << "WLD="; print_vvector(wit_land_dist);
+ // //std::cout << "landmarks="; print_vector(chosen_landmarks); std::cout << std::endl;
+ // for (auto v: WL)
+ // v.push_back(current_number_of_landmarks);
+ // for (int i = 0; i < nbP; ++i)
+ // {
+ // // iteration on points in W. update of distance vectors
+
+ // //std::cout << "In the loop with i=" << i << " and landmark=" << chosen_landmarks[current_number_of_landmarks] << std::endl;
+ // //std::cout << "W[i]="; print_vector(W[i]); std::cout << " W[landmark]="; print_vector(W[chosen_landmarks[current_number_of_landmarks]]); std::cout << std::endl;
+ // curr_dist = euclidean_distance(W[i],W[chosen_landmark]);
+ // //std::cout << "The problem is not in distance function\n";
+ // wit_land_dist[i].push_back(curr_dist);
+ // WL[i].push_back(current_number_of_landmarks);
+ // //std::cout << "Push't back\n";
+ // //j = current_number_of_landmarks;
+ // //std::cout << "First half complete\n";
+ // //std::cout << "result WL="; print_vvector(WL);
+ // //std::cout << "result WLD="; print_vvector(wit_land_dist);
+ // //std::cout << "End loop\n";
+ // }
+ // }
+ // for (int i = 0; i < nbP; i++)
+ // {
+ // sort(WL[i].begin(), WL[i].end(), [&](int j1, int j2){return wit_land_dist[i][j1] < wit_land_dist[i][j2];});
+ // }
+ // //std::cout << endl;
+ // }
+
+ /** \brief Landmark choice strategy by taking random vertices for landmarks.
+ *
+ */
+
+ // template <typename KNearestNeighbours>
+ void landmark_choice_by_random_points(Point_Vector &W, int nbP, std::set<int> &L)
+ {
+ std::cout << "Enter landmark_choice_by_random_points "<< std::endl;
+ //std::cout << "W="; print_vvector(W);
+ //std::unordered_set< int > chosen_landmarks; // landmark set
+
+ //Point_Vector wit_land_dist(nbP,std::vector<double>()); // distance matrix witness x landmarks
+
+ //WL = KNearestNeighbours(nbP,std::vector<int>());
+ int current_number_of_landmarks=0; // counter for landmarks
+
+ srand(24660);
+ int chosen_landmark = rand()%nbP;
+ //double curr_dist;
+ //int j;
+ //int temp_swap_int;
+ //double temp_swap_double;
+ for (current_number_of_landmarks = 0; current_number_of_landmarks != nbL; current_number_of_landmarks++)
+ {
+ while (L.find(chosen_landmark) != L.end())
+ {
+ srand((int)clock());
+ chosen_landmark = rand()% nbP;
+ //std::cout << chosen_landmark << "\n";
+ }
+ L.insert(chosen_landmark);
+ //std::cout << "**********Entered loop with current number of landmarks = " << current_number_of_landmarks << std::endl;
+ //std::cout << "WL="; print_vvector(WL);
+ //std::cout << "WLD="; print_vvector(wit_land_dist);
+ //std::cout << "landmarks="; print_vector(chosen_landmarks); std::cout << std::endl;
+ // for (auto v: WL)
+ // v.push_back(current_number_of_landmarks);
+ // for (int i = 0; i < nbP; ++i)
+ // {
+ // // iteration on points in W. update of distance vectors
+
+ // //std::cout << "In the loop with i=" << i << " and landmark=" << chosen_landmarks[current_number_of_landmarks] << std::endl;
+ // //std::cout << "W[i]="; print_vector(W[i]); std::cout << " W[landmark]="; print_vector(W[chosen_landmarks[current_number_of_landmarks]]); std::cout << std::endl;
+ // curr_dist = euclidean_distance(W[i],W[chosen_landmark]);
+ // //std::cout << "The problem is not in distance function\n";
+ // wit_land_dist[i].push_back(curr_dist);
+ // WL[i].push_back(current_number_of_landmarks);
+ // //std::cout << "Push't back\n";
+ // //j = current_number_of_landmarks;
+ // //std::cout << "First half complete\n";
+ // //std::cout << "result WL="; print_vvector(WL);
+ // //std::cout << "result WLD="; print_vvector(wit_land_dist);
+ // //std::cout << "End loop\n";
+ // }
+ }
+ // for (int i = 0; i < nbP; i++)
+ // {
+ // sort(WL[i].begin(), WL[i].end(), [&](int j1, int j2){return wit_land_dist[i][j1] < wit_land_dist[i][j2];});
+ // }
+ //std::cout << endl;
+ }
+
+
+ /** \brief Construct the matrix |W|x(D+1) of D+1 closest landmarks
+ * where W is the set of witnesses and D is the ambient dimension
+ */
+ template <typename KNearestNeighbours>
+ void nearest_landmarks(Point_Vector &W, std::set<int> &L, KNearestNeighbours &WL)
+ {
+ int D = W[0].size();
+ int nbP = W.size();
+ WL = KNearestNeighbours(nbP,std::vector<int>());
+ typedef std::pair<double,int> dist_i;
+ typedef bool (*comp)(dist_i,dist_i);
+ for (int W_i = 0; W_i < nbP; W_i++)
+ {
+ //std::cout << "<<<<<<<<<<<<<<" << W_i <<"\n";
+ std::priority_queue<dist_i, std::vector<dist_i>, comp> l_heap([&](dist_i j1, dist_i j2){return j1.first > j2.first;});
+ std::set<int>::iterator L_it;
+ int L_i;
+ for (L_it = L.begin(), L_i=0; L_it != L.end(); L_it++, L_i++)
+ {
+ dist_i dist = std::make_pair(euclidean_distance(W[W_i],W[*L_it]), L_i);
+ l_heap.push(dist);
+ }
+ for (int i = 0; i < D+1; i++)
+ {
+ dist_i dist = l_heap.top();
+ WL[W_i].push_back(dist.second);
+ //WL[W_i].insert(WL[W_i].begin(),dist.second);
+ //std::cout << dist.first << " " << dist.second << std::endl;
+ l_heap.pop();
+ }
+ }
+ }
+
+ /** \brief Returns true if the link is good
+ */
+ bool has_good_link(Vertex_handle v, std::vector< int >& bad_count, std::vector< int >& good_count)
+ {
+ std::vector< Vertex_handle > star_vertices;
+ // Fill star_vertices
+ star_vertices.push_back(v);
+ for (auto u: complex_vertex_range())
+ {
+ typeVectorVertex edge = {u,v};
+ if (u != v && find(edge) != null_simplex())
+ star_vertices.push_back(u);
+ }
+ // Find the dimension
+ typeVectorVertex init_simplex = {star_vertices[0]};
+ bool is_pure = true;
+ std::vector<int> dim_coface(star_vertices.size(), 1);
+ int d = star_dim(star_vertices, star_vertices.begin()+1, 0, init_simplex, dim_coface.begin()+1) - 1; //link_dim = star_dim - 1
+ assert(init_simplex.size() == 1);
+ if (!is_pure)
+ std::cout << "Found an impure star around " << v << "\n";
+ for (int dc: dim_coface)
+ is_pure = (dc == dim_coface[0]);
+ /*
+ if (d == count_good.size())
+ {
+ std::cout << "Found a star of dimension " << (d+1) << " around " << v << "\nThe star is ";
+ print_vector(star_vertices); std::cout << std::endl;
+ }
+ */
+ //if (d == -1) bad_count[0]++;
+ bool b= (is_pure && link_is_pseudomanifold(star_vertices,d));
+ if (d != -1) {if (b) good_count[d]++; else bad_count[d]++;}
+ if (!is_pure) bad_count[0]++;
+ return (d != -1 && b && is_pure);
+
+ }
+
+ /** \brief Search and output links around vertices that are not pseudomanifolds
+ *
+ */
+ /*
+ void write_bad_links(std::ofstream& out_file)
+ {
+ out_file << "Bad links list\n";
+ std::cout << "Entered write_bad_links\n";
+ for (auto v: complex_vertex_range())
+ {
+ std::cout << "Vertex " << v << ": ";
+ std::vector< Vertex_handle > link_vertices;
+ // Fill link_vertices
+ for (auto u: complex_vertex_range())
+ {
+ typeVectorVertex edge = {u,v};
+ if (u != v && find(edge) != null_simplex())
+ link_vertices.push_back(u);
+ }
+
+ print_vector(link_vertices);
+ std::cout << "\n";
+
+ // Find the dimension
+ typeVectorVertex empty_simplex = {};
+ int d = link_dim(link_vertices, link_vertices.begin(),-1, empty_simplex);
+ if (link_is_pseudomanifold(link_vertices,d))
+ count_good[d]++;
+ }
+ nc = nbL;
+ for (unsigned int i = 0; i != count_good.size(); i++)
+ {
+ out_file << "count_good[" << i << "] = " << count_good[i] << std::endl;
+ nc -= count_good[i];
+ if (count_good[i] != 0)
+ std::cout << "count_good[" << i << "] = " << count_good[i] << std::endl;
+ }
+ for (unsigned int i = 0; i != count_bad.size(); i++)
+ {
+ out_file << "count_bad[" << i << "] = " << count_bad[i] << std::endl;
+ nc -= count_bad[i];
+ if (count_bad[i] != 0)
+ std::cout << "count_bad[" << i << "] = " << count_bad[i] << std::endl;
+ }
+ std::cout << "not_connected = " << nc << std::endl;
+ }
+ */
+ private:
+
+ std::vector<int> count_good;
+ std::vector<int> count_bad;
+ int nc;
+
+ int star_dim(std::vector< Vertex_handle >& star_vertices,
+ typename std::vector< Vertex_handle >::iterator curr_v,
+ int curr_d,
+ typeVectorVertex& curr_simplex,
+ typename std::vector< int >::iterator curr_dc)
+ {
+ //std::cout << "Entered star_dim for " << *(curr_v-1) << "\n";
+ Simplex_handle sh;
+ int final_d = curr_d;
+ typename std::vector< Vertex_handle >::iterator it;
+ typename std::vector< Vertex_handle >::iterator dc_it;
+ //std::cout << "Current vertex is " <<
+ for (it = curr_v, dc_it = curr_dc; it != star_vertices.end(); ++it, ++dc_it)
+ {
+ curr_simplex.push_back(*it);
+ typeVectorVertex curr_simplex_copy(curr_simplex);
+ /*
+ std::cout << "Searching for ";
+ print_vector(curr_simplex);
+ std::cout << " curr_dim " << curr_d << " final_dim " << final_d;
+ */
+ sh = find(curr_simplex_copy); //Need a copy because find sorts the vector and I want star center to be the first
+ if (sh != null_simplex())
+ {
+ //std::cout << " -> " << *it << "\n";
+ int d = star_dim(star_vertices, it+1, curr_d+1, curr_simplex, dc_it);
+ if (d >= final_d)
+ {
+ final_d = d;
+ //std::cout << d << " ";
+ //print_vector(curr_simplex);
+ //std::cout << std::endl;
+ }
+ if (d >= *dc_it)
+ *dc_it = d;
+ }
+ /*
+ else
+ std::cout << "\n";
+ */
+ curr_simplex.pop_back();
+ }
+ return final_d;
+ }
+
+ // color is false is a (d-1)-dim face, true is a d-dim face
+ //typedef bool Color;
+ // graph is an adjacency list
+ typedef typename boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> Adj_graph;
+ // map that gives to a certain simplex its node in graph and its dimension
+ //typedef std::pair<boost::vecS,Color> Reference;
+ typedef boost::graph_traits<Adj_graph>::vertex_descriptor Vertex_t;
+ typedef boost::graph_traits<Adj_graph>::edge_descriptor Edge_t;
+ typedef boost::graph_traits<Adj_graph>::adjacency_iterator Adj_it;
+ typedef std::pair<Adj_it, Adj_it> Out_edge_it;
+
+ typedef boost::container::flat_map<Simplex_handle, Vertex_t> Graph_map;
+ typedef boost::container::flat_map<Vertex_t, Simplex_handle> Inv_graph_map;
+
+ /* \brief Verifies if the simplices formed by vertices given by link_vertices
+ * form a pseudomanifold.
+ * The idea is to make a bipartite graph, where vertices are the d- and (d-1)-dimensional
+ * faces and edges represent adjacency between them.
+ */
+ bool link_is_pseudomanifold(std::vector< Vertex_handle >& star_vertices,
+ int dimension)
+ {
+ Adj_graph adj_graph;
+ Graph_map d_map, f_map; // d_map = map for d-dimensional simplices
+ // f_map = map for its facets
+ typeVectorVertex init_vector = {};
+ add_vertices_to_link_graph(star_vertices,
+ star_vertices.begin()+1,
+ adj_graph,
+ d_map,
+ f_map,
+ init_vector,
+ 0, dimension);
+ //std::cout << "DMAP_SIZE: " << d_map.size() << "\n";
+ //std::cout << "FMAP_SIZE: " << f_map.size() << "\n";
+ add_edges_to_link_graph(adj_graph, d_map, f_map);
+ for (auto f_map_it : f_map)
+ {
+ //std::cout << "Degree of " << f_map_it.first->first << " is " << boost::out_degree(f_map_it.second, adj_graph) << "\n";
+ if (boost::out_degree(f_map_it.second, adj_graph) != 2)
+ {
+ /*
+ if (boost::out_degree(f_map_it.second, adj_graph) >= 3)
+ {
+ std::cout << "This simplex has 3+ cofaces: ";
+ for(auto v : simplex_vertex_range(f_map_it.first))
+ std::cout << v << " ";
+ std::cout << std::endl;
+ Adj_it ai, ai_end;
+ for (std::tie(ai, ai_end) = boost::adjacent_vertices(f_map_it.second, adj_graph); ai != ai_end; ++ai)
+ {
+
+ }
+ }
+ */
+ count_bad[dimension]++;
+ return false;
+ }
+ }
+ // At this point I know that all (d-1)-simplices are adjacent to exactly 2 d-simplices
+ // What is left is to check the connexity
+ //std::vector<int> components(boost::num_vertices(adj_graph));
+ return true; //Forget the connexity
+ //return (boost::connected_components(adj_graph, &components[0]) == 1);
+ }
+
+ public:
+bool complex_is_pseudomanifold(int dimension)
+ {
+ Adj_graph adj_graph;
+ Graph_map d_map, f_map; // d_map = map for d-dimensional simplices
+ // f_map = map for its facets
+ Inv_graph_map inv_d_map;
+ typeVectorVertex init_vector = {};
+ std::vector<int> star_vertices;
+ for (int v: complex_vertex_range())
+ star_vertices.push_back(v);
+ add_max_simplices_to_graph(star_vertices,
+ star_vertices.begin(),
+ adj_graph,
+ d_map,
+ f_map,
+ inv_d_map,
+ init_vector,
+ 0, dimension);
+ std::cout << "DMAP_SIZE: " << d_map.size() << "\n";
+ std::cout << "FMAP_SIZE: " << f_map.size() << "\n";
+ add_edges_to_link_graph(adj_graph, d_map, f_map);
+ for (auto f_map_it : f_map)
+ {
+ //std::cout << "Degree of " << f_map_it.first->first << " is " << boost::out_degree(f_map_it.second, adj_graph) << "\n";
+ if (boost::out_degree(f_map_it.second, adj_graph) != 2)
+ {
+ if (boost::out_degree(f_map_it.second, adj_graph) >= 3)
+ {
+ std::cout << "This simplex has 3+ cofaces: ";
+ for(auto v : simplex_vertex_range(f_map_it.first))
+ std::cout << v << " ";
+ std::cout << std::endl;
+ Adj_it ai, ai_end;
+ for (std::tie(ai, ai_end) = boost::adjacent_vertices(f_map_it.second, adj_graph); ai != ai_end; ++ai)
+ {
+ auto it = inv_d_map.find(*ai);
+ assert (it != inv_d_map.end());
+ Simplex_handle sh = it->second;
+ for(auto v : simplex_vertex_range(sh))
+ std::cout << v << " ";
+ std::cout << std::endl;
+ }
+ }
+ count_bad[dimension]++;
+ return false;
+ }
+ }
+ // At this point I know that all (d-1)-simplices are adjacent to exactly 2 d-simplices
+ // What is left is to check the connexity
+ //std::vector<int> components(boost::num_vertices(adj_graph));
+ return true; //Forget the connexity
+ //return (boost::connected_components(adj_graph, &components[0]) == 1);
+ }
+
+ private:
+ void add_vertices_to_link_graph(typeVectorVertex& star_vertices,
+ typename typeVectorVertex::iterator curr_v,
+ Adj_graph& adj_graph,
+ Graph_map& d_map,
+ Graph_map& f_map,
+ typeVectorVertex& curr_simplex,
+ int curr_d,
+ int link_dimension)
+ {
+ Simplex_handle sh;
+ Vertex_t vert;
+ typename typeVectorVertex::iterator it;
+ //std::pair<typename Graph_map::iterator,bool> resPair;
+ //typename Graph_map::iterator resPair;
+ //Add vertices
+ //std::cout << "Entered add vertices\n";
+ for (it = curr_v; it != star_vertices.end(); ++it)
+ {
+ curr_simplex.push_back(*it); //push next vertex in question
+ curr_simplex.push_back(star_vertices[0]); //push the center of the star
+ /*
+ std::cout << "Searching for ";
+ print_vector(curr_simplex);
+ std::cout << " curr_dim " << curr_d << " d " << dimension << "";
+ */
+ typeVectorVertex curr_simplex_copy(curr_simplex);
+ sh = find(curr_simplex_copy); //a simplex of the star
+ curr_simplex.pop_back(); //pop the center of the star
+ curr_simplex_copy = typeVectorVertex(curr_simplex);
+ if (sh != null_simplex())
+ {
+ //std::cout << " added\n";
+ if (curr_d == link_dimension)
+ {
+ sh = find(curr_simplex_copy); //a simplex of the link
+ assert(sh != null_simplex()); //ASSERT!
+ vert = boost::add_vertex(adj_graph);
+ d_map.emplace(sh,vert);
+ }
+ else
+ {
+
+ if (curr_d == link_dimension-1)
+ {
+ sh = find(curr_simplex_copy); //a simplex of the link
+ assert(sh != null_simplex());
+ vert = boost::add_vertex(adj_graph);
+ f_map.emplace(sh,vert);
+ }
+
+ //delete (&curr_simplex_copy); //Just so it doesn't stack
+ add_vertices_to_link_graph(star_vertices,
+ it+1,
+ adj_graph,
+ d_map,
+ f_map,
+ curr_simplex,
+ curr_d+1, link_dimension);
+ }
+ }
+ /*
+ else
+ std::cout << "\n";
+ */
+ curr_simplex.pop_back(); //pop the vertex in question
+ }
+ }
+
+ void add_edges_to_link_graph(Adj_graph& adj_graph,
+ Graph_map& d_map,
+ Graph_map& f_map)
+ {
+ Simplex_handle sh;
+ // Add edges
+ //std::cout << "Entered add edges:\n";
+ typename Graph_map::iterator map_it;
+ for (auto d_map_pair : d_map)
+ {
+ //std::cout << "*";
+ sh = d_map_pair.first;
+ Vertex_t d_vert = d_map_pair.second;
+ for (auto facet_sh : boundary_simplex_range(sh))
+ //for (auto f_map_it : f_map)
+ {
+ //std::cout << "'";
+ map_it = f_map.find(facet_sh);
+ //We must have all the facets in the graph at this point
+ assert(map_it != f_map.end());
+ Vertex_t f_vert = map_it->second;
+ //std::cout << "Added edge " << sh->first << "-" << map_it->first->first << "\n";
+ boost::add_edge(d_vert,f_vert,adj_graph);
+ }
+ }
+ }
+
+ void add_max_simplices_to_graph(typeVectorVertex& star_vertices,
+ typename typeVectorVertex::iterator curr_v,
+ Adj_graph& adj_graph,
+ Graph_map& d_map,
+ Graph_map& f_map,
+ Inv_graph_map& inv_d_map,
+ typeVectorVertex& curr_simplex,
+ int curr_d,
+ int link_dimension)
+ {
+ Simplex_handle sh;
+ Vertex_t vert;
+ typename typeVectorVertex::iterator it;
+ //std::pair<typename Graph_map::iterator,bool> resPair;
+ //typename Graph_map::iterator resPair;
+ //Add vertices
+ //std::cout << "Entered add vertices\n";
+ for (it = curr_v; it != star_vertices.end(); ++it)
+ {
+ curr_simplex.push_back(*it); //push next vertex in question
+ //curr_simplex.push_back(star_vertices[0]); //push the center of the star
+ /*
+ std::cout << "Searching for ";
+ print_vector(curr_simplex);
+ std::cout << " curr_dim " << curr_d << " d " << dimension << "";
+ */
+ typeVectorVertex curr_simplex_copy(curr_simplex);
+ sh = find(curr_simplex_copy); //a simplex of the star
+ //curr_simplex.pop_back(); //pop the center of the star
+ curr_simplex_copy = typeVectorVertex(curr_simplex);
+ if (sh != null_simplex())
+ {
+ //std::cout << " added\n";
+ if (curr_d == link_dimension)
+ {
+ sh = find(curr_simplex_copy); //a simplex of the link
+ assert(sh != null_simplex()); //ASSERT!
+ vert = boost::add_vertex(adj_graph);
+ d_map.emplace(sh,vert);
+ inv_d_map.emplace(vert,sh);
+ }
+ else
+ {
+
+ if (curr_d == link_dimension-1)
+ {
+ sh = find(curr_simplex_copy); //a simplex of the link
+ assert(sh != null_simplex());
+ vert = boost::add_vertex(adj_graph);
+ f_map.emplace(sh,vert);
+ }
+
+ //delete (&curr_simplex_copy); //Just so it doesn't stack
+ add_max_simplices_to_graph(star_vertices,
+ it+1,
+ adj_graph,
+ d_map,
+ f_map,
+ inv_d_map,
+ curr_simplex,
+ curr_d+1, link_dimension);
+ }
+ }
+ /*
+ else
+ std::cout << "\n";
+ */
+ curr_simplex.pop_back(); //pop the vertex in question
+ }
+ }
+
+ public:
+ /** \brief Verification if every simplex in the complex is witnessed
+ */
+ template< class KNearestNeighbors >
+ bool is_witness_complex(KNearestNeighbors WL)
+ {
+ //bool final_result = true;
+ for (Simplex_handle sh: complex_simplex_range())
+ {
+ bool is_witnessed = false;
+ typeVectorVertex simplex;
+ int nbV = 0; //number of verticed in the simplex
+ for (int v: simplex_vertex_range(sh))
+ simplex.push_back(v);
+ nbV = simplex.size();
+ for (typeVectorVertex w: WL)
+ {
+ 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;
+ 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)
+ {
+ std::cout << "The following simplex is not witnessed ";
+ print_vector(simplex);
+ std::cout << std::endl;
+ assert(is_witnessed);
+ return false;
+ }
+ }
+ return true; // Arrive here if the not_witnessed check failed all the time
+ }
+
+
+}; //class Witness_complex
+
+
+
+} // namespace Guhdi
+
+#endif