summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.appveyor.yml69
-rw-r--r--.circleci/config.yml91
-rw-r--r--.gitignore17
-rw-r--r--.travis.yml77
-rw-r--r--Dockerfile_ubuntu58
-rw-r--r--README11
-rw-r--r--README.md18
-rw-r--r--biblio/bibliography.bib5
-rw-r--r--data/bitmap/sinusoid.txt77
-rw-r--r--data/points/bunny.COPYRIGHT2
-rw-r--r--data/points/grid_5_5_5_in_0_1.off127
-rw-r--r--src/Alpha_complex/benchmark/Alpha_complex_3d_benchmark.cpp278
-rw-r--r--src/Alpha_complex/benchmark/CMakeLists.txt9
-rw-r--r--src/Alpha_complex/concept/SimplicialComplexForAlpha.h14
-rw-r--r--src/Alpha_complex/concept/SimplicialComplexForAlpha3d.h57
-rw-r--r--src/Alpha_complex/doc/Intro_alpha_complex.h103
-rw-r--r--src/Alpha_complex/example/Alpha_complex_3d_from_points.cpp56
-rw-r--r--src/Alpha_complex/example/Alpha_complex_from_points.cpp20
-rw-r--r--src/Alpha_complex/example/CMakeLists.txt23
-rw-r--r--src/Alpha_complex/example/Weighted_alpha_complex_3d_from_points.cpp52
-rw-r--r--src/Alpha_complex/example/weightedalpha3dfrompoints_for_doc.txt31
-rw-r--r--src/Alpha_complex/include/gudhi/Alpha_complex.h83
-rw-r--r--src/Alpha_complex/include/gudhi/Alpha_complex_3d.h584
-rw-r--r--src/Alpha_complex/include/gudhi/Alpha_complex_options.h45
-rw-r--r--src/Alpha_complex/test/Alpha_complex_3d_unit_test.cpp164
-rw-r--r--src/Alpha_complex/test/CMakeLists.txt30
-rw-r--r--src/Alpha_complex/test/Periodic_alpha_complex_3d_unit_test.cpp190
-rw-r--r--src/Alpha_complex/test/Weighted_alpha_complex_3d_unit_test.cpp147
-rw-r--r--src/Alpha_complex/test/Weighted_periodic_alpha_complex_3d_unit_test.cpp239
-rw-r--r--src/Alpha_complex/utilities/CMakeLists.txt101
-rw-r--r--src/Alpha_complex/utilities/alpha_complex_3d_helper.h74
-rw-r--r--src/Alpha_complex/utilities/alpha_complex_3d_persistence.cpp368
-rw-r--r--src/Alpha_complex/utilities/alphacomplex.md146
-rw-r--r--src/Alpha_complex/utilities/exact_alpha_complex_3d_persistence.cpp265
-rw-r--r--src/Alpha_complex/utilities/periodic_alpha_complex_3d_persistence.cpp302
-rw-r--r--src/Alpha_complex/utilities/weighted_alpha_complex_3d_persistence.cpp316
-rw-r--r--src/Alpha_complex/utilities/weighted_periodic_alpha_complex_3d_persistence.cpp288
-rw-r--r--src/Bitmap_cubical_complex/doc/Gudhi_Cubical_Complex_doc.h11
-rw-r--r--src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex_base.h37
-rw-r--r--src/Bitmap_cubical_complex/test/Bitmap_test.cpp15
-rw-r--r--src/Bitmap_cubical_complex/test/CMakeLists.txt3
-rw-r--r--src/Doxyfile.in3
-rw-r--r--src/Nerve_GIC/include/gudhi/GIC.h29
-rw-r--r--src/Persistent_cohomology/example/persistence_from_file.cpp1
-rw-r--r--src/Rips_complex/doc/Intro_rips_complex.h7
-rw-r--r--src/Rips_complex/include/gudhi/Rips_complex.h2
-rw-r--r--src/Rips_complex/include/gudhi/Sparse_rips_complex.h2
-rw-r--r--src/Rips_complex/utilities/ripscomplex.md4
-rw-r--r--src/Simplex_tree/example/cech_complex_cgal_mini_sphere_3d.cpp2
-rw-r--r--src/Simplex_tree/include/gudhi/Simplex_tree.h135
-rw-r--r--src/Simplex_tree/test/CMakeLists.txt8
-rw-r--r--src/Simplex_tree/test/simplex_tree_ctor_and_move_unit_test.cpp137
-rw-r--r--src/Simplex_tree/test/simplex_tree_unit_test.cpp56
-rw-r--r--src/Tangential_complex/doc/Intro_tangential_complex.h20
-rw-r--r--src/Tangential_complex/include/gudhi/Tangential_complex.h70
-rw-r--r--src/Tangential_complex/test/test_tangential_complex.cpp30
-rw-r--r--src/cmake/modules/GUDHI_third_party_libraries.cmake27
-rw-r--r--src/cmake/modules/GUDHI_user_version_target.cmake2
-rw-r--r--src/common/benchmark/CMakeLists.txt3
-rw-r--r--src/common/benchmark/Graph_simplicial_complex_benchmark.cpp150
-rw-r--r--src/common/doc/examples.h5
-rw-r--r--src/common/doc/file_formats.h6
-rw-r--r--src/common/doc/installation.h32
-rw-r--r--src/common/doc/main_page.h7
-rw-r--r--src/common/include/gudhi/Unitary_tests_utils.h2
-rw-r--r--src/common/include/gudhi/graph_simplicial_complex.h2
-rw-r--r--src/common/include/gudhi/reader_utils.h4
-rw-r--r--src/cython/CMakeLists.txt11
-rw-r--r--src/cython/cython/rips_complex.pyx56
-rw-r--r--src/cython/cython/simplex_tree.pyx12
-rw-r--r--src/cython/cython/tangential_complex.pyx26
-rw-r--r--src/cython/doc/cubical_complex_user.rst10
-rw-r--r--src/cython/doc/examples.rst1
-rw-r--r--src/cython/doc/fileformats.rst10
-rw-r--r--src/cython/doc/installation.rst56
-rw-r--r--src/cython/doc/nerve_gic_complex_ref.rst4
-rw-r--r--src/cython/doc/nerve_gic_complex_user.rst4
-rw-r--r--src/cython/doc/persistent_cohomology_user.rst14
-rw-r--r--src/cython/doc/rips_complex_sum.inc6
-rw-r--r--src/cython/doc/rips_complex_user.rst67
-rw-r--r--src/cython/doc/tangential_complex_user.rst17
-rwxr-xr-xsrc/cython/example/sparse_rips_persistence_diagram.py43
-rwxr-xr-xsrc/cython/example/tangential_complex_plain_homology_from_off_file_example.py1
-rw-r--r--src/cython/include/Rips_complex_interface.h41
-rw-r--r--src/cython/include/Tangential_complex_interface.h15
-rwxr-xr-xsrc/cython/test/test_rips_complex.py20
-rwxr-xr-xsrc/cython/test/test_tangential_complex.py9
87 files changed, 3829 insertions, 1943 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
new file mode 100644
index 00000000..86199265
--- /dev/null
+++ b/.appveyor.yml
@@ -0,0 +1,69 @@
+# Specify version format
+version: "{build}"
+
+image:
+ - Visual Studio 2017
+
+platform:
+ - x64
+
+# specify custom environment variables
+environment:
+ APPVEYOR_SAVE_CACHE_ON_ERROR: true
+
+# build configuration, i.e. Debug, Release, etc.
+configuration:
+ - Debug
+ - Release
+
+# scripts that are called at very beginning, before repo cloning
+init:
+ - cmd: cmake --version
+ - cmd: msbuild /version
+
+# scripts that run after cloning repository
+install:
+ #------------------
+ # Windows 10
+ #------------------
+ # update vcpkg
+ - cmd: cd C:\tools\vcpkg
+ - cmd: git pull
+ - cmd: .\bootstrap-vcpkg.bat
+
+ - cmd: if "%platform%"=="Win32" set VCPKG_ARCH=x86-windows
+ - cmd: if "%platform%"=="x64" set VCPKG_ARCH=x64-windows
+
+ # remove outdated versions
+ - cmd: vcpkg remove --outdated --recurse
+
+ # install required dependencies
+ - cmd: vcpkg install --recurse --triplet %VCPKG_ARCH% zlib boost-date-time boost-program-options boost-system boost-serialization boost-thread boost-units tbb eigen3 cgal[core]
+
+ - cmd: vcpkg integrate install
+ - cmd: cd "%APPVEYOR_BUILD_FOLDER%"
+
+# preserve contents of selected directories and files across project builds
+for:
+-
+ matrix:
+ only:
+ - image: Visual Studio 2017
+ cache:
+ - 'C:\tools\vcpkg\installed'
+
+build_script:
+ # get VCG library
+ - git clone https://github.com/GUDHI/gudhi-devel.git
+
+ #------------------
+ # Windows 10
+ #------------------
+ - cmd: if "%platform%"=="Win32" set CMAKE_GENERATOR=-G"Visual Studio 15 2017"
+ - cmd: if "%platform%"=="x64" set CMAKE_GENERATOR=-G"Visual Studio 15 2017 Win64"
+ - cmd: mkdir build && cd build
+ - cmd: cmake %CMAKE_GENERATOR% -DCMAKE_BUILD_TYPE=%Configuration% -DCMAKE_TOOLCHAIN_FILE="C:\tools\vcpkg\scripts\buildsystems\vcpkg.cmake" -DVCG_ROOT="%APPVEYOR_BUILD_FOLDER%\VCG" ..
+ - cmd: cmake --build . --target ALL_BUILD --config %Configuration% -- /maxcpucount:4
+
+test_script:
+ - cmd: ctest --build-config %Configuration% --output-on-failure
diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 00000000..b9f0376e
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,91 @@
+version: 2.0
+jobs:
+ examples:
+ docker:
+ - image: gudhi/ci_for_gudhi:latest
+ steps:
+ - checkout
+ - run:
+ name: Build and test examples
+ command: |
+ mkdir build;
+ cd build;
+ cmake -DCMAKE_BUILD_TYPE=Release -DWITH_GUDHI_EXAMPLE=ON -DWITH_GUDHI_TEST=OFF -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=OFF ..;
+ make all test;
+
+ tests:
+ docker:
+ - image: gudhi/ci_for_gudhi:latest
+ steps:
+ - checkout
+ - run:
+ name: Build and test unitary tests
+ command: |
+ mkdir build;
+ cd build;
+ cmake -DCMAKE_BUILD_TYPE=Release -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_TEST=ON -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=OFF ..;
+ make all test;
+
+ utils:
+ docker:
+ - image: gudhi/ci_for_gudhi:latest
+ steps:
+ - checkout
+ - run:
+ name: Build and test utilities
+ command: |
+ mkdir build;
+ cd build;
+ cmake -DCMAKE_BUILD_TYPE=Release -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_TEST=OFF -DWITH_GUDHI_UTILITIES=ON -DWITH_GUDHI_PYTHON=OFF ..;
+ make all test;
+
+ python:
+ docker:
+ - image: gudhi/ci_for_gudhi:latest
+ steps:
+ - checkout
+ - run:
+ name: Build and test python module. Generates and tests the python documentation
+ command: |
+ mkdir build;
+ cd build;
+ cmake -DUSER_VERSION_DIR=version ..;
+ make user_version;
+ cd version;
+ mkdir build;
+ cd build;
+ cmake -DCMAKE_BUILD_TYPE=Release -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=ON -DPython_ADDITIONAL_VERSIONS=3 ..;
+ make all test sphinx;
+ cp -R cython/sphinx /tmp/sphinx;
+
+ - store_artifacts:
+ path: /tmp/sphinx
+
+ doxygen:
+ docker:
+ - image: gudhi/ci_for_gudhi:latest
+ steps:
+ - checkout
+ - run:
+ name: Generates the C++ documentation with doxygen
+ command: |
+ mkdir build;
+ cd build;
+ cmake -DCMAKE_BUILD_TYPE=Release -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_TEST=OFF -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=OFF -DUSER_VERSION_DIR=version ..;
+ make doxygen 2>&1 | tee dox.log;
+ grep warning dox.log;
+ cp dox.log version/doc/html/;
+ cp -R version/doc/html /tmp/doxygen;
+
+ - store_artifacts:
+ path: /tmp/doxygen
+
+workflows:
+ version: 2
+ build:
+ jobs:
+ - examples
+ - tests
+ - utils
+ - python
+ - doxygen \ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..5c2195be
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,17 @@
+# Classical CMake build directory
+build/
+
+# Generated by tests
+data/points/COIL_database/lucky_cat.off_dist
+data/points/COIL_database/lucky_cat.off_sc.dot
+data/points/KleinBottle5D.off_dist
+data/points/KleinBottle5D.off_sc.dot
+data/points/human.off_dist
+data/points/human.off_sc.off
+data/points/human.off_sc.txt
+
+# IDE specific
+# CLion
+.idea/
+cmake-build-debug/
+
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..b8a080ea
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,77 @@
+language: cpp
+
+sudo: required
+
+git:
+ depth: 3
+
+matrix:
+ include:
+ # A. Mac OSX
+ - os: osx
+ osx_image: xcode9.4
+ compiler: clang
+ env:
+ # 1. Only examples and associated tests
+ - CMAKE_EXAMPLE='ON' CMAKE_TEST='OFF' CMAKE_UTILITIES='OFF' CMAKE_PYTHON='OFF' MAKE_TARGET='test'
+ - os: osx
+ osx_image: xcode9.4
+ compiler: clang
+ env:
+ # 2. Only unitary tests
+ - CMAKE_EXAMPLE='OFF' CMAKE_TEST='ON' CMAKE_UTILITIES='OFF' CMAKE_PYTHON='OFF' MAKE_TARGET='test'
+ - os: osx
+ osx_image: xcode9.4
+ compiler: clang
+ env:
+ # 3. Only utilities and associated tests
+ - CMAKE_EXAMPLE='OFF' CMAKE_TEST='OFF' CMAKE_UTILITIES='ON' CMAKE_PYTHON='OFF' MAKE_TARGET='test'
+ - os: osx
+ osx_image: xcode9.4
+ compiler: clang
+ env:
+ # 4. Only doxygen documentation
+ - CMAKE_EXAMPLE='OFF' CMAKE_TEST='OFF' CMAKE_UTILITIES='OFF' CMAKE_PYTHON='OFF' MAKE_TARGET='doxygen'
+ # Issue with sphinx-build with sphinx 2.0.1
+ # - os: osx
+ # osx_image: xcode9.4
+ # compiler: clang
+ # env:
+ # # 5. Only Python, associated tests and sphinx documentation
+ # - CMAKE_EXAMPLE='OFF' CMAKE_TEST='OFF' CMAKE_UTILITIES='OFF' CMAKE_PYTHON='ON' MAKE_TARGET='test sphinx'
+
+cache:
+ directories:
+ - $HOME/.cache/pip
+
+addons:
+ homebrew:
+ packages:
+ - cmake
+ - graphviz
+ - doxygen
+ - boost
+ - eigen
+ - gmp
+ - mpfr
+ - tbb
+ - cgal
+ - python3
+
+# When installing through libcgal-dev apt, CMake Error at CGAL Exports.cmake The imported target "CGAL::CGAL Qt5" references the file
+install:
+ - python3 -m pip install --upgrade pip setuptools wheel
+ - python3 -m pip install --user pytest Cython sphinx sphinxcontrib-bibtex matplotlib numpy scipy
+
+script:
+ - rm -rf build
+ - mkdir -p build
+ - cd build
+ - cmake -DCMAKE_BUILD_TYPE=Release -DWITH_GUDHI_EXAMPLE=${CMAKE_EXAMPLE} -DWITH_GUDHI_TEST=${CMAKE_TEST} -DWITH_GUDHI_UTILITIES=${CMAKE_UTILITIES} -DWITH_GUDHI_PYTHON=${CMAKE_PYTHON} -DUSER_VERSION_DIR=version -DPython_ADDITIONAL_VERSIONS=3 ..
+ - make all ${MAKE_TARGET}
+ - cd ..
+
+notifications:
+ email:
+ on_success: change # default: always
+ on_failure: always # default: always
diff --git a/Dockerfile_ubuntu b/Dockerfile_ubuntu
new file mode 100644
index 00000000..b80dbc54
--- /dev/null
+++ b/Dockerfile_ubuntu
@@ -0,0 +1,58 @@
+FROM ubuntu:latest
+
+# Update and upgrade distribution
+RUN apt-get update && \
+ apt-get upgrade -y
+
+# Tools necessary for installing and configuring Ubuntu
+RUN apt-get install -y \
+ apt-utils \
+ locales \
+ tzdata
+
+# Timezone
+RUN echo "Europe/Paris" | tee /etc/timezone && \
+ ln -fs /usr/share/zoneinfo/Europe/Paris /etc/localtime && \
+ dpkg-reconfigure -f noninteractive tzdata
+
+# Locale with UTF-8 support
+RUN echo en_US.UTF-8 UTF-8 >> /etc/locale.gen && \
+ locale-gen && \
+ update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
+ENV LANG en_US.UTF-8
+ENV LANGUAGE en_US:en
+ENV LC_ALL en_US.UTF-8
+
+# Required for Gudhi compilation
+RUN apt-get install -y make \
+ g++ \
+ cmake \
+ graphviz \
+ perl \
+ texlive-bibtex-extra \
+ biber \
+ doxygen \
+ libboost-all-dev \
+ libeigen3-dev \
+ libgmp3-dev \
+ libmpfr-dev \
+ libtbb-dev \
+ libcgal-dev \
+ locales \
+ python3 \
+ python3-pip \
+ python3-pytest \
+ python3-tk \
+ libfreetype6-dev \
+ pkg-config
+
+RUN pip3 install \
+ numpy \
+ matplotlib \
+ scipy \
+ Cython \
+ sphinx \
+ sphinxcontrib-bibtex
+
+# apt clean up
+RUN apt autoremove && rm -rf /var/lib/apt/lists/*
diff --git a/README b/README
deleted file mode 100644
index 2bbe5d14..00000000
--- a/README
+++ /dev/null
@@ -1,11 +0,0 @@
-The Gudhi library is release under the GNU GENERAL PUBLIC LICENSE Version 3. A
-copy of the licence may be found in the file COPYING.
-
-
-To build the library, run in a Terminal:
-
-cd /path-to-gudhi/
-mkdir build
-cd build/
-cmake ..
-make
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..6cc05ff6
--- /dev/null
+++ b/README.md
@@ -0,0 +1,18 @@
+
+[![Build Status](https://travis-ci.org/GUDHI/gudhi-devel.svg?branch=master)](https://travis-ci.org/GUDHI/gudhi-devel)
+[![CircleCI](https://circleci.com/gh/GUDHI/gudhi-devel/tree/master.svg?style=svg)](https://circleci.com/gh/GUDHI/gudhi-devel/tree/master)
+
+![GUDHI](src/common/doc/Gudhi_banner.png "Topological Data Analysis (TDA) and Higher Dimensional Geometry Understanding")
+
+The GUDHI library is a generic open source C++ library, with a Python interface, for Topological Data Analysis (TDA) and Higher Dimensional Geometry Understanding. The library offers state-of-the-art data structures and algorithms to construct simplicial complexes and compute persistent homology.
+
+# Compilation and installation
+
+To install GUDHI, you can follow the [C++ compilation procedure](https://gudhi.inria.fr/doc/latest/installation.html), the [Python compilation procedure](https://gudhi.inria.fr/python/latest/installation.html), use our [conda-forge package](https://gudhi.inria.fr/conda/), or [go with Docker](https://gudhi.inria.fr/dockerfile/).
+
+# More information
+
+* [The GUDHI website](https://gudhi.inria.fr/)
+* [Contact us](https://gudhi.inria.fr/contact/)
+* [Subscribe to the GUDHI users mailing list](https://gudhi.inria.fr/keepintouch/)
+* [Tutorials](https://gudhi.inria.fr/tutorials/)
diff --git a/biblio/bibliography.bib b/biblio/bibliography.bib
index 47c6b35b..be4c2db5 100644
--- a/biblio/bibliography.bib
+++ b/biblio/bibliography.bib
@@ -1073,9 +1073,10 @@ language={English}
@article{buchet16efficient,
title = {Efficient and Robust Persistent Homology for Measures},
author = {Micka\"{e}l Buchet and Fr\'{e}d\'{e}ric Chazal and Steve Y. Oudot and Donald Sheehy},
- booktitle = {Computational Geometry: Theory and Applications},
+ journal = {Computational Geometry: Theory and Applications},
volume = {58},
pages = {70--96},
+ doi = "https://doi.org/10.1016/j.comgeo.2016.07.001",
year = {2016}
}
@@ -1083,6 +1084,7 @@ language={English}
author = {Nicholas J. Cavanna and Mahmoodreza Jahanseir and Donald R. Sheehy},
booktitle = {Proceedings of the Canadian Conference on Computational Geometry},
title = {A Geometric Perspective on Sparse Filtrations},
+ url = {http://research.cs.queensu.ca/cccg2015/CCCG15-papers/01.pdf},
year = {2015}
}
@@ -1101,6 +1103,7 @@ language={English}
volume = {49},
number = {4},
pages = {778--796},
+ doi = "10.1007/s00454-013-9513-1",
year = {2013}
}
diff --git a/data/bitmap/sinusoid.txt b/data/bitmap/sinusoid.txt
new file mode 100644
index 00000000..4318a790
--- /dev/null
+++ b/data/bitmap/sinusoid.txt
@@ -0,0 +1,77 @@
+1
+75
+10.0
+inf
+6.581647338757176
+4.961839035093842
+3.4462687716225506
+2.0647730896031224
+0.843170409296631
+-0.19751272994853286
+-1.041671820306659
+-1.679592041609764
+-2.1077394076819154
+-2.3288666774217717
+-2.351930856552615
+-2.1918247624544565
+-1.8689306968915753
+-1.4085096027502502
+-0.8399440113300294
+-0.19585746852629526
+0.4888631699173285
+1.178113272962392
+1.835652464698967
+2.4261907229474
+2.916445996426541
+3.2761416444450404
+3.47891380654902
+3.503101508895332
+3.332395828417585
+2.956328659790991
+2.3705864371935323
+1.5771394088427577
+0.5841825900410704
+-0.5941098356746579
+-1.9380093068542301
+-3.4228241352585
+-5.019639498406313
+-6.696183996487342
+-8.417796803538899
+-10.148466428045634
+-11.851909952036825
+-13.492660404643832
+-15.037129682296172
+-16.454615160584872
+-17.71821983034286
+-18.80565838211054
+-19.699925081201553
+-20.389803417622236
+-20.870202256994908
+-21.142308418277846
+-21.213551105635062
+-21.0973792604076
+-20.812858505791425
+-20.38409976350673
+-19.839536666415423
+-19.211073422523185
+-18.53312866828296
+-17.841603966244676
+-17.172807860451854
+-16.562367734888753
+-16.044162085815913
+-15.649305207041936
+-15.405214716400426
+-15.334789869008524
+-15.455725282681154
+-15.779980642668242
+-16.3134222782912
+-17.055647353175157
+-17.999995937972063
+-19.13375060376363
+-20.438517554470188
+-21.890777875994743
+-23.46259238155293
+-25.122438929469578
+-26.836157119615592
+-28.567972056597156
+-30.281566498233445
diff --git a/data/points/bunny.COPYRIGHT b/data/points/bunny.COPYRIGHT
index 310ca5b5..e8c47dd9 100644
--- a/data/points/bunny.COPYRIGHT
+++ b/data/points/bunny.COPYRIGHT
@@ -1,4 +1,4 @@
-The bunny pointset comes from the Stanford Computer Graphics Laboratory.
+The bunny pointsets comes from the Stanford Computer Graphics Laboratory.
http://graphics.stanford.edu/data/3Dscanrep/
Please acknowledge...
diff --git a/data/points/grid_5_5_5_in_0_1.off b/data/points/grid_5_5_5_in_0_1.off
new file mode 100644
index 00000000..148bf773
--- /dev/null
+++ b/data/points/grid_5_5_5_in_0_1.off
@@ -0,0 +1,127 @@
+OFF
+125 0 0
+0.0, 0.0, 0.2
+0.0, 0.0, 0.4
+0.0, 0.0, 0.6
+0.0, 0.0, 0.8
+0.0, 0.2, 0.0
+0.0, 0.2, 0.2
+0.0, 0.2, 0.4
+0.0, 0.2, 0.6
+0.0, 0.2, 0.8
+0.0, 0.4, 0.0
+0.0, 0.4, 0.2
+0.0, 0.4, 0.4
+0.0, 0.4, 0.6
+0.0, 0.4, 0.8
+0.0, 0.6, 0.0
+0.0, 0.6, 0.2
+0.0, 0.6, 0.4
+0.0, 0.6, 0.6
+0.0, 0.6, 0.8
+0.0, 0.8, 0.0
+0.0, 0.8, 0.2
+0.0, 0.8, 0.4
+0.0, 0.8, 0.6
+0.0, 0.8, 0.8
+0.2, 0.0, 0.0
+0.2, 0.0, 0.2
+0.2, 0.0, 0.4
+0.2, 0.0, 0.6
+0.2, 0.0, 0.8
+0.2, 0.2, 0.0
+0.2, 0.2, 0.2
+0.2, 0.2, 0.4
+0.2, 0.2, 0.6
+0.2, 0.2, 0.8
+0.2, 0.4, 0.0
+0.2, 0.4, 0.2
+0.2, 0.4, 0.4
+0.2, 0.4, 0.6
+0.2, 0.4, 0.8
+0.2, 0.6, 0.0
+0.2, 0.6, 0.2
+0.2, 0.6, 0.4
+0.2, 0.6, 0.6
+0.2, 0.6, 0.8
+0.0, 0.0, 0.0
+0.2, 0.8, 0.0
+0.2, 0.8, 0.2
+0.2, 0.8, 0.4
+0.2, 0.8, 0.6
+0.2, 0.8, 0.8
+0.4, 0.0, 0.0
+0.4, 0.0, 0.2
+0.4, 0.0, 0.4
+0.4, 0.0, 0.6
+0.4, 0.0, 0.8
+0.4, 0.2, 0.0
+0.4, 0.2, 0.2
+0.4, 0.2, 0.4
+0.4, 0.2, 0.6
+0.4, 0.2, 0.8
+0.4, 0.4, 0.0
+0.4, 0.4, 0.2
+0.4, 0.4, 0.4
+0.4, 0.4, 0.6
+0.4, 0.4, 0.8
+0.4, 0.6, 0.0
+0.4, 0.6, 0.2
+0.4, 0.6, 0.4
+0.4, 0.6, 0.6
+0.4, 0.6, 0.8
+0.4, 0.8, 0.0
+0.4, 0.8, 0.2
+0.4, 0.8, 0.4
+0.4, 0.8, 0.6
+0.4, 0.8, 0.8
+0.6, 0.0, 0.0
+0.6, 0.0, 0.2
+0.6, 0.0, 0.4
+0.6, 0.0, 0.6
+0.6, 0.0, 0.8
+0.6, 0.1, 0.0
+0.6, 0.2, 0.0
+0.6, 0.2, 0.2
+0.6, 0.2, 0.4
+0.6, 0.2, 0.6
+0.6, 0.2, 0.8
+0.6, 0.4, 0.0
+0.6, 0.4, 0.2
+0.6, 0.4, 0.4
+0.6, 0.4, 0.6
+0.6, 0.4, 0.8
+0.6, 0.6, 0.0
+0.6, 0.6, 0.2
+0.6, 0.6, 0.4
+0.6, 0.6, 0.6
+0.6, 0.6, 0.8
+0.6, 0.8, 0.0
+0.6, 0.8, 0.2
+0.6, 0.8, 0.4
+0.6, 0.8, 0.6
+0.6, 0.8, 0.8
+0.8, 0.0, 0.0
+0.8, 0.0, 0.2
+0.8, 0.0, 0.4
+0.8, 0.0, 0.6
+0.8, 0.0, 0.8
+0.8, 0.2, 0.0
+0.8, 0.2, 0.2
+0.8, 0.2, 0.4
+0.8, 0.2, 0.6
+0.8, 0.2, 0.8
+0.8, 0.4, 0.0
+0.8, 0.4, 0.2
+0.8, 0.4, 0.4
+0.8, 0.4, 0.6
+0.8, 0.4, 0.8
+0.8, 0.6, 0.0
+0.8, 0.6, 0.2
+0.8, 0.6, 0.4
+0.8, 0.6, 0.6
+0.8, 0.6, 0.8
+0.8, 0.8, 0.0
+0.8, 0.8, 0.2
+0.8, 0.8, 0.4
+0.8, 0.8, 0.6
diff --git a/src/Alpha_complex/benchmark/Alpha_complex_3d_benchmark.cpp b/src/Alpha_complex/benchmark/Alpha_complex_3d_benchmark.cpp
new file mode 100644
index 00000000..005a712a
--- /dev/null
+++ b/src/Alpha_complex/benchmark/Alpha_complex_3d_benchmark.cpp
@@ -0,0 +1,278 @@
+#include <gudhi/Alpha_complex_3d.h>
+#include <gudhi/Alpha_complex.h>
+// to construct a simplex_tree from alpha complex
+#include <gudhi/Simplex_tree.h>
+#include <gudhi/random_point_generators.h>
+#include <gudhi/Clock.h>
+
+#include <iostream>
+#include <string>
+#include <vector>
+#include <limits> // for numeric limits
+#include <fstream>
+
+#include <CGAL/Epick_d.h>
+#include <CGAL/Epeck_d.h>
+#include <CGAL/Random.h>
+
+std::ofstream results_csv("results.csv");
+
+template <typename Kernel>
+void benchmark_points_on_torus_dD(const std::string& msg) {
+ std::cout << "+ " << msg << std::endl;
+
+ results_csv << "\"" << msg << "\";" << std::endl;
+ results_csv << "\"nb_points\";"
+ << "\"nb_simplices\";"
+ << "\"alpha_creation_time(sec.)\";"
+ << "\"complex_creation_time(sec.)\";" << std::endl;
+
+ using K = CGAL::Epick_d<CGAL::Dimension_tag<3>>;
+ for (int nb_points = 1000; nb_points <= 125000; nb_points *= 5) {
+ std::cout << " Alpha complex dD on torus with " << nb_points << " points." << std::endl;
+ std::vector<K::Point_d> points_on_torus = Gudhi::generate_points_on_torus_3D<K>(nb_points, 1.0, 0.5);
+ std::vector<typename Kernel::Point_d> points;
+
+ for (auto p : points_on_torus) {
+ points.push_back(typename Kernel::Point_d(p.begin(), p.end()));
+ }
+
+ Gudhi::Clock ac_create_clock(" benchmark_points_on_torus_dD - Alpha complex 3d creation");
+ ac_create_clock.begin();
+ Gudhi::alpha_complex::Alpha_complex<Kernel> alpha_complex_from_points(points);
+ ac_create_clock.end();
+ std::cout << ac_create_clock;
+
+ Gudhi::Simplex_tree<> complex;
+ Gudhi::Clock st_create_clock(" benchmark_points_on_torus_dD - complex creation");
+ st_create_clock.begin();
+ alpha_complex_from_points.create_complex(complex);
+ st_create_clock.end();
+ std::cout << st_create_clock;
+
+ results_csv << nb_points << ";" << complex.num_simplices() << ";" << ac_create_clock.num_seconds() << ";"
+ << st_create_clock.num_seconds() << ";" << std::endl;
+
+ std::cout << " benchmark_points_on_torus_dD - nb simplices = " << complex.num_simplices() << std::endl;
+ }
+}
+
+template <typename Alpha_complex_3d>
+void benchmark_points_on_torus_3D(const std::string& msg) {
+ using K = CGAL::Epick_d<CGAL::Dimension_tag<3>>;
+ std::cout << "+ " << msg << std::endl;
+
+ results_csv << "\"" << msg << "\";" << std::endl;
+ results_csv << "\"nb_points\";"
+ << "\"nb_simplices\";"
+ << "\"alpha_creation_time(sec.)\";"
+ << "\"complex_creation_time(sec.)\";" << std::endl;
+
+ for (int nb_points = 1000; nb_points <= 125000; nb_points *= 5) {
+ std::cout << " Alpha complex 3d on torus with " << nb_points << " points." << std::endl;
+ std::vector<K::Point_d> points_on_torus = Gudhi::generate_points_on_torus_3D<K>(nb_points, 1.0, 0.5);
+ std::vector<typename Alpha_complex_3d::Point_3> points;
+
+ for (auto p : points_on_torus) {
+ points.push_back(typename Alpha_complex_3d::Point_3(p[0], p[1], p[2]));
+ }
+
+ Gudhi::Clock ac_create_clock(" benchmark_points_on_torus_3D - Alpha complex 3d creation");
+ ac_create_clock.begin();
+ Alpha_complex_3d alpha_complex_from_points(points);
+ ac_create_clock.end();
+ std::cout << ac_create_clock;
+
+ Gudhi::Simplex_tree<> complex;
+ Gudhi::Clock st_create_clock(" benchmark_points_on_torus_3D - complex creation");
+ st_create_clock.begin();
+ alpha_complex_from_points.create_complex(complex);
+ st_create_clock.end();
+ std::cout << st_create_clock;
+
+ results_csv << nb_points << ";" << complex.num_simplices() << ";" << ac_create_clock.num_seconds() << ";"
+ << st_create_clock.num_seconds() << ";" << std::endl;
+
+ std::cout << " benchmark_points_on_torus_3D - nb simplices = " << complex.num_simplices() << std::endl;
+ }
+}
+
+template <typename Weighted_alpha_complex_3d>
+void benchmark_weighted_points_on_torus_3D(const std::string& msg) {
+ using K = CGAL::Epick_d<CGAL::Dimension_tag<3>>;
+
+ std::cout << "+ " << msg << std::endl;
+
+ results_csv << "\"" << msg << "\";" << std::endl;
+ results_csv << "\"nb_points\";"
+ << "\"nb_simplices\";"
+ << "\"alpha_creation_time(sec.)\";"
+ << "\"complex_creation_time(sec.)\";" << std::endl;
+
+ CGAL::Random random(8);
+
+ for (int nb_points = 1000; nb_points <= 125000; nb_points *= 5) {
+ std::cout << " Alpha complex 3d on torus with " << nb_points << " points." << std::endl;
+ std::vector<K::Point_d> points_on_torus = Gudhi::generate_points_on_torus_3D<K>(nb_points, 1.0, 0.5);
+
+ using Point = typename Weighted_alpha_complex_3d::Point_3;
+ using Weighted_point = typename Weighted_alpha_complex_3d::Weighted_point_3;
+
+ std::vector<Weighted_point> points;
+
+ for (auto p : points_on_torus) {
+ points.push_back(Weighted_point(Point(p[0], p[1], p[2]), 0.9 + random.get_double(0., 0.01)));
+ }
+
+ Gudhi::Clock ac_create_clock(" benchmark_weighted_points_on_torus_3D - Alpha complex 3d creation");
+ ac_create_clock.begin();
+ Weighted_alpha_complex_3d alpha_complex_from_points(points);
+ ac_create_clock.end();
+ std::cout << ac_create_clock;
+
+ Gudhi::Simplex_tree<> complex;
+ Gudhi::Clock st_create_clock(" benchmark_weighted_points_on_torus_3D - complex creation");
+ st_create_clock.begin();
+ alpha_complex_from_points.create_complex(complex);
+ st_create_clock.end();
+ std::cout << st_create_clock;
+
+ results_csv << nb_points << ";" << complex.num_simplices() << ";" << ac_create_clock.num_seconds() << ";"
+ << st_create_clock.num_seconds() << ";" << std::endl;
+
+ std::cout << " benchmark_weighted_points_on_torus_3D - nb simplices = " << complex.num_simplices() << std::endl;
+ }
+}
+
+template <typename Periodic_alpha_complex_3d>
+void benchmark_periodic_points(const std::string& msg) {
+ std::cout << "+ " << msg << std::endl;
+
+ results_csv << "\"" << msg << "\";" << std::endl;
+ results_csv << "\"nb_points\";"
+ << "\"nb_simplices\";"
+ << "\"alpha_creation_time(sec.)\";"
+ << "\"complex_creation_time(sec.)\";" << std::endl;
+
+ CGAL::Random random(8);
+
+ for (double nb_points = 10.; nb_points <= 40.; nb_points += 10.) {
+ std::cout << " Periodic alpha complex 3d with " << nb_points * nb_points * nb_points << " points." << std::endl;
+ using Point = typename Periodic_alpha_complex_3d::Point_3;
+ std::vector<Point> points;
+
+ for (double i = 0; i < nb_points; i++) {
+ for (double j = 0; j < nb_points; j++) {
+ for (double k = 0; k < nb_points; k++) {
+ points.push_back(
+ Point(i + random.get_double(0., 0.1), j + random.get_double(0., 0.1), k + random.get_double(0., 0.1)));
+ }
+ }
+ }
+
+ Gudhi::Clock ac_create_clock(" benchmark_periodic_points - Alpha complex 3d creation");
+ ac_create_clock.begin();
+ Periodic_alpha_complex_3d alpha_complex_from_points(points, 0., 0., 0., nb_points, nb_points, nb_points);
+ ac_create_clock.end();
+ std::cout << ac_create_clock;
+
+ Gudhi::Simplex_tree<> complex;
+ Gudhi::Clock st_create_clock(" benchmark_periodic_points - complex creation");
+ st_create_clock.begin();
+ alpha_complex_from_points.create_complex(complex);
+ st_create_clock.end();
+ std::cout << st_create_clock;
+
+ results_csv << nb_points * nb_points * nb_points << ";" << complex.num_simplices() << ";"
+ << ac_create_clock.num_seconds() << ";" << st_create_clock.num_seconds() << ";" << std::endl;
+
+ std::cout << " benchmark_periodic_points - nb simplices = " << complex.num_simplices() << std::endl;
+ }
+}
+
+template <typename Weighted_periodic_alpha_complex_3d>
+void benchmark_weighted_periodic_points(const std::string& msg) {
+ std::cout << "+ " << msg << std::endl;
+
+ results_csv << "\"" << msg << "\";" << std::endl;
+ results_csv << "\"nb_points\";"
+ << "\"nb_simplices\";"
+ << "\"alpha_creation_time(sec.)\";"
+ << "\"complex_creation_time(sec.)\";" << std::endl;
+
+ CGAL::Random random(8);
+
+ for (double nb_points = 10.; nb_points <= 40.; nb_points += 10.) {
+ std::cout << " Weighted periodic alpha complex 3d with " << nb_points * nb_points * nb_points << " points."
+ << std::endl;
+
+ using Point = typename Weighted_periodic_alpha_complex_3d::Point_3;
+ using Weighted_point = typename Weighted_periodic_alpha_complex_3d::Weighted_point_3;
+ std::vector<Weighted_point> points;
+
+ for (double i = 0; i < nb_points; i++) {
+ for (double j = 0; j < nb_points; j++) {
+ for (double k = 0; k < nb_points; k++) {
+ points.push_back(Weighted_point(
+ Point(i + random.get_double(0., 0.1), j + random.get_double(0., 0.1), k + random.get_double(0., 0.1)),
+ random.get_double(0., (nb_points * nb_points) / 64.)));
+ }
+ }
+ }
+
+ Gudhi::Clock ac_create_clock(" benchmark_weighted_periodic_points - Alpha complex 3d creation");
+ ac_create_clock.begin();
+ Weighted_periodic_alpha_complex_3d alpha_complex_from_points(points, 0., 0., 0., nb_points, nb_points, nb_points);
+ ac_create_clock.end();
+ std::cout << ac_create_clock;
+
+ Gudhi::Simplex_tree<> complex;
+ Gudhi::Clock st_create_clock(" benchmark_weighted_periodic_points - complex creation");
+ st_create_clock.begin();
+ alpha_complex_from_points.create_complex(complex);
+ st_create_clock.end();
+ std::cout << st_create_clock;
+
+ results_csv << nb_points * nb_points * nb_points << ";" << complex.num_simplices() << ";"
+ << ac_create_clock.num_seconds() << ";" << st_create_clock.num_seconds() << ";" << std::endl;
+
+ std::cout << " benchmark_weighted_periodic_points - nb simplices = " << complex.num_simplices() << std::endl;
+ }
+}
+
+int main(int argc, char** argv) {
+ benchmark_points_on_torus_dD<CGAL::Epick_d<CGAL::Dimension_tag<3>>>("Fast static dimension version");
+ benchmark_points_on_torus_dD<CGAL::Epick_d<CGAL::Dynamic_dimension_tag>>("Fast dynamic dimension version");
+ benchmark_points_on_torus_dD<CGAL::Epeck_d<CGAL::Dimension_tag<3>>>("Exact static dimension version");
+ benchmark_points_on_torus_dD<CGAL::Epeck_d<CGAL::Dynamic_dimension_tag>>("Exact dynamic dimension version");
+
+ benchmark_points_on_torus_3D<
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::FAST, false, false>>("Fast version");
+ benchmark_points_on_torus_3D<
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::SAFE, false, false>>("Safe version");
+ benchmark_points_on_torus_3D<
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::EXACT, false, false>>("Exact version");
+
+ benchmark_weighted_points_on_torus_3D<
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::FAST, true, false>>("Fast version");
+ benchmark_weighted_points_on_torus_3D<
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::SAFE, true, false>>("Safe version");
+ benchmark_weighted_points_on_torus_3D<
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::EXACT, true, false>>("Exact version");
+
+ benchmark_periodic_points<
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::FAST, false, true>>("Fast version");
+ benchmark_periodic_points<
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::SAFE, false, true>>("Safe version");
+ benchmark_periodic_points<
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::EXACT, false, true>>("Exact version");
+
+ benchmark_weighted_periodic_points<
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::FAST, true, true>>("Fast version");
+ benchmark_weighted_periodic_points<
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::SAFE, true, true>>("Safe version");
+ benchmark_weighted_periodic_points<
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::EXACT, true, true>>("Exact version");
+
+ return 0;
+}
diff --git a/src/Alpha_complex/benchmark/CMakeLists.txt b/src/Alpha_complex/benchmark/CMakeLists.txt
new file mode 100644
index 00000000..622963dc
--- /dev/null
+++ b/src/Alpha_complex/benchmark/CMakeLists.txt
@@ -0,0 +1,9 @@
+project(Alpha_complex_benchmark)
+
+if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0)
+ add_executable(Alpha_complex_3d_benchmark Alpha_complex_3d_benchmark.cpp)
+ target_link_libraries(Alpha_complex_3d_benchmark ${CGAL_LIBRARY})
+ if (TBB_FOUND)
+ target_link_libraries(Alpha_complex_3d_benchmark ${TBB_LIBRARIES})
+ endif()
+endif ()
diff --git a/src/Alpha_complex/concept/SimplicialComplexForAlpha.h b/src/Alpha_complex/concept/SimplicialComplexForAlpha.h
index a51df127..ba97c802 100644
--- a/src/Alpha_complex/concept/SimplicialComplexForAlpha.h
+++ b/src/Alpha_complex/concept/SimplicialComplexForAlpha.h
@@ -41,9 +41,6 @@ struct SimplicialComplexForAlpha {
/** Returns the number of vertices in the simplicial complex. */
std::size_t num_vertices();
- /** Sets the simplicial complex dimension. */
- void set_dimension(int dimension);
-
/** Gets the 'simplex' dimension. */
int dimension(Simplex_handle simplex);
@@ -65,8 +62,7 @@ struct SimplicialComplexForAlpha {
* 'value type' must be 'Vertex_handle'.*/
typedef unspecified Simplex_vertex_range;
- /** \brief Returns a range over vertices of a given
- * simplex. */
+ /** \brief Returns a range over vertices of a given simplex. */
Simplex_vertex_range simplex_vertex_range(Simplex_handle const & simplex);
/** \brief Iterator over the boundaries of the complex, in an arbitrary order.
@@ -77,6 +73,14 @@ struct SimplicialComplexForAlpha {
/** \brief Returns a range over boundaries of a given simplex. */
Boundary_simplex_range boundary_simplex_range(Simplex_handle const & simplex);
+ /** \brief Iterator over the simplices of the skeleton of the complex, for a given dimension.
+ *
+ * 'value_type' must be 'Simplex_handle'. */
+ typedef unspecified Skeleton_simplex_range;
+ /** \brief Returns a range over the simplices of the skeleton of the simplicial complex, for a given
+ * dimension. */
+ Skeleton_simplex_range skeleton_simplex_range;
+
/** \brief Return type of an insertion of a simplex
*/
typedef unspecified Insertion_result_type;
diff --git a/src/Alpha_complex/concept/SimplicialComplexForAlpha3d.h b/src/Alpha_complex/concept/SimplicialComplexForAlpha3d.h
new file mode 100644
index 00000000..7acdf105
--- /dev/null
+++ b/src/Alpha_complex/concept/SimplicialComplexForAlpha3d.h
@@ -0,0 +1,57 @@
+/* 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) 2018 Inria
+ *
+ * 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 CONCEPT_ALPHA_COMPLEX_SIMPLICIAL_COMPLEX_FOR_ALPHA_3D_H_
+#define CONCEPT_ALPHA_COMPLEX_SIMPLICIAL_COMPLEX_FOR_ALPHA_3D_H_
+
+namespace Gudhi {
+
+namespace alpha_complex {
+
+/** \brief The concept SimplicialComplexForAlpha3d describes the requirements for a type to implement a simplicial
+ * complex, that can be created from a `Alpha_complex_3d`.
+ */
+struct SimplicialComplexForAlpha3d {
+ /** Handle to specify a vertex. Must be a non-negative integer. */
+ typedef unspecified Vertex_handle;
+ /** Handle to specify the simplex filtration value. */
+ typedef unspecified Filtration_value;
+
+ /** Returns the number of vertices in the simplicial complex. */
+ std::size_t num_vertices();
+
+ /** \brief Inserts a simplex from a given simplex (represented by a vector of Vertex_handle) in the
+ * simplicial complex with the given 'filtration' value. */
+ void insert_simplex(std::vector<Vertex_handle> const& vertex_range, Filtration_value filtration);
+
+ /** Browses the simplicial complex to make the filtration non-decreasing. */
+ void make_filtration_non_decreasing();
+
+ /** Prune the simplicial complex above 'filtration' value given as parameter. */
+ void prune_above_filtration(Filtration_value filtration);
+};
+
+} // namespace alpha_complex
+
+} // namespace Gudhi
+
+#endif // CONCEPT_ALPHA_COMPLEX_SIMPLICIAL_COMPLEX_FOR_ALPHA_3D_H_
diff --git a/src/Alpha_complex/doc/Intro_alpha_complex.h b/src/Alpha_complex/doc/Intro_alpha_complex.h
index 7a375c9f..ab7c4794 100644
--- a/src/Alpha_complex/doc/Intro_alpha_complex.h
+++ b/src/Alpha_complex/doc/Intro_alpha_complex.h
@@ -29,34 +29,34 @@ namespace Gudhi {
namespace alpha_complex {
/** \defgroup alpha_complex Alpha complex
- *
+ *
* \author Vincent Rouvreau
*
* @{
- *
+ *
* \section definition Definition
- *
+ *
* Alpha_complex is a <a target="_blank" href="https://en.wikipedia.org/wiki/Simplicial_complex">simplicial complex</a>
* constructed from the finite cells of a Delaunay Triangulation.
- *
+ *
* The filtration value of each simplex is computed as the square of the circumradius of the simplex if the
* circumsphere is empty (the simplex is then said to be Gabriel), and as the minimum of the filtration
* values of the codimension 1 cofaces that make it not Gabriel otherwise.
- *
+ *
* All simplices that have a filtration value strictly greater than a given alpha squared value are not inserted into
* the complex.
- *
+ *
* \image html "alpha_complex_representation.png" "Alpha-complex representation"
- *
+ *
* Alpha_complex is constructing a <a target="_blank"
* href="http://doc.cgal.org/latest/Triangulation/index.html#Chapter_Triangulations">Delaunay Triangulation</a>
* \cite cgal:hdj-t-15b from <a target="_blank" href="http://www.cgal.org/">CGAL</a> (the Computational Geometry
* Algorithms Library \cite cgal:eb-15b) and is able to create a `SimplicialComplexForAlpha`.
- *
+ *
* The complex is a template class requiring an Epick_d <a target="_blank"
* href="http://doc.cgal.org/latest/Kernel_d/index.html#Chapter_dD_Geometry_Kernel">dD Geometry Kernel</a>
* \cite cgal:s-gkd-15b from CGAL as template parameter.
- *
+ *
* \remark
* - When the simplicial complex is constructed with an infinite value of alpha, the complex is a Delaunay
* complex.
@@ -65,30 +65,30 @@ namespace alpha_complex {
* \ref cech_complex can still make sense in higher dimension precisely because you can bound the radii.
*
* \section pointsexample Example from points
- *
+ *
* This example builds the Delaunay triangulation from the given points in a 2D static kernel, and creates a
* `Simplex_tree` with it.
- *
+ *
* Then, it is asked to display information about the simplicial complex.
- *
+ *
* \include Alpha_complex/Alpha_complex_from_points.cpp
- *
+ *
* When launching:
- *
+ *
* \code $> ./Alpha_complex_example_from_points
* \endcode
*
* the program output is:
- *
+ *
* \include Alpha_complex/alphaoffreader_for_doc_60.txt
- *
+ *
* \section createcomplexalgorithm Create complex algorithm
- *
+ *
* \subsection datastructure Data structure
- *
+ *
* In order to create the simplicial complex, first, it is built from the cells of the Delaunay Triangulation.
* The filtration values are set to NaN, which stands for unknown value.
- *
+ *
* In example, :
* \image html "alpha_complex_doc.png" "Simplicial complex structure construction example"
*
@@ -106,7 +106,7 @@ namespace alpha_complex {
* \quad\quad\quad\quad \text{filtration(} \tau \text{) = min( filtration(} \tau \text{), filtration(} \sigma
* \text{) )}\\
* \quad\quad\quad \textbf{else}\\
- * \quad\quad\quad\quad \textbf{if } \textbf{if } \tau \text{ is not Gabriel for } \sigma \textbf{ then}\\
+ * \quad\quad\quad\quad \textbf{if } \tau \text{ is not Gabriel for } \sigma \textbf{ then}\\
* \quad\quad\quad\quad\quad \text{filtration(} \tau \text{) = filtration(} \sigma \text{)}\\
* \quad\quad\quad\quad \textbf{end if}\\
* \quad\quad\quad \textbf{end if}\\
@@ -118,53 +118,78 @@ namespace alpha_complex {
* \f$
*
* \subsubsection dimension2 Dimension 2
- *
+ *
* From the example above, it means the algorithm looks into each triangle ([0,1,2], [0,2,4], [1,2,3], ...),
* computes the filtration value of the triangle, and then propagates the filtration value as described
* here :
* \image html "alpha_complex_doc_420.png" "Filtration value propagation example"
- *
+ *
* \subsubsection dimension1 Dimension 1
- *
+ *
* Then, the algorithm looks into each edge ([0,1], [0,2], [1,2], ...),
* computes the filtration value of the edge (in this case, propagation will have no effect).
- *
+ *
* \subsubsection dimension0 Dimension 0
- *
+ *
* Finally, the algorithm looks into each vertex ([0], [1], [2], [3], [4], [5] and [6]) and
* sets the filtration value (0 in case of a vertex - propagation will have no effect).
- *
+ *
* \subsubsection nondecreasing Non decreasing filtration values
- *
+ *
* As the squared radii computed by CGAL are an approximation, it might happen that these alpha squared values do not
* quite define a proper filtration (i.e. non-decreasing with respect to inclusion).
* We fix that up by calling `SimplicialComplexForAlpha::make_filtration_non_decreasing()`.
- *
+ *
* \subsubsection pruneabove Prune above given filtration value
- *
+ *
* The simplex tree is pruned from the given maximum alpha squared value (cf.
* `SimplicialComplexForAlpha::prune_above_filtration()`).
* In the following example, the value is given by the user as argument of the program.
- *
- *
+ *
+ *
* \section offexample Example from OFF file
- *
+ *
* This example builds the Delaunay triangulation in a dynamic kernel, and initializes the alpha complex with it.
- *
- *
+ *
+ *
* Then, it is asked to display information about the alpha complex.
- *
+ *
* \include Alpha_complex/Alpha_complex_from_off.cpp
- *
+ *
* When launching:
- *
+ *
* \code $> ./Alpha_complex_example_from_off ../../data/points/alphacomplexdoc.off 32.0
* \endcode
*
* the program output is:
- *
+ *
* \include Alpha_complex/alphaoffreader_for_doc_32.txt
- *
+ *
+ *
+ * \section weighted3dexample 3d specific example
+ *
+ * A specific module for Alpha complex is available in 3d (cf. Alpha_complex_3d) and allows to construct standard,
+ * weighted, periodic or weighted and periodic versions of alpha complexes. Alpha values computation can be
+ * Gudhi::alpha_complex::complexity::FAST, Gudhi::alpha_complex::complexity::SAFE (default value) or
+ * Gudhi::alpha_complex::complexity::EXACT.
+ *
+ * This example builds the CGAL 3d weighted alpha shapes from a small molecule, and initializes the alpha complex with
+ * it. This example is taken from <a href="https://doc.cgal.org/latest/Alpha_shapes_3/index.html#title13">CGAL 3d
+ * weighted alpha shapes</a>.
+ *
+ * Then, it is asked to display information about the alpha complex.
+ *
+ * \include Alpha_complex/Weighted_alpha_complex_3d_from_points.cpp
+ *
+ * When launching:
+ *
+ * \code $> ./Alpha_complex_example_weighted_3d_from_points
+ * \endcode
+ *
+ * the program output is:
+ *
+ * \include Alpha_complex/weightedalpha3dfrompoints_for_doc.txt
+ *
*/
/** @} */ // end defgroup alpha_complex
diff --git a/src/Alpha_complex/example/Alpha_complex_3d_from_points.cpp b/src/Alpha_complex/example/Alpha_complex_3d_from_points.cpp
new file mode 100644
index 00000000..0e359a27
--- /dev/null
+++ b/src/Alpha_complex/example/Alpha_complex_3d_from_points.cpp
@@ -0,0 +1,56 @@
+#include <gudhi/Alpha_complex_3d.h>
+// to construct a simplex_tree from alpha complex
+#include <gudhi/Simplex_tree.h>
+
+#include <iostream>
+#include <string>
+#include <vector>
+#include <limits> // for numeric limits
+
+using Alpha_complex_3d = Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::SAFE, false, false>;
+using Point = Alpha_complex_3d::Point_3;
+using Vector_of_points = std::vector<Point>;
+
+int main(int argc, char **argv) {
+ if (argc != 1) {
+ std::cerr << "Error: Number of arguments (" << argc << ") is not correct\n";
+ std::cerr << "Usage: " << (argv[0] - 1) << " \n";
+ exit(-1); // ----- >>
+ }
+
+ // ----------------------------------------------------------------------------
+ // Init of a list of points from a small molecule
+ // ----------------------------------------------------------------------------
+ Vector_of_points points;
+ points.push_back(Point(1, -1, -1));
+ points.push_back(Point(-1, 1, -1));
+ points.push_back(Point(-1, -1, 1));
+ points.push_back(Point(1, 1, 1));
+ points.push_back(Point(2, 2, 2));
+
+ // ----------------------------------------------------------------------------
+ // Init of an alpha complex from the list of points
+ // ----------------------------------------------------------------------------
+ Alpha_complex_3d alpha_complex_from_points(points);
+
+ Gudhi::Simplex_tree<> simplex;
+ if (alpha_complex_from_points.create_complex(simplex)) {
+ // ----------------------------------------------------------------------------
+ // Display information about the alpha complex
+ // ----------------------------------------------------------------------------
+ std::cout << "Alpha complex is of dimension " << simplex.dimension() << " - " << simplex.num_simplices()
+ << " simplices - " << simplex.num_vertices() << " vertices." << std::endl;
+
+ std::cout << "Iterator on alpha complex simplices in the filtration order, with [filtration value]:" << std::endl;
+ for (auto f_simplex : simplex.filtration_simplex_range()) {
+ std::cout << " ( ";
+ for (auto vertex : simplex.simplex_vertex_range(f_simplex)) {
+ std::cout << vertex << " ";
+ }
+ std::cout << ") -> "
+ << "[" << simplex.filtration(f_simplex) << "] ";
+ std::cout << std::endl;
+ }
+ }
+ return 0;
+}
diff --git a/src/Alpha_complex/example/Alpha_complex_from_points.cpp b/src/Alpha_complex/example/Alpha_complex_from_points.cpp
index c19f7cc8..981aa470 100644
--- a/src/Alpha_complex/example/Alpha_complex_from_points.cpp
+++ b/src/Alpha_complex/example/Alpha_complex_from_points.cpp
@@ -5,29 +5,13 @@
#include <CGAL/Epick_d.h>
#include <iostream>
-#include <string>
#include <vector>
-#include <limits> // for numeric limits
using Kernel = CGAL::Epick_d< CGAL::Dimension_tag<2> >;
using Point = Kernel::Point_d;
using Vector_of_points = std::vector<Point>;
-void usage(int nbArgs, char * const progName) {
- std::cerr << "Error: Number of arguments (" << nbArgs << ") is not correct\n";
- std::cerr << "Usage: " << progName << " [alpha_square_max_value]\n";
- std::cerr << " i.e.: " << progName << " 60.0\n";
- exit(-1); // ----- >>
-}
-
-int main(int argc, char **argv) {
- if ((argc != 1) && (argc != 2)) usage(argc, (argv[0] - 1));
-
- // Delaunay complex if alpha_square_max_value is not given by the user.
- double alpha_square_max_value {std::numeric_limits<double>::infinity()};
- if (argc == 2)
- alpha_square_max_value = atof(argv[1]);
-
+int main() {
// ----------------------------------------------------------------------------
// Init of a list of points
// ----------------------------------------------------------------------------
@@ -46,7 +30,7 @@ int main(int argc, char **argv) {
Gudhi::alpha_complex::Alpha_complex<Kernel> alpha_complex_from_points(points);
Gudhi::Simplex_tree<> simplex;
- if (alpha_complex_from_points.create_complex(simplex, alpha_square_max_value)) {
+ if (alpha_complex_from_points.create_complex(simplex)) {
// ----------------------------------------------------------------------------
// Display information about the alpha complex
// ----------------------------------------------------------------------------
diff --git a/src/Alpha_complex/example/CMakeLists.txt b/src/Alpha_complex/example/CMakeLists.txt
index 2fc62452..c62a220c 100644
--- a/src/Alpha_complex/example/CMakeLists.txt
+++ b/src/Alpha_complex/example/CMakeLists.txt
@@ -1,7 +1,5 @@
project(Alpha_complex_examples)
-# need CGAL 4.7
-# cmake -DCGAL_DIR=~/workspace/CGAL-4.7 ..
if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0)
add_executable ( Alpha_complex_example_from_points Alpha_complex_from_points.cpp )
target_link_libraries(Alpha_complex_example_from_points ${CGAL_LIBRARY})
@@ -28,8 +26,23 @@ if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0)
add_test(Alpha_complex_example_from_off_32_diff_files ${DIFF_PATH}
${CMAKE_CURRENT_BINARY_DIR}/alphaoffreader_result_32.txt ${CMAKE_CURRENT_BINARY_DIR}/alphaoffreader_for_doc_32.txt)
endif()
+endif(NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0)
- install(TARGETS Alpha_complex_example_from_points DESTINATION bin)
- install(TARGETS Alpha_complex_example_from_off DESTINATION bin)
+if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0)
+ add_executable ( Alpha_complex_example_weighted_3d_from_points Weighted_alpha_complex_3d_from_points.cpp )
+ target_link_libraries(Alpha_complex_example_weighted_3d_from_points ${CGAL_LIBRARY})
+ if (TBB_FOUND)
+ target_link_libraries(Alpha_complex_example_weighted_3d_from_points ${TBB_LIBRARIES})
+ endif()
+ add_test(NAME Alpha_complex_example_weighted_3d_from_points
+ COMMAND $<TARGET_FILE:Alpha_complex_example_weighted_3d_from_points>)
-endif(NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0)
+ add_executable ( Alpha_complex_example_3d_from_points Alpha_complex_3d_from_points.cpp )
+ target_link_libraries(Alpha_complex_example_3d_from_points ${CGAL_LIBRARY})
+ if (TBB_FOUND)
+ target_link_libraries(Alpha_complex_example_3d_from_points ${TBB_LIBRARIES})
+ endif()
+ add_test(NAME Alpha_complex_example_3d_from_points
+ COMMAND $<TARGET_FILE:Alpha_complex_example_3d_from_points>)
+
+endif(NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0)
diff --git a/src/Alpha_complex/example/Weighted_alpha_complex_3d_from_points.cpp b/src/Alpha_complex/example/Weighted_alpha_complex_3d_from_points.cpp
new file mode 100644
index 00000000..ac11b68c
--- /dev/null
+++ b/src/Alpha_complex/example/Weighted_alpha_complex_3d_from_points.cpp
@@ -0,0 +1,52 @@
+#include <gudhi/Alpha_complex_3d.h>
+// to construct a simplex_tree from alpha complex
+#include <gudhi/Simplex_tree.h>
+
+#include <iostream>
+#include <string>
+#include <vector>
+#include <limits> // for numeric limits
+
+// Complexity = FAST, weighted = true, periodic = false
+using Weighted_alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::SAFE, true, false>;
+using Point = Weighted_alpha_complex_3d::Point_3;
+using Weighted_point = Weighted_alpha_complex_3d::Weighted_point_3;
+
+int main(int argc, char **argv) {
+ // ----------------------------------------------------------------------------
+ // Init of a list of points and weights from a small molecule
+ // ----------------------------------------------------------------------------
+ std::vector<Weighted_point> weighted_points;
+ weighted_points.push_back(Weighted_point(Point(1, -1, -1), 4.));
+ weighted_points.push_back(Weighted_point(Point(-1, 1, -1), 4.));
+ weighted_points.push_back(Weighted_point(Point(-1, -1, 1), 4.));
+ weighted_points.push_back(Weighted_point(Point(1, 1, 1), 4.));
+ weighted_points.push_back(Weighted_point(Point(2, 2, 2), 1.));
+
+ // ----------------------------------------------------------------------------
+ // Init of an alpha complex from the list of points
+ // ----------------------------------------------------------------------------
+ Weighted_alpha_complex_3d alpha_complex_from_points(weighted_points);
+
+ Gudhi::Simplex_tree<> simplex;
+ if (alpha_complex_from_points.create_complex(simplex)) {
+ // ----------------------------------------------------------------------------
+ // Display information about the alpha complex
+ // ----------------------------------------------------------------------------
+ std::cout << "Alpha complex is of dimension " << simplex.dimension() << " - " << simplex.num_simplices()
+ << " simplices - " << simplex.num_vertices() << " vertices." << std::endl;
+
+ std::cout << "Iterator on alpha complex simplices in the filtration order, with [filtration value]:" << std::endl;
+ for (auto f_simplex : simplex.filtration_simplex_range()) {
+ std::cout << " ( ";
+ for (auto vertex : simplex.simplex_vertex_range(f_simplex)) {
+ std::cout << vertex << " ";
+ }
+ std::cout << ") -> "
+ << "[" << simplex.filtration(f_simplex) << "] ";
+ std::cout << std::endl;
+ }
+ }
+ return 0;
+}
diff --git a/src/Alpha_complex/example/weightedalpha3dfrompoints_for_doc.txt b/src/Alpha_complex/example/weightedalpha3dfrompoints_for_doc.txt
new file mode 100644
index 00000000..7a09998d
--- /dev/null
+++ b/src/Alpha_complex/example/weightedalpha3dfrompoints_for_doc.txt
@@ -0,0 +1,31 @@
+Alpha complex is of dimension 3 - 29 simplices - 5 vertices.
+Iterator on alpha complex simplices in the filtration order, with [filtration value]:
+ ( 0 ) -> [-4]
+ ( 1 ) -> [-4]
+ ( 2 ) -> [-4]
+ ( 3 ) -> [-4]
+ ( 1 0 ) -> [-2]
+ ( 2 0 ) -> [-2]
+ ( 2 1 ) -> [-2]
+ ( 3 0 ) -> [-2]
+ ( 3 1 ) -> [-2]
+ ( 3 2 ) -> [-2]
+ ( 2 1 0 ) -> [-1.33333]
+ ( 3 1 0 ) -> [-1.33333]
+ ( 3 2 0 ) -> [-1.33333]
+ ( 3 2 1 ) -> [-1.33333]
+ ( 3 2 1 0 ) -> [-1]
+ ( 4 ) -> [-1]
+ ( 4 2 ) -> [-1]
+ ( 4 0 ) -> [23]
+ ( 4 1 ) -> [23]
+ ( 4 2 0 ) -> [23]
+ ( 4 2 1 ) -> [23]
+ ( 4 3 ) -> [23]
+ ( 4 3 2 ) -> [23]
+ ( 4 1 0 ) -> [95]
+ ( 4 2 1 0 ) -> [95]
+ ( 4 3 0 ) -> [95]
+ ( 4 3 1 ) -> [95]
+ ( 4 3 2 0 ) -> [95]
+ ( 4 3 2 1 ) -> [95]
diff --git a/src/Alpha_complex/include/gudhi/Alpha_complex.h b/src/Alpha_complex/include/gudhi/Alpha_complex.h
index 4c07eddb..af9f59ea 100644
--- a/src/Alpha_complex/include/gudhi/Alpha_complex.h
+++ b/src/Alpha_complex/include/gudhi/Alpha_complex.h
@@ -228,19 +228,14 @@ class Alpha_complex {
}
public:
- template <typename SimplicialComplexForAlpha>
- bool create_complex(SimplicialComplexForAlpha& complex) {
- typedef typename SimplicialComplexForAlpha::Filtration_value Filtration_value;
- return create_complex(complex, std::numeric_limits<Filtration_value>::infinity());
- }
-
/** \brief Inserts all Delaunay triangulation into the simplicial complex.
* It also computes the filtration values accordingly to the \ref createcomplexalgorithm
*
* \tparam SimplicialComplexForAlpha must meet `SimplicialComplexForAlpha` concept.
*
* @param[in] complex SimplicialComplexForAlpha to be created.
- * @param[in] max_alpha_square maximum for alpha square value. Default value is +\f$\infty\f$.
+ * @param[in] max_alpha_square maximum for alpha square value. Default value is +\f$\infty\f$, and there is very
+ * little point using anything else since it does not save time.
*
* @return true if creation succeeds, false otherwise.
*
@@ -249,8 +244,10 @@ class Alpha_complex {
*
* Initialization can be launched once.
*/
- template <typename SimplicialComplexForAlpha, typename Filtration_value>
- bool create_complex(SimplicialComplexForAlpha& complex, Filtration_value max_alpha_square) {
+ template <typename SimplicialComplexForAlpha,
+ typename Filtration_value = typename SimplicialComplexForAlpha::Filtration_value>
+ bool create_complex(SimplicialComplexForAlpha& complex,
+ Filtration_value max_alpha_square = std::numeric_limits<Filtration_value>::infinity()) {
// From SimplicialComplexForAlpha type required to insert into a simplicial complex (with or without subfaces).
typedef typename SimplicialComplexForAlpha::Vertex_handle Vertex_handle;
typedef typename SimplicialComplexForAlpha::Simplex_handle Simplex_handle;
@@ -272,7 +269,9 @@ class Alpha_complex {
// --------------------------------------------------------------------------------------------
// Simplex_tree construction from loop on triangulation finite full cells list
if (triangulation_->number_of_vertices() > 0) {
- for (auto cit = triangulation_->finite_full_cells_begin(); cit != triangulation_->finite_full_cells_end(); ++cit) {
+ for (auto cit = triangulation_->finite_full_cells_begin();
+ cit != triangulation_->finite_full_cells_end();
+ ++cit) {
Vector_vertex vertexVector;
#ifdef DEBUG_TRACES
std::cout << "Simplex_tree insertion ";
@@ -333,7 +332,9 @@ class Alpha_complex {
std::cout << "filt(Sigma) is NaN : filt(Sigma) =" << complex.filtration(f_simplex) << std::endl;
#endif // DEBUG_TRACES
}
- propagate_alpha_filtration(complex, f_simplex, decr_dim);
+ // No need to propagate further, unweighted points all have value 0
+ if (decr_dim > 1)
+ propagate_alpha_filtration(complex, f_simplex);
}
}
}
@@ -350,7 +351,7 @@ class Alpha_complex {
private:
template <typename SimplicialComplexForAlpha, typename Simplex_handle>
- void propagate_alpha_filtration(SimplicialComplexForAlpha& complex, Simplex_handle f_simplex, int decr_dim) {
+ void propagate_alpha_filtration(SimplicialComplexForAlpha& complex, Simplex_handle f_simplex) {
// From SimplicialComplexForAlpha type required to assign filtration values.
typedef typename SimplicialComplexForAlpha::Filtration_value Filtration_value;
#ifdef DEBUG_TRACES
@@ -379,46 +380,42 @@ class Alpha_complex {
#endif // DEBUG_TRACES
// ### Else
} else {
- // No need to compute is_gabriel for dimension <= 2
- // i.e. : Sigma = (3,1) => Tau = 1
- if (decr_dim > 1) {
- // insert the Tau points in a vector for is_gabriel function
- Vector_of_CGAL_points pointVector;
+ // insert the Tau points in a vector for is_gabriel function
+ Vector_of_CGAL_points pointVector;
#ifdef DEBUG_TRACES
- Vertex_handle vertexForGabriel = Vertex_handle();
+ Vertex_handle vertexForGabriel = Vertex_handle();
#endif // DEBUG_TRACES
- for (auto vertex : complex.simplex_vertex_range(f_boundary)) {
- pointVector.push_back(get_point(vertex));
- }
- // Retrieve the Sigma point that is not part of Tau - parameter for is_gabriel function
- Point_d point_for_gabriel;
- for (auto vertex : complex.simplex_vertex_range(f_simplex)) {
- point_for_gabriel = get_point(vertex);
- if (std::find(pointVector.begin(), pointVector.end(), point_for_gabriel) == pointVector.end()) {
+ for (auto vertex : complex.simplex_vertex_range(f_boundary)) {
+ pointVector.push_back(get_point(vertex));
+ }
+ // Retrieve the Sigma point that is not part of Tau - parameter for is_gabriel function
+ Point_d point_for_gabriel;
+ for (auto vertex : complex.simplex_vertex_range(f_simplex)) {
+ point_for_gabriel = get_point(vertex);
+ if (std::find(pointVector.begin(), pointVector.end(), point_for_gabriel) == pointVector.end()) {
#ifdef DEBUG_TRACES
- // vertex is not found in Tau
- vertexForGabriel = vertex;
+ // vertex is not found in Tau
+ vertexForGabriel = vertex;
#endif // DEBUG_TRACES
- // No need to continue loop
- break;
- }
+ // No need to continue loop
+ break;
}
- // is_gabriel function initialization
- Is_Gabriel is_gabriel = kernel_.side_of_bounded_sphere_d_object();
- bool is_gab = is_gabriel(pointVector.begin(), pointVector.end(), point_for_gabriel)
- != CGAL::ON_BOUNDED_SIDE;
+ }
+ // is_gabriel function initialization
+ Is_Gabriel is_gabriel = kernel_.side_of_bounded_sphere_d_object();
+ bool is_gab = is_gabriel(pointVector.begin(), pointVector.end(), point_for_gabriel)
+ != CGAL::ON_BOUNDED_SIDE;
#ifdef DEBUG_TRACES
- std::cout << " | Tau is_gabriel(Sigma)=" << is_gab << " - vertexForGabriel=" << vertexForGabriel << std::endl;
+ std::cout << " | Tau is_gabriel(Sigma)=" << is_gab << " - vertexForGabriel=" << vertexForGabriel << std::endl;
#endif // DEBUG_TRACES
- // ### If Tau is not Gabriel of Sigma
- if (false == is_gab) {
- // ### filt(Tau) = filt(Sigma)
- Filtration_value alpha_complex_filtration = complex.filtration(f_simplex);
- complex.assign_filtration(f_boundary, alpha_complex_filtration);
+ // ### If Tau is not Gabriel of Sigma
+ if (false == is_gab) {
+ // ### filt(Tau) = filt(Sigma)
+ Filtration_value alpha_complex_filtration = complex.filtration(f_simplex);
+ complex.assign_filtration(f_boundary, alpha_complex_filtration);
#ifdef DEBUG_TRACES
- std::cout << " | filt(Tau) = filt(Sigma) = " << complex.filtration(f_boundary) << std::endl;
+ std::cout << " | filt(Tau) = filt(Sigma) = " << complex.filtration(f_boundary) << std::endl;
#endif // DEBUG_TRACES
- }
}
}
}
diff --git a/src/Alpha_complex/include/gudhi/Alpha_complex_3d.h b/src/Alpha_complex/include/gudhi/Alpha_complex_3d.h
new file mode 100644
index 00000000..32dfcc16
--- /dev/null
+++ b/src/Alpha_complex/include/gudhi/Alpha_complex_3d.h
@@ -0,0 +1,584 @@
+/* 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) 2018 Inria
+ *
+ * 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 ALPHA_COMPLEX_3D_H_
+#define ALPHA_COMPLEX_3D_H_
+
+#include <boost/version.hpp>
+#include <boost/variant.hpp>
+
+#include <gudhi/Debug_utils.h>
+#include <gudhi/Alpha_complex_options.h>
+
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Delaunay_triangulation_3.h>
+#include <CGAL/Periodic_3_Delaunay_triangulation_traits_3.h>
+#include <CGAL/Periodic_3_Delaunay_triangulation_3.h>
+#include <CGAL/Periodic_3_regular_triangulation_traits_3.h>
+#include <CGAL/Periodic_3_regular_triangulation_3.h>
+#include <CGAL/Regular_triangulation_3.h>
+#include <CGAL/Alpha_shape_3.h>
+#include <CGAL/Alpha_shape_cell_base_3.h>
+#include <CGAL/Alpha_shape_vertex_base_3.h>
+
+#include <CGAL/Object.h>
+#include <CGAL/tuple.h>
+#include <CGAL/iterator.h>
+#include <CGAL/version.h>
+
+#include <boost/container/static_vector.hpp>
+
+#include <iostream>
+#include <vector>
+#include <unordered_map>
+#include <stdexcept>
+#include <cstddef>
+#include <memory> // for std::unique_ptr
+#include <type_traits> // for std::conditional and std::enable_if
+#include <limits> // for numeric_limits<>
+
+#if CGAL_VERSION_NR < 1041101000
+// Make compilation fail - required for external projects - https://gitlab.inria.fr/GUDHI/gudhi-devel/issues/10
+# error Alpha_complex_3d is only available for CGAL >= 4.11
+#endif
+
+namespace Gudhi {
+
+namespace alpha_complex {
+
+#ifdef GUDHI_CAN_USE_CXX11_THREAD_LOCAL
+thread_local
+#endif // GUDHI_CAN_USE_CXX11_THREAD_LOCAL
+ double RELATIVE_PRECISION_OF_TO_DOUBLE = 0.00001;
+
+// Value_from_iterator returns the filtration value from an iterator on alpha shapes values
+//
+// FAST SAFE EXACT
+// CGAL::to_double(*iterator) CGAL::to_double(*iterator) CGAL::to_double(iterator->exact())
+
+template <complexity Complexity>
+struct Value_from_iterator {
+ template <typename Iterator>
+ static double perform(Iterator it) {
+ // Default behaviour
+ return CGAL::to_double(*it);
+ }
+};
+
+template <>
+struct Value_from_iterator<complexity::EXACT> {
+ template <typename Iterator>
+ static double perform(Iterator it) {
+ return CGAL::to_double(it->exact());
+ }
+};
+
+/**
+ * \class Alpha_complex_3d
+ * \brief Alpha complex data structure for 3d specific case.
+ *
+ * \ingroup alpha_complex
+ *
+ * \details
+ * The data structure is constructing a <a href="https://doc.cgal.org/latest/Alpha_shapes_3/index.html">CGAL 3D Alpha
+ * Shapes</a> from a range of points (can be read from an OFF file, cf. Points_off_reader).
+ * Duplicate points are inserted once in the Alpha_complex. This is the reason why the vertices may be not contiguous.
+ *
+ * \tparam Complexity shall be `Gudhi::alpha_complex::complexity` type. Default value is
+ * `Gudhi::alpha_complex::complexity::SAFE`.
+ *
+ * \tparam Weighted Boolean used to set/unset the weighted version of Alpha_complex_3d. Default value is false.
+ *
+ * \tparam Periodic Boolean used to set/unset the periodic version of Alpha_complex_3d. Default value is false.
+ *
+ * For the weighted version, weights values are explained on CGAL
+ * <a href="https://doc.cgal.org/latest/Alpha_shapes_3/index.html#title0">Alpha shapes 3d</a> and
+ * <a href="https://doc.cgal.org/latest/Triangulation_3/index.html#Triangulation3secclassRegulartriangulation">Regular
+ * triangulation</a> documentation.
+ *
+ * For the periodic version, refer to the
+ * <a href="https://doc.cgal.org/latest/Periodic_3_triangulation_3/index.html">CGAL’s 3D Periodic Triangulations User
+ * Manual </a> for more details.
+ * The periodicity is defined by an iso-oriented cuboid with diagonal opposite vertices (x_min, y_min, z_min) and
+ * (x_max, y_max, z_max).
+ *
+ * Please refer to \ref alpha_complex for examples.
+ *
+ * \remark When Alpha_complex_3d is constructed with an infinite value of alpha (default value), the complex is a
+ * 3d Delaunay complex.
+ *
+ */
+template <complexity Complexity = complexity::SAFE, bool Weighted = false, bool Periodic = false>
+class Alpha_complex_3d {
+ // Epick = Exact_predicates_inexact_constructions_kernel
+ // Epeck = Exact_predicates_exact_constructions_kernel
+ // Exact_alpha_comparison_tag = exact version of CGAL Alpha_shape_3 and of its objects (Alpha_shape_vertex_base_3 and
+ // Alpha_shape_cell_base_3). Not available if weighted or periodic.
+ // Can be CGAL::Tag_false or CGAL::Tag_true. Default is False.
+ // cf. https://doc.cgal.org/latest/Alpha_shapes_3/classCGAL_1_1Alpha__shape__3.html
+ //
+ // We could use Epick + CGAL::Tag_true for not weighted nor periodic, but during benchmark, we found a bug
+ // https://github.com/CGAL/cgal/issues/3460
+ // This is the reason we only use Epick + CGAL::Tag_false, or Epeck
+ //
+ // FAST SAFE EXACT
+ // Epick + CGAL::Tag_false Epeck Epeck
+ using Predicates = typename std::conditional<(Complexity == complexity::FAST),
+ CGAL::Exact_predicates_inexact_constructions_kernel,
+ CGAL::Exact_predicates_exact_constructions_kernel>::type;
+
+ // The other way to do a conditional type. Here there are 3 possibilities
+ template <typename Predicates, bool Weighted_version, bool Periodic_version>
+ struct Kernel_3 {};
+
+ template <typename Predicates, bool Is_periodic>
+ struct Kernel_3<Predicates, Is_periodic, false> {
+ using Kernel = Predicates;
+ };
+
+ template <typename Predicates>
+ struct Kernel_3<Predicates, false, true> {
+ using Kernel = CGAL::Periodic_3_Delaunay_triangulation_traits_3<Predicates>;
+ };
+ template <typename Predicates>
+ struct Kernel_3<Predicates, true, true> {
+ using Kernel = CGAL::Periodic_3_regular_triangulation_traits_3<Predicates>;
+ };
+
+ using Kernel = typename Kernel_3<Predicates, Weighted, Periodic>::Kernel;
+
+ using TdsVb = typename std::conditional<Periodic, CGAL::Periodic_3_triangulation_ds_vertex_base_3<>,
+ CGAL::Triangulation_ds_vertex_base_3<>>::type;
+
+ using Tvb = typename std::conditional<Weighted, CGAL::Regular_triangulation_vertex_base_3<Kernel, TdsVb>,
+ CGAL::Triangulation_vertex_base_3<Kernel, TdsVb>>::type;
+
+ using Vb = CGAL::Alpha_shape_vertex_base_3<Kernel, Tvb>;
+
+ using TdsCb = typename std::conditional<Periodic, CGAL::Periodic_3_triangulation_ds_cell_base_3<>,
+ CGAL::Triangulation_ds_cell_base_3<>>::type;
+
+ using Tcb = typename std::conditional<Weighted, CGAL::Regular_triangulation_cell_base_3<Kernel, TdsCb>,
+ CGAL::Triangulation_cell_base_3<Kernel, TdsCb>>::type;
+
+ using Cb = CGAL::Alpha_shape_cell_base_3<Kernel, Tcb>;
+ using Tds = CGAL::Triangulation_data_structure_3<Vb, Cb>;
+
+ // The other way to do a conditional type. Here there 4 possibilities, cannot use std::conditional
+ template <typename Kernel, typename Tds, bool Weighted_version, bool Periodic_version>
+ struct Triangulation_3 {};
+
+ template <typename Kernel, typename Tds>
+ struct Triangulation_3<Kernel, Tds, false, false> {
+ using Dt = CGAL::Delaunay_triangulation_3<Kernel, Tds>;
+ using Weighted_point_3 = void;
+ };
+ template <typename Kernel, typename Tds>
+ struct Triangulation_3<Kernel, Tds, true, false> {
+ using Dt = CGAL::Regular_triangulation_3<Kernel, Tds>;
+ using Weighted_point_3 = typename Dt::Weighted_point;
+ };
+ template <typename Kernel, typename Tds>
+ struct Triangulation_3<Kernel, Tds, false, true> {
+ using Dt = CGAL::Periodic_3_Delaunay_triangulation_3<Kernel, Tds>;
+ using Weighted_point_3 = void;
+ };
+ template <typename Kernel, typename Tds>
+ struct Triangulation_3<Kernel, Tds, true, true> {
+ using Dt = CGAL::Periodic_3_regular_triangulation_3<Kernel, Tds>;
+ using Weighted_point_3 = typename Dt::Weighted_point;
+ };
+
+ /** \brief Is either Delaunay_triangulation_3 (Weighted = false and Periodic = false),
+ * Regular_triangulation_3 (Weighted = true and Periodic = false),
+ * Periodic_3_Delaunay_triangulation_3 (Weighted = false and Periodic = true)
+ * or Periodic_3_regular_triangulation_3 (Weighted = true and Periodic = true).
+ *
+ * This type is required by `Gudhi::alpha_complex::Alpha_complex_3d::Alpha_shape_3`.
+ * */
+ using Dt = typename Triangulation_3<Kernel, Tds, Weighted, Periodic>::Dt;
+
+ public:
+ /** \brief The <a href="https://doc.cgal.org/latest/Alpha_shapes_3/classCGAL_1_1Alpha__shape__3.html">CGAL 3D Alpha
+ * Shapes</a> type.
+ *
+ * The `Gudhi::alpha_complex::Alpha_complex_3d` is a wrapper on top of this class to ease the standard, weighted
+ * and/or periodic build of the Alpha complex 3d.*/
+ using Alpha_shape_3 = CGAL::Alpha_shape_3<Dt>;
+
+ /** \brief The alpha values type.
+ * Must be compatible with double. */
+ using FT = typename Alpha_shape_3::FT;
+
+ /** \brief Gives public access to the Point_3 type. Here is a Point_3 constructor example:
+\code{.cpp}
+using Alpha_complex_3d = Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::SAFE, false, false>;
+
+// x0 = 1., y0 = -1.1, z0 = -1..
+Alpha_complex_3d::Point_3 p0(1., -1.1, -1.);
+\endcode
+ * */
+ using Point_3 = typename Kernel::Point_3;
+
+ /** \brief Gives public access to the Weighted_point_3 type. A Weighted point can be constructed as follows:
+\code{.cpp}
+using Weighted_alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::SAFE, true, false>;
+
+// x0 = 1., y0 = -1.1, z0 = -1., weight = 4.
+Weighted_alpha_complex_3d::Weighted_point_3 wp0(Weighted_alpha_complex_3d::Point_3(1., -1.1, -1.), 4.);
+\endcode
+ *
+ * Note: This type is defined to void if Alpha complex is not weighted.
+ *
+ * */
+ using Weighted_point_3 = typename Triangulation_3<Kernel, Tds, Weighted, Periodic>::Weighted_point_3;
+
+ private:
+ using Dispatch =
+ CGAL::Dispatch_output_iterator<CGAL::cpp11::tuple<CGAL::Object, FT>,
+ CGAL::cpp11::tuple<std::back_insert_iterator<std::vector<CGAL::Object>>,
+ std::back_insert_iterator<std::vector<FT>>>>;
+
+ using Cell_handle = typename Alpha_shape_3::Cell_handle;
+ using Facet = typename Alpha_shape_3::Facet;
+ using Edge = typename Alpha_shape_3::Edge;
+ using Alpha_vertex_handle = typename Alpha_shape_3::Vertex_handle;
+ using Vertex_list = boost::container::static_vector<Alpha_vertex_handle, 4>;
+
+ public:
+ /** \brief Alpha_complex constructor from a list of points.
+ *
+ * @param[in] points Range of points to triangulate. Points must be in `Alpha_complex_3d::Point_3` or
+ * `Alpha_complex_3d::Weighted_point_3`.
+ *
+ * @pre Available if Alpha_complex_3d is not Periodic.
+ *
+ * The type InputPointRange must be a range for which std::begin and std::end return input iterators on a
+ * `Alpha_complex_3d::Point_3` or a `Alpha_complex_3d::Weighted_point_3`.
+ */
+ template <typename InputPointRange>
+ Alpha_complex_3d(const InputPointRange& points) {
+ static_assert(!Periodic, "This constructor is not available for periodic versions of Alpha_complex_3d");
+
+ alpha_shape_3_ptr_ = std::unique_ptr<Alpha_shape_3>(
+ new Alpha_shape_3(std::begin(points), std::end(points), 0, Alpha_shape_3::GENERAL));
+ }
+
+ /** \brief Alpha_complex constructor from a list of points and associated weights.
+ *
+ * @exception std::invalid_argument In debug mode, if points and weights do not have the same size.
+ *
+ * @param[in] points Range of points to triangulate. Points must be in `Alpha_complex_3d::Point_3`.
+ * @param[in] weights Range of weights on points. Weights shall be in double.
+ *
+ * @pre Available if Alpha_complex_3d is Weighted and not Periodic.
+ *
+ * The type InputPointRange must be a range for which std::begin and
+ * std::end return input iterators on a `Alpha_complex_3d::Point_3`.
+ * The type WeightRange must be a range for which std::begin and
+ * std::end return an input iterator on a double.
+ */
+ template <typename InputPointRange, typename WeightRange>
+ Alpha_complex_3d(const InputPointRange& points, WeightRange weights) {
+ static_assert(Weighted, "This constructor is not available for non-weighted versions of Alpha_complex_3d");
+ static_assert(!Periodic, "This constructor is not available for periodic versions of Alpha_complex_3d");
+ GUDHI_CHECK((weights.size() == points.size()),
+ std::invalid_argument("Points number in range different from weights range number"));
+
+ std::vector<Weighted_point_3> weighted_points_3;
+
+ std::size_t index = 0;
+ weighted_points_3.reserve(points.size());
+ while ((index < weights.size()) && (index < points.size())) {
+ weighted_points_3.push_back(Weighted_point_3(points[index], weights[index]));
+ index++;
+ }
+
+ alpha_shape_3_ptr_ = std::unique_ptr<Alpha_shape_3>(
+ new Alpha_shape_3(std::begin(weighted_points_3), std::end(weighted_points_3), 0, Alpha_shape_3::GENERAL));
+ }
+
+ /** \brief Alpha_complex constructor from a list of points and an iso-cuboid coordinates.
+ *
+ * @exception std::invalid_argument In debug mode, if the size of the cuboid in every directions is not the same.
+ *
+ * @param[in] points Range of points to triangulate. Points must be in `Alpha_complex_3d::Point_3` or
+ * `Alpha_complex_3d::Weighted_point_3`.
+ * @param[in] x_min Iso-oriented cuboid x_min.
+ * @param[in] y_min Iso-oriented cuboid y_min.
+ * @param[in] z_min Iso-oriented cuboid z_min.
+ * @param[in] x_max Iso-oriented cuboid x_max.
+ * @param[in] y_max Iso-oriented cuboid y_max.
+ * @param[in] z_max Iso-oriented cuboid z_max.
+ *
+ * @pre Available if Alpha_complex_3d is Periodic.
+ *
+ * The type InputPointRange must be a range for which std::begin and std::end return input iterators on a
+ * `Alpha_complex_3d::Point_3` or a `Alpha_complex_3d::Weighted_point_3`.
+ *
+ * @note In weighted version, please check weights are greater than zero, and lower than 1/64*cuboid length
+ * squared.
+ */
+ template <typename InputPointRange>
+ Alpha_complex_3d(const InputPointRange& points, FT x_min, FT y_min,
+ FT z_min, FT x_max, FT y_max, FT z_max) {
+ static_assert(Periodic, "This constructor is not available for non-periodic versions of Alpha_complex_3d");
+ // Checking if the cuboid is the same in x,y and z direction. If not, CGAL will not process it.
+ GUDHI_CHECK(
+ (x_max - x_min == y_max - y_min) && (x_max - x_min == z_max - z_min) && (z_max - z_min == y_max - y_min),
+ std::invalid_argument("The size of the cuboid in every directions is not the same."));
+
+ // Define the periodic cube
+ Dt pdt(typename Kernel::Iso_cuboid_3(x_min, y_min, z_min, x_max, y_max, z_max));
+ // Heuristic for inserting large point sets (if pts is reasonably large)
+ pdt.insert(std::begin(points), std::end(points), true);
+ // As pdt won't be modified anymore switch to 1-sheeted cover if possible
+ if (!pdt.is_triangulation_in_1_sheet()) {
+ throw std::invalid_argument("Unable to construct a triangulation within a single periodic domain.");
+ }
+ pdt.convert_to_1_sheeted_covering();
+
+ // alpha shape construction from points. CGAL has a strange behavior in REGULARIZED mode. This is the default mode
+ // Maybe need to set it to GENERAL mode
+ alpha_shape_3_ptr_ = std::unique_ptr<Alpha_shape_3>(new Alpha_shape_3(pdt, 0, Alpha_shape_3::GENERAL));
+ }
+
+ /** \brief Alpha_complex constructor from a list of points, associated weights and an iso-cuboid coordinates.
+ *
+ * @exception std::invalid_argument In debug mode, if points and weights do not have the same size.
+ * @exception std::invalid_argument In debug mode, if the size of the cuboid in every directions is not the same.
+ * @exception std::invalid_argument In debug mode, if a weight is negative, zero, or greater than 1/64*cuboid length
+ * squared.
+ *
+ * @param[in] points Range of points to triangulate. Points must be in `Alpha_complex_3d::Point_3`.
+ * @param[in] weights Range of weights on points. Weights shall be in double.
+ * @param[in] x_min Iso-oriented cuboid x_min.
+ * @param[in] y_min Iso-oriented cuboid y_min.
+ * @param[in] z_min Iso-oriented cuboid z_min.
+ * @param[in] x_max Iso-oriented cuboid x_max.
+ * @param[in] y_max Iso-oriented cuboid y_max.
+ * @param[in] z_max Iso-oriented cuboid z_max.
+ *
+ * @pre Available if Alpha_complex_3d is Weighted and Periodic.
+ *
+ * The type InputPointRange must be a range for which std::begin and
+ * std::end return input iterators on a `Alpha_complex_3d::Point_3`.
+ * The type WeightRange must be a range for which std::begin and
+ * std::end return an input iterator on a double.
+ * The type of x_min, y_min, z_min, x_max, y_max and z_max must be a double.
+ */
+ template <typename InputPointRange, typename WeightRange>
+ Alpha_complex_3d(const InputPointRange& points, WeightRange weights, FT x_min, FT y_min,
+ FT z_min, FT x_max, FT y_max, FT z_max) {
+ static_assert(Weighted, "This constructor is not available for non-weighted versions of Alpha_complex_3d");
+ static_assert(Periodic, "This constructor is not available for non-periodic versions of Alpha_complex_3d");
+ GUDHI_CHECK((weights.size() == points.size()),
+ std::invalid_argument("Points number in range different from weights range number"));
+ // Checking if the cuboid is the same in x,y and z direction. If not, CGAL will not process it.
+ GUDHI_CHECK(
+ (x_max - x_min == y_max - y_min) && (x_max - x_min == z_max - z_min) && (z_max - z_min == y_max - y_min),
+ std::invalid_argument("The size of the cuboid in every directions is not the same."));
+
+ std::vector<Weighted_point_3> weighted_points_3;
+
+ std::size_t index = 0;
+ weighted_points_3.reserve(points.size());
+
+#ifdef GUDHI_DEBUG
+ // Defined in GUDHI_DEBUG to avoid unused variable warning for GUDHI_CHECK
+ FT maximal_possible_weight = 0.015625 * (x_max - x_min) * (x_max - x_min);
+#endif
+
+ while ((index < weights.size()) && (index < points.size())) {
+ GUDHI_CHECK((weights[index] < maximal_possible_weight) && (weights[index] >= 0),
+ std::invalid_argument("Invalid weight at index " + std::to_string(index + 1) +
+ ". Must be positive and less than maximal possible weight = 1/64*cuboid length "
+ "squared, which is not an acceptable input."));
+ weighted_points_3.push_back(Weighted_point_3(points[index], weights[index]));
+ index++;
+ }
+
+ // Define the periodic cube
+ Dt pdt(typename Kernel::Iso_cuboid_3(x_min, y_min, z_min, x_max, y_max, z_max));
+ // Heuristic for inserting large point sets (if pts is reasonably large)
+ pdt.insert(std::begin(weighted_points_3), std::end(weighted_points_3), true);
+ // As pdt won't be modified anymore switch to 1-sheeted cover if possible
+ if (!pdt.is_triangulation_in_1_sheet()) {
+ throw std::invalid_argument("Unable to construct a triangulation within a single periodic domain.");
+ }
+ pdt.convert_to_1_sheeted_covering();
+
+ // alpha shape construction from points. CGAL has a strange behavior in REGULARIZED mode. This is the default mode
+ // Maybe need to set it to GENERAL mode
+ alpha_shape_3_ptr_ = std::unique_ptr<Alpha_shape_3>(new Alpha_shape_3(pdt, 0, Alpha_shape_3::GENERAL));
+ }
+
+ /** \brief Inserts all Delaunay triangulation into the simplicial complex.
+ * It also computes the filtration values accordingly to the \ref createcomplexalgorithm
+ *
+ * \tparam SimplicialComplexForAlpha3d must meet `SimplicialComplexForAlpha3d` concept.
+ *
+ * @param[in] complex SimplicialComplexForAlpha3d to be created.
+ * @param[in] max_alpha_square maximum for alpha square value. Default value is +\f$\infty\f$, and there is very
+ * little point using anything else since it does not save time.
+ *
+ * @return true if creation succeeds, false otherwise.
+ *
+ * @pre The simplicial complex must be empty (no vertices).
+ *
+ */
+ template <typename SimplicialComplexForAlpha3d,
+ typename Filtration_value = typename SimplicialComplexForAlpha3d::Filtration_value>
+ bool create_complex(SimplicialComplexForAlpha3d& complex,
+ Filtration_value max_alpha_square = std::numeric_limits<Filtration_value>::infinity()) {
+ if (complex.num_vertices() > 0) {
+ std::cerr << "Alpha_complex_3d create_complex - complex is not empty\n";
+ return false; // ----- >>
+ }
+
+ // using Filtration_value = typename SimplicialComplexForAlpha3d::Filtration_value;
+ using Complex_vertex_handle = typename SimplicialComplexForAlpha3d::Vertex_handle;
+ using Alpha_shape_simplex_tree_map = std::unordered_map<Alpha_vertex_handle, Complex_vertex_handle>;
+ using Simplex_tree_vector_vertex = std::vector<Complex_vertex_handle>;
+
+#ifdef DEBUG_TRACES
+ std::size_t count_vertices = 0;
+ std::size_t count_edges = 0;
+ std::size_t count_facets = 0;
+ std::size_t count_cells = 0;
+#endif // DEBUG_TRACES
+ std::vector<CGAL::Object> objects;
+ std::vector<FT> alpha_values;
+
+ Dispatch dispatcher = CGAL::dispatch_output<CGAL::Object, FT>(std::back_inserter(objects),
+ std::back_inserter(alpha_values));
+
+ alpha_shape_3_ptr_->filtration_with_alpha_values(dispatcher);
+#ifdef DEBUG_TRACES
+ std::cout << "filtration_with_alpha_values returns : " << objects.size() << " objects" << std::endl;
+#endif // DEBUG_TRACES
+
+ Alpha_shape_simplex_tree_map map_cgal_simplex_tree;
+ using Alpha_value_iterator = typename std::vector<FT>::const_iterator;
+ Alpha_value_iterator alpha_value_iterator = alpha_values.begin();
+ for (auto object_iterator : objects) {
+ Vertex_list vertex_list;
+
+ // Retrieve Alpha shape vertex list from object
+ if (const Cell_handle* cell = CGAL::object_cast<Cell_handle>(&object_iterator)) {
+ for (auto i = 0; i < 4; i++) {
+#ifdef DEBUG_TRACES
+ std::cout << "from cell[" << i << "]=" << (*cell)->vertex(i)->point() << std::endl;
+#endif // DEBUG_TRACES
+ vertex_list.push_back((*cell)->vertex(i));
+ }
+#ifdef DEBUG_TRACES
+ count_cells++;
+#endif // DEBUG_TRACES
+ } else if (const Facet* facet = CGAL::object_cast<Facet>(&object_iterator)) {
+ for (auto i = 0; i < 4; i++) {
+ if ((*facet).second != i) {
+#ifdef DEBUG_TRACES
+ std::cout << "from facet=[" << i << "]" << (*facet).first->vertex(i)->point() << std::endl;
+#endif // DEBUG_TRACES
+ vertex_list.push_back((*facet).first->vertex(i));
+ }
+ }
+#ifdef DEBUG_TRACES
+ count_facets++;
+#endif // DEBUG_TRACES
+ } else if (const Edge* edge = CGAL::object_cast<Edge>(&object_iterator)) {
+ for (auto i : {(*edge).second, (*edge).third}) {
+#ifdef DEBUG_TRACES
+ std::cout << "from edge[" << i << "]=" << (*edge).first->vertex(i)->point() << std::endl;
+#endif // DEBUG_TRACES
+ vertex_list.push_back((*edge).first->vertex(i));
+ }
+#ifdef DEBUG_TRACES
+ count_edges++;
+#endif // DEBUG_TRACES
+ } else if (const Alpha_vertex_handle* vertex = CGAL::object_cast<Alpha_vertex_handle>(&object_iterator)) {
+#ifdef DEBUG_TRACES
+ count_vertices++;
+ std::cout << "from vertex=" << (*vertex)->point() << std::endl;
+#endif // DEBUG_TRACES
+ vertex_list.push_back((*vertex));
+ }
+ // Construction of the vector of simplex_tree vertex from list of alpha_shapes vertex
+ Simplex_tree_vector_vertex the_simplex;
+ for (auto the_alpha_shape_vertex : vertex_list) {
+ auto 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
+ Complex_vertex_handle 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
+ the_simplex.push_back(vertex);
+ map_cgal_simplex_tree.emplace(the_alpha_shape_vertex, vertex);
+ } else {
+ // alpha shape found
+ Complex_vertex_handle 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.push_back(vertex);
+ }
+ }
+ // Construction of the simplex_tree
+ Filtration_value filtr = Value_from_iterator<Complexity>::perform(alpha_value_iterator);
+
+#ifdef DEBUG_TRACES
+ std::cout << "filtration = " << filtr << std::endl;
+#endif // DEBUG_TRACES
+ complex.insert_simplex(the_simplex, static_cast<Filtration_value>(filtr));
+ GUDHI_CHECK(alpha_value_iterator != alpha_values.end(), "CGAL provided more simplices than values");
+ ++alpha_value_iterator;
+ }
+
+#ifdef DEBUG_TRACES
+ std::cout << "vertices \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;
+#endif // DEBUG_TRACES
+ // --------------------------------------------------------------------------------------------
+ // As Alpha value is an approximation, we have to make filtration non decreasing while increasing the dimension
+ complex.make_filtration_non_decreasing();
+ // Remove all simplices that have a filtration value greater than max_alpha_square
+ complex.prune_above_filtration(max_alpha_square);
+ // --------------------------------------------------------------------------------------------
+ return true;
+ }
+
+ private:
+ // use of a unique_ptr on cgal Alpha_shape_3, as copy and default constructor is not available - no need to be freed
+ std::unique_ptr<Alpha_shape_3> alpha_shape_3_ptr_;
+};
+
+} // namespace alpha_complex
+
+} // namespace Gudhi
+
+#endif // ALPHA_COMPLEX_3D_H_
diff --git a/src/Alpha_complex/include/gudhi/Alpha_complex_options.h b/src/Alpha_complex/include/gudhi/Alpha_complex_options.h
new file mode 100644
index 00000000..7a555fa1
--- /dev/null
+++ b/src/Alpha_complex/include/gudhi/Alpha_complex_options.h
@@ -0,0 +1,45 @@
+/* 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) 2018 Inria
+ *
+ * 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 ALPHA_COMPLEX_OPTIONS_H_
+#define ALPHA_COMPLEX_OPTIONS_H_
+
+namespace Gudhi {
+
+namespace alpha_complex {
+
+/**
+ * \brief Alpha complex complexity template parameter possible values.
+ *
+ * \ingroup alpha_complex
+ */
+enum class complexity : char {
+ FAST = 'f', ///< Fast version.
+ SAFE = 's', ///< Safe version.
+ EXACT = 'e', ///< Exact version.
+};
+
+} // namespace alpha_complex
+
+} // namespace Gudhi
+
+#endif // ALPHA_COMPLEX_OPTIONS_H_
diff --git a/src/Alpha_complex/test/Alpha_complex_3d_unit_test.cpp b/src/Alpha_complex/test/Alpha_complex_3d_unit_test.cpp
new file mode 100644
index 00000000..ec905d5b
--- /dev/null
+++ b/src/Alpha_complex/test/Alpha_complex_3d_unit_test.cpp
@@ -0,0 +1,164 @@
+/* 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
+ *
+ * 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_DYN_LINK
+#define BOOST_TEST_MODULE "alpha_complex_3d"
+#include <boost/test/unit_test.hpp>
+
+#include <cmath> // float comparison
+#include <limits>
+#include <string>
+#include <vector>
+#include <random>
+#include <cstddef> // for std::size_t
+
+#include <gudhi/Alpha_complex_3d.h>
+#include <gudhi/graph_simplicial_complex.h>
+#include <gudhi/Simplex_tree.h>
+#include <gudhi/Unitary_tests_utils.h>
+// to construct Alpha_complex from a OFF file of points
+#include <gudhi/Points_3D_off_io.h>
+
+#include <CGAL/Random.h>
+#include <CGAL/point_generators_3.h>
+
+using Fast_alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::FAST, false, false>;
+using Safe_alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::SAFE, false, false>;
+using Exact_alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::EXACT, false, false>;
+
+template <typename Point>
+std::vector<Point> get_points() {
+ std::vector<Point> points;
+ points.push_back(Point(0.0, 0.0, 0.0));
+ points.push_back(Point(0.0, 0.0, 0.2));
+ points.push_back(Point(0.2, 0.0, 0.2));
+ points.push_back(Point(0.6, 0.6, 0.0));
+ points.push_back(Point(0.8, 0.8, 0.2));
+ points.push_back(Point(0.2, 0.8, 0.6));
+
+ return points;
+}
+
+
+BOOST_AUTO_TEST_CASE(Alpha_complex_3d_from_points) {
+ // -----------------
+ // Fast version
+ // -----------------
+ std::cout << "Fast alpha complex 3d" << std::endl;
+
+ Fast_alpha_complex_3d alpha_complex(get_points<Fast_alpha_complex_3d::Point_3>());
+
+ Gudhi::Simplex_tree<> stree;
+ alpha_complex.create_complex(stree);
+
+ // -----------------
+ // Exact version
+ // -----------------
+ std::cout << "Exact alpha complex 3d" << std::endl;
+
+ Exact_alpha_complex_3d exact_alpha_complex(get_points<Exact_alpha_complex_3d::Point_3>());
+
+ Gudhi::Simplex_tree<> exact_stree;
+ exact_alpha_complex.create_complex(exact_stree);
+
+ // ---------------------
+ // Compare both versions
+ // ---------------------
+ std::cout << "Exact Alpha complex 3d is of dimension " << exact_stree.dimension() << " - Fast is "
+ << stree.dimension() << std::endl;
+ BOOST_CHECK(exact_stree.dimension() == stree.dimension());
+ std::cout << "Exact Alpha complex 3d num_simplices " << exact_stree.num_simplices() << " - Fast is "
+ << stree.num_simplices() << std::endl;
+ BOOST_CHECK(exact_stree.num_simplices() == stree.num_simplices());
+ std::cout << "Exact Alpha complex 3d num_vertices " << exact_stree.num_vertices() << " - Fast is "
+ << stree.num_vertices() << std::endl;
+ BOOST_CHECK(exact_stree.num_vertices() == stree.num_vertices());
+
+ auto sh = stree.filtration_simplex_range().begin();
+ while (sh != stree.filtration_simplex_range().end()) {
+ std::vector<int> simplex;
+ std::vector<int> exact_simplex;
+ std::cout << "Fast ( ";
+ for (auto vertex : stree.simplex_vertex_range(*sh)) {
+ simplex.push_back(vertex);
+ std::cout << vertex << " ";
+ }
+ std::cout << ") -> [" << stree.filtration(*sh) << "] ";
+
+ // Find it in the exact structure
+ auto sh_exact = exact_stree.find(simplex);
+ BOOST_CHECK(sh_exact != exact_stree.null_simplex());
+
+ std::cout << " versus [" << exact_stree.filtration(sh_exact) << "] " << std::endl;
+ // Exact and non-exact version is not exactly the same due to float comparison
+ GUDHI_TEST_FLOAT_EQUALITY_CHECK(exact_stree.filtration(sh_exact), stree.filtration(*sh));
+
+ ++sh;
+ }
+ // -----------------
+ // Safe version
+ // -----------------
+ std::cout << "Safe alpha complex 3d" << std::endl;
+
+ Safe_alpha_complex_3d safe_alpha_complex(get_points<Safe_alpha_complex_3d::Point_3>());
+
+ Gudhi::Simplex_tree<> safe_stree;
+ safe_alpha_complex.create_complex(safe_stree);
+
+ // ---------------------
+ // Compare both versions
+ // ---------------------
+ std::cout << "Safe Alpha complex 3d is of dimension " << safe_stree.dimension() << " - Fast is "
+ << stree.dimension() << std::endl;
+ BOOST_CHECK(safe_stree.dimension() == stree.dimension());
+ std::cout << "Safe Alpha complex 3d num_simplices " << safe_stree.num_simplices() << " - Fast is "
+ << stree.num_simplices() << std::endl;
+ BOOST_CHECK(safe_stree.num_simplices() == stree.num_simplices());
+ std::cout << "Safe Alpha complex 3d num_vertices " << safe_stree.num_vertices() << " - Fast is "
+ << stree.num_vertices() << std::endl;
+ BOOST_CHECK(safe_stree.num_vertices() == stree.num_vertices());
+
+ auto safe_sh = stree.filtration_simplex_range().begin();
+ while (safe_sh != stree.filtration_simplex_range().end()) {
+ std::vector<int> simplex;
+ std::vector<int> exact_simplex;
+ std::cout << "Fast ( ";
+ for (auto vertex : stree.simplex_vertex_range(*safe_sh)) {
+ simplex.push_back(vertex);
+ std::cout << vertex << " ";
+ }
+ std::cout << ") -> [" << stree.filtration(*safe_sh) << "] ";
+
+ // Find it in the exact structure
+ auto sh_exact = safe_stree.find(simplex);
+ BOOST_CHECK(sh_exact != safe_stree.null_simplex());
+
+ std::cout << " versus [" << safe_stree.filtration(sh_exact) << "] " << std::endl;
+ // Exact and non-exact version is not exactly the same due to float comparison
+ GUDHI_TEST_FLOAT_EQUALITY_CHECK(safe_stree.filtration(sh_exact), stree.filtration(*safe_sh), 1e-15);
+
+ ++safe_sh;
+ }
+}
diff --git a/src/Alpha_complex/test/CMakeLists.txt b/src/Alpha_complex/test/CMakeLists.txt
index 9255d3db..7c6bf9aa 100644
--- a/src/Alpha_complex/test/CMakeLists.txt
+++ b/src/Alpha_complex/test/CMakeLists.txt
@@ -1,7 +1,10 @@
project(Alpha_complex_tests)
+include(GUDHI_test_coverage)
if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0)
- include(GUDHI_test_coverage)
+
+ # Do not forget to copy test files in current binary dir
+ file(COPY "${CMAKE_SOURCE_DIR}/data/points/alphacomplexdoc.off" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
add_executable ( Alpha_complex_test_unit Alpha_complex_unit_test.cpp )
target_link_libraries(Alpha_complex_test_unit ${CGAL_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
@@ -9,10 +12,29 @@ if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0)
target_link_libraries(Alpha_complex_test_unit ${TBB_LIBRARIES})
endif()
- # Do not forget to copy test files in current binary dir
- file(COPY "${CMAKE_SOURCE_DIR}/data/points/alphacomplexdoc.off" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
-
gudhi_add_coverage_test(Alpha_complex_test_unit)
endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0)
+if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0)
+ add_executable ( Alpha_complex_3d_test_unit Alpha_complex_3d_unit_test.cpp )
+ target_link_libraries(Alpha_complex_3d_test_unit ${CGAL_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
+ add_executable ( Weighted_alpha_complex_3d_test_unit Weighted_alpha_complex_3d_unit_test.cpp )
+ target_link_libraries(Weighted_alpha_complex_3d_test_unit ${CGAL_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
+ add_executable ( Periodic_alpha_complex_3d_test_unit Periodic_alpha_complex_3d_unit_test.cpp )
+ target_link_libraries(Periodic_alpha_complex_3d_test_unit ${CGAL_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
+ add_executable ( Weighted_periodic_alpha_complex_3d_test_unit Weighted_periodic_alpha_complex_3d_unit_test.cpp )
+ target_link_libraries(Weighted_periodic_alpha_complex_3d_test_unit ${CGAL_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
+ if (TBB_FOUND)
+ target_link_libraries(Alpha_complex_3d_test_unit ${TBB_LIBRARIES})
+ target_link_libraries(Weighted_alpha_complex_3d_test_unit ${TBB_LIBRARIES})
+ target_link_libraries(Periodic_alpha_complex_3d_test_unit ${TBB_LIBRARIES})
+ target_link_libraries(Weighted_periodic_alpha_complex_3d_test_unit ${TBB_LIBRARIES})
+ endif()
+
+ gudhi_add_coverage_test(Alpha_complex_3d_test_unit)
+ gudhi_add_coverage_test(Weighted_alpha_complex_3d_test_unit)
+ gudhi_add_coverage_test(Periodic_alpha_complex_3d_test_unit)
+ gudhi_add_coverage_test(Weighted_periodic_alpha_complex_3d_test_unit)
+
+endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0)
diff --git a/src/Alpha_complex/test/Periodic_alpha_complex_3d_unit_test.cpp b/src/Alpha_complex/test/Periodic_alpha_complex_3d_unit_test.cpp
new file mode 100644
index 00000000..ed4cbff0
--- /dev/null
+++ b/src/Alpha_complex/test/Periodic_alpha_complex_3d_unit_test.cpp
@@ -0,0 +1,190 @@
+/* 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
+ *
+ * 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_DYN_LINK
+#define BOOST_TEST_MODULE "alpha_complex_3d"
+#include <boost/test/unit_test.hpp>
+#include <boost/mpl/list.hpp>
+
+#include <cmath> // float comparison
+#include <limits>
+#include <string>
+#include <vector>
+#include <random>
+#include <cstddef> // for std::size_t
+
+#include <gudhi/Alpha_complex_3d.h>
+#include <gudhi/graph_simplicial_complex.h>
+#include <gudhi/Simplex_tree.h>
+#include <gudhi/Unitary_tests_utils.h>
+// to construct Alpha_complex from a OFF file of points
+#include <gudhi/Points_3D_off_io.h>
+
+#include <CGAL/Random.h>
+#include <CGAL/point_generators_3.h>
+
+using Fast_periodic_alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::FAST, false, true>;
+using Safe_periodic_alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::SAFE, false, true>;
+using Exact_periodic_alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::EXACT, false, true>;
+
+#ifdef GUDHI_DEBUG
+typedef boost::mpl::list<Fast_periodic_alpha_complex_3d, Safe_periodic_alpha_complex_3d,
+ Exact_periodic_alpha_complex_3d>
+ periodic_variants_type_list;
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(Alpha_complex_periodic_throw, Periodic_alpha_complex_3d, periodic_variants_type_list) {
+ std::cout << "Periodic alpha complex 3d exception throw" << std::endl;
+ using Point_3 = typename Periodic_alpha_complex_3d::Point_3;
+ std::vector<Point_3> p_points;
+
+ // Not important, this is not what we want to check
+ p_points.push_back(Point_3(0.0, 0.0, 0.0));
+
+ std::cout << "Check exception throw in debug mode" << std::endl;
+ // Check it throws an exception when the cuboid is not iso
+ BOOST_CHECK_THROW(Periodic_alpha_complex_3d periodic_alpha_complex(p_points, 0., 0., 0., 0.9, 1., 1.),
+ std::invalid_argument);
+ BOOST_CHECK_THROW(Periodic_alpha_complex_3d periodic_alpha_complex(p_points, 0., 0., 0., 1., 0.9, 1.),
+ std::invalid_argument);
+ BOOST_CHECK_THROW(Periodic_alpha_complex_3d periodic_alpha_complex(p_points, 0., 0., 0., 1., 1., 0.9),
+ std::invalid_argument);
+ BOOST_CHECK_THROW(Periodic_alpha_complex_3d periodic_alpha_complex(p_points, 0., 0., 0., 1.1, 1., 1.),
+ std::invalid_argument);
+ BOOST_CHECK_THROW(Periodic_alpha_complex_3d periodic_alpha_complex(p_points, 0., 0., 0., 1., 1.1, 1.),
+ std::invalid_argument);
+ BOOST_CHECK_THROW(Periodic_alpha_complex_3d periodic_alpha_complex(p_points, 0., 0., 0., 1., 1., 1.1),
+ std::invalid_argument);
+}
+#endif
+
+BOOST_AUTO_TEST_CASE(Alpha_complex_periodic) {
+ // ---------------------
+ // Fast periodic version
+ // ---------------------
+ std::cout << "Fast periodic alpha complex 3d" << std::endl;
+
+ using Creator = CGAL::Creator_uniform_3<double, Fast_periodic_alpha_complex_3d::Point_3>;
+ CGAL::Random random(7);
+ CGAL::Random_points_in_cube_3<Fast_periodic_alpha_complex_3d::Point_3, Creator> in_cube(1, random);
+ std::vector<Fast_periodic_alpha_complex_3d::Point_3> p_points;
+
+ for (int i = 0; i < 50; i++) {
+ Fast_periodic_alpha_complex_3d::Point_3 p = *in_cube++;
+ p_points.push_back(p);
+ }
+
+ Fast_periodic_alpha_complex_3d periodic_alpha_complex(p_points, -1., -1., -1., 1., 1., 1.);
+
+ Gudhi::Simplex_tree<> stree;
+ periodic_alpha_complex.create_complex(stree);
+
+ // ----------------------
+ // Exact periodic version
+ // ----------------------
+ std::cout << "Exact periodic alpha complex 3d" << std::endl;
+
+ std::vector<Exact_periodic_alpha_complex_3d::Point_3> e_p_points;
+
+ for (auto p : p_points) {
+ e_p_points.push_back(Exact_periodic_alpha_complex_3d::Point_3(p[0], p[1], p[2]));
+ }
+
+ Exact_periodic_alpha_complex_3d exact_alpha_complex(e_p_points, -1., -1., -1., 1., 1., 1.);
+
+ Gudhi::Simplex_tree<> exact_stree;
+ exact_alpha_complex.create_complex(exact_stree);
+
+ // ---------------------
+ // Compare both versions
+ // ---------------------
+ std::cout << "Exact periodic alpha complex 3d is of dimension " << exact_stree.dimension() << " - Non exact is "
+ << stree.dimension() << std::endl;
+ BOOST_CHECK(exact_stree.dimension() == stree.dimension());
+ std::cout << "Exact periodic alpha complex 3d num_simplices " << exact_stree.num_simplices() << " - Non exact is "
+ << stree.num_simplices() << std::endl;
+ BOOST_CHECK(exact_stree.num_simplices() == stree.num_simplices());
+ std::cout << "Exact periodic alpha complex 3d num_vertices " << exact_stree.num_vertices() << " - Non exact is "
+ << stree.num_vertices() << std::endl;
+ BOOST_CHECK(exact_stree.num_vertices() == stree.num_vertices());
+
+ // We cannot compare as objects from dispatcher on the alpha shape is not deterministic.
+ // cf. https://github.com/CGAL/cgal/issues/3346
+ auto sh = stree.filtration_simplex_range().begin();
+ auto sh_exact = exact_stree.filtration_simplex_range().begin();
+
+ while (sh != stree.filtration_simplex_range().end() || sh_exact != exact_stree.filtration_simplex_range().end()) {
+ GUDHI_TEST_FLOAT_EQUALITY_CHECK(stree.filtration(*sh), exact_stree.filtration(*sh_exact), 1e-14);
+
+ std::vector<int> vh(stree.simplex_vertex_range(*sh).begin(), stree.simplex_vertex_range(*sh).end());
+ std::vector<int> exact_vh(exact_stree.simplex_vertex_range(*sh_exact).begin(),
+ exact_stree.simplex_vertex_range(*sh_exact).end());
+
+ BOOST_CHECK(vh.size() == exact_vh.size());
+ ++sh;
+ ++sh_exact;
+ }
+
+ BOOST_CHECK(sh == stree.filtration_simplex_range().end());
+ BOOST_CHECK(sh_exact == exact_stree.filtration_simplex_range().end());
+
+ // ----------------------
+ // Safe periodic version
+ // ----------------------
+ std::cout << "Safe periodic alpha complex 3d" << std::endl;
+
+ std::vector<Safe_periodic_alpha_complex_3d::Point_3> s_p_points;
+
+ for (auto p : p_points) {
+ s_p_points.push_back(Safe_periodic_alpha_complex_3d::Point_3(p[0], p[1], p[2]));
+ }
+
+ Safe_periodic_alpha_complex_3d safe_alpha_complex(s_p_points, -1., -1., -1., 1., 1., 1.);
+
+ Gudhi::Simplex_tree<> safe_stree;
+ safe_alpha_complex.create_complex(safe_stree);
+
+ // ---------------------
+ // Compare both versions
+ // ---------------------
+ // We cannot compare as objects from dispatcher on the alpha shape is not deterministic.
+ // cf. https://github.com/CGAL/cgal/issues/3346
+ sh = stree.filtration_simplex_range().begin();
+ auto sh_safe = safe_stree.filtration_simplex_range().begin();
+
+ while (sh != stree.filtration_simplex_range().end() || sh_safe != safe_stree.filtration_simplex_range().end()) {
+ GUDHI_TEST_FLOAT_EQUALITY_CHECK(stree.filtration(*sh), safe_stree.filtration(*sh_safe), 1e-14);
+
+ std::vector<int> vh(stree.simplex_vertex_range(*sh).begin(), stree.simplex_vertex_range(*sh).end());
+ std::vector<int> safe_vh(safe_stree.simplex_vertex_range(*sh_safe).begin(),
+ safe_stree.simplex_vertex_range(*sh_safe).end());
+
+ BOOST_CHECK(vh.size() == safe_vh.size());
+ ++sh;
+ ++sh_safe;
+ }
+
+ BOOST_CHECK(sh == stree.filtration_simplex_range().end());
+ BOOST_CHECK(sh_safe == safe_stree.filtration_simplex_range().end());
+}
diff --git a/src/Alpha_complex/test/Weighted_alpha_complex_3d_unit_test.cpp b/src/Alpha_complex/test/Weighted_alpha_complex_3d_unit_test.cpp
new file mode 100644
index 00000000..c16b3718
--- /dev/null
+++ b/src/Alpha_complex/test/Weighted_alpha_complex_3d_unit_test.cpp
@@ -0,0 +1,147 @@
+/* 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
+ *
+ * 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_DYN_LINK
+#define BOOST_TEST_MODULE "alpha_complex_3d"
+#include <boost/test/unit_test.hpp>
+#include <boost/mpl/list.hpp>
+
+#include <cmath> // float comparison
+#include <limits>
+#include <string>
+#include <vector>
+#include <random>
+#include <cstddef> // for std::size_t
+
+#include <gudhi/Alpha_complex_3d.h>
+#include <gudhi/graph_simplicial_complex.h>
+#include <gudhi/Simplex_tree.h>
+#include <gudhi/Unitary_tests_utils.h>
+// to construct Alpha_complex from a OFF file of points
+#include <gudhi/Points_3D_off_io.h>
+
+#include <CGAL/Random.h>
+#include <CGAL/point_generators_3.h>
+
+using Fast_weighted_alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::FAST, true, false>;
+using Safe_weighted_alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::SAFE, true, false>;
+using Exact_weighted_alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::EXACT, true, false>;
+
+typedef boost::mpl::list<Fast_weighted_alpha_complex_3d, Safe_weighted_alpha_complex_3d,
+ Exact_weighted_alpha_complex_3d>
+ weighted_variants_type_list;
+
+#ifdef GUDHI_DEBUG
+BOOST_AUTO_TEST_CASE_TEMPLATE(Alpha_complex_weighted_throw, Weighted_alpha_complex_3d, weighted_variants_type_list) {
+ using Point_3 = typename Weighted_alpha_complex_3d::Point_3;
+ std::vector<Point_3> w_points;
+ w_points.push_back(Point_3(0.0, 0.0, 0.0));
+ w_points.push_back(Point_3(0.0, 0.0, 0.2));
+ w_points.push_back(Point_3(0.2, 0.0, 0.2));
+ // w_points.push_back(Point_3(0.6, 0.6, 0.0));
+ // w_points.push_back(Point_3(0.8, 0.8, 0.2));
+ // w_points.push_back(Point_3(0.2, 0.8, 0.6));
+
+ // weights size is different from w_points size to make weighted Alpha_complex_3d throw in debug mode
+ std::vector<double> weights = {0.01, 0.005, 0.006, 0.01, 0.009, 0.001};
+
+ std::cout << "Check exception throw in debug mode" << std::endl;
+ BOOST_CHECK_THROW(Weighted_alpha_complex_3d wac(w_points, weights), std::invalid_argument);
+}
+#endif
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(Alpha_complex_weighted, Weighted_alpha_complex_3d, weighted_variants_type_list) {
+ std::cout << "Weighted alpha complex 3d from points and weights" << std::endl;
+ using Point_3 = typename Weighted_alpha_complex_3d::Point_3;
+ std::vector<Point_3> w_points;
+ w_points.push_back(Point_3(0.0, 0.0, 0.0));
+ w_points.push_back(Point_3(0.0, 0.0, 0.2));
+ w_points.push_back(Point_3(0.2, 0.0, 0.2));
+ w_points.push_back(Point_3(0.6, 0.6, 0.0));
+ w_points.push_back(Point_3(0.8, 0.8, 0.2));
+ w_points.push_back(Point_3(0.2, 0.8, 0.6));
+
+ // weights size is different from w_points size to make weighted Alpha_complex_3d throw in debug mode
+ std::vector<double> weights = {0.01, 0.005, 0.006, 0.01, 0.009, 0.001};
+
+ Weighted_alpha_complex_3d alpha_complex_p_a_w(w_points, weights);
+ Gudhi::Simplex_tree<> stree;
+ alpha_complex_p_a_w.create_complex(stree);
+
+ std::cout << "Weighted alpha complex 3d from weighted points" << std::endl;
+ using Weighted_point_3 = typename Weighted_alpha_complex_3d::Weighted_point_3;
+
+ std::vector<Weighted_point_3> weighted_points;
+
+ for (std::size_t i = 0; i < w_points.size(); i++) {
+ weighted_points.push_back(Weighted_point_3(w_points[i], weights[i]));
+ }
+ Weighted_alpha_complex_3d alpha_complex_w_p(weighted_points);
+
+ Gudhi::Simplex_tree<> stree_bis;
+ alpha_complex_w_p.create_complex(stree_bis);
+
+ // ---------------------
+ // Compare both versions
+ // ---------------------
+ std::cout << "Weighted alpha complex 3d is of dimension " << stree_bis.dimension() << " - versus "
+ << stree.dimension() << std::endl;
+ BOOST_CHECK(stree_bis.dimension() == stree.dimension());
+ std::cout << "Weighted alpha complex 3d num_simplices " << stree_bis.num_simplices() << " - versus "
+ << stree.num_simplices() << std::endl;
+ BOOST_CHECK(stree_bis.num_simplices() == stree.num_simplices());
+ std::cout << "Weighted alpha complex 3d num_vertices " << stree_bis.num_vertices() << " - versus "
+ << stree.num_vertices() << std::endl;
+ BOOST_CHECK(stree_bis.num_vertices() == stree.num_vertices());
+
+ auto sh = stree.filtration_simplex_range().begin();
+ while (sh != stree.filtration_simplex_range().end()) {
+ std::vector<int> simplex;
+ std::vector<int> exact_simplex;
+#ifdef DEBUG_TRACES
+ std::cout << " ( ";
+#endif
+ for (auto vertex : stree.simplex_vertex_range(*sh)) {
+ simplex.push_back(vertex);
+#ifdef DEBUG_TRACES
+ std::cout << vertex << " ";
+#endif
+ }
+#ifdef DEBUG_TRACES
+ std::cout << ") -> "
+ << "[" << stree.filtration(*sh) << "] ";
+ std::cout << std::endl;
+#endif
+
+ // Find it in the exact structure
+ auto sh_exact = stree_bis.find(simplex);
+ BOOST_CHECK(sh_exact != stree_bis.null_simplex());
+
+ // Exact and non-exact version is not exactly the same due to float comparison
+ GUDHI_TEST_FLOAT_EQUALITY_CHECK(stree_bis.filtration(sh_exact), stree.filtration(*sh));
+
+ ++sh;
+ }
+}
diff --git a/src/Alpha_complex/test/Weighted_periodic_alpha_complex_3d_unit_test.cpp b/src/Alpha_complex/test/Weighted_periodic_alpha_complex_3d_unit_test.cpp
new file mode 100644
index 00000000..e8ac83e5
--- /dev/null
+++ b/src/Alpha_complex/test/Weighted_periodic_alpha_complex_3d_unit_test.cpp
@@ -0,0 +1,239 @@
+/* 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
+ *
+ * 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_DYN_LINK
+#define BOOST_TEST_MODULE "alpha_complex_3d"
+#include <boost/test/unit_test.hpp>
+#include <boost/mpl/list.hpp>
+
+#include <cmath> // float comparison
+#include <limits>
+#include <string>
+#include <vector>
+#include <random>
+#include <cstddef> // for std::size_t
+
+#include <gudhi/Alpha_complex_3d.h>
+#include <gudhi/graph_simplicial_complex.h>
+#include <gudhi/Simplex_tree.h>
+#include <gudhi/Unitary_tests_utils.h>
+// to construct Alpha_complex from a OFF file of points
+#include <gudhi/Points_3D_off_io.h>
+
+#include <CGAL/Random.h>
+#include <CGAL/point_generators_3.h>
+
+using Fast_weighted_periodic_alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::FAST, true, true>;
+using Safe_weighted_periodic_alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::SAFE, true, true>;
+using Exact_weighted_periodic_alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::EXACT, true, true>;
+
+
+typedef boost::mpl::list<Fast_weighted_periodic_alpha_complex_3d, Exact_weighted_periodic_alpha_complex_3d,
+ Safe_weighted_periodic_alpha_complex_3d>
+ wp_variants_type_list;
+
+#ifdef GUDHI_DEBUG
+BOOST_AUTO_TEST_CASE_TEMPLATE(Alpha_complex_weighted_periodic_throw, Weighted_periodic_alpha_complex_3d,
+ wp_variants_type_list) {
+ std::cout << "Weighted periodic alpha complex 3d exception throw" << std::endl;
+
+ using Creator = CGAL::Creator_uniform_3<double, typename Weighted_periodic_alpha_complex_3d::Point_3>;
+ CGAL::Random random(7);
+ CGAL::Random_points_in_cube_3<typename Weighted_periodic_alpha_complex_3d::Point_3, Creator> in_cube(1, random);
+ std::vector<typename Weighted_periodic_alpha_complex_3d::Point_3> wp_points;
+
+ for (int i = 0; i < 50; i++) {
+ typename Weighted_periodic_alpha_complex_3d::Point_3 p = *in_cube++;
+ wp_points.push_back(p);
+ }
+ std::vector<double> p_weights;
+ // Weights must be in range ]0, 1/64 = 0.015625[
+ for (std::size_t i = 0; i < wp_points.size(); ++i) {
+ p_weights.push_back(random.get_double(0., 0.01));
+ }
+
+ std::cout << "Cuboid is not iso exception" << std::endl;
+ // Check it throws an exception when the cuboid is not iso
+ BOOST_CHECK_THROW(
+ Weighted_periodic_alpha_complex_3d wp_alpha_complex(wp_points, p_weights, -1., -1., -1., 0.9, 1., 1.),
+ std::invalid_argument);
+ BOOST_CHECK_THROW(
+ Weighted_periodic_alpha_complex_3d wp_alpha_complex(wp_points, p_weights, -1., -1., -1., 1., 0.9, 1.),
+ std::invalid_argument);
+ BOOST_CHECK_THROW(
+ Weighted_periodic_alpha_complex_3d wp_alpha_complex(wp_points, p_weights, -1., -1., -1., 1., 1., 0.9),
+ std::invalid_argument);
+ BOOST_CHECK_THROW(
+ Weighted_periodic_alpha_complex_3d wp_alpha_complex(wp_points, p_weights, -1., -1., -1., 1.1, 1., 1.),
+ std::invalid_argument);
+ BOOST_CHECK_THROW(
+ Weighted_periodic_alpha_complex_3d wp_alpha_complex(wp_points, p_weights, -1., -1., -1., 1., 1.1, 1.),
+ std::invalid_argument);
+ BOOST_CHECK_THROW(
+ Weighted_periodic_alpha_complex_3d wp_alpha_complex(wp_points, p_weights, -1., -1., -1., 1., 1., 1.1),
+ std::invalid_argument);
+
+ std::cout << "0 <= point.weight() < 1/64 * domain_size * domain_size exception" << std::endl;
+ // Weights must be in range ]0, 1/64 = 0.015625[
+ double temp = p_weights[25];
+ p_weights[25] = 1.0;
+ BOOST_CHECK_THROW(Weighted_periodic_alpha_complex_3d wp_alpha_complex(wp_points, p_weights, 0., 0., 0., 1., 1., 1.),
+ std::invalid_argument);
+ // Weights must be in range ]0, 1/64 = 0.015625[
+ p_weights[25] = temp;
+ temp = p_weights[14];
+ p_weights[14] = -1e-10;
+ BOOST_CHECK_THROW(Weighted_periodic_alpha_complex_3d wp_alpha_complex(wp_points, p_weights, 0., 0., 0., 1., 1., 1.),
+ std::invalid_argument);
+ p_weights[14] = temp;
+
+ std::cout << "wp_points and p_weights size exception" << std::endl;
+ // Weights and points must have the same size
+ // + 1
+ p_weights.push_back(1e-10);
+ BOOST_CHECK_THROW(Weighted_periodic_alpha_complex_3d wp_alpha_complex(wp_points, p_weights, 0., 0., 0., 1., 1., 1.),
+ std::invalid_argument);
+ // - 1
+ p_weights.pop_back();
+ p_weights.pop_back();
+ BOOST_CHECK_THROW(Weighted_periodic_alpha_complex_3d wp_alpha_complex(wp_points, p_weights, 0., 0., 0., 1., 1., 1.),
+ std::invalid_argument);
+}
+#endif
+
+BOOST_AUTO_TEST_CASE(Alpha_complex_weighted_periodic) {
+ // ---------------------
+ // Fast weighted periodic version
+ // ---------------------
+ std::cout << "Fast weighted periodic alpha complex 3d" << std::endl;
+
+ using Creator = CGAL::Creator_uniform_3<double, Fast_weighted_periodic_alpha_complex_3d::Point_3>;
+ CGAL::Random random(7);
+ CGAL::Random_points_in_cube_3<Fast_weighted_periodic_alpha_complex_3d::Point_3, Creator> in_cube(1, random);
+ std::vector<Fast_weighted_periodic_alpha_complex_3d::Point_3> p_points;
+
+ for (int i = 0; i < 50; i++) {
+ Fast_weighted_periodic_alpha_complex_3d::Point_3 p = *in_cube++;
+ p_points.push_back(p);
+ }
+ std::vector<double> p_weights;
+ // Weights must be in range ]0, 1/64 = 0.015625[
+ for (std::size_t i = 0; i < p_points.size(); ++i) {
+ p_weights.push_back(random.get_double(0., 0.01));
+ }
+
+ Fast_weighted_periodic_alpha_complex_3d periodic_alpha_complex(p_points, p_weights, -1., -1., -1., 1., 1., 1.);
+
+ Gudhi::Simplex_tree<> stree;
+ periodic_alpha_complex.create_complex(stree);
+
+ // ----------------------
+ // Exact weighted periodic version
+ // ----------------------
+ std::cout << "Exact weighted periodic alpha complex 3d" << std::endl;
+
+ std::vector<Exact_weighted_periodic_alpha_complex_3d::Point_3> e_p_points;
+
+ for (auto p : p_points) {
+ e_p_points.push_back(Exact_weighted_periodic_alpha_complex_3d::Point_3(p[0], p[1], p[2]));
+ }
+
+ Exact_weighted_periodic_alpha_complex_3d exact_alpha_complex(e_p_points, p_weights, -1., -1., -1., 1., 1., 1.);
+
+ Gudhi::Simplex_tree<> exact_stree;
+ exact_alpha_complex.create_complex(exact_stree);
+
+ // ---------------------
+ // Compare both versions
+ // ---------------------
+ std::cout << "Exact weighted periodic alpha complex 3d is of dimension " << exact_stree.dimension()
+ << " - Non exact is " << stree.dimension() << std::endl;
+ BOOST_CHECK(exact_stree.dimension() == stree.dimension());
+ std::cout << "Exact weighted periodic alpha complex 3d num_simplices " << exact_stree.num_simplices()
+ << " - Non exact is " << stree.num_simplices() << std::endl;
+ BOOST_CHECK(exact_stree.num_simplices() == stree.num_simplices());
+ std::cout << "Exact weighted periodic alpha complex 3d num_vertices " << exact_stree.num_vertices()
+ << " - Non exact is " << stree.num_vertices() << std::endl;
+ BOOST_CHECK(exact_stree.num_vertices() == stree.num_vertices());
+
+ // We cannot compare as objects from dispatcher on the alpha shape is not deterministic.
+ // cf. https://github.com/CGAL/cgal/issues/3346
+ auto sh = stree.filtration_simplex_range().begin();
+ auto sh_exact = exact_stree.filtration_simplex_range().begin();
+
+ while (sh != stree.filtration_simplex_range().end() || sh_exact != exact_stree.filtration_simplex_range().end()) {
+ GUDHI_TEST_FLOAT_EQUALITY_CHECK(stree.filtration(*sh), exact_stree.filtration(*sh_exact), 1e-14);
+
+ std::vector<int> vh(stree.simplex_vertex_range(*sh).begin(), stree.simplex_vertex_range(*sh).end());
+ std::vector<int> exact_vh(exact_stree.simplex_vertex_range(*sh_exact).begin(),
+ exact_stree.simplex_vertex_range(*sh_exact).end());
+
+ BOOST_CHECK(vh.size() == exact_vh.size());
+ ++sh;
+ ++sh_exact;
+ }
+
+ BOOST_CHECK(sh == stree.filtration_simplex_range().end());
+ BOOST_CHECK(sh_exact == exact_stree.filtration_simplex_range().end());
+
+ // ----------------------
+ // Safe weighted periodic version
+ // ----------------------
+ std::cout << "Safe weighted periodic alpha complex 3d" << std::endl;
+
+ std::vector<Safe_weighted_periodic_alpha_complex_3d::Point_3> s_p_points;
+
+ for (auto p : p_points) {
+ s_p_points.push_back(Safe_weighted_periodic_alpha_complex_3d::Point_3(p[0], p[1], p[2]));
+ }
+
+ Safe_weighted_periodic_alpha_complex_3d safe_alpha_complex(s_p_points, p_weights, -1., -1., -1., 1., 1., 1.);
+
+ Gudhi::Simplex_tree<> safe_stree;
+ safe_alpha_complex.create_complex(safe_stree);
+
+ // ---------------------
+ // Compare both versions
+ // ---------------------
+ // We cannot compare as objects from dispatcher on the alpha shape is not deterministic.
+ // cf. https://github.com/CGAL/cgal/issues/3346
+ sh = stree.filtration_simplex_range().begin();
+ auto sh_safe = safe_stree.filtration_simplex_range().begin();
+
+ while (sh != stree.filtration_simplex_range().end() || sh_safe != safe_stree.filtration_simplex_range().end()) {
+ GUDHI_TEST_FLOAT_EQUALITY_CHECK(stree.filtration(*sh), safe_stree.filtration(*sh_safe), 1e-14);
+
+ std::vector<int> vh(stree.simplex_vertex_range(*sh).begin(), stree.simplex_vertex_range(*sh).end());
+ std::vector<int> safe_vh(safe_stree.simplex_vertex_range(*sh_safe).begin(),
+ safe_stree.simplex_vertex_range(*sh_safe).end());
+
+ BOOST_CHECK(vh.size() == safe_vh.size());
+ ++sh;
+ ++sh_safe;
+ }
+
+ BOOST_CHECK(sh == stree.filtration_simplex_range().end());
+ BOOST_CHECK(sh_safe == safe_stree.filtration_simplex_range().end());
+}
diff --git a/src/Alpha_complex/utilities/CMakeLists.txt b/src/Alpha_complex/utilities/CMakeLists.txt
index 7ace6064..e76edc5f 100644
--- a/src/Alpha_complex/utilities/CMakeLists.txt
+++ b/src/Alpha_complex/utilities/CMakeLists.txt
@@ -1,64 +1,61 @@
project(Alpha_complex_utilities)
-if(CGAL_FOUND)
- add_executable(alpha_complex_3d_persistence alpha_complex_3d_persistence.cpp)
- target_link_libraries(alpha_complex_3d_persistence ${CGAL_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY})
- add_executable(exact_alpha_complex_3d_persistence exact_alpha_complex_3d_persistence.cpp)
- target_link_libraries(exact_alpha_complex_3d_persistence ${CGAL_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY})
- add_executable(weighted_alpha_complex_3d_persistence weighted_alpha_complex_3d_persistence.cpp)
- target_link_libraries(weighted_alpha_complex_3d_persistence ${CGAL_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY})
+if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0)
+ add_executable (alpha_complex_persistence alpha_complex_persistence.cpp)
+ target_link_libraries(alpha_complex_persistence ${CGAL_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY})
if (TBB_FOUND)
- target_link_libraries(alpha_complex_3d_persistence ${TBB_LIBRARIES})
- target_link_libraries(exact_alpha_complex_3d_persistence ${TBB_LIBRARIES})
- target_link_libraries(weighted_alpha_complex_3d_persistence ${TBB_LIBRARIES})
+ target_link_libraries(alpha_complex_persistence ${TBB_LIBRARIES})
endif(TBB_FOUND)
-
- add_test(NAME Alpha_complex_utilities_alpha_complex_3d_persistence COMMAND $<TARGET_FILE:alpha_complex_3d_persistence>
+ add_test(NAME Alpha_complex_utilities_alpha_complex_persistence COMMAND $<TARGET_FILE:alpha_complex_persistence>
"${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off" "-p" "2" "-m" "0.45")
- add_test(NAME Alpha_complex_utilities_exact_alpha_complex_3d COMMAND $<TARGET_FILE:exact_alpha_complex_3d_persistence>
- "${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off" "-p" "2" "-m" "0.45")
- add_test(NAME Alpha_complex_utilities_weighted_alpha_complex_3d COMMAND $<TARGET_FILE:weighted_alpha_complex_3d_persistence>
- "${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off" "${CMAKE_SOURCE_DIR}/data/points/tore3D_300.weights" "-p" "2" "-m" "0.45")
-
- install(TARGETS alpha_complex_3d_persistence DESTINATION bin)
- install(TARGETS exact_alpha_complex_3d_persistence DESTINATION bin)
- install(TARGETS weighted_alpha_complex_3d_persistence DESTINATION bin)
-
- if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0)
- add_executable (alpha_complex_persistence alpha_complex_persistence.cpp)
- target_link_libraries(alpha_complex_persistence ${CGAL_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY})
-
- add_executable(periodic_alpha_complex_3d_persistence periodic_alpha_complex_3d_persistence.cpp)
- target_link_libraries(periodic_alpha_complex_3d_persistence ${CGAL_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY})
-
- if (TBB_FOUND)
- target_link_libraries(alpha_complex_persistence ${TBB_LIBRARIES})
- target_link_libraries(periodic_alpha_complex_3d_persistence ${TBB_LIBRARIES})
- endif(TBB_FOUND)
- add_test(NAME Alpha_complex_utilities_alpha_complex_persistence COMMAND $<TARGET_FILE:alpha_complex_persistence>
- "${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off" "-p" "2" "-m" "0.45")
- add_test(NAME Alpha_complex_utilities_periodic_alpha_complex_3d_persistence COMMAND $<TARGET_FILE:periodic_alpha_complex_3d_persistence>
- "${CMAKE_SOURCE_DIR}/data/points/grid_10_10_10_in_0_1.off" "${CMAKE_SOURCE_DIR}/data/points/iso_cuboid_3_in_0_1.txt" "-p" "2" "-m" "0")
- install(TARGETS alpha_complex_persistence DESTINATION bin)
- install(TARGETS periodic_alpha_complex_3d_persistence DESTINATION bin)
+ install(TARGETS alpha_complex_persistence DESTINATION bin)
- endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0)
+endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0)
- if (NOT CGAL_VERSION VERSION_LESS 4.11.0)
- add_executable(weighted_periodic_alpha_complex_3d_persistence weighted_periodic_alpha_complex_3d_persistence.cpp)
- target_link_libraries(weighted_periodic_alpha_complex_3d_persistence ${CGAL_LIBRARY})
- if (TBB_FOUND)
- target_link_libraries(weighted_periodic_alpha_complex_3d_persistence ${TBB_LIBRARIES})
- endif(TBB_FOUND)
-
- add_test(NAME Alpha_complex_utilities_weigted_periodic_alpha_complex_3d COMMAND $<TARGET_FILE:weighted_periodic_alpha_complex_3d_persistence>
- "${CMAKE_SOURCE_DIR}/data/points/grid_10_10_10_in_0_1.off" "${CMAKE_SOURCE_DIR}/data/points/grid_10_10_10_in_0_1.weights"
- "${CMAKE_SOURCE_DIR}/data/points/iso_cuboid_3_in_0_1.txt" "3" "1.0")
+if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0)
+ add_executable(alpha_complex_3d_persistence alpha_complex_3d_persistence.cpp)
+ target_link_libraries(alpha_complex_3d_persistence ${CGAL_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY})
+ if (TBB_FOUND)
+ target_link_libraries(alpha_complex_3d_persistence ${TBB_LIBRARIES})
+ endif(TBB_FOUND)
- install(TARGETS weighted_periodic_alpha_complex_3d_persistence DESTINATION bin)
+ add_test(NAME Alpha_complex_utilities_alpha_complex_3d COMMAND $<TARGET_FILE:alpha_complex_3d_persistence>
+ "${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off"
+ "-p" "2" "-m" "0.45" "-o" "safe.pers")
+
+ add_test(NAME Alpha_complex_utilities_exact_alpha_complex_3d COMMAND $<TARGET_FILE:alpha_complex_3d_persistence>
+ "${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off"
+ "-p" "2" "-m" "0.45" "-o" "exact.pers" "-e")
+
+ add_test(NAME Alpha_complex_utilities_safe_alpha_complex_3d COMMAND $<TARGET_FILE:alpha_complex_3d_persistence>
+ "${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off"
+ "-p" "2" "-m" "0.45" "-o" "fast.pers" "-f")
+
+ if (DIFF_PATH)
+ add_test(Alpha_complex_utilities_diff_alpha_complex_3d ${DIFF_PATH}
+ "exact.pers" "safe.pers")
+ add_test(Alpha_complex_utilities_diff_alpha_complex_3d ${DIFF_PATH}
+ "fast.pers" "safe.pers")
+ endif()
+
+ add_test(NAME Alpha_complex_utilities_periodic_alpha_complex_3d_persistence COMMAND $<TARGET_FILE:alpha_complex_3d_persistence>
+ "${CMAKE_SOURCE_DIR}/data/points/grid_10_10_10_in_0_1.off"
+ "-c" "${CMAKE_SOURCE_DIR}/data/points/iso_cuboid_3_in_0_1.txt"
+ "-p" "2" "-m" "0")
+
+ add_test(NAME Alpha_complex_utilities_weighted_alpha_complex_3d COMMAND $<TARGET_FILE:alpha_complex_3d_persistence>
+ "${CMAKE_SOURCE_DIR}/data/points/grid_10_10_10_in_0_1.off"
+ "-w" "${CMAKE_SOURCE_DIR}/data/points/grid_10_10_10_in_0_1.weights"
+ "-p" "2" "-m" "0")
+
+ add_test(NAME Alpha_complex_utilities_weighted_periodic_alpha_complex_3d COMMAND $<TARGET_FILE:alpha_complex_3d_persistence>
+ "${CMAKE_SOURCE_DIR}/data/points/grid_10_10_10_in_0_1.off"
+ "-w" "${CMAKE_SOURCE_DIR}/data/points/grid_10_10_10_in_0_1.weights"
+ "-c" "${CMAKE_SOURCE_DIR}/data/points/iso_cuboid_3_in_0_1.txt"
+ "-p" "2" "-m" "0" "-e")
- endif (NOT CGAL_VERSION VERSION_LESS 4.11.0)
+ install(TARGETS alpha_complex_3d_persistence DESTINATION bin)
-endif(CGAL_FOUND)
+endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0)
diff --git a/src/Alpha_complex/utilities/alpha_complex_3d_helper.h b/src/Alpha_complex/utilities/alpha_complex_3d_helper.h
deleted file mode 100644
index a72fd96d..00000000
--- a/src/Alpha_complex/utilities/alpha_complex_3d_helper.h
+++ /dev/null
@@ -1,74 +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
- *
- * 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 ALPHA_COMPLEX_3D_HELPER_H_
-#define ALPHA_COMPLEX_3D_HELPER_H_
-
-template <class Vertex_list, class Cell_handle>
-Vertex_list from_cell(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;
-}
-
-template <class Vertex_list, class Facet>
-Vertex_list from_facet(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;
-}
-
-template <class Vertex_list, class Edge_3>
-Vertex_list from_edge(const Edge_3& edg) {
- Vertex_list the_list;
- for (auto i : {edg.second, edg.third}) {
-#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;
-}
-
-template <class Vertex_list, class Vertex_handle>
-Vertex_list from_vertex(const 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;
-}
-
-#endif // ALPHA_COMPLEX_3D_HELPER_H_
diff --git a/src/Alpha_complex/utilities/alpha_complex_3d_persistence.cpp b/src/Alpha_complex/utilities/alpha_complex_3d_persistence.cpp
index 6e603155..09c84eb3 100644
--- a/src/Alpha_complex/utilities/alpha_complex_3d_persistence.cpp
+++ b/src/Alpha_complex/utilities/alpha_complex_3d_persistence.cpp
@@ -20,188 +20,219 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <boost/version.hpp>
#include <boost/program_options.hpp>
#include <boost/variant.hpp>
-#if BOOST_VERSION >= 105400
-#include <boost/container/static_vector.hpp>
-#endif
-
+#include <gudhi/Alpha_complex_3d.h>
#include <gudhi/Simplex_tree.h>
#include <gudhi/Persistent_cohomology.h>
#include <gudhi/Points_3D_off_io.h>
-#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
-#include <CGAL/Delaunay_triangulation_3.h>
-#include <CGAL/Alpha_shape_3.h>
-#include <CGAL/Alpha_shape_cell_base_3.h>
-#include <CGAL/Alpha_shape_vertex_base_3.h>
-#include <CGAL/iterator.h>
-
#include <fstream>
-#include <cmath>
#include <string>
-#include <tuple>
-#include <map>
-#include <utility>
#include <vector>
-#include <cstdlib>
-
-#include "alpha_complex_3d_helper.h"
-
-// Alpha_shape_3 templates type definitions
-using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
-using Vb = CGAL::Alpha_shape_vertex_base_3<Kernel>;
-using Fb = CGAL::Alpha_shape_cell_base_3<Kernel>;
-using Tds = CGAL::Triangulation_data_structure_3<Vb, Fb>;
-using Triangulation_3 = CGAL::Delaunay_triangulation_3<Kernel, Tds>;
-using Alpha_shape_3 = CGAL::Alpha_shape_3<Triangulation_3>;
-
-// From file type definition
-using Point_3 = Kernel::Point_3;
-
-// filtration with alpha values needed type definition
-using Alpha_value_type = Alpha_shape_3::FT;
-using Object = CGAL::Object;
-using Dispatch =
- 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> > > >;
-using Cell_handle = Alpha_shape_3::Cell_handle;
-using Facet = Alpha_shape_3::Facet;
-using Edge_3 = Alpha_shape_3::Edge;
-using Vertex_handle = Alpha_shape_3::Vertex_handle;
-
-#if BOOST_VERSION >= 105400
-using Vertex_list = boost::container::static_vector<Alpha_shape_3::Vertex_handle, 4>;
-#else
-using Vertex_list = std::vector<Alpha_shape_3::Vertex_handle>;
-#endif
+#include <limits> // for numeric_limits<>
// gudhi type definition
-using ST = Gudhi::Simplex_tree<Gudhi::Simplex_tree_options_fast_persistence>;
-using Filtration_value = ST::Filtration_value;
-using Simplex_tree_vertex = ST::Vertex_handle;
-using Alpha_shape_simplex_tree_map = std::map<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex>;
-using Simplex_tree_vector_vertex = std::vector<Simplex_tree_vertex>;
+using Simplex_tree = Gudhi::Simplex_tree<Gudhi::Simplex_tree_options_fast_persistence>;
+using Filtration_value = Simplex_tree::Filtration_value;
using Persistent_cohomology =
- Gudhi::persistent_cohomology::Persistent_cohomology<ST, Gudhi::persistent_cohomology::Field_Zp>;
-
-void program_options(int argc, char *argv[], std::string &off_file_points, std::string &output_file_diag,
- int &coeff_field_characteristic, Filtration_value &min_persistence);
-
-int main(int argc, char **argv) {
- std::string off_file_points;
- std::string output_file_diag;
- int coeff_field_characteristic;
- Filtration_value min_persistence;
+ Gudhi::persistent_cohomology::Persistent_cohomology<Simplex_tree, Gudhi::persistent_cohomology::Field_Zp>;
+
+void program_options(int argc, char *argv[], std::string &off_file_points, bool &exact, bool &safe,
+ std::string &weight_file, std::string &cuboid_file, std::string &output_file_diag,
+ Filtration_value &alpha_square_max_value, int &coeff_field_characteristic,
+ Filtration_value &min_persistence);
+
+bool read_weight_file(const std::string &weight_file, std::vector<double> &weights) {
+ // Read weights information from file
+ std::ifstream weights_ifstr(weight_file);
+ if (weights_ifstr.good()) {
+ double weight = 0.0;
+ // Attempt read the weight in a double format, return false if it fails
+ while (weights_ifstr >> weight) {
+ weights.push_back(weight);
+ }
+ } else {
+ return false;
+ }
+ return true;
+}
- program_options(argc, argv, off_file_points, output_file_diag, coeff_field_characteristic, min_persistence);
+bool read_cuboid_file(const std::string &cuboid_file, double &x_min, double &y_min, double &z_min, double &x_max,
+ double &y_max, double &z_max) {
+ // Read weights information from file
+ std::ifstream iso_cuboid_str(cuboid_file);
+ if (iso_cuboid_str.is_open()) {
+ if (!(iso_cuboid_str >> x_min >> y_min >> z_min >> x_max >> y_max >> z_max)) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ return true;
+}
+template <typename AlphaComplex3d>
+std::vector<typename AlphaComplex3d::Point_3> read_off(const std::string &off_file_points) {
// Read the OFF file (input file name given as parameter) and triangulate points
- Gudhi::Points_3D_off_reader<Point_3> off_reader(off_file_points);
+ Gudhi::Points_3D_off_reader<typename AlphaComplex3d::Point_3> off_reader(off_file_points);
// Check the read operation was correct
if (!off_reader.is_valid()) {
- std::cerr << "Unable to read file " << off_file_points << std::endl;
+ std::cerr << "Unable to read OFF file " << off_file_points << std::endl;
exit(-1);
}
+ return off_reader.get_point_cloud();
+}
- // Retrieve the points
- std::vector<Point_3> lp = off_reader.get_point_cloud();
-
- // 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
-
- // 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));
-
- 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
-
- 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;
- ST 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<Vertex_list, Cell_handle>(*cell);
- count_cells++;
- } else if (const Facet *facet = CGAL::object_cast<Facet>(&object_iterator)) {
- vertex_list = from_facet<Vertex_list, Facet>(*facet);
- count_facets++;
- } else if (const Edge_3 *edge = CGAL::object_cast<Edge_3>(&object_iterator)) {
- vertex_list = from_edge<Vertex_list, Edge_3>(*edge);
- count_edges++;
- } else if (const Vertex_handle *vertex = CGAL::object_cast<Vertex_handle>(&object_iterator)) {
- count_vertices++;
- vertex_list = from_vertex<Vertex_list, Vertex_handle>(*vertex);
- }
- // Construction of the vector of simplex_tree vertex from list of alpha_shapes vertex
- Simplex_tree_vector_vertex the_simplex;
- 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 " << vertex << std::endl;
-#endif // DEBUG_TRACES
- the_simplex.push_back(vertex);
- map_cgal_simplex_tree.emplace(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.push_back(vertex);
- }
+int main(int argc, char **argv) {
+ std::string off_file_points;
+ std::string weight_file;
+ std::string cuboid_file;
+ std::string output_file_diag;
+ Filtration_value alpha_square_max_value = 0.;
+ int coeff_field_characteristic = 0;
+ Filtration_value min_persistence = 0.;
+ bool exact_version = false;
+ bool fast_version = false;
+ bool weighted_version = false;
+ bool periodic_version = false;
+
+ program_options(argc, argv, off_file_points, exact_version, fast_version, weight_file, cuboid_file, output_file_diag,
+ alpha_square_max_value, coeff_field_characteristic, min_persistence);
+
+ std::vector<double> weights;
+ if (weight_file != std::string()) {
+ if (!read_weight_file(weight_file, weights)) {
+ std::cerr << "Unable to read weights file " << weight_file << std::endl;
+ exit(-1);
}
- // Construction of the simplex_tree
- Filtration_value filtr = /*std::sqrt*/ (*the_alpha_value_iterator);
-#ifdef DEBUG_TRACES
- std::cout << "filtration = " << filtr << std::endl;
-#endif // DEBUG_TRACES
- simplex_tree.insert_simplex(the_simplex, filtr);
- GUDHI_CHECK(the_alpha_value_iterator != the_alpha_values.end(), "CGAL provided more simplices than values");
- ++the_alpha_value_iterator;
+ weighted_version = true;
}
-#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;
+ double x_min = 0., y_min = 0., z_min = 0., x_max = 0., y_max = 0., z_max = 0.;
+ std::ifstream iso_cuboid_str(argv[3]);
+ if (cuboid_file != std::string()) {
+ if (!read_cuboid_file(cuboid_file, x_min, y_min, z_min, x_max, y_max, z_max)) {
+ std::cerr << "Unable to read cuboid file " << cuboid_file << std::endl;
+ exit(-1);
+ }
+ periodic_version = true;
+ }
- 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;
- std::cout << " Dimension = " << simplex_tree.dimension() << " ";
-#endif // DEBUG_TRACES
+ Gudhi::alpha_complex::complexity complexity = Gudhi::alpha_complex::complexity::SAFE;
+ if (exact_version) {
+ if (fast_version) {
+ std::cerr << "You cannot set the exact and the fast version." << std::endl;
+ exit(-1);
+ }
+ complexity = Gudhi::alpha_complex::complexity::EXACT;
+ }
+ if (fast_version) {
+ complexity = Gudhi::alpha_complex::complexity::FAST;
+ }
-#ifdef DEBUG_TRACES
- std::cout << "Iterator on vertices: " << std::endl;
- for (auto vertex : simplex_tree.complex_vertex_range()) {
- std::cout << vertex << " ";
+ Simplex_tree simplex_tree;
+
+ switch (complexity) {
+ case Gudhi::alpha_complex::complexity::FAST:
+ if (weighted_version) {
+ if (periodic_version) {
+ using Alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::FAST, true, true>;
+ auto points = read_off<Alpha_complex_3d>(off_file_points);
+ Alpha_complex_3d alpha_complex(points, weights, x_min, y_min, z_min, x_max, y_max, z_max);
+ alpha_complex.create_complex(simplex_tree, alpha_square_max_value);
+ } else {
+ using Alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::FAST, true, false>;
+ auto points = read_off<Alpha_complex_3d>(off_file_points);
+ Alpha_complex_3d alpha_complex(points, weights);
+ alpha_complex.create_complex(simplex_tree, alpha_square_max_value);
+ }
+ } else {
+ if (periodic_version) {
+ using Alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::FAST, false, true>;
+ auto points = read_off<Alpha_complex_3d>(off_file_points);
+ Alpha_complex_3d alpha_complex(points, x_min, y_min, z_min, x_max, y_max, z_max);
+ alpha_complex.create_complex(simplex_tree, alpha_square_max_value);
+ } else {
+ using Alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::FAST, false, false>;
+ auto points = read_off<Alpha_complex_3d>(off_file_points);
+ Alpha_complex_3d alpha_complex(points);
+ alpha_complex.create_complex(simplex_tree, alpha_square_max_value);
+ }
+ }
+ break;
+ case Gudhi::alpha_complex::complexity::EXACT:
+ if (weighted_version) {
+ if (periodic_version) {
+ using Alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::EXACT, true, true>;
+ auto points = read_off<Alpha_complex_3d>(off_file_points);
+ Alpha_complex_3d alpha_complex(points, weights, x_min, y_min, z_min, x_max, y_max, z_max);
+ alpha_complex.create_complex(simplex_tree, alpha_square_max_value);
+ } else {
+ using Alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::EXACT, true, false>;
+ auto points = read_off<Alpha_complex_3d>(off_file_points);
+ Alpha_complex_3d alpha_complex(points, weights);
+ alpha_complex.create_complex(simplex_tree, alpha_square_max_value);
+ }
+ } else {
+ if (periodic_version) {
+ using Alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::EXACT, false, true>;
+ auto points = read_off<Alpha_complex_3d>(off_file_points);
+ Alpha_complex_3d alpha_complex(points, x_min, y_min, z_min, x_max, y_max, z_max);
+ alpha_complex.create_complex(simplex_tree, alpha_square_max_value);
+ } else {
+ using Alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::EXACT, false, false>;
+ auto points = read_off<Alpha_complex_3d>(off_file_points);
+ Alpha_complex_3d alpha_complex(points);
+ alpha_complex.create_complex(simplex_tree, alpha_square_max_value);
+ }
+ }
+ break;
+ case Gudhi::alpha_complex::complexity::SAFE:
+ if (weighted_version) {
+ if (periodic_version) {
+ using Alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::SAFE, true, true>;
+ auto points = read_off<Alpha_complex_3d>(off_file_points);
+ Alpha_complex_3d alpha_complex(points, weights, x_min, y_min, z_min, x_max, y_max, z_max);
+ alpha_complex.create_complex(simplex_tree, alpha_square_max_value);
+ } else {
+ using Alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::SAFE, true, false>;
+ auto points = read_off<Alpha_complex_3d>(off_file_points);
+ Alpha_complex_3d alpha_complex(points, weights);
+ alpha_complex.create_complex(simplex_tree, alpha_square_max_value);
+ }
+ } else {
+ if (periodic_version) {
+ using Alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::SAFE, false, true>;
+ auto points = read_off<Alpha_complex_3d>(off_file_points);
+ Alpha_complex_3d alpha_complex(points, x_min, y_min, z_min, x_max, y_max, z_max);
+ alpha_complex.create_complex(simplex_tree, alpha_square_max_value);
+ } else {
+ using Alpha_complex_3d =
+ Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::SAFE, false, false>;
+ auto points = read_off<Alpha_complex_3d>(off_file_points);
+ Alpha_complex_3d alpha_complex(points);
+ alpha_complex.create_complex(simplex_tree, alpha_square_max_value);
+ }
+ }
+ break;
+ default:
+ std::cerr << "Unknown complexity value " << std::endl;
+ exit(-1);
+ break;
}
-#endif // DEBUG_TRACES
// Sort the simplices in the order of the filtration
simplex_tree.initialize_filtration();
@@ -227,8 +258,10 @@ int main(int argc, char **argv) {
return 0;
}
-void program_options(int argc, char *argv[], std::string &off_file_points, std::string &output_file_diag,
- int &coeff_field_characteristic, Filtration_value &min_persistence) {
+void program_options(int argc, char *argv[], std::string &off_file_points, bool &exact, bool &fast,
+ std::string &weight_file, std::string &cuboid_file, std::string &output_file_diag,
+ Filtration_value &alpha_square_max_value, int &coeff_field_characteristic,
+ Filtration_value &min_persistence) {
namespace po = boost::program_options;
po::options_description hidden("Hidden options");
hidden.add_options()("input-file", po::value<std::string>(&off_file_points),
@@ -236,8 +269,20 @@ void program_options(int argc, char *argv[], std::string &off_file_points, std::
po::options_description visible("Allowed options", 100);
visible.add_options()("help,h", "produce help message")(
+ "exact,e", po::bool_switch(&exact),
+ "To activate exact version of Alpha complex 3d (default is false, not available if fast is set)")(
+ "fast,f", po::bool_switch(&fast),
+ "To activate fast version of Alpha complex 3d (default is false, not available if exact is set)")(
+ "weight-file,w", po::value<std::string>(&weight_file)->default_value(std::string()),
+ "Name of file containing a point weights. Format is one weight per line:\n W1\n ...\n Wn ")(
+ "cuboid-file,c", po::value<std::string>(&cuboid_file),
+ "Name of file describing the periodic domain. Format is:\n min_hx min_hy min_hz\n max_hx max_hy max_hz")(
"output-file,o", po::value<std::string>(&output_file_diag)->default_value(std::string()),
"Name of file in which the persistence diagram is written. Default print in std::cout")(
+ "max-alpha-square-value,r",
+ po::value<Filtration_value>(&alpha_square_max_value)
+ ->default_value(std::numeric_limits<Filtration_value>::infinity()),
+ "Maximal alpha square value for the Alpha complex construction.")(
"field-charac,p", po::value<int>(&coeff_field_characteristic)->default_value(11),
"Characteristic p of the coefficient field Z/pZ for computing homology.")(
"min-persistence,m", po::value<Filtration_value>(&min_persistence),
@@ -254,17 +299,18 @@ void program_options(int argc, char *argv[], std::string &off_file_points, std::
po::store(po::command_line_parser(argc, argv).options(all).positional(pos).run(), vm);
po::notify(vm);
- if (vm.count("help") || !vm.count("input-file")) {
+ if (vm.count("help") || !vm.count("input-file") || !vm.count("weight-file")) {
std::cout << std::endl;
std::cout << "Compute the persistent homology with coefficient field Z/pZ \n";
- std::cout << "of a 3D Alpha complex defined on a set of input points.\n \n";
+ std::cout << "of a 3D Alpha complex defined on a set of input points.\n";
+ std::cout << "3D Alpha complex can be safe (by default) exact or fast, weighted and/or periodic\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 << "p is the characteristic of the field Z/pZ used for homology coefficients.\n\n";
- std::cout << "Usage: " << argv[0] << " [options] input-file" << std::endl << std::endl;
+ std::cout << "Usage: " << argv[0] << " [options] input-file weight-file\n\n";
std::cout << visible << std::endl;
exit(-1);
}
diff --git a/src/Alpha_complex/utilities/alphacomplex.md b/src/Alpha_complex/utilities/alphacomplex.md
index b1a33e4b..50a39d32 100644
--- a/src/Alpha_complex/utilities/alphacomplex.md
+++ b/src/Alpha_complex/utilities/alphacomplex.md
@@ -12,15 +12,18 @@ Leave the lines above as it is required by the web site generator 'Jekyll'
## alpha_complex_persistence ##
-This program computes the persistent homology with coefficient field Z/pZ of the dD alpha complex built from a dD point cloud.
+This program computes the persistent homology with coefficient field Z/pZ of
+the dD alpha complex built from a dD point cloud.
The output diagram contains one bar per line, written with the convention:
```
p dim birth death
```
-where `dim` is the dimension of the homological feature, `birth` and `death` are respectively the birth and death of the feature,
-and `p` is the characteristic of the field *Z/pZ* used for homology coefficients (`p` must be a prime number).
+where `dim` is the dimension of the homological feature, `birth` and `death`
+are respectively the birth and death of the feature, and `p` is the
+characteristic of the field *Z/pZ* used for homology coefficients (`p` must be
+a prime number).
**Usage**
@@ -29,15 +32,20 @@ and `p` is the characteristic of the field *Z/pZ* used for homology coefficients
```
where
-`<input OFF file>` is the path to the input point cloud in [nOFF ASCII format](http://www.geomview.org/docs/html/OFF.html).
+`<input OFF file>` is the path to the input point cloud in
+[nOFF ASCII format](http://www.geomview.org/docs/html/OFF.html).
**Allowed options**
* `-h [ --help ]` Produce help message
-* `-o [ --output-file ]` Name of file in which the persistence diagram is written. Default print in standard output.
-* `-r [ --max-alpha-square-value ]` (default = inf) Maximal alpha square value for the Alpha complex construction.
-* `-p [ --field-charac ]` (default = 11) Characteristic p of the coefficient field Z/pZ for computing homology.
-* `-m [ --min-persistence ]` (default = 0) Minimal lifetime of homology feature to be recorded. Enter a negative value to see zero length intervals.
+* `-o [ --output-file ]` Name of file in which the persistence diagram is
+written. Default print in standard output.
+* `-r [ --max-alpha-square-value ]` (default = inf) Maximal alpha square value
+for the Alpha complex construction.
+* `-p [ --field-charac ]` (default = 11) Characteristic p of the
+coefficient field Z/pZ for computing homology.
+* `-m [ --min-persistence ]` (default = 0) Minimal lifetime of homology feature
+to be recorded. Enter a negative value to see zero length intervals.
**Example**
@@ -51,13 +59,26 @@ N.B.:
## alpha_complex_3d_persistence ##
-This program computes the persistent homology with coefficient field Z/pZ of the 3D alpha complex built from a 3D point cloud. The output diagram contains one bar per line, written with the convention:
+This program computes the persistent homology with coefficient field Z/pZ of
+the 3D alpha complex built from a 3D point cloud.
+One can use exact computation. It is slower, but it is necessary when points
+are on a grid for instance.
+Alpha complex 3d can be weighted and/or periodic (refer to the
+[CGAL's 3D Periodic Triangulations User Manual](
+https://doc.cgal.org/latest/Periodic_3_triangulation_3/index.html)
+for more details).
+
+The output diagram contains
+one bar per line, written with the convention:
```
p dim birth death
```
-where `dim` is the dimension of the homological feature, `birth` and `death` are respectively the birth and death of the feature, and `p` is the characteristic of the field *Z/pZ* used for homology coefficients (`p` must be a prime number).
+where `dim` is the dimension of the homological feature, `birth` and `death`
+are respectively the birth and death of the feature, and `p` is the
+characteristic of the field *Z/pZ* used for homology coefficients (`p` must be
+a prime number).
**Usage**
@@ -65,14 +86,28 @@ where `dim` is the dimension of the homological feature, `birth` and `death` are
alpha_complex_3d_persistence [options] <input OFF file>
```
-where `<input OFF file>` is the path to the input point cloud in [nOFF ASCII format](http://www.geomview.org/docs/html/OFF.html).
+where `<input OFF file>` is the path to the input point cloud in
+[nOFF ASCII format](http://www.geomview.org/docs/html/OFF.html).
**Allowed options**
* `-h [ --help ]` Produce help message
-* `-o [ --output-file ]` Name of file in which the persistence diagram is written. Default print in standard output.
-* `-p [ --field-charac ]` (default=11) Characteristic p of the coefficient field Z/pZ for computing homology.
-* `-m [ --min-persistence ]` (default = 0) Minimal lifetime of homology feature to be recorded. Enter a negative value to see zero length intervals.
+* `-o [ --output-file ]` Name of file in which the persistence diagram is
+written. Default print in standard output.
+* `-r [ --max-alpha-square-value ]` (default = inf) Maximal alpha square value
+for the Alpha complex construction.
+* `-p [ --field-charac ]` (default=11) Characteristic p of the coefficient
+field Z/pZ for computing homology.
+* `-m [ --min-persistence ]` (default = 0) Minimal lifetime of homology feature
+to be recorded. Enter a negative value to see zero length intervals.
+* `-c [ --cuboid-file ]` is the path to the file describing the periodic domain.
+It must be in the format described
+[here]({{ site.officialurl }}/doc/latest/fileformats.html#FileFormatsIsoCuboid).
+* `-w [ --weight-file ]` is the path to the file containing the weights of the
+points (one value per line).
+* `-e [ --exact ]` for the exact computation version (not compatible with
+weight and periodic version).
+* `-f [ --fast ]` for the fast computation version.
**Example**
@@ -84,82 +119,7 @@ N.B.:
* `alpha_complex_3d_persistence` only accepts OFF files in dimension 3.
* Filtration values are alpha square values.
-
-
-## exact_alpha_complex_3d_persistence ##
-
-Same as `alpha_complex_3d_persistence`, but using exact computation.
-It is slower, but it is necessary when points are on a grid for instance.
-
-
-
-## weighted_alpha_complex_3d_persistence ##
-
-Same as `alpha_complex_3d_persistence`, but using weighted points.
-
-**Usage**
-
-```
- weighted_alpha_complex_3d_persistence [options] <input OFF file> <weights input file>
-```
-
-where
-
-* `<input OFF file>` is the path to the input point cloud in [nOFF ASCII format](http://www.geomview.org/docs/html/OFF.html).
-* `<input weights file>` is the path to the file containing the weights of the points (one value per line).
-
-**Allowed options**
-
-* `-h [ --help ]` Produce help message
-* `-o [ --output-file ]` Name of file in which the persistence diagram is written. Default print in standard output.
-* `-p [ --field-charac ]` (default=11) Characteristic p of the coefficient field Z/pZ for computing homology.
-* `-m [ --min-persistence ]` (default = 0) Minimal lifetime of homology feature to be recorded. Enter a negative value to see zero length intervals.
-
-**Example**
-
-```
- weighted_alpha_complex_3d_persistence ../../data/points/tore3D_300.off ../../data/points/tore3D_300.weights -p 2 -m 0.45
-```
-
-
-N.B.:
-
-* Weights values are explained on CGAL [Alpha shape](https://doc.cgal.org/latest/Alpha_shapes_3/index.html#title0)
-and [Regular triangulation](https://doc.cgal.org/latest/Triangulation_3/index.html#Triangulation3secclassRegulartriangulation) documentation.
-* Filtration values are alpha square values.
-
-
-## periodic_alpha_complex_3d_persistence ##
-Same as `alpha_complex_3d_persistence`, but using periodic alpha shape 3d.
-Refer to the [CGAL's 3D Periodic Triangulations User Manual](https://doc.cgal.org/latest/Periodic_3_triangulation_3/index.html) for more details.
-
-**Usage**
-
-```
- periodic_alpha_complex_3d_persistence [options] <input OFF file> <cuboid file>
-```
-
-where
-
-* `<input OFF file>` is the path to the input point cloud in [nOFF ASCII format](http://www.geomview.org/docs/html/OFF.html).
-* `<cuboid file>` is the path to the file describing the periodic domain. It must be in the format described
-[here]({{ site.officialurl }}/doc/latest/fileformats.html#FileFormatsIsoCuboid).
-
-**Allowed options**
-
-* `-h [ --help ]` Produce help message
-* `-o [ --output-file ]` Name of file in which the persistence diagram is written. Default print in standard output.
-* `-p [ --field-charac ]` (default=11) Characteristic p of the coefficient field Z/pZ for computing homology.
-* `-m [ --min-persistence ]` (default = 0) Minimal lifetime of homology feature to be recorded. Enter a negative value to see zero length intervals
-
-
-**Example**
-
-```
-periodic_alpha_complex_3d_persistence ../../data/points/grid_10_10_10_in_0_1.off ../../data/points/iso_cuboid_3_in_0_1.txt -p 3 -m 1.0
-```
-
-N.B.:
-
-* Cuboid file must be in the format described [here]({{ site.officialurl }}/doc/latest/fileformats.html#FileFormatsIsoCuboid).
-* Filtration values are alpha square values.
+* Weights values are explained on CGAL
+[Alpha shape](https://doc.cgal.org/latest/Alpha_shapes_3/index.html#title0)
+and
+[Regular triangulation](https://doc.cgal.org/latest/Triangulation_3/index.html#Triangulation3secclassRegulartriangulation) documentation.
diff --git a/src/Alpha_complex/utilities/exact_alpha_complex_3d_persistence.cpp b/src/Alpha_complex/utilities/exact_alpha_complex_3d_persistence.cpp
deleted file mode 100644
index 61f49bb1..00000000
--- a/src/Alpha_complex/utilities/exact_alpha_complex_3d_persistence.cpp
+++ /dev/null
@@ -1,265 +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
- *
- * 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 <boost/program_options.hpp>
-#include <boost/variant.hpp>
-
-#include <gudhi/Simplex_tree.h>
-#include <gudhi/Persistent_cohomology.h>
-#include <gudhi/Points_3D_off_io.h>
-
-#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
-#include <CGAL/Delaunay_triangulation_3.h>
-#include <CGAL/Alpha_shape_3.h>
-#include <CGAL/Alpha_shape_cell_base_3.h>
-#include <CGAL/Alpha_shape_vertex_base_3.h>
-#include <CGAL/iterator.h>
-
-#include <fstream>
-#include <cmath>
-#include <string>
-#include <tuple>
-#include <map>
-#include <utility>
-#include <vector>
-#include <cstdlib>
-
-#include "alpha_complex_3d_helper.h"
-
-// Alpha_shape_3 templates type definitions
-using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
-using Exact_tag = CGAL::Tag_true;
-using Vb = CGAL::Alpha_shape_vertex_base_3<Kernel, CGAL::Default, Exact_tag>;
-using Fb = CGAL::Alpha_shape_cell_base_3<Kernel, CGAL::Default, Exact_tag>;
-using Tds = CGAL::Triangulation_data_structure_3<Vb, Fb>;
-using Triangulation_3 = CGAL::Delaunay_triangulation_3<Kernel, Tds>;
-using Alpha_shape_3 = CGAL::Alpha_shape_3<Triangulation_3, Exact_tag>;
-
-// From file type definition
-using Point_3 = Kernel::Point_3;
-
-// filtration with alpha values needed type definition
-using Alpha_value_type = Alpha_shape_3::FT;
-using Object = CGAL::Object;
-using Dispatch =
- 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> > > >;
-using Cell_handle = Alpha_shape_3::Cell_handle;
-using Facet = Alpha_shape_3::Facet;
-using Edge_3 = Alpha_shape_3::Edge;
-using Vertex_handle = Alpha_shape_3::Vertex_handle;
-using Vertex_list = std::vector<Vertex_handle>;
-
-// gudhi type definition
-using ST = Gudhi::Simplex_tree<Gudhi::Simplex_tree_options_fast_persistence>;
-using Filtration_value = ST::Filtration_value;
-using Simplex_tree_vertex = ST::Vertex_handle;
-using Alpha_shape_simplex_tree_map = std::map<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex>;
-using Simplex_tree_vector_vertex = std::vector<Simplex_tree_vertex>;
-using Persistent_cohomology =
- Gudhi::persistent_cohomology::Persistent_cohomology<ST, Gudhi::persistent_cohomology::Field_Zp>;
-
-void program_options(int argc, char *argv[], std::string &off_file_points, std::string &output_file_diag,
- int &coeff_field_characteristic, Filtration_value &min_persistence);
-
-int main(int argc, char **argv) {
- std::string off_file_points;
- std::string output_file_diag;
- int coeff_field_characteristic;
- Filtration_value min_persistence;
-
- program_options(argc, argv, off_file_points, output_file_diag, coeff_field_characteristic, min_persistence);
-
- // Read the OFF file (input file name given as parameter) and triangulate points
- Gudhi::Points_3D_off_reader<Point_3> off_reader(off_file_points);
- // Check the read operation was correct
- if (!off_reader.is_valid()) {
- std::cerr << "Unable to read file " << off_file_points << std::endl;
- exit(-1);
- }
-
- // Retrieve the points
- std::vector<Point_3> lp = off_reader.get_point_cloud();
-
- // 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
-
- // 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));
-
- 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
-
- 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;
- ST 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<Vertex_list, Cell_handle>(*cell);
- count_cells++;
- } else if (const Facet *facet = CGAL::object_cast<Facet>(&object_iterator)) {
- vertex_list = from_facet<Vertex_list, Facet>(*facet);
- count_facets++;
- } else if (const Edge_3 *edge = CGAL::object_cast<Edge_3>(&object_iterator)) {
- vertex_list = from_edge<Vertex_list, Edge_3>(*edge);
- count_edges++;
- } else if (const Vertex_handle *vertex = CGAL::object_cast<Vertex_handle>(&object_iterator)) {
- count_vertices++;
- vertex_list = from_vertex<Vertex_list, Vertex_handle>(*vertex);
- }
- // Construction of the vector of simplex_tree vertex from list of alpha_shapes vertex
- Simplex_tree_vector_vertex the_simplex;
- 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 " << vertex << std::endl;
-#endif // DEBUG_TRACES
- the_simplex.push_back(vertex);
- map_cgal_simplex_tree.emplace(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.push_back(vertex);
- }
- }
- // Construction of the simplex_tree
- // you can also use the_alpha_value_iterator->exact()
- Filtration_value filtr = /*std::sqrt*/ CGAL::to_double(the_alpha_value_iterator->exact());
-#ifdef DEBUG_TRACES
- std::cout << "filtration = " << filtr << std::endl;
-#endif // DEBUG_TRACES
- simplex_tree.insert_simplex(the_simplex, filtr);
- if (the_alpha_value_iterator != the_alpha_values.end())
- ++the_alpha_value_iterator;
- else
- std::cout << "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 << "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;
- std::cout << " Dimension = " << simplex_tree.dimension() << " ";
-#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
-
- // 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 pcoh(simplex_tree, true);
- // initializes the coefficient field for homology
- pcoh.init_coefficients(coeff_field_characteristic);
-
- pcoh.compute_persistent_cohomology(min_persistence);
-
- // Output the diagram in filediag
- if (output_file_diag.empty()) {
- pcoh.output_diagram();
- } else {
- std::cout << "Result in file: " << output_file_diag << std::endl;
- std::ofstream out(output_file_diag);
- pcoh.output_diagram(out);
- out.close();
- }
-
- return 0;
-}
-
-void program_options(int argc, char *argv[], std::string &off_file_points, std::string &output_file_diag,
- int &coeff_field_characteristic, Filtration_value &min_persistence) {
- namespace po = boost::program_options;
- po::options_description hidden("Hidden options");
- hidden.add_options()("input-file", po::value<std::string>(&off_file_points),
- "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>(&output_file_diag)->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>(&coeff_field_characteristic)->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::variables_map vm;
- po::store(po::command_line_parser(argc, argv).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 3D Alpha 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;
- exit(-1);
- }
-}
diff --git a/src/Alpha_complex/utilities/periodic_alpha_complex_3d_persistence.cpp b/src/Alpha_complex/utilities/periodic_alpha_complex_3d_persistence.cpp
deleted file mode 100644
index a261c5a3..00000000
--- a/src/Alpha_complex/utilities/periodic_alpha_complex_3d_persistence.cpp
+++ /dev/null
@@ -1,302 +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
- * Pawel Dlotko - 2017 - Swansea University, UK
- *
- * Copyright (C) 2014 Inria
- *
- * 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 <boost/program_options.hpp>
-#include <boost/variant.hpp>
-
-#include <gudhi/Simplex_tree.h>
-#include <gudhi/Persistent_cohomology.h>
-#include <gudhi/Points_3D_off_io.h>
-
-#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
-#include <CGAL/Periodic_3_Delaunay_triangulation_traits_3.h>
-#include <CGAL/Periodic_3_Delaunay_triangulation_3.h>
-#include <CGAL/Alpha_shape_3.h>
-#include <CGAL/Alpha_shape_cell_base_3.h>
-#include <CGAL/Alpha_shape_vertex_base_3.h>
-#include <CGAL/iterator.h>
-
-#include <fstream>
-#include <cmath>
-#include <string>
-#include <tuple>
-#include <map>
-#include <utility>
-#include <vector>
-#include <cstdlib>
-
-#include "alpha_complex_3d_helper.h"
-
-// Traits
-using K = CGAL::Exact_predicates_inexact_constructions_kernel;
-using PK = CGAL::Periodic_3_Delaunay_triangulation_traits_3<K>;
-// Vertex type
-using DsVb = CGAL::Periodic_3_triangulation_ds_vertex_base_3<>;
-using Vb = CGAL::Triangulation_vertex_base_3<PK, DsVb>;
-using AsVb = CGAL::Alpha_shape_vertex_base_3<PK, Vb>;
-// Cell type
-using DsCb = CGAL::Periodic_3_triangulation_ds_cell_base_3<>;
-using Cb = CGAL::Triangulation_cell_base_3<PK, DsCb>;
-using AsCb = CGAL::Alpha_shape_cell_base_3<PK, Cb>;
-using Tds = CGAL::Triangulation_data_structure_3<AsVb, AsCb>;
-using P3DT3 = CGAL::Periodic_3_Delaunay_triangulation_3<PK, Tds>;
-using Alpha_shape_3 = CGAL::Alpha_shape_3<P3DT3>;
-using Point_3 = PK::Point_3;
-
-// filtration with alpha values needed type definition
-using Alpha_value_type = Alpha_shape_3::FT;
-using Object = CGAL::Object;
-using Dispatch =
- 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> > > >;
-using Cell_handle = Alpha_shape_3::Cell_handle;
-using Facet = Alpha_shape_3::Facet;
-using Edge_3 = Alpha_shape_3::Edge;
-using Vertex_handle = Alpha_shape_3::Vertex_handle;
-using Vertex_list = std::vector<Alpha_shape_3::Vertex_handle>;
-
-// gudhi type definition
-using ST = Gudhi::Simplex_tree<Gudhi::Simplex_tree_options_fast_persistence>;
-using Filtration_value = ST::Filtration_value;
-using Simplex_tree_vertex = ST::Vertex_handle;
-using Alpha_shape_simplex_tree_map = std::map<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex>;
-using Simplex_tree_vector_vertex = std::vector<Simplex_tree_vertex>;
-using Persistent_cohomology =
- Gudhi::persistent_cohomology::Persistent_cohomology<ST, Gudhi::persistent_cohomology::Field_Zp>;
-
-void program_options(int argc, char *argv[], std::string &off_file_points, std::string &cuboid_file,
- std::string &output_file_diag, int &coeff_field_characteristic, Filtration_value &min_persistence);
-
-int main(int argc, char **argv) {
- std::string off_file_points;
- std::string cuboid_file;
- std::string output_file_diag;
- int coeff_field_characteristic;
- Filtration_value min_persistence;
-
- program_options(argc, argv, off_file_points, cuboid_file, output_file_diag, coeff_field_characteristic,
- min_persistence);
-
- // Read the OFF file (input file name given as parameter) and triangulate points
- Gudhi::Points_3D_off_reader<Point_3> off_reader(off_file_points);
- // Check the read operation was correct
- if (!off_reader.is_valid()) {
- std::cerr << "Unable to read OFF file " << off_file_points << std::endl;
- exit(-1);
- }
-
- // Read iso_cuboid_3 information from file
- std::ifstream iso_cuboid_str(cuboid_file);
- double x_min, y_min, z_min, x_max, y_max, z_max;
- if (iso_cuboid_str.good()) {
- iso_cuboid_str >> x_min >> y_min >> z_min >> x_max >> y_max >> z_max;
- } else {
- std::cerr << "Unable to read file " << cuboid_file << std::endl;
- exit(-1);
- }
- // Checking if the cuboid is the same in x,y and z direction. If not, CGAL will not process it.
- if ((x_max - x_min != y_max - y_min) || (x_max - x_min != z_max - z_min) || (z_max - z_min != y_max - y_min)) {
- std::cerr << "The size of the cuboid in every directions is not the same." << std::endl;
- exit(-1);
- }
-
- // Retrieve the points
- std::vector<Point_3> lp = off_reader.get_point_cloud();
-
- // Define the periodic cube
- P3DT3 pdt(PK::Iso_cuboid_3(x_min, y_min, z_min, x_max, y_max, z_max));
- // Heuristic for inserting large point sets (if pts is reasonably large)
- pdt.insert(lp.begin(), lp.end(), true);
- // As pdt won't be modified anymore switch to 1-sheeted cover if possible
- if (pdt.is_triangulation_in_1_sheet()) {
- pdt.convert_to_1_sheeted_covering();
- } else {
- std::cerr << "ERROR: we were not able to construct a triangulation within a single periodic domain." << std::endl;
- exit(-1);
- }
- std::cout << "Periodic Delaunay computed." << std::endl;
-
- // alpha shape construction from points. CGAL has a strange behavior in REGULARIZED mode. This is the default mode
- // Maybe need to set it to GENERAL mode
- Alpha_shape_3 as(pdt, 0, Alpha_shape_3::GENERAL);
-
- // 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));
-
- 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
-
- 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;
- ST 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<Vertex_list, Cell_handle>(*cell);
- count_cells++;
- } else if (const Facet *facet = CGAL::object_cast<Facet>(&object_iterator)) {
- vertex_list = from_facet<Vertex_list, Facet>(*facet);
- count_facets++;
- } else if (const Edge_3 *edge = CGAL::object_cast<Edge_3>(&object_iterator)) {
- vertex_list = from_edge<Vertex_list, Edge_3>(*edge);
- count_edges++;
- } else if (const Vertex_handle *vertex = CGAL::object_cast<Vertex_handle>(&object_iterator)) {
- count_vertices++;
- vertex_list = from_vertex<Vertex_list, Vertex_handle>(*vertex);
- }
- // Construction of the vector of simplex_tree vertex from list of alpha_shapes vertex
- Simplex_tree_vector_vertex the_simplex;
- 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 " << vertex << std::endl;
-#endif // DEBUG_TRACES
- the_simplex.push_back(vertex);
- map_cgal_simplex_tree.emplace(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.push_back(vertex);
- }
- }
- // Construction of the simplex_tree
- Filtration_value filtr = /*std::sqrt*/ (*the_alpha_value_iterator);
-#ifdef DEBUG_TRACES
- std::cout << "filtration = " << filtr << std::endl;
-#endif // DEBUG_TRACES
- simplex_tree.insert_simplex(the_simplex, filtr);
- if (the_alpha_value_iterator != the_alpha_values.end())
- ++the_alpha_value_iterator;
- else
- std::cout << "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 << "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;
- std::cout << " Dimension = " << simplex_tree.dimension() << " ";
-#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
-
- // 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 pcoh(simplex_tree, true);
- // initializes the coefficient field for homology
- pcoh.init_coefficients(coeff_field_characteristic);
-
- pcoh.compute_persistent_cohomology(min_persistence);
-
- // Output the diagram in filediag
- if (output_file_diag.empty()) {
- pcoh.output_diagram();
- } else {
- std::cout << "Result in file: " << output_file_diag << std::endl;
- std::ofstream out(output_file_diag);
- pcoh.output_diagram(out);
- out.close();
- }
-
- return 0;
-}
-
-void program_options(int argc, char *argv[], std::string &off_file_points, std::string &cuboid_file,
- std::string &output_file_diag, int &coeff_field_characteristic,
- Filtration_value &min_persistence) {
- namespace po = boost::program_options;
- po::options_description hidden("Hidden options");
- hidden.add_options()("input-file", po::value<std::string>(&off_file_points),
- "Name of file containing a point set. Format is one point per line: X1 ... Xd ")(
- "cuboid-file", po::value<std::string>(&cuboid_file),
- "Name of file describing the periodic domain. Format is: min_hx min_hy min_hz\nmax_hx max_hy max_hz");
-
- po::options_description visible("Allowed options", 100);
- visible.add_options()("help,h", "produce help message")(
- "output-file,o", po::value<std::string>(&output_file_diag)->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>(&coeff_field_characteristic)->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);
- pos.add("cuboid-file", 2);
-
- 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);
- po::notify(vm);
-
- if (vm.count("help") || !vm.count("input-file") || !vm.count("cuboid-file")) {
- std::cout << std::endl;
- std::cout << "Compute the persistent homology with coefficient field Z/pZ \n";
- std::cout << "of a periodic 3D Alpha 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 cuboid-file" << std::endl << std::endl;
- std::cout << visible << std::endl;
- exit(-1);
- }
-}
diff --git a/src/Alpha_complex/utilities/weighted_alpha_complex_3d_persistence.cpp b/src/Alpha_complex/utilities/weighted_alpha_complex_3d_persistence.cpp
deleted file mode 100644
index aa7ddee2..00000000
--- a/src/Alpha_complex/utilities/weighted_alpha_complex_3d_persistence.cpp
+++ /dev/null
@@ -1,316 +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
- *
- * 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 <boost/program_options.hpp>
-#include <boost/variant.hpp>
-
-#include <gudhi/Simplex_tree.h>
-#include <gudhi/Persistent_cohomology.h>
-#include <gudhi/Points_3D_off_io.h>
-
-#include <CGAL/config.h>
-#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
-#include <CGAL/Regular_triangulation_3.h>
-#include <CGAL/Alpha_shape_3.h>
-#include <CGAL/Alpha_shape_cell_base_3.h>
-#include <CGAL/Alpha_shape_vertex_base_3.h>
-#include <CGAL/iterator.h>
-
-// For CGAL < 4.11
-#if CGAL_VERSION_NR < 1041100000
-#include <CGAL/Regular_triangulation_euclidean_traits_3.h>
-#endif // CGAL_VERSION_NR < 1041100000
-
-#include <fstream>
-#include <cmath>
-#include <string>
-#include <tuple>
-#include <map>
-#include <utility>
-#include <vector>
-#include <cstdlib>
-
-#include "alpha_complex_3d_helper.h"
-
-// Alpha_shape_3 templates type definitions
-using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
-
-// For CGAL < 4.11
-#if CGAL_VERSION_NR < 1041100000
-using Gt = CGAL::Regular_triangulation_euclidean_traits_3<Kernel>;
-using Vb = CGAL::Alpha_shape_vertex_base_3<Gt>;
-using Fb = CGAL::Alpha_shape_cell_base_3<Gt>;
-using Tds = CGAL::Triangulation_data_structure_3<Vb, Fb>;
-using Triangulation_3 = CGAL::Regular_triangulation_3<Gt, Tds>;
-
-// From file type definition
-using Point_3 = Gt::Bare_point;
-using Weighted_point_3 = Gt::Weighted_point;
-
-// For CGAL >= 4.11
-#else // CGAL_VERSION_NR < 1041100000
-using Rvb = CGAL::Regular_triangulation_vertex_base_3<Kernel>;
-using Vb = CGAL::Alpha_shape_vertex_base_3<Kernel, Rvb>;
-using Rcb = CGAL::Regular_triangulation_cell_base_3<Kernel>;
-using Cb = CGAL::Alpha_shape_cell_base_3<Kernel, Rcb>;
-using Tds = CGAL::Triangulation_data_structure_3<Vb, Cb>;
-using Triangulation_3 = CGAL::Regular_triangulation_3<Kernel, Tds>;
-
-// From file type definition
-using Point_3 = Triangulation_3::Bare_point;
-using Weighted_point_3 = Triangulation_3::Weighted_point;
-#endif // CGAL_VERSION_NR < 1041100000
-
-using Alpha_shape_3 = CGAL::Alpha_shape_3<Triangulation_3>;
-
-// filtration with alpha values needed type definition
-using Alpha_value_type = Alpha_shape_3::FT;
-using Object = CGAL::Object;
-using Dispatch =
- 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> > > >;
-using Cell_handle = Alpha_shape_3::Cell_handle;
-using Facet = Alpha_shape_3::Facet;
-using Edge_3 = Alpha_shape_3::Edge;
-using Vertex_handle = Alpha_shape_3::Vertex_handle;
-using Vertex_list = std::vector<Alpha_shape_3::Vertex_handle>;
-
-// gudhi type definition
-using ST = Gudhi::Simplex_tree<Gudhi::Simplex_tree_options_fast_persistence>;
-using Filtration_value = ST::Filtration_value;
-using Simplex_tree_vertex = ST::Vertex_handle;
-using Alpha_shape_simplex_tree_map = std::map<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex>;
-using Simplex_tree_vector_vertex = std::vector<Simplex_tree_vertex>;
-using Persistent_cohomology =
- Gudhi::persistent_cohomology::Persistent_cohomology<ST, Gudhi::persistent_cohomology::Field_Zp>;
-
-void program_options(int argc, char *argv[], std::string &off_file_points, std::string &weight_file,
- std::string &output_file_diag, int &coeff_field_characteristic, Filtration_value &min_persistence);
-
-int main(int argc, char **argv) {
- std::string off_file_points;
- std::string weight_file;
- std::string output_file_diag;
- int coeff_field_characteristic;
- Filtration_value min_persistence;
-
- program_options(argc, argv, off_file_points, weight_file, output_file_diag, coeff_field_characteristic,
- min_persistence);
-
- // Read the OFF file (input file name given as parameter) and triangulate points
- Gudhi::Points_3D_off_reader<Point_3> off_reader(off_file_points);
- // Check the read operation was correct
- if (!off_reader.is_valid()) {
- std::cerr << "Unable to read OFF file " << off_file_points << std::endl;
- exit(-1);
- }
-
- // Retrieve the points
- std::vector<Point_3> lp = off_reader.get_point_cloud();
-
- // Read weights information from file
- std::ifstream weights_ifstr(weight_file);
- std::vector<Weighted_point_3> wp;
- if (weights_ifstr.good()) {
- double weight = 0.0;
- std::size_t index = 0;
- wp.reserve(lp.size());
- // Attempt read the weight in a double format, return false if it fails
- while ((weights_ifstr >> weight) && (index < lp.size())) {
- wp.push_back(Weighted_point_3(lp[index], weight));
- index++;
- }
- if (index != lp.size()) {
- std::cerr << "Bad number of weights in file " << weight_file << std::endl;
- exit(-1);
- }
- } else {
- std::cerr << "Unable to read weights file " << weight_file << std::endl;
- exit(-1);
- }
-
- // alpha shape construction from points. CGAL has a strange behavior in REGULARIZED mode.
- Alpha_shape_3 as(wp.begin(), wp.end(), 0, Alpha_shape_3::GENERAL);
-#ifdef 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;
-
- 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
-
- 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;
- ST 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<Vertex_list, Cell_handle>(*cell);
- count_cells++;
- } else if (const Facet *facet = CGAL::object_cast<Facet>(&object_iterator)) {
- vertex_list = from_facet<Vertex_list, Facet>(*facet);
- count_facets++;
- } else if (const Edge_3 *edge = CGAL::object_cast<Edge_3>(&object_iterator)) {
- vertex_list = from_edge<Vertex_list, Edge_3>(*edge);
- count_edges++;
- } else if (const Vertex_handle *vertex = CGAL::object_cast<Vertex_handle>(&object_iterator)) {
- count_vertices++;
- vertex_list = from_vertex<Vertex_list, Vertex_handle>(*vertex);
- }
- // Construction of the vector of simplex_tree vertex from list of alpha_shapes vertex
- Simplex_tree_vector_vertex the_simplex;
- 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 " << vertex << std::endl;
-#endif // DEBUG_TRACES
- the_simplex.push_back(vertex);
- map_cgal_simplex_tree.emplace(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.push_back(vertex);
- }
- }
- // Construction of the simplex_tree
- Filtration_value filtr = /*std::sqrt*/ (*the_alpha_value_iterator);
-#ifdef DEBUG_TRACES
- std::cout << "filtration = " << filtr << std::endl;
-#endif // DEBUG_TRACES
- simplex_tree.insert_simplex(the_simplex, filtr);
- if (the_alpha_value_iterator != the_alpha_values.end())
- ++the_alpha_value_iterator;
- else
- std::cout << "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 << "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;
- std::cout << " Dimension = " << simplex_tree.dimension() << " ";
-#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
-
- // 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 pcoh(simplex_tree, true);
- // initializes the coefficient field for homology
- pcoh.init_coefficients(coeff_field_characteristic);
-
- pcoh.compute_persistent_cohomology(min_persistence);
-
- // Output the diagram in filediag
- if (output_file_diag.empty()) {
- pcoh.output_diagram();
- } else {
- std::cout << "Result in file: " << output_file_diag << std::endl;
- std::ofstream out(output_file_diag);
- pcoh.output_diagram(out);
- out.close();
- }
-
- return 0;
-}
-
-void program_options(int argc, char *argv[], std::string &off_file_points, std::string &weight_file,
- std::string &output_file_diag, int &coeff_field_characteristic,
- Filtration_value &min_persistence) {
- namespace po = boost::program_options;
- po::options_description hidden("Hidden options");
- hidden.add_options()("input-file", po::value<std::string>(&off_file_points),
- "Name of file containing a point set. Format is one point per line: X1 ... Xd ")(
- "weight-file", po::value<std::string>(&weight_file),
- "Name of file containing a point weights. Format is one weigt per line: W1\n...\nWn ");
-
- po::options_description visible("Allowed options", 100);
- visible.add_options()("help,h", "produce help message")(
- "output-file,o", po::value<std::string>(&output_file_diag)->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>(&coeff_field_characteristic)->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);
- pos.add("weight-file", 2);
-
- 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);
- po::notify(vm);
-
- if (vm.count("help") || !vm.count("input-file") || !vm.count("weight-file")) {
- std::cout << std::endl;
- std::cout << "Compute the persistent homology with coefficient field Z/pZ \n";
- std::cout << "of a weighted 3D Alpha 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 weight-file" << std::endl << std::endl;
- std::cout << visible << std::endl;
- exit(-1);
- }
-}
diff --git a/src/Alpha_complex/utilities/weighted_periodic_alpha_complex_3d_persistence.cpp b/src/Alpha_complex/utilities/weighted_periodic_alpha_complex_3d_persistence.cpp
deleted file mode 100644
index d030c88c..00000000
--- a/src/Alpha_complex/utilities/weighted_periodic_alpha_complex_3d_persistence.cpp
+++ /dev/null
@@ -1,288 +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
- * Pawel Dlotko - 2017 - Swansea University, UK
- *
- * Copyright (C) 2014 Inria
- *
- * 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 <boost/variant.hpp>
-
-#include <gudhi/Simplex_tree.h>
-#include <gudhi/Persistent_cohomology.h>
-#include <gudhi/Points_3D_off_io.h>
-
-#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
-#include <CGAL/Periodic_3_regular_triangulation_traits_3.h>
-#include <CGAL/Periodic_3_regular_triangulation_3.h>
-#include <CGAL/Alpha_shape_3.h>
-#include <CGAL/Alpha_shape_cell_base_3.h>
-#include <CGAL/Alpha_shape_vertex_base_3.h>
-#include <CGAL/iterator.h>
-
-#include <fstream>
-#include <cmath>
-#include <string>
-#include <tuple>
-#include <map>
-#include <utility>
-#include <vector>
-#include <cstdlib>
-
-#include "alpha_complex_3d_helper.h"
-
-// Traits
-using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
-using PK = CGAL::Periodic_3_regular_triangulation_traits_3<Kernel>;
-
-// Vertex type
-using DsVb = CGAL::Periodic_3_triangulation_ds_vertex_base_3<>;
-using Vb = CGAL::Regular_triangulation_vertex_base_3<PK, DsVb>;
-using AsVb = CGAL::Alpha_shape_vertex_base_3<PK, Vb>;
-// Cell type
-using DsCb = CGAL::Periodic_3_triangulation_ds_cell_base_3<>;
-using Cb = CGAL::Regular_triangulation_cell_base_3<PK, DsCb>;
-using AsCb = CGAL::Alpha_shape_cell_base_3<PK, Cb>;
-using Tds = CGAL::Triangulation_data_structure_3<AsVb, AsCb>;
-using P3RT3 = CGAL::Periodic_3_regular_triangulation_3<PK, Tds>;
-using Alpha_shape_3 = CGAL::Alpha_shape_3<P3RT3>;
-
-using Point_3 = P3RT3::Bare_point;
-using Weighted_point_3 = P3RT3::Weighted_point;
-
-// filtration with alpha values needed type definition
-using Alpha_value_type = Alpha_shape_3::FT;
-using Object = CGAL::Object;
-using Dispatch =
- 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> > > >;
-using Cell_handle = Alpha_shape_3::Cell_handle;
-using Facet = Alpha_shape_3::Facet;
-using Edge_3 = Alpha_shape_3::Edge;
-using Vertex_handle = Alpha_shape_3::Vertex_handle;
-using Vertex_list = std::vector<Alpha_shape_3::Vertex_handle>;
-
-// gudhi type definition
-using ST = Gudhi::Simplex_tree<Gudhi::Simplex_tree_options_fast_persistence>;
-using Filtration_value = ST::Filtration_value;
-using Simplex_tree_vertex = ST::Vertex_handle;
-using Alpha_shape_simplex_tree_map = std::map<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex>;
-using Simplex_tree_vector_vertex = std::vector<Simplex_tree_vertex>;
-using Persistent_cohomology =
- Gudhi::persistent_cohomology::Persistent_cohomology<ST, Gudhi::persistent_cohomology::Field_Zp>;
-
-void usage(const std::string& progName) {
- std::cerr << "Usage: " << progName << " path_to_the_OFF_file path_to_weight_file path_to_the_cuboid_file "
- "coeff_field_characteristic[integer > 0] min_persistence[float >= -1.0]\n";
- exit(-1);
-}
-
-int main(int argc, char* const argv[]) {
- // program args management
- if (argc != 6) {
- std::cerr << "Error: Number of arguments (" << argc << ") is not correct\n";
- usage(argv[0]);
- }
-
- int coeff_field_characteristic = atoi(argv[4]);
- Filtration_value min_persistence = strtof(argv[5], nullptr);
-
- // Read points from file
- std::string offInputFile(argv[1]);
- // Read the OFF file (input file name given as parameter) and triangulate points
- Gudhi::Points_3D_off_reader<Point_3> off_reader(offInputFile);
- // Check the read operation was correct
- if (!off_reader.is_valid()) {
- std::cerr << "Unable to read file " << offInputFile << std::endl;
- usage(argv[0]);
- }
-
- // Retrieve the points
- std::vector<Point_3> lp = off_reader.get_point_cloud();
-
- // Read iso_cuboid_3 information from file
- std::ifstream iso_cuboid_str(argv[3]);
- double x_min, y_min, z_min, x_max, y_max, z_max;
- if (iso_cuboid_str.is_open()) {
- if (!(iso_cuboid_str >> x_min >> y_min >> z_min >> x_max >> y_max >> z_max)) {
- std::cerr << argv[3] << " - Bad file format." << std::endl;
- usage(argv[0]);
- }
-
- } else {
- std::cerr << "Unable to read file " << argv[3] << std::endl;
- usage(argv[0]);
- }
- // Checking if the cuboid is the same in x,y and z direction. If not, CGAL will not process it.
- if ((x_max - x_min != y_max - y_min) || (x_max - x_min != z_max - z_min) || (z_max - z_min != y_max - y_min)) {
- std::cerr << "The size of the cuboid in every directions is not the same." << std::endl;
- exit(-1);
- }
-
- double maximal_possible_weight = 0.015625 * (x_max - x_min) * (x_max - x_min);
-
- // Read weights information from file
- std::ifstream weights_ifstr(argv[2]);
- std::vector<Weighted_point_3> wp;
- if (weights_ifstr.is_open()) {
- double weight = 0.0;
- std::size_t index = 0;
- wp.reserve(lp.size());
- // Attempt read the weight in a double format, return false if it fails
- while ((weights_ifstr >> weight) && (index < lp.size())) {
- if ((weight >= maximal_possible_weight) || (weight < 0)) {
- std::cerr << "At line " << (index + 1) << ", the weight (" << weight
- << ") is negative or more than or equal to maximal possible weight (" << maximal_possible_weight
- << ") = 1/64*cuboid length squared, which is not an acceptable input." << std::endl;
- exit(-1);
- }
-
- wp.push_back(Weighted_point_3(lp[index], weight));
- index++;
- }
- if (index != lp.size()) {
- std::cerr << "Bad number of weights in file " << argv[2] << std::endl;
- usage(argv[0]);
- }
- } else {
- std::cerr << "Unable to read file " << argv[2] << std::endl;
- usage(argv[0]);
- }
-
- // Define the periodic cube
- P3RT3 prt(PK::Iso_cuboid_3(x_min, y_min, z_min, x_max, y_max, z_max));
- // Heuristic for inserting large point sets (if pts is reasonably large)
- prt.insert(wp.begin(), wp.end(), true);
- // As prt won't be modified anymore switch to 1-sheeted cover if possible
- if (prt.is_triangulation_in_1_sheet()) {
- prt.convert_to_1_sheeted_covering();
- } else {
- std::cerr << "ERROR: we were not able to construct a triangulation within a single periodic domain." << std::endl;
- exit(-1);
- }
- std::cout << "Weighted Periodic Delaunay computed." << std::endl;
-
- // alpha shape construction from points. CGAL has a strange behavior in REGULARIZED mode. This is the default mode
- // Maybe need to set it to GENERAL mode
- Alpha_shape_3 as(prt, 0, Alpha_shape_3::GENERAL);
-
- // 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));
-
- 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
-
- 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;
- ST 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<Vertex_list, Cell_handle>(*cell);
- count_cells++;
- } else if (const Facet* facet = CGAL::object_cast<Facet>(&object_iterator)) {
- vertex_list = from_facet<Vertex_list, Facet>(*facet);
- count_facets++;
- } else if (const Edge_3* edge = CGAL::object_cast<Edge_3>(&object_iterator)) {
- vertex_list = from_edge<Vertex_list, Edge_3>(*edge);
- count_edges++;
- } else if (const Vertex_handle* vertex = CGAL::object_cast<Vertex_handle>(&object_iterator)) {
- count_vertices++;
- vertex_list = from_vertex<Vertex_list, Vertex_handle>(*vertex);
- }
- // Construction of the vector of simplex_tree vertex from list of alpha_shapes vertex
- Simplex_tree_vector_vertex the_simplex;
- 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 " << vertex << std::endl;
-#endif // DEBUG_TRACES
- the_simplex.push_back(vertex);
- map_cgal_simplex_tree.emplace(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.push_back(vertex);
- }
- }
- // Construction of the simplex_tree
- Filtration_value filtr = /*std::sqrt*/ (*the_alpha_value_iterator);
-#ifdef DEBUG_TRACES
- std::cout << "filtration = " << filtr << std::endl;
-#endif // DEBUG_TRACES
- simplex_tree.insert_simplex(the_simplex, filtr);
- if (the_alpha_value_iterator != the_alpha_values.end())
- ++the_alpha_value_iterator;
- else
- std::cout << "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 << "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;
- std::cout << " Dimension = " << simplex_tree.dimension() << " ";
-#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
-
- // 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 pcoh(simplex_tree, true);
- // initializes the coefficient field for homology
- pcoh.init_coefficients(coeff_field_characteristic);
-
- pcoh.compute_persistent_cohomology(min_persistence);
-
- pcoh.output_diagram();
-
- return 0;
-}
diff --git a/src/Bitmap_cubical_complex/doc/Gudhi_Cubical_Complex_doc.h b/src/Bitmap_cubical_complex/doc/Gudhi_Cubical_Complex_doc.h
index d1836ef0..5fa02a5e 100644
--- a/src/Bitmap_cubical_complex/doc/Gudhi_Cubical_Complex_doc.h
+++ b/src/Bitmap_cubical_complex/doc/Gudhi_Cubical_Complex_doc.h
@@ -87,11 +87,16 @@ namespace cubical_complex {
*
* \section inputformat Input Format
*
- * In the current implantation, filtration is given at the maximal cubes, and it is then extended by the lower star
+ * In the current implementation, filtration is given at the maximal cubes, and it is then extended by the lower star
* filtration to all cubes. There are a number of constructors that can be used to construct cubical complex by users
* who want to use the code directly. They can be found in the \a Bitmap_cubical_complex class.
- * Currently one input from a text file is used. It uses a format used already in Perseus software
- * (http://www.sas.upenn.edu/~vnanda/perseus/) by Vidit Nanda. The file format is described here: \ref FileFormatsPerseus.
+ * Currently one input from a text file is used. It uses a format inspired from the Perseus software
+ * (http://www.sas.upenn.edu/~vnanda/perseus/) by Vidit Nanda.
+ * \note While Perseus assume the filtration of all maximal cubes to be non-negative, over here we do not enforce this
+ * and we allow any filtration values. As a consequence one cannot use `-1`'s to indicate missing cubes. If you have
+ * missing cubes in your complex, please set their filtration to \f$+\infty\f$ (aka. `inf` in the file).
+ *
+ * The file format is described in details in \ref FileFormatsPerseus file format section.
*
* \section PeriodicBoundaryConditions Periodic boundary conditions
* Often one would like to impose periodic boundary conditions to the cubical complex. Let \f$ I_1\times ... \times
diff --git a/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex_base.h b/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex_base.h
index 9b74e267..f5e005b2 100644
--- a/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex_base.h
+++ b/src/Bitmap_cubical_complex/include/gudhi/Bitmap_cubical_complex_base.h
@@ -650,18 +650,33 @@ void Bitmap_cubical_complex_base<T>::read_perseus_style_file(const char* perseus
Bitmap_cubical_complex_base<T>::Top_dimensional_cells_iterator it(*this);
it = this->top_dimensional_cells_iterator_begin();
- T filtrationLevel;
- for (std::size_t i = 0; i < dimensions; ++i) {
- if (!(inFiltration >> filtrationLevel) || (inFiltration.eof())) {
- throw std::ios_base::failure("Bad Perseus file format.");
- }
- if (dbg) {
- std::cerr << "Cell of an index : " << it.compute_index_in_bitmap()
- << " and dimension: " << this->get_dimension_of_a_cell(it.compute_index_in_bitmap())
- << " get the value : " << filtrationLevel << std::endl;
+ T filtrationLevel = 0.;
+ std::size_t filtration_counter = 0;
+ while (!inFiltration.eof()) {
+ std::string line;
+ getline(inFiltration, line);
+ if (line.length() != 0) {
+ int n = sscanf(line.c_str(), "%lf", &filtrationLevel);
+ if (n != 1) {
+ std::string perseus_error("Bad Perseus file format. This line is incorrect : " + line);
+ throw std::ios_base::failure(perseus_error.c_str());
+ }
+
+ if (dbg) {
+ std::cerr << "Cell of an index : " << it.compute_index_in_bitmap()
+ << " and dimension: " << this->get_dimension_of_a_cell(it.compute_index_in_bitmap())
+ << " get the value : " << filtrationLevel << std::endl;
+ }
+ this->get_cell_data(*it) = filtrationLevel;
+ ++it;
+ ++filtration_counter;
}
- this->get_cell_data(*it) = filtrationLevel;
- ++it;
+ }
+
+ if (filtration_counter != dimensions) {
+ std::string perseus_error("Bad Perseus file format. Read " + std::to_string(filtration_counter) + " expected " + \
+ std::to_string(dimensions) + " values");
+ throw std::ios_base::failure(perseus_error.c_str());
}
inFiltration.close();
diff --git a/src/Bitmap_cubical_complex/test/Bitmap_test.cpp b/src/Bitmap_cubical_complex/test/Bitmap_test.cpp
index ca7bd986..6a917c25 100644
--- a/src/Bitmap_cubical_complex/test/Bitmap_test.cpp
+++ b/src/Bitmap_cubical_complex/test/Bitmap_test.cpp
@@ -32,6 +32,7 @@
#include <iostream>
#include <sstream>
#include <vector>
+#include <limits>
typedef Gudhi::cubical_complex::Bitmap_cubical_complex_base<double> Bitmap_cubical_complex_base;
typedef Gudhi::cubical_complex::Bitmap_cubical_complex<Bitmap_cubical_complex_base> Bitmap_cubical_complex;
@@ -1576,3 +1577,17 @@ BOOST_AUTO_TEST_CASE(compute_incidence_between_cells_test_periodic_boundary_cond
}
}
}
+
+BOOST_AUTO_TEST_CASE(perseus_file_read) {
+ Bitmap_cubical_complex increasing("sinusoid.txt");
+
+ auto it = increasing.top_dimensional_cells_iterator_begin();
+ double value = increasing.get_cell_data(*it);
+ std::cout << "First value of sinusoid.txt is " << value << std::endl;
+ BOOST_CHECK(value == 10.);
+ // Next value
+ ++it;
+ value = increasing.get_cell_data(*it);
+ std::cout << "Second value of sinusoid.txt is " << value << std::endl;
+ BOOST_CHECK(value == std::numeric_limits<double>::infinity());
+}
diff --git a/src/Bitmap_cubical_complex/test/CMakeLists.txt b/src/Bitmap_cubical_complex/test/CMakeLists.txt
index 8b43632a..d2f002a6 100644
--- a/src/Bitmap_cubical_complex/test/CMakeLists.txt
+++ b/src/Bitmap_cubical_complex/test/CMakeLists.txt
@@ -2,6 +2,9 @@ project(Bitmap_cubical_complex_tests)
include(GUDHI_test_coverage)
+# Do not forget to copy test files in current binary dir
+file(COPY "${CMAKE_SOURCE_DIR}/data/bitmap/sinusoid.txt" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
+
add_executable ( Bitmap_cubical_complex_test_unit Bitmap_test.cpp )
target_link_libraries(Bitmap_cubical_complex_test_unit ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
if (TBB_FOUND)
diff --git a/src/Doxyfile.in b/src/Doxyfile.in
index 858a9299..1c293d1c 100644
--- a/src/Doxyfile.in
+++ b/src/Doxyfile.in
@@ -785,7 +785,8 @@ EXCLUDE = data/ \
GudhUI/ \
cmake/ \
src/cython/ \
- include/gudhi_patches/
+ include/gudhi_patches/ \
+ README.md
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
diff --git a/src/Nerve_GIC/include/gudhi/GIC.h b/src/Nerve_GIC/include/gudhi/GIC.h
index 30f89d65..c3085dff 100644
--- a/src/Nerve_GIC/include/gudhi/GIC.h
+++ b/src/Nerve_GIC/include/gudhi/GIC.h
@@ -230,18 +230,17 @@ class Cover_complex {
/** \brief Reads and stores the input point cloud from vector stored in memory.
*
- * @param[in] cloud input vector representing the point cloud. Each row is a point and each coordinate is a vector.
+ * @param[in] point_cloud input vector representing the point cloud. Each row is a point and each coordinate is a vector.
*
*/
- template <class InputRange>
- void set_point_cloud_from_range(InputRange const & cloud) {
- n = cloud.size(); data_dimension = cloud[0].size(); point_cloud_name = "matrix";
+ void set_point_cloud_from_range(const std::vector<std::vector<double> > & point_cloud) {
+ n = point_cloud.size(); data_dimension = point_cloud[0].size();
+ point_cloud_name = "matrix"; cover.resize(n);
for(int i = 0; i < n; i++){
- point_cloud.emplace_back(cloud[i].begin(), cloud[i].begin() + data_dimension);
boost::add_vertex(one_skeleton_OFF);
vertices.push_back(boost::add_vertex(one_skeleton));
- cover.emplace_back();
}
+ this->point_cloud = point_cloud;
}
/** \brief Reads and stores the input point cloud from .(n)OFF file.
@@ -395,18 +394,12 @@ class Cover_complex {
* @param[in] distance_matrix input vector representing the distance matrix.
*
*/
- template <class InputRange>
- void set_distances_from_range(InputRange const & distance_matrix) {
- if(point_cloud.size() == 0){
- n = distance_matrix.size();
- point_cloud_name = "matrix";
- data_dimension = 0;
- for(int i = 0; i < n; i++){
- point_cloud.emplace_back();
- boost::add_vertex(one_skeleton_OFF);
- vertices.push_back(boost::add_vertex(one_skeleton));
- cover.emplace_back();
- }
+ void set_distances_from_range(const std::vector<std::vector<double> > & distance_matrix) {
+ n = distance_matrix.size(); data_dimension = 0; point_cloud_name = "matrix";
+ cover.resize(n); point_cloud.resize(n);
+ for(int i = 0; i < n; i++){
+ boost::add_vertex(one_skeleton_OFF);
+ vertices.push_back(boost::add_vertex(one_skeleton));
}
distances = distance_matrix;
}
diff --git a/src/Persistent_cohomology/example/persistence_from_file.cpp b/src/Persistent_cohomology/example/persistence_from_file.cpp
index 53456919..0a05c193 100644
--- a/src/Persistent_cohomology/example/persistence_from_file.cpp
+++ b/src/Persistent_cohomology/example/persistence_from_file.cpp
@@ -33,7 +33,6 @@
using namespace Gudhi;
using namespace Gudhi::persistent_cohomology;
-typedef int Vertex_handle;
typedef double Filtration_value;
void program_options(int argc, char * argv[]
diff --git a/src/Rips_complex/doc/Intro_rips_complex.h b/src/Rips_complex/doc/Intro_rips_complex.h
index 712d3b6e..a2537036 100644
--- a/src/Rips_complex/doc/Intro_rips_complex.h
+++ b/src/Rips_complex/doc/Intro_rips_complex.h
@@ -39,7 +39,7 @@ namespace rips_complex {
* <a target="_blank" href="https://en.wikipedia.org/wiki/Vietoris%E2%80%93Rips_complex">(Wikipedia)</a>
* is an abstract simplicial complex
* defined on a finite metric space, where each simplex corresponds to a subset
- * of point whose diameter is smaller that some given threshold.
+ * of points whose diameter is smaller that some given threshold.
* Varying the threshold, we can also see the Rips complex as a filtration of
* the \f$(n-1)-\f$dimensional simplex, where the filtration value of each
* simplex is the diameter of the corresponding subset of points.
@@ -53,7 +53,10 @@ namespace rips_complex {
* The number of simplices in the full Rips complex is exponential in the
* number of vertices, it is thus usually restricted, by excluding all the
* simplices with filtration value larger than some threshold, and keeping only
- * the dim_max-skeleton.
+ * the dim_max-skeleton. It may also be a good idea to start by making the
+ * point set sparser, for instance with
+ * `Gudhi::subsampling::sparsify_point_set()`, since small clusters of points
+ * have a disproportionate cost without affecting the persistence diagram much.
*
* In order to build this complex, the algorithm first builds the graph.
* The filtration value of each edge is computed from a user-given distance
diff --git a/src/Rips_complex/include/gudhi/Rips_complex.h b/src/Rips_complex/include/gudhi/Rips_complex.h
index f0fe57f4..e902e52c 100644
--- a/src/Rips_complex/include/gudhi/Rips_complex.h
+++ b/src/Rips_complex/include/gudhi/Rips_complex.h
@@ -59,7 +59,7 @@ class Rips_complex {
/**
* \brief Type of the one skeleton graph stored inside the Rips complex structure.
*/
- typedef typename boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS
+ typedef typename boost::adjacency_list < boost::vecS, boost::vecS, boost::directedS
, boost::property < vertex_filtration_t, Filtration_value >
, boost::property < edge_filtration_t, Filtration_value >> OneSkeletonGraph;
diff --git a/src/Rips_complex/include/gudhi/Sparse_rips_complex.h b/src/Rips_complex/include/gudhi/Sparse_rips_complex.h
index 4dcc08ed..00da148f 100644
--- a/src/Rips_complex/include/gudhi/Sparse_rips_complex.h
+++ b/src/Rips_complex/include/gudhi/Sparse_rips_complex.h
@@ -55,7 +55,7 @@ template <typename Filtration_value>
class Sparse_rips_complex {
private:
// TODO(MG): use a different graph where we know we can safely insert in parallel.
- typedef typename boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS,
+ typedef typename boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS,
boost::property<vertex_filtration_t, Filtration_value>,
boost::property<edge_filtration_t, Filtration_value>>
Graph;
diff --git a/src/Rips_complex/utilities/ripscomplex.md b/src/Rips_complex/utilities/ripscomplex.md
index 6df49310..108cdd50 100644
--- a/src/Rips_complex/utilities/ripscomplex.md
+++ b/src/Rips_complex/utilities/ripscomplex.md
@@ -85,7 +85,7 @@ properly, this is a known issue.
## sparse_rips_persistence ##
This program computes the persistent homology with coefficient field *Z/pZ*
-of a sparse (1+epsilon)-approximation of the Rips complex defined on a set of input Euclidean points. The output diagram contains one bar per line, written with the convention:
+of a sparse (1+epsilon)/(1-epsilon)-approximation of the Rips complex defined on a set of input Euclidean points. The output diagram contains one bar per line, written with the convention:
`p dim birth death`
@@ -99,7 +99,7 @@ where `dim` is the dimension of the homological feature, `birth` and `death` are
* `-h [ --help ]` Produce help message
* `-o [ --output-file ]` Name of file in which the persistence diagram is written. Default print in standard output.
-* `-e [ --approximation ]` (default = .5) Epsilon, where the sparse Rips complex is a (1+epsilon)-approximation of the Rips complex.
+* `-e [ --approximation ]` (default = .5) Epsilon, where the sparse Rips complex is a (1+epsilon)/(1-epsilon)-approximation of the Rips complex.
* `-d [ --cpx-dimension ]` (default = 1) Maximal dimension of the Rips complex we want to compute.
* `-p [ --field-charac ]` (default = 11) Characteristic p of the coefficient field Z/pZ for computing homology.
* `-m [ --min-persistence ]` (default = 0) Minimal lifetime of homology feature to be recorded. Enter a negative value to see zero length intervals.
diff --git a/src/Simplex_tree/example/cech_complex_cgal_mini_sphere_3d.cpp b/src/Simplex_tree/example/cech_complex_cgal_mini_sphere_3d.cpp
index 34092ef6..6bab8adb 100644
--- a/src/Simplex_tree/example/cech_complex_cgal_mini_sphere_3d.cpp
+++ b/src/Simplex_tree/example/cech_complex_cgal_mini_sphere_3d.cpp
@@ -50,7 +50,7 @@ using Vertex_handle = Simplex_tree::Vertex_handle;
using Simplex_handle = Simplex_tree::Simplex_handle;
using Filtration_value = Simplex_tree::Filtration_value;
using Siblings = Simplex_tree::Siblings;
-using Graph_t = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS,
+using Graph_t = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS,
boost::property<Gudhi::vertex_filtration_t, Filtration_value>,
boost::property<Gudhi::edge_filtration_t, Filtration_value> >;
using Edge_t = std::pair<Vertex_handle, Vertex_handle>;
diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h
index 3ab23c12..4b18651c 100644
--- a/src/Simplex_tree/include/gudhi/Simplex_tree.h
+++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h
@@ -296,12 +296,79 @@ class Simplex_tree {
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_),
- root_(nullptr, null_vertex_ , simplex_source.root_.members_),
- filtration_vect_(),
- dimension_(simplex_source.dimension_) {
- auto root_source = simplex_source.root_;
+ Simplex_tree(const Simplex_tree& complex_source) {
+#ifdef DEBUG_TRACES
+ std::cout << "Simplex_tree copy constructor" << std::endl;
+#endif // DEBUG_TRACES
+ copy_from(complex_source);
+ }
+
+ /** \brief User-defined move constructor relocates the whole tree structure.
+ * \exception std::invalid_argument In debug mode, if the complex_source is invalid.
+ */
+ Simplex_tree(Simplex_tree && complex_source) {
+#ifdef DEBUG_TRACES
+ std::cout << "Simplex_tree move constructor" << std::endl;
+#endif // DEBUG_TRACES
+ move_from(complex_source);
+
+ // just need to set dimension_ on source to make it available again
+ // (filtration_vect_ and members are already set from the move)
+ complex_source.dimension_ = -1;
+ }
+
+ /** \brief Destructor; deallocates the whole tree structure. */
+ ~Simplex_tree() {
+ root_members_recursive_deletion();
+ }
+
+ /** \brief User-defined copy assignment reproduces the whole tree structure. */
+ Simplex_tree& operator= (const Simplex_tree& complex_source) {
+#ifdef DEBUG_TRACES
+ std::cout << "Simplex_tree copy assignment" << std::endl;
+#endif // DEBUG_TRACES
+ // Self-assignment detection
+ if (&complex_source != this) {
+ // We start by deleting root_ if not empty
+ root_members_recursive_deletion();
+
+ copy_from(complex_source);
+ }
+ return *this;
+ }
+
+ /** \brief User-defined move assignment relocates the whole tree structure.
+ * \exception std::invalid_argument In debug mode, if the complex_source is invalid.
+ */
+ Simplex_tree& operator=(Simplex_tree&& complex_source) {
+#ifdef DEBUG_TRACES
+ std::cout << "Simplex_tree move assignment" << std::endl;
+#endif // DEBUG_TRACES
+ // Self-assignment detection
+ if (&complex_source != this) {
+ // root_ deletion in case it was not empty
+ root_members_recursive_deletion();
+
+ move_from(complex_source);
+ }
+ return *this;
+ }
+ /** @} */ // end constructor/destructor
+
+ private:
+ // Copy from complex_source to "this"
+ void copy_from(const Simplex_tree& complex_source) {
+ null_vertex_ = complex_source.null_vertex_;
+ filtration_vect_.clear();
+ dimension_ = complex_source.dimension_;
+ auto root_source = complex_source.root_;
+
+ // root members copy
+ root_.members() = Dictionary(boost::container::ordered_unique_range, root_source.members().begin(), root_source.members().end());
+ // Needs to reassign children
+ for (auto& map_el : root_.members()) {
+ map_el.second.assign_children(&root_);
+ }
rec_copy(&root_, &root_source);
}
@@ -320,26 +387,38 @@ class Simplex_tree {
}
}
- /** \brief User-defined move constructor moves the whole tree structure. */
- Simplex_tree(Simplex_tree && old)
- : null_vertex_(std::move(old.null_vertex_)),
- root_(std::move(old.root_)),
- filtration_vect_(std::move(old.filtration_vect_)),
- dimension_(std::move(old.dimension_)) {
- old.dimension_ = -1;
- old.root_ = Siblings(nullptr, null_vertex_);
+ // Move from complex_source to "this"
+ void move_from(Simplex_tree& complex_source) {
+ null_vertex_ = std::move(complex_source.null_vertex_);
+ root_ = std::move(complex_source.root_);
+ filtration_vect_ = std::move(complex_source.filtration_vect_);
+ dimension_ = std::move(complex_source.dimension_);
+
+ // Need to update root members (children->oncles and children need to point on the new root pointer)
+ for (auto& map_el : root_.members()) {
+ if (map_el.second.children() != &(complex_source.root_)) {
+ // reset children->oncles with the moved root_ pointer value
+ map_el.second.children()->oncles_ = &root_;
+ } else {
+ // if simplex is of dimension 0, oncles_ shall be nullptr
+ GUDHI_CHECK(map_el.second.children()->oncles_ == nullptr,
+ std::invalid_argument("Simplex_tree move constructor from an invalid Simplex_tree"));
+ // and children points on root_ - to be moved
+ map_el.second.assign_children(&root_);
+ }
+ }
}
- /** \brief Destructor; deallocates the whole tree structure. */
- ~Simplex_tree() {
+ // delete all root_.members() recursively
+ void root_members_recursive_deletion() {
for (auto sh = root_.members().begin(); sh != root_.members().end(); ++sh) {
if (has_children(sh)) {
rec_delete(sh->second.children());
}
}
+ root_.members().clear();
}
- /** @} */ // end constructor/destructor
- private:
+
// Recursive deletion
void rec_delete(Siblings * sib) {
for (auto sh = sib->members().begin(); sh != sib->members().end(); ++sh) {
@@ -970,7 +1049,8 @@ class Simplex_tree {
* boost::graph_traits<OneSkeletonGraph>::vertex_descriptor
* must be Vertex_handle.
* boost::graph_traits<OneSkeletonGraph>::directed_category
- * must be undirected_tag.
+ * can be directed_tag (the fastest, the least RAM use), undirected_tag or even
+ * bidirected_tag.
*
* If an edge appears with multiplicity, the function will arbitrarily pick
* one representative to read the filtration value. */
@@ -998,12 +1078,14 @@ class Simplex_tree {
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) {
- auto u = source(*e_it, skel_graph);
- auto v = target(*e_it, skel_graph);
+ std::pair<typename boost::graph_traits<OneSkeletonGraph>::edge_iterator,
+ typename boost::graph_traits<OneSkeletonGraph>::edge_iterator> boost_edges = boost::edges(skel_graph);
+ // boost_edges.first is the equivalent to boost_edges.begin()
+ // boost_edges.second is the equivalent to boost_edges.end()
+ for (; boost_edges.first != boost_edges.second; boost_edges.first++) {
+ auto edge = *(boost_edges.first);
+ auto u = source(edge, skel_graph);
+ auto v = target(edge, skel_graph);
if (u == v) throw "Self-loops are not simplicial";
// We cannot skip edges with the wrong orientation and expect them to
// come a second time with the right orientation, that does not always
@@ -1019,7 +1101,7 @@ class Simplex_tree {
}
sh->second.children()->members().emplace(v,
- Node(sh->second.children(), boost::get(edge_filtration_t(), skel_graph, *e_it)));
+ Node(sh->second.children(), boost::get(edge_filtration_t(), skel_graph, edge)));
}
}
@@ -1035,6 +1117,7 @@ class Simplex_tree {
* The Simplex_tree must contain no simplex of dimension bigger than
* 1 when calling the method. */
void expansion(int max_dim) {
+ if (max_dim <= 1) return;
dimension_ = max_dim;
for (Dictionary_it root_it = root_.members_.begin();
root_it != root_.members_.end(); ++root_it) {
diff --git a/src/Simplex_tree/test/CMakeLists.txt b/src/Simplex_tree/test/CMakeLists.txt
index c63d8532..5bea3938 100644
--- a/src/Simplex_tree/test/CMakeLists.txt
+++ b/src/Simplex_tree/test/CMakeLists.txt
@@ -28,3 +28,11 @@ if (TBB_FOUND)
endif()
gudhi_add_coverage_test(Simplex_tree_iostream_operator_test_unit)
+
+add_executable ( Simplex_tree_ctor_and_move_test_unit simplex_tree_ctor_and_move_unit_test.cpp )
+target_link_libraries(Simplex_tree_ctor_and_move_test_unit ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
+if (TBB_FOUND)
+ target_link_libraries(Simplex_tree_ctor_and_move_test_unit ${TBB_LIBRARIES})
+endif()
+
+gudhi_add_coverage_test(Simplex_tree_ctor_and_move_test_unit)
diff --git a/src/Simplex_tree/test/simplex_tree_ctor_and_move_unit_test.cpp b/src/Simplex_tree/test/simplex_tree_ctor_and_move_unit_test.cpp
new file mode 100644
index 00000000..e729cf00
--- /dev/null
+++ b/src/Simplex_tree/test/simplex_tree_ctor_and_move_unit_test.cpp
@@ -0,0 +1,137 @@
+#include <iostream>
+#include <vector>
+#include <string>
+
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MODULE "simplex_tree_constructor_and_move"
+#include <boost/test/unit_test.hpp>
+#include <boost/mpl/list.hpp>
+
+// ^
+// /!\ Nothing else from Simplex_tree shall be included to test includes are well defined.
+#include "gudhi/Simplex_tree.h"
+
+using namespace Gudhi;
+
+typedef boost::mpl::list<Simplex_tree<>, Simplex_tree<Simplex_tree_options_fast_persistence>> list_of_tested_variants;
+
+template<typename Simplex_tree>
+void print_simplex_filtration(Simplex_tree& st, const std::string& msg) {
+ // Required before browsing through filtration values
+ st.initialize_filtration();
+
+ std::cout << "********************************************************************\n";
+ std::cout << "* " << msg << "\n";
+ std::cout << "* The complex contains " << st.num_simplices() << " simplices";
+ std::cout << " - dimension " << st.dimension() << "\n";
+ std::cout << "* Iterator on Simplices in the filtration, with [filtration value]:\n";
+ 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;
+ }
+
+}
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_copy_constructor, Simplex_tree, list_of_tested_variants) {
+ Simplex_tree st;
+
+ st.insert_simplex_and_subfaces({2, 1, 0}, 3.0);
+ st.insert_simplex_and_subfaces({0, 1, 6, 7}, 4.0);
+ st.insert_simplex_and_subfaces({3, 0}, 2.0);
+ st.insert_simplex_and_subfaces({3, 4, 5}, 3.0);
+ st.insert_simplex_and_subfaces({8}, 1.0);
+ /* Inserted simplex: */
+ /* 1 6 */
+ /* o---o */
+ /* /X\7/ */
+ /* o---o---o---o o */
+ /* 2 0 3\X/4 8 */
+ /* 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 vertex [8] */
+
+ print_simplex_filtration(st, "Default Simplex_tree is initialized");
+
+ std::cout << "********************************************************************" << std::endl;
+ std::cout << "TEST OF COPY CONSTRUCTOR" << std::endl;
+
+ Simplex_tree st1(st);
+ Simplex_tree st2(st);
+ print_simplex_filtration(st1, "First copy constructor from the default Simplex_tree");
+ print_simplex_filtration(st2, "Second copy constructor from the default Simplex_tree");
+ // Cross check
+ BOOST_CHECK(st1 == st2);
+ BOOST_CHECK(st == st2);
+ BOOST_CHECK(st1 == st);
+
+ std::cout << "********************************************************************" << std::endl;
+ std::cout << "TEST OF COPY ASSIGNMENT" << std::endl;
+ Simplex_tree st3;
+ // To check there is no memory leak
+ st3.insert_simplex_and_subfaces({9, 10, 11}, 200.0);
+ st3 = st;
+ print_simplex_filtration(st3, "First copy assignment from the default Simplex_tree");
+ Simplex_tree st4;
+ st4 = st;
+ print_simplex_filtration(st4, "Second copy assignment from the default Simplex_tree");
+
+ // Cross check
+ BOOST_CHECK(st3 == st4);
+ BOOST_CHECK(st == st4);
+ BOOST_CHECK(st3 == st);
+
+ st = st;
+ print_simplex_filtration(st4, "Third self copy assignment from the default Simplex_tree");
+
+ BOOST_CHECK(st3 == st);
+
+ std::cout << "********************************************************************" << std::endl;
+ std::cout << "TEST OF MOVE CONSTRUCTOR" << std::endl;
+ Simplex_tree st5(std::move(st1));
+ print_simplex_filtration(st5, "First move constructor from the default Simplex_tree");
+ print_simplex_filtration(st1, "First moved Simplex_tree shall be empty");
+ Simplex_tree st6(std::move(st2));
+ print_simplex_filtration(st6, "Second move constructor from the default Simplex_tree");
+ print_simplex_filtration(st2, "Second moved Simplex_tree shall be empty");
+
+ // Cross check
+ BOOST_CHECK(st5 == st6);
+ BOOST_CHECK(st == st6);
+ BOOST_CHECK(st5 == st);
+
+ Simplex_tree empty_st;
+ BOOST_CHECK(st1 == st2);
+ BOOST_CHECK(empty_st == st2);
+ BOOST_CHECK(st1 == empty_st);
+
+ std::cout << "********************************************************************" << std::endl;
+ std::cout << "TEST OF MOVE ASSIGNMENT" << std::endl;
+
+ Simplex_tree st7;
+ // To check there is no memory leak
+ st7.insert_simplex_and_subfaces({9, 10, 11}, 200.0);
+ st7 = std::move(st3);
+ print_simplex_filtration(st7, "First move assignment from the default Simplex_tree");
+ Simplex_tree st8;
+ st8 = std::move(st4);
+ print_simplex_filtration(st8, "Second move assignment from the default Simplex_tree");
+
+ // Cross check
+ BOOST_CHECK(st7 == st8);
+ BOOST_CHECK(st == st8);
+ BOOST_CHECK(st7 == st);
+
+ st = std::move(st);
+ print_simplex_filtration(st, "Third self move assignment from the default Simplex_tree");
+
+ BOOST_CHECK(st7 == st);
+
+}
diff --git a/src/Simplex_tree/test/simplex_tree_unit_test.cpp b/src/Simplex_tree/test/simplex_tree_unit_test.cpp
index f63ea080..b27bbce8 100644
--- a/src/Simplex_tree/test/simplex_tree_unit_test.cpp
+++ b/src/Simplex_tree/test/simplex_tree_unit_test.cpp
@@ -864,34 +864,60 @@ BOOST_AUTO_TEST_CASE(make_filtration_non_decreasing) {
}
-BOOST_AUTO_TEST_CASE(insert_graph) {
+
+typedef boost::mpl::list<boost::adjacency_list<boost::setS, boost::vecS, boost::directedS,
+ boost::property<vertex_filtration_t, double>,
+ boost::property<edge_filtration_t, double>>,
+ boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS,
+ boost::property<vertex_filtration_t, double>,
+ boost::property<edge_filtration_t, double>>,
+ boost::adjacency_list<boost::setS, boost::vecS, boost::bidirectionalS,
+ boost::property<vertex_filtration_t, double>,
+ boost::property<edge_filtration_t, double>>,
+ boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS,
+ boost::property<vertex_filtration_t, double>,
+ boost::property<edge_filtration_t, double>>,
+ boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS,
+ boost::property<vertex_filtration_t, double>,
+ boost::property<edge_filtration_t, double>>,
+ boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS,
+ boost::property<vertex_filtration_t, double>,
+ boost::property<edge_filtration_t, double>>> list_of_graph_variants;
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_insert_graph, Graph, list_of_graph_variants) {
std::cout << "********************************************************************" << std::endl;
std::cout << "INSERT GRAPH" << std::endl;
- typedef typename boost::adjacency_list<boost::vecS, boost::vecS,
- boost::undirectedS,
- boost::property<vertex_filtration_t, double>,
- boost::property<edge_filtration_t, double>> Graph;
+
Graph g(3);
// filtration value 0 everywhere
put(Gudhi::vertex_filtration_t(), g, 0, 0);
put(Gudhi::vertex_filtration_t(), g, 1, 0);
put(Gudhi::vertex_filtration_t(), g, 2, 0);
// vertices don't always occur in sorted order
- add_edge(0, 1, 0, g);
- add_edge(2, 1, 0, g);
- add_edge(2, 0, 0, g);
+ add_edge(0, 1, 1.1, g);
+ add_edge(2, 0, 2.2, g);
+ add_edge(2, 1, 3.3, g);
- typedef Simplex_tree<> typeST;
- typeST st1;
+ Simplex_tree<> st1;
st1.insert_graph(g);
BOOST_CHECK(st1.num_simplices() == 6);
// edges can have multiplicity in the graph unless we replace the first vecS with (hash_)setS
- add_edge(1, 0, 0, g);
- add_edge(1, 2, 0, g);
- add_edge(0, 2, 0, g);
- add_edge(0, 2, 0, g);
- typeST st2;
+ add_edge(1, 0, 1.1, g);
+ add_edge(1, 2, 3.3, g);
+ add_edge(0, 2, 2.2, g);
+ add_edge(0, 1, 1.1, g);
+ add_edge(2, 1, 3.3, g);
+ add_edge(2, 0, 2.2, g);
+ Simplex_tree<> st2;
st2.insert_graph(g);
BOOST_CHECK(st2.num_simplices() == 6);
+
+ std::cout << "st1 is" << std::endl;
+ std::cout << st1 << std::endl;
+
+ std::cout << "st2 is" << std::endl;
+ std::cout << st2 << std::endl;
+
+ BOOST_CHECK(st1 == st2);
}
diff --git a/src/Tangential_complex/doc/Intro_tangential_complex.h b/src/Tangential_complex/doc/Intro_tangential_complex.h
index f4fc8ac7..501f4a8b 100644
--- a/src/Tangential_complex/doc/Intro_tangential_complex.h
+++ b/src/Tangential_complex/doc/Intro_tangential_complex.h
@@ -35,9 +35,11 @@ namespace tangential_complex {
\section tangentialdefinition Definition
-A Tangential Delaunay complex is a <a target="_blank" href="https://en.wikipedia.org/wiki/Simplicial_complex">simplicial complex</a>
+A Tangential Delaunay complex is a
+<a target="_blank" href="https://en.wikipedia.org/wiki/Simplicial_complex">simplicial complex</a>
designed to reconstruct a \f$k\f$-dimensional smooth manifold embedded in \f$d\f$-dimensional Euclidean space.
-The input is a point sample coming from an unknown manifold, which means that the points lie close to a structure of "small" intrinsic dimension.
+The input is a point sample coming from an unknown manifold, which means that the points lie close to a structure of
+"small" intrinsic dimension.
The running time depends only linearly on the extrinsic dimension \f$ d \f$
and exponentially on the intrinsic dimension \f$ k \f$.
@@ -46,17 +48,19 @@ An extensive description of the Tangential complex can be found in \cite tangent
\subsection whatisthetc What is a Tangential Complex?
Let us start with the description of the Tangential complex of a simple example, with \f$ k=1 \f$ and \f$ d=2 \f$.
-The input data is 4 points \f$ P \f$ located on a curve embedded in 2D.
+The point set \f$ \mathscr P \f$ is located on a closed curve embedded in 2D.
+Only 4 points will be displayed (more are required for PCA) to simplify the figures.
\image html "tc_example_01.png" "The input"
-For each point \f$ p \f$, estimate its tangent subspace \f$ T_p \f$ (e.g. using PCA).
+For each point \f$ P \f$, estimate its tangent subspace \f$ T_P \f$ using PCA.
\image html "tc_example_02.png" "The estimated normals"
-Let us add the Voronoi diagram of the points in orange. For each point \f$ p \f$, construct its star in the Delaunay triangulation of \f$ P \f$ restricted to \f$ T_p \f$.
+Let us add the Voronoi diagram of the points in orange. For each point \f$ P \f$, construct its star in the Delaunay
+triangulation of \f$ \mathscr P \f$ restricted to \f$ T_P \f$.
\image html "tc_example_03.png" "The Voronoi diagram"
The Tangential Delaunay complex is the union of those stars.
In practice, neither the ambient Voronoi diagram nor the ambient Delaunay triangulation is computed.
-Instead, local \f$ k \f$-dimensional regular triangulations are computed with a limited number of points as we only need the star of each point.
-More details can be found in \cite tangentialcomplex2014.
+Instead, local \f$ k \f$-dimensional regular triangulations are computed with a limited number of points as we only
+need the star of each point. More details can be found in \cite tangentialcomplex2014.
\subsection inconsistencies Inconsistencies
@@ -65,7 +69,7 @@ An inconsistency occurs when a simplex is not in the star of all its vertices.
Let us take the same example.
\image html "tc_example_07_before.png" "Before"
-Let us slightly move the tangent subspace \f$ T_q \f$
+Let us slightly move the tangent subspace \f$ T_Q \f$
\image html "tc_example_07_after.png" "After"
Now, the star of \f$ Q \f$ contains \f$ QP \f$, but the star of \f$ P \f$ does not contain \f$ QP \f$. We have an inconsistency.
\image html "tc_example_08.png" "After"
diff --git a/src/Tangential_complex/include/gudhi/Tangential_complex.h b/src/Tangential_complex/include/gudhi/Tangential_complex.h
index d1c846cf..4a78127c 100644
--- a/src/Tangential_complex/include/gudhi/Tangential_complex.h
+++ b/src/Tangential_complex/include/gudhi/Tangential_complex.h
@@ -30,6 +30,7 @@
#include <gudhi/console_color.h>
#include <gudhi/Clock.h>
#include <gudhi/Simplex_tree.h>
+#include <gudhi/Debug_utils.h>
#include <CGAL/Default.h>
#include <CGAL/Dimension.h>
@@ -321,7 +322,11 @@ class Tangential_complex {
for (std::size_t i = 0; i < m_points.size(); ++i) m_are_tangent_spaces_computed[i] = true;
}
- /// Computes the tangential complex.
+ /** \brief Computes the tangential complex.
+ * \exception std::invalid_argument In debug mode, if the computed star dimension is too low. Try to set a bigger
+ * maximal edge length value with `Tangential_complex::set_max_squared_edge_length` if
+ * this happens.
+ */
void compute_tangential_complex() {
#ifdef GUDHI_TC_PERFORM_EXTRA_CHECKS
std::cerr << red << "WARNING: GUDHI_TC_PERFORM_EXTRA_CHECKS is defined. "
@@ -356,7 +361,7 @@ class Tangential_complex {
tbb::parallel_for(tbb::blocked_range<size_t>(0, m_points.size()), Compute_tangent_triangulation(*this));
} else {
#endif // GUDHI_USE_TBB
- // Sequential
+ // Sequential
for (std::size_t i = 0; i < m_points.size(); ++i) compute_tangent_triangulation(i);
#ifdef GUDHI_USE_TBB
}
@@ -629,12 +634,12 @@ class Tangential_complex {
// Don't export infinite cells
if (!export_infinite_simplices && is_infinite(c)) continue;
- if (!export_inconsistent_simplices && !is_simplex_consistent(c)) continue;
-
if (static_cast<int>(c.size()) > max_dim) max_dim = static_cast<int>(c.size());
// Add the missing center vertex
c.insert(idx);
+ if (!export_inconsistent_simplices && !is_simplex_consistent(c)) continue;
+
// Try to insert the simplex
bool inserted = tree.insert_simplex_and_subfaces(c).second;
@@ -689,6 +694,10 @@ class Tangential_complex {
// Don't export infinite cells
if (!export_infinite_simplices && is_infinite(c)) continue;
+ if (static_cast<int>(c.size()) > max_dim) max_dim = static_cast<int>(c.size());
+ // Add the missing center vertex
+ c.insert(idx);
+
if (!export_inconsistent_simplices && !is_simplex_consistent(c)) continue;
// Unusual simplex dim?
@@ -701,10 +710,6 @@ class Tangential_complex {
check_lower_and_higher_dim_simplices = 1;
}
- if (static_cast<int>(c.size()) > max_dim) max_dim = static_cast<int>(c.size());
- // Add the missing center vertex
- c.insert(idx);
-
// Try to insert the simplex
bool added = complex.add_simplex(c, check_lower_and_higher_dim_simplices == 1);
@@ -800,7 +805,7 @@ class Tangential_complex {
tbb::parallel_for(tbb::blocked_range<size_t>(0, m_points.size()), Compute_tangent_triangulation(*this));
} else {
#endif // GUDHI_USE_TBB
- // Sequential
+ // Sequential
for (std::size_t i = 0; i < m_points.size(); ++i) compute_tangent_triangulation(i);
#ifdef GUDHI_USE_TBB
}
@@ -835,7 +840,7 @@ class Tangential_complex {
Refresh_tangent_triangulation(*this, updated_pts_ds));
} else {
#endif // GUDHI_USE_TBB
- // Sequential
+ // Sequential
for (std::size_t i = 0; i < m_points.size(); ++i) refresh_tangent_triangulation(i, updated_pts_ds);
#ifdef GUDHI_USE_TBB
}
@@ -983,10 +988,9 @@ class Tangential_complex {
// of the sphere "star sphere" centered at "center_vertex"
// and which contains all the
// circumspheres of the star of "center_vertex"
- boost::optional<FT> squared_star_sphere_radius_plus_margin = boost::make_optional(false, FT());
- // This is the strange way boost is recommending to get rid of "may be used uninitialized in this function".
- // Former code was :
- // boost::optional<FT> squared_star_sphere_radius_plus_margin;
+ // If th the m_max_squared_edge_length is set the maximal radius of the "star sphere"
+ // is at most square root of m_max_squared_edge_length
+ boost::optional<FT> squared_star_sphere_radius_plus_margin = m_max_squared_edge_length;
// Insert points until we find a point which is outside "star sphere"
for (auto nn_it = ins_range.begin(); nn_it != ins_range.end(); ++nn_it) {
@@ -999,10 +1003,16 @@ class Tangential_complex {
Point neighbor_pt;
FT neighbor_weight;
compute_perturbed_weighted_point(neighbor_point_idx, neighbor_pt, neighbor_weight);
-
+ GUDHI_CHECK(!m_max_squared_edge_length ||
+ squared_star_sphere_radius_plus_margin.value() <= m_max_squared_edge_length.value(),
+ std::invalid_argument("Tangential_complex::compute_star - set a bigger value with set_max_squared_edge_length."));
if (squared_star_sphere_radius_plus_margin &&
- k_sqdist(center_pt, neighbor_pt) > *squared_star_sphere_radius_plus_margin)
+ k_sqdist(center_pt, neighbor_pt) > squared_star_sphere_radius_plus_margin.value()) {
+ GUDHI_CHECK(triangulation.current_dimension() >= tangent_space_dim,
+ std::invalid_argument("Tangential_complex::compute_star - Dimension of the star is only " + \
+ std::to_string(triangulation.current_dimension())));
break;
+ }
Tr_point proj_pt = project_point_and_compute_weight(neighbor_pt, neighbor_weight, tsb, local_tr_traits);
@@ -1044,7 +1054,7 @@ class Tangential_complex {
FT sq_power_sphere_diam = 4 * point_weight(c);
if (!squared_star_sphere_radius_plus_margin ||
- sq_power_sphere_diam > *squared_star_sphere_radius_plus_margin) {
+ sq_power_sphere_diam > squared_star_sphere_radius_plus_margin.value()) {
squared_star_sphere_radius_plus_margin = sq_power_sphere_diam;
}
}
@@ -1055,12 +1065,22 @@ class Tangential_complex {
if (squared_star_sphere_radius_plus_margin) {
// "2*m_last_max_perturb" because both points can be perturbed
squared_star_sphere_radius_plus_margin =
- CGAL::square(std::sqrt(*squared_star_sphere_radius_plus_margin) + 2 * m_last_max_perturb);
+ CGAL::square(std::sqrt(squared_star_sphere_radius_plus_margin.value()) + 2 * m_last_max_perturb);
+
+ // Reduce the square radius to m_max_squared_edge_length if necessary
+ if (m_max_squared_edge_length && squared_star_sphere_radius_plus_margin.value() > m_max_squared_edge_length.value()) {
+ squared_star_sphere_radius_plus_margin = m_max_squared_edge_length.value();
+ }
// Save it in `m_squared_star_spheres_radii_incl_margin`
- m_squared_star_spheres_radii_incl_margin[i] = *squared_star_sphere_radius_plus_margin;
+ m_squared_star_spheres_radii_incl_margin[i] = squared_star_sphere_radius_plus_margin.value();
} else {
- m_squared_star_spheres_radii_incl_margin[i] = FT(-1);
+ if (m_max_squared_edge_length) {
+ squared_star_sphere_radius_plus_margin = m_max_squared_edge_length.value();
+ m_squared_star_spheres_radii_incl_margin[i] = m_max_squared_edge_length.value();
+ } else {
+ m_squared_star_spheres_radii_incl_margin[i] = FT(-1);
+ }
}
}
}
@@ -1968,6 +1988,15 @@ class Tangential_complex {
return os;
}
+ /** \brief Sets the maximal possible squared edge length for the edges in the triangulations.
+ *
+ * @param[in] max_squared_edge_length Maximal possible squared edge length.
+ *
+ * If the maximal edge length value is too low `Tangential_complex::compute_tangential_complex` will throw an
+ * exception in debug mode.
+ */
+ void set_max_squared_edge_length(FT max_squared_edge_length) { m_max_squared_edge_length = max_squared_edge_length; }
+
private:
const K m_k;
const int m_intrinsic_dim;
@@ -1993,6 +2022,7 @@ class Tangential_complex {
// and their center vertex
Stars_container m_stars;
std::vector<FT> m_squared_star_spheres_radii_incl_margin;
+ boost::optional<FT> m_max_squared_edge_length;
#ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
Points m_points_for_tse;
diff --git a/src/Tangential_complex/test/test_tangential_complex.cpp b/src/Tangential_complex/test/test_tangential_complex.cpp
index 4e2d4f65..103b8b30 100644
--- a/src/Tangential_complex/test/test_tangential_complex.cpp
+++ b/src/Tangential_complex/test/test_tangential_complex.cpp
@@ -126,3 +126,33 @@ BOOST_AUTO_TEST_CASE(test_mini_tangential) {
BOOST_CHECK(stree.num_vertices() == 4);
BOOST_CHECK(stree.num_simplices() == 6);
}
+
+#ifdef GUDHI_DEBUG
+BOOST_AUTO_TEST_CASE(test_basic_example_throw) {
+ typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> Kernel;
+ typedef Kernel::FT FT;
+ typedef Kernel::Point_d Point;
+ typedef Kernel::Vector_d Vector;
+ typedef tc::Tangential_complex<Kernel, CGAL::Dynamic_dimension_tag,CGAL::Parallel_tag> TC;
+
+ const int INTRINSIC_DIM = 2;
+ const int AMBIENT_DIM = 3;
+ const int NUM_POINTS = 1000;
+
+ Kernel k;
+
+ // Generate points on a 2-sphere
+ CGAL::Random_points_on_sphere_d<Point> generator(AMBIENT_DIM, 3.);
+ std::vector<Point> points;
+ points.reserve(NUM_POINTS);
+ for (int i = 0; i < NUM_POINTS; ++i)
+ points.push_back(*generator++);
+
+ // Compute the TC
+ TC tc(points, INTRINSIC_DIM, k);
+ tc.set_max_squared_edge_length(0.01);
+ std::cout << "test_basic_example_throw - set_max_squared_edge_length(0.01) to make GUDHI_CHECK fail" << std::endl;
+ BOOST_CHECK_THROW(tc.compute_tangential_complex(), std::invalid_argument);
+
+}
+#endif
diff --git a/src/cmake/modules/GUDHI_third_party_libraries.cmake b/src/cmake/modules/GUDHI_third_party_libraries.cmake
index b020ebfc..57ea7d14 100644
--- a/src/cmake/modules/GUDHI_third_party_libraries.cmake
+++ b/src/cmake/modules/GUDHI_third_party_libraries.cmake
@@ -1,6 +1,6 @@
# This files manage third party libraries required by GUDHI
-find_package(Boost 1.48.0 REQUIRED COMPONENTS system filesystem unit_test_framework program_options thread)
+find_package(Boost 1.56.0 REQUIRED COMPONENTS system filesystem unit_test_framework program_options thread)
if(NOT Boost_FOUND)
message(FATAL_ERROR "NOTICE: This program requires Boost and will not be compiled.")
@@ -148,27 +148,26 @@ if( PYTHONINTERP_FOUND )
find_python_module("matplotlib")
find_python_module("numpy")
find_python_module("scipy")
+ find_python_module("sphinx")
endif()
if(NOT GUDHI_CYTHON_PATH)
message(FATAL_ERROR "ERROR: GUDHI_CYTHON_PATH is not valid.")
endif(NOT GUDHI_CYTHON_PATH)
+option(WITH_GUDHI_CYTHON_RUNTIME_LIBRARY_DIRS "Build with setting runtime_library_dirs. Usefull when setting rpath is not allowed" ON)
+
if(PYTHONINTERP_FOUND AND CYTHON_FOUND)
- # Default found version 2
- if(PYTHON_VERSION_MAJOR EQUAL 2)
+ if(SPHINX_FOUND)
# Documentation generation is available through sphinx
find_program( SPHINX_PATH sphinx-build )
- elseif(PYTHON_VERSION_MAJOR EQUAL 3)
- # No sphinx-build in Pyton3, just hack it
- set(SPHINX_PATH "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/${GUDHI_CYTHON_PATH}/doc/python3-sphinx-build.py")
- else()
- message(FATAL_ERROR "ERROR: Try to compile the Cython interface. Python version ${PYTHON_VERSION_STRING} is not valid.")
- endif(PYTHON_VERSION_MAJOR EQUAL 2)
- # get PYTHON_SITE_PACKAGES relative path from a python command line
- execute_process(
- COMMAND "${PYTHON_EXECUTABLE}" -c "from distutils.sysconfig import get_python_lib; print (get_python_lib(prefix='', plat_specific=True))"
- OUTPUT_VARIABLE PYTHON_SITE_PACKAGES
- OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if(NOT SPHINX_PATH)
+ if(PYTHON_VERSION_MAJOR EQUAL 3)
+ # In Python3, just hack sphinx-build if it does not exist
+ set(SPHINX_PATH "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/${GUDHI_CYTHON_PATH}/doc/python3-sphinx-build.py")
+ endif(PYTHON_VERSION_MAJOR EQUAL 3)
+ endif(NOT SPHINX_PATH)
+ endif(SPHINX_FOUND)
endif(PYTHONINTERP_FOUND AND CYTHON_FOUND)
diff --git a/src/cmake/modules/GUDHI_user_version_target.cmake b/src/cmake/modules/GUDHI_user_version_target.cmake
index d43a6fa6..2ed48c48 100644
--- a/src/cmake/modules/GUDHI_user_version_target.cmake
+++ b/src/cmake/modules/GUDHI_user_version_target.cmake
@@ -27,7 +27,7 @@ add_custom_command(TARGET user_version PRE_BUILD COMMAND ${CMAKE_COMMAND} -E
add_custom_command(TARGET user_version PRE_BUILD COMMAND ${CMAKE_COMMAND} -E
copy ${CMAKE_SOURCE_DIR}/Conventions.txt ${GUDHI_USER_VERSION_DIR}/Conventions.txt)
add_custom_command(TARGET user_version PRE_BUILD COMMAND ${CMAKE_COMMAND} -E
- copy ${CMAKE_SOURCE_DIR}/README ${GUDHI_USER_VERSION_DIR}/README)
+ copy ${CMAKE_SOURCE_DIR}/README.md ${GUDHI_USER_VERSION_DIR}/README.md)
add_custom_command(TARGET user_version PRE_BUILD COMMAND ${CMAKE_COMMAND} -E
copy ${CMAKE_SOURCE_DIR}/COPYING ${GUDHI_USER_VERSION_DIR}/COPYING)
add_custom_command(TARGET user_version PRE_BUILD COMMAND ${CMAKE_COMMAND} -E
diff --git a/src/common/benchmark/CMakeLists.txt b/src/common/benchmark/CMakeLists.txt
new file mode 100644
index 00000000..a3787d6e
--- /dev/null
+++ b/src/common/benchmark/CMakeLists.txt
@@ -0,0 +1,3 @@
+project(common_benchmark)
+
+add_executable(Graph_simplicial_complex_benchmark Graph_simplicial_complex_benchmark.cpp)
diff --git a/src/common/benchmark/Graph_simplicial_complex_benchmark.cpp b/src/common/benchmark/Graph_simplicial_complex_benchmark.cpp
new file mode 100644
index 00000000..825d6cb5
--- /dev/null
+++ b/src/common/benchmark/Graph_simplicial_complex_benchmark.cpp
@@ -0,0 +1,150 @@
+/* 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) 2018 Inria
+ *
+ * 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/distance_functions.h>
+#include <gudhi/Simplex_tree.h>
+#include <gudhi/Clock.h>
+#include <gudhi/Points_off_io.h>
+
+#include <boost/graph/adjacency_list.hpp>
+
+#include <iostream>
+#include <string>
+#include <vector>
+#include <limits> // for numeric limits
+#include <fstream>
+#include <cassert>
+
+
+std::ofstream results_csv("results.csv");
+
+template< typename Adjacency_list, typename ForwardPointRange, typename Distance >
+Adjacency_list proximity_graph_computation(const ForwardPointRange& points, double threshold, Distance distance) {
+ std::vector<std::pair< int, int >> edges;
+ std::vector< double > edges_fil;
+ std::map< int, double > vertices;
+
+ int idx_u, idx_v;
+ double 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);
+ edges_fil.push_back(fil);
+ }
+ }
+ ++idx_u;
+ }
+
+ // Points are labeled from 0 to idx_u-1
+ Adjacency_list skel_graph(edges.begin(), edges.end(), edges_fil.begin(), idx_u);
+
+ auto vertex_prop = boost::get(Gudhi::vertex_filtration_t(), skel_graph);
+
+ typename boost::graph_traits<Adjacency_list>::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.);
+ }
+
+ return skel_graph;
+}
+
+template <typename Adjacency_list>
+void benchmark_proximity_graph(const std::string& msg, const std::string& off_file_name) {
+ Gudhi::Points_off_reader<std::vector<double>> off_reader(off_file_name);
+ assert(off_reader.is_valid());
+
+ std::cout << "+ " << msg << std::endl;
+
+ results_csv << "\"nb_points\";"
+ << "\"nb_simplices\";"
+ << "\"compute proximity graph(sec.)\";"
+ << "\"complex_creation_time(sec.)\";"
+ << "\"" << msg << "\";" << std::endl;
+
+ Gudhi::Clock pg_compute_proximity_graph(" benchmark_proximity_graph - compute proximity graph");
+ pg_compute_proximity_graph.begin();
+ // benchmark begin
+ Adjacency_list proximity_graph = proximity_graph_computation<Adjacency_list>(off_reader.get_point_cloud(),
+ std::numeric_limits<double>::infinity(),
+ Gudhi::Euclidean_distance());
+ // benchmark end
+ pg_compute_proximity_graph.end();
+ std::cout << pg_compute_proximity_graph;
+
+ Gudhi::Simplex_tree<> complex;
+ Gudhi::Clock st_create_clock(" benchmark_proximity_graph - complex creation");
+ st_create_clock.begin();
+ // benchmark begin
+ complex.insert_graph(proximity_graph);
+ // benchmark end
+ st_create_clock.end();
+ std::cout << st_create_clock;
+
+ results_csv << off_reader.get_point_cloud().size() << ";" << complex.num_simplices() << ";"
+ << pg_compute_proximity_graph.num_seconds() << ";"
+ << st_create_clock.num_seconds() << ";" << std::endl;
+
+ std::cout << " benchmark_proximity_graph - nb simplices = " << complex.num_simplices() << std::endl;
+}
+
+int main(int argc, char * const argv[]) {
+ std::string off_file_name(argv[1]);
+
+ // The fastest, the less memory used
+ using vecSdirectedS = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS,
+ boost::property<Gudhi::vertex_filtration_t, double>,
+ boost::property<Gudhi::edge_filtration_t, double>>;
+ benchmark_proximity_graph<vecSdirectedS>("vecSdirectedS", off_file_name);
+
+ using vecSundirectedS = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS,
+ boost::property<Gudhi::vertex_filtration_t, double>,
+ boost::property<Gudhi::edge_filtration_t, double>>;
+ benchmark_proximity_graph<vecSundirectedS>("vecSundirectedS", off_file_name);
+
+ using vecSbidirectionalS = boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS,
+ boost::property<Gudhi::vertex_filtration_t, double>,
+ boost::property<Gudhi::edge_filtration_t, double>>;
+ benchmark_proximity_graph<vecSbidirectionalS>("vecSbidirectionalS", off_file_name);
+
+ using setSdirectedS = boost::adjacency_list<boost::setS, boost::vecS, boost::directedS,
+ boost::property<Gudhi::vertex_filtration_t, double>,
+ boost::property<Gudhi::edge_filtration_t, double>>;
+ benchmark_proximity_graph<setSdirectedS>("setSdirectedS", off_file_name);
+
+ using setSundirectedS = boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS,
+ boost::property<Gudhi::vertex_filtration_t, double>,
+ boost::property<Gudhi::edge_filtration_t, double>>;
+ benchmark_proximity_graph<setSundirectedS>("setSundirectedS", off_file_name);
+
+ using setSbidirectionalS = boost::adjacency_list<boost::setS, boost::vecS, boost::bidirectionalS,
+ boost::property<Gudhi::vertex_filtration_t, double>,
+ boost::property<Gudhi::edge_filtration_t, double>>;
+ benchmark_proximity_graph<setSbidirectionalS>("setSbidirectionalS", off_file_name);
+
+ return 0;
+}
diff --git a/src/common/doc/examples.h b/src/common/doc/examples.h
index 40f202c7..c19b3444 100644
--- a/src/common/doc/examples.h
+++ b/src/common/doc/examples.h
@@ -53,10 +53,7 @@
* @example Spatial_searching/example_spatial_searching.cpp
* @example Alpha_complex/alpha_complex_3d_persistence.cpp
* @example Alpha_complex/alpha_complex_persistence.cpp
- * @example Alpha_complex/weighted_periodic_alpha_complex_3d_persistence.cpp
- * @example Alpha_complex/weighted_alpha_complex_3d_persistence.cpp
- * @example Alpha_complex/periodic_alpha_complex_3d_persistence.cpp
- * @example Alpha_complex/exact_alpha_complex_3d_persistence.cpp
+ * @example Alpha_complex/Weighted_alpha_complex_3d_from_points.cpp
* @example Bottleneck_distance/bottleneck_distance.cpp
* @example Witness_complex/weak_witness_persistence.cpp
* @example Witness_complex/strong_witness_persistence.cpp
diff --git a/src/common/doc/file_formats.h b/src/common/doc/file_formats.h
index 523153b8..23214e25 100644
--- a/src/common/doc/file_formats.h
+++ b/src/common/doc/file_formats.h
@@ -72,7 +72,7 @@ namespace Gudhi {
\section FileFormatsPerseus Perseus
- This file format is the format used by the Perseus software
+ This file format is a format inspired from the Perseus software
(http://www.sas.upenn.edu/~vnanda/perseus/) by Vidit Nanda.
The first line contains a number d begin the dimension of the
bitmap (2 in the example below). Next d lines are the numbers of top dimensional cubes in each dimensions (3 and 3
@@ -118,6 +118,10 @@ namespace Gudhi {
Indicate that we have imposed periodic boundary conditions in the direction x, but not in the direction y.
Other sample files can be found in the `data/bitmap` folder.
+
+ \note Unlike in Perseus format the filtration on the maximal cubes can be any double precision number.
+ Consequently one cannot mark the cubes that are not present with `-1`'s. To do that please set their filtration value
+ to \f$+\infty\f$ (aka. `inf` in the file).
*/
} // namespace Gudhi
diff --git a/src/common/doc/installation.h b/src/common/doc/installation.h
index df7eed37..8fb8b330 100644
--- a/src/common/doc/installation.h
+++ b/src/common/doc/installation.h
@@ -5,7 +5,7 @@
* Examples of GUDHI headers inclusion can be found in \ref utilities.
*
* \section compiling Compiling
- * The library uses c++11 and requires <a target="_blank" href="http://www.boost.org/">Boost</a> &ge; 1.48.0
+ * The library uses c++11 and requires <a target="_blank" href="http://www.boost.org/">Boost</a> &ge; 1.56.0
* and <a target="_blank" href="https://www.cmake.org/">CMake</a> &ge; 3.1.
* It is a multi-platform library and compiles on Linux, Mac OSX and Visual Studio 2015.
*
@@ -72,12 +72,6 @@ make doxygen
*
* The following examples/utilities require the <a target="_blank" href="http://www.cgal.org/">Computational Geometry Algorithms
* Library</a> (CGAL \cite cgal:eb-15b) and will not be built if CGAL is not installed:
- * \li <a href="_alpha_complex_2alpha_complex_3d_persistence_8cpp-example.html">
- * Alpha_complex/alpha_complex_3d_persistence.cpp</a>
- * \li <a href="_alpha_complex_2exact_alpha_complex_3d_persistence_8cpp-example.html">
- * Alpha_complex/exact_alpha_complex_3d_persistence.cpp</a>
- * \li <a href="_alpha_complex_2weighted_alpha_complex_3d_persistence_8cpp-example.html">
- * Alpha_complex/weighted_alpha_complex_3d_persistence.cpp</a>
* \li <a href="_simplex_tree_2example_alpha_shapes_3_simplex_tree_from_off_file_8cpp-example.html">
* Simplex_tree/example_alpha_shapes_3_simplex_tree_from_off_file.cpp</a>
*
@@ -100,8 +94,6 @@ make doxygen
* Alpha_complex/Alpha_complex_from_points.cpp</a>
* \li <a href="_alpha_complex_2alpha_complex_persistence_8cpp-example.html">
* Alpha_complex/alpha_complex_persistence.cpp</a>
- * \li <a href="_alpha_complex_2periodic_alpha_complex_3d_persistence_8cpp-example.html">
- * Alpha_complex/periodic_alpha_complex_3d_persistence.cpp</a>
* \li <a href="_persistent_cohomology_2custom_persistence_sort_8cpp-example.html">
* Persistent_cohomology/custom_persistence_sort.cpp</a>
*
@@ -135,6 +127,12 @@ make doxygen
* \li <a href="_tangential_complex_2example_with_perturb_8cpp-example.html">
* Tangential_complex/example_with_perturb.cpp</a>
*
+ * The following example requires CGAL version &ge; 4.11.0:
+ * \li <a href="_alpha_complex_2_weighted_alpha_complex_3d_from_points_8cpp-example.html">
+ * Alpha_complex/Weighted_alpha_complex_3d_from_points.cpp</a>
+ * \li <a href="_alpha_complex_2alpha_complex_3d_persistence_8cpp-example.html">
+ * Alpha_complex/alpha_complex_3d_persistence.cpp</a>
+ *
* \subsection eigen3 Eigen3
* The \ref alpha_complex data structure and few examples requires
* <a target="_blank" href="http://eigen.tuxfamily.org/">Eigen3</a> is a C++ template library for linear algebra:
@@ -148,8 +146,10 @@ make doxygen
* Alpha_complex/Alpha_complex_from_points.cpp</a>
* \li <a href="_alpha_complex_2alpha_complex_persistence_8cpp-example.html">
* Alpha_complex/alpha_complex_persistence.cpp</a>
- * \li <a href="_alpha_complex_2periodic_alpha_complex_3d_persistence_8cpp-example.html">
- * Alpha_complex/periodic_alpha_complex_3d_persistence.cpp</a>
+ * \li <a href="_alpha_complex_2alpha_complex_3d_persistence_8cpp-example.html">
+ * Alpha_complex/alpha_complex_3d_persistence.cpp</a>
+ * \li <a href="_alpha_complex_2_weighted_alpha_complex_3d_from_points_8cpp-example.html">
+ * Alpha_complex/Weighted_alpha_complex_3d_from_points.cpp</a>
* \li <a href="_bottleneck_distance_2alpha_rips_persistence_bottleneck_distance_8cpp-example.html">
* Bottleneck_distance/alpha_rips_persistence_bottleneck_distance.cpp.cpp</a>
* \li <a href="_persistent_cohomology_2custom_persistence_sort_8cpp-example.html">
@@ -195,12 +195,6 @@ make doxygen
* Alpha_complex/alpha_complex_3d_persistence.cpp</a>
* \li <a href="_alpha_complex_2alpha_complex_persistence_8cpp-example.html">
* Alpha_complex/alpha_complex_persistence.cpp</a>
- * \li <a href="_alpha_complex_2exact_alpha_complex_3d_persistence_8cpp-example.html">
- * Alpha_complex/exact_alpha_complex_3d_persistence.cpp</a>
- * \li <a href="_alpha_complex_2periodic_alpha_complex_3d_persistence_8cpp-example.html">
- * Alpha_complex/periodic_alpha_complex_3d_persistence.cpp</a>
- * \li <a href="_alpha_complex_2weighted_alpha_complex_3d_persistence_8cpp-example.html">
- * Alpha_complex/weighted_alpha_complex_3d_persistence.cpp</a>
* \li <a href="_bitmap_cubical_complex_2_bitmap_cubical_complex_8cpp-example.html">
* Bitmap_cubical_complex/cubical_complex_persistence.cpp</a>
* \li <a href="_bitmap_cubical_complex_2_bitmap_cubical_complex_periodic_boundary_conditions_8cpp-example.html">
@@ -239,10 +233,6 @@ make doxygen
* Persistent_cohomology/rips_multifield_persistence.cpp</a>
* \li <a href="_persistent_cohomology_2rips_persistence_step_by_step_8cpp-example.html">
* Persistent_cohomology/rips_persistence_step_by_step.cpp</a>
- * \li <a href="_persistent_cohomology_2exact_alpha_complex_3d_persistence_8cpp-example.html">
- * Persistent_cohomology/exact_alpha_complex_3d_persistence.cpp</a>
- * \li <a href="_persistent_cohomology_2weighted_alpha_complex_3d_persistence_8cpp-example.html">
- * Persistent_cohomology/weighted_alpha_complex_3d_persistence.cpp</a>
* \li <a href="_persistent_cohomology_2custom_persistence_sort_8cpp-example.html">
* Persistent_cohomology/custom_persistence_sort.cpp</a>
* \li <a href="_rips_complex_2example_one_skeleton_rips_from_points_8cpp-example.html">
diff --git a/src/common/doc/main_page.h b/src/common/doc/main_page.h
index 5ccb648f..afe9b68c 100644
--- a/src/common/doc/main_page.h
+++ b/src/common/doc/main_page.h
@@ -29,7 +29,9 @@
<b>Author:</b> Vincent Rouvreau<br>
<b>Introduced in:</b> GUDHI 1.3.0<br>
<b>Copyright:</b> GPL v3<br>
- <b>Requires:</b> \ref cgal &ge; 4.7.0 and \ref eigen3
+ <b>Requires:</b> \ref eigen3 and<br>
+ \ref cgal &ge; 4.7.0 for Alpha_complex<br>
+ \ref cgal &ge; 4.11.0 for Alpha_complex_3d
</td>
<td width="75%">
Alpha_complex is a simplicial complex constructed from the finite cells of a Delaunay Triangulation.<br>
@@ -38,7 +40,8 @@
values of the codimension 1 cofaces that make it not Gabriel otherwise.
All simplices that have a filtration value strictly greater than a given alpha squared value are not inserted into
the complex.<br>
- <b>User manual:</b> \ref alpha_complex - <b>Reference manual:</b> Gudhi::alpha_complex::Alpha_complex
+ <b>User manual:</b> \ref alpha_complex - <b>Reference manual:</b> Gudhi::alpha_complex::Alpha_complex and
+ Gudhi::alpha_complex::Alpha_complex_3d
</td>
</tr>
</table>
diff --git a/src/common/include/gudhi/Unitary_tests_utils.h b/src/common/include/gudhi/Unitary_tests_utils.h
index e07c8d42..22f00212 100644
--- a/src/common/include/gudhi/Unitary_tests_utils.h
+++ b/src/common/include/gudhi/Unitary_tests_utils.h
@@ -34,7 +34,7 @@ void GUDHI_TEST_FLOAT_EQUALITY_CHECK(FloatingType a, FloatingType b,
std::cout << "GUDHI_TEST_FLOAT_EQUALITY_CHECK - " << a << " versus " << b
<< " | diff = " << std::fabs(a - b) << " - epsilon = " << epsilon << std::endl;
#endif
- BOOST_CHECK(std::fabs(a - b) < epsilon);
+ BOOST_CHECK(std::fabs(a - b) <= epsilon);
}
#endif // UNITARY_TESTS_UTILS_H_
diff --git a/src/common/include/gudhi/graph_simplicial_complex.h b/src/common/include/gudhi/graph_simplicial_complex.h
index 49fe56cc..0d81ca71 100644
--- a/src/common/include/gudhi/graph_simplicial_complex.h
+++ b/src/common/include/gudhi/graph_simplicial_complex.h
@@ -49,7 +49,7 @@ struct vertex_filtration_t {
*
*/
template <typename SimplicialComplexForProximityGraph>
-using Proximity_graph = typename boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS
+using Proximity_graph = typename boost::adjacency_list < boost::vecS, boost::vecS, boost::directedS
, boost::property < vertex_filtration_t, typename SimplicialComplexForProximityGraph::Filtration_value >
, boost::property < edge_filtration_t, typename SimplicialComplexForProximityGraph::Filtration_value >>;
diff --git a/src/common/include/gudhi/reader_utils.h b/src/common/include/gudhi/reader_utils.h
index 26eeb76d..0ee7649d 100644
--- a/src/common/include/gudhi/reader_utils.h
+++ b/src/common/include/gudhi/reader_utils.h
@@ -172,10 +172,10 @@ bool read_simplex(std::istream& in_, std::vector<Vertex_handle>& simplex, Filtra
if (!(in_ >> dim)) return false;
Vertex_handle v;
for (int i = 0; i < dim + 1; ++i) {
- in_ >> v;
+ if (!(in_ >> v)) return false;
simplex.push_back(v);
}
- in_ >> fil;
+ if (!(in_ >> fil)) return false;
in_.ignore((std::numeric_limits<std::streamsize>::max)(), '\n'); // ignore until the carriage return
return true;
}
diff --git a/src/cython/CMakeLists.txt b/src/cython/CMakeLists.txt
index dc2e9278..480332d7 100644
--- a/src/cython/CMakeLists.txt
+++ b/src/cython/CMakeLists.txt
@@ -198,9 +198,9 @@ if(PYTHONINTERP_FOUND)
set(GUDHI_CYTHON_INCLUDE_DIRS "${GUDHI_CYTHON_INCLUDE_DIRS}'${TBB_INCLUDE_DIRS}', ")
endif()
- if(UNIX)
+ if(UNIX AND WITH_GUDHI_CYTHON_RUNTIME_LIBRARY_DIRS)
set( GUDHI_CYTHON_RUNTIME_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}")
- endif(UNIX)
+ endif(UNIX AND WITH_GUDHI_CYTHON_RUNTIME_LIBRARY_DIRS)
# Generate setup.py file to cythonize Gudhi - This file must be named setup.py by convention
configure_file(setup.py.in "${CMAKE_CURRENT_BINARY_DIR}/setup.py" @ONLY)
@@ -215,12 +215,7 @@ if(PYTHONINTERP_FOUND)
add_custom_target(cython ALL DEPENDS gudhi.so
COMMENT "Do not forget to add ${CMAKE_CURRENT_BINARY_DIR}/ to your PYTHONPATH before using examples or tests")
- # For installation purpose
- # TODO(VR) : files matching pattern mechanism is copying all cython directory
- install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" DESTINATION "${PYTHON_SITE_PACKAGES}/" FILES_MATCHING
- PATTERN "*.so"
- PATTERN "*.dylib"
- PATTERN "*.pyd")
+ install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/setup.py install)")
# Test examples
if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1)
diff --git a/src/cython/cython/rips_complex.pyx b/src/cython/cython/rips_complex.pyx
index 30ca4443..7c83241c 100644
--- a/src/cython/cython/rips_complex.pyx
+++ b/src/cython/cython/rips_complex.pyx
@@ -33,7 +33,11 @@ __license__ = "GPL v3"
cdef extern from "Rips_complex_interface.h" namespace "Gudhi":
cdef cppclass Rips_complex_interface "Gudhi::rips_complex::Rips_complex_interface":
- Rips_complex_interface(vector[vector[double]] values, double threshold, bool euclidean)
+ Rips_complex_interface()
+ void init_points(vector[vector[double]] values, double threshold)
+ void init_matrix(vector[vector[double]] values, double threshold)
+ void init_points_sparse(vector[vector[double]] values, double threshold, double sparse)
+ void init_matrix_sparse(vector[vector[double]] values, double threshold, double sparse)
void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, int dim_max)
# RipsComplex python interface
@@ -44,10 +48,11 @@ cdef class RipsComplex:
function, or a distance matrix.
"""
- cdef Rips_complex_interface * thisptr
+ cdef Rips_complex_interface thisref
# Fake constructor that does nothing but documenting the constructor
- def __init__(self, points=None, distance_matrix=None, max_edge_length=float('inf')):
+ def __init__(self, points=None, distance_matrix=None,
+ max_edge_length=float('inf'), sparse=None):
"""RipsComplex constructor.
:param max_edge_length: Rips value.
@@ -59,29 +64,38 @@ cdef class RipsComplex:
Or
:param distance_matrix: A distance matrix (full square or lower
- triangular).
+ triangular).
:type points: list of list of double
+
+ And in both cases
+
+ :param sparse: If this is not None, it switches to building a sparse
+ Rips and represents the approximation parameter epsilon.
+ :type sparse: float
"""
# The real cython constructor
- def __cinit__(self, points=None, distance_matrix=None, max_edge_length=float('inf')):
- if distance_matrix is not None:
- self.thisptr = new Rips_complex_interface(distance_matrix, max_edge_length, False)
+ def __cinit__(self, points=None, distance_matrix=None,
+ max_edge_length=float('inf'), sparse=None):
+ if sparse is not None:
+ if distance_matrix is not None:
+ self.thisref.init_matrix_sparse(distance_matrix,
+ max_edge_length,
+ sparse)
+ else:
+ if points is None:
+ # Empty Rips construction
+ points=[]
+ self.thisref.init_points_sparse(points, max_edge_length, sparse)
else:
- if points is None:
- # Empty Rips construction
- points=[]
- self.thisptr = new Rips_complex_interface(points, max_edge_length, True)
-
-
- def __dealloc__(self):
- if self.thisptr != NULL:
- del self.thisptr
+ if distance_matrix is not None:
+ self.thisref.init_matrix(distance_matrix, max_edge_length)
+ else:
+ if points is None:
+ # Empty Rips construction
+ points=[]
+ self.thisref.init_points(points, max_edge_length)
- def __is_defined(self):
- """Returns true if RipsComplex pointer is not NULL.
- """
- return self.thisptr != NULL
def create_simplex_tree(self, max_dimension=1):
"""
@@ -92,5 +106,5 @@ cdef class RipsComplex:
:rtype: SimplexTree
"""
simplex_tree = SimplexTree()
- self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_dimension)
+ self.thisref.create_simplex_tree(simplex_tree.thisptr, max_dimension)
return simplex_tree
diff --git a/src/cython/cython/simplex_tree.pyx b/src/cython/cython/simplex_tree.pyx
index 8397d9d9..0ab97f80 100644
--- a/src/cython/cython/simplex_tree.pyx
+++ b/src/cython/cython/simplex_tree.pyx
@@ -44,8 +44,8 @@ cdef extern from "Simplex_tree_interface.h" namespace "Gudhi":
void set_dimension(int dimension)
int dimension()
int upper_bound_dimension()
- bint find_simplex(vector[int] simplex)
- bint insert_simplex_and_subfaces(vector[int] simplex,
+ bool find_simplex(vector[int] simplex)
+ bool insert_simplex_and_subfaces(vector[int] simplex,
double filtration)
vector[pair[vector[int], double]] get_filtration()
vector[pair[vector[int], double]] get_skeleton(int dimension)
@@ -355,7 +355,7 @@ cdef class SimplexTree:
:param filtration: Maximum threshold value.
:type filtration: float.
:returns: The filtration modification information.
- :rtype: bint
+ :rtype: bool
.. note::
@@ -406,7 +406,7 @@ cdef class SimplexTree:
value than its faces by increasing the filtration values.
:returns: The filtration modification information.
- :rtype: bint
+ :rtype: bool
.. note::
@@ -432,6 +432,10 @@ cdef class SimplexTree:
0.0.
Sets min_persistence to -1.0 to see all values.
:type min_persistence: float.
+ :param persistence_dim_max: If true, the persistent homology for the
+ maximal dimension in the complex is computed. If false, it is
+ ignored. Default is false.
+ :type persistence_dim_max: bool
:returns: The persistence of the simplicial complex.
:rtype: list of pairs(dimension, pair(birth, death))
"""
diff --git a/src/cython/cython/tangential_complex.pyx b/src/cython/cython/tangential_complex.pyx
index 4bb07076..293ef8cb 100644
--- a/src/cython/cython/tangential_complex.pyx
+++ b/src/cython/cython/tangential_complex.pyx
@@ -36,6 +36,7 @@ cdef extern from "Tangential_complex_interface.h" namespace "Gudhi":
Tangential_complex_interface(int intrisic_dim, vector[vector[double]] points)
# bool from_file is a workaround for cython to find the correct signature
Tangential_complex_interface(int intrisic_dim, string off_file, bool from_file)
+ void compute_tangential_complex() except +
vector[double] get_point(unsigned vertex)
unsigned number_of_vertices()
unsigned number_of_simplices()
@@ -43,6 +44,7 @@ cdef extern from "Tangential_complex_interface.h" namespace "Gudhi":
unsigned number_of_inconsistent_stars()
void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree)
void fix_inconsistencies_using_perturbation(double max_perturb, double time_limit)
+ void set_max_squared_edge_length(double max_squared_edge_length)
# TangentialComplex python interface
cdef class TangentialComplex:
@@ -92,6 +94,17 @@ cdef class TangentialComplex:
"""
return self.thisptr != NULL
+ def compute_tangential_complex(self):
+ """This function computes the tangential complex.
+
+ Raises:
+ ValueError: In debug mode, if the computed star dimension is too
+ low. Try to set a bigger maximal edge length value with
+ :func:`~gudhi.Tangential_complex.set_max_squared_edge_length`
+ if this happens.
+ """
+ self.thisptr.compute_tangential_complex()
+
def get_point(self, vertex):
"""This function returns the point corresponding to a given vertex.
@@ -152,3 +165,16 @@ cdef class TangentialComplex:
"""
self.thisptr.fix_inconsistencies_using_perturbation(max_perturb,
time_limit)
+
+ def set_max_squared_edge_length(self, max_squared_edge_length):
+ """Sets the maximal possible squared edge length for the edges in the
+ triangulations.
+
+ :param max_squared_edge_length: Maximal possible squared edge length.
+ :type max_squared_edge_length: double
+
+ If the maximal edge length value is too low
+ :func:`~gudhi.Tangential_complex.compute_tangential_complex`
+ will throw an exception in debug mode.
+ """
+ self.thisptr.set_max_squared_edge_length(max_squared_edge_length)
diff --git a/src/cython/doc/cubical_complex_user.rst b/src/cython/doc/cubical_complex_user.rst
index 320bd79b..19120360 100644
--- a/src/cython/doc/cubical_complex_user.rst
+++ b/src/cython/doc/cubical_complex_user.rst
@@ -83,9 +83,15 @@ Input Format.
In the current implantation, filtration is given at the maximal cubes, and it is then extended by the lower star
filtration to all cubes. There are a number of constructors that can be used to construct cubical complex by users
who want to use the code directly. They can be found in the :doc:`cubical_complex_ref`.
-Currently one input from a text file is used. It uses a format used already in
+Currently one input from a text file is used. It uses a format inspired from the Perseus software
`Perseus software <http://www.sas.upenn.edu/~vnanda/perseus/>`_ by Vidit Nanda.
-The file format is described here: :doc:`Perseus <fileformats>`.
+
+.. note::
+ While Perseus assume the filtration of all maximal cubes to be non-negative, over here we do not enforce this and
+ we allow any filtration values. As a consequence one cannot use ``-1``'s to indicate missing cubes. If you have
+ missing cubes in your complex, please set their filtration to :math:`+\infty` (aka. ``inf`` in the file).
+
+The file format is described in details in :ref:`Perseus file format` file format section.
.. testcode::
diff --git a/src/cython/doc/examples.rst b/src/cython/doc/examples.rst
index 1f02f8a2..edbc2f72 100644
--- a/src/cython/doc/examples.rst
+++ b/src/cython/doc/examples.rst
@@ -22,6 +22,7 @@ Examples
* :download:`rips_complex_diagram_persistence_from_off_file_example.py <../example/rips_complex_diagram_persistence_from_off_file_example.py>`
* :download:`rips_complex_diagram_persistence_from_distance_matrix_file_example.py <../example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py>`
* :download:`rips_persistence_diagram.py <../example/rips_persistence_diagram.py>`
+ * :download:`sparse_rips_persistence_diagram.py <../example/sparse_rips_persistence_diagram.py>`
* :download:`random_cubical_complex_persistence_example.py <../example/random_cubical_complex_persistence_example.py>`
* :download:`coordinate_graph_induced_complex.py <../example/coordinate_graph_induced_complex.py>`
* :download:`functional_graph_induced_complex.py <../example/functional_graph_induced_complex.py>`
diff --git a/src/cython/doc/fileformats.rst b/src/cython/doc/fileformats.rst
index ff20f26e..e205cc8b 100644
--- a/src/cython/doc/fileformats.rst
+++ b/src/cython/doc/fileformats.rst
@@ -51,10 +51,12 @@ Here is a simple sample file in the 3D case::
1. 1. 1.
+.. _Perseus file format:
+
Perseus
*******
-This file format is the format used by the
+This file format is a format inspired from the
`Perseus software <http://www.sas.upenn.edu/~vnanda/perseus/>`_ by Vidit Nanda.
The first line contains a number d begin the dimension of the bitmap (2 in the
example below). Next d lines are the numbers of top dimensional cubes in each
@@ -88,3 +90,9 @@ Indicate that we have imposed periodic boundary conditions in the direction x,
but not in the direction y.
Other sample files can be found in the `data/bitmap` folder.
+
+.. note::
+ Unlike in Perseus format the filtration on the maximal cubes can be any
+ double precision number. Consequently one cannot mark the cubes that are
+ not present with ``-1``'s. To do that please set their filtration value to
+ :math:`+\infty` (aka. ``inf`` in the file). \ No newline at end of file
diff --git a/src/cython/doc/installation.rst b/src/cython/doc/installation.rst
index ef2f7af2..855dea44 100644
--- a/src/cython/doc/installation.rst
+++ b/src/cython/doc/installation.rst
@@ -7,24 +7,23 @@ Installation
Compiling
*********
-The library uses c++11 and requires `Boost <https://www.boost.org/>`_ ≥ 1.48.0
-and `CMake <https://www.cmake.org/>`_ ≥ 3.1.
+The library uses c++11 and requires `Boost <https://www.boost.org/>`_ ≥ 1.56.0,
+`CMake <https://www.cmake.org/>`_ ≥ 3.1 to generate makefiles, and
+`Cython <https://www.cython.org/>`_ to compile the GUDHI Python module.
It is a multi-platform library and compiles on Linux, Mac OSX and Visual
Studio 2015.
-It also requires cmake to generate makefiles, and cython to compile the
-library.
On `Windows <https://wiki.python.org/moin/WindowsCompilers>`_ , only Python
3.5 and 3.6 are available because of the required Visual Studio version.
-On other systems, if you have several Python/cython installed, the version 2.X
+On other systems, if you have several Python/Cython installed, the version 2.X
will be used by default, but you can force it by adding
:code:`-DPython_ADDITIONAL_VERSIONS=3` to the cmake command.
-GUDHI Cythonization
-===================
+GUDHI Python module compilation
+===============================
-To build the GUDHI cython module, run the following commands in a terminal:
+To build the GUDHI Python module, run the following commands in a terminal:
.. code-block:: bash
@@ -32,7 +31,28 @@ To build the GUDHI cython module, run the following commands in a terminal:
mkdir build
cd build/
cmake ..
- make cython
+ cd cython
+ make
+
+GUDHI Python module installation
+================================
+
+Once the compilation succeeds, one can add the GUDHI Python module path to the
+PYTHONPATH:
+
+.. code-block:: bash
+
+ # For windows, you have to set PYTHONPATH environment variable
+ export PYTHONPATH='$PYTHONPATH:/path-to-gudhi/build/cython'
+
+Or install it definitely in your Python packages folder:
+
+.. code-block:: bash
+
+ cd /path-to-gudhi/build/cython
+ # May require sudo or administrator privileges
+ make install
+
Test suites
===========
@@ -45,7 +65,7 @@ following command in a terminal:
cd /path-to-gudhi/build/cython
# For windows, you have to set PYTHONPATH environment variable
export PYTHONPATH='$PYTHONPATH:/path-to-gudhi/build/cython'
- ctest -R py_test
+ make test
Debugging issues
================
@@ -54,7 +74,7 @@ If tests fail, please check your PYTHONPATH and try to :code:`import gudhi`
and check the errors.
The problem can come from a third-party library bad link or installation.
-If :code:`import gudhi` succeeds, please have a look to debug informations:
+If :code:`import gudhi` succeeds, please have a look to debug information:
.. code-block:: python
@@ -105,13 +125,17 @@ A complete configuration would be :
Documentation
=============
-To build the documentation, `sphinx-doc <http://http://www.sphinx-doc.org>`_ is
-required. Please refer to *conf.py* file to see which
-`sphinx-doc <http://http://www.sphinx-doc.org>`_ modules are required to
-generate the documentation. Run the following commands in a terminal:
+To build the documentation, `sphinx-doc <http://www.sphinx-doc.org>`_ and
+`sphinxcontrib-bibtex <https://sphinxcontrib-bibtex.readthedocs.io>`_ are
+required. As the documentation is auto-tested, `CGAL`_, `Eigen3`_,
+`Matplotlib`_, `NumPy`_ and `SciPy`_ are also mandatory to build the
+documentation.
+
+Run the following commands in a terminal:
.. code-block:: bash
+ cd /path-to-gudhi/build/cython
make sphinx
Optional third-party library
@@ -127,7 +151,7 @@ The :doc:`Alpha complex </alpha_complex_user>`,
C++ library which provides easy access to efficient and reliable geometric
algorithms.
-Having CGAL, the Computational Geometry Algorithms Library, version 4.7.0 or
+Having CGAL, the Computational Geometry Algorithms Library, version 4.7.0 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>`_.
diff --git a/src/cython/doc/nerve_gic_complex_ref.rst b/src/cython/doc/nerve_gic_complex_ref.rst
index e24e01fc..abde2e8c 100644
--- a/src/cython/doc/nerve_gic_complex_ref.rst
+++ b/src/cython/doc/nerve_gic_complex_ref.rst
@@ -1,3 +1,7 @@
+:orphan:
+
+.. To get rid of WARNING: document isn't included in any toctree
+
================================
Cover complexes reference manual
================================
diff --git a/src/cython/doc/nerve_gic_complex_user.rst b/src/cython/doc/nerve_gic_complex_user.rst
index d774827e..44f30e1a 100644
--- a/src/cython/doc/nerve_gic_complex_user.rst
+++ b/src/cython/doc/nerve_gic_complex_user.rst
@@ -1,3 +1,7 @@
+:orphan:
+
+.. To get rid of WARNING: document isn't included in any toctree
+
Cover complexes user manual
===========================
Definition
diff --git a/src/cython/doc/persistent_cohomology_user.rst b/src/cython/doc/persistent_cohomology_user.rst
index ce7fc685..de83cda1 100644
--- a/src/cython/doc/persistent_cohomology_user.rst
+++ b/src/cython/doc/persistent_cohomology_user.rst
@@ -10,12 +10,14 @@ Definition
:Author: Clément Maria :Introduced in: GUDHI PYTHON 2.0.0 :Copyright: GPL v3
===================================== ===================================== =====================================
-+---------------------------------------------+----------------------------------------------------------------------+
-| :doc:`persistent_cohomology_user` | Please refer to each data structure that contains persistence |
-| | feature for reference: |
-| | |
-| | * :doc:`simplex_tree_ref` |
-+---------------------------------------------+----------------------------------------------------------------------+
++-----------------------------------------------------------------+-----------------------------------------------------------------------+
+| :doc:`persistent_cohomology_user` | Please refer to each data structure that contains persistence |
+| | feature for reference: |
+| | |
+| | * :doc:`simplex_tree_ref` |
+| | * :doc:`cubical_complex_ref` |
+| | * :doc:`periodic_cubical_complex_ref` |
++-----------------------------------------------------------------+-----------------------------------------------------------------------+
Computation of persistent cohomology using the algorithm of :cite:`DBLP:journals/dcg/SilvaMV11` and
diff --git a/src/cython/doc/rips_complex_sum.inc b/src/cython/doc/rips_complex_sum.inc
index 5616bfa9..ea26769a 100644
--- a/src/cython/doc/rips_complex_sum.inc
+++ b/src/cython/doc/rips_complex_sum.inc
@@ -1,6 +1,6 @@
-================================================================= =================================== ===================================
-:Author: Clément Maria, Pawel Dlotko, Vincent Rouvreau :Introduced in: GUDHI 2.0.0 :Copyright: GPL v3
-================================================================= =================================== ===================================
+===================================================================== =========================== ===================================
+:Author: Clément Maria, Pawel Dlotko, Vincent Rouvreau, Marc Glisse :Introduced in: GUDHI 2.0.0 :Copyright: GPL v3
+===================================================================== =========================== ===================================
+----------------------------------------------------------------+------------------------------------------------------------------------+
| .. figure:: | Rips complex is a simplicial complex constructed from a one skeleton |
diff --git a/src/cython/doc/rips_complex_user.rst b/src/cython/doc/rips_complex_user.rst
index a8c06cf9..e814b4c3 100644
--- a/src/cython/doc/rips_complex_user.rst
+++ b/src/cython/doc/rips_complex_user.rst
@@ -7,27 +7,27 @@ Rips complex user manual
Definition
----------
-======================================================= ===================================== =====================================
-:Authors: Clément Maria, Pawel Dlotko, Vincent Rouvreau :Introduced in: GUDHI 2.0.0 :Copyright: GPL v3
-======================================================= ===================================== =====================================
+==================================================================== ================================ ======================
+:Authors: Clément Maria, Pawel Dlotko, Vincent Rouvreau, Marc Glisse :Introduced in: GUDHI 2.0.0 :Copyright: GPL v3
+==================================================================== ================================ ======================
+-------------------------------------------+----------------------------------------------------------------------+
| :doc:`rips_complex_user` | :doc:`rips_complex_ref` |
+-------------------------------------------+----------------------------------------------------------------------+
-`Rips complex <https://en.wikipedia.org/wiki/Vietoris%E2%80%93Rips_complex>`_ is a one skeleton graph that allows to
-construct a simplicial complex from it. The input can be a point cloud with a given distance function, or a distance
-matrix.
+The `Rips complex <https://en.wikipedia.org/wiki/Vietoris%E2%80%93Rips_complex>`_ is a simplicial complex that
+generalizes proximity (:math:`\varepsilon`-ball) graphs to higher dimensions. The vertices correspond to the input
+points, and a simplex is present if and only if its diameter is smaller than some parameter α. Considering all
+parameters α defines a filtered simplicial complex, where the filtration value of a simplex is its diameter.
+The filtration can be restricted to values α smaller than some threshold, to reduce its size.
-The filtration value of each edge is computed from a user-given distance function, or directly from the distance
-matrix.
+The input discrete metric space can be provided as a point cloud plus a distance function, or as a distance matrix.
-All edges that have a filtration value strictly greater than a given threshold value are not inserted into the complex.
+When creating a simplicial complex from the graph, :doc:`RipsComplex <rips_complex_ref>` first builds the graph and
+inserts it into the data structure. It then expands the simplicial complex (adds the simplices corresponding to cliques)
+when required. The expansion can be stopped at dimension `max_dimension`, by default 1.
-When creating a simplicial complex from this one skeleton graph, Rips inserts the one skeleton graph into the data
-structure, and then expands the simplicial complex when required.
-
-Vertex name correspond to the index of the point in the given range (aka. the point cloud).
+A vertex name corresponds to the index of the point in the given range (aka. the point cloud).
.. figure::
../../doc/Rips_complex/rips_complex_representation.png
@@ -38,8 +38,27 @@ Vertex name correspond to the index of the point in the given range (aka. the po
On this example, as edges (4,5), (4,6) and (5,6) are in the complex, simplex (4,5,6) is added with the filtration value
set with :math:`max(filtration(4,5), filtration(4,6), filtration(5,6))`. And so on for simplex (0,1,2,3).
-If the Rips_complex interfaces are not detailed enough for your need, please refer to rips_persistence_step_by_step.cpp
-example, where the graph construction over the Simplex_tree is more detailed.
+If the `RipsComplex` interfaces are not detailed enough for your need, please refer to rips_persistence_step_by_step.cpp
+C++ example, where the graph construction over the Simplex_tree is more detailed.
+
+A Rips complex can easily become huge, even if we limit the length of the edges
+and the dimension of the simplices. One easy trick, before building a Rips
+complex on a point cloud, is to call `sparsify_point_set` which removes points
+that are too close to each other. This does not change its persistence diagram
+by more than the length used to define "too close".
+
+A more general technique is to use a sparse approximation of the Rips
+introduced by Don Sheehy :cite:`sheehy13linear`. We are using the version
+described in :cite:`buchet16efficient` (except that we multiply all filtration
+values by 2, to match the usual Rips complex), which proves a
+:math:`\frac{1+\varepsilon}{1-\varepsilon}`-interleaving, although in practice the
+error is usually smaller. A more intuitive presentation of the idea is
+available in :cite:`cavanna15geometric`, and in a video
+:cite:`cavanna15visualizing`. Passing an extra argument `sparse=0.3` at the
+construction of a `RipsComplex` object asks it to build a sparse Rips with
+parameter :math:`\varepsilon=0.3`, while the default `sparse=None` builds the
+regular Rips complex.
+
Point cloud
-----------
@@ -47,7 +66,7 @@ Point cloud
Example from a point cloud
^^^^^^^^^^^^^^^^^^^^^^^^^^
-This example builds the one skeleton graph from the given points, and max_edge_length value.
+This example builds the neighborhood graph from the given points, up to max_edge_length.
Then it creates a :doc:`Simplex_tree <simplex_tree_ref>` with it.
Finally, it is asked to display information about the simplicial complex.
@@ -56,7 +75,7 @@ Finally, it is asked to display information about the simplicial complex.
import gudhi
rips_complex = gudhi.RipsComplex(points=[[1, 1], [7, 0], [4, 6], [9, 6], [0, 14], [2, 19], [9, 17]],
- max_edge_length=12.0)
+ max_edge_length=12.0)
simplex_tree = rips_complex.create_simplex_tree(max_dimension=1)
result_str = 'Rips complex is of dimension ' + repr(simplex_tree.dimension()) + ' - ' + \
@@ -92,10 +111,20 @@ until dimension 1 - one skeleton graph in other words), the output is:
[4, 6] -> 9.49
[3, 6] -> 11.00
+Notice that if we use
+
+.. code-block:: python
+
+ rips_complex = gudhi.RipsComplex(points=[[1, 1], [7, 0], [4, 6], [9, 6], [0, 14], [2, 19], [9, 17]],
+ max_edge_length=12.0, sparse=2)
+
+asking for a very sparse version (theory only gives some guarantee on the meaning of the output if `sparse<1`),
+2 to 5 edges disappear, depending on the random vertex used to start the sparsification.
+
Example from OFF file
^^^^^^^^^^^^^^^^^^^^^
-This example builds the :doc:`Rips_complex <rips_complex_ref>` from the given
+This example builds the :doc:`RipsComplex <rips_complex_ref>` from the given
points in an OFF file, and max_edge_length value.
Then it creates a :doc:`Simplex_tree <simplex_tree_ref>` with it.
@@ -200,7 +229,7 @@ until dimension 1 - one skeleton graph in other words), the output is:
Example from csv file
^^^^^^^^^^^^^^^^^^^^^
-This example builds the :doc:`Rips_complex <rips_complex_ref>` from the given
+This example builds the :doc:`RipsComplex <rips_complex_ref>` from the given
distance matrix in a csv file, and max_edge_length value.
Then it creates a :doc:`Simplex_tree <simplex_tree_ref>` with it.
diff --git a/src/cython/doc/tangential_complex_user.rst b/src/cython/doc/tangential_complex_user.rst
index 5ce69e86..ebfe1e29 100644
--- a/src/cython/doc/tangential_complex_user.rst
+++ b/src/cython/doc/tangential_complex_user.rst
@@ -23,8 +23,10 @@ What is a Tangential Complex?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Let us start with the description of the Tangential complex of a simple
-example, with :math:`k = 1` and :math:`d = 2`. The input data is 4 points
-:math:`P` located on a curve embedded in 2D.
+example, with :math:`k = 1` and :math:`d = 2`. The point set
+:math:`\mathscr P` is located on a closed curve embedded in 2D.
+Only 4 points will be displayed (more are required for PCA) to simplify the
+figures.
.. figure:: ../../doc/Tangential_complex/tc_example_01.png
:alt: The input
@@ -32,8 +34,7 @@ example, with :math:`k = 1` and :math:`d = 2`. The input data is 4 points
The input
-For each point :math:`p`, estimate its tangent subspace :math:`T_p` (e.g.
-using PCA).
+For each point :math:`P`, estimate its tangent subspace :math:`T_P` using PCA.
.. figure:: ../../doc/Tangential_complex/tc_example_02.png
:alt: The estimated normals
@@ -43,8 +44,8 @@ using PCA).
Let us add the Voronoi diagram of the points in orange. For each point
-:math:`p`, construct its star in the Delaunay triangulation of :math:`P`
-restricted to :math:`T_p`.
+:math:`P`, construct its star in the Delaunay triangulation of
+:math:`\mathscr P` restricted to :math:`T_P`.
.. figure:: ../../doc/Tangential_complex/tc_example_03.png
:alt: The Voronoi diagram
@@ -72,7 +73,7 @@ Let us take the same example.
Before
-Let us slightly move the tangent subspace :math:`T_q`
+Let us slightly move the tangent subspace :math:`T_Q`
.. figure:: ../../doc/Tangential_complex/tc_example_07_after.png
:alt: After
@@ -128,6 +129,7 @@ This example builds the Tangential complex of point set read in an OFF file.
import gudhi
tc = gudhi.TangentialComplex(intrisic_dim = 1,
off_file=gudhi.__root_source_dir__ + '/data/points/alphacomplexdoc.off')
+ tc.compute_tangential_complex()
result_str = 'Tangential contains ' + repr(tc.num_simplices()) + \
' simplices - ' + repr(tc.num_vertices()) + ' vertices.'
print(result_str)
@@ -175,6 +177,7 @@ simplices.
import gudhi
tc = gudhi.TangentialComplex(intrisic_dim = 1,
points=[[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]])
+ tc.compute_tangential_complex()
result_str = 'Tangential contains ' + repr(tc.num_vertices()) + ' vertices.'
print(result_str)
diff --git a/src/cython/example/sparse_rips_persistence_diagram.py b/src/cython/example/sparse_rips_persistence_diagram.py
new file mode 100755
index 00000000..d58c244c
--- /dev/null
+++ b/src/cython/example/sparse_rips_persistence_diagram.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+import 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): Marc Glisse
+
+ Copyright (C) 2018 Inria
+
+ 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/>.
+"""
+
+__author__ = "Marc Glisse"
+__copyright__ = "Copyright (C) 2018 Inria"
+__license__ = "GPL v3"
+
+print("#####################################################################")
+print("Sparse RipsComplex creation from points")
+rips = gudhi.RipsComplex(points=[[0, 0], [0, 0.1], [1, 0], [0, 1], [1, 1]],
+ max_edge_length=42, sparse=.5)
+
+simplex_tree = rips.create_simplex_tree(max_dimension=2)
+
+
+diag = simplex_tree.persistence(homology_coeff_field=2, min_persistence=0)
+print("diag=", diag)
+
+pplot = gudhi.plot_persistence_diagram(diag)
+pplot.show()
diff --git a/src/cython/example/tangential_complex_plain_homology_from_off_file_example.py b/src/cython/example/tangential_complex_plain_homology_from_off_file_example.py
index 0f8f5e80..536517d1 100755
--- a/src/cython/example/tangential_complex_plain_homology_from_off_file_example.py
+++ b/src/cython/example/tangential_complex_plain_homology_from_off_file_example.py
@@ -50,6 +50,7 @@ with open(args.file, 'r') as f:
print("TangentialComplex creation from points read in a OFF file")
tc = gudhi.TangentialComplex(intrisic_dim = args.intrisic_dim, off_file=args.file)
+ tc.compute_tangential_complex()
st = tc.create_simplex_tree()
message = "Number of simplices=" + repr(st.num_simplices())
diff --git a/src/cython/include/Rips_complex_interface.h b/src/cython/include/Rips_complex_interface.h
index 8b6c9c35..1a6e2477 100644
--- a/src/cython/include/Rips_complex_interface.h
+++ b/src/cython/include/Rips_complex_interface.h
@@ -25,8 +25,11 @@
#include <gudhi/Simplex_tree.h>
#include <gudhi/Rips_complex.h>
+#include <gudhi/Sparse_rips_complex.h>
#include <gudhi/distance_functions.h>
+#include <boost/optional.hpp>
+
#include "Simplex_tree_interface.h"
#include <iostream>
@@ -43,28 +46,40 @@ class Rips_complex_interface {
using Distance_matrix = std::vector<std::vector<Simplex_tree_interface<>::Filtration_value>>;
public:
- Rips_complex_interface(const std::vector<std::vector<double>>& values, double threshold, bool euclidean) {
- if (euclidean) {
- // Rips construction where values is a vector of points
- rips_complex_ = new Rips_complex<Simplex_tree_interface<>::Filtration_value>(values, threshold,
- Gudhi::Euclidean_distance());
- } else {
- // Rips construction where values is a distance matrix
- rips_complex_ = new Rips_complex<Simplex_tree_interface<>::Filtration_value>(values, threshold);
- }
+ void init_points(const std::vector<std::vector<double>>& points, double threshold) {
+ rips_complex_.emplace(points, threshold, Gudhi::Euclidean_distance());
+ }
+ void init_matrix(const std::vector<std::vector<double>>& matrix, double threshold) {
+ rips_complex_.emplace(matrix, threshold);
}
- ~Rips_complex_interface() {
- delete rips_complex_;
+ void init_points_sparse(const std::vector<std::vector<double>>& points, double threshold, double epsilon) {
+ sparse_rips_complex_.emplace(points, Gudhi::Euclidean_distance(), epsilon);
+ threshold_ = threshold;
+ }
+ void init_matrix_sparse(const std::vector<std::vector<double>>& matrix, double threshold, double epsilon) {
+ sparse_rips_complex_.emplace(matrix, epsilon);
+ threshold_ = threshold;
}
void create_simplex_tree(Simplex_tree_interface<>* simplex_tree, int dim_max) {
- rips_complex_->create_complex(*simplex_tree, dim_max);
+ if (rips_complex_)
+ rips_complex_->create_complex(*simplex_tree, dim_max);
+ else {
+ sparse_rips_complex_->create_complex(*simplex_tree, dim_max);
+ // This pruning should be done much earlier! It isn't that useful for sparse Rips,
+ // but it would be inconsistent not to do it.
+ simplex_tree->prune_above_filtration(threshold_);
+ }
simplex_tree->initialize_filtration();
}
private:
- Rips_complex<Simplex_tree_interface<>::Filtration_value>* rips_complex_;
+ // std::variant would work, but we don't require C++17 yet, and boost::variant is not super convenient.
+ // Anyway, storing a graph would make more sense. Or changing the interface completely so there is no such storage.
+ boost::optional<Rips_complex<Simplex_tree_interface<>::Filtration_value>> rips_complex_;
+ boost::optional<Sparse_rips_complex<Simplex_tree_interface<>::Filtration_value>> sparse_rips_complex_;
+ double threshold_;
};
} // namespace rips_complex
diff --git a/src/cython/include/Tangential_complex_interface.h b/src/cython/include/Tangential_complex_interface.h
index 71418886..c4ddbdbe 100644
--- a/src/cython/include/Tangential_complex_interface.h
+++ b/src/cython/include/Tangential_complex_interface.h
@@ -49,8 +49,6 @@ class Tangential_complex_interface {
Dynamic_kernel k;
tangential_complex_ = new TC(points, intrisic_dim, k);
- tangential_complex_->compute_tangential_complex();
- num_inconsistencies_ = tangential_complex_->number_of_inconsistent_simplices();
}
Tangential_complex_interface(int intrisic_dim, const std::string& off_file_name, bool from_file = true) {
@@ -60,14 +58,17 @@ class Tangential_complex_interface {
std::vector<Point_d> points = off_reader.get_point_cloud();
tangential_complex_ = new TC(points, intrisic_dim, k);
- tangential_complex_->compute_tangential_complex();
- num_inconsistencies_ = tangential_complex_->number_of_inconsistent_simplices();
}
~Tangential_complex_interface() {
delete tangential_complex_;
}
+ void compute_tangential_complex() {
+ tangential_complex_->compute_tangential_complex();
+ num_inconsistencies_ = tangential_complex_->number_of_inconsistent_simplices();
+ }
+
std::vector<double> get_point(unsigned vh) {
std::vector<double> vd;
if (vh < tangential_complex_->number_of_vertices()) {
@@ -104,7 +105,11 @@ class Tangential_complex_interface {
simplex_tree->initialize_filtration();
}
- private:
+ void set_max_squared_edge_length(double max_squared_edge_length) {
+ tangential_complex_->set_max_squared_edge_length(max_squared_edge_length);
+ }
+
+private:
TC* tangential_complex_;
TC::Num_inconsistencies num_inconsistencies_;
};
diff --git a/src/cython/test/test_rips_complex.py b/src/cython/test/test_rips_complex.py
index c37b5400..05dfcaf7 100755
--- a/src/cython/test/test_rips_complex.py
+++ b/src/cython/test/test_rips_complex.py
@@ -30,7 +30,6 @@ __license__ = "GPL v3"
def test_empty_rips():
rips_complex = RipsComplex()
- assert rips_complex.__is_defined() == True
def test_rips_from_points():
point_list = [[0, 0], [1, 0], [0, 1], [1, 1]]
@@ -68,12 +67,26 @@ def test_filtered_rips_from_points():
assert simplex_tree.num_simplices() == 8
assert simplex_tree.num_vertices() == 4
+def test_sparse_filtered_rips_from_points():
+ point_list = [[0, 0], [1, 0], [0, 1], [1, 1]]
+ filtered_rips = RipsComplex(points=point_list, max_edge_length=1.0,
+ sparse=.001)
+
+ simplex_tree = filtered_rips.create_simplex_tree(max_dimension=1)
+
+ assert simplex_tree.__is_defined() == True
+ assert simplex_tree.__is_persistence_defined() == False
+
+ assert simplex_tree.num_simplices() == 8
+ assert simplex_tree.num_vertices() == 4
+
def test_rips_from_distance_matrix():
distance_matrix = [[0],
[1, 0],
[1, sqrt(2), 0],
[sqrt(2), 1, 1, 0]]
- rips_complex = RipsComplex(distance_matrix=distance_matrix, max_edge_length=42)
+ rips_complex = RipsComplex(distance_matrix=distance_matrix,
+ max_edge_length=42)
simplex_tree = rips_complex.create_simplex_tree(max_dimension=1)
@@ -100,7 +113,8 @@ def test_filtered_rips_from_distance_matrix():
[1, 0],
[1, sqrt(2), 0],
[sqrt(2), 1, 1, 0]]
- filtered_rips = RipsComplex(distance_matrix=distance_matrix, max_edge_length=1.0)
+ filtered_rips = RipsComplex(distance_matrix=distance_matrix,
+ max_edge_length=1.0)
simplex_tree = filtered_rips.create_simplex_tree(max_dimension=1)
diff --git a/src/cython/test/test_tangential_complex.py b/src/cython/test/test_tangential_complex.py
index 5385a0d3..5c62f278 100755
--- a/src/cython/test/test_tangential_complex.py
+++ b/src/cython/test/test_tangential_complex.py
@@ -32,6 +32,15 @@ def test_tangential():
tc = TangentialComplex(intrisic_dim = 1, points=point_list)
assert tc.__is_defined() == True
assert tc.num_vertices() == 4
+ assert tc.num_simplices() == 0
+ assert tc.num_inconsistent_simplices() == 0
+ assert tc.num_inconsistent_stars() == 0
+
+ tc.compute_tangential_complex()
+ assert tc.num_vertices() == 4
+ assert tc.num_simplices() == 4
+ assert tc.num_inconsistent_simplices() == 0
+ assert tc.num_inconsistent_stars() == 0
st = tc.create_simplex_tree()
assert st.__is_defined() == True