diff options
author | skachano <skachano@636b058d-ea47-450e-bf9e-a15bfbe3eedb> | 2015-12-07 14:45:43 +0000 |
---|---|---|
committer | skachano <skachano@636b058d-ea47-450e-bf9e-a15bfbe3eedb> | 2015-12-07 14:45:43 +0000 |
commit | c4078affdbf6fac7150c10ade96fcb72270ac013 (patch) | |
tree | 1ad197bb90078a56036a49c6ee3766a032f85e63 | |
parent | f70e386fc98f1dbd8287d1cb7cc715710a8f751b (diff) | |
parent | 061e43a2a48525bc5a69482a1ea80f20ff505e55 (diff) |
Merged with trunk and removed unnecessary files
git-svn-id: svn+ssh://scm.gforge.inria.fr/svnroot/gudhi/branches/witness@934 636b058d-ea47-450e-bf9e-a15bfbe3eedb
Former-commit-id: d0ec52d222d22c102e9fe57590882cd0024c82d5
165 files changed, 10570 insertions, 18212 deletions
diff --git a/CMakeGUDHIVersion.txt b/CMakeGUDHIVersion.txt new file mode 100644 index 00000000..19d10535 --- /dev/null +++ b/CMakeGUDHIVersion.txt @@ -0,0 +1,6 @@ +set (GUDHI_MAJOR_VERSION 1) +set (GUDHI_MINOR_VERSION 2) +set (GUDHI_PATCH_VERSION 0) +set(GUDHI_VERSION ${GUDHI_MAJOR_VERSION}.${GUDHI_MINOR_VERSION}.${GUDHI_PATCH_VERSION}) + +message(STATUS "GUDHI version : ${GUDHI_VERSION}") diff --git a/CMakeLists.txt b/CMakeLists.txt index 57cb14d4..609b5eb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,10 @@ cmake_minimum_required(VERSION 2.6) project(GUDHIdev) +include(CMakeGUDHIVersion.txt) +# Generate GUDHI official version file +configure_file(GUDHIVersion.cmake.in "${PROJECT_BINARY_DIR}/GUDHIVersion.cmake" @ONLY) + find_package(Boost REQUIRED COMPONENTS system filesystem unit_test_framework chrono timer program_options thread REQUIRED) set(CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/src/cmake/modules/") @@ -23,7 +27,6 @@ set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_MULTITHREADED ON) set(Boost_USE_STATIC_RUNTIME OFF) -find_package(Boost) #find_package(GMP) #if(GMP_FOUND) #find_package(GMPXX) @@ -67,9 +70,9 @@ else() LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) message(STATUS "boost include dirs:" ${Boost_INCLUDE_DIRS}) + message(STATUS "boost library dirs:" ${Boost_LIBRARY_DIRS}) include_directories(src/common/include/) - include_directories(src/Alpha_shapes/include/) include_directories(src/Bottleneck/include/) include_directories(src/Contraction/include/) include_directories(src/Hasse_complex/include/) @@ -85,17 +88,21 @@ else() add_subdirectory(src/Skeleton_blocker/test) add_subdirectory(src/Skeleton_blocker/example) add_subdirectory(src/Contraction/example) - add_subdirectory(src/Hasse_complex/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/Alpha_shapes/example) + # add_subdirectory(src/Alpha_shapes/test) add_subdirectory(src/Bottleneck/example) add_subdirectory(src/Bottleneck/test) # data points generator add_subdirectory(data/points/generator) + # Please let GudhUI in last compilation position as QT is known to modify CMAKE_CXX_FLAGS + # GudhUI + add_subdirectory(src/GudhUI) + endif() diff --git a/GUDHIVersion.cmake.in b/GUDHIVersion.cmake.in new file mode 100644 index 00000000..2f433c1c --- /dev/null +++ b/GUDHIVersion.cmake.in @@ -0,0 +1 @@ +@GUDHI_VERSION@ diff --git a/Version.txt b/Version.txt deleted file mode 100644 index 9084fa2f..00000000 --- a/Version.txt +++ /dev/null @@ -1 +0,0 @@ -1.1.0 diff --git a/biblio/how_to_cite_gudhi.bib b/biblio/how_to_cite_gudhi.bib new file mode 100644 index 00000000..851dd5d9 --- /dev/null +++ b/biblio/how_to_cite_gudhi.bib @@ -0,0 +1,44 @@ +@book{gudhi:urm +, title = "{GUDHI} User and Reference Manual" +, author = "{The GUDHI Project}" +, publisher = "{GUDHI Editorial Board}" +, year = 2015 +, url = "http://gudhi.gforge.inria.fr/doc/latest/" +} + +@incollection{gudhi:FilteredComplexes +, author = "Cl\'ement Maria" +, title = "Filtered Complexes" +, publisher = "{GUDHI Editorial Board}" +, booktitle = "{GUDHI} User and Reference Manual" +, url = "http://gudhi.gforge.inria.fr/doc/latest/group__simplex__tree.html" +, year = 2015 +} + +@incollection{gudhi:PersistentCohomology +, author = "Cl\'ement Maria" +, title = "Persistent Cohomology" +, publisher = "{GUDHI Editorial Board}" +, booktitle = "{GUDHI} User and Reference Manual" +, url = "http://gudhi.gforge.inria.fr/doc/latest/group__persistent__cohomology.html" +, year = 2015 +} + +@incollection{gudhi:Contraction +, author = "David Salinas" +, title = "Contraction" +, publisher = "{GUDHI Editorial Board}" +, booktitle = "{GUDHI} User and Reference Manual" +, url = "http://gudhi.gforge.inria.fr/doc/latest/group__contr.html" +, year = 2015 +} + +@incollection{gudhi:Skeleton-Blocker +, author = "David Salinas" +, title = "Skeleton-Blocker" +, publisher = "{GUDHI Editorial Board}" +, booktitle = "{GUDHI} User and Reference Manual" +, url = "http://gudhi.gforge.inria.fr/doc/latest/group__skbl.html" +, year = 2015 +} + diff --git a/data/points/generator/CMakeLists.txt b/data/points/generator/CMakeLists.txt index 0f2674c4..26b44446 100644 --- a/data/points/generator/CMakeLists.txt +++ b/data/points/generator/CMakeLists.txt @@ -4,7 +4,22 @@ project(GUDHIPointsGenerator) if(CGAL_FOUND) if (NOT CGAL_VERSION VERSION_LESS 4.6.0) message(STATUS "CGAL version: ${CGAL_VERSION}.") + include( ${CGAL_USE_FILE} ) + # In CMakeLists.txt, when include(${CGAL_USE_FILE}), CXX_FLAGS are overwritten. + # cf. http://doc.cgal.org/latest/Manual/installation.html#title40 + # A workaround is to add "-std=c++11" again. + # A fix would be to use https://cmake.org/cmake/help/v3.1/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.html + # or even better https://cmake.org/cmake/help/v3.1/variable/CMAKE_CXX_STANDARD.html + # but it implies to use cmake version 3.1 at least. + if(NOT MSVC) + include(CheckCXXCompilerFlag) + CHECK_CXX_COMPILER_FLAG(-std=c++11 COMPILER_SUPPORTS_CXX11) + if(COMPILER_SUPPORTS_CXX11) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + endif() + endif() + # - End of workaround find_package(Eigen3 3.1.0) if (EIGEN3_FOUND) @@ -21,6 +36,6 @@ if(CGAL_FOUND) add_test(hypergenerator_in_cube_50000_2 ${CMAKE_CURRENT_BINARY_DIR}/hypergenerator in cube inCube.off 50000 3) endif() else() - message(WARNING "CGAL version: ${CGAL_VERSION} is too old to compile Alpha shapes feature. Version 4.6.0 is required.") + message(WARNING "CGAL version: ${CGAL_VERSION} is too old to compile hypergenerator. Version 4.6.0 is required.") endif () endif() diff --git a/data/points/generator/hypergenerator.cpp b/data/points/generator/hypergenerator.cpp index f4ea6b07..60890b44 100644 --- a/data/points/generator/hypergenerator.cpp +++ b/data/points/generator/hypergenerator.cpp @@ -35,8 +35,9 @@ typedef CGAL::Epick_d< CGAL::Dynamic_dimension_tag > K; typedef K::Point_d Point; void usage(char * const progName) { - std::cerr << "Usage: " << progName << " in|on sphere|cube off_file_name points_number[integer > 0] dimension[integer > 1] radius[double > 0.0 | default = 1.0]" << std::endl; - exit(-1); // ----- >> + std::cerr << "Usage: " << progName << " in|on sphere|cube off_file_name points_number[integer > 0] " << + "dimension[integer > 1] radius[double > 0.0 | default = 1.0]" << std::endl; + exit(-1); } int main(int argc, char **argv) { @@ -86,8 +87,13 @@ int main(int argc, char **argv) { } std::ofstream diagram_out(argv[3]); - diagram_out << "OFF" << std::endl; - diagram_out << points_number << " 0 0" << std::endl; + if (dimension == 3) { + diagram_out << "OFF" << std::endl; + diagram_out << points_number << " 0 0" << std::endl; + } else { + diagram_out << "nOFF" << std::endl; + diagram_out << dimension << " " << points_number << " 0 0" << std::endl; + } if (diagram_out.is_open()) { // Instanciate a random point generator @@ -114,7 +120,7 @@ int main(int argc, char **argv) { for (auto thePoint : points) { int i = 0; - for (;i < dimension - 1; i++) { + for (; i < dimension - 1; i++) { diagram_out << thePoint[i] << " "; } diagram_out << thePoint[i] << std::endl; // last point + Carriage Return diff --git a/scripts/generate_version.sh b/scripts/generate_version.sh index 4d28cf53..323396dc 100755 --- a/scripts/generate_version.sh +++ b/scripts/generate_version.sh @@ -2,19 +2,22 @@ #usage bash generate_version.sh : dont generate if svn st non empty #usage bash generate_version.sh -f : generate even if svn is empty #usage bash generate_version.sh -f DIR : generate even if svn is empty and save library in dir +# +# 23/06/2015 - Remove source, add biblio, and doc +# 06/10/2015 - Replace static Version.txt with generated GUDHIVersion.cmake file # VERSION CHECK ROOT_DIR=.. -VERSION_FILE="$ROOT_DIR/Version.txt" +VERSION_FILE="$ROOT_DIR/GUDHIVersion.cmake" if [ ! -f $VERSION_FILE ]; then - echo "File not found! : $VERSION_FILE" + echo "File not found! : $VERSION_FILE - Please launch cmake first to generate file" exit 1 fi # SVN STATUS CHECK OR IF FORCED BY USER if [ "$1" != "-f" ] then - SVN_STATUS=`svn status $ROOT_DIR` + SVN_STATUS=`svn status $ROOT_DIR | grep -v $VERSION_FILE` echo $SVN_STATUS fi @@ -42,22 +45,29 @@ mkdir "$VERSION_DIR" # TOP LEVEL FILE COPY cp $VERSION_FILE $VERSION_DIR +cp $ROOT_DIR/CMakeGUDHIVersion.txt $VERSION_DIR cp $ROOT_DIR/README $VERSION_DIR cp $ROOT_DIR/Conventions.txt $VERSION_DIR cp $ROOT_DIR/COPYING $VERSION_DIR cp -R $ROOT_DIR/data $VERSION_DIR cp $ROOT_DIR/src/CMakeLists.txt $VERSION_DIR cp $ROOT_DIR/src/Doxyfile $VERSION_DIR +cp -R $ROOT_DIR/biblio $VERSION_DIR +cp $ROOT_DIR/src/GUDHIConfigVersion.cmake.in $VERSION_DIR +cp $ROOT_DIR/src/GUDHIConfig.cmake.in $VERSION_DIR +cp $ROOT_DIR/GUDHIVersion.cmake.in $VERSION_DIR # PACKAGE LEVEL COPY PACKAGE_INC_DIR="/include" -PACKAGE_SRC_DIR="/source" +#PACKAGE_SRC_DIR="/source" PACKAGE_EX_DIR="/example" +PACKAGE_CONCEPT_DIR="/concept" +PACKAGE_DOC_DIR="/doc" for package in `ls $ROOT_DIR/src/` do - echo $package - if [ -d "$ROOT_DIR/src/$package" ] + if [ -d "$ROOT_DIR/src/$package" ] && [ $package != "Bottleneck" ] then + echo $package if [ "$package" == "cmake" ] then # SPECIFIC FOR CMAKE MODULES @@ -77,20 +87,21 @@ do fi cp -R $ROOT_DIR/src/$package$PACKAGE_INC_DIR/* $VERSION_DIR$PACKAGE_INC_DIR/ fi - if [ -d "$ROOT_DIR/src/$package$PACKAGE_SRC_DIR" ] - then - if [ ! -d "$VERSION_DIR$PACKAGE_SRC_DIR" ] - then - # MUST CREATE DIRECTORY ON FIRST LOOP - mkdir $VERSION_DIR$PACKAGE_INC_DIR - fi - cp -R $ROOT_DIR/src/$package$PACKAGE_SRC_DIR/* $VERSION_DIR$PACKAGE_SRC_DIR/ - fi if [ -d "$ROOT_DIR/src/$package$PACKAGE_EX_DIR" ] then mkdir -p $VERSION_DIR$PACKAGE_EX_DIR/$package cp -R $ROOT_DIR/src/$package$PACKAGE_EX_DIR/* $VERSION_DIR$PACKAGE_EX_DIR/$package fi + if [ -d "$ROOT_DIR/src/$package$PACKAGE_CONCEPT_DIR" ] + then + mkdir -p $VERSION_DIR$PACKAGE_CONCEPT_DIR/$package + cp -R $ROOT_DIR/src/$package$PACKAGE_CONCEPT_DIR/* $VERSION_DIR$PACKAGE_CONCEPT_DIR/$package + fi + if [ -d "$ROOT_DIR/src/$package$PACKAGE_DOC_DIR" ] + then + mkdir -p $VERSION_DIR$PACKAGE_DOC_DIR/$package + cp -R $ROOT_DIR/src/$package$PACKAGE_DOC_DIR/* $VERSION_DIR$PACKAGE_DOC_DIR/$package + fi fi fi done diff --git a/src/Alpha_shapes/example/CMakeLists.txt b/src/Alpha_shapes/example/CMakeLists.txt deleted file mode 100644 index 753238a5..00000000 --- a/src/Alpha_shapes/example/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -cmake_minimum_required(VERSION 2.6) -project(GUDHIAlphaShapesExample) - -# 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} ) - include_directories (BEFORE "../../include") - - add_executable ( dtoffrw Delaunay_triangulation_off_rw.cpp ) - target_link_libraries(dtoffrw ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY}) - add_test(dtoffrw_tore3D ${CMAKE_CURRENT_BINARY_DIR}/dtoffrw ${CMAKE_SOURCE_DIR}/data/points/tore3D_1307.off 3) - - # uncomment to display debug traces - # add_definitions(-DDEBUG_TRACES) - add_executable ( stfromdt Simplex_tree_from_delaunay_triangulation.cpp ) - target_link_libraries(stfromdt ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY}) - 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/Alpha_shapes/example/Delaunay_triangulation_off_rw.cpp b/src/Alpha_shapes/example/Delaunay_triangulation_off_rw.cpp deleted file mode 100644 index 03f6440d..00000000 --- a/src/Alpha_shapes/example/Delaunay_triangulation_off_rw.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* 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 Saclay (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/>. - */ - -// to construct a Delaunay_triangulation from a OFF file -#include "gudhi/Alpha_shapes/Delaunay_triangulation_off_io.h" - -#include <CGAL/Delaunay_triangulation.h> -#include <CGAL/Epick_d.h> -#include <CGAL/point_generators_d.h> -#include <CGAL/algorithm.h> -#include <CGAL/assertions.h> - -#include <iostream> -#include <iterator> -#include <vector> - -#include <stdio.h> -#include <stdlib.h> -#include <string> - -// Use dynamic_dimension_tag for the user to be able to set dimension -typedef CGAL::Epick_d< CGAL::Dynamic_dimension_tag > K; -typedef CGAL::Delaunay_triangulation<K> T; -// The triangulation uses the default instanciation of the -// TriangulationDataStructure template parameter - -void usage(char * const progName) { - std::cerr << "Usage: " << progName << " filename.off dimension" << std::endl; - exit(-1); // ----- >> -} - -int main(int argc, char **argv) { - if (argc != 3) { - std::cerr << "Error: Number of arguments (" << argc << ") is not correct" << std::endl; - usage(argv[0]); - } - - int dimension = 0; - int returnedScanValue = sscanf(argv[2], "%d", &dimension); - if ((returnedScanValue == EOF) || (dimension <= 0)) { - std::cerr << "Error: " << argv[2] << " is not correct" << std::endl; - usage(argv[0]); - } - - T dt(dimension); - std::string offFileName(argv[1]); - Gudhi::alphashapes::Delaunay_triangulation_off_reader<T> off_reader(offFileName, dt, true, true); - if (!off_reader.is_valid()) { - std::cerr << "Unable to read file " << offFileName << std::endl; - exit(-1); // ----- >> - } - - std::cout << "number of vertices=" << dt.number_of_vertices() << std::endl; - std::cout << "number of full cells=" << dt.number_of_full_cells() << std::endl; - std::cout << "number of finite full cells=" << dt.number_of_finite_full_cells() << std::endl; - - // Points list - /*for (T::Vertex_iterator vit = dt.vertices_begin(); vit != dt.vertices_end(); ++vit) { - for (auto Coord = vit->point().cartesian_begin(); Coord != vit->point().cartesian_end(); ++Coord) { - std::cout << *Coord << " "; - } - std::cout << std::endl; - } - std::cout << std::endl;*/ - - int i = 0, j = 0; - typedef T::Full_cell_iterator Full_cell_iterator; - typedef T::Facet Facet; - - for (Full_cell_iterator cit = dt.full_cells_begin(); cit != dt.full_cells_end(); ++cit) { - if (!dt.is_infinite(cit)) { - j++; - continue; - } - Facet fct(cit, cit->index(dt.infinite_vertex())); - i++; - } - std::cout << "There are " << i << " facets on the convex hull." << std::endl; - std::cout << "There are " << j << " facets not on the convex hull." << std::endl; - - - std::string offOutputFile("out.off"); - Gudhi::alphashapes::Delaunay_triangulation_off_writer<T> off_writer(offOutputFile, dt); - - return 0; -}
\ No newline at end of file diff --git a/src/Alpha_shapes/example/Simplex_tree_from_delaunay_triangulation.cpp b/src/Alpha_shapes/example/Simplex_tree_from_delaunay_triangulation.cpp deleted file mode 100644 index 3a17b519..00000000 --- a/src/Alpha_shapes/example/Simplex_tree_from_delaunay_triangulation.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* 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 Saclay (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/>. - */ - -// to construct a Delaunay_triangulation from a OFF file -#include "gudhi/Alpha_shapes/Delaunay_triangulation_off_io.h" -#include "gudhi/Alpha_shapes.h" - -// to construct a simplex_tree from Delaunay_triangulation -#include "gudhi/graph_simplicial_complex.h" -#include "gudhi/Simplex_tree.h" - -#include <CGAL/Delaunay_triangulation.h> -#include <CGAL/Epick_d.h> -#include <CGAL/point_generators_d.h> -#include <CGAL/algorithm.h> -#include <CGAL/assertions.h> - -#include <iostream> -#include <iterator> - -#include <stdio.h> -#include <stdlib.h> -#include <string> - -// Use dynamic_dimension_tag for the user to be able to set dimension -typedef CGAL::Epick_d< CGAL::Dynamic_dimension_tag > K; -typedef CGAL::Delaunay_triangulation<K> T; -// The triangulation uses the default instanciation of the -// TriangulationDataStructure template parameter - -void usage(char * const progName) { - std::cerr << "Usage: " << progName << " filename.off dimension" << std::endl; - exit(-1); // ----- >> -} - -int main(int argc, char **argv) { - if (argc != 3) { - std::cerr << "Error: Number of arguments (" << argc << ") is not correct" << std::endl; - usage(argv[0]); - } - - int dimension = 0; - int returnedScanValue = sscanf(argv[2], "%d", &dimension); - if ((returnedScanValue == EOF) || (dimension <= 0)) { - std::cerr << "Error: " << argv[2] << " is not correct" << std::endl; - usage(argv[0]); - } - - // ---------------------------------------------------------------------------- - // - // Init of an alpha-shape from a Delaunay triangulation - // - // ---------------------------------------------------------------------------- - T dt(dimension); - std::string off_file_name(argv[1]); - - Gudhi::alphashapes::Delaunay_triangulation_off_reader<T> off_reader(off_file_name, dt, false, false); - if (!off_reader.is_valid()) { - std::cerr << "Unable to read file " << off_file_name << std::endl; - exit(-1); // ----- >> - } - - std::cout << "number of vertices=" << dt.number_of_vertices() << std::endl; - std::cout << "number of full cells=" << dt.number_of_full_cells() << std::endl; - std::cout << "number of finite full cells=" << dt.number_of_finite_full_cells() << std::endl; - - Gudhi::alphashapes::Alpha_shapes alpha_shapes_from_dt(dt); - //std::cout << alpha_shapes_from_dt << std::endl; - - // ---------------------------------------------------------------------------- - // - // Init of an alpha-shape from a OFF file - // - // ---------------------------------------------------------------------------- - Gudhi::alphashapes::Alpha_shapes alpha_shapes_from_file(off_file_name, dimension); - //std::cout << alpha_shapes_from_file << std::endl; - - std::cout << "alpha_shapes_from_file.dimension()=" << alpha_shapes_from_file.dimension() << std::endl; - std::cout << "alpha_shapes_from_file.filtration()=" << alpha_shapes_from_file.filtration() << std::endl; - std::cout << "alpha_shapes_from_file.num_simplices()=" << alpha_shapes_from_file.num_simplices() << std::endl; - std::cout << "alpha_shapes_from_file.num_vertices()=" << alpha_shapes_from_file.num_vertices() << std::endl; - - return 0; -}
\ No newline at end of file diff --git a/src/Alpha_shapes/include/gudhi/Alpha_shapes.h b/src/Alpha_shapes/include/gudhi/Alpha_shapes.h deleted file mode 100644 index b8efdb4d..00000000 --- a/src/Alpha_shapes/include/gudhi/Alpha_shapes.h +++ /dev/null @@ -1,200 +0,0 @@ -/* 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) 2015 INRIA Saclay (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 SRC_ALPHA_SHAPES_INCLUDE_GUDHI_ALPHA_SHAPES_H_ -#define SRC_ALPHA_SHAPES_INCLUDE_GUDHI_ALPHA_SHAPES_H_ - -// to construct a Delaunay_triangulation from a OFF file -#include <gudhi/Alpha_shapes/Delaunay_triangulation_off_io.h> - -// to construct a simplex_tree from Delaunay_triangulation -#include <gudhi/graph_simplicial_complex.h> -#include <gudhi/Simplex_tree.h> - -#include <stdio.h> -#include <stdlib.h> - -#include <CGAL/Delaunay_triangulation.h> -#include <CGAL/Epick_d.h> -#include <CGAL/algorithm.h> -#include <CGAL/assertions.h> - -#include <iostream> -#include <iterator> -#include <vector> -#include <string> - -namespace Gudhi { - -namespace alphashapes { - -/** \defgroup alpha_shapes Alpha shapes in dimension N - * - <DT>Implementations:</DT> - Alpha shapes in dimension N are a subset of Delaunay Triangulation in dimension N. - - - * \author Vincent Rouvreau - * \version 1.0 - * \date 2015 - * \copyright GNU General Public License v3. - * @{ - */ - -/** - * \brief Alpha shapes data structure. - * - * \details Every simplex \f$[v_0, \cdots ,v_d]\f$ admits a canonical orientation - * induced by the order relation on vertices \f$ v_0 < \cdots < v_d \f$. - * - * Details may be found in \cite boissonnatmariasimplextreealgorithmica. - * - * \implements FilteredComplex - * - */ -class Alpha_shapes { - private: - // From Simplex_tree - /** \brief Type required to insert into a simplex_tree (with or without subfaces).*/ - typedef std::vector<Vertex_handle> typeVectorVertex; - - // From CGAL - /** \brief Kernel for the Delaunay_triangulation. - * Dimension can be set dynamically. - */ - typedef CGAL::Epick_d< CGAL::Dynamic_dimension_tag > Kernel; - /** \brief Delaunay_triangulation type required to create an alpha-shape. - */ - typedef CGAL::Delaunay_triangulation<Kernel> Delaunay_triangulation; - - private: - /** \brief Upper bound on the simplex tree of the simplicial complex.*/ - Gudhi::Simplex_tree<> _st; - - public: - - Alpha_shapes(std::string off_file_name, int dimension) { - Delaunay_triangulation dt(dimension); - Gudhi::alphashapes::Delaunay_triangulation_off_reader<Delaunay_triangulation> - off_reader(off_file_name, dt, true, true); - if (!off_reader.is_valid()) { - std::cerr << "Unable to read file " << off_file_name << std::endl; - exit(-1); // ----- >> - } -#ifdef DEBUG_TRACES - std::cout << "number of vertices=" << dt.number_of_vertices() << std::endl; - std::cout << "number of full cells=" << dt.number_of_full_cells() << std::endl; - std::cout << "number of finite full cells=" << dt.number_of_finite_full_cells() << std::endl; -#endif // DEBUG_TRACES - init<Delaunay_triangulation>(dt); - } - - template<typename T> - Alpha_shapes(T triangulation) { - init<T>(triangulation); - } - - ~Alpha_shapes() { } - - private: - - template<typename T> - void init(T triangulation) { - _st.set_dimension(triangulation.maximal_dimension()); - _st.set_filtration(0.0); - // triangulation points list - for (auto vit = triangulation.finite_vertices_begin(); - vit != triangulation.finite_vertices_end(); ++vit) { - typeVectorVertex vertexVector; - Vertex_handle vertexHdl = std::distance(triangulation.finite_vertices_begin(), vit); - vertexVector.push_back(vertexHdl); - - // Insert each point in the simplex tree - _st.insert_simplex(vertexVector, 0.0); - -#ifdef DEBUG_TRACES - std::cout << "P" << vertexHdl << ":"; - for (auto Coord = vit->point().cartesian_begin(); Coord != vit->point().cartesian_end(); ++Coord) { - std::cout << *Coord << " "; - } - std::cout << std::endl; -#endif // DEBUG_TRACES - } - // triangulation finite full cells list - for (auto cit = triangulation.finite_full_cells_begin(); - cit != triangulation.finite_full_cells_end(); ++cit) { - typeVectorVertex vertexVector; - for (auto vit = cit->vertices_begin(); vit != cit->vertices_end(); ++vit) { - // Vertex handle is distance - 1 - Vertex_handle vertexHdl = std::distance(triangulation.vertices_begin(), *vit) - 1; - vertexVector.push_back(vertexHdl); - } - // Insert each point in the simplex tree - _st.insert_simplex_and_subfaces(vertexVector, 0.0); - -#ifdef DEBUG_TRACES - std::cout << "C" << std::distance(triangulation.finite_full_cells_begin(), cit) << ":"; - for (auto value : vertexVector) { - std::cout << value << ' '; - } - std::cout << std::endl; -#endif // DEBUG_TRACES - } - } - - public: - - /** \brief Returns the number of vertices in the complex. */ - size_t num_vertices() { - return _st.num_vertices(); - } - - /** \brief Returns the number of simplices in the complex. - * - * Does not count the empty simplex. */ - const unsigned int& num_simplices() const { - return _st.num_simplices(); - } - - /** \brief Returns an upper bound on the dimension of the simplicial complex. */ - int dimension() { - return _st.dimension(); - } - - /** \brief Returns an upper bound of the filtration values of the simplices. */ - Filtration_value filtration() { - return _st.filtration(); - } - - friend std::ostream& operator<<(std::ostream& os, const Alpha_shapes& alpha_shape) { - // TODO: Program terminated with signal SIGABRT, Aborted - Maybe because of copy constructor - Gudhi::Simplex_tree<> st = alpha_shape._st; - os << st << std::endl; - return os; - } -}; - -} // namespace alphashapes - -} // namespace Gudhi - -#endif // SRC_ALPHA_SHAPES_INCLUDE_GUDHI_ALPHA_SHAPES_H_ diff --git a/src/Alpha_shapes/include/gudhi/Alpha_shapes/Delaunay_triangulation_off_io.h b/src/Alpha_shapes/include/gudhi/Alpha_shapes/Delaunay_triangulation_off_io.h deleted file mode 100644 index 693b393e..00000000 --- a/src/Alpha_shapes/include/gudhi/Alpha_shapes/Delaunay_triangulation_off_io.h +++ /dev/null @@ -1,213 +0,0 @@ -/* 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) 2015 INRIA Saclay (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 SRC_ALPHA_SHAPES_INCLUDE_GUDHI_ALPHA_SHAPES_DELAUNAY_TRIANGULATION_OFF_IO_H_ -#define SRC_ALPHA_SHAPES_INCLUDE_GUDHI_ALPHA_SHAPES_DELAUNAY_TRIANGULATION_OFF_IO_H_ - -#include <string> -#include <vector> -#include <fstream> - -#include "gudhi/Off_reader.h" - -namespace Gudhi { - -namespace alphashapes { - -/** - *@brief Off reader visitor with flag that can be passed to Off_reader to read a Delaunay_triangulation_complex. - */ -template<typename Complex> -class Delaunay_triangulation_off_flag_visitor_reader { - Complex& complex_; - typedef typename Complex::Point Point; - - const bool load_only_points_; - - public: - explicit Delaunay_triangulation_off_flag_visitor_reader(Complex& complex, bool load_only_points = false) : - complex_(complex), - load_only_points_(load_only_points) { } - - void init(int dim, int num_vertices, int num_faces, int num_edges) { -#ifdef DEBUG_TRACES - std::cout << "init" << std::endl; -#endif // DEBUG_TRACES - } - - void point(const std::vector<double>& point) { -#ifdef DEBUG_TRACES - std::cout << "p "; - for (auto coordinate: point) { - std::cout << coordinate << " | "; - } - std::cout << std::endl; -#endif // DEBUG_TRACES - complex_.insert(Point(point.size(), point.begin(), point.end())); - } - - void maximal_face(const std::vector<int>& face) { - // For alpha shapes, only points are read - } - - void done() { -#ifdef DEBUG_TRACES - std::cout << "done" << std::endl; -#endif // DEBUG_TRACES - } -}; - -/** - *@brief Off reader visitor that can be passed to Off_reader to read a Delaunay_triangulation_complex. - */ -template<typename Complex> -class Delaunay_triangulation_off_visitor_reader { - Complex& complex_; - // typedef typename Complex::Vertex_handle Vertex_handle; - // typedef typename Complex::Simplex_handle Simplex_handle; - typedef typename Complex::Point Point; - - const bool load_only_points_; - std::vector<Point> points_; - // std::vector<Simplex_handle> maximal_faces_; - - public: - explicit Delaunay_triangulation_off_visitor_reader(Complex& complex, bool load_only_points = false) : - complex_(complex), - load_only_points_(load_only_points) { } - - void init(int dim, int num_vertices, int num_faces, int num_edges) { -#ifdef DEBUG_TRACES - std::cout << "init - " << num_vertices << std::endl; -#endif // DEBUG_TRACES - // maximal_faces_.reserve(num_faces); - points_.reserve(num_vertices); - } - - void point(const std::vector<double>& point) { -#ifdef DEBUG_TRACES - std::cout << "p "; - for (auto coordinate: point) { - std::cout << coordinate << " | "; - } - std::cout << std::endl; -#endif // DEBUG_TRACES - points_.emplace_back(Point(point.size(), point.begin(), point.end())); - } - - void maximal_face(const std::vector<int>& face) { - // For alpha shapes, only points are read - } - - void done() { - complex_.insert(points_.begin(), points_.end()); -#ifdef DEBUG_TRACES - std::cout << "done" << std::endl; -#endif // DEBUG_TRACES - } -}; - -/** - *@brief Class that allows to load a Delaunay_triangulation_complex from an off file. - */ -template<typename Complex> -class Delaunay_triangulation_off_reader { - public: - /** - * name_file : file to read - * read_complex : complex that will receive the file content - * read_only_points : specify true if only the points must be read - */ - Delaunay_triangulation_off_reader(const std::string & name_file, Complex& read_complex, bool read_only_points = false, - bool is_flag = false) : valid_(false) { - std::ifstream stream(name_file); - if (stream.is_open()) { - if (is_flag) { - // For alpha shapes, only points are read - Delaunay_triangulation_off_flag_visitor_reader<Complex> off_visitor(read_complex, true); - Off_reader off_reader(stream); - valid_ = off_reader.read(off_visitor); - } else { - // For alpha shapes, only points are read - Delaunay_triangulation_off_visitor_reader<Complex> off_visitor(read_complex, true); - Off_reader off_reader(stream); - valid_ = off_reader.read(off_visitor); - } - } - } - - /** - * return true if reading did not meet problems. - */ - bool is_valid() const { - return valid_; - } - - private: - bool valid_; -}; - -template<typename Complex> -class Delaunay_triangulation_off_writer { - public: - /** - * name_file : file where the off will be written - * save_complex : complex that be outputted in the file - * for now only save triangles. - */ - Delaunay_triangulation_off_writer(const std::string & name_file, const Complex& save_complex) { - std::ofstream stream(name_file); - if (stream.is_open()) { - // OFF header - stream << "OFF" << std::endl; - // no endl on next line - don't know why... - stream << save_complex.number_of_vertices() << " " << save_complex.number_of_finite_full_cells() << " 0"; - - // Points list - for (auto vit = save_complex.vertices_begin(); vit != save_complex.vertices_end(); ++vit) { - for (auto Coord = vit->point().cartesian_begin(); Coord != vit->point().cartesian_end(); ++Coord) { - stream << *Coord << " "; - } - stream << std::endl; - } - - // Finite cells list - for (auto cit = save_complex.finite_full_cells_begin(); cit != save_complex.finite_full_cells_end(); ++cit) { - stream << std::distance(cit->vertices_begin(), cit->vertices_end()) << " "; // Dimension - for (auto vit = cit->vertices_begin(); vit != cit->vertices_end(); ++vit) { - auto vertexHdl = *vit; - // auto vertexHdl = std::distance(save_complex.vertices_begin(), *vit) - 1; - // stream << std::distance(save_complex.vertices_begin(), *(vit)) - 1 << " "; - } - stream << std::endl; - } - stream.close(); - } else { - std::cerr << "could not open file " << name_file << std::endl; - } - } -}; - -} // namespace alphashapes - -} // namespace Gudhi - -#endif // SRC_ALPHA_SHAPES_INCLUDE_GUDHI_ALPHA_SHAPES_DELAUNAY_TRIANGULATION_OFF_IO_H_ diff --git a/src/Alpha_shapes/test/Alpha_shapes_unit_test.cpp b/src/Alpha_shapes/test/Alpha_shapes_unit_test.cpp deleted file mode 100644 index b4c32321..00000000 --- a/src/Alpha_shapes/test/Alpha_shapes_unit_test.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* 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) 2015 INRIA Saclay (France) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#define BOOST_TEST_MODULE alpha_shapes test -#include <boost/test/included/unit_test.hpp> -#include <boost/system/error_code.hpp> -#include <boost/chrono/thread_clock.hpp> -// to construct a Delaunay_triangulation from a OFF file -#include "gudhi/Alpha_shapes/Delaunay_triangulation_off_io.h" -#include "gudhi/Alpha_shapes.h" - -// to construct a simplex_tree from Delaunay_triangulation -#include "gudhi/graph_simplicial_complex.h" -#include "gudhi/Simplex_tree.h" - -#include <CGAL/Delaunay_triangulation.h> -#include <CGAL/Epick_d.h> -#include <CGAL/point_generators_d.h> -#include <CGAL/algorithm.h> -#include <CGAL/assertions.h> - -#include <iostream> -#include <iterator> - -#include <stdio.h> -#include <stdlib.h> -#include <string> - -// Use dynamic_dimension_tag for the user to be able to set dimension -typedef CGAL::Epick_d< CGAL::Dynamic_dimension_tag > K; -typedef CGAL::Delaunay_triangulation<K> T; -// The triangulation uses the default instanciation of the -// TriangulationDataStructure template parameter - -BOOST_AUTO_TEST_CASE( OFF_file ) { - // ---------------------------------------------------------------------------- - // - // Init of an alpha-shape from a OFF file - // - // ---------------------------------------------------------------------------- - std::string off_file_name("S4_100.off"); - std::cout << "========== OFF FILE NAME = " << off_file_name << " ==========" << std::endl; - - Gudhi::alphashapes::Alpha_shapes alpha_shapes_from_file(off_file_name, 4); - - const int DIMENSION = 4; - std::cout << "alpha_shapes_from_file.dimension()=" << alpha_shapes_from_file.dimension() << std::endl; - BOOST_CHECK(alpha_shapes_from_file.dimension() == DIMENSION); - - const double FILTRATION = 0.0; - std::cout << "alpha_shapes_from_file.filtration()=" << alpha_shapes_from_file.filtration() << std::endl; - BOOST_CHECK(alpha_shapes_from_file.filtration() == FILTRATION); - - const int NUMBER_OF_VERTICES = 100; - std::cout << "alpha_shapes_from_file.num_vertices()=" << alpha_shapes_from_file.num_vertices() << std::endl; - BOOST_CHECK(alpha_shapes_from_file.num_vertices() == NUMBER_OF_VERTICES); - - const int NUMBER_OF_SIMPLICES = 6779; - std::cout << "alpha_shapes_from_file.num_simplices()=" << alpha_shapes_from_file.num_simplices() << std::endl; - BOOST_CHECK(alpha_shapes_from_file.num_simplices() == NUMBER_OF_SIMPLICES); - -} - -BOOST_AUTO_TEST_CASE( Delaunay_triangulation ) { - // ---------------------------------------------------------------------------- - // - // Init of an alpha-shape from a Delauny triangulation - // - // ---------------------------------------------------------------------------- - T dt(8); - std::string off_file_name("S8_10.off"); - std::cout << "========== OFF FILE NAME = " << off_file_name << " ==========" << std::endl; - - Gudhi::alphashapes::Delaunay_triangulation_off_reader<T> off_reader(off_file_name, dt, true, true); - std::cout << "off_reader.is_valid()=" << off_reader.is_valid() << std::endl; - BOOST_CHECK(off_reader.is_valid()); - - const int NUMBER_OF_VERTICES = 10; - std::cout << "dt.number_of_vertices()=" << dt.number_of_vertices() << std::endl; - BOOST_CHECK(dt.number_of_vertices() == NUMBER_OF_VERTICES); - - const int NUMBER_OF_FULL_CELLS = 30; - std::cout << "dt.number_of_full_cells()=" << dt.number_of_full_cells() << std::endl; - BOOST_CHECK(dt.number_of_full_cells() == NUMBER_OF_FULL_CELLS); - - const int NUMBER_OF_FINITE_FULL_CELLS = 6; - std::cout << "dt.number_of_finite_full_cells()=" << dt.number_of_finite_full_cells() << std::endl; - BOOST_CHECK(dt.number_of_finite_full_cells() == NUMBER_OF_FINITE_FULL_CELLS); - - Gudhi::alphashapes::Alpha_shapes alpha_shapes_from_dt(dt); - - const int DIMENSION = 8; - std::cout << "alpha_shapes_from_dt.dimension()=" << alpha_shapes_from_dt.dimension() << std::endl; - BOOST_CHECK(alpha_shapes_from_dt.dimension() == DIMENSION); - - const double FILTRATION = 0.0; - std::cout << "alpha_shapes_from_dt.filtration()=" << alpha_shapes_from_dt.filtration() << std::endl; - BOOST_CHECK(alpha_shapes_from_dt.filtration() == FILTRATION); - - std::cout << "alpha_shapes_from_dt.num_vertices()=" << alpha_shapes_from_dt.num_vertices() << std::endl; - BOOST_CHECK(alpha_shapes_from_dt.num_vertices() == NUMBER_OF_VERTICES); - - const int NUMBER_OF_SIMPLICES = 997; - std::cout << "alpha_shapes_from_dt.num_simplices()=" << alpha_shapes_from_dt.num_simplices() << std::endl; - BOOST_CHECK(alpha_shapes_from_dt.num_simplices() == NUMBER_OF_SIMPLICES); -} - diff --git a/src/Alpha_shapes/test/CMakeLists.txt b/src/Alpha_shapes/test/CMakeLists.txt deleted file mode 100644 index e0d33827..00000000 --- a/src/Alpha_shapes/test/CMakeLists.txt +++ /dev/null @@ -1,48 +0,0 @@ -cmake_minimum_required(VERSION 2.6) -project(GUDHIAlphaShapesUT) - -# 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} ) - include_directories (BEFORE "../../include") - - if (GCOVR_PATH) - # for gcovr to make coverage reports - Corbera Jenkins plugin - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fprofile-arcs -ftest-coverage") - endif() - if (GPROF_PATH) - # for gprof to make coverage reports - Jenkins - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -pg") - endif() - - # uncomment to display debug traces - # add_definitions(-DDEBUG_TRACES) - add_executable ( AlphaShapesUT Alpha_shapes_unit_test.cpp ) - target_link_libraries(AlphaShapesUT ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) - add_test(NAME AlphaShapesUT - COMMAND ${CMAKE_CURRENT_BINARY_DIR}/AlphaShapesUT - # XML format for Jenkins xUnit plugin - --log_format=XML --log_sink=${CMAKE_SOURCE_DIR}/AlphaShapesUT.xml --log_level=test_suite --report_level=no) - - - 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/Alpha_shapes/test/README b/src/Alpha_shapes/test/README deleted file mode 100644 index cddd46ca..00000000 --- a/src/Alpha_shapes/test/README +++ /dev/null @@ -1,14 +0,0 @@ -To compile: -*********** - -cd /path-to-gudhi/ -cmake . -cd /path-to-test/ -make - -To launch with details: -*********************** - -./AlphaShapesUT --report_level=detailed --log_level=all - - ==> echo $? returns 0 in case of success (non-zero otherwise) diff --git a/src/Alpha_shapes/test/S4_100.off b/src/Alpha_shapes/test/S4_100.off deleted file mode 100644 index 0a5dc58c..00000000 --- a/src/Alpha_shapes/test/S4_100.off +++ /dev/null @@ -1,102 +0,0 @@ -OFF -100 0 0 -0.562921 -0.735261 -0.256472 0.277007 --0.803733 -0.0527915 -0.315125 0.501918 --0.24946 -0.354982 -0.410773 -0.801887 -0.916381 -0.0512295 0.371049 0.141223 -0.182222 0.940836 -0.171362 -0.228599 --0.787145 -0.129213 0.568102 -0.202402 -0.0187866 -0.22093 -0.832882 -0.507095 --0.4702 -0.533814 0.353776 0.607286 --0.159798 -0.504771 0.263586 0.806346 -0.295546 0.162541 0.452931 0.825279 -0.242043 -0.107437 -0.913612 -0.308521 -0.875759 -0.113035 -0.469189 -0.0114505 -0.547877 -0.762247 -0.256972 -0.229729 --0.172302 0.521057 0.412013 -0.727363 --0.724729 -0.0574074 -0.0290602 0.686023 -0.700434 -0.102636 0.687285 0.162779 --0.681386 0.0946893 0.610047 0.393178 --0.847553 -0.357132 0.383743 0.0827718 -0.72297 -0.161631 -0.608517 0.284424 -0.757394 0.141549 0.196065 -0.606528 -0.78094 0.00901997 0.434536 0.448586 -0.14166 -0.619339 0.614589 -0.467582 -0.473105 -0.537832 -0.0103746 0.697711 --0.208004 0.536218 0.818027 0.00605288 -0.743694 -0.628926 0.188072 0.126488 --0.462228 -0.278147 0.35514 -0.76345 --0.17361 0.249211 0.758567 -0.57648 -0.416958 -0.254924 -0.576373 -0.654946 --0.590751 -0.286089 -0.424896 0.623402 --0.639538 -0.739693 -0.203745 0.0482932 -0.0731787 0.132121 0.864022 0.480266 --0.149644 -0.164724 -0.249746 -0.94239 --0.348592 0.0120379 -0.928656 -0.126239 -0.395328 -0.54513 0.149976 -0.723917 --0.974164 0.14707 0.157191 0.068302 --0.166425 0.119943 -0.627304 -0.751269 -0.031947 -0.358518 -0.708301 -0.607251 -0.93781 -0.155368 -0.30951 0.0240237 -0.276094 -0.753155 -0.597088 -0.00387459 --0.642876 -0.200551 -0.263517 -0.690687 -0.178711 0.604987 -0.262989 0.729993 --0.520347 0.497922 -0.676144 0.155374 --0.703999 0.500219 -0.484381 0.139789 --0.131013 0.835735 0.506779 0.166004 --0.536116 -0.566557 0.229226 0.582279 --0.334105 0.158252 0.926091 0.0754059 --0.0362677 0.296076 0.897108 0.325915 --0.57486 0.798575 0.15324 -0.0912754 -0.498602 0.0186805 0.72824 0.469801 --0.960329 0.0473356 0.261005 -0.0860505 -0.899134 -0.381392 -0.214508 0.00921711 -0.570576 0.567224 0.393019 -0.445237 --0.761763 -0.614589 -0.0546476 -0.197513 -0.188584 0.289531 0.174031 0.922129 --0.458506 -0.583876 0.639297 -0.2004 -0.785343 -0.21571 0.0794082 -0.574804 -0.0819036 0.65961 -0.247426 0.704973 -0.573125 0.49706 0.373026 0.534145 --0.513286 -0.626226 0.208535 -0.548536 -0.460558 0.468686 0.507832 -0.55707 -0.716158 -0.488201 0.388209 -0.313164 -0.881074 0.152441 0.380128 -0.236589 -0.885793 0.0386389 0.161009 -0.433537 --0.365162 0.298384 0.292846 0.831784 -0.364934 0.632269 -0.197205 -0.654346 --0.31469 -0.429991 0.665304 -0.522923 --0.734198 0.462914 -0.135691 -0.477756 --0.422885 0.674444 -0.364143 -0.483419 -0.829218 -0.154622 -0.381147 0.378439 -0.887881 0.310479 -0.109528 0.321363 --0.354398 -0.693974 0.456019 -0.429941 --0.492045 -0.160008 0.044387 0.854587 -0.0595532 0.158421 0.412577 -0.895062 --0.211441 0.491794 -0.153521 0.83058 --0.33558 -0.504711 0.353831 -0.71236 --0.735211 -0.197714 0.525626 0.379593 -0.465818 -0.424245 0.769469 -0.104627 --0.641071 -0.286339 -0.704442 -0.103923 --0.00446569 0.0249849 -0.194417 -0.980591 --0.610081 -0.252448 0.176698 -0.729966 --0.0859217 -0.154471 0.715027 0.676382 -0.091315 0.0723382 -0.855023 -0.505337 -0.165362 0.200983 -0.428242 -0.865373 --0.587465 0.303019 -0.152442 0.734729 -0.454946 -0.319828 0.437063 -0.706902 --0.384368 0.277509 0.879225 -0.0470385 -0.523335 -0.330233 -0.208592 0.757335 -0.895086 0.0448492 0.268089 -0.353466 --0.0272491 -0.567336 -0.72254 -0.39411 --0.0745014 -0.121818 -0.882466 0.448179 -0.382304 -0.240135 0.851109 -0.267941 --0.418057 -0.852847 -0.3128 0.00606452 --0.554046 0.304237 0.272381 -0.725453 -0.155115 -0.0894732 -0.245017 -0.952838 -0.114459 -0.130722 0.953669 0.245614 -0.0913002 -0.462466 0.244433 0.847374 --0.198849 0.0785111 0.131441 -0.967997 --0.303154 -0.686484 0.639333 0.167604 -0.521455 0.256835 -0.0584503 -0.811606 --0.109787 0.870544 0.161523 0.451676 diff --git a/src/Alpha_shapes/test/S8_10.off b/src/Alpha_shapes/test/S8_10.off deleted file mode 100644 index 1d67e10f..00000000 --- a/src/Alpha_shapes/test/S8_10.off +++ /dev/null @@ -1,12 +0,0 @@ -OFF -10 0 0 -0.440036 -0.574754 -0.200485 0.216537 -0.501251 -0.0329236 -0.196529 0.313023 --0.129367 -0.184089 -0.213021 -0.415848 0.783529 -0.0438025 0.317256 0.120749 -0.132429 0.683748 -0.124536 -0.166133 -0.540695 -0.0887576 0.390234 -0.139031 -0.0137399 -0.161581 -0.609142 -0.370872 -0.320669 -0.364053 0.24127 0.41416 --0.115313 -0.36425 0.190208 0.581871 0.204605 0.112527 0.313562 0.571337 -0.168272 -0.0746917 -0.635156 -0.214488 0.629498 -0.0812499 -0.337255 -0.00823068 -0.369896 -0.514626 -0.173493 -0.1551 -0.127105 0.384377 0.303936 -0.536566 --0.49013 -0.0388242 -0.0196532 0.463953 0.515962 -0.0756047 0.506276 0.119908 --0.434258 0.060347 0.388793 0.250579 -0.653127 -0.275207 0.295714 0.0637842 -0.596172 -0.133284 -0.501793 0.234541 0.428452 0.0800735 0.110912 -0.343109 diff --git a/src/Bottleneck/test/bottleneck_unit_test.cpp b/src/Bottleneck/test/bottleneck_unit_test.cpp index 068b8690..c60f5d8a 100644 --- a/src/Bottleneck/test/bottleneck_unit_test.cpp +++ b/src/Bottleneck/test/bottleneck_unit_test.cpp @@ -1,6 +1,6 @@ -#define BOOST_TEST_MODULE bottleneck test - -#include <boost/test/included/unit_test.hpp> +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE "bottleneck" +#include <boost/test/unit_test.hpp> #include "gudhi/Graph_matching.h" #include <iostream> diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 70fc9a45..864ee040 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,11 +1,14 @@ cmake_minimum_required(VERSION 2.6) project(GUDHI) +include("CMakeGUDHIVersion.txt") + +enable_testing() + list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules/") find_package(Boost REQUIRED COMPONENTS system filesystem program_options chrono timer REQUIRED) - if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release") endif() @@ -19,7 +22,6 @@ set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_MULTITHREADED ON) set(Boost_USE_STATIC_RUNTIME OFF) -find_package(Boost) find_package(GMP) if(GMP_FOUND) find_package(GMPXX) @@ -36,22 +38,53 @@ else() add_definitions(-DBOOST_ALL_NO_LIB) INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) - LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) - include_directories(include/) - + LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) + + #--------------------------------------------------------------------------------------- + # Gudhi compilation part + include_directories(include) + add_subdirectory(example/Simplex_tree) add_subdirectory(example/Persistent_cohomology) 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/Alpha_shapes) add_subdirectory(example/Bottleneck) + # data points generator + add_subdirectory(data/points/generator) + + # Please let GudhUI in last compilation position as QT is known to modify CMAKE_CXX_FLAGS # GudhUI add_subdirectory(GudhUI) + #--------------------------------------------------------------------------------------- - # data points generator - add_subdirectory(data/points/generator) + #--------------------------------------------------------------------------------------- + # GUDHIConfig.cmake + # Export the package for use from the build-tree + # (this registers the build-tree with a global CMake-registry) + export(PACKAGE GUDHI) + + # Create the GUDHIConfig.cmake and GUDHIConfigVersion files + set(CONF_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/include") + configure_file(GUDHIConfig.cmake.in "${PROJECT_BINARY_DIR}/GUDHIConfig.cmake" @ONLY) + configure_file(GUDHIConfigVersion.cmake.in "${PROJECT_BINARY_DIR}/GUDHIConfigVersion.cmake" @ONLY) + + #--------------------------------------------------------------------------------------- + + #--------------------------------------------------------------------------------------- + # Gudhi installation part + + # Install the GUDHIConfig.cmake and GUDHIConfigVersion.cmake + install(FILES + "${PROJECT_BINARY_DIR}/GUDHIConfig.cmake" + "${PROJECT_BINARY_DIR}/GUDHIConfigVersion.cmake" + DESTINATION share/gudhi) + + # install the include file on "make install" + install(DIRECTORY include/gudhi DESTINATION include) + #--------------------------------------------------------------------------------------- endif() diff --git a/src/Contraction/example/Garland_heckbert.cpp b/src/Contraction/example/Garland_heckbert.cpp index a41f65aa..b545a066 100644 --- a/src/Contraction/example/Garland_heckbert.cpp +++ b/src/Contraction/example/Garland_heckbert.cpp @@ -1,7 +1,4 @@ -/* - * Garland_heckbert.h - * Created on: Feb 10, 2015 - * This file is part of the Gudhi Library. The Gudhi library +/* This file is part of the Gudhi Library. The Gudhi library * (Geometric Understanding in Higher Dimensions) is a generic C++ * library for computational topology. * @@ -28,12 +25,13 @@ #ifndef GARLAND_HECKBERT_H_ #define GARLAND_HECKBERT_H_ +#include <gudhi/Point.h> +#include <gudhi/Edge_contraction.h> +#include <gudhi/Skeleton_blocker.h> +#include <gudhi/Off_reader.h> + #include <boost/timer/timer.hpp> #include <iostream> -#include "gudhi/Point.h" -#include "gudhi/Edge_contraction.h" -#include "gudhi/Skeleton_blocker.h" -#include "gudhi/Off_reader.h" #include "Garland_heckbert/Error_quadric.h" @@ -51,7 +49,6 @@ struct Geometry_trait { */ struct Garland_heckbert_traits : public Skeleton_blocker_simple_geometric_traits<Geometry_trait> { public: - struct Garland_heckbert_vertex : public Simple_geometric_vertex { Error_quadric<Geometry_trait::Point> quadric; }; @@ -68,6 +65,7 @@ typedef Skeleton_blocker_contractor<Complex> Complex_contractor; */ class GH_placement : public Gudhi::contraction::Placement_policy<EdgeProfile> { Complex& complex_; + public: typedef Gudhi::contraction::Placement_policy<EdgeProfile>::Placement_type Placement_type; @@ -91,8 +89,8 @@ class GH_placement : public Gudhi::contraction::Placement_policy<EdgeProfile> { */ class GH_cost : public Gudhi::contraction::Cost_policy<EdgeProfile> { Complex& complex_; - public: + public: typedef Gudhi::contraction::Cost_policy<EdgeProfile>::Cost_type Cost_type; GH_cost(Complex& complex) : complex_(complex) { } @@ -115,13 +113,13 @@ class GH_cost : public Gudhi::contraction::Cost_policy<EdgeProfile> { */ class GH_visitor : public Gudhi::contraction::Contraction_visitor<EdgeProfile> { Complex& complex_; - public: + public: GH_visitor(Complex& complex) : complex_(complex) { } - //Compute quadrics for every vertex v - //The quadric of v consists in the sum of quadric - //of every triangles passing through v weighted by its area + // Compute quadrics for every vertex v + // The quadric of v consists in the sum of quadric + // of every triangles passing through v weighted by its area void on_started(Complex & complex) override { for (auto v : complex.vertex_range()) { @@ -147,11 +145,13 @@ class GH_visitor : public Gudhi::contraction::Contraction_visitor<EdgeProfile> { int main(int argc, char *argv[]) { if (argc != 4) { - std::cerr << "Usage " << argv[0] << " input.off output.off N to load the file input.off, contract N edges and save the result to output.off.\n"; + std::cerr << "Usage " << argv[0] << + " input.off output.off N to load the file input.off, contract N edges and save the result to output.off.\n"; return EXIT_FAILURE; } Complex complex; + typedef Complex::Vertex_handle Vertex_handle; // load the points Skeleton_blocker_off_reader<Complex> off_reader(argv[1], complex); @@ -160,8 +160,12 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - std::cout << "Load complex with " << complex.num_vertices() << " vertices" << std::endl; + if (!complex.empty() && !(complex.point(Vertex_handle(0)).dimension() == 3)) { + std::cerr << "Only points of dimension 3 are supported." << std::endl; + return EXIT_FAILURE; + } + std::cout << "Load complex with " << complex.num_vertices() << " vertices" << std::endl; int num_contractions = atoi(argv[3]); @@ -172,23 +176,24 @@ int main(int argc, char *argv[]) { new GH_cost(complex), new GH_placement(complex), contraction::make_link_valid_contraction<EdgeProfile>(), - new GH_visitor(complex) - ); + new GH_visitor(complex)); std::cout << "Contract " << num_contractions << " edges" << std::endl; contractor.contract_edges(num_contractions); std::cout << "Final complex has " << complex.num_vertices() << " vertices, " << - complex.num_edges() << " edges and" << + complex.num_edges() << " edges and " << complex.num_triangles() << " triangles." << std::endl; - //write simplified complex + // write simplified complex Skeleton_blocker_off_writer<Complex> off_writer(argv[2], complex); return EXIT_SUCCESS; } +#endif // GARLAND_HECKBERT_H_ + + -#endif /* GARLAND_HECKBERT_H_ */ diff --git a/src/Contraction/example/Garland_heckbert/Error_quadric.h b/src/Contraction/example/Garland_heckbert/Error_quadric.h index 725a3a56..a033aa00 100644 --- a/src/Contraction/example/Garland_heckbert/Error_quadric.h +++ b/src/Contraction/example/Garland_heckbert/Error_quadric.h @@ -1,164 +1,182 @@ -/*
- * Error_quadric.h
+/* This file is part of the Gudhi Library. The Gudhi library
+ * (Geometric Understanding in Higher Dimensions) is a generic C++
+ * library for computational topology.
*
- * Created on: 24 janv. 2014
- * Author: dsalinas
+ * Author(s): David Salinas
+ *
+ * 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/>.
+ *
*/
#ifndef ERROR_QUADRIC_H_
#define ERROR_QUADRIC_H_
-#include <vector>
-#include <utility>
#include <boost/optional/optional.hpp>
+#include <vector>
+#include <utility>
-template <typename Point> class Error_quadric{
-private :
- double coeff[10];
-
-public :
- Error_quadric(){
- clear();
- }
-
- /**
- * Quadric corresponding to the L2 distance to the plane.
- *
- * According to the notation of Garland Heckbert, they
- * denote a quadric symetric matrix as :
- * Q = [ q11 q12 q13 q14]
- * [ q12 q22 q23 q24]
- * [ q13 q23 q33 q34]
- * [ q14 q24 q34 q44]
- *
- * which is represented by a vector with 10 elts that
- * are denoted ci for clarity with :
- * Q = [ c0 c1 c2 c3 ]
- * [ c1 c4 c5 c6 ]
- * [ c2 c5 c7 c8 ]
- * [ c3 c6 c8 c9 ]
- *
- * The constructor return the quadrics that represents
- * the squared distance to the plane defined by triangle p0,p1,p2
- * times the area of triangle p0,p1,p2.
- */
- Error_quadric(const Point & p0,const Point & p1,const Point & p2){
-
- Point normal(unit_normal(p0,p1,p2));
- double a=normal[0];
- double b=normal[1];
- double c=normal[2];
- double d= -a*p0[0]-b*p0[1]-c*p0[2];
- coeff[0] = a*a ;
- coeff[1] = a*b ;
- coeff[2] = a*c ;
- coeff[3] = a*d ;
- coeff[4] = b*b ;
- coeff[5] = b*c ;
- coeff[6] = b*d ;
- coeff[7] = c*c ;
- coeff[8] = c*d ;
- coeff[9] = d*d ;
-
- double area_p0p1p2 = std::sqrt(squared_area(p0,p1,p2));
- for(auto& x : coeff)
- x*= area_p0p1p2;
- }
-
-
- inline double squared_area(const Point& p0,const Point& p1,const Point& p2) {
- //if (x1,x2,x3) = p1-p0 and (y1,y2,y3) = p2-p0
- //then the squared area is = (u^2+v^2+w^2)/4
- //with: u = x2 * y3 - x3 * y2;
- // v = x3 * y1 - x1 * y3;
- // w = x1 * y2 - x2 * y1;
- Point p0p1(p1-p0);
- Point p0p2(p2-p0);
- double A = p0p1[1] * p0p2[2] - p0p1[2] * p0p2[1];
- double B = p0p1[2] * p0p2[0] - p0p1[0] * p0p2[2];
- double C = p0p1[0] * p0p2[1] - p0p1[1] * p0p2[0];
- return 1./4. * (A*A+B*B+C*C);
- }
-
-
- void clear(){
- for(auto& x:coeff)
- x=0;
- }
-
- Error_quadric& operator+=(const Error_quadric& other){
- if(this!=&other)
- for(int i = 0 ; i < 10; ++i)
- coeff[i] += other.coeff[i];
- return *this;
- }
-
- /**
- * @return The quadric quost defined by the scalar product v^T Q v where Q is the quadratic form of Garland/Heckbert
- */
- inline double cost(const Point& point) const{
- double cost =
- coeff[0]*point.x()*point.x()+coeff[4]*point.y()*point.y()+coeff[7]*point.z()*point.z()
- +2*(coeff[1]*point.x()*point.y()+coeff[5]*point.y()*point.z()+coeff[2]*point.z()*point.x())
- +2*(coeff[3]*point.x()+coeff[6]*point.y()+coeff[8]*point.z())
- +coeff[9];
- if(cost<0) return 0;
- else {
- return cost;
- }
- }
-
- inline double grad_determinant() const{
- return
- coeff[0] * coeff[4] * coeff[7]
- - coeff[0] * coeff[5] * coeff[5]
- - coeff[1] * coeff[1] * coeff[7]
- +2*coeff[1] * coeff[5] * coeff[2]
- - coeff[4] * coeff[2] * coeff[2];
- }
-
- /**
- * Return the point such that it minimizes the gradient of the quadric.
- * Det must be passed with the determinant value of the gradient (should be non zero).
- */
- inline Point solve_linear_gradient(double det = grad_determinant()) const{
- return Point({
- (-coeff[1]*coeff[5]*coeff[8]+coeff[1]*coeff[7]*coeff[6]+coeff[2]*coeff[8]*coeff[4]-coeff[2]*coeff[5]*coeff[6]-coeff[3]*coeff[4]*coeff[7]+coeff[3]*coeff[5]*coeff[5])/ det,
- (coeff[0]*coeff[5]*coeff[8]-coeff[0]*coeff[7]*coeff[6]-coeff[5]*coeff[2]*coeff[3]-coeff[1]*coeff[2]*coeff[8]+coeff[6]*coeff[2]*coeff[2]+coeff[1]*coeff[3]*coeff[7])/det,
- (-coeff[8]*coeff[0]*coeff[4]+coeff[8]*coeff[1]*coeff[1]+coeff[2]*coeff[3]*coeff[4]+coeff[5]*coeff[0]*coeff[6]-coeff[5]*coeff[1]*coeff[3]-coeff[1]*coeff[2]*coeff[6])/det
- });
- }
-
-
- /**
- * returns the point that minimizes the quadric.
- * It inverses the quadric if its determinant is higher that a given threshold .
- * If the determinant is lower than this value the returned value is uninitialized.
- */
- boost::optional<Point> min_cost(double scale=1) const{
- // const double min_determinant = 1e-4 * scale*scale;
- const double min_determinant = 1e-5;
- boost::optional<Point> pt_res;
- double det = grad_determinant();
- if (std::abs(det)>min_determinant)
- pt_res = solve_linear_gradient(det);
- return pt_res;
- }
-
- friend std::ostream& operator<< (std::ostream& stream, const Error_quadric& quadric) {
- stream << "\n[ "<<quadric.coeff[0]<<","<<quadric.coeff[1]<<","<<quadric.coeff[2]<<","<<quadric.coeff[3]<<";\n";
- stream << " "<<quadric.coeff[1]<<","<<quadric.coeff[4]<<","<<quadric.coeff[5]<<","<<quadric.coeff[6]<<";\n";
- stream << " "<<quadric.coeff[2]<<","<<quadric.coeff[5]<<","<<quadric.coeff[7]<<","<<quadric.coeff[8]<<";\n";
- stream << " "<<quadric.coeff[3]<<","<<quadric.coeff[6]<<","<<quadric.coeff[8]<<","<<quadric.coeff[9]<<"]";
- return stream;
- }
-
-
+template <typename Point> class Error_quadric {
+ private:
+ double coeff[10];
+
+ public:
+ Error_quadric() {
+ clear();
+ }
+
+ /**
+ * Quadric corresponding to the L2 distance to the plane.
+ *
+ * According to the notation of Garland Heckbert, they
+ * denote a quadric symetric matrix as :
+ * Q = [ q11 q12 q13 q14]
+ * [ q12 q22 q23 q24]
+ * [ q13 q23 q33 q34]
+ * [ q14 q24 q34 q44]
+ *
+ * which is represented by a vector with 10 elts that
+ * are denoted ci for clarity with :
+ * Q = [ c0 c1 c2 c3 ]
+ * [ c1 c4 c5 c6 ]
+ * [ c2 c5 c7 c8 ]
+ * [ c3 c6 c8 c9 ]
+ *
+ * The constructor return the quadrics that represents
+ * the squared distance to the plane defined by triangle p0,p1,p2
+ * times the area of triangle p0,p1,p2.
+ */
+ Error_quadric(const Point & p0, const Point & p1, const Point & p2) {
+ Point normal(unit_normal(p0, p1, p2));
+ double a = normal[0];
+ double b = normal[1];
+ double c = normal[2];
+ double d = -a * p0[0] - b * p0[1] - c * p0[2];
+ coeff[0] = a*a;
+ coeff[1] = a*b;
+ coeff[2] = a*c;
+ coeff[3] = a*d;
+ coeff[4] = b*b;
+ coeff[5] = b*c;
+ coeff[6] = b*d;
+ coeff[7] = c*c;
+ coeff[8] = c*d;
+ coeff[9] = d*d;
+
+ double area_p0p1p2 = std::sqrt(squared_area(p0, p1, p2));
+ for (auto& x : coeff)
+ x *= area_p0p1p2;
+ }
+
+ inline double squared_area(const Point& p0, const Point& p1, const Point& p2) {
+ // if (x1,x2,x3) = p1-p0 and (y1,y2,y3) = p2-p0
+ // then the squared area is = (u^2+v^2+w^2)/4
+ // with: u = x2 * y3 - x3 * y2;
+ // v = x3 * y1 - x1 * y3;
+ // w = x1 * y2 - x2 * y1;
+ Point p0p1(p1 - p0);
+ Point p0p2(p2 - p0);
+ double A = p0p1[1] * p0p2[2] - p0p1[2] * p0p2[1];
+ double B = p0p1[2] * p0p2[0] - p0p1[0] * p0p2[2];
+ double C = p0p1[0] * p0p2[1] - p0p1[1] * p0p2[0];
+ return 1. / 4. * (A * A + B * B + C * C);
+ }
+
+ void clear() {
+ for (auto& x : coeff)
+ x = 0;
+ }
+
+ Error_quadric& operator+=(const Error_quadric& other) {
+ if (this != &other) {
+ for (int i = 0; i < 10; ++i)
+ coeff[i] += other.coeff[i];
+ }
+ return *this;
+ }
+
+ /**
+ * @return The quadric quost defined by the scalar product v^T Q v where Q is the quadratic form of Garland/Heckbert
+ */
+ inline double cost(const Point& point) const {
+ double cost =
+ coeff[0] * point.x() * point.x() + coeff[4] * point.y() * point.y() + coeff[7] * point.z() * point.z()
+ + 2 * (coeff[1] * point.x() * point.y() + coeff[5] * point.y() * point.z() + coeff[2] * point.z() * point.x())
+ + 2 * (coeff[3] * point.x() + coeff[6] * point.y() + coeff[8] * point.z())
+ + coeff[9];
+ if (cost < 0) {
+ return 0;
+ } else {
+ return cost;
+ }
+ }
+
+ inline double grad_determinant() const {
+ return
+ coeff[0] * coeff[4] * coeff[7]
+ - coeff[0] * coeff[5] * coeff[5]
+ - coeff[1] * coeff[1] * coeff[7]
+ + 2 * coeff[1] * coeff[5] * coeff[2]
+ - coeff[4] * coeff[2] * coeff[2];
+ }
+
+ /**
+ * Return the point such that it minimizes the gradient of the quadric.
+ * Det must be passed with the determinant value of the gradient (should be non zero).
+ */
+ inline Point solve_linear_gradient(double det) const {
+ return Point({
+ (-coeff[1] * coeff[5] * coeff[8] + coeff[1] * coeff[7] * coeff[6] + coeff[2] * coeff[8] * coeff[4] -
+ coeff[2] * coeff[5] * coeff[6] - coeff[3] * coeff[4] * coeff[7] + coeff[3] * coeff[5] * coeff[5])
+ / det,
+ (coeff[0] * coeff[5] * coeff[8] - coeff[0] * coeff[7] * coeff[6] - coeff[5] * coeff[2] * coeff[3] -
+ coeff[1] * coeff[2] * coeff[8] + coeff[6] * coeff[2] * coeff[2] + coeff[1] * coeff[3] * coeff[7])
+ / det,
+ (-coeff[8] * coeff[0] * coeff[4] + coeff[8] * coeff[1] * coeff[1] + coeff[2] * coeff[3] * coeff[4] +
+ coeff[5] * coeff[0] * coeff[6] - coeff[5] * coeff[1] * coeff[3] - coeff[1] * coeff[2] * coeff[6])
+ / det
+ });
+ }
+
+ /**
+ * returns the point that minimizes the quadric.
+ * It inverses the quadric if its determinant is higher that a given threshold .
+ * If the determinant is lower than this value the returned value is uninitialized.
+ */
+ boost::optional<Point> min_cost(double scale = 1) const {
+ // const double min_determinant = 1e-4 * scale*scale;
+ const double min_determinant = 1e-5;
+ boost::optional<Point> pt_res;
+ double det = grad_determinant();
+ if (std::abs(det) > min_determinant)
+ pt_res = solve_linear_gradient(det);
+ return pt_res;
+ }
+
+ friend std::ostream& operator<<(std::ostream& stream, const Error_quadric& quadric) {
+ stream << "\n[ " << quadric.coeff[0] << "," << quadric.coeff[1] << "," << quadric.coeff[2] << "," <<
+ quadric.coeff[3] << ";\n";
+ stream << " " << quadric.coeff[1] << "," << quadric.coeff[4] << "," << quadric.coeff[5] << "," <<
+ quadric.coeff[6] << ";\n";
+ stream << " " << quadric.coeff[2] << "," << quadric.coeff[5] << "," << quadric.coeff[7] << "," <<
+ quadric.coeff[8] << ";\n";
+ stream << " " << quadric.coeff[3] << "," << quadric.coeff[6] << "," << quadric.coeff[8] << "," <<
+ quadric.coeff[9] << "]";
+ return stream;
+ }
};
-
-
-
-#endif /* ERROR_QUADRIC_H_ */
-
+#endif // ERROR_QUADRIC_H_
diff --git a/src/Contraction/example/Rips_contraction.cpp b/src/Contraction/example/Rips_contraction.cpp index bd0a8b8c..f80cc2dc 100644 --- a/src/Contraction/example/Rips_contraction.cpp +++ b/src/Contraction/example/Rips_contraction.cpp @@ -19,24 +19,23 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <gudhi/Edge_contraction.h> +#include <gudhi/Skeleton_blocker.h> +#include <gudhi/Off_reader.h> +#include <gudhi/Point.h> + #include <boost/timer/timer.hpp> #include <iostream> -#include "gudhi/Edge_contraction.h" -#include "gudhi/Skeleton_blocker.h" -#include "gudhi/Off_reader.h" -#include "gudhi/Point.h" using namespace std; using namespace Gudhi; using namespace skbl; using namespace contraction; - -struct Geometry_trait{ - typedef Point_d Point; +struct Geometry_trait { + typedef Point_d Point; }; - typedef Geometry_trait::Point Point; typedef Skeleton_blocker_simple_geometric_traits<Geometry_trait> Complex_geometric_traits; typedef Skeleton_blocker_geometric_complex< Complex_geometric_traits > Complex; @@ -44,62 +43,62 @@ typedef Edge_profile<Complex> Profile; typedef Skeleton_blocker_contractor<Complex> Complex_contractor; template<typename ComplexType> -void build_rips(ComplexType& complex, double offset){ - if (offset<=0) return; - auto vertices = complex.vertex_range(); - for (auto p = vertices.begin(); p != vertices.end(); ++p) - for (auto q = p; ++q != vertices.end(); /**/){ - if ( squared_dist(complex.point(*p), complex.point(*q)) < 4 * offset * offset) - complex.add_edge(*p,*q); - } +void build_rips(ComplexType& complex, double offset) { + if (offset <= 0) return; + auto vertices = complex.vertex_range(); + for (auto p = vertices.begin(); p != vertices.end(); ++p) + for (auto q = p; ++q != vertices.end(); /**/) { + if (squared_dist(complex.point(*p), complex.point(*q)) < 4 * offset * offset) + complex.add_edge_without_blockers(*p, *q); + } } -int main (int argc, char *argv[]) -{ - if (argc!=3){ - std::cerr << "Usage "<<argv[0]<<" ../../../data/meshes/SO3_10000.off 0.3 to load the file ../../data/SO3_10000.off and contract the Rips complex built with paremeter 0.3.\n"; - return -1; - } +int main(int argc, char *argv[]) { + if (argc != 3) { + std::cerr << "Usage " << argv[0] << " ../../../data/meshes/SO3_10000.off 0.3 to load the file " << + "../../data/SO3_10000.off and contract the Rips complex built with paremeter 0.3.\n"; + return -1; + } - Complex complex; + Complex complex; - // load only the points - Skeleton_blocker_off_reader<Complex> off_reader(argv[1],complex,true); - if(!off_reader.is_valid()){ - std::cerr << "Unable to read file:"<<argv[1]<<std::endl; - return EXIT_FAILURE; - } + // load only the points + Skeleton_blocker_off_reader<Complex> off_reader(argv[1], complex, true); + if (!off_reader.is_valid()) { + std::cerr << "Unable to read file:" << argv[1] << std::endl; + return EXIT_FAILURE; + } - std::cout << "Build the Rips complex with "<<complex.num_vertices()<<" vertices"<<std::endl; + std::cout << "Build the Rips complex with " << complex.num_vertices() << " vertices" << std::endl; - build_rips(complex,atof(argv[2])); + build_rips(complex, atof(argv[2])); - boost::timer::auto_cpu_timer t; + boost::timer::auto_cpu_timer t; - std::cout << "Initial complex has "<< - complex.num_vertices()<<" vertices and "<< - complex.num_edges()<<" edges"<<std::endl; + std::cout << "Initial complex has " << + complex.num_vertices() << " vertices and " << + complex.num_edges() << " edges" << std::endl; - Complex_contractor contractor(complex, - new Edge_length_cost<Profile>, - contraction::make_first_vertex_placement<Profile>(), - contraction::make_link_valid_contraction<Profile>(), - contraction::make_remove_popable_blockers_visitor<Profile>()); - contractor.contract_edges(); + Complex_contractor contractor(complex, + new Edge_length_cost<Profile>, + contraction::make_first_vertex_placement<Profile>(), + contraction::make_link_valid_contraction<Profile>(), + contraction::make_remove_popable_blockers_visitor<Profile>()); + contractor.contract_edges(); - std::cout << "Counting final number of simplices \n"; - unsigned num_simplices = std::distance(complex.simplex_range().begin(),complex.simplex_range().end()); + std::cout << "Counting final number of simplices \n"; + unsigned num_simplices = std::distance(complex.complex_simplex_range().begin(), complex.complex_simplex_range().end()); - std::cout << "Final complex has "<< - complex.num_vertices()<<" vertices, "<< - complex.num_edges()<<" edges, "<< - complex.num_blockers()<<" blockers and "<< - num_simplices<<" simplices"<<std::endl; + std::cout << "Final complex has " << + complex.num_vertices() << " vertices, " << + complex.num_edges() << " edges, " << + complex.num_blockers() << " blockers and " << + num_simplices << " simplices" << std::endl; - std::cout << "Time to simplify and enumerate simplices:\n"; + std::cout << "Time to simplify and enumerate simplices:\n"; - return EXIT_SUCCESS; + return EXIT_SUCCESS; } diff --git a/src/Contraction/include/gudhi/Contraction/CGAL_queue/Modifiable_priority_queue.h b/src/Contraction/include/gudhi/Contraction/CGAL_queue/Modifiable_priority_queue.h index 10b89e13..5a55c513 100644 --- a/src/Contraction/include/gudhi/Contraction/CGAL_queue/Modifiable_priority_queue.h +++ b/src/Contraction/include/gudhi/Contraction/CGAL_queue/Modifiable_priority_queue.h @@ -16,76 +16,86 @@ // // Author(s) : Fernando Cacciola <fernando.cacciola@geometryfactory.com> // -#ifndef CGAL_MODIFIABLE_PRIORITY_QUEUE_H -#define CGAL_MODIFIABLE_PRIORITY_QUEUE_H +#ifndef CONTRACTION_CGAL_QUEUE_MODIFIABLE_PRIORITY_QUEUE_H_ +#define CONTRACTION_CGAL_QUEUE_MODIFIABLE_PRIORITY_QUEUE_H_ #define CGAL_SURFACE_MESH_SIMPLIFICATION_USE_RELAXED_HEAP -#include <climits> // Neeeded by the following Boost header for CHAR_BIT. #include <boost/optional.hpp> #include <boost/pending/relaxed_heap.hpp> -namespace CGAL { +#include <climits> // Neeeded by the following Boost header for CHAR_BIT. +#include <functional> // for less -template <class IndexedType_ - ,class Compare_ = std::less<IndexedType_> - ,class ID_ = boost::identity_property_map - > -class Modifiable_priority_queue -{ -public: +namespace CGAL { +template <class IndexedType_, class Compare_ = std::less<IndexedType_>, class ID_ = boost::identity_property_map> +class Modifiable_priority_queue { + public: typedef Modifiable_priority_queue Self; - - typedef IndexedType_ IndexedType ; - typedef Compare_ Compare; - typedef ID_ ID ; - - typedef boost::relaxed_heap<IndexedType,Compare,ID> Heap; + + typedef IndexedType_ IndexedType; + typedef Compare_ Compare; + typedef ID_ ID; + + typedef boost::relaxed_heap<IndexedType, Compare, ID> Heap; typedef typename Heap::value_type value_type; - typedef typename Heap::size_type size_type; - - typedef bool handle ; - -public: - - Modifiable_priority_queue( size_type largest_ID, Compare const& c, ID const& id ) : mHeap(largest_ID,c,id) {} - - handle push ( value_type const& v ) { mHeap.push(v) ; return handle(true) ; } - - handle update ( value_type const& v, handle h ) { mHeap.update(v); return h ; } - - handle erase ( value_type const& v, handle ) { mHeap.remove(v); return null_handle() ; } - - value_type top() const { return mHeap.top() ; } - - void pop() { mHeap.pop(); } - - bool empty() const { return mHeap.empty() ; } - - bool contains ( value_type const& v ) { return mHeap.contains(v) ; } - - boost::optional<value_type> extract_top() - { - boost::optional<value_type> r ; - if ( !empty() ) - { + typedef typename Heap::size_type size_type; + + typedef bool handle; + + public: + Modifiable_priority_queue(size_type largest_ID, Compare const& c, ID const& id) : mHeap(largest_ID, c, id) { } + + handle push(value_type const& v) { + mHeap.push(v); + return handle(true); + } + + handle update(value_type const& v, handle h) { + mHeap.update(v); + return h; + } + + handle erase(value_type const& v, handle) { + mHeap.remove(v); + return null_handle(); + } + + value_type top() const { + return mHeap.top(); + } + + void pop() { + mHeap.pop(); + } + + bool empty() const { + return mHeap.empty(); + } + + bool contains(value_type const& v) { + return mHeap.contains(v); + } + + boost::optional<value_type> extract_top() { + boost::optional<value_type> r; + if (!empty()) { value_type v = top(); pop(); - r = boost::optional<value_type>(v) ; - } - return r ; + r = boost::optional<value_type>(v); + } + return r; + } + + static handle null_handle() { + return handle(false); } - - static handle null_handle() { return handle(false); } - -private: - Heap mHeap ; - -} ; + private: + Heap mHeap; +}; -} //namespace CGAL +} // namespace CGAL -#endif - +#endif // CONTRACTION_CGAL_QUEUE_MODIFIABLE_PRIORITY_QUEUE_H_ diff --git a/src/Contraction/include/gudhi/Contraction/Edge_profile.h b/src/Contraction/include/gudhi/Contraction/Edge_profile.h index f90bd71a..e4910b27 100644 --- a/src/Contraction/include/gudhi/Contraction/Edge_profile.h +++ b/src/Contraction/include/gudhi/Contraction/Edge_profile.h @@ -1,130 +1,130 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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_EDGE_PROFILE_H_ -#define GUDHI_EDGE_PROFILE_H_ -//#include "combinatorics/Skeleton_blocker/Simplex.h" - - -namespace Gudhi{ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 CONTRACTION_EDGE_PROFILE_H_ +#define CONTRACTION_EDGE_PROFILE_H_ + +#include <ostream> + +namespace Gudhi { namespace contraction { -template<typename GeometricSimplifiableComplex> class Edge_profile{ -public: - typedef GeometricSimplifiableComplex Complex; - typedef typename Complex::GT GT; +template<typename GeometricSimplifiableComplex> class Edge_profile { + public: + typedef GeometricSimplifiableComplex Complex; + typedef typename Complex::GT GT; - typedef typename GeometricSimplifiableComplex::Vertex_handle Vertex_handle; - typedef typename GeometricSimplifiableComplex::Root_vertex_handle Root_vertex_handle; + typedef typename GeometricSimplifiableComplex::Vertex_handle Vertex_handle; + typedef typename GeometricSimplifiableComplex::Root_vertex_handle Root_vertex_handle; - typedef typename GeometricSimplifiableComplex::Edge_handle Edge_handle; - typedef typename GeometricSimplifiableComplex::Graph_vertex Graph_vertex; - typedef typename GeometricSimplifiableComplex::Graph_edge Graph_edge; - typedef typename GeometricSimplifiableComplex::Point Point; + typedef typename GeometricSimplifiableComplex::Edge_handle Edge_handle; + typedef typename GeometricSimplifiableComplex::Graph_vertex Graph_vertex; + typedef typename GeometricSimplifiableComplex::Graph_edge Graph_edge; + typedef typename GeometricSimplifiableComplex::Point Point; + Edge_profile(GeometricSimplifiableComplex& complex, Edge_handle edge) : complex_(complex), edge_handle_(edge), + v0_(complex_.first_vertex(edge_handle_)), v1_(complex_.second_vertex(edge_handle_)) { + assert(complex_.get_address(complex_[edge_handle_].first())); + assert(complex_.get_address(complex_[edge_handle_].second())); + assert(complex_.contains_edge(v0_handle(), v1_handle())); + assert(v0_handle() != v1_handle()); + } + virtual ~Edge_profile() { } + GeometricSimplifiableComplex& complex() const { + return complex_; + } - Edge_profile( GeometricSimplifiableComplex& complex,Edge_handle edge):complex_(complex),edge_handle_(edge), - v0_(complex_.first_vertex(edge_handle_)),v1_(complex_.second_vertex(edge_handle_)) -{ - assert(complex_.get_address(complex_[edge_handle_].first())); - assert(complex_.get_address(complex_[edge_handle_].second())); - assert(complex_.contains_edge(v0_handle(),v1_handle())); - assert(v0_handle() != v1_handle()); -} + Edge_handle edge_handle() const { + return edge_handle_; + } - virtual ~Edge_profile(){ } + Graph_edge& edge() const { + return complex_[edge_handle_]; + } + Graph_vertex& v0() const { + return complex_[v0_handle()]; + } - GeometricSimplifiableComplex& complex() const { - return complex_; - } + Graph_vertex& v1() const { + return complex_[v1_handle()]; + } - Edge_handle edge_handle() const{ - return edge_handle_; - } + Vertex_handle v0_handle() const { + return v0_; + // Root_vertex_handle root = complex_[edge_handle_].first(); + // assert(complex_.get_address(root)); + // return *complex_.get_address(root); + } - Graph_edge& edge() const{ - return complex_[edge_handle_]; - } + Vertex_handle v1_handle() const { + return v1_; + // Root_vertex_handle root = complex_[edge_handle_].second(); + // assert(complex_.get_address(root)); + // return *complex_.get_address(root); + } + const Point& p0() const { + return complex_.point(v0_handle()); + } - Graph_vertex& v0() const{return complex_[v0_handle()];} - Graph_vertex& v1() const{return complex_[v1_handle()];} + const Point& p1() const { + return complex_.point(v1_handle()); + } + friend std::ostream& operator<<(std::ostream& o, const Edge_profile& v) { + return o << "v0:" << v.v0_handle() << " v1:" << v.v1_handle(); + } - Vertex_handle v0_handle() const{ - return v0_; -// Root_vertex_handle root = complex_[edge_handle_].first(); -// assert(complex_.get_address(root)); -// return *complex_.get_address(root); - } + private: + GeometricSimplifiableComplex& complex_; - Vertex_handle v1_handle() const{ - return v1_; -// Root_vertex_handle root = complex_[edge_handle_].second(); -// assert(complex_.get_address(root)); -// return *complex_.get_address(root); - } + Edge_handle edge_handle_; - const Point& p0() const {return complex_.point(v0_handle());} + Vertex_handle v0_; - const Point& p1() const {return complex_.point(v1_handle());} - - friend std::ostream& operator << (std::ostream& o, const Edge_profile & v){ - o << "v0:"<<v.v0_handle() << " v1:"<<v.v1_handle(); - return o; - } -private: - - GeometricSimplifiableComplex& complex_; - - Edge_handle edge_handle_; - - Vertex_handle v0_; + Vertex_handle v1_; +}; - Vertex_handle v1_; +template<typename EdgeProfile> class Edge_profile_factory { + public: + typedef typename EdgeProfile::Edge_handle Edge_handle_; + typedef typename EdgeProfile::Complex Complex_; -}; + virtual EdgeProfile make_profile( + Complex_& complex, + Edge_handle_ edge) const { + return EdgeProfile(complex, edge); + } -template<typename EdgeProfile> class Edge_profile_factory{ -public: - typedef typename EdgeProfile::Edge_handle Edge_handle_; - typedef typename EdgeProfile::Complex Complex_; - virtual EdgeProfile make_profile( - Complex_& complex, - Edge_handle_ edge) const{ - return EdgeProfile(complex,edge); - } - - virtual ~Edge_profile_factory(){}; + virtual ~Edge_profile_factory() { } }; - } // namespace contraction -} // namespace GUDHI +} // namespace Gudhi -#endif /* GUDHI_EDGE_PROFILE_H_ */ +#endif // CONTRACTION_EDGE_PROFILE_H_ diff --git a/src/Contraction/include/gudhi/Contraction/policies/Contraction_visitor.h b/src/Contraction/include/gudhi/Contraction/policies/Contraction_visitor.h index b8b1e87a..7ee05aad 100644 --- a/src/Contraction/include/gudhi/Contraction/policies/Contraction_visitor.h +++ b/src/Contraction/include/gudhi/Contraction/policies/Contraction_visitor.h @@ -1,32 +1,32 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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_CONTRACTION_VISITOR_H_ -#define GUDHI_CONTRACTION_VISITOR_H_ - -#include "gudhi/Contraction/Edge_profile.h" -#include "boost/optional.hpp" - -namespace Gudhi{ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 CONTRACTION_POLICIES_CONTRACTION_VISITOR_H_ +#define CONTRACTION_POLICIES_CONTRACTION_VISITOR_H_ + +#include <gudhi/Contraction/Edge_profile.h> +#include <boost/optional.hpp> + +namespace Gudhi { namespace contraction { @@ -36,66 +36,56 @@ namespace contraction { *@ingroup contr */ template <typename EdgeProfile> -class Contraction_visitor {//: public Dummy_complex_visitor<typename EdgeProfile::Vertex_handle> { -public: - //typedef typename ComplexType::GeometryTrait GT; - typedef EdgeProfile Profile; - typedef double FT; - typedef typename Profile::Complex Complex; - typedef Complex ComplexType; - typedef typename ComplexType::Point Point; - - - virtual ~Contraction_visitor(){}; - - /** - * @brief Called before the edge contraction process starts. - */ - virtual void on_started (ComplexType & complex){} - - /** - * @brief Called when the algorithm stops. - */ - virtual void on_stop_condition_reached (){} - - - /** - * @brief Called during the collecting phase (when a cost is assigned to the edges), for each edge collected. - */ - virtual void on_collected (const Profile &profile, boost::optional< FT > cost){} - - /** - * @brief Called during the processing phase (when edges are contracted), for each edge that is selected. - */ - virtual void on_selected (const Profile &profile, boost::optional< FT > cost, int initial_count, int current_count){} - - - /** - * @brief Called when an edge is about to be contracted and replaced by a vertex whose position is *placement. - */ - virtual void on_contracting(const Profile &profile, boost::optional< Point > placement){ - } - - - - /** - * @brief Called when after an edge has been contracted onto a new point placement. - * A possibility would to remove popable blockers at this point for instance. - */ - virtual void on_contracted(const Profile &profile, boost::optional< Point > placement){ - - } - - - /** - * @brief Called for each selected edge which cannot be contracted because the ValidContractionPredicate is false - */ - virtual void on_non_valid(const Profile &profile){} - +class Contraction_visitor { // : public Dummy_complex_visitor<typename EdgeProfile::Vertex_handle> { + public: + // typedef typename ComplexType::GeometryTrait GT; + typedef EdgeProfile Profile; + typedef double FT; + typedef typename Profile::Complex Complex; + typedef Complex ComplexType; + typedef typename ComplexType::Point Point; + + virtual ~Contraction_visitor() { } + + /** + * @brief Called before the edge contraction process starts. + */ + virtual void on_started(ComplexType & complex) { } + + /** + * @brief Called when the algorithm stops. + */ + virtual void on_stop_condition_reached() { } + + /** + * @brief Called during the collecting phase (when a cost is assigned to the edges), for each edge collected. + */ + virtual void on_collected(const Profile &profile, boost::optional< FT > cost) { } + + /** + * @brief Called during the processing phase (when edges are contracted), for each edge that is selected. + */ + virtual void on_selected(const Profile &profile, boost::optional< FT > cost, int initial_count, int current_count) { } + + /** + * @brief Called when an edge is about to be contracted and replaced by a vertex whose position is *placement. + */ + virtual void on_contracting(const Profile &profile, boost::optional< Point > placement) { } + + /** + * @brief Called when after an edge has been contracted onto a new point placement. + * A possibility would to remove popable blockers at this point for instance. + */ + virtual void on_contracted(const Profile &profile, boost::optional< Point > placement) { } + + /** + * @brief Called for each selected edge which cannot be contracted because the ValidContractionPredicate is false + */ + virtual void on_non_valid(const Profile &profile) { } }; } // namespace contraction -} // namespace GUDHI +} // namespace Gudhi -#endif /* GUDHI_CONTRACTION_VISITOR_H_ */ +#endif // CONTRACTION_POLICIES_CONTRACTION_VISITOR_H_ diff --git a/src/Contraction/include/gudhi/Contraction/policies/Cost_policy.h b/src/Contraction/include/gudhi/Contraction/policies/Cost_policy.h index 3cb18c86..f4d343ec 100644 --- a/src/Contraction/include/gudhi/Contraction/policies/Cost_policy.h +++ b/src/Contraction/include/gudhi/Contraction/policies/Cost_policy.h @@ -1,51 +1,53 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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_COST_POLICY_H_ -#define GUDHI_COST_POLICY_H_ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 CONTRACTION_POLICIES_COST_POLICY_H_ +#define CONTRACTION_POLICIES_COST_POLICY_H_ #include <boost/optional.hpp> -namespace Gudhi{ +namespace Gudhi { namespace contraction { /** -*@brief Policy to specify the cost of contracting an edge. + *@brief Policy to specify the cost of contracting an edge. *@ingroup contr -*/ -template< typename EdgeProfile> class Cost_policy{ -public: - typedef typename EdgeProfile::Point Point; - typedef typename EdgeProfile::Graph_vertex Graph_vertex; + */ +template< typename EdgeProfile> +class Cost_policy { + public: + typedef typename EdgeProfile::Point Point; + typedef typename EdgeProfile::Graph_vertex Graph_vertex; - typedef boost::optional<double> Cost_type; + typedef boost::optional<double> Cost_type; - virtual Cost_type operator()(const EdgeProfile& profile, const boost::optional<Point>& placement) const =0; - virtual ~Cost_policy(){ - }; + virtual Cost_type operator()(const EdgeProfile& profile, const boost::optional<Point>& placement) const = 0; + + virtual ~Cost_policy() { } }; } // namespace contraction -} // namespace GUDHI -#endif /* GUDHI_COST_POLICY_H_ */ +} // namespace Gudhi + +#endif // CONTRACTION_POLICIES_COST_POLICY_H_ diff --git a/src/Contraction/include/gudhi/Contraction/policies/Dummy_valid_contraction.h b/src/Contraction/include/gudhi/Contraction/policies/Dummy_valid_contraction.h index de473944..5d329496 100644 --- a/src/Contraction/include/gudhi/Contraction/policies/Dummy_valid_contraction.h +++ b/src/Contraction/include/gudhi/Contraction/policies/Dummy_valid_contraction.h @@ -1,51 +1,49 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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_DUMMY_VALID_CONTRACTION_H_ -#define GUDHI_DUMMY_VALID_CONTRACTION_H_ - -#include "Valid_contraction_policy.h" - -namespace Gudhi{ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 CONTRACTION_POLICIES_DUMMY_VALID_CONTRACTION_H_ +#define CONTRACTION_POLICIES_DUMMY_VALID_CONTRACTION_H_ + +#include <gudhi/Contraction/policies/Valid_contraction_policy.h> + +namespace Gudhi { namespace contraction { - - - /** - *@brief Policy that accept all edge contraction. - */ -template< typename EdgeProfile> class Dummy_valid_contraction : public Valid_contraction_policy<EdgeProfile>{ -public: - typedef typename EdgeProfile::Point Point; - bool operator()(const EdgeProfile& profile,const boost::optional<Point>& placement){ - return true; - } +/** + *@brief Policy that accept all edge contraction. + */ +template< typename EdgeProfile> +class Dummy_valid_contraction : public Valid_contraction_policy<EdgeProfile> { + public: + typedef typename EdgeProfile::Point Point; + + bool operator()(const EdgeProfile& profile, const boost::optional<Point>& placement) { + return true; + } }; } // namespace contraction -} // namespace GUDHI - - +} // namespace Gudhi -#endif /* GUDHI_DUMMY_VALID_CONTRACTION_H_ */ +#endif // CONTRACTION_POLICIES_DUMMY_VALID_CONTRACTION_H_ diff --git a/src/Contraction/include/gudhi/Contraction/policies/Edge_length_cost.h b/src/Contraction/include/gudhi/Contraction/policies/Edge_length_cost.h index b22ada0d..dac2d448 100644 --- a/src/Contraction/include/gudhi/Contraction/policies/Edge_length_cost.h +++ b/src/Contraction/include/gudhi/Contraction/policies/Edge_length_cost.h @@ -1,56 +1,56 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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_EDGE_LENGTH_COST_H_ -#define GUDHI_EDGE_LENGTH_COST_H_ - -#include "Cost_policy.h" - -namespace Gudhi{ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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/>. + */ -namespace contraction { +#ifndef CONTRACTION_POLICIES_EDGE_LENGTH_COST_H_ +#define CONTRACTION_POLICIES_EDGE_LENGTH_COST_H_ + +#include <gudhi/Contraction/policies/Cost_policy.h> +namespace Gudhi { + +namespace contraction { /** * @brief return a cost corresponding to the squared length of the edge */ -template< typename EdgeProfile> class Edge_length_cost : public Cost_policy<EdgeProfile>{ -public: - typedef typename Cost_policy<EdgeProfile>::Cost_type Cost_type; - typedef typename EdgeProfile::Point Point; - Cost_type operator()(const EdgeProfile& profile, const boost::optional<Point>& placement) const override{ - double res = 0; - auto p0_coord = profile.p0().begin(); - auto p1_coord = profile.p1().begin(); - for(; p0_coord != profile.p0().end(); p0_coord++, p1_coord++){ - res += (*p0_coord - *p1_coord) * (*p0_coord - *p1_coord); - } - return res; - } - +template< typename EdgeProfile> +class Edge_length_cost : public Cost_policy<EdgeProfile> { + public: + typedef typename Cost_policy<EdgeProfile>::Cost_type Cost_type; + typedef typename EdgeProfile::Point Point; + + Cost_type operator()(const EdgeProfile& profile, const boost::optional<Point>& placement) const override { + double res = 0; + auto p0_coord = profile.p0().begin(); + auto p1_coord = profile.p1().begin(); + for (; p0_coord != profile.p0().end(); p0_coord++, p1_coord++) { + res += (*p0_coord - *p1_coord) * (*p0_coord - *p1_coord); + } + return res; + } }; } // namespace contraction -} // namespace GUDHI +} // namespace Gudhi -#endif /* GUDHI_EDGE_LENGTH_COST_H_ */ +#endif // CONTRACTION_POLICIES_EDGE_LENGTH_COST_H_ diff --git a/src/Contraction/include/gudhi/Contraction/policies/First_vertex_placement.h b/src/Contraction/include/gudhi/Contraction/policies/First_vertex_placement.h index 93abac35..1f68db0d 100644 --- a/src/Contraction/include/gudhi/Contraction/policies/First_vertex_placement.h +++ b/src/Contraction/include/gudhi/Contraction/policies/First_vertex_placement.h @@ -1,53 +1,52 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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_FIRST_VERTEX_PLACEMENT_H_ -#define GUDHI_FIRST_VERTEX_PLACEMENT_H_ - -#include "Placement_policy.h" - -namespace Gudhi{ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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/>. + */ -namespace contraction { +#ifndef CONTRACTION_POLICIES_FIRST_VERTEX_PLACEMENT_H_ +#define CONTRACTION_POLICIES_FIRST_VERTEX_PLACEMENT_H_ + +#include <gudhi/Contraction/policies/Placement_policy.h> + +namespace Gudhi { +namespace contraction { /** * @brief Places the contracted point onto the first point of the edge */ -template< typename EdgeProfile> class First_vertex_placement : public Placement_policy<EdgeProfile>{ - -public: - typedef typename EdgeProfile::Point Point; - typedef typename EdgeProfile::Edge_handle Edge_handle; +template< typename EdgeProfile> +class First_vertex_placement : public Placement_policy<EdgeProfile> { + public: + typedef typename EdgeProfile::Point Point; + typedef typename EdgeProfile::Edge_handle Edge_handle; - typedef typename Placement_policy<EdgeProfile>::Placement_type Placement_type; + typedef typename Placement_policy<EdgeProfile>::Placement_type Placement_type; - Placement_type operator()(const EdgeProfile& profile) const override{ - return Placement_type(profile.p0()); - } + Placement_type operator()(const EdgeProfile& profile) const override { + return Placement_type(profile.p0()); + } }; -} // namespace contraction -} // namespace GUDHI +} // namespace contraction +} // namespace Gudhi -#endif /* GUDHI_FIRST_VERTEX_PLACEMENT_H_ */ +#endif // CONTRACTION_POLICIES_FIRST_VERTEX_PLACEMENT_H_ diff --git a/src/Contraction/include/gudhi/Contraction/policies/Link_condition_valid_contraction.h b/src/Contraction/include/gudhi/Contraction/policies/Link_condition_valid_contraction.h index c901e629..919df243 100644 --- a/src/Contraction/include/gudhi/Contraction/policies/Link_condition_valid_contraction.h +++ b/src/Contraction/include/gudhi/Contraction/policies/Link_condition_valid_contraction.h @@ -1,54 +1,56 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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_LINK_CONDITION_VALID_CONTRACTION_H_ -#define GUDHI_LINK_CONDITION_VALID_CONTRACTION_H_ - -#include "gudhi/Utils.h" -#include "Valid_contraction_policy.h" - - -namespace Gudhi{ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 CONTRACTION_POLICIES_LINK_CONDITION_VALID_CONTRACTION_H_ +#define CONTRACTION_POLICIES_LINK_CONDITION_VALID_CONTRACTION_H_ + +#include <gudhi/Utils.h> +#include <gudhi/Contraction/policies/Valid_contraction_policy.h> + + +namespace Gudhi { namespace contraction { - - /** - *@brief Policy that only accept edges verifying the link condition (and therefore whose contraction preserving homotopy type). - *@ingroup contr - */ -template< typename EdgeProfile> class Link_condition_valid_contraction : public Valid_contraction_policy<EdgeProfile>{ -public: - typedef typename EdgeProfile::Edge_handle Edge_handle; - typedef typename EdgeProfile::Point Point; - //typedef typename EdgeProfile::Edge_handle Edge_handle; - bool operator()(const EdgeProfile& profile,const boost::optional<Point>& placement) const override{ - Edge_handle edge(profile.edge_handle()); - DBGMSG("Link_condition_valid_contraction:",profile.complex().link_condition(edge)); - return profile.complex().link_condition(edge); - } +/** + *@brief Policy that only accept edges verifying the link condition (and therefore whose contraction preserving homotopy type). + *@ingroup contr + */ +template< typename EdgeProfile> +class Link_condition_valid_contraction : public Valid_contraction_policy<EdgeProfile> { + public: + typedef typename EdgeProfile::Edge_handle Edge_handle; + typedef typename EdgeProfile::Point Point; + // typedef typename EdgeProfile::Edge_handle Edge_handle; + + bool operator()(const EdgeProfile& profile, const boost::optional<Point>& placement) const override { + Edge_handle edge(profile.edge_handle()); + DBGMSG("Link_condition_valid_contraction:", profile.complex().link_condition(edge)); + return profile.complex().link_condition(edge); + } }; + } // namespace contraction -} // namespace GUDHI +} // namespace Gudhi -#endif /* GUDHI_LINK_CONDITION_VALID_CONTRACTION_H_ */ +#endif // CONTRACTION_POLICIES_LINK_CONDITION_VALID_CONTRACTION_H_ diff --git a/src/Contraction/include/gudhi/Contraction/policies/Middle_placement.h b/src/Contraction/include/gudhi/Contraction/policies/Middle_placement.h index 30f0a570..4b59f1b5 100644 --- a/src/Contraction/include/gudhi/Contraction/policies/Middle_placement.h +++ b/src/Contraction/include/gudhi/Contraction/policies/Middle_placement.h @@ -1,52 +1,51 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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_MIDDLE_PLACEMENT_H_ -#define GUDHI_MIDDLE_PLACEMENT_H_ - -#include "Placement_policy.h" - - -namespace Gudhi{ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 CONTRACTION_POLICIES_MIDDLE_PLACEMENT_H_ +#define CONTRACTION_POLICIES_MIDDLE_PLACEMENT_H_ + +#include <gudhi/Contraction/policies/Placement_policy.h> + +namespace Gudhi { namespace contraction { +template< typename EdgeProfile> +class Middle_placement : public Placement_policy<EdgeProfile> { + public: + typedef typename EdgeProfile::Point Point; + typedef typename EdgeProfile::Edge_handle Edge_handle; + typedef typename EdgeProfile::Graph_vertex Graph_vertex; - -template< typename EdgeProfile> class Middle_placement : public Placement_policy<EdgeProfile>{ + typedef typename Placement_policy<EdgeProfile>::Placement_type Placement_type; -public: - typedef typename EdgeProfile::Point Point; - typedef typename EdgeProfile::Edge_handle Edge_handle; - typedef typename EdgeProfile::Graph_vertex Graph_vertex; - - typedef typename Placement_policy<EdgeProfile>::Placement_type Placement_type; - - Placement_type operator()(const EdgeProfile& profile) const override{ - //todo compute the middle - return Placement_type(profile.p0()); - } + Placement_type operator()(const EdgeProfile& profile) const override { + // todo compute the middle + return Placement_type(profile.p0()); + } }; + } // namespace contraction -} // namespace GUDHI -#endif /* GUDHI_MIDDLE_PLACEMENT_H_ */ +} // namespace Gudhi + +#endif // CONTRACTION_POLICIES_MIDDLE_PLACEMENT_H_ diff --git a/src/Contraction/include/gudhi/Contraction/policies/Placement_policy.h b/src/Contraction/include/gudhi/Contraction/policies/Placement_policy.h index 3a804cf0..34ffa49f 100644 --- a/src/Contraction/include/gudhi/Contraction/policies/Placement_policy.h +++ b/src/Contraction/include/gudhi/Contraction/policies/Placement_policy.h @@ -1,49 +1,51 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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_PLACEMENT_POLICY_H_ -#define GUDHI_PLACEMENT_POLICY_H_ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 CONTRACTION_POLICIES_PLACEMENT_POLICY_H_ +#define CONTRACTION_POLICIES_PLACEMENT_POLICY_H_ #include <boost/optional.hpp> namespace Gudhi { + namespace contraction { +/** + *@brief Policy to specify where the merged point had to be placed after an edge contraction. + *@ingroup contr + */ +template< typename EdgeProfile> +class Placement_policy { + public: + typedef typename EdgeProfile::Point Point; + typedef boost::optional<Point> Placement_type; - /** - *@brief Policy to specify where the merged point had to be placed after an edge contraction. - *@ingroup contr - */ -template< typename EdgeProfile> class Placement_policy{ -public: - typedef typename EdgeProfile::Point Point; - typedef boost::optional<Point> Placement_type; + virtual Placement_type operator()(const EdgeProfile& profile) const = 0; - virtual Placement_type operator()(const EdgeProfile& profile) const=0; - virtual ~Placement_policy(){}; + virtual ~Placement_policy() { } }; - } // namespace contraction -} // namespace GUDHI -#endif /* GUDHI_PLACEMENT_POLICY_H_ */ +} // namespace Gudhi + +#endif // CONTRACTION_POLICIES_PLACEMENT_POLICY_H_ diff --git a/src/Contraction/include/gudhi/Contraction/policies/Valid_contraction_policy.h b/src/Contraction/include/gudhi/Contraction/policies/Valid_contraction_policy.h index bee2ecd7..78d61173 100644 --- a/src/Contraction/include/gudhi/Contraction/policies/Valid_contraction_policy.h +++ b/src/Contraction/include/gudhi/Contraction/policies/Valid_contraction_policy.h @@ -1,47 +1,51 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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_VALID_CONTRACTION_POLICY_H_ -#define GUDHI_VALID_CONTRACTION_POLICY_H_ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 CONTRACTION_POLICIES_VALID_CONTRACTION_POLICY_H_ +#define CONTRACTION_POLICIES_VALID_CONTRACTION_POLICY_H_ namespace Gudhi { + namespace contraction { - /** - *@brief Policy to specify if an edge contraction is valid or not. - *@ingroup contr - */ -template< typename EdgeProfile> class Valid_contraction_policy{ -public: - typedef typename EdgeProfile::Point Point; - typedef typename EdgeProfile::Edge_handle Edge_handle; - typedef typename EdgeProfile::Graph_vertex Graph_vertex; - - virtual bool operator()(const EdgeProfile& profile,const boost::optional<Point>& placement) const =0; - virtual ~Valid_contraction_policy(){}; +/** + *@brief Policy to specify if an edge contraction is valid or not. + *@ingroup contr + */ +template< typename EdgeProfile> +class Valid_contraction_policy { + public: + typedef typename EdgeProfile::Point Point; + typedef typename EdgeProfile::Edge_handle Edge_handle; + typedef typename EdgeProfile::Graph_vertex Graph_vertex; + + virtual bool operator()(const EdgeProfile& profile, const boost::optional<Point>& placement) const = 0; + + virtual ~Valid_contraction_policy() { } }; } // namespace contraction -} // namespace GUDHI + +} // namespace Gudhi -#endif /* GUDHI_VALID_CONTRACTION_POLICY_H_ */ +#endif // CONTRACTION_POLICIES_VALID_CONTRACTION_POLICY_H_ diff --git a/src/Contraction/include/gudhi/Edge_contraction.h b/src/Contraction/include/gudhi/Edge_contraction.h index 2c254710..ee3e3de1 100644 --- a/src/Contraction/include/gudhi/Edge_contraction.h +++ b/src/Contraction/include/gudhi/Edge_contraction.h @@ -20,24 +20,24 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef GUDHI_EDGE_CONTRACTION_H_ -#define GUDHI_EDGE_CONTRACTION_H_ +#ifndef EDGE_CONTRACTION_H_ +#define EDGE_CONTRACTION_H_ -#include "gudhi/Skeleton_blocker_contractor.h" -#include "gudhi/Contraction/policies/Edge_length_cost.h" -#include "gudhi/Contraction/policies/First_vertex_placement.h" -#include "gudhi/Contraction/policies/Valid_contraction_policy.h" -#include "gudhi/Contraction/policies/Dummy_valid_contraction.h" -#include "gudhi/Contraction/policies/Link_condition_valid_contraction.h" -#include "gudhi/Utils.h" +#include <gudhi/Skeleton_blocker_contractor.h> +#include <gudhi/Contraction/policies/Edge_length_cost.h> +#include <gudhi/Contraction/policies/First_vertex_placement.h> +#include <gudhi/Contraction/policies/Valid_contraction_policy.h> +#include <gudhi/Contraction/policies/Dummy_valid_contraction.h> +#include <gudhi/Contraction/policies/Link_condition_valid_contraction.h> +#include <gudhi/Utils.h> +namespace Gudhi { -namespace Gudhi{ -namespace contraction{ +namespace contraction { -/** \defgroup contr Contraction +/** \defgroup contr Edge contraction \author David Salinas @@ -120,9 +120,9 @@ while ensuring its homotopy type is preserved during the contraction (edge are c \code{.cpp} #include <boost/timer/timer.hpp> #include <iostream> -#include "gudhi/Edge_contraction.h" -#include "gudhi/Skeleton_blocker.h" -#include "gudhi/Off_reader.h" +#include <gudhi/Edge_contraction.h> +#include <gudhi/Skeleton_blocker.h> +#include <gudhi/Off_reader.h> using namespace std; @@ -158,7 +158,7 @@ void build_rips(ComplexType& complex, double offset){ for (auto p = vertices.begin(); p != vertices.end(); ++p) for (auto q = p; ++q != vertices.end(); ) if (eucl_distance(complex.point(*p), complex.point(*q)) < 2 * offset) - complex.add_edge(*p,*q); + complex.add_edge_without_blockers(*p,*q); } int main (int argc, char *argv[]) @@ -194,7 +194,7 @@ int main (int argc, char *argv[]) contractor.contract_edges(); std::cout << "Counting final number of simplices \n"; - unsigned num_simplices = std::distance(complex.simplex_range().begin(),complex.simplex_range().end()); + unsigned num_simplices = std::distance(complex.star_simplex_range().begin(),complex.star_simplex_range().end()); std::cout << "Final complex has "<< complex.num_vertices()<<" vertices, "<< @@ -226,11 +226,11 @@ Time to simplify and enumerate simplices: \copyright GNU General Public License v3. -\verbatim Contact: David Salinas, david.salinas@inria.fr \endverbatim +\verbatim Contact: gudhi-users@lists.gforge.inria.fr \endverbatim */ -/** @} */ // end defgroup +/** @} */ // end defgroup +} // namespace contraction -} -} +} // namespace Gudhi -#endif /* GUDHI_EDGE_CONTRACTION_H_ */ +#endif // EDGE_CONTRACTION_H_ diff --git a/src/Contraction/include/gudhi/Skeleton_blocker_contractor.h b/src/Contraction/include/gudhi/Skeleton_blocker_contractor.h index dcc05c22..d6350a2c 100644 --- a/src/Contraction/include/gudhi/Skeleton_blocker_contractor.h +++ b/src/Contraction/include/gudhi/Skeleton_blocker_contractor.h @@ -20,80 +20,69 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef GUDHI_SKELETON_BLOCKER_CONTRACTOR_H_ -#define GUDHI_SKELETON_BLOCKER_CONTRACTOR_H_ - -#include <memory> -#include <cassert> +#ifndef SKELETON_BLOCKER_CONTRACTOR_H_ +#define SKELETON_BLOCKER_CONTRACTOR_H_ // todo remove the queue to be independent from cgald -#include "gudhi/Contraction/CGAL_queue/Modifiable_priority_queue.h" - - -#include <list> -#include <boost/scoped_array.hpp> -#include <boost/scoped_ptr.hpp> - +#include <gudhi/Contraction/CGAL_queue/Modifiable_priority_queue.h> -#include "gudhi/Contraction/Edge_profile.h" -#include "gudhi/Contraction/policies/Cost_policy.h" -#include "gudhi/Contraction/policies/Edge_length_cost.h" -#include "gudhi/Contraction/policies/Placement_policy.h" -#include "gudhi/Contraction/policies/First_vertex_placement.h" +#include <gudhi/Contraction/Edge_profile.h> +#include <gudhi/Contraction/policies/Cost_policy.h> +#include <gudhi/Contraction/policies/Edge_length_cost.h> +#include <gudhi/Contraction/policies/Placement_policy.h> +#include <gudhi/Contraction/policies/First_vertex_placement.h> +#include <gudhi/Contraction/policies/Valid_contraction_policy.h> +#include <gudhi/Contraction/policies/Dummy_valid_contraction.h> // xxx remove +#include <gudhi/Contraction/policies/Link_condition_valid_contraction.h> // xxx remove +#include <gudhi/Contraction/policies/Contraction_visitor.h> -#include "gudhi/Contraction/policies/Valid_contraction_policy.h" -#include "gudhi/Contraction/policies/Dummy_valid_contraction.h" //xxx remove -#include "gudhi/Contraction/policies/Link_condition_valid_contraction.h" //xxx remove +#include <gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h> +#include <gudhi/Utils.h> -#include "gudhi/Contraction/policies/Contraction_visitor.h" -#include "gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h" +#include <boost/scoped_array.hpp> +#include <boost/scoped_ptr.hpp> -#include "gudhi/Utils.h" +#include <memory> +#include <cassert> +#include <list> +#include <utility> // for pair +#include <vector> -namespace Gudhi{ +namespace Gudhi { namespace contraction { - - - template <class Profile> -Placement_policy<Profile>* make_first_vertex_placement(){ - return new First_vertex_placement<Profile>(); +Placement_policy<Profile>* make_first_vertex_placement() { + return new First_vertex_placement<Profile>(); } template <class Profile> -Valid_contraction_policy<Profile>* make_link_valid_contraction(){ - return new Link_condition_valid_contraction<Profile>(); +Valid_contraction_policy<Profile>* make_link_valid_contraction() { + return new Link_condition_valid_contraction<Profile>(); } - /** -*@brief Visitor to remove popable blockers after an edge contraction. -*/ + *@brief Visitor to remove popable blockers after an edge contraction. + */ template <class Profile> -class Contraction_visitor_remove_popable : public Contraction_visitor<Profile>{ -public: - typedef typename Profile::Point Point; - typedef typename Profile::Complex Complex; - typedef typename Complex::Vertex_handle Vertex_handle; - - void on_contracted(const Profile &profile, boost::optional< Point > placement) override{ - profile.complex().remove_all_popable_blockers(profile.v0_handle()); - } +class Contraction_visitor_remove_popable : public Contraction_visitor<Profile> { + public: + typedef typename Profile::Point Point; + typedef typename Profile::Complex Complex; + typedef typename Complex::Vertex_handle Vertex_handle; + + void on_contracted(const Profile &profile, boost::optional< Point > placement) override { + profile.complex().remove_all_popable_blockers(profile.v0_handle()); + } }; template <class Profile> -Contraction_visitor<Profile>* make_remove_popable_blockers_visitor(){ - return new Contraction_visitor_remove_popable<Profile>(); +Contraction_visitor<Profile>* make_remove_popable_blockers_visitor() { + return new Contraction_visitor_remove_popable<Profile>(); } - - - - - /** *@class Skeleton_blocker_contractor *@brief Class that allows to contract iteratively edges of a simplicial complex. @@ -110,519 +99,484 @@ Contraction_visitor<Profile>* make_remove_popable_blockers_visitor(){ * a topological condition (link condition) or a geometrical condition (normals messed up). * */ -template< -class GeometricSimplifiableComplex, -class EdgeProfile = Edge_profile<GeometricSimplifiableComplex> -> -class Skeleton_blocker_contractor : private skbl::Dummy_complex_visitor<typename GeometricSimplifiableComplex::Vertex_handle>{ - - GeometricSimplifiableComplex& complex_; - -public: - typedef typename GeometricSimplifiableComplex::Graph_vertex Graph_vertex; - typedef typename GeometricSimplifiableComplex::Vertex_handle Vertex_handle; - typedef typename GeometricSimplifiableComplex::Simplex_handle Simplex_handle; - typedef typename GeometricSimplifiableComplex::Simplex_handle_iterator Simplex_handle_iterator; - - +template<class GeometricSimplifiableComplex, class EdgeProfile = Edge_profile<GeometricSimplifiableComplex>> +class Skeleton_blocker_contractor : private skbl::Dummy_complex_visitor< +typename GeometricSimplifiableComplex::Vertex_handle> { + GeometricSimplifiableComplex& complex_; - typedef typename GeometricSimplifiableComplex::Root_vertex_handle Root_vertex_handle; + public: + typedef typename GeometricSimplifiableComplex::Graph_vertex Graph_vertex; + typedef typename GeometricSimplifiableComplex::Vertex_handle Vertex_handle; + typedef typename GeometricSimplifiableComplex::Simplex Simplex; + typedef typename GeometricSimplifiableComplex::Root_vertex_handle Root_vertex_handle; + typedef typename GeometricSimplifiableComplex::Graph_edge Graph_edge; + typedef typename GeometricSimplifiableComplex::Edge_handle Edge_handle; + typedef typename GeometricSimplifiableComplex::Point Point; - typedef typename GeometricSimplifiableComplex::Graph_edge Graph_edge; - typedef typename GeometricSimplifiableComplex::Edge_handle Edge_handle; - typedef typename GeometricSimplifiableComplex::Point Point; + typedef EdgeProfile Profile; - typedef EdgeProfile Profile; + typedef Cost_policy<Profile> Cost_policy_; + typedef Placement_policy<Profile> Placement_policy_; + typedef Valid_contraction_policy<Profile> Valid_contraction_policy_; + typedef Contraction_visitor<EdgeProfile> Contraction_visitor_; + typedef Edge_profile_factory<EdgeProfile> Edge_profile_factory_; - typedef Cost_policy<Profile> Cost_policy_; - typedef Placement_policy<Profile> Placement_policy_; - typedef Valid_contraction_policy<Profile> Valid_contraction_policy_; - typedef Contraction_visitor<EdgeProfile> Contraction_visitor_; - typedef Edge_profile_factory<EdgeProfile> Edge_profile_factory_; + typedef boost::optional<double> Cost_type; + typedef boost::optional<Point> Placement_type; - typedef boost::optional<double> Cost_type; - typedef boost::optional<Point> Placement_type ; + typedef size_t size_type; - typedef size_t size_type; + typedef Skeleton_blocker_contractor Self; - typedef Skeleton_blocker_contractor Self ; + private: + struct Compare_id { + Compare_id() : algorithm_(0) { } + Compare_id(Self const* aAlgorithm) : algorithm_(aAlgorithm) { } + bool operator()(Edge_handle a, Edge_handle b) const { + return algorithm_->get_undirected_edge_id(a) < algorithm_->get_undirected_edge_id(b); + } -private: + Self const* algorithm_; + }; - struct Compare_id - { - Compare_id() : algorithm_(0) {} + struct Compare_cost { + Compare_cost() : algorithm_(0) { } - Compare_id( Self const* aAlgorithm ) : algorithm_(aAlgorithm) {} + Compare_cost(Self const* aAlgorithm) : algorithm_(aAlgorithm) { } - bool operator() ( Edge_handle a, Edge_handle b ) const - { - return algorithm_->get_undirected_edge_id(a) < algorithm_->get_undirected_edge_id(b); - } + bool operator()(Edge_handle a, Edge_handle b) const { + // NOTE: A cost is an optional<> value. + // Absent optionals are ordered first; that is, "none < T" and "T > none" for any defined T != none. + // In consequence, edges with undefined costs will be promoted to the top of the priority queue and popped out + // first. + return algorithm_->get_data(a).cost() < algorithm_->get_data(b).cost(); + } - Self const* algorithm_ ; - } ; + Self const* algorithm_; + }; - struct Compare_cost - { - Compare_cost() : algorithm_(0) { - } + struct Undirected_edge_id : boost::put_get_helper<size_type, Undirected_edge_id> { + typedef boost::readable_property_map_tag category; + typedef size_type value_type; + typedef size_type reference; + typedef Edge_handle key_type; - Compare_cost( Self const* aAlgorithm ) : algorithm_(aAlgorithm) { - } + Undirected_edge_id() : algorithm_(0) { } - bool operator() ( Edge_handle a, Edge_handle b ) const - { - // NOTE: A cost is an optional<> value. - // Absent optionals are ordered first; that is, "none < T" and "T > none" for any defined T != none. - // In consequence, edges with undefined costs will be promoted to the top of the priority queue and poped out first. - return algorithm_->get_data(a).cost() < algorithm_->get_data(b).cost(); - } + Undirected_edge_id(Self const* aAlgorithm) : algorithm_(aAlgorithm) { } - Self const* algorithm_ ; + size_type operator[](Edge_handle e) const { + return algorithm_->get_undirected_edge_id(e); + } - } ; + Self const* algorithm_; + }; + + typedef CGAL::Modifiable_priority_queue<Edge_handle, Compare_cost, Undirected_edge_id> PQ; + typedef typename PQ::handle pq_handle; + + + // An Edge_data is associated with EVERY edge in the complex (collapsible or not). + // It relates the edge with the PQ-handle needed to update the priority queue + // It also relates the edge with a policy-based cache - struct Undirected_edge_id : boost::put_get_helper<size_type, Undirected_edge_id> - { - typedef boost::readable_property_map_tag category; - typedef size_type value_type; - typedef size_type reference; - typedef Edge_handle key_type; + class Edge_data { + public: + Edge_data() : PQHandle_(), cost_() { } - Undirected_edge_id() : algorithm_(0) {} + Cost_type const& cost() const { + return cost_; + } + + Cost_type & cost() { + return cost_; + } + + pq_handle PQ_handle() const { + return PQHandle_; + } + + bool is_in_PQ() const { + return PQHandle_ != PQ::null_handle(); + } + + void set_PQ_handle(pq_handle h) { + PQHandle_ = h; + } - Undirected_edge_id( Self const* aAlgorithm ) : algorithm_(aAlgorithm) {} - - size_type operator[] ( Edge_handle e ) const { return algorithm_->get_undirected_edge_id(e); } - - Self const* algorithm_ ; - } ; - - typedef CGAL::Modifiable_priority_queue<Edge_handle,Compare_cost,Undirected_edge_id> PQ ; - typedef typename PQ::handle pq_handle ; - - - // An Edge_data is associated with EVERY edge in the complex (collapsible or not). - // It relates the edge with the PQ-handle needed to update the priority queue - // It also relates the edge with a policy-based cache - class Edge_data - { - public : - - Edge_data() : PQHandle_(),cost_() {} - - Cost_type const& cost() const { return cost_ ; } - Cost_type & cost() { return cost_ ; } - - pq_handle PQ_handle() const { return PQHandle_ ;} - - bool is_in_PQ() const { return PQHandle_ != PQ::null_handle() ; } - - void set_PQ_handle( pq_handle h ) { PQHandle_ = h ; } - - void reset_PQ_handle() { PQHandle_ = PQ::null_handle() ; } - - private: - pq_handle PQHandle_ ; - Cost_type cost_ ; - - } ; - typedef Edge_data* Edge_data_ptr ; - typedef boost::scoped_array<Edge_data> Edge_data_array ; - - - int get_undirected_edge_id ( Edge_handle edge ) const { - return complex_[edge].index() ; - } - - - const Edge_data& get_data ( Edge_handle edge ) const - { - return edge_data_array_[get_undirected_edge_id(edge)]; - } - - - Edge_data& get_data ( Edge_handle edge ) - { - return edge_data_array_[get_undirected_edge_id(edge)]; - } - - Cost_type get_cost(const Profile & profile) const{ - return (*cost_policy_)(profile,get_placement(profile)); - } - - Profile create_profile(Edge_handle edge) const{ - if(edge_profile_factory_) - return edge_profile_factory_->make_profile(complex_,edge); - else - return Profile(complex_,edge); - } - - - void insert_in_PQ( Edge_handle edge, Edge_data& data ) - { - data.set_PQ_handle(heap_PQ_->push(edge)); - ++current_num_edges_heap_; - } - - void update_in_PQ( Edge_handle edge, Edge_data& data ) - { - data.set_PQ_handle(heap_PQ_->update(edge,data.PQ_handle())) ; - } - - void remove_from_PQ( Edge_handle edge, Edge_data& data ) - { - data.set_PQ_handle(heap_PQ_->erase(edge,data.PQ_handle())); - --current_num_edges_heap_; - } - - boost::optional<Edge_handle> pop_from_PQ() { - boost::optional<Edge_handle> edge = heap_PQ_->extract_top(); - if ( edge ) - get_data(*edge).reset_PQ_handle(); - return edge ; - } - - - -private: - - /** - * @brief Collect edges. - * - * Iterates over all edges of the simplicial complex and - * 1) inserts them in the priority queue sorted according to the Cost policy. - * 2) set the id() field of each edge - */ - void collect_edges(){ - // - // Loop over all the edges in the complex in the heap - // - size_type size = complex_.num_edges(); - DBG("Collecting edges ..."); - DBGMSG("num edges :",size); - - edge_data_array_.reset( new Edge_data[size] ) ; - - heap_PQ_.reset( new PQ (size, Compare_cost(this), Undirected_edge_id(this) ) ) ; - - std::size_t id = 0 ; - - //xxx do a parralel for - for(auto edge : complex_.edge_range()){ - complex_[edge].index() = id++; - Profile const& profile = create_profile(edge); - Edge_data& data = get_data(edge); - data.cost() = get_cost(profile) ; - ++initial_num_edges_heap_; - insert_in_PQ(edge,data); - if(contraction_visitor_) contraction_visitor_->on_collected(profile,data.cost()); - } - - DBG("Edges collected."); - - } - - bool should_stop(double lCost,const Profile &profile) const{ - return false; - } - - boost::optional<Point> get_placement(const Profile& profile) const{ - return (*placement_policy_)(profile); - } - - bool is_contraction_valid( Profile const& profile, Placement_type placement ) const{ - if(!valid_contraction_policy_) return true; - return (*valid_contraction_policy_)(profile,placement); - } - - -public: - /** - * \brief Contract edges. - * - * While the heap is not empty, it extracts the edge with the minimum - * cost in the heap then try to contract it. - * It stops when the Stop policy says so or when the number of contractions - * given by 'num_max_contractions' is reached (if this number is positive). - */ - void contract_edges(int num_max_contractions=-1){ - - DBG("\n\nContract edges"); - int num_contraction = 0 ; - - bool unspecified_num_contractions = (num_max_contractions == -1); - // - // Pops and processes each edge from the PQ - // - boost::optional<Edge_handle> edge ; - while ( (edge = pop_from_PQ())&& ((num_contraction<num_max_contractions)||(unspecified_num_contractions))) - { - Profile const& profile = create_profile(*edge); - Cost_type cost(get_data(*edge).cost()); - if(contraction_visitor_) contraction_visitor_->on_selected(profile,cost,0,0); - - DBGMSG("\n\n---- Pop edge - num vertices :",complex_.num_vertices()); - - if (cost){ - DBGMSG("sqrt(cost):",std::sqrt(*cost)); - if (should_stop(*cost,profile) ) - { - if(contraction_visitor_) contraction_visitor_->on_stop_condition_reached(); - DBG("should_stop"); - break ; - } - Placement_type placement = get_placement(profile); - if ( is_contraction_valid(profile,placement) && placement ) - { - DBG("contraction_valid"); - contract_edge(profile,placement); - ++ num_contraction; - } - else - { - DBG("contraction not valid"); - if(contraction_visitor_) contraction_visitor_->on_non_valid(profile); - } - } - else - DBG("uncomputable cost"); - } - if(contraction_visitor_) contraction_visitor_->on_stop_condition_reached(); - } - - - bool is_in_heap(Edge_handle edge) const{ - if(heap_PQ_->empty()) return false; - else{ - return edge_data_array_[get_undirected_edge_id(edge)].is_in_PQ(); - } - } - - bool is_heap_empty() const{ - return heap_PQ_->empty(); - } - - - /** - * @brief Returns an Edge_handle and a Placement_type. This pair consists in - * the edge with the lowest cost in the heap together with its placement. - * The returned value is initialized iff the heap is non-empty. - */ - boost::optional<std::pair<Edge_handle,Placement_type > > top_edge(){ - boost::optional<std::pair<Edge_handle,Placement_type > > res; - - if(!heap_PQ_->empty()) { - auto edge = heap_PQ_->top(); - Profile const& profile = create_profile(edge); - Placement_type placement = get_placement(profile); - res = make_pair(edge,placement); - DBGMSG("top edge:",complex_[edge]); - - } - return res; - } - - - /** - * @brief Constructor with default policies. - * - * @details The default cost, placement, valid and visitor policies - * are respectively : the edge length, the first point, the link condition - */ - Skeleton_blocker_contractor(GeometricSimplifiableComplex& complex) - :complex_(complex), - cost_policy_(new Edge_length_cost<Profile>), - placement_policy_(new First_vertex_placement<Profile>), - valid_contraction_policy_(new Link_condition_valid_contraction<Profile>), - contraction_visitor_(new Contraction_visitor_()), - edge_profile_factory_(0), - initial_num_edges_heap_(0), - current_num_edges_heap_(0) - { - complex_.set_visitor(this); - if(contraction_visitor_) contraction_visitor_->on_started(complex); - collect_edges(); - } - - /** - * @brief Constructor with customed policies. - * @remark Policies destruction is handle by the class with smart pointers. - */ - Skeleton_blocker_contractor(GeometricSimplifiableComplex& complex, - Cost_policy_ *cost_policy, - Placement_policy_ * placement_policy = new First_vertex_placement<Profile>, - Valid_contraction_policy_ * valid_contraction_policy = new Link_condition_valid_contraction<Profile>, - Contraction_visitor_* contraction_visitor = new Contraction_visitor_(), - Edge_profile_factory_* edge_profile_factory = NULL - ): - complex_(complex), - cost_policy_(cost_policy), - placement_policy_(placement_policy), - valid_contraction_policy_(valid_contraction_policy), - contraction_visitor_(contraction_visitor), - edge_profile_factory_(edge_profile_factory), - initial_num_edges_heap_(0), - current_num_edges_heap_(0) - { - complex_.set_visitor(this); - if(contraction_visitor) contraction_visitor->on_started(complex); - collect_edges(); - } - - - ~Skeleton_blocker_contractor(){ - complex_.set_visitor(0); - } - -private: - - - void contract_edge(const Profile& profile, Placement_type placement ) { - if(contraction_visitor_) contraction_visitor_->on_contracting(profile,placement); - - assert(complex_.contains_vertex(profile.v0_handle())); - assert(complex_.contains_vertex(profile.v1_handle())); - assert(placement); - - profile.complex().point(profile.v0_handle()) = *placement; - - // remark : this is not necessary since v1 will be deactivated - // profile.complex().point(profile.v1_handle()) = *placement; - - complex_.contract_edge(profile.v0_handle(),profile.v1_handle()); - - assert(complex_.contains_vertex(profile.v0_handle())); - assert(!complex_.contains_vertex(profile.v1_handle())); - - update_changed_edges(); - - // the visitor could do something as complex_.remove_popable_blockers(); - if(contraction_visitor_) contraction_visitor_->on_contracted(profile,placement); - } - -private: - - // every time the visitor's method on_changed_edge is called, it adds an - // edge to changed_edges_ - std::vector< Edge_handle > changed_edges_; - - /** - * @brief we update the cost and the position in the heap of an edge that has - * been changed - */ - inline void on_changed_edge(Vertex_handle a,Vertex_handle b) override{ - boost::optional<Edge_handle> ab(complex_[std::make_pair(a,b)]); - assert(ab); - changed_edges_.push_back(*ab); - } - - void update_changed_edges(){ - //xxx do a parralel for - - DBG("update edges"); - - // sequential loop - for(auto ab : changed_edges_){ - //1-get the Edge_handle corresponding to ab - //2-change the data in mEdgeArray[ab.id()] - //3-update the heap - Edge_data& data = get_data(ab); - Profile const& profile = create_profile(ab); - data.cost() = get_cost(profile) ; - if ( data.is_in_PQ()){ - update_in_PQ(ab,data); - } - else{ - insert_in_PQ(ab,data); - } - } - changed_edges_.clear(); - } - - -private: - void on_remove_edge(Vertex_handle a,Vertex_handle b) override{ - - boost::optional<Edge_handle> ab((complex_[std::make_pair(a,b)])); - assert(ab); - Edge_data& lData = get_data(*ab) ; - if ( lData.is_in_PQ() ) - { - remove_from_PQ(*ab,lData) ; - } - } -private: - /** - * @brief Called when the edge 'ax' has been added while the edge 'bx' - * is still there but will be removed on next instruction. - * We assign the index of 'bx' to the edge index of 'ax' - */ - void on_swaped_edge(Vertex_handle a,Vertex_handle b,Vertex_handle x) override{ - boost::optional<Edge_handle> ax(complex_[std::make_pair(a,x)]); - boost::optional<Edge_handle> bx(complex_[std::make_pair(b,x)]); - assert(ax&& bx); - complex_[*ax].index() =complex_[*bx].index(); - } -private: - /** - * @brief Called when a blocker is removed. - * All the edges that passes through the blocker may be edge-contractible - * again and are thus reinserted in the heap. - */ - void on_delete_blocker(const Simplex_handle * blocker) override{ - // we go for all pairs xy that belongs to the blocker - // note that such pairs xy are necessarily edges of the complex - // by definition of a blocker - - // todo uniqument utile pour la link condition - // laisser ŕ l'utilisateur? booleen update_heap_on_removed_blocker? - Simplex_handle blocker_copy(*blocker); - for (auto x = blocker_copy.begin(); x!= blocker_copy.end(); ++x){ - for(auto y=x ; ++y != blocker_copy.end(); ){ - auto edge_descr(complex_[std::make_pair(*x,*y)]); - assert(edge_descr); - Edge_data& data = get_data(*edge_descr); - Profile const& profile = create_profile(*edge_descr); - data.cost() = get_cost(profile) ; - - // If the edge is already in the heap - // its priority has not changed. - // If the edge is not present, we reinsert it - // remark : we could also reinsert the edge - // only if it is valid - if ( !data.is_in_PQ() ){ - insert_in_PQ(*edge_descr,data); - } - } - } - } - - -private: - std::shared_ptr<Cost_policy_> cost_policy_; - std::shared_ptr<Placement_policy_> placement_policy_; - std::shared_ptr<Valid_contraction_policy_> valid_contraction_policy_; - std::shared_ptr<Contraction_visitor_> contraction_visitor_; - - //in case the user wants to do something special when the edge profile - //are created (for instance add some info) - std::shared_ptr<Edge_profile_factory_> edge_profile_factory_; - Edge_data_array edge_data_array_ ; - - boost::scoped_ptr<PQ> heap_PQ_ ; - int initial_num_edges_heap_; - int current_num_edges_heap_; + void reset_PQ_handle() { + PQHandle_ = PQ::null_handle(); + } + private: + pq_handle PQHandle_; + Cost_type cost_; + }; + typedef Edge_data* Edge_data_ptr; + typedef boost::scoped_array<Edge_data> Edge_data_array; + + int get_undirected_edge_id(Edge_handle edge) const { + return complex_[edge].index(); + } + + const Edge_data& get_data(Edge_handle edge) const { + return edge_data_array_[get_undirected_edge_id(edge)]; + } + + Edge_data& get_data(Edge_handle edge) { + return edge_data_array_[get_undirected_edge_id(edge)]; + } + + Cost_type get_cost(const Profile & profile) const { + return (*cost_policy_)(profile, get_placement(profile)); + } + + Profile create_profile(Edge_handle edge) const { + if (edge_profile_factory_) + return edge_profile_factory_->make_profile(complex_, edge); + else + return Profile(complex_, edge); + } + + void insert_in_PQ(Edge_handle edge, Edge_data& data) { + data.set_PQ_handle(heap_PQ_->push(edge)); + ++current_num_edges_heap_; + } + + void update_in_PQ(Edge_handle edge, Edge_data& data) { + data.set_PQ_handle(heap_PQ_->update(edge, data.PQ_handle())); + } + + void remove_from_PQ(Edge_handle edge, Edge_data& data) { + data.set_PQ_handle(heap_PQ_->erase(edge, data.PQ_handle())); + --current_num_edges_heap_; + } + + boost::optional<Edge_handle> pop_from_PQ() { + boost::optional<Edge_handle> edge = heap_PQ_->extract_top(); + if (edge) + get_data(*edge).reset_PQ_handle(); + return edge; + } + + private: + /** + * @brief Collect edges. + * + * Iterates over all edges of the simplicial complex and + * 1) inserts them in the priority queue sorted according to the Cost policy. + * 2) set the id() field of each edge + */ + void collect_edges() { + // + // Loop over all the edges in the complex in the heap + // + size_type size = complex_.num_edges(); + DBG("Collecting edges ..."); + DBGMSG("num edges :", size); + + edge_data_array_.reset(new Edge_data[size]); + + heap_PQ_.reset(new PQ(size, Compare_cost(this), Undirected_edge_id(this))); + + std::size_t id = 0; + + // xxx do a parralel for + for (auto edge : complex_.edge_range()) { + complex_[edge].index() = id++; + Profile const& profile = create_profile(edge); + Edge_data& data = get_data(edge); + data.cost() = get_cost(profile); + ++initial_num_edges_heap_; + insert_in_PQ(edge, data); + if (contraction_visitor_) contraction_visitor_->on_collected(profile, data.cost()); + } + + DBG("Edges collected."); + } + + bool should_stop(double lCost, const Profile &profile) const { + return false; + } + + boost::optional<Point> get_placement(const Profile& profile) const { + return (*placement_policy_)(profile); + } + + bool is_contraction_valid(Profile const& profile, Placement_type placement) const { + if (!valid_contraction_policy_) return true; + return (*valid_contraction_policy_)(profile, placement); + } + + + public: + /** + * \brief Contract edges. + * + * While the heap is not empty, it extracts the edge with the minimum + * cost in the heap then try to contract it. + * It stops when the Stop policy says so or when the number of contractions + * given by 'num_max_contractions' is reached (if this number is positive). + */ + void contract_edges(int num_max_contractions = -1) { + DBG("\n\nContract edges"); + int num_contraction = 0; + + bool unspecified_num_contractions = (num_max_contractions == -1); + // + // Pops and processes each edge from the PQ + // + boost::optional<Edge_handle> edge; + while ((edge = pop_from_PQ()) && ((num_contraction < num_max_contractions) || (unspecified_num_contractions))) { + Profile const& profile = create_profile(*edge); + Cost_type cost(get_data(*edge).cost()); + if (contraction_visitor_) contraction_visitor_->on_selected(profile, cost, 0, 0); + + DBGMSG("\n\n---- Pop edge - num vertices :", complex_.num_vertices()); + + if (cost) { + DBGMSG("sqrt(cost):", std::sqrt(*cost)); + if (should_stop(*cost, profile)) { + if (contraction_visitor_) contraction_visitor_->on_stop_condition_reached(); + DBG("should_stop"); + break; + } + Placement_type placement = get_placement(profile); + if (is_contraction_valid(profile, placement) && placement) { + DBG("contraction_valid"); + contract_edge(profile, placement); + ++num_contraction; + } else { + DBG("contraction not valid"); + if (contraction_visitor_) contraction_visitor_->on_non_valid(profile); + } + } else { + DBG("uncomputable cost"); + } + } + if (contraction_visitor_) contraction_visitor_->on_stop_condition_reached(); + } + + bool is_in_heap(Edge_handle edge) const { + if (heap_PQ_->empty()) { + return false; + } else { + return edge_data_array_[get_undirected_edge_id(edge)].is_in_PQ(); + } + } + + bool is_heap_empty() const { + return heap_PQ_->empty(); + } + + /** + * @brief Returns an Edge_handle and a Placement_type. This pair consists in + * the edge with the lowest cost in the heap together with its placement. + * The returned value is initialized iff the heap is non-empty. + */ + boost::optional<std::pair<Edge_handle, Placement_type > > top_edge() { + boost::optional<std::pair<Edge_handle, Placement_type > > res; + + if (!heap_PQ_->empty()) { + auto edge = heap_PQ_->top(); + Profile const& profile = create_profile(edge); + Placement_type placement = get_placement(profile); + res = std::make_pair(edge, placement); + DBGMSG("top edge:", complex_[edge]); + } + return res; + } + + /** + * @brief Constructor with default policies. + * + * @details The default cost, placement, valid and visitor policies + * are respectively : the edge length, the first point, the link condition + */ + Skeleton_blocker_contractor(GeometricSimplifiableComplex& complex) + : complex_(complex), + cost_policy_(new Edge_length_cost<Profile>), + placement_policy_(new First_vertex_placement<Profile>), + valid_contraction_policy_(new Link_condition_valid_contraction<Profile>), + contraction_visitor_(new Contraction_visitor_()), + edge_profile_factory_(0), + initial_num_edges_heap_(0), + current_num_edges_heap_(0) { + complex_.set_visitor(this); + if (contraction_visitor_) contraction_visitor_->on_started(complex); + collect_edges(); + } + + /** + * @brief Constructor with customed policies. + * @remark Policies destruction is handle by the class with smart pointers. + */ + Skeleton_blocker_contractor(GeometricSimplifiableComplex& complex, + Cost_policy_ *cost_policy, + Placement_policy_ * placement_policy = new First_vertex_placement<Profile>, + Valid_contraction_policy_ * valid_contraction_policy = + new Link_condition_valid_contraction<Profile>, + Contraction_visitor_* contraction_visitor = new Contraction_visitor_(), + Edge_profile_factory_* edge_profile_factory = NULL) : + complex_(complex), + cost_policy_(cost_policy), + placement_policy_(placement_policy), + valid_contraction_policy_(valid_contraction_policy), + contraction_visitor_(contraction_visitor), + edge_profile_factory_(edge_profile_factory), + initial_num_edges_heap_(0), + current_num_edges_heap_(0) { + complex_.set_visitor(this); + if (contraction_visitor) contraction_visitor->on_started(complex); + collect_edges(); + } + + ~Skeleton_blocker_contractor() { + complex_.set_visitor(0); + } + + private: + void contract_edge(const Profile& profile, Placement_type placement) { + if (contraction_visitor_) contraction_visitor_->on_contracting(profile, placement); + + assert(complex_.contains_vertex(profile.v0_handle())); + assert(complex_.contains_vertex(profile.v1_handle())); + assert(placement); + + profile.complex().point(profile.v0_handle()) = *placement; + + // remark : this is not necessary since v1 will be deactivated + // profile.complex().point(profile.v1_handle()) = *placement; + + complex_.contract_edge(profile.v0_handle(), profile.v1_handle()); + + assert(complex_.contains_vertex(profile.v0_handle())); + assert(!complex_.contains_vertex(profile.v1_handle())); + + update_changed_edges(); + + // the visitor could do something as complex_.remove_popable_blockers(); + if (contraction_visitor_) contraction_visitor_->on_contracted(profile, placement); + } + + private: + // every time the visitor's method on_changed_edge is called, it adds an + // edge to changed_edges_ + std::vector< Edge_handle > changed_edges_; + + /** + * @brief we update the cost and the position in the heap of an edge that has + * been changed + */ + inline void on_changed_edge(Vertex_handle a, Vertex_handle b) override { + boost::optional<Edge_handle> ab(complex_[std::make_pair(a, b)]); + assert(ab); + changed_edges_.push_back(*ab); + } + + void update_changed_edges() { + // xxx do a parralel for + DBG("update edges"); + + // sequential loop + for (auto ab : changed_edges_) { + // 1-get the Edge_handle corresponding to ab + // 2-change the data in mEdgeArray[ab.id()] + // 3-update the heap + Edge_data& data = get_data(ab); + Profile const& profile = create_profile(ab); + data.cost() = get_cost(profile); + if (data.is_in_PQ()) { + update_in_PQ(ab, data); + } else { + insert_in_PQ(ab, data); + } + } + changed_edges_.clear(); + } + + + private: + void on_remove_edge(Vertex_handle a, Vertex_handle b) override { + boost::optional<Edge_handle> ab((complex_[std::make_pair(a, b)])); + assert(ab); + Edge_data& lData = get_data(*ab); + if (lData.is_in_PQ()) { + remove_from_PQ(*ab, lData); + } + } + + private: + /** + * @brief Called when the edge 'ax' has been added while the edge 'bx' + * is still there but will be removed on next instruction. + * We assign the index of 'bx' to the edge index of 'ax' + */ + void on_swaped_edge(Vertex_handle a, Vertex_handle b, Vertex_handle x) override { + boost::optional<Edge_handle> ax(complex_[std::make_pair(a, x)]); + boost::optional<Edge_handle> bx(complex_[std::make_pair(b, x)]); + assert(ax && bx); + complex_[*ax].index() = complex_[*bx].index(); + } + + private: + /** + * @brief Called when a blocker is removed. + * All the edges that passes through the blocker may be edge-contractible + * again and are thus reinserted in the heap. + */ + void on_delete_blocker(const Simplex * blocker) override { + // we go for all pairs xy that belongs to the blocker + // note that such pairs xy are necessarily edges of the complex + // by definition of a blocker + + // todo uniqument utile pour la link condition + // laisser a l'utilisateur ? booleen update_heap_on_removed_blocker? + Simplex blocker_copy(*blocker); + for (auto x = blocker_copy.begin(); x != blocker_copy.end(); ++x) { + for (auto y = x; ++y != blocker_copy.end();) { + auto edge_descr(complex_[std::make_pair(*x, *y)]); + assert(edge_descr); + Edge_data& data = get_data(*edge_descr); + Profile const& profile = create_profile(*edge_descr); + data.cost() = get_cost(profile); + + // If the edge is already in the heap + // its priority has not changed. + // If the edge is not present, we reinsert it + // remark : we could also reinsert the edge + // only if it is valid + if (!data.is_in_PQ()) { + insert_in_PQ(*edge_descr, data); + } + } + } + } + + + private: + std::shared_ptr<Cost_policy_> cost_policy_; + std::shared_ptr<Placement_policy_> placement_policy_; + std::shared_ptr<Valid_contraction_policy_> valid_contraction_policy_; + std::shared_ptr<Contraction_visitor_> contraction_visitor_; + + // in case the user wants to do something special when the edge profile + // are created (for instance add some info) + std::shared_ptr<Edge_profile_factory_> edge_profile_factory_; + Edge_data_array edge_data_array_; + + boost::scoped_ptr<PQ> heap_PQ_; + int initial_num_edges_heap_; + int current_num_edges_heap_; }; } // namespace contraction -} // namespace GUDHI -#endif /* GUDHI_SKELETON_BLOCKER_CONTRACTOR_H_ */ +} // namespace Gudhi + +#endif // SKELETON_BLOCKER_CONTRACTOR_H_ diff --git a/src/Doxyfile b/src/Doxyfile index 62412627..faa0d3fe 100644 --- a/src/Doxyfile +++ b/src/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "Gudhi" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "1.1.0" +PROJECT_NUMBER = "1.2.0" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -672,7 +672,8 @@ LAYOUT_FILE = # search path. Do not use file names with spaces, bibtex cannot handle them. See # also \cite for info how to create references. -CITE_BIB_FILES = ../biblio/bibliography.bib +CITE_BIB_FILES = biblio/bibliography.bib \ + biblio/how_to_cite_gudhi.bib #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages @@ -811,7 +812,7 @@ EXCLUDE_SYMBOLS = # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = biblio/ # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and @@ -831,9 +832,9 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = Skeleton_blocker/doc/ \ - common/doc/ \ - Contraction/doc/ +IMAGE_PATH = doc/Skeleton_blocker/ \ + doc/common/ \ + doc/Contraction/ # The INPUT_FILTER tag can be used to specify a program that doxygen should @@ -1338,7 +1339,7 @@ ECLIPSE_DOC_ID = org.doxygen.Project # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -DISABLE_INDEX = NO +DISABLE_INDEX = YES # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag @@ -1355,7 +1356,7 @@ DISABLE_INDEX = NO # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_TREEVIEW = NO +GENERATE_TREEVIEW = YES # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. diff --git a/src/GUDHIConfig.cmake.in b/src/GUDHIConfig.cmake.in new file mode 100644 index 00000000..02b540dc --- /dev/null +++ b/src/GUDHIConfig.cmake.in @@ -0,0 +1,7 @@ +# - Config file for the GUDHI package +# It defines the following variables +# GUDHI_INCLUDE_DIRS - include directories for GUDHI + +# Compute paths +set(GUDHI_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@") + diff --git a/src/GUDHIConfigVersion.cmake.in b/src/GUDHIConfigVersion.cmake.in new file mode 100644 index 00000000..6d443ef6 --- /dev/null +++ b/src/GUDHIConfigVersion.cmake.in @@ -0,0 +1,11 @@ +set(PACKAGE_VERSION "@GUDHI_VERSION@") + +# Check whether the requested PACKAGE_FIND_VERSION is compatible +if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() diff --git a/src/GudhUI/CMakeLists.txt b/src/GudhUI/CMakeLists.txt index ddbae969..71f4fd1a 100644 --- a/src/GudhUI/CMakeLists.txt +++ b/src/GudhUI/CMakeLists.txt @@ -5,9 +5,6 @@ find_package(CGAL COMPONENTS Qt4) find_package(Qt4) find_package(QGLViewer) find_package(OpenGL) -message("CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}") -message("CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}") -message("CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}") if ( CGAL_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND ) set( QT_USE_QTXML TRUE ) @@ -21,7 +18,23 @@ if ( CGAL_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND ) LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) include(${QT_USE_FILE}) + include(${CGAL_USE_FILE}) + # In CMakeLists.txt, when include(${CGAL_USE_FILE}), CXX_FLAGS are overwritten. + # cf. http://doc.cgal.org/latest/Manual/installation.html#title40 + # A workaround is to add "-std=c++11" again. + # A fix would be to use https://cmake.org/cmake/help/v3.1/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.html + # or even better https://cmake.org/cmake/help/v3.1/variable/CMAKE_CXX_STANDARD.html + # but it implies to use cmake version 3.1 at least. + if(NOT MSVC) + include(CheckCXXCompilerFlag) + CHECK_CXX_COMPILER_FLAG(-std=c++11 COMPILER_SUPPORTS_CXX11) + if(COMPILER_SUPPORTS_CXX11) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + endif() + endif() + # - End of workaround + include_directories (${QGLVIEWER_INCLUDE_DIR}) include_directories(.) @@ -66,5 +79,5 @@ if ( CGAL_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND ) target_link_libraries( GudhUI ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} ) else() - message(STATUS "NOTICE: This demo requires CGAL, the QGLViewer, OpenGL and Qt4, and will not be compiled.") + message(STATUS "NOTICE: GudhUI requires CGAL, the QGLViewer, OpenGL and Qt4, and will not be compiled.") endif() diff --git a/src/GudhUI/gui/MainWindow.cpp b/src/GudhUI/gui/MainWindow.cpp index e41b15ba..779ccd33 100644 --- a/src/GudhUI/gui/MainWindow.cpp +++ b/src/GudhUI/gui/MainWindow.cpp @@ -1,3 +1,25 @@ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 "MainWindow.h" #include <QWidget> @@ -6,292 +28,271 @@ #include <fenv.h> - #include "gui/Menu_k_nearest_neighbors.h" #include "gui/Menu_uniform_neighbors.h" #include "gui/Menu_edge_contraction.h" #include "gui/Menu_persistence.h" +MainWindow::MainWindow(QWidget* parent) : + menu_k_nearest_neighbors_(new Menu_k_nearest_neighbors(this)), + menu_uniform_neighbors_(new Menu_uniform_neighbors(this)), + menu_edge_contraction_(new Menu_edge_contraction(this, model_)), + menu_persistence_(new Menu_persistence(this)) { + // #ifndef NDEBUG // catch nan + // feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); + // #endif -MainWindow::MainWindow(QWidget* parent): -menu_k_nearest_neighbors_(new Menu_k_nearest_neighbors(this)), -menu_uniform_neighbors_(new Menu_uniform_neighbors(this)), -menu_edge_contraction_(new Menu_edge_contraction(this,model_)), -menu_persistence_(new Menu_persistence(this)) -{ -//#ifndef NDEBUG // catch nan -//feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); -//#endif + setupUi(this); - setupUi(this); + viewer_instructor_ = new Viewer_instructor( + this, + this->viewer, + model_.complex_); - viewer_instructor_ = new Viewer_instructor( - this, - this->viewer, - model_.complex_ - ); + connectActions(); - connectActions(); - - update_view(); + update_view(); } -void -MainWindow::closeEvent(QCloseEvent *event){ - exit(0); +void +MainWindow::closeEvent(QCloseEvent *event) { + exit(0); } - -void -MainWindow::connectActions(){ - QObject::connect(this->actionLoad_complex, SIGNAL(triggered()), this, - SLOT(off_file_open())); - QObject::connect(this->actionLoad_points, SIGNAL(triggered()), this, - SLOT(off_points_open())); - QObject::connect(this->actionSave_complex, SIGNAL(triggered()), this, - SLOT(off_file_save())); - QObject::connect(this->actionSave_points, SIGNAL(triggered()), this, - SLOT(off_points_save())); - - QObject::connect(this->actionShow_graph_stats, SIGNAL(triggered()), this, - SLOT(show_graph_stats())); - QObject::connect(this->actionShow_complex_stats, SIGNAL(triggered()), this, - SLOT(show_complex_stats())); - QObject::connect(this->actionShow_complex_dimension, SIGNAL(triggered()), this, - SLOT(show_complex_dimension())); - - QObject::connect(this->actionUniform_proximity_graph, SIGNAL(triggered()), this, - SLOT(build_rips_menu())); - QObject::connect(this->actionK_nearest_neighbors_graph, SIGNAL(triggered()), this, - SLOT(build_k_nearest_neighbors_menu())); - - - QObject::connect(this->actionContract_edges, SIGNAL(triggered()), this, - SLOT(contract_edge_menu())); - - QObject::connect(this->actionCollapse_vertices, SIGNAL(triggered()), this, - SLOT(collapse_vertices())); - - QObject::connect(this->actionCollapse_edges, SIGNAL(triggered()), this, - SLOT(collapse_edges())); - - QObject::connect(this->actionNoise, SIGNAL(triggered()), this, - SLOT(uniform_noise())); - QObject::connect(this->actionLloyd, SIGNAL(triggered()), this, - SLOT(lloyd())); - - - //view - QObject::connect(this->actionPoints, SIGNAL(triggered()), this->viewer_instructor_, - SLOT(change_draw_vertices())); - QObject::connect(this->actionEdges, SIGNAL(triggered()), this->viewer_instructor_, - SLOT(change_draw_edges())); - QObject::connect(this->actionTriangles, SIGNAL(triggered()), this->viewer_instructor_, - SLOT(change_draw_triangles())); - - //topology - QObject::connect(this->actionShow_homology_group, SIGNAL(triggered()), this, - SLOT(show_homology_group())); - QObject::connect(this->actionEuler_characteristic, SIGNAL(triggered()), this, - SLOT(show_euler_characteristic())); - QObject::connect(this->actionPersistence, SIGNAL(triggered()), this, - SLOT(persistence_menu())); - QObject::connect(this->actionEstimate_topological_changes, SIGNAL(triggered()), this, - SLOT(critical_points_menu())); - QObject::connect(this->actionIs_manifold, SIGNAL(triggered()), this, - SLOT(is_manifold_menu())); - - - QObject::connect(this, SIGNAL(sceneChanged()), this->viewer_instructor_, - SLOT(sceneChanged())); - +void +MainWindow::connectActions() { + QObject::connect(this->actionLoad_complex, SIGNAL(triggered()), this, + SLOT(off_file_open())); + QObject::connect(this->actionLoad_points, SIGNAL(triggered()), this, + SLOT(off_points_open())); + QObject::connect(this->actionSave_complex, SIGNAL(triggered()), this, + SLOT(off_file_save())); + QObject::connect(this->actionSave_points, SIGNAL(triggered()), this, + SLOT(off_points_save())); + + QObject::connect(this->actionShow_graph_stats, SIGNAL(triggered()), this, + SLOT(show_graph_stats())); + QObject::connect(this->actionShow_complex_stats, SIGNAL(triggered()), this, + SLOT(show_complex_stats())); + QObject::connect(this->actionShow_complex_dimension, SIGNAL(triggered()), this, + SLOT(show_complex_dimension())); + + QObject::connect(this->actionUniform_proximity_graph, SIGNAL(triggered()), this, + SLOT(build_rips_menu())); + QObject::connect(this->actionK_nearest_neighbors_graph, SIGNAL(triggered()), this, + SLOT(build_k_nearest_neighbors_menu())); + + + QObject::connect(this->actionContract_edges, SIGNAL(triggered()), this, + SLOT(contract_edge_menu())); + + QObject::connect(this->actionCollapse_vertices, SIGNAL(triggered()), this, + SLOT(collapse_vertices())); + + QObject::connect(this->actionCollapse_edges, SIGNAL(triggered()), this, + SLOT(collapse_edges())); + + QObject::connect(this->actionNoise, SIGNAL(triggered()), this, + SLOT(uniform_noise())); + QObject::connect(this->actionLloyd, SIGNAL(triggered()), this, + SLOT(lloyd())); + + + // view + QObject::connect(this->actionPoints, SIGNAL(triggered()), this->viewer_instructor_, + SLOT(change_draw_vertices())); + QObject::connect(this->actionEdges, SIGNAL(triggered()), this->viewer_instructor_, + SLOT(change_draw_edges())); + QObject::connect(this->actionTriangles, SIGNAL(triggered()), this->viewer_instructor_, + SLOT(change_draw_triangles())); + + // topology + QObject::connect(this->actionShow_homology_group, SIGNAL(triggered()), this, + SLOT(show_homology_group())); + QObject::connect(this->actionEuler_characteristic, SIGNAL(triggered()), this, + SLOT(show_euler_characteristic())); + QObject::connect(this->actionPersistence, SIGNAL(triggered()), this, + SLOT(persistence_menu())); + QObject::connect(this->actionEstimate_topological_changes, SIGNAL(triggered()), this, + SLOT(critical_points_menu())); + QObject::connect(this->actionIs_manifold, SIGNAL(triggered()), this, + SLOT(is_manifold_menu())); + + + QObject::connect(this, SIGNAL(sceneChanged()), this->viewer_instructor_, + SLOT(sceneChanged())); } void -MainWindow::init_view() const{ - viewer_instructor_->initialize_bounding_box(); - viewer_instructor_->show_entire_scene(); - update_view(); +MainWindow::init_view() const { + viewer_instructor_->initialize_bounding_box(); + viewer_instructor_->show_entire_scene(); + update_view(); } - void -MainWindow::update_view() const{ - emit (sceneChanged()); +MainWindow::update_view() const { + emit(sceneChanged()); } - - /** * open a file chooser to choose an off to load */ -void -MainWindow::off_file_open(){ - QString fileName = QFileDialog::getOpenFileName(this, tr("Open off File"), - "~/", tr("off files (*.off)")); - if (!fileName.isEmpty()){ - model_.off_file_open(fileName.toStdString()); - init_view(); - } +void +MainWindow::off_file_open() { + QString fileName = QFileDialog::getOpenFileName(this, tr("Open off File"), + "~/", tr("off files (*.off)")); + if (!fileName.isEmpty()) { + model_.off_file_open(fileName.toStdString()); + init_view(); + } } void -MainWindow::off_points_open(){ - QString fileName = QFileDialog::getOpenFileName(this, tr("Open points in a off file"), - "~/", tr("off files (*.off)")); - if (!fileName.isEmpty()){ - model_.off_points_open(fileName.toStdString()); - init_view(); - } +MainWindow::off_points_open() { + QString fileName = QFileDialog::getOpenFileName(this, tr("Open points in a off file"), + "~/", tr("off files (*.off)")); + if (!fileName.isEmpty()) { + model_.off_points_open(fileName.toStdString()); + init_view(); + } } - /** * open a file chooser to choose an off to save */ -void -MainWindow::off_file_save(){ - QString fileName = QFileDialog::getOpenFileName(this, tr("Save to off File"), - "~/", tr("off files (*.off)")); - if (!fileName.isEmpty()) - { - model_.off_file_save(fileName.toStdString()); - } +void +MainWindow::off_file_save() { + QString fileName = QFileDialog::getOpenFileName(this, tr("Save to off File"), + "~/", tr("off files (*.off)")); + if (!fileName.isEmpty()) { + model_.off_file_save(fileName.toStdString()); + } } /** * open a file chooser to choose an off to save */ void -MainWindow::off_points_save(){ - QString fileName = QFileDialog::getOpenFileName(this, tr("Save to off File"), - "~/", tr("off files (*.off)")); - if (!fileName.isEmpty()) - { - model_.off_points_save(fileName.toStdString()); - } +MainWindow::off_points_save() { + QString fileName = QFileDialog::getOpenFileName(this, tr("Save to off File"), + "~/", tr("off files (*.off)")); + if (!fileName.isEmpty()) { + model_.off_points_save(fileName.toStdString()); + } } - void -MainWindow::show_graph_stats(){ - model_.show_graph_stats(); +MainWindow::show_graph_stats() { + model_.show_graph_stats(); } void -MainWindow::show_complex_stats(){ - model_.show_complex_stats(); +MainWindow::show_complex_stats() { + model_.show_complex_stats(); } -void -MainWindow::show_complex_dimension(){ - model_.show_complex_dimension(); +void +MainWindow::show_complex_dimension() { + model_.show_complex_dimension(); } - void -MainWindow::build_rips_menu(){ - menu_uniform_neighbors_->show(); +MainWindow::build_rips_menu() { + menu_uniform_neighbors_->show(); } void -MainWindow::build_rips(double alpha){ - model_.build_rips(alpha); - update_view(); +MainWindow::build_rips(double alpha) { + model_.build_rips(alpha); + update_view(); } void -MainWindow::build_k_nearest_neighbors_menu(){ - menu_k_nearest_neighbors_->show(); +MainWindow::build_k_nearest_neighbors_menu() { + menu_k_nearest_neighbors_->show(); } void -MainWindow::build_k_nearest_neighbors(unsigned k){ - model_.build_k_nearest_neighbors(k); - update_view(); +MainWindow::build_k_nearest_neighbors(unsigned k) { + model_.build_k_nearest_neighbors(k); + update_view(); } void -MainWindow::contract_edge_menu(){ - menu_edge_contraction_->show(); +MainWindow::contract_edge_menu() { + menu_edge_contraction_->show(); } void -MainWindow::contract_edges(unsigned num_collapses){ - std::cerr <<"Collapse "<<num_collapses<< " vertices\n"; - model_.contract_edges(num_collapses); - update_view(); +MainWindow::contract_edges(unsigned num_collapses) { + std::cerr << "Collapse " << num_collapses << " vertices\n"; + model_.contract_edges(num_collapses); + update_view(); } - void -MainWindow::collapse_edges(){ - model_.collapse_edges(model_.num_edges()); - update_view(); +MainWindow::collapse_edges() { + model_.collapse_edges(model_.num_edges()); + update_view(); } - - void -MainWindow::collapse_vertices(){ - std::cerr <<"Collapse vertices edges\n"; - model_.collapse_vertices(0); - update_view(); +MainWindow::collapse_vertices() { + std::cerr << "Collapse vertices edges\n"; + model_.collapse_vertices(0); + update_view(); } - void -MainWindow::uniform_noise(){ - bool ok; - double amplitude = QInputDialog::getDouble(this, tr("Uniform noise"), - tr("Amplitude:"), 0, 0, 10000, 3, &ok); - srand(time(NULL)); - if (ok) - model_.uniform_noise(amplitude); +MainWindow::uniform_noise() { + bool ok; + double amplitude = QInputDialog::getDouble(this, tr("Uniform noise"), + tr("Amplitude:"), 0, 0, 10000, 3, &ok); + srand(time(NULL)); + if (ok) + model_.uniform_noise(amplitude); } - void -MainWindow::lloyd(){ - //todo 1 ask lloyd parameters - model_.lloyd(0,0); - update_view(); +MainWindow::lloyd() { + // todo 1 ask lloyd parameters + model_.lloyd(0, 0); + update_view(); } void -MainWindow::show_homology_group(){ - model_.show_homology_group(); +MainWindow::show_homology_group() { + model_.show_homology_group(); } void -MainWindow::show_euler_characteristic(){ - model_.show_euler_characteristic(); +MainWindow::show_euler_characteristic() { + model_.show_euler_characteristic(); } - - void -MainWindow::persistence_menu(){ - menu_persistence_->show(); +MainWindow::persistence_menu() { + menu_persistence_->show(); } void -MainWindow::compute_persistence(int p,double threshold,int max_dim,double min_pers){ - model_.show_persistence(p,threshold,max_dim,min_pers); +MainWindow::compute_persistence(int p, double threshold, int max_dim, double min_pers) { + model_.show_persistence(p, threshold, max_dim, min_pers); } void -MainWindow::critical_points_menu(){ - bool ok; - double max_length = QInputDialog::getDouble(this, tr("Maximal edge length for the Rips"), - tr("Maximal edge length:"), 0, 0, 10000, 3, &ok); - if (ok) - model_.show_critical_points(max_length); +MainWindow::critical_points_menu() { + bool ok; + double max_length = QInputDialog::getDouble(this, tr("Maximal edge length for the Rips"), + tr("Maximal edge length:"), 0, 0, 10000, 3, &ok); + if (ok) + model_.show_critical_points(max_length); } void -MainWindow::is_manifold_menu(){ - model_.show_is_manifold(); +MainWindow::is_manifold_menu() { + model_.show_is_manifold(); } diff --git a/src/GudhUI/gui/MainWindow.h b/src/GudhUI/gui/MainWindow.h index 587f1c6f..c8c3fcf6 100644 --- a/src/GudhUI/gui/MainWindow.h +++ b/src/GudhUI/gui/MainWindow.h @@ -1,6 +1,30 @@ -#ifndef MAIN_WINDOW_H -#define MAIN_WINDOW_H - +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 GUI_MAINWINDOW_H_ +#define GUI_MAINWINDOW_H_ + +// Workaround for moc-qt4 not parsing boost headers +#include <CGAL/config.h> #include <QMainWindow> #include "ui_main_window.h" @@ -13,86 +37,82 @@ class Menu_uniform_neighbors; class Menu_edge_contraction; class Menu_persistence; -class MainWindow : public QMainWindow,public Ui::MainWindow{ - Q_OBJECT - -private: - Model model_; - Viewer_instructor* viewer_instructor_; - Menu_k_nearest_neighbors* menu_k_nearest_neighbors_; - Menu_uniform_neighbors* menu_uniform_neighbors_; - Menu_edge_contraction* menu_edge_contraction_; - Menu_persistence* menu_persistence_; - -public: - MainWindow(QWidget* parent = 0); - void connectActions(); - - /** - * compute the bounding box and calls update view - */ - void init_view() const; - void update_view() const; +class MainWindow : public QMainWindow, public Ui::MainWindow { + Q_OBJECT + private: + Model model_; + Viewer_instructor* viewer_instructor_; + Menu_k_nearest_neighbors* menu_k_nearest_neighbors_; + Menu_uniform_neighbors* menu_uniform_neighbors_; + Menu_edge_contraction* menu_edge_contraction_; + Menu_persistence* menu_persistence_; -protected: - void closeEvent(QCloseEvent *event); - void keyPressEvent(QKeyEvent *event){} + public: + MainWindow(QWidget* parent = 0); + void connectActions(); -public: + /** + * compute the bounding box and calls update view + */ + void init_view() const; + void update_view() const; - public slots: + protected: + void closeEvent(QCloseEvent *event); - /** - * open a file chooser to choose an off to load - */ - void off_file_open(); + void keyPressEvent(QKeyEvent *event) { } - void off_points_open(); + public: + public slots: + /** + * open a file chooser to choose an off to load + */ + void off_file_open(); - /** - * open a file chooser to choose an off to save - */ - void off_file_save(); - void off_points_save(); + void off_points_open(); - void show_graph_stats(); - void show_complex_stats(); - void show_complex_dimension(); + /** + * open a file chooser to choose an off to save + */ + void off_file_save(); + void off_points_save(); + void show_graph_stats(); + void show_complex_stats(); + void show_complex_dimension(); - void build_rips_menu(); - void build_rips(double alpha); - void build_k_nearest_neighbors_menu(); - void build_k_nearest_neighbors(unsigned k); + void build_rips_menu(); + void build_rips(double alpha); + void build_k_nearest_neighbors_menu(); + void build_k_nearest_neighbors(unsigned k); - void contract_edge_menu(); - void contract_edges(unsigned num_collapses); + void contract_edge_menu(); + void contract_edges(unsigned num_collapses); - void collapse_vertices(); - void collapse_edges(); + void collapse_vertices(); + void collapse_edges(); - void uniform_noise(); - void lloyd(); - void show_homology_group(); - void show_euler_characteristic(); - void persistence_menu(); - void compute_persistence(int p,double threshold,int max_dim,double min_pers); - void critical_points_menu(); - void is_manifold_menu(); + void uniform_noise(); + void lloyd(); + void show_homology_group(); + void show_euler_characteristic(); + void persistence_menu(); + void compute_persistence(int p, double threshold, int max_dim, double min_pers); + void critical_points_menu(); + void is_manifold_menu(); -public: - signals: - void sceneChanged() const; - + public: + signals: + void sceneChanged() const; }; -#endif +#endif // GUI_MAINWINDOW_H_ diff --git a/src/GudhUI/gui/Menu_edge_contraction.cpp b/src/GudhUI/gui/Menu_edge_contraction.cpp index dd2621be..a679b0bf 100644 --- a/src/GudhUI/gui/Menu_edge_contraction.cpp +++ b/src/GudhUI/gui/Menu_edge_contraction.cpp @@ -1,91 +1,97 @@ -/* - * Menu_edge_contraction.cpp +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Sep 11, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 MENU_EDGE_CONTRACTION_CPP_ -#define MENU_EDGE_CONTRACTION_CPP_ - +#ifndef GUI_MENU_EDGE_CONTRACTION_CPP_ +#define GUI_MENU_EDGE_CONTRACTION_CPP_ #include "Menu_edge_contraction.h" -Menu_edge_contraction::Menu_edge_contraction(MainWindow* parent,const Model& model): -parent_(parent),model_(model) -{ - setupUi(this); - connectActions(parent_); +Menu_edge_contraction::Menu_edge_contraction(MainWindow* parent, const Model& model) : + parent_(parent), model_(model) { + setupUi(this); + connectActions(parent_); } -void Menu_edge_contraction::connectActions(MainWindow* parent) -{ - QObject::connect( - this->horizontalSlider, - SIGNAL(valueChanged(int)), - this, - SLOT(slider_value_changed(int)) - ); +void Menu_edge_contraction::connectActions(MainWindow* parent) { + QObject::connect( + this->horizontalSlider, + SIGNAL(valueChanged(int)), + this, + SLOT(slider_value_changed(int))); - QObject::connect(this, SIGNAL(contract_edges(unsigned)), parent, SLOT(contract_edges(unsigned))); - - QObject::connect(this->pushButton_collapse, SIGNAL(clicked()), this, SLOT(send_contract_edges())); + QObject::connect(this, SIGNAL(contract_edges(unsigned)), parent, SLOT(contract_edges(unsigned))); + QObject::connect(this->pushButton_collapse, SIGNAL(clicked()), this, SLOT(send_contract_edges())); } -void Menu_edge_contraction::slider_value_changed(int new_slider_value){ - int num_collapses = - (horizontalSlider->value()==1)? 1 : horizontalSlider->value() * model_.num_vertices() / 100 ; - this->txt_nb_vertices->setNum((int)model_.num_vertices()); - this->txt_nb_collapses->setNum(num_collapses); - this->spinBox_nb_remaining_vertices->setValue(model_.num_vertices()-num_collapses); +void Menu_edge_contraction::slider_value_changed(int new_slider_value) { + int num_collapses = + (horizontalSlider->value() == 1) ? 1 : horizontalSlider->value() * model_.num_vertices() / 100; + this->txt_nb_vertices->setNum(static_cast<int>(model_.num_vertices())); + this->txt_nb_collapses->setNum(num_collapses); + this->spinBox_nb_remaining_vertices->setValue(model_.num_vertices() - num_collapses); } - void -Menu_edge_contraction::update_slider_value(){ - int num_vertices = model_.num_vertices(); - int num_collapses = (horizontalSlider->value()==1)? 1 : horizontalSlider->value() * num_vertices / 100 ; - int horizontal_slider_position = num_vertices>0? num_collapses/(double)num_vertices * 100 : 1 ; - horizontalSlider->setValue(horizontal_slider_position); +Menu_edge_contraction::update_slider_value() { + int num_vertices = model_.num_vertices(); + int num_collapses = (horizontalSlider->value() == 1) ? 1 : horizontalSlider->value() * num_vertices / 100; + int horizontal_slider_position = num_vertices > 0 ? num_collapses / static_cast<double>(num_vertices * 100) : 1; + horizontalSlider->setValue(horizontal_slider_position); } - void -Menu_edge_contraction::update_gui_numbers(){ - update_slider_value(); - bool ok; - int num_collapses = this->txt_nb_collapses->text().toInt(&ok,10); - if(!ok) return; - this->txt_nb_vertices->setNum((int)model_.num_vertices()); - this->txt_nb_collapses->setNum(num_collapses); - this->spinBox_nb_remaining_vertices->setValue(model_.num_vertices()-num_collapses); +Menu_edge_contraction::update_gui_numbers() { + update_slider_value(); + bool ok; + int num_collapses = this->txt_nb_collapses->text().toInt(&ok, 10); + if (!ok) return; + this->txt_nb_vertices->setNum(static_cast<int>(model_.num_vertices())); + this->txt_nb_collapses->setNum(num_collapses); + this->spinBox_nb_remaining_vertices->setValue(model_.num_vertices() - num_collapses); } void -Menu_edge_contraction::update_gui_numbers(int new_value){ - update_gui_numbers(); +Menu_edge_contraction::update_gui_numbers(int new_value) { + update_gui_numbers(); } - void -Menu_edge_contraction::send_contract_edges(){ - emit(contract_edges(num_collapses())); - update_gui_numbers(); +Menu_edge_contraction::send_contract_edges() { + emit(contract_edges(num_collapses())); + update_gui_numbers(); } unsigned -Menu_edge_contraction::num_vertices(){ - return model_.num_vertices(); +Menu_edge_contraction::num_vertices() { + return model_.num_vertices(); } unsigned -Menu_edge_contraction::num_collapses(){ - return (horizontalSlider->value()==1)? 1 : horizontalSlider->value() * num_vertices() / 100 ; +Menu_edge_contraction::num_collapses() { + return (horizontalSlider->value() == 1) ? 1 : horizontalSlider->value() * num_vertices() / 100; } - #include "Menu_edge_contraction.moc" -#endif /* MENU_EDGE_CONTRACTION_CPP_ */ +#endif // GUI_MENU_EDGE_CONTRACTION_CPP_ diff --git a/src/GudhUI/gui/Menu_edge_contraction.h b/src/GudhUI/gui/Menu_edge_contraction.h index e497a90f..08f0bf67 100644 --- a/src/GudhUI/gui/Menu_edge_contraction.h +++ b/src/GudhUI/gui/Menu_edge_contraction.h @@ -1,52 +1,63 @@ -/* - * Menu_edge_contraction.h +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Sep 11, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 MENU_EDGE_CONTRACTION_H_ -#define MENU_EDGE_CONTRACTION_H_ +#ifndef GUI_MENU_EDGE_CONTRACTION_H_ +#define GUI_MENU_EDGE_CONTRACTION_H_ +// Workaround for moc-qt4 not parsing boost headers +#include <CGAL/config.h> #include "gui/MainWindow.h" #include "gui/ui_MenuEdgeContraction.h" #include "model/Model.h" +class Menu_edge_contraction : public QDialog, public Ui::MenuEdgeContraction { + Q_OBJECT -class Menu_edge_contraction : public QDialog,public Ui::MenuEdgeContraction{ - Q_OBJECT -private: - MainWindow* parent_; - const Model& model_; - + private: + MainWindow* parent_; + const Model& model_; - void update_slider_value(); -public: + void update_slider_value(); - Menu_edge_contraction(MainWindow* parent,const Model& model); + public: + Menu_edge_contraction(MainWindow* parent, const Model& model); - void connectActions(MainWindow* parent); + void connectActions(MainWindow* parent); + private: + unsigned num_vertices(); + unsigned num_collapses(); -private: - unsigned num_vertices(); - unsigned num_collapses(); + public slots: + void slider_value_changed(int new_slider_value); + void update_gui_numbers(); + void update_gui_numbers(int gui_numbers); - public slots: - - void slider_value_changed(int new_slider_value); - void update_gui_numbers(); - void update_gui_numbers(int); - - void send_contract_edges(); - signals: - - void contract_edges(unsigned num_collapses); + void send_contract_edges(); + signals: + void contract_edges(unsigned num_collapses); }; - - -#endif /* MENU_EDGE_CONTRACTION_H_ */ +#endif // GUI_MENU_EDGE_CONTRACTION_H_ diff --git a/src/GudhUI/gui/Menu_k_nearest_neighbors.cpp b/src/GudhUI/gui/Menu_k_nearest_neighbors.cpp index 21c67b2a..e24865f2 100644 --- a/src/GudhUI/gui/Menu_k_nearest_neighbors.cpp +++ b/src/GudhUI/gui/Menu_k_nearest_neighbors.cpp @@ -1,55 +1,59 @@ -/* - * Menu_k_nearest_neighbors.cpp +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Sep 11, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 "Menu_k_nearest_neighbors.h" -Menu_k_nearest_neighbors::Menu_k_nearest_neighbors(QMainWindow* parent_): -parent(parent_) -{ - setupUi(this); - connectActions(parent_); +Menu_k_nearest_neighbors::Menu_k_nearest_neighbors(QMainWindow* parent_) + : parent(parent_) { + setupUi(this); + connectActions(parent_); } -void Menu_k_nearest_neighbors::connectActions(QMainWindow* parent){ - - QObject::connect( - this->pushButtonCompute, - SIGNAL(clicked()), - this, - SLOT(send_compute_k_nearest_neighbors()) - ); - QObject::connect( - this->spinBoxK, - SIGNAL(valueChanged(int)), - this, - SLOT(update_k(int)) - ); - QObject::connect( - this, - SIGNAL(compute_k_nearest_neighbors(unsigned)), - parent, - SLOT(build_k_nearest_neighbors(unsigned)) - ); - +void Menu_k_nearest_neighbors::connectActions(QMainWindow* parent) { + QObject::connect(this->pushButtonCompute, + SIGNAL(clicked()), + this, + SLOT(send_compute_k_nearest_neighbors())); + QObject::connect(this->spinBoxK, + SIGNAL(valueChanged(int)), + this, + SLOT(update_k(int))); + QObject::connect(this, + SIGNAL(compute_k_nearest_neighbors(unsigned)), + parent, + SLOT(build_k_nearest_neighbors(unsigned))); } -void Menu_k_nearest_neighbors::send_compute_k_nearest_neighbors(){ - emit(compute_k_nearest_neighbors((unsigned)spinBoxK->value())); +void Menu_k_nearest_neighbors::send_compute_k_nearest_neighbors() { + emit(compute_k_nearest_neighbors((unsigned) spinBoxK->value())); } -void Menu_k_nearest_neighbors::accept(){ - send_compute_k_nearest_neighbors(); +void Menu_k_nearest_neighbors::accept() { + send_compute_k_nearest_neighbors(); } -void Menu_k_nearest_neighbors::update_k(int new_k_value){ - if(checkBoxAutoUpdate->isChecked()) - emit(compute_k_nearest_neighbors((unsigned)spinBoxK->value())); +void Menu_k_nearest_neighbors::update_k(int new_k_value) { + if (checkBoxAutoUpdate->isChecked()) + emit(compute_k_nearest_neighbors((unsigned) spinBoxK->value())); } - #include "Menu_k_nearest_neighbors.moc" diff --git a/src/GudhUI/gui/Menu_k_nearest_neighbors.h b/src/GudhUI/gui/Menu_k_nearest_neighbors.h index d72b0074..8088b768 100644 --- a/src/GudhUI/gui/Menu_k_nearest_neighbors.h +++ b/src/GudhUI/gui/Menu_k_nearest_neighbors.h @@ -1,39 +1,51 @@ -/* - * Menu_k_nearest_neighbors.h +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Sep 11, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 MENU_K_NEAREST_NEIGHBORS_H_ -#define MENU_K_NEAREST_NEIGHBORS_H_ +#ifndef GUI_MENU_K_NEAREST_NEIGHBORS_H_ +#define GUI_MENU_K_NEAREST_NEIGHBORS_H_ #include <QMainWindow> #include "gui/ui_KNearestNeighborsMenu.h" class QWidget; +class Menu_k_nearest_neighbors : public QDialog, public Ui::KNearestNeighborsMenu { + Q_OBJECT -class Menu_k_nearest_neighbors : public QDialog,public Ui::KNearestNeighborsMenu{ - Q_OBJECT -private: - QMainWindow* parent; + private: + QMainWindow* parent; -public: + public: + Menu_k_nearest_neighbors(QMainWindow* parent_); - Menu_k_nearest_neighbors(QMainWindow* parent_); + void connectActions(QMainWindow* parent); - void connectActions(QMainWindow* parent); - - public slots: - void send_compute_k_nearest_neighbors(); - void update_k(int); - void accept(); - - signals: - void compute_k_nearest_neighbors(unsigned k); + public slots: + void send_compute_k_nearest_neighbors(); + void update_k(int k); + void accept(); + signals: + void compute_k_nearest_neighbors(unsigned k); }; - -#endif /* MENU_K_NEAREST_NEIGHBORS_H_ */ +#endif // GUI_MENU_K_NEAREST_NEIGHBORS_H_ diff --git a/src/GudhUI/gui/Menu_persistence.cpp b/src/GudhUI/gui/Menu_persistence.cpp index fae3a0e6..016c076b 100644 --- a/src/GudhUI/gui/Menu_persistence.cpp +++ b/src/GudhUI/gui/Menu_persistence.cpp @@ -1,13 +1,10 @@ -/* - * Menu_persistence.cpp - * Created on: Jan 27, 2015 - * This file is part of the Gudhi Library. The Gudhi library +/* 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): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (France) + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 @@ -27,34 +24,30 @@ #include "Menu_persistence.h" -Menu_persistence::Menu_persistence(QMainWindow* parent_):parent(parent_) -{ - setupUi(this); - connectActions(parent_); +Menu_persistence::Menu_persistence(QMainWindow* parent_) : parent(parent_) { + setupUi(this); + connectActions(parent_); } -void Menu_persistence::connectActions(QMainWindow* parent){ - QObject::connect( - this, - SIGNAL(compute_persistence(int,double,int,double)), - parent, - SLOT(compute_persistence(int,double,int,double)) - ); +void Menu_persistence::connectActions(QMainWindow* parent) { + QObject::connect(this, + SIGNAL(compute_persistence(int, double, int, double)), + parent, + SLOT(compute_persistence(int, double, int, double))); } -void Menu_persistence::send_compute_persistence(){ - emit(compute_persistence(p_spinBox->value(),threshold_doubleSpinBox->value(), - maxdimension_spinBox->value(),minpersistence_doubleSpinBox->value())); +void Menu_persistence::send_compute_persistence() { + emit(compute_persistence(p_spinBox->value(), threshold_doubleSpinBox->value(), + maxdimension_spinBox->value(), minpersistence_doubleSpinBox->value())); } -void Menu_persistence::accept(){ - send_compute_persistence(); +void Menu_persistence::accept() { + send_compute_persistence(); } -//void Menu_persistence::compute_persistence(int p_fied,double threshold,int dim_max,double min_persistence){ -//// if(checkBoxAutoUpdate->isChecked()) -//// emit(compute_k_nearest_neighbors((unsigned)spinBoxK->value())); -//} - +// void Menu_persistence::compute_persistence(int p_fied,double threshold,int dim_max,double min_persistence) { +// if(checkBoxAutoUpdate->isChecked()) +// emit(compute_k_nearest_neighbors((unsigned)spinBoxK->value())); +// } #include "Menu_persistence.moc" diff --git a/src/GudhUI/gui/Menu_persistence.h b/src/GudhUI/gui/Menu_persistence.h index 67b64afa..8c4df158 100644 --- a/src/GudhUI/gui/Menu_persistence.h +++ b/src/GudhUI/gui/Menu_persistence.h @@ -1,13 +1,10 @@ -/* - * Menu_persistence.h - * Created on: Jan 27, 2015 - * This file is part of the Gudhi Library. The Gudhi library +/* 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): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (France) + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 @@ -24,36 +21,31 @@ * */ - -#ifndef MENU_PERSISTENCE_H_ -#define MENU_PERSISTENCE_H_ - +#ifndef GUI_MENU_PERSISTENCE_H_ +#define GUI_MENU_PERSISTENCE_H_ #include <QMainWindow> #include "gui/ui_PersistenceMenu.h" class QWidget; +class Menu_persistence : public QDialog, public Ui::PersistenceMenu { + Q_OBJECT -class Menu_persistence : public QDialog,public Ui::PersistenceMenu{ - Q_OBJECT -private: - QMainWindow* parent; - -public: + private: + QMainWindow* parent; - Menu_persistence(QMainWindow* parent_); + public: + Menu_persistence(QMainWindow* parent_); - void connectActions(QMainWindow* parent); + void connectActions(QMainWindow* parent); - public slots: - void send_compute_persistence(); - void accept(); - signals: - void compute_persistence(int p_fied,double threshold,int dim_max,double min_persistence); + public slots: + void send_compute_persistence(); + void accept(); + signals: + void compute_persistence(int p_fied, double threshold, int dim_max, double min_persistence); }; - - -#endif /* MENU_PERSISTENCE_H_ */ +#endif // GUI_MENU_PERSISTENCE_H_ diff --git a/src/GudhUI/gui/Menu_uniform_neighbors.cpp b/src/GudhUI/gui/Menu_uniform_neighbors.cpp index 86e2593e..20e4f98f 100644 --- a/src/GudhUI/gui/Menu_uniform_neighbors.cpp +++ b/src/GudhUI/gui/Menu_uniform_neighbors.cpp @@ -1,59 +1,60 @@ -/* - * Menu_uniform_neighbors.cpp +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Sep 11, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 "Menu_uniform_neighbors.h" -Menu_uniform_neighbors::Menu_uniform_neighbors(QMainWindow* parent_): -parent(parent_) -{ - setupUi(this); - connectActions(parent_); +Menu_uniform_neighbors::Menu_uniform_neighbors(QMainWindow* parent_) : + parent(parent_) { + setupUi(this); + connectActions(parent_); } -void Menu_uniform_neighbors::connectActions(QMainWindow* parent){ - - QObject::connect( - this->pushButtonCompute, - SIGNAL(clicked()), - this, - SLOT(send_compute_uniform_neighbors()) - ); - QObject::connect( - this->doubleSpinBoxAlpha, - SIGNAL(valueChanged(double)), - this, - SLOT(update_alpha(double)) - ); - QObject::connect( - this, - SIGNAL(compute_uniform_neighbors(double)), - parent, - SLOT(build_rips(double)) - ); - +void Menu_uniform_neighbors::connectActions(QMainWindow* parent) { + QObject::connect(this->pushButtonCompute, + SIGNAL(clicked()), + this, + SLOT(send_compute_uniform_neighbors())); + QObject::connect(this->doubleSpinBoxAlpha, + SIGNAL(valueChanged(double)), + this, + SLOT(update_alpha(double))); + QObject::connect(this, + SIGNAL(compute_uniform_neighbors(double)), + parent, + SLOT(build_rips(double))); } -void Menu_uniform_neighbors::send_compute_uniform_neighbors(){ - emit(compute_uniform_neighbors(doubleSpinBoxAlpha->value())); +void Menu_uniform_neighbors::send_compute_uniform_neighbors() { + emit(compute_uniform_neighbors(doubleSpinBoxAlpha->value())); } -void Menu_uniform_neighbors::accept(){ - send_compute_uniform_neighbors(); +void Menu_uniform_neighbors::accept() { + send_compute_uniform_neighbors(); } -void Menu_uniform_neighbors::update_alpha(double alpha){ - if(checkBoxAutoUpdate->isChecked()) - emit(compute_uniform_neighbors(doubleSpinBoxAlpha->value())); +void Menu_uniform_neighbors::update_alpha(double alpha) { + if (checkBoxAutoUpdate->isChecked()) + emit(compute_uniform_neighbors(doubleSpinBoxAlpha->value())); } - - #include "Menu_uniform_neighbors.moc" diff --git a/src/GudhUI/gui/Menu_uniform_neighbors.h b/src/GudhUI/gui/Menu_uniform_neighbors.h index cb90cc88..0b6f65fe 100644 --- a/src/GudhUI/gui/Menu_uniform_neighbors.h +++ b/src/GudhUI/gui/Menu_uniform_neighbors.h @@ -1,36 +1,51 @@ -/* - * Menu_uniform_neighbors.h +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Sep 11, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 MENU_UNIFORM_NEIGHBORS_H_ -#define MENU_UNIFORM_NEIGHBORS_H_ +#ifndef GUI_MENU_UNIFORM_NEIGHBORS_H_ +#define GUI_MENU_UNIFORM_NEIGHBORS_H_ #include <QMainWindow> #include "gui/ui_UniformNeighborsMenu.h" -class Menu_uniform_neighbors : public QDialog,public Ui::UniformMenu { - Q_OBJECT -private: - QMainWindow* parent; - -public: +class Menu_uniform_neighbors : public QDialog, public Ui::UniformMenu { + Q_OBJECT - Menu_uniform_neighbors(QMainWindow* parent_); + private: + QMainWindow* parent; - void connectActions(QMainWindow* parent); + public: + Menu_uniform_neighbors(QMainWindow* parent_); - public slots: - void send_compute_uniform_neighbors(); - void update_alpha(double); - void accept(); + void connectActions(QMainWindow* parent); - signals: - void compute_uniform_neighbors(double alpha); + public slots: + void send_compute_uniform_neighbors(); + void update_alpha(double alpha); + void accept(); + signals: + void compute_uniform_neighbors(double alpha); }; -#endif /* MENU_UNIFORM_NEIGHBORS_H_ */ +#endif // GUI_MENU_UNIFORM_NEIGHBORS_H_ diff --git a/src/GudhUI/gui/Viewer.cpp b/src/GudhUI/gui/Viewer.cpp deleted file mode 100644 index e69de29b..00000000 --- a/src/GudhUI/gui/Viewer.cpp +++ /dev/null diff --git a/src/GudhUI/gui/Viewer_instructor.cpp b/src/GudhUI/gui/Viewer_instructor.cpp deleted file mode 100644 index e69de29b..00000000 --- a/src/GudhUI/gui/Viewer_instructor.cpp +++ /dev/null diff --git a/src/GudhUI/gui/gudhui.cpp b/src/GudhUI/gui/gudhui.cpp index 8d90270f..377cd2f2 100644 --- a/src/GudhUI/gui/gudhui.cpp +++ b/src/GudhUI/gui/gudhui.cpp @@ -1,15 +1,36 @@ +/* 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): David Salinas
+ *
+ * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 "MainWindow.h"
#include <QApplication>
#include <CGAL/Qt/resources.h>
+int main(int argc, char** argv) {
+ QApplication application(argc, argv);
+ application.setOrganizationDomain("inria.fr");
+ application.setOrganizationName("INRIA");
+ application.setApplicationName("GudhUI");
-int main(int argc, char** argv)
-{
- QApplication application(argc,argv);
- application.setOrganizationDomain("inria.fr");
- application.setOrganizationName("INRIA");
- application.setApplicationName("GudhUI");
-
MainWindow mw;
application.setQuitOnLastWindowClosed(false);
mw.show();
diff --git a/src/GudhUI/model/Complex_typedefs.h b/src/GudhUI/model/Complex_typedefs.h index b6404d62..c310d4a6 100644 --- a/src/GudhUI/model/Complex_typedefs.h +++ b/src/GudhUI/model/Complex_typedefs.h @@ -1,39 +1,49 @@ -/* - * Complex_typedefs.h +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Aug 26, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 COMPLEX_TYPEDEFS_H_ -#define COMPLEX_TYPEDEFS_H_ - +#ifndef MODEL_COMPLEX_TYPEDEFS_H_ +#define MODEL_COMPLEX_TYPEDEFS_H_ - -#include "gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h" -#include "gudhi/Skeleton_blocker_geometric_complex.h" +#include <gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h> +#include <gudhi/Skeleton_blocker_geometric_complex.h> #include <CGAL/Kernel_d/Point_d.h> - #include <CGAL/Cartesian.h> #include <CGAL/Cartesian_d.h> - struct Geometry_trait : public CGAL::Cartesian_d<double> { - typedef CGAL::Cartesian<double>::Point_3 Point_3; - typedef CGAL::Cartesian<double>::Vector_3 Vector_3; - typedef CGAL::Point_d<Cartesian_d<double>> Point; - typedef CGAL::Vector_d<Cartesian_d<double>> Vector; + typedef CGAL::Cartesian<double>::Point_3 Point_3; + typedef CGAL::Cartesian<double>::Vector_3 Vector_3; + typedef CGAL::Point_d<Cartesian_d<double>> Point; + typedef CGAL::Vector_d<Cartesian_d<double>> Vector; }; typedef Geometry_trait::Point Point; - using namespace Gudhi; using namespace Gudhi::skbl; typedef Skeleton_blocker_simple_geometric_traits<Geometry_trait> Complex_geometric_traits; typedef Skeleton_blocker_geometric_complex< Complex_geometric_traits > Complex; - -#endif /* COMPLEX_TYPEDEFS_H_ */ +#endif // MODEL_COMPLEX_TYPEDEFS_H_ diff --git a/src/GudhUI/model/Model.h b/src/GudhUI/model/Model.h index 17a7d278..07a67a0c 100644 --- a/src/GudhUI/model/Model.h +++ b/src/GudhUI/model/Model.h @@ -1,16 +1,41 @@ -/* - * Model.h +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Aug 25, 2014 - * Author: david + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 MODEL_H_ -#define MODEL_H_ +#ifndef MODEL_MODEL_H_ +#define MODEL_MODEL_H_ + +#include <gudhi/Clock.h> +#include <gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h> +#include <gudhi/Skeleton_blocker_geometric_complex.h> +#include <gudhi/Off_reader.h> + +#include <CGAL/Euclidean_distance.h> #include <fstream> #include <limits> -#include "gudhi/Clock.h" +#include <string> +#include <vector> + #include "utils/UI_utils.h" #include "utils/Lloyd_builder.h" #include "utils/Rips_builder.h" @@ -22,328 +47,309 @@ #include "utils/Critical_points.h" #include "utils/Is_manifold.h" -#include "gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h" -#include "gudhi/Skeleton_blocker_geometric_complex.h" - -#include "gudhi/Off_reader.h" - #include "Complex_typedefs.h" - -#include <CGAL/Euclidean_distance.h> - - template<typename Complex> -class CGAL_geometric_flag_complex_wrapper{ - Complex& complex_; - typedef typename Complex::Vertex_handle Vertex_handle; - typedef typename Complex::Point Point; - - const bool load_only_points_; - -public: - CGAL_geometric_flag_complex_wrapper(Complex& complex,bool load_only_points = false): - complex_(complex), - load_only_points_(load_only_points){ - } - - void init(int dim,int num_vertices,int num_max_faces,int num_edges) const{ - } - - void point(const std::vector<double>& coords){ - Point p(coords.size(),coords.begin(),coords.end()); - complex_.add_vertex(p); - } - - void maximal_face(std::vector<int> vertices){ - if (!load_only_points_){ - std::cout<<"size:"<<vertices.size()<<std::endl; - for (int i = 0; i<vertices.size() ; ++i) - for (int j = i+1; j<vertices.size() ; ++j) - complex_.add_edge(Vertex_handle(vertices[i]),Vertex_handle(vertices[j])); - } - } - void done() const{} +class CGAL_geometric_flag_complex_wrapper { + Complex& complex_; + typedef typename Complex::Vertex_handle Vertex_handle; + typedef typename Complex::Point Point; + + const bool load_only_points_; + + public: + CGAL_geometric_flag_complex_wrapper(Complex& complex, bool load_only_points = false) : + complex_(complex), + load_only_points_(load_only_points) { } + + void init(int dim, int num_vertices, int num_max_faces, int num_edges) const { } + + void point(const std::vector<double>& coords) { + Point p(coords.size(), coords.begin(), coords.end()); + complex_.add_vertex(p); + } + + void maximal_face(std::vector<int> vertices) { + if (!load_only_points_) { + std::cout << "size:" << vertices.size() << std::endl; + for (int i = 0; i < vertices.size(); ++i) + for (int j = i + 1; j < vertices.size(); ++j) + complex_.add_edge(Vertex_handle(vertices[i]), Vertex_handle(vertices[j])); + } + } + + void done() const { } }; - -class Model{ - -public: - Complex complex_; - typedef Complex::Vertex_handle Vertex_handle; - - Model():complex_(){ - } - -public: - void off_file_open(const std::string& name_file){ - UIDBGMSG("load off file",name_file); - complex_.clear(); - CGAL_geometric_flag_complex_wrapper<Complex> read_wraper(complex_,false); - Gudhi::read_off(name_file,read_wraper); - } - - void off_points_open(const std::string& name_file){ - UIDBGMSG("load off points",name_file); - complex_.clear(); - CGAL_geometric_flag_complex_wrapper<Complex> read_wraper(complex_,true); - Gudhi::read_off(name_file,read_wraper); - } - - void off_file_save(const std::string& name_file){ - UIDBG("save off file"); - UIDBG("save off off_points_save"); - std::ofstream file(name_file); - if(file.is_open()){ - file<<"OFF\n"; - file<<complex_.num_vertices()<<" "<<complex_.num_edges()<<" 0\n"; - for(auto v : complex_.vertex_range()){ - const auto& pt(complex_.point(v)); - for(auto it = pt.cartesian_begin();it!=pt.cartesian_end();++it) - file<<*it<<" "; - file<<std::endl; - } - for(auto e : complex_.edge_range()) - file<<"2 "<<complex_.first_vertex(e)<<" "<<complex_.second_vertex(e)<<"\n"; - file.close(); - } - else std::cerr << "Could not open file "<<name_file<<std::endl; - - } - - void off_points_save(const std::string& name_file){ - UIDBG("save off off_points_save"); - std::ofstream file(name_file); - if(file.is_open()){ - file<<"OFF\n"; - file<<complex_.num_vertices()<<" 0 0\n"; - for(auto v : complex_.vertex_range()){ - const auto& pt(complex_.point(v)); - for(auto it = pt.cartesian_begin();it!=pt.cartesian_end();++it) - file<<*it<<" "; - file<<std::endl; - } - file.close(); - } - else std::cerr << "Could not open file "<<name_file<<std::endl; - - } - - // point sets operations - void uniform_noise(double amplitude){ - UIDBG("unif noise"); - for (auto v : complex_.vertex_range()) - complex_.point(v) = add_uniform_noise(complex_.point(v),amplitude); - } - -private: - Point add_uniform_noise(const Point& point,double amplitude){ - std::vector<double> new_point(point.dimension()); - for(int i = 0 ; i < point.dimension();++i){ - new_point[i] = point[i] + (rand() % 2 - .5) * amplitude; - } - return Point(point.dimension(), new_point.begin(),new_point.end()); - } - -public: - - void lloyd(int num_iterations,int num_closest_neighbors){ - UIDBG("lloyd"); - Lloyd_builder<Complex> lloyd_builder(complex_,1); - } - - double squared_eucl_distance(const Point& p1,const Point& p2) const{ - return Geometry_trait::Squared_distance_d()(p1,p2); - } - - // complex operations from points - void build_rips(double alpha){ - UIDBG("build_rips"); - Rips_builder<Complex> rips_builder(complex_,alpha); - } - - void build_k_nearest_neighbors(unsigned k){ - UIDBG("build_k_nearest"); - complex_.keep_only_vertices(); - K_nearest_builder<Complex> k_nearest_builder(complex_,k); - } - - void build_delaunay(){ - UIDBG("build_delaunay"); - complex_.keep_only_vertices(); - } - - - - void contract_edges(unsigned num_contractions){ - Clock c; - Edge_contractor<Complex> contractor(complex_,num_contractions); - std::cout<<"Time to simplify: "<<c.num_seconds()<<"s"<<std::endl; - } - - - void collapse_vertices(unsigned num_collapses){ - - auto old_num_vertices = complex_.num_vertices(); - Vertex_collapsor<Complex> collapsor(complex_,complex_.num_vertices()); - UIDBGMSG("num vertices collapsed:",old_num_vertices - complex_.num_vertices()); - } - - void collapse_edges(unsigned num_collapses){ - Edge_collapsor<Complex> collapsor(complex_,num_collapses); - } - - - void show_graph_stats(){ - std::cout << "++++++ Graph stats +++++++"<< std::endl; - std::cout << "Num vertices : " << complex_.num_vertices()<<std::endl; - std::cout << "Num edges : " << complex_.num_edges()<<std::endl; - std::cout << "Num connected components : " << complex_.num_connected_components()<<std::endl; - std::cout << "Min/avg/max degree : " << min_degree()<<"/"<<avg_degree()<<"/"<<max_degree()<<std::endl; - std::cout << "Num connected components : " << complex_.num_connected_components()<<std::endl; - std::cout << "Num connected components : " << complex_.num_connected_components()<<std::endl; - std::cout << "+++++++++++++++++++++++++"<< std::endl; - } - -private: - int min_degree() const{ - int res = (std::numeric_limits<int>::max)(); - for(auto v : complex_.vertex_range()) - res= (std::min)(res,complex_.degree(v)); - return res; - } - - int max_degree() const{ - int res = 0; - for(auto v : complex_.vertex_range()) - res= (std::max)(res,complex_.degree(v)); - return res; - } - - int avg_degree() const{ - int res = 0; - for(auto v : complex_.vertex_range()) - res+= complex_.degree(v); - return res / complex_.num_vertices(); - } - -public: - - - - void show_complex_stats(){ - std::cout << "++++++ Mesh stats +++++++"<< std::endl; - std::cout << "Num vertices : " << complex_.num_vertices()<<std::endl; - std::cout << "Num edges : " << complex_.num_edges()<<std::endl; - std::cout << "Num connected components : " << complex_.num_connected_components()<<std::endl; - std::cout << "+++++++++++++++++++++++++"<< std::endl; - - } - - void show_complex_dimension(){ - unsigned num_simplices = 0; - int euler = 0; - int dimension = 0; - Clock clock; - for(const auto &s : complex_.simplex_range()){ - num_simplices++; - dimension = (std::max)(s.dimension(),dimension); - if(s.dimension()%2==0) - euler+=1; - else - euler-=1; - } - clock.end(); - std::cout << "++++++ Mesh dimension +++++++"<< std::endl; - std::cout << "Dimension : " << dimension<<std::endl; - std::cout << "Euler characteristic : " << euler<<std::endl; - std::cout << "Num simplices : " << num_simplices <<std::endl; - std::cout << "Total time: " << clock <<std::endl; - std::cout << "Time per simplex: " << clock.num_seconds()/num_simplices <<" s"<<std::endl; - std::cout << "+++++++++++++++++++++++++"<< std::endl; - } - - - void show_homology_group(){ +class Model { + public: + Complex complex_; + typedef Complex::Vertex_handle Vertex_handle; + + Model() : complex_() { } + + public: + void off_file_open(const std::string& name_file) { + UIDBGMSG("load off file", name_file); + complex_.clear(); + CGAL_geometric_flag_complex_wrapper<Complex> read_wraper(complex_, false); + Gudhi::read_off(name_file, read_wraper); + } + + void off_points_open(const std::string& name_file) { + UIDBGMSG("load off points", name_file); + complex_.clear(); + CGAL_geometric_flag_complex_wrapper<Complex> read_wraper(complex_, true); + Gudhi::read_off(name_file, read_wraper); + } + + void off_file_save(const std::string& name_file) { + UIDBG("save off file"); + UIDBG("save off off_points_save"); + std::ofstream file(name_file); + if (file.is_open()) { + file << "OFF\n"; + file << complex_.num_vertices() << " " << complex_.num_edges() << " 0\n"; + for (auto v : complex_.vertex_range()) { + const auto& pt(complex_.point(v)); + for (auto it = pt.cartesian_begin(); it != pt.cartesian_end(); ++it) + file << *it << " "; + file << std::endl; + } + for (auto e : complex_.edge_range()) + file << "2 " << complex_.first_vertex(e) << " " << complex_.second_vertex(e) << "\n"; + file.close(); + } else { + std::cerr << "Could not open file " << name_file << std::endl; + } + } + + void off_points_save(const std::string& name_file) { + UIDBG("save off off_points_save"); + std::ofstream file(name_file); + if (file.is_open()) { + file << "OFF\n"; + file << complex_.num_vertices() << " 0 0\n"; + for (auto v : complex_.vertex_range()) { + const auto& pt(complex_.point(v)); + for (auto it = pt.cartesian_begin(); it != pt.cartesian_end(); ++it) + file << *it << " "; + file << std::endl; + } + file.close(); + } else { + std::cerr << "Could not open file " << name_file << std::endl; + } + } + + // point sets operations + void uniform_noise(double amplitude) { + UIDBG("unif noise"); + for (auto v : complex_.vertex_range()) + complex_.point(v) = add_uniform_noise(complex_.point(v), amplitude); + } + + private: + Point add_uniform_noise(const Point& point, double amplitude) { + std::vector<double> new_point(point.dimension()); + for (int i = 0; i < point.dimension(); ++i) { + new_point[i] = point[i] + (rand() % 2 - .5) * amplitude; + } + return Point(point.dimension(), new_point.begin(), new_point.end()); + } + + public: + void lloyd(int num_iterations, int num_closest_neighbors) { + UIDBG("lloyd"); + Lloyd_builder<Complex> lloyd_builder(complex_, 1); + } + + double squared_eucl_distance(const Point& p1, const Point& p2) const { + return Geometry_trait::Squared_distance_d()(p1, p2); + } + + // complex operations from points + + void build_rips(double alpha) { + UIDBG("build_rips"); + Rips_builder<Complex> rips_builder(complex_, alpha); + } + + void build_k_nearest_neighbors(unsigned k) { + UIDBG("build_k_nearest"); + complex_.keep_only_vertices(); + K_nearest_builder<Complex> k_nearest_builder(complex_, k); + } + + void build_delaunay() { + UIDBG("build_delaunay"); + complex_.keep_only_vertices(); + } + + void contract_edges(unsigned num_contractions) { + Clock c; + Edge_contractor<Complex> contractor(complex_, num_contractions); + std::cout << "Time to simplify: " << c.num_seconds() << "s" << std::endl; + } + + void collapse_vertices(unsigned num_collapses) { + auto old_num_vertices = complex_.num_vertices(); + Vertex_collapsor<Complex> collapsor(complex_, complex_.num_vertices()); + UIDBGMSG("num vertices collapsed:", old_num_vertices - complex_.num_vertices()); + } + + void collapse_edges(unsigned num_collapses) { + Edge_collapsor<Complex> collapsor(complex_, num_collapses); + } + + void show_graph_stats() { + std::cout << "++++++ Graph stats +++++++" << std::endl; + std::cout << "Num vertices : " << complex_.num_vertices() << std::endl; + std::cout << "Num edges : " << complex_.num_edges() << std::endl; + std::cout << "Num connected components : " << complex_.num_connected_components() << std::endl; + std::cout << "Min/avg/max degree : " << min_degree() << "/" << avg_degree() << "/" << max_degree() << std::endl; + std::cout << "Num connected components : " << complex_.num_connected_components() << std::endl; + std::cout << "Num connected components : " << complex_.num_connected_components() << std::endl; + std::cout << "+++++++++++++++++++++++++" << std::endl; + } + + private: + int min_degree() const { + int res = (std::numeric_limits<int>::max)(); + for (auto v : complex_.vertex_range()) + res = (std::min)(res, complex_.degree(v)); + return res; + } + + int max_degree() const { + int res = 0; + for (auto v : complex_.vertex_range()) + res = (std::max)(res, complex_.degree(v)); + return res; + } + + int avg_degree() const { + int res = 0; + for (auto v : complex_.vertex_range()) + res += complex_.degree(v); + return res / complex_.num_vertices(); + } + + public: + void show_complex_stats() { + std::cout << "++++++ Mesh stats +++++++" << std::endl; + std::cout << "Num vertices : " << complex_.num_vertices() << std::endl; + std::cout << "Num edges : " << complex_.num_edges() << std::endl; + std::cout << "Num connected components : " << complex_.num_connected_components() << std::endl; + std::cout << "+++++++++++++++++++++++++" << std::endl; + } + + void show_complex_dimension() { + unsigned num_simplices = 0; + int euler = 0; + int dimension = 0; + Clock clock; + for (const auto &s : complex_.complex_simplex_range()) { + num_simplices++; + dimension = (std::max)(s.dimension(), dimension); + if (s.dimension() % 2 == 0) + euler += 1; + else + euler -= 1; + } + clock.end(); + std::cout << "++++++ Mesh dimension +++++++" << std::endl; + std::cout << "Dimension : " << dimension << std::endl; + std::cout << "Euler characteristic : " << euler << std::endl; + std::cout << "Num simplices : " << num_simplices << std::endl; + std::cout << "Total time: " << clock << std::endl; + std::cout << "Time per simplex: " << clock.num_seconds() / num_simplices << " s" << std::endl; + std::cout << "+++++++++++++++++++++++++" << std::endl; + } + + void show_homology_group() { #ifdef _WIN32 - std::cout << "Works only on linux x64 for the moment\n"; + std::cout << "Works only on linux x64 for the moment\n"; #else - Clock clock; - run_chomp(); - clock.end(); + Clock clock; + run_chomp(); + clock.end(); #endif - } - - void show_euler_characteristic(){ - unsigned num_simplices = 0; - int euler = 0; - int dimension = 0; - for(const auto &s : complex_.simplex_range()){ - num_simplices++; - dimension = (std::max)(s.dimension(),dimension); - if(s.dimension()%2==0) - euler+=1; - else - euler-=1; - } - std::cout << "Saw "<<num_simplices<<" simplices with maximum dimension " << dimension<<std::endl; - std::cout << "The euler characteristic is : " << euler<<std::endl; - } - - void show_persistence( int p,double threshold,int max_dim,double min_pers){ - Persistence_compute<Complex> persistence(complex_,std::cout,Persistence_params(p,threshold,max_dim,min_pers)); - } - - void show_critical_points(double max_distance){ - Critical_points<Complex> critical_points(complex_,std::cout,max_distance); - } - - void show_is_manifold(){ - unsigned dim; - bool is_manifold; - Is_manifold<Complex> test_manifold(complex_,dim,is_manifold); - - if(is_manifold) std::cout << "The complex is a "<<dim<<"-manifold\n"; - else - if(dim<4) std::cout << "The complex has dimension greater than "<<dim<<" and is not a manifold\n"; - else std::cout << "The complex has dimension>=4 and may or may not be a manifold\n"; - } - - -private: - void run_chomp(){ - save_complex_in_file_for_chomp(); - std::cout << "Call CHOMP library\n"; - int returnValue = system("utils/homsimpl chomp.sim"); - std::cout << "CHOMP returns" << returnValue << std::endl; - } - - void save_complex_in_file_for_chomp(){ - std::ofstream file; - file.open("chomp.sim"); - for(const auto &s : complex_.simplex_range()){ - bool first = true; - file<<"("; - for(auto x : s){ - if(first) first = false; - else file<<","; - file << x; - } - file<<")\n"; - } - } -public: - - - unsigned num_vertices() const{ - return complex_.num_vertices(); - } - - unsigned num_edges() const{ - return complex_.num_edges(); - } - + } + + void show_euler_characteristic() { + unsigned num_simplices = 0; + int euler = 0; + int dimension = 0; + for (const auto &s : complex_.complex_simplex_range()) { + num_simplices++; + dimension = (std::max)(s.dimension(), dimension); + if (s.dimension() % 2 == 0) + euler += 1; + else + euler -= 1; + } + std::cout << "Saw " << num_simplices << " simplices with maximum dimension " << dimension << std::endl; + std::cout << "The euler characteristic is : " << euler << std::endl; + } + + void show_persistence(int p, double threshold, int max_dim, double min_pers) { + Persistence_compute<Complex> persistence(complex_, std::cout, Persistence_params(p, threshold, max_dim, min_pers)); + } + + void show_critical_points(double max_distance) { + Critical_points<Complex> critical_points(complex_, std::cout, max_distance); + } + + void show_is_manifold() { + unsigned dim; + bool is_manifold; + Is_manifold<Complex> test_manifold(complex_, dim, is_manifold); + + if (is_manifold) { + std::cout << "The complex is a " << dim << "-manifold\n"; + } else { + if (dim < 4) { + std::cout << "The complex has dimension greater than " << dim << " and is not a manifold\n"; + } else { + std::cout << "The complex has dimension>=4 and may or may not be a manifold\n"; + } + } + } + + private: + void run_chomp() { + save_complex_in_file_for_chomp(); + std::cout << "Call CHOMP library\n"; + int returnValue = system("utils/homsimpl chomp.sim"); + std::cout << "CHOMP returns" << returnValue << std::endl; + } + + void save_complex_in_file_for_chomp() { + std::ofstream file; + file.open("chomp.sim"); + for (const auto &s : complex_.complex_simplex_range()) { + bool first = true; + file << "("; + for (auto x : s) { + if (first) + first = false; + else + file << ","; + file << x; + } + file << ")\n"; + } + } + + public: + unsigned num_vertices() const { + return complex_.num_vertices(); + } + + unsigned num_edges() const { + return complex_.num_edges(); + } }; -#endif /* MODEL_H_ */ +#endif // MODEL_MODEL_H_ diff --git a/src/GudhUI/utils/Critical_points.h b/src/GudhUI/utils/Critical_points.h index 92392d4a..3021a5fe 100644 --- a/src/GudhUI/utils/Critical_points.h +++ b/src/GudhUI/utils/Critical_points.h @@ -1,13 +1,10 @@ -/* - * Critical_points.h - * Created on: Jan 27, 2015 - * This file is part of the Gudhi Library. The Gudhi library +/* 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): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (France) + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 @@ -24,11 +21,13 @@ * */ - -#ifndef CRITICAL_POINTS_H_ -#define CRITICAL_POINTS_H_ +#ifndef UTILS_CRITICAL_POINTS_H_ +#define UTILS_CRITICAL_POINTS_H_ #include <deque> +#include <utility> // for pair<> +#include <algorithm> // for sort + #include "utils/Edge_contractor.h" /** @@ -37,101 +36,97 @@ * * todo do a sparsification with some parameter eps while growing */ -template<typename SkBlComplex> class Critical_points{ -private: - SkBlComplex filled_complex_; - const SkBlComplex& input_complex_; - double max_length_; - std::ostream& stream_; -public: - typedef typename SkBlComplex::Vertex_handle Vertex_handle; - typedef typename SkBlComplex::Edge_handle Edge_handle; - typedef typename std::pair<Vertex_handle,Vertex_handle> Edge; - - /** - * @brief check all pair of points with length smaller than max_length - */ - Critical_points(const SkBlComplex& input_complex,std::ostream& stream,double max_length): - input_complex_(input_complex),max_length_(max_length),stream_(stream) - { - - std::deque<Edge> edges; - auto vertices = input_complex.vertex_range(); - for(auto p = vertices.begin(); p!= vertices.end(); ++p){ - filled_complex_.add_vertex(input_complex.point(*p)); - for (auto q = p; ++q != vertices.end(); /**/) - if (squared_eucl_distance(input_complex.point(*p),input_complex.point(*q)) < max_length_*max_length_) - edges.emplace_back(*p,*q); - } - - std::sort(edges.begin(),edges.end(), - [&](Edge e1,Edge e2){ - return squared_edge_length(e1) < squared_edge_length(e2); - }); - - anti_collapse_edges(edges); - - } - -private: - double squared_eucl_distance(const Point& p1,const Point& p2) const{ - return Geometry_trait::Squared_distance_d()(p1,p2); - } - - - void anti_collapse_edges(const std::deque<Edge>& edges){ - unsigned pos = 0; - for(Edge e : edges){ - std::cout<<"edge "<<pos++<<"/"<<edges.size()<<"\n"; - auto eh = filled_complex_.add_edge(e.first,e.second); - int is_contractible(is_link_reducible(eh)); - - switch (is_contractible) { - case 0: - stream_<<"alpha="<<std::sqrt(squared_edge_length(e))<< " topological change"<<std::endl; - break; - case 2: - stream_<<"alpha="<<std::sqrt(squared_edge_length(e))<< " maybe a topological change"<<std::endl; - break; - default: - break; - } - } - - } - - - //0 -> not - //1 -> yes - //2 -> maybe - int is_link_reducible(Edge_handle e){ - auto link = filled_complex_.link(e); - - if(link.empty()) return 0; - - Edge_contractor<Complex> contractor(link,link.num_vertices()-1); - - if(link.num_connected_components()>1) return 0; //one than more CC -> not contractible - - if (link.num_vertices()==1) return 1; //reduced to one point -> contractible - else return 2; //we dont know - } - - - double squared_edge_length(Edge_handle e) const{ - return squared_eucl_distance(input_complex_.point(input_complex_.first_vertex(e)),input_complex_.point(input_complex_.second_vertex(e))); - } - - double squared_edge_length(Edge e) const{ - return squared_eucl_distance(input_complex_.point(e.first),input_complex_.point(e.second)); - } - - - +template<typename SkBlComplex> class Critical_points { + private: + SkBlComplex filled_complex_; + const SkBlComplex& input_complex_; + double max_length_; + std::ostream& stream_; + + public: + typedef typename SkBlComplex::Vertex_handle Vertex_handle; + typedef typename SkBlComplex::Edge_handle Edge_handle; + typedef typename std::pair<Vertex_handle, Vertex_handle> Edge; + + /** + * @brief check all pair of points with length smaller than max_length + */ + Critical_points(const SkBlComplex& input_complex, std::ostream& stream, double max_length) : + input_complex_(input_complex), max_length_(max_length), stream_(stream) { + std::deque<Edge> edges; + auto vertices = input_complex.vertex_range(); + for (auto p = vertices.begin(); p != vertices.end(); ++p) { + filled_complex_.add_vertex(input_complex.point(*p)); + for (auto q = p; ++q != vertices.end(); /**/) + if (squared_eucl_distance(input_complex.point(*p), input_complex.point(*q)) < max_length_ * max_length_) + edges.emplace_back(*p, *q); + } + + std::sort(edges.begin(), edges.end(), + [&](Edge e1, Edge e2) { + return squared_edge_length(e1) < squared_edge_length(e2); + }); + + anti_collapse_edges(edges); + } + + private: + double squared_eucl_distance(const Point& p1, const Point& p2) const { + return Geometry_trait::Squared_distance_d()(p1, p2); + } + + void anti_collapse_edges(const std::deque<Edge>& edges) { + unsigned pos = 0; + for (Edge e : edges) { + std::cout << "edge " << pos++ << "/" << edges.size() << "\n"; + auto eh = filled_complex_.add_edge(e.first, e.second); + int is_contractible(is_link_reducible(eh)); + + switch (is_contractible) { + case 0: + stream_ << "alpha=" << std::sqrt(squared_edge_length(e)) << " topological change" << std::endl; + break; + case 2: + stream_ << "alpha=" << std::sqrt(squared_edge_length(e)) << " maybe a topological change" << std::endl; + break; + default: + break; + } + } + } + + // 0 -> not + // 1 -> yes + // 2 -> maybe + + int is_link_reducible(Edge_handle e) { + auto link = filled_complex_.link(e); + + if (link.empty()) + return 0; + + Edge_contractor<Complex> contractor(link, link.num_vertices() - 1); + + if (link.num_connected_components() > 1) + // one than more CC -> not contractible + return 0; + + if (link.num_vertices() == 1) + // reduced to one point -> contractible + return 1; + else + // we dont know + return 2; + } + + double squared_edge_length(Edge_handle e) const { + return squared_eucl_distance(input_complex_.point(input_complex_.first_vertex(e)), + input_complex_.point(input_complex_.second_vertex(e))); + } + + double squared_edge_length(Edge e) const { + return squared_eucl_distance(input_complex_.point(e.first), input_complex_.point(e.second)); + } }; - - - - -#endif /* CRITICAL_POINTS_H_ */ +#endif // UTILS_CRITICAL_POINTS_H_ diff --git a/src/GudhUI/utils/Edge_collapsor.h b/src/GudhUI/utils/Edge_collapsor.h index 4dcd18ac..151e9b01 100644 --- a/src/GudhUI/utils/Edge_collapsor.h +++ b/src/GudhUI/utils/Edge_collapsor.h @@ -1,12 +1,28 @@ -/* - * Collapsor.h +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Sep 25, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 COLLAPSOR_H_ -#define COLLAPSOR_H_ +#ifndef UTILS_EDGE_COLLAPSOR_H_ +#define UTILS_EDGE_COLLAPSOR_H_ #include <list> #include "utils/Edge_contractor.h" @@ -15,71 +31,67 @@ /** * Iteratively puts every vertex at the center of its neighbors */ -template<typename SkBlComplex> class Edge_collapsor{ -private: - SkBlComplex& complex_; - unsigned num_collapses_; -public: - typedef typename SkBlComplex::Vertex_handle Vertex_handle; - typedef typename SkBlComplex::Edge_handle Edge_handle; - - /** - * @brief Collapse num_collapses edges. If num_collapses<0 then it collapses all possible edges. - * Largest edges are collapsed first. - * - */ - Edge_collapsor(SkBlComplex& complex,unsigned num_collapses): - complex_(complex),num_collapses_(num_collapses) - { - std::list<Edge_handle> edges; - edges.insert(edges.begin(),complex_.edge_range().begin(),complex_.edge_range().end()); - - edges.sort( - [&](Edge_handle e1,Edge_handle e2){ - return squared_edge_length(e1) < squared_edge_length(e2); - }); - - collapse_edges(edges); - - } - -private: - - void collapse_edges(std::list<Edge_handle>& edges){ - while(!edges.empty() && num_collapses_--){ - Edge_handle current_edge = edges.front(); - edges.pop_front(); - if(is_link_reducible(current_edge)) - complex_.remove_edge(current_edge); - } - - } - - bool is_link_reducible(Edge_handle e){ - auto link = complex_.link(e); - - if(link.empty()) return false; - - if(link.is_cone()) return true; - - if(link.num_connected_components()>1) return false; - - Edge_contractor<SkBlComplex> contractor(link,link.num_vertices()-1); - - return (link.num_vertices()==1); - } - - - double squared_edge_length(Edge_handle e) const{ - return squared_eucl_distance(complex_.point(complex_.first_vertex(e)),complex_.point(complex_.second_vertex(e))); - } - - double squared_eucl_distance(const Point& p1,const Point& p2) const{ - return Geometry_trait::Squared_distance_d()(p1,p2); - } - +template<typename SkBlComplex> class Edge_collapsor { + private: + SkBlComplex& complex_; + unsigned num_collapses_; + + public: + typedef typename SkBlComplex::Vertex_handle Vertex_handle; + typedef typename SkBlComplex::Edge_handle Edge_handle; + + /** + * @brief Collapse num_collapses edges. If num_collapses<0 then it collapses all possible edges. + * Largest edges are collapsed first. + * + */ + Edge_collapsor(SkBlComplex& complex, unsigned num_collapses) : + complex_(complex), num_collapses_(num_collapses) { + std::list<Edge_handle> edges; + edges.insert(edges.begin(), complex_.edge_range().begin(), complex_.edge_range().end()); + + edges.sort( + [&](Edge_handle e1, Edge_handle e2) { + return squared_edge_length(e1) < squared_edge_length(e2); + }); + + collapse_edges(edges); + } + + private: + void collapse_edges(std::list<Edge_handle>& edges) { + while (!edges.empty() && num_collapses_--) { + Edge_handle current_edge = edges.front(); + edges.pop_front(); + if (is_link_reducible(current_edge)) + complex_.remove_edge(current_edge); + } + } + + bool is_link_reducible(Edge_handle e) { + auto link = complex_.link(e); + + if (link.empty()) + return false; + + if (link.is_cone()) + return true; + + if (link.num_connected_components() > 1) + return false; + + Edge_contractor<SkBlComplex> contractor(link, link.num_vertices() - 1); + + return (link.num_vertices() == 1); + } + + double squared_edge_length(Edge_handle e) const { + return squared_eucl_distance(complex_.point(complex_.first_vertex(e)), complex_.point(complex_.second_vertex(e))); + } + + double squared_eucl_distance(const Point& p1, const Point& p2) const { + return Geometry_trait::Squared_distance_d()(p1, p2); + } }; - - -#endif /* COLLAPSOR_H_ */ +#endif // UTILS_EDGE_COLLAPSOR_H_ diff --git a/src/GudhUI/utils/Edge_contractor.h b/src/GudhUI/utils/Edge_contractor.h index d0a1f866..45079a40 100644 --- a/src/GudhUI/utils/Edge_contractor.h +++ b/src/GudhUI/utils/Edge_contractor.h @@ -1,85 +1,97 @@ -/* - * Contractor.h +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Sep 25, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 EDGE_CONTRACTOR_H_ -#define EDGE_CONTRACTOR_H_ +#ifndef UTILS_EDGE_CONTRACTOR_H_ +#define UTILS_EDGE_CONTRACTOR_H_ -#include "gudhi/Skeleton_blocker_contractor.h" - -#include "gudhi/Contraction/Edge_profile.h" -#include "gudhi/Contraction/policies/Cost_policy.h" +#include <gudhi/Skeleton_blocker_contractor.h> +#include <gudhi/Contraction/Edge_profile.h> +#include <gudhi/Contraction/policies/Cost_policy.h> +#include <vector> /** * Iteratively puts every vertex at the center of its neighbors */ -template<typename SkBlComplex> class Edge_contractor{ -private: - SkBlComplex& complex_; - unsigned num_contractions_; - - /** - * @brief return a cost corresponding to the squared length of the edge - */ - template< typename EdgeProfile> class Length_cost : public contraction::Cost_policy<EdgeProfile>{ - public: - typedef typename contraction::Cost_policy<EdgeProfile>::Cost_type Cost_type; - typedef typename EdgeProfile::Point Point; - Cost_type operator()(const EdgeProfile& profile, const boost::optional<Point>& placement) const override{ - Cost_type res; - if(!placement) return res; - return Geometry_trait::Squared_distance_d()(profile.p0(),profile.p1()); //not working?? - } - }; - - - /** - * @brief return a cost corresponding to the squared length of the edge - */ - template< typename EdgeProfile> class Middle_placement : public contraction::Placement_policy<EdgeProfile>{ - public: - typedef typename contraction::Placement_policy<EdgeProfile>::Placement_type Placement_type; - typedef typename EdgeProfile::Point Point; - Placement_type operator()(const EdgeProfile& profile) const override{ - std::vector<double> mid_coords(profile.p0().dimension(),0); - for (size_t i = 0; i < profile.p0().dimension(); ++i){ - mid_coords[i] = (profile.p0()[i] + profile.p1()[i]) / 2.; - } - return Point(profile.p0().dimension(),mid_coords.begin(), mid_coords.end()); - } - }; - - public: - typedef typename SkBlComplex::Vertex_handle Vertex_handle; - typedef typename SkBlComplex::Edge_handle Edge_handle; - - /** - * @brief Modify complex to be the expansion of the k-nearest neighbor - * symetric graph. - */ - Edge_contractor(SkBlComplex& complex,unsigned num_contractions): - complex_(complex),num_contractions_(num_contractions) - { - typedef typename contraction::Edge_profile<Complex> Profile; - num_contractions = (std::min)((int)num_contractions,(int)(complex_.num_vertices()-1)); - contraction::Skeleton_blocker_contractor<Complex> contractor( - complex_, - new Length_cost<contraction::Edge_profile<Complex>>(), - new Middle_placement<contraction::Edge_profile<Complex>>(), - contraction::make_link_valid_contraction<Profile>(), - contraction::make_remove_popable_blockers_visitor<Profile>() - ); - contractor.contract_edges(num_contractions); - } - - +template<typename SkBlComplex> class Edge_contractor { + private: + SkBlComplex& complex_; + unsigned num_contractions_; + + /** + * @brief return a cost corresponding to the squared length of the edge + */ + template< typename EdgeProfile> class Length_cost : public contraction::Cost_policy<EdgeProfile> { + public: + typedef typename contraction::Cost_policy<EdgeProfile>::Cost_type Cost_type; + typedef typename EdgeProfile::Point Point; + + Cost_type operator()(const EdgeProfile& profile, const boost::optional<Point>& placement) const override { + Cost_type res; + if (!placement) + return res; + return Geometry_trait::Squared_distance_d()(profile.p0(), profile.p1()); // not working?? + } + }; + + /** + * @brief return a cost corresponding to the squared length of the edge + */ + template< typename EdgeProfile> class Middle_placement : public contraction::Placement_policy<EdgeProfile> { + public: + typedef typename contraction::Placement_policy<EdgeProfile>::Placement_type Placement_type; + typedef typename EdgeProfile::Point Point; + + Placement_type operator()(const EdgeProfile& profile) const override { + std::vector<double> mid_coords(profile.p0().dimension(), 0); + for (size_t i = 0; i < profile.p0().dimension(); ++i) { + mid_coords[i] = (profile.p0()[i] + profile.p1()[i]) / 2.; + } + return Point(profile.p0().dimension(), mid_coords.begin(), mid_coords.end()); + } + }; + + public: + typedef typename SkBlComplex::Vertex_handle Vertex_handle; + typedef typename SkBlComplex::Edge_handle Edge_handle; + + /** + * @brief Modify complex to be the expansion of the k-nearest neighbor + * symetric graph. + */ + Edge_contractor(SkBlComplex& complex, unsigned num_contractions) : + complex_(complex), num_contractions_(num_contractions) { + typedef typename contraction::Edge_profile<Complex> Profile; + num_contractions = (std::min)(static_cast<int>(num_contractions), static_cast<int>(complex_.num_vertices() - 1)); + typedef typename contraction::Skeleton_blocker_contractor<Complex> Contractor; + Contractor contractor(complex_, + new Length_cost<contraction::Edge_profile < Complex >> (), + new Middle_placement<contraction::Edge_profile < Complex >> (), + contraction::make_link_valid_contraction<Profile>(), + contraction::make_remove_popable_blockers_visitor<Profile>()); + contractor.contract_edges(num_contractions); + } }; - - -#endif /* EDGE_CONTRACTOR_H_ */ +#endif // UTILS_EDGE_CONTRACTOR_H_ diff --git a/src/GudhUI/utils/Furthest_point_epsilon_net.h b/src/GudhUI/utils/Furthest_point_epsilon_net.h index 590b65c4..f2a216f6 100644 --- a/src/GudhUI/utils/Furthest_point_epsilon_net.h +++ b/src/GudhUI/utils/Furthest_point_epsilon_net.h @@ -1,134 +1,132 @@ -/* - * Furthest_point_epsilon_net.h +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Sep 26, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 FURTHEST_POINT_EPSILON_NET_H_ -#define FURTHEST_POINT_EPSILON_NET_H_ +#ifndef UTILS_FURTHEST_POINT_EPSILON_NET_H_ +#define UTILS_FURTHEST_POINT_EPSILON_NET_H_ -#include "utils/UI_utils.h" #include <vector> +#include <algorithm> // for sort + +#include "utils/UI_utils.h" /** * Computes an epsilon net with furthest point strategy. */ -template<typename SkBlComplex> class Furthest_point_epsilon_net{ -private: - SkBlComplex& complex_; - typedef typename SkBlComplex::Vertex_handle Vertex_handle; - typedef typename SkBlComplex::Edge_handle Edge_handle; - - /** - * Let V be the set of vertices. - * Initially v0 is one arbitrarly vertex and the set V0 is {v0}. - * Then Vk is computed as follows. - * First we compute the vertex pk that is the furthest from Vk - * then Vk = Vk \cup pk. - * The radius of pk is its distance to Vk and its meeting vertex - * is the vertex of Vk for which this distance is achieved. - */ - struct Net_filtration_vertex{ - Vertex_handle vertex_handle; - Vertex_handle meeting_vertex; - double radius; - - - Net_filtration_vertex( - Vertex_handle vertex_handle_, - Vertex_handle meeting_vertex_, - double radius_): - vertex_handle(vertex_handle_),meeting_vertex(meeting_vertex_),radius(radius_) - {} - - bool operator<(const Net_filtration_vertex& other ) const{ - return radius < other.radius; - } - - }; - -public: - - - std::vector<Net_filtration_vertex> net_filtration_; - - /** - * @brief Modify complex to be the expansion of the k-nearest neighbor - * symetric graph. - */ - Furthest_point_epsilon_net(SkBlComplex& complex): - complex_(complex) - { - if(!complex.empty()){ - init_filtration(); - for(int k = 2; k < net_filtration_.size(); ++k){ - update_radius_value(k); - } - } - } - - //xxx does not work if complex not full - double radius(Vertex_handle v){ - return net_filtration_[v.vertex].radius; - } - - - - -private: - - void init_filtration(){ - Vertex_handle v0 = *(complex_.vertex_range().begin()); - net_filtration_.reserve(complex_.num_vertices()); - for(auto v : complex_.vertex_range()){ - if(v != v0) - net_filtration_.push_back( - Net_filtration_vertex(v, - Vertex_handle(-1), - squared_eucl_distance(v,v0)) - ); - } - net_filtration_.push_back(Net_filtration_vertex(v0,Vertex_handle(-1),1e10)); - auto n = net_filtration_.size(); - sort_filtration(n-1); - } - - void update_radius_value(int k){ - int n = net_filtration_.size(); - int index_to_update = n-k; - for(int i = 0; i< index_to_update; ++i){ - net_filtration_[i].radius = (std::min)(net_filtration_[i].radius , - squared_eucl_distance( - net_filtration_[i].vertex_handle, - net_filtration_[index_to_update].vertex_handle - ) - ); - } - sort_filtration(n-k); - } - - /** - * sort all i first elements. - */ - void sort_filtration(int i){ - std::sort(net_filtration_.begin(),net_filtration_.begin()+ i); - } - - double squared_eucl_distance(Vertex_handle v1,Vertex_handle v2) const{ - return std::sqrt(Geometry_trait::Squared_distance_d()( - complex_.point(v1),complex_.point(v2)) - ); - } - - void print_filtration() const{ - for(auto v : net_filtration_){ - std::cerr <<"v="<<v.vertex_handle<<"-> d="<<v.radius<<std::endl; - } - } - +template<typename SkBlComplex> class Furthest_point_epsilon_net { + private: + SkBlComplex& complex_; + typedef typename SkBlComplex::Vertex_handle Vertex_handle; + typedef typename SkBlComplex::Edge_handle Edge_handle; + + /** + * Let V be the set of vertices. + * Initially v0 is one arbitrarly vertex and the set V0 is {v0}. + * Then Vk is computed as follows. + * First we compute the vertex pk that is the furthest from Vk + * then Vk = Vk \cup pk. + * The radius of pk is its distance to Vk and its meeting vertex + * is the vertex of Vk for which this distance is achieved. + */ + struct Net_filtration_vertex { + Vertex_handle vertex_handle; + Vertex_handle meeting_vertex; + double radius; + + Net_filtration_vertex(Vertex_handle vertex_handle_, + Vertex_handle meeting_vertex_, + double radius_) : + vertex_handle(vertex_handle_), meeting_vertex(meeting_vertex_), radius(radius_) { } + + bool operator<(const Net_filtration_vertex& other) const { + return radius < other.radius; + } + }; + + public: + std::vector<Net_filtration_vertex> net_filtration_; + + /** + * @brief Modify complex to be the expansion of the k-nearest neighbor + * symetric graph. + */ + Furthest_point_epsilon_net(SkBlComplex& complex) : + complex_(complex) { + if (!complex.empty()) { + init_filtration(); + for (int k = 2; k < net_filtration_.size(); ++k) { + update_radius_value(k); + } + } + } + + // xxx does not work if complex not full + + double radius(Vertex_handle v) { + return net_filtration_[v.vertex].radius; + } + + private: + void init_filtration() { + Vertex_handle v0 = *(complex_.vertex_range().begin()); + net_filtration_.reserve(complex_.num_vertices()); + for (auto v : complex_.vertex_range()) { + if (v != v0) + net_filtration_.push_back(Net_filtration_vertex(v, + Vertex_handle(-1), + squared_eucl_distance(v, v0))); + } + net_filtration_.push_back(Net_filtration_vertex(v0, Vertex_handle(-1), 1e10)); + auto n = net_filtration_.size(); + sort_filtration(n - 1); + } + + void update_radius_value(int k) { + int n = net_filtration_.size(); + int index_to_update = n - k; + for (int i = 0; i < index_to_update; ++i) { + net_filtration_[i].radius = (std::min)(net_filtration_[i].radius, + squared_eucl_distance(net_filtration_[i].vertex_handle, + net_filtration_[index_to_update].vertex_handle)); + } + sort_filtration(n - k); + } + + /** + * sort all i first elements. + */ + void sort_filtration(int i) { + std::sort(net_filtration_.begin(), net_filtration_.begin() + i); + } + + double squared_eucl_distance(Vertex_handle v1, Vertex_handle v2) const { + return std::sqrt(Geometry_trait::Squared_distance_d()(complex_.point(v1), complex_.point(v2))); + } + + void print_filtration() const { + for (auto v : net_filtration_) { + std::cerr << "v=" << v.vertex_handle << "-> d=" << v.radius << std::endl; + } + } }; - - -#endif /* FURTHEST_POINT_EPSILON_NET_H_ */ +#endif // UTILS_FURTHEST_POINT_EPSILON_NET_H_ diff --git a/src/GudhUI/utils/Is_manifold.h b/src/GudhUI/utils/Is_manifold.h index e708a6a4..0640ea47 100644 --- a/src/GudhUI/utils/Is_manifold.h +++ b/src/GudhUI/utils/Is_manifold.h @@ -7,7 +7,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (France) + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 @@ -25,11 +25,10 @@ */ -#ifndef IS_MANIFOLD_H_ -#define IS_MANIFOLD_H_ +#ifndef UTILS_IS_MANIFOLD_H_ +#define UTILS_IS_MANIFOLD_H_ #include "utils/UI_utils.h" - #include "utils/Edge_contractor.h" /** @@ -38,67 +37,67 @@ * * todo do a sparsification with some parameter eps while growing */ -template<typename SkBlComplex> class Is_manifold{ -private: - const SkBlComplex& input_complex_; - typedef typename SkBlComplex::Vertex_handle Vertex_handle; +template<typename SkBlComplex> class Is_manifold { + private: + const SkBlComplex& input_complex_; + typedef typename SkBlComplex::Vertex_handle Vertex_handle; + public: + /* + * return dim the maximum dimension around one simplex and res which is true if the complex is a manifold. + * If the complex has dimension <= 3 then if res is false, the complex is not a manifold. + * For d-manifold with d>=4, res may be false while the complex is a manifold. + */ + Is_manifold(const SkBlComplex& input_complex, unsigned& dim, bool & res) : input_complex_(input_complex) { + res = true; + dim = -1; + if (!input_complex_.empty()) { + for (auto v : input_complex_.vertex_range()) { + dim = local_dimension(v); + break; + } + // check that the link of every vertex is a dim-1 sphere + for (auto v : input_complex_.vertex_range()) { + if (!is_k_sphere(v, dim - 1)) { + res = false; + break; + } + } + } + } -public: - /* - * return dim the maximum dimension around one simplex and res which is true if the complex is a manifold. - * If the complex has dimension <= 3 then if res is false, the complex is not a manifold. - * For d-manifold with d>=4, res may be false while the complex is a manifold. - */ - Is_manifold(const SkBlComplex& input_complex,unsigned& dim,bool & res):input_complex_(input_complex){ - res = true; - dim = -1; - if(!input_complex_.empty()){ - for(auto v : input_complex_.vertex_range()){ - dim = local_dimension(v); - break; - } - //check that the link of every vertex is a dim-1 sphere - for(auto v : input_complex_.vertex_range()){ - if(!is_k_sphere(v,dim-1)) { - res = false; - break; - } - } - } - } + private: + unsigned local_dimension(Vertex_handle v) { + unsigned dim = 0; + for (const auto& s : input_complex_.star_simplex_range(v)) + dim = (std::max)(dim, (unsigned) s.dimension()); + return dim; + } -private: - unsigned local_dimension(Vertex_handle v){ - unsigned dim = 0; - for(const auto& s: input_complex_.simplex_range(v)) - dim = (std::max)(dim,(unsigned)s.dimension()); - return dim; - } + bool is_k_sphere(Vertex_handle v, int k) { + auto link = input_complex_.link(v); + Edge_contractor<Complex> contractor(link, link.num_vertices() - 1); + return (is_sphere_simplex(link) == k); + } - bool is_k_sphere(Vertex_handle v,int k){ - auto link = input_complex_.link(v); - Edge_contractor<Complex> contractor(link,link.num_vertices()-1); - return (is_sphere_simplex(link)==k); - } + // A minimal sphere is a complex that contains vertices v1...vn and all faces + // made upon this set except the face {v1,...,vn} + // return -2 if not a minimal sphere + // and d otherwise if complex is a d minimal sphere - // A minimal sphere is a complex that contains vertices v1...vn and all faces - // made upon this set except the face {v1,...,vn} - // return -2 if not a minimal sphere - // and d otherwise if complex is a d minimal sphere - template<typename SubComplex> - int is_sphere_simplex(const SubComplex& complex){ - if(complex.empty()) return -1; - if(complex.num_blockers()!=1) return -2; + template<typename SubComplex> + int is_sphere_simplex(const SubComplex& complex) { + if (complex.empty()) return -1; + if (complex.num_blockers() != 1) return -2; - //necessary and sufficient condition : there exists a unique blocker that passes through all vertices - auto first_blocker = *(complex.const_blocker_range().begin()); + // necessary and sufficient condition : there exists a unique blocker that passes through all vertices + auto first_blocker = *(complex.const_blocker_range().begin()); - if (first_blocker->dimension()+1 != complex.num_vertices()) - return -2; - else - return (first_blocker->dimension()-1); - } + if (first_blocker->dimension() + 1 != complex.num_vertices()) + return -2; + else + return (first_blocker->dimension() - 1); + } }; -#endif /* IS_MANIFOLD_H_ */ +#endif // UTILS_IS_MANIFOLD_H_ diff --git a/src/GudhUI/utils/K_nearest_builder.h b/src/GudhUI/utils/K_nearest_builder.h index b65a79e0..cab24b7c 100644 --- a/src/GudhUI/utils/K_nearest_builder.h +++ b/src/GudhUI/utils/K_nearest_builder.h @@ -1,81 +1,92 @@ -/* - * K_nearest_builder.h +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Sep 10, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 K_NEAREST_BUILDER_H_ -#define K_NEAREST_BUILDER_H_ +#ifndef UTILS_K_NEAREST_BUILDER_H_ +#define UTILS_K_NEAREST_BUILDER_H_ -#include <unordered_map> -#include <boost/iterator/iterator_facade.hpp> #include <CGAL/Euclidean_distance.h> #include <CGAL/Orthogonal_k_neighbor_search.h> #include <CGAL/Search_traits_d.h> #include <CGAL/Search_traits_adapter.h> -#include <CGAL/property_map.h>
+#include <CGAL/property_map.h> +#include <boost/iterator/iterator_facade.hpp> #include <boost/iterator/zip_iterator.hpp> +#include <unordered_map> +#include <tuple> +#include <list> + #include "utils/UI_utils.h" #include "model/Complex_typedefs.h" - - -template<typename SkBlComplex> class K_nearest_builder{ -private: - - typedef Geometry_trait Kernel; - typedef Point Point_d;
- typedef boost::tuple<Point_d, unsigned> Point_d_with_id;
- typedef CGAL::Search_traits_d<Kernel> Traits_base;
- typedef CGAL::Search_traits_adapter<Point_d_with_id, CGAL::Nth_of_tuple_property_map<0, Point_d_with_id>, Traits_base> Traits;
- typedef CGAL::Orthogonal_k_neighbor_search<Traits> Neighbor_search;
- typedef Neighbor_search::Tree Tree;
- typedef Neighbor_search::Distance Distance;
- - SkBlComplex& complex_; -public: - - /** - * @brief Modify complex to be the expansion of the k-nearest neighbor - * symetric graph. - */ - K_nearest_builder(SkBlComplex& complex,unsigned k):complex_(complex){ - complex.keep_only_vertices(); - compute_edges(k); - } - -private: - - - - double squared_eucl_distance(const Point& p1,const Point& p2) const{ - return Geometry_trait::Squared_distance_d()(p1,p2); - } - - void compute_edges(unsigned k){ - - std::list<Point_d_with_id> points_with_id; - for(auto v: complex_.vertex_range()){ - Point_d_with_id point_v(complex_.point(v),v.vertex); - points_with_id.push_back(point_v); - } - - Tree tree(points_with_id.begin(),points_with_id.end()); - - typedef typename SkBlComplex::Vertex_handle Vertex_handle; - for (auto p : complex_.vertex_range()){ - Neighbor_search search(tree, complex_.point(p),k+1); - for(auto it = ++search.begin(); it != search.end(); ++it){ - Vertex_handle q(boost::get<1>(it->first)); - if (p != q && complex_.contains_vertex(p) && complex_.contains_vertex(q)) - complex_.add_edge(p,q); - } - } - } - - +template<typename SkBlComplex> class K_nearest_builder { + private: + typedef Geometry_trait Kernel; + typedef Point Point_d; + typedef boost::tuple<Point_d, unsigned> Point_d_with_id; + typedef CGAL::Search_traits_d<Kernel> Traits_base; + typedef CGAL::Search_traits_adapter<Point_d_with_id, CGAL::Nth_of_tuple_property_map<0, Point_d_with_id>, + Traits_base> Traits; + typedef CGAL::Orthogonal_k_neighbor_search<Traits> Neighbor_search; + typedef Neighbor_search::Tree Tree; + typedef Neighbor_search::Distance Distance; + + SkBlComplex& complex_; + + public: + /** + * @brief Modify complex to be the expansion of the k-nearest neighbor + * symetric graph. + */ + K_nearest_builder(SkBlComplex& complex, unsigned k) : complex_(complex) { + complex.keep_only_vertices(); + compute_edges(k); + } + + private: + double squared_eucl_distance(const Point& p1, const Point& p2) const { + return Geometry_trait::Squared_distance_d()(p1, p2); + } + + void compute_edges(unsigned k) { + std::list<Point_d_with_id> points_with_id; + for (auto v : complex_.vertex_range()) { + Point_d_with_id point_v(complex_.point(v), v.vertex); + points_with_id.push_back(point_v); + } + + Tree tree(points_with_id.begin(), points_with_id.end()); + + typedef typename SkBlComplex::Vertex_handle Vertex_handle; + for (auto p : complex_.vertex_range()) { + Neighbor_search search(tree, complex_.point(p), k + 1); + for (auto it = ++search.begin(); it != search.end(); ++it) { + Vertex_handle q(boost::get<1>(it->first)); + if (p != q && complex_.contains_vertex(p) && complex_.contains_vertex(q)) + complex_.add_edge(p, q); + } + } + } }; -#endif /* K_NEAREST_BUILDER_H_ */ +#endif // UTILS_K_NEAREST_BUILDER_H_ diff --git a/src/GudhUI/utils/Lloyd_builder.h b/src/GudhUI/utils/Lloyd_builder.h index db2a7973..18ec9fac 100644 --- a/src/GudhUI/utils/Lloyd_builder.h +++ b/src/GudhUI/utils/Lloyd_builder.h @@ -1,78 +1,91 @@ -/* - * Lloyd.h +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Sep 25, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 LLOYD_H_ -#define LLOYD_H_ - +#ifndef UTILS_LLOYD_BUILDER_H_ +#define UTILS_LLOYD_BUILDER_H_ #include <vector> +#include <list> /** * Iteratively puts every vertex at the center of its neighbors */ -template<typename SkBlComplex> class Lloyd_builder{ -private: - SkBlComplex& complex_; - int dim; -public: - typedef typename SkBlComplex::Vertex_handle Vertex_handle; - /** - * @brief Modify complex to be the expansion of the k-nearest neighbor - * symetric graph. - */ - Lloyd_builder(SkBlComplex& complex,unsigned num_iterations):complex_(complex),dim(-1){ - if(!complex_.empty()){ - dim = get_dimension(); - while(num_iterations--){ - std::list<Point> new_points; - for(auto v : complex.vertex_range()) - new_points.push_back(barycenter_neighbors(v)); - - auto new_points_it = new_points.begin(); - for(auto v : complex.vertex_range()) - complex_.point(v) = *(new_points_it++); - } - } - } +template<typename SkBlComplex> class Lloyd_builder { + private: + SkBlComplex& complex_; + int dim; -private: + public: + typedef typename SkBlComplex::Vertex_handle Vertex_handle; - int get_dimension(){ - assert(!complex_.empty()); - for(auto v : complex_.vertex_range()) - return complex_.point(v).dimension(); - return -1; - } + /** + * @brief Modify complex to be the expansion of the k-nearest neighbor + * symetric graph. + */ + Lloyd_builder(SkBlComplex& complex, unsigned num_iterations) : complex_(complex), dim(-1) { + if (!complex_.empty()) { + dim = get_dimension(); + while (num_iterations--) { + std::list<Point> new_points; + for (auto v : complex.vertex_range()) + new_points.push_back(barycenter_neighbors(v)); - Point barycenter_neighbors(Vertex_handle v) const{ - if(complex_.degree(v)==0) - return complex_.point(v); + auto new_points_it = new_points.begin(); + for (auto v : complex.vertex_range()) + complex_.point(v) = *(new_points_it++); + } + } + } - std::vector<double> res(dim,0); - unsigned num_points = 0; - for(auto nv : complex_.vertex_range(v)){ - ++num_points; - const Point& point = complex_.point(nv); - assert(point.dimension() == dim); - for(int i = 0; i < point.dimension() ; ++i) - res[i] += point[i]; - } - for(auto& x : res) - x/= num_points; - return Point(dim,res.begin(),res.end()); - } + private: + int get_dimension() { + assert(!complex_.empty()); + for (auto v : complex_.vertex_range()) + return complex_.point(v).dimension(); + return -1; + } + Point barycenter_neighbors(Vertex_handle v) const { + if (complex_.degree(v) == 0) + return complex_.point(v); + std::vector<double> res(dim, 0); + unsigned num_points = 0; + for (auto nv : complex_.vertex_range(v)) { + ++num_points; + const Point& point = complex_.point(nv); + assert(point.dimension() == dim); + for (int i = 0; i < point.dimension(); ++i) + res[i] += point[i]; + } + for (auto& x : res) + x /= num_points; + return Point(dim, res.begin(), res.end()); + } - double squared_eucl_distance(const Point& p1,const Point& p2) const{ - return Geometry_trait::Squared_distance_d()(p1,p2); - } - + double squared_eucl_distance(const Point& p1, const Point& p2) const { + return Geometry_trait::Squared_distance_d()(p1, p2); + } }; - -#endif /* LLOYD_H_ */ +#endif // UTILS_LLOYD_BUILDER_H_ diff --git a/src/GudhUI/utils/MClock.h b/src/GudhUI/utils/MClock.h index b5c7d191..e8d8918a 100644 --- a/src/GudhUI/utils/MClock.h +++ b/src/GudhUI/utils/MClock.h @@ -1,57 +1,70 @@ -/* - * Clock.h +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Jun 17, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 CLOCK_H_ -#define CLOCK_H_ +#ifndef UTILS_MCLOCK_H_ +#define UTILS_MCLOCK_H_ #include <sys/time.h> +class MClock { + public: + MClock() { + end_called = false; + begin(); + } -class MClock{ - -public: - MClock(){ - end_called = false; - begin(); - } - - void begin() const{ - end_called = false; - gettimeofday(&startTime, NULL); - } - - void end() const{ - end_called = true; - gettimeofday(&endTime, NULL); - } - - friend std::ostream& operator<< (std::ostream& stream,const MClock& clock){ - // if(!clock.end_called) clock.end(); - if(!clock.end_called) stream << "end not called"; - else{ - long totalTime = (clock.endTime.tv_sec - clock.startTime.tv_sec) * 1000000L; - totalTime += (clock.endTime.tv_usec - clock.startTime.tv_usec); - stream << clock.num_seconds() <<"s"; - } - return stream; - - } - - double num_seconds() const{ - if(!end_called) end(); - long totalTime = (endTime.tv_sec - startTime.tv_sec) * 1000000L; - totalTime += (endTime.tv_usec - startTime.tv_usec); - return (totalTime / 1000L)/(double) 1000; - } - -private: - mutable struct timeval startTime, endTime; - mutable bool end_called; -}; + void begin() const { + end_called = false; + gettimeofday(&startTime, NULL); + } + void end() const { + end_called = true; + gettimeofday(&endTime, NULL); + } + + friend std::ostream& operator<<(std::ostream& stream, const MClock& clock) { + // if(!clock.end_called) clock.end(); + if (!clock.end_called) { + stream << "end not called"; + } else { + long totalTime = (clock.endTime.tv_sec - clock.startTime.tv_sec) * 1000000L; + totalTime += (clock.endTime.tv_usec - clock.startTime.tv_usec); + stream << clock.num_seconds() << "s"; + } + return stream; + } + + double num_seconds() const { + if (!end_called) end(); + long totalTime = (endTime.tv_sec - startTime.tv_sec) * 1000000L; + totalTime += (endTime.tv_usec - startTime.tv_usec); + return (totalTime / 1000L) / static_cast<double>(1000); + } + + private: + mutable struct timeval startTime, endTime; + mutable bool end_called; +}; -#endif /* CLOCK_H_ */ +#endif // UTILS_MCLOCK_H_ diff --git a/src/GudhUI/utils/Persistence_compute.h b/src/GudhUI/utils/Persistence_compute.h index 50d340b8..0b9961d3 100644 --- a/src/GudhUI/utils/Persistence_compute.h +++ b/src/GudhUI/utils/Persistence_compute.h @@ -1,13 +1,10 @@ -/* - * Persistence_compute.h - * Created on: Jan 26, 2015 - * This file is part of the Gudhi Library. The Gudhi library +/* 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): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (France) + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 @@ -25,83 +22,76 @@ */ -#ifndef PERSISTENCE_COMPUTE_H_ -#define PERSISTENCE_COMPUTE_H_ +#ifndef UTILS_PERSISTENCE_COMPUTE_H_ +#define UTILS_PERSISTENCE_COMPUTE_H_ +#include <gudhi/graph_simplicial_complex.h> +#include <gudhi/Simplex_tree.h> +#include <gudhi/distance_functions.h> +#include <gudhi/Persistent_cohomology.h> -#include "gudhi/graph_simplicial_complex.h" -#include "gudhi/Simplex_tree.h" -#include "gudhi/distance_functions.h" -#include "gudhi/Persistent_cohomology.h" +#include <vector> +struct Persistence_params { + int p; + double threshold; + int max_dim; + double min_pers; -struct Persistence_params{ - int p; - double threshold; - int max_dim; - double min_pers; - - Persistence_params(int p_,double th_,int max_dim_=10,double min_pers_=0) - :p(p_),threshold(th_),max_dim(max_dim_),min_pers(min_pers_){} + Persistence_params(int p_, double th_, int max_dim_ = 10, double min_pers_ = 0) + : p(p_), threshold(th_), max_dim(max_dim_), min_pers(min_pers_) { } }; - /** * Show persistence into output stream */ -template<typename SkBlComplex> class Persistence_compute{ -private: - SkBlComplex& complex_; - std::ostream& stream_; -public: - typedef typename SkBlComplex::Vertex_handle Vertex_handle; - typedef typename SkBlComplex::Edge_handle Edge_handle; - - /** - * @brief Compute persistence - * parameters : - * unsigned dim_max - * double threshold - * int p for coefficient Z_p - */ - Persistence_compute(SkBlComplex& complex,std::ostream& stream,const Persistence_params& params): -// -// double threshold = 0.5,unsigned dim_max = 8): - complex_(complex),stream_(stream){ - - //for now everything is copied, todo boost adapt iterators to points of SkBlComplex instead of copying to an intial vector - typedef std::vector<double> Point_t; - std::vector< Point_t > points; - points.reserve(complex.num_vertices()); - for(auto v : complex.vertex_range()){ - const auto & pt = complex.point(v); - Point_t pt_to_add(pt.cartesian_begin(),pt.cartesian_end()); - points.emplace_back(std::move(pt_to_add)); - } - - - Graph_t prox_graph = compute_proximity_graph( points, params.threshold, euclidean_distance<Point_t> ); - Gudhi::Simplex_tree<> st; - st.insert_graph(prox_graph); - st.expansion( params.max_dim ); - - Gudhi::persistent_cohomology::Persistent_cohomology< Gudhi::Simplex_tree<>,Gudhi::persistent_cohomology::Field_Zp > pcoh (st); - pcoh.init_coefficients( params.p ); //initilizes the coefficient field for homology - pcoh.compute_persistent_cohomology( params.min_pers ); //put params.min_pers - stream_<<"persistence: \n"; - stream_<<"p dimension birth death: \n"; - - pcoh.output_diagram(stream_); - } - -private: - - +template<typename SkBlComplex> class Persistence_compute { + private: + SkBlComplex& complex_; + std::ostream& stream_; + + public: + typedef typename SkBlComplex::Vertex_handle Vertex_handle; + typedef typename SkBlComplex::Edge_handle Edge_handle; + + /** + * @brief Compute persistence + * parameters : + * unsigned dim_max + * double threshold + * int p for coefficient Z_p + */ + Persistence_compute(SkBlComplex& complex, std::ostream& stream, const Persistence_params& params) : + // double threshold = 0.5,unsigned dim_max = 8): + complex_(complex), stream_(stream) { + // for now everything is copied, todo boost adapt iterators to points of SkBlComplex instead of copying to an + // initial vector + typedef std::vector<double> Point_t; + std::vector< Point_t > points; + points.reserve(complex.num_vertices()); + for (auto v : complex.vertex_range()) { + const auto & pt = complex.point(v); + Point_t pt_to_add(pt.cartesian_begin(), pt.cartesian_end()); + points.emplace_back(std::move(pt_to_add)); + } + + + Graph_t prox_graph = compute_proximity_graph(points, params.threshold, euclidean_distance<Point_t>); + Gudhi::Simplex_tree<> st; + st.insert_graph(prox_graph); + st.expansion(params.max_dim); + + Gudhi::persistent_cohomology::Persistent_cohomology< Gudhi::Simplex_tree<>, + Gudhi::persistent_cohomology::Field_Zp > pcoh(st); + // initializes the coefficient field for homology + pcoh.init_coefficients(params.p); + // put params.min_pers + pcoh.compute_persistent_cohomology(params.min_pers); + stream_ << "persistence: \n"; + stream_ << "p dimension birth death: \n"; + + pcoh.output_diagram(stream_); + } }; - - - - - -#endif /* PERSISTENCE_COMPUTE_H_ */ +#endif // UTILS_PERSISTENCE_COMPUTE_H_ diff --git a/src/GudhUI/utils/Rips_builder.h b/src/GudhUI/utils/Rips_builder.h index 9484f9ab..b22f4db6 100644 --- a/src/GudhUI/utils/Rips_builder.h +++ b/src/GudhUI/utils/Rips_builder.h @@ -1,56 +1,69 @@ -/* - * Rips_builder.h +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Sep 10, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 RIPS_BUILDER_H_ -#define RIPS_BUILDER_H_ +#ifndef UTILS_RIPS_BUILDER_H_ +#define UTILS_RIPS_BUILDER_H_ #include <boost/iterator/iterator_facade.hpp> -#include "utils/UI_utils.h" -#include "model/Complex_typedefs.h" #include <CGAL/Euclidean_distance.h> - #include <CGAL/Orthogonal_k_neighbor_search.h> #include <CGAL/Search_traits_d.h> -template<typename SkBlComplex> class Rips_builder{ -private: - SkBlComplex& complex_; -public: - - /** - * @brief Modify complex to be the Rips complex - * of its points with offset alpha. - */ - Rips_builder(SkBlComplex& complex,double alpha):complex_(complex){ - complex.keep_only_vertices(); - if (alpha<=0) return; - compute_edges(alpha); - } - -private: - - - double squared_eucl_distance(const Point& p1,const Point& p2) const{ - return Geometry_trait::Squared_distance_d()(p1,p2); - } - - void compute_edges(double alpha){ - auto vertices = complex_.vertex_range(); - for(auto p = vertices.begin(); p!= vertices.end(); ++p){ - std::cout << *p << " "; std::cout.flush(); - for (auto q = p; ++q != vertices.end(); /**/) - if (squared_eucl_distance(complex_.point(*p),complex_.point(*q)) < 4*alpha*alpha) - complex_.add_edge(*p,*q); - } - std::cout << std::endl; - } +#include "utils/UI_utils.h" +#include "model/Complex_typedefs.h" -}; +template<typename SkBlComplex> class Rips_builder { + private: + SkBlComplex& complex_; + public: + /** + * @brief Modify complex to be the Rips complex + * of its points with offset alpha. + */ + Rips_builder(SkBlComplex& complex, double alpha) : complex_(complex) { + complex.keep_only_vertices(); + if (alpha <= 0) return; + compute_edges(alpha); + } + + private: + double squared_eucl_distance(const Point& p1, const Point& p2) const { + return Geometry_trait::Squared_distance_d()(p1, p2); + } + + void compute_edges(double alpha) { + auto vertices = complex_.vertex_range(); + for (auto p = vertices.begin(); p != vertices.end(); ++p) { + std::cout << *p << " "; + std::cout.flush(); + for (auto q = p; ++q != vertices.end(); /**/) + if (squared_eucl_distance(complex_.point(*p), complex_.point(*q)) < 4 * alpha * alpha) + complex_.add_edge(*p, *q); + } + std::cout << std::endl; + } +}; -#endif /* RIPS_BUILDER_H_ */ +#endif // UTILS_RIPS_BUILDER_H_ diff --git a/src/GudhUI/utils/UI_utils.h b/src/GudhUI/utils/UI_utils.h index a7c0689f..9cc209d3 100644 --- a/src/GudhUI/utils/UI_utils.h +++ b/src/GudhUI/utils/UI_utils.h @@ -1,33 +1,45 @@ -/* - * UI_utils.h +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Aug 25, 2014 - * Author: david + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 UI_UTILS_H_ -#define UI_UTILS_H_ - -#define PRINT(a) std::cerr << #a << ": " << (a) << " (DISP)"<<std::endl +#ifndef UTILS_UI_UTILS_H_ +#define UTILS_UI_UTILS_H_ #define UIDBG_VERBOSE - #ifdef UIDBG_VERBOSE -#define UIDBG(a) std::cerr << "UIDBG: " << (a)<<std::endl -#define UIDBGMSG(a,b) std::cerr << "UIDBG: " << a<<b<<std::endl -#define UIDBGVALUE(a) std::cerr << "UIDBG: " << #a << ": " << a<<std::endl -#define UIDBGCONT(a) std::cerr << "UIDBG: container "<< #a<<" -> "; for(auto x:a) std::cerr<< x << ","; std::cerr<<std::endl +#define UIDBG(a) std::cerr << "UIDBG: " << (a) << std::endl +#define UIDBGMSG(a, b) std::cerr << "UIDBG: " << a << b << std::endl +#define UIDBGVALUE(a) std::cerr << "UIDBG: " << #a << ": " << a << std::endl +#define UIDBGCONT(a) std::cerr << "UIDBG: container " << #a << " -> "; for (auto x : a) std::cerr << x << ","; std::cerr << std::endl } #else -//#define DBG(a) a -//#define DBGMSG(a,b) b -//#define DBGVALUE(a) a -//#define DBGCONT(a) a +// #define DBG(a) a +// #define DBGMSG(a, b) b +// #define DBGVALUE(a) a +// #define DBGCONT(a) a #define UIDBG(a) -#define UIDBGMSG(a,b) +#define UIDBGMSG(a, b) #define UIDBGVALUE(a) #define UIDBGCONT(a) #endif - -#endif /* UI_UTILS_H_ */ +#endif // UTILS_UI_UTILS_H_ diff --git a/src/GudhUI/utils/Vertex_collapsor.h b/src/GudhUI/utils/Vertex_collapsor.h index d4911a35..2b36cb3a 100644 --- a/src/GudhUI/utils/Vertex_collapsor.h +++ b/src/GudhUI/utils/Vertex_collapsor.h @@ -1,76 +1,88 @@ -/* - * Vertex_collapsor.h +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Sep 25, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 VERTEX_COLLAPSOR_H_ -#define VERTEX_COLLAPSOR_H_ +#ifndef UTILS_VERTEX_COLLAPSOR_H_ +#define UTILS_VERTEX_COLLAPSOR_H_ + +#include <list> #include "utils/Edge_contractor.h" #include "utils/Furthest_point_epsilon_net.h" #include "utils/UI_utils.h" + /** * Iteratively puts every vertex at the center of its neighbors */ -template<typename SkBlComplex> class Vertex_collapsor{ -private: - SkBlComplex& complex_; - size_t num_collapses_; -public: - typedef typename SkBlComplex::Vertex_handle Vertex_handle; - typedef typename SkBlComplex::Edge_handle Edge_handle; - - /** - * @brief Modify complex to be the expansion of the k-nearest neighbor - * symetric graph. - */ - Vertex_collapsor(SkBlComplex& complex, size_t num_collapses) : - complex_(complex),num_collapses_(num_collapses) - { -// std::list<Vertex_handle> vertices; -// vertices.insert(vertices.begin(),complex_.vertex_range().begin(),complex_.vertex_range().end()); -// UIDBG("Collapse vertices"); -// collapse_vertices(vertices); - - std::list<Vertex_handle> vertices; - - UIDBG("Compute eps net"); - Furthest_point_epsilon_net<Complex> eps_net(complex_); - - for(auto vh : eps_net.net_filtration_) - vertices.push_back(vh.vertex_handle); - - UIDBG("Collapse vertices"); - collapse_vertices(vertices); - - - - } - -private: - - - void collapse_vertices(std::list<Vertex_handle>& vertices){ - while(!vertices.empty() && num_collapses_--){ - Vertex_handle current_vertex = vertices.front(); - vertices.pop_front(); - if(is_link_reducible(current_vertex)) - complex_.remove_vertex(current_vertex); - } - } - - bool is_link_reducible(Vertex_handle v){ - auto link = complex_.link(v); - if(link.empty()) return false; - if(link.is_cone()) return true; - if(link.num_connected_components()>1) return false; - Edge_contractor<Complex> contractor(link,link.num_vertices()-1); - return (link.num_vertices()==1); - } - +template<typename SkBlComplex> class Vertex_collapsor { + private: + SkBlComplex& complex_; + size_t num_collapses_; + + public: + typedef typename SkBlComplex::Vertex_handle Vertex_handle; + typedef typename SkBlComplex::Edge_handle Edge_handle; + + /** + * @brief Modify complex to be the expansion of the k-nearest neighbor + * symetric graph. + */ + Vertex_collapsor(SkBlComplex& complex, size_t num_collapses) : + complex_(complex), num_collapses_(num_collapses) { + // std::list<Vertex_handle> vertices; + // vertices.insert(vertices.begin(),complex_.vertex_range().begin(),complex_.vertex_range().end()); + // UIDBG("Collapse vertices"); + // collapse_vertices(vertices); + + std::list<Vertex_handle> vertices; + + UIDBG("Compute eps net"); + Furthest_point_epsilon_net<Complex> eps_net(complex_); + + for (auto vh : eps_net.net_filtration_) + vertices.push_back(vh.vertex_handle); + + UIDBG("Collapse vertices"); + collapse_vertices(vertices); + } + + private: + void collapse_vertices(std::list<Vertex_handle>& vertices) { + while (!vertices.empty() && num_collapses_--) { + Vertex_handle current_vertex = vertices.front(); + vertices.pop_front(); + if (is_link_reducible(current_vertex)) + complex_.remove_vertex(current_vertex); + } + } + + bool is_link_reducible(Vertex_handle v) { + auto link = complex_.link(v); + if (link.empty()) return false; + if (link.is_cone()) return true; + if (link.num_connected_components() > 1) return false; + Edge_contractor<Complex> contractor(link, link.num_vertices() - 1); + return (link.num_vertices() == 1); + } }; - -#endif /* VERTEX_COLLAPSOR_H_ */ +#endif // UTILS_VERTEX_COLLAPSOR_H_ diff --git a/src/GudhUI/view/Color.h b/src/GudhUI/view/Color.h index a63456cb..ba0592e1 100644 --- a/src/GudhUI/view/Color.h +++ b/src/GudhUI/view/Color.h @@ -1,21 +1,35 @@ -/* - * Color.h +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Aug 26, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 COLOR_H_ -#define COLOR_H_ - +#ifndef VIEW_COLOR_H_ +#define VIEW_COLOR_H_ +struct Color { + double r; + double g; + double b; -struct Color{ - double r; - double g; - double b; - Color(double r_,double g_,double b_):r(r_),g(g_),b(b_){} + Color(double r_, double g_, double b_) : r(r_), g(g_), b(b_) { } }; - -#endif /* COLOR_H_ */ +#endif // VIEW_COLOR_H_ diff --git a/src/GudhUI/view/FirstCoordProjector.h b/src/GudhUI/view/FirstCoordProjector.h index 2659eef1..529d2d42 100644 --- a/src/GudhUI/view/FirstCoordProjector.h +++ b/src/GudhUI/view/FirstCoordProjector.h @@ -1,24 +1,40 @@ -/* - * FirstCoordProjector.h +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Aug 27, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 FIRSTCOORDPROJECTOR_H_ -#define FIRSTCOORDPROJECTOR_H_ +#ifndef VIEW_FIRSTCOORDPROJECTOR_H_ +#define VIEW_FIRSTCOORDPROJECTOR_H_ #include "utils/UI_utils.h" #include "Projector3D.h" -class FirstCoordProjector3D : public Projector3D{ - typedef Projector3D::Point Point; - typedef Projector3D::Point_3 Point_3; +class FirstCoordProjector3D : public Projector3D { + typedef Projector3D::Point Point; + typedef Projector3D::Point_3 Point_3; - Point_3 operator()(const Point& p) const{ - assert(p.dimension()>=3); - return Point_3(p.x(),p.y(),p.z()); - } + Point_3 operator()(const Point& p) const { + assert(p.dimension() >= 3); + return Point_3(p.x(), p.y(), p.z()); + } }; -#endif /* FIRSTCOORDPROJECTOR_H_ */ +#endif // VIEW_FIRSTCOORDPROJECTOR_H_ diff --git a/src/GudhUI/view/Projector3D.h b/src/GudhUI/view/Projector3D.h index 503b35c5..2a756541 100644 --- a/src/GudhUI/view/Projector3D.h +++ b/src/GudhUI/view/Projector3D.h @@ -1,28 +1,39 @@ -/* - * Projector.h +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Aug 27, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 PROJECTOR3D_H_ -#define PROJECTOR3D_H_ +#ifndef VIEW_PROJECTOR3D_H_ +#define VIEW_PROJECTOR3D_H_ #include "model/Complex_typedefs.h" +class Projector3D { + public: + typedef Geometry_trait::Point Point; + typedef Geometry_trait::Point_3 Point_3; -class Projector3D{ -public: - typedef Geometry_trait::Point Point; - typedef Geometry_trait::Point_3 Point_3; - - virtual Point_3 operator()(const Point&) const = 0; - - virtual ~Projector3D(){ - } + virtual Point_3 operator()(const Point&) const = 0; + virtual ~Projector3D() { } }; - - -#endif /* PROJECTOR3D_H_ */ +#endif // VIEW_PROJECTOR3D_H_ diff --git a/src/GudhUI/view/View_parameter.h b/src/GudhUI/view/View_parameter.h index 39c5d7dd..9805abc2 100644 --- a/src/GudhUI/view/View_parameter.h +++ b/src/GudhUI/view/View_parameter.h @@ -1,13 +1,28 @@ -/* - * View_parameter.h +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Mar 10, 2014 - * Author: David Salinas - * Copyright 2013 INRIA. All rights reserved + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 VIEW_PARAMETER_H_ -#define VIEW_PARAMETER_H_ +#ifndef VIEW_VIEW_PARAMETER_H_ +#define VIEW_VIEW_PARAMETER_H_ #include <iostream> @@ -15,123 +30,122 @@ * Different parameters for the view such as the camera angle, * the light, options for vertices/edges/triangles. */ -class View_parameter{ -public: - bool light; - bool relative_light; - - double size_vertices; - double size_edges; - double light_edges; // in 0-1 - double light_triangles;// in 0-1 - - /** - * light angle - */ - double theta; - double phi; - - enum VERTEX_MODE{ V_NONE,V_SIMPLE,V_COUNT}; - enum EDGE_MODE{ E_NONE,E_SIMPLE,E_COUNT}; - enum TRIANGLE_MODE{ T_NONE,T_SIMPLE,T_COUNT}; - - - - - VERTEX_MODE vertex_mode; - EDGE_MODE edge_mode; - TRIANGLE_MODE triangle_mode; - - void change_vertex_mode(){ - int current_value = vertex_mode; - vertex_mode = static_cast<VERTEX_MODE>(++current_value % V_COUNT); - std::cout<<"Vertex mode : "; - switch (vertex_mode) { - case V_NONE: - std::cout<<"empty\n"; - break; - case V_SIMPLE: - std::cout<<"simple\n"; - break; - default: - break; - } - } - - void change_vertex_mode(int new_mode){ - vertex_mode = static_cast<VERTEX_MODE>(new_mode % V_COUNT); - } - - void change_edge_mode(){ - int current_value = edge_mode; - edge_mode = static_cast<EDGE_MODE>(++current_value % E_COUNT); - } - - void change_edge_mode(int new_mode){ - edge_mode = static_cast<EDGE_MODE>(new_mode % E_COUNT); - } - - - void change_triangle_mode(){ - int current_value = triangle_mode; - triangle_mode = static_cast<TRIANGLE_MODE>(++current_value % T_COUNT); - } - - - - - - View_parameter(){ - light = true; - relative_light = true; - vertex_mode = V_SIMPLE; - edge_mode = E_SIMPLE; - triangle_mode = T_NONE; - - size_vertices = 3; - size_edges = 2; - - light_edges = 0.3; - light_triangles = 0.85; - theta = 0; - phi = 0; - } - - friend std::ostream& operator<<(std::ostream& stream, const View_parameter& param){ - stream << param.light<< " "; - stream << param.relative_light<< " "; - stream << param.vertex_mode<< " "; - stream << param.edge_mode<< " "; - stream << param.triangle_mode<< " "; - stream << param.size_vertices<< " "; - stream << param.size_edges<< " "; - stream << param.light_edges<< " "; - stream << param.light_triangles<< " "; - stream << param.theta<< " "; - stream << param.phi<< " "; - return stream; - } - - friend std::istream& operator>>(std::istream& stream, View_parameter& param){ - stream >> param.light; - stream >> param.relative_light; - int a; - stream>>a; - param.vertex_mode = static_cast<VERTEX_MODE>(a % V_COUNT); - stream>>a; - param.edge_mode = static_cast<EDGE_MODE>(a % E_COUNT); - stream>>a; - param.triangle_mode = static_cast<TRIANGLE_MODE>(a % T_COUNT); - stream>>a; - stream >> param.size_vertices; - stream >> param.size_edges; - stream >> param.light_edges; - stream >> param.light_triangles; - stream >> param.theta; - stream >> param.phi; - return stream; - } - +class View_parameter { + public: + bool light; + bool relative_light; + + double size_vertices; + double size_edges; + double light_edges; // in 0-1 + double light_triangles; // in 0-1 + + /** + * light angle + */ + double theta; + double phi; + + enum VERTEX_MODE { + V_NONE, V_SIMPLE, V_COUNT + }; + + enum EDGE_MODE { + E_NONE, E_SIMPLE, E_COUNT + }; + + enum TRIANGLE_MODE { + T_NONE, T_SIMPLE, T_COUNT + }; + + VERTEX_MODE vertex_mode; + EDGE_MODE edge_mode; + TRIANGLE_MODE triangle_mode; + + void change_vertex_mode() { + int current_value = vertex_mode; + vertex_mode = static_cast<VERTEX_MODE> (++current_value % V_COUNT); + std::cout << "Vertex mode : "; + switch (vertex_mode) { + case V_NONE: + std::cout << "empty\n"; + break; + case V_SIMPLE: + std::cout << "simple\n"; + break; + default: + break; + } + } + + void change_vertex_mode(int new_mode) { + vertex_mode = static_cast<VERTEX_MODE> (new_mode % V_COUNT); + } + + void change_edge_mode() { + int current_value = edge_mode; + edge_mode = static_cast<EDGE_MODE> (++current_value % E_COUNT); + } + + void change_edge_mode(int new_mode) { + edge_mode = static_cast<EDGE_MODE> (new_mode % E_COUNT); + } + + void change_triangle_mode() { + int current_value = triangle_mode; + triangle_mode = static_cast<TRIANGLE_MODE> (++current_value % T_COUNT); + } + + View_parameter() { + light = true; + relative_light = true; + vertex_mode = V_SIMPLE; + edge_mode = E_SIMPLE; + triangle_mode = T_NONE; + + size_vertices = 3; + size_edges = 2; + + light_edges = 0.3; + light_triangles = 0.85; + theta = 0; + phi = 0; + } + + friend std::ostream& operator<<(std::ostream& stream, const View_parameter& param) { + stream << param.light << " "; + stream << param.relative_light << " "; + stream << param.vertex_mode << " "; + stream << param.edge_mode << " "; + stream << param.triangle_mode << " "; + stream << param.size_vertices << " "; + stream << param.size_edges << " "; + stream << param.light_edges << " "; + stream << param.light_triangles << " "; + stream << param.theta << " "; + stream << param.phi << " "; + return stream; + } + + friend std::istream& operator>>(std::istream& stream, View_parameter& param) { + stream >> param.light; + stream >> param.relative_light; + int a; + stream >> a; + param.vertex_mode = static_cast<VERTEX_MODE> (a % V_COUNT); + stream >> a; + param.edge_mode = static_cast<EDGE_MODE> (a % E_COUNT); + stream >> a; + param.triangle_mode = static_cast<TRIANGLE_MODE> (a % T_COUNT); + stream >> a; + stream >> param.size_vertices; + stream >> param.size_edges; + stream >> param.light_edges; + stream >> param.light_triangles; + stream >> param.theta; + stream >> param.phi; + return stream; + } }; -#endif /* VIEW_PARAMETER_H_ */ +#endif // VIEW_VIEW_PARAMETER_H_ diff --git a/src/GudhUI/view/Viewer.cpp b/src/GudhUI/view/Viewer.cpp index d8a35faf..c6c2b345 100644 --- a/src/GudhUI/view/Viewer.cpp +++ b/src/GudhUI/view/Viewer.cpp @@ -1,197 +1,186 @@ -/* - * Viewer.cpp +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Aug 26, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 "Viewer.h" #include "utils/UI_utils.h" -Viewer::Viewer(QWidget* parent): QGLViewer(QGLFormat(QGL::SampleBuffers),parent),instructor(0),theta(0),phi(0){ -} +Viewer::Viewer(QWidget* parent) : QGLViewer(QGLFormat(QGL::SampleBuffers), parent), instructor(0), theta(0), phi(0) { } -void -Viewer::set_instructor(Viewer_instructor* instructor_){ - instructor = instructor_; +void Viewer::set_instructor(Viewer_instructor* instructor_) { + instructor = instructor_; } -void -Viewer::show_entire_scene(){ - this->showEntireScene(); +void Viewer::show_entire_scene() { + this->showEntireScene(); } -void -Viewer::draw(){ - instructor->give_instructions(); +void Viewer::draw() { + instructor->give_instructions(); } - -void -Viewer::set_bounding_box(const Point_3 & lower_left,const Point_3 & upper_right){ - this->camera()->setSceneBoundingBox( - qglviewer::Vec(lower_left[0], lower_left[1], lower_left[2]), - qglviewer::Vec(upper_right[0], upper_right[1], upper_right[2]) - ); +void Viewer::set_bounding_box(const Point_3 & lower_left, const Point_3 & upper_right) { + this->camera()->setSceneBoundingBox(qglviewer::Vec(lower_left[0], lower_left[1], lower_left[2]), + qglviewer::Vec(upper_right[0], upper_right[1], upper_right[2])); } -void -Viewer::update_GL(){ - this->updateGL(); - +void Viewer::update_GL() { + this->updateGL(); } -void -Viewer::init_scene(){ - this->setBackgroundColor(Qt::white); - ::glEnable(GL_LINE_SMOOTH); - init_light(); +void Viewer::init_scene() { + this->setBackgroundColor(Qt::white); + ::glEnable(GL_LINE_SMOOTH); + init_light(); } -void -Viewer::init_light(){ - ::glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); +void Viewer::init_light() { + ::glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); } -void -Viewer::set_light(){ - if(theta>=0 && phi >=0){ - const GLfloat pos[4] = {(float)(sin(phi)*cos(theta)),(float)(sin(phi)*sin(theta)),(float)(cos(phi)),0.}; - glLightfv(GL_LIGHT0, GL_POSITION, pos); - } +void Viewer::set_light() { + if (theta >= 0 && phi >= 0) { + const GLfloat pos[4] = {static_cast<float> (sin(phi) * cos(theta)), + static_cast<float> (sin(phi) * sin(theta)), + static_cast<float> (cos(phi)), 0.}; + glLightfv(GL_LIGHT0, GL_POSITION, pos); + } } -void -Viewer::set_light_direction(double theta_,double phi_){ - theta = theta_; - phi = phi_; +void Viewer::set_light_direction(double theta_, double phi_) { + theta = theta_; + phi = phi_; } /** * set the light in the direction of the observer */ -void -Viewer::set_light_direction(){ - theta = -1; - phi = -1; +void Viewer::set_light_direction() { + theta = -1; + phi = -1; } +void Viewer::postSelection(const QPoint& point) { + bool found; -void -Viewer::postSelection(const QPoint& point){ - bool found; + auto vec = this->camera()->pointUnderPixel(point, found); - auto vec = this->camera()->pointUnderPixel(point,found); - - if(found){ - Point_3 position(vec[0],vec[1],vec[2]); - emit(click(position)); - } + if (found) { + Point_3 position(vec[0], vec[1], vec[2]); + emit(click(position)); + } } //////////////////////// // draw //////////////////////// -void -Viewer::set_size_point(double size_points){ - ::glPointSize(size_points); -} - -void -Viewer::draw_point(const Point_3& p,const Color& color,double size_points){ - ::glColor3f(color.r,color.g,color.b); - ::glDisable(GL_LIGHTING); - ::glEnable(GL_POINT_SMOOTH); - ::glPointSize(size_points); - ::glBegin(GL_POINTS); - ::glVertex3d(p.x(), p.y(), p.z()); - ::glEnd(); - ::glDisable(GL_POINT_SMOOTH); -} - -void -Viewer::begin_draw_points(double size,bool light){ - light?glEnable(GL_LIGHTING):glDisable(GL_LIGHTING); - ::glEnable(GL_POINT_SMOOTH); - ::glPointSize(size); - ::glBegin(GL_POINTS); -} - -void -Viewer::set_color(const Color& color){ - ::glColor3f(color.r,color.g,color.b); -} - -void -Viewer::draw_points(const Point_3 & point){ - ::glVertex3d(point.x(),point.y(),point.z()); -} - -void -Viewer::end_draw_points(){ - ::glEnd(); - ::glDisable(GL_POINT_SMOOTH); -} - -void -Viewer::draw_edge(const Point_3 &a,const Point_3 &b,const Color& color,double size){ - ::glColor3f(color.r,color.g,color.b); - ::glPointSize(3.0); - ::glLineWidth(size); - ::glBegin(GL_LINES); - ::glVertex3f(a.x(),a.y(),a.z()); - ::glVertex3f(b.x(),b.y(),b.z()); - ::glEnd(); -} - -void -Viewer::begin_draw_edges(double size,bool light){ - ::glLineWidth(size); - ::glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); - ::glEnable(GL_POLYGON_OFFSET_LINE); - ::glPolygonOffset(3.0f,-3.0f); - light?glEnable(GL_LIGHTING):glDisable(GL_LIGHTING); - ::glBegin(GL_LINES); -} - -void -Viewer::draw_edges(const Point_3 &a,const Point_3 &b){ - ::glVertex3f(a.x(),a.y(),a.z()); - ::glVertex3f(b.x(),b.y(),b.z()); -} - -void -Viewer::end_draw_edges(){ - ::glEnd(); -} - -void -Viewer::begin_draw_triangles(double size,bool light,bool transparent){ - if(transparent){ - ::glEnable (GL_BLEND); - ::glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - ::glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); - ::glEnable(GL_POLYGON_OFFSET_FILL); - ::glPolygonOffset(3.0f,-3.0f); - light?glEnable(GL_LIGHTING):glDisable(GL_LIGHTING); - ::glBegin(GL_TRIANGLES); -} - -void -Viewer::draw_triangles(const Point_3& p1,const Point_3& p2,const Point_3& p3){ - if(!CGAL::collinear(p1,p2,p3)){ - auto triangle_normal = CGAL::unit_normal(p1,p2,p3); - ::glNormal3d(triangle_normal.x(),triangle_normal.y(),triangle_normal.z()); - ::glVertex3d(p1.x(),p1.y(),p1.z()); - ::glVertex3d(p2.x(),p2.y(),p2.z()); - ::glVertex3d(p3.x(),p3.y(),p3.z()); - } -} - -void -Viewer::end_draw_triangles(){ - ::glEnd(); + +void Viewer::set_size_point(double size_points) { + ::glPointSize(size_points); +} + +void Viewer::draw_point(const Point_3& p, const Color& color, double size_points) { + ::glColor3f(color.r, color.g, color.b); + ::glDisable(GL_LIGHTING); + ::glEnable(GL_POINT_SMOOTH); + ::glPointSize(size_points); + ::glBegin(GL_POINTS); + ::glVertex3d(p.x(), p.y(), p.z()); + ::glEnd(); + ::glDisable(GL_POINT_SMOOTH); +} + +void Viewer::begin_draw_points(double size, bool light) { + light ? glEnable(GL_LIGHTING) : glDisable(GL_LIGHTING); + ::glEnable(GL_POINT_SMOOTH); + ::glPointSize(size); + ::glBegin(GL_POINTS); +} + +void Viewer::set_color(const Color& color) { + ::glColor3f(color.r, color.g, color.b); +} + +void Viewer::draw_points(const Point_3 & point) { + ::glVertex3d(point.x(), point.y(), point.z()); +} + +void Viewer::end_draw_points() { + ::glEnd(); + ::glDisable(GL_POINT_SMOOTH); +} + +void Viewer::draw_edge(const Point_3 &a, const Point_3 &b, const Color& color, double size) { + ::glColor3f(color.r, color.g, color.b); + ::glPointSize(3.0); + ::glLineWidth(size); + ::glBegin(GL_LINES); + ::glVertex3f(a.x(), a.y(), a.z()); + ::glVertex3f(b.x(), b.y(), b.z()); + ::glEnd(); +} + +void Viewer::begin_draw_edges(double size, bool light) { + ::glLineWidth(size); + ::glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + ::glEnable(GL_POLYGON_OFFSET_LINE); + ::glPolygonOffset(3.0f, -3.0f); + light ? glEnable(GL_LIGHTING) : glDisable(GL_LIGHTING); + ::glBegin(GL_LINES); +} + +void Viewer::draw_edges(const Point_3 &a, const Point_3 &b) { + ::glVertex3f(a.x(), a.y(), a.z()); + ::glVertex3f(b.x(), b.y(), b.z()); +} + +void Viewer::end_draw_edges() { + ::glEnd(); +} + +void Viewer::begin_draw_triangles(double size, bool light, bool transparent) { + if (transparent) { + ::glEnable(GL_BLEND); + ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + ::glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + ::glEnable(GL_POLYGON_OFFSET_FILL); + ::glPolygonOffset(3.0f, -3.0f); + light ? glEnable(GL_LIGHTING) : glDisable(GL_LIGHTING); + ::glBegin(GL_TRIANGLES); +} + +void Viewer::draw_triangles(const Point_3& p1, const Point_3& p2, const Point_3& p3) { + if (!CGAL::collinear(p1, p2, p3)) { + auto triangle_normal = CGAL::unit_normal(p1, p2, p3); + ::glNormal3d(triangle_normal.x(), triangle_normal.y(), triangle_normal.z()); + ::glVertex3d(p1.x(), p1.y(), p1.z()); + ::glVertex3d(p2.x(), p2.y(), p2.z()); + ::glVertex3d(p3.x(), p3.y(), p3.z()); + } +} + +void Viewer::end_draw_triangles() { + ::glEnd(); } #include "Viewer.moc" diff --git a/src/GudhUI/view/Viewer.h b/src/GudhUI/view/Viewer.h index 5639aa56..276ccd3c 100644 --- a/src/GudhUI/view/Viewer.h +++ b/src/GudhUI/view/Viewer.h @@ -1,7 +1,36 @@ -#ifndef VIEWER_H
-#define VIEWER_H
+/* 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): David Salinas
+ *
+ * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 VIEW_VIEWER_H_
+#define VIEW_VIEWER_H_
+
+// Workaround for moc-qt4 not parsing boost headers
+#include <CGAL/config.h>
#include <QGLViewer/qglviewer.h>
+
+#include <vector>
+
#include "View_parameter.h"
#include "model/Complex_typedefs.h"
#include "Color.h"
@@ -10,87 +39,82 @@ class Viewer_instructor;
class Viewer : public QGLViewer {
- Q_OBJECT
-
- Viewer_instructor * instructor;
-
- /**
- * light angles
- */
- double theta,phi;
- typedef Complex::GT Gudhi_kernel;
- typedef Gudhi_kernel::Point_3 Point_3;
-public:
- Viewer(QWidget* parent);
+ Q_OBJECT
- void set_instructor(Viewer_instructor* instructor_);
+ Viewer_instructor * instructor;
- void show_entire_scene();
+ /**
+ * light angles
+ */
+ double theta, phi;
+ typedef Complex::GT Gudhi_kernel;
+ typedef Gudhi_kernel::Point_3 Point_3;
- void draw();
+ public:
+ Viewer(QWidget* parent);
+ void set_instructor(Viewer_instructor* instructor_);
- void set_bounding_box(const Point_3 & lower_left,const Point_3 & upper_right);
+ void show_entire_scene();
- void update_GL();
+ void draw();
- void init_scene();
+ void set_bounding_box(const Point_3 & lower_left, const Point_3 & upper_right);
- void init_light();
+ void update_GL();
- void set_light();
+ void init_scene();
- void set_light_direction(double theta,double phi);
+ void init_light();
- /**
- * set the light in the direction of the observer
- */
- void set_light_direction();
+ void set_light();
+ void set_light_direction(double theta, double phi);
-protected:
- virtual void postSelection(const QPoint& point);
+ /**
+ * set the light in the direction of the observer
+ */
+ void set_light_direction();
+ protected:
+ virtual void postSelection(const QPoint& point);
-public:
+ public:
+ ////////////////////////
+ // draw
+ ////////////////////////
+ void set_size_point(double size_points);
- ////////////////////////
- // draw
- ////////////////////////
- void set_size_point(double size_points);
+ void set_color(const Color& color);
- void set_color(const Color& color);
+ void draw_point(const Point_3& p, const Color& color, double size_points);
- void draw_point(const Point_3& p,const Color& color,double size_points);
+ void begin_draw_points(double size, bool light = false);
- void begin_draw_points(double size,bool light=false);
+ void draw_points(const Point_3 & point);
- void draw_points(const Point_3 & point);
+ void end_draw_points();
- void end_draw_points();
+ void draw_edge(const Point_3 &a, const Point_3 &b, const Color& color, double size);
- void draw_edge(const Point_3 &a,const Point_3 &b,const Color& color,double size);
+ void begin_draw_edges(double size, bool light = false);
- void begin_draw_edges(double size,bool light=false);
+ void draw_edges(const Point_3 &a, const Point_3 &b);
- void draw_edges(const Point_3 &a,const Point_3 &b);
+ void end_draw_edges();
- void end_draw_edges();
+ void begin_draw_triangles(double size, bool light, bool transparent = false);
- void begin_draw_triangles(double size,bool light,bool transparent = false);
+ void draw_triangles(const Point_3& p1, const Point_3& p2, const Point_3& p3);
- void draw_triangles(const Point_3& p1,const Point_3& p2,const Point_3& p3);
+ // todo remove
+ void draw_triangles(const std::vector<Point_3*>& points);
- //todo remove
- void draw_triangles(const std::vector<Point_3*>& points);
+ void end_draw_triangles();
- void end_draw_triangles();
-
- signals:
- void click(const Point_3& position);
+ signals:
+ void click(const Point_3& position);
};
-
-
-#endif
+#endif // VIEW_VIEWER_H_
diff --git a/src/GudhUI/view/Viewer_instructor.cpp b/src/GudhUI/view/Viewer_instructor.cpp index 3cb8f152..1ddd4d8b 100644 --- a/src/GudhUI/view/Viewer_instructor.cpp +++ b/src/GudhUI/view/Viewer_instructor.cpp @@ -1,206 +1,192 @@ -/* - * Viewer_instructor.cpp +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. * - * Created on: Aug 26, 2014 - * Author: dsalinas + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 <utility> + #include "Viewer_instructor.h" #include "utils/UI_utils.h" #include "FirstCoordProjector.h" - Viewer_instructor::Viewer_instructor(QWidget* parent, - Viewer* viewer, - const Complex& mesh -):viewer_(viewer),mesh_(mesh),projector_(new FirstCoordProjector3D()){ - viewer_->set_instructor(this); + Viewer* viewer, + const Complex& mesh + ) + : viewer_(viewer), mesh_(mesh), projector_(new FirstCoordProjector3D()) { + viewer_->set_instructor(this); +} + +void Viewer_instructor::initialize_bounding_box() { + auto pair_bounding_box = compute_bounding_box_corners(); + viewer_->set_bounding_box(proj(pair_bounding_box.first), proj(pair_bounding_box.second)); + viewer_->init_scene(); } +std::pair<Complex::Point, Complex::Point> Viewer_instructor::compute_bounding_box_corners() { + if (mesh_.empty()) { + return std::make_pair(Point(-1, -1, -1, 1), Point(1, 1, 1, 1)); + } else { + double x_min = 1e10; + double y_min = 1e10; + double z_min = 1e10; + double x_max = -1e10; + double y_max = -1e10; + double z_max = -1e10; + for (auto vi : mesh_.vertex_range()) { + auto pt = proj(mesh_.point(vi)); + x_min = (std::min)(x_min, pt.x()); + y_min = (std::min)(y_min, pt.y()); + z_min = (std::min)(z_min, pt.z()); -void -Viewer_instructor::initialize_bounding_box(){ - auto pair_bounding_box = compute_bounding_box_corners(); - viewer_->set_bounding_box(proj(pair_bounding_box.first),proj(pair_bounding_box.second)); - viewer_->init_scene(); -} - -std::pair<Complex::Point,Complex::Point> -Viewer_instructor::compute_bounding_box_corners(){ - if(mesh_.empty()){ - return std::make_pair(Point(-1,-1,-1,1),Point(1,1,1,1)); - } - else{ - double x_min = 1e10; - double y_min = 1e10; - double z_min = 1e10; - double x_max = -1e10; - double y_max = -1e10; - double z_max = -1e10; - for( auto vi : mesh_.vertex_range()) - { - auto pt = proj(mesh_.point(vi)); - x_min = (std::min)(x_min,pt.x()); - y_min = (std::min)(y_min,pt.y()); - z_min = (std::min)(z_min,pt.z()); - - x_max = (std::max)(x_max,pt.x()); - y_max = (std::max)(y_max,pt.y()); - z_max = (std::max)(z_max,pt.z()); - - } - return std::make_pair( - Point(x_min,y_min,z_min,1.), - Point(x_max,y_max,z_max,1.) - ); - } + x_max = (std::max)(x_max, pt.x()); + y_max = (std::max)(y_max, pt.y()); + z_max = (std::max)(z_max, pt.z()); + } + return std::make_pair(Point(x_min, y_min, z_min, 1.), + Point(x_max, y_max, z_max, 1.)); + } } -void -Viewer_instructor::show_entire_scene(){ - viewer_->show_entire_scene(); +void Viewer_instructor::show_entire_scene() { + viewer_->show_entire_scene(); } -const qglviewer::Camera* -Viewer_instructor::camera() const{ - return viewer_->camera(); +const qglviewer::Camera* Viewer_instructor::camera() const { + return viewer_->camera(); } int -Viewer_instructor::width() const{ - return viewer_->width(); +Viewer_instructor::width() const { + return viewer_->width(); } + int -Viewer_instructor::height() const{ - return viewer_->height(); +Viewer_instructor::height() const { + return viewer_->height(); } /** * to change display parameters */ -View_parameter& -Viewer_instructor::view_params(){ - return view_params_; +View_parameter& Viewer_instructor::view_params() { + return view_params_; } - void -Viewer_instructor::give_instructions(){ - if(view_params_.relative_light) - viewer_->set_light_direction(); - else - viewer_->set_light_direction(view_params_.theta,view_params_.phi); - viewer_->set_light(); - - if (view_params_.edge_mode) draw_edges(); - if (view_params_.triangle_mode) draw_triangles(); - if (view_params_.vertex_mode) draw_points(); +Viewer_instructor::give_instructions() { + if (view_params_.relative_light) + viewer_->set_light_direction(); + else + viewer_->set_light_direction(view_params_.theta, view_params_.phi); + viewer_->set_light(); + if (view_params_.edge_mode) draw_edges(); + if (view_params_.triangle_mode) draw_triangles(); + if (view_params_.vertex_mode) draw_points(); } -void -Viewer_instructor::draw_edges(){ - viewer_->begin_draw_edges(view_params_.size_edges,false); +void Viewer_instructor::draw_edges() { + viewer_->begin_draw_edges(view_params_.size_edges, false); - for(auto edge : mesh_.edge_range()){ - set_color_edge(edge); - const Point& a = mesh_.point(mesh_.first_vertex(edge)); - const Point& b = mesh_.point(mesh_.second_vertex(edge)) ; - viewer_->draw_edges(proj(a),proj(b)); - } + for (auto edge : mesh_.edge_range()) { + set_color_edge(edge); + const Point& a = mesh_.point(mesh_.first_vertex(edge)); + const Point& b = mesh_.point(mesh_.second_vertex(edge)); + viewer_->draw_edges(proj(a), proj(b)); + } - viewer_->end_draw_edges(); + viewer_->end_draw_edges(); } -void -Viewer_instructor::draw_triangles(){ - const double size_triangles = 1.0; - viewer_->begin_draw_triangles(size_triangles,view_params_.light); - - for(const auto& fit : mesh_.triangle_range()) { - set_color_triangle(fit); - if(view_params_.triangle_mode){ - auto fit_it = fit.begin(); - const Point& p1 = mesh_.point(*fit_it); - const Point& p2 = mesh_.point(*(++fit_it)); - const Point& p3 = mesh_.point(*(++fit_it)); - viewer_->draw_triangles(proj(p1),proj(p2),proj(p3)); - } - } - viewer_->end_draw_triangles(); -} +void Viewer_instructor::draw_triangles() { + const double size_triangles = 1.0; + viewer_->begin_draw_triangles(size_triangles, view_params_.light); -void -Viewer_instructor::draw_points(){ - viewer_->begin_draw_points( view_params_.size_vertices); - for( auto vi : mesh_.vertex_range()) - { - viewer_->set_size_point(view_params_.size_vertices); - set_color_vertex(vi); - viewer_->draw_points(proj(mesh_.point(vi))); - } - viewer_->end_draw_points(); + for (const auto& fit : mesh_.triangle_range()) { + set_color_triangle(fit); + if (view_params_.triangle_mode) { + auto fit_it = fit.begin(); + const Point& p1 = mesh_.point(*fit_it); + const Point& p2 = mesh_.point(*(++fit_it)); + const Point& p3 = mesh_.point(*(++fit_it)); + viewer_->draw_triangles(proj(p1), proj(p2), proj(p3)); + } + } + viewer_->end_draw_triangles(); } - -void -Viewer_instructor::draw_edge(const Point&,const Point&){ - +void Viewer_instructor::draw_points() { + viewer_->begin_draw_points(view_params_.size_vertices); + for (auto vi : mesh_.vertex_range()) { + viewer_->set_size_point(view_params_.size_vertices); + set_color_vertex(vi); + viewer_->draw_points(proj(mesh_.point(vi))); + } + viewer_->end_draw_points(); } -void -Viewer_instructor::draw_point(const Point&){ - -} +void Viewer_instructor::draw_edge(const Point&, const Point&) { } +void Viewer_instructor::draw_point(const Point&) { } /** * set the right color of vertex/edge/triangle considering the view_params choice */ -void -Viewer_instructor::set_color_vertex(Vertex_handle vh){ - viewer_->set_color(Color(view_params_.light_edges,view_params_.light_edges,view_params_.light_edges)); +void Viewer_instructor::set_color_vertex(Vertex_handle vh) { + viewer_->set_color(Color(view_params_.light_edges, view_params_.light_edges, view_params_.light_edges)); } -void -Viewer_instructor::set_color_edge(Edge_handle eh) { - viewer_->set_color(Color(view_params_.light_edges,view_params_.light_edges,view_params_.light_edges)); +void Viewer_instructor::set_color_edge(Edge_handle eh) { + viewer_->set_color(Color(view_params_.light_edges, view_params_.light_edges, view_params_.light_edges)); } -void -Viewer_instructor::set_color_triangle(const Simplex_handle& triangle){ - viewer_->set_color(Color(view_params_.light_triangles,view_params_.light_triangles,view_params_.light_triangles)); +void Viewer_instructor::set_color_triangle(const Simplex& triangle) { + viewer_->set_color(Color(view_params_.light_triangles, view_params_.light_triangles, view_params_.light_triangles)); } - Viewer_instructor::Point_3 -Viewer_instructor::proj(const Point& p) const{ - return (*projector_)(p); +Viewer_instructor::proj(const Point& p) const { + return (*projector_)(p); } - -void -Viewer_instructor::sceneChanged(){ - UIDBG("sceneChanged"); - viewer_->update_GL(); +void Viewer_instructor::sceneChanged() { + UIDBG("sceneChanged"); + viewer_->update_GL(); } -void -Viewer_instructor::change_draw_vertices(){ - view_params_.change_vertex_mode(); +void Viewer_instructor::change_draw_vertices() { + view_params_.change_vertex_mode(); } -void -Viewer_instructor::change_draw_edges(){ - view_params_.change_edge_mode(); + +void Viewer_instructor::change_draw_edges() { + view_params_.change_edge_mode(); } -void -Viewer_instructor::change_draw_triangles(){ - view_params_.change_triangle_mode(); + +void Viewer_instructor::change_draw_triangles() { + view_params_.change_triangle_mode(); } -void -Viewer_instructor::change_light(){ - view_params_.light =! view_params_.light ; + +void Viewer_instructor::change_light() { + view_params_.light = !view_params_.light; } #include "Viewer_instructor.moc" diff --git a/src/GudhUI/view/Viewer_instructor.h b/src/GudhUI/view/Viewer_instructor.h index 9a2a236b..82c8e346 100644 --- a/src/GudhUI/view/Viewer_instructor.h +++ b/src/GudhUI/view/Viewer_instructor.h @@ -1,15 +1,40 @@ -#ifndef VIEWER_INSTRUCTOR_H
-#define VIEWER_INSTRUCTOR_H
+/* 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): David Salinas
+ *
+ * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 VIEW_VIEWER_INSTRUCTOR_H_
+#define VIEW_VIEWER_INSTRUCTOR_H_
// todo do a viewer instructor that have directely a pointer to a QGLviewer and buffer ot not triangles
-
-#include <memory>
+// Workaround for moc-qt4 not parsing boost headers
+#include <CGAL/config.h>
#include <QFileDialog>
#include <QKeyEvent>
#include <QGLViewer/camera.h>
+#include <memory>
+#include <utility> // for pair<>
#include "model/Complex_typedefs.h"
@@ -20,89 +45,73 @@ class Viewer;
class Viewer_parameter;
-class Viewer_instructor : public QWidget{
- Q_OBJECT
-
- typedef Geometry_trait::Point_3 Point_3;
- typedef Complex::Point Point;
- typedef Complex::Vertex_handle Vertex_handle;
- typedef Complex::Edge_handle Edge_handle;
- typedef Complex::Simplex_handle Simplex_handle;
-
-
- Viewer* viewer_;
- View_parameter view_params_;
- const Complex& mesh_;
- std::unique_ptr<Projector3D> projector_;
-
-
-public:
-
- Viewer_instructor(QWidget* parent,
- Viewer* viewer,
- const Complex& mesh
- );
-
-
- void initialize_bounding_box();
-
- std::pair<Point,Point> compute_bounding_box_corners();
-
- void show_entire_scene();
-
- const qglviewer::Camera* camera() const;
-
- int width() const;
- int height() const;
-
- /**
- * to change display parameters
- */
- View_parameter& view_params();
+class Viewer_instructor : public QWidget {
+ Q_OBJECT
+ typedef Geometry_trait::Point_3 Point_3;
+ typedef Complex::Point Point;
+ typedef Complex::Vertex_handle Vertex_handle;
+ typedef Complex::Edge_handle Edge_handle;
+ typedef Complex::Simplex Simplex;
-public:
+ Viewer* viewer_;
+ View_parameter view_params_;
+ const Complex& mesh_;
+ std::unique_ptr<Projector3D> projector_;
- /**
- * gives instructions to the viewer
- */
- void give_instructions();
+ public:
+ Viewer_instructor(QWidget* parent, Viewer* viewer, const Complex& mesh);
- void draw_edges();
- void draw_triangles();
- void draw_points();
+ void initialize_bounding_box();
+ std::pair<Point, Point> compute_bounding_box_corners();
- void draw_edge(const Point&,const Point&);
+ void show_entire_scene();
- void draw_point(const Point&);
+ const qglviewer::Camera* camera() const;
+ int width() const;
+ int height() const;
- /**
- * set the right color of vertex/edge/triangle considering the view_params choice
- */
- void set_color_vertex(Vertex_handle vh);
- void set_color_edge(Edge_handle eh);
+ /**
+ * to change display parameters
+ */
+ View_parameter& view_params();
- void set_color_triangle(const Simplex_handle& triangle);
+ public:
+ /**
+ * gives instructions to the viewer
+ */
+ void give_instructions();
-private:
- /**
- * Projection to 3D needed for the viewer.
- */
- Point_3 proj(const Point& p) const;
+ void draw_edges();
+ void draw_triangles();
+ void draw_points();
- public slots :
+ void draw_edge(const Point&, const Point&);
- void sceneChanged();
+ void draw_point(const Point&);
- void change_draw_vertices();
- void change_draw_edges();
- void change_draw_triangles();
- void change_light();
+ /**
+ * set the right color of vertex/edge/triangle considering the view_params choice
+ */
+ void set_color_vertex(Vertex_handle vh);
+ void set_color_edge(Edge_handle eh);
+ void set_color_triangle(const Simplex& triangle);
+ private:
+ /**
+ * Projection to 3D needed for the viewer.
+ */
+ Point_3 proj(const Point& p) const;
+ public slots:
+ void sceneChanged();
+ void change_draw_vertices();
+ void change_draw_edges();
+ void change_draw_triangles();
+ void change_light();
};
-#endif //VIEWER_INSTRUCTOR_H
+#endif // VIEW_VIEWER_INSTRUCTOR_H_
diff --git a/src/Hasse_complex/example/CMakeLists.txt b/src/Hasse_complex/example/CMakeLists.txt deleted file mode 100644 index 564df49d..00000000 --- a/src/Hasse_complex/example/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -cmake_minimum_required(VERSION 2.6) -project(GUDHIHasseComplexExample) - -add_executable ( hasse_complex_from_simplex_tree hasse_complex_from_simplex_tree.cpp ) -add_test(hasse_complex_from_simplex_tree ${CMAKE_CURRENT_BINARY_DIR}/hasse_complex_from_simplex_tree) diff --git a/src/Hasse_complex/example/hasse_complex_from_simplex_tree.cpp b/src/Hasse_complex/example/hasse_complex_from_simplex_tree.cpp deleted file mode 100644 index 1de43ab7..00000000 --- a/src/Hasse_complex/example/hasse_complex_from_simplex_tree.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* 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 Saclay (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/Simplex_tree.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; -typedef Simplex_tree<> typeST; - -int main(int argc, char * const argv[]) { - // TEST OF INSERTION - std::cout << "********************************************************************" << std::endl; - std::cout << "TEST OF INSERTION" << std::endl; - typeST st; - - // ++ FIRST - std::cout << " - INSERT (2,1,0)" << std::endl; - typeVectorVertex SimplexVector1; - SimplexVector1.push_back(2); - SimplexVector1.push_back(1); - SimplexVector1.push_back(0); - st.insert_simplex_and_subfaces(SimplexVector1, 0.3); - - // ++ SECOND - std::cout << " - INSERT 3" << std::endl; - typeVectorVertex SimplexVector2; - SimplexVector2.push_back(3); - st.insert_simplex_and_subfaces(SimplexVector2, 0.1); - - // ++ THIRD - std::cout << " - INSERT (0,3)" << std::endl; - typeVectorVertex SimplexVector3; - SimplexVector3.push_back(3); - SimplexVector3.push_back(0); - st.insert_simplex_and_subfaces(SimplexVector3, 0.2); - - // ++ FOURTH - std::cout << " - INSERT (1,0) (already inserted)" << std::endl; - typeVectorVertex SimplexVector4; - SimplexVector4.push_back(1); - SimplexVector4.push_back(0); - st.insert_simplex_and_subfaces(SimplexVector4, 0.2); - - // ++ FIFTH - std::cout << " - INSERT (3,4,5)" << std::endl; - typeVectorVertex SimplexVector5; - SimplexVector5.push_back(3); - SimplexVector5.push_back(4); - SimplexVector5.push_back(5); - st.insert_simplex_and_subfaces(SimplexVector5, 0.3); - - // ++ SIXTH - std::cout << " - INSERT (0,1,6,7)" << std::endl; - typeVectorVertex SimplexVector6; - SimplexVector6.push_back(0); - SimplexVector6.push_back(1); - SimplexVector6.push_back(6); - SimplexVector6.push_back(7); - st.insert_simplex_and_subfaces(SimplexVector6, 0.4); - - /* Inserted simplex: */ - /* 1 6 */ - /* o---o */ - /* /X\7/ 4 */ - /* o---o---o---o */ - /* 2 0 3\X/ */ - /* o */ - /* 5 */ - - /* In other words: */ - /* A facet [2,1,0] */ - /* An edge [0,3] */ - /* A facet [3,4,5] */ - /* A cell [0,1,6,7] */ - /* A cell [4,5,8,9] */ - /* A facet [9,10,11] */ - /* An edge [11,6] */ - /* An edge [10,12,2] */ - - // ++ GENERAL VARIABLE SET - st.set_filtration(0.4); // Max filtration value - st.set_dimension(3); // Max dimension = 3 -> (0,1,6,7) - - std::cout << "The complex contains " << st.num_simplices() << " simplices - " << st.num_vertices() << " vertices " << std::endl; - std::cout << " - dimension " << st.dimension() << " - filtration " << st.filtration() << std::endl; - std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; - std::cout << "**************************************************************" << std::endl; - - for( auto f_simplex : st.filtration_simplex_range() ) - { - std::cout << " " << "[" << st.filtration(f_simplex) << "] "; - for( auto vertex : st.simplex_vertex_range(f_simplex) ) - { - std::cout << (int)vertex; - } - } - - return 0; -} diff --git a/src/Hasse_complex/include/gudhi/Hasse_complex.h b/src/Hasse_complex/include/gudhi/Hasse_complex.h index 427d9916..67079687 100644 --- a/src/Hasse_complex/include/gudhi/Hasse_complex.h +++ b/src/Hasse_complex/include/gudhi/Hasse_complex.h @@ -1,208 +1,234 @@ - /* 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): Clément Maria - * - * 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/>. - */ - -#ifndef GUDHI_HASSE_DIAGRAM_H -#define GUDHI_HASSE_DIAGRAM_H +/* 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): Clément Maria + * + * 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/>. + */ + +#ifndef HASSE_COMPLEX_H_ +#define HASSE_COMPLEX_H_ -#include <algorithm> #include <boost/iterator/counting_iterator.hpp> -namespace Gudhi{ +#include <algorithm> +#include <utility> // for pair +#include <vector> + +namespace Gudhi { template < class HasseCpx > -struct Hasse_simplex -{ -//Complex_ds must verify that cpx->key(sh) is the order of sh in the filtration +struct Hasse_simplex { + // Complex_ds must verify that cpx->key(sh) is the order of sh in the filtration + template< class Complex_ds > - Hasse_simplex ( Complex_ds & cpx - , typename Complex_ds::Simplex_handle sh ) - : key_(cpx.key(sh)) - , filtration_(cpx.filtration(sh)) - , boundary_() - { - boundary_.reserve(cpx.dimension(sh)+1); - for( auto b_sh : cpx.boundary_simplex_range(sh) ) - { boundary_.push_back( cpx.key(b_sh) ); } - } - - Hasse_simplex ( typename HasseCpx::Simplex_key key + Hasse_simplex(Complex_ds & cpx + , typename Complex_ds::Simplex_handle sh) + : key_(cpx.key(sh)) + , filtration_(cpx.filtration(sh)) + , boundary_() { + boundary_.reserve(cpx.dimension(sh) + 1); + for (auto b_sh : cpx.boundary_simplex_range(sh)) { + boundary_.push_back(cpx.key(b_sh)); + } + } + + Hasse_simplex(typename HasseCpx::Simplex_key key , typename HasseCpx::Filtration_value fil , std::vector<typename HasseCpx::Simplex_handle> boundary) - : key_(key) - , filtration_(fil) - , boundary_(boundary) {} + : key_(key) + , filtration_(fil) + , boundary_(boundary) { } - typename HasseCpx::Simplex_key key_; - typename HasseCpx::Filtration_value filtration_; + typename HasseCpx::Simplex_key key_; + typename HasseCpx::Filtration_value filtration_; std::vector<typename HasseCpx::Simplex_handle> boundary_; }; - - -/** \brief Data structure representing a Hasse diagram, i.e. - * a complex where all codimension 1 incidence - * relations are explicitly encoded. - * - * \implements FilteredComplex - * \ingroup simplex_tree - */ -template < typename FiltrationValue = double - , typename SimplexKey = int - , typename VertexHandle = int - > -class Hasse_complex -{ -public: - - typedef Hasse_simplex<Hasse_complex> Hasse_simp; - typedef FiltrationValue Filtration_value; - typedef SimplexKey Simplex_key; - typedef int Simplex_handle; //index in vector complex_ - - typedef boost::counting_iterator< Simplex_handle > Filtration_simplex_iterator; - typedef boost::iterator_range<Filtration_simplex_iterator> Filtration_simplex_range; - - typedef typename std::vector< Simplex_handle >::iterator Boundary_simplex_iterator; - typedef boost::iterator_range<Boundary_simplex_iterator> Boundary_simplex_range; - - typedef typename std::vector< Simplex_handle >::iterator Skeleton_simplex_iterator; - typedef boost::iterator_range< Skeleton_simplex_iterator > Skeleton_simplex_range; - - -/* only dimension 0 skeleton_simplex_range(...) */ - Skeleton_simplex_range skeleton_simplex_range( int dim = 0 ) { - if(dim != 0) { std::cerr << "Dimension must be 0 \n"; } - return Skeleton_simplex_range(vertices_.begin(),vertices_.end()); +/** \private + * \brief Data structure representing a Hasse diagram, i.e. + * a complex where all codimension 1 incidence + * relations are explicitly encoded. + * + * \implements FilteredComplex + * \ingroup simplex_tree + */ +template < typename FiltrationValue = double +, typename SimplexKey = int +, typename VertexHandle = int +> +class Hasse_complex { + public: + typedef Hasse_simplex<Hasse_complex> Hasse_simp; + typedef FiltrationValue Filtration_value; + typedef SimplexKey Simplex_key; + typedef int Simplex_handle; // index in vector complex_ + + typedef boost::counting_iterator< Simplex_handle > Filtration_simplex_iterator; + typedef boost::iterator_range<Filtration_simplex_iterator> Filtration_simplex_range; + + typedef typename std::vector< Simplex_handle >::iterator Boundary_simplex_iterator; + typedef boost::iterator_range<Boundary_simplex_iterator> Boundary_simplex_range; + + typedef typename std::vector< Simplex_handle >::iterator Skeleton_simplex_iterator; + typedef boost::iterator_range< Skeleton_simplex_iterator > Skeleton_simplex_range; + + /* only dimension 0 skeleton_simplex_range(...) */ + Skeleton_simplex_range skeleton_simplex_range(int dim = 0) { + if (dim != 0) { + std::cerr << "Dimension must be 0 \n"; + } + return Skeleton_simplex_range(vertices_.begin(), vertices_.end()); } template < class Complex_ds > Hasse_complex(Complex_ds & cpx) - : complex_() - , vertices_() - , threshold_(cpx.filtration()) - , num_vertices_() - , dim_max_(cpx.dimension()) - { + : complex_() + , vertices_() + , threshold_(cpx.filtration()) + , num_vertices_() + , dim_max_(cpx.dimension()) { complex_.reserve(cpx.num_simplices()); int idx = 0; - for(auto cpx_sh : cpx.filtration_simplex_range()) - { - complex_.push_back(Hasse_simp(cpx,cpx_sh)); - if(dimension(idx) == 0) { vertices_.push_back(idx); } - ++idx; + for (auto cpx_sh : cpx.filtration_simplex_range()) { + complex_.push_back(Hasse_simp(cpx, cpx_sh)); + if (dimension(idx) == 0) { + vertices_.push_back(idx); + } + ++idx; } } Hasse_complex() - : complex_() - , vertices_() - , threshold_(0) - , num_vertices_(0) - , dim_max_(-1) {} - - size_t num_simplices() { return complex_.size(); } + : complex_() + , vertices_() + , threshold_(0) + , num_vertices_(0) + , dim_max_(-1) { } + + size_t num_simplices() { + return complex_.size(); + } - Filtration_simplex_range filtration_simplex_range() - { return Filtration_simplex_range( Filtration_simplex_iterator(0) - , Filtration_simplex_iterator(complex_.size()) ); } + Filtration_simplex_range filtration_simplex_range() { + return Filtration_simplex_range(Filtration_simplex_iterator(0) + , Filtration_simplex_iterator(complex_.size())); + } - Simplex_key key( Simplex_handle sh ) { return complex_[sh].key_; } + Simplex_key key(Simplex_handle sh) { + return complex_[sh].key_; + } - Simplex_key null_key() { return -1; } + Simplex_key null_key() { + return -1; + } - Simplex_handle simplex( Simplex_key key ) - { - if(key == null_key()) return null_simplex(); + Simplex_handle simplex(Simplex_key key) { + if (key == null_key()) return null_simplex(); return key; } - Simplex_handle null_simplex() { return -1; } + Simplex_handle null_simplex() { + return -1; + } - Filtration_value filtration( Simplex_handle sh ) { - if( sh == null_simplex() ) { return filtration(); } + Filtration_value filtration(Simplex_handle sh) { + if (sh == null_simplex()) { + return filtration(); + } return complex_[sh].filtration_; } - Filtration_value filtration() { return threshold_; } + Filtration_value filtration() { + return threshold_; + } + + int dimension(Simplex_handle sh) { + if (complex_[sh].boundary_.empty()) return 0; + return complex_[sh].boundary_.size() - 1; + } - int dimension ( Simplex_handle sh ) { - if(complex_[sh].boundary_.empty()) return 0; - return complex_[sh].boundary_.size()-1; + int dimension() { + return dim_max_; } - int dimension () { return dim_max_; } - std::pair<Simplex_handle,Simplex_handle> endpoints( Simplex_handle sh ) - { return std::pair<Simplex_handle,Simplex_handle>( complex_[sh].boundary_[0] - , complex_[sh].boundary_[1] ) ;} + std::pair<Simplex_handle, Simplex_handle> endpoints(Simplex_handle sh) { + return std::pair<Simplex_handle, Simplex_handle>(complex_[sh].boundary_[0] + , complex_[sh].boundary_[1]); + } - void assign_key( Simplex_handle sh, Simplex_key key) { complex_[sh].key_ = key; } + void assign_key(Simplex_handle sh, Simplex_key key) { + complex_[sh].key_ = key; + } - Boundary_simplex_range boundary_simplex_range ( Simplex_handle sh ) - { return Boundary_simplex_range( complex_[sh].boundary_.begin() - , complex_[sh].boundary_.end() ); } + Boundary_simplex_range boundary_simplex_range(Simplex_handle sh) { + return Boundary_simplex_range(complex_[sh].boundary_.begin() + , complex_[sh].boundary_.end()); + } - void display_simplex(Simplex_handle sh) - { + void display_simplex(Simplex_handle sh) { std::cout << dimension(sh) << " "; - for(auto sh_b : boundary_simplex_range(sh)) std::cout << sh_b << " "; + for (auto sh_b : boundary_simplex_range(sh)) std::cout << sh_b << " "; std::cout << " " << filtration(sh) << " key=" << key(sh); } - void initialize_filtration() - { + void initialize_filtration() { Simplex_key key = 0; - for(auto & h_simp : complex_) { h_simp.key_ = key; ++key; } + for (auto & h_simp : complex_) { + h_simp.key_ = key; + ++key; + } } - std::vector< Hasse_simp > complex_; + std::vector< Hasse_simp > complex_; std::vector<Simplex_handle> vertices_; - Filtration_value threshold_; - size_t num_vertices_; - int dim_max_; + Filtration_value threshold_; + size_t num_vertices_; + int dim_max_; }; template< typename T1, typename T2, typename T3 > -std::istream& operator>> ( std::istream & is - , Hasse_complex< T1, T2, T3 > & hcpx ) -{ +std::istream& operator>>(std::istream & is + , Hasse_complex< T1, T2, T3 > & hcpx) { assert(hcpx.num_simplices() == 0); size_t num_simp; is >> num_simp; - hcpx.complex_.reserve(num_simp); - - std::vector< typename Hasse_complex<T1,T2,T3>::Simplex_key > boundary; - typename Hasse_complex<T1,T2,T3>::Filtration_value fil; - typename Hasse_complex<T1,T2,T3>::Filtration_value max_fil = 0 ; - int max_dim = -1; - int key = 0 ; - while(read_hasse_simplex( is, boundary, fil )) //read all simplices in the file as a list of vertices - { - //insert every simplex in the simplex tree - hcpx.complex_.push_back( Hasse_simplex< Hasse_complex<T1,T2,T3> >(key,fil,boundary)); - - if(max_dim < hcpx.dimension(key)) { max_dim = hcpx.dimension(key); } - if(hcpx.dimension(key) == 0) { hcpx.vertices_.push_back(key); } - if(max_fil < fil) { max_fil = fil; } + hcpx.complex_.reserve(num_simp); + + std::vector< typename Hasse_complex<T1, T2, T3>::Simplex_key > boundary; + typename Hasse_complex<T1, T2, T3>::Filtration_value fil; + typename Hasse_complex<T1, T2, T3>::Filtration_value max_fil = 0; + int max_dim = -1; + int key = 0; + // read all simplices in the file as a list of vertices + while (read_hasse_simplex(is, boundary, fil)) { + // insert every simplex in the simplex tree + hcpx.complex_.push_back(Hasse_simplex< Hasse_complex<T1, T2, T3> >(key, fil, boundary)); + + if (max_dim < hcpx.dimension(key)) { + max_dim = hcpx.dimension(key); + } + if (hcpx.dimension(key) == 0) { + hcpx.vertices_.push_back(key); + } + if (max_fil < fil) { + max_fil = fil; + } ++key; boundary.clear(); @@ -214,6 +240,6 @@ std::istream& operator>> ( std::istream & is return is; } -} // namespace GUDHI +} // namespace Gudhi -#endif // GUDHI_HASSE_DIAGRAM_H +#endif // HASSE_COMPLEX_H_ diff --git a/src/Persistent_cohomology/example/CMakeLists.txt b/src/Persistent_cohomology/example/CMakeLists.txt index 9487cce6..50d10025 100644 --- a/src/Persistent_cohomology/example/CMakeLists.txt +++ b/src/Persistent_cohomology/example/CMakeLists.txt @@ -2,39 +2,47 @@ cmake_minimum_required(VERSION 2.6) project(GUDHIExPersCohom) # problem with Visual Studio link on Boost program_options -if (NOT MSVC) - add_executable(persistence_from_simple_simplex_tree persistence_from_simple_simplex_tree.cpp) - target_link_libraries(persistence_from_simple_simplex_tree ${Boost_SYSTEM_LIBRARY}) +add_definitions( -DBOOST_ALL_NO_LIB ) +add_definitions( -DBOOST_ALL_DYN_LINK ) - add_executable(rips_persistence rips_persistence.cpp) - target_link_libraries(rips_persistence ${Boost_SYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY}) - - add_test(rips_persistence_3 ${CMAKE_CURRENT_BINARY_DIR}/rips_persistence ${CMAKE_SOURCE_DIR}/data/points/Kl.txt -r 0.25 -d 3 -p 3 -m 100) - - add_executable(persistence_from_file persistence_from_file.cpp) - target_link_libraries(persistence_from_file ${Boost_SYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY}) - add_test(persistence_from_file_3_2_0 ${CMAKE_CURRENT_BINARY_DIR}/persistence_from_file ${CMAKE_SOURCE_DIR}/data/points/bunny_5000.st -p 2 -m 0) - add_test(persistence_from_file_3_3_100 ${CMAKE_CURRENT_BINARY_DIR}/persistence_from_file ${CMAKE_SOURCE_DIR}/data/points/bunny_5000.st -p 3 -m 100) - - if(GMPXX_FOUND AND GMP_FOUND) - message("GMPXX_LIBRARIES = ${GMPXX_LIBRARIES}") - message("GMP_LIBRARIES = ${GMP_LIBRARIES}") - - add_executable(rips_multifield_persistence rips_multifield_persistence.cpp ) - target_link_libraries(rips_multifield_persistence ${Boost_SYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${GMPXX_LIBRARIES} ${GMP_LIBRARIES}) - add_test(rips_multifield_persistence_2_71 ${CMAKE_CURRENT_BINARY_DIR}/rips_multifield_persistence ${CMAKE_SOURCE_DIR}/data/points/Kl.txt -r 0.25 -d 3 -p 2 -q 71 -m 100) +add_executable(plain_homology plain_homology.cpp) +target_link_libraries(plain_homology ${Boost_SYSTEM_LIBRARY}) +add_test(plain_homology ${CMAKE_CURRENT_BINARY_DIR}/plain_homology) + +add_executable(persistence_from_simple_simplex_tree persistence_from_simple_simplex_tree.cpp) +target_link_libraries(persistence_from_simple_simplex_tree ${Boost_SYSTEM_LIBRARY}) +add_test(persistence_from_simple_simplex_tree ${CMAKE_CURRENT_BINARY_DIR}/persistence_from_simple_simplex_tree 1 0) + +add_executable(rips_persistence rips_persistence.cpp) +target_link_libraries(rips_persistence ${Boost_SYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY}) - add_executable ( performance_rips_persistence performance_rips_persistence.cpp ) - target_link_libraries(performance_rips_persistence ${Boost_SYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${GMPXX_LIBRARIES} ${GMP_LIBRARIES}) +add_test(rips_persistence_3 ${CMAKE_CURRENT_BINARY_DIR}/rips_persistence ${CMAKE_SOURCE_DIR}/data/points/Kl.txt -r 0.25 -d 3 -p 3 -m 100) - if(CGAL_FOUND) - # uncomment to display debug traces - # add_definitions(-DDEBUG_TRACES) - add_executable(alpha_shapes_persistence alpha_shapes_persistence.cpp) - target_link_libraries(alpha_shapes_persistence ${Boost_SYSTEM_LIBRARY} ${GMPXX_LIBRARIES} ${GMP_LIBRARIES} ${CGAL_LIBRARY}) - add_test(alpha_shapes_persistence_2_0_5 ${CMAKE_CURRENT_BINARY_DIR}/alpha_shapes_persistence ${CMAKE_SOURCE_DIR}/data/points/bunny_5000 2 0.5) - #add_test(alpha_shapes_persistence_3_3_100 ${CMAKE_CURRENT_BINARY_DIR}/alpha_shapes_persistence ${CMAKE_SOURCE_DIR}/data/points/bunny_5000.st -p 3 -m 100) - endif() +add_executable(persistence_from_file persistence_from_file.cpp) +target_link_libraries(persistence_from_file ${Boost_SYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY}) +add_test(persistence_from_file_3_2_0 ${CMAKE_CURRENT_BINARY_DIR}/persistence_from_file ${CMAKE_SOURCE_DIR}/data/points/bunny_5000.st -p 2 -m 0) +add_test(persistence_from_file_3_3_100 ${CMAKE_CURRENT_BINARY_DIR}/persistence_from_file ${CMAKE_SOURCE_DIR}/data/points/bunny_5000.st -p 3 -m 100) +if(GMPXX_FOUND AND GMP_FOUND) + message("GMPXX_LIBRARIES = ${GMPXX_LIBRARIES}") + message("GMP_LIBRARIES = ${GMP_LIBRARIES}") + + add_executable(rips_multifield_persistence rips_multifield_persistence.cpp ) + target_link_libraries(rips_multifield_persistence ${Boost_SYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${GMPXX_LIBRARIES} ${GMP_LIBRARIES}) + add_test(rips_multifield_persistence_2_71 ${CMAKE_CURRENT_BINARY_DIR}/rips_multifield_persistence ${CMAKE_SOURCE_DIR}/data/points/Kl.txt -r 0.25 -d 3 -p 2 -q 71 -m 100) + + add_executable ( performance_rips_persistence performance_rips_persistence.cpp ) + target_link_libraries(performance_rips_persistence ${Boost_SYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${GMPXX_LIBRARIES} ${GMP_LIBRARIES}) + + if(CGAL_FOUND) + if (CMAKE_BUILD_TYPE MATCHES Debug) + # For programs to be more verbose + add_definitions(-DDEBUG_TRACES) + endif() + add_executable(alpha_shapes_persistence alpha_shapes_persistence.cpp) + target_link_libraries(alpha_shapes_persistence ${Boost_SYSTEM_LIBRARY} ${GMPXX_LIBRARIES} ${GMP_LIBRARIES} ${CGAL_LIBRARY}) + add_test(alpha_shapes_persistence_2_0_5 ${CMAKE_CURRENT_BINARY_DIR}/alpha_shapes_persistence ${CMAKE_SOURCE_DIR}/data/points/bunny_5000 2 0.5) + #add_test(alpha_shapes_persistence_3_3_100 ${CMAKE_CURRENT_BINARY_DIR}/alpha_shapes_persistence ${CMAKE_SOURCE_DIR}/data/points/bunny_5000.st -p 3 -m 100) endif() + endif() diff --git a/src/Persistent_cohomology/example/alpha_shapes_persistence.cpp b/src/Persistent_cohomology/example/alpha_shapes_persistence.cpp index 3a50c84c..6d5eebcf 100644 --- a/src/Persistent_cohomology/example/alpha_shapes_persistence.cpp +++ b/src/Persistent_cohomology/example/alpha_shapes_persistence.cpp @@ -1,24 +1,29 @@ - /* 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 Saclay (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/>. - */ +/* 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 Saclay (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <gudhi/graph_simplicial_complex.h> +#include <gudhi/Simplex_tree.h> +#include <gudhi/Persistent_cohomology.h> +#include <boost/variant.hpp> #include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Delaunay_triangulation_3.h> @@ -27,36 +32,37 @@ #include <fstream> #include <cmath> - -#include "gudhi/graph_simplicial_complex.h" -#include "gudhi/Simplex_tree.h" -#include "gudhi/Persistent_cohomology.h" -#include <boost/variant.hpp> +#include <string> +#include <tuple> +#include <map> +#include <utility> +#include <list> +#include <vector> using namespace Gudhi; using namespace Gudhi::persistent_cohomology; // Alpha_shape_3 templates type definitions typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; -typedef CGAL::Alpha_shape_vertex_base_3<Kernel> Vb; -typedef CGAL::Alpha_shape_cell_base_3<Kernel> Fb; -typedef CGAL::Triangulation_data_structure_3<Vb,Fb> Tds; -typedef CGAL::Delaunay_triangulation_3<Kernel,Tds> Triangulation_3; -typedef CGAL::Alpha_shape_3<Triangulation_3> Alpha_shape_3; +typedef CGAL::Alpha_shape_vertex_base_3<Kernel> Vb; +typedef CGAL::Alpha_shape_cell_base_3<Kernel> Fb; +typedef CGAL::Triangulation_data_structure_3<Vb, Fb> Tds; +typedef CGAL::Delaunay_triangulation_3<Kernel, Tds> Triangulation_3; +typedef CGAL::Alpha_shape_3<Triangulation_3> Alpha_shape_3; // From file type definition -typedef Kernel::Point_3 Point_3; +typedef Kernel::Point_3 Point_3; // filtration with alpha values needed type definition typedef Alpha_shape_3::FT Alpha_value_type; -typedef CGAL::Object Object; +typedef CGAL::Object Object; typedef CGAL::Dispatch_output_iterator< - CGAL::cpp11::tuple<Object, Alpha_value_type>, - CGAL::cpp11::tuple<std::back_insert_iterator< std::vector<Object> >, std::back_insert_iterator< std::vector<Alpha_value_type> > - > > Dispatch; -typedef Alpha_shape_3::Cell_handle Cell_handle; -typedef Alpha_shape_3::Facet Facet; -typedef Alpha_shape_3::Edge Edge_3; +CGAL::cpp11::tuple<Object, Alpha_value_type>, +CGAL::cpp11::tuple<std::back_insert_iterator< std::vector<Object> >, + std::back_insert_iterator< std::vector<Alpha_value_type> > > > Dispatch; +typedef Alpha_shape_3::Cell_handle Cell_handle; +typedef Alpha_shape_3::Facet Facet; +typedef Alpha_shape_3::Edge Edge_3; typedef std::list<Alpha_shape_3::Vertex_handle> Vertex_list; // gudhi type definition @@ -65,70 +71,60 @@ typedef std::map<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex > Alpha_shape typedef std::pair<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex> Alpha_shape_simplex_tree_pair; typedef std::vector< Simplex_tree_vertex > Simplex_tree_vector_vertex; -//#define DEBUG_TRACES - -Vertex_list from (const Cell_handle& ch) -{ +Vertex_list from(const Cell_handle& ch) { Vertex_list the_list; - for (auto i = 0; i < 4; i++) - { + for (auto i = 0; i < 4; i++) { #ifdef DEBUG_TRACES std::cout << "from cell[" << i << "]=" << ch->vertex(i)->point() << std::endl; -#endif // DEBUG_TRACES +#endif // DEBUG_TRACES the_list.push_back(ch->vertex(i)); } return the_list; } -Vertex_list from (const Facet& fct) -{ + +Vertex_list from(const Facet& fct) { Vertex_list the_list; - for (auto i = 0; i < 4; i++) - { - if (fct.second != i) - { + for (auto i = 0; i < 4; i++) { + if (fct.second != i) { #ifdef DEBUG_TRACES std::cout << "from facet=[" << i << "]" << fct.first->vertex(i)->point() << std::endl; -#endif // DEBUG_TRACES +#endif // DEBUG_TRACES the_list.push_back(fct.first->vertex(i)); } } return the_list; } -Vertex_list from (const Edge_3& edg) -{ + +Vertex_list from(const Edge_3& edg) { Vertex_list the_list; - for (auto i = 0; i < 4; i++) - { - if ((edg.second == i) ||(edg.third == i)) - { + for (auto i = 0; i < 4; i++) { + if ((edg.second == i) || (edg.third == i)) { #ifdef DEBUG_TRACES std::cout << "from edge[" << i << "]=" << edg.first->vertex(i)->point() << std::endl; -#endif // DEBUG_TRACES +#endif // DEBUG_TRACES the_list.push_back(edg.first->vertex(i)); } } return the_list; } -Vertex_list from (const Alpha_shape_3::Vertex_handle& vh) -{ + +Vertex_list from(const Alpha_shape_3::Vertex_handle& vh) { Vertex_list the_list; #ifdef DEBUG_TRACES std::cout << "from vertex=" << vh->point() << std::endl; -#endif // DEBUG_TRACES +#endif // DEBUG_TRACES the_list.push_back(vh); return the_list; } -void usage(char * const progName) -{ - std::cerr << "Usage: " << progName << " path_to_file_graph coeff_field_characteristic[integer > 0] min_persistence[float >= -1.0]\n"; - exit(-1); // ----- >> +void usage(char * const progName) { + std::cerr << "Usage: " << progName << + " path_to_file_graph coeff_field_characteristic[integer > 0] min_persistence[float >= -1.0]\n"; + exit(-1); } -int main (int argc, char * const argv[]) -{ - - int coeff_field_characteristic=0; +int main(int argc, char * const argv[]) { + int coeff_field_characteristic = 0; int returnedScanValue = sscanf(argv[2], "%d", &coeff_field_characteristic); if ((returnedScanValue == EOF) || (coeff_field_characteristic <= 0)) { std::cerr << "Error: " << argv[2] << " is not correct\n"; @@ -149,102 +145,96 @@ int main (int argc, char * const argv[]) } // Read points from file - std::string filegraph = argv[1]; + std::string filegraph = argv[1]; std::list<Point_3> lp; std::ifstream is(filegraph.c_str()); int n; is >> n; #ifdef DEBUG_TRACES std::cout << "Reading " << n << " points " << std::endl; -#endif // DEBUG_TRACES +#endif // DEBUG_TRACES Point_3 p; - for( ; n>0 ; n--) { + for (; n > 0; n--) { is >> p; lp.push_back(p); } // alpha shape construction from points. CGAL has a strange behavior in REGULARIZED mode. - Alpha_shape_3 as(lp.begin(),lp.end(),0,Alpha_shape_3::GENERAL); + Alpha_shape_3 as(lp.begin(), lp.end(), 0, Alpha_shape_3::GENERAL); #ifdef DEBUG_TRACES std::cout << "Alpha shape computed in GENERAL mode" << std::endl; -#endif // DEBUG_TRACES +#endif // DEBUG_TRACES // filtration with alpha values from alpha shape std::vector<Object> the_objects; std::vector<Alpha_value_type> the_alpha_values; - Dispatch disp = CGAL::dispatch_output<Object, Alpha_value_type>( std::back_inserter(the_objects), std::back_inserter(the_alpha_values)); + Dispatch disp = CGAL::dispatch_output<Object, Alpha_value_type>(std::back_inserter(the_objects), + std::back_inserter(the_alpha_values)); as.filtration_with_alpha_values(disp); #ifdef DEBUG_TRACES std::cout << "filtration_with_alpha_values returns : " << the_objects.size() << " objects" << std::endl; -#endif // DEBUG_TRACES +#endif // DEBUG_TRACES Alpha_shape_3::size_type count_vertices = 0; - Alpha_shape_3::size_type count_edges = 0; - Alpha_shape_3::size_type count_facets = 0; - Alpha_shape_3::size_type count_cells = 0; + Alpha_shape_3::size_type count_edges = 0; + Alpha_shape_3::size_type count_facets = 0; + Alpha_shape_3::size_type count_cells = 0; // Loop on objects vector Vertex_list vertex_list; Simplex_tree<> simplex_tree; Alpha_shape_simplex_tree_map map_cgal_simplex_tree; std::vector<Alpha_value_type>::iterator the_alpha_value_iterator = the_alpha_values.begin(); - int dim_max=0; - Filtration_value filtration_max=0.0; - for(auto object_iterator: the_objects) - { + int dim_max = 0; + Filtration_value filtration_max = 0.0; + for (auto object_iterator : the_objects) { // Retrieve Alpha shape vertex list from object - if (const Cell_handle* cell = CGAL::object_cast<Cell_handle>(&object_iterator)) - { + if (const Cell_handle * cell = CGAL::object_cast<Cell_handle>(&object_iterator)) { vertex_list = from(*cell); count_cells++; if (dim_max < 3) { - dim_max=3; // Cell is of dim 3 + // Cell is of dim 3 + dim_max = 3; } - } - else if (const Facet* facet = CGAL::object_cast<Facet>(&object_iterator)) - { + } else if (const Facet * facet = CGAL::object_cast<Facet>(&object_iterator)) { vertex_list = from(*facet); count_facets++; if (dim_max < 2) { - dim_max=2; // Facet is of dim 2 + // Facet is of dim 2 + dim_max = 2; } - } - else if (const Edge_3* edge = CGAL::object_cast<Edge_3>(&object_iterator)) - { + } else if (const Edge_3 * edge = CGAL::object_cast<Edge_3>(&object_iterator)) { vertex_list = from(*edge); count_edges++; if (dim_max < 1) { - dim_max=1; // Edge_3 is of dim 1 + // Edge_3 is of dim 1 + dim_max = 1; } - } - else if (const Alpha_shape_3::Vertex_handle* vertex = CGAL::object_cast<Alpha_shape_3::Vertex_handle>(&object_iterator)) - { + } else if (const Alpha_shape_3::Vertex_handle * vertex = + CGAL::object_cast<Alpha_shape_3::Vertex_handle>(&object_iterator)) { count_vertices++; vertex_list = from(*vertex); } // Construction of the vector of simplex_tree vertex from list of alpha_shapes vertex Simplex_tree_vector_vertex the_simplex_tree; - for (auto the_alpha_shape_vertex:vertex_list) - { + for (auto the_alpha_shape_vertex : vertex_list) { Alpha_shape_simplex_tree_map::iterator the_map_iterator = map_cgal_simplex_tree.find(the_alpha_shape_vertex); - if (the_map_iterator == map_cgal_simplex_tree.end()) - { + if (the_map_iterator == map_cgal_simplex_tree.end()) { // alpha shape not found Simplex_tree_vertex vertex = map_cgal_simplex_tree.size(); #ifdef DEBUG_TRACES std::cout << "vertex [" << the_alpha_shape_vertex->point() << "] not found - insert " << vertex << std::endl; -#endif // DEBUG_TRACES +#endif // DEBUG_TRACES the_simplex_tree.push_back(vertex); - map_cgal_simplex_tree.insert(Alpha_shape_simplex_tree_pair(the_alpha_shape_vertex,vertex)); - } else - { + map_cgal_simplex_tree.insert(Alpha_shape_simplex_tree_pair(the_alpha_shape_vertex, vertex)); + } else { // alpha shape found Simplex_tree_vertex vertex = the_map_iterator->second; #ifdef DEBUG_TRACES std::cout << "vertex [" << the_alpha_shape_vertex->point() << "] found in " << vertex << std::endl; -#endif // DEBUG_TRACES +#endif // DEBUG_TRACES the_simplex_tree.push_back(vertex); } } @@ -252,7 +242,7 @@ int main (int argc, char * const argv[]) Filtration_value filtr = std::sqrt(*the_alpha_value_iterator); #ifdef DEBUG_TRACES std::cout << "filtration = " << filtr << std::endl; -#endif // DEBUG_TRACES +#endif // DEBUG_TRACES if (filtr > filtration_max) { filtration_max = filtr; } @@ -263,14 +253,13 @@ int main (int argc, char * const argv[]) std::cout << "This shall not happen" << std::endl; } simplex_tree.set_filtration(filtration_max); - simplex_tree.set_num_simplices(count_vertices + count_edges + count_facets + count_cells); simplex_tree.set_dimension(dim_max); #ifdef DEBUG_TRACES std::cout << "vertices \t\t" << count_vertices << std::endl; - std::cout << "edges \t\t" << count_edges << std::endl; - std::cout << "facets \t\t" << count_facets << std::endl; - std::cout << "cells \t\t" << count_cells << std::endl; + std::cout << "edges \t\t" << count_edges << std::endl; + std::cout << "facets \t\t" << count_facets << std::endl; + std::cout << "cells \t\t" << count_cells << std::endl; std::cout << "Information of the Simplex Tree: " << std::endl; @@ -278,23 +267,25 @@ int main (int argc, char * const argv[]) std::cout << " Number of simplices = " << simplex_tree.num_simplices() << std::endl << std::endl; std::cout << " Dimension = " << simplex_tree.dimension() << " "; std::cout << " filtration = " << simplex_tree.filtration() << std::endl << std::endl; -#endif // DEBUG_TRACES +#endif // DEBUG_TRACES #ifdef DEBUG_TRACES std::cout << "Iterator on vertices: " << std::endl; - for( auto vertex : simplex_tree.complex_vertex_range() ) - { std::cout << vertex << " "; } -#endif // DEBUG_TRACES + for (auto vertex : simplex_tree.complex_vertex_range()) { + std::cout << vertex << " "; + } +#endif // DEBUG_TRACES // Sort the simplices in the order of the filtration simplex_tree.initialize_filtration(); std::cout << "Simplex_tree dim: " << simplex_tree.dimension() << std::endl; // Compute the persistence diagram of the complex - Persistent_cohomology< Simplex_tree<>, Field_Zp > pcoh( simplex_tree ); - pcoh.init_coefficients( coeff_field_characteristic ); //initializes the coefficient field for homology + Persistent_cohomology< Simplex_tree<>, Field_Zp > pcoh(simplex_tree); + // initializes the coefficient field for homology + pcoh.init_coefficients(coeff_field_characteristic); - pcoh.compute_persistent_cohomology( min_persistence ); + pcoh.compute_persistent_cohomology(min_persistence); pcoh.output_diagram(); diff --git a/src/Persistent_cohomology/example/performance_rips_persistence.cpp b/src/Persistent_cohomology/example/performance_rips_persistence.cpp index 077c2b07..fc48d6b1 100644 --- a/src/Persistent_cohomology/example/performance_rips_persistence.cpp +++ b/src/Persistent_cohomology/example/performance_rips_persistence.cpp @@ -1,49 +1,51 @@ - /* 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): Clément Maria - * - * 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 "gudhi/reader_utils.h" -#include "gudhi/graph_simplicial_complex.h" -#include "gudhi/distance_functions.h" -#include "gudhi/Simplex_tree.h" -#include "gudhi/Persistent_cohomology.h" -#include "gudhi/Persistent_cohomology/Multi_field.h" -#include "gudhi/Hasse_complex.h" +/* 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): Clément Maria + * + * 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 <gudhi/reader_utils.h> +#include <gudhi/graph_simplicial_complex.h> +#include <gudhi/distance_functions.h> +#include <gudhi/Simplex_tree.h> +#include <gudhi/Persistent_cohomology.h> +#include <gudhi/Persistent_cohomology/Multi_field.h> +#include <gudhi/Hasse_complex.h> #include <chrono> +#include <string> +#include <vector> using namespace Gudhi; using namespace Gudhi::persistent_cohomology; /* Compute the persistent homology of the complex cpx with coefficients in Z/pZ. */ template< typename FilteredComplex> -void timing_persistence( FilteredComplex & cpx - , int p ); +void timing_persistence(FilteredComplex & cpx + , int p); /* Compute multi-field persistent homology of the complex cpx with coefficients in * Z/rZ for all prime number r in [p;q].*/ template< typename FilteredComplex> -void timing_persistence( FilteredComplex & cpx - , int p - , int q ); +void timing_persistence(FilteredComplex & cpx + , int p + , int q); /* Timings for the computation of persistent homology with different * representations of a Rips complex and different coefficient fields. The @@ -59,111 +61,154 @@ void timing_persistence( FilteredComplex & cpx * We present also timings for the computation of multi-field persistent * homology in all fields Z/rZ for r prime between 2 and 1223. */ -int main (int argc, char * argv[]) -{ +int main(int argc, char * argv[]) { std::chrono::time_point<std::chrono::system_clock> start, end; - int enlapsed_sec; + int elapsed_sec; + { - std::string filepoints = "../examples/Kl.txt"; - Filtration_value threshold = 0.3; - int dim_max = 3; - int p = 2; - int q = 1223; + std::string filepoints = "../../../data/points/Kl.txt"; + Filtration_value threshold = 0.27; + int dim_max = 3; + int p = 2; + int q = 1223; -// Extract the points from the file filepoints + // Extract the points from the file filepoints typedef std::vector<double> Point_t; std::vector< Point_t > points; - read_points( filepoints, points ); + read_points(filepoints, points); -// Compute the proximity graph of the points + // Compute the proximity graph of the points start = std::chrono::system_clock::now(); - Graph_t prox_graph = compute_proximity_graph( points, threshold - , euclidean_distance<Point_t> ); + Graph_t prox_graph = compute_proximity_graph(points, threshold + , euclidean_distance<Point_t>); end = std::chrono::system_clock::now(); - enlapsed_sec = std::chrono::duration_cast<std::chrono::seconds>(end-start).count(); - std::cout << "Compute Rips graph in " << enlapsed_sec << " sec.\n"; + elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); + std::cout << "Compute Rips graph in " << elapsed_sec << " ms.\n"; -// Construct the Rips complex in a Simplex Tree - Simplex_tree<> st; + // Construct the Rips complex in a Simplex Tree + Simplex_tree<> st; start = std::chrono::system_clock::now(); - st.insert_graph(prox_graph); // insert the proximity graph in the simplex tree - st.expansion( dim_max ); // expand the graph until dimension dim_max + // insert the proximity graph in the simplex tree + st.insert_graph(prox_graph); + // expand the graph until dimension dim_max + st.expansion(dim_max); end = std::chrono::system_clock::now(); - enlapsed_sec = std::chrono::duration_cast<std::chrono::seconds>(end-start).count(); - std::cout << "Compute Rips complex in " << enlapsed_sec << " sec.\n"; + elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); + std::cout << "Compute Rips complex in " << elapsed_sec << " ms.\n"; std::cout << " - dimension = " << st.dimension() << std::endl; std::cout << " - number of simplices = " << st.num_simplices() << std::endl; -// Sort the simplices in the order of the filtration + // Sort the simplices in the order of the filtration start = std::chrono::system_clock::now(); st.initialize_filtration(); end = std::chrono::system_clock::now(); - enlapsed_sec = std::chrono::duration_cast<std::chrono::seconds>(end-start).count(); - std::cout << "Order the simplices of the filtration in " << enlapsed_sec << " sec.\n"; + elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); + std::cout << "Order the simplices of the filtration in " << elapsed_sec << " ms.\n"; + + // Copy the keys inside the simplices + start = std::chrono::system_clock::now(); + { + int count = 0; + for (auto sh : st.filtration_simplex_range()) + st.assign_key(sh, count++); + } + end = std::chrono::system_clock::now(); + elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); + std::cout << "Copied the keys inside the simplices in " << elapsed_sec << " ms.\n"; -// Convert the simplex tree into a hasse diagram + // Convert the simplex tree into a hasse diagram start = std::chrono::system_clock::now(); Hasse_complex<> hcpx(st); end = std::chrono::system_clock::now(); - enlapsed_sec = std::chrono::duration_cast<std::chrono::seconds>(end-start).count(); - std::cout << "Convert the simplex tree into a Hasse diagram in " << enlapsed_sec << " sec.\n"; + elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); + std::cout << "Convert the simplex tree into a Hasse diagram in " << elapsed_sec << " ms.\n"; std::cout << "Timings when using a simplex tree: \n"; - timing_persistence(st,p); - timing_persistence(st,q); - timing_persistence(st,p,q); + timing_persistence(st, p); + timing_persistence(st, q); + timing_persistence(st, p, q); std::cout << "Timings when using a Hasse complex: \n"; - timing_persistence(hcpx,p); - timing_persistence(hcpx,q); - timing_persistence(hcpx,p,q); + timing_persistence(hcpx, p); + timing_persistence(hcpx, q); + timing_persistence(hcpx, p, q); + start = std::chrono::system_clock::now(); + } + end = std::chrono::system_clock::now(); + elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); + std::cout << "Running the complex destructors in " << elapsed_sec << " ms.\n"; return 0; } - template< typename FilteredComplex> void -timing_persistence( FilteredComplex & cpx - , int p ) -{ +timing_persistence(FilteredComplex & cpx + , int p) { std::chrono::time_point<std::chrono::system_clock> start, end; - int enlapsed_sec; + int elapsed_sec; + { + start = std::chrono::system_clock::now(); + Persistent_cohomology< FilteredComplex, Field_Zp > pcoh(cpx); + end = std::chrono::system_clock::now(); + elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); + std::cout << " Initialize pcoh in " << elapsed_sec << " ms.\n"; + // initializes the coefficient field for homology + start = std::chrono::system_clock::now(); + pcoh.init_coefficients(p); + end = std::chrono::system_clock::now(); + elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); + std::cout << " Initialize the coefficient field in " << elapsed_sec << " ms.\n"; - Persistent_cohomology< FilteredComplex, Field_Zp > pcoh (cpx); - pcoh.init_coefficients( p ); //initilizes the coefficient field for homology - start = std::chrono::system_clock::now(); - - pcoh.compute_persistent_cohomology( INFINITY ); - + + pcoh.compute_persistent_cohomology(INFINITY); + + end = std::chrono::system_clock::now(); + elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); + std::cout << " Compute persistent homology in Z/" << p << "Z in " << elapsed_sec << " ms.\n"; + start = std::chrono::system_clock::now(); + } end = std::chrono::system_clock::now(); - enlapsed_sec = std::chrono::duration_cast<std::chrono::seconds>(end-start).count(); - std::cout << " Compute persistent homology in Z/"<<p<<"Z in " << enlapsed_sec << " sec.\n"; + elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); + std::cout << " Run the persistence destructors in " << elapsed_sec << " ms.\n"; } template< typename FilteredComplex> void -timing_persistence( FilteredComplex & cpx - , int p - , int q ) -{ +timing_persistence(FilteredComplex & cpx + , int p + , int q) { std::chrono::time_point<std::chrono::system_clock> start, end; - int enlapsed_sec; - - Persistent_cohomology< FilteredComplex, Multi_field > pcoh (cpx); - pcoh.init_coefficients( p, q ); //initilizes the coefficient field for homology + int elapsed_sec; + { + start = std::chrono::system_clock::now(); + Persistent_cohomology< FilteredComplex, Multi_field > pcoh(cpx); + end = std::chrono::system_clock::now(); + elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); + std::cout << " Initialize pcoh in " << elapsed_sec << " ms.\n"; + // initializes the coefficient field for homology + start = std::chrono::system_clock::now(); + pcoh.init_coefficients(p, q); + end = std::chrono::system_clock::now(); + elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); + std::cout << " Initialize the coefficient field in " << elapsed_sec << " ms.\n"; // compute persistent homology, disgarding persistent features of life shorter than min_persistence start = std::chrono::system_clock::now(); - pcoh.compute_persistent_cohomology( INFINITY ); + pcoh.compute_persistent_cohomology(INFINITY); end = std::chrono::system_clock::now(); - enlapsed_sec = std::chrono::duration_cast<std::chrono::seconds>(end-start).count(); + elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); std::cout << " Compute multi-field persistent homology in all coefficient fields Z/pZ " - << "with p in ["<<p<<";"<<q<<"] in " << enlapsed_sec << " sec.\n"; + << "with p in [" << p << ";" << q << "] in " << elapsed_sec << " ms.\n"; + start = std::chrono::system_clock::now(); + } + end = std::chrono::system_clock::now(); + elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); + std::cout << " Run the persistence destructors in " << elapsed_sec << " ms.\n"; } diff --git a/src/Persistent_cohomology/example/persistence_from_file.cpp b/src/Persistent_cohomology/example/persistence_from_file.cpp index e886aea7..8eb8d0f3 100644 --- a/src/Persistent_cohomology/example/persistence_from_file.cpp +++ b/src/Persistent_cohomology/example/persistence_from_file.cpp @@ -1,141 +1,144 @@ - /* 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 Saclay (France) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "gudhi/reader_utils.h" -#include "gudhi/graph_simplicial_complex.h" -#include "gudhi/distance_functions.h" -#include "gudhi/Simplex_tree.h" -#include "gudhi/Persistent_cohomology.h" +/* 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 Saclay (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <gudhi/reader_utils.h> +#include <gudhi/graph_simplicial_complex.h> +#include <gudhi/distance_functions.h> +#include <gudhi/Simplex_tree.h> +#include <gudhi/Persistent_cohomology.h> #include <boost/program_options.hpp> +#include <string> + using namespace Gudhi; using namespace Gudhi::persistent_cohomology; -typedef int Vertex_handle; -typedef double Filtration_value; - -void program_options( int argc, char * argv[] - , std::string & simplex_tree_file - , std::string & output_file - , int & p - , Filtration_value & min_persistence ); - -int main (int argc, char * argv[]) -{ - std::string simplex_tree_file; - std::string output_file ; - int p ; - Filtration_value min_persistence; - - program_options(argc,argv,simplex_tree_file,output_file,p,min_persistence); - - std::cout << "Simplex_tree from file=" << simplex_tree_file.c_str() << " - output_file=" << output_file.c_str() << std::endl; - std::cout << " - p=" << p << " - min_persistence=" << min_persistence << std::endl; - - // Construct the Rips complex in a Simplex Tree - Simplex_tree<> simplex_tree; - - std::ifstream simplex_tree_stream(simplex_tree_file); - simplex_tree_stream >> simplex_tree; - - std::cout << "The complex contains " << simplex_tree.num_simplices() << " simplices" << std::endl; - std::cout << " - dimension " << simplex_tree.dimension() << " - filtration " << simplex_tree.filtration() << std::endl; - - /* - std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; - for( auto f_simplex : simplex_tree.filtration_simplex_range() ) - { std::cout << " " << "[" << simplex_tree.filtration(f_simplex) << "] "; - for( auto vertex : simplex_tree.simplex_vertex_range(f_simplex) ) - { std::cout << vertex << " "; } - std::cout << std::endl; - }*/ - - // Sort the simplices in the order of the filtration - simplex_tree.initialize_filtration(); - - // Compute the persistence diagram of the complex - Persistent_cohomology< Simplex_tree<>, Field_Zp > pcoh( simplex_tree ); - pcoh.init_coefficients( p ); //initilizes the coefficient field for homology - - pcoh.compute_persistent_cohomology( min_persistence ); - - // Output the diagram in output_file - if(output_file.empty()) { pcoh.output_diagram(); } - else { - std::ofstream out(output_file); - pcoh.output_diagram(out); - out.close(); } +typedef int Vertex_handle; +typedef double Filtration_value; + +void program_options(int argc, char * argv[] + , std::string & simplex_tree_file + , std::string & output_file + , int & p + , Filtration_value & min_persistence); + +int main(int argc, char * argv[]) { + std::string simplex_tree_file; + std::string output_file; + int p; + Filtration_value min_persistence; + + program_options(argc, argv, simplex_tree_file, output_file, p, min_persistence); + + std::cout << "Simplex_tree from file=" << simplex_tree_file.c_str() << " - output_file=" << output_file.c_str() + << std::endl; + std::cout << " - p=" << p << " - min_persistence=" << min_persistence << std::endl; + + // Construct the Rips complex in a Simplex Tree + Simplex_tree<> simplex_tree; + + std::ifstream simplex_tree_stream(simplex_tree_file); + simplex_tree_stream >> simplex_tree; + + std::cout << "The complex contains " << simplex_tree.num_simplices() << " simplices" << std::endl; + std::cout << " - dimension " << simplex_tree.dimension() << " - filtration " << simplex_tree.filtration() + << std::endl; + + /* + std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; + for( auto f_simplex : simplex_tree.filtration_simplex_range() ) + { std::cout << " " << "[" << simplex_tree.filtration(f_simplex) << "] "; + for( auto vertex : simplex_tree.simplex_vertex_range(f_simplex) ) + { std::cout << vertex << " "; } + std::cout << std::endl; + }*/ + + // Sort the simplices in the order of the filtration + simplex_tree.initialize_filtration(); + + // Compute the persistence diagram of the complex + Persistent_cohomology< Simplex_tree<>, Field_Zp > pcoh(simplex_tree); + // initializes the coefficient field for homology + pcoh.init_coefficients(p); + + pcoh.compute_persistent_cohomology(min_persistence); + + // Output the diagram in output_file + if (output_file.empty()) { + pcoh.output_diagram(); + } else { + std::ofstream out(output_file); + pcoh.output_diagram(out); + out.close(); + } - return 0; + return 0; } - - -void program_options( int argc, char * argv[] - , std::string & simplex_tree_file - , std::string & output_file - , int & p - , Filtration_value & min_persistence ) -{ +void program_options(int argc, char * argv[] + , std::string & simplex_tree_file + , std::string & output_file + , int & p + , Filtration_value & min_persistence) { namespace po = boost::program_options; - po::options_description hidden("Hidden options"); + po::options_description hidden("Hidden options"); hidden.add_options() - ("input-file", po::value<std::string>(&simplex_tree_file), - "Name of file containing a simplex set. Format is one simplex per line (cf. reader_utils.h - read_simplex): Dim1 X11 X12 ... X1d Fil1 "); - + ("input-file", po::value<std::string>(&simplex_tree_file), + "Name of file containing a simplex set. Format is one simplex per line (cf. reader_utils.h - read_simplex): Dim1 X11 X12 ... X1d Fil1 "); + po::options_description visible("Allowed options", 100); visible.add_options() - ("help,h", "produce help message") - ("output-file,o", po::value<std::string>(&output_file)->default_value(std::string()), - "Name of file in which the persistence diagram is written. Default print in std::cout") - ("field-charac,p", po::value<int>(&p)->default_value(11), - "Characteristic p of the coefficient field Z/pZ for computing homology.") - ("min-persistence,m", po::value<Filtration_value>(&min_persistence), - "Minimal lifetime of homology feature to be recorded. Default is 0"); + ("help,h", "produce help message") + ("output-file,o", po::value<std::string>(&output_file)->default_value(std::string()), + "Name of file in which the persistence diagram is written. Default print in std::cout") + ("field-charac,p", po::value<int>(&p)->default_value(11), + "Characteristic p of the coefficient field Z/pZ for computing homology.") + ("min-persistence,m", po::value<Filtration_value>(&min_persistence), + "Minimal lifetime of homology feature to be recorded. Default is 0"); po::positional_options_description pos; pos.add("input-file", 1); - - po::options_description all; all.add(visible).add(hidden); + + po::options_description all; + all.add(visible).add(hidden); po::variables_map vm; po::store(po::command_line_parser(argc, argv). - options(all).positional(pos).run(), vm); + options(all).positional(pos).run(), vm); po::notify(vm); - if (vm.count("help") || !vm.count("input-file")) - { - std::cout << std::endl; - std::cout << "Compute the persistent homology with coefficient field Z/pZ \n"; - std::cout << "of a Rips complex defined on a set of input points.\n \n"; - std::cout << "The output diagram contains one bar per line, written with the convention: \n"; - std::cout << " p dim b d \n"; - std::cout << "where dim is the dimension of the homological feature,\n"; - std::cout << "b and d are respectively the birth and death of the feature and \n"; - std::cout << "p is the characteristic of the field Z/pZ used for homology coefficients." << std::endl << std::endl; - - std::cout << "Usage: " << argv[0] << " [options] input-file" << std::endl << std::endl; - std::cout << visible << std::endl; - std::abort(); + if (vm.count("help") || !vm.count("input-file")) { + std::cout << std::endl; + std::cout << "Compute the persistent homology with coefficient field Z/pZ \n"; + std::cout << "of a Rips complex defined on a set of input points.\n \n"; + std::cout << "The output diagram contains one bar per line, written with the convention: \n"; + std::cout << " p dim b d \n"; + std::cout << "where dim is the dimension of the homological feature,\n"; + std::cout << "b and d are respectively the birth and death of the feature and \n"; + std::cout << "p is the characteristic of the field Z/pZ used for homology coefficients." << std::endl << std::endl; + + std::cout << "Usage: " << argv[0] << " [options] input-file" << std::endl << std::endl; + std::cout << visible << std::endl; + std::abort(); } } diff --git a/src/Persistent_cohomology/example/persistence_from_simple_simplex_tree.cpp b/src/Persistent_cohomology/example/persistence_from_simple_simplex_tree.cpp index ba82e4e6..ba772f04 100644 --- a/src/Persistent_cohomology/example/persistence_from_simple_simplex_tree.cpp +++ b/src/Persistent_cohomology/example/persistence_from_simple_simplex_tree.cpp @@ -20,11 +20,14 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <gudhi/graph_simplicial_complex.h> +#include <gudhi/Simplex_tree.h> +#include <gudhi/Persistent_cohomology.h> + #include <iostream> #include <ctime> -#include "gudhi/graph_simplicial_complex.h" -#include "gudhi/Simplex_tree.h" -#include "gudhi/Persistent_cohomology.h" +#include <utility> +#include <vector> using namespace Gudhi; using namespace Gudhi::persistent_cohomology; @@ -34,15 +37,19 @@ typedef std::pair<typeVectorVertex, Filtration_value> typeSimplex; typedef std::pair< Simplex_tree<>::Simplex_handle, bool > typePairSimplexBool; typedef Simplex_tree<> typeST; -void usage(char * const progName) -{ +void usage(char * const progName) { std::cerr << "Usage: " << progName << " coeff_field_characteristic[integer > 0] min_persistence[float >= -1.0]\n"; - exit(-1); // ----- >> + exit(-1); } -int main (int argc, char * const argv[]) -{ - int coeff_field_characteristic=0; +int main(int argc, char * const argv[]) { + // program args management + if (argc != 3) { + std::cerr << "Error: Number of arguments (" << argc << ") is not correct\n"; + usage(argv[0]); + } + + int coeff_field_characteristic = 0; int returnedScanValue = sscanf(argv[1], "%d", &coeff_field_characteristic); if ((returnedScanValue == EOF) || (coeff_field_characteristic <= 0)) { std::cerr << "Error: " << argv[1] << " is not correct\n"; @@ -56,101 +63,65 @@ int main (int argc, char * const argv[]) usage(argv[0]); } - // program args management - if (argc != 3) { - std::cerr << "Error: Number of arguments (" << argc << ") is not correct\n"; - usage(argv[0]); - } - // TEST OF INSERTION std::cout << "********************************************************************" << std::endl; std::cout << "TEST OF INSERTION" << std::endl; typeST st; // ++ FIRST - std::cout << " - INSERT (2,1,0)" << std::endl; - typeVectorVertex SimplexVector1; - SimplexVector1.push_back(2); - SimplexVector1.push_back(1); - SimplexVector1.push_back(0); - st.insert_simplex_and_subfaces ( SimplexVector1, 0.3); + std::cout << " - INSERT (0,1,2)" << std::endl; + typeVectorVertex SimplexVector = {0, 1, 2}; + st.insert_simplex_and_subfaces(SimplexVector, 0.3); // ++ SECOND std::cout << " - INSERT 3" << std::endl; - typeVectorVertex SimplexVector2; - SimplexVector2.push_back(3); - st.insert_simplex_and_subfaces ( SimplexVector2, 0.1); + SimplexVector = {3}; + st.insert_simplex_and_subfaces(SimplexVector, 0.1); // ++ THIRD std::cout << " - INSERT (0,3)" << std::endl; - typeVectorVertex SimplexVector3; - SimplexVector3.push_back(3); - SimplexVector3.push_back(0); - st.insert_simplex_and_subfaces ( SimplexVector3, 0.2); + SimplexVector = {0, 3}; + st.insert_simplex_and_subfaces(SimplexVector, 0.2); // ++ FOURTH - std::cout << " - INSERT (1,0) (already inserted)" << std::endl; - typeVectorVertex SimplexVector4; - SimplexVector4.push_back(1); - SimplexVector4.push_back(0); - st.insert_simplex_and_subfaces ( SimplexVector4, 0.2); + std::cout << " - INSERT (0,1) (already inserted)" << std::endl; + SimplexVector = {0, 1}; + st.insert_simplex_and_subfaces(SimplexVector, 0.2); // ++ FIFTH std::cout << " - INSERT (3,4,5)" << std::endl; - typeVectorVertex SimplexVector5; - SimplexVector5.push_back(3); - SimplexVector5.push_back(4); - SimplexVector5.push_back(5); - st.insert_simplex_and_subfaces ( SimplexVector5, 0.3); + SimplexVector = {3, 4, 5}; + st.insert_simplex_and_subfaces(SimplexVector, 0.3); // ++ SIXTH std::cout << " - INSERT (0,1,6,7)" << std::endl; - typeVectorVertex SimplexVector6; - SimplexVector6.push_back(0); - SimplexVector6.push_back(1); - SimplexVector6.push_back(6); - SimplexVector6.push_back(7); - st.insert_simplex_and_subfaces ( SimplexVector6, 0.4); + SimplexVector = {0, 1, 6, 7}; + st.insert_simplex_and_subfaces(SimplexVector, 0.4); // ++ SEVENTH std::cout << " - INSERT (4,5,8,9)" << std::endl; - typeVectorVertex SimplexVector7; - SimplexVector7.push_back(4); - SimplexVector7.push_back(5); - SimplexVector7.push_back(8); - SimplexVector7.push_back(9); - st.insert_simplex_and_subfaces ( SimplexVector7, 0.4); + SimplexVector = {4, 5, 8, 9}; + st.insert_simplex_and_subfaces(SimplexVector, 0.4); // ++ EIGHTH std::cout << " - INSERT (9,10,11)" << std::endl; - typeVectorVertex SimplexVector8; - SimplexVector8.push_back(9); - SimplexVector8.push_back(10); - SimplexVector8.push_back(11); - st.insert_simplex_and_subfaces ( SimplexVector8, 0.3); - + SimplexVector = {9, 10, 11}; + st.insert_simplex_and_subfaces(SimplexVector, 0.3); + // ++ NINETH std::cout << " - INSERT (2,10,12)" << std::endl; - typeVectorVertex SimplexVector9; - SimplexVector9.push_back(2); - SimplexVector9.push_back(10); - SimplexVector9.push_back(12); - st.insert_simplex_and_subfaces ( SimplexVector9, 0.3); - + SimplexVector = {2, 10, 12}; + st.insert_simplex_and_subfaces(SimplexVector, 0.3); + // ++ TENTH std::cout << " - INSERT (11,6)" << std::endl; - typeVectorVertex SimplexVector10; - SimplexVector10.push_back(11); - SimplexVector10.push_back(6); - st.insert_simplex_and_subfaces ( SimplexVector10, 0.2); + SimplexVector = {6, 11}; + st.insert_simplex_and_subfaces(SimplexVector, 0.2); // ++ ELEVENTH std::cout << " - INSERT (13,14,15)" << std::endl; - typeVectorVertex SimplexVector11; - SimplexVector11.push_back(13); - SimplexVector11.push_back(14); - SimplexVector11.push_back(15); - st.insert_simplex_and_subfaces ( SimplexVector11, 0.25); + SimplexVector = {13, 14, 15}; + st.insert_simplex_and_subfaces(SimplexVector, 0.25); /* Inserted simplex: */ /* 1 6 */ @@ -175,33 +146,31 @@ int main (int argc, char * const argv[]) st.set_dimension(2); st.set_filtration(0.4); - std::cout << "The complex contains " << st.num_simplices() << " simplices - " << st.num_vertices() << " vertices " << std::endl; + std::cout << "The complex contains " << st.num_simplices() << " simplices - " << st.num_vertices() << " vertices " + << std::endl; std::cout << " - dimension " << st.dimension() << " - filtration " << st.filtration() << std::endl; - std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; + std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, with [filtration value]:" + << std::endl; std::cout << "**************************************************************" << std::endl; std::cout << "strict graph G { " << std::endl; - for( auto f_simplex : st.filtration_simplex_range() ) - { + for (auto f_simplex : st.filtration_simplex_range()) { std::cout << " " << "[" << st.filtration(f_simplex) << "] "; - for( auto vertex : st.simplex_vertex_range(f_simplex) ) - { - std::cout << (int)vertex << " -- "; + for (auto vertex : st.simplex_vertex_range(f_simplex)) { + std::cout << static_cast<int>(vertex) << " -- "; } std::cout << ";" << std::endl; } std::cout << "}" << std::endl; - //std::cout << "**************************************************************" << std::endl; - //st.print_hasse(std::cout); std::cout << "**************************************************************" << std::endl; - // Compute the persistence diagram of the complex persistent_cohomology::Persistent_cohomology< Simplex_tree<>, Field_Zp > pcoh(st); - pcoh.init_coefficients( coeff_field_characteristic ); //initiliazes the coefficient field for homology + // initializes the coefficient field for homology + pcoh.init_coefficients(coeff_field_characteristic); - pcoh.compute_persistent_cohomology( min_persistence ); + pcoh.compute_persistent_cohomology(min_persistence); // Output the diagram in filediag pcoh.output_diagram(); diff --git a/src/Persistent_cohomology/example/plain_homology.cpp b/src/Persistent_cohomology/example/plain_homology.cpp new file mode 100644 index 00000000..0a692717 --- /dev/null +++ b/src/Persistent_cohomology/example/plain_homology.cpp @@ -0,0 +1,84 @@ +/* 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): Marc Glisse + * + * Copyright (C) 2015 INRIA Saclay - Ile-de-France (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <gudhi/Simplex_tree.h> +#include <gudhi/Persistent_cohomology.h> + +#include <iostream> + +using namespace Gudhi; + +/* We could perfectly well use the default Simplex_tree<> (which uses + * Simplex_tree_options_full_featured), the following simply demonstrates + * how to save on storage by not storing a filtration value. */ + +struct MyOptions : Simplex_tree_options_full_featured { + // Implicitly use 0 as filtration value for all simplices + static const bool store_filtration = false; + // The persistence algorithm needs this + static const bool store_key = true; + // I have few vertices + typedef short Vertex_handle; +}; +typedef Simplex_tree<MyOptions> ST; + +int main() { + ST st; + + /* Complex to build. */ + /* 1 3 */ + /* o---o */ + /* /X\ / */ + /* o---o o */ + /* 2 0 4 */ + + const short triangle012[] = {0, 1, 2}; + const short edge03[] = {0, 3}; + const short edge13[] = {1, 3}; + const short vertex4[] = {4}; + st.insert_simplex_and_subfaces(triangle012); + st.insert_simplex_and_subfaces(edge03); + st.insert_simplex(edge13); + st.insert_simplex(vertex4); + // FIXME: Remove this line + st.set_dimension(2); + + // Sort the simplices in the order of the filtration + st.initialize_filtration(); + + // Class for homology computation + persistent_cohomology::Persistent_cohomology<ST, persistent_cohomology::Field_Zp> pcoh(st); + + // Initialize the coefficient field Z/2Z for homology + pcoh.init_coefficients(2); + + // Compute the persistence diagram of the complex + pcoh.compute_persistent_cohomology(); + + // Print the result. The format is, on each line: 2 dim 0 inf + // where 2 represents the field, dim the dimension of the feature. + // 2 0 0 inf + // 2 0 0 inf + // 2 1 0 inf + // means that in Z/2Z-homology, the Betti numbers are b0=2 and b1=1. + pcoh.output_diagram(); +} diff --git a/src/Persistent_cohomology/example/rips_multifield_persistence.cpp b/src/Persistent_cohomology/example/rips_multifield_persistence.cpp index 297a8f98..5277bf7a 100644 --- a/src/Persistent_cohomology/example/rips_multifield_persistence.cpp +++ b/src/Persistent_cohomology/example/rips_multifield_persistence.cpp @@ -1,153 +1,157 @@ - /* 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): Clément Maria - * - * 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 "gudhi/reader_utils.h" -#include "gudhi/graph_simplicial_complex.h" -#include "gudhi/distance_functions.h" -#include "gudhi/Simplex_tree.h" -#include "gudhi/Persistent_cohomology.h" -#include "gudhi/Persistent_cohomology/Multi_field.h" +/* 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): Clément Maria + * + * 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 <gudhi/reader_utils.h> +#include <gudhi/graph_simplicial_complex.h> +#include <gudhi/distance_functions.h> +#include <gudhi/Simplex_tree.h> +#include <gudhi/Persistent_cohomology.h> +#include <gudhi/Persistent_cohomology/Multi_field.h> #include <boost/program_options.hpp> +#include <string> +#include <vector> + using namespace Gudhi; using namespace Gudhi::persistent_cohomology; -typedef int Vertex_handle; +typedef int Vertex_handle; typedef double Filtration_value; -void program_options( int argc, char * argv[] - , std::string & filepoints - , std::string & filediag - , Filtration_value & threshold - , int & dim_max - , int & min_p - , int & max_p - , Filtration_value & min_persistence ); - -int main (int argc, char * argv[]) -{ - std::string filepoints; - std::string filediag; +void program_options(int argc, char * argv[] + , std::string & filepoints + , std::string & filediag + , Filtration_value & threshold + , int & dim_max + , int & min_p + , int & max_p + , Filtration_value & min_persistence); + +int main(int argc, char * argv[]) { + std::string filepoints; + std::string filediag; Filtration_value threshold; - int dim_max; - int min_p; - int max_p; + int dim_max; + int min_p; + int max_p; Filtration_value min_persistence; - program_options(argc,argv,filepoints,filediag,threshold,dim_max,min_p,max_p,min_persistence); + program_options(argc, argv, filepoints, filediag, threshold, dim_max, min_p, max_p, min_persistence); -// Extract the points from the file filepoints + // Extract the points from the file filepoints typedef std::vector<double> Point_t; std::vector< Point_t > points; - read_points( filepoints, points ); + read_points(filepoints, points); -// Compute the proximity graph of the points - Graph_t prox_graph = compute_proximity_graph( points, threshold - , euclidean_distance<Point_t> ); + // Compute the proximity graph of the points + Graph_t prox_graph = compute_proximity_graph(points, threshold + , euclidean_distance<Point_t>); -// Construct the Rips complex in a Simplex Tree - Simplex_tree<> st; - st.insert_graph(prox_graph); // insert the proximity graph in the simplex tree - st.expansion( dim_max ); // expand the graph until dimension dim_max + // Construct the Rips complex in a Simplex Tree + Simplex_tree<> st; + // insert the proximity graph in the simplex tree + st.insert_graph(prox_graph); + // expand the graph until dimension dim_max + st.expansion(dim_max); -// Sort the simplices in the order of the filtration + // Sort the simplices in the order of the filtration st.initialize_filtration(); -// Compute the persistence diagram of the complex - Persistent_cohomology< Simplex_tree<>, Multi_field > pcoh( st ); - pcoh.init_coefficients( min_p, max_p ); //initilizes the coefficient field for homology + // Compute the persistence diagram of the complex + Persistent_cohomology< Simplex_tree<>, Multi_field > pcoh(st); + // initializes the coefficient field for homology + pcoh.init_coefficients(min_p, max_p); // compute persistent homology, disgarding persistent features of life shorter than min_persistence - pcoh.compute_persistent_cohomology( min_persistence ); - -// Output the diagram in filediag - if(filediag.empty()) { pcoh.output_diagram(); } - else { - std::ofstream out(filediag); - pcoh.output_diagram(out); - out.close(); } + pcoh.compute_persistent_cohomology(min_persistence); + + // Output the diagram in filediag + if (filediag.empty()) { + pcoh.output_diagram(); + } else { + std::ofstream out(filediag); + pcoh.output_diagram(out); + out.close(); + } return 0; } - - -void program_options( int argc, char * argv[] - , std::string & filepoints - , std::string & filediag - , Filtration_value & threshold - , int & dim_max - , int & min_p - , int & max_p - , Filtration_value & min_persistence ) -{ +void program_options(int argc, char * argv[] + , std::string & filepoints + , std::string & filediag + , Filtration_value & threshold + , int & dim_max + , int & min_p + , int & max_p + , Filtration_value & min_persistence) { namespace po = boost::program_options; - po::options_description hidden("Hidden options"); + po::options_description hidden("Hidden options"); hidden.add_options() - ("input-file", po::value<std::string>(&filepoints), - "Name of file containing a point set. Format is one point per line: X1 ... Xd \n"); - + ("input-file", po::value<std::string>(&filepoints), + "Name of file containing a point set. Format is one point per line: X1 ... Xd \n"); + po::options_description visible("Allowed options"); visible.add_options() - ("help,h", "produce help message") - ("output-file,o", po::value<std::string>(&filediag)->default_value(std::string()), - "Name of file in which the persistence diagram is written. Default print in std::cout") - ("max-edge-length,r", po::value<Filtration_value>(&threshold)->default_value(0), - "Maximal length of an edge for the Rips complex construction.") - ("cpx-dimension,d", po::value<int>(&dim_max)->default_value(1), - "Maximal dimension of the Rips complex we want to compute.") - ("min-field-charac,p", po::value<int>(&min_p)->default_value(2), - "Minimal characteristic p of the coefficient field Z/pZ.") - ("max-field-charac,q", po::value<int>(&max_p)->default_value(1223), - "Minimial characteristic q of the coefficient field Z/pZ.") - ("min-persistence,m", po::value<Filtration_value>(&min_persistence), - "Minimal lifetime of homology feature to be recorded. Default is 0"); + ("help,h", "produce help message") + ("output-file,o", po::value<std::string>(&filediag)->default_value(std::string()), + "Name of file in which the persistence diagram is written. Default print in std::cout") + ("max-edge-length,r", po::value<Filtration_value>(&threshold)->default_value(0), + "Maximal length of an edge for the Rips complex construction.") + ("cpx-dimension,d", po::value<int>(&dim_max)->default_value(1), + "Maximal dimension of the Rips complex we want to compute.") + ("min-field-charac,p", po::value<int>(&min_p)->default_value(2), + "Minimal characteristic p of the coefficient field Z/pZ.") + ("max-field-charac,q", po::value<int>(&max_p)->default_value(1223), + "Minimial characteristic q of the coefficient field Z/pZ.") + ("min-persistence,m", po::value<Filtration_value>(&min_persistence), + "Minimal lifetime of homology feature to be recorded. Default is 0"); po::positional_options_description pos; pos.add("input-file", 1); - - po::options_description all; all.add(visible).add(hidden); + + po::options_description all; + all.add(visible).add(hidden); po::variables_map vm; po::store(po::command_line_parser(argc, argv). - options(all).positional(pos).run(), vm); + options(all).positional(pos).run(), vm); po::notify(vm); - if (vm.count("help") || !vm.count("input-file")) - { - std::cout << std::endl; - std::cout << "Compute the persistent homology with various coefficient fields \n"; - std::cout << "of a Rips complex defined on a set of input points. The coefficient \n"; - std::cout << "fields are all the Z/rZ for a prime number r contained in the \n"; - std::cout << "specified range [p,q]\n \n"; - std::cout << "The output diagram contains one bar per line, written with the convention: \n"; - std::cout << " p1*...*pr dim b d \n"; - std::cout << "where dim is the dimension of the homological feature,\n"; - std::cout << "b and d are respectively the birth and death of the feature and \n"; - std::cout << "p1*...*pr is the product of prime numbers pi such that the homology \n"; - std::cout << "feature exists in homology with Z/piZ coefficients."<< std::endl << std::endl; - - std::cout << "Usage: " << argv[0] << " [options] input-file" << std::endl << std::endl; - std::cout << visible << std::endl; - std::abort(); + if (vm.count("help") || !vm.count("input-file")) { + std::cout << std::endl; + std::cout << "Compute the persistent homology with various coefficient fields \n"; + std::cout << "of a Rips complex defined on a set of input points. The coefficient \n"; + std::cout << "fields are all the Z/rZ for a prime number r contained in the \n"; + std::cout << "specified range [p,q]\n \n"; + std::cout << "The output diagram contains one bar per line, written with the convention: \n"; + std::cout << " p1*...*pr dim b d \n"; + std::cout << "where dim is the dimension of the homological feature,\n"; + std::cout << "b and d are respectively the birth and death of the feature and \n"; + std::cout << "p1*...*pr is the product of prime numbers pi such that the homology \n"; + std::cout << "feature exists in homology with Z/piZ coefficients." << std::endl << std::endl; + + std::cout << "Usage: " << argv[0] << " [options] input-file" << std::endl << std::endl; + std::cout << visible << std::endl; + std::abort(); } } diff --git a/src/Persistent_cohomology/example/rips_persistence.cpp b/src/Persistent_cohomology/example/rips_persistence.cpp index 4253def9..9b1ef42f 100644 --- a/src/Persistent_cohomology/example/rips_persistence.cpp +++ b/src/Persistent_cohomology/example/rips_persistence.cpp @@ -1,147 +1,151 @@ - /* 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): Clément Maria - * - * 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 "gudhi/reader_utils.h" -#include "gudhi/graph_simplicial_complex.h" -#include "gudhi/distance_functions.h" -#include "gudhi/Simplex_tree.h" -#include "gudhi/Persistent_cohomology.h" +/* 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): Clément Maria + * + * 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 <gudhi/reader_utils.h> +#include <gudhi/graph_simplicial_complex.h> +#include <gudhi/distance_functions.h> +#include <gudhi/Simplex_tree.h> +#include <gudhi/Persistent_cohomology.h> #include <boost/program_options.hpp> +#include <string> +#include <vector> + using namespace Gudhi; using namespace Gudhi::persistent_cohomology; -typedef int Vertex_handle; -typedef double Filtration_value; - -void program_options( int argc, char * argv[] - , std::string & filepoints - , std::string & filediag - , Filtration_value & threshold - , int & dim_max - , int & p - , Filtration_value & min_persistence ); - -int main (int argc, char * argv[]) -{ - std::string filepoints; - std::string filediag ; - Filtration_value threshold ; - int dim_max ; - int p ; +typedef int Vertex_handle; +typedef double Filtration_value; + +void program_options(int argc, char * argv[] + , std::string & filepoints + , std::string & filediag + , Filtration_value & threshold + , int & dim_max + , int & p + , Filtration_value & min_persistence); + +int main(int argc, char * argv[]) { + std::string filepoints; + std::string filediag; + Filtration_value threshold; + int dim_max; + int p; Filtration_value min_persistence; - program_options(argc,argv,filepoints,filediag,threshold,dim_max,p,min_persistence); + program_options(argc, argv, filepoints, filediag, threshold, dim_max, p, min_persistence); -// Extract the points from the file filepoints + // Extract the points from the file filepoints typedef std::vector<double> Point_t; std::vector< Point_t > points; - read_points( filepoints, points ); + read_points(filepoints, points); -// Compute the proximity graph of the points - Graph_t prox_graph = compute_proximity_graph( points, threshold - , euclidean_distance<Point_t> ); + // Compute the proximity graph of the points + Graph_t prox_graph = compute_proximity_graph(points, threshold + , euclidean_distance<Point_t>); -// Construct the Rips complex in a Simplex Tree - Simplex_tree<> st; - st.insert_graph(prox_graph); // insert the proximity graph in the simplex tree - st.expansion( dim_max ); // expand the graph until dimension dim_max + // Construct the Rips complex in a Simplex Tree + Simplex_tree<> st; + // insert the proximity graph in the simplex tree + st.insert_graph(prox_graph); + // expand the graph until dimension dim_max + st.expansion(dim_max); std::cout << "The complex contains " << st.num_simplices() << " simplices \n"; std::cout << " and has dimension " << st.dimension() << " \n"; -// Sort the simplices in the order of the filtration + // Sort the simplices in the order of the filtration st.initialize_filtration(); -// Compute the persistence diagram of the complex + // Compute the persistence diagram of the complex persistent_cohomology::Persistent_cohomology< Simplex_tree<>, Field_Zp > pcoh(st); - pcoh.init_coefficients( p ); //initilizes the coefficient field for homology - - pcoh.compute_persistent_cohomology( min_persistence ); - -// Output the diagram in filediag - if(filediag.empty()) { pcoh.output_diagram(); } - else { - std::ofstream out(filediag); - pcoh.output_diagram(out); - out.close(); } + // initializes the coefficient field for homology + pcoh.init_coefficients(p); + + pcoh.compute_persistent_cohomology(min_persistence); + + // Output the diagram in filediag + if (filediag.empty()) { + pcoh.output_diagram(); + } else { + std::ofstream out(filediag); + pcoh.output_diagram(out); + out.close(); + } return 0; } - - -void program_options( int argc, char * argv[] - , std::string & filepoints - , std::string & filediag - , Filtration_value & threshold - , int & dim_max - , int & p - , Filtration_value & min_persistence ) -{ +void program_options(int argc, char * argv[] + , std::string & filepoints + , std::string & filediag + , Filtration_value & threshold + , int & dim_max + , int & p + , Filtration_value & min_persistence) { namespace po = boost::program_options; - po::options_description hidden("Hidden options"); + po::options_description hidden("Hidden options"); hidden.add_options() - ("input-file", po::value<std::string>(&filepoints), - "Name of file containing a point set. Format is one point per line: X1 ... Xd "); - + ("input-file", po::value<std::string>(&filepoints), + "Name of file containing a point set. Format is one point per line: X1 ... Xd "); + po::options_description visible("Allowed options", 100); visible.add_options() - ("help,h", "produce help message") - ("output-file,o", po::value<std::string>(&filediag)->default_value(std::string()), - "Name of file in which the persistence diagram is written. Default print in std::cout") - ("max-edge-length,r", po::value<Filtration_value>(&threshold)->default_value(0), - "Maximal length of an edge for the Rips complex construction.") - ("cpx-dimension,d", po::value<int>(&dim_max)->default_value(1), - "Maximal dimension of the Rips complex we want to compute.") - ("field-charac,p", po::value<int>(&p)->default_value(11), - "Characteristic p of the coefficient field Z/pZ for computing homology.") - ("min-persistence,m", po::value<Filtration_value>(&min_persistence), - "Minimal lifetime of homology feature to be recorded. Default is 0. Enter a negative value to see zero length intervals"); + ("help,h", "produce help message") + ("output-file,o", po::value<std::string>(&filediag)->default_value(std::string()), + "Name of file in which the persistence diagram is written. Default print in std::cout") + ("max-edge-length,r", po::value<Filtration_value>(&threshold)->default_value(0), + "Maximal length of an edge for the Rips complex construction.") + ("cpx-dimension,d", po::value<int>(&dim_max)->default_value(1), + "Maximal dimension of the Rips complex we want to compute.") + ("field-charac,p", po::value<int>(&p)->default_value(11), + "Characteristic p of the coefficient field Z/pZ for computing homology.") + ("min-persistence,m", po::value<Filtration_value>(&min_persistence), + "Minimal lifetime of homology feature to be recorded. Default is 0. Enter a negative value to see zero length intervals"); po::positional_options_description pos; pos.add("input-file", 1); - - po::options_description all; all.add(visible).add(hidden); + + po::options_description all; + all.add(visible).add(hidden); po::variables_map vm; po::store(po::command_line_parser(argc, argv). - options(all).positional(pos).run(), vm); + options(all).positional(pos).run(), vm); po::notify(vm); - if (vm.count("help") || !vm.count("input-file")) - { - std::cout << std::endl; - std::cout << "Compute the persistent homology with coefficient field Z/pZ \n"; - std::cout << "of a Rips complex defined on a set of input points.\n \n"; - std::cout << "The output diagram contains one bar per line, written with the convention: \n"; - std::cout << " p dim b d \n"; - std::cout << "where dim is the dimension of the homological feature,\n"; - std::cout << "b and d are respectively the birth and death of the feature and \n"; - std::cout << "p is the characteristic of the field Z/pZ used for homology coefficients." << std::endl << std::endl; - - std::cout << "Usage: " << argv[0] << " [options] input-file" << std::endl << std::endl; - std::cout << visible << std::endl; - std::abort(); + if (vm.count("help") || !vm.count("input-file")) { + std::cout << std::endl; + std::cout << "Compute the persistent homology with coefficient field Z/pZ \n"; + std::cout << "of a Rips complex defined on a set of input points.\n \n"; + std::cout << "The output diagram contains one bar per line, written with the convention: \n"; + std::cout << " p dim b d \n"; + std::cout << "where dim is the dimension of the homological feature,\n"; + std::cout << "b and d are respectively the birth and death of the feature and \n"; + std::cout << "p is the characteristic of the field Z/pZ used for homology coefficients." << std::endl << std::endl; + + std::cout << "Usage: " << argv[0] << " [options] input-file" << std::endl << std::endl; + std::cout << visible << std::endl; + std::abort(); } } diff --git a/src/Persistent_cohomology/include/gudhi/Persistent_cohomology.h b/src/Persistent_cohomology/include/gudhi/Persistent_cohomology.h index b0d68f09..2a405830 100644 --- a/src/Persistent_cohomology/include/gudhi/Persistent_cohomology.h +++ b/src/Persistent_cohomology/include/gudhi/Persistent_cohomology.h @@ -20,23 +20,28 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SRC_PERSISTENT_COHOMOLOGY_INCLUDE_GUDHI_PERSISTENT_COHOMOLOGY_H_ -#define SRC_PERSISTENT_COHOMOLOGY_INCLUDE_GUDHI_PERSISTENT_COHOMOLOGY_H_ +#ifndef PERSISTENT_COHOMOLOGY_H_ +#define PERSISTENT_COHOMOLOGY_H_ #include <gudhi/Persistent_cohomology/Persistent_cohomology_column.h> #include <gudhi/Persistent_cohomology/Field_Zp.h> +#include <gudhi/Simple_object_pool.h> #include <boost/tuple/tuple.hpp> #include <boost/intrusive/set.hpp> #include <boost/pending/disjoint_sets.hpp> #include <boost/intrusive/list.hpp> -#include <boost/pool/object_pool.hpp> #include <map> #include <utility> #include <list> #include <vector> #include <set> +#include <fstream> // std::ofstream +#include <limits> // for numeric_limits<> +#include <tuple> +#include <algorithm> +#include <string> namespace Gudhi { @@ -229,9 +234,10 @@ class Persistent_cohomology { : cpx_(&cpx), dim_max_(cpx.dimension()), // upper bound on the dimension of the simplices coeff_field_(), // initialize the field coefficient structure. - ds_rank_(cpx_->num_simplices()), // union-find - ds_parent_(cpx_->num_simplices()), // union-find - ds_repr_(cpx_->num_simplices(), NULL), // union-find -> annotation vectors + num_simplices_(cpx_->num_simplices()), // num_simplices save to avoid to call thrice the function + ds_rank_(num_simplices_), // union-find + ds_parent_(num_simplices_), // union-find + ds_repr_(num_simplices_, NULL), // union-find -> annotation vectors dsets_(&ds_rank_[0], &ds_parent_[0]), // union-find cam_(), // collection of annotation vectors zero_cocycles_(), // union-find -> Simplex_key of creator for 0-homology @@ -241,7 +247,7 @@ class Persistent_cohomology { column_pool_(), // memory pools for the CAM cell_pool_() { Simplex_key idx_fil = 0; - for (auto & sh : cpx_->filtration_simplex_range()) { + for (auto sh : cpx_->filtration_simplex_range()) { cpx_->assign_key(sh, idx_fil); ++idx_fil; dsets_.make_set(cpx_->key(sh)); @@ -264,13 +270,10 @@ class Persistent_cohomology { } ~Persistent_cohomology() { -// Clean the remaining columns in the matrix. - for (auto & cam_ref : cam_) { - cam_ref.col_.clear(); - } -// Clean the transversal lists + // Clean the transversal lists for (auto & transverse_ref : transverse_idx_) { - transverse_ref.second.row_->clear(); + // Destruct all the cells + transverse_ref.second.row_->clear_and_dispose([&](Cell*p){p->~Cell();}); delete transverse_ref.second.row_; } } @@ -335,18 +338,18 @@ class Persistent_cohomology { if (ds_parent_[key] == key // root of its tree && zero_cocycles_.find(key) == zero_cocycles_.end()) { - persistent_pairs_.push_back( - Persistent_interval(cpx_->simplex(key), cpx_->null_simplex(), coeff_field_.characteristic())); + persistent_pairs_.emplace_back( + cpx_->simplex(key), cpx_->null_simplex(), coeff_field_.characteristic()); } } for (auto zero_idx : zero_cocycles_) { - persistent_pairs_.push_back( - Persistent_interval(cpx_->simplex(zero_idx.second), cpx_->null_simplex(), coeff_field_.characteristic())); + persistent_pairs_.emplace_back( + cpx_->simplex(zero_idx.second), cpx_->null_simplex(), coeff_field_.characteristic()); } // Compute infinite interval of dimension > 0 for (auto cocycle : transverse_idx_) { - persistent_pairs_.push_back( - Persistent_interval(cpx_->simplex(cocycle.first), cpx_->null_simplex(), cocycle.second.characteristics_)); + persistent_pairs_.emplace_back( + cpx_->simplex(cocycle.first), cpx_->null_simplex(), cocycle.second.characteristics_); } } @@ -386,8 +389,8 @@ class Persistent_cohomology { if (cpx_->filtration(cpx_->simplex(idx_coc_u)) < cpx_->filtration(cpx_->simplex(idx_coc_v))) { // Kill cocycle [idx_coc_v], which is younger. if (interval_length_policy(cpx_->simplex(idx_coc_v), sigma)) { - persistent_pairs_.push_back( - Persistent_interval(cpx_->simplex(idx_coc_v), sigma, coeff_field_.characteristic())); + persistent_pairs_.emplace_back( + cpx_->simplex(idx_coc_v), sigma, coeff_field_.characteristic()); } // Maintain the index of the 0-cocycle alive. if (kv != idx_coc_v) { @@ -401,8 +404,8 @@ class Persistent_cohomology { } } else { // Kill cocycle [idx_coc_u], which is younger. if (interval_length_policy(cpx_->simplex(idx_coc_u), sigma)) { - persistent_pairs_.push_back( - Persistent_interval(cpx_->simplex(idx_coc_u), sigma, coeff_field_.characteristic())); + persistent_pairs_.emplace_back( + cpx_->simplex(idx_coc_u), sigma, coeff_field_.characteristic()); } // Maintain the index of the 0-cocycle alive. if (ku != idx_coc_u) { @@ -428,9 +431,12 @@ class Persistent_cohomology { std::map<Simplex_key, Arith_element> & map_a_ds, Simplex_handle sigma, int dim_sigma) { // traverses the boundary of sigma, keeps track of the annotation vectors, - // with multiplicity, in a map. - std::map<Column *, int> annotations_in_boundary; - std::pair<typename std::map<Column *, int>::iterator, bool> result_insert_bound; + // with multiplicity. We used to sum the coefficients directly in + // annotations_in_boundary by using a map, we now do it later. + typedef std::pair<Column *, int> annotation_t; + // Danger: not thread-safe! + static std::vector<annotation_t> annotations_in_boundary; + annotations_in_boundary.clear(); int sign = 1 - 2 * (dim_sigma % 2); // \in {-1,1} provides the sign in the // alternate sum in the boundary. Simplex_key key; @@ -442,22 +448,29 @@ class Persistent_cohomology { // Find its annotation vector curr_col = ds_repr_[dsets_.find_set(key)]; if (curr_col != NULL) { // and insert it in annotations_in_boundary with multyiplicative factor "sign". - result_insert_bound = annotations_in_boundary.insert(std::pair<Column *, int>(curr_col, sign)); - if (!(result_insert_bound.second)) { - result_insert_bound.first->second += sign; - } + annotations_in_boundary.emplace_back(curr_col, sign); } } sign = -sign; } + // Place identical annotations consecutively so we can easily sum their multiplicities. + std::sort(annotations_in_boundary.begin(), annotations_in_boundary.end(), + [](annotation_t const& a, annotation_t const& b) { return a.first < b.first; }); + // Sum the annotations with multiplicity, using a map<key,coeff> // to represent a sparse vector. std::pair<typename std::map<Simplex_key, Arith_element>::iterator, bool> result_insert_a_ds; - for (auto ann_ref : annotations_in_boundary) { - if (ann_ref.second != coeff_field_.additive_identity()) { // For all columns in the boundary, - for (auto cell_ref : ann_ref.first->col_) { // insert every cell in map_a_ds with multiplicity - Arith_element w_y = coeff_field_.times(cell_ref.coefficient_, ann_ref.second); // coefficient * multiplicity + for (auto ann_it = annotations_in_boundary.begin(); ann_it != annotations_in_boundary.end(); /**/) { + Column* col = ann_it->first; + int mult = ann_it->second; + while (++ann_it != annotations_in_boundary.end() && ann_it->first == col) { + mult += ann_it->second; + } + // The following test is just a heuristic, it is not required, and it is fine that is misses p == 0. + if (mult != coeff_field_.additive_identity()) { // For all columns in the boundary, + for (auto cell_ref : col->col_) { // insert every cell in map_a_ds with multiplicity + Arith_element w_y = coeff_field_.times(cell_ref.coefficient_, mult); // coefficient * multiplicity if (w_y != coeff_field_.additive_identity()) { // if != 0 result_insert_a_ds = map_a_ds.insert(std::pair<Simplex_key, Arith_element>(cell_ref.key_, w_y)); @@ -525,8 +538,8 @@ class Persistent_cohomology { Arith_element charac) { Simplex_key key = cpx_->key(sigma); // Create a column containing only one cell, - Column * new_col = column_pool_.construct(Column(key)); - Cell * new_cell = cell_pool_.construct(Cell(key, x, new_col)); + Column * new_col = column_pool_.construct(key); + Cell * new_cell = cell_pool_.construct(key, x, new_col); new_col->col_.push_back(*new_cell); // and insert it in the matrix, in constant time thanks to the hint cam_.end(). // Indeed *new_col has the biggest lexicographic value because key is the @@ -552,9 +565,9 @@ class Persistent_cohomology { Arith_element charac) { // Create a finite persistent interval for which the interval exists if (interval_length_policy(cpx_->simplex(death_key), sigma)) { - persistent_pairs_.push_back(Persistent_interval(cpx_->simplex(death_key) // creator - , sigma // destructor - , charac)); // fields + persistent_pairs_.emplace_back(cpx_->simplex(death_key) // creator + , sigma // destructor + , charac); // fields } auto death_key_row = transverse_idx_.find(death_key); // Find the beginning of the row. @@ -570,9 +583,8 @@ class Persistent_cohomology { Column * curr_col = row_cell_it->self_col_; ++row_cell_it; // Disconnect the column from the rows in the CAM. - for (auto col_cell_it = curr_col->col_.begin(); - col_cell_it != curr_col->col_.end(); ++col_cell_it) { - col_cell_it->base_hook_cam_h::unlink(); + for (auto& col_cell : curr_col->col_) { + col_cell.base_hook_cam_h::unlink(); } // Remove the column from the CAM before modifying its value @@ -587,9 +599,9 @@ class Persistent_cohomology { // Find whether the column obtained is already in the CAM result_insert_cam = cam_.insert(*curr_col); if (result_insert_cam.second) { // If it was not in the CAM before: insertion has succeeded - for (auto col_cell_it = curr_col->col_.begin(); col_cell_it != curr_col->col_.end(); ++col_cell_it) { + for (auto& col_cell : curr_col->col_) { // re-establish the row links - transverse_idx_[col_cell_it->key_].row_->push_front(*col_cell_it); + transverse_idx_[col_cell.key_].row_->push_front(col_cell); } } else { // There is already an identical column in the CAM: // merge two disjoint sets. @@ -599,6 +611,8 @@ class Persistent_cohomology { Simplex_key key_tmp = dsets_.find_set(curr_col->class_key_); ds_repr_[key_tmp] = &(*(result_insert_cam.first)); result_insert_cam.first->class_key_ = key_tmp; + // intrusive containers don't own their elements, we have to release them manually + curr_col->col_.clear_and_dispose([&](Cell*p){cell_pool_.destroy(p);}); column_pool_.destroy(curr_col); // delete curr_col; } } @@ -694,7 +708,7 @@ class Persistent_cohomology { void output_diagram(std::ostream& ostream = std::cout) { cmp_intervals_by_length cmp(cpx_); - persistent_pairs_.sort(cmp); + std::sort(std::begin(persistent_pairs_), std::end(persistent_pairs_), cmp); bool has_infinity = std::numeric_limits<Filtration_value>::has_infinity; for (auto pair : persistent_pairs_) { // Special case on windows, inf is "1.#INF" (cf. unitary tests and R package TDA) @@ -709,13 +723,11 @@ class Persistent_cohomology { } } - void write_output_diagram(std::string diagram_name) - { - std::ofstream diagram_out(diagram_name.c_str()); - cmp_intervals_by_length cmp( cpx_ ); - persistent_pairs_.sort( cmp ); - for(auto pair : persistent_pairs_) - { + void write_output_diagram(std::string diagram_name) { + std::ofstream diagram_out(diagram_name.c_str()); + cmp_intervals_by_length cmp(cpx_); + std::sort(std::begin(persistent_pairs_), std::end(persistent_pairs_), cmp); + for (auto pair : persistent_pairs_) { diagram_out << cpx_->dimension(get<0>(pair)) << " " << cpx_->filtration(get<0>(pair)) << " " << cpx_->filtration(get<1>(pair)) << std::endl; @@ -742,6 +754,7 @@ class Persistent_cohomology { Complex_ds * cpx_; int dim_max_; CoefficientField coeff_field_; + size_t num_simplices_; /* Disjoint sets data structure to link the model of FilteredComplex * with the compressed annotation matrix. @@ -760,11 +773,11 @@ class Persistent_cohomology { /* Key -> row. */ std::map<Simplex_key, cocycle> transverse_idx_; /* Persistent intervals. */ - std::list<Persistent_interval> persistent_pairs_; + std::vector<Persistent_interval> persistent_pairs_; length_interval interval_length_policy; - boost::object_pool<Column> column_pool_; - boost::object_pool<Cell> cell_pool_; + Simple_object_pool<Column> column_pool_; + Simple_object_pool<Cell> cell_pool_; }; /** @} */ // end defgroup persistent_cohomology @@ -773,4 +786,4 @@ class Persistent_cohomology { } // namespace Gudhi -#endif // SRC_PERSISTENT_COHOMOLOGY_INCLUDE_GUDHI_PERSISTENT_COHOMOLOGY_H_ +#endif // PERSISTENT_COHOMOLOGY_H_ diff --git a/src/Persistent_cohomology/include/gudhi/Persistent_cohomology/Field_Zp.h b/src/Persistent_cohomology/include/gudhi/Persistent_cohomology/Field_Zp.h index 2a4c8692..6db16e69 100644 --- a/src/Persistent_cohomology/include/gudhi/Persistent_cohomology/Field_Zp.h +++ b/src/Persistent_cohomology/include/gudhi/Persistent_cohomology/Field_Zp.h @@ -20,8 +20,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SRC_PERSISTENT_COHOMOLOGY_INCLUDE_GUDHI_PERSISTENT_COHOMOLOGY_FIELD_ZP_H_ -#define SRC_PERSISTENT_COHOMOLOGY_INCLUDE_GUDHI_PERSISTENT_COHOMOLOGY_FIELD_ZP_H_ +#ifndef PERSISTENT_COHOMOLOGY_FIELD_ZP_H_ +#define PERSISTENT_COHOMOLOGY_FIELD_ZP_H_ #include <utility> #include <vector> @@ -41,9 +41,7 @@ class Field_Zp { Field_Zp() : Prime(0), - inverse_(), - mult_id_all(1), - add_id_all(0) { + inverse_() { } void init(int charac) { @@ -81,14 +79,14 @@ class Field_Zp { } /** \brief Returns the additive idendity \f$0_{\Bbbk}\f$ of the field.*/ - const Element& additive_identity() const { - return add_id_all; + Element additive_identity() const { + return 0; } /** \brief Returns the multiplicative identity \f$1_{\Bbbk}\f$ of the field.*/ - const Element& multiplicative_identity(Element = 0) const { - return mult_id_all; + Element multiplicative_identity(Element = 0) const { + return 1; } - /** Returns the inverse in the field. Modifies P.*/ + /** Returns the inverse in the field. Modifies P. ??? */ std::pair<Element, Element> inverse(Element x, Element P) { return std::pair<Element, Element>(inverse_[x], P); } // <------ return the product of field characteristic for which x is invertible @@ -101,7 +99,7 @@ class Field_Zp { } /** \brief Returns the characteristic \f$p\f$ of the field.*/ - const int& characteristic() const { + int characteristic() const { return Prime; } @@ -109,12 +107,10 @@ class Field_Zp { int Prime; /** Property map Element -> Element, which associate to an element its inverse in the field.*/ std::vector<Element> inverse_; - const Element mult_id_all; - const Element add_id_all; }; } // namespace persistent_cohomology } // namespace Gudhi -#endif // SRC_PERSISTENT_COHOMOLOGY_INCLUDE_GUDHI_PERSISTENT_COHOMOLOGY_FIELD_ZP_H_ +#endif // PERSISTENT_COHOMOLOGY_FIELD_ZP_H_ diff --git a/src/Persistent_cohomology/include/gudhi/Persistent_cohomology/Multi_field.h b/src/Persistent_cohomology/include/gudhi/Persistent_cohomology/Multi_field.h index c6fd5282..38bc08d1 100644 --- a/src/Persistent_cohomology/include/gudhi/Persistent_cohomology/Multi_field.h +++ b/src/Persistent_cohomology/include/gudhi/Persistent_cohomology/Multi_field.h @@ -20,8 +20,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SRC_PERSISTENT_COHOMOLOGY_INCLUDE_GUDHI_PERSISTENT_COHOMOLOGY_MULTI_FIELD_H_ -#define SRC_PERSISTENT_COHOMOLOGY_INCLUDE_GUDHI_PERSISTENT_COHOMOLOGY_MULTI_FIELD_H_ +#ifndef PERSISTENT_COHOMOLOGY_MULTI_FIELD_H_ +#define PERSISTENT_COHOMOLOGY_MULTI_FIELD_H_ #include <gmpxx.h> @@ -81,8 +81,7 @@ class Multi_field { // set m to primorial(bound_prime) prod_characteristics_ = 1; for (auto p : primes_) { - mpz_mul_ui(prod_characteristics_.get_mpz_t(), - prod_characteristics_.get_mpz_t(), p); + prod_characteristics_ *= p; } // Uvect_ @@ -142,7 +141,7 @@ class Multi_field { return prod_characteristics_; } - /** Returns the inverse in the field. Modifies P.*/ + /** Returns the inverse in the field. Modifies P. ??? */ std::pair<Element, Element> inverse(Element x, Element QS) { Element QR; mpz_gcd(QR.get_mpz_t(), x.get_mpz_t(), QS.get_mpz_t()); // QR <- gcd(x,QS) @@ -153,12 +152,12 @@ class Multi_field { mpz_invert(inv_qt.get_mpz_t(), x.get_mpz_t(), QT.get_mpz_t()); assert(prod_characteristics_ > 0); // division by zero + non negative values - return std::pair<Element, Element>( - (inv_qt * multiplicative_identity(QT)) % prod_characteristics_, QT); + return { (inv_qt * multiplicative_identity(QT)) % prod_characteristics_, QT }; } /** Returns -x * y.*/ Element times_minus(const Element& x, const Element& y) { assert(prod_characteristics_ > 0); // division by zero + non negative values + /* This assumes that (x*y)%pc cannot be zero, but Field_Zp has specific code for the 0 case ??? */ return prod_characteristics_ - ((x * y) % prod_characteristics_); } @@ -183,4 +182,4 @@ class Multi_field { } // namespace Gudhi -#endif // SRC_PERSISTENT_COHOMOLOGY_INCLUDE_GUDHI_PERSISTENT_COHOMOLOGY_MULTI_FIELD_H_ +#endif // PERSISTENT_COHOMOLOGY_MULTI_FIELD_H_ diff --git a/src/Persistent_cohomology/include/gudhi/Persistent_cohomology/Persistent_cohomology_column.h b/src/Persistent_cohomology/include/gudhi/Persistent_cohomology/Persistent_cohomology_column.h index fcec819a..612658e6 100644 --- a/src/Persistent_cohomology/include/gudhi/Persistent_cohomology/Persistent_cohomology_column.h +++ b/src/Persistent_cohomology/include/gudhi/Persistent_cohomology/Persistent_cohomology_column.h @@ -20,14 +20,14 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SRC_PERSISTENT_COHOMOLOGY_INCLUDE_GUDHI_PERSISTENT_COHOMOLOGY_PERSISTENT_COHOMOLOGY_COLUMN_H_ -#define SRC_PERSISTENT_COHOMOLOGY_INCLUDE_GUDHI_PERSISTENT_COHOMOLOGY_PERSISTENT_COHOMOLOGY_COLUMN_H_ +#ifndef PERSISTENT_COHOMOLOGY_PERSISTENT_COHOMOLOGY_COLUMN_H_ +#define PERSISTENT_COHOMOLOGY_PERSISTENT_COHOMOLOGY_COLUMN_H_ -#include <list> +#include <boost/tuple/tuple.hpp> +#include <boost/intrusive/set.hpp> +#include <boost/intrusive/list.hpp> -#include "boost/tuple/tuple.hpp" -#include "boost/intrusive/set.hpp" -#include "boost/intrusive/list.hpp" +#include <list> namespace Gudhi { @@ -80,40 +80,33 @@ class Persistent_cohomology_cell : public base_hook_cam_h, * The non-zero coefficients of the column are stored in a * boost::intrusive::list. Contains a hook to be stored in a * boost::intrusive::set. + * + * Movable but not Copyable. */ template<typename SimplexKey, typename ArithmeticElement> class Persistent_cohomology_column : public boost::intrusive::set_base_hook< boost::intrusive::link_mode<boost::intrusive::normal_link> > { - private: template<class T1, class T2> friend class Persistent_cohomology; + public: typedef Persistent_cohomology_cell<SimplexKey, ArithmeticElement> Cell; typedef boost::intrusive::list<Cell, boost::intrusive::constant_time_size<false>, boost::intrusive::base_hook<base_hook_cam_v> > Col_type; /** \brief Creates an empty column.*/ - explicit Persistent_cohomology_column(SimplexKey key) { - class_key_ = key; - col_ = Col_type(); - } - public: - /** Copy constructor.*/ - Persistent_cohomology_column(Persistent_cohomology_column const &other) + explicit Persistent_cohomology_column(SimplexKey key) : col_(), - class_key_(other.class_key_) { - if (!other.col_.empty()) - std::cerr << "Copying a non-empty column.\n"; - } + class_key_(key) {} /** \brief Returns true iff the column is null.*/ - bool is_null() { + bool is_null() const { return col_.empty(); } /** \brief Returns the key of the representative simplex of * the set of simplices having this column as annotation vector * in the compressed annotation matrix.*/ - SimplexKey class_key() { + SimplexKey class_key() const { return class_key_; } @@ -145,4 +138,4 @@ class Persistent_cohomology_column : public boost::intrusive::set_base_hook< } // namespace Gudhi -#endif // SRC_PERSISTENT_COHOMOLOGY_INCLUDE_GUDHI_PERSISTENT_COHOMOLOGY_PERSISTENT_COHOMOLOGY_COLUMN_H_ +#endif // PERSISTENT_COHOMOLOGY_PERSISTENT_COHOMOLOGY_COLUMN_H_ diff --git a/src/Persistent_cohomology/test/persistent_cohomology_unit_test.cpp b/src/Persistent_cohomology/test/persistent_cohomology_unit_test.cpp index 55bc7066..194b3e74 100644 --- a/src/Persistent_cohomology/test/persistent_cohomology_unit_test.cpp +++ b/src/Persistent_cohomology/test/persistent_cohomology_unit_test.cpp @@ -1,15 +1,14 @@ -#define BOOST_TEST_MODULE persistent_cohomology test -#include <boost/test/included/unit_test.hpp> -#include <boost/system/error_code.hpp> -#include <boost/chrono/thread_clock.hpp> #include <iostream> #include <string> - +#include <algorithm> #include <utility> // std::pair, std::make_pair - #include <cmath> // float comparison #include <limits> +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE "persistent_cohomology" +#include <boost/test/unit_test.hpp> + #include "gudhi/graph_simplicial_complex.h" #include "gudhi/reader_utils.h" #include "gudhi/Simplex_tree.h" diff --git a/src/Persistent_cohomology/test/persistent_cohomology_unit_test_multi_field.cpp b/src/Persistent_cohomology/test/persistent_cohomology_unit_test_multi_field.cpp index 18a4725e..703682e1 100644 --- a/src/Persistent_cohomology/test/persistent_cohomology_unit_test_multi_field.cpp +++ b/src/Persistent_cohomology/test/persistent_cohomology_unit_test_multi_field.cpp @@ -1,15 +1,14 @@ -#define BOOST_TEST_MODULE persistent_cohomology_multi_field test -#include <boost/test/included/unit_test.hpp> -#include <boost/system/error_code.hpp> -#include <boost/chrono/thread_clock.hpp> #include <iostream> #include <string> - +#include <algorithm> #include <utility> // std::pair, std::make_pair - #include <cmath> // float comparison #include <limits> +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE "persistent_cohomology_multi_field" +#include <boost/test/unit_test.hpp> + #include "gudhi/graph_simplicial_complex.h" #include "gudhi/reader_utils.h" #include "gudhi/Simplex_tree.h" diff --git a/src/Simplex_tree/concept/IndexingTag.h b/src/Simplex_tree/concept/IndexingTag.h index d690da11..1dcdd756 100644 --- a/src/Simplex_tree/concept/IndexingTag.h +++ b/src/Simplex_tree/concept/IndexingTag.h @@ -25,6 +25,6 @@ * continuous maps to a cell complex, and compute its persistent * homology. * - * Must be linear_indexing_tag. + * Must be `Gudhi::linear_indexing_tag`. */ struct IndexingTag {}; diff --git a/src/Simplex_tree/concept/SimplexKey.h b/src/Simplex_tree/concept/SimplexKey.h index ce5b2382..7fdbdd84 100644 --- a/src/Simplex_tree/concept/SimplexKey.h +++ b/src/Simplex_tree/concept/SimplexKey.h @@ -22,7 +22,7 @@ /** \brief Key type used as simplex identifier. * - * Must be <CODE>int</CODE> + * Must be a signed integer type. */ struct SimplexKey {}; -
\ No newline at end of file + diff --git a/src/Simplex_tree/concept/SimplexTreeOptions.h b/src/Simplex_tree/concept/SimplexTreeOptions.h new file mode 100644 index 00000000..add3ebdd --- /dev/null +++ b/src/Simplex_tree/concept/SimplexTreeOptions.h @@ -0,0 +1,41 @@ + /* 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): Marc Glisse + * + * Copyright (C) 2015 INRIA Saclay - Ile-de-France (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/>. + */ + +/** \brief Concept of the template parameter for the class `Gudhi::Simplex_tree<SimplexTreeOptions>`. + * + * One model for this is `Gudhi::Simplex_tree_options_full_featured`. If you want to provide your own, it is recommended that you derive from it and override some parts instead of writing a class from scratch. + */ +struct SimplexTreeOptions { + /// Forced for now. + typedef IndexingTag Indexing_tag; + /// Must be a signed integer type. It admits a total order <. + typedef VertexHandle Vertex_handle; + /// Must be comparable with operator<. + typedef FiltrationValue Filtration_value; + /// Must be a signed integer type. + typedef SimplexKey Simplex_key; + /// If true, each simplex has extra storage for one `Simplex_key`. Necessary for `Persistent_cohomology`. + static const bool store_key; + /// If true, each simplex has extra storage for one `Filtration_value`, and this value is propagated by operations like `Gudhi::Simplex_tree::expansion`. Without it, `Persistent_cohomology` degenerates to computing usual (non-persistent) cohomology. + static const bool store_filtration; +}; + diff --git a/src/Simplex_tree/concept/VertexHandle.h b/src/Simplex_tree/concept/VertexHandle.h index 491f0f56..3efbba61 100644 --- a/src/Simplex_tree/concept/VertexHandle.h +++ b/src/Simplex_tree/concept/VertexHandle.h @@ -22,5 +22,6 @@ /** \brief Handle type for the vertices of a cell complex. * - * Must be int.*/ + * Must be a signed integer type. <code>operator<</code> defines a total order on it. + */ struct VertexHandle {}; diff --git a/src/Simplex_tree/example/CMakeLists.txt b/src/Simplex_tree/example/CMakeLists.txt index 1a3cdfbf..c70cfe35 100644 --- a/src/Simplex_tree/example/CMakeLists.txt +++ b/src/Simplex_tree/example/CMakeLists.txt @@ -1,21 +1,24 @@ cmake_minimum_required(VERSION 2.6) project(GUDHISimplexTreeFromFile) -add_executable ( simplex_tree_from_file simplex_tree_from_file.cpp ) -add_test(simplex_tree_from_file_2 ${CMAKE_CURRENT_BINARY_DIR}/simplex_tree_from_file ${CMAKE_SOURCE_DIR}/data/points/Klein_bottle_complex.txt 2) -add_test(simplex_tree_from_file_3 ${CMAKE_CURRENT_BINARY_DIR}/simplex_tree_from_file ${CMAKE_SOURCE_DIR}/data/points/Klein_bottle_complex.txt 3) +add_executable ( simplex_tree_from_cliques_of_graph simplex_tree_from_cliques_of_graph.cpp ) +add_test(simplex_tree_from_cliques_of_graph_2 ${CMAKE_CURRENT_BINARY_DIR}/simplex_tree_from_cliques_of_graph ${CMAKE_SOURCE_DIR}/data/points/Klein_bottle_complex.txt 2) +add_test(simplex_tree_from_cliques_of_graph_3 ${CMAKE_CURRENT_BINARY_DIR}/simplex_tree_from_cliques_of_graph ${CMAKE_SOURCE_DIR}/data/points/Klein_bottle_complex.txt 3) add_executable ( simple_simplex_tree simple_simplex_tree.cpp ) add_test(simple_simplex_tree ${CMAKE_CURRENT_BINARY_DIR}/simple_simplex_tree) - + +add_executable ( mini_simplex_tree mini_simplex_tree.cpp ) +add_test(mini_simplex_tree ${CMAKE_CURRENT_BINARY_DIR}/mini_simplex_tree) + # An example with Simplex-tree using CGAL alpha_shapes_3 if(GMP_FOUND AND CGAL_FOUND) message("CGAL_lib = ${CGAL_LIBRARIES_DIR}") - message("GMP_LIBRARIES = ${GMP_LIBRARIES}") + message("GMP_LIBRARIES = ${GMP_LIBRARIES}") INCLUDE_DIRECTORIES(${GMP_INCLUDE_DIR}) INCLUDE_DIRECTORIES(${CGAL_INCLUDE_DIRS}) add_executable ( simplex_tree_from_alpha_shapes_3 simplex_tree_from_alpha_shapes_3.cpp ) target_link_libraries(simplex_tree_from_alpha_shapes_3 ${GMP_LIBRARIES} ${CGAL_LIBRARY}) add_test(simplex_tree_from_alpha_shapes_3 ${CMAKE_CURRENT_BINARY_DIR}/simplex_tree_from_alpha_shapes_3 ${CMAKE_SOURCE_DIR}/data/points/bunny_5000) -endif() +endif() diff --git a/src/Simplex_tree/example/mini_simplex_tree.cpp b/src/Simplex_tree/example/mini_simplex_tree.cpp new file mode 100644 index 00000000..7e48aaaf --- /dev/null +++ b/src/Simplex_tree/example/mini_simplex_tree.cpp @@ -0,0 +1,69 @@ +/* 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): Marc Glisse + * + * Copyright (C) 2015 INRIA Saclay - Ile-de-France (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <gudhi/Simplex_tree.h> +#include <iostream> +#include <initializer_list> + +using namespace Gudhi; + +struct MyOptions : Simplex_tree_options_full_featured { + // Not doing persistence, so we don't need those + static const bool store_key = false; + static const bool store_filtration = false; + // I have few vertices + typedef short Vertex_handle; +}; +typedef Simplex_tree<MyOptions> ST; + +// Dictionary should be private, but for now this is the easiest way. +static_assert(sizeof(ST::Dictionary::value_type) < sizeof(Simplex_tree<>::Dictionary::value_type), + "Not storing the filtration and key should save some space"); + +int main() { + ST st; + + /* Complex to build. */ + /* 1 */ + /* o */ + /* /X\ */ + /* o---o---o */ + /* 2 0 3 */ + + auto triangle012 = {0, 1, 2}; + auto edge03 = {0, 3}; + st.insert_simplex_and_subfaces(triangle012); + st.insert_simplex_and_subfaces(edge03); + // FIXME: Remove this line + st.set_dimension(2); + + auto edge02 = {0, 2}; + ST::Simplex_handle e = st.find(edge02); + // We are not using filtrations so everything has value 0 + assert(st.filtration(e) == 0); + for (ST::Simplex_handle t : st.cofaces_simplex_range(e, 1)) { + // Only coface is 012 + for (ST::Vertex_handle v : st.simplex_vertex_range(t)) // v in { 0, 1, 2 } + std::cout << v; + std::cout << '\n'; + } +} diff --git a/src/Simplex_tree/example/simple_simplex_tree.cpp b/src/Simplex_tree/example/simple_simplex_tree.cpp index 6d20e43e..5146b906 100644 --- a/src/Simplex_tree/example/simple_simplex_tree.cpp +++ b/src/Simplex_tree/example/simple_simplex_tree.cpp @@ -20,10 +20,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <gudhi/graph_simplicial_complex.h> +#include <gudhi/Simplex_tree.h> + #include <iostream> -#include <ctime> -#include "gudhi/graph_simplicial_complex.h" -#include "gudhi/Simplex_tree.h" +#include <utility> // for pair +#include <vector> using namespace Gudhi; @@ -35,15 +37,11 @@ int main(int argc, char * const argv[]) { const Filtration_value SECOND_FILTRATION_VALUE = 0.2; const Filtration_value THIRD_FILTRATION_VALUE = 0.3; const Filtration_value FOURTH_FILTRATION_VALUE = 0.4; - Vertex_handle FIRST_VERTEX_HANDLE = (Vertex_handle) 0; - Vertex_handle SECOND_VERTEX_HANDLE = (Vertex_handle) 1; - Vertex_handle THIRD_VERTEX_HANDLE = (Vertex_handle) 2; - Vertex_handle FOURTH_VERTEX_HANDLE = (Vertex_handle) 3; // TEST OF INSERTION std::cout << "********************************************************************" << std::endl; std::cout << "EXAMPLE OF SIMPLE INSERTION" << std::endl; - //Construct the Simplex Tree + // Construct the Simplex Tree Simplex_tree<> simplexTree; /* Simplex to be inserted: */ @@ -55,190 +53,149 @@ int main(int argc, char * const argv[]) { // ++ FIRST std::cout << " * INSERT 0" << std::endl; - typeVectorVertex firstSimplexVector; - firstSimplexVector.push_back(FIRST_VERTEX_HANDLE); + typeVectorVertex firstSimplexVector = { 0 }; typePairSimplexBool returnValue = simplexTree.insert_simplex(firstSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + 0 INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - 0 NOT INSERTED" << std::endl; } // ++ SECOND std::cout << " * INSERT 1" << std::endl; - typeVectorVertex secondSimplexVector; - secondSimplexVector.push_back(SECOND_VERTEX_HANDLE); + typeVectorVertex secondSimplexVector = { 1 }; returnValue = simplexTree.insert_simplex(secondSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + 1 INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - 1 NOT INSERTED" << std::endl; } // ++ THIRD std::cout << " * INSERT (0,1)" << std::endl; - typeVectorVertex thirdSimplexVector; - thirdSimplexVector.push_back(FIRST_VERTEX_HANDLE); - thirdSimplexVector.push_back(SECOND_VERTEX_HANDLE); + typeVectorVertex thirdSimplexVector = { 0, 1 }; returnValue = simplexTree.insert_simplex(thirdSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + (0,1) INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - (0,1) NOT INSERTED" << std::endl; } // ++ FOURTH std::cout << " * INSERT 2" << std::endl; - typeVectorVertex fourthSimplexVector; - fourthSimplexVector.push_back(THIRD_VERTEX_HANDLE); + typeVectorVertex fourthSimplexVector = { 2 }; returnValue = simplexTree.insert_simplex(fourthSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + 2 INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - 2 NOT INSERTED" << std::endl; } // ++ FIFTH std::cout << " * INSERT (2,0)" << std::endl; - typeVectorVertex fifthSimplexVector; - fifthSimplexVector.push_back(THIRD_VERTEX_HANDLE); - fifthSimplexVector.push_back(FIRST_VERTEX_HANDLE); + typeVectorVertex fifthSimplexVector = { 2, 0 }; returnValue = simplexTree.insert_simplex(fifthSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + (2,0) INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - (2,0) NOT INSERTED" << std::endl; } // ++ SIXTH std::cout << " * INSERT (2,1)" << std::endl; - typeVectorVertex sixthSimplexVector; - sixthSimplexVector.push_back(THIRD_VERTEX_HANDLE); - sixthSimplexVector.push_back(SECOND_VERTEX_HANDLE); + typeVectorVertex sixthSimplexVector = { 2, 1 }; returnValue = simplexTree.insert_simplex(sixthSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + (2,1) INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - (2,1) NOT INSERTED" << std::endl; } // ++ SEVENTH std::cout << " * INSERT (2,1,0)" << std::endl; - typeVectorVertex seventhSimplexVector; - seventhSimplexVector.push_back(THIRD_VERTEX_HANDLE); - seventhSimplexVector.push_back(SECOND_VERTEX_HANDLE); - seventhSimplexVector.push_back(FIRST_VERTEX_HANDLE); + typeVectorVertex seventhSimplexVector = { 2, 1, 0 }; returnValue = simplexTree.insert_simplex(seventhSimplexVector, Filtration_value(THIRD_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + (2,1,0) INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - (2,1,0) NOT INSERTED" << std::endl; } // ++ EIGHTH std::cout << " * INSERT 3" << std::endl; - typeVectorVertex eighthSimplexVector; - eighthSimplexVector.push_back(FOURTH_VERTEX_HANDLE); + typeVectorVertex eighthSimplexVector = { 3 }; returnValue = simplexTree.insert_simplex(eighthSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + 3 INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - 3 NOT INSERTED" << std::endl; } // ++ NINETH std::cout << " * INSERT (3,0)" << std::endl; - typeVectorVertex ninethSimplexVector; - ninethSimplexVector.push_back(FOURTH_VERTEX_HANDLE); - ninethSimplexVector.push_back(FIRST_VERTEX_HANDLE); + typeVectorVertex ninethSimplexVector = { 3, 0 }; returnValue = simplexTree.insert_simplex(ninethSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + (3,0) INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - (3,0) NOT INSERTED" << std::endl; } // ++ TENTH std::cout << " * INSERT 0 (already inserted)" << std::endl; - typeVectorVertex tenthSimplexVector; - tenthSimplexVector.push_back(FIRST_VERTEX_HANDLE); - returnValue = - simplexTree.insert_simplex(tenthSimplexVector, Filtration_value(FOURTH_FILTRATION_VALUE)); // With a different filtration value + typeVectorVertex tenthSimplexVector = { 0 }; + // With a different filtration value + returnValue = simplexTree.insert_simplex(tenthSimplexVector, Filtration_value(FOURTH_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + 0 INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - 0 NOT INSERTED" << std::endl; } // ++ ELEVENTH std::cout << " * INSERT (2,1,0) (already inserted)" << std::endl; - typeVectorVertex eleventhSimplexVector; - eleventhSimplexVector.push_back(THIRD_VERTEX_HANDLE); - eleventhSimplexVector.push_back(SECOND_VERTEX_HANDLE); - eleventhSimplexVector.push_back(FIRST_VERTEX_HANDLE); + typeVectorVertex eleventhSimplexVector = { 2, 1, 0 }; returnValue = simplexTree.insert_simplex(eleventhSimplexVector, Filtration_value(FOURTH_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + (2,1,0) INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - (2,1,0) NOT INSERTED" << std::endl; } // ++ GENERAL VARIABLE SET - simplexTree.set_filtration(FOURTH_FILTRATION_VALUE); // Max filtration value - simplexTree.set_dimension(2); // Max dimension = 2 -> (2,1,0) + simplexTree.set_filtration(FOURTH_FILTRATION_VALUE); // Max filtration value + simplexTree.set_dimension(2); // Max dimension = 2 -> (2,1,0) - std::cout << "********************************************************************" << std::endl; + std::cout << "********************************************************************\n"; // Display the Simplex_tree - Can not be done in the middle of 2 inserts - std::cout << "* The complex contains " << simplexTree.num_simplices() << " simplices" << std::endl; - std::cout << " - dimension " << simplexTree.dimension() << " - filtration " << simplexTree.filtration() << std::endl; - std::cout << "* Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; + std::cout << "* The complex contains " << simplexTree.num_simplices() << " simplices\n"; + std::cout << " - dimension " << simplexTree.dimension() << " - filtration " << simplexTree.filtration() << "\n"; + std::cout << "* Iterator on Simplices in the filtration, with [filtration value]:\n"; for (auto f_simplex : simplexTree.filtration_simplex_range()) { std::cout << " " << "[" << simplexTree.filtration(f_simplex) << "] "; for (auto vertex : simplexTree.simplex_vertex_range(f_simplex)) { - std::cout << (int) vertex << " "; + std::cout << static_cast<int>(vertex) << " "; } std::cout << std::endl; } @@ -262,9 +219,7 @@ int main(int argc, char * const argv[]) { else std::cout << "***- NO IT ISN'T\n"; - Vertex_handle UNKNOWN_VERTEX_HANDLE = (Vertex_handle) 15; - typeVectorVertex unknownSimplexVector; - unknownSimplexVector.push_back(UNKNOWN_VERTEX_HANDLE); + typeVectorVertex unknownSimplexVector = { 15 }; simplexFound = simplexTree.find(unknownSimplexVector); std::cout << "**************IS THE SIMPLEX {15} IN THE SIMPLEX TREE ?\n"; if (simplexFound != simplexTree.null_simplex()) @@ -279,9 +234,7 @@ int main(int argc, char * const argv[]) { else std::cout << "***- NO IT ISN'T\n"; - typeVectorVertex otherSimplexVector; - otherSimplexVector.push_back(UNKNOWN_VERTEX_HANDLE); - otherSimplexVector.push_back(SECOND_VERTEX_HANDLE); + typeVectorVertex otherSimplexVector = { 1, 15 }; simplexFound = simplexTree.find(otherSimplexVector); std::cout << "**************IS THE SIMPLEX {15,1} IN THE SIMPLEX TREE ?\n"; if (simplexFound != simplexTree.null_simplex()) @@ -289,10 +242,7 @@ int main(int argc, char * const argv[]) { else std::cout << "***- NO IT ISN'T\n"; - typeVectorVertex invSimplexVector; - invSimplexVector.push_back(SECOND_VERTEX_HANDLE); - invSimplexVector.push_back(THIRD_VERTEX_HANDLE); - invSimplexVector.push_back(FIRST_VERTEX_HANDLE); + typeVectorVertex invSimplexVector = { 1, 2, 0 }; simplexFound = simplexTree.find(invSimplexVector); std::cout << "**************IS THE SIMPLEX {1,2,0} IN THE SIMPLEX TREE ?\n"; if (simplexFound != simplexTree.null_simplex()) diff --git a/src/Simplex_tree/example/simplex_tree_from_alpha_shapes_3.cpp b/src/Simplex_tree/example/simplex_tree_from_alpha_shapes_3.cpp index 5f797e93..45efe3ed 100644 --- a/src/Simplex_tree/example/simplex_tree_from_alpha_shapes_3.cpp +++ b/src/Simplex_tree/example/simplex_tree_from_alpha_shapes_3.cpp @@ -1,24 +1,28 @@ - /* 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 Saclay (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/>. - */ +/* 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 Saclay (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <gudhi/graph_simplicial_complex.h> +#include <gudhi/Simplex_tree.h> +#include <boost/variant.hpp> #include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Delaunay_triangulation_3.h> @@ -27,32 +31,34 @@ #include <fstream> #include <cmath> - -#include "gudhi/graph_simplicial_complex.h" -#include "gudhi/Simplex_tree.h" -#include <boost/variant.hpp> +#include <string> +#include <tuple> // for tuple<> +#include <map> +#include <utility> // for pair<> +#include <list> +#include <vector> // Alpha_shape_3 templates type definitions typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; -typedef CGAL::Alpha_shape_vertex_base_3<Kernel> Vb; -typedef CGAL::Alpha_shape_cell_base_3<Kernel> Fb; -typedef CGAL::Triangulation_data_structure_3<Vb,Fb> Tds; -typedef CGAL::Delaunay_triangulation_3<Kernel,Tds> Triangulation_3; -typedef CGAL::Alpha_shape_3<Triangulation_3> Alpha_shape_3; +typedef CGAL::Alpha_shape_vertex_base_3<Kernel> Vb; +typedef CGAL::Alpha_shape_cell_base_3<Kernel> Fb; +typedef CGAL::Triangulation_data_structure_3<Vb, Fb> Tds; +typedef CGAL::Delaunay_triangulation_3<Kernel, Tds> Triangulation_3; +typedef CGAL::Alpha_shape_3<Triangulation_3> Alpha_shape_3; // From file type definition -typedef Kernel::Point_3 Point; +typedef Kernel::Point_3 Point; // filtration with alpha values needed type definition typedef Alpha_shape_3::FT Alpha_value_type; -typedef CGAL::Object Object; +typedef CGAL::Object Object; typedef CGAL::Dispatch_output_iterator< - CGAL::cpp11::tuple<Object, Alpha_value_type>, - CGAL::cpp11::tuple<std::back_insert_iterator< std::vector<Object> >, std::back_insert_iterator< std::vector<Alpha_value_type> > - > > Dispatch; -typedef Alpha_shape_3::Cell_handle Cell_handle; -typedef Alpha_shape_3::Facet Facet; -typedef Alpha_shape_3::Edge Edge; +CGAL::cpp11::tuple<Object, Alpha_value_type>, +CGAL::cpp11::tuple<std::back_insert_iterator< std::vector<Object> >, + std::back_insert_iterator< std::vector<Alpha_value_type> > > > Dispatch; +typedef Alpha_shape_3::Cell_handle Cell_handle; +typedef Alpha_shape_3::Facet Facet; +typedef Alpha_shape_3::Edge Edge; typedef std::list<Alpha_shape_3::Vertex_handle> Vertex_list; // gudhi type definition @@ -61,225 +67,209 @@ typedef std::map<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex > Alpha_shape typedef std::pair<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex> Alpha_shape_simplex_tree_pair; typedef std::vector< Simplex_tree_vertex > Simplex_tree_vector_vertex; -//#define DEBUG_TRACES - -Vertex_list from (const Cell_handle& ch) -{ - Vertex_list the_list; - for (auto i = 0; i < 4; i++) - { +Vertex_list from(const Cell_handle& ch) { + Vertex_list the_list; + for (auto i = 0; i < 4; i++) { #ifdef DEBUG_TRACES - std::cout << "from cell[" << i << "]=" << ch->vertex(i)->point() << std::endl; -#endif // DEBUG_TRACES - the_list.push_back(ch->vertex(i)); - } - return the_list; + std::cout << "from cell[" << i << "]=" << ch->vertex(i)->point() << std::endl; +#endif // DEBUG_TRACES + the_list.push_back(ch->vertex(i)); + } + return the_list; } -Vertex_list from (const Facet& fct) -{ - Vertex_list the_list; - for (auto i = 0; i < 4; i++) - { - if (fct.second != i) - { + +Vertex_list from(const Facet& fct) { + Vertex_list the_list; + for (auto i = 0; i < 4; i++) { + if (fct.second != i) { #ifdef DEBUG_TRACES - std::cout << "from facet=[" << i << "]" << fct.first->vertex(i)->point() << std::endl; -#endif // DEBUG_TRACES - the_list.push_back(fct.first->vertex(i)); - } - } - return the_list; + std::cout << "from facet=[" << i << "]" << fct.first->vertex(i)->point() << std::endl; +#endif // DEBUG_TRACES + the_list.push_back(fct.first->vertex(i)); + } + } + return the_list; } -Vertex_list from (const Edge& edg) -{ - Vertex_list the_list; - for (auto i = 0; i < 4; i++) - { - if ((edg.second == i) ||(edg.third == i)) - { + +Vertex_list from(const Edge& edg) { + Vertex_list the_list; + for (auto i = 0; i < 4; i++) { + if ((edg.second == i) || (edg.third == i)) { #ifdef DEBUG_TRACES - std::cout << "from edge[" << i << "]=" << edg.first->vertex(i)->point() << std::endl; -#endif // DEBUG_TRACES - the_list.push_back(edg.first->vertex(i)); - } - } - return the_list; + std::cout << "from edge[" << i << "]=" << edg.first->vertex(i)->point() << std::endl; +#endif // DEBUG_TRACES + the_list.push_back(edg.first->vertex(i)); + } + } + return the_list; } -Vertex_list from (const Alpha_shape_3::Vertex_handle& vh) -{ - Vertex_list the_list; + +Vertex_list from(const Alpha_shape_3::Vertex_handle& vh) { + Vertex_list the_list; #ifdef DEBUG_TRACES - std::cout << "from vertex=" << vh->point() << std::endl; -#endif // DEBUG_TRACES - the_list.push_back(vh); - return the_list; + std::cout << "from vertex=" << vh->point() << std::endl; +#endif // DEBUG_TRACES + the_list.push_back(vh); + return the_list; } +int main(int argc, char * const argv[]) { + // program args management + if (argc != 2) { + std::cerr << "Usage: " << argv[0] + << " path_to_file_graph \n"; + return 0; + } -int main (int argc, char * const argv[]) -{ - // program args management - if (argc != 2) { - std::cerr << "Usage: " << argv[0] - << " path_to_file_graph \n"; - return 0; // ----- >> - } - - // Read points from file - std::string filegraph = argv[1]; - std::list<Point> lp; - std::ifstream is(filegraph.c_str()); - int n; - is >> n; + // Read points from file + std::string filegraph = argv[1]; + std::list<Point> lp; + std::ifstream is(filegraph.c_str()); + int n; + is >> n; #ifdef DEBUG_TRACES - std::cout << "Reading " << n << " points " << std::endl; -#endif // DEBUG_TRACES - Point p; - for( ; n>0 ; n--) { - is >> p; - lp.push_back(p); - } + std::cout << "Reading " << n << " points " << std::endl; +#endif // DEBUG_TRACES + Point p; + for (; n > 0; n--) { + is >> p; + lp.push_back(p); + } - // alpha shape construction from points. CGAL has a strange behavior in REGULARIZED mode. - Alpha_shape_3 as(lp.begin(),lp.end(),0,Alpha_shape_3::GENERAL); + // alpha shape construction from points. CGAL has a strange behavior in REGULARIZED mode. + Alpha_shape_3 as(lp.begin(), lp.end(), 0, Alpha_shape_3::GENERAL); #ifdef DEBUG_TRACES - std::cout << "Alpha shape computed in GENERAL mode" << std::endl; -#endif // DEBUG_TRACES + std::cout << "Alpha shape computed in GENERAL mode" << std::endl; +#endif // DEBUG_TRACES - // filtration with alpha values from alpha shape - std::vector<Object> the_objects; - std::vector<Alpha_value_type> the_alpha_values; + // filtration with alpha values from alpha shape + std::vector<Object> the_objects; + std::vector<Alpha_value_type> the_alpha_values; - Dispatch disp = CGAL::dispatch_output<Object, Alpha_value_type>( std::back_inserter(the_objects), std::back_inserter(the_alpha_values)); + Dispatch disp = CGAL::dispatch_output<Object, Alpha_value_type>(std::back_inserter(the_objects), + std::back_inserter(the_alpha_values)); - as.filtration_with_alpha_values(disp); + as.filtration_with_alpha_values(disp); #ifdef DEBUG_TRACES - std::cout << "filtration_with_alpha_values returns : " << the_objects.size() << " objects" << std::endl; -#endif // DEBUG_TRACES + std::cout << "filtration_with_alpha_values returns : " << the_objects.size() << " objects" << std::endl; +#endif // DEBUG_TRACES - Alpha_shape_3::size_type count_vertices = 0; - Alpha_shape_3::size_type count_edges = 0; - Alpha_shape_3::size_type count_facets = 0; - Alpha_shape_3::size_type count_cells = 0; + Alpha_shape_3::size_type count_vertices = 0; + Alpha_shape_3::size_type count_edges = 0; + Alpha_shape_3::size_type count_facets = 0; + Alpha_shape_3::size_type count_cells = 0; - // Loop on objects vector - Vertex_list vertex_list; - Gudhi::Simplex_tree<> simplex_tree; - Alpha_shape_simplex_tree_map map_cgal_simplex_tree; - std::vector<Alpha_value_type>::iterator the_alpha_value_iterator = the_alpha_values.begin(); - for(auto object_iterator: the_objects) - { - // Retrieve Alpha shape vertex list from object - if (const Cell_handle* cell = CGAL::object_cast<Cell_handle>(&object_iterator)) - { - vertex_list = from(*cell); - count_cells++; - } - else if (const Facet* facet = CGAL::object_cast<Facet>(&object_iterator)) - { - vertex_list = from(*facet); - count_facets++; - } - else if (const Edge* edge = CGAL::object_cast<Edge>(&object_iterator)) - { - vertex_list = from(*edge); - count_edges++; - } - else if (const Alpha_shape_3::Vertex_handle* vertex = CGAL::object_cast<Alpha_shape_3::Vertex_handle>(&object_iterator)) - { - count_vertices++; - vertex_list = from(*vertex); - } - // Construction of the vector of simplex_tree vertex from list of alpha_shapes vertex - Simplex_tree_vector_vertex the_simplex_tree; - for (auto the_alpha_shape_vertex:vertex_list) - { - Alpha_shape_simplex_tree_map::iterator the_map_iterator = map_cgal_simplex_tree.find(the_alpha_shape_vertex); - if (the_map_iterator == map_cgal_simplex_tree.end()) - { - // alpha shape not found - Simplex_tree_vertex vertex = map_cgal_simplex_tree.size(); + // Loop on objects vector + Vertex_list vertex_list; + Gudhi::Simplex_tree<> simplex_tree; + Alpha_shape_simplex_tree_map map_cgal_simplex_tree; + std::vector<Alpha_value_type>::iterator the_alpha_value_iterator = the_alpha_values.begin(); + for (auto object_iterator : the_objects) { + // Retrieve Alpha shape vertex list from object + if (const Cell_handle * cell = CGAL::object_cast<Cell_handle>(&object_iterator)) { + vertex_list = from(*cell); + count_cells++; + } else if (const Facet * facet = CGAL::object_cast<Facet>(&object_iterator)) { + vertex_list = from(*facet); + count_facets++; + } else if (const Edge * edge = CGAL::object_cast<Edge>(&object_iterator)) { + vertex_list = from(*edge); + count_edges++; + } else if (const Alpha_shape_3::Vertex_handle * vertex = + CGAL::object_cast<Alpha_shape_3::Vertex_handle>(&object_iterator)) { + count_vertices++; + vertex_list = from(*vertex); + } + // Construction of the vector of simplex_tree vertex from list of alpha_shapes vertex + Simplex_tree_vector_vertex the_simplex_tree; + for (auto the_alpha_shape_vertex : vertex_list) { + Alpha_shape_simplex_tree_map::iterator the_map_iterator = map_cgal_simplex_tree.find(the_alpha_shape_vertex); + if (the_map_iterator == map_cgal_simplex_tree.end()) { + // alpha shape not found + Simplex_tree_vertex vertex = map_cgal_simplex_tree.size(); #ifdef DEBUG_TRACES - std::cout << "vertex [" << the_alpha_shape_vertex->point() << "] not found - insert_simplex " << vertex << std::endl; -#endif // DEBUG_TRACES - the_simplex_tree.push_back(vertex); - map_cgal_simplex_tree.insert(Alpha_shape_simplex_tree_pair(the_alpha_shape_vertex,vertex)); - } else - { - // alpha shape found - Simplex_tree_vertex vertex = the_map_iterator->second; + std::cout << "vertex [" << the_alpha_shape_vertex->point() << "] not found - insert_simplex " << vertex << "\n"; +#endif // DEBUG_TRACES + the_simplex_tree.push_back(vertex); + map_cgal_simplex_tree.insert(Alpha_shape_simplex_tree_pair(the_alpha_shape_vertex, vertex)); + } else { + // alpha shape found + Simplex_tree_vertex vertex = the_map_iterator->second; #ifdef DEBUG_TRACES - std::cout << "vertex [" << the_alpha_shape_vertex->point() << "] found in " << vertex << std::endl; -#endif // DEBUG_TRACES - the_simplex_tree.push_back(vertex); - } - } - // Construction of the simplex_tree + std::cout << "vertex [" << the_alpha_shape_vertex->point() << "] found in " << vertex << std::endl; +#endif // DEBUG_TRACES + the_simplex_tree.push_back(vertex); + } + } + // Construction of the simplex_tree #ifdef DEBUG_TRACES - std::cout << "filtration = " << *the_alpha_value_iterator << std::endl; -#endif // DEBUG_TRACES - simplex_tree.insert_simplex(the_simplex_tree, std::sqrt(*the_alpha_value_iterator)); - if (the_alpha_value_iterator != the_alpha_values.end()) - ++the_alpha_value_iterator; - else - std::cout << "This shall not happen" << std::endl; - } + std::cout << "filtration = " << *the_alpha_value_iterator << std::endl; +#endif // DEBUG_TRACES + simplex_tree.insert_simplex(the_simplex_tree, std::sqrt(*the_alpha_value_iterator)); + if (the_alpha_value_iterator != the_alpha_values.end()) + ++the_alpha_value_iterator; + else + std::cerr << "This shall not happen" << std::endl; + } #ifdef DEBUG_TRACES - std::cout << "vertices \t\t" << count_vertices << std::endl; - std::cout << "edges \t\t" << count_edges << std::endl; - std::cout << "facets \t\t" << count_facets << std::endl; - std::cout << "cells \t\t" << count_cells << std::endl; + std::cout << "vertices \t\t" << count_vertices << std::endl; + std::cout << "edges \t\t" << count_edges << std::endl; + std::cout << "facets \t\t" << count_facets << std::endl; + std::cout << "cells \t\t" << count_cells << std::endl; - std::cout << "Information of the Simplex Tree: " << std::endl; - std::cout << " Number of vertices = " << simplex_tree.num_vertices() << " "; - std::cout << " Number of simplices = " << simplex_tree.num_simplices() << std::endl << std::endl; -#endif // DEBUG_TRACES + std::cout << "Information of the Simplex Tree:\n"; + std::cout << " Number of vertices = " << simplex_tree.num_vertices() << " "; + std::cout << " Number of simplices = " << simplex_tree.num_simplices() << std::endl << std::endl; +#endif // DEBUG_TRACES #ifdef DEBUG_TRACES - std::cout << "Iterator on vertices: " << std::endl; - for( auto vertex : simplex_tree.complex_vertex_range() ) - { std::cout << vertex << " "; } -#endif // DEBUG_TRACES + std::cout << "Iterator on vertices: \n"; + for (auto vertex : simplex_tree.complex_vertex_range()) { + std::cout << vertex << " "; + } +#endif // DEBUG_TRACES - std::cout << simplex_tree << std::endl; + std::cout << simplex_tree << std::endl; #ifdef DEBUG_TRACES - std::cout << std::endl << std::endl << "Iterator on simplices: " << std::endl; - for( auto simplex : simplex_tree.complex_simplex_range() ) - { - std::cout << " "; - for( auto vertex : simplex_tree.simplex_vertex_range(simplex) ) { std::cout << vertex << " "; } - std::cout << std::endl; - } -#endif // DEBUG_TRACES + std::cout << std::endl << std::endl << "Iterator on simplices:\n"; + for (auto simplex : simplex_tree.complex_simplex_range()) { + std::cout << " "; + for (auto vertex : simplex_tree.simplex_vertex_range(simplex)) { + std::cout << vertex << " "; + } + std::cout << std::endl; + } +#endif // DEBUG_TRACES #ifdef DEBUG_TRACES - std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; - for( auto f_simplex : simplex_tree.filtration_simplex_range() ) - { std::cout << " " << "[" << simplex_tree.filtration(f_simplex) << "] "; - for( auto vertex : simplex_tree.simplex_vertex_range(f_simplex) ) - { std::cout << vertex << " "; } - std::cout << std::endl; - } -#endif // DEBUG_TRACES + std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, with [filtration value]:\n"; + for (auto f_simplex : simplex_tree.filtration_simplex_range()) { + std::cout << " " << "[" << simplex_tree.filtration(f_simplex) << "] "; + for (auto vertex : simplex_tree.simplex_vertex_range(f_simplex)) { + std::cout << vertex << " "; + } + std::cout << std::endl; + } +#endif // DEBUG_TRACES #ifdef DEBUG_TRACES - std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, and their boundary simplices:" << std::endl; - for( auto f_simplex : simplex_tree.filtration_simplex_range() ) - { - std::cout << " " << "[" << simplex_tree.filtration(f_simplex) << "] "; - for( auto vertex : simplex_tree.simplex_vertex_range(f_simplex) ) - { std::cout << vertex << " "; } - std::cout << std::endl; + std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, and their boundary simplices:\n"; + for (auto f_simplex : simplex_tree.filtration_simplex_range()) { + std::cout << " " << "[" << simplex_tree.filtration(f_simplex) << "] "; + for (auto vertex : simplex_tree.simplex_vertex_range(f_simplex)) { + std::cout << vertex << " "; + } + std::cout << std::endl; - for( auto b_simplex : simplex_tree.boundary_simplex_range(f_simplex) ) - { - std::cout << " " << "[" << simplex_tree.filtration(b_simplex) << "] "; - for( auto vertex : simplex_tree.simplex_vertex_range(b_simplex) ) - { std::cout << vertex << " "; } - std::cout << std::endl; - } - } -#endif // DEBUG_TRACES + for (auto b_simplex : simplex_tree.boundary_simplex_range(f_simplex)) { + std::cout << " " << "[" << simplex_tree.filtration(b_simplex) << "] "; + for (auto vertex : simplex_tree.simplex_vertex_range(b_simplex)) { + std::cout << vertex << " "; + } + std::cout << std::endl; + } + } +#endif // DEBUG_TRACES - return 0; + return 0; } diff --git a/src/Simplex_tree/example/simplex_tree_from_cliques_of_graph.cpp b/src/Simplex_tree/example/simplex_tree_from_cliques_of_graph.cpp new file mode 100644 index 00000000..58085014 --- /dev/null +++ b/src/Simplex_tree/example/simplex_tree_from_cliques_of_graph.cpp @@ -0,0 +1,114 @@ +/* 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): ClĂ©ment Maria + * + * 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 <gudhi/reader_utils.h> +#include <gudhi/Simplex_tree.h> + +#include <iostream> +#include <ctime> +#include <string> + +using namespace Gudhi; + +int main(int argc, char * const argv[]) { + if (argc != 3) { + std::cerr << "Usage: " << argv[0] + << " path_to_file_graph max_dim \n"; + return 0; + } + std::string filegraph = argv[1]; + int max_dim = atoi(argv[2]); + + clock_t start, end; + // Construct the Simplex Tree + Simplex_tree<> st; + + start = clock(); + auto g = read_graph(filegraph); + // insert the graph in the simplex tree as 1-skeleton + st.insert_graph(g); + end = clock(); + std::cout << "Insert the 1-skeleton in the simplex tree in " + << static_cast<double>(end - start) / CLOCKS_PER_SEC << " s. \n"; + + start = clock(); + // expand the 1-skeleton until dimension max_dim + st.expansion(max_dim); + end = clock(); + std::cout << "max_dim = " << max_dim << "\n"; + std::cout << "Expand the simplex tree in " + << static_cast<double>(end - start) / CLOCKS_PER_SEC << " s. \n"; + + std::cout << "Information of the Simplex Tree: " << std::endl; + std::cout << " Number of vertices = " << st.num_vertices() << " "; + std::cout << " Number of simplices = " << st.num_simplices() << std::endl; + std::cout << std::endl << std::endl; + + std::cout << "Iterator on vertices: "; + for (auto vertex : st.complex_vertex_range()) { + std::cout << vertex << " "; + } + + std::cout << std::endl; + + std::cout << std::endl << std::endl; + + std::cout << "Iterator on simplices: " << std::endl; + for (auto simplex : st.complex_simplex_range()) { + std::cout << " "; + for (auto vertex : st.simplex_vertex_range(simplex)) { + std::cout << vertex << " "; + } + std::cout << std::endl; + } + + std::cout << std::endl << std::endl; + + std::cout << "Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; + for (auto f_simplex : st.filtration_simplex_range()) { + std::cout << " " << "[" << st.filtration(f_simplex) << "] "; + for (auto vertex : st.simplex_vertex_range(f_simplex)) { + std::cout << vertex << " "; + } + std::cout << std::endl; + } + + std::cout << std::endl << std::endl; + + std::cout << "Iterator on Simplices in the filtration, and their boundary simplices:" << std::endl; + for (auto f_simplex : st.filtration_simplex_range()) { + std::cout << " " << "[" << st.filtration(f_simplex) << "] "; + for (auto vertex : st.simplex_vertex_range(f_simplex)) { + std::cout << vertex << " "; + } + std::cout << std::endl; + + for (auto b_simplex : st.boundary_simplex_range(f_simplex)) { + std::cout << " " << "[" << st.filtration(b_simplex) << "] "; + for (auto vertex : st.simplex_vertex_range(b_simplex)) { + std::cout << vertex << " "; + } + std::cout << std::endl; + } + } + return 0; +} diff --git a/src/Simplex_tree/example/simplex_tree_from_file.cpp b/src/Simplex_tree/example/simplex_tree_from_file.cpp deleted file mode 100644 index 20e8f067..00000000 --- a/src/Simplex_tree/example/simplex_tree_from_file.cpp +++ /dev/null @@ -1,104 +0,0 @@ - /* 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): ClĂ©ment Maria - * - * 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/reader_utils.h" -#include "gudhi/Simplex_tree.h" - -using namespace Gudhi; - -int main (int argc, char * const argv[]) -{ - if (argc != 3) { - std::cerr << "Usage: " << argv[0] - << " path_to_file_graph max_dim \n"; - return 0; - } - std::string filegraph = argv[1]; - int max_dim = atoi(argv[2]); - - clock_t start, end; - //Construct the Simplex Tree - Simplex_tree<> st; - - start = clock(); - auto g = read_graph(filegraph); - st.insert_graph (g); //insert the graph in the simplex tree as 1-skeleton - end = clock(); - std::cout << "Insert the 1-skeleton in the simplex tree in " - << (double)(end-start)/CLOCKS_PER_SEC << " s. \n"; - - start = clock(); - st.expansion ( max_dim ); //expand the 1-skeleton until dimension max_dim - end = clock(); - std::cout << "max_dim = " << max_dim << "\n"; - std::cout << "Expand the simplex tree in " - << (double)(end-start)/CLOCKS_PER_SEC << " s. \n"; - - std::cout << "Information of the Simplex Tree: " << std::endl; - std::cout << " Number of vertices = " << st.num_vertices() << " "; - std::cout << " Number of simplices = " << st.num_simplices() << std::endl; - std::cout << std::endl << std::endl; - - std::cout << "Iterator on vertices: "; - for( auto vertex : st.complex_vertex_range() ) { std::cout << vertex << " "; } - - std::cout << std::endl; - - std::cout << std::endl << std::endl; - - std::cout << "Iterator on simplices: " << std::endl; - for( auto simplex : st.complex_simplex_range() ) - { - std::cout << " "; - for( auto vertex : st.simplex_vertex_range(simplex) ) { std::cout << vertex << " "; } - std::cout << std::endl; - } - - std::cout << std::endl << std::endl; - - std::cout << "Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; - for( auto f_simplex : st.filtration_simplex_range() ) - { std::cout << " " << "[" << st.filtration(f_simplex) << "] "; - for( auto vertex : st.simplex_vertex_range(f_simplex) ) - { std::cout << vertex << " "; } std::cout << std::endl; - } - - std::cout << std::endl << std::endl; - - std::cout << "Iterator on Simplices in the filtration, and their boundary simplices:" << std::endl; - for( auto f_simplex : st.filtration_simplex_range() ) - { - std::cout << " " << "[" << st.filtration(f_simplex) << "] "; - for( auto vertex : st.simplex_vertex_range(f_simplex) ) - { std::cout << vertex << " "; } std::cout << std::endl; - - for( auto b_simplex : st.boundary_simplex_range(f_simplex) ) - { - std::cout << " " << "[" << st.filtration(b_simplex) << "] "; - for( auto vertex : st.simplex_vertex_range(b_simplex) ) - { std::cout << vertex << " "; } std::cout << std::endl; - } - } - return 0; -} diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h index 5d3753ca..ea61fa2e 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h @@ -20,14 +20,17 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_H_ -#define SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_H_ +#ifndef SIMPLEX_TREE_H_ +#define SIMPLEX_TREE_H_ #include <gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h> #include <gudhi/Simplex_tree/Simplex_tree_siblings.h> #include <gudhi/Simplex_tree/Simplex_tree_iterators.h> #include <gudhi/Simplex_tree/indexing_tag.h> +#include <gudhi/reader_utils.h> +#include <gudhi/graph_simplicial_complex.h> + #include <boost/container/flat_map.hpp> #include <boost/iterator/transform_iterator.hpp> #include <boost/graph/adjacency_list.hpp> @@ -35,10 +38,11 @@ #include <algorithm> #include <utility> #include <vector> -#include <iostream> +#include <functional> // for greater<> +#include <initializer_list> namespace Gudhi { - + /** \defgroup simplex_tree Filtered Complexes * * A simplicial complex \f$\mathbf{K}\f$ @@ -73,6 +77,17 @@ namespace Gudhi { * \copyright GNU General Public License v3. * @{ */ + +/// Model of SimplexTreeOptions. +struct Simplex_tree_options_full_featured { + typedef linear_indexing_tag Indexing_tag; + typedef int Vertex_handle; + typedef double Filtration_value; + typedef int Simplex_key; + static const bool store_key = true; + static const bool store_filtration = true; +}; + /** * \brief Simplex Tree data structure for representing simplicial complexes. * @@ -84,46 +99,69 @@ namespace Gudhi { * \implements FilteredComplex * */ -template<typename IndexingTag = linear_indexing_tag, - typename FiltrationValue = double, typename SimplexKey = int // must be a signed integer type - , typename VertexHandle = int // must be a signed integer type, int convertible to it -// , bool ContiguousVertexHandles = true //true is Vertex_handles are exactly the set [0;n) -> + +template<typename SimplexTreeOptions = Simplex_tree_options_full_featured> class Simplex_tree { public: - typedef IndexingTag Indexing_tag; + typedef SimplexTreeOptions Options; + typedef typename Options::Indexing_tag Indexing_tag; /** \brief Type for the value of the filtration function. * * Must be comparable with <. */ - typedef FiltrationValue Filtration_value; + typedef typename Options::Filtration_value Filtration_value; /** \brief Key associated to each simplex. * * Must be a signed integer type. */ - typedef SimplexKey Simplex_key; + typedef typename Options::Simplex_key Simplex_key; /** \brief Type for the vertex handle. * * Must be a signed integer type. It admits a total order <. */ - typedef VertexHandle Vertex_handle; + typedef typename Options::Vertex_handle 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. */ + // Note: this wastes space when Vertex_handle is 32 bits and Node is aligned on 64 bits. It would be better to use a + // flat_set (with our own comparator) where we can control the layout of the struct (put Vertex_handle and + // Simplex_key next to each other). typedef typename boost::container::flat_map<Vertex_handle, Node> Dictionary; - friend class Simplex_tree_node_explicit_storage< Simplex_tree<FiltrationValue, SimplexKey, VertexHandle> >; - friend class Simplex_tree_siblings< Simplex_tree<FiltrationValue, SimplexKey, VertexHandle>, Dictionary>; - friend class Simplex_tree_simplex_vertex_iterator< Simplex_tree<FiltrationValue, SimplexKey, VertexHandle> >; - friend class Simplex_tree_boundary_simplex_iterator< Simplex_tree<FiltrationValue, SimplexKey, VertexHandle> >; - friend class Simplex_tree_complex_simplex_iterator< Simplex_tree<FiltrationValue, SimplexKey, VertexHandle> >; - friend class Simplex_tree_skeleton_simplex_iterator< Simplex_tree<FiltrationValue, SimplexKey, VertexHandle> >; - /* \brief Set of nodes sharing a same parent in the simplex tree. */ /* \brief Set of nodes sharing a same parent in the simplex tree. */ typedef Simplex_tree_siblings<Simplex_tree, Dictionary> Siblings; + struct Key_simplex_base_real { + Key_simplex_base_real() : key_(-1) {} + void assign_key(Simplex_key k) { key_ = k; } + Simplex_key key() const { return key_; } + private: + Simplex_key key_; + }; + struct Key_simplex_base_dummy { + Key_simplex_base_dummy() {} + void assign_key(Simplex_key) { } + Simplex_key key() const { assert(false); return -1; } + }; + typedef typename std::conditional<Options::store_key, Key_simplex_base_real, Key_simplex_base_dummy>::type Key_simplex_base; + + struct Filtration_simplex_base_real { + Filtration_simplex_base_real() : filt_(0) {} + void assign_filtration(Filtration_value f) { filt_ = f; } + Filtration_value filtration() const { return filt_; } + private: + Filtration_value filt_; + }; + struct Filtration_simplex_base_dummy { + Filtration_simplex_base_dummy() {} + void assign_filtration(Filtration_value f) { assert(f == 0); } + Filtration_value filtration() const { return 0; } + }; + typedef typename std::conditional<Options::store_filtration, Filtration_simplex_base_real, + Filtration_simplex_base_dummy>::type Filtration_simplex_base; + public: /** \brief Handle type to a simplex contained in the simplicial complex represented - * byt he simplex tree. */ + * by the simplex tree. */ typedef typename Dictionary::iterator Simplex_handle; private: @@ -157,6 +195,8 @@ class Simplex_tree { typedef Simplex_tree_simplex_vertex_iterator<Simplex_tree> Simplex_vertex_iterator; /** \brief Range over the vertices of a simplex. */ typedef boost::iterator_range<Simplex_vertex_iterator> Simplex_vertex_range; + /** \brief Range over the cofaces of a simplex. */ + typedef std::vector<Simplex_handle> Cofaces_simplex_range; /** \brief Iterator over the simplices of the boundary of a simplex. * * 'value_type' is Simplex_handle. */ @@ -177,24 +217,23 @@ class Simplex_tree { /** \brief Range over the simplices of the skeleton of the simplicial complex, for a given * dimension. */ typedef boost::iterator_range<Skeleton_simplex_iterator> Skeleton_simplex_range; + /** \brief Range over the simplices of the simplicial complex, ordered by the filtration. */ + typedef std::vector<Simplex_handle> Filtration_simplex_range; /** \brief Iterator over the simplices of the simplicial complex, ordered by the filtration. * * 'value_type' is Simplex_handle. */ - typedef typename std::vector<Simplex_handle>::iterator Filtration_simplex_iterator; - /** \brief Range over the simplices of the simplicial complex, ordered by the filtration. */ - typedef boost::iterator_range<Filtration_simplex_iterator> Filtration_simplex_range; + typedef typename Filtration_simplex_range::const_iterator Filtration_simplex_iterator; /* @} */ // end name range and iterator types /** \name Range and iterator methods * @{ */ - /** \brief Returns a range over the vertices of the simplicial complex. - * + /** \brief Returns a range over the vertices of the simplicial complex. * The order is increasing according to < on Vertex_handles.*/ Complex_vertex_range complex_vertex_range() { return Complex_vertex_range( - boost::make_transform_iterator(root_.members_.begin(), return_first()), - boost::make_transform_iterator(root_.members_.end(), return_first())); + boost::make_transform_iterator(root_.members_.begin(), return_first()), + boost::make_transform_iterator(root_.members_.end(), return_first())); } /** \brief Returns a range over the simplices of the simplicial complex. @@ -234,18 +273,15 @@ class Simplex_tree { * order is used. * * The filtration must be valid. If the filtration has not been initialized yet, the - * method initializes it (i.e. order the simplices). */ - Filtration_simplex_range filtration_simplex_range(Indexing_tag) { + * method initializes it (i.e. order the simplices). If the complex has changed since the last time the filtration + * was initialized, please call `initialize_filtration()` to recompute it. */ + Filtration_simplex_range const& filtration_simplex_range(Indexing_tag = Indexing_tag()) { if (filtration_vect_.empty()) { initialize_filtration(); } - return Filtration_simplex_range(filtration_vect_.begin(), - filtration_vect_.end()); + return filtration_vect_; } - Filtration_simplex_range filtration_simplex_range() { - return filtration_simplex_range(Indexing_tag()); - } /** \brief Returns a range over the vertices of a simplex. * * The order in which the vertices are visited is the decreasing order for < on Vertex_handles, @@ -253,6 +289,7 @@ class Simplex_tree { * equal to \f$(-1)^{\text{dim} \sigma}\f$ the canonical orientation on the simplex. */ Simplex_vertex_range simplex_vertex_range(Simplex_handle sh) { + assert(sh != null_simplex()); // Empty simplex return Simplex_vertex_range(Simplex_vertex_iterator(this, sh), Simplex_vertex_iterator(this)); } @@ -283,11 +320,48 @@ class Simplex_tree { /** \brief Constructs an empty simplex tree. */ Simplex_tree() : null_vertex_(-1), - threshold_(0), - num_simplices_(0), - root_(NULL, null_vertex_), - filtration_vect_(), - dimension_(-1) { + threshold_(0), + root_(nullptr, null_vertex_), + filtration_vect_(), + dimension_(-1) { } + + /** \brief User-defined copy constructor reproduces the whole tree structure. */ + Simplex_tree(const Simplex_tree& simplex_source) + : null_vertex_(simplex_source.null_vertex_), + threshold_(simplex_source.threshold_), + filtration_vect_(), + dimension_(simplex_source.dimension_) { + auto root_source = simplex_source.root_; + auto memb_source = root_source.members(); + root_ = Siblings(nullptr, null_vertex_, memb_source); + rec_copy(&root_, &root_source); + } + + /** \brief depth first search, inserts simplices when reaching a leaf. */ + void rec_copy(Siblings *sib, Siblings *sib_source) { + for (auto sh = sib->members().begin(), sh_source = sib_source->members().begin(); + sh != sib->members().end(); ++sh, ++sh_source) { + if (has_children(sh_source)) { + Siblings * newsib = new Siblings(sib, sh_source->first); + newsib->members_.reserve(sh_source->second.children()->members().size()); + for (auto & child : sh_source->second.children()->members()) + newsib->members_.emplace_hint(newsib->members_.end(), child.first, Node(sib, child.second.filtration())); + rec_copy(newsib, sh_source->second.children()); + sh->second.assign_children(newsib); + } + } + } + + /** \brief User-defined move constructor moves the whole tree structure. */ + Simplex_tree(Simplex_tree && old) + : null_vertex_(std::move(old.null_vertex_)), + threshold_(std::move(old.threshold_)), + root_(std::move(old.root_)), + filtration_vect_(std::move(old.filtration_vect_)), + dimension_(std::move(old.dimension_)) { + old.dimension_ = -1; + old.threshold_ = 0; + old.root_ = Siblings(nullptr, null_vertex_); } /** \brief Destructor; deallocates the whole tree structure. */ @@ -300,7 +374,7 @@ class Simplex_tree { } /** @} */ // end constructor/destructor private: - /** Recursive deletion. */ + // Recursive deletion void rec_delete(Siblings * sib) { for (auto sh = sib->members().begin(); sh != sib->members().end(); ++sh) { if (has_children(sh)) { @@ -311,72 +385,135 @@ class Simplex_tree { } public: + /** \brief Checks if two simplex trees are equal. */ + bool operator==(Simplex_tree& st2) { + if ((null_vertex_ != st2.null_vertex_) || + (threshold_ != st2.threshold_) || + (dimension_ != st2.dimension_)) + return false; + return rec_equal(&root_, &st2.root_); + } + + /** \brief Checks if two simplex trees are different. */ + bool operator!=(Simplex_tree& st2) { + return (!(*this == st2)); + } + + private: + /** rec_equal: Checks recursively whether or not two simplex trees are equal, using depth first search. */ + bool rec_equal(Siblings* s1, Siblings* s2) { + if (s1->members().size() != s2->members().size()) + return false; + for (auto sh1 = s1->members().begin(), sh2 = s2->members().begin(); + (sh1 != s1->members().end() && sh2 != s2->members().end()); ++sh1, ++sh2) { + if (sh1->first != sh2->first || sh1->second.filtration() != sh2->second.filtration()) + return false; + if (has_children(sh1) != has_children(sh2)) + return false; + // Recursivity on children only if both have children + else if (has_children(sh1)) + if (!rec_equal(sh1->second.children(), sh2->second.children())) + return false; + } + return true; + } + + public: /** \brief Returns the key associated to a simplex. * - * The filtration must be initialized. */ - Simplex_key key(Simplex_handle sh) { + * The filtration must be initialized. + * \pre SimplexTreeOptions::store_key + */ + static Simplex_key key(Simplex_handle sh) { return sh->second.key(); } + /** \brief Returns the simplex associated to a key. * - * The filtration must be initialized. */ - Simplex_handle simplex(Simplex_key key) { + * The filtration must be initialized. + * \pre SimplexTreeOptions::store_key + */ + Simplex_handle simplex(Simplex_key key) const { return filtration_vect_[key]; } + /** \brief Returns the filtration value of a simplex. * - * Called on the null_simplex, returns INFINITY. */ - Filtration_value filtration(Simplex_handle sh) const { + * Called on the null_simplex, returns INFINITY. + * If SimplexTreeOptions::store_filtration is false, returns 0. + */ + static Filtration_value filtration(Simplex_handle sh) { if (sh != null_simplex()) { return sh->second.filtration(); } else { return INFINITY; - } // filtration(); } + } } + /** \brief Returns an upper bound of the filtration values of the simplices. */ Filtration_value filtration() const { return threshold_; } + /** \brief Returns a Simplex_handle different from all Simplex_handles * associated to the simplices in the simplicial complex. * * One can call filtration(null_simplex()). */ - Simplex_handle null_simplex() const { - return Dictionary_it(NULL); + static Simplex_handle null_simplex() { + return Dictionary_it(nullptr); } + /** \brief Returns a key different for all keys associated to the * simplices of the simplicial complex. */ - Simplex_key null_key() const { + static Simplex_key null_key() { return -1; } + /** \brief Returns a Vertex_handle different from all Vertex_handles associated * to the vertices of the simplicial complex. */ Vertex_handle null_vertex() const { return null_vertex_; } + /** \brief Returns the number of vertices in the complex. */ size_t num_vertices() const { return root_.members_.size(); } - /** \brief Returns the number of simplices in the complex. - * - * Does not count the empty simplex. */ - unsigned int num_simplices() const { - return num_simplices_; + + public: + /** \brief returns the number of simplices in the simplex_tree. */ + size_t num_simplices() { + return num_simplices(&root_); } + private: + /** \brief returns the number of simplices in the simplex_tree. */ + size_t num_simplices(Siblings * sib) { + auto sib_begin = sib->members().begin(); + auto sib_end = sib->members().end(); + size_t simplices_number = sib_end - sib_begin; + for (auto sh = sib_begin; sh != sib_end; ++sh) { + if (has_children(sh)) { + simplices_number += num_simplices(sh->second.children()); + } + } + return simplices_number; + } + + public: /** \brief Returns the dimension of a simplex. * * Must be different from null_simplex().*/ int dimension(Simplex_handle sh) { Siblings * curr_sib = self_siblings(sh); int dim = 0; - while (curr_sib != NULL) { + while (curr_sib != nullptr) { ++dim; curr_sib = curr_sib->oncles(); } return dim - 1; } + /** \brief Returns an upper bound on the dimension of the simplicial complex. */ int dimension() const { return dimension_; @@ -388,25 +525,34 @@ class Simplex_tree { return (sh->second.children()->parent() == sh->first); } - /** \brief Given a range of Vertex_handles, returns the Simplex_handle + /** \brief Given a range of Vertex_handles, returns the Simplex_handle * of the simplex in the simplicial complex containing the corresponding * vertices. Return null_simplex() if the simplex is not in the complex. * - * The type RandomAccessVertexRange must be a range for which .begin() and - * .end() return random access iterators, with <CODE>value_type</CODE> - * <CODE>Vertex_handle</CODE>. + * The type InputVertexRange must be a range of <CODE>Vertex_handle</CODE> + * on which we can call std::begin() function */ - template<class RandomAccessVertexRange> - Simplex_handle find(RandomAccessVertexRange & s) { - if (s.begin() == s.end()) - std::cerr << "Empty simplex \n"; - - sort(s.begin(), s.end()); + template<class InputVertexRange=std::initializer_list<Vertex_handle>> + Simplex_handle find(const InputVertexRange & s) { + auto first = std::begin(s); + auto last = std::end(s); + + if (first == last) + return null_simplex(); // ----->> + + // Copy before sorting + std::vector<Vertex_handle> copy(first, last); + std::sort(std::begin(copy), std::end(copy)); + return find_simplex(copy); + } + private: + /** Find function, with a sorted range of vertices. */ + Simplex_handle find_simplex(const std::vector<Vertex_handle> & simplex) { Siblings * tmp_sib = &root_; Dictionary_it tmp_dit; - Vertex_handle last = s[s.size() - 1]; - for (auto v : s) { + Vertex_handle last = simplex.back(); + for (auto v : simplex) { tmp_dit = tmp_sib->members_.find(v); if (tmp_dit == tmp_sib->members_.end()) { return null_simplex(); @@ -424,8 +570,39 @@ class Simplex_tree { Simplex_handle find_vertex(Vertex_handle v) { return root_.members_.begin() + v; } -//{ return root_.members_.find(v); } + //{ return root_.members_.find(v); } + + private: + /** \brief Inserts a simplex represented by a vector of vertex. + \warning the vector must be sorted by increasing vertex handle order */ + std::pair<Simplex_handle, bool> insert_vertex_vector(const std::vector<Vertex_handle>& simplex, + Filtration_value filtration) { + Siblings * curr_sib = &root_; + std::pair<Simplex_handle, bool> res_insert; + auto vi = simplex.begin(); + for (; vi != simplex.end() - 1; ++vi) { + res_insert = curr_sib->members_.emplace(*vi, Node(curr_sib, filtration)); + if (!(has_children(res_insert.first))) { + res_insert.first->second.assign_children(new Siblings(curr_sib, *vi)); + } + curr_sib = res_insert.first->second.children(); + } + res_insert = curr_sib->members_.emplace(*vi, Node(curr_sib, filtration)); + if (!res_insert.second) { + // if already in the complex + if (res_insert.first->second.filtration() > filtration) { + // if filtration value modified + res_insert.first->second.assign_filtration(filtration); + return res_insert; + } + // if filtration value unchanged + return std::pair<Simplex_handle, bool>(null_simplex(), false); + } + // otherwise the insertion has succeeded + return res_insert; + } + public: /** \brief Insert a simplex, represented by a range of Vertex_handles, in the simplicial complex. * * @param[in] simplex range of Vertex_handles, representing the vertices of the new simplex @@ -435,7 +612,7 @@ class Simplex_tree { * to the new simplex. * If the insertion fails (the simplex is already there), the bool is set to false. If the insertion * fails and the simplex already in the complex has a filtration value strictly bigger than 'filtration', - * we assign this simplex with the new value 'filtration', and set the Simplex_handle filed of the + * we assign this simplex with the new value 'filtration', and set the Simplex_handle field of the * output pair to the Simplex_handle of the simplex. Otherwise, we set the Simplex_handle part to * null_simplex. * @@ -447,76 +624,107 @@ class Simplex_tree { * The filtration value * assigned to the new simplex must preserve the monotonicity of the filtration. * - * The type RandomAccessVertexRange must be a range for which .begin() and - * .end() return random access iterators, with 'value_type' Vertex_handle. */ - template<class RandomAccessVertexRange> - std::pair<Simplex_handle, bool> insert_simplex(RandomAccessVertexRange & simplex, - Filtration_value filtration) { - if (simplex.empty()) { - return std::pair<Simplex_handle, bool>(null_simplex(), true); - } - - sort(simplex.begin(), simplex.end()); // must be sorted in increasing order - - Siblings * curr_sib = &root_; - std::pair<Simplex_handle, bool> res_insert; - typename RandomAccessVertexRange::iterator vi; - for (vi = simplex.begin(); vi != simplex.end() - 1; ++vi) { - res_insert = curr_sib->members_.emplace(*vi, Node(curr_sib, filtration)); - if (!(has_children(res_insert.first))) { - res_insert.first->second.assign_children(new Siblings(curr_sib, *vi)); - } - curr_sib = res_insert.first->second.children(); - } - res_insert = curr_sib->members_.emplace(*vi, Node(curr_sib, filtration)); - if (!res_insert.second) { // if already in the complex - if (res_insert.first->second.filtration() > filtration) { // if filtration value modified - res_insert.first->second.assign_filtration(filtration); - return res_insert; - } - return std::pair<Simplex_handle, bool>(null_simplex(), false); // if filtration value unchanged - } - // otherwise the insertion has succeeded - return res_insert; + * The type InputVertexRange must be a range for which .begin() and + * .end() return input iterators, with 'value_type' Vertex_handle. */ + template<class InputVertexRange=std::initializer_list<Vertex_handle>> + std::pair<Simplex_handle, bool> insert_simplex(const InputVertexRange & simplex, + Filtration_value filtration = 0) { + auto first = std::begin(simplex); + auto last = std::end(simplex); + + if (first == last) + return std::pair<Simplex_handle, bool>(null_simplex(), true); // ----->> + + // Copy before sorting + std::vector<Vertex_handle> copy(first, last); + std::sort(std::begin(copy), std::end(copy)); + return insert_vertex_vector(copy, filtration); } - - /** \brief Insert a N-simplex and all his subfaces, from a N-simplex represented by a range of + /** \brief Insert a N-simplex and all his subfaces, from a N-simplex represented by a range of * Vertex_handles, in the simplicial complex. * * @param[in] Nsimplex range of Vertex_handles, representing the vertices of the new N-simplex * @param[in] filtration the filtration value assigned to the new N-simplex. - */ - template<class RandomAccessVertexRange> - void insert_simplex_and_subfaces(RandomAccessVertexRange& Nsimplex, - Filtration_value filtration = 0.0) { - if (Nsimplex.size() > 1) { - for (unsigned int NIndex = 0; NIndex < Nsimplex.size(); NIndex++) { - // insert N (N-1)-Simplex - RandomAccessVertexRange NsimplexMinusOne; - for (unsigned int NListIter = 0; NListIter < Nsimplex.size() - 1; NListIter++) { - // (N-1)-Simplex creation - NsimplexMinusOne.push_back( Nsimplex[(NIndex + NListIter) % Nsimplex.size()]); - } - // (N-1)-Simplex recursive call - insert_simplex_and_subfaces(NsimplexMinusOne, filtration); + * The return type is a pair. If the new simplex is inserted successfully (i.e. it was not in the + * simplicial complex yet) the bool is set to true and the Simplex_handle is the handle assigned + * to the new simplex. + * If the insertion fails (the simplex is already there), the bool is set to false. If the insertion + * fails and the simplex already in the complex has a filtration value strictly bigger than 'filtration', + * we assign this simplex with the new value 'filtration', and set the Simplex_handle field of the + * output pair to the Simplex_handle of the simplex. Otherwise, we set the Simplex_handle part to + * null_simplex. + */ + template<class InputVertexRange=std::initializer_list<Vertex_handle>> + std::pair<Simplex_handle, bool> insert_simplex_and_subfaces(const InputVertexRange& Nsimplex, + Filtration_value filtration = 0) { + auto first = std::begin(Nsimplex); + auto last = std::end(Nsimplex); + + if (first == last) + return std::pair<Simplex_handle, bool>(null_simplex(), true); // ----->> + + // Copy before sorting + std::vector<Vertex_handle> copy(first, last); + std::sort(std::begin(copy), std::end(copy)); + + std::vector<std::vector<Vertex_handle>> to_be_inserted; + std::vector<std::vector<Vertex_handle>> to_be_propagated; + return rec_insert_simplex_and_subfaces(copy, to_be_inserted, to_be_propagated, filtration); + } + + private: + std::pair<Simplex_handle, bool> rec_insert_simplex_and_subfaces(std::vector<Vertex_handle>& the_simplex, + std::vector<std::vector<Vertex_handle>>& to_be_inserted, + std::vector<std::vector<Vertex_handle>>& to_be_propagated, + Filtration_value filtration = 0.0) { + std::pair<Simplex_handle, bool> insert_result; + if (the_simplex.size() > 1) { + // Get and remove last vertex + Vertex_handle last_vertex = the_simplex.back(); + the_simplex.pop_back(); + // Recursive call after last vertex removal + insert_result = rec_insert_simplex_and_subfaces(the_simplex, to_be_inserted, to_be_propagated, filtration); + + // Concatenation of to_be_inserted and to_be_propagated + to_be_inserted.insert(to_be_inserted.begin(), to_be_propagated.begin(), to_be_propagated.end()); + to_be_propagated = to_be_inserted; + + // to_be_inserted treatment + for (auto& simplex_tbi : to_be_inserted) { + simplex_tbi.push_back(last_vertex); } - // N-Simplex insert - std::pair<Simplex_handle, bool> returned = insert_simplex(Nsimplex, filtration); - if (returned.second == true) { - num_simplices_++; + std::vector<Vertex_handle> last_simplex(1, last_vertex); + to_be_inserted.insert(to_be_inserted.begin(), last_simplex); + // i.e. (0,1,2) => + // [to_be_inserted | to_be_propagated] = [(1) (0,1) | (0)] + // [to_be_inserted | to_be_propagated] = [(2) (0,2) (1,2) (0,1,2) | (0) (1) (0,1)] + // N.B. : it is important the last inserted to be the highest in dimension + // in order to return the "last" insert_simplex result + + // insert all to_be_inserted + for (auto& simplex_tbi : to_be_inserted) { + insert_result = insert_vertex_vector(simplex_tbi, filtration); } - } else if (Nsimplex.size() == 1) { - // 1-Simplex insert - End of recursivity - std::pair<Simplex_handle, bool> returned = insert_simplex(Nsimplex, filtration); - if (returned.second == true) { - num_simplices_++; + } else if (the_simplex.size() == 1) { + // When reaching the end of recursivity, vector of simplices shall be empty and filled on back recursive + if ((to_be_inserted.size() != 0) || (to_be_propagated.size() != 0)) { + std::cerr << "Simplex_tree::rec_insert_simplex_and_subfaces - Error vector not empty" << std::endl; + exit(-1); } + std::vector<Vertex_handle> first_simplex(1, the_simplex.back()); + // i.e. (0,1,2) => [to_be_inserted | to_be_propagated] = [(0) | ] + to_be_inserted.push_back(first_simplex); + + insert_result = insert_vertex_vector(first_simplex, filtration); } else { - // Nothing to insert - empty vector + std::cerr << "Simplex_tree::rec_insert_simplex_and_subfaces - Recursivity error" << std::endl; + exit(-1); } + return insert_result; } + public: /** \brief Assign a value 'key' to the key of the simplex * represented by the Simplex_handle 'sh'. */ void assign_key(Simplex_handle sh, Simplex_key key) { @@ -528,9 +736,8 @@ class Simplex_tree { * and edge. sh must point to a 1-dimensional simplex. This is an * optimized version of the boundary computation. */ std::pair<Simplex_handle, Simplex_handle> endpoints(Simplex_handle sh) { - return std::pair<Simplex_handle, Simplex_handle>( - root_.members_.find(sh->first), - root_.members_.find(self_siblings(sh)->parent())); + assert(dimension(sh) == 1); + return { find_vertex(sh->first), find_vertex(self_siblings(sh)->parent()) }; } /** Returns the Siblings containing a simplex.*/ @@ -541,32 +748,17 @@ class Simplex_tree { return sh->second.children(); } -// void display_simplex(Simplex_handle sh) -// { -// std::cout << " " << "[" << filtration(sh) << "] "; -// for( auto vertex : simplex_vertex_range(sh) ) -// { std::cout << vertex << " "; } -// } - - // void print(Simplex_handle sh, std::ostream& os = std::cout) - // { for(auto v : simplex_vertex_range(sh)) {os << v << " ";} - // os << std::endl; } - public: /** Returns a pointer to the root nodes of the simplex tree. */ Siblings * root() { return &root_; } - public: /** Set an upper bound for the filtration values. */ void set_filtration(Filtration_value fil) { threshold_ = fil; } - /** Set a number of simplices for the simplicial complex. */ - void set_num_simplices(unsigned int num_simplices) { - num_simplices_ = num_simplices; - } + /** Set a dimension for the simplicial complex. */ void set_dimension(int dimension) { dimension_ = dimension; @@ -580,28 +772,114 @@ class Simplex_tree { * assigned a Simplex_key corresponding to its order in the filtration (from 0 to m-1 for a * simplicial complex with m simplices). * - * The use of a depth-first traversal of the simplex tree, provided by - * complex_simplex_range(), combined with - * a stable sort is meant to optimize the order of simplices with same - * filtration value. The heuristic consists in inserting the cofaces of a - * simplex as soon as possible. - * * Will be automatically called when calling filtration_simplex_range() * if the filtration has never been initialized yet. */ void initialize_filtration() { filtration_vect_.clear(); filtration_vect_.reserve(num_simplices()); - for (auto cpx_it = complex_simplex_range().begin(); - cpx_it != complex_simplex_range().end(); ++cpx_it) { - filtration_vect_.push_back(*cpx_it); - } - - // the stable sort ensures the ordering heuristic + for (Simplex_handle sh : complex_simplex_range()) + filtration_vect_.push_back(sh); + + /* We use stable_sort here because with libstdc++ it is faster than sort. + * is_before_in_filtration is now a total order, but we used to call + * stable_sort for the following heuristic: + * The use of a depth-first traversal of the simplex tree, provided by + * complex_simplex_range(), combined with a stable sort is meant to + * optimize the order of simplices with same filtration value. The + * heuristic consists in inserting the cofaces of a simplex as soon as + * possible. + */ std::stable_sort(filtration_vect_.begin(), filtration_vect_.end(), is_before_in_filtration(this)); } private: + /** Recursive search of cofaces + * This function uses DFS + *\param vertices contains a list of vertices, which represent the vertices of the simplex not found yet. + *\param curr_nbVertices represents the number of vertices of the simplex we reached by going through the tree. + *\param cofaces contains a list of Simplex_handle, representing all the cofaces asked. + *\param star true if we need the star of the simplex + *\param nbVertices number of vertices of the cofaces we search + * Prefix actions : When the bottom vertex matches with the current vertex in the tree, we remove the bottom vertex from vertices. + * Infix actions : Then we call or not the recursion. + * Postfix actions : Finally, we add back the removed vertex into vertices, and remove this vertex from curr_nbVertices so that we didn't change the parameters. + * If the vertices list is empty, we need to check if curr_nbVertices matches with the dimension of the cofaces asked. + */ + void rec_coface(std::vector<Vertex_handle> &vertices, Siblings *curr_sib, int curr_nbVertices, + std::vector<Simplex_handle>& cofaces, bool star, int nbVertices) { + if (!(star || curr_nbVertices <= nbVertices)) // dimension of actual simplex <= nbVertices + return; + for (Simplex_handle simplex = curr_sib->members().begin(); simplex != curr_sib->members().end(); ++simplex) { + if (vertices.empty()) { + // If we reached the end of the vertices, and the simplex has more vertices than the given simplex + // => we found a coface + + // Add a coface if we wan't the star or if the number of vertices of the current simplex matches with nbVertices + bool addCoface = (star || curr_nbVertices == nbVertices); + if (addCoface) + cofaces.push_back(simplex); + if ((!addCoface || star) && has_children(simplex)) // Rec call + rec_coface(vertices, simplex->second.children(), curr_nbVertices + 1, cofaces, star, nbVertices); + } else { + if (simplex->first == vertices.back()) { + // If curr_sib matches with the top vertex + bool equalDim = (star || curr_nbVertices == nbVertices); // dimension of actual simplex == nbVertices + bool addCoface = vertices.size() == 1 && equalDim; + if (addCoface) + cofaces.push_back(simplex); + if ((!addCoface || star) && has_children(simplex)) { + // Rec call + Vertex_handle tmp = vertices.back(); + vertices.pop_back(); + rec_coface(vertices, simplex->second.children(), curr_nbVertices + 1, cofaces, star, nbVertices); + vertices.push_back(tmp); + } + } else if (simplex->first > vertices.back()) { + return; + } else { + // (simplex->first < vertices.back() + if (has_children(simplex)) + rec_coface(vertices, simplex->second.children(), curr_nbVertices + 1, cofaces, star, nbVertices); + } + } + } + } + + public: + /** \brief Compute the star of a n simplex + * \param simplex represent the simplex of which we search the star + * \return Vector of Simplex_handle, empty vector if no cofaces found. + */ + + Cofaces_simplex_range star_simplex_range(const Simplex_handle simplex) { + return cofaces_simplex_range(simplex, 0); + } + + /** \brief Compute the cofaces of a n simplex + * \param simplex represent the n-simplex of which we search the n+codimension cofaces + * \param codimension The function returns the n+codimension-cofaces of the n-simplex. If codimension = 0, + * return all cofaces (equivalent of star function) + * \return Vector of Simplex_handle, empty vector if no cofaces found. + */ + + Cofaces_simplex_range cofaces_simplex_range(const Simplex_handle simplex, int codimension) { + Cofaces_simplex_range cofaces; + // codimension must be positive or null integer + assert(codimension >= 0); + Simplex_vertex_range rg = simplex_vertex_range(simplex); + std::vector<Vertex_handle> copy(rg.begin(), rg.end()); + if (codimension + static_cast<int>(copy.size()) > dimension_ + 1 || + (codimension == 0 && static_cast<int>(copy.size()) > dimension_)) // n+codimension greater than dimension_ + return cofaces; + // must be sorted in decreasing order + assert(std::is_sorted(copy.begin(), copy.end(), std::greater<Vertex_handle>())); + bool star = codimension == 0; + rec_coface(copy, &root_, 1, cofaces, star, codimension + static_cast<int>(copy.size())); + return cofaces; + } + + private: /** \brief Returns true iff the list of vertices of sh1 * is smaller than the list of vertices of sh2 w.r.t. * lexicographic order on the lists read in reverse. @@ -624,6 +902,7 @@ class Simplex_tree { } return ((it1 == rg1.end()) && (it2 != rg2.end())); } + /** \brief StrictWeakOrdering, for the simplices, defined by the filtration. * * It corresponds to the partial order @@ -632,15 +911,15 @@ class Simplex_tree { * to be smaller. The filtration function must be monotonic. */ struct is_before_in_filtration { explicit is_before_in_filtration(Simplex_tree * st) - : st_(st) { - } + : st_(st) { } bool operator()(const Simplex_handle sh1, const Simplex_handle sh2) const { - if (st_->filtration(sh1) != st_->filtration(sh2)) { - return st_->filtration(sh1) < st_->filtration(sh2); + // Not using st_->filtration(sh1) because it uselessly tests for null_simplex. + if (sh1->second.filtration() != sh2->second.filtration()) { + return sh1->second.filtration() < sh2->second.filtration(); } - - return st_->reverse_lexicographic_order(sh1, sh2); // is sh1 a proper subface of sh2 + // is sh1 a proper subface of sh2 + return st_->reverse_lexicographic_order(sh1, sh2); } Simplex_tree * st_; @@ -667,7 +946,8 @@ class Simplex_tree { * must be undirected_tag. */ template<class OneSkeletonGraph> void insert_graph(const OneSkeletonGraph& skel_graph) { - assert(num_simplices() == 0); // the simplex tree must be empty + // the simplex tree must be empty + assert(num_simplices() == 0); if (boost::num_vertices(skel_graph) == 0) { return; @@ -678,37 +958,37 @@ class Simplex_tree { dimension_ = 1; } - num_simplices_ = boost::num_vertices(skel_graph) - + boost::num_edges(skel_graph); root_.members_.reserve(boost::num_vertices(skel_graph)); typename boost::graph_traits<OneSkeletonGraph>::vertex_iterator v_it, v_it_end; for (std::tie(v_it, v_it_end) = boost::vertices(skel_graph); v_it != v_it_end; - ++v_it) { + ++v_it) { root_.members_.emplace_hint( - root_.members_.end(), *v_it, - Node(&root_, boost::get(vertex_filtration_t(), skel_graph, *v_it))); + root_.members_.end(), *v_it, + Node(&root_, boost::get(vertex_filtration_t(), skel_graph, *v_it))); } typename boost::graph_traits<OneSkeletonGraph>::edge_iterator e_it, e_it_end; for (std::tie(e_it, e_it_end) = boost::edges(skel_graph); e_it != e_it_end; - ++e_it) { + ++e_it) { auto u = source(*e_it, skel_graph); auto v = target(*e_it, skel_graph); - if (u < v) { // count edges only once { std::swap(u,v); } // u < v + if (u < v) { + // count edges only once { std::swap(u,v); } // u < v auto sh = find_vertex(u); if (!has_children(sh)) { sh->second.assign_children(new Siblings(&root_, sh->first)); } sh->second.children()->members().emplace( - v, - Node(sh->second.children(), - boost::get(edge_filtration_t(), skel_graph, *e_it))); + v, + Node(sh->second.children(), + boost::get(edge_filtration_t(), skel_graph, *e_it))); } } } + /** \brief Expands the Simplex_tree containing only its one skeleton * until dimension max_dim. * @@ -723,7 +1003,7 @@ class Simplex_tree { void expansion(int max_dim) { dimension_ = max_dim; for (Dictionary_it root_it = root_.members_.begin(); - root_it != root_.members_.end(); ++root_it) { + root_it != root_.members_.end(); ++root_it) { if (has_children(root_it)) { siblings_expansion(root_it->second.children(), max_dim - 1); } @@ -734,7 +1014,7 @@ class Simplex_tree { private: /** \brief Recursive expansion of the simplex tree.*/ void siblings_expansion(Siblings * siblings, // must contain elements - int k) { + int k) { if (dimension_ > k) { dimension_ = k; } @@ -745,68 +1025,55 @@ class Simplex_tree { static std::vector<std::pair<Vertex_handle, Node> > inter; // static, not thread-safe. for (Dictionary_it s_h = siblings->members().begin(); - s_h != siblings->members().end(); ++s_h, ++next) { + s_h != siblings->members().end(); ++s_h, ++next) { Simplex_handle root_sh = find_vertex(s_h->first); if (has_children(root_sh)) { intersection( - inter, // output intersection - next, // begin - siblings->members().end(), // end - root_sh->second.children()->members().begin(), - root_sh->second.children()->members().end(), - s_h->second.filtration()); + inter, // output intersection + next, // begin + siblings->members().end(), // end + root_sh->second.children()->members().begin(), + root_sh->second.children()->members().end(), + s_h->second.filtration()); if (inter.size() != 0) { - this->num_simplices_ += inter.size(); Siblings * new_sib = new Siblings(siblings, // oncles - s_h->first, // parent - inter); // boost::container::ordered_unique_range_t + s_h->first, // parent + inter); // boost::container::ordered_unique_range_t inter.clear(); s_h->second.assign_children(new_sib); siblings_expansion(new_sib, k - 1); } else { - s_h->second.assign_children(siblings); // ensure the children property + // ensure the children property + s_h->second.assign_children(siblings); inter.clear(); } } } } + /** \brief Intersects Dictionary 1 [begin1;end1) with Dictionary 2 [begin2,end2) * and assigns the maximal possible Filtration_value to the Nodes. */ static void intersection(std::vector<std::pair<Vertex_handle, Node> >& intersection, Dictionary_it begin1, Dictionary_it end1, Dictionary_it begin2, Dictionary_it end2, - Filtration_value filtration) { + Filtration_value filtration_) { if (begin1 == end1 || begin2 == end2) return; // ----->> while (true) { if (begin1->first == begin2->first) { - intersection.push_back( - std::pair<Vertex_handle, Node>( - begin1->first, - Node(NULL, maximum(begin1->second.filtration(), begin2->second.filtration(), filtration)))); - ++begin1; - ++begin2; - if (begin1 == end1 || begin2 == end2) + Filtration_value filt = (std::max)({begin1->second.filtration(), begin2->second.filtration(), filtration_}); + intersection.emplace_back(begin1->first, Node(nullptr, filt)); + if (++begin1 == end1 || ++begin2 == end2) + return; // ----->> + } else if (begin1->first < begin2->first) { + if (++begin1 == end1) + return; + } else /* begin1->first > begin2->first */ { + if (++begin2 == end2) return; // ----->> - } else { - if (begin1->first < begin2->first) { - ++begin1; - if (begin1 == end1) - return; - } else { - ++begin2; - if (begin2 == end2) - return; // ----->> - } } } } - /** Maximum over 3 values.*/ - static Filtration_value maximum(Filtration_value a, Filtration_value b, - Filtration_value c) { - Filtration_value max = (a < b) ? b : a; - return ((max < c) ? c : max); - } public: /** \brief Write the hasse diagram of the simplicial complex in os. @@ -817,7 +1084,7 @@ class Simplex_tree { * of the simplex, and fil is its filtration value. */ void print_hasse(std::ostream& os) { os << num_simplices() << " " << std::endl; - for (auto sh : filtration_simplex_range(Indexing_tag())) { + for (auto sh : filtration_simplex_range()) { os << dimension(sh) << " "; for (auto b_sh : boundary_simplex_range(sh)) { os << key(b_sh) << " "; @@ -831,7 +1098,6 @@ class Simplex_tree { /** \brief Upper bound on the filtration values of the simplices.*/ Filtration_value threshold_; /** \brief Total number of simplices in the complex, without the empty simplex.*/ - unsigned int num_simplices_; /** \brief Set of simplex tree Nodes representing the vertices.*/ Siblings root_; /** \brief Simplices ordered according to a filtration.*/ @@ -841,8 +1107,9 @@ class Simplex_tree { }; // Print a Simplex_tree in os. -template<typename T1, typename T2, typename T3> -std::ostream& operator<<(std::ostream & os, Simplex_tree<T1, T2, T3> & st) { + +template<typename...T> +std::ostream& operator<<(std::ostream & os, Simplex_tree<T...> & st) { for (auto sh : st.filtration_simplex_range()) { os << st.dimension(sh) << " "; for (auto v : st.simplex_vertex_range(sh)) { @@ -852,35 +1119,35 @@ std::ostream& operator<<(std::ostream & os, Simplex_tree<T1, T2, T3> & st) { } return os; } -template<typename T1, typename T2, typename T3> -std::istream& operator>>(std::istream & is, Simplex_tree<T1, T2, T3> & st) { - // assert(st.num_simplices() == 0); - std::vector<typename Simplex_tree<T1, T2, T3>::Vertex_handle> simplex; - typename Simplex_tree<T1, T2, T3>::Filtration_value fil; - typename Simplex_tree<T1, T2, T3>::Filtration_value max_fil = 0; +template<typename...T> +std::istream& operator>>(std::istream & is, Simplex_tree<T...> & st) { + typedef Simplex_tree<T...> ST; + std::vector<typename ST::Vertex_handle> simplex; + typename ST::Filtration_value fil; + typename ST::Filtration_value max_fil = 0; int max_dim = -1; - size_t num_simplices = 0; - while (read_simplex(is, simplex, fil)) { // read all simplices in the file as a list of vertices - ++num_simplices; - int dim = static_cast<int>(simplex.size() - 1); // Warning : simplex_size needs to be casted in int - Can be 0 + while (read_simplex(is, simplex, fil)) { + // read all simplices in the file as a list of vertices + // Warning : simplex_size needs to be casted in int - Can be 0 + int dim = static_cast<int> (simplex.size() - 1); if (max_dim < dim) { max_dim = dim; } if (max_fil < fil) { max_fil = fil; } - st.insert_simplex(simplex, fil); // insert every simplex in the simplex tree + // insert every simplex in the simplex tree + st.insert_simplex(simplex, fil); simplex.clear(); } - st.set_num_simplices(num_simplices); st.set_dimension(max_dim); st.set_filtration(max_fil); return is; } - /** @} */ // end defgroup simplex_tree + } // namespace Gudhi -#endif // SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_H_ +#endif // SIMPLEX_TREE_H_ diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_iterators.h b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_iterators.h index 06462c88..372ef329 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_iterators.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_iterators.h @@ -20,10 +20,14 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_SIMPLEX_TREE_ITERATORS_H_ -#define SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_SIMPLEX_TREE_ITERATORS_H_ +#ifndef SIMPLEX_TREE_SIMPLEX_TREE_ITERATORS_H_ +#define SIMPLEX_TREE_SIMPLEX_TREE_ITERATORS_H_ #include <boost/iterator/iterator_facade.hpp> +#include <boost/version.hpp> +#if BOOST_VERSION >= 105600 +# include <boost/container/static_vector.hpp> +#endif #include <vector> @@ -131,8 +135,7 @@ class Simplex_tree_boundary_simplex_iterator : public boost::iterator_facade< } Siblings * for_sib = sib_; - for (typename std::vector<Vertex_handle>::reverse_iterator rit = suffix_ - .rbegin(); rit != suffix_.rend(); ++rit) { + for (auto rit = suffix_.rbegin(); rit != suffix_.rend(); ++rit) { sh_ = for_sib->find(*rit); for_sib = sh_->second.children(); } @@ -142,9 +145,18 @@ class Simplex_tree_boundary_simplex_iterator : public boost::iterator_facade< sib_ = sib_->oncles(); } + // Most of the storage should be moved to the range, iterators should be light. Vertex_handle last_; // last vertex of the simplex Vertex_handle next_; // next vertex to push in suffix_ +#if BOOST_VERSION >= 105600 + // 40 seems a conservative bound on the dimension of a Simplex_tree for now, + // as it would not fit on the biggest hard-drive. + boost::container::static_vector<Vertex_handle, 40> suffix_; + // static_vector still has some overhead compared to a trivial hand-made + // version using std::aligned_storage, or compared to making suffix_ static. +#else std::vector<Vertex_handle> suffix_; +#endif Siblings * sib_; // where the next search will start from Simplex_handle sh_; // current Simplex_handle in the boundary SimplexTree * st_; // simplex containing the simplicial complex @@ -303,4 +315,4 @@ class Simplex_tree_skeleton_simplex_iterator : public boost::iterator_facade< /* @} */ // end addtogroup simplex_tree } // namespace Gudhi -#endif // SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_SIMPLEX_TREE_ITERATORS_H_ +#endif // SIMPLEX_TREE_SIMPLEX_TREE_ITERATORS_H_ diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h index 1f1a34cc..25d4888a 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h @@ -20,8 +20,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_SIMPLEX_TREE_NODE_EXPLICIT_STORAGE_H_ -#define SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_SIMPLEX_TREE_NODE_EXPLICIT_STORAGE_H_ +#ifndef SIMPLEX_TREE_SIMPLEX_TREE_NODE_EXPLICIT_STORAGE_H_ +#define SIMPLEX_TREE_SIMPLEX_TREE_NODE_EXPLICIT_STORAGE_H_ #include <vector> @@ -39,65 +39,34 @@ namespace Gudhi { * It stores explicitely its own filtration value and its own Simplex_key. */ template<class SimplexTree> -class Simplex_tree_node_explicit_storage { - public: +struct Simplex_tree_node_explicit_storage : SimplexTree::Filtration_simplex_base, SimplexTree::Key_simplex_base { typedef typename SimplexTree::Siblings Siblings; typedef typename SimplexTree::Filtration_value Filtration_value; typedef typename SimplexTree::Simplex_key Simplex_key; - // Default constructor. - Simplex_tree_node_explicit_storage() - : children_(NULL), - simplex_key_(-1), - filtration_(0) { - } - - Simplex_tree_node_explicit_storage(Siblings * sib, - Filtration_value filtration) - : children_(sib), - simplex_key_(-1), - filtration_(filtration) { - } - - void assign_key(Simplex_key key) { - simplex_key_ = key; + Simplex_tree_node_explicit_storage(Siblings * sib = nullptr, + Filtration_value filtration = 0) + : children_(sib) { + this->assign_filtration(filtration); } /* - * Assign a children to the node + * Assign children to the node */ void assign_children(Siblings * children) { children_ = children; } - /* - * - */ - void assign_filtration(double filtration_value) { - filtration_ = filtration_value; - } - - Filtration_value filtration() { - return filtration_; - } /* Careful -> children_ can be NULL*/ Siblings * children() { return children_; } - Simplex_key key() { - return simplex_key_; - } - private: Siblings * children_; - - // Data attached to simplex, explicit storage - Simplex_key simplex_key_; - Filtration_value filtration_; // value in the filtration }; /* @} */ // end addtogroup simplex_tree } // namespace Gudhi -#endif // SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_SIMPLEX_TREE_NODE_EXPLICIT_STORAGE_H_ +#endif // SIMPLEX_TREE_SIMPLEX_TREE_NODE_EXPLICIT_STORAGE_H_ diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_siblings.h b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_siblings.h index 977fafa1..158ee1f7 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_siblings.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_siblings.h @@ -20,11 +20,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_SIMPLEX_TREE_SIBLINGS_H_ -#define SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_SIMPLEX_TREE_SIBLINGS_H_ +#ifndef SIMPLEX_TREE_SIMPLEX_TREE_SIBLINGS_H_ +#define SIMPLEX_TREE_SIMPLEX_TREE_SIBLINGS_H_ -#include "boost/container/flat_map.hpp" -#include "Simplex_tree_node_explicit_storage.h" +#include <gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h> + +#include <boost/container/flat_map.hpp> #include <utility> #include <vector> @@ -71,14 +72,14 @@ class Simplex_tree_siblings { /* \brief Constructor with initialized set of members. * * 'members' must be sorted and unique.*/ - Simplex_tree_siblings(Simplex_tree_siblings * oncles, Vertex_handle parent, - const std::vector<std::pair<Vertex_handle, Node> > & members) + template<typename RandomAccessVertexRange> + Simplex_tree_siblings(Simplex_tree_siblings * oncles, Vertex_handle parent, const RandomAccessVertexRange & members) : oncles_(oncles), parent_(parent), members_(boost::container::ordered_unique_range, members.begin(), members.end()) { - for (auto map_it = members_.begin(); map_it != members_.end(); map_it++) { - map_it->second.assign_children(this); + for (auto& map_el : members_) { + map_el.second.assign_children(this); } } @@ -90,19 +91,12 @@ class Simplex_tree_siblings { * present in the node. */ void insert(Vertex_handle v, Filtration_value filtration_value) { - typename Dictionary::iterator sh = members_.find(v); - if (sh != members_.end() && sh->second.filtration() > filtration_value) { - sh->second.assign_filtration(filtration_value); - return; - } - if (sh == members_.end()) { - members_.insert( - std::pair<Vertex_handle, Node>(v, Node(this, filtration_value))); - return; - } + auto ins = members_.emplace(v, Node(this, filtration_value)); + if (!ins.second && filtration(ins.first) > filtration_value) + ins.first->second.assign_filtration(filtration_value); } - typename Dictionary::iterator find(Vertex_handle v) { + Dictionary_it find(Vertex_handle v) { return members_.find(v); } @@ -110,7 +104,7 @@ class Simplex_tree_siblings { return oncles_; } - Vertex_handle parent() { + Vertex_handle parent() const { return parent_; } @@ -118,7 +112,7 @@ class Simplex_tree_siblings { return members_; } - size_t size() { + size_t size() const { return members_.size(); } @@ -130,4 +124,4 @@ class Simplex_tree_siblings { /* @} */ // end addtogroup simplex_tree } // namespace Gudhi -#endif // SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_SIMPLEX_TREE_SIBLINGS_H_ +#endif // SIMPLEX_TREE_SIMPLEX_TREE_SIBLINGS_H_ diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree/indexing_tag.h b/src/Simplex_tree/include/gudhi/Simplex_tree/indexing_tag.h index 69ffa44b..0adeb46d 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree/indexing_tag.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree/indexing_tag.h @@ -20,8 +20,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_INDEXING_TAG_H_ -#define SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_INDEXING_TAG_H_ +#ifndef SIMPLEX_TREE_INDEXING_TAG_H_ +#define SIMPLEX_TREE_INDEXING_TAG_H_ namespace Gudhi { @@ -36,4 +36,4 @@ struct linear_indexing_tag { // struct zigzag_indexing_tag {}; } // namespace Gudhi -#endif // SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_INDEXING_TAG_H_ +#endif // SIMPLEX_TREE_INDEXING_TAG_H_ diff --git a/src/Simplex_tree/test/CMakeLists.txt b/src/Simplex_tree/test/CMakeLists.txt index b6a1c0b6..c9eae163 100644 --- a/src/Simplex_tree/test/CMakeLists.txt +++ b/src/Simplex_tree/test/CMakeLists.txt @@ -17,6 +17,9 @@ endif() add_executable ( SimplexTreeUT simplex_tree_unit_test.cpp ) target_link_libraries(SimplexTreeUT ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) +# Do not forget to copy test files in current binary dir +file(COPY "simplex_tree_for_unit_test.txt" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) + # Unitary tests add_test(NAME SimplexTreeUT COMMAND ${CMAKE_CURRENT_BINARY_DIR}/SimplexTreeUT diff --git a/src/Simplex_tree/test/simplex_tree_unit_test.cpp b/src/Simplex_tree/test/simplex_tree_unit_test.cpp index 6b0a1f3d..fff00d77 100644 --- a/src/Simplex_tree/test/simplex_tree_unit_test.cpp +++ b/src/Simplex_tree/test/simplex_tree_unit_test.cpp @@ -1,17 +1,16 @@ -#define BOOST_TEST_MODULE simplex_tree test -#include <boost/test/included/unit_test.hpp> -#include <boost/system/error_code.hpp> -#include <boost/chrono/thread_clock.hpp> #include <iostream> #include <string> - +#include <algorithm> #include <utility> // std::pair, std::make_pair - #include <cmath> // float comparison #include <limits> -#include "gudhi/graph_simplicial_complex.h" -#include "gudhi/reader_utils.h" +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE "simplex_tree" +#include <boost/test/unit_test.hpp> + +// ^ +// /!\ Nothing else from Simplex_tree shall be included to test includes are well defined. #include "gudhi/Simplex_tree.h" using namespace Gudhi; @@ -21,7 +20,7 @@ typedef std::pair<typeST::Simplex_handle, bool> typePairSimplexBool; typedef std::vector<Vertex_handle> typeVectorVertex; typedef std::pair<typeVectorVertex, Filtration_value> typeSimplex; -const Vertex_handle DEFAULT_VERTEX_HANDLE = (const Vertex_handle) -1; +const Vertex_handle DEFAULT_VERTEX_HANDLE = (const Vertex_handle) - 1; const Filtration_value DEFAULT_FILTRATION_VALUE = (const Filtration_value) 0.0; void test_empty_simplex_tree(typeST& tst) { @@ -40,55 +39,52 @@ void test_iterators_on_empty_simplex_tree(typeST& tst) { std::cout << "Iterator on vertices: " << std::endl; for (auto vertex : tst.complex_vertex_range()) { std::cout << "vertice:" << vertex << std::endl; - BOOST_CHECK(false); // shall be empty + BOOST_CHECK(false); // shall be empty } std::cout << "Iterator on simplices: " << std::endl; for (auto simplex : tst.complex_simplex_range()) { - BOOST_CHECK(simplex != simplex); // shall be empty - to remove warning of non-used simplex + BOOST_CHECK(simplex != simplex); // shall be empty - to remove warning of non-used simplex } std::cout << "Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; for (auto f_simplex : tst.filtration_simplex_range()) { - BOOST_CHECK(false); // shall be empty + BOOST_CHECK(false); // shall be empty std::cout << "test_iterators_on_empty_simplex_tree - filtration=" << tst.filtration(f_simplex) << std::endl; } } -BOOST_AUTO_TEST_CASE( simplex_tree_when_empty ) -{ +BOOST_AUTO_TEST_CASE(simplex_tree_when_empty) { const Filtration_value DEFAULT_FILTRATION_VALUE = 0; - // TEST OF DEFAULT CONSTRUCTOR std::cout << "********************************************************************" << std::endl; std::cout << "TEST OF DEFAULT CONSTRUCTOR" << std::endl; typeST st; - test_empty_simplex_tree (st); + test_empty_simplex_tree(st); - test_iterators_on_empty_simplex_tree (st); + test_iterators_on_empty_simplex_tree(st); // TEST OF EMPTY INSERTION std::cout << "TEST OF EMPTY INSERTION" << std::endl; typeVectorVertex simplexVectorEmpty; BOOST_CHECK(simplexVectorEmpty.empty() == true); typePairSimplexBool returnEmptyValue = st.insert_simplex(simplexVectorEmpty, - DEFAULT_FILTRATION_VALUE); + DEFAULT_FILTRATION_VALUE); BOOST_CHECK(returnEmptyValue.first == typeST::Simplex_handle(NULL)); BOOST_CHECK(returnEmptyValue.second == true); - test_empty_simplex_tree (st); + test_empty_simplex_tree(st); - test_iterators_on_empty_simplex_tree (st); + test_iterators_on_empty_simplex_tree(st); } bool AreAlmostTheSame(float a, float b) { return std::fabs(a - b) < std::numeric_limits<float>::epsilon(); } -BOOST_AUTO_TEST_CASE( simplex_tree_from_file ) -{ +BOOST_AUTO_TEST_CASE(simplex_tree_from_file) { // TEST OF INSERTION std::cout << "********************************************************************" << std::endl; std::cout << "TEST OF SIMPLEX TREE FROM A FILE" << std::endl; @@ -108,16 +104,16 @@ BOOST_AUTO_TEST_CASE( simplex_tree_from_file ) BOOST_CHECK(st.filtration() == 0.4); int previous_size = 0; - for( auto f_simplex : st.filtration_simplex_range() ) - { + for (auto f_simplex : st.filtration_simplex_range()) { // Size of simplex int size = 0; - for( auto vertex : st.simplex_vertex_range(f_simplex) ) - { + for (auto vertex : st.simplex_vertex_range(f_simplex)) { + // Remove warning + (void) vertex; size++; } - BOOST_CHECK(AreAlmostTheSame(st.filtration(f_simplex),(0.1* size))); // Specific test: filtration = 0.1 * simplex_size - BOOST_CHECK(previous_size <= size);// Check list is sorted (because of sorted filtrations in simplex_tree.txt) + BOOST_CHECK(AreAlmostTheSame(st.filtration(f_simplex), (0.1 * size))); // Specific test: filtration = 0.1 * simplex_size + BOOST_CHECK(previous_size <= size); // Check list is sorted (because of sorted filtrations in simplex_tree.txt) previous_size = size; } simplex_tree_stream.close(); @@ -127,13 +123,13 @@ void test_simplex_tree_contains(typeST& simplexTree, typeSimplex& simplex, int p auto f_simplex = simplexTree.filtration_simplex_range().begin() + pos; std::cout << "test_simplex_tree_contains - filtration=" << simplexTree.filtration(*f_simplex) << "||" << simplex.second << std::endl; - BOOST_CHECK( AreAlmostTheSame(simplexTree.filtration(*f_simplex),simplex.second) ); + BOOST_CHECK(AreAlmostTheSame(simplexTree.filtration(*f_simplex), simplex.second)); - int simplexIndex=simplex.first.size()-1; - for( auto vertex : simplexTree.simplex_vertex_range(*f_simplex) ) - { + int simplexIndex = simplex.first.size() - 1; + std::sort(simplex.first.begin(), simplex.first.end()); // if the simplex wasn't sorted, the next test could fail + for (auto vertex : simplexTree.simplex_vertex_range(*f_simplex)) { std::cout << "test_simplex_tree_contains - vertex=" << vertex << "||" << simplex.first.at(simplexIndex) << std::endl; - BOOST_CHECK(vertex == simplex.first.at(simplexIndex)); + BOOST_CHECK(vertex == simplex.first.at(simplexIndex)); BOOST_CHECK(simplexIndex >= 0); simplexIndex--; } @@ -141,7 +137,7 @@ void test_simplex_tree_contains(typeST& simplexTree, typeSimplex& simplex, int p void test_simplex_tree_insert_returns_true(const typePairSimplexBool& returnValue) { BOOST_CHECK(returnValue.second == true); - typeST::Simplex_handle shReturned = returnValue.first; // Simplex_handle = boost::container::flat_map< Vertex_handle, Node >::iterator + typeST::Simplex_handle shReturned = returnValue.first; // Simplex_handle = boost::container::flat_map< Vertex_handle, Node >::iterator BOOST_CHECK(shReturned != typeST::Simplex_handle(NULL)); } @@ -162,24 +158,26 @@ void set_and_test_simplex_tree_dim_fil(typeST& simplexTree, int vectorSize, cons std::cout << " set_and_test_simplex_tree_dim_fil - max_fil=" << max_fil << std::endl; } - unsigned int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); BOOST_CHECK(simplexTree.dimension() == dim_max); BOOST_CHECK(AreAlmostTheSame(simplexTree.filtration(), max_fil)); - BOOST_CHECK(simplexTree.num_simplices() == nb_simplices); + + // Another way to count simplices: + size_t num_simp = 0; + for (auto f_simplex : simplexTree.complex_simplex_range()) { + // Remove warning + (void) f_simplex; + num_simp++; + } + + BOOST_CHECK(simplexTree.num_simplices() == num_simp); } -BOOST_AUTO_TEST_CASE( simplex_tree_insertion ) -{ +BOOST_AUTO_TEST_CASE(simplex_tree_insertion) { const Filtration_value FIRST_FILTRATION_VALUE = 0.1; const Filtration_value SECOND_FILTRATION_VALUE = 0.2; const Filtration_value THIRD_FILTRATION_VALUE = 0.3; const Filtration_value FOURTH_FILTRATION_VALUE = 0.4; - Vertex_handle FIRST_VERTEX_HANDLE = (Vertex_handle) 0; - Vertex_handle SECOND_VERTEX_HANDLE = (Vertex_handle) 1; - Vertex_handle THIRD_VERTEX_HANDLE = (Vertex_handle) 2; - Vertex_handle FOURTH_VERTEX_HANDLE = (Vertex_handle) 3; // TEST OF INSERTION std::cout << "********************************************************************" << std::endl; @@ -188,171 +186,131 @@ BOOST_AUTO_TEST_CASE( simplex_tree_insertion ) // ++ FIRST std::cout << " - INSERT 0" << std::endl; - typeVectorVertex firstSimplexVector; - firstSimplexVector.push_back(FIRST_VERTEX_HANDLE); - BOOST_CHECK( firstSimplexVector.size() == 1 ); - typeSimplex firstSimplex = std::make_pair( - firstSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); - typePairSimplexBool returnValue = st.insert_simplex(firstSimplex.first, - firstSimplex.second); - - test_simplex_tree_insert_returns_true (returnValue); + typeVectorVertex firstSimplexVector{0}; + BOOST_CHECK(firstSimplexVector.size() == 1); + typeSimplex firstSimplex = std::make_pair(firstSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); + typePairSimplexBool returnValue = st.insert_simplex(firstSimplex.first, firstSimplex.second); + + test_simplex_tree_insert_returns_true(returnValue); set_and_test_simplex_tree_dim_fil(st, firstSimplexVector.size(), firstSimplex.second); - BOOST_CHECK( st.num_vertices() == (size_t)1 ); + BOOST_CHECK(st.num_vertices() == (size_t) 1); // ++ SECOND std::cout << " - INSERT 1" << std::endl; - typeVectorVertex secondSimplexVector; - secondSimplexVector.push_back(SECOND_VERTEX_HANDLE); - BOOST_CHECK( secondSimplexVector.size() == 1 ); - typeSimplex secondSimplex = std::make_pair( - secondSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); - returnValue = - st.insert_simplex ( secondSimplex.first, secondSimplex.second ); - - test_simplex_tree_insert_returns_true (returnValue); + typeVectorVertex secondSimplexVector{1}; + BOOST_CHECK(secondSimplexVector.size() == 1); + typeSimplex secondSimplex = std::make_pair(secondSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); + returnValue = st.insert_simplex(secondSimplex.first, secondSimplex.second); + + test_simplex_tree_insert_returns_true(returnValue); set_and_test_simplex_tree_dim_fil(st, secondSimplexVector.size(), secondSimplex.second); - BOOST_CHECK( st.num_vertices() == (size_t)2 ); + BOOST_CHECK(st.num_vertices() == (size_t) 2); // ++ THIRD std::cout << " - INSERT (0,1)" << std::endl; - typeVectorVertex thirdSimplexVector; - thirdSimplexVector.push_back(FIRST_VERTEX_HANDLE); - thirdSimplexVector.push_back(SECOND_VERTEX_HANDLE); - BOOST_CHECK( thirdSimplexVector.size() == 2 ); - typeSimplex thirdSimplex = std::make_pair( - thirdSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); - returnValue = - st.insert_simplex ( thirdSimplex.first, thirdSimplex.second ); - - test_simplex_tree_insert_returns_true (returnValue); + typeVectorVertex thirdSimplexVector{0, 1}; + BOOST_CHECK(thirdSimplexVector.size() == 2); + typeSimplex thirdSimplex = std::make_pair(thirdSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); + returnValue = st.insert_simplex(thirdSimplex.first, thirdSimplex.second); + + test_simplex_tree_insert_returns_true(returnValue); set_and_test_simplex_tree_dim_fil(st, thirdSimplexVector.size(), thirdSimplex.second); - BOOST_CHECK( st.num_vertices() == (size_t)2 ); // Not incremented !! + BOOST_CHECK(st.num_vertices() == (size_t) 2); // Not incremented !! // ++ FOURTH std::cout << " - INSERT 2" << std::endl; - typeVectorVertex fourthSimplexVector; - fourthSimplexVector.push_back(THIRD_VERTEX_HANDLE); - BOOST_CHECK( fourthSimplexVector.size() == 1 ); - typeSimplex fourthSimplex = std::make_pair( - fourthSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); - returnValue = - st.insert_simplex ( fourthSimplex.first, fourthSimplex.second ); - - test_simplex_tree_insert_returns_true (returnValue); + typeVectorVertex fourthSimplexVector{2}; + BOOST_CHECK(fourthSimplexVector.size() == 1); + typeSimplex fourthSimplex = std::make_pair(fourthSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); + returnValue = st.insert_simplex(fourthSimplex.first, fourthSimplex.second); + + test_simplex_tree_insert_returns_true(returnValue); set_and_test_simplex_tree_dim_fil(st, fourthSimplexVector.size(), fourthSimplex.second); - BOOST_CHECK( st.num_vertices() == (size_t)3 ); + BOOST_CHECK(st.num_vertices() == (size_t) 3); // ++ FIFTH std::cout << " - INSERT (2,0)" << std::endl; - typeVectorVertex fifthSimplexVector; - fifthSimplexVector.push_back(THIRD_VERTEX_HANDLE); - fifthSimplexVector.push_back(FIRST_VERTEX_HANDLE); - BOOST_CHECK( fifthSimplexVector.size() == 2 ); - typeSimplex fifthSimplex = std::make_pair( - fifthSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); - returnValue = - st.insert_simplex ( fifthSimplex.first, fifthSimplex.second ); - - test_simplex_tree_insert_returns_true (returnValue); + typeVectorVertex fifthSimplexVector{2, 0}; + BOOST_CHECK(fifthSimplexVector.size() == 2); + typeSimplex fifthSimplex = std::make_pair(fifthSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); + returnValue = st.insert_simplex(fifthSimplex.first, fifthSimplex.second); + + test_simplex_tree_insert_returns_true(returnValue); set_and_test_simplex_tree_dim_fil(st, fifthSimplexVector.size(), fifthSimplex.second); - BOOST_CHECK( st.num_vertices() == (size_t)3 ); // Not incremented !! + BOOST_CHECK(st.num_vertices() == (size_t) 3); // Not incremented !! // ++ SIXTH std::cout << " - INSERT (2,1)" << std::endl; - typeVectorVertex sixthSimplexVector; - sixthSimplexVector.push_back(THIRD_VERTEX_HANDLE); - sixthSimplexVector.push_back(SECOND_VERTEX_HANDLE); - BOOST_CHECK( sixthSimplexVector.size() == 2 ); - typeSimplex sixthSimplex = std::make_pair( - sixthSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); - returnValue = - st.insert_simplex ( sixthSimplex.first, sixthSimplex.second ); - - test_simplex_tree_insert_returns_true (returnValue); + typeVectorVertex sixthSimplexVector{2, 1}; + BOOST_CHECK(sixthSimplexVector.size() == 2); + typeSimplex sixthSimplex = std::make_pair(sixthSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); + returnValue = st.insert_simplex(sixthSimplex.first, sixthSimplex.second); + + test_simplex_tree_insert_returns_true(returnValue); set_and_test_simplex_tree_dim_fil(st, sixthSimplexVector.size(), sixthSimplex.second); - BOOST_CHECK( st.num_vertices() == (size_t)3 ); // Not incremented !! + BOOST_CHECK(st.num_vertices() == (size_t) 3); // Not incremented !! // ++ SEVENTH std::cout << " - INSERT (2,1,0)" << std::endl; - typeVectorVertex seventhSimplexVector; - seventhSimplexVector.push_back(THIRD_VERTEX_HANDLE); - seventhSimplexVector.push_back(SECOND_VERTEX_HANDLE); - seventhSimplexVector.push_back(FIRST_VERTEX_HANDLE); - BOOST_CHECK( seventhSimplexVector.size() == 3 ); - typeSimplex seventhSimplex = std::make_pair( - seventhSimplexVector, Filtration_value(THIRD_FILTRATION_VALUE)); - returnValue = - st.insert_simplex ( seventhSimplex.first, seventhSimplex.second ); - - test_simplex_tree_insert_returns_true (returnValue); + typeVectorVertex seventhSimplexVector{2, 1, 0}; + BOOST_CHECK(seventhSimplexVector.size() == 3); + typeSimplex seventhSimplex = std::make_pair(seventhSimplexVector, Filtration_value(THIRD_FILTRATION_VALUE)); + returnValue = st.insert_simplex(seventhSimplex.first, seventhSimplex.second); + + test_simplex_tree_insert_returns_true(returnValue); set_and_test_simplex_tree_dim_fil(st, seventhSimplexVector.size(), seventhSimplex.second); - BOOST_CHECK( st.num_vertices() == (size_t)3 ); // Not incremented !! + BOOST_CHECK(st.num_vertices() == (size_t) 3); // Not incremented !! // ++ EIGHTH std::cout << " - INSERT 3" << std::endl; - typeVectorVertex eighthSimplexVector; - eighthSimplexVector.push_back(FOURTH_VERTEX_HANDLE); - BOOST_CHECK( eighthSimplexVector.size() == 1 ); - typeSimplex eighthSimplex = std::make_pair( - eighthSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); - returnValue = - st.insert_simplex ( eighthSimplex.first, eighthSimplex.second ); - - test_simplex_tree_insert_returns_true (returnValue); + typeVectorVertex eighthSimplexVector{3}; + BOOST_CHECK(eighthSimplexVector.size() == 1); + typeSimplex eighthSimplex = std::make_pair(eighthSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); + returnValue = st.insert_simplex(eighthSimplex.first, eighthSimplex.second); + + test_simplex_tree_insert_returns_true(returnValue); set_and_test_simplex_tree_dim_fil(st, eighthSimplexVector.size(), eighthSimplex.second); - BOOST_CHECK( st.num_vertices() == (size_t)4 ); + BOOST_CHECK(st.num_vertices() == (size_t) 4); // ++ NINETH std::cout << " - INSERT (3,0)" << std::endl; - typeVectorVertex ninethSimplexVector; - ninethSimplexVector.push_back(FOURTH_VERTEX_HANDLE); - ninethSimplexVector.push_back(FIRST_VERTEX_HANDLE); - BOOST_CHECK( ninethSimplexVector.size() == 2 ); - typeSimplex ninethSimplex = std::make_pair( - ninethSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); - returnValue = - st.insert_simplex ( ninethSimplex.first, ninethSimplex.second ); - - test_simplex_tree_insert_returns_true (returnValue); + typeVectorVertex ninethSimplexVector{3, 0}; + BOOST_CHECK(ninethSimplexVector.size() == 2); + typeSimplex ninethSimplex = std::make_pair(ninethSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); + returnValue = st.insert_simplex(ninethSimplex.first, ninethSimplex.second); + + test_simplex_tree_insert_returns_true(returnValue); set_and_test_simplex_tree_dim_fil(st, ninethSimplexVector.size(), ninethSimplex.second); - BOOST_CHECK( st.num_vertices() == (size_t)4 ); // Not incremented !! + BOOST_CHECK(st.num_vertices() == (size_t) 4); // Not incremented !! // ++ TENTH std::cout << " - INSERT 0 (already inserted)" << std::endl; - typeVectorVertex tenthSimplexVector; - tenthSimplexVector.push_back(FIRST_VERTEX_HANDLE); - BOOST_CHECK( tenthSimplexVector.size() == 1 ); - typeSimplex tenthSimplex = std::make_pair( - tenthSimplexVector, Filtration_value(FOURTH_FILTRATION_VALUE)); // With a different filtration value - returnValue = - st.insert_simplex ( tenthSimplex.first, tenthSimplex.second ); + typeVectorVertex tenthSimplexVector{0}; + BOOST_CHECK(tenthSimplexVector.size() == 1); + // With a different filtration value + typeSimplex tenthSimplex = std::make_pair(tenthSimplexVector, Filtration_value(FOURTH_FILTRATION_VALUE)); + returnValue = st.insert_simplex(tenthSimplex.first, tenthSimplex.second); BOOST_CHECK(returnValue.second == false); - typeST::Simplex_handle shReturned = returnValue.first; // Simplex_handle = boost::container::flat_map< Vertex_handle, Node >::iterator + typeST::Simplex_handle shReturned = returnValue.first; // Simplex_handle = boost::container::flat_map< Vertex_handle, Node >::iterator BOOST_CHECK(shReturned == typeST::Simplex_handle(NULL)); - BOOST_CHECK( st.num_vertices() == (size_t)4 ); // Not incremented !! - BOOST_CHECK( st.dimension() == dim_max ); - BOOST_CHECK( AreAlmostTheSame(st.filtration(), max_fil) ); + BOOST_CHECK(st.num_vertices() == (size_t) 4); // Not incremented !! + BOOST_CHECK(st.dimension() == dim_max); + BOOST_CHECK(AreAlmostTheSame(st.filtration(), max_fil)); // ++ ELEVENTH std::cout << " - INSERT (2,1,0) (already inserted)" << std::endl; - typeVectorVertex eleventhSimplexVector; - eleventhSimplexVector.push_back(THIRD_VERTEX_HANDLE); - eleventhSimplexVector.push_back(SECOND_VERTEX_HANDLE); - eleventhSimplexVector.push_back(FIRST_VERTEX_HANDLE); - BOOST_CHECK( eleventhSimplexVector.size() == 3 ); - typeSimplex eleventhSimplex = std::make_pair( - eleventhSimplexVector, Filtration_value(FOURTH_FILTRATION_VALUE)); - returnValue = - st.insert_simplex ( eleventhSimplex.first, eleventhSimplex.second ); + typeVectorVertex eleventhSimplexVector{2, 1, 0}; + BOOST_CHECK(eleventhSimplexVector.size() == 3); + typeSimplex eleventhSimplex = std::make_pair(eleventhSimplexVector, Filtration_value(FOURTH_FILTRATION_VALUE)); + returnValue = st.insert_simplex(eleventhSimplex.first, eleventhSimplex.second); BOOST_CHECK(returnValue.second == false); - shReturned = returnValue.first; // Simplex_handle = boost::container::flat_map< Vertex_handle, Node >::iterator + shReturned = returnValue.first; // Simplex_handle = boost::container::flat_map< Vertex_handle, Node >::iterator BOOST_CHECK(shReturned == typeST::Simplex_handle(NULL)); - BOOST_CHECK( st.num_vertices() == (size_t)4 );// Not incremented !! - BOOST_CHECK( st.dimension() == dim_max ); - BOOST_CHECK( AreAlmostTheSame(st.filtration(), max_fil) ); + BOOST_CHECK(st.num_vertices() == (size_t) 4); // Not incremented !! + BOOST_CHECK(st.dimension() == dim_max); + BOOST_CHECK(AreAlmostTheSame(st.filtration(), max_fil)); /* Inserted simplex: */ /* 1 */ @@ -372,119 +330,153 @@ BOOST_AUTO_TEST_CASE( simplex_tree_insertion ) // [0.3] 2 1 0 // !! Be careful, simplex are sorted by filtration value on insertion !! std::cout << "simplex_tree_insertion - first - 0" << std::endl; - test_simplex_tree_contains(st, firstSimplex, 0);// (0) -> 0 + test_simplex_tree_contains(st, firstSimplex, 0); // (0) -> 0 std::cout << "simplex_tree_insertion - second - 1" << std::endl; - test_simplex_tree_contains(st, secondSimplex, 1);// (1) -> 1 + test_simplex_tree_contains(st, secondSimplex, 1); // (1) -> 1 std::cout << "simplex_tree_insertion - third - 4" << std::endl; - test_simplex_tree_contains(st, thirdSimplex, 4);// (0,1) -> 4 + test_simplex_tree_contains(st, thirdSimplex, 4); // (0,1) -> 4 std::cout << "simplex_tree_insertion - fourth - 2" << std::endl; - test_simplex_tree_contains(st, fourthSimplex, 2);// (2) -> 2 + test_simplex_tree_contains(st, fourthSimplex, 2); // (2) -> 2 std::cout << "simplex_tree_insertion - fifth - 5" << std::endl; - test_simplex_tree_contains(st, fifthSimplex, 5);// (2,0) -> 5 + test_simplex_tree_contains(st, fifthSimplex, 5); // (2,0) -> 5 std::cout << "simplex_tree_insertion - sixth - 6" << std::endl; - test_simplex_tree_contains(st, sixthSimplex, 6);//(2,1) -> 6 + test_simplex_tree_contains(st, sixthSimplex, 6); //(2,1) -> 6 std::cout << "simplex_tree_insertion - seventh - 8" << std::endl; - test_simplex_tree_contains(st, seventhSimplex, 8);// (2,1,0) -> 8 + test_simplex_tree_contains(st, seventhSimplex, 8); // (2,1,0) -> 8 std::cout << "simplex_tree_insertion - eighth - 3" << std::endl; - test_simplex_tree_contains(st, eighthSimplex, 3);// (3) -> 3 + test_simplex_tree_contains(st, eighthSimplex, 3); // (3) -> 3 std::cout << "simplex_tree_insertion - nineth - 7" << std::endl; - test_simplex_tree_contains(st, ninethSimplex, 7);// (3,0) -> 7 + test_simplex_tree_contains(st, ninethSimplex, 7); // (3,0) -> 7 // Display the Simplex_tree - Can not be done in the middle of 2 inserts std::cout << "The complex contains " << st.num_simplices() << " simplices" << std::endl; std::cout << " - dimension " << st.dimension() << " - filtration " << st.filtration() << std::endl; std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; - for( auto f_simplex : st.filtration_simplex_range() ) - { + for (auto f_simplex : st.filtration_simplex_range()) { std::cout << " " << "[" << st.filtration(f_simplex) << "] "; - for( auto vertex : st.simplex_vertex_range(f_simplex) ) - { - std::cout << (int)vertex << " "; + for (auto vertex : st.simplex_vertex_range(f_simplex)) { + std::cout << (int) vertex << " "; } std::cout << std::endl; } } -BOOST_AUTO_TEST_CASE( NSimplexAndSubfaces_tree_insertion ) -{ - Vertex_handle FIRST_VERTEX_HANDLE = (Vertex_handle)0; - Vertex_handle SECOND_VERTEX_HANDLE = (Vertex_handle) 1; - Vertex_handle THIRD_VERTEX_HANDLE = (Vertex_handle) 2; - Vertex_handle FOURTH_VERTEX_HANDLE = (Vertex_handle) 3; - Vertex_handle FIFTH_VERTEX_HANDLE = (Vertex_handle) 4; - Vertex_handle SIXTH_VERTEX_HANDLE = (Vertex_handle) 5; - Vertex_handle SEVENTH_VERTEX_HANDLE = (Vertex_handle) 6; - Vertex_handle EIGHTH_VERTEX_HANDLE = (Vertex_handle) 7; +bool sort_in_decr_order (Vertex_handle i,Vertex_handle j) { return (i>j); } - // TEST OF INSERTION +BOOST_AUTO_TEST_CASE(NSimplexAndSubfaces_tree_insertion) { std::cout << "********************************************************************" << std::endl; - std::cout << "TEST OF INSERTION" << std::endl; + std::cout << "TEST OF RECURSIVE INSERTION" << std::endl; typeST st; + typePairSimplexBool returnValue; + int position = 0; // ++ FIRST std::cout << " - INSERT (2,1,0)" << std::endl; - typeVectorVertex SimplexVector1; - SimplexVector1.push_back(THIRD_VERTEX_HANDLE); - SimplexVector1.push_back(SECOND_VERTEX_HANDLE); - SimplexVector1.push_back(FIRST_VERTEX_HANDLE); - BOOST_CHECK( SimplexVector1.size() == 3 ); - st.insert_simplex_and_subfaces ( SimplexVector1 ); - - BOOST_CHECK( st.num_vertices() == (size_t)3 ); // +3 (2, 1 and 0 are not existing) + typeVectorVertex SimplexVector1{2, 1, 0}; + BOOST_CHECK(SimplexVector1.size() == 3); + returnValue = st.insert_simplex_and_subfaces(SimplexVector1); + + BOOST_CHECK(st.num_vertices() == (size_t) 3); // +3 (2, 1 and 0 are not existing) + + // Check it is well inserted + BOOST_CHECK(true == returnValue.second); + position = 0; + std::sort(SimplexVector1.begin(), SimplexVector1.end(), sort_in_decr_order); + for (auto vertex : st.simplex_vertex_range(returnValue.first)) { + // Check returned Simplex_handle + std::cout << "vertex = " << vertex << " | vector[" << position << "] = " << SimplexVector1[position] << std::endl; + BOOST_CHECK(vertex == SimplexVector1[position]); + position++; + } // ++ SECOND std::cout << " - INSERT 3" << std::endl; - typeVectorVertex SimplexVector2; - SimplexVector2.push_back(FOURTH_VERTEX_HANDLE); - BOOST_CHECK( SimplexVector2.size() == 1 ); - st.insert_simplex_and_subfaces ( SimplexVector2 ); - - BOOST_CHECK( st.num_vertices() == (size_t)4 ); // +1 (3 is not existing) + typeVectorVertex SimplexVector2{3}; + BOOST_CHECK(SimplexVector2.size() == 1); + returnValue = st.insert_simplex_and_subfaces(SimplexVector2); + + BOOST_CHECK(st.num_vertices() == (size_t) 4); // +1 (3 is not existing) + + // Check it is well inserted + BOOST_CHECK(true == returnValue.second); + position = 0; + std::sort(SimplexVector2.begin(), SimplexVector2.end(), sort_in_decr_order); + for (auto vertex : st.simplex_vertex_range(returnValue.first)) { + // Check returned Simplex_handle + std::cout << "vertex = " << vertex << " | vector[" << position << "] = " << SimplexVector2[position] << std::endl; + BOOST_CHECK(vertex == SimplexVector2[position]); + position++; + } // ++ THIRD std::cout << " - INSERT (0,3)" << std::endl; - typeVectorVertex SimplexVector3; - SimplexVector3.push_back(FOURTH_VERTEX_HANDLE); - SimplexVector3.push_back(FIRST_VERTEX_HANDLE); - BOOST_CHECK( SimplexVector3.size() == 2 ); - st.insert_simplex_and_subfaces ( SimplexVector3 ); - - BOOST_CHECK( st.num_vertices() == (size_t)4 ); // Not incremented (all are existing) + typeVectorVertex SimplexVector3{3, 0}; + BOOST_CHECK(SimplexVector3.size() == 2); + returnValue = st.insert_simplex_and_subfaces(SimplexVector3); + + BOOST_CHECK(st.num_vertices() == (size_t) 4); // Not incremented (all are existing) + + // Check it is well inserted + BOOST_CHECK(true == returnValue.second); + position = 0; + std::sort(SimplexVector3.begin(), SimplexVector3.end(), sort_in_decr_order); + for (auto vertex : st.simplex_vertex_range(returnValue.first)) { + // Check returned Simplex_handle + std::cout << "vertex = " << vertex << " | vector[" << position << "] = " << SimplexVector3[position] << std::endl; + BOOST_CHECK(vertex == SimplexVector3[position]); + position++; + } // ++ FOURTH std::cout << " - INSERT (1,0) (already inserted)" << std::endl; - typeVectorVertex SimplexVector4; - SimplexVector4.push_back(SECOND_VERTEX_HANDLE); - SimplexVector4.push_back(FIRST_VERTEX_HANDLE); - BOOST_CHECK( SimplexVector4.size() == 2 ); - st.insert_simplex_and_subfaces ( SimplexVector4 ); + typeVectorVertex SimplexVector4{1, 0}; + BOOST_CHECK(SimplexVector4.size() == 2); + returnValue = st.insert_simplex_and_subfaces(SimplexVector4); - BOOST_CHECK( st.num_vertices() == (size_t)4 ); // Not incremented (all are existing) + BOOST_CHECK(st.num_vertices() == (size_t) 4); // Not incremented (all are existing) + + // Check it was not inserted (already there from {2,1,0} insertion) + BOOST_CHECK(false == returnValue.second); // ++ FIFTH std::cout << " - INSERT (3,4,5)" << std::endl; - typeVectorVertex SimplexVector5; - SimplexVector5.push_back(FOURTH_VERTEX_HANDLE); - SimplexVector5.push_back(FIFTH_VERTEX_HANDLE); - SimplexVector5.push_back(SIXTH_VERTEX_HANDLE); - BOOST_CHECK( SimplexVector5.size() == 3 ); - st.insert_simplex_and_subfaces ( SimplexVector5 ); - - BOOST_CHECK( st.num_vertices() == (size_t)6 ); + typeVectorVertex SimplexVector5{3, 4, 5}; + BOOST_CHECK(SimplexVector5.size() == 3); + returnValue = st.insert_simplex_and_subfaces(SimplexVector5); + + BOOST_CHECK(st.num_vertices() == (size_t) 6); + + // Check it is well inserted + BOOST_CHECK(true == returnValue.second); + position = 0; + std::sort(SimplexVector5.begin(), SimplexVector5.end(), sort_in_decr_order); + for (auto vertex : st.simplex_vertex_range(returnValue.first)) { + // Check returned Simplex_handle + std::cout << "vertex = " << vertex << " | vector[" << position << "] = " << SimplexVector5[position] << std::endl; + BOOST_CHECK(vertex == SimplexVector5[position]); + position++; + } // ++ SIXTH std::cout << " - INSERT (0,1,6,7)" << std::endl; - typeVectorVertex SimplexVector6; - SimplexVector6.push_back(FIRST_VERTEX_HANDLE); - SimplexVector6.push_back(SECOND_VERTEX_HANDLE); - SimplexVector6.push_back(SEVENTH_VERTEX_HANDLE); - SimplexVector6.push_back(EIGHTH_VERTEX_HANDLE); - BOOST_CHECK( SimplexVector6.size() == 4 ); - st.insert_simplex_and_subfaces ( SimplexVector6 ); - - BOOST_CHECK( st.num_vertices() == (size_t)8 ); // +2 (6 and 7 are not existing - 0 and 1 are already existing) - + typeVectorVertex SimplexVector6{0, 1, 6, 7}; + BOOST_CHECK(SimplexVector6.size() == 4); + returnValue = st.insert_simplex_and_subfaces(SimplexVector6); + + BOOST_CHECK(st.num_vertices() == (size_t) 8); // +2 (6 and 7 are not existing - 0 and 1 are already existing) + + // Check it is well inserted + BOOST_CHECK(true == returnValue.second); + position = 0; + std::sort(SimplexVector6.begin(), SimplexVector6.end(), sort_in_decr_order); + for (auto vertex : st.simplex_vertex_range(returnValue.first)) { + // Check returned Simplex_handle + std::cout << "vertex = " << vertex << " | vector[" << position << "] = " << SimplexVector6[position] << std::endl; + BOOST_CHECK(vertex == SimplexVector6[position]); + position++; + } + /* Inserted simplex: */ /* 1 6 */ /* o---o */ @@ -506,18 +498,17 @@ BOOST_AUTO_TEST_CASE( NSimplexAndSubfaces_tree_insertion ) typeSimplex simplexPair4 = std::make_pair(SimplexVector4, DEFAULT_FILTRATION_VALUE); typeSimplex simplexPair5 = std::make_pair(SimplexVector5, DEFAULT_FILTRATION_VALUE); typeSimplex simplexPair6 = std::make_pair(SimplexVector6, DEFAULT_FILTRATION_VALUE); - test_simplex_tree_contains(st,simplexPair1,6); // (2,1,0) is in position 6 - test_simplex_tree_contains(st,simplexPair2,7); // (3) is in position 7 - test_simplex_tree_contains(st,simplexPair3,8); // (3,0) is in position 8 - test_simplex_tree_contains(st,simplexPair4,2); // (1,0) is in position 2 - test_simplex_tree_contains(st,simplexPair5,14); // (3,4,5) is in position 14 - test_simplex_tree_contains(st,simplexPair6,26); // (7,6,1,0) is in position 26 - + test_simplex_tree_contains(st, simplexPair1, 6); // (2,1,0) is in position 6 + test_simplex_tree_contains(st, simplexPair2, 7); // (3) is in position 7 + test_simplex_tree_contains(st, simplexPair3, 8); // (3,0) is in position 8 + test_simplex_tree_contains(st, simplexPair4, 2); // (1,0) is in position 2 + test_simplex_tree_contains(st, simplexPair5, 14); // (3,4,5) is in position 14 + test_simplex_tree_contains(st, simplexPair6, 26); // (7,6,1,0) is in position 26 + // ------------------------------------------------------------------------------------------------------------------ // Find in the simplex_tree // ------------------------------------------------------------------------------------------------------------------ - typeVectorVertex simpleSimplexVector; - simpleSimplexVector.push_back(SECOND_VERTEX_HANDLE); + typeVectorVertex simpleSimplexVector{1}; Simplex_tree<>::Simplex_handle simplexFound = st.find(simpleSimplexVector); std::cout << "**************IS THE SIMPLEX {1} IN THE SIMPLEX TREE ?\n"; if (simplexFound != st.null_simplex()) @@ -527,9 +518,7 @@ BOOST_AUTO_TEST_CASE( NSimplexAndSubfaces_tree_insertion ) // Check it is found BOOST_CHECK(simplexFound != st.null_simplex()); - Vertex_handle UNKNOWN_VERTEX_HANDLE = (Vertex_handle) 15; - typeVectorVertex unknownSimplexVector; - unknownSimplexVector.push_back(UNKNOWN_VERTEX_HANDLE); + typeVectorVertex unknownSimplexVector{15}; simplexFound = st.find(unknownSimplexVector); std::cout << "**************IS THE SIMPLEX {15} IN THE SIMPLEX TREE ?\n"; if (simplexFound != st.null_simplex()) @@ -547,10 +536,8 @@ BOOST_AUTO_TEST_CASE( NSimplexAndSubfaces_tree_insertion ) std::cout << "***- NO IT ISN'T\n"; // Check it is found BOOST_CHECK(simplexFound != st.null_simplex()); - - typeVectorVertex otherSimplexVector; - otherSimplexVector.push_back(UNKNOWN_VERTEX_HANDLE); - otherSimplexVector.push_back(SECOND_VERTEX_HANDLE); + + typeVectorVertex otherSimplexVector{1, 15}; simplexFound = st.find(otherSimplexVector); std::cout << "**************IS THE SIMPLEX {15,1} IN THE SIMPLEX TREE ?\n"; if (simplexFound != st.null_simplex()) @@ -560,10 +547,7 @@ BOOST_AUTO_TEST_CASE( NSimplexAndSubfaces_tree_insertion ) // Check it is NOT found BOOST_CHECK(simplexFound == st.null_simplex()); - typeVectorVertex invSimplexVector; - invSimplexVector.push_back(SECOND_VERTEX_HANDLE); - invSimplexVector.push_back(THIRD_VERTEX_HANDLE); - invSimplexVector.push_back(FIRST_VERTEX_HANDLE); + typeVectorVertex invSimplexVector{1, 2, 0}; simplexFound = st.find(invSimplexVector); std::cout << "**************IS THE SIMPLEX {1,2,0} IN THE SIMPLEX TREE ?\n"; if (simplexFound != st.null_simplex()) @@ -572,19 +556,191 @@ BOOST_AUTO_TEST_CASE( NSimplexAndSubfaces_tree_insertion ) std::cout << "***- NO IT ISN'T\n"; // Check it is found BOOST_CHECK(simplexFound != st.null_simplex()); - + // Display the Simplex_tree - Can not be done in the middle of 2 inserts std::cout << "The complex contains " << st.num_simplices() << " simplices" << std::endl; std::cout << " - dimension " << st.dimension() << " - filtration " << st.filtration() << std::endl; std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; - for( auto f_simplex : st.filtration_simplex_range() ) - { + for (auto f_simplex : st.filtration_simplex_range()) { std::cout << " " << "[" << st.filtration(f_simplex) << "] "; - for( auto vertex : st.simplex_vertex_range(f_simplex) ) - { - std::cout << (int)vertex << " "; + for (auto vertex : st.simplex_vertex_range(f_simplex)) { + std::cout << (int) vertex << " "; + } + std::cout << std::endl; + } +} + +void test_cofaces(typeST& st, std::vector<Vertex_handle> expected, int dim, std::vector<typeST::Simplex_handle> res) { + typeST::Cofaces_simplex_range cofaces; + if (dim == 0) + cofaces = st.star_simplex_range(st.find(expected)); + else + cofaces = st.cofaces_simplex_range(st.find(expected), dim); + for (auto simplex = cofaces.begin(); simplex != cofaces.end(); ++simplex) { + typeST::Simplex_vertex_range rg = st.simplex_vertex_range(*simplex); + for (auto vertex = rg.begin(); vertex != rg.end(); ++vertex) { + std::cout << "(" << *vertex << ")"; } std::cout << std::endl; + BOOST_CHECK(std::find(res.begin(), res.end(), *simplex) != res.end()); } +} + +BOOST_AUTO_TEST_CASE(coface_on_simplex_tree) { + std::cout << "********************************************************************" << std::endl; + std::cout << "TEST COFACE ALGORITHM" << std::endl; + typeST st; + + typeVectorVertex SimplexVector{2, 1, 0}; + st.insert_simplex_and_subfaces(SimplexVector); + SimplexVector = {3, 0}; + st.insert_simplex_and_subfaces(SimplexVector); + + SimplexVector = {3, 4, 5}; + st.insert_simplex_and_subfaces(SimplexVector); + + SimplexVector = {0, 1, 6, 7}; + st.insert_simplex_and_subfaces(SimplexVector); + + /* Inserted simplex: */ + /* 1 6 */ + /* o---o */ + /* /X\7/ */ + /* o---o---o---o */ + /* 2 0 3\X/4 */ + /* o */ + /* 5 */ + + // FIXME + st.set_dimension(3); + + std::vector<Vertex_handle> simplex_result; + std::vector<typeST::Simplex_handle> result; + std::cout << "First test - Star of (3):" << std::endl; + + simplex_result = {3}; + result.push_back(st.find(simplex_result)); + + simplex_result = {3, 0}; + result.push_back(st.find(simplex_result)); + + simplex_result = {4, 3}; + result.push_back(st.find(simplex_result)); + + simplex_result = {5, 4, 3}; + result.push_back(st.find(simplex_result)); + + simplex_result = {5, 3}; + result.push_back(st.find(simplex_result)); + simplex_result.clear(); + + std::vector<Vertex_handle> vertex = {3}; + test_cofaces(st, vertex, 0, result); + vertex.clear(); + result.clear(); + + vertex.push_back(1); + vertex.push_back(7); + std::cout << "Second test - Star of (1,7): " << std::endl; + + simplex_result = {7, 1}; + result.push_back(st.find(simplex_result)); + + simplex_result = {7, 6, 1, 0}; + result.push_back(st.find(simplex_result)); + + simplex_result = {7, 1, 0}; + result.push_back(st.find(simplex_result)); + + simplex_result = {7, 6, 1}; + result.push_back(st.find(simplex_result)); + + test_cofaces(st, vertex, 0, result); + result.clear(); + + std::cout << "Third test - 2-dimension Cofaces of simplex(1,7) : " << std::endl; + + simplex_result = {7, 1, 0}; + result.push_back(st.find(simplex_result)); + + simplex_result = {7, 6, 1}; + result.push_back(st.find(simplex_result)); + + test_cofaces(st, vertex, 1, result); + result.clear(); + + std::cout << "Cofaces with a codimension too high (codimension + vetices > tree.dimension) :" << std::endl; + test_cofaces(st, vertex, 5, result); + + //std::cout << "Cofaces with an empty codimension" << std::endl; + //test_cofaces(st, vertex, -1, result); + // std::cout << "Cofaces in an empty simplex tree" << std::endl; + // typeST empty_tree; + // test_cofaces(empty_tree, vertex, 1, result); + //std::cout << "Cofaces of an empty simplex" << std::endl; + //vertex.clear(); + // test_cofaces(st, vertex, 1, result); + +} + +BOOST_AUTO_TEST_CASE(copy_move_on_simplex_tree) { + std::cout << "********************************************************************" << std::endl; + std::cout << "TEST COPY MOVE CONSTRUCTORS" << std::endl; + typeST st; + + typeVectorVertex SimplexVector{2, 1, 0}; + st.insert_simplex_and_subfaces(SimplexVector); + + SimplexVector = {3, 0}; + st.insert_simplex_and_subfaces(SimplexVector); + + SimplexVector = {3, 4, 5}; + st.insert_simplex_and_subfaces(SimplexVector); + + SimplexVector = {0, 1, 6, 7}; + st.insert_simplex_and_subfaces(SimplexVector); + + /* Inserted simplex: */ + /* 1 6 */ + /* o---o */ + /* /X\7/ */ + /* o---o---o---o */ + /* 2 0 3\X/4 */ + /* o */ + /* 5 */ + + // FIXME + st.set_dimension(3); + + std::cout << "Printing st - address = " << &st << std::endl; + + // Copy constructor + typeST st_copy = st; + std::cout << "Printing a copy of st - address = " << &st_copy << std::endl; + + // Check the data are the same + BOOST_CHECK(st == st_copy); + // Check there is a new simplex tree reference + BOOST_CHECK(&st != &st_copy); + + // Move constructor + typeST st_move = std::move(st); + std::cout << "Printing a move of st - address = " << &st_move << std::endl; + + // Check the data are the same + BOOST_CHECK(st_move == st_copy); + // Check there is a new simplex tree reference + BOOST_CHECK(&st_move != &st_copy); + BOOST_CHECK(&st_move != &st); + + typeST st_empty; + // Check st has been emptied by the move + BOOST_CHECK(st == st_empty); + BOOST_CHECK(st.filtration() == 0); + BOOST_CHECK(st.dimension() == -1); + BOOST_CHECK(st.num_simplices() == 0); + BOOST_CHECK(st.num_vertices() == (size_t)0); + + std::cout << "Printing st once again- address = " << &st << std::endl; } diff --git a/src/Skeleton_blocker/example/CMakeLists.txt b/src/Skeleton_blocker/example/CMakeLists.txt index d1228526..de0c7bba 100644 --- a/src/Skeleton_blocker/example/CMakeLists.txt +++ b/src/Skeleton_blocker/example/CMakeLists.txt @@ -1,10 +1,12 @@ cmake_minimum_required(VERSION 2.6) project(GUDHIskbl) - add_executable(SkeletonBlockerFromSimplices Skeleton_blocker_from_simplices.cpp) add_executable(SkeletonBlockerIteration Skeleton_blocker_iteration.cpp) add_executable(SkeletonBlockerLink Skeleton_blocker_link.cpp) +target_link_libraries(SkeletonBlockerIteration ${Boost_TIMER_LIBRARY} ${Boost_SYSTEM_LIBRARY}) -target_link_libraries(SkeletonBlockerIteration ${Boost_TIMER_LIBRARY} ${Boost_SYSTEM_LIBRARY}) +add_test(SkeletonBlockerFromSimplices ${CMAKE_CURRENT_BINARY_DIR}/SkeletonBlockerFromSimplices) +add_test(SkeletonBlockerIteration ${CMAKE_CURRENT_BINARY_DIR}/SkeletonBlockerIteration) +add_test(SkeletonBlockerLink ${CMAKE_CURRENT_BINARY_DIR}/SkeletonBlockerLink) diff --git a/src/Skeleton_blocker/example/Skeleton_blocker_from_simplices.cpp b/src/Skeleton_blocker/example/Skeleton_blocker_from_simplices.cpp index 9f9b3d52..5935a56d 100644 --- a/src/Skeleton_blocker/example/Skeleton_blocker_from_simplices.cpp +++ b/src/Skeleton_blocker/example/Skeleton_blocker_from_simplices.cpp @@ -1,34 +1,33 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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/>. - */ - +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <gudhi/Skeleton_blocker.h> #include <stdio.h> #include <stdlib.h> #include <string> #include <fstream> #include <sstream> - - -#include "gudhi/Skeleton_blocker.h" +#include <vector> using namespace std; using namespace Gudhi; @@ -36,48 +35,46 @@ using namespace skbl; typedef Skeleton_blocker_complex<Skeleton_blocker_simple_traits> Complex; typedef Complex::Vertex_handle Vertex_handle; -typedef Complex::Simplex_handle Simplex_handle; -typedef Complex::Simplex_handle Simplex; +typedef Complex::Simplex Simplex; -int main (int argc, char *argv[]){ - std::vector<Simplex_handle> simplices; +int main(int argc, char *argv[]) { + std::vector<Simplex> simplices; - //add 4 triangles of a tetrahedron 0123 - simplices.push_back(Simplex_handle(Vertex_handle(0),Vertex_handle(1),Vertex_handle(2))); - simplices.push_back(Simplex_handle(Vertex_handle(1),Vertex_handle(2),Vertex_handle(3))); - simplices.push_back(Simplex_handle(Vertex_handle(3),Vertex_handle(0),Vertex_handle(2))); - simplices.push_back(Simplex_handle(Vertex_handle(3),Vertex_handle(0),Vertex_handle(1))); + // add 4 triangles of a tetrahedron 0123 + simplices.push_back(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2))); + simplices.push_back(Simplex(Vertex_handle(1), Vertex_handle(2), Vertex_handle(3))); + simplices.push_back(Simplex(Vertex_handle(3), Vertex_handle(0), Vertex_handle(2))); + simplices.push_back(Simplex(Vertex_handle(3), Vertex_handle(0), Vertex_handle(1))); - //get complex from top faces - Complex complex(make_complex_from_top_faces<Complex>(simplices.begin(),simplices.end())); + // get complex from top faces + Complex complex(make_complex_from_top_faces<Complex>(simplices.begin(), simplices.end())); - std::cout << "Simplices:"<<std::endl; - for(const Simplex & s : complex.simplex_range()) - std::cout << s << " "; - std::cout << std::endl; + std::cout << "Simplices:" << std::endl; + for (const Simplex & s : complex.complex_simplex_range()) + std::cout << s << " "; + std::cout << std::endl; - //One blocker as simplex 0123 is not in the complex but all its proper faces are. - std::cout << "Blockers: "<<complex.blockers_to_string()<<std::endl; + // One blocker as simplex 0123 is not in the complex but all its proper faces are. + std::cout << "Blockers: " << complex.blockers_to_string() << std::endl; - //now build a complex from its full list of simplices - simplices.clear(); - simplices.push_back(Simplex_handle(Vertex_handle(0))); - simplices.push_back(Simplex_handle(Vertex_handle(1))); - simplices.push_back(Simplex_handle(Vertex_handle(2))); - simplices.push_back(Simplex_handle(Vertex_handle(0),Vertex_handle(1))); - simplices.push_back(Simplex_handle(Vertex_handle(1),Vertex_handle(2))); - simplices.push_back(Simplex_handle(Vertex_handle(2),Vertex_handle(0))); - complex = Complex(simplices.begin(),simplices.end()); + // now build a complex from its full list of simplices + simplices.clear(); + simplices.push_back(Simplex(Vertex_handle(0))); + simplices.push_back(Simplex(Vertex_handle(1))); + simplices.push_back(Simplex(Vertex_handle(2))); + simplices.push_back(Simplex(Vertex_handle(0), Vertex_handle(1))); + simplices.push_back(Simplex(Vertex_handle(1), Vertex_handle(2))); + simplices.push_back(Simplex(Vertex_handle(2), Vertex_handle(0))); + complex = Complex(simplices.begin(), simplices.end()); - std::cout << "Simplices:"<<std::endl; - for(const Simplex & s : complex.simplex_range()) - std::cout << s << " "; - std::cout << std::endl; + std::cout << "Simplices:" << std::endl; + for (const Simplex & s : complex.complex_simplex_range()) + std::cout << s << " "; + std::cout << std::endl; - //One blocker as simplex 012 is not in the complex but all its proper faces are. - std::cout << "Blockers: "<<complex.blockers_to_string()<<std::endl; + // One blocker as simplex 012 is not in the complex but all its proper faces are. + std::cout << "Blockers: " << complex.blockers_to_string() << std::endl; - return EXIT_SUCCESS; + return EXIT_SUCCESS; } - diff --git a/src/Skeleton_blocker/example/Skeleton_blocker_iteration.cpp b/src/Skeleton_blocker/example/Skeleton_blocker_iteration.cpp index 126e32ec..41b5ee00 100644 --- a/src/Skeleton_blocker/example/Skeleton_blocker_iteration.cpp +++ b/src/Skeleton_blocker/example/Skeleton_blocker_iteration.cpp @@ -1,24 +1,26 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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/>. - */ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <gudhi/Skeleton_blocker.h> #include <boost/timer/timer.hpp> @@ -29,64 +31,60 @@ #include <sstream> -#include "gudhi/Skeleton_blocker.h" - using namespace std; using namespace Gudhi; using namespace skbl; typedef Skeleton_blocker_complex<Skeleton_blocker_simple_traits> Complex; typedef Complex::Vertex_handle Vertex_handle; -typedef Complex::Simplex_handle Simplex; +typedef Complex::Simplex Simplex; - -Complex build_complete_complex(int n){ - // build a full complex with n vertices and 2^n-1 simplices - Complex complex; - for(int i=0;i<n;i++) - complex.add_vertex(); - for(int i=0;i<n;i++) - for(int j=0;j<i;j++) - //note that add_edge, add the edge and all its cofaces - complex.add_edge(Vertex_handle(i),Vertex_handle(j)); - return complex; +Complex build_complete_complex(int n) { + // build a full complex with n vertices and 2^n-1 simplices + Complex complex; + for (int i = 0; i < n; i++) + complex.add_vertex(); + for (int i = 0; i < n; i++) + for (int j = 0; j < i; j++) + complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j)); + return complex; } -int main (int argc, char *argv[]){ - boost::timer::auto_cpu_timer t; +int main(int argc, char *argv[]) { + boost::timer::auto_cpu_timer t; - const int n = 15; + const int n = 15; - // build a full complex with n vertices and 2^n-1 simplices - Complex complex(build_complete_complex(n)); + // build a full complex with n vertices and 2^n-1 simplices + Complex complex(build_complete_complex(n)); - // this is just to illustrate iterators, to count number of vertices - // or edges, complex.num_vertices() and complex.num_edges() are - // more appropriated! - unsigned num_vertices = 0; - for(auto v : complex.vertex_range()) { - std::cout << "Vertex " << v <<std::endl; - ++num_vertices; - } + // this is just to illustrate iterators, to count number of vertices + // or edges, complex.num_vertices() and complex.num_edges() are + // more appropriated! + unsigned num_vertices = 0; + for (auto v : complex.vertex_range()) { + std::cout << "Vertex " << v << std::endl; + ++num_vertices; + } - // such loop can also be done directly with distance as iterators are STL compliant - auto edges = complex.edge_range(); - unsigned num_edges = std::distance(edges.begin(), edges.end()); + // such loop can also be done directly with distance as iterators are STL compliant + auto edges = complex.edge_range(); + unsigned num_edges = std::distance(edges.begin(), edges.end()); - unsigned euler = 0; - unsigned num_simplices = 0; - // we use a reference to a simplex instead of a copy - // value here because a simplex is a set of integers - // and copying it cost time - for(const Simplex & s : complex.simplex_range()){ - ++num_simplices; - if(s.dimension()%2 == 0) - euler += 1; - else - euler -= 1; - } - std::cout << "Saw "<<num_vertices<<" vertices, "<<num_edges<<" edges and "<<num_simplices<<" simplices"<<std::endl; - std::cout << "The Euler Characteristic is "<<euler<<std::endl; - return EXIT_SUCCESS; + unsigned euler = 0; + unsigned num_simplices = 0; + // we use a reference to a simplex instead of a copy + // value here because a simplex is a set of integers + // and copying it cost time + for (const Simplex & s : complex.complex_simplex_range()) { + ++num_simplices; + if (s.dimension() % 2 == 0) + euler += 1; + else + euler -= 1; + } + std::cout << "Saw " << num_vertices << " vertices, " << num_edges << " edges and " << num_simplices << " simplices" + << std::endl; + std::cout << "The Euler Characteristic is " << euler << std::endl; + return EXIT_SUCCESS; } - diff --git a/src/Skeleton_blocker/example/Skeleton_blocker_link.cpp b/src/Skeleton_blocker/example/Skeleton_blocker_link.cpp index 0987cc89..698a8106 100644 --- a/src/Skeleton_blocker/example/Skeleton_blocker_link.cpp +++ b/src/Skeleton_blocker/example/Skeleton_blocker_link.cpp @@ -1,25 +1,26 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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/>. - */ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include <gudhi/Skeleton_blocker.h> #include <stdio.h> #include <stdlib.h> @@ -27,9 +28,6 @@ #include <fstream> #include <sstream> - -#include "gudhi/Skeleton_blocker.h" - using namespace std; using namespace Gudhi; using namespace skbl; @@ -37,35 +35,37 @@ using namespace skbl; typedef Skeleton_blocker_complex<Skeleton_blocker_simple_traits> Complex; typedef Complex::Vertex_handle Vertex_handle; typedef Complex::Root_vertex_handle Root_vertex_handle; -typedef Complex::Simplex_handle Simplex; +typedef Complex::Simplex Simplex; +int main(int argc, char *argv[]) { + // build a full complex with 4 vertices and 2^4-1 simplices -int main (int argc, char *argv[]){ - // build a full complex with 4 vertices and 2^4-1 simplices - // Initial vertices are (0,1,2,3,4) - Simplex tetrahedron(Vertex_handle(0),Vertex_handle(1),Vertex_handle(2),Vertex_handle(3)); - Complex complex; - complex.add_simplex(tetrahedron); + // Create a complex with four vertices (0,1,2,3) + Complex complex; - cout<<"complex:"<<complex.to_string()<<endl; + // Add a tetrahedron to this complex + Simplex tetrahedron(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2), Vertex_handle(3)); + complex.add_simplex(tetrahedron); - //build the link of vertex 1, eg a triangle {0,2,3} - auto link = complex.link(Vertex_handle(1)); - cout<<"link:"<<link.to_string()<<endl; + cout << "complex:" << complex.to_string() << endl; - //Internally link is a subcomplex of 'complex' and its vertices are stored in a vector. - //They can be accessed via Vertex_handle(x) where x is an index of the vector. - //In that example, link has three vertices and thus it contains only - // Vertex_handle(0),Vertex_handle(1) and Vertex_handle(2) are). - for(int i = 0; i<5; ++i) - cout << "link.contains_vertex(Vertex_handle("<<i<<")):"<<link.contains_vertex(Vertex_handle(i))<<endl; - cout<<endl; + // build the link of vertex 1, eg a triangle {0,2,3} + auto link = complex.link(Vertex_handle(1)); + cout << "link:" << link.to_string() << endl; - //To access to the initial vertices eg (0,1,2,3,4), Root_vertex_handle must be used. - //For instance, to test if the link contains the vertex that was labeled i: - for(int i = 0; i<5; ++i) - cout << "link.contains_vertex(Root_vertex_handle("<<i<<")):"<<link.contains_vertex(Root_vertex_handle(i))<<endl; + // Internally link is a subcomplex of 'complex' and its vertices are stored in a vector. + // They can be accessed via Vertex_handle(x) where x is an index of the vector. + // In that example, link has three vertices and thus it contains only + // Vertex_handle(0),Vertex_handle(1) and Vertex_handle(2) are). + for (int i = 0; i < 5; ++i) + cout << "link.contains_vertex(Vertex_handle(" << i << ")):" << link.contains_vertex(Vertex_handle(i)) << endl; + cout << endl; - return EXIT_SUCCESS; -} + // To access to the initial vertices eg (0,1,2,3,4), Root_vertex_handle must be used. + // For instance, to test if the link contains the vertex that was labeled i: + for (int i = 0; i < 5; ++i) + cout << "link.contains_vertex(Root_vertex_handle(" << i << ")):" << + link.contains_vertex(Root_vertex_handle(i)) << endl; + return EXIT_SUCCESS; +} diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker.h index 289819b5..615b3a81 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker.h @@ -19,23 +19,24 @@ * 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 SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_H_ -#define SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_H_ -#include "gudhi/Skeleton_blocker_complex.h" -#include "gudhi/Skeleton_blocker_geometric_complex.h" -#include "gudhi/Skeleton_blocker_simplifiable_complex.h" -#include "gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h" +#ifndef SKELETON_BLOCKER_H_ +#define SKELETON_BLOCKER_H_ -#include "gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h" -#include "gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h" +#include <gudhi/Skeleton_blocker_complex.h> +#include <gudhi/Skeleton_blocker_geometric_complex.h> +#include <gudhi/Skeleton_blocker_simplifiable_complex.h> +#include <gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h> +#include <gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h> +#include <gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h> -#include "gudhi/Utils.h" // xxx - +#include <gudhi/Utils.h> // xxx namespace Gudhi { + namespace skbl { + /** \defgroup skbl Skeleton-Blocker \author David Salinas @@ -128,7 +129,7 @@ of a simplicial complex. \code{.cpp} typedef Skeleton_blocker_complex<Skeleton_blocker_simple_traits> Complex; typedef Complex::Vertex_handle Vertex_handle; - typedef Complex::Simplex_handle Simplex; + typedef Complex::Simplex Simplex; const int n = 15; @@ -138,8 +139,7 @@ of a simplicial complex. complex.add_vertex(); for(int i=0;i<n;i++) for(int j=0;j<i;j++) - //note that add_edge adds the edge and all its cofaces - complex.add_edge(Vertex_handle(i),Vertex_handle(j)); + complex.add_edge_without_blockers(Vertex_handle(i),Vertex_handle(j)); // this is just to illustrate iterators, to count number of vertices // or edges, complex.num_vertices() and complex.num_edges() are @@ -158,7 +158,7 @@ of a simplicial complex. // we use a reference to a simplex instead of a copy // value here because a simplex is a set of integers // and copying it cost time - for(const Simplex & s : complex.simplex_range()){ + for(const Simplex & s : complex.star_simplex_range()){ ++num_simplices; if(s.dimension()%2 == 0) euler += 1; @@ -181,20 +181,20 @@ The Euler Characteristic is 1 \subsection s Constructing a skeleton-blockers from a list of maximal faces or from a list of faces \code{.cpp} - std::vector<Simplex_handle> simplices; + std::vector<Simplex> simplices; //add 4 triangles of a tetrahedron 0123 - simplices.push_back(Simplex_handle(Vertex_handle(0),Vertex_handle(1),Vertex_handle(2))); - simplices.push_back(Simplex_handle(Vertex_handle(1),Vertex_handle(2),Vertex_handle(3))); - simplices.push_back(Simplex_handle(Vertex_handle(3),Vertex_handle(0),Vertex_handle(2))); - simplices.push_back(Simplex_handle(Vertex_handle(3),Vertex_handle(0),Vertex_handle(1))); + simplices.push_back(Simplex(Vertex_handle(0),Vertex_handle(1),Vertex_handle(2))); + simplices.push_back(Simplex(Vertex_handle(1),Vertex_handle(2),Vertex_handle(3))); + simplices.push_back(Simplex(Vertex_handle(3),Vertex_handle(0),Vertex_handle(2))); + simplices.push_back(Simplex(Vertex_handle(3),Vertex_handle(0),Vertex_handle(1))); Complex complex; //get complex from top faces make_complex_from_top_faces(complex,simplices.begin(),simplices.end()); std::cout << "Simplices:"<<std::endl; - for(const Simplex & s : complex.simplex_range()) + for(const Simplex & s : complex.star_simplex_range()) std::cout << s << " "; std::cout << std::endl; @@ -203,16 +203,16 @@ The Euler Characteristic is 1 //now build a complex from its full list of simplices simplices.clear(); - simplices.push_back(Simplex_handle(Vertex_handle(0))); - simplices.push_back(Simplex_handle(Vertex_handle(1))); - simplices.push_back(Simplex_handle(Vertex_handle(2))); - simplices.push_back(Simplex_handle(Vertex_handle(0),Vertex_handle(1))); - simplices.push_back(Simplex_handle(Vertex_handle(1),Vertex_handle(2))); - simplices.push_back(Simplex_handle(Vertex_handle(2),Vertex_handle(0))); + simplices.push_back(Simplex(Vertex_handle(0))); + simplices.push_back(Simplex(Vertex_handle(1))); + simplices.push_back(Simplex(Vertex_handle(2))); + simplices.push_back(Simplex(Vertex_handle(0),Vertex_handle(1))); + simplices.push_back(Simplex(Vertex_handle(1),Vertex_handle(2))); + simplices.push_back(Simplex(Vertex_handle(2),Vertex_handle(0))); complex = Complex(simplices.begin(),simplices.end()); std::cout << "Simplices:"<<std::endl; - for(const Simplex & s : complex.simplex_range()) + for(const Simplex & s : complex.star_simplex_range()) std::cout << s << " "; std::cout << std::endl; @@ -240,14 +240,12 @@ their collaboration to write the two initial papers \copyright GNU General Public License v3. -\verbatim Contact: David Salinas, david.salinas@inria.fr \endverbatim +\verbatim Contact: gudhi-users@lists.gforge.inria.fr \endverbatim */ /** @} */ // end defgroup -} // namespace skbl -} // namespace Gudhi - - -#endif // SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_H_ +} // namespace skbl +} // namespace Gudhi +#endif // SKELETON_BLOCKER_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h index 829ab1e8..4ade68e7 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h @@ -19,10 +19,10 @@ * 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 SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_COMPLEX_VISITOR_H_ -#define SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_COMPLEX_VISITOR_H_ +#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_COMPLEX_VISITOR_H_ +#define SKELETON_BLOCKER_SKELETON_BLOCKER_COMPLEX_VISITOR_H_ -#include "gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h" +#include <gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h> namespace Gudhi { @@ -41,7 +41,7 @@ class Skeleton_blocker_complex_visitor { virtual void on_add_vertex(Vertex_handle) = 0; virtual void on_remove_vertex(Vertex_handle) = 0; - virtual void on_add_edge(Vertex_handle a, Vertex_handle b) = 0; + virtual void on_add_edge_without_blockers(Vertex_handle a, Vertex_handle b) = 0; virtual void on_remove_edge(Vertex_handle a, Vertex_handle b) = 0; /** @@ -54,12 +54,12 @@ class Skeleton_blocker_complex_visitor { * @brief Called when performing an edge contraction when * an edge bx is replaced by an edge ax (not already present). * Precisely, this methods is called this way in contract_edge : - * add_edge(a,x) + * add_edge_without_blockers(a,x) * on_swaped_edge(a,b,x) * remove_edge(b,x) */ virtual void on_swaped_edge(Vertex_handle a, Vertex_handle b, - Vertex_handle x)=0; + Vertex_handle x) = 0; virtual void on_add_blocker( const Skeleton_blocker_simplex<Vertex_handle>&) = 0; virtual void on_delete_blocker( @@ -79,7 +79,7 @@ class Dummy_complex_visitor : public Skeleton_blocker_complex_visitor< } void on_remove_vertex(Vertex_handle) { } - void on_add_edge(Vertex_handle a, Vertex_handle b) { + void on_add_edge_without_blockers(Vertex_handle a, Vertex_handle b) { } void on_remove_edge(Vertex_handle a, Vertex_handle b) { } @@ -108,8 +108,8 @@ class Print_complex_visitor : public Skeleton_blocker_complex_visitor< void on_remove_vertex(Vertex_handle v) { std::cerr << "on_remove_vertex:" << v << std::endl; } - void on_add_edge(Vertex_handle a, Vertex_handle b) { - std::cerr << "on_add_edge:" << a << "," << b << std::endl; + void on_add_edge_without_blockers(Vertex_handle a, Vertex_handle b) { + std::cerr << "on_add_edge_without_blockers:" << a << "," << b << std::endl; } void on_remove_edge(Vertex_handle a, Vertex_handle b) { std::cerr << "on_remove_edge:" << a << "," << b << std::endl; @@ -132,4 +132,4 @@ class Print_complex_visitor : public Skeleton_blocker_complex_visitor< } // namespace Gudhi -#endif // SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_COMPLEX_VISITOR_H_ +#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_COMPLEX_VISITOR_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h index 17d58956..876bdba9 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h @@ -19,10 +19,10 @@ * 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 SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_LINK_SUPERIOR_H_ -#define SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_LINK_SUPERIOR_H_ +#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_LINK_SUPERIOR_H_ +#define SKELETON_BLOCKER_SKELETON_BLOCKER_LINK_SUPERIOR_H_ -#include "gudhi/Skeleton_blocker_link_complex.h" +#include <gudhi/Skeleton_blocker_link_complex.h> namespace Gudhi { @@ -44,13 +44,13 @@ class Skeleton_blocker_link_superior : public Skeleton_blocker_link_complex< public: typedef typename ComplexType::Vertex_handle Vertex_handle; typedef typename ComplexType::Root_vertex_handle Root_vertex_handle; - typedef typename ComplexType::Simplex_handle Simplex_handle; + typedef typename ComplexType::Simplex Simplex; typedef typename ComplexType::Root_simplex_handle Root_simplex_handle; typedef typename ComplexType::BlockerMap BlockerMap; typedef typename ComplexType::BlockerPair BlockerPair; typedef typename ComplexType::BlockerMapIterator BlockerMapIterator; typedef typename ComplexType::BlockerMapConstIterator BlockerMapConstIterator; - typedef typename ComplexType::Simplex_handle::Simplex_vertex_const_iterator AddressSimplexConstIterator; + typedef typename ComplexType::Simplex::Simplex_vertex_const_iterator AddressSimplexConstIterator; typedef typename ComplexType::Root_simplex_handle::Simplex_vertex_const_iterator IdSimplexConstIterator; Skeleton_blocker_link_superior() @@ -58,7 +58,7 @@ class Skeleton_blocker_link_superior : public Skeleton_blocker_link_complex< } Skeleton_blocker_link_superior(const ComplexType & parent_complex, - Simplex_handle& alpha_parent_adress) + Simplex& alpha_parent_adress) : Skeleton_blocker_link_complex<ComplexType>(parent_complex, alpha_parent_adress, true) { } @@ -74,4 +74,4 @@ class Skeleton_blocker_link_superior : public Skeleton_blocker_link_complex< } // namespace Gudhi -#endif // SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_LINK_SUPERIOR_H_ +#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_LINK_SUPERIOR_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h index aaaab8b0..ad2d2f85 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h @@ -19,15 +19,15 @@ * 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 SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_OFF_IO_H_ -#define SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_OFF_IO_H_ +#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_OFF_IO_H_ +#define SKELETON_BLOCKER_SKELETON_BLOCKER_OFF_IO_H_ + +#include <gudhi/Off_reader.h> #include <string> #include <vector> #include <map> -#include "gudhi/Off_reader.h" - namespace Gudhi { namespace skbl { @@ -61,7 +61,7 @@ class Skeleton_blocker_off_flag_visitor_reader { if (!load_only_points_) { for (size_t i = 0; i < face.size(); ++i) for (size_t j = i + 1; j < face.size(); ++j) { - complex_.add_edge(Vertex_handle(face[i]), Vertex_handle(face[j])); + complex_.add_edge_without_blockers(Vertex_handle(face[i]), Vertex_handle(face[j])); } } } @@ -76,12 +76,12 @@ template<typename Complex> class Skeleton_blocker_off_visitor_reader { Complex& complex_; typedef typename Complex::Vertex_handle Vertex_handle; - typedef typename Complex::Simplex_handle Simplex_handle; + typedef typename Complex::Simplex Simplex; typedef typename Complex::Point Point; const bool load_only_points_; std::vector<Point> points_; - std::vector<Simplex_handle> maximal_faces_; + std::vector<Simplex> maximal_faces_; public: explicit Skeleton_blocker_off_visitor_reader(Complex& complex, bool load_only_points = false) : @@ -99,7 +99,7 @@ class Skeleton_blocker_off_visitor_reader { void maximal_face(const std::vector<int>& face) { if (!load_only_points_) { - Simplex_handle s; + Simplex s; for (auto x : face) s.add_vertex(Vertex_handle(x)); maximal_faces_.emplace_back(s); @@ -107,7 +107,7 @@ class Skeleton_blocker_off_visitor_reader { } void done() { - complex_ = make_complex_from_top_faces(maximal_faces_.begin(), maximal_faces_.end(), + complex_ = make_complex_from_top_faces<Complex>(maximal_faces_.begin(), maximal_faces_.end(), points_.begin(), points_.end() ); } }; @@ -197,4 +197,4 @@ class Skeleton_blocker_off_writer { } // namespace Gudhi -#endif // SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_OFF_IO_H_ +#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_OFF_IO_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h index d3a5b9d8..8508d9a5 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h @@ -19,14 +19,14 @@ * 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 SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_GEOMETRIC_TRAITS_H_ -#define SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_GEOMETRIC_TRAITS_H_ +#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_GEOMETRIC_TRAITS_H_ +#define SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_GEOMETRIC_TRAITS_H_ + +#include <gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h> #include <string> #include <sstream> -#include "gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h" - namespace Gudhi { namespace skbl { @@ -91,4 +91,4 @@ struct Skeleton_blocker_simple_geometric_traits : } // namespace Gudhi -#endif // SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_GEOMETRIC_TRAITS_H_ +#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_GEOMETRIC_TRAITS_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h index 52e454ea..0d2de767 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h @@ -19,12 +19,13 @@ * 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 SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_TRAITS_H_ -#define SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_TRAITS_H_ +#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_TRAITS_H_ +#define SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_TRAITS_H_ + +#include <gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h> #include <string> #include <sstream> -#include "Skeleton_blocker_simplex.h" namespace Gudhi { @@ -77,7 +78,7 @@ struct Skeleton_blocker_simple_traits { : vertex(val) { } - operator int() const { return (int)vertex; } + operator int() const { return static_cast<int>(vertex); } boost_vertex_handle vertex; @@ -178,4 +179,4 @@ struct Skeleton_blocker_simple_traits { } // namespace Gudhi -#endif // SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_TRAITS_H_ +#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_TRAITS_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h index 10d64e98..714bf23c 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h @@ -20,8 +20,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLEX_H_ -#define SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLEX_H_ +#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLEX_H_ +#define SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLEX_H_ #include <cassert> #include <iostream> @@ -69,7 +69,9 @@ class Skeleton_blocker_simplex { } Skeleton_blocker_simplex(std::initializer_list<T>& list) { - for_each(list.begin(), list.end(), add_vertex); + std::for_each(list.begin(), list.end(), [&] (T const& elt) { + add_vertex(elt); + }); } template<typename ... Args> @@ -216,7 +218,7 @@ class Skeleton_blocker_simplex { } /** - * Returns the first vertex of the (oriented) simplex. + * Returns the first and smallest vertex of the simplex. * * Be careful : assumes the simplex is non-empty. */ @@ -226,7 +228,7 @@ class Skeleton_blocker_simplex { } /** - * Returns the last vertex of the (oriented) simplex. + * Returns the last and greatest vertex of the simplex. * * Be careful : assumes the simplex is non-empty. */ @@ -369,5 +371,4 @@ class Skeleton_blocker_simplex { } // namespace Gudhi -#endif // SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLEX_H_ - +#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLEX_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h index e906df75..50a83345 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h @@ -20,16 +20,16 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_SUB_COMPLEX_H_ -#define SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_SUB_COMPLEX_H_ +#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_SUB_COMPLEX_H_ +#define SKELETON_BLOCKER_SKELETON_BLOCKER_SUB_COMPLEX_H_ + +#include <gudhi/Skeleton_blocker_complex.h> +#include <gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h> +#include <gudhi/Utils.h> #include <map> #include <vector> -#include "gudhi/Skeleton_blocker_complex.h" -#include "gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h" -#include "gudhi/Utils.h" - namespace Gudhi { namespace skbl { @@ -66,34 +66,19 @@ class Skeleton_blocker_sub_complex : public ComplexType { public: using ComplexType::add_vertex; - using ComplexType::add_edge; + using ComplexType::add_edge_without_blockers; using ComplexType::add_blocker; typedef typename ComplexType::Vertex_handle Vertex_handle; typedef typename ComplexType::Root_vertex_handle Root_vertex_handle; - typedef typename ComplexType::Simplex_handle Simplex_handle; + typedef typename ComplexType::Simplex Simplex; typedef typename ComplexType::Root_simplex_handle Root_simplex_handle; protected: - ///** - //* @brief Returns true iff the simplex formed by all vertices contained in 'addresses_sigma_in_link' - //* but 'vertex_to_be_ignored' is in 'link' - //*/ - /* - template<typename T> friend bool - proper_face_in_union( - Skeleton_blocker_sub_complex<T> & link, - std::vector<boost::optional<typename T::Vertex_handle> > & addresses_sigma_in_link, - int vertex_to_be_ignored);*/ - /** * @brief Determines whether all proper faces of simplex 'sigma' belong to 'link1' \cup 'link2' * where 'link1' and 'link2' are subcomplexes of the same complex of type ComplexType */ - // template<typename T> friend bool - // proper_faces_in_union(Skeleton_blocker_simplex<typename T::Root_vertex_handle> & sigma, Skeleton_blocker_sub_complex<T> & link1, Skeleton_blocker_sub_complex<T> & link2){ - // template<typename T> friend bool - // proper_faces_in_union(Skeleton_blocker_simplex<typename T::Root_vertex_handle> & sigma, Skeleton_blocker_sub_complex<T> & link1, Skeleton_blocker_sub_complex<T> & link2); typedef std::map<Root_vertex_handle, Vertex_handle> IdAddressMap; typedef typename IdAddressMap::value_type AddressPair; typedef typename IdAddressMap::iterator IdAddressMapIterator; @@ -124,11 +109,11 @@ class Skeleton_blocker_sub_complex : public ComplexType { * It assumes that both vertices corresponding to v1_root and v2_root are present * in the sub-complex. */ - void add_edge(Root_vertex_handle v1_root, Root_vertex_handle v2_root) { + void add_edge_without_blockers(Root_vertex_handle v1_root, Root_vertex_handle v2_root) { auto v1_sub(this->get_address(v1_root)); auto v2_sub(this->get_address(v2_root)); assert(v1_sub && v2_sub); - this->ComplexType::add_edge(*v1_sub, *v2_sub); + this->ComplexType::add_edge_without_blockers(*v1_sub, *v2_sub); } /** @@ -139,7 +124,7 @@ class Skeleton_blocker_sub_complex : public ComplexType { void add_blocker(const Root_simplex_handle& blocker_root) { auto blocker_sub = this->get_address(blocker_root); assert(blocker_sub); - this->add_blocker(new Simplex_handle(*blocker_sub)); + this->add_blocker(new Simplex(*blocker_sub)); } public: @@ -148,7 +133,7 @@ class Skeleton_blocker_sub_complex : public ComplexType { * vertices of 'simplex'. */ void make_restricted_complex(const ComplexType & parent_complex, - const Simplex_handle& simplex) { + const Simplex& simplex) { this->clear(); // add vertices to the sub complex for (auto x : simplex) { @@ -160,11 +145,11 @@ class Skeleton_blocker_sub_complex : public ComplexType { // add edges to the sub complex for (auto x : simplex) { // x_neigh is the neighbor of x intersected with vertices_simplex - Simplex_handle x_neigh; + Simplex x_neigh; parent_complex.add_neighbours(x, x_neigh, true); x_neigh.intersection(simplex); for (auto y : x_neigh) { - this->add_edge(parent_complex[x].get_id(), parent_complex[y].get_id()); + this->add_edge_without_blockers(parent_complex[x].get_id(), parent_complex[y].get_id()); } } @@ -173,9 +158,9 @@ class Skeleton_blocker_sub_complex : public ComplexType { // check if it is the first time we encounter the blocker if (simplex.contains(*blocker)) { Root_simplex_handle blocker_root(parent_complex.get_id(*(blocker))); - Simplex_handle blocker_restr( + Simplex blocker_restr( *(this->get_simplex_address(blocker_root))); - this->add_blocker(new Simplex_handle(blocker_restr)); + this->add_blocker(new Simplex(blocker_restr)); } } } @@ -203,7 +188,7 @@ class Skeleton_blocker_sub_complex : public ComplexType { // * Allocates a simplex in L corresponding to the simplex s in K // * with its local adresses and returns an AddressSimplex. // */ - // boost::optional<Simplex_handle> get_address(const Root_simplex_handle & s) const; + // boost::optional<Simplex> get_address(const Root_simplex_handle & s) const; // private: /** @@ -235,7 +220,7 @@ bool proper_face_in_union( // we test that all vertices of 'addresses_sigma_in_link' but 'vertex_to_be_ignored' // are in link1 if it is the case we construct the corresponding simplex bool vertices_sigma_are_in_link = true; - typename ComplexType::Simplex_handle sigma_in_link; + typename ComplexType::Simplex sigma_in_link; for (int i = 0; i < addresses_sigma_in_link.size(); ++i) { if (i != vertex_to_be_ignored) { if (!addresses_sigma_in_link[i]) { @@ -301,5 +286,5 @@ bool proper_faces_in_union( } // namespace Gudhi -#endif // SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SKELETON_BLOCKER_SUB_COMPLEX_H_ +#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_SUB_COMPLEX_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Top_faces.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Top_faces.h index 32538f38..eb970195 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Top_faces.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Top_faces.h @@ -1,67 +1,70 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 TOP_FACES_H_ -#define TOP_FACES_H_ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 SKELETON_BLOCKER_INTERNAL_TOP_FACES_H_ +#define SKELETON_BLOCKER_INTERNAL_TOP_FACES_H_ #include <list> #include <vector> #include <set> +namespace Gudhi { + +namespace skbl { + template<typename SimplexHandle> -std::list<SimplexHandle> subfaces(SimplexHandle top_face){ - std::list<SimplexHandle> res; - if(top_face.dimension()==-1) return res; - if(top_face.dimension()==0) { - res.push_back(top_face); - return res; - } - else{ - auto first_vertex = top_face.first_vertex(); - top_face.remove_vertex(first_vertex); - res = subfaces(top_face); - std::list<SimplexHandle> copy = res; - for(auto& simplex : copy){ - simplex.add_vertex(first_vertex); - } - res.push_back(SimplexHandle(first_vertex)); - res.splice(res.end(),copy); - return res; - } +std::list<SimplexHandle> subfaces(SimplexHandle top_face) { + std::list<SimplexHandle> res; + if (top_face.dimension() == -1) return res; + if (top_face.dimension() == 0) { + res.push_back(top_face); + return res; + } else { + auto first_vertex = top_face.first_vertex(); + top_face.remove_vertex(first_vertex); + res = subfaces(top_face); + std::list<SimplexHandle> copy = res; + for (auto& simplex : copy) { + simplex.add_vertex(first_vertex); + } + res.push_back(SimplexHandle(first_vertex)); + res.splice(res.end(), copy); + return res; + } } /** * add all faces of top_face in simplices_per_dimension */ template<typename SimplexHandle> -void register_faces( - std::vector< std::set<SimplexHandle> >& simplices_per_dimension, - const SimplexHandle& top_face){ - std::list<SimplexHandle> subfaces_list = subfaces(top_face); - for(auto& simplex : subfaces_list ){ - simplices_per_dimension[simplex.dimension()].insert(simplex); - } +void register_faces(std::vector< std::set<SimplexHandle> >& simplices_per_dimension, + const SimplexHandle& top_face) { + std::list<SimplexHandle> subfaces_list = subfaces(top_face); + for (auto& simplex : subfaces_list) { + simplices_per_dimension[simplex.dimension()].insert(simplex); + } } +} // namespace skbl +} // namespace Gudhi - -#endif /* TOP_FACES_H_ */ +#endif // SKELETON_BLOCKER_INTERNAL_TOP_FACES_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Trie.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Trie.h index f2a443dc..499980c4 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Trie.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Trie.h @@ -1,13 +1,10 @@ -/* - * Trie.h - * Created on: Jan 29, 2015 - * This file is part of the Gudhi Library. The Gudhi library +/* 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): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (France) + * 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 @@ -25,8 +22,8 @@ */ -#ifndef TRIE_H_ -#define TRIE_H_ +#ifndef SKELETON_BLOCKER_INTERNAL_TRIE_H_ +#define SKELETON_BLOCKER_INTERNAL_TRIE_H_ #include <memory> #include <vector> @@ -35,242 +32,237 @@ namespace Gudhi { - namespace skbl { - template<typename SimplexHandle> -struct Trie{ - typedef SimplexHandle Simplex_handle; - typedef typename SimplexHandle::Vertex_handle Vertex_handle; - - Vertex_handle v; - std::vector<std::shared_ptr<Trie> > childs; - //std::vector<std::unique_ptr<Trie> > childs; -> use of deleted function -private: - const Trie* parent_; -public: - Trie():parent_(0){} - Trie(Vertex_handle v_):v(v_),parent_(0){} - - Trie(Vertex_handle v_,Trie* parent):v(v_),parent_(parent){} - - - bool operator==(const Trie& other) const{ - return (v == other.v) ; - } - - void add_child(Trie* child){ - if(child){ - std::shared_ptr<Trie> ptr_to_add(child); - childs.push_back(ptr_to_add); - child->parent_ = this; - } - } - - typedef typename Simplex_handle::Simplex_vertex_const_iterator Simplex_vertex_const_iterator; - - - Trie* make_trie(Simplex_vertex_const_iterator s_it,Simplex_vertex_const_iterator s_end){ - if(s_it == s_end) return 0; - else{ - Trie* res = new Trie(*s_it); - Trie* child = make_trie(++s_it,s_end); - res->add_child(child); - return res; - } - } -private: - //go down recursively in the tree while advancing the simplex iterator. - //when it reaches a leaf, it inserts the remaining that is not present - void add_simplex_helper(Simplex_vertex_const_iterator s_it,Simplex_vertex_const_iterator s_end){ - assert(*s_it == v); - ++s_it; - if(s_it==s_end) return ; - if(!is_leaf()){ - for(auto child : childs){ - if(child->v == *s_it) - return child->add_simplex_helper(s_it,s_end); - } - //s_it is not found and needs to be inserted - } - //not leaf -> remaining of s needs to be inserted - Trie* son_with_what_remains_of_s(make_trie(s_it,s_end)); - add_child(son_with_what_remains_of_s); - return; - } - - void maximal_faces_helper(std::vector<Simplex_handle>& res) const{ - if(is_leaf()) res.push_back(simplex()); - else - for(auto child : childs) - child->maximal_faces_helper(res); - } - -public: - /** - * adds the simplex to the trie - */ - void add_simplex(const Simplex_handle& s){ - if(s.empty()) return; - assert(v==s.first_vertex()); - add_simplex_helper(s.begin(),s.end()); - } - - std::vector<Simplex_handle> maximal_faces() const{ - std::vector<Simplex_handle> res; - maximal_faces_helper(res); - return res; - } - - /** - * Goes to the root in the trie to consitute simplex - */ - void add_vertices_up_to_the_root(Simplex_handle& res) const{ - res.add_vertex(v); - if(parent_) - parent_->add_vertices_up_to_the_root(res); - } - - Simplex_handle simplex() const{ - Simplex_handle res; - add_vertices_up_to_the_root(res); - return res; - } - - bool is_leaf() const{ - return childs.empty(); - } - - bool is_root() const{ - return parent_==0; - } - - const Trie* parent() { - return parent_; - } - - void remove_leaf() { - assert(is_leaf); - if(!is_root()) - parent_->childs.erase(this); - } - - /** - * true iff the simplex corresponds to one node in the trie - */ - bool contains(const Simplex_handle& s) const{ - Trie const* current = this; - if(s.empty()) return true; - if(current->v != s.first_vertex()) return false; - auto s_pos = s.begin(); - ++s_pos; - while(s_pos != s.end() && current != 0){ - bool found = false; - for(const auto child : current->childs){ - if(child->v == *s_pos) { - ++s_pos; - current = child.get(); - found = true; - break; - } - } - if(!found) return false; - } - return current!=0; - } - - Trie* go_bottom_left(){ - if(is_leaf()) - return this; - else - return (*childs.begin())->go_bottom_left(); - } - - friend std::ostream& operator<<(std::ostream& stream, const Trie& trie){ - stream<< "T( "<< trie.v<< " "; - for(auto t : trie.childs) - stream << *t ; - stream<<")"; - return stream; - } +struct Trie { + typedef SimplexHandle Simplex; + typedef typename SimplexHandle::Vertex_handle Vertex_handle; + + Vertex_handle v; + std::vector<std::shared_ptr<Trie> > childs; + // std::vector<std::unique_ptr<Trie> > childs; -> use of deleted function + private: + const Trie* parent_; + + public: + Trie() : parent_(0) { } + + Trie(Vertex_handle v_) : v(v_), parent_(0) { } + + Trie(Vertex_handle v_, Trie* parent) : v(v_), parent_(parent) { } + + bool operator==(const Trie& other) const { + return (v == other.v); + } + + void add_child(Trie* child) { + if (child) { + std::shared_ptr<Trie> ptr_to_add(child); + childs.push_back(ptr_to_add); + child->parent_ = this; + } + } + + typedef typename Simplex::Simplex_vertex_const_iterator Simplex_vertex_const_iterator; + + Trie* make_trie(Simplex_vertex_const_iterator s_it, Simplex_vertex_const_iterator s_end) { + if (s_it == s_end) { + return 0; + } else { + Trie* res = new Trie(*s_it); + Trie* child = make_trie(++s_it, s_end); + res->add_child(child); + return res; + } + } + + private: + // go down recursively in the tree while advancing the simplex iterator. + // when it reaches a leaf, it inserts the remaining that is not present + void add_simplex_helper(Simplex_vertex_const_iterator s_it, Simplex_vertex_const_iterator s_end) { + assert(*s_it == v); + ++s_it; + if (s_it == s_end) return; + if (!is_leaf()) { + for (auto child : childs) { + if (child->v == *s_it) + return child->add_simplex_helper(s_it, s_end); + } + // s_it is not found and needs to be inserted + } + // not leaf -> remaining of s needs to be inserted + Trie * son_with_what_remains_of_s(make_trie(s_it, s_end)); + add_child(son_with_what_remains_of_s); + return; + } + + void maximal_faces_helper(std::vector<Simplex>& res) const { + if (is_leaf()) res.push_back(simplex()); + else + for (auto child : childs) + child->maximal_faces_helper(res); + } + + public: + /** + * adds the simplex to the trie + */ + void add_simplex(const Simplex& s) { + if (s.empty()) return; + assert(v == s.first_vertex()); + add_simplex_helper(s.begin(), s.end()); + } + + std::vector<Simplex> maximal_faces() const { + std::vector<Simplex> res; + maximal_faces_helper(res); + return res; + } + + /** + * Goes to the root in the trie to consitute simplex + */ + void add_vertices_up_to_the_root(Simplex& res) const { + res.add_vertex(v); + if (parent_) + parent_->add_vertices_up_to_the_root(res); + } + + Simplex simplex() const { + Simplex res; + add_vertices_up_to_the_root(res); + return res; + } + + bool is_leaf() const { + return childs.empty(); + } + + bool is_root() const { + return parent_ == 0; + } + + const Trie* parent() { + return parent_; + } + + void remove_leaf() { + assert(is_leaf); + if (!is_root()) + parent_->childs.erase(this); + } + + /** + * true iff the simplex corresponds to one node in the trie + */ + bool contains(const Simplex& s) const { + Trie const* current = this; + if (s.empty()) return true; + if (current->v != s.first_vertex()) return false; + auto s_pos = s.begin(); + ++s_pos; + while (s_pos != s.end() && current != 0) { + bool found = false; + for (const auto child : current->childs) { + if (child->v == *s_pos) { + ++s_pos; + current = child.get(); + found = true; + break; + } + } + if (!found) return false; + } + return current != 0; + } + + Trie* go_bottom_left() { + if (is_leaf()) + return this; + else + return (*childs.begin())->go_bottom_left(); + } + + friend std::ostream& operator<<(std::ostream& stream, const Trie& trie) { + stream << "T( " << trie.v << " "; + for (auto t : trie.childs) + stream << *t; + stream << ")"; + return stream; + } }; - template<typename SimplexHandle> -struct Tries{ - typedef typename SimplexHandle::Vertex_handle Vertex_handle; - typedef SimplexHandle Simplex_handle; - - typedef Trie<Simplex_handle> STrie; - - - template<typename SimpleHandleOutputIterator> - Tries(unsigned num_vertices,SimpleHandleOutputIterator simplex_begin, SimpleHandleOutputIterator simplex_end): - cofaces_(num_vertices,0){ - for (auto i = 0u; i < num_vertices; ++i) - cofaces_[i] = new STrie(Vertex_handle(i)); - for (auto s_it = simplex_begin; s_it != simplex_end; ++s_it) { - if (s_it->dimension() >= 1) - cofaces_[s_it->first_vertex()]->add_simplex(*s_it); - } - } - - ~Tries(){ - for(STrie* t : cofaces_) - delete t; - } - - //return a simplex that consists in all u such uv is an edge and u>v - Simplex_handle positive_neighbors(Vertex_handle v) const{ - Simplex_handle res; - for(auto child : cofaces_[v]->childs) - res.add_vertex(child->v); - return res; - } - - bool contains(const Simplex_handle& s) const{ - auto first_v = s.first_vertex(); - return cofaces_[first_v]->contains(s); - } - - friend std::ostream& operator<<(std::ostream& stream, const Tries& tries){ - for(auto trie : tries.cofaces_) - stream<<*trie<<std::endl; - return stream; - } - - //init_next_dimension must be called first - std::vector<Simplex_handle> next_dimension_simplices() const{ - std::vector<Simplex_handle> res; - while(!to_see_.empty() && to_see_.front()->simplex().dimension()==current_dimension_){ - res.emplace_back(to_see_.front()->simplex()); - for(auto child : to_see_.front()->childs) - to_see_.push_back(child.get()); - to_see_.pop_front(); - } - ++current_dimension_; - return res; - } - - void init_next_dimension() const{ - for(auto trie : cofaces_) - to_see_.push_back(trie); - } - -private: - mutable std::deque<STrie*> to_see_; - mutable unsigned current_dimension_=0; - - - std::vector<STrie*> cofaces_; - +struct Tries { + typedef typename SimplexHandle::Vertex_handle Vertex_handle; + typedef SimplexHandle Simplex; + + typedef Trie<Simplex> STrie; + + template<typename SimpleHandleOutputIterator> + Tries(unsigned num_vertices, SimpleHandleOutputIterator simplex_begin, SimpleHandleOutputIterator simplex_end) : + cofaces_(num_vertices, 0) { + for (auto i = 0u; i < num_vertices; ++i) + cofaces_[i] = new STrie(Vertex_handle(i)); + for (auto s_it = simplex_begin; s_it != simplex_end; ++s_it) { + if (s_it->dimension() >= 1) + cofaces_[s_it->first_vertex()]->add_simplex(*s_it); + } + } + + ~Tries() { + for (STrie* t : cofaces_) + delete t; + } + + // return a simplex that consists in all u such uv is an edge and u>v + + Simplex positive_neighbors(Vertex_handle v) const { + Simplex res; + for (auto child : cofaces_[v]->childs) + res.add_vertex(child->v); + return res; + } + + bool contains(const Simplex& s) const { + auto first_v = s.first_vertex(); + return cofaces_[first_v]->contains(s); + } + + friend std::ostream& operator<<(std::ostream& stream, const Tries& tries) { + for (auto trie : tries.cofaces_) + stream << *trie << std::endl; + return stream; + } + + // init_next_dimension must be called first + + std::vector<Simplex> next_dimension_simplices() const { + std::vector<Simplex> res; + while (!to_see_.empty() && to_see_.front()->simplex().dimension() == current_dimension_) { + res.emplace_back(to_see_.front()->simplex()); + for (auto child : to_see_.front()->childs) + to_see_.push_back(child.get()); + to_see_.pop_front(); + } + ++current_dimension_; + return res; + } + + void init_next_dimension() const { + for (auto trie : cofaces_) + to_see_.push_back(trie); + } + + private: + mutable std::deque<STrie*> to_see_; + mutable unsigned current_dimension_ = 0; + std::vector<STrie*> cofaces_; }; +} // namespace skbl +} // namespace Gudhi -} - -} - -#endif /* TRIE_H_ */ +#endif // SKELETON_BLOCKER_INTERNAL_TRIE_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h index f6f2c955..4a437ac6 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h @@ -1,134 +1,131 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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_SKELETON_BLOCKERS_BLOCKERS_ITERATORS_H_ -#define GUDHI_SKELETON_BLOCKERS_BLOCKERS_ITERATORS_H_ - -#include "boost/iterator/iterator_facade.hpp" - -namespace Gudhi{ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_BLOCKERS_ITERATORS_H_ +#define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_BLOCKERS_ITERATORS_H_ + +#include <boost/iterator/iterator_facade.hpp> + +namespace Gudhi { namespace skbl { /** * @brief Iterator through the blockers of a vertex. - */ -// ReturnType = const Simplex_handle* or Simplex_handle* + */ +// ReturnType = const Simplex* or Simplex* // MapIteratorType = BlockerMapConstIterator or BlockerMapIterator + template<typename MapIteratorType, typename ReturnType> class Blocker_iterator_internal : public boost::iterator_facade< - Blocker_iterator_internal<MapIteratorType,ReturnType>, - ReturnType, - boost::forward_traversal_tag, - ReturnType - >{ -private: - MapIteratorType current_position; - MapIteratorType end_of_map; -public: - - Blocker_iterator_internal():current_position(){} - - Blocker_iterator_internal(MapIteratorType position,MapIteratorType end_of_map_ ): - current_position(position), end_of_map(end_of_map_) - { } - - bool equal(const Blocker_iterator_internal& other) const{ - return current_position == other.current_position; - } - - void increment(){ - goto_next_blocker(); - } - - ReturnType dereference() const { - return(current_position->second); - } - -private: - /** - * Let the current pair be (v,sigma) where v is a vertex and sigma is a blocker. - * If v is not the first vertex of sigma then we already have seen sigma as a blocker - * and we look for the next one. - */ - void goto_next_blocker(){ - do { - ++current_position; - } while (!(current_position == end_of_map) && !first_time_blocker_is_seen()); - } - - bool first_time_blocker_is_seen() const{ - return current_position->first == current_position->second->first_vertex(); - } +Blocker_iterator_internal<MapIteratorType, ReturnType>, +ReturnType, +boost::forward_traversal_tag, +ReturnType +> { + private: + MapIteratorType current_position; + MapIteratorType end_of_map; + + public: + Blocker_iterator_internal() : current_position() { } + + Blocker_iterator_internal(MapIteratorType position, MapIteratorType end_of_map_) : + current_position(position), end_of_map(end_of_map_) { } + + bool equal(const Blocker_iterator_internal& other) const { + return current_position == other.current_position; + } + + void increment() { + goto_next_blocker(); + } + + ReturnType dereference() const { + return (current_position->second); + } + + private: + /** + * Let the current pair be (v,sigma) where v is a vertex and sigma is a blocker. + * If v is not the first vertex of sigma then we already have seen sigma as a blocker + * and we look for the next one. + */ + void goto_next_blocker() { + do { + ++current_position; + } while (!(current_position == end_of_map) && !first_time_blocker_is_seen()); + } + + bool first_time_blocker_is_seen() const { + return current_position->first == current_position->second->first_vertex(); + } }; - - /** * @brief Iterator through the blockers of a vertex */ -// ReturnType = const Simplex_handle* or Simplex_handle* +// ReturnType = const Simplex* or Simplex* // MapIteratorType = BlockerMapConstIterator or BlockerMapIterator + template<typename MapIteratorType, typename ReturnType> class Blocker_iterator_around_vertex_internal : public boost::iterator_facade< - Blocker_iterator_around_vertex_internal<MapIteratorType,ReturnType>, - ReturnType, - boost::forward_traversal_tag, - ReturnType ->{ -private: - MapIteratorType current_position_; -public: - - Blocker_iterator_around_vertex_internal():current_position_(){} - - Blocker_iterator_around_vertex_internal(MapIteratorType position): - current_position_(position) - {} - - Blocker_iterator_around_vertex_internal& operator=(Blocker_iterator_around_vertex_internal other){ - this->current_position_ = other.current_position_; - return *this; - } - - bool equal(const Blocker_iterator_around_vertex_internal& other) const{ - return current_position_ == other.current_position_; - } - - void increment(){ - current_position_++; - } - - ReturnType dereference() const{ - return(current_position_->second); - } - - - MapIteratorType current_position(){ - return this->current_position_; - } +Blocker_iterator_around_vertex_internal<MapIteratorType, ReturnType>, +ReturnType, +boost::forward_traversal_tag, +ReturnType +> { + private: + MapIteratorType current_position_; + + public: + Blocker_iterator_around_vertex_internal() : current_position_() { } + + Blocker_iterator_around_vertex_internal(MapIteratorType position) : + current_position_(position) { } + + Blocker_iterator_around_vertex_internal& operator=(Blocker_iterator_around_vertex_internal other) { + this->current_position_ = other.current_position_; + return *this; + } + + bool equal(const Blocker_iterator_around_vertex_internal& other) const { + return current_position_ == other.current_position_; + } + + void increment() { + current_position_++; + } + + ReturnType dereference() const { + return (current_position_->second); + } + + MapIteratorType current_position() { + return this->current_position_; + } }; -} +} // namespace skbl -} // namespace GUDHI +} // namespace Gudhi -#endif /* GUDHI_SKELETON_BLOCKERS_BLOCKERS_ITERATORS_H_ */ +#endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_BLOCKERS_ITERATORS_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h index 0be6c74d..ef4c7970 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h @@ -1,167 +1,144 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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_SKELETON_BLOCKERS_ITERATORS_EDGES_H_ -#define GUDHI_SKELETON_BLOCKERS_ITERATORS_EDGES_H_ - -#include "boost/iterator/iterator_facade.hpp" - - -namespace Gudhi{ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_EDGES_ITERATORS_H_ +#define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_EDGES_ITERATORS_H_ + +#include <boost/iterator/iterator_facade.hpp> +#include <boost/graph/adjacency_list.hpp> + +#include <utility> // for pair<> + +namespace Gudhi { namespace skbl { template<typename SkeletonBlockerComplex> -class Edge_around_vertex_iterator : - public boost::iterator_facade < Edge_around_vertex_iterator<SkeletonBlockerComplex> - , typename SkeletonBlockerComplex::Edge_handle const - , boost::forward_traversal_tag - , typename SkeletonBlockerComplex::Edge_handle const - > -{ - friend class boost::iterator_core_access; - - typedef SkeletonBlockerComplex Complex; - typedef typename Complex::boost_adjacency_iterator boost_adjacency_iterator; - typedef typename Complex::Vertex_handle Vertex_handle; - typedef typename Complex::Edge_handle Edge_handle; - -private: - - const Complex* complex; - Vertex_handle v; - - boost_adjacency_iterator current_; - boost_adjacency_iterator end_; - -public: - - Edge_around_vertex_iterator():complex(NULL){ - } - - Edge_around_vertex_iterator(const Complex* complex_,Vertex_handle v_): - complex(complex_), - v(v_) - { - tie(current_,end_) = adjacent_vertices(v.vertex, complex->skeleton); - } - - /** - * returns an iterator to the end - */ - Edge_around_vertex_iterator(const Complex* complex_,Vertex_handle v_,int end): - complex(complex_), - v(v_) - { - tie(current_,end_) = adjacent_vertices(v.vertex, complex->skeleton); - set_end(); - } - - bool equal(const Edge_around_vertex_iterator& other) const{ - return (complex== other.complex) && (v == other.v) && (current_ == other.current_) && (end_ == other.end_); - } - - void increment(){ - if(current_ != end_) - ++current_; - } - - Edge_handle dereference() const{ - return *(*complex)[std::make_pair(v,static_cast<Vertex_handle>(*current_))]; - } - -private: - //remove this ugly hack - void set_end(){ - current_ = end_; - } +class Edge_around_vertex_iterator : public boost::iterator_facade <Edge_around_vertex_iterator<SkeletonBlockerComplex> +, typename SkeletonBlockerComplex::Edge_handle const, boost::forward_traversal_tag +, typename SkeletonBlockerComplex::Edge_handle const> { + friend class boost::iterator_core_access; + + typedef SkeletonBlockerComplex Complex; + typedef typename Complex::boost_adjacency_iterator boost_adjacency_iterator; + typedef typename Complex::Vertex_handle Vertex_handle; + typedef typename Complex::Edge_handle Edge_handle; + + private: + const Complex* complex; + Vertex_handle v; + + boost_adjacency_iterator current_; + boost_adjacency_iterator end_; + + public: + Edge_around_vertex_iterator() : complex(NULL) { } + + Edge_around_vertex_iterator(const Complex* complex_, Vertex_handle v_) : + complex(complex_), + v(v_) { + tie(current_, end_) = adjacent_vertices(v.vertex, complex->skeleton); + } + + /** + * returns an iterator to the end + */ + Edge_around_vertex_iterator(const Complex* complex_, Vertex_handle v_, int end) : + complex(complex_), + v(v_) { + tie(current_, end_) = adjacent_vertices(v.vertex, complex->skeleton); + set_end(); + } + + bool equal(const Edge_around_vertex_iterator& other) const { + return (complex == other.complex) && (v == other.v) && (current_ == other.current_) && (end_ == other.end_); + } + + void increment() { + if (current_ != end_) + ++current_; + } + + Edge_handle dereference() const { + return *(*complex)[std::make_pair(v, static_cast<Vertex_handle> (*current_))]; + } + + private: + // remove this ugly hack + void set_end() { + current_ = end_; + } }; - - /** *@brief Iterator on the edges of a simplicial complex. * */ template<typename SkeletonBlockerComplex> -class Edge_iterator : -public boost::iterator_facade < Edge_iterator<SkeletonBlockerComplex> +class Edge_iterator : public boost::iterator_facade <Edge_iterator<SkeletonBlockerComplex> , typename SkeletonBlockerComplex::Edge_handle const , boost::forward_traversal_tag -, typename SkeletonBlockerComplex::Edge_handle const -> - -{ - friend class boost::iterator_core_access; -public: - typedef SkeletonBlockerComplex Complex; - typedef typename Complex::boost_edge_iterator boost_edge_iterator; - typedef typename Complex::Edge_handle Edge_handle; - - - const Complex* complex; - std::pair<boost_edge_iterator,boost_edge_iterator> edge_iterator ; - - Edge_iterator():complex(NULL){ - } - - Edge_iterator(const SkeletonBlockerComplex* complex_): - complex(complex_), - edge_iterator(boost::edges(complex_->skeleton)) - { - } - - /** - * return an iterator to the end - */ - Edge_iterator(const SkeletonBlockerComplex* complex_,int end): - complex(complex_), - edge_iterator(boost::edges(complex_->skeleton)) - { - edge_iterator.first = edge_iterator.second; - } - - - bool equal(const Edge_iterator& other) const{ - return (complex == other.complex) && (edge_iterator == other.edge_iterator); - } - - void increment(){ - if(edge_iterator.first != edge_iterator.second){ - ++(edge_iterator.first); - } - } - - Edge_handle dereference() const{ - return(*(edge_iterator.first)); - } +, typename SkeletonBlockerComplex::Edge_handle const> { + friend class boost::iterator_core_access; + + public: + typedef SkeletonBlockerComplex Complex; + typedef typename Complex::boost_edge_iterator boost_edge_iterator; + typedef typename Complex::Edge_handle Edge_handle; + + const Complex* complex; + std::pair<boost_edge_iterator, boost_edge_iterator> edge_iterator; + + Edge_iterator() : complex(NULL) { } + + Edge_iterator(const SkeletonBlockerComplex* complex_) : + complex(complex_), + edge_iterator(boost::edges(complex_->skeleton)) { } + + /** + * return an iterator to the end + */ + Edge_iterator(const SkeletonBlockerComplex* complex_, int end) : + complex(complex_), + edge_iterator(boost::edges(complex_->skeleton)) { + edge_iterator.first = edge_iterator.second; + } + + bool equal(const Edge_iterator& other) const { + return (complex == other.complex) && (edge_iterator == other.edge_iterator); + } + + void increment() { + if (edge_iterator.first != edge_iterator.second) { + ++(edge_iterator.first); + } + } + + Edge_handle dereference() const { + return (*(edge_iterator.first)); + } }; +} // namespace skbl +} // namespace Gudhi -} - -} // namespace GUDHI - - -#endif /* GUDHI_SKELETON_BLOCKERS_ITERATORS_EDGES_H_ */ - - +#endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_EDGES_ITERATORS_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h index 20a94734..cc3ed276 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h @@ -19,17 +19,14 @@ * 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_SKELETON_BLOCKERS_ITERATORS_H_ -#define GUDHI_SKELETON_BLOCKERS_ITERATORS_H_ +#ifndef SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_ITERATORS_H_ +#define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_ITERATORS_H_ -#include "Skeleton_blockers_vertices_iterators.h" -#include "Skeleton_blockers_edges_iterators.h" -#include "Skeleton_blockers_blockers_iterators.h" -#include "Skeleton_blockers_triangles_iterators.h" -#include "Skeleton_blockers_simplices_iterators.h" +#include <gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h> +#include <gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h> +#include <gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h> +#include <gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h> +#include <gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h> - - - -#endif /* GUDHI_SKELETON_BLOCKERS_ITERATORS_H_ */ +#endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_ITERATORS_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h index 666ce430..ce565166 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h @@ -1,46 +1,42 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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_KELETON_BLOCKERS_SIMPLICES_ITERATORS_H_ -#define GUDHI_SKELETON_BLOCKERS_SIMPLICES_ITERATORS_H_ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_SIMPLICES_ITERATORS_H_ +#define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_SIMPLICES_ITERATORS_H_ + +#include <gudhi/Skeleton_blocker_link_complex.h> +#include <gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h> +#include <gudhi/Skeleton_blocker/internal/Trie.h> +#include <gudhi/Utils.h> + +#include <boost/iterator/iterator_facade.hpp> #include <memory> #include <list> #include <iostream> -#include "gudhi/Utils.h" -#include "boost/iterator/iterator_facade.hpp" - - -#include "gudhi/Skeleton_blocker_link_complex.h" -#include "gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h" - -#include "gudhi/Skeleton_blocker/internal/Trie.h" - namespace Gudhi { - namespace skbl { - /** * Link may be Skeleton_blocker_link_complex<SkeletonBlockerComplex> to iterate over all * simplices around a vertex OR @@ -49,299 +45,354 @@ namespace skbl { * The iteration is done by computing a trie with the link and doing a breadth-first traversal * of the trie. */ -template<typename SkeletonBlockerComplex,typename Link> +template<typename SkeletonBlockerComplex, typename Link> class Simplex_around_vertex_iterator : - public boost::iterator_facade < Simplex_around_vertex_iterator<SkeletonBlockerComplex,Link> -, typename SkeletonBlockerComplex::Simplex_handle +public boost::iterator_facade < Simplex_around_vertex_iterator<SkeletonBlockerComplex, Link> +, typename SkeletonBlockerComplex::Simplex , boost::forward_traversal_tag -, typename SkeletonBlockerComplex::Simplex_handle -> -{ - friend class boost::iterator_core_access; - typedef SkeletonBlockerComplex Complex; - typedef typename Complex::Vertex_handle Vertex_handle; - typedef typename Complex::Edge_handle Edge_handle; - typedef typename Complex::Simplex_handle Simplex_handle; - - - typedef typename Link::Vertex_handle Link_vertex_handle; - // Link_vertex_handle == Complex_Vertex_handle but this renaming helps avoiding confusion - - typedef typename Gudhi::skbl::Trie<Simplex_handle> Trie; - - -private: - const Complex* complex; - Vertex_handle v; - std::shared_ptr<Link> link_v; - std::shared_ptr<Trie> trie; - std::list<Trie*> nodes_to_be_seen; // todo deque - -public: - Simplex_around_vertex_iterator():complex(0){ - } - - Simplex_around_vertex_iterator(const Complex* complex_,Vertex_handle v_): - complex(complex_), - v(v_), - link_v(new Link(*complex_,v_)), - trie(new Trie(v_)){ - compute_trie_and_nodes_to_be_seen(); - } - - // todo avoid useless copy - // todo currently just work if copy begin iterator - Simplex_around_vertex_iterator(const Simplex_around_vertex_iterator& other): - complex(other.complex), - v(other.v), - link_v(other.link_v), - trie(other.trie), - nodes_to_be_seen(other.nodes_to_be_seen){ - if(!other.is_end()){ - } - } - - /** - * returns an iterator to the end - */ - Simplex_around_vertex_iterator(const Complex* complex_,Vertex_handle v_,bool end): - complex(complex_), - v(v_){ - set_end(); - } - -private: - - - void compute_trie_and_nodes_to_be_seen(){ - // once we go through every simplices passing through v0 - // we remove v0. That way, it prevents from passing a lot of times - // though edges leaving v0. - // another solution would have been to provides an adjacency iterator - // to superior vertices that avoids lower ones. - while(!link_v->empty()){ - auto v0 = *(link_v->vertex_range().begin()); - trie->add_child(build_trie(v0,trie.get())); - link_v->remove_vertex(v0); - } - nodes_to_be_seen.push_back(trie.get()); - } - - Trie* build_trie(Link_vertex_handle link_vh,Trie* parent){ - Trie* res = new Trie(parent_vertex(link_vh),parent); - for(Link_vertex_handle nv : link_v->vertex_range(link_vh)) { - if(link_vh < nv){ - Simplex_handle simplex_node_plus_nv(res->simplex()); - simplex_node_plus_nv.add_vertex(parent_vertex(nv)); - if(complex->contains(simplex_node_plus_nv)){ - res->add_child(build_trie(nv,res)); - } - } - } - return res; - } - - bool is_node_in_complex(Trie* trie){ - return true; - } - - Vertex_handle parent_vertex(Link_vertex_handle link_vh) const{ - return complex->convert_handle_from_another_complex(*link_v,link_vh); - } - - - -public: - - friend std::ostream& operator<<(std::ostream& stream, const Simplex_around_vertex_iterator& savi){ - stream<< savi.trie<< std::endl; ; - stream << "("<<savi.nodes_to_be_seen.size()<<") nodes to see\n"; - return stream; - } - - bool equal(const Simplex_around_vertex_iterator& other) const{ - bool same_complex = (complex == other.complex); - if(!same_complex) - return false; - - if(!(v == other.v)) - return false; - - bool both_empty = nodes_to_be_seen.empty() && other.nodes_to_be_seen.empty(); - if(both_empty) - return true; - - bool both_non_empty = !nodes_to_be_seen.empty() && !other.nodes_to_be_seen.empty(); - - if(!both_non_empty) return false; //one is empty the other is not - - bool same_node = (**(nodes_to_be_seen.begin()) == **(other.nodes_to_be_seen.begin())); - return same_node; - } - - void increment(){ - assert(!is_end()); - Trie* first_node = nodes_to_be_seen.front(); - - nodes_to_be_seen.pop_front(); - - for(auto childs : first_node->childs){ - nodes_to_be_seen.push_back(childs.get()); - } - - } - - Simplex_handle dereference() const{ - assert(!nodes_to_be_seen.empty()); - Trie* first_node = nodes_to_be_seen.front(); - return first_node->simplex(); - } - -//private: - Simplex_handle get_trie_address() const{ - assert(!nodes_to_be_seen.empty()); - return nodes_to_be_seen.front(); - } - -private: - void set_end(){ - nodes_to_be_seen.clear(); - } - - bool is_end() const{ - return nodes_to_be_seen.empty(); - } +, typename SkeletonBlockerComplex::Simplex +> { + friend class boost::iterator_core_access; + typedef SkeletonBlockerComplex Complex; + typedef typename Complex::Vertex_handle Vertex_handle; + typedef typename Complex::Edge_handle Edge_handle; + typedef typename Complex::Simplex Simplex; + + // Link_vertex_handle == Complex_Vertex_handle but this renaming helps avoiding confusion + typedef typename Link::Vertex_handle Link_vertex_handle; + + typedef typename Gudhi::skbl::Trie<Simplex> Trie; + + private: + const Complex* complex; + Vertex_handle v; + std::shared_ptr<Link> link_v; + std::shared_ptr<Trie> trie; + std::list<Trie*> nodes_to_be_seen; // todo deque + + public: + Simplex_around_vertex_iterator() : complex(0) {} + + Simplex_around_vertex_iterator(const Complex* complex_, Vertex_handle v_) : + complex(complex_), + v(v_), + link_v(new Link(*complex_, v_)), + trie(new Trie(v_)) { + compute_trie_and_nodes_to_be_seen(); + } + + // todo avoid useless copy + // todo currently just work if copy begin iterator + Simplex_around_vertex_iterator(const Simplex_around_vertex_iterator& other) : + complex(other.complex), + v(other.v), + link_v(other.link_v), + trie(other.trie), + nodes_to_be_seen(other.nodes_to_be_seen) { + if (!other.is_end()) {} + } + + /** + * returns an iterator to the end + */ + Simplex_around_vertex_iterator(const Complex* complex_, Vertex_handle v_, bool end) : + complex(complex_), + v(v_) { + set_end(); + } + + private: + void compute_trie_and_nodes_to_be_seen() { + // once we go through every simplices passing through v0 + // we remove v0. That way, it prevents from passing a lot of times + // though edges leaving v0. + // another solution would have been to provides an adjacency iterator + // to superior vertices that avoids lower ones. + while (!link_v->empty()) { + auto v0 = *(link_v->vertex_range().begin()); + trie->add_child(build_trie(v0, trie.get())); + link_v->remove_vertex(v0); + } + nodes_to_be_seen.push_back(trie.get()); + } + + Trie* build_trie(Link_vertex_handle link_vh, Trie* parent) { + Trie* res = new Trie(parent_vertex(link_vh), parent); + for (Link_vertex_handle nv : link_v->vertex_range(link_vh)) { + if (link_vh < nv) { + Simplex simplex_node_plus_nv(res->simplex()); + simplex_node_plus_nv.add_vertex(parent_vertex(nv)); + if (complex->contains(simplex_node_plus_nv)) { + res->add_child(build_trie(nv, res)); + } + } + } + return res; + } + + bool is_node_in_complex(Trie* trie) { + return true; + } + + Vertex_handle parent_vertex(Link_vertex_handle link_vh) const { + return complex->convert_handle_from_another_complex(*link_v, link_vh); + } + + public: + friend std::ostream& operator<<(std::ostream& stream, const Simplex_around_vertex_iterator& savi) { + stream << savi.trie << std::endl; + stream << "(" << savi.nodes_to_be_seen.size() << ") nodes to see\n"; + return stream; + } + + bool equal(const Simplex_around_vertex_iterator& other) const { + bool same_complex = (complex == other.complex); + if (!same_complex) + return false; + + if (!(v == other.v)) + return false; + + bool both_empty = nodes_to_be_seen.empty() && other.nodes_to_be_seen.empty(); + if (both_empty) + return true; + + bool both_non_empty = !nodes_to_be_seen.empty() && !other.nodes_to_be_seen.empty(); + + if (!both_non_empty) return false; // one is empty the other is not + + bool same_node = (**(nodes_to_be_seen.begin()) == **(other.nodes_to_be_seen.begin())); + return same_node; + } + + void increment() { + assert(!is_end()); + Trie* first_node = nodes_to_be_seen.front(); + + nodes_to_be_seen.pop_front(); + + for (auto childs : first_node->childs) { + nodes_to_be_seen.push_back(childs.get()); + } + } + + Simplex dereference() const { + assert(!nodes_to_be_seen.empty()); + Trie* first_node = nodes_to_be_seen.front(); + return first_node->simplex(); + } + + Simplex get_trie_address() const { + assert(!nodes_to_be_seen.empty()); + return nodes_to_be_seen.front(); + } + + private: + void set_end() { + nodes_to_be_seen.clear(); + } + + bool is_end() const { + return nodes_to_be_seen.empty(); + } }; - - template<typename SkeletonBlockerComplex> class Simplex_iterator : - public boost::iterator_facade < Simplex_iterator<SkeletonBlockerComplex> -, typename SkeletonBlockerComplex::Simplex_handle +public boost::iterator_facade < Simplex_iterator<SkeletonBlockerComplex> +, typename SkeletonBlockerComplex::Simplex , boost::forward_traversal_tag -, typename SkeletonBlockerComplex::Simplex_handle -> -{ - typedef Skeleton_blocker_link_superior<SkeletonBlockerComplex> Link; - - friend class boost::iterator_core_access; - - template<class SkBlDS> friend class Skeleton_blocker_complex; - - - typedef SkeletonBlockerComplex Complex; - typedef typename Complex::Vertex_handle Vertex_handle; - typedef typename Complex::Edge_handle Edge_handle; - typedef typename Complex::Simplex_handle Simplex_handle; - - typedef typename Complex::Complex_vertex_iterator Complex_vertex_iterator; - - - typedef typename Link::Vertex_handle Link_vertex_handle; - -private: - - const Complex* complex_; - Complex_vertex_iterator current_vertex_; - - typedef Simplex_around_vertex_iterator<SkeletonBlockerComplex,Link> SAVI; - SAVI current_simplex_around_current_vertex_; - SAVI simplices_around_current_vertex_end_; - - -public: - Simplex_iterator():complex_(0){} - - // should not be called if the complex is empty - Simplex_iterator(const Complex* complex): - complex_(complex), - current_vertex_(complex->vertex_range().begin()), - current_simplex_around_current_vertex_(complex,*current_vertex_), - simplices_around_current_vertex_end_(complex,*current_vertex_,true) - { - assert(!complex->empty()); - } +, typename SkeletonBlockerComplex::Simplex +> { + typedef Skeleton_blocker_link_superior<SkeletonBlockerComplex> Link; + + friend class boost::iterator_core_access; + + template<class SkBlDS> friend class Skeleton_blocker_complex; + + typedef SkeletonBlockerComplex Complex; + typedef typename Complex::Vertex_handle Vertex_handle; + typedef typename Complex::Edge_handle Edge_handle; + typedef typename Complex::Simplex Simplex; + typedef typename Complex::Complex_vertex_iterator Complex_vertex_iterator; + typedef typename Link::Vertex_handle Link_vertex_handle; + + private: + const Complex* complex_; + Complex_vertex_iterator current_vertex_; + + typedef Simplex_around_vertex_iterator<SkeletonBlockerComplex, Link> SAVI; + SAVI current_simplex_around_current_vertex_; + SAVI simplices_around_current_vertex_end_; + + public: + Simplex_iterator() : complex_(0) { } + + Simplex_iterator(const Complex* complex) : + complex_(complex), + current_vertex_(complex->vertex_range().begin()), + current_simplex_around_current_vertex_(complex, *current_vertex_), + simplices_around_current_vertex_end_(complex, *current_vertex_, true) { + // should not be called if the complex is empty + assert(!complex->empty()); + } + + private: + // todo return to private + Simplex_iterator(const Complex* complex, bool end) : + complex_(complex) { + set_end(); + } + + public: + Simplex_iterator(const Simplex_iterator& other) + : + complex_(other.complex_), + current_vertex_(other.current_vertex_), + current_simplex_around_current_vertex_(other.current_simplex_around_current_vertex_), + simplices_around_current_vertex_end_(other.simplices_around_current_vertex_end_) { } + + friend Simplex_iterator make_begin_iterator(const Complex* complex) { + if (complex->empty()) + return make_end_simplex_iterator(complex); + else + return Simplex_iterator(complex); + } + + friend Simplex_iterator make_end_simplex_iterator(const Complex* complex) { + return Simplex_iterator(complex, true); + } + + bool equal(const Simplex_iterator& other) const { + if (complex_ != other.complex_) return false; + if (current_vertex_ != other.current_vertex_) return false; + if (is_end() && other.is_end()) return true; + if (current_simplex_around_current_vertex_ != other.current_simplex_around_current_vertex_) + return false; + return true; + } + + void increment() { + if (current_simplex_around_current_vertex_ != simplices_around_current_vertex_end_) { + current_simplex_around_current_vertex_.increment(); + if (current_simplex_around_current_vertex_ == simplices_around_current_vertex_end_) + goto_next_vertex(); + } else { + goto_next_vertex(); + } + } + + void goto_next_vertex() { + current_vertex_.increment(); + if (!is_end()) { + current_simplex_around_current_vertex_ = SAVI(complex_, *current_vertex_); + simplices_around_current_vertex_end_ = SAVI(complex_, *current_vertex_, true); + } + } + + Simplex dereference() const { + return current_simplex_around_current_vertex_.dereference(); + } + + private: + void set_end() { + current_vertex_ = complex_->vertex_range().end(); + } + + bool is_end() const { + return (current_vertex_ == complex_->vertex_range().end()); + } +}; -private: - // todo return to private - Simplex_iterator(const Complex* complex,bool end): - complex_(complex) - { - set_end(); - } +/** + * Iterator through the maximal faces of the coboundary of a simplex. + */ +template<typename SkeletonBlockerComplex, typename Link> +class Simplex_coboundary_iterator : +public boost::iterator_facade < Simplex_coboundary_iterator<SkeletonBlockerComplex, Link> +, typename SkeletonBlockerComplex::Simplex, boost::forward_traversal_tag, typename SkeletonBlockerComplex::Simplex> { + friend class boost::iterator_core_access; + typedef SkeletonBlockerComplex Complex; + typedef typename Complex::Vertex_handle Vertex_handle; + typedef typename Complex::Edge_handle Edge_handle; + typedef typename Complex::Simplex Simplex; + typedef typename Complex::Complex_vertex_iterator Complex_vertex_iterator; + + // Link_vertex_handle == Complex_Vertex_handle but this renaming helps avoiding confusion + typedef typename Link::Vertex_handle Link_vertex_handle; + + private: + const Complex* complex; + const Simplex& sigma; + std::shared_ptr<Link> link; + Complex_vertex_iterator current_vertex; + Complex_vertex_iterator link_vertex_end; + + public: + Simplex_coboundary_iterator() : complex(0) {} + + Simplex_coboundary_iterator(const Complex* complex_, const Simplex& sigma_) : + complex(complex_), + sigma(sigma_), + //need only vertices of the link hence the true flag + link(new Link(*complex_, sigma_, false, true)) { + auto link_vertex_range = link->vertex_range(); + current_vertex = link_vertex_range.begin(); + link_vertex_end = link_vertex_range.end(); + } + + Simplex_coboundary_iterator(const Simplex_coboundary_iterator& other) : + complex(other.complex), + sigma(other.sigma), + link(other.link), + current_vertex(other.current_vertex), + link_vertex_end(other.link_vertex_end) { } + + // returns an iterator to the end + Simplex_coboundary_iterator(const Complex* complex_,const Simplex& sigma_, bool end) : + complex(complex_), + sigma(sigma_) { + // to represent an end iterator without having to build a useless link, we use + // the convection that link is not initialized. + } + + private: + Vertex_handle parent_vertex(Link_vertex_handle link_vh) const { + return complex->convert_handle_from_another_complex(*link, link_vh); + } public: - - Simplex_iterator(const Simplex_iterator& other) - : - complex_(other.complex_), - current_vertex_(other.current_vertex_), - current_simplex_around_current_vertex_(other.current_simplex_around_current_vertex_), - simplices_around_current_vertex_end_(other.simplices_around_current_vertex_end_) - { - } - - friend Simplex_iterator make_begin_iterator(const Complex* complex){ - if(complex->empty()) - return make_end_simplex_iterator(complex); - else - return Simplex_iterator(complex); - } - - friend Simplex_iterator make_end_simplex_iterator(const Complex* complex){ - return Simplex_iterator(complex,true); - } - - bool equal(const Simplex_iterator& other) const{ - if(complex_!=other.complex_) return false; - if(current_vertex_!=other.current_vertex_) return false; - if(is_end() && other.is_end()) return true; - if(current_simplex_around_current_vertex_ != other.current_simplex_around_current_vertex_) - return false; - return true; - } - - void increment(){ - if(current_simplex_around_current_vertex_!= simplices_around_current_vertex_end_){ - current_simplex_around_current_vertex_.increment(); - if( current_simplex_around_current_vertex_== simplices_around_current_vertex_end_) - goto_next_vertex(); - } - else{ - goto_next_vertex(); - } - } - - void goto_next_vertex(){ - current_vertex_.increment(); - if(!is_end()){ - current_simplex_around_current_vertex_= SAVI(complex_,*current_vertex_); - simplices_around_current_vertex_end_ = SAVI(complex_,*current_vertex_,true); - } - } - - Simplex_handle dereference() const{ - return current_simplex_around_current_vertex_.dereference(); - } + friend std::ostream& operator<<(std::ostream& stream, const Simplex_coboundary_iterator& sci) { + return stream; + } + + // assume that iterator points to the same complex and comes from the same simplex + bool equal(const Simplex_coboundary_iterator& other) const { + assert(complex == other.complex && sigma == other.sigma); + if(is_end()) return other.is_end(); + if(other.is_end()) return is_end(); + return *current_vertex == *(other.current_vertex); + } + + void increment() { + ++current_vertex; + } + + Simplex dereference() const { + Simplex res(sigma); + res.add_vertex(parent_vertex(*current_vertex)); + return res; + } private: - void set_end(){ - current_vertex_ = complex_->vertex_range().end(); - } - - bool is_end() const{ - return (current_vertex_ == complex_->vertex_range().end()); - } + bool is_end() const { + return !link || current_vertex == link_vertex_end; + } }; -} - -} // namespace GUDHI - - - +} // namespace skbl +} // namespace Gudhi -#endif /* SKELETON_BLOCKERS_SIMPLICES_ITERATORS_H_ */ +#endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_SIMPLICES_ITERATORS_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h index e137d1ea..116023d7 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h @@ -1,117 +1,108 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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_SKELETON_BLOCKERS_TRIANGLES_ITERATORS_H_ -#define GUDHI_SKELETON_BLOCKERS_TRIANGLES_ITERATORS_H_ - -#include "boost/iterator/iterator_facade.hpp" +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_TRIANGLES_ITERATORS_H_ +#define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_TRIANGLES_ITERATORS_H_ + +#include <boost/iterator/iterator_facade.hpp> #include <memory> -namespace Gudhi{ +namespace Gudhi { namespace skbl { -////////////////////////////////////////////////////////////////////// /** * \brief Iterator over the triangles that are * adjacent to a vertex of the simplicial complex. * \remark Will be removed soon -> dont look */ -template<typename Complex,typename LinkType> +template<typename Complex, typename LinkType> class Triangle_around_vertex_iterator : public boost::iterator_facade -< Triangle_around_vertex_iterator <Complex,LinkType> -, typename Complex::Simplex_handle const +< Triangle_around_vertex_iterator <Complex, LinkType> +, typename Complex::Simplex const , boost::forward_traversal_tag -, typename Complex::Simplex_handle const -> -{ - friend class boost::iterator_core_access; - template<typename T> friend class Triangle_iterator; -private: - typedef typename LinkType::Vertex_handle Vertex_handle; - typedef typename LinkType::Root_vertex_handle Root_vertex_handle; - typedef typename LinkType::Simplex_handle Simplex_handle; - typedef typename Complex::Complex_edge_iterator Complex_edge_iterator_; - - const Complex* complex_; - Vertex_handle v_; - std::shared_ptr<LinkType> link_; - Complex_edge_iterator_ current_edge_; - bool is_end_; -public: - Triangle_around_vertex_iterator(const Complex* complex,Vertex_handle v): - complex_(complex),v_(v),link_(new LinkType(*complex,v_)), - current_edge_(link_->edge_range().begin()), - is_end_(current_edge_ == link_->edge_range().end()){ - } - - /** - * @brief ugly hack to get an iterator to the end - */ - Triangle_around_vertex_iterator(const Complex* complex,Vertex_handle v,bool is_end): - complex_(complex),v_(v),link_(0),is_end_(true){ - } - - /** - * @brief ugly hack to get an iterator to the end - */ - Triangle_around_vertex_iterator(): - complex_(0),v_(-1),link_(0),is_end_(true){ - } - - - Triangle_around_vertex_iterator(const Triangle_around_vertex_iterator& other){ - v_ = other.v_; - complex_ = other.complex_; - is_end_ = other.is_end_; - - if(!is_end_){ - link_ = other.link_; - current_edge_= other.current_edge_; - } - } - - bool equal(const Triangle_around_vertex_iterator& other) const{ - return (complex_==other.complex_) && ((finished() &&other.finished()) || current_edge_ == other.current_edge_); - } - - Simplex_handle dereference() const{ - Root_vertex_handle v1 = (*link_)[*current_edge_].first(); - Root_vertex_handle v2 = (*link_)[*current_edge_].second(); - return Simplex_handle(v_,*(complex_->get_address(v1)),*(complex_->get_address(v2))); - } - - void increment(){ - ++current_edge_; - } - -private: - bool finished() const{ - return is_end_ || (current_edge_ == link_->edge_range().end()); - } - +, typename Complex::Simplex const> { + friend class boost::iterator_core_access; + template<typename T> friend class Triangle_iterator; + private: + typedef typename LinkType::Vertex_handle Vertex_handle; + typedef typename LinkType::Root_vertex_handle Root_vertex_handle; + typedef typename LinkType::Simplex Simplex; + typedef typename Complex::Complex_edge_iterator Complex_edge_iterator_; + + const Complex* complex_; + Vertex_handle v_; + std::shared_ptr<LinkType> link_; + Complex_edge_iterator_ current_edge_; + bool is_end_; + + public: + Triangle_around_vertex_iterator(const Complex* complex, Vertex_handle v) : + complex_(complex), v_(v), link_(new LinkType(*complex, v_)), + current_edge_(link_->edge_range().begin()), + is_end_(current_edge_ == link_->edge_range().end()) { } + + /** + * @brief ugly hack to get an iterator to the end + */ + Triangle_around_vertex_iterator(const Complex* complex, Vertex_handle v, bool is_end) : + complex_(complex), v_(v), link_(0), is_end_(true) { } + + /** + * @brief ugly hack to get an iterator to the end + */ + Triangle_around_vertex_iterator() : + complex_(0), v_(-1), link_(0), is_end_(true) { } + + Triangle_around_vertex_iterator(const Triangle_around_vertex_iterator& other) { + v_ = other.v_; + complex_ = other.complex_; + is_end_ = other.is_end_; + + if (!is_end_) { + link_ = other.link_; + current_edge_ = other.current_edge_; + } + } + + bool equal(const Triangle_around_vertex_iterator& other) const { + return (complex_ == other.complex_) && ((finished() && other.finished()) || current_edge_ == other.current_edge_); + } + + Simplex dereference() const { + Root_vertex_handle v1 = (*link_)[*current_edge_].first(); + Root_vertex_handle v2 = (*link_)[*current_edge_].second(); + return Simplex(v_, *(complex_->get_address(v1)), *(complex_->get_address(v2))); + } + + void increment() { + ++current_edge_; + } + + private: + bool finished() const { + return is_end_ || (current_edge_ == link_->edge_range().end()); + } }; - - /** * \brief Iterator over the triangles of the * simplicial complex. @@ -119,121 +110,111 @@ private: * */ template<typename SkeletonBlockerComplex> -class Triangle_iterator : - public boost::iterator_facade< - Triangle_iterator <SkeletonBlockerComplex>, - typename SkeletonBlockerComplex::Simplex_handle const - , boost::forward_traversal_tag - , typename SkeletonBlockerComplex::Simplex_handle const - > -{ - friend class boost::iterator_core_access; -private: - typedef typename SkeletonBlockerComplex::Vertex_handle Vertex_handle; - typedef typename SkeletonBlockerComplex::Root_vertex_handle Root_vertex_handle; - typedef typename SkeletonBlockerComplex::Simplex_handle Simplex_handle; - typedef typename SkeletonBlockerComplex::Superior_triangle_around_vertex_iterator STAVI; - typedef typename SkeletonBlockerComplex::Complex_vertex_iterator Complex_vertex_iterator; - - const SkeletonBlockerComplex* complex_; - Complex_vertex_iterator current_vertex_; - STAVI current_triangle_; - bool is_end_; -public: - - /* - * @remark assume that the complex is non-empty - */ - Triangle_iterator(const SkeletonBlockerComplex* complex): - complex_(complex), - current_vertex_(complex->vertex_range().begin()), - current_triangle_(complex,*current_vertex_), // xxx this line is problematic is the complex is empty - is_end_(false){ - - assert(!complex->empty()); - gotoFirstTriangle(); - } - -private: - //goto to the first triangle or to the end if none - void gotoFirstTriangle(){ - if(!is_finished() && current_triangle_.finished()){ - goto_next_vertex(); - } - } -public: - - /** - * @brief ugly hack to get an iterator to the end - * @remark assume that the complex is non-empty - */ - Triangle_iterator(const SkeletonBlockerComplex* complex,bool is_end): - complex_(complex), - current_vertex_(complex->vertex_range().end()), - current_triangle_(), // xxx this line is problematic is the complex is empty - is_end_(true){ - } - - - Triangle_iterator& operator=(const Triangle_iterator & other){ - complex_ = other.complex_; - Complex_vertex_iterator current_vertex_; - STAVI current_triangle_; - return *this; - } - - - bool equal(const Triangle_iterator& other) const{ - bool both_are_finished = is_finished() && other.is_finished(); - bool both_arent_finished = !is_finished() && !other.is_finished(); - // if the two iterators are not finished, they must have the same state - return (complex_==other.complex_) && - (both_are_finished || - ( (both_arent_finished) && current_vertex_ == other.current_vertex_ && current_triangle_ == other.current_triangle_)); - - } - - Simplex_handle dereference() const{ - return *current_triangle_; - } - -private: - - // goto the next vertex that has a triangle pending or the - // end vertex iterator if none exists - void goto_next_vertex(){ - assert(current_triangle_.finished()); //we mush have consume all triangles passing through the vertex - assert(!is_finished()); // we must not be done - - ++current_vertex_; - - if(!is_finished()){ - current_triangle_ = STAVI(complex_, *current_vertex_); - if(current_triangle_.finished()) - goto_next_vertex(); - } - } -public: - void increment(){ - if(!current_triangle_.finished()){ - ++current_triangle_; // problem here - if(current_triangle_.finished()) - goto_next_vertex(); - } - else{ - assert(!is_finished()); - goto_next_vertex(); - } - } - -private: - bool is_finished() const{ - return is_end_ || current_vertex_ == complex_->vertex_range().end(); - } +class Triangle_iterator : public boost::iterator_facade< +Triangle_iterator <SkeletonBlockerComplex>, +typename SkeletonBlockerComplex::Simplex const +, boost::forward_traversal_tag +, typename SkeletonBlockerComplex::Simplex const> { + friend class boost::iterator_core_access; + private: + typedef typename SkeletonBlockerComplex::Vertex_handle Vertex_handle; + typedef typename SkeletonBlockerComplex::Root_vertex_handle Root_vertex_handle; + typedef typename SkeletonBlockerComplex::Simplex Simplex; + typedef typename SkeletonBlockerComplex::Superior_triangle_around_vertex_iterator STAVI; + typedef typename SkeletonBlockerComplex::Complex_vertex_iterator Complex_vertex_iterator; + + const SkeletonBlockerComplex* complex_; + Complex_vertex_iterator current_vertex_; + STAVI current_triangle_; + bool is_end_; + + public: + /* + * @remark assume that the complex is non-empty + */ + Triangle_iterator(const SkeletonBlockerComplex* complex) : + complex_(complex), + current_vertex_(complex->vertex_range().begin()), + current_triangle_(complex, *current_vertex_), // xxx this line is problematic is the complex is empty + is_end_(false) { + assert(!complex->empty()); + gotoFirstTriangle(); + } + + private: + // goto to the first triangle or to the end if none + void gotoFirstTriangle() { + if (!is_finished() && current_triangle_.finished()) { + goto_next_vertex(); + } + } + + public: + /** + * @brief ugly hack to get an iterator to the end + * @remark assume that the complex is non-empty + */ + Triangle_iterator(const SkeletonBlockerComplex* complex, bool is_end) : + complex_(complex), + current_vertex_(complex->vertex_range().end()), + current_triangle_(), // xxx this line is problematic is the complex is empty + is_end_(true) { } + + Triangle_iterator& operator=(const Triangle_iterator & other) { + complex_ = other.complex_; + Complex_vertex_iterator current_vertex_; + STAVI current_triangle_; + return *this; + } + + bool equal(const Triangle_iterator& other) const { + bool both_are_finished = is_finished() && other.is_finished(); + bool both_arent_finished = !is_finished() && !other.is_finished(); + // if the two iterators are not finished, they must have the same state + return (complex_ == other.complex_) && (both_are_finished || ((both_arent_finished) && + current_vertex_ == other.current_vertex_ && current_triangle_ == other.current_triangle_)); + } + + Simplex dereference() const { + return *current_triangle_; + } + + private: + // goto the next vertex that has a triangle pending or the + // end vertex iterator if none exists + void goto_next_vertex() { + assert(current_triangle_.finished()); // we mush have consume all triangles passing through the vertex + assert(!is_finished()); // we must not be done + + ++current_vertex_; + + if (!is_finished()) { + current_triangle_ = STAVI(complex_, *current_vertex_); + if (current_triangle_.finished()) + goto_next_vertex(); + } + } + + public: + void increment() { + if (!current_triangle_.finished()) { + ++current_triangle_; // problem here + if (current_triangle_.finished()) + goto_next_vertex(); + } else { + assert(!is_finished()); + goto_next_vertex(); + } + } + + private: + bool is_finished() const { + return is_end_ || current_vertex_ == complex_->vertex_range().end(); + } }; -} +} // namespace skbl -} // namespace GUDHI +} // namespace Gudhi -#endif /* GUDHI_SKELETON_BLOCKERS_TRIANGLES_ITERATORS_H_ */ +#endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_TRIANGLES_ITERATORS_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h index a9d4e373..14ae136a 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h @@ -1,31 +1,32 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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_SKELETON_BLOCKERS_VERTICES_ITERATORS_H_ -#define GUDHI_SKELETON_BLOCKERS_VERTICES_ITERATORS_H_ - -#include "boost/iterator/iterator_facade.hpp" - - -namespace Gudhi{ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_VERTICES_ITERATORS_H_ +#define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_VERTICES_ITERATORS_H_ + +#include <boost/iterator/iterator_facade.hpp> + +#include <utility> // for pair<> + +namespace Gudhi { namespace skbl { @@ -35,148 +36,137 @@ namespace skbl { *@remark Incrementation increases Vertex_handle. */ template<typename SkeletonBlockerComplex> -class Vertex_iterator : public boost::iterator_facade -< Vertex_iterator <SkeletonBlockerComplex> - , typename SkeletonBlockerComplex::Vertex_handle const - , boost::forward_traversal_tag - , typename SkeletonBlockerComplex::Vertex_handle const - > -{ - friend class boost::iterator_core_access; - - typedef typename SkeletonBlockerComplex::boost_vertex_iterator boost_vertex_iterator; - typedef typename SkeletonBlockerComplex::Vertex_handle Vertex_handle; -private: - const SkeletonBlockerComplex* complex; - std::pair<boost_vertex_iterator,boost_vertex_iterator> vertexIterator; - - -public: - Vertex_iterator():complex(NULL){ - } - - Vertex_iterator(const SkeletonBlockerComplex* complex_): - complex(complex_), - vertexIterator(vertices(complex_->skeleton)){ - if(!finished() && !is_active()) { - goto_next_valid(); - } - } - - /** - * return an iterator to the end. - */ - Vertex_iterator(const SkeletonBlockerComplex* complex_,int end): - complex(complex_),vertexIterator(vertices(complex_->skeleton)){ - vertexIterator.first = vertexIterator.second ; - } - -public: - void increment () {goto_next_valid();} - Vertex_handle dereference() const { - return(Vertex_handle(*(vertexIterator.first))); - } - - bool equal(const Vertex_iterator& other) const{ - return vertexIterator == other.vertexIterator && complex == other.complex; - } - - bool operator<(const Vertex_iterator& other) const{ - return dereference()<other.dereference(); - } - -private: - bool finished() const{ - return vertexIterator.first == vertexIterator.second; - } - - void goto_next_valid(){ - ++vertexIterator.first; - if(!finished() && !is_active()){ - goto_next_valid(); - } - } - - bool is_active() const{ - return ((*complex)[Vertex_handle(*vertexIterator.first)]).is_active(); - } - +class Vertex_iterator : public boost::iterator_facade< Vertex_iterator <SkeletonBlockerComplex> +, typename SkeletonBlockerComplex::Vertex_handle const +, boost::forward_traversal_tag +, typename SkeletonBlockerComplex::Vertex_handle const> { + friend class boost::iterator_core_access; + + typedef typename SkeletonBlockerComplex::boost_vertex_iterator boost_vertex_iterator; + typedef typename SkeletonBlockerComplex::Vertex_handle Vertex_handle; + private: + const SkeletonBlockerComplex* complex; + std::pair<boost_vertex_iterator, boost_vertex_iterator> vertexIterator; + + + public: + Vertex_iterator() : complex(NULL) { } + + Vertex_iterator(const SkeletonBlockerComplex* complex_) : + complex(complex_), + vertexIterator(vertices(complex_->skeleton)) { + if (!finished() && !is_active()) { + goto_next_valid(); + } + } + + /** + * return an iterator to the end. + */ + Vertex_iterator(const SkeletonBlockerComplex* complex_, int end) : + complex(complex_), vertexIterator(vertices(complex_->skeleton)) { + vertexIterator.first = vertexIterator.second; + } + + public: + void increment() { + goto_next_valid(); + } + + Vertex_handle dereference() const { + return (Vertex_handle(*(vertexIterator.first))); + } + + bool equal(const Vertex_iterator& other) const { + return vertexIterator == other.vertexIterator && complex == other.complex; + } + + bool operator<(const Vertex_iterator& other) const { + return dereference() < other.dereference(); + } + + private: + bool finished() const { + return vertexIterator.first == vertexIterator.second; + } + + void goto_next_valid() { + ++vertexIterator.first; + if (!finished() && !is_active()) { + goto_next_valid(); + } + } + + bool is_active() const { + return ((*complex)[Vertex_handle(*vertexIterator.first)]).is_active(); + } }; - - - template<typename SkeletonBlockerComplex> -class Neighbors_vertices_iterator -: public boost::iterator_facade < Neighbors_vertices_iterator<SkeletonBlockerComplex> - , typename SkeletonBlockerComplex::Vertex_handle const - , boost::forward_traversal_tag - , typename SkeletonBlockerComplex::Vertex_handle const - > -{ - friend class boost::iterator_core_access; - - typedef SkeletonBlockerComplex Complex; - typedef typename Complex::boost_adjacency_iterator boost_adjacency_iterator; - typedef typename Complex::Vertex_handle Vertex_handle; - typedef typename Complex::Edge_handle Edge_handle; - -private: - - const Complex* complex; - Vertex_handle v; - - boost_adjacency_iterator current_; - boost_adjacency_iterator end_; - -public: - // boost_adjacency_iterator ai, ai_end; - // for (tie(ai, ai_end) = adjacent_vertices(v.vertex, skeleton); ai != ai_end; ++ai){ - - Neighbors_vertices_iterator():complex(NULL){ - } - - Neighbors_vertices_iterator(const Complex* complex_,Vertex_handle v_): - complex(complex_), - v(v_){ - tie(current_,end_) = adjacent_vertices(v.vertex, complex->skeleton); - } - - /** - * returns an iterator to the end - */ - Neighbors_vertices_iterator(const Complex* complex_,Vertex_handle v_,int end): - complex(complex_), - v(v_){ - tie(current_,end_) = adjacent_vertices(v.vertex, complex->skeleton); - set_end(); - } - - - void increment () { - if(current_ != end_) - ++current_; - } - - Vertex_handle dereference() const { - return(Vertex_handle(*current_)); - } - - bool equal(const Neighbors_vertices_iterator& other) const{ - return (complex== other.complex) && (v == other.v) && (current_ == other.current_) && (end_ == other.end_); - } - -private: - //todo remove this ugly hack - void set_end(){ - current_ = end_; - } +class Neighbors_vertices_iterator: public boost::iterator_facade < Neighbors_vertices_iterator<SkeletonBlockerComplex> +, typename SkeletonBlockerComplex::Vertex_handle const +, boost::forward_traversal_tag +, typename SkeletonBlockerComplex::Vertex_handle const> { + friend class boost::iterator_core_access; + + typedef SkeletonBlockerComplex Complex; + typedef typename Complex::boost_adjacency_iterator boost_adjacency_iterator; + typedef typename Complex::Vertex_handle Vertex_handle; + typedef typename Complex::Edge_handle Edge_handle; + + private: + const Complex* complex; + Vertex_handle v; + + boost_adjacency_iterator current_; + boost_adjacency_iterator end_; + + public: + // boost_adjacency_iterator ai, ai_end; + // for (tie(ai, ai_end) = adjacent_vertices(v.vertex, skeleton); ai != ai_end; ++ai) { + + Neighbors_vertices_iterator() : complex(NULL) { } + + Neighbors_vertices_iterator(const Complex* complex_, Vertex_handle v_) : + complex(complex_), + v(v_) { + tie(current_, end_) = adjacent_vertices(v.vertex, complex->skeleton); + } + + /** + * returns an iterator to the end + */ + Neighbors_vertices_iterator(const Complex* complex_, Vertex_handle v_, int end) : + complex(complex_), + v(v_) { + tie(current_, end_) = adjacent_vertices(v.vertex, complex->skeleton); + set_end(); + } + + void increment() { + if (current_ != end_) + ++current_; + } + + Vertex_handle dereference() const { + return (Vertex_handle(*current_)); + } + + bool equal(const Neighbors_vertices_iterator& other) const { + return (complex == other.complex) && (v == other.v) && (current_ == other.current_) && (end_ == other.end_); + } + + private: + // todo remove this ugly hack + void set_end() { + current_ = end_; + } }; -} +} // namespace skbl -} // namespace GUDHI +} // namespace Gudhi -#endif /* GUDHI_SKELETON_BLOCKERS_VERTICES_ITERATORS_H_ */ +#endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_VERTICES_ITERATORS_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h index 700830f2..5b774f25 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h @@ -20,8 +20,18 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_COMPLEX_H_ -#define SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_COMPLEX_H_ +#ifndef SKELETON_BLOCKER_COMPLEX_H_ +#define SKELETON_BLOCKER_COMPLEX_H_ + +#include <gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h> +#include <gudhi/Skeleton_blocker_link_complex.h> +#include <gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h> +#include <gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h> +#include <gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h> +#include <gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h> +#include <gudhi/Skeleton_blocker/internal/Top_faces.h> +#include <gudhi/Skeleton_blocker/internal/Trie.h> +#include <gudhi/Utils.h> #include <boost/graph/adjacency_list.hpp> #include <boost/graph/connected_components.hpp> @@ -40,18 +50,6 @@ #include <algorithm> #include <utility> -#include "gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h" -#include "gudhi/Skeleton_blocker_link_complex.h" -#include "gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h" -#include "gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h" -#include "gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h" - -#include "gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h" -#include "gudhi/Skeleton_blocker/internal/Top_faces.h" -#include "gudhi/Skeleton_blocker/internal/Trie.h" - -#include "gudhi/Utils.h" - namespace Gudhi { namespace skbl { @@ -94,16 +92,16 @@ class Skeleton_blocker_complex { /** * @brief A ordered set of integers that represents a simplex. */ - typedef Skeleton_blocker_simplex<Vertex_handle> Simplex_handle; + typedef Skeleton_blocker_simplex<Vertex_handle> Simplex; typedef Skeleton_blocker_simplex<Root_vertex_handle> Root_simplex_handle; /** * @brief Handle to a blocker of the complex. */ - typedef Simplex_handle* Blocker_handle; + typedef Simplex* Blocker_handle; typedef typename Root_simplex_handle::Simplex_vertex_const_iterator Root_simplex_iterator; - typedef typename Simplex_handle::Simplex_vertex_const_iterator Simplex_handle_iterator; + typedef typename Simplex::Simplex_vertex_const_iterator Simplex_handle_iterator; protected: typedef typename boost::adjacency_list<boost::setS, // edges @@ -128,14 +126,14 @@ class Skeleton_blocker_complex { typedef typename boost::graph_traits<Graph>::edge_descriptor Edge_handle; protected: - typedef std::multimap<Vertex_handle, Simplex_handle *> BlockerMap; - typedef typename std::multimap<Vertex_handle, Simplex_handle *>::value_type BlockerPair; - typedef typename std::multimap<Vertex_handle, Simplex_handle *>::iterator BlockerMapIterator; - typedef typename std::multimap<Vertex_handle, Simplex_handle *>::const_iterator BlockerMapConstIterator; + typedef std::multimap<Vertex_handle, Simplex *> BlockerMap; + typedef typename std::multimap<Vertex_handle, Simplex *>::value_type BlockerPair; + typedef typename std::multimap<Vertex_handle, Simplex *>::iterator BlockerMapIterator; + typedef typename std::multimap<Vertex_handle, Simplex *>::const_iterator BlockerMapConstIterator; protected: - int num_vertices_; - int num_blockers_; + size_t num_vertices_; + size_t num_blockers_; typedef Skeleton_blocker_complex_visitor<Vertex_handle> Visitor; // typedef Visitor* Visitor_ptr; @@ -164,17 +162,17 @@ class Skeleton_blocker_complex { /** *@brief constructs a simplicial complex with a given number of vertices and a visitor. */ - explicit Skeleton_blocker_complex(int num_vertices_ = 0, Visitor* visitor_ = NULL) + explicit Skeleton_blocker_complex(size_t num_vertices_ = 0, Visitor* visitor_ = NULL) : visitor(visitor_) { clear(); - for (int i = 0; i < num_vertices_; ++i) { + for (size_t i = 0; i < num_vertices_; ++i) { add_vertex(); } } private: // typedef Trie<Skeleton_blocker_complex<SkeletonBlockerDS>> STrie; - typedef Trie<Simplex_handle> STrie; + typedef Trie<Simplex> STrie; public: /** @@ -182,37 +180,41 @@ class Skeleton_blocker_complex { * @details is_flag_complex indicates if the complex is a flag complex or not (to know if blockers have to be computed or not). */ template<typename SimpleHandleOutputIterator> - Skeleton_blocker_complex(SimpleHandleOutputIterator simplex_begin, SimpleHandleOutputIterator simplex_end, + Skeleton_blocker_complex(SimpleHandleOutputIterator simplices_begin, SimpleHandleOutputIterator simplices_end, bool is_flag_complex = false, Visitor* visitor_ = NULL) : num_vertices_(0), num_blockers_(0), visitor(visitor_) { - add_vertex_and_edges(simplex_begin, simplex_end); + add_vertices_and_edges(simplices_begin, simplices_end); if (!is_flag_complex) // need to compute blockers - add_blockers(simplex_begin, simplex_end); + add_blockers(simplices_begin, simplices_end); } private: + /** + * Add vertices and edges of a simplex in one pass + */ template<typename SimpleHandleOutputIterator> - void add_vertex_and_edges(SimpleHandleOutputIterator simplex_begin, SimpleHandleOutputIterator simplex_end) { + void add_vertices_and_edges(SimpleHandleOutputIterator simplices_begin, SimpleHandleOutputIterator simplices_end) { std::vector<std::pair<Vertex_handle, Vertex_handle>> edges; // first pass to add vertices and edges int num_vertex = -1; - for (auto s_it = simplex_begin; s_it != simplex_end; ++s_it) { + for (auto s_it = simplices_begin; s_it != simplices_end; ++s_it) { if (s_it->dimension() == 0) num_vertex = (std::max)(num_vertex, s_it->first_vertex().vertex); if (s_it->dimension() == 1) edges.emplace_back(s_it->first_vertex(), s_it->last_vertex()); } while (num_vertex-- >= 0) add_vertex(); for (const auto& e : edges) - add_edge(e.first, e.second); + add_edge_without_blockers(e.first, e.second); } + template<typename SimpleHandleOutputIterator> - void add_blockers(SimpleHandleOutputIterator simplex_begin, SimpleHandleOutputIterator simplex_end) { - Tries<Simplex_handle> tries(num_vertices(), simplex_begin, simplex_end); + void add_blockers(SimpleHandleOutputIterator simplices_begin, SimpleHandleOutputIterator simplices_end) { + Tries<Simplex> tries(num_vertices(), simplices_begin, simplices_end); tries.init_next_dimension(); auto simplices(tries.next_dimension_simplices()); @@ -221,7 +223,7 @@ class Skeleton_blocker_complex { for (auto& sigma : simplices) { // common_positive_neighbors is the set of vertices u such that // for all s in sigma, us is an edge and u>s - Simplex_handle common_positive_neighbors(tries.positive_neighbors(sigma.last_vertex())); + Simplex common_positive_neighbors(tries.positive_neighbors(sigma.last_vertex())); for (auto sigma_it = sigma.rbegin(); sigma_it != sigma.rend(); ++sigma_it) if (sigma_it != sigma.rbegin()) common_positive_neighbors.intersection(tries.positive_neighbors(*sigma_it)); @@ -378,6 +380,7 @@ class Skeleton_blocker_complex { /** * @brief Adds a vertex to the simplicial complex and returns its Vertex_handle. + * @remark Vertex representation is contiguous. */ Vertex_handle add_vertex() { Vertex_handle address(boost::add_vertex(skeleton)); @@ -427,7 +430,7 @@ class Skeleton_blocker_complex { * @return true iff the simplicial complex contains all vertices * of simplex sigma */ - bool contains_vertices(const Simplex_handle & sigma) const { + bool contains_vertices(const Simplex & sigma) const { for (auto vertex : sigma) if (!contains_vertex(vertex)) return false; @@ -535,41 +538,68 @@ class Skeleton_blocker_complex { * @details it assumes that the edge is present in the complex */ - Simplex_handle get_vertices(Edge_handle edge_handle) const { + Simplex get_vertices(Edge_handle edge_handle) const { auto edge((*this)[edge_handle]); - return Simplex_handle((*this)[edge.first()], (*this)[edge.second()]); + return Simplex((*this)[edge.first()], (*this)[edge.second()]); } /** - * @brief Adds an edge between vertices a and b and all its cofaces. + * @brief Adds an edge between vertices a and b. + * @details For instance, the complex contains edge 01 and 12, then calling + * add_edge with vertex 0 and 2 will create a complex containing + * the edges 01, 12, 20 but not the triangle 012 (and hence this complex + * will contains a blocker 012). */ Edge_handle add_edge(Vertex_handle a, Vertex_handle b) { + // if the edge is already there we musnt go further + // as we may add blockers that should not be here + if (contains_edge(a, b)) + return *((*this)[std::make_pair(a, b)]); + auto res = add_edge_without_blockers(a, b); + add_blockers_after_simplex_insertion(Simplex(a, b)); + return res; + } + + /** + * @brief Adds all edges of s in the complex. + */ + void add_edge(const Simplex& s) { + for (auto i = s.begin(); i != s.end(); ++i) + for (auto j = i; ++j != s.end(); /**/) + add_edge(*i, *j); + } + + /** + * @brief Adds an edge between vertices a and b without blockers. + * @details For instance, the complex contains edge 01 and 12, then calling + * add_edge with vertex 0 and 2 will create a complex containing + * the triangle 012. + */ + Edge_handle add_edge_without_blockers(Vertex_handle a, Vertex_handle b) { assert(contains_vertex(a) && contains_vertex(b)); assert(a != b); auto edge_handle((*this)[std::make_pair(a, b)]); - // std::pair<Edge_handle,bool> pair_descr_bool = (*this)[std::make_pair(a,b)]; - // Edge_handle edge_descr; - // bool edge_present = pair_descr_bool.second; if (!edge_handle) { edge_handle = boost::add_edge(a.vertex, b.vertex, skeleton).first; (*this)[*edge_handle].setId(get_id(a), get_id(b)); degree_[a.vertex]++; degree_[b.vertex]++; if (visitor) - visitor->on_add_edge(a, b); + visitor->on_add_edge_without_blockers(a, b); } return *edge_handle; } + /** - * @brief Adds all edges and their cofaces of a simplex to the simplicial complex. + * @brief Adds all edges of s in the complex without adding blockers. */ - void add_edges(const Simplex_handle & sigma) { - Simplex_handle_iterator i, j; - for (i = sigma.begin(); i != sigma.end(); ++i) - for (j = i, j++; j != sigma.end(); ++j) - add_edge(*i, *j); + void add_edge_without_blockers(Simplex s) { + for (auto i = s.begin(); i != s.end(); ++i) { + for (auto j = i; ++j != s.end(); /**/) + add_edge_without_blockers(*i, *j); + } } /** @@ -627,7 +657,7 @@ class Skeleton_blocker_complex { * @return true iff the simplicial complex contains all vertices * and all edges of simplex sigma */ - bool contains_edges(const Simplex_handle & sigma) const { + bool contains_edges(const Simplex & sigma) const { for (auto i = sigma.begin(); i != sigma.end(); ++i) { if (!contains_vertex(*i)) return false; @@ -649,15 +679,14 @@ class Skeleton_blocker_complex { * @brief Adds the simplex to the set of blockers and * returns a Blocker_handle toward it if was not present before and 0 otherwise. */ - Blocker_handle add_blocker(const Simplex_handle& blocker) { + Blocker_handle add_blocker(const Simplex& blocker) { assert(blocker.dimension() > 1); if (contains_blocker(blocker)) { - // std::cerr << "ATTEMPT TO ADD A BLOCKER ALREADY THERE ---> BLOCKER IGNORED" << endl; return 0; } else { if (visitor) visitor->on_add_blocker(blocker); - Blocker_handle blocker_pt = new Simplex_handle(blocker); + Blocker_handle blocker_pt = new Simplex(blocker); num_blockers_++; auto vertex = blocker_pt->begin(); while (vertex != blocker_pt->end()) { @@ -739,7 +768,7 @@ class Skeleton_blocker_complex { * * @remark contrarily to delete_blockers does not call the destructor */ - void remove_blocker(const Simplex_handle& sigma) { + void remove_blocker(const Simplex& sigma) { assert(contains_blocker(sigma)); for (auto vertex : sigma) remove_blocker(sigma, vertex); @@ -777,7 +806,7 @@ class Skeleton_blocker_complex { /** * @return true iff s is a blocker of the simplicial complex */ - bool contains_blocker(const Simplex_handle & s) const { + bool contains_blocker(const Simplex & s) const { if (s.dimension() < 2) return false; @@ -795,7 +824,7 @@ class Skeleton_blocker_complex { * @return true iff a blocker of the simplicial complex * is a face of sigma. */ - bool blocks(const Simplex_handle & sigma) const { + bool blocks(const Simplex & sigma) const { for (auto s : sigma) for (auto blocker : const_blocker_range(s)) if (sigma.contains(*blocker)) @@ -810,7 +839,7 @@ class Skeleton_blocker_complex { * @details Adds to simplex the neighbours of v e.g. \f$ n \leftarrow n \cup N(v) \f$. * If keep_only_superior is true then only vertices that are greater than v are added. */ - virtual void add_neighbours(Vertex_handle v, Simplex_handle & n, + virtual void add_neighbours(Vertex_handle v, Simplex & n, bool keep_only_superior = false) const { boost_adjacency_iterator ai, ai_end; for (tie(ai, ai_end) = adjacent_vertices(v.vertex, skeleton); ai != ai_end; @@ -833,7 +862,7 @@ class Skeleton_blocker_complex { * todo revoir * */ - virtual void add_neighbours(const Simplex_handle &alpha, Simplex_handle & res, + virtual void add_neighbours(const Simplex &alpha, Simplex & res, bool keep_only_superior = false) const { res.clear(); auto alpha_vertex = alpha.begin(); @@ -848,9 +877,9 @@ class Skeleton_blocker_complex { * not neighbours of v e.g. \f$ res \leftarrow res \cap N(v) \f$. * If 'keep_only_superior' is true then only vertices that are greater than v are keeped. */ - virtual void keep_neighbours(Vertex_handle v, Simplex_handle& res, + virtual void keep_neighbours(Vertex_handle v, Simplex& res, bool keep_only_superior = false) const { - Simplex_handle nv; + Simplex nv; add_neighbours(v, nv, keep_only_superior); res.intersection(nv); } @@ -860,9 +889,9 @@ class Skeleton_blocker_complex { * neighbours of v eg \f$ res \leftarrow res \setminus N(v) \f$. * If 'keep_only_superior' is true then only vertices that are greater than v are added. */ - virtual void remove_neighbours(Vertex_handle v, Simplex_handle & res, + virtual void remove_neighbours(Vertex_handle v, Simplex & res, bool keep_only_superior = false) const { - Simplex_handle nv; + Simplex nv; add_neighbours(v, nv, keep_only_superior); res.difference(nv); } @@ -874,7 +903,7 @@ class Skeleton_blocker_complex { * Constructs the link of 'simplex' with points coordinates. */ Link_complex link(Vertex_handle v) const { - return Link_complex(*this, Simplex_handle(v)); + return Link_complex(*this, Simplex(v)); } /** @@ -887,7 +916,7 @@ class Skeleton_blocker_complex { /** * Constructs the link of 'simplex' with points coordinates. */ - Link_complex link(const Simplex_handle& simplex) const { + Link_complex link(const Simplex& simplex) const { return Link_complex(*this, simplex); } @@ -899,11 +928,11 @@ class Skeleton_blocker_complex { */ // xxx rename get_address et place un using dans sub_complex - boost::optional<Simplex_handle> get_simplex_address( + boost::optional<Simplex> get_simplex_address( const Root_simplex_handle& s) const { - boost::optional<Simplex_handle> res; + boost::optional<Simplex> res; - Simplex_handle s_address; + Simplex s_address; // Root_simplex_const_iterator i; for (auto i = s.begin(); i != s.end(); ++i) { boost::optional<Vertex_handle> address = get_address(*i); @@ -920,7 +949,7 @@ class Skeleton_blocker_complex { * @brief returns a simplex with vertices which are the id of vertices of the * argument. */ - Root_simplex_handle get_id(const Simplex_handle& local_simplex) const { + Root_simplex_handle get_id(const Simplex& local_simplex) const { Root_simplex_handle global_simplex; for (auto x = local_simplex.begin(); x != local_simplex.end(); ++x) { global_simplex.add_vertex(get_id(*x)); @@ -932,7 +961,7 @@ class Skeleton_blocker_complex { * @brief returns true iff the simplex s belongs to the simplicial * complex. */ - virtual bool contains(const Simplex_handle & s) const { + virtual bool contains(const Simplex & s) const { if (s.dimension() == -1) { return false; } else if (s.dimension() == 0) { @@ -972,10 +1001,31 @@ class Skeleton_blocker_complex { return std::distance(triangles.begin(), triangles.end()); } + + /* + * @brief returns the number of simplices of a given dimension in the complex. + */ + size_t num_simplices() const { + auto simplices = complex_simplex_range(); + return std::distance(simplices.begin(), simplices.end()); + } + + /* + * @brief returns the number of simplices of a given dimension in the complex. + */ + size_t num_simplices(unsigned dimension) const { + // TODO(DS): iterator on k-simplices + size_t res = 0; + for (const auto& s : complex_simplex_range()) + if (s.dimension() == dimension) + ++res; + return res; + } + /* * @brief returns the number of blockers in the complex. */ - int num_blockers() const { + size_t num_blockers() const { return num_blockers_; } @@ -1018,7 +1068,7 @@ class Skeleton_blocker_complex { } //@} - /** @Simplification operations + /** @name Simplification operations */ //@{ @@ -1061,7 +1111,7 @@ class Skeleton_blocker_complex { * Furthermore, all simplices tau of the form sigma \setminus simplex_to_be_removed must be added * whenever the dimension of tau is at least 2. */ - void update_blockers_after_remove_star_of_vertex_or_edge(const Simplex_handle& simplex_to_be_removed); + void update_blockers_after_remove_star_of_vertex_or_edge(const Simplex& simplex_to_be_removed); public: /** @@ -1078,31 +1128,33 @@ class Skeleton_blocker_complex { /** * Remove the star of the simplex 'sigma' which needs to belong to the complex */ - void remove_star(const Simplex_handle& sigma); + void remove_star(const Simplex& sigma); /** - * @brief add a maximal simplex plus all its cofaces. - * @details the simplex must have dimension greater than one (otherwise use add_vertex or add_edge). + * @brief add a simplex and all its faces. + * @details the simplex must have dimension greater than one (otherwise use add_vertex or add_edge_without_blockers). */ - void add_simplex(const Simplex_handle& sigma); + void add_simplex(const Simplex& sigma); private: + void add_blockers_after_simplex_insertion(Simplex s); + /** * remove all blockers that contains sigma */ - void remove_blocker_containing_simplex(const Simplex_handle& sigma); + void remove_blocker_containing_simplex(const Simplex& sigma); /** * remove all blockers that contains sigma */ - void remove_blocker_include_in_simplex(const Simplex_handle& sigma); + void remove_blocker_include_in_simplex(const Simplex& sigma); public: enum simplifiable_status { NOT_HOMOTOPY_EQ, MAYBE_HOMOTOPY_EQ, HOMOTOPY_EQ }; - simplifiable_status is_remove_star_homotopy_preserving(const Simplex_handle& simplex) { + simplifiable_status is_remove_star_homotopy_preserving(const Simplex& simplex) { // todo write a virtual method 'link' in Skeleton_blocker_complex which will be overloaded by the current one of // Skeleton_blocker_geometric_complex // then call it there to build the link and return the value of link.is_contractible() @@ -1131,7 +1183,7 @@ class Skeleton_blocker_complex { } //@} - /** @Edge contraction operations + /** @name Edge contraction operations */ //@{ @@ -1174,7 +1226,7 @@ class Skeleton_blocker_complex { * that may be used to construct a new blocker after contracting ab. * It requires that the link condition is satisfied. */ - void tip_blockers(Vertex_handle a, Vertex_handle b, std::vector<Simplex_handle> & buffer) const; + void tip_blockers(Vertex_handle a, Vertex_handle b, std::vector<Simplex> & buffer) const; private: /** @@ -1217,7 +1269,7 @@ class Skeleton_blocker_complex { private: void get_blockers_to_be_added_after_contraction(Vertex_handle a, Vertex_handle b, - std::set<Simplex_handle>& blockers_to_add); + std::set<Simplex>& blockers_to_add); /** * delete all blockers that passes through a or b */ @@ -1358,12 +1410,28 @@ class Skeleton_blocker_complex { /** * @brief Returns a Complex_simplex_around_vertex_range over all the simplices around a vertex of the complex */ - Complex_simplex_around_vertex_range simplex_range(Vertex_handle v) const { + Complex_simplex_around_vertex_range star_simplex_range(Vertex_handle v) const { assert(contains_vertex(v)); return Complex_simplex_around_vertex_range( Complex_simplex_around_vertex_iterator(this, v), Complex_simplex_around_vertex_iterator(this, v, true)); } + typedef Simplex_coboundary_iterator<Skeleton_blocker_complex, Link> Complex_simplex_coboundary_iterator; + + /** + * @brief Range over the simplices of the coboundary of a simplex. + * Methods .begin() and .end() return a Complex_simplex_coboundary_iterator. + */ + typedef boost::iterator_range < Complex_simplex_coboundary_iterator > Complex_coboundary_range; + + /** + * @brief Returns a Complex_simplex_coboundary_iterator over the simplices of the coboundary of a simplex. + */ + Complex_coboundary_range coboundary_range(const Simplex& s) const { + assert(contains(s)); + return Complex_coboundary_range(Complex_simplex_coboundary_iterator(this, s), + Complex_simplex_coboundary_iterator(this, s, true)); + } // typedef Simplex_iterator<Skeleton_blocker_complex,Superior_link> Complex_simplex_iterator; typedef Simplex_iterator<Skeleton_blocker_complex> Complex_simplex_iterator; @@ -1373,7 +1441,7 @@ class Skeleton_blocker_complex { /** * @brief Returns a Complex_simplex_range over all the simplices of the complex */ - Complex_simplex_range simplex_range() const { + Complex_simplex_range complex_simplex_range() const { Complex_simplex_iterator end(this, true); if (empty()) { return Complex_simplex_range(end, end); @@ -1393,7 +1461,7 @@ class Skeleton_blocker_complex { * @brief Iterator over the blockers adjacent to a vertex */ typedef Blocker_iterator_around_vertex_internal< - typename std::multimap<Vertex_handle, Simplex_handle *>::iterator, + typename std::multimap<Vertex_handle, Simplex *>::iterator, Blocker_handle> Complex_blocker_around_vertex_iterator; @@ -1401,12 +1469,13 @@ class Skeleton_blocker_complex { * @brief Iterator over (constant) blockers adjacent to a vertex */ typedef Blocker_iterator_around_vertex_internal< - typename std::multimap<Vertex_handle, Simplex_handle *>::const_iterator, + typename std::multimap<Vertex_handle, Simplex *>::const_iterator, const Blocker_handle> Const_complex_blocker_around_vertex_iterator; typedef boost::iterator_range <Complex_blocker_around_vertex_iterator> Complex_blocker_around_vertex_range; - typedef boost::iterator_range <Const_complex_blocker_around_vertex_iterator> Const_complex_blocker_around_vertex_range; + typedef boost::iterator_range <Const_complex_blocker_around_vertex_iterator> + Const_complex_blocker_around_vertex_range; public: /** @@ -1432,7 +1501,7 @@ class Skeleton_blocker_complex { * @brief Iterator over the blockers. */ typedef Blocker_iterator_internal< - typename std::multimap<Vertex_handle, Simplex_handle *>::iterator, + typename std::multimap<Vertex_handle, Simplex *>::iterator, Blocker_handle> Complex_blocker_iterator; @@ -1440,7 +1509,7 @@ class Skeleton_blocker_complex { * @brief Iterator over the (constant) blockers. */ typedef Blocker_iterator_internal< - typename std::multimap<Vertex_handle, Simplex_handle *>::const_iterator, + typename std::multimap<Vertex_handle, Simplex *>::const_iterator, const Blocker_handle> Const_complex_blocker_iterator; @@ -1514,11 +1583,12 @@ class Skeleton_blocker_complex { * return the total number of simplices */ template<typename Complex, typename SimplexHandleIterator> -Complex make_complex_from_top_faces(SimplexHandleIterator simplex_begin, SimplexHandleIterator simplex_end, +Complex make_complex_from_top_faces(SimplexHandleIterator simplices_begin, SimplexHandleIterator simplices_end, bool is_flag_complex = false) { - typedef typename Complex::Simplex_handle Simplex_handle; - std::vector<Simplex_handle> simplices; - for (auto top_face = simplex_begin; top_face != simplex_end; ++top_face) { + // TODO(DS): use add_simplex instead! should be more efficient and more elegant :) + typedef typename Complex::Simplex Simplex; + std::vector<Simplex> simplices; + for (auto top_face = simplices_begin; top_face != simplices_end; ++top_face) { auto subfaces_topface = subfaces(*top_face); simplices.insert(simplices.end(), subfaces_topface.begin(), subfaces_topface.end()); } @@ -1531,6 +1601,4 @@ Complex make_complex_from_top_faces(SimplexHandleIterator simplex_begin, Simplex #include "Skeleton_blocker_simplifiable_complex.h" - -#endif // SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_COMPLEX_H_ - +#endif // SKELETON_BLOCKER_COMPLEX_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_geometric_complex.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_geometric_complex.h index 437482cb..5c898152 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_geometric_complex.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_geometric_complex.h @@ -19,12 +19,12 @@ * 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 SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_GEOMETRIC_COMPLEX_H_ -#define SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_GEOMETRIC_COMPLEX_H_ +#ifndef SKELETON_BLOCKER_GEOMETRIC_COMPLEX_H_ +#define SKELETON_BLOCKER_GEOMETRIC_COMPLEX_H_ -#include "gudhi/Utils.h" -#include "gudhi/Skeleton_blocker_complex.h" -#include "gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h" +#include <gudhi/Utils.h> +#include <gudhi/Skeleton_blocker_complex.h> +#include <gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h> namespace Gudhi { @@ -46,7 +46,7 @@ public Skeleton_blocker_complex<SkeletonBlockerGeometricDS> { typedef typename SimplifiableSkeletonblocker::Vertex_handle Vertex_handle; typedef typename SimplifiableSkeletonblocker::Root_vertex_handle Root_vertex_handle; typedef typename SimplifiableSkeletonblocker::Edge_handle Edge_handle; - typedef typename SimplifiableSkeletonblocker::Simplex_handle Simplex_handle; + typedef typename SimplifiableSkeletonblocker::Simplex Simplex; typedef typename SimplifiableSkeletonblocker::Graph_vertex Graph_vertex; @@ -79,23 +79,6 @@ public Skeleton_blocker_complex<SkeletonBlockerGeometricDS> { (*this)[Vertex_handle(current++)].point() = Point(point->begin(), point->end()); } - template<typename SimpleHandleOutputIterator, typename PointIterator> - friend Skeleton_blocker_geometric_complex make_complex_from_top_faces( - SimpleHandleOutputIterator simplex_begin, - SimpleHandleOutputIterator simplex_end, - PointIterator points_begin, - PointIterator points_end, - bool is_flag_complex = false) { - Skeleton_blocker_geometric_complex complex; - unsigned current = 0; - complex = - make_complex_from_top_faces<Skeleton_blocker_geometric_complex>(simplex_begin, simplex_end, is_flag_complex); - for (auto point = points_begin; point != points_end; ++point) - // complex.point(Vertex_handle(current++)) = Point(point->begin(),point->end()); - complex.point(Vertex_handle(current++)) = Point(*point); - return complex; - } - /** * @brief Constructor with a list of simplices. * Points of every vertex are the point constructed with default constructor. @@ -157,7 +140,7 @@ public Skeleton_blocker_complex<SkeletonBlockerGeometricDS> { * Constructs the link of 'simplex' with points coordinates. */ Geometric_link link(Vertex_handle v) const { - Geometric_link link(*this, Simplex_handle(v)); + Geometric_link link(*this, Simplex(v)); // we now add the point info add_points_to_link(link); return link; @@ -166,7 +149,7 @@ public Skeleton_blocker_complex<SkeletonBlockerGeometricDS> { /** * Constructs the link of 'simplex' with points coordinates. */ - Geometric_link link(const Simplex_handle& simplex) const { + Geometric_link link(const Simplex& simplex) const { Geometric_link link(*this, simplex); // we now add the point info add_points_to_link(link); @@ -189,13 +172,13 @@ public Skeleton_blocker_complex<SkeletonBlockerGeometricDS> { * Constructs the abstract link of v (without points coordinates). */ Abstract_link abstract_link(Vertex_handle v) const { - return Abstract_link(*this, Simplex_handle(v)); + return Abstract_link(*this, Simplex(v)); } /** * Constructs the link of 'simplex' with points coordinates. */ - Abstract_link abstract_link(const Simplex_handle& simplex) const { + Abstract_link abstract_link(const Simplex& simplex) const { return Abstract_link(*this, simplex); } @@ -215,8 +198,27 @@ public Skeleton_blocker_complex<SkeletonBlockerGeometricDS> { } }; + +template<typename SkeletonBlockerGeometricComplex, typename SimpleHandleOutputIterator, typename PointIterator> +SkeletonBlockerGeometricComplex make_complex_from_top_faces( + SimpleHandleOutputIterator simplex_begin, + SimpleHandleOutputIterator simplex_end, + PointIterator points_begin, + PointIterator points_end, + bool is_flag_complex = false) { + typedef SkeletonBlockerGeometricComplex SBGC; + SkeletonBlockerGeometricComplex complex; + unsigned current = 0; + complex = + make_complex_from_top_faces<SBGC>(simplex_begin, simplex_end, is_flag_complex); + for (auto point = points_begin; point != points_end; ++point) + // complex.point(Vertex_handle(current++)) = Point(point->begin(),point->end()); + complex.point(typename SBGC::Vertex_handle(current++)) = typename SBGC::Point(*point); + return complex; +} + } // namespace skbl } // namespace Gudhi -#endif // SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_GEOMETRIC_COMPLEX_H_ +#endif // SKELETON_BLOCKER_GEOMETRIC_COMPLEX_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_link_complex.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_link_complex.h index 725ecce5..85a6b0b5 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_link_complex.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_link_complex.h @@ -19,11 +19,11 @@ * 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 SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_LINK_COMPLEX_H_ -#define SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_LINK_COMPLEX_H_ +#ifndef SKELETON_BLOCKER_LINK_COMPLEX_H_ +#define SKELETON_BLOCKER_LINK_COMPLEX_H_ -#include "gudhi/Utils.h" -#include "gudhi/Skeleton_blocker_complex.h" +#include <gudhi/Utils.h> +#include <gudhi/Skeleton_blocker_complex.h> namespace Gudhi { @@ -52,12 +52,11 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< typedef typename ComplexType::Vertex_handle Vertex_handle; typedef typename ComplexType::Root_vertex_handle Root_vertex_handle; - typedef typename ComplexType::Simplex_handle Simplex_handle; + typedef typename ComplexType::Simplex Simplex; typedef typename ComplexType::Root_simplex_handle Root_simplex_handle; typedef typename ComplexType::Blocker_handle Blocker_handle; - typedef typename ComplexType::Simplex_handle::Simplex_vertex_const_iterator Simplex_handle_iterator; typedef typename ComplexType::Root_simplex_handle::Simplex_vertex_const_iterator Root_simplex_handle_iterator; explicit Skeleton_blocker_link_complex(bool only_superior_vertices = false) @@ -67,13 +66,15 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< /** * If the parameter only_superior_vertices is true, * only vertices greater than the one of alpha are added. + * Only vertices are computed if only_vertices is true. */ Skeleton_blocker_link_complex(const ComplexType & parent_complex, - const Simplex_handle& alpha_parent_adress, - bool only_superior_vertices = false) + const Simplex& alpha_parent_adress, + bool only_superior_vertices = false, + bool only_vertices = false) : only_superior_vertices_(only_superior_vertices) { if (!alpha_parent_adress.empty()) - build_link(parent_complex, alpha_parent_adress); + build_link(parent_complex, alpha_parent_adress, only_vertices); } /** @@ -84,7 +85,7 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< Vertex_handle a_parent_adress, bool only_superior_vertices = false) : only_superior_vertices_(only_superior_vertices) { - Simplex_handle alpha_simplex(a_parent_adress); + Simplex alpha_simplex(a_parent_adress); build_link(parent_complex, alpha_simplex); } @@ -96,7 +97,7 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< Edge_handle edge, bool only_superior_vertices = false) : only_superior_vertices_(only_superior_vertices) { - Simplex_handle alpha_simplex(parent_complex.first_vertex(edge), + Simplex alpha_simplex(parent_complex.first_vertex(edge), parent_complex.second_vertex(edge)); build_link(parent_complex, alpha_simplex); } @@ -108,7 +109,7 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< * are greater than vertices of alpha_parent_adress are added. */ void compute_link_vertices(const ComplexType & parent_complex, - const Simplex_handle& alpha_parent_adress, + const Simplex& alpha_parent_adress, bool only_superior_vertices, bool is_alpha_blocker = false) { if (alpha_parent_adress.dimension() == 0) { @@ -119,7 +120,7 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< only_superior_vertices_); } else { // we compute the intersection of neighbors of alpha and store it in link_vertices - Simplex_handle link_vertices_parent; + Simplex link_vertices_parent; parent_complex.add_neighbours(alpha_parent_adress, link_vertices_parent, only_superior_vertices); // For all vertex 'v' in this intersection, we go through all its adjacent blockers. @@ -162,13 +163,8 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< } void compute_link_edges(const ComplexType & parent_complex, - const Simplex_handle& alpha_parent_adress, + const Simplex& alpha_parent_adress, bool is_alpha_blocker = false) { - Simplex_handle_iterator y_link, x_parent, y_parent; - // ---------------------------- - // Compute edges in the link - // ------------------------- - if (this->num_vertices() <= 1) return; @@ -194,7 +190,7 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< } } if (new_edge) - this->add_edge(*x_link, *y_link); + this->add_edge_without_blockers(*x_link, *y_link); } } } @@ -217,7 +213,7 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< * the blocker is anticollapsed. */ void compute_link_blockers(const ComplexType & parent_complex, - const Simplex_handle& alpha_parent, + const Simplex& alpha_parent, bool is_alpha_blocker = false) { for (auto x_link : this->vertex_range()) { Vertex_handle x_parent = *this->give_equivalent_vertex(parent_complex, @@ -225,7 +221,7 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< for (auto blocker_parent : parent_complex.const_blocker_range(x_parent)) { if (!is_alpha_blocker || *blocker_parent != alpha_parent) { - Simplex_handle sigma_parent(*blocker_parent); + Simplex sigma_parent(*blocker_parent); sigma_parent.difference(alpha_parent); @@ -239,7 +235,7 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< for (auto a : alpha_parent) { for (auto eta_parent : parent_complex.const_blocker_range(a)) { if (!is_alpha_blocker || *eta_parent != alpha_parent) { - Simplex_handle eta_minus_alpha(*eta_parent); + Simplex eta_minus_alpha(*eta_parent); eta_minus_alpha.difference(alpha_parent); if (eta_minus_alpha != sigma_parent && sigma_parent.contains_difference(*eta_parent, @@ -253,7 +249,7 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< break; } if (is_new_blocker) - this->add_blocker(new Simplex_handle(*sigma_link)); + this->add_blocker(new Simplex(*sigma_link)); } } } @@ -268,14 +264,15 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< * with vertices that are greater than vertices of alpha_parent_adress. */ void build_link(const ComplexType & parent_complex, - const Simplex_handle& alpha_parent_adress, - bool is_alpha_blocker = false) { + const Simplex& alpha_parent_adress, + bool is_alpha_blocker = false, + bool only_vertices = false) { assert(is_alpha_blocker || parent_complex.contains(alpha_parent_adress)); - compute_link_vertices(parent_complex, alpha_parent_adress, - only_superior_vertices_); - compute_link_edges(parent_complex, alpha_parent_adress, is_alpha_blocker); - compute_link_blockers(parent_complex, alpha_parent_adress, - is_alpha_blocker); + compute_link_vertices(parent_complex, alpha_parent_adress, only_superior_vertices_); + if(!only_vertices) { + compute_link_edges(parent_complex, alpha_parent_adress, is_alpha_blocker); + compute_link_blockers(parent_complex, alpha_parent_adress, is_alpha_blocker); + } } /** @@ -284,7 +281,7 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< * removed from the blockers of the complex. */ friend void build_link_of_blocker(const ComplexType & parent_complex, - Simplex_handle& blocker, + Simplex& blocker, Skeleton_blocker_link_complex & result) { assert(blocker.dimension() >= 2); assert(parent_complex.contains_blocker(blocker)); @@ -297,4 +294,4 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< } // namespace Gudhi -#endif // SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_LINK_COMPLEX_H_ +#endif // SKELETON_BLOCKER_LINK_COMPLEX_H_ diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_simplifiable_complex.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_simplifiable_complex.h index dd8d898e..94a125c1 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_simplifiable_complex.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_simplifiable_complex.h @@ -19,15 +19,15 @@ * 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 SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SIMPLIFIABLE_COMPLEX_H_ -#define SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SIMPLIFIABLE_COMPLEX_H_ +#ifndef SKELETON_BLOCKER_SIMPLIFIABLE_COMPLEX_H_ +#define SKELETON_BLOCKER_SIMPLIFIABLE_COMPLEX_H_ + +#include <gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h> #include <list> #include <vector> #include <set> -#include "gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h" - namespace Gudhi { namespace skbl { @@ -45,9 +45,7 @@ bool Skeleton_blocker_complex<SkeletonBlockerDS>::is_popable_blocker(Blocker_han assert(this->contains_blocker(*sigma)); Skeleton_blocker_link_complex<Skeleton_blocker_complex> link_blocker_sigma; build_link_of_blocker(*this, *sigma, link_blocker_sigma); - - bool res = link_blocker_sigma.is_contractible() == CONTRACTIBLE; - return res; + return link_blocker_sigma.is_contractible() == CONTRACTIBLE; } /** @@ -133,7 +131,7 @@ void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_all_popable_blockers(Ve template<typename SkeletonBlockerDS> void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_star(Vertex_handle v) { // we remove the blockers that are not consistent anymore - update_blockers_after_remove_star_of_vertex_or_edge(Simplex_handle(v)); + update_blockers_after_remove_star_of_vertex_or_edge(Simplex(v)); while (this->degree(v) > 0) { Vertex_handle w(* (adjacent_vertices(v.vertex, this->skeleton).first)); this->remove_edge(v, w); @@ -148,7 +146,7 @@ void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_star(Vertex_handle v) { */ template<typename SkeletonBlockerDS> void Skeleton_blocker_complex<SkeletonBlockerDS>::update_blockers_after_remove_star_of_vertex_or_edge( - const Simplex_handle& simplex_to_be_removed) { + const Simplex& simplex_to_be_removed) { std::list <Blocker_handle> blockers_to_update; if (simplex_to_be_removed.empty()) return; @@ -159,7 +157,7 @@ void Skeleton_blocker_complex<SkeletonBlockerDS>::update_blockers_after_remove_s } for (auto blocker_to_update : blockers_to_update) { - Simplex_handle sub_blocker_to_be_added; + Simplex sub_blocker_to_be_added; bool sub_blocker_need_to_be_added = (blocker_to_update->dimension() - simplex_to_be_removed.dimension()) >= 2; if (sub_blocker_need_to_be_added) { @@ -178,7 +176,7 @@ void Skeleton_blocker_complex<SkeletonBlockerDS>::update_blockers_after_remove_s */ template<typename SkeletonBlockerDS> void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_star(Vertex_handle a, Vertex_handle b) { - update_blockers_after_remove_star_of_vertex_or_edge(Simplex_handle(a, b)); + update_blockers_after_remove_star_of_vertex_or_edge(Simplex(a, b)); // we remove the edge this->remove_edge(a, b); } @@ -195,7 +193,7 @@ void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_star(Edge_handle e) { * Remove the star of the simplex 'sigma' which needs to belong to the complex */ template<typename SkeletonBlockerDS> -void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_star(const Simplex_handle& sigma) { +void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_star(const Simplex& sigma) { assert(this->contains(sigma)); if (sigma.dimension() == 0) { remove_star(sigma.first_vertex()); @@ -207,33 +205,41 @@ void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_star(const Simplex_hand } } -/** - * @brief add a maximal simplex plus all its cofaces. - * @details the simplex must have dimension greater than one (otherwise use add_vertex or add_edge). - */ template<typename SkeletonBlockerDS> -void Skeleton_blocker_complex<SkeletonBlockerDS>::add_simplex(const Simplex_handle& sigma) { +void Skeleton_blocker_complex<SkeletonBlockerDS>::add_simplex(const Simplex& sigma) { + // to add a simplex s, all blockers included in s are first removed + // and then all simplex in the coboundary of s are added as blockers assert(!this->contains(sigma)); assert(sigma.dimension() > 1); + if (!contains_vertices(sigma)) { + std::cerr << "add_simplex: Some vertices were not present in the complex, adding them" << std::endl; + size_t num_vertices_to_add = sigma.last_vertex() - this->num_vertices() + 1; + for (size_t i = 0; i < num_vertices_to_add; ++i) + this->add_vertex(); + } + assert(contains_vertices(sigma)); + if (!contains_edges(sigma)) + add_edge(sigma); + remove_blocker_include_in_simplex(sigma); + add_blockers_after_simplex_insertion(sigma); +} - int num_vertex_to_add = 0; - for (auto v : sigma) - if (!contains_vertex(v)) ++num_vertex_to_add; - while (num_vertex_to_add--) add_vertex(); - for (auto u_it = sigma.begin(); u_it != sigma.end(); ++u_it) - for (auto v_it = u_it; ++v_it != sigma.end(); /**/) { - // std::cout << "add edge" << *u_it << " " << *v_it << std::endl; - add_edge(*u_it, *v_it); - } - remove_blocker_include_in_simplex(sigma); + +template<typename SkeletonBlockerDS> +void Skeleton_blocker_complex<SkeletonBlockerDS>::add_blockers_after_simplex_insertion(Simplex sigma) { + if (sigma.dimension() < 1) return; + + for (auto s : coboundary_range(sigma)) { + this->add_blocker(s); + } } /** * remove all blockers that contains sigma */ template<typename SkeletonBlockerDS> -void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_blocker_containing_simplex(const Simplex_handle& sigma) { +void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_blocker_containing_simplex(const Simplex& sigma) { std::vector <Blocker_handle> blockers_to_remove; for (auto blocker : this->blocker_range(sigma.first_vertex())) { if (blocker->contains(sigma)) @@ -247,14 +253,26 @@ void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_blocker_containing_simp * remove all blockers that contains sigma */ template<typename SkeletonBlockerDS> -void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_blocker_include_in_simplex(const Simplex_handle& sigma) { - std::vector <Blocker_handle> blockers_to_remove; - for (auto blocker : this->blocker_range(sigma.first_vertex())) { - if (sigma.contains(*blocker)) - blockers_to_remove.push_back(blocker); +void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_blocker_include_in_simplex(const Simplex& sigma) { + // TODO(DS): write efficiently by using only superior blockers + // eg for all s, check blockers whose vertices are all greater than s + std::set <Blocker_handle> blockers_to_remove; + for (auto s : sigma) { + for (auto blocker : this->blocker_range(s)) { + if (sigma.contains(*blocker)) + blockers_to_remove.insert(blocker); + } } - for (auto blocker_to_update : blockers_to_remove) + for (auto blocker_to_update : blockers_to_remove) { + auto s = *blocker_to_update; this->delete_blocker(blocker_to_update); + // now if there is a vertex v in the link of s + // and v is not included in sigma then v.s is a blocker + // (all faces of v.s are there since v belongs to the link of s) + for (const auto& b : coboundary_range(s)) + if (!sigma.contains(b)) + this->add_blocker(b); + } } /** @@ -264,21 +282,21 @@ void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_blocker_include_in_simp */ template<typename SkeletonBlockerDS> void Skeleton_blocker_complex<SkeletonBlockerDS>::tip_blockers(Vertex_handle a, Vertex_handle b, - std::vector<Simplex_handle> & buffer) const { + std::vector<Simplex> & buffer) const { for (auto const & blocker : this->const_blocker_range(a)) { - Simplex_handle beta = (*blocker); + Simplex beta = (*blocker); beta.remove_vertex(a); buffer.push_back(beta); } - Simplex_handle n; + Simplex n; this->add_neighbours(b, n); this->remove_neighbours(a, n); n.remove_vertex(a); for (Vertex_handle y : n) { - Simplex_handle beta; + Simplex beta; beta.add_vertex(y); buffer.push_back(beta); } @@ -295,7 +313,7 @@ void Skeleton_blocker_complex<SkeletonBlockerDS>::tip_blockers(Vertex_handle a, template<typename SkeletonBlockerDS> void Skeleton_blocker_complex<SkeletonBlockerDS>::swap_edge(Vertex_handle a, Vertex_handle b, Vertex_handle x) { - this->add_edge(a, x); + this->add_edge_without_blockers(a, x); if (this->visitor) this->visitor->on_swaped_edge(a, b, x); this->remove_edge(b, x); } @@ -338,13 +356,15 @@ void Skeleton_blocker_complex<SkeletonBlockerDS>::contract_edge(Vertex_handle a, Vertex_handle b) { assert(this->contains_vertex(a)); assert(this->contains_vertex(b)); - assert(this->contains_edge(a, b)); - // if some blockers passes through 'ab', we remove them. + if (this->contains_edge(a, b)) + this->add_edge_without_blockers(a, b); + + // if some blockers passes through 'ab', we need to remove them. if (!link_condition(a, b)) delete_blockers_around_edge(a, b); - std::set<Simplex_handle> blockers_to_add; + std::set<Simplex> blockers_to_add; get_blockers_to_be_added_after_contraction(a, b, blockers_to_add); @@ -364,9 +384,8 @@ Skeleton_blocker_complex<SkeletonBlockerDS>::contract_edge(Vertex_handle a, Vert } template<typename SkeletonBlockerDS> -void -Skeleton_blocker_complex<SkeletonBlockerDS>::get_blockers_to_be_added_after_contraction(Vertex_handle a, Vertex_handle b, - std::set<Simplex_handle>& blockers_to_add) { +void Skeleton_blocker_complex<SkeletonBlockerDS>::get_blockers_to_be_added_after_contraction(Vertex_handle a, + Vertex_handle b, std::set<Simplex>& blockers_to_add) { blockers_to_add.clear(); typedef Skeleton_blocker_link_complex<Skeleton_blocker_complex<SkeletonBlockerDS> > LinkComplexType; @@ -374,19 +393,19 @@ Skeleton_blocker_complex<SkeletonBlockerDS>::get_blockers_to_be_added_after_cont LinkComplexType link_a(*this, a); LinkComplexType link_b(*this, b); - std::vector<Simplex_handle> vector_alpha, vector_beta; + std::vector<Simplex> vector_alpha, vector_beta; tip_blockers(a, b, vector_alpha); tip_blockers(b, a, vector_beta); for (auto alpha = vector_alpha.begin(); alpha != vector_alpha.end(); ++alpha) { for (auto beta = vector_beta.begin(); beta != vector_beta.end(); ++beta) { - Simplex_handle sigma = *alpha; + Simplex sigma = *alpha; sigma.union_vertices(*beta); Root_simplex_handle sigma_id = this->get_id(sigma); if (this->contains(sigma) && proper_faces_in_union<Skeleton_blocker_complex < SkeletonBlockerDS >> (sigma_id, link_a, link_b)) { - // Blocker_handle blocker = new Simplex_handle(sigma); + // Blocker_handle blocker = new Simplex(sigma); sigma.add_vertex(a); blockers_to_add.insert(sigma); } @@ -444,4 +463,4 @@ Skeleton_blocker_complex<SkeletonBlockerDS>::notify_changed_edges(Vertex_handle } // namespace Gudhi -#endif // SRC_SKELETON_BLOCKER_INCLUDE_GUDHI_SKELETON_BLOCKER_SIMPLIFIABLE_COMPLEX_H_ +#endif // SKELETON_BLOCKER_SIMPLIFIABLE_COMPLEX_H_ diff --git a/src/Skeleton_blocker/test/CMakeLists.txt b/src/Skeleton_blocker/test/CMakeLists.txt index e62600a2..8b6fb672 100644 --- a/src/Skeleton_blocker/test/CMakeLists.txt +++ b/src/Skeleton_blocker/test/CMakeLists.txt @@ -18,6 +18,10 @@ add_executable(TestSkeletonBlockerComplex TestSkeletonBlockerComplex.cpp) add_executable(TestSimplifiable TestSimplifiable.cpp) add_executable(TestGeometricComplex TestGeometricComplex.cpp) +# Do not forget to copy test files in current binary dir +file(COPY "test.off" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) +file(COPY "test2.off" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) + add_test(TestSkeletonBlockerComplex ${CMAKE_CURRENT_BINARY_DIR}/TestSkeletonBlockerComplex) add_test(TestSimplifiable ${CMAKE_CURRENT_BINARY_DIR}/TestSimplifiable) add_test(TestGeometricComplex ${CMAKE_CURRENT_BINARY_DIR}/TestGeometricComplex) diff --git a/src/Skeleton_blocker/test/TestGeometricComplex.cpp b/src/Skeleton_blocker/test/TestGeometricComplex.cpp index bd7af89b..084e2b6b 100644 --- a/src/Skeleton_blocker/test/TestGeometricComplex.cpp +++ b/src/Skeleton_blocker/test/TestGeometricComplex.cpp @@ -1,24 +1,24 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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/>. - */ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 <stdio.h> #include <stdlib.h> @@ -33,8 +33,8 @@ using namespace std; using namespace Gudhi; using namespace skbl; -struct Geometry_trait{ - typedef std::vector<double> Point; +struct Geometry_trait { + typedef std::vector<double> Point; }; typedef Geometry_trait::Point Point; @@ -42,79 +42,77 @@ typedef Skeleton_blocker_simple_geometric_traits<Geometry_trait> Complex_geometr typedef Skeleton_blocker_geometric_complex< Complex_geometric_traits > Complex; typedef Complex::Vertex_handle Vertex_handle; +bool test_constructor1() { + Complex complex; + Skeleton_blocker_off_reader<Complex> off_reader("test2.off", complex); + if (!off_reader.is_valid()) { + std::cerr << "Unable to read file" << std::endl; + return false; + } -bool test_constructor1(){ - Complex complex; - Skeleton_blocker_off_reader<Complex> off_reader("test2.off",complex); - if(!off_reader.is_valid()){ - std::cerr << "Unable to read file"<<std::endl; - return false; - } + std::cout << "complex has " << + complex.num_vertices() << " vertices, " << + complex.num_blockers() << " blockers, " << + complex.num_edges() << " edges and" << + complex.num_triangles() << " triangles."; - std::cout << "complex has "<< - complex.num_vertices()<<" vertices, "<< - complex.num_blockers()<<" blockers, "<< - complex.num_edges()<<" edges and" << - complex.num_triangles()<<" triangles."; + if (complex.num_vertices() != 7 || complex.num_edges() != 12 || complex.num_triangles() != 6) + return false; - if(complex.num_vertices()!=7 || complex.num_edges()!=12 || complex.num_triangles() !=6) - return false; + Skeleton_blocker_off_writer<Complex> off_writer("tmp.off", complex); + Complex same; + Skeleton_blocker_off_reader<Complex> off_reader2("tmp.off", same); - Skeleton_blocker_off_writer<Complex> off_writer("tmp.off",complex); - Complex same; - Skeleton_blocker_off_reader<Complex> off_reader2("tmp.off",same); + std::cout << "\ncomplex:" << complex.to_string() << endl; + std::cout << "\nsame:" << same.to_string() << endl; - std::cout<<"\ncomplex:"<<complex.to_string()<<endl; - std::cout<<"\nsame:"<<same.to_string()<<endl; - - return (complex==same); + return (complex == same); } -bool test_constructor2(){ - Complex complex; - Skeleton_blocker_off_reader<Complex> off_reader("test2.off",complex); - if(!off_reader.is_valid()){ - std::cerr << "Unable to read file"<<std::endl; - return false; - } - std::cout << "complex has "<< - complex.num_vertices()<<" vertices, "<< - complex.num_blockers()<<" blockers, "<< - complex.num_edges()<<" edges and" << - complex.num_triangles()<<" triangles."; +bool test_constructor2() { + Complex complex; + Skeleton_blocker_off_reader<Complex> off_reader("test2.off", complex); + if (!off_reader.is_valid()) { + std::cerr << "Unable to read file" << std::endl; + return false; + } + std::cout << "complex has " << + complex.num_vertices() << " vertices, " << + complex.num_blockers() << " blockers, " << + complex.num_edges() << " edges and" << + complex.num_triangles() << " triangles."; - if(complex.num_vertices()!=7 || complex.num_edges()!=12 || complex.num_triangles() !=6) - return false; + if (complex.num_vertices() != 7 || complex.num_edges() != 12 || complex.num_triangles() != 6) + return false; - auto link_0 = complex.abstract_link(Vertex_handle(0)); + auto link_0 = complex.abstract_link(Vertex_handle(0)); - std::cout<<"\n link(0):"<<link_0.to_string()<<endl; + std::cout << "\n link(0):" << link_0.to_string() << endl; - auto link_geometric_0 = complex.link(Vertex_handle(0)); + auto link_geometric_0 = complex.link(Vertex_handle(0)); - auto print_point = [&](Vertex_handle v){for(auto x : link_geometric_0.point(v)) std::cout <<x<<" "; std::cout<<std::endl;}; + auto print_point = [&](Vertex_handle v) { + for (auto x : link_geometric_0.point(v)) std::cout << x << " "; + std::cout << std::endl; + }; - std::for_each(link_geometric_0.vertex_range().begin(),link_geometric_0.vertex_range().end(),print_point); + std::for_each(link_geometric_0.vertex_range().begin(), link_geometric_0.vertex_range().end(), print_point); -// for(auto v : link_geometric_0.vertex_range()) -// std::cout<<"point("<<v<<"):"<<link_geometric_0.point(v)<<std::endl; + // for(auto v : link_geometric_0.vertex_range()) + // std::cout<<"point("<<v<<"):"<<link_geometric_0.point(v)<<std::endl; - return link_0.num_vertices()==2; + return link_0.num_vertices() == 2; } +int main(int argc, char *argv[]) { + Tests tests_geometric_complex; + tests_geometric_complex.add("Test constructor 1", test_constructor1); + tests_geometric_complex.add("Test constructor 2", test_constructor2); - - -int main (int argc, char *argv[]) -{ - Tests tests_geometric_complex; - tests_geometric_complex.add("Test constructor 1",test_constructor1); - tests_geometric_complex.add("Test constructor 2",test_constructor2); - - if(tests_geometric_complex.run()) - return EXIT_SUCCESS; - else - return EXIT_FAILURE; + if (tests_geometric_complex.run()) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; } diff --git a/src/Skeleton_blocker/test/TestSimplifiable.cpp b/src/Skeleton_blocker/test/TestSimplifiable.cpp index 09176934..b0855ce9 100644 --- a/src/Skeleton_blocker/test/TestSimplifiable.cpp +++ b/src/Skeleton_blocker/test/TestSimplifiable.cpp @@ -1,24 +1,24 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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/>. - */ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 <stdio.h> @@ -41,316 +41,382 @@ template<typename ComplexType> class Skeleton_blocker_sub_complex; typedef Skeleton_blocker_complex<Skeleton_blocker_simple_traits> Complex; typedef Complex::Vertex_handle Vertex_handle; typedef Complex::Root_vertex_handle Root_vertex_handle; -typedef Skeleton_blocker_simplex<Vertex_handle> Simplex_handle; +typedef Skeleton_blocker_simplex<Vertex_handle> Simplex; // true iff v \in complex -bool assert_vertex(Complex &complex,Vertex_handle v){ - Simplex_handle simplex(v); - bool test = complex.contains(simplex); - assert(test); - return test; + +bool assert_vertex(Complex &complex, Vertex_handle v) { + Simplex simplex(v); + bool test = complex.contains(simplex); + assert(test); + return test; } // true iff the blocker (a,b,c) is in complex -bool assert_blocker(Complex &complex,Root_vertex_handle a,Root_vertex_handle b,Root_vertex_handle c){ - return complex.contains_blocker(Simplex_handle(*complex.get_address(a),*complex.get_address(b),*complex.get_address(c))); - //return complex.contains_blocker((a),(b),(c)); +bool assert_blocker(Complex &complex, Root_vertex_handle a, Root_vertex_handle b, Root_vertex_handle c) { + + return complex.contains_blocker(Simplex(*complex.get_address(a), *complex.get_address(b), *complex.get_address(c))); + //return complex.contains_blocker((a),(b),(c)); } -void build_complete(int n,Complex& complex){ - complex.clear(); - for(int i=0;i<n;i++) - complex.add_vertex(); - for(int i=0;i<n;i++) - for(int j=0;j<i;j++) - complex.add_edge(Vertex_handle(i),Vertex_handle(j)); +void build_complete(int n, Complex& complex) { + complex.clear(); + for (int i = 0; i < n; i++) + complex.add_vertex(); + for (int i = 0; i < n; i++) + for (int j = 0; j < i; j++) + complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j)); } -bool test_contraction1(){ - enum { a, b, x, y, z, n }; - Complex complex(n); - build_complete(n,complex); - complex.remove_edge(static_cast<Vertex_handle>(b), static_cast<Vertex_handle>(z)); - complex.add_blocker(Simplex_handle(static_cast<Vertex_handle>(a), static_cast<Vertex_handle>(x), - static_cast<Vertex_handle>(y))); - complex.add_blocker(Simplex_handle(static_cast<Vertex_handle>(b), static_cast<Vertex_handle>(x), - static_cast<Vertex_handle>(y))); - - // Print result - cerr << "complex before complex"<< complex.to_string()<<endl; - - cerr <<endl<<endl; - complex.contract_edge(static_cast<Vertex_handle>(a),static_cast<Vertex_handle>(b)); - // Print result - cerr << "ContractEdge(0,1)\n"; - PRINT(complex.to_string()); - - // verification - for (int i=0;i<5;i++) - if (i!=1) assert_vertex(complex, static_cast<Vertex_handle>(i)); - bool test1 = !complex.contains_edge(static_cast<Vertex_handle>(a),static_cast<Vertex_handle>(b)); - bool test2 = assert_blocker(complex,Root_vertex_handle(a),Root_vertex_handle(x),Root_vertex_handle(y)); - bool test3 = complex.num_edges()==6; - bool test4 = complex.num_blockers()==1; - Simplex_handle sigma; - sigma.add_vertex(static_cast<Vertex_handle>(a)); - sigma.add_vertex(static_cast<Vertex_handle>(x)); - sigma.add_vertex(static_cast<Vertex_handle>(y)); - sigma.add_vertex(static_cast<Vertex_handle>(z)); - bool test5 = !(complex.contains(sigma)); - return test1&&test2&&test3&&test4&&test5; +bool test_contraction1() { + + enum { + a, b, x, y, z, n + }; + Complex complex(n); + build_complete(n, complex); + complex.remove_edge(static_cast<Vertex_handle> (b), static_cast<Vertex_handle> (z)); + complex.add_blocker(Simplex(static_cast<Vertex_handle> (a), static_cast<Vertex_handle> (x), + static_cast<Vertex_handle> (y))); + complex.add_blocker(Simplex(static_cast<Vertex_handle> (b), static_cast<Vertex_handle> (x), + static_cast<Vertex_handle> (y))); + + // Print result + cerr << "complex before complex" << complex.to_string() << endl; + + cerr << endl << endl; + complex.contract_edge(static_cast<Vertex_handle> (a), static_cast<Vertex_handle> (b)); + // Print result + cerr << "ContractEdge(0,1)\n"; + PRINT(complex.to_string()); + + // verification + for (int i = 0; i < 5; i++) + if (i != 1) assert_vertex(complex, static_cast<Vertex_handle> (i)); + bool test1 = !complex.contains_edge(static_cast<Vertex_handle> (a), static_cast<Vertex_handle> (b)); + bool test2 = assert_blocker(complex, Root_vertex_handle(a), Root_vertex_handle(x), Root_vertex_handle(y)); + bool test3 = complex.num_edges() == 6; + bool test4 = complex.num_blockers() == 1; + Simplex sigma; + sigma.add_vertex(static_cast<Vertex_handle> (a)); + sigma.add_vertex(static_cast<Vertex_handle> (x)); + sigma.add_vertex(static_cast<Vertex_handle> (y)); + sigma.add_vertex(static_cast<Vertex_handle> (z)); + bool test5 = !(complex.contains(sigma)); + return test1 && test2 && test3 && test4&&test5; } +bool test_contraction2() { -bool test_contraction2(){ - enum { a, b, x, y, z, n }; - Complex complex(n); - build_complete(n,complex); - complex.remove_edge(static_cast<Vertex_handle>(b),static_cast<Vertex_handle>(x)); - Simplex_handle blocker; - blocker.add_vertex(static_cast<Vertex_handle>(a)); - blocker.add_vertex(static_cast<Vertex_handle>(y)); - blocker.add_vertex(static_cast<Vertex_handle>(z)); + enum { + a, b, x, y, z, n + }; + Complex complex(n); + build_complete(n, complex); + complex.remove_edge(static_cast<Vertex_handle> (b), static_cast<Vertex_handle> (x)); + Simplex blocker; + blocker.add_vertex(static_cast<Vertex_handle> (a)); + blocker.add_vertex(static_cast<Vertex_handle> (y)); + blocker.add_vertex(static_cast<Vertex_handle> (z)); - complex.add_blocker(blocker); + complex.add_blocker(blocker); - // Print result - cerr << "complex complex"<< complex.to_string(); - cerr <<endl<<endl; - complex.contract_edge(static_cast<Vertex_handle>(a),static_cast<Vertex_handle>(b)); + // Print result + cerr << "complex complex" << complex.to_string(); + cerr << endl << endl; + complex.contract_edge(static_cast<Vertex_handle> (a), static_cast<Vertex_handle> (b)); - cerr << "complex.ContractEdge(a,b)"<< complex.to_string(); + cerr << "complex.ContractEdge(a,b)" << complex.to_string(); - cerr <<endl<<endl; + cerr << endl << endl; - // there should be one blocker (a,c,d,e) in the complex - bool test ; - test = complex.contains_blocker(Simplex_handle(static_cast<Vertex_handle>(a), static_cast<Vertex_handle>(x), - static_cast<Vertex_handle>(y),static_cast<Vertex_handle>(z))); - test = test && complex.num_blockers()==1; - return test; + // there should be one blocker (a,c,d,e) in the complex + bool test; + test = complex.contains_blocker(Simplex(static_cast<Vertex_handle> (a), static_cast<Vertex_handle> (x), + static_cast<Vertex_handle> (y), static_cast<Vertex_handle> (z))); + test = test && complex.num_blockers() == 1; + return test; } -bool test_link_condition1(){ +bool test_link_condition1() { - Complex complex(0); - // Build the complexes - build_complete(4,complex); - complex.add_blocker(Simplex_handle(static_cast<Vertex_handle>(0), static_cast<Vertex_handle>(1), static_cast<Vertex_handle>(2))); + Complex complex(0); + // Build the complexes + build_complete(4, complex); + complex.add_blocker(Simplex(static_cast<Vertex_handle> (0), static_cast<Vertex_handle> (1), static_cast<Vertex_handle> (2))); - // Print result - cerr << "complex complex"<< complex.to_string(); - cerr <<endl<<endl; + // Print result + cerr << "complex complex" << complex.to_string(); + cerr << endl << endl; - bool weak_link_condition = complex.link_condition(Vertex_handle(1),Vertex_handle(2),true); + bool weak_link_condition = complex.link_condition(Vertex_handle(1), Vertex_handle(2), true); - bool strong_link_condition = complex.link_condition(Vertex_handle(1),Vertex_handle(2),false); + bool strong_link_condition = complex.link_condition(Vertex_handle(1), Vertex_handle(2), false); - return weak_link_condition && !strong_link_condition; + return weak_link_condition && !strong_link_condition; } - -bool test_collapse0(){ - Complex complex(5); - build_complete(4,complex); - complex.add_vertex(); - complex.add_edge(static_cast<Vertex_handle>(2), static_cast<Vertex_handle>(4)); - complex.add_edge(static_cast<Vertex_handle>(3), static_cast<Vertex_handle>(4)); - // Print result - cerr << "initial complex :\n"<< complex.to_string(); - cerr <<endl<<endl; - - Simplex_handle simplex_123(static_cast<Vertex_handle>(1), static_cast<Vertex_handle>(2), static_cast<Vertex_handle>(3)); - complex.remove_star(simplex_123); - cerr << "complex.remove_star(1,2,3):\n"<< complex.to_string(); - cerr <<endl<<endl; - - // verification - bool blocker123_here = complex.contains_blocker(simplex_123); - cerr <<"----> Ocomplex \n"; - return blocker123_here; +bool test_collapse0() { + Complex complex(5); + build_complete(4, complex); + complex.add_vertex(); + complex.add_edge_without_blockers(static_cast<Vertex_handle> (2), static_cast<Vertex_handle> (4)); + complex.add_edge_without_blockers(static_cast<Vertex_handle> (3), static_cast<Vertex_handle> (4)); + // Print result + cerr << "initial complex :\n" << complex.to_string(); + cerr << endl << endl; + + Simplex simplex_123(static_cast<Vertex_handle> (1), static_cast<Vertex_handle> (2), static_cast<Vertex_handle> (3)); + complex.remove_star(simplex_123); + cerr << "complex.remove_star(1,2,3):\n" << complex.to_string(); + cerr << endl << endl; + + // verification + bool blocker123_here = complex.contains_blocker(simplex_123); + cerr << "----> Ocomplex \n"; + return blocker123_here; } - -bool test_collapse1(){ - Complex complex(5); - build_complete(4,complex); - complex.add_blocker(Simplex_handle(Vertex_handle(0),Vertex_handle(1),Vertex_handle(2),Vertex_handle(3))); - // Print result - cerr << "initial complex :\n"<< complex.to_string(); - cerr <<endl<<endl; - - Simplex_handle simplex_123(Vertex_handle(1),Vertex_handle(2),Vertex_handle(3)); - complex.remove_star(simplex_123); - cerr << "complex.remove_star(1,2,3):\n"<< complex.to_string(); - cerr <<endl<<endl; - - // verification - bool res = complex.contains_blocker(simplex_123); - res = res && complex.num_blockers()==1; - cerr <<"----> Ocomplex \n"; - return res; +bool test_collapse1() { + Complex complex(5); + build_complete(4, complex); + complex.add_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2), Vertex_handle(3))); + // Print result + cerr << "initial complex :\n" << complex.to_string(); + cerr << endl << endl; + + Simplex simplex_123(Vertex_handle(1), Vertex_handle(2), Vertex_handle(3)); + complex.remove_star(simplex_123); + cerr << "complex.remove_star(1,2,3):\n" << complex.to_string(); + cerr << endl << endl; + + // verification + bool res = complex.contains_blocker(simplex_123); + res = res && complex.num_blockers() == 1; + cerr << "----> Ocomplex \n"; + return res; } -bool test_collapse2(){ - Complex complex(5); - build_complete(4,complex); - complex.add_vertex(); - complex.add_edge(Vertex_handle(1),Vertex_handle(4)); - complex.add_edge(Vertex_handle(2),Vertex_handle(4)); - complex.add_edge(Vertex_handle(3),Vertex_handle(4)); - complex.add_blocker(Simplex_handle(Vertex_handle(1),Vertex_handle(2),Vertex_handle(3),Vertex_handle(4))); - // Print result - cerr << "initial complex :\n"<< complex.to_string(); - cerr <<endl<<endl; - - Simplex_handle sigma(Vertex_handle(1),Vertex_handle(2),Vertex_handle(3)); - complex.remove_star(sigma); - cerr << "complex.remove_star(1,2,3):\n"<< complex.to_string(); - cerr <<endl<<endl; - - // verification - bool blocker_removed = !complex.contains_blocker(Simplex_handle(Vertex_handle(1),Vertex_handle(2),Vertex_handle(3),Vertex_handle(4))); - bool blocker123_here = complex.contains_blocker(sigma); - return blocker_removed && blocker123_here; +bool test_collapse2() { + Complex complex(5); + build_complete(4, complex); + complex.add_vertex(); + complex.add_edge_without_blockers(Vertex_handle(1), Vertex_handle(4)); + complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(4)); + complex.add_edge_without_blockers(Vertex_handle(3), Vertex_handle(4)); + complex.add_blocker(Simplex(Vertex_handle(1), Vertex_handle(2), Vertex_handle(3), Vertex_handle(4))); + // Print result + cerr << "initial complex :\n" << complex.to_string(); + cerr << endl << endl; + + Simplex sigma(Vertex_handle(1), Vertex_handle(2), Vertex_handle(3)); + complex.remove_star(sigma); + cerr << "complex.remove_star(1,2,3):\n" << complex.to_string(); + cerr << endl << endl; + + // verification + bool blocker_removed = !complex.contains_blocker(Simplex(Vertex_handle(1), Vertex_handle(2), Vertex_handle(3), Vertex_handle(4))); + bool blocker123_here = complex.contains_blocker(sigma); + return blocker_removed && blocker123_here; } -bool test_collapse3(){ - Complex complex(5); - build_complete(4,complex); - complex.add_vertex(); - complex.add_edge(Vertex_handle(1),Vertex_handle(4)); - complex.add_edge(Vertex_handle(2),Vertex_handle(4)); - complex.add_edge(Vertex_handle(3),Vertex_handle(4)); - complex.add_blocker(Simplex_handle(Vertex_handle(1),Vertex_handle(2),Vertex_handle(3),Vertex_handle(4))); - // Print result - cerr << "initial complex:\n"<< complex.to_string(); - cerr <<endl<<endl; - - complex.remove_star(static_cast<Vertex_handle>(2)); - cerr << "complex after remove star of 2:\n"<< complex.to_string(); - - bool blocker134_here = complex.contains_blocker(Simplex_handle(Vertex_handle(1),Vertex_handle(3),Vertex_handle(4))); - bool blocker1234_here = complex.contains_blocker(Simplex_handle(Vertex_handle(1),Vertex_handle(2),Vertex_handle(3),Vertex_handle(4))); - return blocker134_here && !blocker1234_here; +bool test_collapse3() { + Complex complex(5); + build_complete(4, complex); + complex.add_vertex(); + complex.add_edge_without_blockers(Vertex_handle(1), Vertex_handle(4)); + complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(4)); + complex.add_edge_without_blockers(Vertex_handle(3), Vertex_handle(4)); + complex.add_blocker(Simplex(Vertex_handle(1), Vertex_handle(2), Vertex_handle(3), Vertex_handle(4))); + // Print result + cerr << "initial complex:\n" << complex.to_string(); + cerr << endl << endl; + + complex.remove_star(static_cast<Vertex_handle> (2)); + cerr << "complex after remove star of 2:\n" << complex.to_string(); + + bool blocker134_here = complex.contains_blocker(Simplex(Vertex_handle(1), Vertex_handle(3), Vertex_handle(4))); + bool blocker1234_here = complex.contains_blocker(Simplex(Vertex_handle(1), Vertex_handle(2), Vertex_handle(3), Vertex_handle(4))); + return blocker134_here && !blocker1234_here; } -bool test_add_simplex(){ - Complex complex(5); - build_complete(4,complex); - complex.add_blocker(Simplex_handle(Vertex_handle(0),Vertex_handle(1),Vertex_handle(2))); - // Print result - cerr << "initial complex:\n"<< complex.to_string(); - cerr <<endl<<endl; - - complex.add_simplex(Simplex_handle(Vertex_handle(0),Vertex_handle(1),Vertex_handle(2),Vertex_handle(3))); - cerr << "complex after add_simplex:\n"<< complex.to_string(); - - return complex.num_blockers()==0; +bool test_add_simplex() { + Complex complex(4); + build_complete(4, complex); + complex.add_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(3))); + cerr << "initial complex:\n" << complex.to_string(); + cerr << endl << endl; + + complex.add_simplex(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(3))); + cerr << "complex after add_simplex:\n" << complex.to_string(); + return complex.num_blockers() == 1 + && complex.contains_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2), Vertex_handle(3))); } -bool test_add_simplex2(){ - Complex complex; - build_complete(4,complex); - // Print result - cerr << "initial complex:\n"<< complex.to_string(); - cerr <<endl<<endl; +bool test_add_simplex2() { + Complex complex; + build_complete(4, complex); + // Print result + cerr << "initial complex:\n" << complex.to_string(); + cerr << endl << endl; - Complex copy(complex.num_vertices()); + Complex copy(complex.num_vertices()); - std::vector<Simplex_handle> simplices(complex.simplex_range().begin(),complex.simplex_range().end()); - sort(simplices.begin(),simplices.end(),[&](const Simplex_handle& s1,const Simplex_handle& s2){ - return s1.dimension()<s2.dimension(); - }); - for(const auto & simplex : simplices){ - if(!copy.contains(simplex) && simplex.dimension()==1) - copy.add_edge(simplex.first_vertex(),simplex.last_vertex()); - if(!copy.contains(simplex) && simplex.dimension()>1) - copy.add_simplex(simplex); - } + std::vector<Simplex> simplices(complex.complex_simplex_range().begin(), complex.complex_simplex_range().end()); + sort(simplices.begin(), simplices.end(), [&](const Simplex& s1, const Simplex & s2) { + return s1.dimension() < s2.dimension(); + }); + for (const auto & simplex : simplices) { + if (!copy.contains(simplex) && simplex.dimension() == 1) + copy.add_edge_without_blockers(simplex.first_vertex(), simplex.last_vertex()); + if (!copy.contains(simplex) && simplex.dimension() > 1) + copy.add_simplex(simplex); + } - cerr << "complex after add_simplex:\n"<< copy.to_string(); + cerr << "complex after add_simplex:\n" << copy.to_string(); - return complex.num_blockers()==copy.num_blockers() && - complex.num_edges()==copy.num_edges() && - complex.num_vertices()==copy.num_vertices(); + return complex.num_blockers() == copy.num_blockers() && + complex.num_edges() == copy.num_edges() && + complex.num_vertices() == copy.num_vertices(); } +bool test_add_simplex3() { + Complex complex(5); + build_complete(5, complex); + complex.remove_edge(Vertex_handle(3), Vertex_handle(4)); + Simplex sigma(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2)); + complex.add_blocker(sigma); + // Print result + cerr << "initial complex:\n" << complex.to_string(); + cerr << endl << endl; + complex.add_simplex(sigma); + //should create two blockers 0123 and 0124 + cerr << "complex after adding simplex 012:\n" << complex.to_string(); + return complex.num_blockers() == 2 + && complex.contains_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2), Vertex_handle(3))) + && complex.contains_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2), Vertex_handle(4))); +} - -bool test_remove_popable_blockers(){ - Complex complex; - build_complete(4,complex); - complex.add_vertex(); - complex.add_edge(Vertex_handle(3),Vertex_handle(4)); - complex.add_edge(Vertex_handle(2),Vertex_handle(4)); - Simplex_handle sigma1=Simplex_handle(Vertex_handle(1),Vertex_handle(2),Vertex_handle(3)); - Simplex_handle sigma2=Simplex_handle(Vertex_handle(2),Vertex_handle(3),Vertex_handle(4)); - - complex.add_blocker(sigma1); - complex.add_blocker(sigma2); - cerr << "complex complex"<< complex.to_string(); - cerr <<endl<<endl; - cerr << "complex.RemovePopableBlockers();"<<endl; - complex.remove_popable_blockers(); - cerr << "complex complex"<< complex.to_string(); - cerr <<endl<<endl; - - bool test1 = (complex.num_blockers()==1); - - - // test 2 - complex.clear(); - build_complete(4,complex); - complex.add_vertex(); - complex.add_vertex(); - complex.add_edge(Vertex_handle(3),Vertex_handle(4)); - complex.add_edge(Vertex_handle(2),Vertex_handle(4)); - complex.add_edge(Vertex_handle(2),Vertex_handle(5)); - complex.add_edge(Vertex_handle(3),Vertex_handle(5)); - complex.add_edge(Vertex_handle(4),Vertex_handle(5)); - sigma1=Simplex_handle(Vertex_handle(1),Vertex_handle(2),Vertex_handle(3)); - sigma2=Simplex_handle(Vertex_handle(2),Vertex_handle(3),Vertex_handle(4)); - - complex.add_blocker(sigma1); - complex.add_blocker(sigma2); - cerr << "complex complex"<< complex.to_string(); - cerr <<endl<<endl; cerr << "complex.RemovePopableBlockers();"<<endl; - complex.remove_popable_blockers(); - cerr << "complex complex"<< complex.to_string(); - - cerr <<endl<<endl; - bool test2 = (complex.num_blockers()==0); - return test1&&test2; +bool test_add_simplex4() { + int n = 6; + Complex complex(n); + + // add all simplex 0..n without i + for (int i = 0; i < n; i++) { + Simplex s; + for (int k = 0; k < n; k++) + s.add_vertex(Vertex_handle(k)); + s.remove_vertex(Vertex_handle(i)); + complex.add_simplex(s); + + //at step i there is only blocker 0..i + if (i < 2 && complex.num_blockers() > 0) + return false; + if (i >= 2 && complex.num_blockers() != 1) { + Simplex b; + for (int k = 0; k < i; k++) + b.add_vertex(Vertex_handle(i)); + if (!complex.contains_blocker(b)) + return false; + } + TESTVALUE(complex.blockers_to_string()); + } + Simplex s; + for (int k = 0; k < n; k++) + s.add_vertex(Vertex_handle(k)); + return complex.num_blockers() == 1 && complex.contains_blocker(s); } +bool test_add_edge() { + Complex complex(4); + for (unsigned i = 0u; i < 4; i++) + complex.add_edge(Vertex_handle(i), Vertex_handle((i + 1) % 4)); + + // Print result + cerr << "initial complex:\n" << complex.to_string(); + cerr << endl << endl; + complex.add_edge(Vertex_handle(1), Vertex_handle(3)); + //should create two blockers 013 and 012 + cerr << "complex after adding edge 13:\n" << complex.to_string(); + return complex.num_blockers() == 2 + && complex.contains_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(3))) + && complex.contains_blocker(Simplex(Vertex_handle(1), Vertex_handle(2), Vertex_handle(3))); +} +bool test_remove_popable_blockers() { + Complex complex; + build_complete(4, complex); + complex.add_vertex(); + complex.add_edge_without_blockers(Vertex_handle(3), Vertex_handle(4)); + complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(4)); + Simplex sigma1 = Simplex(Vertex_handle(1), Vertex_handle(2), Vertex_handle(3)); + Simplex sigma2 = Simplex(Vertex_handle(2), Vertex_handle(3), Vertex_handle(4)); + + complex.add_blocker(sigma1); + complex.add_blocker(sigma2); + cerr << "complex complex" << complex.to_string(); + cerr << endl << endl; + cerr << "complex.RemovePopableBlockers();" << endl; + complex.remove_popable_blockers(); + cerr << "complex complex" << complex.to_string(); + cerr << endl << endl; + + bool test1 = (complex.num_blockers() == 1); + + + // test 2 + complex.clear(); + build_complete(4, complex); + complex.add_vertex(); + complex.add_vertex(); + complex.add_edge_without_blockers(Vertex_handle(3), Vertex_handle(4)); + complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(4)); + complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(5)); + complex.add_edge_without_blockers(Vertex_handle(3), Vertex_handle(5)); + complex.add_edge_without_blockers(Vertex_handle(4), Vertex_handle(5)); + sigma1 = Simplex(Vertex_handle(1), Vertex_handle(2), Vertex_handle(3)); + sigma2 = Simplex(Vertex_handle(2), Vertex_handle(3), Vertex_handle(4)); + + complex.add_blocker(sigma1); + complex.add_blocker(sigma2); + cerr << "complex complex" << complex.to_string(); + cerr << endl << endl; + cerr << "complex.RemovePopableBlockers();" << endl; + complex.remove_popable_blockers(); + cerr << "complex complex" << complex.to_string(); + + cerr << endl << endl; + bool test2 = (complex.num_blockers() == 0); + return test1&&test2; +} -int main (int argc, char *argv[]) -{ - Tests tests_simplifiable_complex; - tests_simplifiable_complex.add("Test contraction 1",test_contraction1); - tests_simplifiable_complex.add("Test contraction 2",test_contraction2); - tests_simplifiable_complex.add("Test Link condition 1",test_link_condition1); - tests_simplifiable_complex.add("Test remove popable blockers",test_remove_popable_blockers); +int main(int argc, char *argv[]) { + Tests tests_simplifiable_complex; + tests_simplifiable_complex.add("Test contraction 1", test_contraction1); + tests_simplifiable_complex.add("Test contraction 2", test_contraction2); + tests_simplifiable_complex.add("Test Link condition 1", test_link_condition1); + tests_simplifiable_complex.add("Test remove popable blockers", test_remove_popable_blockers); - tests_simplifiable_complex.add("Test collapse 0",test_collapse0); - tests_simplifiable_complex.add("Test collapse 1",test_collapse1); - tests_simplifiable_complex.add("Test collapse 2",test_collapse2); - tests_simplifiable_complex.add("Test collapse 3",test_collapse3); + tests_simplifiable_complex.add("Test collapse 0", test_collapse0); + tests_simplifiable_complex.add("Test collapse 1", test_collapse1); + tests_simplifiable_complex.add("Test collapse 2", test_collapse2); + tests_simplifiable_complex.add("Test collapse 3", test_collapse3); - tests_simplifiable_complex.add("Test add simplex",test_add_simplex); - tests_simplifiable_complex.add("Test add simplex2",test_add_simplex2); + tests_simplifiable_complex.add("Test add edge",test_add_edge); + tests_simplifiable_complex.add("Test add simplex", test_add_simplex); + tests_simplifiable_complex.add("Test add simplex2", test_add_simplex2); + tests_simplifiable_complex.add("Test add simplex3",test_add_simplex3); + tests_simplifiable_complex.add("Test add simplex4",test_add_simplex4); - tests_simplifiable_complex.run(); + tests_simplifiable_complex.run(); - if(tests_simplifiable_complex.run()) - return EXIT_SUCCESS; - else - return EXIT_FAILURE; + if (tests_simplifiable_complex.run()) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; } diff --git a/src/Skeleton_blocker/test/TestSkeletonBlockerComplex.cpp b/src/Skeleton_blocker/test/TestSkeletonBlockerComplex.cpp index 3dc38572..42482e23 100644 --- a/src/Skeleton_blocker/test/TestSkeletonBlockerComplex.cpp +++ b/src/Skeleton_blocker/test/TestSkeletonBlockerComplex.cpp @@ -42,911 +42,911 @@ using namespace skbl; typedef Skeleton_blocker_complex<Skeleton_blocker_simple_traits> Complex; typedef Complex::Vertex_handle Vertex_handle; typedef Complex::Root_vertex_handle Root_vertex_handle; -typedef Complex::Simplex_handle Simplex_handle; +typedef Complex::Simplex Simplex; typedef Complex::Root_simplex_handle Root_simplex_handle; -typedef Simplex_handle::Simplex_vertex_const_iterator Simplex_vertex_const_iterator; +typedef Simplex::Simplex_vertex_const_iterator Simplex_vertex_const_iterator; typedef Complex::Edge_handle Edge_handle; // true if v in complex -bool assert_vertex(Complex &complex,Vertex_handle v){ - //assert(complex.contains(v)); - return complex.contains(static_cast<Simplex_handle>(v)); -} - -bool assert_simplex(Complex &complex,Root_vertex_handle a,Root_vertex_handle b,Root_vertex_handle c){ - return true; - // AddressSimplex simplex((a),(b),(c)); - // return complex.contains(&simplex); -} -// true iff the blocker (a,b,c) is in complex -bool assert_blocker(Complex &complex,Root_vertex_handle a,Root_vertex_handle b,Root_vertex_handle c){ - return true; - //return complex.contains_blocker((a),(b),(c)); +bool assert_vertex(Complex &complex, Vertex_handle v) { + //assert(complex.contains(v)); + return complex.contains(static_cast<Simplex> (v)); } -// true iff the blocker (a,b,c,d) is in complex -bool assert_blocker(Complex &complex,Root_vertex_handle a,Root_vertex_handle b,Root_vertex_handle c,Root_vertex_handle d){ - return true; - //Simplex blocker (a,b,c,d); - //return complex.contains_blocker(&blocker); -} - - - -void build_complete(int n,Complex& complex){ - complex.clear(); - for(int i=0;i<n;i++) - complex.add_vertex(); - - // for(int i=n-1;i>=0;i--) - // for(int j=i-1;j>=0;j--) - // complex.add_edge(Vertex_handle(i),Vertex_handle(j)); - - for(int i=0;i<n;i++) - for(int j=0;j<i;j++) - complex.add_edge(Vertex_handle(i),Vertex_handle(j)); -} - - -bool test_simplex(){ - // PRINT("test simplex"); - Simplex_handle simplex(Vertex_handle(0),Vertex_handle(1),Vertex_handle(2),Vertex_handle(3)); - for (auto i = simplex.begin() ; i != simplex.end() ; ++i){ - PRINT(*i); - auto j = i; - for (++j ; - j != simplex.end() ; - ++j){ - PRINT(*j); - } - } - return simplex.dimension()==3; -} - - -bool test_iterator_vertices1(){ - int n = 10; - Complex complex(10); - cerr << "complex.num_vertices():"<<complex.num_vertices()<<endl; - int num_vertex_seen = 0; - for(auto vi :complex.vertex_range()){ - cerr << "vertex:"<<vi<<endl; - ++num_vertex_seen; - } - return num_vertex_seen == n; -} - -bool test_iterator_vertices2(){ - int n = 10; - Complex complex(10); - build_complete(10,complex); - cerr << "complex.num_vertices():"<<complex.num_vertices()<<endl; - cerr << "complex.num_edges():"<<complex.num_edges()<<endl; - int num_vertex_seen = 0; - for(auto vi :complex.vertex_range(Vertex_handle(2))){ - cerr << "vertex:"<<vi<<endl; - ++num_vertex_seen; - } - std::cerr<<"num_vertex_seen:"<<num_vertex_seen<<std::endl; - return num_vertex_seen == (n-1); -} - - - -bool test_iterator_edge(){ - const int n = 10; - Complex complex(n); - for(int i=0;i<n;i++) - for(int j=0;j<i;j++) - complex.add_edge(Vertex_handle(i),Vertex_handle(j)); - complex.remove_edge(Vertex_handle(2),Vertex_handle(3)); - complex.remove_edge(Vertex_handle(3),Vertex_handle(5)); - cerr << "complex.num_edges():"<<complex.num_edges()<<endl; - int num_edges_seen = 0; - for(auto edge : complex.edge_range()){ - cerr << "edge :"<<complex[edge]<<endl; - ++num_edges_seen; - } - - return num_edges_seen == n*(n-1)/2-2; -} - -bool test_iterator_edge2(){ - const int n = 10; - Complex complex(n); - for(int i=0;i<n;i++) - for(int j=0;j<i;j++) - complex.add_edge(Vertex_handle(i),Vertex_handle(j)); - complex.remove_edge(Vertex_handle(2),Vertex_handle(3)); - complex.remove_edge(Vertex_handle(3),Vertex_handle(5)); - cerr << "complex.num_edges():"<<complex.num_edges()<<endl; - int num_neigbors_seen = 0; - for(auto neighbor : complex.vertex_range(Vertex_handle(2))){ - cerr << "neighbor"<<neighbor<<endl; - ++num_neigbors_seen; - } - return num_neigbors_seen==8; -} - - - -bool test_iterator_edge3(){ - const int n = 10; - Complex complex(n); - for(int i=0;i<n;i++) - for(int j=0;j<i;j++) - complex.add_edge(Vertex_handle(i),Vertex_handle(j)); - complex.remove_edge(Vertex_handle(2),Vertex_handle(3)); - complex.remove_edge(Vertex_handle(3),Vertex_handle(5)); - cerr << "complex.num_edges():"<<complex.num_edges()<<endl; - int num_neigbors_seen = 0; - for(auto edge : complex.edge_range(Vertex_handle(2))){ - std::cerr << edge<< std::endl; - ++num_neigbors_seen; - } - return num_neigbors_seen==8; -} - - - -bool test_iterator_triangles(){ - const int n = 7; - Complex complex(n); - //create a "ring" around '0' - for(int i=1;i<n;i++) - complex.add_edge(Vertex_handle(0),Vertex_handle(i)); - for(int i=1;i<n-1;i++) - complex.add_edge(Vertex_handle(i),Vertex_handle(i+1)); - complex.add_edge(Vertex_handle(1),Vertex_handle(6)); - - PRINT(complex.to_string()); - - int num_triangles_seen=0; - //for (auto t : complex.triangle_range(5)){ - TEST("triangles around 5 (should be 2 of them):"); - for (auto t : complex.triangle_range(Vertex_handle(5))){ - PRINT(t); - ++num_triangles_seen; - } - bool test = (num_triangles_seen==2); - - num_triangles_seen=0; - TEST("triangles around 0 (should be 6 of them):"); - for (auto t : complex.triangle_range(Vertex_handle(0))){ - PRINT(t); - ++num_triangles_seen; - } - test = test&&(num_triangles_seen==6); - - // we now add another triangle - complex.add_vertex(); - complex.add_edge(Vertex_handle(4),Vertex_handle(7)); - complex.add_edge(Vertex_handle(3),Vertex_handle(7)); - complex.add_blocker(Simplex_handle(Vertex_handle(0),Vertex_handle(1),Vertex_handle(6))); - num_triangles_seen=0; - - TEST("triangles (should be 6 of them):"); - num_triangles_seen=0; - for (auto t : complex.triangle_range()){ - PRINT(t); - ++num_triangles_seen; - } - test = test&&(num_triangles_seen==6); - PRINT(num_triangles_seen); - - return test; +bool assert_simplex(Complex &complex, Root_vertex_handle a, Root_vertex_handle b, Root_vertex_handle c) { + return true; + // AddressSimplex simplex((a),(b),(c)); + // return complex.contains(&simplex); } +// true iff the blocker (a,b,c) is in complex -//#include "combinatorics/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h" - -bool test_iterator_simplices(){ - Complex complex(6); - complex.add_edge(Vertex_handle(0),Vertex_handle(1)); - complex.add_edge(Vertex_handle(1),Vertex_handle(2)); - complex.add_edge(Vertex_handle(2),Vertex_handle(0)); - complex.add_edge(Vertex_handle(1),Vertex_handle(3)); - complex.add_edge(Vertex_handle(2),Vertex_handle(3)); - complex.add_edge(Vertex_handle(2),Vertex_handle(5)); - complex.add_edge(Vertex_handle(3),Vertex_handle(5)); - complex.add_edge(Vertex_handle(2),Vertex_handle(4)); - complex.add_edge(Vertex_handle(4),Vertex_handle(5)); - complex.add_edge(Vertex_handle(3),Vertex_handle(4)); - - complex.add_blocker(Simplex_handle(Vertex_handle(2),Vertex_handle(3),Vertex_handle(4),Vertex_handle(5))); - - bool correct_number_simplices = true; - - std::map<Vertex_handle,unsigned> expected_num_simplices; - - expected_num_simplices[Vertex_handle(0)] = 4; - expected_num_simplices[Vertex_handle(1)] = 6; - expected_num_simplices[Vertex_handle(2)] = 11; - expected_num_simplices[Vertex_handle(3)] = 9; - expected_num_simplices[Vertex_handle(4)] = 7; - expected_num_simplices[Vertex_handle(5)] = 7; - - for(auto pair : expected_num_simplices){ - unsigned num_simplices_around = 0; - for(const auto& simplex : complex.simplex_range(pair.first)){ - simplex.dimension(); - DBGVALUE(simplex); - ++num_simplices_around; - } - - correct_number_simplices = correct_number_simplices && (num_simplices_around == pair.second); - - DBGMSG("current vertex:",pair.first); - DBGMSG("expected_num_simplices:",pair.second); - DBGMSG("found:",num_simplices_around); - } - return correct_number_simplices; +bool assert_blocker(Complex &complex, Root_vertex_handle a, Root_vertex_handle b, Root_vertex_handle c) { + return true; + //return complex.contains_blocker((a),(b),(c)); } +// true iff the blocker (a,b,c,d) is in complex - -bool test_iterator_simplices2(){ - Complex complex(2); - complex.add_edge(Vertex_handle(0),Vertex_handle(1)); - - for(const auto& s:complex.triangle_range()){ - s.dimension(); - return false; // there are no triangles - } - - unsigned num_simplices = 0 ; - - - DBGVALUE(complex.to_string()); - - for(const auto& simplex : complex.simplex_range(Vertex_handle(0))){ - simplex.dimension(); - DBGVALUE(simplex); - } - - - for(const auto& simplex : complex.simplex_range()){ - DBGVALUE(simplex); - simplex.dimension(); - ++num_simplices; - } - bool correct_number_simplices = (num_simplices == 3); - return correct_number_simplices; +bool assert_blocker(Complex &complex, Root_vertex_handle a, Root_vertex_handle b, Root_vertex_handle c, Root_vertex_handle d) { + return true; + //Simplex blocker (a,b,c,d); + //return complex.contains_blocker(&blocker); +} + +void build_complete(int n, Complex& complex) { + complex.clear(); + for (int i = 0; i < n; i++) + complex.add_vertex(); + + // for(int i=n-1;i>=0;i--) + // for(int j=i-1;j>=0;j--) + // complex.add_edge_without_blockers(Vertex_handle(i),Vertex_handle(j)); + + for (int i = 0; i < n; i++) + for (int j = 0; j < i; j++) + complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j)); +} + +bool test_simplex() { + // PRINT("test simplex"); + Simplex simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2), Vertex_handle(3)); + for (auto i = simplex.begin(); i != simplex.end(); ++i) { + PRINT(*i); + auto j = i; + for (++j; + j != simplex.end(); + ++j) { + PRINT(*j); + } + } + return simplex.dimension() == 3; +} + +bool test_num_simplices() { + int n = 4; + Complex complex; + build_complete(n, complex); + size_t sum = 0; + for (int i = 0; i < n; i++) { + PRINT(complex.num_simplices(i)); + sum += complex.num_simplices(i); + } + return + complex.num_vertices() == n && + complex.num_edges() == 6 && + sum == 15 && + complex.num_simplices() == 15; +} + + +bool test_iterator_vertices1() { + int n = 10; + Complex complex(10); + cerr << "complex.num_vertices():" << complex.num_vertices() << endl; + int num_vertex_seen = 0; + for (auto vi : complex.vertex_range()) { + cerr << "vertex:" << vi << endl; + ++num_vertex_seen; + } + return num_vertex_seen == n; +} + +bool test_iterator_vertices2() { + int n = 10; + Complex complex; + build_complete(10, complex); + cerr << "complex.num_vertices():" << complex.num_vertices() << endl; + cerr << "complex.num_edges():" << complex.num_edges() << endl; + int num_vertex_seen = 0; + for (auto vi : complex.vertex_range(Vertex_handle(2))) { + cerr << "vertex:" << vi << endl; + ++num_vertex_seen; + } + std::cerr << "num_vertex_seen:" << num_vertex_seen << std::endl; + return num_vertex_seen == (n - 1); +} + +bool test_iterator_edge() { + const int n = 10; + Complex complex(n); + for (int i = 0; i < n; i++) + for (int j = 0; j < i; j++) + complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j)); + complex.remove_edge(Vertex_handle(2), Vertex_handle(3)); + complex.remove_edge(Vertex_handle(3), Vertex_handle(5)); + cerr << "complex.num_edges():" << complex.num_edges() << endl; + int num_edges_seen = 0; + for (auto edge : complex.edge_range()) { + cerr << "edge :" << complex[edge] << endl; + ++num_edges_seen; + } + + return num_edges_seen == n * (n - 1) / 2 - 2; +} + +bool test_iterator_edge2() { + const int n = 10; + Complex complex(n); + for (int i = 0; i < n; i++) + for (int j = 0; j < i; j++) + complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j)); + complex.remove_edge(Vertex_handle(2), Vertex_handle(3)); + complex.remove_edge(Vertex_handle(3), Vertex_handle(5)); + cerr << "complex.num_edges():" << complex.num_edges() << endl; + int num_neigbors_seen = 0; + for (auto neighbor : complex.vertex_range(Vertex_handle(2))) { + cerr << "neighbor" << neighbor << endl; + ++num_neigbors_seen; + } + return num_neigbors_seen == 8; +} + +bool test_iterator_edge3() { + const int n = 10; + Complex complex(n); + for (int i = 0; i < n; i++) + for (int j = 0; j < i; j++) + complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j)); + complex.remove_edge(Vertex_handle(2), Vertex_handle(3)); + complex.remove_edge(Vertex_handle(3), Vertex_handle(5)); + cerr << "complex.num_edges():" << complex.num_edges() << endl; + int num_neigbors_seen = 0; + for (auto edge : complex.edge_range(Vertex_handle(2))) { + std::cerr << edge << std::endl; + ++num_neigbors_seen; + } + return num_neigbors_seen == 8; +} + +bool test_iterator_triangles() { + const int n = 7; + Complex complex(n); + //create a "ring" around '0' + for (int i = 1; i < n; i++) + complex.add_edge_without_blockers(Vertex_handle(0), Vertex_handle(i)); + for (int i = 1; i < n - 1; i++) + complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(i + 1)); + complex.add_edge_without_blockers(Vertex_handle(1), Vertex_handle(6)); + + PRINT(complex.to_string()); + + int num_triangles_seen = 0; + //for (auto t : complex.triangle_range(5)){ + TEST("triangles around 5 (should be 2 of them):"); + for (auto t : complex.triangle_range(Vertex_handle(5))) { + PRINT(t); + ++num_triangles_seen; + } + bool test = (num_triangles_seen == 2); + + num_triangles_seen = 0; + TEST("triangles around 0 (should be 6 of them):"); + for (auto t : complex.triangle_range(Vertex_handle(0))) { + PRINT(t); + ++num_triangles_seen; + } + test = test && (num_triangles_seen == 6); + + // we now add another triangle + complex.add_vertex(); + complex.add_edge_without_blockers(Vertex_handle(4), Vertex_handle(7)); + complex.add_edge_without_blockers(Vertex_handle(3), Vertex_handle(7)); + complex.add_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(6))); + num_triangles_seen = 0; + + TEST("triangles (should be 6 of them):"); + num_triangles_seen = 0; + for (auto t : complex.triangle_range()) { + PRINT(t); + ++num_triangles_seen; + } + test = test && (num_triangles_seen == 6); + PRINT(num_triangles_seen); + + return test; } -bool test_iterator_simplices3(){ - Complex complex(3); - complex.add_edge(Vertex_handle(0),Vertex_handle(1)); - complex.add_edge(Vertex_handle(1),Vertex_handle(2)); - complex.add_edge(Vertex_handle(2),Vertex_handle(0)); - complex.add_blocker(Simplex_handle(Vertex_handle(0),Vertex_handle(1),Vertex_handle(2))); - - unsigned num_simplices = 0 ; - - for(const auto& simplex : complex.simplex_range(Vertex_handle(0))){ - simplex.dimension(); - DBGVALUE(simplex); - } - +//#include "combinatorics/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h" - for(const auto& simplex : complex.simplex_range()){ - DBGVALUE(simplex); - simplex.dimension(); - ++num_simplices; - } - bool correct_number_simplices = (num_simplices == 6); - return correct_number_simplices; +bool test_iterator_simplices() { + Complex complex(6); + complex.add_edge_without_blockers(Vertex_handle(0), Vertex_handle(1)); + complex.add_edge_without_blockers(Vertex_handle(1), Vertex_handle(2)); + complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(0)); + complex.add_edge_without_blockers(Vertex_handle(1), Vertex_handle(3)); + complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(3)); + complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(5)); + complex.add_edge_without_blockers(Vertex_handle(3), Vertex_handle(5)); + complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(4)); + complex.add_edge_without_blockers(Vertex_handle(4), Vertex_handle(5)); + complex.add_edge_without_blockers(Vertex_handle(3), Vertex_handle(4)); + + complex.add_blocker(Simplex(Vertex_handle(2), Vertex_handle(3), Vertex_handle(4), Vertex_handle(5))); + + bool correct_number_simplices = true; + + std::map<Vertex_handle, unsigned> expected_num_simplices; + + expected_num_simplices[Vertex_handle(0)] = 4; + expected_num_simplices[Vertex_handle(1)] = 6; + expected_num_simplices[Vertex_handle(2)] = 11; + expected_num_simplices[Vertex_handle(3)] = 9; + expected_num_simplices[Vertex_handle(4)] = 7; + expected_num_simplices[Vertex_handle(5)] = 7; + + for (auto pair : expected_num_simplices) { + unsigned num_simplices_around = 0; + for (const auto& simplex : complex.star_simplex_range(pair.first)) { + simplex.dimension(); + DBGVALUE(simplex); + ++num_simplices_around; + } + + correct_number_simplices = correct_number_simplices && (num_simplices_around == pair.second); + + DBGMSG("current vertex:", pair.first); + DBGMSG("expected_num_simplices:", pair.second); + DBGMSG("found:", num_simplices_around); + } + return correct_number_simplices; +} + +bool test_iterator_simplices2() { + Complex complex(2); + complex.add_edge_without_blockers(Vertex_handle(0), Vertex_handle(1)); + + for (const auto& s : complex.triangle_range()) { + s.dimension(); + return false; // there are no triangles + } + + unsigned num_simplices = 0; + + + DBGVALUE(complex.to_string()); + + for (const auto& simplex : complex.star_simplex_range(Vertex_handle(0))) { + simplex.dimension(); + DBGVALUE(simplex); + } + + + for (const auto& simplex : complex.complex_simplex_range()) { + DBGVALUE(simplex); + simplex.dimension(); + ++num_simplices; + } + bool correct_number_simplices = (num_simplices == 3); + return correct_number_simplices; +} + +bool test_iterator_simplices3() { + Complex complex(3); + complex.add_edge_without_blockers(Vertex_handle(0), Vertex_handle(1)); + complex.add_edge_without_blockers(Vertex_handle(1), Vertex_handle(2)); + complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(0)); + complex.add_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2))); + + unsigned num_simplices = 0; + + for (const auto& simplex : complex.star_simplex_range(Vertex_handle(0))) { + simplex.dimension(); + DBGVALUE(simplex); + } + + + for (const auto& simplex : complex.complex_simplex_range()) { + DBGVALUE(simplex); + simplex.dimension(); + ++num_simplices; + } + bool correct_number_simplices = (num_simplices == 6); + return correct_number_simplices; +} + +bool test_iterator_simplices4() { + Complex empty_complex; + for (auto v : empty_complex.vertex_range()) { + (void) v; + } + for (auto e : empty_complex.edge_range()) { + empty_complex[e]; + } + for (auto t : empty_complex.triangle_range()) { + t.dimension(); + } + for (auto s : empty_complex.complex_simplex_range()) { + s.dimension(); + } + return true; } -bool test_iterator_simplices4(){ - Complex empty_complex; - for(auto v : empty_complex.vertex_range()){ - v; - } - for(auto e : empty_complex.edge_range()){ - empty_complex[e]; - } - for(auto t : empty_complex.triangle_range()){ - t.dimension(); - } - for(auto s : empty_complex.simplex_range()){ - s.dimension(); - } - return true; +bool test_iterator_coboundary() { + Complex c; + build_complete(4, c); + c.remove_edge(Vertex_handle(1), Vertex_handle(3)); + PRINT(c.to_string()); + Simplex s02(Vertex_handle(0), Vertex_handle(2)); + int n = 0; + std::set<Simplex> expected; + expected.insert(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2))); + expected.insert(Simplex(Vertex_handle(0), Vertex_handle(2), Vertex_handle(3))); + for (const auto & s : c.coboundary_range(s02)) { + PRINT(s); + if (expected.find(s) == expected.end()) + return false; + ++n; + } + return n == 2; } - template<typename Map> -auto blocker_range(Map map) -> decltype( map | boost::adaptors::map_values){ - return map| boost::adaptors::map_values ; -} - - -bool test_iterator_blockers(){ - Complex complex; - Simplex_handle alpha; - Simplex_handle vertex_set_expected; - // Build the complexes - for (int i=0;i<20;i++){ - complex.add_vertex(); - } - for (int i=10;i<15;i++){ - for (int j=i+1;j<15;j++) - complex.add_edge(Vertex_handle(i),Vertex_handle(j)); - } - - complex.add_blocker(Simplex_handle(Vertex_handle(10),Vertex_handle(11),Vertex_handle(12))); - complex.add_blocker(Simplex_handle(Vertex_handle(2),Vertex_handle(1),Vertex_handle(10))); - complex.add_blocker(Simplex_handle(Vertex_handle(10),Vertex_handle(9),Vertex_handle(15))); - complex.add_blocker(Simplex_handle(Vertex_handle(1),Vertex_handle(9),Vertex_handle(8))); - - // Print result - int num_blockers=0; - for(auto blockers : complex.blocker_range(Vertex_handle(10))){ - TESTVALUE(*blockers) ; - num_blockers++; - } - bool test = (num_blockers==3); - - num_blockers=0; - for (auto blockers : complex.blocker_range()){ - TESTVALUE(*blockers) ; - num_blockers++; - } - test = test && (num_blockers==4) ; - - return test; -} - - -bool test_link0(){ - - enum { a, b, c, d, n }; - Complex complex(n); - complex.add_edge(Vertex_handle(b),Vertex_handle(c));complex.add_edge(Vertex_handle(c),Vertex_handle(d)); - Simplex_handle alpha = Simplex_handle(Vertex_handle(c)); - Skeleton_blocker_link_complex<Complex> L(complex,alpha); - - auto L2 = complex.link(alpha); - if(L!=L2) return false; - - PRINT(L.num_vertices()); - PRINT(L.to_string()); - - bool test1 = L.contains_vertex(*L.get_address(Root_vertex_handle(b))); - bool test2 = L.contains_vertex(*L.get_address(Root_vertex_handle(d))); - bool test3 = L.num_edges()==0; - bool test4 = L.num_blockers()==0; - return test1&&test2&&test3&&test4; - -} - -bool test_link1(){ - Complex complex; - - - // Build the complexes - for (int i=0;i<20;i++){ - complex.add_vertex(); - } - for (int i=10;i<15;i++){ - for (int j=i+1;j<15;j++) - complex.add_edge(Vertex_handle(i),Vertex_handle(j)); - } - Simplex_handle alpha(Vertex_handle(12),Vertex_handle(14)); - Skeleton_blocker_link_complex<Complex> L(complex,alpha); - // Complexes built - - auto L2 = complex.link(alpha); - if(L!=L2) return false; - - // verification - bool test1 = L.contains_vertex(*L.get_address(Root_vertex_handle(10))); - bool test2 = L.contains_vertex(*L.get_address(Root_vertex_handle(11))); - bool test3 = L.contains_vertex(*L.get_address(Root_vertex_handle(13))); - bool test4 = L.num_edges()==3; - bool test5 = L.num_blockers()==0; - Root_simplex_handle simplex; - simplex.add_vertex(Root_vertex_handle(10)); - simplex.add_vertex(Root_vertex_handle(11)); - simplex.add_vertex(Root_vertex_handle(13)); - bool test6(L.get_simplex_address(simplex)); - bool test7 = L.contains(*(L.get_simplex_address(simplex))); - cerr <<"----> Ocomplex \n"; - return test1&&test2&&test3&&test4&&test5&&test6&&test7 ; - -} - - -bool test_link2(){ - Complex complex; - - Simplex_handle alpha; - Simplex_handle vertex_set_expected; - // Build the complexes - for (int i=0;i<20;i++){ - complex.add_vertex(); - } - for (int i=10;i<15;i++){ - for (int j=i+1;j<15;j++) - complex.add_edge(Vertex_handle(i),Vertex_handle(j)); - } - complex.add_blocker(Simplex_handle(Vertex_handle(10),Vertex_handle(11),Vertex_handle(13))); - alpha = Simplex_handle(Vertex_handle(12),Vertex_handle(14)); - Skeleton_blocker_link_complex<Complex> L(complex,alpha); - // Complexes built - - // Print result - cerr << "complex complex"<< complex.to_string(); - cerr <<endl<<endl; - cerr << "L= Link_complex("<<alpha<<") : \n"<<L.to_string(); - - auto L2 = complex.link(alpha); - if(L!=L2) return false; - - - // verification - bool test1 = L.contains_vertex(*L.get_address(Root_vertex_handle(10))); - bool test2 = L.contains_vertex(*L.get_address(Root_vertex_handle(11))); - bool test3 = L.contains_vertex(*L.get_address(Root_vertex_handle(13))); - bool test4 = L.num_edges()==3; - bool test5 = L.num_blockers()==1; - Root_simplex_handle simplex; - simplex.add_vertex(Root_vertex_handle(10)); - simplex.add_vertex(Root_vertex_handle(11)); - simplex.add_vertex(Root_vertex_handle(13)); - bool test6 = L.contains_blocker(*(L.get_simplex_address(simplex))); - cerr <<"----> Ocomplex \n"; - return test1&&test2&&test3&&test4&&test5&&test6 ; -} - -bool test_link3(){ - Complex complex; - - Simplex_handle alpha; - Simplex_handle vertex_set_expected; - // Build the complexes - for (int i=0;i<20;i++){ - complex.add_vertex(); - } - for (int i=10;i<15;i++){ - for (int j=i+1;j<15;j++) - complex.add_edge(Vertex_handle(i),Vertex_handle(j)); - } - complex.add_blocker(Simplex_handle(Vertex_handle(10),Vertex_handle(11),Vertex_handle(12))); - alpha = Simplex_handle(Vertex_handle(12),Vertex_handle(14)); - Skeleton_blocker_link_complex<Complex> L(complex,alpha); - // Complexes built - - // Print result - cerr << "complex complex"<< complex.to_string(); - cerr <<endl<<endl; - cerr << "L= Link_complex("<<alpha<<") : \n"<<L.to_string(); - - auto L2 = complex.link(alpha); - if(L!=L2) return false; - - - // verification - bool test = assert_vertex(L,*L.get_address(Root_vertex_handle(10))); - test = test&& assert_vertex(L,*L.get_address(Root_vertex_handle(11))); - test = test&& assert_vertex(L,*L.get_address(Root_vertex_handle(13))); - test = test&& L.num_edges()==2; - test = test&&L.contains_edge(*L.get_address(Root_vertex_handle(10)),*L.get_address(Root_vertex_handle(13))); - test=test&&L.contains_edge(*L.get_address(Root_vertex_handle(13)),*L.get_address(Root_vertex_handle(11))); - test=test&&L.num_blockers()==0; - return test; -} - -bool test_link4(){ - Complex complex; - - // Build the complexes - for (int i=0;i<20;i++){ - complex.add_vertex(); - } - for (int i=10;i<15;i++){ - for (int j=i+1;j<15;j++) - complex.add_edge(Vertex_handle(i),Vertex_handle(j)); - } - complex.add_blocker(Simplex_handle(Vertex_handle(10),Vertex_handle(11),Vertex_handle(12),Vertex_handle(13))); - Simplex_handle alpha(Vertex_handle(12),Vertex_handle(14)); - Skeleton_blocker_link_complex<Complex> L(complex,alpha); - // Complexes built - - // verification - bool test1 = L.contains_vertex(*L.get_address(Root_vertex_handle(10))); - bool test2 = L.contains_vertex(*L.get_address(Root_vertex_handle(11))); - bool test3 = L.contains_vertex(*L.get_address(Root_vertex_handle(13))); - bool test4 = L.num_edges()==3; - bool test5 = L.num_blockers()==1; - Root_simplex_handle simplex; - simplex.add_vertex(Root_vertex_handle(10)); - simplex.add_vertex(Root_vertex_handle(11)); - simplex.add_vertex(Root_vertex_handle(13)); - bool test6 = L.contains_blocker(*(L.get_simplex_address(simplex))); - cerr <<"----> Ocomplex \n"; - return test1&&test2&&test3&&test4&&test5&&test6 ; - -} - -bool test_link5(){ - Complex complex(0,new Print_complex_visitor<Vertex_handle>()); - // Build the complexes - build_complete(4,complex); - complex.add_blocker(Simplex_handle(Vertex_handle(0),Vertex_handle(1),Vertex_handle(2),Vertex_handle(3))); - - Simplex_handle alpha(Vertex_handle(0),Vertex_handle(1),Vertex_handle(2)); +auto blocker_range(Map map) -> decltype(map | boost::adaptors::map_values) { + return map | boost::adaptors::map_values; +} + +bool test_iterator_blockers() { + Complex complex; + Simplex alpha; + Simplex vertex_set_expected; + // Build the complexes + for (int i = 0; i < 20; i++) { + complex.add_vertex(); + } + for (int i = 10; i < 15; i++) { + for (int j = i + 1; j < 15; j++) + complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j)); + } + + complex.add_blocker(Simplex(Vertex_handle(10), Vertex_handle(11), Vertex_handle(12))); + complex.add_blocker(Simplex(Vertex_handle(2), Vertex_handle(1), Vertex_handle(10))); + complex.add_blocker(Simplex(Vertex_handle(10), Vertex_handle(9), Vertex_handle(15))); + complex.add_blocker(Simplex(Vertex_handle(1), Vertex_handle(9), Vertex_handle(8))); + + // Print result + int num_blockers = 0; + for (auto blockers : complex.blocker_range(Vertex_handle(10))) { + TESTVALUE(*blockers); + num_blockers++; + } + bool test = (num_blockers == 3); + + num_blockers = 0; + for (auto blockers : complex.blocker_range()) { + TESTVALUE(*blockers); + num_blockers++; + } + test = test && (num_blockers == 4); + + return test; +} + +bool test_link0() { + + enum { + a, b, c, d, n + }; + Complex complex(n); + complex.add_edge_without_blockers(Vertex_handle(b), Vertex_handle(c)); + complex.add_edge_without_blockers(Vertex_handle(c), Vertex_handle(d)); + Simplex alpha = Simplex(Vertex_handle(c)); + Skeleton_blocker_link_complex<Complex> L(complex, alpha); + + auto L2 = complex.link(alpha); + if (L != L2) return false; + + PRINT(L.num_vertices()); + PRINT(L.to_string()); + + bool test1 = L.contains_vertex(*L.get_address(Root_vertex_handle(b))); + bool test2 = L.contains_vertex(*L.get_address(Root_vertex_handle(d))); + bool test3 = L.num_edges() == 0; + bool test4 = L.num_blockers() == 0; + return test1 && test2 && test3&&test4; + +} + +bool test_link1() { + Complex complex; + + + // Build the complexes + for (int i = 0; i < 20; i++) { + complex.add_vertex(); + } + for (int i = 10; i < 15; i++) { + for (int j = i + 1; j < 15; j++) + complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j)); + } + Simplex alpha(Vertex_handle(12), Vertex_handle(14)); + Skeleton_blocker_link_complex<Complex> L(complex, alpha); + // Complexes built + + auto L2 = complex.link(alpha); + if (L != L2) return false; + + // verification + bool test1 = L.contains_vertex(*L.get_address(Root_vertex_handle(10))); + bool test2 = L.contains_vertex(*L.get_address(Root_vertex_handle(11))); + bool test3 = L.contains_vertex(*L.get_address(Root_vertex_handle(13))); + bool test4 = L.num_edges() == 3; + bool test5 = L.num_blockers() == 0; + Root_simplex_handle simplex; + simplex.add_vertex(Root_vertex_handle(10)); + simplex.add_vertex(Root_vertex_handle(11)); + simplex.add_vertex(Root_vertex_handle(13)); + bool test6(L.get_simplex_address(simplex)); + bool test7 = L.contains(*(L.get_simplex_address(simplex))); + cerr << "----> Ocomplex \n"; + return test1 && test2 && test3 && test4 && test5 && test6&&test7; + +} + +bool test_link2() { + Complex complex; + + Simplex alpha; + Simplex vertex_set_expected; + // Build the complexes + for (int i = 0; i < 20; i++) { + complex.add_vertex(); + } + for (int i = 10; i < 15; i++) { + for (int j = i + 1; j < 15; j++) + complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j)); + } + complex.add_blocker(Simplex(Vertex_handle(10), Vertex_handle(11), Vertex_handle(13))); + alpha = Simplex(Vertex_handle(12), Vertex_handle(14)); + Skeleton_blocker_link_complex<Complex> L(complex, alpha); + // Complexes built + + // Print result + cerr << "complex complex" << complex.to_string(); + cerr << endl << endl; + cerr << "L= Link_complex(" << alpha << ") : \n" << L.to_string(); + + auto L2 = complex.link(alpha); + if (L != L2) return false; + + + // verification + bool test1 = L.contains_vertex(*L.get_address(Root_vertex_handle(10))); + bool test2 = L.contains_vertex(*L.get_address(Root_vertex_handle(11))); + bool test3 = L.contains_vertex(*L.get_address(Root_vertex_handle(13))); + bool test4 = L.num_edges() == 3; + bool test5 = L.num_blockers() == 1; + Root_simplex_handle simplex; + simplex.add_vertex(Root_vertex_handle(10)); + simplex.add_vertex(Root_vertex_handle(11)); + simplex.add_vertex(Root_vertex_handle(13)); + bool test6 = L.contains_blocker(*(L.get_simplex_address(simplex))); + cerr << "----> Ocomplex \n"; + return test1 && test2 && test3 && test4 && test5&&test6; +} + +bool test_link3() { + Complex complex; + + Simplex alpha; + Simplex vertex_set_expected; + // Build the complexes + for (int i = 0; i < 20; i++) { + complex.add_vertex(); + } + for (int i = 10; i < 15; i++) { + for (int j = i + 1; j < 15; j++) + complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j)); + } + complex.add_blocker(Simplex(Vertex_handle(10), Vertex_handle(11), Vertex_handle(12))); + alpha = Simplex(Vertex_handle(12), Vertex_handle(14)); + Skeleton_blocker_link_complex<Complex> L(complex, alpha); + // Complexes built + + // Print result + cerr << "complex complex" << complex.to_string(); + cerr << endl << endl; + cerr << "L= Link_complex(" << alpha << ") : \n" << L.to_string(); + + auto L2 = complex.link(alpha); + if (L != L2) return false; + + + // verification + bool test = assert_vertex(L, *L.get_address(Root_vertex_handle(10))); + test = test && assert_vertex(L, *L.get_address(Root_vertex_handle(11))); + test = test && assert_vertex(L, *L.get_address(Root_vertex_handle(13))); + test = test && L.num_edges() == 2; + test = test && L.contains_edge(*L.get_address(Root_vertex_handle(10)), *L.get_address(Root_vertex_handle(13))); + test = test && L.contains_edge(*L.get_address(Root_vertex_handle(13)), *L.get_address(Root_vertex_handle(11))); + test = test && L.num_blockers() == 0; + return test; +} + +bool test_link4() { + Complex complex; + + // Build the complexes + for (int i = 0; i < 20; i++) { + complex.add_vertex(); + } + for (int i = 10; i < 15; i++) { + for (int j = i + 1; j < 15; j++) + complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j)); + } + complex.add_blocker(Simplex(Vertex_handle(10), Vertex_handle(11), Vertex_handle(12), Vertex_handle(13))); + Simplex alpha(Vertex_handle(12), Vertex_handle(14)); + Skeleton_blocker_link_complex<Complex> L(complex, alpha); + // Complexes built + + // verification + bool test1 = L.contains_vertex(*L.get_address(Root_vertex_handle(10))); + bool test2 = L.contains_vertex(*L.get_address(Root_vertex_handle(11))); + bool test3 = L.contains_vertex(*L.get_address(Root_vertex_handle(13))); + bool test4 = L.num_edges() == 3; + bool test5 = L.num_blockers() == 1; + Root_simplex_handle simplex; + simplex.add_vertex(Root_vertex_handle(10)); + simplex.add_vertex(Root_vertex_handle(11)); + simplex.add_vertex(Root_vertex_handle(13)); + bool test6 = L.contains_blocker(*(L.get_simplex_address(simplex))); + cerr << "----> Ocomplex \n"; + return test1 && test2 && test3 && test4 && test5&&test6; + +} + +bool test_link5() { + Complex complex(0, new Print_complex_visitor<Vertex_handle>()); + // Build the complexes + build_complete(4, complex); + complex.add_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2), Vertex_handle(3))); + + Simplex alpha(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2)); + + + Skeleton_blocker_link_complex<Complex> L(complex, alpha); // Complexes built + + // Print result + PRINT(complex.to_string()); + cerr << endl << endl; + PRINT(L.to_string()); + + // verification + return L.num_vertices() == 0; +} + +bool test_link6() { + Complex complex(0, new Print_complex_visitor<Vertex_handle>()); + // Build the complexes + build_complete(4, complex); + complex.add_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2))); + Simplex alpha(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2)); - Skeleton_blocker_link_complex<Complex> L(complex,alpha); // Complexes built + Skeleton_blocker_link_complex<Complex> link_blocker_alpha; - // Print result - PRINT(complex.to_string()); - cerr <<endl<<endl; - PRINT(L.to_string()); + build_link_of_blocker(complex, alpha, link_blocker_alpha); + + // Print result + PRINT(complex.to_string()); + cerr << endl << endl; + PRINT(link_blocker_alpha.to_string()); - // verification - return L.num_vertices()==0; + // verification + return link_blocker_alpha.num_vertices() == 1; } -bool test_link6(){ - Complex complex(0,new Print_complex_visitor<Vertex_handle>()); - // Build the complexes - build_complete(4,complex); - complex.add_blocker(Simplex_handle(Vertex_handle(0),Vertex_handle(1),Vertex_handle(2))); +bool test_link7() { + Complex complex(0, new Print_complex_visitor<Vertex_handle>()); + // Build the complexes + build_complete(6, complex); + complex.add_vertex(); + complex.add_vertex(); + for (int i = 3; i < 6; ++i) { + complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(6)); + complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(7)); + } + complex.add_edge_without_blockers(Vertex_handle(6), Vertex_handle(7)); + complex.add_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2))); + complex.add_blocker(Simplex(Vertex_handle(3), Vertex_handle(4), Vertex_handle(5))); - Simplex_handle alpha(Vertex_handle(0),Vertex_handle(1),Vertex_handle(2)); + Simplex alpha(Vertex_handle(3), Vertex_handle(4), Vertex_handle(5)); - Skeleton_blocker_link_complex<Complex> link_blocker_alpha; + Skeleton_blocker_link_complex<Complex> link_blocker_alpha; - build_link_of_blocker(complex,alpha,link_blocker_alpha); + build_link_of_blocker(complex, alpha, link_blocker_alpha); - // Print result - PRINT(complex.to_string()); - cerr <<endl<<endl; - PRINT(link_blocker_alpha.to_string()); + //the result should be the edge {6,7} plus the blocker {0,1,2} - // verification - return link_blocker_alpha.num_vertices()==1; -} - - -bool test_link7(){ - Complex complex(0,new Print_complex_visitor<Vertex_handle>()); - // Build the complexes - build_complete(6,complex); - complex.add_vertex(); - complex.add_vertex(); - for(int i = 3; i<6; ++i){ - complex.add_edge(Vertex_handle(i),Vertex_handle(6)); - complex.add_edge(Vertex_handle(i),Vertex_handle(7)); - } - complex.add_edge(Vertex_handle(6),Vertex_handle(7)); - complex.add_blocker(Simplex_handle(Vertex_handle(0),Vertex_handle(1),Vertex_handle(2))); - complex.add_blocker(Simplex_handle(Vertex_handle(3),Vertex_handle(4),Vertex_handle(5))); - - Simplex_handle alpha(Vertex_handle(3),Vertex_handle(4),Vertex_handle(5)); - - Skeleton_blocker_link_complex<Complex> link_blocker_alpha; - - build_link_of_blocker(complex,alpha,link_blocker_alpha); + // Print result + PRINT(complex.to_string()); + cerr << endl << endl; + DBGVALUE(link_blocker_alpha.to_string()); - //the result should be the edge {6,7} plus the blocker {0,1,2} + Skeleton_blocker_link_complex<Complex> link_blocker_alpha_cpy = link_blocker_alpha; - // Print result - PRINT(complex.to_string()); - cerr <<endl<<endl; - DBGVALUE(link_blocker_alpha.to_string()); + DBGVALUE(link_blocker_alpha_cpy.to_string()); - Skeleton_blocker_link_complex<Complex> link_blocker_alpha_cpy = link_blocker_alpha; + bool equal_complexes = + (link_blocker_alpha.num_vertices() == link_blocker_alpha_cpy.num_vertices()) + &&(link_blocker_alpha.num_blockers() == link_blocker_alpha_cpy.num_blockers()) + &&(link_blocker_alpha.num_edges() == link_blocker_alpha_cpy.num_edges()) + ; + DBGVALUE((link_blocker_alpha.num_blockers() == link_blocker_alpha_cpy.num_blockers())); + DBGVALUE((link_blocker_alpha.num_blockers())); + DBGVALUE((link_blocker_alpha_cpy.num_blockers())); - DBGVALUE(link_blocker_alpha_cpy.to_string()); + DBGVALUE(equal_complexes); - bool equal_complexes = - (link_blocker_alpha.num_vertices() == link_blocker_alpha_cpy.num_vertices()) - &&(link_blocker_alpha.num_blockers() == link_blocker_alpha_cpy.num_blockers()) - &&(link_blocker_alpha.num_edges() == link_blocker_alpha_cpy.num_edges()) - ; - DBGVALUE((link_blocker_alpha.num_blockers() == link_blocker_alpha_cpy.num_blockers())); - DBGVALUE((link_blocker_alpha.num_blockers() )); - DBGVALUE(( link_blocker_alpha_cpy.num_blockers())); - - DBGVALUE(equal_complexes); - - // verification - return link_blocker_alpha.num_vertices()==5 && link_blocker_alpha.num_edges()==4 && link_blocker_alpha.num_blockers()==1 && equal_complexes; + // verification + return link_blocker_alpha.num_vertices() == 5 && link_blocker_alpha.num_edges() == 4 && link_blocker_alpha.num_blockers() == 1 && equal_complexes; } - - - - - - - template<typename SimplexHandle> -void add_triangle_edges(int a,int b,int c,list<SimplexHandle>& simplices){ - typedef SimplexHandle Simplex_handle; - typedef typename SimplexHandle::Vertex_handle Vertex_handle; +void add_triangle_edges(int a, int b, int c, list<SimplexHandle>& simplices) { + typedef SimplexHandle Simplex; + typedef typename SimplexHandle::Vertex_handle Vertex_handle; - simplices.push_back(Simplex_handle(Vertex_handle(a),Vertex_handle(b) )); - simplices.push_back(Simplex_handle(Vertex_handle(b),Vertex_handle(c) )); - simplices.push_back(Simplex_handle(Vertex_handle(c),Vertex_handle(a) )); + simplices.push_back(Simplex(Vertex_handle(a), Vertex_handle(b))); + simplices.push_back(Simplex(Vertex_handle(b), Vertex_handle(c))); + simplices.push_back(Simplex(Vertex_handle(c), Vertex_handle(a))); } template<typename SimplexHandle> -void add_triangle(int a,int b,int c,list<SimplexHandle>& simplices){ - typedef SimplexHandle Simplex_handle; - typedef typename SimplexHandle::Vertex_handle Vertex_handle; - simplices.push_back(Simplex_handle(Vertex_handle(a),Vertex_handle(b),Vertex_handle(c))); -} - -bool test_constructor(){ - list <Simplex_handle> simplices; - - simplices.push_back(Simplex_handle(Vertex_handle(0))); - simplices.push_back(Simplex_handle(Vertex_handle(1))); - simplices.push_back(Simplex_handle(Vertex_handle(2))); - simplices.push_back(Simplex_handle(Vertex_handle(3))); - simplices.push_back(Simplex_handle(Vertex_handle(4))); - simplices.push_back(Simplex_handle(Vertex_handle(5))); - - simplices.push_back(Simplex_handle(Vertex_handle(3),Vertex_handle(5) )); - - add_triangle_edges(0,1,5,simplices); - add_triangle_edges(1,2,3,simplices); - add_triangle_edges(2,3,4,simplices); - add_triangle_edges(1,3,4,simplices); - add_triangle_edges(1,2,4,simplices); - - - add_triangle(0,1,5,simplices); - add_triangle(1,2,3,simplices); - add_triangle(1,3,4,simplices); - add_triangle(1,2,4,simplices); - add_triangle(2,3,4,simplices); - - Complex complex(simplices.begin(),simplices.end()); - - PRINT(complex.to_string()); - - return ( complex.num_vertices()==6&&complex.num_edges()==10&& complex.num_blockers()==2); -} - - -list<Simplex_handle> subfaces(Simplex_handle top_face){ - list<Simplex_handle> res; - if(top_face.dimension()==-1) return res; - if(top_face.dimension()==0) { - res.push_back(top_face); - return res; - } - else{ - Vertex_handle first_vertex = top_face.first_vertex(); - top_face.remove_vertex(first_vertex); - res = subfaces(top_face); - list<Simplex_handle> copy = res; - for(auto& simplex : copy){ - simplex.add_vertex(first_vertex); - } - res.push_back(Simplex_handle(first_vertex)); - res.splice(res.end(),copy); - return res; - } -} - - -bool test_constructor2(){ - Simplex_handle simplex; - for(int i =0 ; i < 5;++i) - simplex.add_vertex(static_cast<Vertex_handle>(i)); - - list <Simplex_handle> simplices(subfaces(simplex)); - simplices.remove(simplex); - - Complex complex(simplices.begin(),simplices.end()); - - PRINT(complex.to_string()); - - for(auto b : complex.const_blocker_range()){ - cout << "b:"<<b<<endl; - } - - return ( complex.num_vertices()==5&&complex.num_edges()==10&& complex.num_blockers()==1); +void add_triangle(int a, int b, int c, list<SimplexHandle>& simplices) { + typedef SimplexHandle Simplex; + typedef typename SimplexHandle::Vertex_handle Vertex_handle; + simplices.push_back(Simplex(Vertex_handle(a), Vertex_handle(b), Vertex_handle(c))); } +bool test_constructor() { + list <Simplex> simplices; -bool test_constructor3(){ - typedef Vertex_handle Vh; - typedef Simplex_handle Sh; - std::vector<Simplex_handle> simplices; - auto subf(subfaces(Sh(Vh(0),Vh(1),Vh(2)))); - subf.pop_back(); //remove max face -> now a blocker 012 - simplices.insert(simplices.begin(),subf.begin(),subf.end()); - DBGCONT(simplices); - Complex complex(simplices.begin(),simplices.end()); - - DBGVALUE(complex.to_string()); + simplices.push_back(Simplex(Vertex_handle(0))); + simplices.push_back(Simplex(Vertex_handle(1))); + simplices.push_back(Simplex(Vertex_handle(2))); + simplices.push_back(Simplex(Vertex_handle(3))); + simplices.push_back(Simplex(Vertex_handle(4))); + simplices.push_back(Simplex(Vertex_handle(5))); - if(complex.num_blockers()!=1) return false; - Sh expected_blocker(Vh(0),Vh(1),Vh(2)); - for(auto b : complex.const_blocker_range()) - if(*b!=expected_blocker) return false; + simplices.push_back(Simplex(Vertex_handle(3), Vertex_handle(5))); + add_triangle_edges(0, 1, 5, simplices); + add_triangle_edges(1, 2, 3, simplices); + add_triangle_edges(2, 3, 4, simplices); + add_triangle_edges(1, 3, 4, simplices); + add_triangle_edges(1, 2, 4, simplices); - return complex.num_vertices()==3 && complex.num_blockers()==1; -} - -bool test_constructor4(){ - typedef Vertex_handle Vh; - typedef Simplex_handle Sh; - std::vector<Simplex_handle> simplices; - auto subf(subfaces(Sh(Vh(0),Vh(1),Vh(2),Vh(3)))); - simplices.insert(simplices.begin(),subf.begin(),subf.end()); - simplices.push_back(Sh(Vh(4))); - simplices.push_back(Sh(Vh(4),Vh(1))); - simplices.push_back(Sh(Vh(4),Vh(0))); + add_triangle(0, 1, 5, simplices); + add_triangle(1, 2, 3, simplices); + add_triangle(1, 3, 4, simplices); + add_triangle(1, 2, 4, simplices); + add_triangle(2, 3, 4, simplices); - DBGCONT(simplices); - Complex complex(simplices.begin(),simplices.end()); + Complex complex(simplices.begin(), simplices.end()); - DBGVALUE(complex.to_string()); - if(complex.num_blockers()!=1) return false; - Sh expected_blocker(Vh(0),Vh(1),Vh(4)); - for(auto b : complex.const_blocker_range()) - if(*b!=expected_blocker) return false; + PRINT(complex.to_string()); - return complex.num_vertices()==5 && complex.num_blockers()==1 && complex.num_edges()==8; + return ( complex.num_vertices() == 6 && complex.num_edges() == 10 && complex.num_blockers() == 2); } - - -bool test_constructor5(){ - typedef Vertex_handle Vh; - typedef Simplex_handle Sh; - std::vector<Simplex_handle> simplices; - auto subf(subfaces(Sh(Vh(0),Vh(1),Vh(2)))); - simplices.insert(simplices.begin(),subf.begin(),subf.end()); - - simplices.push_back(Sh(Vh(3))); - simplices.push_back(Sh(Vh(3),Vh(1))); - simplices.push_back(Sh(Vh(3),Vh(2))); - simplices.push_back(Sh(Vh(4))); - simplices.push_back(Sh(Vh(4),Vh(1))); - simplices.push_back(Sh(Vh(4),Vh(0))); - simplices.push_back(Sh(Vh(5))); - simplices.push_back(Sh(Vh(5),Vh(2))); - simplices.push_back(Sh(Vh(5),Vh(0))); - - DBGCONT(simplices); - Complex complex(simplices.begin(),simplices.end()); - - DBGVALUE(complex.to_string()); - - return complex.num_vertices()==6 && complex.num_blockers()==3 && complex.num_edges()==9; +list<Simplex> subfaces(Simplex top_face) { + list<Simplex> res; + if (top_face.dimension() == -1) return res; + if (top_face.dimension() == 0) { + res.push_back(top_face); + return res; + } else { + Vertex_handle first_vertex = top_face.first_vertex(); + top_face.remove_vertex(first_vertex); + res = subfaces(top_face); + list<Simplex> copy = res; + for (auto& simplex : copy) { + simplex.add_vertex(first_vertex); + } + res.push_back(Simplex(first_vertex)); + res.splice(res.end(), copy); + return res; + } } +bool test_constructor2() { + Simplex simplex; + for (int i = 0; i < 5; ++i) + simplex.add_vertex(static_cast<Vertex_handle> (i)); -bool test_constructor6(){ - typedef Vertex_handle Vh; - typedef Simplex_handle Sh; - std::vector<Simplex_handle> simplices; - auto subf(subfaces(Sh(Vh(0),Vh(1),Vh(2),Vh(3)))); - for(auto s:subf){ - Sh s1(Vh(0),Vh(1),Vh(2),Vh(3)); - Sh s2(Vh(1),Vh(2),Vh(3)); - if(s!=s1 && s!=s2) simplices.push_back(s); - } + list <Simplex> simplices(subfaces(simplex)); + simplices.remove(simplex); - DBGCONT(simplices); - Complex complex(simplices.begin(),simplices.end()); + Complex complex(simplices.begin(), simplices.end()); - DBGVALUE(complex.to_string()); + PRINT(complex.to_string()); - if(complex.num_blockers()!=1) return false; - Sh expected_blocker(Vh(1),Vh(2),Vh(3)); - for(auto b : complex.const_blocker_range()) - if(*b!=expected_blocker) return false; - return complex.num_vertices()==4 && complex.num_blockers()==1 && complex.num_edges()==6; -} + for (auto b : complex.const_blocker_range()) { + cout << "b:" << b << endl; + } - -bool test_constructor7(){ - typedef Vertex_handle Vh; - typedef Simplex_handle Sh; - std::vector<Simplex_handle> simplices; - simplices.push_back(Sh(Vh(0),Vh(1),Vh(2))); - simplices.push_back(Sh(Vh(1),Vh(2),Vh(3))); - simplices.push_back(Sh(Vh(3),Vh(0),Vh(2))); - simplices.push_back(Sh(Vh(3),Vh(0),Vh(1))); - - //get complex from top faces - Complex complex(make_complex_from_top_faces<Complex>(simplices.begin(),simplices.end())); - - DBGVALUE(complex.to_string()); - - if(complex.num_blockers()!=1) return false; - Sh expected_blocker(Vh(0),Vh(1),Vh(2),Vh(3)); - for(auto b : complex.const_blocker_range()) - if(*b!=expected_blocker) return false; - return complex.num_vertices()==4 && complex.num_blockers()==1 && complex.num_edges()==6; + return ( complex.num_vertices() == 5 && complex.num_edges() == 10 && complex.num_blockers() == 1); } +bool test_constructor3() { + typedef Vertex_handle Vh; + typedef Simplex Sh; + std::vector<Simplex> simplices; + auto subf(subfaces(Sh(Vh(0), Vh(1), Vh(2)))); + subf.pop_back(); //remove max face -> now a blocker 012 + simplices.insert(simplices.begin(), subf.begin(), subf.end()); + DBGCONT(simplices); + Complex complex(simplices.begin(), simplices.end()); -bool test_constructor8(){ - typedef Vertex_handle Vh; - typedef Simplex_handle Sh; - std::vector<Simplex_handle> simplices; - simplices.push_back(Sh(Vh(0),Vh(1))); - simplices.push_back(Sh(Vh(2),Vh(1))); - simplices.push_back(Sh(Vh(0),Vh(2))); - simplices.push_back(Sh(Vh(3),Vh(1))); - simplices.push_back(Sh(Vh(2),Vh(3))); + DBGVALUE(complex.to_string()); - //get complex from top faces - Complex complex(make_complex_from_top_faces<Complex>(simplices.begin(),simplices.end())); + if (complex.num_blockers() != 1) return false; + Sh expected_blocker(Vh(0), Vh(1), Vh(2)); + for (auto b : complex.const_blocker_range()) + if (*b != expected_blocker) return false; - DBGVALUE(complex.to_string()); - return complex.num_vertices()==4 && complex.num_blockers()==2 && complex.num_edges()==5; + return complex.num_vertices() == 3 && complex.num_blockers() == 1; } +bool test_constructor4() { + typedef Vertex_handle Vh; + typedef Simplex Sh; + std::vector<Simplex> simplices; + auto subf(subfaces(Sh(Vh(0), Vh(1), Vh(2), Vh(3)))); + simplices.insert(simplices.begin(), subf.begin(), subf.end()); + simplices.push_back(Sh(Vh(4))); + simplices.push_back(Sh(Vh(4), Vh(1))); + simplices.push_back(Sh(Vh(4), Vh(0))); + DBGCONT(simplices); + Complex complex(simplices.begin(), simplices.end()); + DBGVALUE(complex.to_string()); + if (complex.num_blockers() != 1) return false; + Sh expected_blocker(Vh(0), Vh(1), Vh(4)); + for (auto b : complex.const_blocker_range()) + if (*b != expected_blocker) return false; -int main (int argc, char *argv[]) -{ - Tests tests_complex; - tests_complex.add("test simplex",test_simplex); - tests_complex.add("test_link0",test_link0); - tests_complex.add("test_link1",test_link1); - tests_complex.add("test_link2",test_link2); - tests_complex.add("test_link3",test_link3); - tests_complex.add("test_link4",test_link4); - tests_complex.add("test_link5",test_link5); - tests_complex.add("test_link6",test_link6); - tests_complex.add("test_link7",test_link7); - - tests_complex.add("test iterator vertices 1",test_iterator_vertices1); - tests_complex.add("test iterator vertices 2",test_iterator_vertices2); - tests_complex.add("test iterator edges",test_iterator_edge); - tests_complex.add("test iterator edges 2",test_iterator_edge2); - tests_complex.add("test iterator edges 3",test_iterator_edge3); - - tests_complex.add("test iterator simplices",test_iterator_simplices); - tests_complex.add("test iterator simplices2",test_iterator_simplices2); - tests_complex.add("test iterator simplices3",test_iterator_simplices3); - tests_complex.add("test iterator simplices4",test_iterator_simplices4); - - - tests_complex.add("test iterator blockers",test_iterator_blockers); - tests_complex.add("test_iterator_triangles",test_iterator_triangles); - - tests_complex.add("test_constructor_list_simplices",test_constructor); - tests_complex.add("test_constructor_list_simplices2",test_constructor2); - tests_complex.add("test_constructor_list_simplices3",test_constructor3); - tests_complex.add("test_constructor_list_simplices4",test_constructor4); - tests_complex.add("test_constructor_list_simplices5",test_constructor5); - tests_complex.add("test_constructor_list_simplices6",test_constructor6); - tests_complex.add("test_constructor_list_simplices7",test_constructor7); - tests_complex.add("test_constructor_list_simplices8",test_constructor8); - - - if(tests_complex.run()){ - return EXIT_SUCCESS; - } - else{ - return EXIT_FAILURE; - } + return complex.num_vertices() == 5 && complex.num_blockers() == 1 && complex.num_edges() == 8; +} - // test_iterator_simplices(); +bool test_constructor5() { + typedef Vertex_handle Vh; + typedef Simplex Sh; + std::vector<Simplex> simplices; + auto subf(subfaces(Sh(Vh(0), Vh(1), Vh(2)))); + simplices.insert(simplices.begin(), subf.begin(), subf.end()); + + simplices.push_back(Sh(Vh(3))); + simplices.push_back(Sh(Vh(3), Vh(1))); + simplices.push_back(Sh(Vh(3), Vh(2))); + simplices.push_back(Sh(Vh(4))); + simplices.push_back(Sh(Vh(4), Vh(1))); + simplices.push_back(Sh(Vh(4), Vh(0))); + simplices.push_back(Sh(Vh(5))); + simplices.push_back(Sh(Vh(5), Vh(2))); + simplices.push_back(Sh(Vh(5), Vh(0))); + + DBGCONT(simplices); + Complex complex(simplices.begin(), simplices.end()); + + DBGVALUE(complex.to_string()); + + return complex.num_vertices() == 6 && complex.num_blockers() == 3 && complex.num_edges() == 9; +} + +bool test_constructor6() { + typedef Vertex_handle Vh; + typedef Simplex Sh; + std::vector<Simplex> simplices; + auto subf(subfaces(Sh(Vh(0), Vh(1), Vh(2), Vh(3)))); + for (auto s : subf) { + Sh s1(Vh(0), Vh(1), Vh(2), Vh(3)); + Sh s2(Vh(1), Vh(2), Vh(3)); + if (s != s1 && s != s2) simplices.push_back(s); + } + + DBGCONT(simplices); + Complex complex(simplices.begin(), simplices.end()); + + DBGVALUE(complex.to_string()); + + if (complex.num_blockers() != 1) return false; + Sh expected_blocker(Vh(1), Vh(2), Vh(3)); + for (auto b : complex.const_blocker_range()) + if (*b != expected_blocker) return false; + return complex.num_vertices() == 4 && complex.num_blockers() == 1 && complex.num_edges() == 6; +} + +bool test_constructor7() { + typedef Vertex_handle Vh; + typedef Simplex Sh; + std::vector<Simplex> simplices; + simplices.push_back(Sh(Vh(0), Vh(1), Vh(2))); + simplices.push_back(Sh(Vh(1), Vh(2), Vh(3))); + simplices.push_back(Sh(Vh(3), Vh(0), Vh(2))); + simplices.push_back(Sh(Vh(3), Vh(0), Vh(1))); + + //get complex from top faces + Complex complex(make_complex_from_top_faces<Complex>(simplices.begin(), simplices.end())); + + DBGVALUE(complex.to_string()); + + if (complex.num_blockers() != 1) return false; + Sh expected_blocker(Vh(0), Vh(1), Vh(2), Vh(3)); + for (auto b : complex.const_blocker_range()) + if (*b != expected_blocker) return false; + return complex.num_vertices() == 4 && complex.num_blockers() == 1 && complex.num_edges() == 6; +} + +bool test_constructor8() { + typedef Vertex_handle Vh; + typedef Simplex Sh; + std::vector<Simplex> simplices; + simplices.push_back(Sh(Vh(0), Vh(1))); + simplices.push_back(Sh(Vh(2), Vh(1))); + simplices.push_back(Sh(Vh(0), Vh(2))); + simplices.push_back(Sh(Vh(3), Vh(1))); + simplices.push_back(Sh(Vh(2), Vh(3))); + + //get complex from top faces + Complex complex(make_complex_from_top_faces<Complex>(simplices.begin(), simplices.end())); + + DBGVALUE(complex.to_string()); + + return complex.num_vertices() == 4 && complex.num_blockers() == 2 && complex.num_edges() == 5; +} + +int main(int argc, char *argv[]) { + Tests tests_complex; + tests_complex.add("test simplex", test_simplex); + tests_complex.add("test_num_simplices", test_num_simplices); + tests_complex.add("test_link0", test_link0); + tests_complex.add("test_link1", test_link1); + tests_complex.add("test_link2", test_link2); + tests_complex.add("test_link3", test_link3); + tests_complex.add("test_link4", test_link4); + tests_complex.add("test_link5", test_link5); + tests_complex.add("test_link6", test_link6); + tests_complex.add("test_link7", test_link7); + + tests_complex.add("test_constructor_list_simplices", test_constructor); + tests_complex.add("test_constructor_list_simplices2", test_constructor2); + tests_complex.add("test_constructor_list_simplices3", test_constructor3); + tests_complex.add("test_constructor_list_simplices4", test_constructor4); + tests_complex.add("test_constructor_list_simplices5", test_constructor5); + tests_complex.add("test_constructor_list_simplices6", test_constructor6); + tests_complex.add("test_constructor_list_simplices7", test_constructor7); + tests_complex.add("test_constructor_list_simplices8", test_constructor8); + + tests_complex.add("test iterator vertices 1", test_iterator_vertices1); + tests_complex.add("test iterator vertices 2", test_iterator_vertices2); + tests_complex.add("test iterator edges", test_iterator_edge); + tests_complex.add("test iterator edges 2", test_iterator_edge2); + tests_complex.add("test iterator edges 3", test_iterator_edge3); + tests_complex.add("test iterator blockers", test_iterator_blockers); + tests_complex.add("test_iterator_triangles", test_iterator_triangles); + tests_complex.add("test iterator simplices", test_iterator_simplices); + tests_complex.add("test iterator simplices2", test_iterator_simplices2); + tests_complex.add("test iterator simplices3", test_iterator_simplices3); + tests_complex.add("test iterator simplices4", test_iterator_simplices4); + tests_complex.add("test iterator coboundary", test_iterator_coboundary); + + if (tests_complex.run()) { + return EXIT_SUCCESS; + } else { + return EXIT_FAILURE; + } + + // test_iterator_simplices(); } diff --git a/src/Witness_complex/example/Torus_distance.h b/src/Witness_complex/example/Torus_distance.h deleted file mode 100644 index 5ae127df..00000000 --- a/src/Witness_complex/example/Torus_distance.h +++ /dev/null @@ -1,209 +0,0 @@ -#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 deleted file mode 100644 index edfd9a5f..00000000 --- a/src/Witness_complex/example/protected_sets/output_tikz.h +++ /dev/null @@ -1,67 +0,0 @@ -#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 deleted file mode 100644 index ec627808..00000000 --- a/src/Witness_complex/example/protected_sets/protected_sets.h +++ /dev/null @@ -1,597 +0,0 @@ -#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 deleted file mode 100644 index f3df3f1e..00000000 --- a/src/Witness_complex/example/protected_sets/protected_sets_paper.cpp +++ /dev/null @@ -1,610 +0,0 @@ -#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 deleted file mode 100644 index 61fcc75b..00000000 --- a/src/Witness_complex/example/protected_sets/protected_sets_paper.h +++ /dev/null @@ -1,917 +0,0 @@ -#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 deleted file mode 100644 index 04b5e3bc..00000000 --- a/src/Witness_complex/example/protected_sets/protected_sets_paper2.h +++ /dev/null @@ -1,1384 +0,0 @@ -#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/witness_complex_cube.cpp b/src/Witness_complex/example/witness_complex_cube.cpp deleted file mode 100644 index e448c55d..00000000 --- a/src/Witness_complex/example/witness_complex_cube.cpp +++ /dev/null @@ -1,590 +0,0 @@ -/* 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 deleted file mode 100644 index 2f4ee1cb..00000000 --- a/src/Witness_complex/example/witness_complex_cubic_systems.cpp +++ /dev/null @@ -1,547 +0,0 @@ -/* 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 deleted file mode 100644 index 7f8b985f..00000000 --- a/src/Witness_complex/example/witness_complex_epsilon.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* 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 deleted file mode 100644 index 49383154..00000000 --- a/src/Witness_complex/example/witness_complex_flat_torus.cpp +++ /dev/null @@ -1,851 +0,0 @@ -/* 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_off.cpp b/src/Witness_complex/example/witness_complex_from_off.cpp deleted file mode 100644 index 948f09a8..00000000 --- a/src/Witness_complex/example/witness_complex_from_off.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* 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 deleted file mode 100644 index 614bb945..00000000 --- a/src/Witness_complex/example/witness_complex_from_wl_matrix.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* 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 deleted file mode 100644 index c45bc0c1..00000000 --- a/src/Witness_complex/example/witness_complex_knn_landmarks.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* 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 deleted file mode 100644 index f78bcdab..00000000 --- a/src/Witness_complex/example/witness_complex_perturbations.cpp +++ /dev/null @@ -1,462 +0,0 @@ -/* 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 deleted file mode 100644 index 77a167a5..00000000 --- a/src/Witness_complex/example/witness_complex_protected_delaunay.cpp +++ /dev/null @@ -1,604 +0,0 @@ -/* 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 deleted file mode 100644 index bf3015fa..00000000 --- a/src/Witness_complex/example/witness_complex_sphere.cpp +++ /dev/null @@ -1,457 +0,0 @@ -/* 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/cmake/modules/FindEigen3.cmake b/src/cmake/modules/FindEigen3.cmake new file mode 100644 index 00000000..70c07dfb --- /dev/null +++ b/src/cmake/modules/FindEigen3.cmake @@ -0,0 +1,86 @@ +# - Try to find Eigen3 lib +# +# This module supports requiring a minimum version, e.g. you can do +# find_package(Eigen3 3.1.2) +# to require version 3.1.2 or newer of Eigen3. +# +# Once done this will define +# +# EIGEN3_FOUND - system has eigen lib with correct version +# EIGEN3_INCLUDE_DIR - the eigen include directory +# EIGEN3_VERSION - eigen version + +# Copyright (c) 2006, 2007 Montel Laurent, <montel@kde.org> +# Copyright (c) 2008, 2009 Gael Guennebaud, <g.gael@free.fr> +# Copyright (c) 2009 Benoit Jacob <jacob.benoit.1@gmail.com> +# Redistribution and use is allowed according to the terms of the 2-clause BSD license. + +include(FindPackageHandleStandardArgs) + +if(NOT Eigen3_FIND_VERSION) + if(NOT Eigen3_FIND_VERSION_MAJOR) + set(Eigen3_FIND_VERSION_MAJOR 2) + endif(NOT Eigen3_FIND_VERSION_MAJOR) + if(NOT Eigen3_FIND_VERSION_MINOR) + set(Eigen3_FIND_VERSION_MINOR 91) + endif(NOT Eigen3_FIND_VERSION_MINOR) + if(NOT Eigen3_FIND_VERSION_PATCH) + set(Eigen3_FIND_VERSION_PATCH 0) + endif(NOT Eigen3_FIND_VERSION_PATCH) + + set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}") +endif(NOT Eigen3_FIND_VERSION) + +macro(_eigen3_get_version) + file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header) + + string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}") + set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}") + string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}") + set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}") + string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}") + set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}") + + set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION}) +endmacro(_eigen3_get_version) + +set(EIGEN3_USE_FILE "UseEigen3") + +if (EIGEN3_INCLUDE_DIR) + + if (EXISTS ${EIGEN3_INCLUDE_DIR}/signature_of_eigen3_matrix_library) + # in cache already and valid + _eigen3_get_version() + set(EIGEN3_FOUND ${EIGEN3_VERSION_OK}) + + find_package_handle_standard_args(Eigen3 + REQUIRED_VARS EIGEN3_INCLUDE_DIR + VERSION_VAR EIGEN3_VERSION) + + else() + message(STATUS "Eigen3 path specified in cmake variable EIGEN3_INCLUDE_DIR is " + "set to ${EIGEN3_INCLUDE_DIR}, but that path does not contains the file " + "signature_of_eigen3_matrix_library and is considered as invalid.") + endif() + + + +else (EIGEN3_INCLUDE_DIR) + + find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library + HINTS ENV EIGEN3_INC_DIR + ENV EIGEN3_DIR + PATHS ${KDE4_INCLUDE_DIR} + PATH_SUFFIXES include eigen3 eigen + DOC "Directory containing the Eigen3 header files" + ) + + if(EIGEN3_INCLUDE_DIR) + _eigen3_get_version() + endif(EIGEN3_INCLUDE_DIR) + + find_package_handle_standard_args(Eigen3 + REQUIRED_VARS EIGEN3_INCLUDE_DIR + VERSION_VAR EIGEN3_VERSION) + +endif(EIGEN3_INCLUDE_DIR) diff --git a/src/cmake/modules/UseEigen3.cmake b/src/cmake/modules/UseEigen3.cmake new file mode 100644 index 00000000..e3ed18be --- /dev/null +++ b/src/cmake/modules/UseEigen3.cmake @@ -0,0 +1,9 @@ +# This module setups the compiler for using Eigen v3 library. +# It assumes that find_package(Eigen3) was already called. + + +include_directories( SYSTEM ${EIGEN3_INCLUDE_DIR} ) + +add_definitions(-DCGAL_EIGEN3_ENABLED) + +set (EIGEN3_SETUP TRUE) diff --git a/src/common/doc/main_page.h b/src/common/doc/main_page.h index 315aa0ac..41b8ba1e 100644 --- a/src/common/doc/main_page.h +++ b/src/common/doc/main_page.h @@ -1,72 +1,115 @@ -/** -\mainpage - -\image html "Gudhi_banner.jpg" "" width=20cm - -The Gudhi library (Geometric Understanding in Higher Dimensions) is a generic C++ library for -topological analysis of high-dimensional data whose goal is to provide robust, efficient, flexible and easy to use -implementations of -state-of-the-art algorithms and data structures for computational topology. -This library is part of the <a href="https://project.inria.fr/gudhi/">Gudhi project</a>. - -The current release of the library allows to use several data-structures for simplicial complexes : -simplex tree, Hasse diagram or skeleton-blocker. Several operations can then be done on top of these -representations such as persistent homology computation or simplification. -All data-structures are generic and several of their aspects (such as stored elements, policies) -can be parameterized via template classes. -We refer to -\cite gudhilibrary_ICMS14 -for a detailed description of the design of the library. - -\section installation Gudhi installation - -As Gudhi is a header only library, there is no need to install the library. - -Examples of Gudhi headers inclusion can be found in \ref demos. - - -\section compiling Compiling - -The library uses c++11 and requires <a href="http://www.boost.org/">Boost</a> with version 1.48.0 or more recent. -It is a multi-platform library and compiles on Linux, Mac OSX and Visual Studio 2013. - - -\subsection gmp GMP: -The multi-field persistent homology algorithm requires GMP which is a free library for arbitrary-precision -arithmetic, operating on signed integers, rational numbers, and floating point numbers. - -The following examples require the <a href="http://gmplib.org/">GNU Multiple Precision Arithmetic Library</a> (GMP) -and will not be built if GMP is not installed: - - Persistent_cohomology/rips_multifield_persistence - - Simplex_tree/simplex_tree_from_alpha_shapes_3 - -Having GMP version 4.2 or higher installed is recommended. - -\subsection cgal CGAL: -CGAL is a C++ library which provides easy access to efficient and reliable geometric algorithms. - -The following example requires the <a href="http://www.cgal.org/">Computational Geometry Algorithms Library</a> (CGAL) -and will not be built if CGAL is not installed: - - Simplex_tree/simplex_tree_from_alpha_shapes_3 - -Having CGAL version 4.4 or higher installed is recommended. The procedure to install this library according to -your operating system is detailed here http://doc.cgal.org/latest/Manual/installation.html - -\subsection demos Demos and examples - -To build the demos and libraries, run the following commands in a terminal: +/*! \mainpage + * \image html "Gudhi_banner.jpg" "" width=20cm + * + * \section Introduction Introduction + * The Gudhi library (Geometric Understanding in Higher Dimensions) is a generic open source C++ library for + * Computational Topology and Topological Data Analysis + * (<a class="el" target="_blank" href="https://en.wikipedia.org/wiki/Topological_data_analysis">TDA</a>). + * The GUDHI library is developed as part of the + * <a class="el" target="_blank" href="https://project.inria.fr/gudhi/">GUDHI project</a> supported by the European + * Research Council. The GUDHI library intends to help the development of new algorithmic solutions in TDA and their + * transfer to applications. It provides robust, efficient, flexible and easy to use implementations of + * state-of-the-art algorithms and data structures. + * + * The current release of the GUDHI library includes: + * + * \li Data structures to represent, construct and manipulate simplicial complexes. + * \li Algorithms to compute persistent homology and multi-field persistent homology. + * \li Simplication of simplicial complexes by edge contraction. + * + * All data-structures are generic and several of their aspects can be parameterized via template classes. + * We refer to \cite gudhilibrary_ICMS14 for a detailed description of the design of the library. + * + * The library is available <a class="el" target="_blank" href="https://gforge.inria.fr/frs/?group_id=3865">here</a> + * and the documentation is available at this <a class="el" href="http://gudhi.gforge.inria.fr/doc/latest/"> + * webpage</a>. + * + * The library comes with data sets, \ref demos and \ref testsuites. + * + * Gudhi is also accessible though the + * <a class="el" target="_blank" href="https://cran.r-project.org/web/packages/TDA/index.html">R package TDA</a> + * (Statistical Tools for Topological Data Analysis). + * + * The development of the GUDHI library is steered by an Editorial Board composed of: + * + * \li <a class="el" target="_blank" href="http://www-sop.inria.fr/members/Jean-Daniel.Boissonnat/"> + * Jean-Daniel Boissonnat</a> | INRIA Sophia Antipolis - MĂ©diterranĂ©e + * \li <a class="el" target="_blank" href="http://geometrica.saclay.inria.fr/team/Marc.Glisse/">Marc Glisse</a> | INRIA Saclay - Ile de France + * \li ClĂ©ment Jamin | INRIA Sophia Antipolis - MĂ©diterranĂ©e + * \li Vincent Rouvreau | INRIA Saclay - Ile de France + * +*/ -\verbatim -cd /path-to-gudhi/ +/*! \page installation Gudhi installation + * As Gudhi is a header only library, there is no need to install the library. + * + * Examples of Gudhi headers inclusion can be found in \ref demos. + * + * \section compiling Compiling + * The library uses c++11 and requires <a target="_blank" href="http://www.boost.org/">Boost</a> with version 1.48.0 or + * more recent. It is a multi-platform library and compiles on Linux, Mac OSX and Visual Studio 2013. + * + * \subsection gmp GMP: + * The multi-field persistent homology algorithm requires GMP which is a free library for arbitrary-precision + * arithmetic, operating on signed integers, rational numbers, and floating point numbers. + * + * The following example requires the <a target="_blank" href="http://gmplib.org/">GNU Multiple Precision Arithmetic + * Library</a> (GMP) and will not be built if GMP is not installed: + * \li Persistent_cohomology/rips_multifield_persistence + * + * Having GMP version 4.2 or higher installed is recommended. + * + * \subsection cgal CGAL: + * CGAL is a C++ library which provides easy access to efficient and reliable geometric algorithms. + * + * The following examples require the <a target="_blank" href="http://www.cgal.org/">Computational Geometry Algorithms + * Library</a> (CGAL) and will not be built if CGAL is not installed: + * \li GudhUI + * \li Persistent_cohomology/alpha_shapes_persistence + * \li Simplex_tree/simplex_tree_from_alpha_shapes_3 + * + * Having CGAL version 4.4 or higher installed is recommended. The procedure to install this library according to + * your operating system is detailed here http://doc.cgal.org/latest/Manual/installation.html + * + * \subsection demos Demos and examples + * To build the demos and libraries, run the following commands in a terminal: +\verbatim cd /path-to-gudhi/ mkdir build cd build/ cmake .. -make -\endverbatim - -\details +make \endverbatim + * + * \subsection testsuites Test suites + * To test your build, run the following command in a terminal: + * \verbatim make test \endverbatim + * + * \section Contributions Bug reports and contributions + * Please help us improving the quality of the GUDHI library. You may report bugs or suggestions to: + * \verbatim Contact: gudhi-users@lists.gforge.inria.fr \endverbatim + * + * Gudhi is open to external contributions. If you want to join our development team, please contact us. + * +*/ -\copyright GNU General Public License v3. -\verbatim Contact: gudhi-users@lists.gforge.inria.fr \endverbatim +/*! \page Upcoming Upcoming + * + * The library is under active development. New packages to be released next include: + * \li Alpha complex. + * \li Bottleneck distance. + * \li Zig zag persistence. + * \li Witness complex. + * \li Tangential complex. + * \li Clustering. +*/ +/*! \page Citation Acknowledging the GUDHI library + * We kindly ask users to cite the GUDHI library as appropriately as possible in their papers, and to mention the use + * of the GUDHI library on the web pages of their projects using GUDHI and provide us with links to these web pages. + * Feel free to contact us in case you have any question or remark on this topic. + * + * We provide \ref GudhiBibtex entries for the modules of the User and Reference Manual, as well as for publications + * directly related to the GUDHI library. + * \section GudhiBibtex GUDHI bibtex + * \verbinclude biblio/how_to_cite_gudhi.bib */ + diff --git a/src/common/include/gudhi/Clock.h b/src/common/include/gudhi/Clock.h index 08096c05..04c6ffb9 100644 --- a/src/common/include/gudhi/Clock.h +++ b/src/common/include/gudhi/Clock.h @@ -1,82 +1,79 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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_CLOCK_H_ -#define GUDHI_CLOCK_H_ - +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 CLOCK_H_ +#define CLOCK_H_ #include <boost/date_time/posix_time/posix_time.hpp> -class Clock{ - -public: - Clock():end_called(false){ - startTime = boost::posix_time::microsec_clock::local_time( ); - } - - Clock(const std::string& msg_){ - end_called = false; - begin(); - msg = msg_; - } - - - void begin() const{ - end_called = false; - startTime = boost::posix_time::microsec_clock::local_time( ); - } - - void end() const{ - end_called = true; - endTime = boost::posix_time::microsec_clock::local_time( ); - } - - void print() const{ - std::cout << *this << std::endl; - } - - friend std::ostream& operator<< (std::ostream& stream,const Clock& clock){ - if(!clock.end_called) - clock.end(); - - if(!clock.end_called) stream << "end not called"; - else{ - stream << clock.msg <<":"<<clock.num_seconds() <<"s"; - } - return stream; - - } - - double num_seconds() const{ - if(!end_called) return -1; - return (endTime-startTime).total_milliseconds()/1000.; - } - -private: - mutable boost::posix_time::ptime startTime, endTime; - mutable bool end_called; - std::string msg; - +#include <string> + +class Clock { + public: + Clock() : end_called(false) { + startTime = boost::posix_time::microsec_clock::local_time(); + } + + Clock(const std::string& msg_) { + end_called = false; + begin(); + msg = msg_; + } + + void begin() const { + end_called = false; + startTime = boost::posix_time::microsec_clock::local_time(); + } + + void end() const { + end_called = true; + endTime = boost::posix_time::microsec_clock::local_time(); + } + + void print() const { + std::cout << *this << std::endl; + } + + friend std::ostream& operator<<(std::ostream& stream, const Clock& clock) { + if (!clock.end_called) + clock.end(); + + if (!clock.end_called) { + stream << "end not called"; + } else { + stream << clock.msg << ":" << clock.num_seconds() << "s"; + } + return stream; + } + + double num_seconds() const { + if (!end_called) return -1; + return (endTime - startTime).total_milliseconds() / 1000.; + } + + private: + mutable boost::posix_time::ptime startTime, endTime; + mutable bool end_called; + std::string msg; }; - -#endif /* GUDHI_CLOCK_H_ */ +#endif // CLOCK_H_ diff --git a/src/common/include/gudhi/Off_reader.h b/src/common/include/gudhi/Off_reader.h index e29218d8..81b9e634 100644 --- a/src/common/include/gudhi/Off_reader.h +++ b/src/common/include/gudhi/Off_reader.h @@ -1,13 +1,10 @@ -/* - * Off_reader.h - * Created on: Nov 28, 2014 - * This file is part of the Gudhi Library. The Gudhi library +/* 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): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (France) + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 @@ -25,14 +22,15 @@ */ -#ifndef GUDHI_OFF_READER_H_ -#define GUDHI_OFF_READER_H_ +#ifndef OFF_READER_H_ +#define OFF_READER_H_ #include <sstream> #include <iostream> #include <iterator> - +#include <string> +#include <vector> namespace Gudhi { @@ -48,151 +46,144 @@ namespace Gudhi { * * The number of edges num_edges is optional and can be left to zero. */ -class Off_reader{ -public: - Off_reader(std::ifstream& stream):stream_(stream){ - } -// Off_reader(const std::string& name):stream_(name){ -// if(!stream_.is_open()) -// std::cerr <<"could not open file \n"; -// } - - ~Off_reader(){ - stream_.close(); - } - - /** - * read an off file and calls the following methods : - * void init(int dim,int num_vertices,int num_faces,int num_edges); //num_edges may not be set - * void point(const std::vector<double>& point); - * void maximal_face(const std::list<int>& face); - * void done(); - * of the visitor when reading a point or a maximal face. - */ - template<typename OffVisitor> - bool read(OffVisitor& off_visitor){ - bool success_read_off_preambule = read_off_preambule(off_visitor); - if(!success_read_off_preambule) { - std::cerr <<"could not read off preambule\n"; - return false; - } - - bool success_read_off_points = read_off_points(off_visitor); - if(!success_read_off_points) { - std::cerr <<"could not read off points\n"; - return false; - } - - bool success_read_off_faces = read_off_faces(off_visitor); - if(!success_read_off_faces) { - std::cerr <<"could not read off faces\n"; - return false; - } - - off_visitor.done(); - return success_read_off_preambule && success_read_off_points && success_read_off_faces; - } - -private: - std::ifstream& stream_; - - struct Off_info{ - int dim; - int num_vertices; - int num_edges; - int num_faces; - }; - - Off_info off_info_; - - template<typename OffVisitor> - bool read_off_preambule(OffVisitor& off_visitor){ - std::string line; - if(!goto_next_uncomment_line(line)) return false; - - bool is_off_file = (line.find("OFF") != std::string::npos); - bool is_noff_file = (line.find("nOFF") != std::string::npos); - - if(!is_off_file && !is_noff_file) { - std::cerr << line<<std::endl; - std::cerr << "missing off header\n"; - return false; - } - - if(!goto_next_uncomment_line(line)) return false; - std::istringstream iss(line); - if(is_off_file){ - off_info_.dim = 3; - if(!(iss >> off_info_.num_vertices >> off_info_.num_faces >> off_info_.num_edges)){ - std::cerr << "incorrect number of vertices/faces/edges\n"; - return false; - } - } - else - if(!(iss >> off_info_.dim >> off_info_.num_vertices >> off_info_.num_faces >> off_info_.num_edges)){ - std::cerr << "incorrect number of vertices/faces/edges\n"; - return false; - } - off_visitor.init(off_info_.dim,off_info_.num_vertices,off_info_.num_faces,off_info_.num_edges); - - return true; - } - - bool goto_next_uncomment_line(std::string& uncomment_line){ - uncomment_line.clear(); - do - std::getline(stream_, uncomment_line); - while(uncomment_line[0] == '%');// || uncomment_line.empty()); - return (uncomment_line.size()>0 && uncomment_line[0] != '%'); - } - - - template<typename OffVisitor> - bool read_off_points(OffVisitor& visitor){ - int num_vertices_to_read = off_info_.num_vertices; - while(num_vertices_to_read--){ - std::string line; - if(!goto_next_uncomment_line(line)) return false; - std::vector<double> point; - std::istringstream iss(line); - point.assign(std::istream_iterator<double>(iss),std::istream_iterator<double>()); -// if(point.size() != off_info_.dim) return false; - visitor.point(point); - } - return true; - } - - template<typename OffVisitor> - bool read_off_faces(OffVisitor& visitor){ - std::string line; - while(goto_next_uncomment_line(line)){ - std::istringstream iss(line); - int num_face_vertices; - iss >> num_face_vertices; - std::vector<int> face; - face.assign(std::istream_iterator<int>(iss),std::istream_iterator<int>()); - if(!face.size() == off_info_.num_vertices) return false; - visitor.maximal_face(face); - } - return true; - } +class Off_reader { + public: + Off_reader(std::ifstream& stream) : stream_(stream) { } + // Off_reader(const std::string& name):stream_(name){ + // if(!stream_.is_open()) + // std::cerr <<"could not open file \n"; + // } + + ~Off_reader() { + stream_.close(); + } + + /** + * read an off file and calls the following methods : + * void init(int dim,int num_vertices,int num_faces,int num_edges); //num_edges may not be set + * void point(const std::vector<double>& point); + * void maximal_face(const std::list<int>& face); + * void done(); + * of the visitor when reading a point or a maximal face. + */ + template<typename OffVisitor> + bool read(OffVisitor& off_visitor) { + bool success_read_off_preambule = read_off_preambule(off_visitor); + if (!success_read_off_preambule) { + std::cerr << "could not read off preambule\n"; + return false; + } + + bool success_read_off_points = read_off_points(off_visitor); + if (!success_read_off_points) { + std::cerr << "could not read off points\n"; + return false; + } + + bool success_read_off_faces = read_off_faces(off_visitor); + if (!success_read_off_faces) { + std::cerr << "could not read off faces\n"; + return false; + } + + off_visitor.done(); + return success_read_off_preambule && success_read_off_points && success_read_off_faces; + } + + private: + std::ifstream& stream_; + + struct Off_info { + int dim; + int num_vertices; + int num_edges; + int num_faces; + }; + + Off_info off_info_; + + template<typename OffVisitor> + bool read_off_preambule(OffVisitor& off_visitor) { + std::string line; + if (!goto_next_uncomment_line(line)) return false; + + bool is_off_file = (line.find("OFF") != std::string::npos); + bool is_noff_file = (line.find("nOFF") != std::string::npos); + + if (!is_off_file && !is_noff_file) { + std::cerr << line << std::endl; + std::cerr << "missing off header\n"; + return false; + } + + if (!goto_next_uncomment_line(line)) return false; + std::istringstream iss(line); + if (is_off_file) { + off_info_.dim = 3; + if (!(iss >> off_info_.num_vertices >> off_info_.num_faces >> off_info_.num_edges)) { + std::cerr << "incorrect number of vertices/faces/edges\n"; + return false; + } + } else { + if (!(iss >> off_info_.dim >> off_info_.num_vertices >> off_info_.num_faces >> off_info_.num_edges)) { + std::cerr << "incorrect number of vertices/faces/edges\n"; + return false; + } + } + off_visitor.init(off_info_.dim, off_info_.num_vertices, off_info_.num_faces, off_info_.num_edges); + + return true; + } + + bool goto_next_uncomment_line(std::string& uncomment_line) { + uncomment_line.clear(); + do + std::getline(stream_, uncomment_line); while (uncomment_line[0] == '%'); // || uncomment_line.empty()); + return (uncomment_line.size() > 0 && uncomment_line[0] != '%'); + } + + template<typename OffVisitor> + bool read_off_points(OffVisitor& visitor) { + int num_vertices_to_read = off_info_.num_vertices; + while (num_vertices_to_read--) { + std::string line; + if (!goto_next_uncomment_line(line)) return false; + std::vector<double> point; + std::istringstream iss(line); + point.assign(std::istream_iterator<double>(iss), std::istream_iterator<double>()); + // if(point.size() != off_info_.dim) return false; + visitor.point(point); + } + return true; + } + + template<typename OffVisitor> + bool read_off_faces(OffVisitor& visitor) { + std::string line; + while (goto_next_uncomment_line(line)) { + std::istringstream iss(line); + int num_face_vertices; + iss >> num_face_vertices; + std::vector<int> face; + face.assign(std::istream_iterator<int>(iss), std::istream_iterator<int>()); + if (face.size() != off_info_.dim) return false; + visitor.maximal_face(face); + } + return true; + } }; - template<typename OFFVisitor> -void read_off(const std::string& name_file_off,OFFVisitor& vis){ - std::ifstream stream(name_file_off); - if(!stream.is_open()) - std::cerr <<"could not open file \n"; - else{ - Off_reader off_reader(stream); - off_reader.read(vis); - } +void read_off(const std::string& name_file_off, OFFVisitor& vis) { + std::ifstream stream(name_file_off); + if (!stream.is_open()) { + std::cerr << "could not open file \n"; + } else { + Off_reader off_reader(stream); + off_reader.read(vis); + } } - - } // namespace Gudhi - -#endif /* GUDHI_OFF_READER_H_ */ +#endif // OFF_READER_H_ diff --git a/src/common/include/gudhi/Point.h b/src/common/include/gudhi/Point.h index 4023445b..0479e71e 100644 --- a/src/common/include/gudhi/Point.h +++ b/src/common/include/gudhi/Point.h @@ -1,13 +1,10 @@ -/* - * Basic_geometry.h - * Created on: Feb 10, 2015 - * This file is part of the Gudhi Library. The Gudhi library +/* 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): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (France) + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 @@ -24,9 +21,8 @@ * */ - -#ifndef BASIC_GEOMETRY_H_ -#define BASIC_GEOMETRY_H_ +#ifndef POINT_H_ +#define POINT_H_ #include <cmath> #include <vector> @@ -34,143 +30,141 @@ #include <cstddef> #include <initializer_list> -class Point_d{ -public: - Point_d(size_t dim=3):coords_(dim,0){} - Point_d(const Point_d& other):coords_(other.coords_){} - Point_d(const std::initializer_list<double>& list):coords_(list) { - } - template<typename CoordsIt> - Point_d(CoordsIt begin,CoordsIt end):coords_(begin,end){} - - size_t dimension() const{ - return coords_.size(); - } - - double x() const{ - return coords_[0]; - } - - double y() const{ - return coords_[1]; - } - - double z() const{ - return coords_[2]; - } - - double& x(){ - return coords_[0]; - } - - double& y(){ - return coords_[1]; - } - - double& z(){ - return coords_[2]; - } - - std::vector<double>::const_iterator begin() const{ - return coords_.begin(); - } - - std::vector<double>::const_iterator end() const{ - return coords_.end(); - } - - double& operator[](unsigned i){ - return coords_[i]; - } - const double& operator[](unsigned i) const{ - return coords_[i]; - } - - double squared_norm() const{ - double res = 0; - for(auto x : coords_) - res+= x*x; - return res; - } - - friend double squared_dist(const Point_d& p1,const Point_d& p2){ - assert(p1.dimension()==p2.dimension()); - double res = 0; - for(unsigned i = 0; i < p1.coords_.size(); ++i) - res+= (p1[i]-p2[i])*(p1[i]-p2[i]); - return res; - } - - /** - * dot product - */ - double operator*(const Point_d& other) const{ - assert(dimension()==other.dimension()); - double res = 0; - for(unsigned i = 0; i < coords_.size(); ++i) - res+= coords_[i]*other[i]; - return res; - } - - /** - * only if points have dimension 3 - */ - Point_d cross_product(const Point_d& other){ - assert(dimension()==3 && other.dimension()==3); - Point_d res(3); - res[0] = (*this)[1] * other[2] - (*this)[2] * other[1]; - res[1] = (*this)[2] * other[0] - (*this)[0] * other[2]; - res[2] = (*this)[0] * other[1] - (*this)[1] * other[0]; - return res; - } - - Point_d operator+(const Point_d& other) const{ - assert(dimension()==other.dimension()); - Point_d res(dimension()); - for(unsigned i = 0; i < coords_.size(); ++i) - res[i] = (*this)[i] + other[i]; - return res; - } - - Point_d operator*(double lambda) const{ - Point_d res(dimension()); - for(unsigned i = 0; i < coords_.size(); ++i) - res[i] = (*this)[i] * lambda; - return res; - } - - Point_d operator/(double lambda) const{ - Point_d res(dimension()); - for(unsigned i = 0; i < coords_.size(); ++i) - res[i] = (*this)[i] / lambda; - return res; - } - - Point_d operator-(const Point_d& other) const{ - assert(dimension()==other.dimension()); - Point_d res(dimension()); - for(unsigned i = 0; i < coords_.size(); ++i) - res[i] = (*this)[i] - other[i]; - return res; - } - - friend Point_d unit_normal(const Point_d& p1,const Point_d& p2,const Point_d& p3){ - assert(p1.dimension()==3); - assert(p2.dimension()==3); - assert(p3.dimension()==3); - Point_d p1p2 = p2 - p1; - Point_d p1p3 = p3 - p1; - Point_d res(p1p2.cross_product(p1p3)); - return res / std::sqrt(res.squared_norm()); - } - - -private: - std::vector<double> coords_; +class Point_d { + public: + Point_d(size_t dim = 3) : coords_(dim, 0) { } + + Point_d(const Point_d& other) : coords_(other.coords_) { } + + Point_d(const std::initializer_list<double>& list) : coords_(list) { } + + template<typename CoordsIt> + Point_d(CoordsIt begin, CoordsIt end) : coords_(begin, end) { } + + size_t dimension() const { + return coords_.size(); + } + + double x() const { + return coords_[0]; + } + + double y() const { + return coords_[1]; + } + + double z() const { + return coords_[2]; + } + + double& x() { + return coords_[0]; + } + + double& y() { + return coords_[1]; + } + + double& z() { + return coords_[2]; + } + + std::vector<double>::const_iterator begin() const { + return coords_.begin(); + } + + std::vector<double>::const_iterator end() const { + return coords_.end(); + } + + double& operator[](unsigned i) { + return coords_[i]; + } + + const double& operator[](unsigned i) const { + return coords_[i]; + } + + double squared_norm() const { + double res = 0; + for (auto x : coords_) + res += x * x; + return res; + } + + friend double squared_dist(const Point_d& p1, const Point_d& p2) { + assert(p1.dimension() == p2.dimension()); + double res = 0; + for (unsigned i = 0; i < p1.coords_.size(); ++i) + res += (p1[i] - p2[i])*(p1[i] - p2[i]); + return res; + } + + /** + * dot product + */ + double operator*(const Point_d& other) const { + assert(dimension() == other.dimension()); + double res = 0; + for (unsigned i = 0; i < coords_.size(); ++i) + res += coords_[i] * other[i]; + return res; + } + + /** + * only if points have dimension 3 + */ + Point_d cross_product(const Point_d& other) { + assert(dimension() == 3 && other.dimension() == 3); + Point_d res(3); + res[0] = (*this)[1] * other[2] - (*this)[2] * other[1]; + res[1] = (*this)[2] * other[0] - (*this)[0] * other[2]; + res[2] = (*this)[0] * other[1] - (*this)[1] * other[0]; + return res; + } + + Point_d operator+(const Point_d& other) const { + assert(dimension() == other.dimension()); + Point_d res(dimension()); + for (unsigned i = 0; i < coords_.size(); ++i) + res[i] = (*this)[i] + other[i]; + return res; + } + + Point_d operator*(double lambda) const { + Point_d res(dimension()); + for (unsigned i = 0; i < coords_.size(); ++i) + res[i] = (*this)[i] * lambda; + return res; + } + + Point_d operator/(double lambda) const { + Point_d res(dimension()); + for (unsigned i = 0; i < coords_.size(); ++i) + res[i] = (*this)[i] / lambda; + return res; + } + + Point_d operator-(const Point_d& other) const { + assert(dimension() == other.dimension()); + Point_d res(dimension()); + for (unsigned i = 0; i < coords_.size(); ++i) + res[i] = (*this)[i] - other[i]; + return res; + } + + friend Point_d unit_normal(const Point_d& p1, const Point_d& p2, const Point_d& p3) { + assert(p1.dimension() == 3); + assert(p2.dimension() == 3); + assert(p3.dimension() == 3); + Point_d p1p2 = p2 - p1; + Point_d p1p3 = p3 - p1; + Point_d res(p1p2.cross_product(p1p3)); + return res / std::sqrt(res.squared_norm()); + } + + private: + std::vector<double> coords_; }; - - - - -#endif /* BASIC_GEOMETRY_H_ */ +#endif // POINT_H_ diff --git a/src/common/include/gudhi/Simple_object_pool.h b/src/common/include/gudhi/Simple_object_pool.h new file mode 100644 index 00000000..fb9c8e23 --- /dev/null +++ b/src/common/include/gudhi/Simple_object_pool.h @@ -0,0 +1,81 @@ +/* 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): Marc Glisse + * + * Copyright (C) 2015 INRIA Saclay - Ile de 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 SIMPLE_OBJECT_POOL_H_ +#define SIMPLE_OBJECT_POOL_H_ + +#include <boost/pool/pool.hpp> +#include <utility> + +namespace Gudhi { + +/** \private + * This is a simpler version of boost::object_pool, that requires + * that users explicitly destroy all objects. This lets the + * performance scale much better, see + * https://svn.boost.org/trac/boost/ticket/3789 . + */ +template <class T> +class Simple_object_pool : protected boost::pool<boost::default_user_allocator_malloc_free> { + protected: + typedef boost::pool<boost::default_user_allocator_malloc_free> Base; + typedef T* pointer; + + Base& base() { + return *this; + } + + Base const& base()const { + return *this; + } + + public: + typedef T element_type; + typedef boost::default_user_allocator_malloc_free user_allocator; + typedef typename Base::size_type size_type; + typedef typename Base::difference_type difference_type; + + template<class...U> + Simple_object_pool(U&&...u) : Base(sizeof (T), std::forward<U>(u)...) { } + + template<class...U> + pointer construct(U&&...u) { + void* p = base().malloc BOOST_PREVENT_MACRO_SUBSTITUTION(); + assert(p); + try { + new(p) T(std::forward<U>(u)...); + } catch (...) { + base().free BOOST_PREVENT_MACRO_SUBSTITUTION(p); + throw; + } + return static_cast<pointer> (p); + } + + void destroy(pointer p) { + p->~T(); + base().free BOOST_PREVENT_MACRO_SUBSTITUTION(p); + } +}; + +} // namespace Gudhi + +#endif // SIMPLE_OBJECT_POOL_H_ diff --git a/src/common/include/gudhi/Test.h b/src/common/include/gudhi/Test.h index 18b7ca82..6024c822 100644 --- a/src/common/include/gudhi/Test.h +++ b/src/common/include/gudhi/Test.h @@ -1,5 +1,28 @@ -#ifndef __TEST_H -#define __TEST_H +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 TEST_H_ +#define TEST_H_ #include <list> #include <string> @@ -8,78 +31,75 @@ #include <iostream> -#define TEST(a) std::cout << "TEST: " << (a)<<std::endl -#define TESTMSG(a,b) std::cout << "TEST: " << a<<b<<std::endl -#define TESTVALUE(a) std::cout << "TEST: " << #a << ": " << a<<std::endl - +#define TEST(a) std::cout << "TEST: " << (a) << std::endl +#define TESTMSG(a, b) std::cout << "TEST: " << a << b << std::endl +#define TESTVALUE(a) std::cout << "TEST: " << #a << ": " << a << std::endl /** * Class to perform test */ -class Test -{ -private : - std::string name; - bool (*test)(); - - std::string separation() const{ - return "+++++++++++++++++++++++++++++++++++++++++++++++++\n"; - } - - std::string print_between_plus(std::string& s) const{ - std::stringstream res; - res << "+++++++++++++++++"<<s<<"+++++++++++++++++\n"; - return res.str(); - } - - -public: - Test(std::string name_,bool (*test_)()){ - name=name_; - test =test_; - } - - bool run(){ - std::cout << print_between_plus(name); - return test(); - } - std::string getName(){ - return name; - } +class Test { + private: + std::string name; + bool (*test)(); + + std::string separation() const { + return "+++++++++++++++++++++++++++++++++++++++++++++++++\n"; + } + + std::string print_between_plus(std::string& s) const { + std::stringstream res; + res << "+++++++++++++++++" << s << "+++++++++++++++++\n"; + return res.str(); + } + + public: + Test(std::string name_, bool (*test_)()) { + name = name_; + test = test_; + } + + bool run() { + std::cout << print_between_plus(name); + return test(); + } + + std::string getName() { + return name; + } }; - -class Tests -{ -private: - std::list<Test> tests; - -public: - void add(std::string name_,bool (*test_)()){ - Test test(name_,test_); - tests.push_back(test); - } - bool run(){ - bool tests_succesful(true); - std::vector<bool> res; - for (Test test : tests){ - res.push_back(test.run()); - } - std::cout << "\n\n results of tests : "<<std::endl; - int i=0; - for (Test t : tests){ - std::cout << "Test "<<i<< " \""<<t.getName()<<"\" --> "; - if (res[i++]) std::cout << "OK"<<std::endl; - else { - std::cout << "Fail"<<std::endl; - tests_succesful = false; - break; - } - } - return tests_succesful; - - } +class Tests { + private: + std::list<Test> tests; + + public: + void add(std::string name_, bool (*test_)()) { + Test test(name_, test_); + tests.push_back(test); + } + + bool run() { + bool tests_succesful(true); + std::vector<bool> res; + for (Test test : tests) { + res.push_back(test.run()); + } + std::cout << "\n\n results of tests : " << std::endl; + int i = 0; + for (Test t : tests) { + std::cout << "Test " << i << " \"" << t.getName() << "\" --> "; + if (res[i++]) { + std::cout << "OK" << std::endl; + } else { + std::cout << "Fail" << std::endl; + tests_succesful = false; + break; + } + } + return tests_succesful; + } }; -#endif +#endif // TEST_H_ diff --git a/src/common/include/gudhi/Utils.h b/src/common/include/gudhi/Utils.h index 7678685c..43916f11 100644 --- a/src/common/include/gudhi/Utils.h +++ b/src/common/include/gudhi/Utils.h @@ -1,48 +1,46 @@ - /* 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): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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_UTILS_H_ -#define GUDHI_UTILS_H_ +/* 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): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (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 UTILS_H_ +#define UTILS_H_ -#define PRINT(a) std::cerr << #a << ": " << (a) << " (DISP)"<<std::endl +#define PRINT(a) std::cerr << #a << ": " << (a) << " (DISP)" << std::endl -//#define DBG_VERBOSE +// #define DBG_VERBOSE #ifdef DBG_VERBOSE -#define DBG(a) std::cerr << "DBG: " << (a)<<std::endl -#define DBGMSG(a,b) std::cerr << "DBG: " << a<<b<<std::endl -#define DBGVALUE(a) std::cerr << "DBG: " << #a << ": " << a<<std::endl -#define DBGCONT(a) std::cerr << "DBG: container "<< #a<<" -> "; for(auto x:a) std::cerr<< x << ","; std::cerr<<std::endl +#define DBG(a) std::cerr << "DBG: " << (a) << std::endl +#define DBGMSG(a, b) std::cerr << "DBG: " << a << b << std::endl +#define DBGVALUE(a) std::cerr << "DBG: " << #a << ": " << a << std::endl +#define DBGCONT(a) std::cerr << "DBG: container " << #a << " -> "; for (auto x : a) std::cerr << x << ","; std::cerr << +std::endl #else -//#define DBG(a) a -//#define DBGMSG(a,b) b -//#define DBGVALUE(a) a -//#define DBGCONT(a) a +// #define DBG(a) a +// #define DBGMSG(a,b) b +// #define DBGVALUE(a) a +// #define DBGCONT(a) a #define DBG(a) -#define DBGMSG(a,b) +#define DBGMSG(a, b) #define DBGVALUE(a) #define DBGCONT(a) #endif - - - -#endif /* UTILS_H_ */ +#endif // UTILS_H_ diff --git a/src/common/include/gudhi/distance_functions.h b/src/common/include/gudhi/distance_functions.h index 7a2ab035..e5c79ded 100644 --- a/src/common/include/gudhi/distance_functions.h +++ b/src/common/include/gudhi/distance_functions.h @@ -1,37 +1,41 @@ - /* 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): ClĂ©ment Maria - * - * 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/>. - */ +/* 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): ClĂ©ment Maria + * + * 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/>. + */ + +#ifndef DISTANCE_FUNCTIONS_H_ +#define DISTANCE_FUNCTIONS_H_ /* Compute the Euclidean distance between two Points given * by a range of coordinates. The points are assumed to have * the same dimension. */ template< typename Point > -double euclidean_distance( Point &p1, Point &p2) -{ +double euclidean_distance(Point &p1, Point &p2) { double dist = 0.; - auto it1 = p1.begin(); auto it2 = p2.begin(); - for(; it1 != p1.end(); ++it1, ++it2) - { - double tmp = *it1 - *it2; - dist += tmp*tmp; - } - return sqrt(dist); + auto it1 = p1.begin(); + auto it2 = p2.begin(); + for (; it1 != p1.end(); ++it1, ++it2) { + double tmp = *it1 - *it2; + dist += tmp*tmp; + } + return sqrt(dist); } + +#endif // DISTANCE_FUNCTIONS_H_ diff --git a/src/common/include/gudhi/graph_simplicial_complex.h b/src/common/include/gudhi/graph_simplicial_complex.h index 1ad9dabd..042ef516 100644 --- a/src/common/include/gudhi/graph_simplicial_complex.h +++ b/src/common/include/gudhi/graph_simplicial_complex.h @@ -1,96 +1,99 @@ - /* 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): ClĂ©ment Maria - * - * 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/>. - */ +/* 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): ClĂ©ment Maria + * + * 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/>. + */ -#ifndef GUDHI_GRAPH_SIMPLICIAL_COMPLEX_FILTRATION_TAG_H -#define GUDHI_GRAPH_SIMPLICIAL_COMPLEX_FILTRATION_TAG_H +#ifndef GRAPH_SIMPLICIAL_COMPLEX_H_ +#define GRAPH_SIMPLICIAL_COMPLEX_H_ #include <boost/graph/adjacency_list.hpp> +#include <utility> // for pair<> +#include <vector> +#include <map> + /* Edge tag for Boost PropertyGraph. */ struct edge_filtration_t { typedef boost::edge_property_tag kind; }; + /* Vertex tag for Boost PropertyGraph. */ struct vertex_filtration_t { typedef boost::vertex_property_tag kind; }; -typedef int Vertex_handle; -typedef double Filtration_value; +typedef int Vertex_handle; +typedef double Filtration_value; typedef boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS - , boost::property < vertex_filtration_t, Filtration_value > - , boost::property < edge_filtration_t, Filtration_value > - > Graph_t; +, boost::property < vertex_filtration_t, Filtration_value > +, boost::property < edge_filtration_t, Filtration_value > +> Graph_t; typedef std::pair< Vertex_handle, Vertex_handle > Edge_t; /** \brief Output the proximity graph of the points. - * - * If points contains n elements, the proximity graph is the graph - * with n vertices, and an edge [u,v] iff the distance function between - * points u and v is smaller than threshold. - * - * The type PointCloud furnishes .begin() and .end() methods, that return - * iterators with value_type Point. - */ + * + * If points contains n elements, the proximity graph is the graph + * with n vertices, and an edge [u,v] iff the distance function between + * points u and v is smaller than threshold. + * + * The type PointCloud furnishes .begin() and .end() methods, that return + * iterators with value_type Point. + */ template< typename PointCloud - , typename Point > -Graph_t compute_proximity_graph( PointCloud &points - , Filtration_value threshold - , Filtration_value distance(Point p1, Point p2) ) -{ - std::vector< Edge_t > edges; - std::vector< Filtration_value > edges_fil; +, typename Point > +Graph_t compute_proximity_graph(PointCloud &points + , Filtration_value threshold + , Filtration_value distance(Point p1, Point p2)) { + std::vector< Edge_t > edges; + std::vector< Filtration_value > edges_fil; std::map< Vertex_handle, Filtration_value > vertices; Vertex_handle idx_u, idx_v; Filtration_value fil; idx_u = 0; - for(auto it_u = points.begin(); it_u != points.end(); ++it_u) - { - idx_v = idx_u+1; - for(auto it_v = it_u+1; it_v != points.end(); ++it_v, ++idx_v) - { - fil = distance(*it_u,*it_v); - if(fil <= threshold) { - edges.emplace_back(idx_u,idx_v); + for (auto it_u = points.begin(); it_u != points.end(); ++it_u) { + idx_v = idx_u + 1; + for (auto it_v = it_u + 1; it_v != points.end(); ++it_v, ++idx_v) { + fil = distance(*it_u, *it_v); + if (fil <= threshold) { + edges.emplace_back(idx_u, idx_v); edges_fil.push_back(fil); } } ++idx_u; } - Graph_t skel_graph( edges.begin() - , edges.end() - , edges_fil.begin() - , idx_u); //number of points labeled from 0 to idx_u-1 + Graph_t skel_graph(edges.begin() + , edges.end() + , edges_fil.begin() + , idx_u); // number of points labeled from 0 to idx_u-1 - auto vertex_prop = boost::get(vertex_filtration_t(),skel_graph); + auto vertex_prop = boost::get(vertex_filtration_t(), skel_graph); boost::graph_traits<Graph_t>::vertex_iterator vi, vi_end; - for ( std::tie(vi, vi_end) = boost::vertices(skel_graph); - vi != vi_end; ++vi ) - { boost::put(vertex_prop, *vi, 0.); } - + for (std::tie(vi, vi_end) = boost::vertices(skel_graph); + vi != vi_end; ++vi) { + boost::put(vertex_prop, *vi, 0.); + } + return skel_graph; } -#endif // GUDHI_GRAPH_SIMPLICIAL_COMPLEX_FILTRATION_TAG_H +#endif // GRAPH_SIMPLICIAL_COMPLEX_H_ diff --git a/src/common/include/gudhi/reader_utils.h b/src/common/include/gudhi/reader_utils.h index ab12c268..e05714c7 100644 --- a/src/common/include/gudhi/reader_utils.h +++ b/src/common/include/gudhi/reader_utils.h @@ -1,32 +1,38 @@ - /* 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): ClĂ©ment Maria - * - * 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/>. - */ - -#ifndef GUDHI_READER_UTILS_H -#define GUDHI_READER_UTILS_H +/* 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): ClĂ©ment Maria + * + * 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/>. + */ + +#ifndef READER_UTILS_H_ +#define READER_UTILS_H_ + +#include <gudhi/graph_simplicial_complex.h> + +#include <boost/graph/adjacency_list.hpp> #include <iostream> #include <fstream> -#include <boost/graph/adjacency_list.hpp> -#include "gudhi/graph_simplicial_complex.h" +#include <map> +#include <limits> // for numeric_limits<> +#include <string> +#include <vector> /** * \brief Read a set of points to turn it @@ -37,22 +43,21 @@ * X21 X22 ... X2d * etc */ -inline void -read_points ( 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()) { +inline void read_points(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;} + return; + } std::string line; double x; - while( getline ( in_file , line ) ) - { + while (getline(in_file, line)) { std::vector< double > point; - std::istringstream iss( line ); - while(iss >> x) { point.push_back(x); } + std::istringstream iss(line); + while (iss >> x) { + point.push_back(x); + } points.push_back(point); } in_file.close(); @@ -70,53 +75,64 @@ read_points ( std::string file_name * Every simplex must appear exactly once. * Simplices of dimension more than 1 are ignored. */ -inline Graph_t -read_graph ( std::string file_name ) -{ - std::ifstream in_ (file_name.c_str(),std::ios::in); - if(!in_.is_open()) { std::cerr << "Unable to open file " << file_name << std::endl; } - - std::vector< Edge_t > edges; - std::vector< Filtration_value > edges_fil; +inline Graph_t read_graph(std::string file_name) { + std::ifstream in_(file_name.c_str(), std::ios::in); + if (!in_.is_open()) { + std::cerr << "Unable to open file " << file_name << std::endl; + } + + std::vector< Edge_t > edges; + std::vector< Filtration_value > edges_fil; std::map< Vertex_handle, Filtration_value > vertices; - - std::string line; - int dim; - Vertex_handle u,v,max_h = -1; + + std::string line; + int dim; + Vertex_handle u, v, max_h = -1; Filtration_value fil; - while( getline ( in_ , line ) ) - { - std::istringstream iss( line ); - while(iss >> dim) { - switch ( dim ) { - case 0 : { - iss >> u; iss >> fil; + while (getline(in_, line)) { + std::istringstream iss(line); + while (iss >> dim) { + switch (dim) { + case 0: + { + iss >> u; + iss >> fil; vertices[u] = fil; - if(max_h < u) { max_h = u; } + if (max_h < u) { + max_h = u; + } break; } - case 1 : { - iss >> u; iss >> v; iss >> fil; - edges.push_back(Edge_t(u,v)); + case 1: + { + iss >> u; + iss >> v; + iss >> fil; + edges.push_back(Edge_t(u, v)); edges_fil.push_back(fil); break; } - default: {break;} - } + default: + { + break; + } + } } } in_.close(); - if((size_t)(max_h+1) != vertices.size()) - { std::cerr << "Error: vertices must be labeled from 0 to n-1 \n"; } + if ((size_t) (max_h + 1) != vertices.size()) { + std::cerr << "Error: vertices must be labeled from 0 to n-1 \n"; + } - Graph_t skel_graph(edges.begin(),edges.end(),edges_fil.begin(),vertices.size()); - auto vertex_prop = boost::get(vertex_filtration_t(),skel_graph); + Graph_t skel_graph(edges.begin(), edges.end(), edges_fil.begin(), vertices.size()); + auto vertex_prop = boost::get(vertex_filtration_t(), skel_graph); boost::graph_traits<Graph_t>::vertex_iterator vi, vi_end; auto v_it = vertices.begin(); - for (std::tie(vi, vi_end) = boost::vertices(skel_graph); vi != vi_end; ++vi,++v_it) - { boost::put(vertex_prop, *vi, v_it->second); } + for (std::tie(vi, vi_end) = boost::vertices(skel_graph); vi != vi_end; ++vi, ++v_it) { + boost::put(vertex_prop, *vi, v_it->second); + } return skel_graph; } @@ -133,17 +149,15 @@ read_graph ( std::string file_name ) * Every simplex must appear exactly once. * Simplices of dimension more than 1 are ignored. */ -template< typename Vertex_handle - , typename Filtration_value > -bool read_simplex ( std::istream & in_ - , std::vector< Vertex_handle > & simplex - , Filtration_value & fil ) -{ - int dim=0; - if(!(in_ >> dim)) return false; +template< typename Vertex_handle, typename Filtration_value > +bool read_simplex(std::istream & in_, std::vector< Vertex_handle > & simplex, Filtration_value & fil) { + int dim = 0; + if (!(in_ >> dim)) return false; Vertex_handle v; - for(int i=0; i<dim+1; ++i) - { in_ >> v; simplex.push_back(v); } + for (int i = 0; i < dim + 1; ++i) { + in_ >> v; + simplex.push_back(v); + } in_ >> fil; in_.ignore((std::numeric_limits<std::streamsize>::max)(), '\n'); // ignore until the carriage return return true; @@ -162,20 +176,21 @@ bool read_simplex ( std::istream & in_ * Dimi ki1 ki2 ... kiDimi Fili means that the ith simplex in the * filtration has dimension Dimi, filtration value fil1 and simplices with * key ki1 ... kiDimi in its boundary.*/ -template< typename Simplex_key - , typename Filtration_value > -bool read_hasse_simplex ( std::istream & in_ - , std::vector< Simplex_key > & boundary - , Filtration_value & fil ) -{ +template< typename Simplex_key, typename Filtration_value > +bool read_hasse_simplex(std::istream & in_, std::vector< Simplex_key > & boundary, Filtration_value & fil) { int dim; - if(!(in_ >> dim)) return false; - if(dim == 0) {in_ >> fil; return true;} + if (!(in_ >> dim)) return false; + if (dim == 0) { + in_ >> fil; + return true; + } Simplex_key key; - for(int i=0; i<dim+1; ++i) - { in_ >> key; boundary.push_back(key); } + for (int i = 0; i < dim + 1; ++i) { + in_ >> key; + boundary.push_back(key); + } in_ >> fil; return true; } -#endif // GUDHI_READER_UTILS_H +#endif // READER_UTILS_H_ |