From 5407637f45369a3d454e0e92d6f0a6ae809737f5 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Mon, 17 Jul 2023 14:48:38 +0200 Subject: [PATCH 01/96] restore after merge --- .../benchmark/CMakeLists.txt | 17 + .../benchmark/Zigzag_benchmark.cpp | 198 ++ .../benchmark/Zigzag_old_benchmark.cpp | 112 + .../benchmark/Zigzag_other_benchmark.cpp | 144 + .../benchmark/rips-zigzag-dionysus.h | 211 ++ src/Zigzag_persistence/example/CMakeLists.txt | 29 + .../example/comparison_for_tests.cpp | 440 +++ .../example_rips_zigzag_filtration.cpp | 158 + .../example_simple_zigzag_filtration.cpp | 118 + .../example/ext_zz/dionysus/chain.h | 153 + .../example/ext_zz/dionysus/chain.hpp | 188 ++ .../ext_zz/dionysus/clearing-reduction.h | 45 + .../ext_zz/dionysus/clearing-reduction.hpp | 60 + .../example/ext_zz/dionysus/cnpy.h | 241 ++ .../ext_zz/dionysus/cohomology-persistence.h | 116 + .../dionysus/cohomology-persistence.hpp | 61 + .../example/ext_zz/dionysus/common.h | 25 + .../example/ext_zz/dionysus/diagram.h | 114 + .../example/ext_zz/dionysus/distances.h | 93 + .../example/ext_zz/dionysus/distances.hpp | 30 + .../example/ext_zz/dionysus/dlog/progress.h | 57 + .../example/ext_zz/dionysus/fields/q.h | 63 + .../example/ext_zz/dionysus/fields/z2.h | 31 + .../example/ext_zz/dionysus/fields/zp.h | 55 + .../example/ext_zz/dionysus/filtration.h | 124 + .../example/ext_zz/dionysus/format.h | 8 + .../example/ext_zz/dionysus/format/format.cc | 1156 ++++++++ .../example/ext_zz/dionysus/format/format.h | 2546 +++++++++++++++++ .../example/ext_zz/dionysus/grid/box.h | 136 + .../example/ext_zz/dionysus/grid/box.hpp | 141 + .../example/ext_zz/dionysus/grid/grid.h | 143 + .../example/ext_zz/dionysus/grid/point.h | 132 + .../example/ext_zz/dionysus/grid/vertices.h | 86 + .../ext_zz/dionysus/matrix-filtration.h | 120 + .../ext_zz/dionysus/omni-field-persistence.h | 145 + .../dionysus/omni-field-persistence.hpp | 250 ++ .../example/ext_zz/dionysus/opts/opts.h | 499 ++++ .../ext_zz/dionysus/ordinary-persistence.h | 64 + .../example/ext_zz/dionysus/pair-recorder.h | 78 + .../example/ext_zz/dionysus/reduced-matrix.h | 170 ++ .../ext_zz/dionysus/reduced-matrix.hpp | 78 + .../example/ext_zz/dionysus/reduction.h | 109 + .../dionysus/relative-homology-zigzag.h | 84 + .../dionysus/relative-homology-zigzag.hpp | 122 + .../example/ext_zz/dionysus/rips.h | 147 + .../example/ext_zz/dionysus/rips.hpp | 162 ++ .../example/ext_zz/dionysus/row-reduction.h | 54 + .../example/ext_zz/dionysus/row-reduction.hpp | 103 + .../example/ext_zz/dionysus/simplex.h | 280 ++ .../ext_zz/dionysus/sparse-row-matrix.h | 184 ++ .../ext_zz/dionysus/sparse-row-matrix.hpp | 103 + .../ext_zz/dionysus/standard-reduction.h | 44 + .../ext_zz/dionysus/standard-reduction.hpp | 47 + .../example/ext_zz/dionysus/trails-chains.h | 17 + .../ext_zz/dionysus/zigzag-persistence.h | 142 + .../ext_zz/dionysus/zigzag-persistence.hpp | 541 ++++ .../example/ext_zz/fzz/fzz.cpp | 206 ++ .../example/ext_zz/fzz/fzz.h | 87 + .../ext_zz/phat/algorithms/chunk_reduction.h | 223 ++ .../ext_zz/phat/algorithms/row_reduction.h | 56 + .../algorithms/spectral_sequence_reduction.h | 80 + .../phat/algorithms/standard_reduction.h | 47 + .../ext_zz/phat/algorithms/twist_reduction.h | 51 + .../example/ext_zz/phat/boundary_matrix.h | 343 +++ .../ext_zz/phat/compute_persistence_pairs.h | 128 + .../example/ext_zz/phat/helpers/dualize.h | 74 + .../example/ext_zz/phat/helpers/misc.h | 75 + .../phat/helpers/thread_local_storage.h | 52 + .../example/ext_zz/phat/persistence_pairs.h | 155 + .../representations/abstract_pivot_column.h | 102 + .../representations/bit_tree_pivot_column.h | 165 ++ .../phat/representations/full_pivot_column.h | 100 + .../phat/representations/heap_pivot_column.h | 126 + .../representations/sparse_pivot_column.h | 79 + .../ext_zz/phat/representations/vector_heap.h | 170 ++ .../ext_zz/phat/representations/vector_list.h | 101 + .../ext_zz/phat/representations/vector_set.h | 99 + .../phat/representations/vector_vector.h | 107 + .../example/rips-zigzag-dionysus.h | 211 ++ .../include/gudhi/Zigzag_persistence.h | 725 +++++ .../include/gudhi/Zigzag_persistence_old.h | 1326 +++++++++ src/Zigzag_persistence/test/CMakeLists.txt | 16 + .../test/zigzag_persistence_unit_test.cpp | 468 +++ 83 files changed, 16146 insertions(+) create mode 100644 src/Zigzag_persistence/benchmark/CMakeLists.txt create mode 100644 src/Zigzag_persistence/benchmark/Zigzag_benchmark.cpp create mode 100644 src/Zigzag_persistence/benchmark/Zigzag_old_benchmark.cpp create mode 100644 src/Zigzag_persistence/benchmark/Zigzag_other_benchmark.cpp create mode 100644 src/Zigzag_persistence/benchmark/rips-zigzag-dionysus.h create mode 100644 src/Zigzag_persistence/example/CMakeLists.txt create mode 100644 src/Zigzag_persistence/example/comparison_for_tests.cpp create mode 100644 src/Zigzag_persistence/example/example_rips_zigzag_filtration.cpp create mode 100644 src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/chain.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/chain.hpp create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/clearing-reduction.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/clearing-reduction.hpp create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/cnpy.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/cohomology-persistence.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/cohomology-persistence.hpp create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/common.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/diagram.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/distances.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/distances.hpp create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/dlog/progress.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/fields/q.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/fields/z2.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/fields/zp.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/filtration.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/format.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/format/format.cc create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/format/format.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/grid/box.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/grid/box.hpp create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/grid/grid.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/grid/point.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/grid/vertices.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/matrix-filtration.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/omni-field-persistence.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/omni-field-persistence.hpp create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/opts/opts.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/ordinary-persistence.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/pair-recorder.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/reduced-matrix.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/reduced-matrix.hpp create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/reduction.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/relative-homology-zigzag.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/relative-homology-zigzag.hpp create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/rips.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/rips.hpp create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/row-reduction.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/row-reduction.hpp create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/simplex.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/sparse-row-matrix.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/sparse-row-matrix.hpp create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/standard-reduction.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/standard-reduction.hpp create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/trails-chains.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/zigzag-persistence.h create mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/zigzag-persistence.hpp create mode 100644 src/Zigzag_persistence/example/ext_zz/fzz/fzz.cpp create mode 100644 src/Zigzag_persistence/example/ext_zz/fzz/fzz.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/algorithms/chunk_reduction.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/algorithms/row_reduction.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/algorithms/spectral_sequence_reduction.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/algorithms/standard_reduction.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/algorithms/twist_reduction.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/boundary_matrix.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/compute_persistence_pairs.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/helpers/dualize.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/helpers/misc.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/helpers/thread_local_storage.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/persistence_pairs.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/representations/abstract_pivot_column.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/representations/bit_tree_pivot_column.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/representations/full_pivot_column.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/representations/heap_pivot_column.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/representations/sparse_pivot_column.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/representations/vector_heap.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/representations/vector_list.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/representations/vector_set.h create mode 100644 src/Zigzag_persistence/example/ext_zz/phat/representations/vector_vector.h create mode 100644 src/Zigzag_persistence/example/rips-zigzag-dionysus.h create mode 100644 src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h create mode 100644 src/Zigzag_persistence/include/gudhi/Zigzag_persistence_old.h create mode 100644 src/Zigzag_persistence/test/CMakeLists.txt create mode 100644 src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp diff --git a/src/Zigzag_persistence/benchmark/CMakeLists.txt b/src/Zigzag_persistence/benchmark/CMakeLists.txt new file mode 100644 index 0000000000..1f0faeb542 --- /dev/null +++ b/src/Zigzag_persistence/benchmark/CMakeLists.txt @@ -0,0 +1,17 @@ +project(Zigzag_benchmark) + +find_package(benchmark REQUIRED) + +add_executable(Zigzag_benchmark Zigzag_benchmark.cpp) +target_link_libraries(Zigzag_benchmark benchmark::benchmark) +target_include_directories(Zigzag_benchmark PUBLIC . ../example/ext_zz) + +add_executable(Zigzag_old_benchmark Zigzag_old_benchmark.cpp) +target_link_libraries(Zigzag_old_benchmark benchmark::benchmark) +target_include_directories(Zigzag_old_benchmark PUBLIC . ../example/ext_zz) + +add_executable(Zigzag_other_benchmark Zigzag_other_benchmark.cpp ../example/ext_zz/fzz/fzz.cpp) +target_link_libraries(Zigzag_other_benchmark benchmark::benchmark) +target_include_directories(Zigzag_other_benchmark PUBLIC . ../example/ext_zz) +target_compile_options(Zigzag_other_benchmark PUBLIC "-fopenmp") +target_link_options(Zigzag_other_benchmark PUBLIC "-fopenmp") diff --git a/src/Zigzag_persistence/benchmark/Zigzag_benchmark.cpp b/src/Zigzag_persistence/benchmark/Zigzag_benchmark.cpp new file mode 100644 index 0000000000..3edac39c8d --- /dev/null +++ b/src/Zigzag_persistence/benchmark/Zigzag_benchmark.cpp @@ -0,0 +1,198 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Hannah Schreiber + * + * Copyright (C) 2022 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +#include +#include +#include +#include +#include // for pair +#include +#include + +#include +#include + +#include +#include +#include + +#include "rips-zigzag-dionysus.h" + +using ST = Gudhi::Simplex_tree; +// using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; +using Vertex_handle = ST::Vertex_handle; +using Filtration_value = ST::Filtration_value; +// using interval_filtration = ZP::interval_filtration; + +using Gudhi::persistence_matrix::Zigzag_options; +using CT = Gudhi::persistence_matrix::Column_types; + +template +std::vector< std::pair > print_indices(ZP& zp, unsigned int numberOfSimplices){ + std::set essentials; + std::vector< std::pair > res; + + for (unsigned int i = 0; i < numberOfSimplices; ++i){ + essentials.insert(essentials.end(), i); + } + + for (auto& bar : zp.index_persistence_diagram()){ + res.emplace_back(bar.birth(), bar.death()); + essentials.erase(bar.birth()); + essentials.erase(bar.death()); + } + + for (unsigned int v : essentials){ + res.emplace_back(v, numberOfSimplices); + } + + return res; +} + +template +std::vector< std::pair > compute_with_gudhi( + const std::vector >& simplices, + const std::vector& dirs) +{ + ZP zp(simplices.size()); + + // std::cout << "====================== Gudhi =====================\n"; + + std::vector filValues(simplices.size(), 1.0); + + auto start = simplices.begin(); + auto filIt = filValues.begin(); + unsigned int i = 0; + + while (start != simplices.end()){ + unsigned int c = 1; + auto end = start + 1; + ++i; + while (end != simplices.end() && dirs[i - 1] == dirs[i]) { + ++end; + ++i; + ++c; + } + + if (dirs[i - 1]){ + zp.insert_simplices_contiguously( + start, end, filIt); + } else { + zp.remove_simplices_contiguously( + start, end, filIt); + } + + start = end; + filIt += c; + } + + // std::cout << "==================================================\n"; + + return print_indices(zp, i); +} + +static void Compute_zigzag_with_gudhi_intrusive_list(benchmark::State& state) { + using ZP = Gudhi::zigzag_persistence::Zigzag_persistence >; + + unsigned int numberOfPoints = state.range(0); + int seed = numberOfPoints; + std::vector > simplices; + std::vector dirs; + + build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); + + for (auto _ : state){ + compute_with_gudhi(simplices, dirs); + } +} +BENCHMARK(Compute_zigzag_with_gudhi_intrusive_list)->RangeMultiplier(2)->Range(100, 1000)->Unit(benchmark::kMillisecond)->MinWarmUpTime(1); + +static void Compute_zigzag_with_gudhi_intrusive_set(benchmark::State& state) { + using ZP = Gudhi::zigzag_persistence::Zigzag_persistence >; + + unsigned int numberOfPoints = state.range(0); + int seed = numberOfPoints; + std::vector > simplices; + std::vector dirs; + + build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); + + for (auto _ : state){ + compute_with_gudhi(simplices, dirs); + } +} +BENCHMARK(Compute_zigzag_with_gudhi_intrusive_set)->RangeMultiplier(2)->Range(100, 1000)->Unit(benchmark::kMillisecond)->MinWarmUpTime(1); + +static void Compute_zigzag_with_gudhi_list(benchmark::State& state) { + using ZP = Gudhi::zigzag_persistence::Zigzag_persistence >; + + unsigned int numberOfPoints = state.range(0); + int seed = numberOfPoints; + std::vector > simplices; + std::vector dirs; + + build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); + + for (auto _ : state){ + compute_with_gudhi(simplices, dirs); + } +} +BENCHMARK(Compute_zigzag_with_gudhi_list)->RangeMultiplier(2)->Range(100, 1000)->Unit(benchmark::kMillisecond)->MinWarmUpTime(1); + +// static void Compute_zigzag_with_gudhi_set(benchmark::State& state) { +// using ZP = Gudhi::zigzag_persistence::Zigzag_persistence >; + +// unsigned int numberOfPoints = state.range(0); +// int seed = numberOfPoints; +// std::vector > simplices; +// std::vector dirs; + +// build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); + +// for (auto _ : state){ +// compute_with_gudhi(simplices, dirs); +// } +// } +// BENCHMARK(Compute_zigzag_with_gudhi_set)->RangeMultiplier(2)->Range(100, 1000)->Unit(benchmark::kMillisecond)->MinWarmUpTime(1); + +// static void Compute_zigzag_with_gudhi_unordered_set(benchmark::State& state) { +// using ZP = Gudhi::zigzag_persistence::Zigzag_persistence>; + +// unsigned int numberOfPoints = state.range(0); +// int seed = numberOfPoints; +// std::vector > simplices; +// std::vector dirs; + +// build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); + +// for (auto _ : state){ +// compute_with_gudhi(simplices, dirs); +// } +// } +// BENCHMARK(Compute_zigzag_with_gudhi_unordered_set)->RangeMultiplier(2)->Range(100, 1000)->Unit(benchmark::kMillisecond)->MinWarmUpTime(1); + +static void Compute_zigzag_with_gudhi_vector(benchmark::State& state) { + using ZP = Gudhi::zigzag_persistence::Zigzag_persistence>; + + unsigned int numberOfPoints = state.range(0); + int seed = numberOfPoints; + std::vector > simplices; + std::vector dirs; + + build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); + + for (auto _ : state){ + compute_with_gudhi(simplices, dirs); + } +} +BENCHMARK(Compute_zigzag_with_gudhi_vector)->RangeMultiplier(2)->Range(100, 1000)->Unit(benchmark::kMillisecond)->MinWarmUpTime(1); + +BENCHMARK_MAIN(); + diff --git a/src/Zigzag_persistence/benchmark/Zigzag_old_benchmark.cpp b/src/Zigzag_persistence/benchmark/Zigzag_old_benchmark.cpp new file mode 100644 index 0000000000..bb24be2942 --- /dev/null +++ b/src/Zigzag_persistence/benchmark/Zigzag_old_benchmark.cpp @@ -0,0 +1,112 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Hannah Schreiber + * + * Copyright (C) 2022 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +#include +#include +#include +#include +#include // for pair +#include +#include + +#include +#include + +#include +#include + +#include "rips-zigzag-dionysus.h" + +using ST = Gudhi::Simplex_tree; +using coltype = Gudhi::zigzag_persistence::Zigzag_persistence_collist; +using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; +// using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; +using Vertex_handle = ST::Vertex_handle; +using Filtration_value = ST::Filtration_value; +using interval_filtration = ZP::interval_filtration; + +std::vector< std::pair > print_indices(ZP& zp, unsigned int numberOfSimplices){ + std::set essentials; + std::vector< std::pair > res; + + for (unsigned int i = 0; i < numberOfSimplices; ++i){ + essentials.insert(essentials.end(), i); + } + + for (auto& bar : zp.index_persistence_diagram()){ + res.emplace_back(bar.birth(), bar.death()); + essentials.erase(bar.birth()); + essentials.erase(bar.death()); + } + + for (unsigned int v : essentials){ + res.emplace_back(v, numberOfSimplices); + } + + return res; +} + +std::vector< std::pair > compute_with_gudhi( + const std::vector >& simplices, + const std::vector& dirs) +{ + ZP zp(simplices.size()); + + // std::cout << "====================== Gudhi =====================\n"; + + std::vector filValues(simplices.size(), 1.0); + + auto start = simplices.begin(); + auto filIt = filValues.begin(); + unsigned int i = 0; + + while (start != simplices.end()){ + unsigned int c = 1; + auto end = start + 1; + ++i; + while (end != simplices.end() && dirs[i - 1] == dirs[i]) { + ++end; + ++i; + ++c; + } + + if (dirs[i - 1]){ + zp.insert_simplices_contiguously( + start, end, filIt); + } else { + zp.remove_simplices_contiguously( + start, end, filIt); + } + + start = end; + filIt += c; + } + + // std::cout << "==================================================\n"; + + return print_indices(zp, i); +} + +static void Compute_zigzag_with_gudhi(benchmark::State& state) { + unsigned int numberOfPoints = state.range(0);; + int seed = numberOfPoints; + std::vector > simplices; + std::vector dirs; + + build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); + + for (auto _ : state){ + compute_with_gudhi(simplices, dirs); + } +} +BENCHMARK(Compute_zigzag_with_gudhi)->RangeMultiplier(2)->Range(100, 1000)->Unit(benchmark::kMillisecond)->MinWarmUpTime(1); + +BENCHMARK_MAIN(); + diff --git a/src/Zigzag_persistence/benchmark/Zigzag_other_benchmark.cpp b/src/Zigzag_persistence/benchmark/Zigzag_other_benchmark.cpp new file mode 100644 index 0000000000..6e51854338 --- /dev/null +++ b/src/Zigzag_persistence/benchmark/Zigzag_other_benchmark.cpp @@ -0,0 +1,144 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Hannah Schreiber + * + * Copyright (C) 2022 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +#include +#include +#include +#include +#include // for pair +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "rips-zigzag-dionysus.h" + +using DField = dionysus::Z2Field; +using Simplex = dionysus::Simplex<>; +using DFiltration = dionysus::Filtration; +using DZZ = dionysus::ZigzagPersistence; +using DIndex = typename DZZ::Index; +using DChain = dionysus::ChainEntry; +using DIChain = dionysus::ChainEntry; +using Vertex_handle = int; + +std::vector< std::pair > compute_with_dionysus( + const std::vector >& simplices, + const std::vector& dirs) +{ + DField k; + std::unordered_map indices; + DZZ persistence(k); + std::vector< std::pair > res; + + // std::cout << "==================== Dionysus ====================\n"; + + std::set essentials; + + unsigned int op = 0; + unsigned int idx = 0; + + for (const std::vector& simplex : simplices){ + Simplex c(simplex); + DIndex pair; + if (dirs[op]) { + indices.try_emplace(c, idx++); + pair = persistence.add(c.boundary(persistence.field()) | + boost::adaptors::transformed([&indices](const DChain& e) { + return DIChain(e.element(), indices.find(e.index())->second); + })); + } else { + auto idxIt = indices.find(c); + pair = persistence.remove(idxIt->second); + indices.erase(idxIt); + } + + if (pair != DZZ::unpaired()) { + res.emplace_back(pair, op); + essentials.erase(pair); + } else { + essentials.insert(essentials.end(), op); + } + op++; + } + + for (unsigned int v : essentials){ + res.emplace_back(v, op); + } + + // std::cout << "==================================================\n"; + + return res; +} + +std::vector< std::tuple > compute_with_fzz( + const std::vector >& simplices, + const std::vector& dirs) +{ + std::vector< std::tuple > persistence; + FZZ::FastZigzag fzz; + + // std::cout << "======================= FZZ ======================\n"; + + fzz.compute(simplices, dirs, &persistence); + + std::sort(persistence.begin(), persistence.end(), + [](const std::tuple& p1, const std::tuple& p2){ + if (std::get<1>(p1) == std::get<1>(p2)){ + return std::get<0>(p1) < std::get<0>(p2); + } + + return std::get<1>(p1) < std::get<1>(p2); + }); + + // std::cout << "==================================================\n"; + + return persistence; +} + +static void Compute_zigzag_with_dionysus(benchmark::State& state) { + unsigned int numberOfPoints = state.range(0);; + int seed = numberOfPoints; + std::vector > simplices; + std::vector dirs; + + build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); + + for (auto _ : state){ + compute_with_dionysus(simplices, dirs); + } +} +BENCHMARK(Compute_zigzag_with_dionysus)->RangeMultiplier(2)->Range(100, 1000)->Unit(benchmark::kMillisecond)->MinWarmUpTime(1); + +static void Compute_zigzag_with_fzz(benchmark::State& state) { + unsigned int numberOfPoints = state.range(0);; + int seed = numberOfPoints; + std::vector > simplices; + std::vector dirs; + + build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); + + for (auto _ : state){ + compute_with_fzz(simplices, dirs); + } +} +BENCHMARK(Compute_zigzag_with_fzz)->RangeMultiplier(2)->Range(100, 1000)->Unit(benchmark::kMillisecond)->MinWarmUpTime(1); + +BENCHMARK_MAIN(); + diff --git a/src/Zigzag_persistence/benchmark/rips-zigzag-dionysus.h b/src/Zigzag_persistence/benchmark/rips-zigzag-dionysus.h new file mode 100644 index 0000000000..5cd2c585c4 --- /dev/null +++ b/src/Zigzag_persistence/benchmark/rips-zigzag-dionysus.h @@ -0,0 +1,211 @@ +#include +#include +#include +#include + +#include +namespace ba = boost::adaptors; + +#include +#include +#include +namespace d = dionysus; + +#include + +typedef std::vector Point; +typedef std::vector PointContainer; + +typedef d::PairwiseDistances> PairDistances; +typedef PairDistances::DistanceType DistanceType; +typedef PairDistances::IndexType Vertex; + +typedef d::Rips Generator; +typedef Generator::Simplex Simplex; +typedef std::set SimplexSet; + +typedef std::vector VertexVector; +typedef std::vector EpsilonVector; +typedef std::tuple Edge; +typedef std::vector EdgeVector; + +inline PointContainer compute_points(unsigned int numberOfPoints, int seed = -1) +{ + PointContainer finalPoints; + std::set points; + std::random_device dev; + std::mt19937 rng(dev()); + if (seed > -1) rng.seed(seed); + std::uniform_real_distribution dist(0,10); + + for (unsigned int i = 0; i < numberOfPoints; ++i){ + auto res = points.insert({dist(rng), dist(rng)}); + while(!res.second){ + res = points.insert({dist(rng), dist(rng)}); + } + finalPoints.push_back(*res.first); + } + + return finalPoints; +} + +inline void compute_vertices_and_epsilons(const PairDistances& distances, + VertexVector& vertices, + EpsilonVector& epsilons) +{ + DistanceType inf = std::numeric_limits::infinity(); + EpsilonVector dist(distances.size(), inf); + + vertices.push_back(distances.begin()); + // epsilons.push_back(inf); + while (vertices.size() < distances.size()) { + for (Vertex v = distances.begin(); v != distances.end(); ++v) + dist[v] = std::min(dist[v], distances(v, vertices.back())); + auto max = std::max_element(dist.begin(), dist.end()); + vertices.push_back(max - dist.begin()); + epsilons.push_back(*max); + } + epsilons.push_back(0); +} + +inline void compute_edges(const PairDistances& distances, + const VertexVector& vertices, + const EpsilonVector& epsilons, + const DistanceType& multiplier, + EdgeVector& edges) +{ + for (unsigned i = 0; i != vertices.size(); ++i) + for (unsigned j = i + 1; j != vertices.size(); ++j) { + Vertex u = vertices[i]; + Vertex v = vertices[j]; + if (distances(u, v) <= multiplier * epsilons[j - 1]) edges.emplace_back(u, v); + } + std::sort(edges.begin(), edges.end(), + [&distances](const Edge& e1, const Edge& e2) { + return distances(std::get<0>(e1), std::get<1>(e1)) < + distances(std::get<0>(e2), std::get<1>(e2)); + }); +} + +inline void compute_positive_cofaces( + const PairDistances& distances, + const VertexVector& vertices, + const EdgeVector& edges, + const EpsilonVector& epsilons, + const DistanceType& multiplier, + Generator& rips, + short unsigned& skeleton, + unsigned& ce, + unsigned& i, + SimplexSet& cofaces) +{ + cofaces.clear(); + + // Add anything else that needs to be inserted into the complex + while (ce < edges.size()) { + Vertex u, v; + std::tie(u, v) = edges[ce]; + if (distances(u, v) <= multiplier * epsilons[i - 1]) + ++ce; + else + break; + // std::cout << "Adding cofaces of " << u << ' ' << v << std::endl; + rips.edge_cofaces( + u, v, + skeleton, + multiplier * epsilons[i - 1], + [&cofaces](Simplex&& s) { cofaces.insert(s); }, + vertices.begin(), + vertices.begin() + i + 1); + } +} + +inline void compute_negative_cofaces( + const VertexVector& vertices, + const EpsilonVector& epsilons, + const DistanceType& multiplier, + Generator& rips, + short unsigned& skeleton, + unsigned& i, + SimplexSet& cofaces) +{ + cofaces.clear(); + rips.vertex_cofaces( + vertices[i], + skeleton, + multiplier * epsilons[i - 1], + [&cofaces](Simplex&& s) { cofaces.insert(s); }, + vertices.begin(), + vertices.begin() + i + 1); + // std::cout << "Total cofaces: " << cofaces.size() << std::endl; +} + +inline unsigned int build_rips_zigzag_filtration(std::vector > &simpls, + std::vector& dirs, + unsigned int numberOfPoints, + int seed = -1, + short unsigned skeleton = 2, + DistanceType multiplier = 6) +{ + // std::cout << "Building filtration" << std::endl; + unsigned int numberOfSimplices = 0; + + PointContainer points = compute_points(numberOfPoints, seed); + + // Construct distances and Rips generator + PairDistances distances(points); + Generator rips(distances); + + // Order vertices and epsilons (in maxmin fashion) + VertexVector vertices; + EpsilonVector epsilons; + EdgeVector edges; + + compute_vertices_and_epsilons(distances, vertices, epsilons); + + // Generate and sort all the edges + compute_edges(distances, vertices, epsilons, multiplier, edges); + + // Insert vertices + for (auto v : vertices) { + // Add a vertex + simpls.push_back({static_cast(v)}); + dirs.push_back(true); + ++numberOfSimplices; + } + + // Process vertices + // dlog::progress progress(vertices.size()); + unsigned ce = 0; // index of the current one past last edge in the complex + SimplexSet cofaces; // record the cofaces of all the simplices that need to be removed and reinserted + + for (unsigned stage = 0; stage != vertices.size() - 1; ++stage) { + unsigned i = vertices.size() - 1 - stage; + + /* Increase epsilon */ + compute_positive_cofaces(distances, vertices, edges, epsilons, multiplier, rips, skeleton, ce, i, cofaces); + + for (auto& s : cofaces) { + // std::cout << "Inserting: " << s << std::endl; + simpls.emplace_back(s.begin(), s.end()); + dirs.push_back(true); + ++numberOfSimplices; + } + + /* Remove the vertex */ + // std::cout << "Removing vertex: " << vertices[i] << std::endl; + compute_negative_cofaces(vertices, epsilons, multiplier, rips, skeleton, i, cofaces); + + for (auto& s : cofaces | ba::reversed) { + // std::cout << "Removing: " << s << std::endl; + simpls.emplace_back(s.begin(), s.end()); + dirs.push_back(false); + } + + // ++progress; + } + + return numberOfSimplices; + // std::cout << "Finished" << std::endl; +} diff --git a/src/Zigzag_persistence/example/CMakeLists.txt b/src/Zigzag_persistence/example/CMakeLists.txt new file mode 100644 index 0000000000..1a981ce998 --- /dev/null +++ b/src/Zigzag_persistence/example/CMakeLists.txt @@ -0,0 +1,29 @@ +project(Zigzag_persistence_examples) + +add_executable ( Zigzag_persistence_example_simple_zigzag_filtration example_simple_zigzag_filtration.cpp ) +if(TARGET TBB::tbb) + target_link_libraries(Zigzag_persistence_example_simple_zigzag_filtration TBB::tbb) +endif() +add_test(NAME Zigzag_persistence_example_simple_zigzag_filtration COMMAND $) + +add_executable ( comp comparison_for_tests.cpp ./ext_zz/fzz/fzz.cpp ) +target_include_directories(comp PUBLIC ./ext_zz) +target_compile_options(comp PUBLIC "-fopenmp") +target_link_options(comp PUBLIC "-fopenmp") + +# add_executable ( Zigzag_persistence_example_rips_zigzag_filtration example_rips_zigzag_filtration.cpp ) +# target_include_directories(Zigzag_persistence_example_rips_zigzag_filtration PUBLIC ./ext_zz) +# target_compile_options(Zigzag_persistence_example_rips_zigzag_filtration PUBLIC "-fopenmp") +# target_link_options(Zigzag_persistence_example_rips_zigzag_filtration PUBLIC "-fopenmp") + +add_executable ( rips example_rips_zigzag_filtration.cpp ) +target_include_directories(rips PUBLIC ./ext_zz) +target_compile_options(rips PUBLIC "-fopenmp") +target_link_options(rips PUBLIC "-fopenmp") + +# add_executable ( rips_old example_rips_zigzag_filtration.cpp ) +# target_include_directories(rips_old PUBLIC ./ext_zz) +# target_compile_options(rips_old PUBLIC "-fopenmp") +# target_link_options(rips_old PUBLIC "-fopenmp") + + diff --git a/src/Zigzag_persistence/example/comparison_for_tests.cpp b/src/Zigzag_persistence/example/comparison_for_tests.cpp new file mode 100644 index 0000000000..2beded4910 --- /dev/null +++ b/src/Zigzag_persistence/example/comparison_for_tests.cpp @@ -0,0 +1,440 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Hannah Schreiber + * + * Copyright (C) 2014 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +#include +#include +#include +#include +#include // for pair +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rips-zigzag-dionysus.h" + +using ST = Gudhi::Simplex_tree; +using Gudhi::persistence_matrix::Zigzag_options; +using CT = Gudhi::persistence_matrix::Column_types; +using ZP = Gudhi::zigzag_persistence::Zigzag_persistence >; +using Vertex_handle = ST::Vertex_handle; +using Filtration_value = ST::Filtration_value; +using interval_filtration = ZP::interval_filtration; + +using DField = dionysus::Z2Field; +using Simplex = dionysus::Simplex<>; +using DFiltration = dionysus::Filtration; +using DZZ = dionysus::ZigzagPersistence; +using DIndex = typename DZZ::Index; +using DChain = dionysus::ChainEntry; +using DIChain = dionysus::ChainEntry; + +void print_complex(ZP& zp){ + std::clog << std::endl << "Current complex:" << std::endl; + zp.print_current_complex(); +} + +// void print_barcode(ZP& zp){ +// std::clog << std::endl << "Current barcode:" << std::endl; +// for (auto& bar : zp.persistence_diagram()){ +// std::clog << std::floor(bar.birth()) << " - "; +// if (bar.death() == std::numeric_limits::infinity()){ +// std::clog << "inf"; +// } else { +// std::clog << std::floor(bar.death()); +// } +// std::clog << " (" << bar.dim() << ")\n"; +// } +// } + +std::vector< std::pair > print_indices(ZP& zp, unsigned int numberOfSimplices){ + std::set essentials; + std::vector< std::pair > res; + + for (unsigned int i = 0; i < numberOfSimplices; ++i){ + essentials.insert(essentials.end(), i); + } + + for (auto& bar : zp.index_persistence_diagram()){ + // std::clog << bar.birth() << " - "; + // std::clog << bar.death(); + // std::clog << " (" << bar.dim() << ")\n"; + res.emplace_back(bar.birth(), bar.death()); + essentials.erase(bar.birth()); + essentials.erase(bar.death()); + } + + for (unsigned int v : essentials){ + // std::clog << v << " - "; + // std::clog << "inf\n"; + res.emplace_back(v, numberOfSimplices); + } + + return res; +} + +// std::vector > get_simplices() +// { +// return { +// {0}, +// {1}, +// {2}, +// {0,1}, +// {0,2}, +// {3}, +// {1,2}, +// {4}, +// {3,4}, +// {5}, +// {0,1,2}, +// {4,5}, +// {3,5}, +// {3,4,5}, +// {0,1,2}, //r +// {3,4,5}, //r +// {1,4}, +// {0,1,2}, +// {2,4}, +// {3,4,5}, +// {0,4}, +// {0,2,4}, +// {1,2,4}, +// {0,1,4}, +// {3,4,5}, //r +// {3,4}, //r +// {3,5}, //r +// {0,1,2,4}}; +// } + +// std::vector get_filtration_values() +// { +// return { +// 0, 0, 0, +// 1, 1, 1, +// 2, 2, 2, +// 3, 3, 3, 3, +// 4, +// 5, +// 6, 6, 6, +// 7, 7, 7, 7, 7, 7, +// 8, +// 9, 9, 9 +// }; +// } + +// std::vector get_directions() +// { +// return { +// true, +// true, +// true, +// true, +// true, +// true, +// true, +// true, +// true, +// true, +// true, +// true, +// true, +// true, +// false, +// false, +// true, +// true, +// true, +// true, +// true, +// true, +// true, +// true, +// false, +// false, +// false, +// true}; +// } + +std::vector< std::pair > compute_with_gudhi( + const std::vector >& simplices, + const std::vector& dirs) +{ + ZP zp(simplices.size()); + + std::cout << "====================== Gudhi =====================\n"; + + // std::vector filValues = get_filtration_values(); + std::vector filValues(simplices.size(), 1.0); + + auto start = simplices.begin(); + auto filIt = filValues.begin(); + unsigned int i = 0; + + while (start != simplices.end()){ + unsigned int c = 1; + auto end = start + 1; + ++i; + while (end != simplices.end() && dirs[i - 1] == dirs[i]) { + ++end; + ++i; + ++c; + } + + if (dirs[i - 1]){ + zp.insert_simplices_contiguously( + start, end, filIt); + } else { + zp.remove_simplices_contiguously( + start, end, filIt); + } + + start = end; + filIt += c; + // print_complex(zp); + } + + std::cout << "==================================================\n"; + + // print_complex(zp); + // print_barcode(zp); + return print_indices(zp, i); +} + +std::vector< std::pair > compute_with_dionysus( + const std::vector >& simplices, + const std::vector& dirs) +{ + DField k; + std::unordered_map indices; + DZZ persistence(k); + std::vector< std::pair > res; + + std::cout << "==================== Dionysus ====================\n"; + + std::set essentials; + + unsigned int op = 0; + unsigned int idx = 0; + + for (const std::vector& simplex : simplices){ + Simplex c(simplex); + DIndex pair; + if (dirs[op]) { + indices.try_emplace(c, idx++); + // int dim = boost::distance(c.boundary(persistence.field())); + // dim = dim == 0 ? 0 : dim -1; + // fmt::print("[{}] Adding: {} : {}\n", op, c, dim); + pair = persistence.add(c.boundary(persistence.field()) | + boost::adaptors::transformed([&indices](const DChain& e) { + return DIChain(e.element(), indices.find(e.index())->second); + })); + } else { + // fmt::print("[{}] Removing: {} : {}\n", op, c, boost::distance(c.boundary(persistence.field())) - 1); + auto idxIt = indices.find(c); + pair = persistence.remove(idxIt->second); + indices.erase(idxIt); + } + + if (pair != DZZ::unpaired()) { + // fmt::print("{} - {}\n", pair, op); + res.emplace_back(pair, op); + essentials.erase(pair); + } else { + essentials.insert(essentials.end(), op); + } + op++; + } + + for (unsigned int v : essentials){ + // fmt::print("{} - inf\n", v); + res.emplace_back(v, op); + } + + std::cout << "==================================================\n"; + + return res; +} + +std::vector< std::tuple > compute_with_fzz( + const std::vector >& simplices, + const std::vector& dirs) +{ + std::vector< std::tuple > persistence; + // std::vector< std::pair > res; + FZZ::FastZigzag fzz; + + std::cout << "======================= FZZ ======================\n"; + + fzz.compute(simplices, dirs, &persistence); + + std::sort(persistence.begin(), persistence.end(), + [](const std::tuple& p1, const std::tuple& p2){ + if (std::get<1>(p1) == std::get<1>(p2)){ + return std::get<0>(p1) < std::get<0>(p2); + } + + return std::get<1>(p1) < std::get<1>(p2); + }); + + // for (auto& t : persistence) + // res.emplace_back(std::get<0>(t), std::get<1>(t)); + + // for (const auto& e : persistence) { + // std::cout << (std::get<0>(e) - 1) << " - "; + // if (static_cast(std::get<1>(e)) == simplices.size()) std::cout << "inf"; + // else std::cout << std::get<1>(e); + // std::cout << " (" << std::get<2>(e) << ")" << std::endl; + // } + + std::cout << "==================================================\n"; + + return persistence; +} + +bool are_equal(const std::vector >& gudhiRes, + const std::vector >& dioRes) +{ + if (gudhiRes.size() != dioRes.size()) return false; + + for (unsigned int i = 0; i < gudhiRes.size(); ++i){ + if (gudhiRes[i].first != dioRes[i].first || gudhiRes[i].second != dioRes[i].second) + return false; + } + + return true; +} + +bool are_equal(const std::vector >& gudhiRes, + const std::vector >& fzzRes) +{ + if (gudhiRes.size() != fzzRes.size()) return false; + + for (unsigned int i = 0; i < gudhiRes.size(); ++i){ + if (static_cast(gudhiRes[i].first) != std::get<0>(fzzRes[i]) - 1 || static_cast(gudhiRes[i].second) != std::get<1>(fzzRes[i])) + return false; + } + + return true; +} + +void print(const std::vector >& res, unsigned int infValue){ + for (const auto& p : res) { + std::cout << p.first << " - "; + if (p.second == infValue) std::cout << "inf"; + else std::cout << p.second; + std::cout << std::endl; + } +} + +void print(const std::vector >& res, int infValue){ + for (const auto& e : res) { + std::cout << (std::get<0>(e) - 1) << " - "; + if (std::get<1>(e) == infValue) std::cout << "inf"; + else std::cout << std::get<1>(e); + std::cout << std::endl; + } +} + +void print_differences(const std::vector >& gudhiRes, + const std::vector >& dioRes, + unsigned int infValue) +{ + for (unsigned int i = 0; i < gudhiRes.size(); ++i){ + if (gudhiRes[i].first != dioRes[i].first || gudhiRes[i].second != dioRes[i].second){ + std::string dg = gudhiRes[i].second == infValue ? "inf" : std::to_string(gudhiRes[i].second); + std::string dd = dioRes[i].second == infValue ? "inf" : std::to_string(dioRes[i].second); + std::cout << "[" << i << "] " + << gudhiRes[i].first << " - " << dg + << " / " + << dioRes[i].first << " - " << dd + << "\n"; + } + } +} + +void print_differences(const std::vector >& gudhiRes, + const std::vector >& fzzRes, + int infValue) +{ + for (unsigned int i = 0; i < gudhiRes.size(); ++i){ + if (static_cast(gudhiRes[i].first) != std::get<0>(fzzRes[i]) || static_cast(gudhiRes[i].second) != std::get<1>(fzzRes[i])){ + std::string dg = static_cast(gudhiRes[i].second) == infValue ? "inf" : std::to_string(gudhiRes[i].second); + std::string dd = std::get<1>(fzzRes[i]) == infValue ? "inf" : std::to_string(std::get<1>(fzzRes[i])); + std::cout << "[" << i << "] " + << gudhiRes[i].first << " - " << dg + << " / " + << std::get<0>(fzzRes[i]) << " - " << dd + << "\n"; + } + } +} + + + +int main(int argc, char* const argv[]) { + if (argc < 2 || argc > 3) { + std::cout << "Wrong arguments.\n"; + return 0; + } + + // std::vector > simplices = get_simplices(); + // std::vector dirs = get_directions(); + std::vector > simplices; + std::vector dirs; + + unsigned int numberOfPoints = std::stoi(argv[1]); + int seed = -1; + + if (argc == 3) + seed = std::stoi(argv[2]); + + unsigned int numberOfSimplices = build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); + std::cout << "\n" << "numberOfSimplices: " << numberOfSimplices << "\n"; + + auto gudhiRes = compute_with_gudhi(simplices, dirs); + auto dioRes = compute_with_dionysus(simplices, dirs); + auto fzzRes = compute_with_fzz(simplices, dirs); + + std::cout << "Res sizes: " << gudhiRes.size() << ", " << dioRes.size() << ", " << fzzRes.size() << "\n"; + + bool firstRes = are_equal(gudhiRes, dioRes); + if (!firstRes){ + std::cout << "------------------------ Gudhi and Dionysus results are not equal!\n"; + // print(gudhiRes, numberOfSimplices); + // std::cout << "------------------------\n"; + // print(dioRes, numberOfSimplices); + print_differences(gudhiRes, dioRes, numberOfSimplices); + } else { + std::cout << "+++++++++++++++++++++++++ Gudhi and Dionysus results are equal.\n"; + } + + if (!are_equal(gudhiRes, fzzRes)){ + std::cout << "------------------------ Gudhi and FZZ results are not equal!\n"; + // if (firstRes) { + // print(gudhiRes, numberOfSimplices); + // std::cout << "------------------------\n"; + // } + // print(fzzRes, numberOfSimplices); + } else { + std::cout << "+++++++++++++++++++++++++ Gudhi and FZZ results are equal.\n"; + } + + return 0; +} diff --git a/src/Zigzag_persistence/example/example_rips_zigzag_filtration.cpp b/src/Zigzag_persistence/example/example_rips_zigzag_filtration.cpp new file mode 100644 index 0000000000..ed021faecc --- /dev/null +++ b/src/Zigzag_persistence/example/example_rips_zigzag_filtration.cpp @@ -0,0 +1,158 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Hannah Schreiber + * + * Copyright (C) 2014 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +#include // atoi, getenv +#include // size_t +#include // printf +#include // strcmp +#include // read, write +#include +#include + +#include +#include +#include + +#include +#include // for pair +#include + +#include "rips-zigzag-dionysus.h" + +using ST = Gudhi::Simplex_tree; +using Gudhi::persistence_matrix::Zigzag_options; +using CT = Gudhi::persistence_matrix::Column_types; +using ZP = Gudhi::zigzag_persistence::Zigzag_persistence >; +// using coltype = Gudhi::zigzag_persistence::Zigzag_persistence_collist; +// using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; +using Vertex_handle = ST::Vertex_handle; +using Filtration_value = ST::Filtration_value; +using interval_filtration = ZP::interval_filtration; + +std::vector< std::pair > print_indices(ZP& zp, unsigned int numberOfSimplices){ + std::set essentials; + std::vector< std::pair > res; + + for (unsigned int i = 0; i < numberOfSimplices; ++i){ + essentials.insert(essentials.end(), i); + } + + for (auto& bar : zp.index_persistence_diagram()){ + res.emplace_back(bar.birth(), bar.death()); + essentials.erase(bar.birth()); + essentials.erase(bar.death()); + } + + for (unsigned int v : essentials){ + res.emplace_back(v, numberOfSimplices); + } + + return res; +} + +std::vector< std::pair > compute_with_gudhi( + const std::vector >& simplices, + const std::vector& dirs) +{ + ZP zp(simplices.size()); + + // std::cout << "====================== Gudhi =====================\n"; + + std::vector filValues(simplices.size(), 1.0); + + auto start = simplices.begin(); + auto filIt = filValues.begin(); + unsigned int i = 0; + + while (start != simplices.end()){ + unsigned int c = 1; + auto end = start + 1; + ++i; + while (end != simplices.end() && dirs[i - 1] == dirs[i]) { + ++end; + ++i; + ++c; + } + + if (dirs[i - 1]){ + zp.insert_simplices_contiguously( + start, end, filIt); + } else { + zp.remove_simplices_contiguously( + start, end, filIt); + } + + start = end; + filIt += c; + } + + // std::cout << "==================================================\n"; + + return print_indices(zp, i); +} + +int main(int argc, char* const argv[]) { + if (argc < 2 || argc > 3) { + std::cout << "Wrong arguments.\n"; + return 0; + } + + int perf_ctl_fd = open("/tmp/perf_ctl.fifo",O_WRONLY); + int perf_ctl_ack_fd = open("/tmp/perf_ctl_ack.fifo",O_RDONLY); + char ack[5]; + std::cout << "perf_ctl_fd: " << perf_ctl_fd << "\n"; + std::cout << "perf_ctl_ack_fd: " << perf_ctl_ack_fd << "\n"; + + unsigned int numberOfPoints = std::stoi(argv[1]); + int seed = -1; + if (argc == 3) + seed = std::stoi(argv[2]); + + std::vector > simplices; + std::vector dirs; + + unsigned int numberOfSimplices = build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); + std::cout << "Filtration size: " << simplices.size() << "\n"; + std::cout << "Number of simplices: " << numberOfSimplices << "\n"; + + // Start the performance counter and read the ack + if (perf_ctl_fd != -1){ + write(perf_ctl_fd, "enable\n", 8); + read(perf_ctl_ack_fd, ack, 5); + if(std::strcmp(ack, "ack\n") != 0){ + std::cout << "No acknowledgment\n"; + return 1; + } + } + + Gudhi::Clock time("Zigzag Rips"); + /* auto res = */compute_with_gudhi(simplices, dirs); + time.end(); + std::cout << time; + + // Stop the performance counter and read the ack + if (perf_ctl_fd != -1){ + write(perf_ctl_fd, "disable\n", 9); + read(perf_ctl_ack_fd, ack, 5); + if(std::strcmp(ack, "ack\n") != 0){ + std::cout << "No acknowledgment\n"; + return 1; + } + } + + // for (const auto& p : res) { + // std::cout << p.first << " - "; + // if (p.second == numberOfSimplices) std::cout << "inf"; + // else std::cout << p.second; + // std::cout << std::endl; + // } + + return 0; +} diff --git a/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp b/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp new file mode 100644 index 0000000000..4750eb5358 --- /dev/null +++ b/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp @@ -0,0 +1,118 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Hannah Schreiber + * + * Copyright (C) 2014 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +#include +#include + +#include +#include // for pair +#include + +using ST = Gudhi::Simplex_tree; +using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; +using Vertex_handle = ST::Vertex_handle; +using Filtration_value = ST::Filtration_value; +using interval_filtration = ZP::interval_filtration; + +void print_complex(ZP& zp){ + std::clog << std::endl << "Current complex:" << std::endl; + zp.print_current_complex(); +} + +void print_barcode(ZP& zp){ + std::clog << std::endl << "Current barcode:" << std::endl; + for (auto& bar : zp.persistence_diagram()){ + std::clog << std::floor(bar.birth()) << " - "; + if (bar.death() == std::numeric_limits::infinity()){ + std::clog << "inf"; + } else { + std::clog << std::floor(bar.death()); + } + std::clog << " (" << bar.dim() << ")\n"; + } +} + +void print_indices(ZP& zp){ + std::clog << std::endl << "Current pairs:" << std::endl; + for (auto& bar : zp.index_persistence_diagram()){ + std::clog << bar.birth() << " - "; + std::clog << bar.death(); + std::clog << " (" << bar.dim() << ")\n"; + } +} + +int main(int argc, char* const argv[]) { + ZP zp; + + std::vector > simplices{ + {0},{1},{2}, + {0,1},{0,2},{3}, + {1,2},{4},{3,4}, + {5},{0,1,2},{4,5},{3,5}}; + std::vector fils{0,0,0,1,1,1,2,2,2,3,3,3,3}; + zp.insert_simplices_contiguously(simplices, fils); + + print_complex(zp); + print_barcode(zp); + print_indices(zp); + + std::vector simplex{3,4,5}; + zp.insert_simplex(simplex, 4); + + print_complex(zp); + print_barcode(zp); + print_indices(zp); + + simplex[0] = 0; + simplex[1] = 1; + simplex[2] = 2; + zp.remove_simplex(simplex, 5); + + print_complex(zp); + print_barcode(zp); + print_indices(zp); + + simplex[0] = 3; + simplex[1] = 4; + simplex[2] = 5; + zp.remove_simplex(simplex, 6); + + print_complex(zp); + print_barcode(zp); + print_indices(zp); + + simplices = {{1,4},{0,1,2},{2,4},{3,4,5},{0,4},{0,2,4},{1,2,4},{0,1,4}}; + fils = {6,6,7,7,7,7,7,7}; + zp.insert_simplices_contiguously(simplices, fils); + + print_complex(zp); + print_barcode(zp); + print_indices(zp); + + simplices = {{3,4,5},{3,4},{3,5}}; + fils = {8,9,9}; + zp.remove_simplices_contiguously(simplices, fils); + + print_complex(zp); + print_barcode(zp); + print_indices(zp); + + simplex[0] = 0; + simplex[1] = 1; + simplex[2] = 2; + simplex.push_back(4); + zp.insert_simplex(simplex, 9); + + print_complex(zp); + print_barcode(zp); + print_indices(zp); + + return 0; +} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/chain.h b/src/Zigzag_persistence/example/ext_zz/dionysus/chain.h new file mode 100644 index 0000000000..00c983623a --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/chain.h @@ -0,0 +1,153 @@ +#ifndef DIONYSUS_CHAIN_H +#define DIONYSUS_CHAIN_H + +#include +#include +#include + +#include "fields/z2.h" + +namespace dionysus +{ + +template +struct FieldElement +{ + typedef typename Field::Element Element; + FieldElement(Element e_): + e(e_) {} + Element element() const { return e; } + void set_element(Element e_) { e = e_; } + Element e; +}; + +template<> +struct FieldElement +{ + typedef Z2Field::Element Element; + FieldElement(Element) {} + Element element() const { return Z2Field::id(); } + void set_element(Element) {} +}; + +template +struct ChainEntry: public FieldElement, public Extra... +{ + typedef Field_ Field; + typedef Index_ Index; + + typedef FieldElement Parent; + typedef typename Parent::Element Element; + + ChainEntry(): Parent(Element()), i(Index()) {} // need for serialization + + ChainEntry(ChainEntry&& other) = default; + ChainEntry(const ChainEntry& other) = default; + ChainEntry& operator=(ChainEntry&& other) = default; + + ChainEntry(Element e_, const Index& i_): + Parent(e_), i(i_) {} + + ChainEntry(Element e_, Index&& i_): + Parent(e_), i(std::move(i_)) {} + + const Index& index() const { return i; } + Index& index() { return i; } + + // debug + bool operator==(const ChainEntry& other) const { return i == other.i; } + + Index i; +}; + +template +struct Chain +{ + struct Visitor + { + template + void first(Iter it) const {} + + template + void second(Iter it) const {} + + template + void equal_keep(Iter it) const {} + + template + void equal_drop(Iter it) const {} + }; + + // x += a*y + template + static void addto(C1& x, typename Field::Element a, const C2& y, const Field& field, const Cmp& cmp, const Visitor_& = Visitor_()); +}; + +template +struct Chain> +{ + struct Visitor + { + template + void first(Iter it) const {} + + template + void second(Iter it) const {} + + template + void equal_keep(Iter it) const {} + + template + void equal_drop(Iter it) const {} + }; + + // x += a*y + template + static void addto(std::list& x, typename Field::Element a, const C2& y, + const Field& field, const Cmp& cmp, const Visitor_& visitor = Visitor_()); +}; + + +template +struct Chain> +{ + struct Visitor + { + template + void first(Iter it) const {} + + template + void second(Iter it) const {} + + template + void equal_keep(Iter it) const {} + + template + void equal_drop(Iter it) const {} + }; + + // x += a*y + template + static void addto(std::set& x, typename Field::Element a, const C2& y, + const Field& field, const Cmp& cmp, const Visitor_& = Visitor_()); + + template + static void addto(std::set& x, typename Field::Element a, T&& y, + const Field& field, const Cmp& cmp, const Visitor_& = Visitor_()); +}; + +} + +//namespace std +//{ +// template +// void swap(::dionysus::ChainEntry& x, ::dionysus::ChainEntry& y) +// { +// std::swap(x.e, y.e); +// std::swap(x.i, y.i); +// } +//} + +#include "chain.hpp" + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/chain.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/chain.hpp new file mode 100644 index 0000000000..4da9f44615 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/chain.hpp @@ -0,0 +1,188 @@ +template +template +void +dionysus::Chain>:: +addto(std::list& x, typename Field::Element a, const C2& y, const Field& field, const Cmp& cmp, const Visitor_& visitor) +{ + typedef typename Field::Element Element; + + auto cur_x = std::begin(x), + end_x = std::end(x); + auto cur_y = std::begin(y), + end_y = std::end(y); + + while (cur_x != end_x && cur_y != end_y) + { + if (cmp(cur_x->index(), cur_y->index())) + { + visitor.first(cur_x++); + } else if (cmp(cur_y->index(), cur_x->index())) + { + // multiply and add + Element ay = field.mul(a, cur_y->element()); + auto nw_x = x.insert(cur_x, *cur_y); + nw_x->set_element(ay); + ++cur_y; + visitor.second(nw_x); + } else + { + Element ay = field.mul(a, cur_y->element()); + Element r = field.add(cur_x->element(), ay); + if (field.is_zero(r)) + { + visitor.equal_drop(cur_x); + x.erase(cur_x++); + } + else + { + cur_x->set_element(r); + visitor.equal_keep(cur_x); + ++cur_x; + } + ++cur_y; + } + } + + for (auto it = cur_y; it != end_y; ++it) + { + Element ay = field.mul(a, it->element()); + x.push_back(*it); + x.back().set_element(ay); + visitor.second(--x.end()); + } +} + +template +template +void +dionysus::Chain>:: +addto(std::set& x, typename Field::Element a, const C2& y, const Field& field, const Cmp&, const Visitor_& visitor) +{ + typedef typename Field::Element Element; + + auto cur_y = std::begin(y), + end_y = std::end(y); + + while (cur_y != end_y) + { + auto cur_x = x.find(*cur_y); + if (cur_x == x.end()) + { + auto nw = x.insert(*cur_y).first; + Element ay = field.mul(a, nw->element()); + const_cast(*nw).set_element(ay); + visitor.second(nw); + } else + { + Element ay = field.mul(a, cur_y->element()); + Element r = field.add(cur_x->element(), ay); + if (field.is_zero(r)) + { + visitor.equal_drop(cur_x); + x.erase(cur_x); + } + else + { + const_cast(*cur_x).set_element(r); + visitor.equal_keep(cur_x); + } + } + ++cur_y; + } +} + +template +template +void +dionysus::Chain>:: +addto(std::set& x, typename Field::Element a, T&& y, const Field& field, const Cmp&, const Visitor_& visitor) +{ + typedef typename Field::Element Element; + + auto cur_x = x.find(y); + if (cur_x == x.end()) + { + auto nw = x.insert(std::move(y)).first; + Element ay = field.mul(a, nw->element()); + const_cast(*nw).set_element(ay); + visitor.second(nw); + } else + { + Element ay = field.mul(a, y.element()); + Element r = field.add(cur_x->element(), ay); + if (field.is_zero(r)) + { + visitor.equal_drop(cur_x); + x.erase(cur_x); + } + else + { + const_cast(*cur_x).set_element(r); + visitor.equal_keep(cur_x); + } + } +} + +template +template +void +dionysus::Chain:: +addto(C1& x, typename Field::Element a, const C2& y, const Field& field, const Cmp& cmp, const Visitor_& visitor) +{ + typedef typename Field::Element Element; + + C1 res; + + auto cur_x = std::begin(x), + end_x = std::end(x); + auto cur_y = std::begin(y), + end_y = std::end(y); + + while (cur_x != end_x && cur_y != end_y) + { + if (cmp(*cur_x, *cur_y)) + { + res.emplace_back(std::move(*cur_x)); + visitor.first(--res.end()); + ++cur_x; + } else if (cmp(*cur_y, *cur_x)) + { + // multiply and add + Element ay = field.mul(a, cur_y->element()); + res.emplace_back(ay, cur_y->index()); + visitor.second(--res.end()); + ++cur_y; + } else + { + Element ay = field.mul(a, cur_y->element()); + Element r = field.add(cur_x->element(), ay); + if (field.is_zero(r)) + visitor.equal_drop(cur_x); + else + { + res.emplace_back(std::move(*cur_x)); + res.back().set_element(r); + visitor.equal_keep(--res.end()); + } + ++cur_x; + ++cur_y; + } + } + + while (cur_y != end_y) + { + Element ay = field.mul(a, cur_y->element()); + res.emplace_back(ay, cur_y->index()); + visitor.second(--res.end()); + ++cur_y; + } + + while (cur_x != end_x) + { + res.emplace_back(std::move(*cur_x)); + visitor.first(--res.end()); + ++cur_x; + } + + x.swap(res); +} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/clearing-reduction.h b/src/Zigzag_persistence/example/ext_zz/dionysus/clearing-reduction.h new file mode 100644 index 0000000000..8651e9a69a --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/clearing-reduction.h @@ -0,0 +1,45 @@ +#ifndef DIONYSUS_CLEARING_REDUCTION_H +#define DIONYSUS_CLEARING_REDUCTION_H + +namespace dionysus +{ + +// Mid-level interface +template +class ClearingReduction +{ + public: + using Persistence = Persistence_; + using Field = typename Persistence::Field; + using Index = typename Persistence::Index; + + public: + ClearingReduction(Persistence& persistence): + persistence_(persistence) {} + + template + void operator()(const Filtration& f, const Relative& relative, const ReportPair& report_pair, const Progress& progress); + + template + void operator()(const Filtration& f, const ReportPair& report_pair); + + template + void operator()(const Filtration& f) { return (*this)(f, &no_report_pair); } + + static void no_report_pair(int, Index, Index) {} + static void no_progress() {} + + const Persistence& + persistence() const { return persistence_; } + Persistence& persistence() { return persistence_; } + + private: + Persistence& persistence_; +}; + +} + +#include "clearing-reduction.hpp" + +#endif + diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/clearing-reduction.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/clearing-reduction.hpp new file mode 100644 index 0000000000..ceac11879d --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/clearing-reduction.hpp @@ -0,0 +1,60 @@ +#include +#include + +#include +namespace ba = boost::adaptors; + +template +template +void +dionysus::ClearingReduction

:: +operator()(const Filtration& filtration, const ReportPair& report_pair) +{ + using Cell = typename Filtration::Cell; + (*this)(filtration, [](const Cell&) { return false; }, report_pair, &no_progress); +} + +template +template +void +dionysus::ClearingReduction

:: +operator()(const Filtration& filtration, const Relative& relative, const ReportPair& report_pair, const Progress& progress) +{ + persistence_.resize(filtration.size()); + + // sort indices by decreasing dimension + std::vector indices(filtration.size()); + std::iota(indices.begin(), indices.end(), 0); + std::stable_sort(indices.begin(), indices.end(), + [&filtration](size_t x, size_t y) + { return filtration[x].dimension() > filtration[y].dimension(); }); + + typedef typename Filtration::Cell Cell; + typedef ChainEntry CellChainEntry; + typedef ChainEntry ChainEntry; + + for(size_t i : indices) + { + progress(); + const auto& c = filtration[i]; + + if (relative(c)) + { + persistence_.set_skip(i); + continue; + } + + if (persistence_.pair(i) != persistence_.unpaired()) + continue; + + persistence_.set(i, c.boundary(persistence_.field()) | + ba::filtered([relative](const CellChainEntry& e) { return !relative(e.index()); }) | + ba::transformed([this,&filtration](const CellChainEntry& e) + { return ChainEntry(e.element(), filtration.index(e.index())); })); + + Index pair = persistence_.reduce(i); + if (pair != persistence_.unpaired()) + report_pair(c.dimension(), pair, i); + } +} + diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/cnpy.h b/src/Zigzag_persistence/example/ext_zz/dionysus/cnpy.h new file mode 100644 index 0000000000..b11013b9d7 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/cnpy.h @@ -0,0 +1,241 @@ +//Copyright (C) 2011 Carl Rogers +//Released under MIT License +//license available in LICENSE file, or at http://www.opensource.org/licenses/mit-license.php + +#ifndef LIBCNPY_H_ +#define LIBCNPY_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace cnpy { + + struct NpyArray { + char* data; + std::vector shape; + unsigned int word_size; + bool fortran_order; + void destruct() {delete[] data;} + }; + + struct npz_t : public std::map + { + void destruct() + { + npz_t::iterator it = this->begin(); + for(; it != this->end(); ++it) (*it).second.destruct(); + } + }; + + char BigEndianTest(); + char map_type(const std::type_info& t); + template std::vector create_npy_header(const T* data, const unsigned int* shape, const unsigned int ndims); + void parse_npy_header(FILE* fp,unsigned int& word_size, unsigned int*& shape, unsigned int& ndims, bool& fortran_order); + void parse_zip_footer(FILE* fp, unsigned short& nrecs, unsigned int& global_header_size, unsigned int& global_header_offset); + npz_t npz_load(std::string fname); + NpyArray npz_load(std::string fname, std::string varname); + NpyArray npy_load(std::string fname); + + template std::vector& operator+=(std::vector& lhs, const T rhs) { + //write in little endian + for(char byte = 0; byte < sizeof(T); byte++) { + char val = *((char*)&rhs+byte); + lhs.push_back(val); + } + return lhs; + } + + template<> std::vector& operator+=(std::vector& lhs, const std::string rhs); + template<> std::vector& operator+=(std::vector& lhs, const char* rhs); + + + template std::string tostring(T i, int pad = 0, char padval = ' ') { + std::stringstream s; + s << i; + return s.str(); + } + + template void npy_save(std::string fname, const T* data, const unsigned int* shape, const unsigned int ndims, std::string mode = "w") { + FILE* fp = NULL; + + if(mode == "a") fp = fopen(fname.c_str(),"r+b"); + + if(fp) { + //file exists. we need to append to it. read the header, modify the array size + unsigned int word_size, tmp_dims; + unsigned int* tmp_shape = 0; + bool fortran_order; + parse_npy_header(fp,word_size,tmp_shape,tmp_dims,fortran_order); + assert(!fortran_order); + + if(word_size != sizeof(T)) { + std::cout<<"libnpy error: "< header = create_npy_header(data,tmp_shape,ndims); + fwrite(&header[0],sizeof(char),header.size(),fp); + fseek(fp,0,SEEK_END); + + delete[] tmp_shape; + } + else { + fp = fopen(fname.c_str(),"wb"); + std::vector header = create_npy_header(data,shape,ndims); + fwrite(&header[0],sizeof(char),header.size(),fp); + } + + unsigned int nels = 1; + for(int i = 0;i < ndims;i++) nels *= shape[i]; + + fwrite(data,sizeof(T),nels,fp); + fclose(fp); + } + + template void npz_save(std::string zipname, std::string fname, const T* data, const unsigned int* shape, const unsigned int ndims, std::string mode = "w") + { + //first, append a .npy to the fname + fname += ".npy"; + + //now, on with the show + FILE* fp = NULL; + unsigned short nrecs = 0; + unsigned int global_header_offset = 0; + std::vector global_header; + + if(mode == "a") fp = fopen(zipname.c_str(),"r+b"); + + if(fp) { + //zip file exists. we need to add a new npy file to it. + //first read the footer. this gives us the offset and size of the global header + //then read and store the global header. + //below, we will write the the new data at the start of the global header then append the global header and footer below it + unsigned int global_header_size; + parse_zip_footer(fp,nrecs,global_header_size,global_header_offset); + fseek(fp,global_header_offset,SEEK_SET); + global_header.resize(global_header_size); + size_t res = fread(&global_header[0],sizeof(char),global_header_size,fp); + if(res != global_header_size){ + throw std::runtime_error("npz_save: header read error while adding to existing zip"); + } + fseek(fp,global_header_offset,SEEK_SET); + } + else { + fp = fopen(zipname.c_str(),"wb"); + } + + std::vector npy_header = create_npy_header(data,shape,ndims); + + unsigned long nels = 1; + for (int m=0; m local_header; + local_header += "PK"; //first part of sig + local_header += (unsigned short) 0x0403; //second part of sig + local_header += (unsigned short) 20; //min version to extract + local_header += (unsigned short) 0; //general purpose bit flag + local_header += (unsigned short) 0; //compression method + local_header += (unsigned short) 0; //file last mod time + local_header += (unsigned short) 0; //file last mod date + local_header += (unsigned int) crc; //crc + local_header += (unsigned int) nbytes; //compressed size + local_header += (unsigned int) nbytes; //uncompressed size + local_header += (unsigned short) fname.size(); //fname length + local_header += (unsigned short) 0; //extra field length + local_header += fname; + + //build global header + global_header += "PK"; //first part of sig + global_header += (unsigned short) 0x0201; //second part of sig + global_header += (unsigned short) 20; //version made by + global_header.insert(global_header.end(),local_header.begin()+4,local_header.begin()+30); + global_header += (unsigned short) 0; //file comment length + global_header += (unsigned short) 0; //disk number where file starts + global_header += (unsigned short) 0; //internal file attributes + global_header += (unsigned int) 0; //external file attributes + global_header += (unsigned int) global_header_offset; //relative offset of local file header, since it begins where the global header used to begin + global_header += fname; + + //build footer + std::vector footer; + footer += "PK"; //first part of sig + footer += (unsigned short) 0x0605; //second part of sig + footer += (unsigned short) 0; //number of this disk + footer += (unsigned short) 0; //disk where footer starts + footer += (unsigned short) (nrecs+1); //number of records on this disk + footer += (unsigned short) (nrecs+1); //total number of records + footer += (unsigned int) global_header.size(); //nbytes of global headers + footer += (unsigned int) (global_header_offset + nbytes + local_header.size()); //offset of start of global headers, since global header now starts after newly written array + footer += (unsigned short) 0; //zip file comment length + + //write everything + fwrite(&local_header[0],sizeof(char),local_header.size(),fp); + fwrite(&npy_header[0],sizeof(char),npy_header.size(),fp); + fwrite(data,sizeof(T),nels,fp); + fwrite(&global_header[0],sizeof(char),global_header.size(),fp); + fwrite(&footer[0],sizeof(char),footer.size(),fp); + fclose(fp); + } + + template std::vector create_npy_header(const T* data, const unsigned int* shape, const unsigned int ndims) { + + std::vector dict; + dict += "{'descr': '"; + dict += BigEndianTest(); + dict += map_type(typeid(T)); + dict += tostring(sizeof(T)); + dict += "', 'fortran_order': False, 'shape': ("; + dict += tostring(shape[0]); + for(int i = 1;i < ndims;i++) { + dict += ", "; + dict += tostring(shape[i]); + } + if(ndims == 1) dict += ","; + dict += "), }"; + //pad with spaces so that preamble+dict is modulo 16 bytes. preamble is 10 bytes. dict needs to end with \n + int remainder = 16 - (10 + dict.size()) % 16; + dict.insert(dict.end(),remainder,' '); + dict.back() = '\n'; + + std::vector header; + header += (char) 0x93; + header += "NUMPY"; + header += (char) 0x01; //major version of numpy format + header += (char) 0x00; //minor version of numpy format + header += (unsigned short) dict.size(); + header.insert(header.end(),dict.begin(),dict.end()); + + return header; + } + + +} + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/cohomology-persistence.h b/src/Zigzag_persistence/example/ext_zz/dionysus/cohomology-persistence.h new file mode 100644 index 0000000000..8d2019e89d --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/cohomology-persistence.h @@ -0,0 +1,116 @@ +#ifndef DIONYSUS_COHOMOLOGY_PERSISTENCE_H +#define DIONYSUS_COHOMOLOGY_PERSISTENCE_H + +#include +#include + +#include +namespace bi = boost::intrusive; + +#include "reduction.h" +#include "chain.h" + +namespace dionysus +{ + +template> +class CohomologyPersistence +{ + public: + typedef Field_ Field; + typedef Index_ Index; + typedef Comparison_ Comparison; + + typedef typename Field::Element FieldElement; + + typedef bi::list_base_hook> auto_unlink_hook; + struct Entry; + struct ColumnHead; + + typedef std::vector Column; + typedef bi::list> Row; + typedef std::list Columns; + typedef typename Columns::iterator ColumnsIterator; + typedef Column Chain; + + using IndexColumn = std::tuple; + + CohomologyPersistence(const Field& field, + const Comparison& cmp = Comparison()): + field_(field), cmp_(cmp) {} + + CohomologyPersistence(Field&& field, + const Comparison& cmp = Comparison()): + field_(std::move(field)), + cmp_(cmp) {} + + CohomologyPersistence(CohomologyPersistence&& other): + field_(std::move(other.field_)), + cmp_(std::move(other.cmp_)), + columns_(std::move(other.columns_)), + rows_(std::move(other.rows_)) {} + + template + Index add(const ChainRange& chain); + + template + IndexColumn add(const ChainRange& chain, bool keep_cocycle); + + // TODO: no skip support for now + bool skip(Index) const { return false; } + void add_skip() {} + void set_skip(Index, bool flag = true) {} + + const Field& field() const { return field_; } + const Columns& columns() const { return columns_; } + void reserve(size_t s) { rows_.reserve(s); } + + struct AddtoVisitor; + + static const Index unpaired() { return Reduction::unpaired; } + + private: + Field field_; + Comparison cmp_; + Columns columns_; + std::vector rows_; +}; + + +template +struct CohomologyPersistence::ColumnHead +{ + ColumnHead(Index i): index_(i) {} + + Index index() const { return index_; } + + Index index_; + Column chain; +}; + +template +struct CohomologyPersistence::Entry: + public ChainEntry +{ + typedef ChainEntry Parent; + + Entry(FieldElement e, const Index& i): // slightly dangerous + Parent(e,i) {} + + Entry(FieldElement e, const Index& i, ColumnsIterator it): + Parent(e,i), column(it) {} + + Entry(const Entry& other) = default; + Entry(Entry&& other) = default; + + void unlink() { auto_unlink_hook::unlink(); } + bool is_linked() const { return auto_unlink_hook::is_linked(); } + + ColumnsIterator column; // TODO: I really don't like this overhead +}; + +} + +#include "cohomology-persistence.hpp" + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/cohomology-persistence.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/cohomology-persistence.hpp new file mode 100644 index 0000000000..b2334f99e1 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/cohomology-persistence.hpp @@ -0,0 +1,61 @@ +template +template +typename dionysus::CohomologyPersistence::Index +dionysus::CohomologyPersistence:: +add(const ChainRange& chain) +{ + return std::get<0>(add(chain, false)); // return just the index +} + + +template +template +typename dionysus::CohomologyPersistence::IndexColumn +dionysus::CohomologyPersistence:: +add(const ChainRange& chain, bool keep_cocycle) +{ + auto entry_cmp = [this](const Entry& e1, const Entry& e2) { return this->cmp_(e1.index(), e2.index()); }; + std::set row_sum(entry_cmp); + for (auto it = std::begin(chain); it != std::end(chain); ++it) + for (auto& re : rows_[it->index()]) + dionysus::Chain::addto(row_sum, it->element(), Entry(re.element(), re.column->index(), re.column), field_, cmp_); + + if (row_sum.empty()) // Birth + { + columns_.emplace_back(rows_.size()); + auto before_end = columns_.end(); + --before_end; + columns_.back().chain.push_back(Entry(field_.id(), rows_.size(), before_end)); + rows_.emplace_back(); + rows_.back().push_back(columns_.back().chain.front()); + return std::make_tuple(unpaired(), Column()); + } else // Death + { + // Select front element in terms of comparison (rows are unsorted) + auto it = std::max_element(std::begin(row_sum), std::end(row_sum), entry_cmp); + + Entry first = std::move(*it); + row_sum.erase(it); + + for (auto& ce : row_sum) + { + FieldElement ay = field_.neg(field_.div(ce.element(), first.element())); + dionysus::Chain::addto(ce.column->chain, ay, first.column->chain, field_, + [this](const Entry& e1, const Entry& e2) + { return this->cmp_(e1.index(), e2.index()); }); + + for (auto& x : ce.column->chain) + { + x.column = ce.column; + rows_[x.index()].push_back(x); + } + } + Index pair = first.column->index(); + Column cocycle; + if (keep_cocycle) + cocycle = std::move(first.column->chain); + columns_.erase(first.column); + rows_.emplace_back(); // useless row; only present to make indices match + return std::make_tuple(pair, cocycle); + } +} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/common.h b/src/Zigzag_persistence/example/ext_zz/dionysus/common.h new file mode 100644 index 0000000000..e012b10539 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/common.h @@ -0,0 +1,25 @@ +#ifndef DIONYSUS_EXAMPLES_COMMON_H +#define DIONYSUS_EXAMPLES_COMMON_H + +#include +#include + +template +void read_points(const std::string& infilename, PointContainer& points) +{ + typedef typename PointContainer::value_type Point; + + std::ifstream in(infilename.c_str()); + std::string line; + while(std::getline(in, line)) + { + if (line[0] == '#') continue; // comment line in the file + std::stringstream linestream(line); + double x; + points.push_back(Point()); + while (linestream >> x) + points.back().push_back(x); + } +} + +#endif // DIONYSUS_EXAMPLES_COMMON_H diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/diagram.h b/src/Zigzag_persistence/example/ext_zz/dionysus/diagram.h new file mode 100644 index 0000000000..04eb29a927 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/diagram.h @@ -0,0 +1,114 @@ +#ifndef DIONYSUS_DIAGRAM_H +#define DIONYSUS_DIAGRAM_H + +#include +#include +#include + +namespace dionysus +{ + +template +class Diagram +{ + public: + using Value = Value_; + using Data = Data_; + struct Point: public std::pair + { + using Parent = std::pair; + + Point(Value b, Value d, Data dd): + Parent(b,d), data(dd) {} + + Value birth() const { return Parent::first; } + Value death() const { return Parent::second; } + + // FIXME: temporary hack + Value operator[](size_t i) const { if (i == 0) return birth(); return death(); } + + Data data; + }; + + using Points = std::vector; + using iterator = typename Points::iterator; + using const_iterator = typename Points::const_iterator; + using value_type = Point; + + public: + const_iterator begin() const { return points.begin(); } + const_iterator end() const { return points.end(); } + iterator begin() { return points.begin(); } + iterator end() { return points.end(); } + + const Point& operator[](size_t i) const { return points[i]; } + + size_t size() const { return points.size(); } + void push_back(const Point& p) { points.push_back(p); } + template + void emplace_back(Args&&... args) { points.emplace_back(std::forward(args)...); } + + private: + std::vector points; +}; + +namespace detail +{ + template + struct Diagrams + { + using Value = decltype(std::declval()(std::declval())); + using Data = decltype(std::declval()(std::declval())); + using type = std::vector>; + }; +} + +template +typename detail::Diagrams::type +init_diagrams(const ReducedMatrix& m, const Filtration& f, const GetValue& get_value, const GetData& get_data) +{ + using Result = typename detail::Diagrams::type; + + Result diagrams; + for (typename ReducedMatrix::Index i = 0; i < m.size(); ++i) + { + if (m.skip(i)) + continue; + + auto s = f[i]; + auto d = s.dimension(); + + while (d + 1 > diagrams.size()) + diagrams.emplace_back(); + + auto pair = m.pair(i); + if (pair == m.unpaired()) + { + auto birth = get_value(s); + using Value = decltype(birth); + Value death = std::numeric_limits::infinity(); + diagrams[d].emplace_back(birth, death, get_data(i)); + } else if (pair > i) // positive + { + auto birth = get_value(s); + auto death = get_value(f[pair]); + + // hack to work with coboundaries + auto pd = f[pair].dimension(); + if (pd < d) + { + d = pd; + std::swap(birth, death); + } + + if (birth != death) // skip diagonal + diagrams[d].emplace_back(birth, death, get_data(i)); + } // else negative: do nothing + } + + return diagrams; +} + +} + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/distances.h b/src/Zigzag_persistence/example/ext_zz/dionysus/distances.h new file mode 100644 index 0000000000..29cac601af --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/distances.h @@ -0,0 +1,93 @@ +#ifndef DIONYSUS_DISTANCES_H +#define DIONYSUS_DISTANCES_H + +#include +#include + +namespace dionysus +{ + +/** + * Class: ExplicitDistances + * Stores the pairwise distances of Distances_ instance passed at construction. + * It's a protypical Distances template argument for the Rips complex. + */ +template +class ExplicitDistances +{ + public: + typedef Distances_ Distances; + typedef size_t IndexType; + typedef typename Distances::DistanceType DistanceType; + + ExplicitDistances(IndexType size): + size_(size), + distances_(size*(size + 1)/2 + size) {} + ExplicitDistances(const Distances& distances); + + DistanceType operator()(IndexType a, IndexType b) const; + DistanceType& operator()(IndexType a, IndexType b); + + size_t size() const { return size_; } + IndexType begin() const { return 0; } + IndexType end() const { return size(); } + + private: + std::vector distances_; + size_t size_; +}; + + +/** + * Class: PairwiseDistances + * Given a Container_ of points and a Distance_, it computes distances between elements + * in the container (given as instances of Index_ defaulted to unsigned) using the Distance_ functor. + * + * Container_ is assumed to be an std::vector. That simplifies a number of things. + */ +template +class PairwiseDistances +{ + public: + typedef Container_ Container; + typedef Distance_ Distance; + typedef Index_ IndexType; + typedef typename Distance::result_type DistanceType; + + + PairwiseDistances(const Container& container, + const Distance& distance = Distance()): + container_(container), distance_(distance) {} + + DistanceType operator()(IndexType a, IndexType b) const { return distance_(container_[a], container_[b]); } + + size_t size() const { return container_.size(); } + IndexType begin() const { return 0; } + IndexType end() const { return size(); } + + private: + const Container& container_; + Distance distance_; +}; + +template +struct L2Distance +{ + typedef Point_ Point; + typedef decltype(Point()[0] + 0) result_type; + + result_type operator()(const Point& p1, const Point& p2) const + { + result_type sum = 0; + for (size_t i = 0; i < p1.size(); ++i) + sum += (p1[i] - p2[i])*(p1[i] - p2[i]); + + return sqrt(sum); + } +}; + +} + +#include "distances.hpp" + +#endif // DIONYSUS_DISTANCES_H diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/distances.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/distances.hpp new file mode 100644 index 0000000000..9b1f20aa2b --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/distances.hpp @@ -0,0 +1,30 @@ +template +dionysus::ExplicitDistances:: +ExplicitDistances(const Distances& distances): + size_(distances.size()), distances_((distances.size() * (distances.size() + 1))/2) +{ + IndexType i = 0; + for (typename Distances::IndexType a = distances.begin(); a != distances.end(); ++a) + for (typename Distances::IndexType b = a; b != distances.end(); ++b) + { + distances_[i++] = distances(a,b); + } +} + +template +typename dionysus::ExplicitDistances::DistanceType +dionysus::ExplicitDistances:: +operator()(IndexType a, IndexType b) const +{ + if (a > b) std::swap(a,b); + return distances_[a*size_ - ((a*(a-1))/2) + (b-a)]; +} + +template +typename dionysus::ExplicitDistances::DistanceType& +dionysus::ExplicitDistances:: +operator()(IndexType a, IndexType b) +{ + if (a > b) std::swap(a,b); + return distances_[a*size_ - ((a*(a-1))/2) + (b-a)]; +} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/dlog/progress.h b/src/Zigzag_persistence/example/ext_zz/dionysus/dlog/progress.h new file mode 100644 index 0000000000..12bf86a4a2 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/dlog/progress.h @@ -0,0 +1,57 @@ +#ifndef DLOG_PROGRESS_H +#define DLOG_PROGRESS_H + +#include +#include +#include +#include + +namespace dlog +{ + +struct progress +{ + progress(size_t total): + current_(0), total_(total) { show_progress(); } + + progress& operator++() { current_++; if (current_ * 100 / total_ > (current_ - 1) * 100 / total_) show_progress(); check_done(); return *this; } + progress& operator=(size_t cur) { current_ = cur; show_progress(); check_done(); return *this; } + progress& operator()(const std::string& s) { message_ = s; show_progress(); check_done(); return *this; } + template + progress& operator()(const T& x) { std::ostringstream oss; oss << x; return (*this)(oss.str()); } + + inline void show_progress() const; + void check_done() const { if (current_ >= total_) std::cout << "\n" << std::flush; } + + private: + size_t current_, total_; + std::string message_; +}; + +} + +void +dlog::progress:: +show_progress() const +{ + int barWidth = 70; + + std::cout << "["; + int pos = barWidth * current_ / total_; + for (int i = 0; i < barWidth; ++i) + { + if (i < pos) + std::cout << "="; + else if (i == pos) + std::cout << ">"; + else + std::cout << " "; + } + std::cout << "] " << std::setw(3) << current_ * 100 / total_ << "%"; + if (!message_.empty()) + std::cout << " (" << message_ << ")"; + std::cout << "\r"; + std::cout.flush(); +} + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/fields/q.h b/src/Zigzag_persistence/example/ext_zz/dionysus/fields/q.h new file mode 100644 index 0000000000..8972ae2b5a --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/fields/q.h @@ -0,0 +1,63 @@ +#ifndef DIONYSUS_Q_H +#define DIONYSUS_Q_H + +#include + +// TODO: eventually need to be able to adaptively switch to arbitrary precision arithmetic + +namespace dionysus +{ + +template +class Q +{ + public: + using BaseElement = Element_; + struct Element + { + BaseElement numerator, denominator; + + bool operator==(Element o) const { return numerator == o.numerator && denominator == o.denominator; } + bool operator!=(Element o) const { return !((*this) == o); } + + friend + std::ostream& operator<<(std::ostream& out, Element e) { out << e.numerator << '/' << e.denominator; return out; } + }; + + Element id() const { return { 1,1 }; } + Element zero() const { return { 0,1 }; } + Element init(BaseElement a) const { return { a,1 }; } + + Element neg(Element a) const { return { -a.numerator, a.denominator }; } + Element add(Element a, Element b) const { Element x { a.numerator*b.denominator + b.numerator*a.denominator, a.denominator*b.denominator }; normalize(x); return x; } + + Element inv(Element a) const { return { a.denominator, a.numerator }; } + Element mul(Element a, Element b) const { Element x { a.numerator*b.numerator, a.denominator*b.denominator }; normalize(x); return x; } + Element div(Element a, Element b) const { return mul(a, inv(b)); } + + bool is_zero(Element a) const { return a.numerator == 0; } + + BaseElement numerator(const Element& x) const { return x.numerator; } + BaseElement denominator(const Element& x) const { return x.denominator; } + + static void normalize(Element& x) + { + BaseElement q = gcd(abs(x.numerator), abs(x.denominator)); + x.numerator /= q; + x.denominator /= q; + if (x.denominator < 0) + { + x.numerator = -x.numerator; + x.denominator = -x.denominator; + } + } + + static BaseElement abs(BaseElement x) { if (x < 0) return -x; return x; } + static BaseElement gcd(BaseElement a, BaseElement b) { if (b < a) return gcd(b,a); while (a != 0) { b %= a; std::swap(a,b); } return b; } + + static bool is_prime(BaseElement x) { return false; } // Ok, since is_prime is only used as a shortcut +}; + +} + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/fields/z2.h b/src/Zigzag_persistence/example/ext_zz/dionysus/fields/z2.h new file mode 100644 index 0000000000..6317ace6df --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/fields/z2.h @@ -0,0 +1,31 @@ +#ifndef DIONYSUS_Z2_H +#define DIONYSUS_Z2_H + +namespace dionysus +{ + +class Z2Field +{ + public: + typedef short Element; + + Z2Field() {} + + static Element id() { return 1; } + static Element zero() { return 0; } + static Element init(int a) { return (a % 2 + 2) % 2; } + + Element neg(Element a) const { return 2 - a; } + Element add(Element a, Element b) const { return (a+b) % 2; } + + Element inv(Element a) const { return a; } + Element mul(Element a, Element b) const { return a*b; } + Element div(Element a, Element b) const { return a; } + + bool is_zero(Element a) const { return a == 0; } +}; + +} + +#endif + diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/fields/zp.h b/src/Zigzag_persistence/example/ext_zz/dionysus/fields/zp.h new file mode 100644 index 0000000000..c70c61cc87 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/fields/zp.h @@ -0,0 +1,55 @@ +#ifndef DIONYSUS_ZP_H +#define DIONYSUS_ZP_H + +#include + +namespace dionysus +{ + +template +class ZpField +{ + public: + typedef Element_ Element; + + ZpField(Element p); + ZpField(const ZpField& other) = default; + ZpField(ZpField&& other) = default; + + Element id() const { return 1; } + Element zero() const { return 0; } + Element init(int a) const { return (a % p_ + p_) % p_; } + + Element neg(Element a) const { return p_ - a; } + Element add(Element a, Element b) const { return (a+b) % p_; } + + Element inv(Element a) const { while (a < 0) a += p_; return inverses_[a]; } + Element mul(Element a, Element b) const { return (a*b) % p_; } + Element div(Element a, Element b) const { return mul(a, inv(b)); } + + bool is_zero(Element a) const { return (a % p_) == 0; } + + Element prime() const { return p_; } + + private: + Element p_; + std::vector inverses_; +}; + +template +ZpField:: +ZpField(Element p): + p_(p), inverses_(p_) +{ + for (Element i = 1; i < p_; ++i) + for (Element j = 1; j < p_; ++j) + if (mul(i,j) == 1) + { + inverses_[i] = j; + break; + } +} + +} + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/filtration.h b/src/Zigzag_persistence/example/ext_zz/dionysus/filtration.h new file mode 100644 index 0000000000..caf871cdfb --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/filtration.h @@ -0,0 +1,124 @@ +#ifndef DIONYSUS_FILTRATION_H +#define DIONYSUS_FILTRATION_H + +#include +#include + +#include +#include +#include +#include + +namespace b = boost; +namespace bmi = boost::multi_index; + +namespace dionysus +{ + +// Filtration stores a filtered cell complex as boost::multi_index_container<...>. +// It allows for bidirectional translation between a cell and its index. +template>, + bool checked_index = false> +class Filtration +{ + public: + struct order {}; + + typedef Cell_ Cell; + typedef CellLookupIndex_ CellLookupIndex; + + typedef b::multi_index_container> + >> Container; + typedef typename Container::value_type value_type; + + typedef typename Container::template nth_index<0>::type Complex; + typedef typename Container::template nth_index<1>::type Order; + typedef typename Order::const_iterator OrderConstIterator; + typedef typename Order::iterator OrderIterator; + + + public: + Filtration() = default; + Filtration(Filtration&& other) = default; + Filtration& operator=(Filtration&& other) = default; + + Filtration(const std::initializer_list& cells): + Filtration(std::begin(cells), std::end(cells)) {} + + template + Filtration(Iterator bg, Iterator end): + cells_(bg, end) {} + + template + Filtration(const CellRange& cells): + Filtration(std::begin(cells), std::end(cells)) {} + + // Lookup + const Cell& operator[](size_t i) const { return cells_.template get()[i]; } + OrderConstIterator iterator(const Cell& s) const { return bmi::project(cells_, cells_.find(s)); } + size_t index(const Cell& s) const; + bool contains(const Cell& s) const { return cells_.find(s) != cells_.end(); } + + void push_back(const Cell& s) { cells_.template get().push_back(s); } + void push_back(Cell&& s) { cells_.template get().push_back(s); } + + void replace(size_t i, const Cell& s) { cells_.template get().replace(begin() + i, s); } + + // return index of the cell, adding it, if necessary + size_t add(const Cell& s) { size_t i = (iterator(s) - begin()); if (i == size()) emplace_back(s); return i; } + size_t add(Cell&& s) { size_t i = (iterator(s) - begin()); if (i == size()) emplace_back(std::move(s)); return i; } + + template + void emplace_back(Args&&... args) { cells_.template get().emplace_back(std::forward(args)...); } + + template> + void sort(const Cmp& cmp = Cmp()) { cells_.template get().sort(cmp); } + + void rearrange(const std::vector& indices); + + OrderConstIterator begin() const { return cells_.template get().begin(); } + OrderConstIterator end() const { return cells_.template get().end(); } + OrderIterator begin() { return cells_.template get().begin(); } + OrderIterator end() { return cells_.template get().end(); } + size_t size() const { return cells_.size(); } + void clear() { return Container().swap(cells_); } + + Cell& back() { return const_cast(cells_.template get().back()); } + const Cell& back() const { return cells_.template get().back(); } + + private: + Container cells_; +}; + +} + +template +size_t +dionysus::Filtration:: +index(const Cell& s) const +{ + auto it = iterator(s); + if (checked_index && it == end()) + { + std::ostringstream oss; + oss << "Trying to access non-existent cell: " << s; + throw std::runtime_error(oss.str()); + } + return it - begin(); +} + +template +void +dionysus::Filtration:: +rearrange(const std::vector& indices) +{ + std::vector> references; references.reserve(indices.size()); + for (size_t i : indices) + references.push_back(std::cref((*this)[i])); + cells_.template get().rearrange(references.begin()); +} + + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/format.h b/src/Zigzag_persistence/example/ext_zz/dionysus/format.h new file mode 100644 index 0000000000..7f7ba83318 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/format.h @@ -0,0 +1,8 @@ +#ifndef DIONYSUS_FORMAT_H +#define DIONYSUS_FORMAT_H + +#define FMT_HEADER_ONLY + +#include "format/format.h" + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/format/format.cc b/src/Zigzag_persistence/example/ext_zz/dionysus/format/format.cc new file mode 100644 index 0000000000..a01e272fd7 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/format/format.cc @@ -0,0 +1,1156 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - 2014, Victor Zverovich + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "format.h" + +#include + +#include +#include +#include +#include +#include + +#ifdef _WIN32 +# ifdef __MINGW32__ +# include +# endif +# include +#endif + +using fmt::internal::Arg; + +// Check if exceptions are disabled. +#if __GNUC__ && !__EXCEPTIONS +# define FMT_EXCEPTIONS 0 +#endif +#if _MSC_VER && !_HAS_EXCEPTIONS +# define FMT_EXCEPTIONS 0 +#endif +#ifndef FMT_EXCEPTIONS +# define FMT_EXCEPTIONS 1 +#endif + +#if FMT_EXCEPTIONS +# define FMT_TRY try +# define FMT_CATCH(x) catch (x) +#else +# define FMT_TRY if (true) +# define FMT_CATCH(x) if (false) +#endif + +#ifndef FMT_THROW +# if FMT_EXCEPTIONS +# define FMT_THROW(x) throw x +# define FMT_RETURN_AFTER_THROW(x) +# else +# define FMT_THROW(x) assert(false) +# define FMT_RETURN_AFTER_THROW(x) return x +# endif +#endif + +#ifdef FMT_HEADER_ONLY +# define FMT_FUNC inline +#else +# define FMT_FUNC +#endif + +#if _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4127) // conditional expression is constant +# pragma warning(disable: 4702) // unreachable code +#endif + +namespace { + +#ifndef _MSC_VER +# define FMT_SNPRINTF snprintf +#else // _MSC_VER +inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { + va_list args; + va_start(args, format); + int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); + va_end(args); + return result; +} +# define FMT_SNPRINTF fmt_snprintf +#endif // _MSC_VER + +// Checks if a value fits in int - used to avoid warnings about comparing +// signed and unsigned integers. +template +struct IntChecker { + template + static bool fits_in_int(T value) { + unsigned max = INT_MAX; + return value <= max; + } +}; + +template <> +struct IntChecker { + template + static bool fits_in_int(T value) { + return value >= INT_MIN && value <= INT_MAX; + } +}; + +const char RESET_COLOR[] = "\x1b[0m"; + +typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef); + +// Portable thread-safe version of strerror. +// Sets buffer to point to a string describing the error code. +// This can be either a pointer to a string stored in buffer, +// or a pointer to some static immutable string. +// Returns one of the following values: +// 0 - success +// ERANGE - buffer is not large enough to store the error message +// other - failure +// Buffer should be at least of size 1. +int safe_strerror( + int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { + assert(buffer != 0 && buffer_size != 0); + int result = 0; +#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || __ANDROID__ + // XSI-compliant version of strerror_r. + result = strerror_r(error_code, buffer, buffer_size); + if (result != 0) + result = errno; +#elif _GNU_SOURCE + // GNU-specific version of strerror_r. + char *message = strerror_r(error_code, buffer, buffer_size); + // If the buffer is full then the message is probably truncated. + if (message == buffer && strlen(buffer) == buffer_size - 1) + result = ERANGE; + buffer = message; +#elif __MINGW32__ + errno = 0; + (void)buffer_size; + buffer = strerror(error_code); + result = errno; +#elif _WIN32 + result = strerror_s(buffer, buffer_size, error_code); + // If the buffer is full then the message is probably truncated. + if (result == 0 && std::strlen(buffer) == buffer_size - 1) + result = ERANGE; +#else + result = strerror_r(error_code, buffer, buffer_size); + if (result == -1) + result = errno; // glibc versions before 2.13 return result in errno. +#endif + return result; +} + +void format_error_code(fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT { + // Report error code making sure that the output fits into + // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential + // bad_alloc. + out.clear(); + static const char SEP[] = ": "; + static const char ERR[] = "error "; + fmt::internal::IntTraits::MainType ec_value = error_code; + // Subtract 2 to account for terminating null characters in SEP and ERR. + std::size_t error_code_size = + sizeof(SEP) + sizeof(ERR) + fmt::internal::count_digits(ec_value) - 2; + if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size) + out << message << SEP; + out << ERR << error_code; + assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE); +} + +void report_error(FormatFunc func, + int error_code, fmt::StringRef message) FMT_NOEXCEPT { + fmt::MemoryWriter full_message; + func(full_message, error_code, message); + // Use Writer::data instead of Writer::c_str to avoid potential memory + // allocation. + std::fwrite(full_message.data(), full_message.size(), 1, stderr); + std::fputc('\n', stderr); +} + +// IsZeroInt::visit(arg) returns true iff arg is a zero integer. +class IsZeroInt : public fmt::internal::ArgVisitor { + public: + template + bool visit_any_int(T value) { return value == 0; } +}; + +// Parses an unsigned integer advancing s to the end of the parsed input. +// This function assumes that the first character of s is a digit. +template +int parse_nonnegative_int(const Char *&s) { + assert('0' <= *s && *s <= '9'); + unsigned value = 0; + do { + unsigned new_value = value * 10 + (*s++ - '0'); + // Check if value wrapped around. + if (new_value < value) { + value = UINT_MAX; + break; + } + value = new_value; + } while ('0' <= *s && *s <= '9'); + if (value > INT_MAX) + FMT_THROW(fmt::FormatError("number is too big")); + return value; +} + +inline void require_numeric_argument(const Arg &arg, char spec) { + if (arg.type > Arg::LAST_NUMERIC_TYPE) { + std::string message = + fmt::format("format specifier '{}' requires numeric argument", spec); + FMT_THROW(fmt::FormatError(message)); + } +} + +template +void check_sign(const Char *&s, const Arg &arg) { + char sign = static_cast(*s); + require_numeric_argument(arg, sign); + if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { + FMT_THROW(fmt::FormatError(fmt::format( + "format specifier '{}' requires signed argument", sign))); + } + ++s; +} + +// Checks if an argument is a valid printf width specifier and sets +// left alignment if it is negative. +class WidthHandler : public fmt::internal::ArgVisitor { + private: + fmt::FormatSpec &spec_; + + FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); + + public: + explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {} + + unsigned visit_unhandled_arg() { + FMT_THROW(fmt::FormatError("width is not integer")); + FMT_RETURN_AFTER_THROW(0); + } + + template + unsigned visit_any_int(T value) { + typedef typename fmt::internal::IntTraits::MainType UnsignedType; + UnsignedType width = value; + if (fmt::internal::is_negative(value)) { + spec_.align_ = fmt::ALIGN_LEFT; + width = 0 - width; + } + if (width > INT_MAX) + FMT_THROW(fmt::FormatError("number is too big")); + return static_cast(width); + } +}; + +class PrecisionHandler : + public fmt::internal::ArgVisitor { + public: + unsigned visit_unhandled_arg() { + FMT_THROW(fmt::FormatError("precision is not integer")); + FMT_RETURN_AFTER_THROW(0); + } + + template + int visit_any_int(T value) { + if (!IntChecker::is_signed>::fits_in_int(value)) + FMT_THROW(fmt::FormatError("number is too big")); + return static_cast(value); + } +}; + +// Converts an integer argument to an integral type T for printf. +template +class ArgConverter : public fmt::internal::ArgVisitor, void> { + private: + fmt::internal::Arg &arg_; + wchar_t type_; + + FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); + + public: + ArgConverter(fmt::internal::Arg &arg, wchar_t type) + : arg_(arg), type_(type) {} + + template + void visit_any_int(U value) { + bool is_signed = type_ == 'd' || type_ == 'i'; + using fmt::internal::Arg; + if (sizeof(T) <= sizeof(int)) { + // Extra casts are used to silence warnings. + if (is_signed) { + arg_.type = Arg::INT; + arg_.int_value = static_cast(static_cast(value)); + } else { + arg_.type = Arg::UINT; + arg_.uint_value = static_cast( + static_cast::Type>(value)); + } + } else { + if (is_signed) { + arg_.type = Arg::LONG_LONG; + arg_.long_long_value = + static_cast::Type>(value); + } else { + arg_.type = Arg::ULONG_LONG; + arg_.ulong_long_value = + static_cast::Type>(value); + } + } + } +}; + +// Converts an integer argument to char for printf. +class CharConverter : public fmt::internal::ArgVisitor { + private: + fmt::internal::Arg &arg_; + + FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); + + public: + explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {} + + template + void visit_any_int(T value) { + arg_.type = Arg::CHAR; + arg_.int_value = static_cast(value); + } +}; + +// This function template is used to prevent compile errors when handling +// incompatible string arguments, e.g. handling a wide string in a narrow +// string formatter. +template +Arg::StringValue ignore_incompatible_str(Arg::StringValue); + +template <> +inline Arg::StringValue ignore_incompatible_str( + Arg::StringValue) { return Arg::StringValue(); } + +template <> +inline Arg::StringValue ignore_incompatible_str( + Arg::StringValue s) { return s; } +} // namespace + +FMT_FUNC void fmt::SystemError::init( + int err_code, StringRef format_str, ArgList args) { + error_code_ = err_code; + MemoryWriter w; + internal::format_system_error(w, err_code, format(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(w.str()); +} + +template +int fmt::internal::CharTraits::format_float( + char *buffer, std::size_t size, const char *format, + unsigned width, int precision, T value) { + if (width == 0) { + return precision < 0 ? + FMT_SNPRINTF(buffer, size, format, value) : + FMT_SNPRINTF(buffer, size, format, precision, value); + } + return precision < 0 ? + FMT_SNPRINTF(buffer, size, format, width, value) : + FMT_SNPRINTF(buffer, size, format, width, precision, value); +} + +template +int fmt::internal::CharTraits::format_float( + wchar_t *buffer, std::size_t size, const wchar_t *format, + unsigned width, int precision, T value) { + if (width == 0) { + return precision < 0 ? + swprintf(buffer, size, format, value) : + swprintf(buffer, size, format, precision, value); + } + return precision < 0 ? + swprintf(buffer, size, format, width, value) : + swprintf(buffer, size, format, width, precision, value); +} + +template +const char fmt::internal::BasicData::DIGITS[] = + "0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"; + +#define FMT_POWERS_OF_10(factor) \ + factor * 10, \ + factor * 100, \ + factor * 1000, \ + factor * 10000, \ + factor * 100000, \ + factor * 1000000, \ + factor * 10000000, \ + factor * 100000000, \ + factor * 1000000000 + +template +const uint32_t fmt::internal::BasicData::POWERS_OF_10_32[] = { + 0, FMT_POWERS_OF_10(1) +}; + +template +const uint64_t fmt::internal::BasicData::POWERS_OF_10_64[] = { + 0, + FMT_POWERS_OF_10(1), + FMT_POWERS_OF_10(fmt::ULongLong(1000000000)), + // Multiply several constants instead of using a single long long constant + // to avoid warnings about C++98 not supporting long long. + fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10 +}; + +FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) { + if (std::isprint(static_cast(code))) { + FMT_THROW(fmt::FormatError( + fmt::format("unknown format code '{}' for {}", code, type))); + } + FMT_THROW(fmt::FormatError( + fmt::format("unknown format code '\\x{:02x}' for {}", + static_cast(code), type))); +} + +#ifdef _WIN32 + +FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { + int length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0); + static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; + if (length == 0) + FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); + buffer_.resize(length); + length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length); + if (length == 0) + FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); +} + +FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { + if (int error_code = convert(s)) { + FMT_THROW(WindowsError(error_code, + "cannot convert string from UTF-16 to UTF-8")); + } +} + +FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) { + int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0); + if (length == 0) + return GetLastError(); + buffer_.resize(length); + length = WideCharToMultiByte( + CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0); + if (length == 0) + return GetLastError(); + return 0; +} + +FMT_FUNC void fmt::WindowsError::init( + int err_code, StringRef format_str, ArgList args) { + error_code_ = err_code; + MemoryWriter w; + internal::format_windows_error(w, err_code, format(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(w.str()); +} + +#endif + +FMT_FUNC void fmt::internal::format_system_error( + fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT { + FMT_TRY { + MemoryBuffer buffer; + buffer.resize(INLINE_BUFFER_SIZE); + for (;;) { + char *system_message = &buffer[0]; + int result = safe_strerror(error_code, system_message, buffer.size()); + if (result == 0) { + out << message << ": " << system_message; + return; + } + if (result != ERANGE) + break; // Can't get error message, report error code instead. + buffer.resize(buffer.size() * 2); + } + } FMT_CATCH(...) {} + format_error_code(out, error_code, message); +} + +#ifdef _WIN32 +FMT_FUNC void fmt::internal::format_windows_error( + fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT { + class String { + private: + LPWSTR str_; + + public: + String() : str_() {} + ~String() { LocalFree(str_); } + LPWSTR *ptr() { return &str_; } + LPCWSTR c_str() const { return str_; } + }; + FMT_TRY { + String system_message; + if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, + error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast(system_message.ptr()), 0, 0)) { + UTF16ToUTF8 utf8_message; + if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) { + out << message << ": " << utf8_message; + return; + } + } + } FMT_CATCH(...) {} + format_error_code(out, error_code, message); +} +#endif + +// An argument formatter. +template +class fmt::internal::ArgFormatter : + public fmt::internal::ArgVisitor, void> { + private: + fmt::BasicFormatter &formatter_; + fmt::BasicWriter &writer_; + fmt::FormatSpec &spec_; + const Char *format_; + + FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatter); + + public: + ArgFormatter( + fmt::BasicFormatter &f,fmt::FormatSpec &s, const Char *fmt) + : formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {} + + template + void visit_any_int(T value) { writer_.write_int(value, spec_); } + + template + void visit_any_double(T value) { writer_.write_double(value, spec_); } + + void visit_char(int value) { + if (spec_.type_ && spec_.type_ != 'c') { + spec_.flags_ |= CHAR_FLAG; + writer_.write_int(value, spec_); + return; + } + if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) + FMT_THROW(FormatError("invalid format specifier for char")); + typedef typename fmt::BasicWriter::CharPtr CharPtr; + Char fill = static_cast(spec_.fill()); + if (spec_.precision_ == 0) { + std::fill_n(writer_.grow_buffer(spec_.width_), spec_.width_, fill); + return; + } + CharPtr out = CharPtr(); + if (spec_.width_ > 1) { + out = writer_.grow_buffer(spec_.width_); + if (spec_.align_ == fmt::ALIGN_RIGHT) { + std::fill_n(out, spec_.width_ - 1, fill); + out += spec_.width_ - 1; + } else if (spec_.align_ == fmt::ALIGN_CENTER) { + out = writer_.fill_padding(out, spec_.width_, 1, fill); + } else { + std::fill_n(out + 1, spec_.width_ - 1, fill); + } + } else { + out = writer_.grow_buffer(1); + } + *out = static_cast(value); + } + + void visit_string(Arg::StringValue value) { + writer_.write_str(value, spec_); + } + void visit_wstring(Arg::StringValue value) { + writer_.write_str(ignore_incompatible_str(value), spec_); + } + + void visit_pointer(const void *value) { + if (spec_.type_ && spec_.type_ != 'p') + fmt::internal::report_unknown_type(spec_.type_, "pointer"); + spec_.flags_ = fmt::HASH_FLAG; + spec_.type_ = 'x'; + writer_.write_int(reinterpret_cast(value), spec_); + } + + void visit_custom(Arg::CustomValue c) { + c.format(&formatter_, c.value, &format_); + } +}; + +template +template +void fmt::BasicWriter::write_str( + const Arg::StringValue &s, const FormatSpec &spec) { + // Check if StrChar is convertible to Char. + internal::CharTraits::convert(StrChar()); + if (spec.type_ && spec.type_ != 's') + internal::report_unknown_type(spec.type_, "string"); + const StrChar *str_value = s.value; + std::size_t str_size = s.size; + if (str_size == 0) { + if (!str_value) + FMT_THROW(FormatError("string pointer is null")); + if (*str_value) + str_size = std::char_traits::length(str_value); + } + std::size_t precision = spec.precision_; + if (spec.precision_ >= 0 && precision < str_size) + str_size = spec.precision_; + write_str(str_value, str_size, spec); +} + +template +inline Arg fmt::BasicFormatter::parse_arg_index(const Char *&s) { + const char *error = 0; + Arg arg = *s < '0' || *s > '9' ? + next_arg(error) : get_arg(parse_nonnegative_int(s), error); + if (error) { + FMT_THROW(FormatError( + *s != '}' && *s != ':' ? "invalid format string" : error)); + } + return arg; +} + +FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( + unsigned arg_index, const char *&error) { + Arg arg = args_[arg_index]; + if (arg.type == Arg::NONE) + error = "argument index out of range"; + return arg; +} + +inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) { + if (next_arg_index_ >= 0) + return do_get_arg(next_arg_index_++, error); + error = "cannot switch from manual to automatic argument indexing"; + return Arg(); +} + +inline Arg fmt::internal::FormatterBase::get_arg( + unsigned arg_index, const char *&error) { + if (next_arg_index_ <= 0) { + next_arg_index_ = -1; + return do_get_arg(arg_index, error); + } + error = "cannot switch from automatic to manual argument indexing"; + return Arg(); +} + +template +void fmt::internal::PrintfFormatter::parse_flags( + FormatSpec &spec, const Char *&s) { + for (;;) { + switch (*s++) { + case '-': + spec.align_ = ALIGN_LEFT; + break; + case '+': + spec.flags_ |= SIGN_FLAG | PLUS_FLAG; + break; + case '0': + spec.fill_ = '0'; + break; + case ' ': + spec.flags_ |= SIGN_FLAG; + break; + case '#': + spec.flags_ |= HASH_FLAG; + break; + default: + --s; + return; + } + } +} + +template +Arg fmt::internal::PrintfFormatter::get_arg( + const Char *s, unsigned arg_index) { + const char *error = 0; + Arg arg = arg_index == UINT_MAX ? + next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); + if (error) + FMT_THROW(FormatError(!*s ? "invalid format string" : error)); + return arg; +} + +template +unsigned fmt::internal::PrintfFormatter::parse_header( + const Char *&s, FormatSpec &spec) { + unsigned arg_index = UINT_MAX; + Char c = *s; + if (c >= '0' && c <= '9') { + // Parse an argument index (if followed by '$') or a width possibly + // preceded with '0' flag(s). + unsigned value = parse_nonnegative_int(s); + if (*s == '$') { // value is an argument index + ++s; + arg_index = value; + } else { + if (c == '0') + spec.fill_ = '0'; + if (value != 0) { + // Nonzero value means that we parsed width and don't need to + // parse it or flags again, so return now. + spec.width_ = value; + return arg_index; + } + } + } + parse_flags(spec, s); + // Parse width. + if (*s >= '0' && *s <= '9') { + spec.width_ = parse_nonnegative_int(s); + } else if (*s == '*') { + ++s; + spec.width_ = WidthHandler(spec).visit(get_arg(s)); + } + return arg_index; +} + +template +void fmt::internal::PrintfFormatter::format( + BasicWriter &writer, BasicStringRef format_str, + const ArgList &args) { + const Char *start = format_str.c_str(); + set_args(args); + const Char *s = start; + while (*s) { + Char c = *s++; + if (c != '%') continue; + if (*s == c) { + write(writer, start, s); + start = ++s; + continue; + } + write(writer, start, s - 1); + + FormatSpec spec; + spec.align_ = ALIGN_RIGHT; + + // Parse argument index, flags and width. + unsigned arg_index = parse_header(s, spec); + + // Parse precision. + if (*s == '.') { + ++s; + if ('0' <= *s && *s <= '9') { + spec.precision_ = parse_nonnegative_int(s); + } else if (*s == '*') { + ++s; + spec.precision_ = PrecisionHandler().visit(get_arg(s)); + } + } + + Arg arg = get_arg(s, arg_index); + if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg)) + spec.flags_ &= ~HASH_FLAG; + if (spec.fill_ == '0') { + if (arg.type <= Arg::LAST_NUMERIC_TYPE) + spec.align_ = ALIGN_NUMERIC; + else + spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. + } + + // Parse length and convert the argument to the required type. + switch (*s++) { + case 'h': + if (*s == 'h') + ArgConverter(arg, *++s).visit(arg); + else + ArgConverter(arg, *s).visit(arg); + break; + case 'l': + if (*s == 'l') + ArgConverter(arg, *++s).visit(arg); + else + ArgConverter(arg, *s).visit(arg); + break; + case 'j': + ArgConverter(arg, *s).visit(arg); + break; + case 'z': + ArgConverter(arg, *s).visit(arg); + break; + case 't': + ArgConverter(arg, *s).visit(arg); + break; + case 'L': + // printf produces garbage when 'L' is omitted for long double, no + // need to do the same. + break; + default: + --s; + ArgConverter(arg, *s).visit(arg); + } + + // Parse type. + if (!*s) + FMT_THROW(FormatError("invalid format string")); + spec.type_ = static_cast(*s++); + if (arg.type <= Arg::LAST_INTEGER_TYPE) { + // Normalize type. + switch (spec.type_) { + case 'i': case 'u': + spec.type_ = 'd'; + break; + case 'c': + // TODO: handle wchar_t + CharConverter(arg).visit(arg); + break; + } + } + + start = s; + + // Format argument. + switch (arg.type) { + case Arg::INT: + writer.write_int(arg.int_value, spec); + break; + case Arg::UINT: + writer.write_int(arg.uint_value, spec); + break; + case Arg::LONG_LONG: + writer.write_int(arg.long_long_value, spec); + break; + case Arg::ULONG_LONG: + writer.write_int(arg.ulong_long_value, spec); + break; + case Arg::CHAR: { + if (spec.type_ && spec.type_ != 'c') + writer.write_int(arg.int_value, spec); + typedef typename BasicWriter::CharPtr CharPtr; + CharPtr out = CharPtr(); + if (spec.width_ > 1) { + Char fill = ' '; + out = writer.grow_buffer(spec.width_); + if (spec.align_ != ALIGN_LEFT) { + std::fill_n(out, spec.width_ - 1, fill); + out += spec.width_ - 1; + } else { + std::fill_n(out + 1, spec.width_ - 1, fill); + } + } else { + out = writer.grow_buffer(1); + } + *out = static_cast(arg.int_value); + break; + } + case Arg::DOUBLE: + writer.write_double(arg.double_value, spec); + break; + case Arg::LONG_DOUBLE: + writer.write_double(arg.long_double_value, spec); + break; + case Arg::CSTRING: + arg.string.size = 0; + writer.write_str(arg.string, spec); + break; + case Arg::STRING: + writer.write_str(arg.string, spec); + break; + case Arg::WSTRING: + writer.write_str(ignore_incompatible_str(arg.wstring), spec); + break; + case Arg::POINTER: + if (spec.type_ && spec.type_ != 'p') + internal::report_unknown_type(spec.type_, "pointer"); + spec.flags_= HASH_FLAG; + spec.type_ = 'x'; + writer.write_int(reinterpret_cast(arg.pointer), spec); + break; + case Arg::CUSTOM: { + if (spec.type_) + internal::report_unknown_type(spec.type_, "object"); + const void *str_format = "s"; + arg.custom.format(&writer, arg.custom.value, &str_format); + break; + } + default: + assert(false); + break; + } + } + write(writer, start, s); +} + +template +const Char *fmt::BasicFormatter::format( + const Char *&format_str, const Arg &arg) { + const Char *s = format_str; + FormatSpec spec; + if (*s == ':') { + if (arg.type == Arg::CUSTOM) { + arg.custom.format(this, arg.custom.value, &s); + return s; + } + ++s; + // Parse fill and alignment. + if (Char c = *s) { + const Char *p = s + 1; + spec.align_ = ALIGN_DEFAULT; + do { + switch (*p) { + case '<': + spec.align_ = ALIGN_LEFT; + break; + case '>': + spec.align_ = ALIGN_RIGHT; + break; + case '=': + spec.align_ = ALIGN_NUMERIC; + break; + case '^': + spec.align_ = ALIGN_CENTER; + break; + } + if (spec.align_ != ALIGN_DEFAULT) { + if (p != s) { + if (c == '}') break; + if (c == '{') + FMT_THROW(FormatError("invalid fill character '{'")); + s += 2; + spec.fill_ = c; + } else ++s; + if (spec.align_ == ALIGN_NUMERIC) + require_numeric_argument(arg, '='); + break; + } + } while (--p >= s); + } + + // Parse sign. + switch (*s) { + case '+': + check_sign(s, arg); + spec.flags_ |= SIGN_FLAG | PLUS_FLAG; + break; + case '-': + check_sign(s, arg); + spec.flags_ |= MINUS_FLAG; + break; + case ' ': + check_sign(s, arg); + spec.flags_ |= SIGN_FLAG; + break; + } + + if (*s == '#') { + require_numeric_argument(arg, '#'); + spec.flags_ |= HASH_FLAG; + ++s; + } + + // Parse width and zero flag. + if ('0' <= *s && *s <= '9') { + if (*s == '0') { + require_numeric_argument(arg, '0'); + spec.align_ = ALIGN_NUMERIC; + spec.fill_ = '0'; + } + // Zero may be parsed again as a part of the width, but it is simpler + // and more efficient than checking if the next char is a digit. + spec.width_ = parse_nonnegative_int(s); + } + + // Parse precision. + if (*s == '.') { + ++s; + spec.precision_ = 0; + if ('0' <= *s && *s <= '9') { + spec.precision_ = parse_nonnegative_int(s); + } else if (*s == '{') { + ++s; + const Arg &precision_arg = parse_arg_index(s); + if (*s++ != '}') + FMT_THROW(FormatError("invalid format string")); + ULongLong value = 0; + switch (precision_arg.type) { + case Arg::INT: + if (precision_arg.int_value < 0) + FMT_THROW(FormatError("negative precision")); + value = precision_arg.int_value; + break; + case Arg::UINT: + value = precision_arg.uint_value; + break; + case Arg::LONG_LONG: + if (precision_arg.long_long_value < 0) + FMT_THROW(FormatError("negative precision")); + value = precision_arg.long_long_value; + break; + case Arg::ULONG_LONG: + value = precision_arg.ulong_long_value; + break; + default: + FMT_THROW(FormatError("precision is not integer")); + } + if (value > INT_MAX) + FMT_THROW(FormatError("number is too big")); + spec.precision_ = static_cast(value); + } else { + FMT_THROW(FormatError("missing precision specifier")); + } + if (arg.type < Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) { + FMT_THROW(FormatError( + fmt::format("precision not allowed in {} format specifier", + arg.type == Arg::POINTER ? "pointer" : "integer"))); + } + } + + // Parse type. + if (*s != '}' && *s) + spec.type_ = static_cast(*s++); + } + + if (*s++ != '}') + FMT_THROW(FormatError("missing '}' in format string")); + start_ = s; + + // Format argument. + internal::ArgFormatter(*this, spec, s - 1).visit(arg); + return s; +} + +template +void fmt::BasicFormatter::format( + BasicStringRef format_str, const ArgList &args) { + const Char *s = start_ = format_str.c_str(); + set_args(args); + while (*s) { + Char c = *s++; + if (c != '{' && c != '}') continue; + if (*s == c) { + write(writer_, start_, s); + start_ = ++s; + continue; + } + if (c == '}') + FMT_THROW(FormatError("unmatched '}' in format string")); + write(writer_, start_, s - 1); + Arg arg = parse_arg_index(s); + s = format(s, arg); + } + write(writer_, start_, s); +} + +FMT_FUNC void fmt::report_system_error( + int error_code, fmt::StringRef message) FMT_NOEXCEPT { + report_error(internal::format_system_error, error_code, message); +} + +#ifdef _WIN32 +FMT_FUNC void fmt::report_windows_error( + int error_code, fmt::StringRef message) FMT_NOEXCEPT { + report_error(internal::format_windows_error, error_code, message); +} +#endif + +FMT_FUNC void fmt::print(std::FILE *f, StringRef format_str, ArgList args) { + MemoryWriter w; + w.write(format_str, args); + std::fwrite(w.data(), 1, w.size(), f); +} + +FMT_FUNC void fmt::print(StringRef format_str, ArgList args) { + print(stdout, format_str, args); +} + +FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args) { + MemoryWriter w; + w.write(format_str, args); + os.write(w.data(), w.size()); +} + +FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) { + char escape[] = "\x1b[30m"; + escape[3] = '0' + static_cast(c); + std::fputs(escape, stdout); + print(format, args); + std::fputs(RESET_COLOR, stdout); +} + +FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) { + MemoryWriter w; + printf(w, format, args); + std::size_t size = w.size(); + return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast(size); +} + +// Explicit instantiations for char. + +template const char *fmt::BasicFormatter::format( + const char *&format_str, const fmt::internal::Arg &arg); + +template void fmt::BasicFormatter::format( + BasicStringRef format, const ArgList &args); + +template void fmt::internal::PrintfFormatter::format( + BasicWriter &writer, BasicStringRef format, const ArgList &args); + +template int fmt::internal::CharTraits::format_float( + char *buffer, std::size_t size, const char *format, + unsigned width, int precision, double value); + +template int fmt::internal::CharTraits::format_float( + char *buffer, std::size_t size, const char *format, + unsigned width, int precision, long double value); + +// Explicit instantiations for wchar_t. + +template const wchar_t *fmt::BasicFormatter::format( + const wchar_t *&format_str, const fmt::internal::Arg &arg); + +template void fmt::BasicFormatter::format( + BasicStringRef format, const ArgList &args); + +template void fmt::internal::PrintfFormatter::format( + BasicWriter &writer, BasicStringRef format, + const ArgList &args); + +template int fmt::internal::CharTraits::format_float( + wchar_t *buffer, std::size_t size, const wchar_t *format, + unsigned width, int precision, double value); + +template int fmt::internal::CharTraits::format_float( + wchar_t *buffer, std::size_t size, const wchar_t *format, + unsigned width, int precision, long double value); + +#if _MSC_VER +# pragma warning(pop) +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/format/format.h b/src/Zigzag_persistence/example/ext_zz/dionysus/format/format.h new file mode 100644 index 0000000000..03ed685383 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/format/format.h @@ -0,0 +1,2546 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - 2014, Victor Zverovich + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FMT_FORMAT_H_ +#define FMT_FORMAT_H_ + +#include + +#include +#include +#include // for std::ptrdiff_t +#include +#include +#include +#include +#include +#include + +#if _SECURE_SCL +# include +#endif + +#ifdef _MSC_VER +# include // _BitScanReverse, _BitScanReverse64 + +namespace fmt { +namespace internal { +# pragma intrinsic(_BitScanReverse) +inline uint32_t clz(uint32_t x) { + unsigned long r = 0; + _BitScanReverse(&r, x); + return 31 - r; +} +# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) +inline uint32_t clzll(uint64_t x) { + unsigned long r = 0; +# ifdef _WIN64 +# pragma intrinsic(_BitScanReverse64) + _BitScanReverse64(&r, x); +# else + // Scan the high 32 bits. + if (_BitScanReverse(&r, static_cast(x >> 32))) + return 63 - (r + 32); + + // Scan the low 32 bits. + _BitScanReverse(&r, static_cast(x)); +# endif + return 63 - r; +} +# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) +} +} +#endif + +#ifdef __GNUC__ +# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +# define FMT_GCC_EXTENSION __extension__ +# if FMT_GCC_VERSION >= 406 +# pragma GCC diagnostic push +// Disable the warning about "long long" which is sometimes reported even +// when using __extension__. +# pragma GCC diagnostic ignored "-Wlong-long" +// Disable the warning about declaration shadowing because it affects too +// many valid cases. +# pragma GCC diagnostic ignored "-Wshadow" +# endif +# if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__ +# define FMT_HAS_GXX_CXX11 1 +# endif +#else +# define FMT_GCC_EXTENSION +#endif + +#ifdef __clang__ +# pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#endif + +#ifdef __GNUC_LIBSTD__ +# define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__) +#endif + +#ifdef __has_feature +# define FMT_HAS_FEATURE(x) __has_feature(x) +#else +# define FMT_HAS_FEATURE(x) 0 +#endif + +#ifdef __has_builtin +# define FMT_HAS_BUILTIN(x) __has_builtin(x) +#else +# define FMT_HAS_BUILTIN(x) 0 +#endif + +#ifdef __has_cpp_attribute +# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define FMT_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +#ifndef FMT_USE_VARIADIC_TEMPLATES +// Variadic templates are available in GCC since version 4.4 +// (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++ +// since version 2013. +# define FMT_USE_VARIADIC_TEMPLATES \ + (FMT_HAS_FEATURE(cxx_variadic_templates) || \ + (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800) +#endif + +#ifndef FMT_USE_RVALUE_REFERENCES +// Don't use rvalue references when compiling with clang and an old libstdc++ +// as the latter doesn't provide std::move. +# if defined(FMT_GNUC_LIBSTD_VERSION) && FMT_GNUC_LIBSTD_VERSION <= 402 +# define FMT_USE_RVALUE_REFERENCES 0 +# else +# define FMT_USE_RVALUE_REFERENCES \ + (FMT_HAS_FEATURE(cxx_rvalue_references) || \ + (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600) +# endif +#endif + +#if FMT_USE_RVALUE_REFERENCES +# include // for std::move +#endif + +// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature). +#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) +# define FMT_NOEXCEPT noexcept +#else +# define FMT_NOEXCEPT throw() +#endif + +// A macro to disallow the copy constructor and operator= functions +// This should be used in the private: declarations for a class +#if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \ + (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800 +# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&) = delete; \ + TypeName& operator=(const TypeName&) = delete +#else +# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + TypeName& operator=(const TypeName&) +#endif + +namespace fmt { + +// Fix the warning about long long on older versions of GCC +// that don't support the diagnostic pragma. +FMT_GCC_EXTENSION typedef long long LongLong; +FMT_GCC_EXTENSION typedef unsigned long long ULongLong; + +#if FMT_USE_RVALUE_REFERENCES +using std::move; +#endif + +template +class BasicWriter; + +typedef BasicWriter Writer; +typedef BasicWriter WWriter; + +template +class BasicFormatter; + +template +void format(BasicFormatter &f, const Char *&format_str, const T &value); + +/** + \rst + A string reference. It can be constructed from a C string or + ``std::string``. + + You can use one of the following typedefs for common character types: + + +------------+-------------------------+ + | Type | Definition | + +============+=========================+ + | StringRef | BasicStringRef | + +------------+-------------------------+ + | WStringRef | BasicStringRef | + +------------+-------------------------+ + + This class is most useful as a parameter type to allow passing + different types of strings to a function, for example:: + + template + std::string format(StringRef format_str, const Args & ... args); + + format("{}", 42); + format(std::string("{}"), 42); + \endrst + */ +template +class BasicStringRef { + private: + const Char *data_; + std::size_t size_; + + public: + /** + Constructs a string reference object from a C string and a size. + */ + BasicStringRef(const Char *s, std::size_t size) : data_(s), size_(size) {} + + /** + Constructs a string reference object from a C string computing + the size with ``std::char_traits::length``. + */ + BasicStringRef(const Char *s) + : data_(s), size_(std::char_traits::length(s)) {} + + /** + Constructs a string reference from an `std::string` object. + */ + BasicStringRef(const std::basic_string &s) + : data_(s.c_str()), size_(s.size()) {} + + /** + Converts a string reference to an `std::string` object. + */ + operator std::basic_string() const { + return std::basic_string(data_, size()); + } + + /** + Returns the pointer to a C string. + */ + const Char *c_str() const { return data_; } + + /** + Returns the string size. + */ + std::size_t size() const { return size_; } + + friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { + return lhs.data_ == rhs.data_; + } + friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) { + return lhs.data_ != rhs.data_; + } +}; + +typedef BasicStringRef StringRef; +typedef BasicStringRef WStringRef; + +/** + A formatting error such as invalid format string. +*/ +class FormatError : public std::runtime_error { +public: + explicit FormatError(StringRef message) + : std::runtime_error(message.c_str()) {} +}; + +namespace internal { + +// The number of characters to store in the MemoryBuffer object itself +// to avoid dynamic memory allocation. +enum { INLINE_BUFFER_SIZE = 500 }; + +#if _SECURE_SCL +// Use checked iterator to avoid warnings on MSVC. +template +inline stdext::checked_array_iterator make_ptr(T *ptr, std::size_t size) { + return stdext::checked_array_iterator(ptr, size); +} +#else +template +inline T *make_ptr(T *ptr, std::size_t) { return ptr; } +#endif + +// A buffer for POD types. It supports a subset of std::vector's operations. +template +class Buffer { + private: + FMT_DISALLOW_COPY_AND_ASSIGN(Buffer); + + protected: + T *ptr_; + std::size_t size_; + std::size_t capacity_; + + Buffer(T *ptr = 0, std::size_t capacity = 0) + : ptr_(ptr), size_(0), capacity_(capacity) {} + + virtual void grow(std::size_t size) = 0; + + public: + virtual ~Buffer() {} + + // Returns the size of this buffer. + std::size_t size() const { return size_; } + + // Returns the capacity of this buffer. + std::size_t capacity() const { return capacity_; } + + // Resizes the buffer. If T is a POD type new elements are not initialized. + void resize(std::size_t new_size) { + if (new_size > capacity_) + grow(new_size); + size_ = new_size; + } + + // Reserves space to store at least capacity elements. + void reserve(std::size_t capacity) { + if (capacity > capacity_) + grow(capacity); + } + + void clear() FMT_NOEXCEPT { size_ = 0; } + + void push_back(const T &value) { + if (size_ == capacity_) + grow(size_ + 1); + ptr_[size_++] = value; + } + + // Appends data to the end of the buffer. + void append(const T *begin, const T *end); + + T &operator[](std::size_t index) { return ptr_[index]; } + const T &operator[](std::size_t index) const { return ptr_[index]; } +}; + +template +void Buffer::append(const T *begin, const T *end) { + std::ptrdiff_t num_elements = end - begin; + if (size_ + num_elements > capacity_) + grow(size_ + num_elements); + std::copy(begin, end, make_ptr(ptr_, capacity_) + size_); + size_ += num_elements; +} + +// A memory buffer for POD types with the first SIZE elements stored in +// the object itself. +template > +class MemoryBuffer : private Allocator, public Buffer { + private: + T data_[SIZE]; + + // Free memory allocated by the buffer. + void free() { + if (this->ptr_ != data_) this->deallocate(this->ptr_, this->capacity_); + } + + protected: + void grow(std::size_t size); + + public: + explicit MemoryBuffer(const Allocator &alloc = Allocator()) + : Allocator(alloc), Buffer(data_, SIZE) {} + ~MemoryBuffer() { free(); } + +#if FMT_USE_RVALUE_REFERENCES + private: + // Move data from other to this buffer. + void move(MemoryBuffer &other) { + Allocator &this_alloc = *this, &other_alloc = other; + this_alloc = std::move(other_alloc); + this->size_ = other.size_; + this->capacity_ = other.capacity_; + if (other.ptr_ == other.data_) { + this->ptr_ = data_; + std::copy(other.data_, + other.data_ + this->size_, make_ptr(data_, this->capacity_)); + } else { + this->ptr_ = other.ptr_; + // Set pointer to the inline array so that delete is not called + // when freeing. + other.ptr_ = other.data_; + } + } + + public: + MemoryBuffer(MemoryBuffer &&other) { + move(other); + } + + MemoryBuffer &operator=(MemoryBuffer &&other) { + assert(this != &other); + free(); + move(other); + return *this; + } +#endif + + // Returns a copy of the allocator associated with this buffer. + Allocator get_allocator() const { return *this; } +}; + +template +void MemoryBuffer::grow(std::size_t size) { + std::size_t new_capacity = + (std::max)(size, this->capacity_ + this->capacity_ / 2); + T *new_ptr = this->allocate(new_capacity); + // The following code doesn't throw, so the raw pointer above doesn't leak. + std::copy(this->ptr_, + this->ptr_ + this->size_, make_ptr(new_ptr, new_capacity)); + std::size_t old_capacity = this->capacity_; + T *old_ptr = this->ptr_; + this->capacity_ = new_capacity; + this->ptr_ = new_ptr; + // deallocate may throw (at least in principle), but it doesn't matter since + // the buffer already uses the new storage and will deallocate it in case + // of exception. + if (old_ptr != data_) + this->deallocate(old_ptr, old_capacity); +} + +#ifndef _MSC_VER +// Portable version of signbit. +inline int getsign(double x) { + // When compiled in C++11 mode signbit is no longer a macro but a function + // defined in namespace std and the macro is undefined. +# ifdef signbit + return signbit(x); +# else + return std::signbit(x); +# endif +} + +// Portable version of isinf. +# ifdef isinf +inline int isinfinity(double x) { return isinf(x); } +inline int isinfinity(long double x) { return isinf(x); } +# else +inline int isinfinity(double x) { return std::isinf(x); } +inline int isinfinity(long double x) { return std::isinf(x); } +# endif +#else +inline int getsign(double value) { + if (value < 0) return 1; + if (value == value) return 0; + int dec = 0, sign = 0; + char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail. + _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign); + return sign; +} +inline int isinfinity(double x) { return !_finite(x); } +inline int isinfinity(long double x) { return !_finite(static_cast(x)); } +#endif + +template +class BasicCharTraits { + public: +#if _SECURE_SCL + typedef stdext::checked_array_iterator CharPtr; +#else + typedef Char *CharPtr; +#endif +}; + +template +class CharTraits; + +template <> +class CharTraits : public BasicCharTraits { + private: + // Conversion from wchar_t to char is not allowed. + static char convert(wchar_t); + +public: + typedef const wchar_t *UnsupportedStrType; + + static char convert(char value) { return value; } + + // Formats a floating-point number. + template + static int format_float(char *buffer, std::size_t size, + const char *format, unsigned width, int precision, T value); +}; + +template <> +class CharTraits : public BasicCharTraits { + public: + typedef const char *UnsupportedStrType; + + static wchar_t convert(char value) { return value; } + static wchar_t convert(wchar_t value) { return value; } + + template + static int format_float(wchar_t *buffer, std::size_t size, + const wchar_t *format, unsigned width, int precision, T value); +}; + +// Checks if a number is negative - used to avoid warnings. +template +struct SignChecker { + template + static bool is_negative(T value) { return value < 0; } +}; + +template <> +struct SignChecker { + template + static bool is_negative(T) { return false; } +}; + +// Returns true if value is negative, false otherwise. +// Same as (value < 0) but doesn't produce warnings if T is an unsigned type. +template +inline bool is_negative(T value) { + return SignChecker::is_signed>::is_negative(value); +} + +// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise. +template +struct TypeSelector { typedef uint32_t Type; }; + +template <> +struct TypeSelector { typedef uint64_t Type; }; + +template +struct IntTraits { + // Smallest of uint32_t and uint64_t that is large enough to represent + // all values of T. + typedef typename + TypeSelector::digits <= 32>::Type MainType; +}; + +// MakeUnsigned::Type gives an unsigned type corresponding to integer type T. +template +struct MakeUnsigned { typedef T Type; }; + +#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \ + template <> \ + struct MakeUnsigned { typedef U Type; } + +FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char); +FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char); +FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short); +FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned); +FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long); +FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong); + +void report_unknown_type(char code, const char *type); + +// Static data is placed in this class template to allow header-only +// configuration. +template +struct BasicData { + static const uint32_t POWERS_OF_10_32[]; + static const uint64_t POWERS_OF_10_64[]; + static const char DIGITS[]; +}; + +typedef BasicData<> Data; + +#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) +# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +#endif + +#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) +# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +#endif + +#ifdef FMT_BUILTIN_CLZLL +// Returns the number of decimal digits in n. Leading zeros are not counted +// except for n == 0 in which case count_digits returns 1. +inline unsigned count_digits(uint64_t n) { + // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 + // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. + unsigned t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; + return t - (n < Data::POWERS_OF_10_64[t]) + 1; +} +#else +// Fallback version of count_digits used when __builtin_clz is not available. +inline unsigned count_digits(uint64_t n) { + unsigned count = 1; + for (;;) { + // Integer division is slow so do it for a group of four digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + if (n < 10) return count; + if (n < 100) return count + 1; + if (n < 1000) return count + 2; + if (n < 10000) return count + 3; + n /= 10000u; + count += 4; + } +} +#endif + +#ifdef FMT_BUILTIN_CLZ +// Optional version of count_digits for better performance on 32-bit platforms. +inline unsigned count_digits(uint32_t n) { + uint32_t t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; + return t - (n < Data::POWERS_OF_10_32[t]) + 1; +} +#endif + +// Formats a decimal unsigned integer value writing into buffer. +template +inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { + --num_digits; + while (value >= 100) { + // Integer division is slow so do it for a group of two digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + unsigned index = (value % 100) * 2; + value /= 100; + buffer[num_digits] = Data::DIGITS[index + 1]; + buffer[num_digits - 1] = Data::DIGITS[index]; + num_digits -= 2; + } + if (value < 10) { + *buffer = static_cast('0' + value); + return; + } + unsigned index = static_cast(value * 2); + buffer[1] = Data::DIGITS[index + 1]; + buffer[0] = Data::DIGITS[index]; +} + +#ifdef _WIN32 +// A converter from UTF-8 to UTF-16. +// It is only provided for Windows since other systems support UTF-8 natively. +class UTF8ToUTF16 { + private: + MemoryBuffer buffer_; + + public: + explicit UTF8ToUTF16(StringRef s); + operator WStringRef() const { return WStringRef(&buffer_[0], size()); } + size_t size() const { return buffer_.size() - 1; } + const wchar_t *c_str() const { return &buffer_[0]; } + std::wstring str() const { return std::wstring(&buffer_[0], size()); } +}; + +// A converter from UTF-16 to UTF-8. +// It is only provided for Windows since other systems support UTF-8 natively. +class UTF16ToUTF8 { + private: + MemoryBuffer buffer_; + + public: + UTF16ToUTF8() {} + explicit UTF16ToUTF8(WStringRef s); + operator StringRef() const { return StringRef(&buffer_[0], size()); } + size_t size() const { return buffer_.size() - 1; } + const char *c_str() const { return &buffer_[0]; } + std::string str() const { return std::string(&buffer_[0], size()); } + + // Performs conversion returning a system error code instead of + // throwing exception on conversion error. This method may still throw + // in case of memory allocation error. + int convert(WStringRef s); +}; +#endif + +void format_system_error(fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT; + +#ifdef _WIN32 +void format_windows_error(fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT; +#endif + +// Computes max(Arg, 1) at compile time. It is used to avoid errors about +// allocating an array of 0 size. +template +struct NonZero { + enum { VALUE = Arg }; +}; + +template <> +struct NonZero<0> { + enum { VALUE = 1 }; +}; + +// The value of a formatting argument. It is a POD type to allow storage in +// internal::MemoryBuffer. +struct Value { + template + struct StringValue { + const Char *value; + std::size_t size; + }; + + typedef void (*FormatFunc)( + void *formatter, const void *arg, void *format_str_ptr); + + struct CustomValue { + const void *value; + FormatFunc format; + }; + + union { + int int_value; + unsigned uint_value; + LongLong long_long_value; + ULongLong ulong_long_value; + double double_value; + long double long_double_value; + const void *pointer; + StringValue string; + StringValue sstring; + StringValue ustring; + StringValue wstring; + CustomValue custom; + }; +}; + +struct Arg : Value { + enum Type { + NONE, + // Integer types should go first, + INT, UINT, LONG_LONG, ULONG_LONG, CHAR, LAST_INTEGER_TYPE = CHAR, + // followed by floating-point types. + DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, + CSTRING, STRING, WSTRING, POINTER, CUSTOM + }; + Type type; +}; + +// Makes a Value object from any type. +template +class MakeValue : public Value { + private: + // The following two methods are private to disallow formatting of + // arbitrary pointers. If you want to output a pointer cast it to + // "void *" or "const void *". In particular, this forbids formatting + // of "[const] volatile char *" which is printed as bool by iostreams. + // Do not implement! + template + MakeValue(const T *value); + template + MakeValue(T *value); + + void set_string(StringRef str) { + string.value = str.c_str(); + string.size = str.size(); + } + + void set_string(WStringRef str) { + CharTraits::convert(wchar_t()); + wstring.value = str.c_str(); + wstring.size = str.size(); + } + + // Formats an argument of a custom type, such as a user-defined class. + template + static void format_custom_arg( + void *formatter, const void *arg, void *format_str_ptr) { + format(*static_cast*>(formatter), + *static_cast(format_str_ptr), + *static_cast(arg)); + } + +public: + MakeValue() {} + +#define FMT_MAKE_VALUE(Type, field, TYPE) \ + MakeValue(Type value) { field = value; } \ + static uint64_t type(Type) { return Arg::TYPE; } + + FMT_MAKE_VALUE(bool, int_value, INT) + FMT_MAKE_VALUE(short, int_value, INT) + FMT_MAKE_VALUE(unsigned short, uint_value, UINT) + FMT_MAKE_VALUE(int, int_value, INT) + FMT_MAKE_VALUE(unsigned, uint_value, UINT) + + MakeValue(long value) { + // To minimize the number of types we need to deal with, long is + // translated either to int or to long long depending on its size. + if (sizeof(long) == sizeof(int)) + int_value = static_cast(value); + else + long_long_value = value; + } + static uint64_t type(long) { + return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; + } + + MakeValue(unsigned long value) { + if (sizeof(unsigned long) == sizeof(unsigned)) + uint_value = static_cast(value); + else + ulong_long_value = value; + } + static uint64_t type(unsigned long) { + return sizeof(unsigned long) == sizeof(unsigned) ? + Arg::UINT : Arg::ULONG_LONG; + } + + FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG) + FMT_MAKE_VALUE(ULongLong, ulong_long_value, ULONG_LONG) + FMT_MAKE_VALUE(float, double_value, DOUBLE) + FMT_MAKE_VALUE(double, double_value, DOUBLE) + FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE) + FMT_MAKE_VALUE(signed char, int_value, CHAR) + FMT_MAKE_VALUE(unsigned char, int_value, CHAR) + FMT_MAKE_VALUE(char, int_value, CHAR) + + MakeValue(wchar_t value) { + int_value = internal::CharTraits::convert(value); + } + static uint64_t type(wchar_t) { return Arg::CHAR; } + +#define FMT_MAKE_STR_VALUE(Type, TYPE) \ + MakeValue(Type value) { set_string(value); } \ + static uint64_t type(Type) { return Arg::TYPE; } + + FMT_MAKE_VALUE(char *, string.value, CSTRING) + FMT_MAKE_VALUE(const char *, string.value, CSTRING) + FMT_MAKE_VALUE(const signed char *, sstring.value, CSTRING) + FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) + FMT_MAKE_STR_VALUE(const std::string &, STRING) + FMT_MAKE_STR_VALUE(StringRef, STRING) + + FMT_MAKE_STR_VALUE(wchar_t *, WSTRING) + FMT_MAKE_STR_VALUE(const wchar_t *, WSTRING) + FMT_MAKE_STR_VALUE(const std::wstring &, WSTRING) + FMT_MAKE_STR_VALUE(WStringRef, WSTRING) + + FMT_MAKE_VALUE(void *, pointer, POINTER) + FMT_MAKE_VALUE(const void *, pointer, POINTER) + + template + MakeValue(const T &value) { + custom.value = &value; + custom.format = &format_custom_arg; + } + template + static uint64_t type(const T &) { return Arg::CUSTOM; } +}; + +#define FMT_DISPATCH(call) static_cast(this)->call + +// An argument visitor. +// To use ArgVisitor define a subclass that implements some or all of the +// visit methods with the same signatures as the methods in ArgVisitor, +// for example, visit_int(int). +// Specify the subclass name as the Impl template parameter. Then calling +// ArgVisitor::visit for some argument will dispatch to a visit method +// specific to the argument type. For example, if the argument type is +// double then visit_double(double) method of a subclass will be called. +// If the subclass doesn't contain a method with this signature, then +// a corresponding method of ArgVisitor will be called. +// +// Example: +// class MyArgVisitor : public ArgVisitor { +// public: +// void visit_int(int value) { print("{}", value); } +// void visit_double(double value) { print("{}", value ); } +// }; +// +// ArgVisitor uses the curiously recurring template pattern: +// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern +template +class ArgVisitor { + public: + Result visit_unhandled_arg() { return Result(); } + + Result visit_int(int value) { + return FMT_DISPATCH(visit_any_int(value)); + } + Result visit_long_long(LongLong value) { + return FMT_DISPATCH(visit_any_int(value)); + } + Result visit_uint(unsigned value) { + return FMT_DISPATCH(visit_any_int(value)); + } + Result visit_ulong_long(ULongLong value) { + return FMT_DISPATCH(visit_any_int(value)); + } + Result visit_char(int value) { + return FMT_DISPATCH(visit_any_int(value)); + } + template + Result visit_any_int(T) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + Result visit_double(double value) { + return FMT_DISPATCH(visit_any_double(value)); + } + Result visit_long_double(long double value) { + return FMT_DISPATCH(visit_any_double(value)); + } + template + Result visit_any_double(T) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + Result visit_string(Arg::StringValue) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + Result visit_wstring(Arg::StringValue) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + Result visit_pointer(const void *) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + Result visit_custom(Arg::CustomValue) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + Result visit(const Arg &arg) { + switch (arg.type) { + default: + assert(false); + return Result(); + case Arg::INT: + return FMT_DISPATCH(visit_int(arg.int_value)); + case Arg::UINT: + return FMT_DISPATCH(visit_uint(arg.uint_value)); + case Arg::LONG_LONG: + return FMT_DISPATCH(visit_long_long(arg.long_long_value)); + case Arg::ULONG_LONG: + return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value)); + case Arg::DOUBLE: + return FMT_DISPATCH(visit_double(arg.double_value)); + case Arg::LONG_DOUBLE: + return FMT_DISPATCH(visit_long_double(arg.long_double_value)); + case Arg::CHAR: + return FMT_DISPATCH(visit_char(arg.int_value)); + case Arg::CSTRING: { + Value::StringValue str = arg.string; + str.size = 0; + return FMT_DISPATCH(visit_string(str)); + } + case Arg::STRING: + return FMT_DISPATCH(visit_string(arg.string)); + case Arg::WSTRING: + return FMT_DISPATCH(visit_wstring(arg.wstring)); + case Arg::POINTER: + return FMT_DISPATCH(visit_pointer(arg.pointer)); + case Arg::CUSTOM: + return FMT_DISPATCH(visit_custom(arg.custom)); + } + } +}; + +class RuntimeError : public std::runtime_error { + protected: + RuntimeError() : std::runtime_error("") {} +}; + +template +class ArgFormatter; +} // namespace internal + +/** + An argument list. + */ +class ArgList { + private: + uint64_t types_; + const internal::Value *values_; + + public: + // Maximum number of arguments that can be passed in ArgList. + enum { MAX_ARGS = 16 }; + + ArgList() : types_(0) {} + ArgList(ULongLong types, const internal::Value *values) + : types_(types), values_(values) {} + + /** + Returns the argument at specified index. + */ + internal::Arg operator[](unsigned index) const { + using internal::Arg; + Arg arg; + if (index >= MAX_ARGS) { + arg.type = Arg::NONE; + return arg; + } + unsigned shift = index * 4; + uint64_t mask = 0xf; + Arg::Type type = + static_cast((types_ & (mask << shift)) >> shift); + arg.type = type; + if (type != Arg::NONE) { + internal::Value &value = arg; + value = values_[index]; + } + return arg; + } +}; + +struct FormatSpec; + +namespace internal { + +class FormatterBase { + private: + ArgList args_; + int next_arg_index_; + + // Returns the argument with specified index. + Arg do_get_arg(unsigned arg_index, const char *&error); + + protected: + void set_args(const ArgList &args) { + args_ = args; + next_arg_index_ = 0; + } + + // Returns the next argument. + Arg next_arg(const char *&error); + + // Checks if manual indexing is used and returns the argument with + // specified index. + Arg get_arg(unsigned arg_index, const char *&error); + + template + void write(BasicWriter &w, const Char *start, const Char *end) { + if (start != end) + w << BasicStringRef(start, end - start); + } +}; + +// A printf formatter. +template +class PrintfFormatter : private FormatterBase { + private: + void parse_flags(FormatSpec &spec, const Char *&s); + + // Returns the argument with specified index or, if arg_index is equal + // to the maximum unsigned value, the next argument. + Arg get_arg(const Char *s, + unsigned arg_index = (std::numeric_limits::max)()); + + // Parses argument index, flags and width and returns the argument index. + unsigned parse_header(const Char *&s, FormatSpec &spec); + + public: + void format(BasicWriter &writer, + BasicStringRef format_str, const ArgList &args); +}; +} // namespace internal + +// A formatter. +template +class BasicFormatter : private internal::FormatterBase { + private: + BasicWriter &writer_; + const Char *start_; + + FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter); + + // Parses argument index and returns corresponding argument. + internal::Arg parse_arg_index(const Char *&s); + + public: + explicit BasicFormatter(BasicWriter &w) : writer_(w) {} + + BasicWriter &writer() { return writer_; } + + void format(BasicStringRef format_str, const ArgList &args); + + const Char *format(const Char *&format_str, const internal::Arg &arg); +}; + +enum Alignment { + ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC +}; + +// Flags. +enum { + SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8, + CHAR_FLAG = 0x10 // Argument has char type - used in error reporting. +}; + +// An empty format specifier. +struct EmptySpec {}; + +// A type specifier. +template +struct TypeSpec : EmptySpec { + Alignment align() const { return ALIGN_DEFAULT; } + unsigned width() const { return 0; } + int precision() const { return -1; } + bool flag(unsigned) const { return false; } + char type() const { return TYPE; } + char fill() const { return ' '; } +}; + +// A width specifier. +struct WidthSpec { + unsigned width_; + // Fill is always wchar_t and cast to char if necessary to avoid having + // two specialization of WidthSpec and its subclasses. + wchar_t fill_; + + WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {} + + unsigned width() const { return width_; } + wchar_t fill() const { return fill_; } +}; + +// An alignment specifier. +struct AlignSpec : WidthSpec { + Alignment align_; + + AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT) + : WidthSpec(width, fill), align_(align) {} + + Alignment align() const { return align_; } + + int precision() const { return -1; } +}; + +// An alignment and type specifier. +template +struct AlignTypeSpec : AlignSpec { + AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {} + + bool flag(unsigned) const { return false; } + char type() const { return TYPE; } +}; + +// A full format specifier. +struct FormatSpec : AlignSpec { + unsigned flags_; + int precision_; + char type_; + + FormatSpec( + unsigned width = 0, char type = 0, wchar_t fill = ' ') + : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} + + bool flag(unsigned f) const { return (flags_ & f) != 0; } + int precision() const { return precision_; } + char type() const { return type_; } +}; + +// An integer format specifier. +template , typename Char = char> +class IntFormatSpec : public SpecT { + private: + T value_; + + public: + IntFormatSpec(T val, const SpecT &spec = SpecT()) + : SpecT(spec), value_(val) {} + + T value() const { return value_; } +}; + +// A string format specifier. +template +class StrFormatSpec : public AlignSpec { + private: + const T *str_; + + public: + StrFormatSpec(const T *str, unsigned width, wchar_t fill) + : AlignSpec(width, fill), str_(str) {} + + const T *str() const { return str_; } +}; + +/** + Returns an integer format specifier to format the value in base 2. + */ +IntFormatSpec > bin(int value); + +/** + Returns an integer format specifier to format the value in base 8. + */ +IntFormatSpec > oct(int value); + +/** + Returns an integer format specifier to format the value in base 16 using + lower-case letters for the digits above 9. + */ +IntFormatSpec > hex(int value); + +/** + Returns an integer formatter format specifier to format in base 16 using + upper-case letters for the digits above 9. + */ +IntFormatSpec > hexu(int value); + +/** + \rst + Returns an integer format specifier to pad the formatted argument with the + fill character to the specified width using the default (right) numeric + alignment. + + **Example**:: + + MemoryWriter out; + out << pad(hex(0xcafe), 8, '0'); + // out.str() == "0000cafe" + + \endrst + */ +template +IntFormatSpec, Char> pad( + int value, unsigned width, Char fill = ' '); + +#define FMT_DEFINE_INT_FORMATTERS(TYPE) \ +inline IntFormatSpec > bin(TYPE value) { \ + return IntFormatSpec >(value, TypeSpec<'b'>()); \ +} \ + \ +inline IntFormatSpec > oct(TYPE value) { \ + return IntFormatSpec >(value, TypeSpec<'o'>()); \ +} \ + \ +inline IntFormatSpec > hex(TYPE value) { \ + return IntFormatSpec >(value, TypeSpec<'x'>()); \ +} \ + \ +inline IntFormatSpec > hexu(TYPE value) { \ + return IntFormatSpec >(value, TypeSpec<'X'>()); \ +} \ + \ +template \ +inline IntFormatSpec > pad( \ + IntFormatSpec > f, unsigned width) { \ + return IntFormatSpec >( \ + f.value(), AlignTypeSpec(width, ' ')); \ +} \ + \ +/* For compatibility with older compilers we provide two overloads for pad, */ \ +/* one that takes a fill character and one that doesn't. In the future this */ \ +/* can be replaced with one overload making the template argument Char */ \ +/* default to char (C++11). */ \ +template \ +inline IntFormatSpec, Char> pad( \ + IntFormatSpec, Char> f, \ + unsigned width, Char fill) { \ + return IntFormatSpec, Char>( \ + f.value(), AlignTypeSpec(width, fill)); \ +} \ + \ +inline IntFormatSpec > pad( \ + TYPE value, unsigned width) { \ + return IntFormatSpec >( \ + value, AlignTypeSpec<0>(width, ' ')); \ +} \ + \ +template \ +inline IntFormatSpec, Char> pad( \ + TYPE value, unsigned width, Char fill) { \ + return IntFormatSpec, Char>( \ + value, AlignTypeSpec<0>(width, fill)); \ +} + +FMT_DEFINE_INT_FORMATTERS(int) +FMT_DEFINE_INT_FORMATTERS(long) +FMT_DEFINE_INT_FORMATTERS(unsigned) +FMT_DEFINE_INT_FORMATTERS(unsigned long) +FMT_DEFINE_INT_FORMATTERS(LongLong) +FMT_DEFINE_INT_FORMATTERS(ULongLong) + +/** + \rst + Returns a string formatter that pads the formatted argument with the fill + character to the specified width using the default (left) string alignment. + + **Example**:: + + std::string s = str(MemoryWriter() << pad("abc", 8)); + // s == "abc " + + \endrst + */ +template +inline StrFormatSpec pad( + const Char *str, unsigned width, Char fill = ' ') { + return StrFormatSpec(str, width, fill); +} + +inline StrFormatSpec pad( + const wchar_t *str, unsigned width, char fill = ' ') { + return StrFormatSpec(str, width, fill); +} + +// Generates a comma-separated list with results of applying f to +// numbers 0..n-1. +# define FMT_GEN(n, f) FMT_GEN##n(f) +# define FMT_GEN1(f) f(0) +# define FMT_GEN2(f) FMT_GEN1(f), f(1) +# define FMT_GEN3(f) FMT_GEN2(f), f(2) +# define FMT_GEN4(f) FMT_GEN3(f), f(3) +# define FMT_GEN5(f) FMT_GEN4(f), f(4) +# define FMT_GEN6(f) FMT_GEN5(f), f(5) +# define FMT_GEN7(f) FMT_GEN6(f), f(6) +# define FMT_GEN8(f) FMT_GEN7(f), f(7) +# define FMT_GEN9(f) FMT_GEN8(f), f(8) +# define FMT_GEN10(f) FMT_GEN9(f), f(9) +# define FMT_GEN11(f) FMT_GEN10(f), f(10) +# define FMT_GEN12(f) FMT_GEN11(f), f(11) +# define FMT_GEN13(f) FMT_GEN12(f), f(12) +# define FMT_GEN14(f) FMT_GEN13(f), f(13) +# define FMT_GEN15(f) FMT_GEN14(f), f(14) + +namespace internal { +inline uint64_t make_type() { return 0; } + +template +inline uint64_t make_type(const T &arg) { return MakeValue::type(arg); } + +#if FMT_USE_VARIADIC_TEMPLATES +template +inline uint64_t make_type(const Arg &first, const Args & ... tail) { + return make_type(first) | (make_type(tail...) << 4); +} +#else + +struct ArgType { + uint64_t type; + + ArgType() : type(0) {} + + template + ArgType(const T &arg) : type(make_type(arg)) {} +}; + +# define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType() + +inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { + return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) | + (t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) | + (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) | + (t12.type << 48) | (t13.type << 52) | (t14.type << 56); +} +#endif +} // namespace internal + +# define FMT_MAKE_TEMPLATE_ARG(n) typename T##n +# define FMT_MAKE_ARG_TYPE(n) T##n +# define FMT_MAKE_ARG(n) const T##n &v##n +# define FMT_MAKE_REF_char(n) fmt::internal::MakeValue(v##n) +# define FMT_MAKE_REF_wchar_t(n) fmt::internal::MakeValue(v##n) + +#if FMT_USE_VARIADIC_TEMPLATES +// Defines a variadic function returning void. +# define FMT_VARIADIC_VOID(func, arg_type) \ + template \ + void func(arg_type arg1, const Args & ... args) { \ + const fmt::internal::Value values[ \ + fmt::internal::NonZero::VALUE] = { \ + fmt::internal::MakeValue(args)... \ + }; \ + func(arg1, ArgList(fmt::internal::make_type(args...), values)); \ + } + +// Defines a variadic constructor. +# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ + template \ + ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ + using fmt::internal::MakeValue; \ + const fmt::internal::Value values[ \ + fmt::internal::NonZero::VALUE] = { \ + MakeValue(args)... \ + }; \ + func(arg0, arg1, ArgList(fmt::internal::make_type(args...), values)); \ + } + +#else + +# define FMT_MAKE_REF(n) fmt::internal::MakeValue(v##n) +# define FMT_MAKE_REF2(n) v##n + +// Defines a wrapper for a function taking one argument of type arg_type +// and n additional arguments of arbitrary types. +# define FMT_WRAP1(func, arg_type, n) \ + template \ + inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ + const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ + func(arg1, fmt::ArgList( \ + fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ + } + +// Emulates a variadic function returning void on a pre-C++11 compiler. +# define FMT_VARIADIC_VOID(func, arg_type) \ + inline void func(arg_type arg) { func(arg, fmt::ArgList()); } \ + FMT_WRAP1(func, arg_type, 1) FMT_WRAP1(func, arg_type, 2) \ + FMT_WRAP1(func, arg_type, 3) FMT_WRAP1(func, arg_type, 4) \ + FMT_WRAP1(func, arg_type, 5) FMT_WRAP1(func, arg_type, 6) \ + FMT_WRAP1(func, arg_type, 7) FMT_WRAP1(func, arg_type, 8) \ + FMT_WRAP1(func, arg_type, 9) FMT_WRAP1(func, arg_type, 10) + +# define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \ + template \ + ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ + const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ + func(arg0, arg1, fmt::ArgList( \ + fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ + } + +// Emulates a variadic constructor on a pre-C++11 compiler. +# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 1) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 2) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 3) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 4) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 5) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 6) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 7) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 8) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 9) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 10) +#endif + +// Generates a comma-separated list with results of applying f to pairs +// (argument, index). +#define FMT_FOR_EACH1(f, x0) f(x0, 0) +#define FMT_FOR_EACH2(f, x0, x1) \ + FMT_FOR_EACH1(f, x0), f(x1, 1) +#define FMT_FOR_EACH3(f, x0, x1, x2) \ + FMT_FOR_EACH2(f, x0 ,x1), f(x2, 2) +#define FMT_FOR_EACH4(f, x0, x1, x2, x3) \ + FMT_FOR_EACH3(f, x0, x1, x2), f(x3, 3) +#define FMT_FOR_EACH5(f, x0, x1, x2, x3, x4) \ + FMT_FOR_EACH4(f, x0, x1, x2, x3), f(x4, 4) +#define FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5) \ + FMT_FOR_EACH5(f, x0, x1, x2, x3, x4), f(x5, 5) +#define FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6) \ + FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5), f(x6, 6) +#define FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7) \ + FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6), f(x7, 7) +#define FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8) \ + FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7), f(x8, 8) +#define FMT_FOR_EACH10(f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) \ + FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8), f(x9, 9) + +/** + An error returned by an operating system or a language runtime, + for example a file opening error. +*/ +class SystemError : public internal::RuntimeError { + private: + void init(int err_code, StringRef format_str, ArgList args); + + protected: + int error_code_; + + typedef char Char; // For FMT_VARIADIC_CTOR. + + SystemError() {} + + public: + /** + \rst + Constructs a :class:`fmt::SystemError` object with the description + of the form + + .. parsed-literal:: + **: ** + + where ** is the formatted message and ** is + the system message corresponding to the error code. + *error_code* is a system error code as given by ``errno``. + If *error_code* is not a valid error code such as -1, the system message + may look like "Unknown error -1" and is platform-dependent. + + **Example**:: + + // This throws a SystemError with the description + // cannot open file 'madeup': No such file or directory + // or similar (system message may vary). + const char *filename = "madeup"; + std::FILE *file = std::fopen(filename, "r"); + if (!file) + throw fmt::SystemError(errno, "cannot open file '{}'", filename); + \endrst + */ + SystemError(int error_code, StringRef message) { + init(error_code, message, ArgList()); + } + FMT_VARIADIC_CTOR(SystemError, init, int, StringRef) + + int error_code() const { return error_code_; } +}; + +/** + \rst + This template provides operations for formatting and writing data into + a character stream. The output is stored in a buffer provided by a subclass + such as :class:`fmt::BasicMemoryWriter`. + + You can use one of the following typedefs for common character types: + + +---------+----------------------+ + | Type | Definition | + +=========+======================+ + | Writer | BasicWriter | + +---------+----------------------+ + | WWriter | BasicWriter | + +---------+----------------------+ + + \endrst + */ +template +class BasicWriter { + private: + // Output buffer. + internal::Buffer &buffer_; + + FMT_DISALLOW_COPY_AND_ASSIGN(BasicWriter); + + typedef typename internal::CharTraits::CharPtr CharPtr; + +#if _SECURE_SCL + // Returns pointer value. + static Char *get(CharPtr p) { return p.base(); } +#else + static Char *get(Char *p) { return p; } +#endif + + // Fills the padding around the content and returns the pointer to the + // content area. + static CharPtr fill_padding(CharPtr buffer, + unsigned total_size, std::size_t content_size, wchar_t fill); + + // Grows the buffer by n characters and returns a pointer to the newly + // allocated area. + CharPtr grow_buffer(std::size_t n) { + std::size_t size = buffer_.size(); + buffer_.resize(size + n); + return internal::make_ptr(&buffer_[size], n); + } + + // Prepare a buffer for integer formatting. + CharPtr prepare_int_buffer(unsigned num_digits, + const EmptySpec &, const char *prefix, unsigned prefix_size) { + unsigned size = prefix_size + num_digits; + CharPtr p = grow_buffer(size); + std::copy(prefix, prefix + prefix_size, p); + return p + size - 1; + } + + template + CharPtr prepare_int_buffer(unsigned num_digits, + const Spec &spec, const char *prefix, unsigned prefix_size); + + // Formats an integer. + template + void write_int(T value, Spec spec); + + // Formats a floating-point number (double or long double). + template + void write_double(T value, const FormatSpec &spec); + + // Writes a formatted string. + template + CharPtr write_str( + const StrChar *s, std::size_t size, const AlignSpec &spec); + + template + void write_str( + const internal::Arg::StringValue &str, const FormatSpec &spec); + + // This method is private to disallow writing a wide string to a + // char stream and vice versa. If you want to print a wide string + // as a pointer as std::ostream does, cast it to const void*. + // Do not implement! + void operator<<(typename internal::CharTraits::UnsupportedStrType); + + // Appends floating-point length specifier to the format string. + // The second argument is only used for overload resolution. + void append_float_length(Char *&format_ptr, long double) { + *format_ptr++ = 'L'; + } + + template + void append_float_length(Char *&, T) {} + + friend class internal::ArgFormatter; + friend class internal::PrintfFormatter; + + protected: + /** + Constructs a ``BasicWriter`` object. + */ + explicit BasicWriter(internal::Buffer &b) : buffer_(b) {} + + public: + /** + Destroys a ``BasicWriter`` object. + */ + virtual ~BasicWriter() {} + + /** + Returns the total number of characters written. + */ + std::size_t size() const { return buffer_.size(); } + + /** + Returns a pointer to the output buffer content. No terminating null + character is appended. + */ + const Char *data() const FMT_NOEXCEPT { return &buffer_[0]; } + + /** + Returns a pointer to the output buffer content with terminating null + character appended. + */ + const Char *c_str() const { + std::size_t size = buffer_.size(); + buffer_.reserve(size + 1); + buffer_[size] = '\0'; + return &buffer_[0]; + } + + /** + Returns the content of the output buffer as an `std::string`. + */ + std::basic_string str() const { + return std::basic_string(&buffer_[0], buffer_.size()); + } + + /** + \rst + Writes formatted data. + + *args* is an argument list representing arbitrary arguments. + + **Example**:: + + MemoryWriter out; + out.write("Current point:\n"); + out.write("({:+f}, {:+f})", -3.14, 3.14); + + This will write the following output to the ``out`` object: + + .. code-block:: none + + Current point: + (-3.140000, +3.140000) + + The output can be accessed using :func:`data()`, :func:`c_str` or + :func:`str` methods. + + See also :ref:`syntax`. + \endrst + */ + void write(BasicStringRef format, ArgList args) { + BasicFormatter(*this).format(format, args); + } + FMT_VARIADIC_VOID(write, BasicStringRef) + + BasicWriter &operator<<(int value) { + return *this << IntFormatSpec(value); + } + BasicWriter &operator<<(unsigned value) { + return *this << IntFormatSpec(value); + } + BasicWriter &operator<<(long value) { + return *this << IntFormatSpec(value); + } + BasicWriter &operator<<(unsigned long value) { + return *this << IntFormatSpec(value); + } + BasicWriter &operator<<(LongLong value) { + return *this << IntFormatSpec(value); + } + + /** + Formats *value* and writes it to the stream. + */ + BasicWriter &operator<<(ULongLong value) { + return *this << IntFormatSpec(value); + } + + BasicWriter &operator<<(double value) { + write_double(value, FormatSpec()); + return *this; + } + + /** + Formats *value* using the general format for floating-point numbers + (``'g'``) and writes it to the stream. + */ + BasicWriter &operator<<(long double value) { + write_double(value, FormatSpec()); + return *this; + } + + /** + Writes a character to the stream. + */ + BasicWriter &operator<<(char value) { + buffer_.push_back(value); + return *this; + } + + BasicWriter &operator<<(wchar_t value) { + buffer_.push_back(internal::CharTraits::convert(value)); + return *this; + } + + /** + Writes *value* to the stream. + */ + BasicWriter &operator<<(fmt::BasicStringRef value) { + const Char *str = value.c_str(); + buffer_.append(str, str + value.size()); + return *this; + } + + template + BasicWriter &operator<<(IntFormatSpec spec) { + internal::CharTraits::convert(FillChar()); + write_int(spec.value(), spec); + return *this; + } + + template + BasicWriter &operator<<(const StrFormatSpec &spec) { + const StrChar *s = spec.str(); + // TODO: error if fill is not convertible to Char + write_str(s, std::char_traits::length(s), spec); + return *this; + } + + void clear() FMT_NOEXCEPT { buffer_.clear(); } +}; + +template +template +typename BasicWriter::CharPtr BasicWriter::write_str( + const StrChar *s, std::size_t size, const AlignSpec &spec) { + CharPtr out = CharPtr(); + if (spec.width() > size) { + out = grow_buffer(spec.width()); + Char fill = static_cast(spec.fill()); + if (spec.align() == ALIGN_RIGHT) { + std::fill_n(out, spec.width() - size, fill); + out += spec.width() - size; + } else if (spec.align() == ALIGN_CENTER) { + out = fill_padding(out, spec.width(), size, fill); + } else { + std::fill_n(out + size, spec.width() - size, fill); + } + } else { + out = grow_buffer(size); + } + std::copy(s, s + size, out); + return out; +} + +template +typename BasicWriter::CharPtr + BasicWriter::fill_padding( + CharPtr buffer, unsigned total_size, + std::size_t content_size, wchar_t fill) { + std::size_t padding = total_size - content_size; + std::size_t left_padding = padding / 2; + Char fill_char = static_cast(fill); + std::fill_n(buffer, left_padding, fill_char); + buffer += left_padding; + CharPtr content = buffer; + std::fill_n(buffer + content_size, padding - left_padding, fill_char); + return content; +} + +template +template +typename BasicWriter::CharPtr + BasicWriter::prepare_int_buffer( + unsigned num_digits, const Spec &spec, + const char *prefix, unsigned prefix_size) { + unsigned width = spec.width(); + Alignment align = spec.align(); + Char fill = static_cast(spec.fill()); + if (spec.precision() > static_cast(num_digits)) { + // Octal prefix '0' is counted as a digit, so ignore it if precision + // is specified. + if (prefix_size > 0 && prefix[prefix_size - 1] == '0') + --prefix_size; + unsigned number_size = prefix_size + spec.precision(); + AlignSpec subspec(number_size, '0', ALIGN_NUMERIC); + if (number_size >= width) + return prepare_int_buffer(num_digits, subspec, prefix, prefix_size); + buffer_.reserve(width); + unsigned fill_size = width - number_size; + if (align != ALIGN_LEFT) { + CharPtr p = grow_buffer(fill_size); + std::fill(p, p + fill_size, fill); + } + CharPtr result = prepare_int_buffer( + num_digits, subspec, prefix, prefix_size); + if (align == ALIGN_LEFT) { + CharPtr p = grow_buffer(fill_size); + std::fill(p, p + fill_size, fill); + } + return result; + } + unsigned size = prefix_size + num_digits; + if (width <= size) { + CharPtr p = grow_buffer(size); + std::copy(prefix, prefix + prefix_size, p); + return p + size - 1; + } + CharPtr p = grow_buffer(width); + CharPtr end = p + width; + if (align == ALIGN_LEFT) { + std::copy(prefix, prefix + prefix_size, p); + p += size; + std::fill(p, end, fill); + } else if (align == ALIGN_CENTER) { + p = fill_padding(p, width, size, fill); + std::copy(prefix, prefix + prefix_size, p); + p += size; + } else { + if (align == ALIGN_NUMERIC) { + if (prefix_size != 0) { + p = std::copy(prefix, prefix + prefix_size, p); + size -= prefix_size; + } + } else { + std::copy(prefix, prefix + prefix_size, end - size); + } + std::fill(p, end - size, fill); + p = end; + } + return p - 1; +} + +template +template +void BasicWriter::write_int(T value, Spec spec) { + unsigned prefix_size = 0; + typedef typename internal::IntTraits::MainType UnsignedType; + UnsignedType abs_value = value; + char prefix[4] = ""; + if (internal::is_negative(value)) { + prefix[0] = '-'; + ++prefix_size; + abs_value = 0 - abs_value; + } else if (spec.flag(SIGN_FLAG)) { + prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' '; + ++prefix_size; + } + switch (spec.type()) { + case 0: case 'd': { + unsigned num_digits = internal::count_digits(abs_value); + CharPtr p = prepare_int_buffer( + num_digits, spec, prefix, prefix_size) + 1 - num_digits; + internal::format_decimal(get(p), abs_value, num_digits); + break; + } + case 'x': case 'X': { + UnsignedType n = abs_value; + if (spec.flag(HASH_FLAG)) { + prefix[prefix_size++] = '0'; + prefix[prefix_size++] = spec.type(); + } + unsigned num_digits = 0; + do { + ++num_digits; + } while ((n >>= 4) != 0); + Char *p = get(prepare_int_buffer( + num_digits, spec, prefix, prefix_size)); + n = abs_value; + const char *digits = spec.type() == 'x' ? + "0123456789abcdef" : "0123456789ABCDEF"; + do { + *p-- = digits[n & 0xf]; + } while ((n >>= 4) != 0); + break; + } + case 'b': case 'B': { + UnsignedType n = abs_value; + if (spec.flag(HASH_FLAG)) { + prefix[prefix_size++] = '0'; + prefix[prefix_size++] = spec.type(); + } + unsigned num_digits = 0; + do { + ++num_digits; + } while ((n >>= 1) != 0); + Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); + n = abs_value; + do { + *p-- = '0' + (n & 1); + } while ((n >>= 1) != 0); + break; + } + case 'o': { + UnsignedType n = abs_value; + if (spec.flag(HASH_FLAG)) + prefix[prefix_size++] = '0'; + unsigned num_digits = 0; + do { + ++num_digits; + } while ((n >>= 3) != 0); + Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); + n = abs_value; + do { + *p-- = '0' + (n & 7); + } while ((n >>= 3) != 0); + break; + } + default: + internal::report_unknown_type( + spec.type(), spec.flag(CHAR_FLAG) ? "char" : "integer"); + break; + } +} + +template +template +void BasicWriter::write_double( + T value, const FormatSpec &spec) { + // Check type. + char type = spec.type(); + bool upper = false; + switch (type) { + case 0: + type = 'g'; + break; + case 'e': case 'f': case 'g': case 'a': + break; + case 'F': +#ifdef _MSC_VER + // MSVC's printf doesn't support 'F'. + type = 'f'; +#endif + // Fall through. + case 'E': case 'G': case 'A': + upper = true; + break; + default: + internal::report_unknown_type(type, "double"); + break; + } + + char sign = 0; + // Use getsign instead of value < 0 because the latter is always + // false for NaN. + if (internal::getsign(static_cast(value))) { + sign = '-'; + value = -value; + } else if (spec.flag(SIGN_FLAG)) { + sign = spec.flag(PLUS_FLAG) ? '+' : ' '; + } + + if (value != value) { + // Format NaN ourselves because sprintf's output is not consistent + // across platforms. + std::size_t nan_size = 4; + const char *nan = upper ? " NAN" : " nan"; + if (!sign) { + --nan_size; + ++nan; + } + CharPtr out = write_str(nan, nan_size, spec); + if (sign) + *out = sign; + return; + } + + if (internal::isinfinity(value)) { + // Format infinity ourselves because sprintf's output is not consistent + // across platforms. + std::size_t inf_size = 4; + const char *inf = upper ? " INF" : " inf"; + if (!sign) { + --inf_size; + ++inf; + } + CharPtr out = write_str(inf, inf_size, spec); + if (sign) + *out = sign; + return; + } + + std::size_t offset = buffer_.size(); + unsigned width = spec.width(); + if (sign) { + buffer_.reserve(buffer_.size() + (std::max)(width, 1u)); + if (width > 0) + --width; + ++offset; + } + + // Build format string. + enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg + Char format[MAX_FORMAT_SIZE]; + Char *format_ptr = format; + *format_ptr++ = '%'; + unsigned width_for_sprintf = width; + if (spec.flag(HASH_FLAG)) + *format_ptr++ = '#'; + if (spec.align() == ALIGN_CENTER) { + width_for_sprintf = 0; + } else { + if (spec.align() == ALIGN_LEFT) + *format_ptr++ = '-'; + if (width != 0) + *format_ptr++ = '*'; + } + if (spec.precision() >= 0) { + *format_ptr++ = '.'; + *format_ptr++ = '*'; + } + + append_float_length(format_ptr, value); + *format_ptr++ = type; + *format_ptr = '\0'; + + // Format using snprintf. + Char fill = static_cast(spec.fill()); + for (;;) { + std::size_t buffer_size = buffer_.capacity() - offset; +#if _MSC_VER + // MSVC's vsnprintf_s doesn't work with zero size, so reserve + // space for at least one extra character to make the size non-zero. + // Note that the buffer's capacity will increase by more than 1. + if (buffer_size == 0) { + buffer_.reserve(offset + 1); + buffer_size = buffer_.capacity() - offset; + } +#endif + Char *start = &buffer_[offset]; + int n = internal::CharTraits::format_float( + start, buffer_size, format, width_for_sprintf, spec.precision(), value); + if (n >= 0 && offset + n < buffer_.capacity()) { + if (sign) { + if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || + *start != ' ') { + *(start - 1) = sign; + sign = 0; + } else { + *(start - 1) = fill; + } + ++n; + } + if (spec.align() == ALIGN_CENTER && + spec.width() > static_cast(n)) { + width = spec.width(); + CharPtr p = grow_buffer(width); + std::copy(p, p + n, p + (width - n) / 2); + fill_padding(p, spec.width(), n, fill); + return; + } + if (spec.fill() != ' ' || sign) { + while (*start == ' ') + *start++ = fill; + if (sign) + *(start - 1) = sign; + } + grow_buffer(n); + return; + } + // If n is negative we ask to increase the capacity by at least 1, + // but as std::vector, the buffer grows exponentially. + buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1); + } +} + +/** + \rst + This template provides operations for formatting and writing data into + a character stream. The output is stored in a memory buffer that grows + dynamically. + + You can use one of the following typedefs for common character types + and the standard allocator: + + +---------------+-----------------------------------------------+ + | Type | Definition | + +===============+===============================================+ + | MemoryWriter | BasicWriter> | + +---------------+-----------------------------------------------+ + | WMemoryWriter | BasicWriter> | + +---------------+-----------------------------------------------+ + + **Example**:: + + MemoryWriter out; + out << "The answer is " << 42 << "\n"; + out.write("({:+f}, {:+f})", -3.14, 3.14); + + This will write the following output to the ``out`` object: + + .. code-block:: none + + The answer is 42 + (-3.140000, +3.140000) + + The output can be converted to an ``std::string`` with ``out.str()`` or + accessed as a C string with ``out.c_str()``. + \endrst + */ +template > +class BasicMemoryWriter : public BasicWriter { + private: + internal::MemoryBuffer buffer_; + + public: + explicit BasicMemoryWriter(const Allocator& alloc = Allocator()) + : BasicWriter(buffer_), buffer_(alloc) {} + +#if FMT_USE_RVALUE_REFERENCES + /** + Constructs a :class:`fmt::BasicMemoryWriter` object moving the content + of the other object to it. + */ + BasicMemoryWriter(BasicMemoryWriter &&other) + : BasicWriter(buffer_), buffer_(std::move(other.buffer_)) { + } + + /** + Moves the content of the other ``BasicMemoryWriter`` object to this one. + */ + BasicMemoryWriter &operator=(BasicMemoryWriter &&other) { + buffer_ = std::move(other.buffer_); + return *this; + } +#endif +}; + +typedef BasicMemoryWriter MemoryWriter; +typedef BasicMemoryWriter WMemoryWriter; + +// Formats a value. +template +void format(BasicFormatter &f, const Char *&format_str, const T &value) { + std::basic_ostringstream os; + os << value; + internal::Arg arg; + internal::Value &arg_value = arg; + std::basic_string str = os.str(); + arg_value = internal::MakeValue(str); + arg.type = static_cast(internal::MakeValue::type(str)); + format_str = f.format(format_str, arg); +} + +// Reports a system error without throwing an exception. +// Can be used to report errors from destructors. +void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT; + +#ifdef _WIN32 + +/** A Windows error. */ +class WindowsError : public SystemError { + private: + void init(int error_code, StringRef format_str, ArgList args); + + public: + /** + \rst + Constructs a :class:`fmt::WindowsError` object with the description + of the form + + .. parsed-literal:: + **: ** + + where ** is the formatted message and ** is the system + message corresponding to the error code. + *error_code* is a Windows error code as given by ``GetLastError``. + If *error_code* is not a valid error code such as -1, the system message + will look like "error -1". + + **Example**:: + + // This throws a WindowsError with the description + // cannot open file 'madeup': The system cannot find the file specified. + // or similar (system message may vary). + const char *filename = "madeup"; + LPOFSTRUCT of = LPOFSTRUCT(); + HFILE file = OpenFile(filename, &of, OF_READ); + if (file == HFILE_ERROR) + throw fmt::WindowsError(GetLastError(), "cannot open file '{}'", filename); + \endrst + */ + WindowsError(int error_code, StringRef message) { + init(error_code, message, ArgList()); + } + FMT_VARIADIC_CTOR(WindowsError, init, int, StringRef) +}; + +// Reports a Windows error without throwing an exception. +// Can be used to report errors from destructors. +void report_windows_error(int error_code, StringRef message) FMT_NOEXCEPT; + +#endif + +enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; + +/** + Formats a string and prints it to stdout using ANSI escape sequences + to specify color (experimental). + Example: + PrintColored(fmt::RED, "Elapsed time: {0:.2f} seconds") << 1.23; + */ +void print_colored(Color c, StringRef format, ArgList args); + +/** + \rst + Formats arguments and returns the result as a string. + + **Example**:: + + std::string message = format("The answer is {}", 42); + \endrst +*/ +inline std::string format(StringRef format_str, ArgList args) { + MemoryWriter w; + w.write(format_str, args); + return w.str(); +} + +inline std::wstring format(WStringRef format_str, ArgList args) { + WMemoryWriter w; + w.write(format_str, args); + return w.str(); +} + +/** + \rst + Prints formatted data to the file *f*. + + **Example**:: + + print(stderr, "Don't {}!", "panic"); + \endrst + */ +void print(std::FILE *f, StringRef format_str, ArgList args); + +/** + \rst + Prints formatted data to ``stdout``. + + **Example**:: + + print("Elapsed time: {0:.2f} seconds", 1.23); + \endrst + */ +void print(StringRef format_str, ArgList args); + +/** + \rst + Prints formatted data to the stream *os*. + + **Example**:: + + print(cerr, "Don't {}!", "panic"); + \endrst + */ +void print(std::ostream &os, StringRef format_str, ArgList args); + +template +void printf(BasicWriter &w, BasicStringRef format, ArgList args) { + internal::PrintfFormatter().format(w, format, args); +} + +/** + \rst + Formats arguments and returns the result as a string. + + **Example**:: + + std::string message = fmt::sprintf("The answer is %d", 42); + \endrst +*/ +inline std::string sprintf(StringRef format, ArgList args) { + MemoryWriter w; + printf(w, format, args); + return w.str(); +} + +/** + \rst + Prints formatted data to the file *f*. + + **Example**:: + + fmt::fprintf(stderr, "Don't %s!", "panic"); + \endrst + */ +int fprintf(std::FILE *f, StringRef format, ArgList args); + +/** + \rst + Prints formatted data to ``stdout``. + + **Example**:: + + fmt::printf("Elapsed time: %.2f seconds", 1.23); + \endrst + */ +inline int printf(StringRef format, ArgList args) { + return fprintf(stdout, format, args); +} + +/** + Fast integer formatter. + */ +class FormatInt { + private: + // Buffer should be large enough to hold all digits (digits10 + 1), + // a sign and a null character. + enum {BUFFER_SIZE = std::numeric_limits::digits10 + 3}; + mutable char buffer_[BUFFER_SIZE]; + char *str_; + + // Formats value in reverse and returns the number of digits. + char *format_decimal(ULongLong value) { + char *buffer_end = buffer_ + BUFFER_SIZE - 1; + while (value >= 100) { + // Integer division is slow so do it for a group of two digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + unsigned index = (value % 100) * 2; + value /= 100; + *--buffer_end = internal::Data::DIGITS[index + 1]; + *--buffer_end = internal::Data::DIGITS[index]; + } + if (value < 10) { + *--buffer_end = static_cast('0' + value); + return buffer_end; + } + unsigned index = static_cast(value * 2); + *--buffer_end = internal::Data::DIGITS[index + 1]; + *--buffer_end = internal::Data::DIGITS[index]; + return buffer_end; + } + + void FormatSigned(LongLong value) { + ULongLong abs_value = static_cast(value); + bool negative = value < 0; + if (negative) + abs_value = 0 - abs_value; + str_ = format_decimal(abs_value); + if (negative) + *--str_ = '-'; + } + + public: + explicit FormatInt(int value) { FormatSigned(value); } + explicit FormatInt(long value) { FormatSigned(value); } + explicit FormatInt(LongLong value) { FormatSigned(value); } + explicit FormatInt(unsigned value) : str_(format_decimal(value)) {} + explicit FormatInt(unsigned long value) : str_(format_decimal(value)) {} + explicit FormatInt(ULongLong value) : str_(format_decimal(value)) {} + + /** + Returns the number of characters written to the output buffer. + */ + std::size_t size() const { return buffer_ - str_ + BUFFER_SIZE - 1; } + + /** + Returns a pointer to the output buffer content. No terminating null + character is appended. + */ + const char *data() const { return str_; } + + /** + Returns a pointer to the output buffer content with terminating null + character appended. + */ + const char *c_str() const { + buffer_[BUFFER_SIZE - 1] = '\0'; + return str_; + } + + /** + Returns the content of the output buffer as an `std::string`. + */ + std::string str() const { return std::string(str_, size()); } +}; + +// Formats a decimal integer value writing into buffer and returns +// a pointer to the end of the formatted string. This function doesn't +// write a terminating null character. +template +inline void format_decimal(char *&buffer, T value) { + typename internal::IntTraits::MainType abs_value = value; + if (internal::is_negative(value)) { + *buffer++ = '-'; + abs_value = 0 - abs_value; + } + if (abs_value < 100) { + if (abs_value < 10) { + *buffer++ = static_cast('0' + abs_value); + return; + } + unsigned index = static_cast(abs_value * 2); + *buffer++ = internal::Data::DIGITS[index]; + *buffer++ = internal::Data::DIGITS[index + 1]; + return; + } + unsigned num_digits = internal::count_digits(abs_value); + internal::format_decimal(buffer, abs_value, num_digits); + buffer += num_digits; +} +} + +#if FMT_GCC_VERSION +// Use the system_header pragma to suppress warnings about variadic macros +// because suppressing -Wvariadic-macros with the diagnostic pragma doesn't +// work. It is used at the end because we want to suppress as little warnings +// as possible. +# pragma GCC system_header +#endif + +// This is used to work around VC++ bugs in handling variadic macros. +#define FMT_EXPAND(args) args + +// Returns the number of arguments. +// Based on https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s. +#define FMT_NARG(...) FMT_NARG_(__VA_ARGS__, FMT_RSEQ_N()) +#define FMT_NARG_(...) FMT_EXPAND(FMT_ARG_N(__VA_ARGS__)) +#define FMT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N +#define FMT_RSEQ_N() 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + +#define FMT_CONCAT(a, b) a##b +#define FMT_FOR_EACH_(N, f, ...) \ + FMT_EXPAND(FMT_CONCAT(FMT_FOR_EACH, N)(f, __VA_ARGS__)) +#define FMT_FOR_EACH(f, ...) \ + FMT_EXPAND(FMT_FOR_EACH_(FMT_NARG(__VA_ARGS__), f, __VA_ARGS__)) + +#define FMT_ADD_ARG_NAME(type, index) type arg##index +#define FMT_GET_ARG_NAME(type, index) arg##index + +#if FMT_USE_VARIADIC_TEMPLATES +# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ + template \ + ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ + const Args & ... args) { \ + using fmt::internal::Value; \ + const Value values[fmt::internal::NonZero::VALUE] = { \ + fmt::internal::MakeValue(args)... \ + }; \ + call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ + fmt::internal::make_type(args...), values)); \ + } +#else +// Defines a wrapper for a function taking __VA_ARGS__ arguments +// and n additional arguments of arbitrary types. +# define FMT_WRAP(Char, ReturnType, func, call, n, ...) \ + template \ + inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ + FMT_GEN(n, FMT_MAKE_ARG)) { \ + const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF_##Char)}; \ + call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ + fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ + } + +# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ + inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) { \ + call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList()); \ + } \ + FMT_WRAP(Char, ReturnType, func, call, 1, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 2, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 3, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 4, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 5, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 6, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 7, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 8, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 9, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 10, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 11, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 12, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 13, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 14, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 15, __VA_ARGS__) +#endif // FMT_USE_VARIADIC_TEMPLATES + +/** + \rst + Defines a variadic function with the specified return type, function name + and argument types passed as variable arguments to this macro. + + **Example**:: + + void print_error(const char *file, int line, const char *format, + fmt::ArgList args) { + fmt::print("{}: {}: ", file, line); + fmt::print(format, args); + } + FMT_VARIADIC(void, print_error, const char *, int, const char *) + + ``FMT_VARIADIC`` is used for compatibility with legacy C++ compilers that + don't implement variadic templates. You don't have to use this macro if + you don't need legacy compiler support and can use variadic templates + directly:: + + template + void print_error(const char *file, int line, const char *format, + const Args & ... args) { + fmt::print("{}: {}: ", file, line); + fmt::print(format, args...); + } + \endrst + */ +#define FMT_VARIADIC(ReturnType, func, ...) \ + FMT_VARIADIC_(char, ReturnType, func, return func, __VA_ARGS__) + +#define FMT_VARIADIC_W(ReturnType, func, ...) \ + FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__) + +namespace fmt { +FMT_VARIADIC(std::string, format, StringRef) +FMT_VARIADIC_W(std::wstring, format, WStringRef) +FMT_VARIADIC(void, print, StringRef) +FMT_VARIADIC(void, print, std::FILE *, StringRef) +FMT_VARIADIC(void, print, std::ostream &, StringRef) +FMT_VARIADIC(void, print_colored, Color, StringRef) +FMT_VARIADIC(std::string, sprintf, StringRef) +FMT_VARIADIC(int, printf, StringRef) +FMT_VARIADIC(int, fprintf, std::FILE *, StringRef) +} + +// Restore warnings. +#if FMT_GCC_VERSION >= 406 +# pragma GCC diagnostic pop +#endif + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + +#ifdef FMT_HEADER_ONLY +# include "format.cc" +#endif + +#endif // FMT_FORMAT_H_ diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/grid/box.h b/src/Zigzag_persistence/example/ext_zz/dionysus/grid/box.h new file mode 100644 index 0000000000..5602141cb8 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/grid/box.h @@ -0,0 +1,136 @@ +#ifndef BOX_H +#define BOX_H + +#include +#include + +#include "grid.h" +#include "vertices.h" + +namespace grid +{ + +namespace ba = boost::adaptors; + +template +class Box +{ + public: + typedef GridRef GridProxy; + typedef typename GridProxy::Vertex Position; + + struct InternalTest; + struct BoundaryTest; + struct BoundsTest; + struct PositionToVertex; + + class FreudenthalLinkIterator; + typedef boost::iterator_range FreudenthalLinkRange; + + typedef VerticesIterator VI; + typedef boost::transformed_range + > VertexRange; + + // Topology interface + typedef typename GridProxy::Index Vertex; + typedef boost::transformed_range + > Link; + + + Box(): g_(0, Position()) {} + Box(const Position& shape): + g_(0, shape), to_(shape - Position::one()) {} + Box(const Position& shape, + const Position& from, + const Position& to): + g_(0, shape), from_(from), to_(to) {} + + + const Position& from() const { return from_; } + const Position& to() const { return to_; } + Position& from() { return from_; } + Position& to() { return to_; } + Position shape() const { return to_ - from_ + Position::one(); } + const Position& grid_shape() const { return g_.shape(); } + static unsigned dimension() { return D; } + + size_t size() const { size_t c = 1; for (unsigned i = 0; i < D; ++i) c *= (to_[i] - from_[i] + 1); return c; } + + VertexRange vertices() const { return boost::iterator_range(VI::begin(from_, to_), VI::end(from_, to_)) + | ba::transformed(position_to_vertex()); } + Link link(const Position& p) const { return FreudenthalLinkRange(FreudenthalLinkIterator::begin(p), FreudenthalLinkIterator::end(p)) + | ba::filtered(bounds_test()) + | ba::transformed(position_to_vertex()); } + Link link(const Vertex& v) const { return link(position(v)); } + + Box intersect(const Box& other) const; + bool intersects(const Box& other) const; + void merge(const Box& other); + + bool contains(const Position& p) const; + bool contains(const Vertex& v) const { return contains(position(v)); } + + bool boundary(const Position& p, bool degenerate = false) const; + bool boundary(const Vertex& v, bool deg = false) const { return boundary(position(v), deg); } + Box side(unsigned axis, bool upper) const; + + InternalTest internal_test() const { return InternalTest(*this); } + BoundaryTest boundary_test() const { return BoundaryTest(*this); } + BoundsTest bounds_test() const { return BoundsTest(*this); } + PositionToVertex position_to_vertex() const { return PositionToVertex(*this); } + + + void swap(Box& other) { g_.swap(other.g_); std::swap(from_, other.from_); std::swap(to_, other.to_); } + + bool operator==(const Box& other) const { return from_ == other.from_ && to_ == other.to_; } + + template + friend std::basic_ostream& + operator<<(std::basic_ostream& out, const Box& b) { out << "Box: " << b.from_ << " - " << b.to_ << " inside " << b.g_.shape(); return out; } + + struct InternalTest + { + InternalTest(const Box& box): box_(box) {} + bool operator()(const Vertex& v) const { return !box_.boundary(v); } + const Box& box_; + }; + + struct BoundaryTest + { + BoundaryTest(const Box& box): box_(box) {} + bool operator()(const Vertex& v) const { return box_.boundary(v); } + const Box& box_; + }; + + struct BoundsTest + { + BoundsTest(const Box& box): box_(box) {} + bool operator()(const Position& p) const { return box_.contains(p); } + bool operator()(const Vertex& v) const { return box_.contains(v); } + const Box& box_; + }; + + struct PositionToVertex + { + typedef Vertex result_type; + PositionToVertex(const Box& box): box_(box) {} + Vertex operator()(Position p) const { for (unsigned i = 0; i < D; ++i) p[i] %= box_.grid_shape()[i]; return box_.g_.index(p); } + const Box& box_; + }; + + // computes position inside the box (adjusted for the wrap-around, if need be) + Position position(const Vertex& v) const { Position p = g_.vertex(v); for (unsigned i = 0; i < D; ++i) if (p[i] < from()[i]) p[i] += grid_shape()[i]; return p; } + + private: + GridProxy g_; + Position from_, to_; +}; + +} + +#include "box.hpp" + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/grid/box.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/grid/box.hpp new file mode 100644 index 0000000000..f3af50c047 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/grid/box.hpp @@ -0,0 +1,141 @@ +template +grid::Box +grid::Box:: +intersect(const Box& other) const +{ + Position from, to; + for (unsigned i = 0; i < D; ++i) + { + from[i] = std::max(from_[i], other.from_[i]); + to[i] = std::min(to_[i], other.to_[i]); + } + + return Box(g_, from, to); +} + +template +bool +grid::Box:: +intersects(const Box& other) const +{ + for (unsigned i = 0; i < D; ++i) + if (std::max(from_[i], other.from_[i]) > std::min(to_[i], other.to_[i])) + return false; + + return true; +} + +template +bool +grid::Box:: +contains(const Position& p) const +{ + for (unsigned i = 0; i < D; ++i) + if (p[i] > to_[i] || p[i] < from_[i]) + return false; + return true; +} + +template +bool +grid::Box:: +boundary(const Position& p, bool degenerate) const +{ + for (unsigned i = 0; i < D; ++i) + { + if (degenerate && from_[i] == to_[i]) continue; + if (p[i] == from_[i] || p[i] == to_[i]) + return true; + } + + return false; +} + +template +grid::Box +grid::Box:: +side(unsigned axis, bool upper) const +{ + Box res(*this); + + if (upper) + res.from()[axis] = res.to()[axis]; + else + res.to()[axis] = res.from()[axis]; + + return res; +} + +template +void +grid::Box:: +merge(const Box& other) +{ + for (unsigned i = 0; i < D; ++i) + { + from_[i] = std::min(from_[i], other.from_[i]); + to_[i] = std::max(to_[i], other.to_[i]); + } +} + +/* Box::FreudenthalLinkIterator */ +template +class grid::Box::FreudenthalLinkIterator: + public boost::iterator_facade +{ + typedef boost::iterator_facade Parent; + + + public: + typedef typename Parent::value_type value_type; + typedef typename Parent::difference_type difference_type; + typedef typename Parent::reference reference; + + FreudenthalLinkIterator(): loc_(0), dir_(0) {} + FreudenthalLinkIterator(const Position& p, int loc = 0, int dir = 1): + p_(p), v_(p), loc_(loc), dir_(dir) {} + + static FreudenthalLinkIterator + begin(const Position& p) { FreudenthalLinkIterator it(p); ++it; return it; } + static FreudenthalLinkIterator + end(const Position& p) { return FreudenthalLinkIterator(p, 0, -1); } + + private: + void increment(); + bool equal(const FreudenthalLinkIterator& other) const { return v_ == other.v_; } + reference dereference() const { return v_; } + + friend class ::boost::iterator_core_access; + + private: + Position p_, v_; + int loc_; + int dir_; +}; + +template +void +grid::Box::FreudenthalLinkIterator:: +increment() +{ + loc_ += dir_; + if (loc_ == (1 << D)) + { + dir_ = -1; + loc_ += dir_; + } + + for (unsigned i = 0; i < D; ++i) + if (loc_ & (1 << i)) + v_[i] = p_[i] + dir_; + else + v_[i] = p_[i]; +} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/grid/grid.h b/src/Zigzag_persistence/example/ext_zz/dionysus/grid/grid.h new file mode 100644 index 0000000000..c63fc7c598 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/grid/grid.h @@ -0,0 +1,143 @@ +#ifndef GRID_H +#define GRID_H + +#include "point.h" + +namespace grid +{ + +template +struct Grid; + +template +struct GridRef +{ + public: + typedef C Value; + + typedef Point Vertex; + typedef size_t Index; + + public: + template + GridRef(C* data, const Point& shape, bool c_order = true): + data_(data), shape_(shape), c_order_(c_order) { set_stride(); } + + GridRef(Grid& g): + data_(g.data()), shape_(g.shape()), + c_order_(g.c_order()) { set_stride(); } + + template + C operator()(const Point& v) const { return data_[v*stride_]; } + + template + C& operator()(const Point& v) { return data_[v*stride_]; } + + C operator()(Index i) const { return data_[i]; } + C& operator()(Index i) { return data_[i]; } + + const Vertex& + shape() const { return shape_; } + + const C* + data() const { return data_; } + C* data() { return data_; } + + // Set every element to the given value + GridRef& operator=(C value) { Index s = size(); for (Index i = 0; i < s; ++i) data_[i] = value; return *this; } + GridRef& operator/=(C value) { Index s = size(); for (Index i = 0; i < s; ++i) data_[i] /= value; return *this; } + + Vertex vertex(Index idx) const { Vertex v; for (unsigned i = 0; i < D; ++i) { v[i] = idx / stride_[i]; idx %= stride_[i]; } return v; } + Index index(const Vertex& v) const { return v*stride_; } + + Index size() const { return size(shape()); } + void swap(GridRef& other) { std::swap(data_, other.data_); std::swap(shape_, other.shape_); std::swap(stride_, other.stride_); } + + bool c_order() const { return c_order_; } + + protected: + static Index + size(const Vertex& v) { Index res = 1; for (unsigned i = 0; i < D; ++i) res *= v[i]; return res; } + + void set_stride() + { + Index cur = 1; + if (c_order_) + for (unsigned i = D; i > 0; --i) { stride_[i-1] = cur; cur *= shape_[i-1]; } + else + for (unsigned i = 0; i < D; ++i) { stride_[i] = cur; cur *= shape_[i]; } + + } + void set_shape(const Vertex& v) { shape_ = v; set_stride(); } + void set_data(C* data) { data_ = data; } + void set_c_order(bool order) { c_order_ = order; } + + private: + C* data_; + Vertex shape_; + Vertex stride_; + bool c_order_; +}; + + +template +struct Grid: public GridRef +{ + public: + typedef GridRef Parent; + typedef typename Parent::Value Value; + typedef typename Parent::Index Index; + typedef Parent Reference; + + template + struct rebind { typedef Grid type; }; + + public: + template + Grid(const Point& shape, bool c_order = true): + Parent(new C[size(shape)], shape, c_order) + {} + + Grid(const Parent& g): + Parent(new C[size(g.shape())], g.shape(), + g.c_order()) { copy_data(g.data()); } + + template + Grid(const OtherGrid& g): + Parent(new C[size(g.shape())], + g.shape(), + g.c_order()) { copy_data(g.data()); } + + ~Grid() { delete[] Parent::data(); } + + template + Grid& operator=(const GridRef& other) + { + delete[] Parent::data(); + Parent::set_c_order(other.c_order()); // NB: order needs to be set before the shape, to set the stride correctly + Parent::set_shape(other.shape()); + Index s = size(shape()); + Parent::set_data(new C[s]); + copy_data(other.data()); + return *this; + } + + using Parent::data; + using Parent::shape; + using Parent::operator(); + using Parent::operator=; + using Parent::size; + + private: + template + void copy_data(const OC* data) + { + Index s = size(shape()); + for (Index i = 0; i < s; ++i) + Parent::data()[i] = data[i]; + } +}; + +} + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/grid/point.h b/src/Zigzag_persistence/example/ext_zz/dionysus/grid/point.h new file mode 100644 index 0000000000..0e867c34aa --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/grid/point.h @@ -0,0 +1,132 @@ +#ifndef POINT_H +#define POINT_H + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace grid +{ + +template +class Point: public boost::array, + private boost::addable< Point // Point + Point + , boost::subtractable< Point // Point - Point + , boost::dividable2< Point, Coordinate_ // Point / Coordinate + , boost::multipliable2< Point, Coordinate_ // Point * Coordinate, Coordinate * Point + > > > > +{ + public: + typedef Coordinate_ Coordinate; + typedef boost::array ArrayParent; + + typedef Point LPoint; + typedef Point UPoint; + + template + struct rebind { typedef Point type; }; + + public: + Point() { for (unsigned i = 0; i < D; ++i) (*this)[i] = 0; } + Point(const ArrayParent& a): + ArrayParent(a) {} + template Point(const Point& p) { for (size_t i = 0; i < D; ++i) (*this)[i] = p[i]; } + template Point(const T* a) { for (unsigned i = 0; i < D; ++i) (*this)[i] = a[i]; } + template Point(const std::vector& a) { for (unsigned i = 0; i < D; ++i) (*this)[i] = a[i]; } + + static + unsigned dimension() { return D; } + + static Point zero() { return Point(); } + static Point one() { Point p; for (unsigned i = 0; i < D; ++i) p[i] = 1; return p; } + + LPoint drop(int dim) const { LPoint p; unsigned c = 0; for (unsigned i = 0; i < D; ++i) { if (i == dim) continue; p[c++] = (*this)[i]; } return p; } + UPoint lift(int dim, Coordinate x) const { UPoint p; for (unsigned i = 0; i < D+1; ++i) { if (i < dim) p[i] = (*this)[i]; else if (i == dim) p[i] = x; else if (i > dim) p[i] = (*this)[i-1]; } return p; } + + using ArrayParent::operator[]; + + Point& operator+=(const Point& y) { for (unsigned i = 0; i < D; ++i) (*this)[i] += y[i]; return *this; } + Point& operator-=(const Point& y) { for (unsigned i = 0; i < D; ++i) (*this)[i] -= y[i]; return *this; } + Point& operator*=(Coordinate a) { for (unsigned i = 0; i < D; ++i) (*this)[i] *= a; return *this; } + Point& operator/=(Coordinate a) { for (unsigned i = 0; i < D; ++i) (*this)[i] /= a; return *this; } + + Point operator-() const { Point res; for (unsigned i = 0; i < D; ++i) res[i] = -(*this)[i]; return res; } + + Coordinate norm() const { return (*this)*(*this); } + + std::ostream& operator<<(std::ostream& out) const { out << (*this)[0]; for (unsigned i = 1; i < D; ++i) out << " " << (*this)[i]; return out; } + std::istream& operator>>(std::istream& in); + + friend + Coordinate operator*(const Point& x, const Point& y) { Coordinate n = 0; for (size_t i = 0; i < D; ++i) n += x[i] * y[i]; return n; } + + template + friend + Coordinate operator*(const Point& x, const Point& y) { Coordinate n = 0; for (size_t i = 0; i < D; ++i) n += x[i] * y[i]; return n; } + + private: + friend class boost::serialization::access; + + template + void serialize(Archive& ar, const unsigned int version) { ar & boost::serialization::base_object(*this); } +}; + +template +std::istream& +Point:: +operator>>(std::istream& in) +{ + std::string point_str; + in >> point_str; // read until ' ' + std::stringstream ps(point_str); + + char x; + for (unsigned i = 0; i < dimension(); ++i) + { + ps >> (*this)[i]; + ps >> x; + } + + return in; +} + + +template +Coordinate norm2(const Point& p) +{ Coordinate res = 0; for (unsigned i = 0; i < D; ++i) res += p[i]*p[i]; return res; } + +template +std::ostream& +operator<<(std::ostream& out, const Point& p) +{ return p.operator<<(out); } + +template +std::istream& +operator>>(std::istream& in, Point& p) +{ return p.operator>>(in); } + +} + +namespace opts +{ + template + struct Traits; + + template + struct Traits< grid::Point > + { + static + std::string type_string() { return "POINT"; } + }; +} + + +#endif // POINT_H diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/grid/vertices.h b/src/Zigzag_persistence/example/ext_zz/dionysus/grid/vertices.h new file mode 100644 index 0000000000..339782e8c4 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/grid/vertices.h @@ -0,0 +1,86 @@ +#ifndef VERTICES_H +#define VERTICES_H + +#include + +namespace grid +{ + +template +class VerticesIterator: + public boost::iterator_facade, + Vertex_, + boost::forward_traversal_tag, + Vertex_, + std::ptrdiff_t> +{ + typedef boost::iterator_facade Parent; + + + public: + typedef typename Parent::value_type value_type; + typedef typename Parent::difference_type difference_type; + typedef typename Parent::reference reference; + + typedef value_type Vertex; + typedef typename Vertex::Coordinate Coordinate; + + // upper bounds are non-inclusive + VerticesIterator(const Vertex& bounds): + to_(bounds - Vertex::one()) {} + + VerticesIterator(const Vertex& pos, + const Vertex& bounds): + pos_(pos), to_(bounds - Vertex::one()) {} + + VerticesIterator(const Vertex& pos, + const Vertex& from, + const Vertex& to): + pos_(pos), from_(from), + to_(to) {} + + + static VerticesIterator + begin(const Vertex& bounds) { return VerticesIterator(bounds); } + static VerticesIterator + end(const Vertex& bounds) { Vertex e; e[0] = bounds[0]; return VerticesIterator(e, bounds); } + + static VerticesIterator + begin(const Vertex& from, const Vertex& to) { return VerticesIterator(from, from, to); } + static VerticesIterator + end(const Vertex& from, const Vertex& to) { Vertex e = from; e[0] = to[0] + 1; return VerticesIterator(e, from, to); } + + private: + void increment(); + bool equal(const VerticesIterator& other) const { return pos_ == other.pos_; } + reference dereference() const { return pos_; } + + friend class ::boost::iterator_core_access; + + private: + Vertex pos_; + Vertex from_; + Vertex to_; +}; + +} + +template +void +grid::VerticesIterator:: +increment() +{ + unsigned j = Vertex::dimension() - 1; + while (j > 0 && pos_[j] == to_[j]) + { + pos_[j] = from_[j]; + --j; + } + ++pos_[j]; +} + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/matrix-filtration.h b/src/Zigzag_persistence/example/ext_zz/dionysus/matrix-filtration.h new file mode 100644 index 0000000000..516f27b2d1 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/matrix-filtration.h @@ -0,0 +1,120 @@ +#pragma once + +#include +#include +#include + +namespace dionysus +{ + + +template +class MatrixFiltrationCell; + + +// adapt Matrix as a Filtration to make it possible to feed into reduction algorithms +template +class MatrixFiltration +{ + public: + using Matrix = Matrix_; + using CellValue = CellValue_; + using Dimensions = std::vector; + using Values = std::vector; + using Cell = MatrixFiltrationCell; + + + public: + MatrixFiltration(Matrix m, Dimensions dimensions, Values values): + m_(std::move(m)), + dimensions_(dimensions), + values_(values) { assert(m_->size() == dimensions_.size()); assert(m_->size() == values_.size()); } + + Cell operator[](size_t i) const { return Cell(this, i); } + size_t size() const { return m_.size(); } + + size_t index(const Cell& c) const; + + Cell begin() const { return Cell(this, 0); } + Cell end() const { return Cell(this, size()); } + + const Dimensions& dimensions() const { return dimensions_; } + const Values& values() const { return values_; } + + private: + Matrix m_; + Dimensions dimensions_; + Values values_; + + friend class MatrixFiltrationCell; +}; + + +template +class MatrixFiltrationCell +{ + public: + using MatrixFiltration = MatrixFiltration_; + using Matrix = typename MatrixFiltration::Matrix; + using Data = typename MatrixFiltration::CellValue; + using Field = typename Matrix::Field; + + template + using Entry = ChainEntry; + + template + using BoundaryChain = std::vector>; + + public: + MatrixFiltrationCell(const MatrixFiltration* mf, size_t i): + mf_(mf), i_(i) {} + + short unsigned dimension() const { return mf_->dimensions_[i_]; } + const Data& data() const { return mf_->values_[i_]; } + + bool operator==(const MatrixFiltrationCell& other) const { return i_ == other.i_; } + bool operator!=(const MatrixFiltrationCell& other) const { return i_ != other.i_; } + + BoundaryChain<> boundary() const + { + BoundaryChain<> bdry; + for (auto& entry : (mf_->m_)[i_]) + bdry.emplace_back(Entry<> { entry.e, MatrixFiltrationCell(mf_, entry.i) }); + return bdry; + } + + template + BoundaryChain boundary(const Field_& field) const + { + BoundaryChain bdry; + for (auto& entry : (mf_->m_)[i_]) + bdry.emplace_back(Entry { field.init(entry.e), MatrixFiltrationCell(mf_, entry.i) }); + return bdry; + } + + // iterator interface + MatrixFiltrationCell operator++(int) { MatrixFiltrationCell copy = *this; i_++; return copy; } + MatrixFiltrationCell& operator++() { ++i_; return *this; } + + const MatrixFiltrationCell& operator*() const { return *this; } + MatrixFiltrationCell& operator*() { return *this; } + + size_t i() const { return i_; } + + friend + std::ostream& operator<<(std::ostream& out, const MatrixFiltrationCell& c) + { out << c.i_; return out; } + + private: + const MatrixFiltration* mf_ = nullptr; + size_t i_; +}; + +template +size_t +MatrixFiltration::index(const Cell& c) const +{ + return c.i(); +} + +} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/omni-field-persistence.h b/src/Zigzag_persistence/example/ext_zz/dionysus/omni-field-persistence.h new file mode 100644 index 0000000000..3d83d4ae44 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/omni-field-persistence.h @@ -0,0 +1,145 @@ +#ifndef DIONYSUS_OMNI_FIELD_REDUCTION_H +#define DIONYSUS_OMNI_FIELD_REDUCTION_H + +#include +#include + +#include "reduction.h" // for unpaired +#include "fields/q.h" +#include "fields/zp.h" +#include "chain.h" + +namespace dionysus +{ + +template, class Q_ = ::dionysus::Q<>, class Zp_ = ::dionysus::ZpField> +class OmniFieldPersistence +{ + public: + using Index = Index_; + using Q = Q_; + using Field = Q; + using Comparison = Comparison_; + + using BaseElement = typename Q::BaseElement; + using Zp = Zp_; + using Zps = std::unordered_map; + + using QElement = typename Q::Element; + using QEntry = ChainEntry; + using QChain = std::vector; + + using ZpElement = typename Zp::Element; + using ZpEntry = ChainEntry; + using ZpChain = std::vector; + + using QChains = std::vector; + using ZpChains = std::unordered_map>; + + using QLows = std::unordered_map; + using ZpLows = std::unordered_map>; + + using QPairs = std::vector; + using ZpPairs = std::unordered_map>; + + using Factors = std::vector; + + using Specials = std::unordered_map>; + + const Field& field() const { return q_; } + + void sort(QChain& c) { std::sort(c.begin(), c.end(), + [this](const QEntry& e1, const QEntry& e2) + { return this->cmp_(e1.index(), e2.index()); }); } + + template + void add(const ChainRange& chain) { return add(QChain(std::begin(chain), std::end(chain))); } + void add(QChain&& chain); + + void reserve(size_t s) { q_chains_.reserve(s); q_pairs_.reserve(s); } + size_t size() const { return q_pairs_.size(); } + + void reduce(ZpChain& zp_chain, BaseElement p); + ZpChain convert(const QChain& c, const Zp& field) const; + bool special(Index i, BaseElement p) const { auto it = zp_chains_.find(i); if (it == zp_chains_.end()) return false; if (it->second.find(p) == it->second.end()) return false; return true; } + Specials specials() const + { + Specials specials; + for (auto& x : zp_chains_) + for (auto& y : x.second) + specials[x.first].push_back(y.first); + return specials; + } + + const Zp& zp(BaseElement p) const { auto it = zps_.find(p); if (it != zps_.end()) return it->second; return zps_.emplace(p, Zp(p)).first->second; } + + static Factors factor(BaseElement x); + + const QChains& q_chains() const { return q_chains_; } + const ZpChains& zp_chains() const { return zp_chains_; } + + // This is a bit of a hack; it takes advantage of the fact that zp(p) + // generates field on-demand and memoizes them. So there is an entry in + // zps_ only if something special happened over the prime. + Factors primes() const { Factors result; result.reserve(zps_.size()); for (auto& x : zps_) result.push_back(x.first); return result; } + + // TODO: no skip support for now + bool skip(Index) const { return false; } + void add_skip() {} + void set_skip(Index, bool flag = true) {} + + Index pair(Index i, BaseElement p) const; + void set_pair(Index i, Index j); + void set_pair(Index i, Index j, BaseElement p); + static const Index unpaired() { return Reduction::unpaired; } + + private: + QChains q_chains_; + ZpChains zp_chains_; + + QLows q_lows_; + ZpLows zp_lows_; + + QPairs q_pairs_; + ZpPairs zp_pairs_; + + Q q_; + mutable Zps zps_; + + Comparison cmp_; +}; + +// Make OmniFieldPersistence act like a ReducedMatrix (e.g., for the purpose of constructing a persistence diagram) +template +struct PrimeAdapter +{ + using Persistence = OmniFieldPersistence; + using Prime = typename Persistence::BaseElement; + using Index = typename Persistence::Index; + + PrimeAdapter(const Persistence& persistence, Prime p): + persistence_(persistence), p_(p) {} + + bool skip(Index i) const { return persistence_.skip(i); } + + size_t size() const { return persistence_.size(); } + Index pair(Index i) const { return persistence_.pair(i, p_); } + static const Index unpaired() { return Persistence::unpaired(); } + + const Persistence& persistence_; + Prime p_; +}; + +template +PrimeAdapter +prime_adapter(const OmniFieldPersistence& persistence, + typename PrimeAdapter::Prime p) +{ + return PrimeAdapter(persistence, p); +} + +} // dionysus + +#include "omni-field-persistence.hpp" + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/omni-field-persistence.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/omni-field-persistence.hpp new file mode 100644 index 0000000000..68d5fbede7 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/omni-field-persistence.hpp @@ -0,0 +1,250 @@ +template +void +dionysus::OmniFieldPersistence:: +add(QChain&& chain) +{ + sort(chain); + + q_chains_.emplace_back(std::move(chain)); + q_pairs_.emplace_back(unpaired()); + Index i = q_chains_.size() - 1; + + QChain& c = q_chains_.back(); + + auto reduce = [this,&c,i](BaseElement p) + { + auto zp_chain = convert(c, zp(p)); + + this->reduce(zp_chain, p); + + if (!zp_chain.empty()) + { + auto l = zp_chain.back().index(); + zp_lows_[l].emplace(p,i); + set_pair(l,i,p); + } + + zp_chains_[i].emplace(p, std::move(zp_chain)); // empty chain is still a valid indicator that we don't need to bother with this field + }; + + // reduce + auto entry_cmp = [this](const QEntry& e1, const QEntry& e2) { return this->cmp_(e1.index(), e2.index()); }; + while (!c.empty()) + { + auto& low = c.back(); + + auto e = low.element(); + auto l = low.index(); + assert(!q_.is_zero(e)); + if (e != q_.id()) + { + auto factors = factor(q_.numerator(e)); + for (auto p : factors) + { + if (!special(i, p)) // there is already a dedicated column over p + reduce(p); + } + } + + auto it_zp = zp_lows_.find(l); + if (it_zp != zp_lows_.end()) + for (auto& x : it_zp->second) + { + auto p = x.first; + if (!special(i,p)) + reduce(p); + } + + auto it_q = q_lows_.find(l); + if (it_q != q_lows_.end()) + { + Index j = it_q->second; + + // add the primes from j to i + auto it_zp = zp_chains_.find(j); + if (it_zp != zp_chains_.end()) + for (auto& x : it_zp->second) + { + auto p = x.first; + if (!special(i,p)) + reduce(p); + } + + // reduce over Q + auto j_chain = q_chains_[j]; + auto j_e = j_chain.back().element(); + + auto m = q_.neg(q_.div(e,j_e)); + Chain::addto(c, m, j_chain, q_, entry_cmp); + assert(c.empty() || !q_.is_zero(c.back().element())); + } else + { + q_lows_.emplace(l,i); + set_pair(l,i); + break; + } + } +} + +template +void +dionysus::OmniFieldPersistence:: +reduce(ZpChain& zp_chain, BaseElement p) +{ + auto& field = zp(p); + + auto entry_cmp = [this](const ZpEntry& e1, const ZpEntry& e2) { return this->cmp_(e1.index(), e2.index()); }; + + while (!zp_chain.empty()) + { + auto& low = zp_chain.back(); + auto j = low.index(); + + auto it = zp_lows_.find(j); + if (it != zp_lows_.end()) + { + auto it2 = it->second.find(p); + if (it2 != it->second.end()) + { + const ZpChain& co = zp_chains_[it2->second][p]; + + auto m = field.neg(field.div(low.element(), co.back().element())); + assert(m < p); + Chain::addto(zp_chain, m, co, field, entry_cmp); + continue; + } + } + + auto qit = q_lows_.find(j); + if (qit == q_lows_.end() || special(qit->second, p)) // no valid pivot over Q + return; + + // TODO: this could be optimized (add and convert on the fly) + auto& q_chain = q_chains_[qit->second]; + assert(q_chain.empty() || !q_.is_zero(q_chain.back().element())); + + auto co = convert(q_chain, field); + auto m = field.neg(field.div(low.element(), co.back().element())); + Chain::addto(zp_chain, m, co, field, entry_cmp); + + assert(!zp_chain.empty() || zp_chain.back().index() != j); + } +} + +template +typename dionysus::OmniFieldPersistence::ZpChain +dionysus::OmniFieldPersistence:: +convert(const QChain& c, const Zp& field) const +{ + ZpChain result; + result.reserve(c.size()); + auto p = field.prime(); + for (auto& x : c) + { + auto num = q_.numerator(x.element()) % p; + if (num != 0) + { + while (num < 0) num += p; + auto denom = q_.denominator(x.element()) % p; + while (denom < 0) denom += p; + assert(denom % p != 0); + result.emplace_back(field.div(num, denom), x.index()); + } + } + return result; +} + + +template +typename dionysus::OmniFieldPersistence::Factors +dionysus::OmniFieldPersistence:: +factor(BaseElement x) +{ + if (x < 0) + x = -x; + Factors result; + + if (Q::is_prime(x)) + { + result.push_back(x); + return result; + } + + BaseElement p { 2 }; + while (p*p <= x) + { + if (x % p == 0) + { + result.push_back(p); + do { x /= p; } while (x % p == 0); + if (Q::is_prime(x)) + { + result.push_back(x); + break; + } + } + ++p; + } + if (x > 1) + result.push_back(x); + + return result; +} + +template +typename dionysus::OmniFieldPersistence::Index +dionysus::OmniFieldPersistence:: +pair(Index i, BaseElement p) const +{ + if (p == 1) + return q_pairs_[i]; + else + { + auto it = zp_pairs_.find(p); + if (it == zp_pairs_.end()) + return q_pairs_[i]; + else + { + auto pit = it->second.find(i); + if (pit == it->second.end()) + return q_pairs_[i]; + else + return pit->second; + } + } +} + +template +void +dionysus::OmniFieldPersistence:: +set_pair(Index i, Index j, BaseElement p) +{ + auto& pairs = zp_pairs_[p]; + pairs[i] = j; + pairs[j] = i; +} + +template +void +dionysus::OmniFieldPersistence:: +set_pair(Index i, Index j) +{ + q_pairs_[i] = j; + q_pairs_[j] = i; + + auto it = zp_chains_.find(j); + if (it == zp_chains_.end()) + return; + + auto& chains = it->second; + for (auto& x : chains) + { + auto p = x.first; + auto& chain = x.second; + if (chain.empty()) + { + zp_pairs_[p][j] = unpaired(); + zp_pairs_[p][i] = unpaired(); + } + } +} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/opts/opts.h b/src/Zigzag_persistence/example/ext_zz/dionysus/opts/opts.h new file mode 100644 index 0000000000..1a9bbf71bf --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/opts/opts.h @@ -0,0 +1,499 @@ +/** + * Author: Dmitriy Morozov + * The interface is heavily influenced by GetOptPP (https://code.google.com/p/getoptpp/). + * The parsing logic is from ProgramOptions.hxx (https://github.com/Fytch/ProgramOptions.hxx). + * + * History: + * - 2015-06-01: added Traits<...>::type_string() for long, unsigned long + * - ... + * - 2018-04-27: replace parsing logic with the one from ProgramOptions.hxx to + * make the parser compliant with [GNU Program Argument Syntax + * Conventions](https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html) + * - 2018-05-11: add dashed_non_option(), to accept arguments that are negative numbers + */ + +#ifndef OPTS_OPTS_H +#define OPTS_OPTS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace opts { + +// Converters +template +struct Converter +{ + Converter() {} + static + bool convert(const std::string& val, T& res) + { + std::istringstream iss(val); + iss >> res; + return !iss.fail() && iss.eof(); + } +}; + +// Type +template +struct Traits +{ + static std::string type_string() { return "UNKNOWN TYPE"; } +}; + +template<> +struct Traits +{ + static std::string type_string() { return "INT"; } +}; + +template<> +struct Traits +{ + static std::string type_string() { return "SHORT INT"; } +}; + +template<> +struct Traits +{ + static std::string type_string() { return "LONG"; } +}; + +template<> +struct Traits +{ + static std::string type_string() { return "UNSIGNED INT"; } +}; + +template<> +struct Traits +{ + static std::string type_string() { return "SHORT UNSIGNED INT"; } +}; + +template<> +struct Traits +{ + static std::string type_string() { return "UNSIGNED LONG"; } +}; + +template<> +struct Traits +{ + static std::string type_string() { return "FLOAT"; } +}; + +template<> +struct Traits +{ + static std::string type_string() { return "DOUBLE"; } +}; + +template<> +struct Traits +{ + static std::string type_string() { return "STRING"; } +}; + + +struct BasicOption +{ + using IsShort = std::function; + + BasicOption(char s_, + std::string l_, + std::string default_, + std::string type_, + std::string help_): + s(s_), l(l_), d(default_), t(type_), help(help_) {} + virtual ~BasicOption() {} + + int long_size() const { return l.size() + 1 + t.size(); } + + void output(std::ostream& out, int max_long) const + { + out << " "; + if (s) + out << '-' << s << ", "; + else + out << " "; + + out << "--" << l << ' '; + + if (!t.empty()) + out << t; + + for (int i = long_size(); i < max_long; ++i) + out << ' '; + + out << " " << help; + + if (!d.empty()) + { + out << " [default: " << d << "]"; + } + out << '\n'; + } + + virtual bool flag() const { return false; } + virtual bool parse(int argc, char** argv, int& i, int j, IsShort is_short); + virtual bool set(std::string arg) =0; + + char s; + std::string l; + std::string d; + std::string t; + std::string help; +}; + +// Option +template +struct OptionContainer: public BasicOption +{ + OptionContainer(char s_, + const std::string& l_, + T& var_, + const std::string& help_, + const std::string& type_ = Traits::type_string()): + BasicOption(s_, l_, default_value(var_), type_, help_), + var(&var_) {} + + static + std::string default_value(const T& def) + { + std::ostringstream oss; + oss << def; + return oss.str(); + } + + bool set(std::string s) override { return Converter::convert(s, *var); } + + T* var; +}; + +template<> +struct OptionContainer: public BasicOption +{ + OptionContainer(char s_, + const std::string& l_, + bool& var_, + const std::string& help_): + BasicOption(s_, l_, "", "", help_), + var(&var_) { *var = false; } + + bool parse(int, char**, int&, int, IsShort) override { *var = true; return true; } + bool set(std::string) override { return true; } + bool flag() const override { return true; } + + bool* var; +}; + +template +struct OptionContainer< std::vector >: public BasicOption +{ + OptionContainer(char s_, + const std::string& l_, + std::vector& var_, + const std::string& help_, + const std::string& type_ = "SEQUENCE"): + BasicOption(s_, l_, default_value(var_), type_, help_), + var(&var_), first(true) { } + + static + std::string default_value(const std::vector& def) + { + std::ostringstream oss; + oss << "("; + if (def.size()) + oss << def[0]; + for (size_t i = 1; i < def.size(); ++i) + oss << ", " << def[i]; + oss << ")"; + return oss.str(); + } + + bool set(std::string s) override + { + if (first) + { + var->clear(); + first = false; + } + + T x; + bool result = Converter::convert(s,x); + var->emplace_back(std::move(x)); + return result; + } + + std::vector* var; + mutable bool first; +}; + + +template +std::unique_ptr +Option(char s, const std::string& l, T& var, const std::string& help) { return std::unique_ptr{new OptionContainer(s, l, var, help)}; } + +template +std::unique_ptr +Option(char s, const std::string& l, T& var, + const std::string& type, const std::string& help) { return std::unique_ptr{new OptionContainer(s, l, var, help, type)}; } + +template +std::unique_ptr +Option(const std::string& l, T& var, const std::string& help) { return std::unique_ptr{new OptionContainer(0, l, var, help)}; } + +template +std::unique_ptr +Option(const std::string& l, T& var, + const std::string& type, const std::string& help) { return std::unique_ptr{new OptionContainer(0, l, var, help, type)}; } + +// PosOption +template +struct PosOptionContainer +{ + PosOptionContainer(T& var_): + var(&var_) {} + + bool parse(std::list& args) const + { + if (args.empty()) + return false; + + bool result = Converter::convert(args.front(), *var); + if (!result) + std::cerr << "error: failed to parse " << args.front() << '\n'; + args.pop_front(); + return result; + } + + T* var; +}; + +template +PosOptionContainer +PosOption(T& var) { return PosOptionContainer(var); } + + +// Options +struct Options +{ + Options(): + failed(false) {} + + inline + Options& operator>>(std::unique_ptr opt); + template + Options& operator>>(const PosOptionContainer& poc); + + operator bool() { return !failed; } + + + friend + std::ostream& + operator<<(std::ostream& out, const Options& ops) + { + int max_long = 0; + for (auto& cur : ops.options) + { + int cur_long = cur->long_size(); + if (cur_long > max_long) + max_long = cur_long; + } + + out << "Options:\n"; + for (auto& cur : ops.options) + cur->output(out, max_long); + + return out; + } + + bool parse(int argc, char** argv); + + void unrecognized_option(std::string arg) const + { + std::cerr << "error: unrecognized option " << arg << '\n'; + } + + static bool dashed_non_option(char* arg, BasicOption::IsShort is_short) + { + return arg[ 0 ] == '-' + && (std::isdigit(arg[ 1 ]) || arg[ 1 ] == '.') + && !is_short(arg[ 1 ]); + } + + private: + std::list args; + std::list> options; + bool failed; +}; + +bool +BasicOption::parse(int argc, char** argv, int& i, int j, IsShort is_short) +{ + char* argument; + char* cur_arg = argv[i]; + // -v... + if (argv[i][j] == '\0') + { + // -v data + if (i + 1 < argc && (argv[i+1][0] != '-' || Options::dashed_non_option(argv[i+1], is_short))) + { + ++i; + argument = argv[i]; + } else + { + std::cerr << "error: cannot find the argument; ignoring " << argv[i] << '\n'; + return false; + } + } else if (argv[i][j] == '=') + { + // -v=data + argument = &argv[i][j+1]; + } else if( j == 2 ) { // only for short options + // -vdata + argument = &argv[i][j]; + } else + { + std::cerr << "error: unexpected character \'" << argv[i][j] << "\' ignoring " << argv[i] << '\n'; + return false; + } + bool result = set(argument); + if (!result) + std::cerr << "error: failed to parse " << argument << " in " << cur_arg << '\n'; + return result; +} + +bool +Options::parse(int argc, char** argv) +{ + std::map short_opts; + std::map long_opts; + + for (auto& opt : options) + { + if (opt->s) + short_opts[opt->s] = opt.get(); + + long_opts[opt->l] = opt.get(); + } + + auto is_short = [&short_opts](char c) -> bool { return short_opts.find(c) != short_opts.end(); }; + + for (int i = 1; i < argc; ++i) + { + if( argv[ i ][ 0 ] == '\0' ) + continue; + if( argv[ i ][ 0 ] != '-' || dashed_non_option(argv[i], is_short)) + args.push_back(argv[i]); + else + { + // -... + if( argv[ i ][ 1 ] == '\0' ) + { + // - + args.push_back(argv[i]); + } else if( argv[ i ][ 1 ] == '-' ) + { + if( argv[ i ][ 2 ] == '\0' ) + { + // -- + while( ++i < argc ) + args.push_back(argv[i]); + } else { + // --... + char* first = &argv[ i ][ 2 ]; + char* last = first; + for(; *last != '=' && *last != '\0'; ++last); + if (first == last) + { + failed = true; + unrecognized_option(argv[i]); + } else + { + auto opt_it = long_opts.find(std::string{first,last}); + if (opt_it == long_opts.end()) + { + failed = true; + unrecognized_option(argv[i]); + } else + { + failed |= !opt_it->second->parse(argc, argv, i, last - argv[i], is_short); + } + } + } + } else + { + // -f... + auto opt_it = short_opts.find(argv[i][1]); + if (opt_it == short_opts.end()) + { + failed = true; + unrecognized_option(argv[i]); + } else if (opt_it->second->flag()) + { + opt_it->second->parse(argc, argv, i, 0, is_short); // arguments are meaningless; just sets the flag + + // -fgh + char c; + for(int j = 1; (c = argv[i][j]) != '\0'; ++j) + { + if (!std::isprint(c) || c == '-') + { + failed = true; + std::cerr << "error: invalid character\'" << c << " ignoring " << &argv[i][j] << '\n'; + break; + } + opt_it = short_opts.find(c); + if (opt_it == short_opts.end()) + { + failed = true; + unrecognized_option("-" + std::string(1, c)); + continue; + } + if (!opt_it->second->flag()) + { + failed = true; + std::cerr << "error: non-void options not allowed in option packs; ignoring " << c << '\n'; + continue; + } + opt_it->second->parse(argc, argv, i, 0, is_short); // arguments are meaningless; just sets the flag + } + } else + { + failed |= !opt_it->second->parse(argc, argv, i, 2, is_short); + } + } + } + } + + return !failed; +} + +Options& +Options::operator>>(std::unique_ptr opt) +{ + options.emplace_back(std::move(opt)); + return *this; +} + +template +Options& +Options::operator>>(const PosOptionContainer& poc) +{ + if (!failed) + failed = !poc.parse(args); + return *this; +} + +} + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/ordinary-persistence.h b/src/Zigzag_persistence/example/ext_zz/dionysus/ordinary-persistence.h new file mode 100644 index 0000000000..5f26bd2a1b --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/ordinary-persistence.h @@ -0,0 +1,64 @@ +#ifndef DIONYSUS_ORDINARY_PERSISTENCE_H +#define DIONYSUS_ORDINARY_PERSISTENCE_H + +#include "reduced-matrix.h" + +namespace dionysus +{ + +/* Move this into a ReducedMatrix class */ + +// Ordinary D -> R reduction +template, + template class... Visitors> +using OrdinaryPersistence = ReducedMatrix; + +// No negative optimization +template> +struct NoNegative +{ + template + struct Visitor: public EmptyVisitor + { + template + void chain_initialized(Self* matrix, Chain& c) + { + for (auto cur = std::begin(c); cur != std::end(c); ++cur) + { + Index i = cur->index(); + Index p = matrix->pair(i); + if (!(p == Self::unpaired() || (*matrix)[i].empty())) + c.erase(cur--); + } + } + }; + + template + using V2 = EmptyVisitor; +}; + +template, + template class... Visitors> +using OrdinaryPersistenceNoNegative = ReducedMatrix::template Visitor, + Visitors...>; + +// TODO: add clearing optimization (possibly bake it into the code itself) + +template, + template class... Visitors> +using FastPersistence = ReducedMatrix::template Visitor, + //Clearing::template Visitor, // FIXME + Visitors...>; + + +} + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/pair-recorder.h b/src/Zigzag_persistence/example/ext_zz/dionysus/pair-recorder.h new file mode 100644 index 0000000000..81c066bda6 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/pair-recorder.h @@ -0,0 +1,78 @@ +#ifndef DIONYSUS_PAIR_RECORDER_H +#define DIONYSUS_PAIR_RECORDER_H + +namespace dionysus +{ + +template +struct PairRecorder: public Persistence_ +{ + typedef Persistence_ Persistence; + typedef typename Persistence::Index Index; + + + using Persistence::Persistence; + + template + Index add(const ChainRange& chain) + { + Index p = Persistence::add(chain); + pairs_.push_back(p); + if (p != unpaired()) + pairs_[p] = pairs_.size() - 1; + + return p; + } + + Index pair(Index i) const { return pairs_[i]; } + + void resize(size_t s) { Persistence::resize(s); pairs_.resize(s, unpaired()); } + size_t size() const { return pairs_.size(); } + static const Index unpaired() { return Reduction::unpaired; } + + std::vector pairs_; +}; + +template +struct PairChainRecorder: public PairRecorder +{ + using Persistence = Persistence_; + using Parent = PairRecorder; + using Index = typename Persistence_::Index; + using Chain = typename Persistence_::Chain; + + using Parent::Parent; + + template + Index add(const ChainRange& chain) + { + auto p_chain = Persistence::add(chain, keep_cocycles); + Index p = std::get<0>(p_chain); + + pairs_.push_back(p); + chains_.emplace_back(); + + if (p != unpaired()) + { + pairs_[p] = pairs_.size() - 1; + chains_[p] = std::move(std::get<1>(p_chain)); + } + + return p; + } + + using Parent::unpaired; + + Index pair(Index i) const { return pairs_[i]; } + const Chain& chain(Index i) const { return chains_[i]; } // chain that dies at i + void resize(size_t s) { Parent::resize(s); chains_.resize(s); } + + std::vector chains_; + using Parent::pairs_; + + bool keep_cocycles = true; +}; + +} + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/reduced-matrix.h b/src/Zigzag_persistence/example/ext_zz/dionysus/reduced-matrix.h new file mode 100644 index 0000000000..f7a04b130d --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/reduced-matrix.h @@ -0,0 +1,170 @@ +#ifndef DIONYSUS_REDUCED_MATRIX_H +#define DIONYSUS_REDUCED_MATRIX_H + +#include +#include + +#include "chain.h" +#include "reduction.h" + +namespace dionysus +{ + +template, template class... Visitors> +class ReducedMatrix +{ + public: + typedef ReducedMatrix Self; + + typedef Field_ Field; + typedef Index_ Index; + typedef Comparison_ Comparison; + + typedef std::tuple...> VisitorsTuple; + template + using Visitor = std::tuple_element; + + typedef typename Field::Element FieldElement; + typedef ChainEntry Entry; + typedef std::vector Chain; + + typedef std::vector Chains; + typedef std::vector Indices; + typedef std::vector SkipFlags; + + public: + ReducedMatrix(const Field& field): + field_(field) {} + + ReducedMatrix(const Field& field, + const Comparison& cmp, + const Visitors&... visitors): + field_(field), + cmp_(cmp), + visitors_(visitors...) {} + + ReducedMatrix(Field&& field, + Comparison&& cmp, + Visitors&&... visitors): + field_(std::move(field)), + cmp_(std::move(cmp)), + visitors_(visitors...) {} + + ReducedMatrix(Self&& m) = default; + ReducedMatrix(const Self& m) = default; + + template class... OtherVisitors> + ReducedMatrix(ReducedMatrix&& other): + field_(other.field_), + cmp_(other.cmp_), + reduced_(std::move(other.reduced_)), + pairs_(std::move(other.pairs_)), + skip_(std::move(other.skip_)) {} + + template + Index add(const ChainRange& chain) { return add(Chain(std::begin(chain), std::end(chain))); } + Index add(Chain&& chain); + + template + void set(Index i, const ChainRange& chain) { return set(i, Chain(std::begin(chain), std::end(chain))); } + void set(Index i, Chain&& chain); + + Index reduce(Index i); + Index reduce(Chain& c) { return reduce(c, reduced_, pairs_); } + template + Index reduce(Chain& c, const ChainsLookup& chains, const LowLookup& low); + + Index reduce_upto(Index i); // TODO + + size_t size() const { return pairs_.size(); } + void clear() { Chains().swap(reduced_); Indices().swap(pairs_); } + + void sort(Chain& c) { std::sort(c.begin(), c.end(), [this](const Entry& e1, const Entry& e2) { return this->cmp_(e1.index(), e2.index()); }); } + + const Chain& operator[](Index i) const { return reduced_[i]; } + Index pair(Index i) const { return pairs_[i]; } + void set_pair(Index i, Index j) { pairs_[i] = j; pairs_[j] = i; } + + Chain& column(Index i) { return reduced_[i]; } + + bool skip(Index i) const { return skip_[i]; } + void add_skip(); + void set_skip(Index i, bool flag = true) { skip_[i] = flag; } + + const Field& field() const { return field_; } + const Comparison& cmp() const { return cmp_; } + void reserve(size_t s) { reduced_.reserve(s); pairs_.reserve(s); } + void resize(size_t s); + + const Chains& columns() const { return reduced_; } + + template + Visitor& visitor() { return std::get(visitors_); } + + static const Index unpaired() { return Reduction::unpaired; } + + private: + template class... Vs> + friend class ReducedMatrix; // let's all be friends + + public: + // Visitors::chain_initialized(c) + template + typename std::enable_if::type + visitors_chain_initialized(Chain& c) {} + + template + typename std::enable_if::type + visitors_chain_initialized(Chain& c) { std::get(visitors_).chain_initialized(this, c); visitors_chain_initialized(c); } + + // Visitors::addto(m, cl) + template + typename std::enable_if::type + visitors_addto(FieldElement m, Index cl) {} + + template + typename std::enable_if::type + visitors_addto(FieldElement m, Index cl) { std::get(visitors_).addto(this, m, cl); visitors_addto(m, cl); } + + // Visitors::reduction_finished(m, cl) + template + typename std::enable_if::type + visitors_reduction_finished() {} + + template + typename std::enable_if::type + visitors_reduction_finished() { std::get(visitors_).reduction_finished(this); visitors_reduction_finished(); } + + private: + Field field_; + Comparison cmp_; + Chains reduced_; // matrix R + Indices pairs_; + SkipFlags skip_; // indicates whether the column should be skipped (e.g., for relative homology) + VisitorsTuple visitors_; +}; + +/* Visitors */ + +// The prototypical visitor. Others may (and probably should) inherit from it. +template +struct EmptyVisitor +{ + EmptyVisitor() = default; + + template + EmptyVisitor(const EmptyVisitor&) {} + + + template + void chain_initialized(Self*, Chain& c) {} + + void addto(Self*, typename Field::Element m, Index cl) {} + void reduction_finished(Self*) {} +}; + +} + +#include "reduced-matrix.hpp" + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/reduced-matrix.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/reduced-matrix.hpp new file mode 100644 index 0000000000..3e4aca8f29 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/reduced-matrix.hpp @@ -0,0 +1,78 @@ +template class... V> +void +dionysus::ReducedMatrix:: +resize(size_t s) +{ + reduced_.resize(s); + pairs_.resize(s, unpaired()); + skip_.resize(s, false); +} + +template class... V> +typename dionysus::ReducedMatrix::Index +dionysus::ReducedMatrix:: +add(Chain&& chain) +{ + // TODO: skip the computation entirely if we already know this is positive (in case of the clearing optimization) + Index i = pairs_.size(); + pairs_.emplace_back(unpaired()); + reduced_.emplace_back(); + skip_.push_back(false); + + set(i, std::move(chain)); + + return reduce(i); +} + +template class... V> +void +dionysus::ReducedMatrix:: +add_skip() +{ + pairs_.emplace_back(unpaired()); + reduced_.emplace_back(); + skip_.push_back(true); +} + +template class... V> +void +dionysus::ReducedMatrix:: +set(Index i, Chain&& c) +{ + sort(c); + visitors_chain_initialized(c); + reduced_[i] = std::move(c); +} + +template class... V> +typename dionysus::ReducedMatrix::Index +dionysus::ReducedMatrix:: +reduce(Index i) +{ + Chain& c = column(i); + Index pair = reduce(c); + + if (pair != unpaired()) + pairs_[pair] = i; + + pairs_[i] = pair; + visitors_reduction_finished<>(); + + return pair; +} + +template class... V> +template +typename dionysus::ReducedMatrix::Index +dionysus::ReducedMatrix:: +reduce( Chain& c, + const ChainsLookup& chains, + const LowLookup& lows) +{ + auto entry_cmp = [this](const Entry& e1, const Entry& e2) { return this->cmp_(e1.index(), e2.index()); }; + return Reduction::reduce(c, chains, lows, field_, + [this](FieldElement m, Index cl) + { this->visitors_addto<>(m, cl); }, + entry_cmp); +} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/reduction.h b/src/Zigzag_persistence/example/ext_zz/dionysus/reduction.h new file mode 100644 index 0000000000..2afd333d41 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/reduction.h @@ -0,0 +1,109 @@ +#ifndef DIONYSUS_REDUCTION_H +#define DIONYSUS_REDUCTION_H + +#include +#include +#include +#include +#include "chain.h" + +namespace dionysus +{ + +namespace detail +{ + +template +struct Unpaired +{ static constexpr Index value() { return std::numeric_limits::max(); } }; + +} + +template +struct Reduction +{ + typedef Index_ Index; + + template + using AddtoVisitor = std::function; + + template + struct CallToSub; + + static const Index unpaired; + + template> + static + Index reduce(Chain1& c, + const ChainsLookup& chains, + const LowLookup& lows, + const Field& field, + const AddtoVisitor& visitor = [](typename Field::Element, Index) {}, + const Comparison& cmp = Comparison()) + { + typedef typename Field::Element FieldElement; + + while (!c.empty()) + { + //auto& low = c.back(); + auto& low = *(std::prev(c.end())); + Index l = low.index(); + Index cl = lows(l); + // std::cout << "idx: " << std::get<0>(cl) << ", " << std::get<1>(cl) << "\n"; + if (cl == unpaired) + return l; + else + { + // Reduce further + auto& co = chains(cl); + auto& co_low = co.back(); + FieldElement m = field.neg(field.div(low.element(), co_low.element())); + // c += m*co + Chain::addto(c, m, co, field, cmp); + visitor(m, cl); + } + } + return unpaired; + } + + template> + static + Index reduce(Chain1& c, + const std::vector& chains, + const std::vector& lows, + const Field& field, + const AddtoVisitor& visitor = [](typename Field::Element, Index) {}, + const Comparison& cmp = Comparison()) + { + return reduce(c, + CallToSub(chains), + CallToSub(lows), + field, visitor, cmp); + } + + // This is a work-around a bug in GCC (should really be a lambda function) + template + struct CallToSub + { + CallToSub(const std::vector& items_): + items(items_) {} + const Item& operator()(Index i) const { return items[i]; } + const std::vector& items; + }; +}; + + +template +const Index +Reduction::unpaired = detail::Unpaired::value(); + +} + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/relative-homology-zigzag.h b/src/Zigzag_persistence/example/ext_zz/dionysus/relative-homology-zigzag.h new file mode 100644 index 0000000000..167a32779d --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/relative-homology-zigzag.h @@ -0,0 +1,84 @@ +#ifndef RELATIVE_HOMOLOGY_ZIGZAG_H +#define RELATIVE_HOMOLOGY_ZIGZAG_H + +#include +#include + +#include "zigzag-persistence.h" + +namespace dionysus +{ + +namespace ba = boost::adaptors; + +template> +class RelativeHomologyZigzag +{ + public: + typedef Field_ Field; + typedef Index_ Index; + typedef Comparison_ Comparison; + + typedef ZigzagPersistence ZZP; + typedef typename ZZP::IndexChain IndexChain; + typedef typename ZZP::FieldElement FieldElement; + typedef typename IndexChain::value_type ChainEntry; + + + typedef Comparison Cmp; + + RelativeHomologyZigzag(const Field& field, + const Comparison& cmp = Comparison()): + zzp_(field, cmp) + { + zzp_.add( IndexChain() ); // vertex w + ++zzp_op_; + ++zzp_cell_; + } + + template + void add_both(const ChainRange& chain); + + void remove_both(Index cell); + + // index of the absolute cell; chain = its boundary + template + Index add(Index cell, const ChainRange& chain); // add to the relative part + + Index remove(Index cell); // remove from the relative part + + const Field& field() const { return zzp_.field(); } + const Cmp& cmp() const { return zzp_.cmp(); } + + size_t alive_size() const { return zzp_.alive_size() - 1; } // -1 for the cone vertex + + static + const Index unpaired() { return ZZP::unpaired(); } + + private: + template + IndexChain relative_chain(Index cell, const ChainRange& chain) const; + + template + IndexChain absolute_chain(const ChainRange& chain) const; + + Index abs_index(Index idx) const { return absolute_.left.find(idx)->second; } + Index rel_index(Index idx) const { return relative_.left.find(idx)->second; } + Index decode_pair(Index pair); + + private: + ZZP zzp_; // underlying (cone) implementation + boost::bimap absolute_; // bimap between our cells and zzp absolute cells + boost::bimap relative_; // bimap between our cells and zzp relative cells + std::unordered_map op_map_; // map from zzp_op to our op + Index op_ = 0, + zzp_op_ = 0, + cell_ = 0, + zzp_cell_ = 0; +}; + +} + +#include "relative-homology-zigzag.hpp" + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/relative-homology-zigzag.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/relative-homology-zigzag.hpp new file mode 100644 index 0000000000..499807106c --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/relative-homology-zigzag.hpp @@ -0,0 +1,122 @@ +template +template +void +dionysus::RelativeHomologyZigzag:: +add_both(const ChainRange& chain) +{ + zzp_.add(absolute_chain(chain)); + op_map_.insert( { zzp_op_++, op_ } ); + absolute_.left.insert( { cell_, zzp_cell_++ } ); + + zzp_.add(relative_chain(cell_, chain)); + op_map_.insert( { zzp_op_++, op_ } ); + relative_.left.insert( { cell_, zzp_cell_++ } ); + + cell_++; + op_++; +} + +template +void +dionysus::RelativeHomologyZigzag:: +remove_both(Index cell) +{ + Index abs_cell = absolute_.left.find(cell)->second; + Index rel_cell = relative_.left.find(cell)->second; + + zzp_.remove(rel_cell); + zzp_.remove(abs_cell); + + absolute_.left.erase(cell); + relative_.left.erase(cell); + + op_map_.insert( { zzp_op_++, op_ } ); + op_map_.insert( { zzp_op_++, op_ } ); + + op_++; +} + +template +template +typename dionysus::RelativeHomologyZigzag::Index +dionysus::RelativeHomologyZigzag:: +add(Index cell, const ChainRange& chain) +{ + Index pair = zzp_.add(relative_chain(cell, chain)); + op_map_.insert( { zzp_op_++, op_++ } ); + relative_.left.insert( { cell, zzp_cell_++ } ); + + return decode_pair(pair); +} + + +template +typename dionysus::RelativeHomologyZigzag::Index +dionysus::RelativeHomologyZigzag:: +decode_pair(Index pair) +{ + if (pair == unpaired()) + return pair; + + Index decoded = op_map_.find(pair)->second; + op_map_.erase(pair); + return decoded; +} + +template +template +typename dionysus::RelativeHomologyZigzag::IndexChain +dionysus::RelativeHomologyZigzag:: +absolute_chain(const ChainRange& chain) const +{ + IndexChain res; + for (const auto& e : chain) + res.push_back(ChainEntry(e.element(), abs_index(e.index()))); + return res; +} + +template +template +typename dionysus::RelativeHomologyZigzag::IndexChain +dionysus::RelativeHomologyZigzag:: +relative_chain(Index cell, const ChainRange& chain) const +{ + // NB: to compute the signs correctly, + // this assumes that the cone vertex w is the last vertex in some total order + + typedef typename IndexChain::value_type ChainEntry; + + IndexChain res; + if (!chain.empty()) + { + for (const auto& e : chain) + res.push_back(ChainEntry(e.element(), rel_index(e.index()))); + + FieldElement a = field().id(); + if (chain.size() % 2 == 0) // TODO: double-check + a = field().neg(a); + res.push_back(ChainEntry(a, abs_index(cell))); // add the base space cell + } else + { + res.reserve(2); + res.push_back(ChainEntry(field().id(), abs_index(cell))); + res.push_back(ChainEntry(field().neg(field().id()), 0)); + } + return res; +} + + +template +typename dionysus::RelativeHomologyZigzag::Index +dionysus::RelativeHomologyZigzag:: +remove(Index cell) +{ + Index rel_cell = rel_index(cell); + Index pair = zzp_.remove(rel_cell); + pair = decode_pair(pair); + + op_map_.insert( { zzp_op_++, op_++ } ); + relative_.left.erase(cell); + + return pair; +} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/rips.h b/src/Zigzag_persistence/example/ext_zz/dionysus/rips.h new file mode 100644 index 0000000000..c7ccb1189e --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/rips.h @@ -0,0 +1,147 @@ +#ifndef DIONYSUS_RIPS_H +#define DIONYSUS_RIPS_H + +#include +#include + +#include + +#include "simplex.h" + +namespace dionysus +{ + +/** + * Rips class + * + * Class providing basic operations to work with Rips complexes. It implements Bron-Kerbosch algorithm, + * and provides simple wrappers for various functions. + * + * Distances_ is expected to define types IndexType and DistanceType as well as + * provide operator()(...) which given two IndexTypes should return + * the distance between them. There should be methods begin() and end() + * for iterating over IndexTypes as well as a method size(). + */ +template > +class Rips +{ + public: + typedef Distances_ Distances; + typedef typename Distances::IndexType IndexType; + typedef typename Distances::DistanceType DistanceType; + + typedef Simplex_ Simplex; + typedef typename Simplex::Vertex Vertex; // should be the same as IndexType + typedef std::vector VertexContainer; + + typedef short unsigned Dimension; + + class Evaluator; + class Comparison; + + public: + Rips(const Distances& distances): + distances_(distances) {} + + // Calls functor f on each simplex in the k-skeleton of the Rips complex + template + void generate(Dimension k, DistanceType max, const Functor& f, + Iterator candidates_begin, Iterator candidates_end) const; + + // Calls functor f on all the simplices of the Rips complex that contain the given vertex v + template + void vertex_cofaces(IndexType v, Dimension k, DistanceType max, const Functor& f, + Iterator candidates_begin, Iterator candidates_end) const; + + // Calls functor f on all the simplices of the Rips complex that contain the given edge [u,v] + template + void edge_cofaces(IndexType u, IndexType v, Dimension k, DistanceType max, const Functor& f, + Iterator candidates_begin, Iterator candidates_end) const; + + // Calls functor f on all the simplices of the Rips complex that contain the given Simplex s + // (unlike the previous methods it does not call the functor on the Simplex s itself) + template + void cofaces(const Simplex& s, Dimension k, DistanceType max, const Functor& f, + Iterator candidates_begin, Iterator candidates_end) const; + + + /* No Iterator argument means Iterator = IndexType and the range is [distances().begin(), distances().end()) */ + template + void generate(Dimension k, DistanceType max, const Functor& f) const + { generate(k, max, f, boost::make_counting_iterator(distances().begin()), boost::make_counting_iterator(distances().end())); } + + template + void vertex_cofaces(IndexType v, Dimension k, DistanceType max, const Functor& f) const + { vertex_cofaces(v, k, max, f, boost::make_counting_iterator(distances().begin()), boost::make_counting_iterator(distances().end())); } + + template + void edge_cofaces(IndexType u, IndexType v, Dimension k, DistanceType max, const Functor& f) const + { edge_cofaces(u, v, k, max, f, boost::make_counting_iterator(distances().begin()), boost::make_counting_iterator(distances().end())); } + + template + void cofaces(const Simplex& s, Dimension k, DistanceType max, const Functor& f) const + { cofaces(s, k, max, f, boost::make_counting_iterator(distances().begin()), boost::make_counting_iterator(distances().end())); } + + + const Distances& distances() const { return distances_; } + DistanceType max_distance() const; + + DistanceType distance(const Simplex& s1, const Simplex& s2) const; + + + template + static void bron_kerbosch(VertexContainer& current, + const VertexContainer& candidates, + typename VertexContainer::const_iterator excluded, + Dimension max_dim, + const NeighborTest& neighbor, + const Functor& functor, + bool check_initial = true); + + protected: + const Distances& distances_; +}; + +template +class Rips::Evaluator +{ + public: + typedef Simplex_ Simplex; + + Evaluator(const Distances& distances): + distances_(distances) {} + + DistanceType operator()(const Simplex& s) const; + + protected: + const Distances& distances_; +}; + +template +class Rips::Comparison +{ + public: + typedef Simplex_ Simplex; + + Comparison(const Distances& distances): + eval_(distances) {} + + bool operator()(const Simplex& s1, const Simplex& s2) const + { + DistanceType e1 = eval_(s1), + e2 = eval_(s2); + if (e1 == e2) + return s1.dimension() < s2.dimension(); + + return e1 < e2; + } + + protected: + Evaluator eval_; +}; + +} + +#include "rips.hpp" + +#endif // DIONYSUS_RIPS_H diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/rips.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/rips.hpp new file mode 100644 index 0000000000..2fdda34a7a --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/rips.hpp @@ -0,0 +1,162 @@ +#include +#include +#include +#include + +#include +#include + +template +template +void +dionysus::Rips:: +generate(Dimension k, DistanceType max, const Functor& f, Iterator bg, Iterator end) const +{ + auto neighbor = [this, max](Vertex u, Vertex v) { return this->distances()(u,v) <= max; }; + + // current = empty + // candidates = everything + VertexContainer current; + VertexContainer candidates(bg, end); + bron_kerbosch(current, candidates, std::prev(candidates.begin()), k, neighbor, f); +} + +template +template +void +dionysus::Rips:: +vertex_cofaces(IndexType v, Dimension k, DistanceType max, const Functor& f, Iterator bg, Iterator end) const +{ + auto neighbor = [this, max](Vertex u, Vertex v) { return this->distances()(u,v) <= max; }; + + // current = [v] + // candidates = everything - [v] + VertexContainer current; current.push_back(v); + VertexContainer candidates; + for (Iterator cur = bg; cur != end; ++cur) + if (*cur != v && neighbor(v, *cur)) + candidates.push_back(*cur); + + bron_kerbosch(current, candidates, std::prev(candidates.begin()), k, neighbor, f); +} + +template +template +void +dionysus::Rips:: +edge_cofaces(IndexType u, IndexType v, Dimension k, DistanceType max, const Functor& f, Iterator bg, Iterator end) const +{ + auto neighbor = [this, max](Vertex u, Vertex v) { return this->distances()(u,v) <= max; }; + + // current = [u,v] + // candidates = everything - [u,v] + VertexContainer current; current.push_back(u); current.push_back(v); + + VertexContainer candidates; + for (Iterator cur = bg; cur != end; ++cur) + if (*cur != u && *cur != v && neighbor(v,*cur) && neighbor(u,*cur)) + candidates.push_back(*cur); + + bron_kerbosch(current, candidates, std::prev(candidates.begin()), k, neighbor, f); +} + +template +template +void +dionysus::Rips:: +cofaces(const Simplex& s, Dimension k, DistanceType max, const Functor& f, Iterator bg, Iterator end) const +{ + namespace ba = boost::adaptors; + + auto neighbor = [this, max](Vertex u, Vertex v) { return this->distances()(u,v) <= max; }; + + // current = s + VertexContainer current(s.begin(), s.end()); + + // candidates = everything - s that is a neighbor of every vertex in the simplex + VertexContainer candidates; + boost::set_difference(std::make_pair(bg, end) | + ba::filtered([this,&s,&neighbor](Vertex cur) + { for (auto& v : s) + if (!neighbor(v, cur)) + return false; + }), + s, + std::back_inserter(candidates)); + + bron_kerbosch(current, candidates, std::prev(candidates.begin()), k, neighbor, f, false); +} + + +template +template +void +dionysus::Rips:: +bron_kerbosch(VertexContainer& current, + const VertexContainer& candidates, + typename VertexContainer::const_iterator excluded, + Dimension max_dim, + const NeighborTest& neighbor, + const Functor& functor, + bool check_initial) +{ + if (check_initial && !current.empty()) + functor(Simplex(current)); + + if (current.size() == static_cast(max_dim) + 1) + return; + + for (auto cur = std::next(excluded); cur != candidates.end(); ++cur) + { + current.push_back(*cur); + + VertexContainer new_candidates; + for (auto ccur = candidates.begin(); ccur != cur; ++ccur) + if (neighbor(*ccur, *cur)) + new_candidates.push_back(*ccur); + size_t ex = new_candidates.size(); + for (auto ccur = std::next(cur); ccur != candidates.end(); ++ccur) + if (neighbor(*ccur, *cur)) + new_candidates.push_back(*ccur); + excluded = new_candidates.begin() + (ex - 1); + + bron_kerbosch(current, new_candidates, excluded, max_dim, neighbor, functor); + current.pop_back(); + } +} + +template +typename dionysus::Rips::DistanceType +dionysus::Rips:: +distance(const Simplex& s1, const Simplex& s2) const +{ + DistanceType mx = 0; + for (auto a : s1) + for (auto b : s2) + mx = std::max(mx, distances_(a,b)); + return mx; +} + +template +typename dionysus::Rips::DistanceType +dionysus::Rips:: +max_distance() const +{ + DistanceType mx = 0; + for (IndexType a = distances_.begin(); a != distances_.end(); ++a) + for (IndexType b = std::next(a); b != distances_.end(); ++b) + mx = std::max(mx, distances_(a,b)); + return mx; +} + +template +typename dionysus::Rips::DistanceType +dionysus::Rips::Evaluator:: +operator()(const Simplex& s) const +{ + DistanceType mx = 0; + for (auto a = s.begin(); a != s.end(); ++a) + for (auto b = std::next(a); b != s.end(); ++b) + mx = std::max(mx, distances_(*a,*b)); + return mx; +} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/row-reduction.h b/src/Zigzag_persistence/example/ext_zz/dionysus/row-reduction.h new file mode 100644 index 0000000000..e2481ce080 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/row-reduction.h @@ -0,0 +1,54 @@ +#ifndef DIONYSUS_ROW_REDUCTION_H +#define DIONYSUS_ROW_REDUCTION_H + +#include "reduced-matrix.h" + +namespace dionysus +{ + +// Mid-level interface +template, template class... Visitors> +class RowReduction +{ + public: + typedef Field_ Field; + typedef Index_ Index; + typedef Comparison_ Comparison; + + typedef ReducedMatrix Persistence; + + public: + RowReduction(const Field& field): + persistence_(field) {} + + RowReduction(const Field& field, + const Comparison& cmp, + const Visitors&... visitors): + persistence_(field, cmp, visitors...) {} + + template + void operator()(const Filtration& f, const Relative& relative, const ReportPair& report_pair, const Progress& progress); + + template + void operator()(const Filtration& f, const ReportPair& report_pair); + + template + void operator()(const Filtration& f) { return (*this)(f, &no_report_pair); } + + static void no_report_pair(int, Index, Index) {} + static void no_progress() {} + + const Persistence& + persistence() const { return persistence_; } + Persistence& persistence() { return persistence_; } + + private: + Persistence persistence_; +}; + +} + +#include "row-reduction.hpp" + +#endif + diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/row-reduction.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/row-reduction.hpp new file mode 100644 index 0000000000..edb1652872 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/row-reduction.hpp @@ -0,0 +1,103 @@ +#include +namespace ba = boost::adaptors; + +template class... V> +template +void +dionysus::RowReduction:: +operator()(const Filtration& filtration, const ReportPair& report_pair) +{ + using Cell = typename Filtration::Cell; + (*this)(filtration, [](const Cell&) { return false; }, report_pair, &no_progress); +} + +template class... V> +template +void +dionysus::RowReduction:: +operator()(const Filtration& filtration, const Relative& relative, const ReportPair& report_pair, const Progress& progress) +{ + persistence_.resize(filtration.size()); + + typedef typename Persistence::Index Index; + typedef typename Persistence::FieldElement Element; + typedef typename Persistence::Chain Chain; + typedef typename Filtration::Cell Cell; + typedef ChainEntry CellChainEntry; + typedef ChainEntry ChainEntry; + + std::vector rows(persistence_.size()); + + auto& field = persistence_.field(); + + // fill the matrix + Index i = 0; + for(auto& c : filtration) + { + progress(); + + if (relative(c)) + { + persistence_.set_skip(i); + ++i; + continue; + } + + persistence_.set(i, c.boundary(field) | + ba::filtered([relative](const CellChainEntry& e) { return !relative(e.index()); }) | + ba::transformed([this,&filtration](const CellChainEntry& e) + { return ChainEntry(e.element(), filtration.index(e.index())); })); + if (!persistence_[i].empty()) + { + auto& x = persistence_[i].back(); + rows[x.index()].emplace_back(x.element(),i); + } + ++i; + } + + auto entry_cmp = [this](const ChainEntry& e1, const ChainEntry& e2) { return this->persistence_.cmp()(e1.index(), e2.index()); }; + + // reduce the matrix from the bottom up + for (auto it = rows.rbegin(); it != rows.rend(); ++it) + { + auto& row = *it; + Index r = rows.rend() - it - 1; + + if (row.empty()) + continue; + + // add the first column to every other column + Index c = row.front().index(); + Element e = row.front().element(); + Chain& first = persistence_.column(c); + for (size_t i = 1; i < row.size(); ++i) + { + Index cur_idx = row[i].index(); + Element cur_elem = row[i].element(); + Chain& cur = persistence_.column(cur_idx); + if (cur.empty()) // zeroed out by the clearing optimization + continue; + + Element m = field.neg(field.div(cur_elem, e)); + // cur += m*first + ::dionysus::Chain::addto(cur, m, first, field, entry_cmp); + + // update row + if (!cur.empty()) + { + ChainEntry ce = cur.back(); + auto& new_row = rows[ce.index()]; + new_row.emplace_back(ce.element(), cur_idx); + if (entry_cmp(new_row.back(), new_row.front())) + std::swap(new_row.back(), new_row.front()); + } + } + + persistence_.set_pair(r,c); + report_pair(filtration[r].dimension(), r, c); + + // zero out the corresponding column (the clearing optimization) + persistence_.column(r).clear(); + } +} + diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/simplex.h b/src/Zigzag_persistence/example/ext_zz/dionysus/simplex.h new file mode 100644 index 0000000000..4ac5cb6945 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/simplex.h @@ -0,0 +1,280 @@ +#ifndef DIONYSUS_SIMPLEX_H +#define DIONYSUS_SIMPLEX_H + +#include +#include + +//#include +#include +#include +#include + +#include "chain.h" + +namespace dionysus +{ + +struct Empty {}; + +template +class Simplex +{ + public: + typedef Vertex_ Vertex; + typedef T Data; + typedef std::unique_ptr Vertices; + + template + struct BoundaryChainIterator; + struct BoundaryIterator; + + template + using BoundaryChainRange = boost::iterator_range>; + using BoundaryRange = boost::iterator_range; + + template + using Entry = ChainEntry; + + public: + Simplex(const Data& d = Data()): + dim_(-1), data_(d) {} + + Simplex(const std::initializer_list& vertices, + Data&& d = Data()): + Simplex(vertices.size() - 1, vertices.begin(), vertices.end(), std::move(d)) + {} + + Simplex(const std::initializer_list& vertices, + const Data& d): + Simplex(vertices.size() - 1, vertices.begin(), vertices.end(), d) {} + + Simplex(short unsigned dim, Vertices&& vertices, Data&& data = Data()): + dim_(dim), vertices_(std::move(vertices)), data_(std::move(data)) { std::sort(begin(), end()); } + + template + Simplex(const VertexRange& vertices, + Data&& d = Data()): + Simplex(vertices.size() - 1, vertices.begin(), vertices.end(), std::move(d)) + {} + + template + Simplex(const VertexRange& vertices, + const Data& d): + Simplex(vertices.size() - 1, vertices.begin(), vertices.end(), d) {} + + Simplex(const Simplex& other): + Simplex(other.dim_, other.begin(), other.end(), other.data_) {} + Simplex& operator=(const Simplex& other) { dim_ = other.dim_; vertices_ = Vertices(new Vertex[dim_+1]); std::copy(other.begin(), other.end(), begin()); data_ = other.data_; return *this; } + + Simplex(Simplex&& other) noexcept: + dim_(other.dim_), + vertices_(std::move(other.vertices_)), + data_(std::move(other.data_)) {} + Simplex& operator=(Simplex&& other) = default; + + template + Simplex(short unsigned dim, + Iterator b, Iterator e, + Data&& d = Data()): + dim_(dim), + vertices_(new Vertex[dim_+1]), + data_(std::move(d)) { std::copy(b, e, begin()); std::sort(begin(), end()); } + + template + Simplex(short unsigned dim, + Iterator b, Iterator e, + const Data& d): + dim_(dim), + vertices_(new Vertex[dim_+1]), + data_(d) { std::copy(b, e, begin()); std::sort(begin(), end()); } + + short unsigned dimension() const { return dim_; } + + BoundaryRange boundary() const { return BoundaryRange(boundary_begin(), boundary_end()); } + BoundaryIterator boundary_begin() const; + BoundaryIterator boundary_end() const; + + template + BoundaryChainRange + boundary(const Field& field) const { return BoundaryChainRange(boundary_begin(field), boundary_end(field)); } + + template + BoundaryChainIterator + boundary_begin(const Field& field) const; + template + BoundaryChainIterator + boundary_end(const Field& field) const; + + const Vertex* begin() const { return vertices_.get(); } + const Vertex* end() const { return begin() + dim_ + 1; } + size_t size() const { return dim_ + 1; } + + std::pair + range() const { return std::make_pair(begin(), end()); } + + Simplex join(const Vertex& v) const { Vertices vertices(new Vertex[dim_+2]); std::copy(begin(), end(), vertices.get()); vertices[dim_+1] = v; return Simplex(dim_ + 1, std::move(vertices), Data(data_)); } + + bool operator==(const Simplex& other) const { return dim_ == other.dim_ && std::equal(begin(), end(), other.begin()); } + bool operator!=(const Simplex& other) const { return !operator==(other); } + bool operator<(const Simplex& other) const { return dim_ < other.dim_ || (dim_ == other.dim_ && std::lexicographical_compare(begin(), end(), other.begin(), other.end())); } + bool operator>(const Simplex& other) const { return other < (*this); } + + Vertex operator[](short unsigned i) const { return vertices_[i]; } + const Data& data() const { return data_; } + Data& data() { return data_; } + + friend + std::ostream& operator<<(std::ostream& out, const Simplex& s) + { out << '<' << *s.begin(); for (auto it = s.begin() + 1; it != s.end(); ++it) out << ',' << *it; out << '>'; return out; } + + private: + Vertex* begin() { return vertices_.get(); } + Vertex* end() { return begin() + dim_ + 1; } + + private: + short unsigned dim_; + //boost::compressed_pair vertices_data_; + Vertices vertices_; + Data data_; // TODO: optimize +}; + +template +size_t hash_value(const Simplex& s) { return boost::hash_range(s.begin(), s.end()); } + + +template +struct Simplex::BoundaryIterator: + public boost::iterator_adaptor, // Value + boost::use_default, + Simplex> // Reference +{ + public: + typedef const V* Iterator; + typedef Simplex Value; + + typedef boost::iterator_adaptor Parent; + + BoundaryIterator() {} + explicit BoundaryIterator(short unsigned dim, Iterator iter, Iterator bg, Iterator end): + Parent(iter), dim_(dim), bg_(bg), end_(end) {} + + Iterator begin() const { return bg_; } + + private: + friend class boost::iterator_core_access; + Value dereference() const + { + typedef std::not_equal_to NotEqualVertex; + + using std::placeholders::_1; + return Simplex(dim_ - 1, + boost::make_filter_iterator(std::bind(NotEqualVertex(), _1, *(this->base())), bg_, end_), + boost::make_filter_iterator(std::bind(NotEqualVertex(), _1, *(this->base())), end_, end_)); + } + + short unsigned dim_; + Iterator bg_; + Iterator end_; +}; + +template +template +struct Simplex::BoundaryChainIterator: + public boost::iterator_adaptor, // Derived + BoundaryIterator, + ChainEntry>, // Value + boost::use_default, + ChainEntry>> // Reference +{ + public: + typedef F Field; + typedef BoundaryIterator Iterator; + typedef ChainEntry> Value; + + typedef boost::iterator_adaptor Parent; + + BoundaryChainIterator() {} + explicit BoundaryChainIterator(const Field& field, Iterator iter): + Parent(iter), field_(&field) {} + + private: + friend class boost::iterator_core_access; + Value dereference() const + { + return Value(((this->base().base() - this->base().begin()) % 2 == 0)? field_->id() : field_->neg(field_->id()), + *(this->base())); + } + + const Field* field_ = nullptr; +}; + + +/* Simplex */ +template +typename Simplex::BoundaryIterator +Simplex:: +boundary_begin() const +{ + if (dimension() == 0) return boundary_end(); + return BoundaryIterator(dimension(), begin(), begin(), end()); +} + +template +typename Simplex::BoundaryIterator +Simplex:: +boundary_end() const +{ + return BoundaryIterator(dimension(), end(), begin(), end()); +} + +template +template +#if defined(_MSC_VER) +typename Simplex::BoundaryChainIterator +#else +typename Simplex::template BoundaryChainIterator +#endif +Simplex:: +boundary_begin(const F& field) const +{ + if (dimension() == 0) return boundary_end(field); + return BoundaryChainIterator(field, boundary_begin()); +} + +template +template +#if defined(_MSC_VER) +typename Simplex::BoundaryChainIterator +#else +typename Simplex::template BoundaryChainIterator +#endif +Simplex:: +boundary_end(const F& field) const +{ + return BoundaryChainIterator(field, boundary_end()); +} + +} // dionysus + +namespace std +{ + +template +struct hash> +{ + size_t operator()(const dionysus::Simplex& s) const { return hash_value(s); } +}; + +} // std + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/sparse-row-matrix.h b/src/Zigzag_persistence/example/ext_zz/dionysus/sparse-row-matrix.h new file mode 100644 index 0000000000..fb1e929e02 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/sparse-row-matrix.h @@ -0,0 +1,184 @@ +#ifndef DIONYSUS_SPARSE_ROW_MATRIX_H +#define DIONYSUS_SPARSE_ROW_MATRIX_H + +#include +#include +#include +#include // for debugging output + +#include + +#include "chain.h" +#include "reduction.h" + +namespace dionysus +{ + +namespace bi = boost::intrusive; + +namespace detail +{ + typedef bi::list_base_hook> auto_unlink_hook; + + template + struct SparseRowMatrixEntry: + public ChainEntry, auto_unlink_hook> + { + typedef I Index; + typedef typename F::Element FieldElement; + typedef std::tuple IndexPair; // (id, pair) + typedef ChainEntry Parent; + typedef SparseRowMatrixEntry Entry; + + SparseRowMatrixEntry(FieldElement e, const IndexPair& ip): + Parent(e,ip) {} + + SparseRowMatrixEntry(FieldElement e, const Index& r, const Index& c): + Parent(e,IndexPair(r,c)) {} + + SparseRowMatrixEntry(const Entry& other) = default; + SparseRowMatrixEntry(Entry&& other) = default; + Entry& operator=(Entry&& other) = default; + + void unlink() { auto_unlink_hook::unlink(); } + bool is_linked() const { return auto_unlink_hook::is_linked(); } + }; +} + +template, + template class Column_ = std::vector> +class SparseRowMatrix +{ + public: + typedef Field_ Field; + typedef Index_ Index; + typedef Comparison_ Comparison; + + typedef typename Field::Element FieldElement; + + typedef detail::SparseRowMatrixEntry Entry; + typedef Column_ Column; + typedef typename Entry::IndexPair IndexPair; + typedef bi::list> Row; + + typedef std::vector> IndexChain; + + typedef std::unordered_map Columns; + typedef std::unordered_map Rows; + typedef std::unordered_map LowMap; + + public: + SparseRowMatrix(const Field& field, + const Comparison& cmp = Comparison()): + field_(field), cmp_(cmp) {} + + SparseRowMatrix(SparseRowMatrix&& other) = default; + + + template + Column reduce(const ChainRange& chain, IndexChain& trail); + + Index set(Index i, Column&& chain); // returns previous column with this low + void fix(Index c, Column& column); + void fix(Index c) { fix(c, col(c)); } + + const Row& prepend_row(Index r, FieldElement m, const Row& chain); // could be horribly inefficient if Column is chosen poorly + + void drop_row(Index r) { rows_.erase(r); if (is_low(r)) lows_.erase(r); } + void drop_col(Index c) + { + auto cit = columns_.find(c); + Column& column = cit->second; + if (!column.empty()) + { + Index rlow = std::get<0>(column.back().index()); + auto it = lows_.find(rlow); + if (it != lows_.end() && it->second == c) + lows_.erase(it); + } + columns_.erase(cit); + } + void drop_low(Index r) { lows_.erase(r); } + + // accessors + Row& row(Index r) { return rows_[r]; } + Column& col(Index c) { assert(col_exists(c)); return columns_.find(c)->second; } + const Column& col(Index c) const { assert(col_exists(c)); return columns_.find(c)->second; } + Index low(Index r) const { return lows_.find(r)->second; } + bool is_low(Index r) const { return lows_.find(r) != lows_.end(); } + void update_low(Index c) { lows_[std::get<0>(col(c).back().index())] = c; } + + const Field& field() const { return field_; } + void reserve(size_t) {} // here for compatibility only + const Comparison& cmp() const { return cmp_; } + + // debug + bool col_exists(Index c) const { return columns_.find(c) != columns_.end(); } + const Columns& columns() const { return columns_; } + void check_columns() const + { + for (auto& x : columns_) + { + Index c = x.first; + if (x.second.empty()) + std::cout << "Warning: empty column " << c << std::endl; + Index rl = std::get<0>(x.second.back().index()); + if (!is_low(rl) || low(rl) != c) + { + std::cout << "Columns don't check out: lows don't match" << std::endl; + std::cout << " " << c << ' ' << rl << ' ' << ' ' << low(rl) << std::endl; + std::cout << "---\n"; + for (auto& x : col(c)) + std::cout << " " << x.element() << ' ' << std::get<0>(x.index()) << ' ' << std::get<1>(x.index()) << '\n'; + std::cout << "---\n"; + for (auto& x : col(low(rl))) + std::cout << " " << x.element() << ' ' << std::get<0>(x.index()) << ' ' << std::get<1>(x.index()) << '\n'; + assert(0); + } + + for (auto& x : lows_) + { + if (!col_exists(x.second)) + { + std::cout << "Still keeping low of a removed column" << std::endl; + assert(0); + } + else if (std::get<0>(col(x.second).back().index()) != x.first) + { + std::cout << "Low mismatch: " << x.second << ' ' << std::get<0>(col(x.second).back().index()) << ' ' << x.first << '\n'; + assert(0); + } + } + } + } + + private: + Field field_; + Comparison cmp_; + + Columns columns_; + Rows rows_; + LowMap lows_; // column that has this low +}; + + +namespace detail +{ + +template +struct Unpaired> +{ + static + constexpr std::tuple + value() + { return std::make_tuple(std::numeric_limits::max(), + std::numeric_limits::max()); } +}; + +} + +} + +#include "sparse-row-matrix.hpp" + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/sparse-row-matrix.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/sparse-row-matrix.hpp new file mode 100644 index 0000000000..10f4808c17 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/sparse-row-matrix.hpp @@ -0,0 +1,103 @@ +template class Col> +template +typename dionysus::SparseRowMatrix::Column +dionysus::SparseRowMatrix:: +reduce(const ChainRange& chain_, IndexChain& trail) +{ + auto row_cmp = [this](const Entry& e1, const Entry& e2) + { return this->cmp_(std::get<0>(e1.index()), std::get<0>(e2.index())); }; + +#define __DIONYSUS_USE_VECTOR_CHAINS 1 + +#if !(__DIONYSUS_USE_VECTOR_CHAINS) + std::set chain(row_cmp); + for (auto x : chain_) + chain.insert(Entry(x.element(), IndexPair(x.index(), 0))); +#else + Column chain; + for (auto x : chain_) + chain.emplace_back(x.element(), IndexPair(x.index(), 0)); + std::sort(chain.begin(), chain.end(), row_cmp); +#endif + + typedef Reduction ReductionIP; + + auto chains = [this](const IndexPair& rc) -> const Column& { return this->col(std::get<1>(rc)); }; + auto lows = [this](const IndexPair& rc) -> IndexPair + { + Index r = std::get<0>(rc); + auto it = this->lows_.find(r); + if (it == this->lows_.end()) + return ReductionIP::unpaired; + else + { + Index rr = std::get<0>(col(it->second).back().index()); + if (rr != r) + std::cout << "Mismatch: " << rr << ' ' << r << std::endl; + return IndexPair(r, it->second); + } + }; + + auto addto = [&trail](FieldElement m, const IndexPair& rc) { trail.emplace_back(m, std::get<1>(rc)); }; + + ReductionIP::reduce(chain, + chains, lows, + field_, addto, row_cmp); + +#if !(__DIONYSUS_USE_VECTOR_CHAINS) + return Column(std::begin(chain), std::end(chain)); +#else + return chain; +#endif +} + +template class Col> +typename dionysus::SparseRowMatrix::Index +dionysus::SparseRowMatrix:: +set(Index col, Column&& chain) +{ + Column& column = columns_.emplace(col, std::move(chain)).first->second; + + fix(col, column); + + Index r = std::get<0>(column.back().index()); + Index res; + if (is_low(r)) + res = low(r); + else + res = col; + lows_[r] = col; + + return res; +} + +template class Col> +void +dionysus::SparseRowMatrix:: +fix(Index col, Column& column) +{ + for (auto& x : column) + { + std::get<1>(x.index()) = col; + Index r = std::get<0>(x.index()); + row(r).push_back(x); + } +} + +template class Col> +const typename dionysus::SparseRowMatrix::Row& +dionysus::SparseRowMatrix:: +prepend_row(Index r, FieldElement m, const Row& chain) +{ + Row& new_row = row(r); + + for (auto& x : chain) + { + Index c = std::get<1>(x.index()); + Column& column = col(c); + auto it = column.emplace(column.begin(), field().mul(x.element(), m), r, c); + new_row.push_back(*it); + } + + return new_row; +} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/standard-reduction.h b/src/Zigzag_persistence/example/ext_zz/dionysus/standard-reduction.h new file mode 100644 index 0000000000..0477d4683f --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/standard-reduction.h @@ -0,0 +1,44 @@ +#ifndef DIONYSUS_STANDARD_REDUCTION_H +#define DIONYSUS_STANDARD_REDUCTION_H + +namespace dionysus +{ + +// Mid-level interface +template +class StandardReduction +{ + public: + typedef Persistence_ Persistence; + typedef typename Persistence::Field Field; + typedef typename Persistence::Index Index; + + public: + StandardReduction(Persistence& persistence): + persistence_(persistence) {} + + template + void operator()(const Filtration& f, const Relative& relative, const ReportPair& report_pair, const Progress& progress); + + template + void operator()(const Filtration& f, const ReportPair& report_pair); + + template + void operator()(const Filtration& f) { return (*this)(f, &no_report_pair); } + + static void no_report_pair(int, Index, Index) {} + static void no_progress() {} + + const Persistence& + persistence() const { return persistence_; } + Persistence& persistence() { return persistence_; } + + private: + Persistence& persistence_; +}; + +} + +#include "standard-reduction.hpp" + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/standard-reduction.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/standard-reduction.hpp new file mode 100644 index 0000000000..9aa3396a8c --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/standard-reduction.hpp @@ -0,0 +1,47 @@ +#include +namespace ba = boost::adaptors; + +template +template +void +dionysus::StandardReduction

:: +operator()(const Filtration& filtration, const ReportPair& report_pair) +{ + using Cell = typename Filtration::Cell; + (*this)(filtration, [](const Cell&) { return false; }, report_pair, no_progress); +} + +template +template +void +dionysus::StandardReduction

:: +operator()(const Filtration& filtration, const Relative& relative, const ReportPair& report_pair, const Progress& progress) +{ + persistence_.reserve(filtration.size()); + + typedef typename Filtration::Cell Cell; + typedef ChainEntry CellChainEntry; + typedef ChainEntry ChainEntry; + + unsigned i = 0; + for(auto& c : filtration) + { + progress(); + + if (relative(c)) + { + ++i; + persistence_.add_skip(); + continue; + } + + //std::cout << "Adding: " << c << " : " << boost::distance(c.boundary(persistence_.field())) << std::endl; + Index pair = persistence_.add(c.boundary(persistence_.field()) | + ba::filtered([relative](const CellChainEntry& e) { return !relative(e.index()); }) | + ba::transformed([this,&filtration](const CellChainEntry& e) + { return ChainEntry(e.element(), filtration.index(e.index())); })); + if (pair != persistence_.unpaired()) + report_pair(c.dimension(), pair, i); + ++i; + } +} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/trails-chains.h b/src/Zigzag_persistence/example/ext_zz/dionysus/trails-chains.h new file mode 100644 index 0000000000..f18ff897e4 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/trails-chains.h @@ -0,0 +1,17 @@ +#ifndef DIONYSUS_TRAILS_CHAINS_H +#define DIONYSUS_TRAILS_CHAINS_H + +#include "ordinary-persistence.h" + +template +struct ChainsVisitor: public EmptyVisitor +{ + template + void chain_initialized(Chain& c) { } + + void addto(typename Field::Element m, Index cl) {} + void reduction_finished() {} +}; + + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/zigzag-persistence.h b/src/Zigzag_persistence/example/ext_zz/dionysus/zigzag-persistence.h new file mode 100644 index 0000000000..e9423099aa --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/zigzag-persistence.h @@ -0,0 +1,142 @@ +#ifndef DIONYSUS_ZIGZAG_PERSISTENCE_H +#define DIONYSUS_ZIGZAG_PERSISTENCE_H + +#include +#include +#include + +#include +#include + +#include "sparse-row-matrix.h" + +namespace dionysus +{ + +namespace ba = boost::adaptors; + +template> +class ZigzagPersistence +{ + static_assert(std::is_signed::value, "Index type used in ZigzagPersistence must be a *signed* integer"); + + public: + typedef Field_ Field; + typedef Index_ Index; + typedef Comparison_ Comparison; + + typedef SparseRowMatrix RowMatrix; + typedef SparseRowMatrix DequeRowMatrix; + typedef typename RowMatrix::IndexPair IndexPair; + typedef typename RowMatrix::FieldElement FieldElement; + typedef typename RowMatrix::IndexChain IndexChain; + typedef typename RowMatrix::Column Column; + typedef typename RowMatrix::Row Row; + typedef typename DequeRowMatrix::Column DequeColumn; + typedef typename DequeRowMatrix::Row DequeRow; + + typedef std::unordered_map BirthIndexMap; + + + ZigzagPersistence(const Field& field, + const Comparison& cmp = Comparison()): + Z(field, cmp), C(field, cmp), B(field, cmp), + operations(0), + cell_indices(0), + z_indicies_last(0), + z_indicies_first(-1), + b_indices(0) {} + + template + Index add(const ChainRange& chain) // returns the id of the dying cycle (or unpaired) + { + Index res = add_impl(chain); +#ifdef DIONYSUS_ZIGZAG_DEBUG + check_sorted(); + check_b_cols(); + Z.check_columns(); +#endif + return res; + } + Index remove(Index cell) + { + Index res = remove_impl(cell); +#ifdef DIONYSUS_ZIGZAG_DEBUG + check_sorted(); + check_b_cols(); + Z.check_columns(); +#endif + return res; + } + + struct IsAlive + { + IsAlive(const ZigzagPersistence& zz_): zz(&zz_) {} + bool operator()(const std::pair& x) const { return zz->is_alive(x.first); } + const ZigzagPersistence* zz; + }; + + bool is_alive(Index x) const { return !B.is_low(x); } + + auto alive_ops() const -> decltype(BirthIndexMap() | ba::filtered(IsAlive(*this)) | ba::map_values) + { return birth_index | ba::filtered(IsAlive(*this)) | ba::map_values; } + + auto alive_cycles() const -> decltype(BirthIndexMap() | ba::filtered(IsAlive(*this)) | ba::map_keys) + { return birth_index | ba::filtered(IsAlive(*this)) | ba::map_keys; } + + size_t alive_size() const { return Z.columns().size() - B.columns().size(); } + + void reserve(size_t) {} // here for compatibility only + const Field& field() const { return Z.field(); } + const Comparison& cmp() const { return Z.cmp(); } + + template + static Index row(const Entry& e) { return std::get<0>(e.index()); } + template + static Index col(const Entry& e) { return std::get<1>(e.index()); } + + static + const Index unpaired() { return Reduction::unpaired; } + + const Column& cycle(Index i) const { return Z.col(i); } + + // debug + void check_b_cols() const; + + template + void check_boundaries(const SimplexToIndex& s2i, const IndexToSimplex& i2s) const; + template + void check_cycles(const SimplexToIndex& s2i, const IndexToSimplex& i2s) const; + + Column zb_dot(Index c) const; + + template + Column dc_dot(Index c, const SimplexToIndex& s2i, const IndexToSimplex& i2s) const; + + template + Column boundary(Index i, const SimplexToIndex& s2i, const IndexToSimplex& i2s) const; + + void check_sorted() const; + + private: + template + Index add_impl(const ChainRange& chain); + Index remove_impl(Index cell); + + private: + RowMatrix Z, C; + DequeRowMatrix B; + + BirthIndexMap birth_index; + Index operations; + Index cell_indices; + Index z_indicies_last, z_indicies_first; + Index b_indices; +}; + +} + +#include "zigzag-persistence.hpp" + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/zigzag-persistence.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/zigzag-persistence.hpp new file mode 100644 index 0000000000..96331a3b15 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/dionysus/zigzag-persistence.hpp @@ -0,0 +1,541 @@ +#include + +template +template +typename dionysus::ZigzagPersistence::Index +dionysus::ZigzagPersistence:: +add_impl(const ChainRange& chain_) +{ + // std::cout << "add(" << cell_indices << ")" << std::endl; + Index op = operations++; + + IndexChain cycles; // chain_ -> Z*cycles + Column z_remainder = Z.reduce(chain_, cycles); + // std::cout << "cycle: "; + // for (auto& v : cycles){ + // std::cout << v.index() << " "; + // } + // std::cout << "\n"; + assert(z_remainder.empty()); + + IndexChain boundaries; + DequeColumn b_remainder = B.reduce(cycles, boundaries); + + // add up columns of C indexed by boundaries + typedef typename Column::value_type Entry; + auto row_cmp = [this](const Entry& e1, const Entry& e2) + { return this->cmp()(row(e1), row(e2)); }; + Column chain; + for (auto& x : boundaries) + Chain::addto(chain, x.element(), C.col(x.index()), field(), row_cmp); + chain.push_back(Entry(field().neg(field().id()), IndexPair(cell_indices++,0))); + + if (b_remainder.empty()) // birth + { + // std::cout << " birth" << std::endl; + Index z_col = z_indicies_last++; + Z.set(z_col, std::move(chain)); + birth_index[z_col] = op; + return unpaired(); + } + else // death + { + // std::cout << " death" << std::endl; + Index b_col = b_indices++; + Index pair = row(b_remainder.back()); + B.set(b_col, std::move(b_remainder)); + C.set(b_col, std::move(chain)); + return birth_index[pair]; + } +} + +template +typename dionysus::ZigzagPersistence::Index +dionysus::ZigzagPersistence:: +remove_impl(Index cell) +{ + //std::cout << "remove(" << cell << ")" << std::endl; + + Index op = operations++; + + typedef typename Column::value_type Entry; + auto row_cmp = [this](const Entry& e1, const Entry& e2) + { return this->cmp()(row(e1), row(e2)); }; + typedef typename DequeColumn::value_type DequeEntry; + auto b_row_cmp = [this](const DequeEntry& e1, const DequeEntry& e2) + { return this->cmp()(row(e1), row(e2)); }; + + IndexChain z_row; + for (auto& x : Z.row(cell)) + z_row.emplace_back(x.element(), col(x)); + + if (z_row.empty()) // birth + { + //std::cout << " birth" << std::endl; + Row& c_row = C.row(cell); + // c_row.front() may not be the first column in order, but that doesn't really matter, does it? (TODO) + auto& c_front = c_row.front(); + + Index j = col(c_front); + Index l = row(B.col(j).back()); + + //std::cout << j << ' ' << l << std::endl; + + // cycle = ZB[j] = DC[j] + Column cycle; + for (auto& x : B.col(j)) + Chain::addto(cycle, x.element(), Z.col(row(x)), field(), row_cmp); + + //std::cout << "Cycle:" << std::endl; + //for (auto& x : cycle) + // std::cout << x.element() << ' ' << row(x) << std::endl; + + // 1: prepend the cycle + Index znew = z_indicies_first--; + Index oth = Z.set(znew, std::move(cycle)); // oth records our collision (used in step 6) + birth_index[znew] = op; + + //std::cout << "znew oth: " << znew << ' ' << oth << std::endl; + //std::cout << "oth column:" << std::endl; + //for (auto& x : Z.col(oth)) + // std::cout << x.element() << ' ' << row(x) << std::endl; + + // 2: prepend the row to B + FieldElement m = field().neg(field().inv(c_front.element())); // m = -1/c + const DequeRow& b_row = B.prepend_row(znew, m, c_row); + //std::cout << "Prepended row with multiplier: " << m << " (" << b_row.size() << ")" << std::endl; + + // 3: subtract C[j] from every C[k] + const Column& Cj = C.col(j); + + // use the copy of c_row in B, since c_row will be modified in the following loop + for (auto it = std::next(b_row.begin()); it != b_row.end(); ++it) + { + Index c = col(*it); + assert(c != j); + //std::cout << "adding to " << c << " in C" << std::endl; + Chain::addto(C.col(c), it->element(), Cj, field(), row_cmp); // using it->element() since b_row = m*c_row + C.fix(c); // old elements got removed via auto_unlink_hook + // we don't need lows in C, so not updating them + } + //std::cout << "Done with step 3" << std::endl; + + // 4: subtract B[j] from every B[k] that has l + // (we don't need to update C because ZB[j] = 0 after step 2) + DequeColumn& Bj = B.col(j); + FieldElement bm = field().neg(field().inv(Bj.back().element())); // bm = -1/B[l,j] + IndexChain Bl_row; // make a copy of Bl_row, since it will be changing + for (auto& x : B.row(l)) + { + if (col(x) == j) + continue; + Bl_row.emplace_back(x.element(), col(x)); + } + for (auto& x : Bl_row) + { + Index c = x.index(); + assert(c != j); + Chain::addto(B.col(c), field().mul(bm, x.element()), Bj, field(), b_row_cmp); + B.fix(c); // old elements got removed via auto_unlink_hook + // l cannot be the low in c, so no need to update lows + } + //std::cout << "Done with step 4" << std::endl; + + // 5: drop row l and column j from B; drop column l from Z; drop column j from C + B.drop_col(j); + assert(B.row(l).empty()); + B.drop_row(l); + Index Zl_low = row(Z.col(l).back()); + Z.drop_col(l); + birth_index.erase(l); + C.drop_col(j); + assert(Z.row(cell).empty()); + assert(C.row(cell).empty()); + C.drop_row(cell); + Z.drop_row(cell); + //std::cout << "Done with step 5" << std::endl; + if (oth == l) // we just dropped our collision in Z + oth = znew; + else + Z.drop_low(Zl_low); + + // 6: reduce Z + std::unordered_map b_changes; // the columns to add in B to apply row changes + Index cur = znew; + while (oth != cur) + { + Column& cur_col = Z.col(cur); + Column& oth_col = Z.col(oth); + assert(row(cur_col.back()) == row(oth_col.back())); + //std::cout << "--- " << cur << " (" << cur_col.size() << ") " << oth << " (" << oth_col.size() << ")" << std::endl; + FieldElement m1 = cur_col.back().element(); + FieldElement m2 = oth_col.back().element(); + FieldElement m2_div_m1 = field().div(m2, m1); + Chain::addto(oth_col, field().neg(m2_div_m1), cur_col, field(), row_cmp); + Z.fix(oth, oth_col); + + // record the changes we need to make in B; + // because there is only one collision in the matrix during the reduction, + // once we use a row as the source, we never revisit it. This means once the row is updated in B, + // we never touch it again, so below record is fine. + for (auto& x : this->B.row(oth)) + b_changes[col(x)].emplace_back(field().mul(x.element(), m2_div_m1), cur, col(x)); + + cur = oth; + Index low = row(oth_col.back()); + if (Z.is_low(low)) + oth = Z.low(low); + //std::cout << "--- -- new low: " << low << ' ' << cur << ' ' << oth << std::endl; + + if (cmp()(oth, cur)) + std::swap(oth, cur); + else + Z.update_low(cur); + } + + // apply changes in B (the complexity here could get ugly) + for (auto& bx : b_changes) + { + std::sort(bx.second.begin(), bx.second.end(), b_row_cmp); + Chain::addto(B.col(bx.first), field().id(), bx.second, field(), b_row_cmp); + B.fix(bx.first); + // no need to update low (additions from bottom up) + } + //std::cout << "Done with step 6" << std::endl; + + return unpaired(); + } + else // death + { + //std::cout << " death" << std::endl; + + auto index_chain_cmp = [this](const typename IndexChain::value_type& e1, const typename IndexChain::value_type& e2) + { return this->cmp()(e1.index(), e2.index()); }; + + // 1: change basis to clear z_row + std::sort(z_row.begin(), z_row.end(), index_chain_cmp); // this adds a log factor, but it makes life easier + Index j = z_row.front().index(); + FieldElement e = z_row.front().element(); + + if (z_row.size() > 1) + { + // figure out the columns we use for reduction + typedef typename IndexChain::const_iterator RowIterator; + std::vector reducers; + reducers.push_back(z_row.begin()); + for (RowIterator it = std::next(z_row.begin()); it != z_row.end(); ++it) + { + Index c = it->index(); + + assert(Z.col_exists(c)); + assert(Z.col_exists(reducers.back()->index())); + if (cmp()(row(Z.col(c).back()), + row(Z.col(reducers.back()->index()).back()))) + reducers.push_back(it); + } + reducers.push_back(z_row.end()); + //std::cout << "reducers.size(): " << reducers.size() << std::endl; + //std::cout << "z_row.size(): " << z_row.size() << std::endl; + + + std::map b_changes; // the rows to add to B + auto add_in_z = [this,&b_changes,&row_cmp,&index_chain_cmp](Index to, Index from, FieldElement m, FieldElement e) + { + //std::cout << " add_in_z: " << from << ' ' << to << std::endl; + + FieldElement mult = this->field().mul(m, e); + assert(Z.col_exists(to)); + assert(Z.col_exists(from)); + Chain::addto(Z.col(to), mult, Z.col(from), this->field(), row_cmp); + assert(!Z.col(to).empty()); + this->Z.fix(to); // NB: rows will be linked in the back, so the iterators are Ok + this->Z.update_low(to); + + // subtract B.row(to) from B.row(from) + IndexChain Bto_row; + for (auto& x : this->B.row(to)) + Bto_row.emplace_back(x.element(), col(x)); + std::sort(Bto_row.begin(), Bto_row.end(), index_chain_cmp); + +#if 0 + for (auto& x : this->B.row(to)) + std::cout << x.element() << ' ' << row(x) << ' ' << col(x) << std::endl; + + std::cout << "---\n"; + + for (auto& x : this->B.row(from)) + std::cout << x.element() << ' ' << row(x) << ' ' << col(x) << std::endl; +#endif + + Chain::addto(b_changes[from], this->field().neg(mult), Bto_row, this->field(), index_chain_cmp); + + // if there is b_changes[to] add it, too + auto it = b_changes.find(to); + if (it != b_changes.end()) + Chain::addto(b_changes[from], this->field().neg(mult), it->second, this->field(), index_chain_cmp); + }; + Index last_low = row(Z.col(reducers[reducers.size() - 2]->index()).back()); + for (int i = reducers.size() - 2; i >= 0; --i) + { + auto rit = reducers[i]; + FieldElement m = field().neg(field().inv(rit->element())); + + for (auto it = std::next(rit); it != reducers[i+1]; ++it) + add_in_z(it->index(), rit->index(), m, it->element()); + + if (static_cast(i + 1) != reducers.size() - 1) + { + auto it = reducers[i+1]; + add_in_z(it->index(), rit->index(), m, it->element()); + } + } + if (reducers.size() > 2) + Z.drop_low(last_low); + + // apply changes in b (the complexity here could get ugly) + // Specifically, transpose b_changes and add it in + std::unordered_map b_changes_transposed; + for (auto& b_row : b_changes) + for (auto& bx : b_row.second) + b_changes_transposed[bx.index()].emplace_back(bx.element(), b_row.first, bx.index()); + + for (auto& b_col : b_changes_transposed) + { +#if 0 + std::cout << "Adding:" << std::endl; + for (auto& x : b_col.second) + std::cout << x.element() << ' ' << row(x) << ' ' << col(x) << std::endl; +#endif + Chain::addto(B.col(b_col.first), field().id(), b_col.second, field(), b_row_cmp); + assert(!B.col(b_col.first).empty()); + B.fix(b_col.first); + // no need to update low (additions from bottom up) + } + } // z_row.size() > 1 + + // 2: subtract cycle from every chain in C + const Column& Zj = Z.col(j); + //std::cout << "Zj:" << std::endl; + //for (auto& x : Zj) + // std::cout << x.element() << " * " << row(x) << std::endl; + + IndexChain Ccols; // save the columns in C, we'll be modifying C.row(cell) + for (auto& x : C.row(cell)) + Ccols.emplace_back(x.element(), col(x)); + + for (auto& x : Ccols) + { + Index c = x.index(); + FieldElement m = field().neg(field().div(x.element(), e)); // m = -C[k][cell]/Z[j][cell] + //std::cout << "Adding to C: " << c << std::endl; + Chain::addto(C.col(c), m, Zj, field(), row_cmp); + C.fix(c); + // we don't care about lows in C, so don't update them + } + + // 3: drop + assert(Z.row(cell).size() == 1); + Z.drop_col(j); + assert(Z.row(cell).empty()); + assert(C.row(cell).empty()); + Z.drop_row(cell); + C.drop_row(cell); + assert(B.row(j).empty()); + B.drop_row(j); + + Index birth = birth_index[j]; + birth_index.erase(j); + + return birth; + } +} + + +/* debug routines */ +template +void +dionysus::ZigzagPersistence:: +check_b_cols() const +{ + // check that entries in B refer to existing Z columns + bool stop = false; + for (auto& b : B.columns()) + for (auto& x : b.second) + if (!Z.col_exists(row(x))) + { + std::cout << "B refers to a non-existent column in Z: " << row(x) << std::endl; + stop = true; + } + if (stop) + assert(0); +} + +template +template +void +dionysus::ZigzagPersistence:: +check_cycles(const SimplexToIndex& s2i, const IndexToSimplex& i2s) const +{ + typedef typename Column::value_type Entry; + auto row_cmp = [this](const Entry& e1, const Entry& e2) + { return this->cmp()(row(e1), row(e2)); }; + + for (auto& z : Z.columns()) + { + Column res; + for (auto& x : z.second) + { + Column bdry = boundary(row(x), s2i, i2s); + Chain::addto(res, x.element(), bdry, field(), row_cmp); + } + assert(res.empty()); + } +} + +template +template +void +dionysus::ZigzagPersistence:: +check_boundaries(const SimplexToIndex& s2i, const IndexToSimplex& i2s) const +{ + check_cycles(s2i, i2s); + + for (auto& x : B.columns()) + if (!C.col_exists(x.first)) + { + std::cout << x.first << " in B, but not in C" << std::endl; + assert(0); + } + + for (auto& x : C.columns()) + if (!B.col_exists(x.first)) + { + std::cout << x.first << " in B, but not in C" << std::endl; + assert(0); + } + + for (auto& x : B.columns()) + { + auto zb = zb_dot(x.first); + auto dc = dc_dot(x.first, s2i, i2s); + + auto it_zb = zb.begin(), + it_dc = dc.begin(); + for (; it_zb != zb.end(); ++it_zb, ++it_dc) + { + if (it_zb->element() != it_dc->element() || row(*it_zb) != row(*it_dc)) + { + std::cout << "Boundary mismatch: " << x.first << std::endl; + std::cout << "===" << std::endl; + for (auto& x : zb) + std::cout << " " << x.element() << ' ' << row(x) << std::endl; + for (auto& y : B.col(x.first)) + { + std::cout << " " << y.element() << " * " << row(y) << std::endl; + for (auto& z : Z.col(row(y))) + std::cout << " " << z.element() << ' ' << row(z) << std::endl; + std::cout << " ---" << std::endl; + } + std::cout << "===" << std::endl; + for (auto& x : dc) + std::cout << " " << x.element() << ' ' << row(x) << std::endl; + for (auto& y : C.col(x.first)) + { + std::cout << " " << y.element() << " * " << row(y) << std::endl; + for (auto& z : boundary(row(y), s2i, i2s)) + std::cout << " " << z.element() << ' ' << row(z) << std::endl; + std::cout << " ---" << std::endl; + } + assert(0); + } + } + if (it_zb != zb.end() || it_dc != dc.end()) + { + std::cout << "zb.end() doesn't match dc.end()" << std::endl; + assert(0); + } + } +} + +template +typename dionysus::ZigzagPersistence::Column +dionysus::ZigzagPersistence:: +zb_dot(Index c) const +{ + typedef typename Column::value_type Entry; + auto row_cmp = [this](const Entry& e1, const Entry& e2) + { return this->cmp()(row(e1), row(e2)); }; + Column res; + for (auto& x : B.col(c)) + Chain::addto(res, x.element(), Z.col(row(x)), field(), row_cmp); + + return res; +} + +template +template +typename dionysus::ZigzagPersistence::Column +dionysus::ZigzagPersistence:: +dc_dot(Index c, const SimplexToIndex& s2i, const IndexToSimplex& i2s) const +{ + typedef typename Column::value_type Entry; + auto row_cmp = [this](const Entry& e1, const Entry& e2) + { return this->cmp()(row(e1), row(e2)); }; + Column res; + for (auto& x : C.col(c)) + { + Column bdry = boundary(row(x), s2i, i2s); + Chain::addto(res, x.element(), bdry, field(), row_cmp); + } + return res; +} + +template +template +typename dionysus::ZigzagPersistence::Column +dionysus::ZigzagPersistence:: +boundary(Index i, const SimplexToIndex& s2i, const IndexToSimplex& i2s) const +{ + typedef typename Column::value_type Entry; + auto row_cmp = [this](const Entry& e1, const Entry& e2) + { return this->cmp()(row(e1), row(e2)); }; + Column bdry; + auto s = i2s(i); + for (auto y : s.boundary(field())) + bdry.emplace_back(y.element(), s2i(y.index()), 0); + std::sort(bdry.begin(), bdry.end(), row_cmp); + return bdry; +} + +template +void +dionysus::ZigzagPersistence:: +check_sorted() const +{ + typedef typename Column::value_type Entry; + auto row_cmp = [this](const Entry& e1, const Entry& e2) + { return this->cmp()(row(e1), row(e2)); }; + typedef typename DequeColumn::value_type DequeEntry; + auto b_row_cmp = [this](const DequeEntry& e1, const DequeEntry& e2) + { return this->cmp()(row(e1), row(e2)); }; + + for (auto& x : Z.columns()) + if (!std::is_sorted(x.second.begin(), x.second.end(), row_cmp)) + { + std::cout << "Z column not sorted: " << x.first << std::endl; + assert(0); + } + for (auto& x : C.columns()) + if (!std::is_sorted(x.second.begin(), x.second.end(), row_cmp)) + { + std::cout << "C column not sorted: " << x.first << std::endl; + assert(0); + } + for (auto& x : B.columns()) + if (!std::is_sorted(x.second.begin(), x.second.end(), b_row_cmp)) + { + std::cout << "B column not sorted: " << x.first << std::endl; + assert(0); + } +} + diff --git a/src/Zigzag_persistence/example/ext_zz/fzz/fzz.cpp b/src/Zigzag_persistence/example/ext_zz/fzz/fzz.cpp new file mode 100644 index 0000000000..5217a4f38c --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/fzz/fzz.cpp @@ -0,0 +1,206 @@ +#include "fzz.h" + +#include + +// phat headers +// wrapper algorithm that computes the persistence pairs of a given boundary matrix using a specified algorithm +#include + +// main data structure (choice affects performance) +#include +#include + +// algorithm (choice affects performance) +#include +#include +#include +#include + +namespace FZZ { + +template +class VecHash { +public: + size_t operator()(const std::vector& v) const; +}; + +template +size_t VecHash + ::operator()(const std::vector& v) const { + + std::size_t seed = 0; + + for (auto e : v) { boost::hash_combine(seed, e); } + + return seed; +} + +template +class VecEqual { +public: + bool operator()(const std::vector& v1, + const std::vector& v2) const; +}; + +template +bool VecEqual + ::operator()(const std::vector& v1, + const std::vector& v2) const { + + if (v1.size() != v2.size()) { return false; } + + for (unsigned int i = 0; i < v1.size(); i ++) { + if (v1[i] != v2[i]) { + return false; + } + } + + return true; +} + +typedef std::unordered_map< Simplex, Integer, + VecHash, VecEqual > SimplexIdMap; + +void getBoundaryChainPhat(const std::vector &id_maps, + const Simplex &simp, std::vector &bound_c) { + + bound_c.clear(); + + if (simp.size() <= 1) { return; } + + bound_c.reserve(simp.size()); + + Simplex bound_simp(simp.begin()+1, simp.end()); + bound_c.push_back(id_maps.at(bound_simp.size() - 1).at(bound_simp)); + + for (unsigned int i = 0; i < simp.size()-1; ++i) { + bound_simp[i] = simp[i]; + bound_c.push_back(id_maps.at(bound_simp.size() - 1).at(bound_simp)); + } + + std::sort(bound_c.begin(), bound_c.end()); +} + +inline Integer getDim(const std::vector &bound_c) { + if (bound_c.size() == 0) { return 0; } + return bound_c.size() - 1; +} + +void FastZigzag::compute(const std::vector &filt_simp, + const std::vector &filt_op, + std::vector< std::tuple > *persistence) { + + orig_f_add_id.clear(); + orig_f_del_id.clear(); + persistence->clear(); + + simp_num = 0; + Integer max_dim = 0; + for (unsigned int i = 0; i < filt_op.size(); ++i) { + if (filt_op[i]) { + ++simp_num; + if (static_cast(filt_simp[i].size()) - 1 > max_dim) { max_dim = filt_simp[i].size() - 1; } + } + } + + std::vector bound_c; + // phat::boundary_matrix< phat::vector_vector > bound_chains; + phat::boundary_matrix< phat::bit_tree_pivot_column > bound_chains; + bound_chains.set_num_cols(simp_num * 2 + 1); + + // Add the Omega vertex for the coning + bound_chains.set_col(0, bound_c); + bound_chains.set_dim(0, 0); + + orig_f_add_id.reserve(simp_num); + orig_f_del_id.reserve(simp_num); + + std::vector del_ids; + del_ids.reserve(simp_num); + + std::vector *p_id_maps = new std::vector(max_dim+1); + std::vector &id_maps = *p_id_maps; + + Integer orig_f_id = 0; + Integer s_id = 1; + + for (unsigned int i = 0; i < filt_simp.size(); ++i) { + const Simplex &simp = filt_simp[i]; + + if (filt_op[i]) { + getBoundaryChainPhat(id_maps, simp, bound_c); + bound_chains.set_col(s_id, bound_c); + bound_chains.set_dim(s_id, getDim(bound_c)); + + // assert(s_id == bound_chains.size()-1); + id_maps.at(simp.size() - 1)[simp] = s_id; + orig_f_add_id.push_back(orig_f_id); + s_id ++; + } else { + del_ids.push_back(id_maps.at(simp.size() - 1)[simp]); + id_maps.at(simp.size() - 1).erase(simp); + orig_f_del_id.push_back(orig_f_id); + } + + orig_f_id ++; + } + + for (Integer i = id_maps.size() - 1; i >= 0; -- i) { + for (const auto &it : id_maps.at(i)) { + del_ids.push_back(it.second); + orig_f_del_id.push_back(orig_f_id); + orig_f_id ++; + } + } + + assert(del_ids.size() == s_id-1); + delete p_id_maps; + + assert(simp_num == del_ids.size()); + + std::vector cone_sid(simp_num+1); + + for (auto del_id_it = del_ids.rbegin(); del_id_it != del_ids.rend(); ++del_id_it) { + bound_c.clear(); + bound_c.push_back(*del_id_it); + + std::vector orig_bound_c; + bound_chains.get_col(*del_id_it, orig_bound_c); + + if (orig_bound_c.size() == 0) { + bound_c.push_back(0); + } else { + for (auto bsimp : orig_bound_c) { + // assert(cone_sid[bsimp] >= 0); + bound_c.push_back(cone_sid[bsimp]); + } + } + + std::sort(bound_c.begin(), bound_c.end()); + + bound_chains.set_col(s_id, bound_c); + bound_chains.set_dim(s_id, getDim(bound_c)); + + cone_sid[*del_id_it] = s_id; + + s_id ++; + } + + phat::persistence_pairs pairs; + phat::compute_persistence_pairs< phat::twist_reduction >( pairs, bound_chains ); + + for (phat::index idx = 0; idx < pairs.get_num_pairs(); idx++) { + Integer b = pairs.get_pair(idx).first; + Integer d = pairs.get_pair(idx).second - 1; + Integer p = bound_chains.get_dim(b); + + if (d < simp_num) { mapOrdIntv(b, d); } + else { mapRelExtIntv(p, b, d); } + + if (b > static_cast(filt_simp.size())) { continue; } + if (d > static_cast(filt_simp.size())) { d = filt_simp.size(); } + persistence->emplace_back(b, d, p); + } +} + +} // namespace FZZ { diff --git a/src/Zigzag_persistence/example/ext_zz/fzz/fzz.h b/src/Zigzag_persistence/example/ext_zz/fzz/fzz.h new file mode 100644 index 0000000000..8613bc3793 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/fzz/fzz.h @@ -0,0 +1,87 @@ +#ifndef _FZZ_H_ +#define _FZZ_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace FZZ { + +typedef int Integer; +typedef std::vector Simplex; + +class FastZigzag { +public: + /* + 'filt_simp' and 'filt_op' should have the same length which altogether + specify the input zigzag filtration. 'filt_simp' specifies the simplices + being added or deleted (following the order of the filtration) and + 'filt_op' specifies whether it's an addition (true) or deletion (false). + 'persistence' returns the barcode, with the first element of the tuple + being the birth, the second element being the death, and the third + being the dimension. + */ + void compute( + const std::vector &filt_simp, + const std::vector &filt_op, + std::vector< std::tuple > *persistence); + +private: + void mapOrdIntv(Integer &b, Integer &d) { + // assert(b-1 > 0); + // assert(d < orig_f_add_id.size()); + + // Up-down interval is same, + // so directly map to interval of input filtration + b = orig_f_add_id[b-1] + 1; + d = orig_f_add_id[d]; + } + + void mapRelExtIntv(Integer &p, Integer &b, Integer &d) { + // assert(d >= simp_num); + + if (b > simp_num) { // Open-closed + // Map to up-down interval + std::swap(b, d); + b = 3*simp_num - b; + d = 3*simp_num - d; + p --; + + // Map to interval of input filtration + b = orig_f_del_id[b-1-simp_num] + 1; + d = orig_f_del_id[d-simp_num]; + } else { // Closed-closed + // Map to up-down interval + d = 3*simp_num - d-1; + + // Map to interval of input filtration + b = orig_f_add_id[b-1]; + d = orig_f_del_id[d-simp_num]; + + if (b < d) { + b = b+1; + } else { + std::swap(b, d); + b = b+1; + p = p-1; + } + } + } + +private: + // 'orig_f_add_id' and 'orig_f_del_id' form a mapping + // from the up-down filtration to the original filtration + std::vector orig_f_add_id; + std::vector orig_f_del_id; + + Integer simp_num; +}; + +} + +#endif diff --git a/src/Zigzag_persistence/example/ext_zz/phat/algorithms/chunk_reduction.h b/src/Zigzag_persistence/example/ext_zz/phat/algorithms/chunk_reduction.h new file mode 100644 index 0000000000..179702312f --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/algorithms/chunk_reduction.h @@ -0,0 +1,223 @@ +/* Copyright 2013 IST Austria + Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +#include +#include + +namespace phat { + class chunk_reduction { + public: + enum column_type { GLOBAL + , LOCAL_POSITIVE + , LOCAL_NEGATIVE }; + + public: + template< typename Representation > + void operator() ( boundary_matrix< Representation >& boundary_matrix ) { + + + const index nr_columns = boundary_matrix.get_num_cols(); + if( omp_get_max_threads( ) > nr_columns ) + omp_set_num_threads( 1 ); + + const dimension max_dim = boundary_matrix.get_max_dim(); + + std::vector< index > lowest_one_lookup( nr_columns, -1 ); + std::vector < column_type > column_type( nr_columns, GLOBAL ); + std::vector< char > is_active( nr_columns, false ); + + const index chunk_size = omp_get_max_threads() == 1 ? (index)sqrt( (double)nr_columns ) : nr_columns / omp_get_max_threads(); + + std::vector< index > chunk_boundaries; + for( index cur_boundary = 0; cur_boundary < nr_columns; cur_boundary += chunk_size ) + chunk_boundaries.push_back( cur_boundary ); + chunk_boundaries.push_back( nr_columns ); + + for( dimension cur_dim = max_dim; cur_dim >= 1; cur_dim-- ) { + // Phase 1: Reduce chunks locally -- 1st pass + #pragma omp parallel for schedule( guided, 1 ) + for( index chunk_id = 0; chunk_id < (index)chunk_boundaries.size() - 1; chunk_id++ ) + _local_chunk_reduction( boundary_matrix, lowest_one_lookup, column_type, cur_dim, + chunk_boundaries[ chunk_id ], chunk_boundaries[ chunk_id + 1 ], chunk_boundaries[ chunk_id ] ); + boundary_matrix.sync(); + + // Phase 1: Reduce chunks locally -- 2nd pass + #pragma omp parallel for schedule( guided, 1 ) + for( index chunk_id = 1; chunk_id < (index)chunk_boundaries.size( ) - 1; chunk_id++ ) + _local_chunk_reduction( boundary_matrix, lowest_one_lookup, column_type, cur_dim, + chunk_boundaries[ chunk_id ], chunk_boundaries[ chunk_id + 1 ], chunk_boundaries[ chunk_id - 1 ] ); + boundary_matrix.sync( ); + } + + // get global columns + std::vector< index > global_columns; + for( index cur_col_idx = 0; cur_col_idx < nr_columns; cur_col_idx++ ) + if( column_type[ cur_col_idx ] == GLOBAL ) + global_columns.push_back( cur_col_idx ); + + // get active columns + #pragma omp parallel for + for( index idx = 0; idx < (index)global_columns.size(); idx++ ) + is_active[ global_columns[ idx ] ] = true; + _get_active_columns( boundary_matrix, lowest_one_lookup, column_type, global_columns, is_active ); + + // Phase 2+3: Simplify columns and reduce them + for( dimension cur_dim = max_dim; cur_dim >= 1; cur_dim-- ) { + // Phase 2: Simplify columns + std::vector< index > temp_col; + #pragma omp parallel for schedule( guided, 1 ), private( temp_col ) + for( index idx = 0; idx < (index)global_columns.size(); idx++ ) + if( boundary_matrix.get_dim( global_columns[ idx ] ) == cur_dim ) + _global_column_simplification( global_columns[ idx ], boundary_matrix, lowest_one_lookup, column_type, is_active, temp_col ); + boundary_matrix.sync(); + + // Phase 3: Reduce columns + for( index idx = 0; idx < (index)global_columns.size(); idx++ ) { + index cur_col = global_columns[ idx ]; + if( boundary_matrix.get_dim( cur_col ) == cur_dim && column_type[ cur_col ] == GLOBAL ) { + index lowest_one = boundary_matrix.get_max_index( cur_col ); + while( lowest_one != -1 && lowest_one_lookup[ lowest_one ] != -1 ) { + boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col ); + lowest_one = boundary_matrix.get_max_index( cur_col ); + } + if( lowest_one != -1 ) { + lowest_one_lookup[ lowest_one ] = cur_col; + boundary_matrix.clear( lowest_one ); + } + boundary_matrix.finalize( cur_col ); + } + } + } + + boundary_matrix.sync(); + } + + protected: + template< typename Representation > + void _local_chunk_reduction( boundary_matrix< Representation >& boundary_matrix + , std::vector& lowest_one_lookup + , std::vector< column_type >& column_type + , const dimension cur_dim + , const index chunk_begin + , const index chunk_end + , const index row_begin ) { + + for( index cur_col = chunk_begin; cur_col < chunk_end; cur_col++ ) { + if( column_type[ cur_col ] == GLOBAL && boundary_matrix.get_dim( cur_col ) == cur_dim ) { + index lowest_one = boundary_matrix.get_max_index( cur_col ); + while( lowest_one != -1 && lowest_one >= row_begin && lowest_one_lookup[ lowest_one ] != -1 ) { + boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col ); + lowest_one = boundary_matrix.get_max_index( cur_col ); + } + if( lowest_one >= row_begin ) { + lowest_one_lookup[ lowest_one ] = cur_col; + column_type[ cur_col ] = LOCAL_NEGATIVE; + column_type[ lowest_one ] = LOCAL_POSITIVE; + boundary_matrix.clear( lowest_one ); + boundary_matrix.finalize( cur_col ); + } + } + } + } + + template< typename Representation > + void _get_active_columns( const boundary_matrix< Representation >& boundary_matrix + , const std::vector< index >& lowest_one_lookup + , const std::vector< column_type >& column_type + , const std::vector< index >& global_columns + , std::vector< char >& is_active ) { + + const index nr_columns = boundary_matrix.get_num_cols(); + std::vector< char > finished( nr_columns, false ); + + std::vector< std::pair < index, index > > stack; + std::vector< index > cur_col_values; + #pragma omp parallel for schedule( guided, 1 ), private( stack, cur_col_values ) + for( index idx = 0; idx < (index)global_columns.size(); idx++ ) { + bool pop_next = false; + index start_col = global_columns[ idx ]; + stack.push_back( std::pair< index, index >( start_col, -1 ) ); + while( !stack.empty() ) { + index cur_col = stack.back().first; + index prev_col = stack.back().second; + if( pop_next ) { + stack.pop_back(); + pop_next = false; + if( prev_col != -1 ) { + if( is_active[ cur_col ] ) { + is_active[ prev_col ] = true; + } + if( prev_col == stack.back().first ) { + finished[ prev_col ] = true; + pop_next = true; + } + } + } else { + pop_next = true; + boundary_matrix.get_col( cur_col, cur_col_values ); + for( index idx = 0; idx < (index) cur_col_values.size(); idx++ ) { + index cur_row = cur_col_values[ idx ]; + if( ( column_type[ cur_row ] == GLOBAL ) ) { + is_active[ cur_col ] = true; + } else if( column_type[ cur_row ] == LOCAL_POSITIVE ) { + index next_col = lowest_one_lookup[ cur_row ]; + if( next_col != cur_col && !finished[ cur_col ] ) { + stack.push_back( std::make_pair( next_col, cur_col ) ); + pop_next = false; + } + } + } + } + } + } + } + + template< typename Representation > + void _global_column_simplification( const index col_idx + , boundary_matrix< Representation >& boundary_matrix + , const std::vector< index >& lowest_one_lookup + , const std::vector< column_type >& column_type + , const std::vector< char >& is_active + , std::vector< index >& temp_col ) + { + temp_col.clear(); + while( !boundary_matrix.is_empty( col_idx ) ) { + index cur_row = boundary_matrix.get_max_index( col_idx ); + switch( column_type[ cur_row ] ) { + case GLOBAL: + temp_col.push_back( cur_row ); + boundary_matrix.remove_max( col_idx ); + break; + case LOCAL_NEGATIVE: + boundary_matrix.remove_max( col_idx ); + break; + case LOCAL_POSITIVE: + if( is_active[ lowest_one_lookup[ cur_row ] ] ) + boundary_matrix.add_to( lowest_one_lookup[ cur_row ], col_idx ); + else + boundary_matrix.remove_max( col_idx ); + break; + } + } + std::reverse( temp_col.begin(), temp_col.end() ); + boundary_matrix.set_col( col_idx, temp_col ); + } + }; +} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/algorithms/row_reduction.h b/src/Zigzag_persistence/example/ext_zz/phat/algorithms/row_reduction.h new file mode 100644 index 0000000000..cdd1a8fd18 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/algorithms/row_reduction.h @@ -0,0 +1,56 @@ +/* Copyright 2013 IST Austria + Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +#include +#include + +namespace phat { + class row_reduction { + public: + template< typename Representation > + void operator() ( boundary_matrix< Representation >& boundary_matrix ) { + + const index nr_columns = boundary_matrix.get_num_cols(); + std::vector< std::vector< index > > lowest_one_lookup( nr_columns ); + + for( index cur_col = nr_columns - 1; cur_col >= 0; cur_col-- ) { + if( !boundary_matrix.is_empty( cur_col ) ) + lowest_one_lookup[ boundary_matrix.get_max_index( cur_col ) ].push_back( cur_col ); + + if( !lowest_one_lookup[ cur_col ].empty() ) { + boundary_matrix.clear( cur_col ); + boundary_matrix.finalize( cur_col ); + std::vector< index >& cols_with_cur_lowest = lowest_one_lookup[ cur_col ]; + index source = *min_element( cols_with_cur_lowest.begin(), cols_with_cur_lowest.end() ); + for( index idx = 0; idx < (index)cols_with_cur_lowest.size(); idx++ ) { + index target = cols_with_cur_lowest[ idx ]; + if( target != source && !boundary_matrix.is_empty( target ) ) { + boundary_matrix.add_to( source, target ); + if( !boundary_matrix.is_empty( target ) ) { + index lowest_one_of_target = boundary_matrix.get_max_index( target ); + lowest_one_lookup[ lowest_one_of_target ].push_back( target ); + } + } + } + } + } + } + }; +} \ No newline at end of file diff --git a/src/Zigzag_persistence/example/ext_zz/phat/algorithms/spectral_sequence_reduction.h b/src/Zigzag_persistence/example/ext_zz/phat/algorithms/spectral_sequence_reduction.h new file mode 100644 index 0000000000..bf442e6089 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/algorithms/spectral_sequence_reduction.h @@ -0,0 +1,80 @@ +/* Copyright 2013 IST Austria + Contributed by: Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +#include +#include + +namespace phat { + class spectral_sequence_reduction { + public: + template< typename Representation > + void operator () ( boundary_matrix< Representation >& boundary_matrix ) { + + const index nr_columns = boundary_matrix.get_num_cols(); + std::vector< index > lowest_one_lookup( nr_columns, -1 ); + + //const index num_stripes = (index) sqrt( (double)nr_columns ); + const index num_stripes = omp_get_max_threads(); + + index block_size = ( nr_columns % num_stripes == 0 ) ? nr_columns / num_stripes : block_size = nr_columns / num_stripes + 1; + + std::vector< std::vector< index > > unreduced_cols_cur_pass( num_stripes ); + std::vector< std::vector< index > > unreduced_cols_next_pass( num_stripes ); + + for( index cur_dim = boundary_matrix.get_max_dim(); cur_dim >= 1 ; cur_dim-- ) { + #pragma omp parallel for schedule( guided, 1 ) + for( index cur_stripe = 0; cur_stripe < num_stripes; cur_stripe++ ) { + index col_begin = cur_stripe * block_size; + index col_end = std::min( (cur_stripe+1) * block_size, nr_columns ); + for( index cur_col = col_begin; cur_col < col_end; cur_col++ ) + if( boundary_matrix.get_dim( cur_col ) == cur_dim && boundary_matrix.get_max_index( cur_col ) != -1 ) + unreduced_cols_cur_pass[ cur_stripe ].push_back( cur_col ); + } + for( index cur_pass = 0; cur_pass < num_stripes; cur_pass++ ) { + boundary_matrix.sync(); + #pragma omp parallel for schedule( guided, 1 ) + for( int cur_stripe = 0; cur_stripe < num_stripes; cur_stripe++ ) { + index row_begin = (cur_stripe - cur_pass) * block_size; + index row_end = row_begin + block_size; + unreduced_cols_next_pass[ cur_stripe ].clear(); + for( index idx = 0; idx < (index)unreduced_cols_cur_pass[ cur_stripe ].size(); idx++ ) { + index cur_col = unreduced_cols_cur_pass[ cur_stripe ][ idx ]; + index lowest_one = boundary_matrix.get_max_index( cur_col ); + while( lowest_one != -1 && lowest_one >= row_begin && lowest_one < row_end && lowest_one_lookup[ lowest_one ] != -1 ) { + boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col ); + lowest_one = boundary_matrix.get_max_index( cur_col ); + } + if( lowest_one != -1 ) { + if( lowest_one >= row_begin && lowest_one < row_end ) { + lowest_one_lookup[ lowest_one ] = cur_col; + boundary_matrix.clear( lowest_one ); + boundary_matrix.finalize( cur_col ); + } else { + unreduced_cols_next_pass[ cur_stripe ].push_back( cur_col ); + } + } + } + unreduced_cols_next_pass[ cur_stripe ].swap( unreduced_cols_cur_pass[ cur_stripe ] ); + } + } + } + } + }; +} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/algorithms/standard_reduction.h b/src/Zigzag_persistence/example/ext_zz/phat/algorithms/standard_reduction.h new file mode 100644 index 0000000000..e490a5e0d1 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/algorithms/standard_reduction.h @@ -0,0 +1,47 @@ +/* Copyright 2013 IST Austria + Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +#include +#include + +namespace phat { + class standard_reduction { + public: + template< typename Representation > + void operator() ( boundary_matrix< Representation >& boundary_matrix ) { + + const index nr_columns = boundary_matrix.get_num_cols(); + std::vector< index > lowest_one_lookup( nr_columns, -1 ); + + for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) { + index lowest_one = boundary_matrix.get_max_index( cur_col ); + while( lowest_one != -1 && lowest_one_lookup[ lowest_one ] != -1 ) { + boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col ); + lowest_one = boundary_matrix.get_max_index( cur_col ); + } + if( lowest_one != -1 ) { + lowest_one_lookup[ lowest_one ] = cur_col; + } + boundary_matrix.finalize( cur_col ); + } + } + }; +} + diff --git a/src/Zigzag_persistence/example/ext_zz/phat/algorithms/twist_reduction.h b/src/Zigzag_persistence/example/ext_zz/phat/algorithms/twist_reduction.h new file mode 100644 index 0000000000..2357df0256 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/algorithms/twist_reduction.h @@ -0,0 +1,51 @@ +/* Copyright 2013 IST Austria + Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +#include +#include + +namespace phat { + class twist_reduction { + public: + template< typename Representation > + void operator () ( boundary_matrix< Representation >& boundary_matrix ) { + + const index nr_columns = boundary_matrix.get_num_cols(); + std::vector< index > lowest_one_lookup( nr_columns, -1 ); + + for( index cur_dim = boundary_matrix.get_max_dim(); cur_dim >= 1 ; cur_dim-- ) { + for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) { + if( boundary_matrix.get_dim( cur_col ) == cur_dim ) { + index lowest_one = boundary_matrix.get_max_index( cur_col ); + while( lowest_one != -1 && lowest_one_lookup[ lowest_one ] != -1 ) { + boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col ); + lowest_one = boundary_matrix.get_max_index( cur_col ); + } + if( lowest_one != -1 ) { + lowest_one_lookup[ lowest_one ] = cur_col; + boundary_matrix.clear( lowest_one ); + } + boundary_matrix.finalize( cur_col ); + } + } + } + } + }; +} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/boundary_matrix.h b/src/Zigzag_persistence/example/ext_zz/phat/boundary_matrix.h new file mode 100644 index 0000000000..10c66cca13 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/boundary_matrix.h @@ -0,0 +1,343 @@ +/* Copyright 2013 IST Austria + Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +#include +#include + +// interface class for the main data structure -- implementations of the interface can be found in ./representations +namespace phat { + template< class Representation = bit_tree_pivot_column > + class boundary_matrix + { + + protected: + Representation rep; + + // interface functions -- actual implementation and complexity depends on chosen @Representation template + public: + // get overall number of columns in boundary_matrix + index get_num_cols() const { return rep._get_num_cols(); } + + // set overall number of columns in boundary_matrix + void set_num_cols( index nr_of_columns ) { rep._set_num_cols( nr_of_columns ); } + + // get dimension of given index + dimension get_dim( index idx ) const { return rep._get_dim( idx ); } + + // set dimension of given index + void set_dim( index idx, dimension dim ) { rep._set_dim( idx, dim ); } + + // replaces content of @col with boundary of given index + void get_col( index idx, column& col ) const { col.clear(); rep._get_col( idx, col ); } + + // set column @idx to the values contained in @col + void set_col( index idx, const column& col ) { rep._set_col( idx, col ); } + + // true iff boundary of given column is empty + bool is_empty( index idx ) const { return rep._is_empty( idx ); } + + // largest index of given column (new name for lowestOne()) -- NOT thread-safe + index get_max_index( index idx ) const { return rep._get_max_index( idx ); } + + // removes maximal index from given column + void remove_max( index idx ) { rep._remove_max( idx ); } + + // adds column @source to column @target' + void add_to( index source, index target ) { rep._add_to( source, target ); } + + // clears given column + void clear( index idx ) { rep._clear( idx ); } + + // finalizes given column + void finalize( index idx ) { rep._finalize( idx ); } + + // syncronizes all internal data structures -- has to be called before and after any multithreaded access! + void sync() { rep._sync(); } + + // info functions -- independent of chosen 'Representation' + public: + // maximal dimension + dimension get_max_dim() const { + dimension cur_max_dim = 0; + for( index idx = 0; idx < get_num_cols(); idx++ ) + cur_max_dim = get_dim( idx ) > cur_max_dim ? get_dim( idx ) : cur_max_dim; + return cur_max_dim; + } + + // number of nonzero rows for given column @idx + index get_num_rows( index idx ) const { + column cur_col; + get_col( idx, cur_col ); + return cur_col.size(); + } + + // maximal number of nonzero rows of all columns + index get_max_col_entries() const { + index max_col_entries = -1; + const index nr_of_columns = get_num_cols(); + for( index idx = 0; idx < nr_of_columns; idx++ ) + max_col_entries = get_num_rows( idx ) > max_col_entries ? get_num_rows( idx ) : max_col_entries; + return max_col_entries; + } + + // maximal number of nonzero cols of all rows + index get_max_row_entries() const { + size_t max_row_entries = 0; + const index nr_of_columns = get_num_cols(); + std::vector< std::vector< index > > transposed_matrix( nr_of_columns ); + column temp_col; + for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) { + get_col( cur_col, temp_col ); + for( index idx = 0; idx < (index)temp_col.size(); idx++) + transposed_matrix[ temp_col[ idx ] ].push_back( cur_col ); + } + for( index idx = 0; idx < nr_of_columns; idx++ ) + max_row_entries = transposed_matrix[ idx ].size() > max_row_entries ? transposed_matrix[ idx ].size() : max_row_entries; + return max_row_entries; + } + + // overall number of entries in the matrix + index get_num_entries() const { + index number_of_nonzero_entries = 0; + const index nr_of_columns = get_num_cols(); + for( index idx = 0; idx < nr_of_columns; idx++ ) + number_of_nonzero_entries += get_num_rows( idx ); + return number_of_nonzero_entries; + } + + // operators / constructors + public: + boundary_matrix() {}; + + template< class OtherRepresentation > + boundary_matrix( const boundary_matrix< OtherRepresentation >& other ) { + *this = other; + } + + template< typename OtherRepresentation > + bool operator==( const boundary_matrix< OtherRepresentation >& other_boundary_matrix ) const { + const index number_of_columns = this->get_num_cols(); + + if( number_of_columns != other_boundary_matrix.get_num_cols() ) + return false; + + column temp_col; + column other_temp_col; + for( index idx = 0; idx < number_of_columns; idx++ ) { + this->get_col( idx, temp_col ); + other_boundary_matrix.get_col( idx, other_temp_col ); + if( temp_col != other_temp_col || this->get_dim( idx ) != other_boundary_matrix.get_dim( idx ) ) + return false; + } + return true; + } + + template< typename OtherRepresentation > + bool operator!=( const boundary_matrix< OtherRepresentation >& other_boundary_matrix ) const { + return !( *this == other_boundary_matrix ); + } + + template< typename OtherRepresentation > + boundary_matrix< Representation >& operator=( const boundary_matrix< OtherRepresentation >& other ) + { + const index nr_of_columns = other.get_num_cols(); + this->set_num_cols( nr_of_columns ); + column temp_col; + for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) { + this->set_dim( cur_col, other.get_dim( cur_col ) ); + other.get_col( cur_col, temp_col ); + this->set_col( cur_col, temp_col ); + } + + // by convention, always return *this + return *this; + } + + // I/O -- independent of chosen 'Representation' + public: + + // initializes boundary_matrix from (vector, vector) pair -- untested + template< typename index_type, typename dimemsion_type > + void load_vector_vector( const std::vector< std::vector< index_type > >& input_matrix, const std::vector< dimemsion_type >& input_dims ) { + const index nr_of_columns = (index)input_matrix.size(); + this->set_num_cols( nr_of_columns ); + column temp_col; + #pragma omp parallel for private( temp_col ) + for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) { + this->set_dim( cur_col, (dimension)input_dims[ cur_col ] ); + + index num_rows = input_matrix[ cur_col ].size(); + temp_col.resize( num_rows ); + for( index cur_row = 0; cur_row < num_rows; cur_row++ ) + temp_col[ cur_row ] = (index)input_matrix[ cur_col ][ cur_row ]; + this->set_col( cur_col, temp_col ); + } + } + + template< typename index_type, typename dimemsion_type > + void save_vector_vector( std::vector< std::vector< index_type > >& output_matrix, std::vector< dimemsion_type >& output_dims ) { + const index nr_of_columns = get_num_cols(); + output_matrix.resize( nr_of_columns ); + output_dims.resize( nr_of_columns ); + column temp_col; + for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) { + output_dims[ cur_col ] = (dimemsion_type)get_dim( cur_col ); + get_col( cur_col, temp_col ); + index num_rows = temp_col.size(); + output_matrix[ cur_col ].clear(); + output_matrix[ cur_col ].resize( num_rows ); + for( index cur_row = 0; cur_row < num_rows; cur_row++ ) + output_matrix[ cur_col ][ cur_row ] = (index_type)temp_col[ cur_row ]; + } + } + + + // Loads the boundary_matrix from given file in ascii format + // Format: each line represents a column, first number is dimension, other numbers are the content of the column. + // Ignores empty lines and lines starting with a '#'. + bool load_ascii( std::string filename ) { + // first count number of columns: + std::string cur_line; + std::ifstream dummy( filename .c_str() ); + if( dummy.fail() ) + return false; + + index number_of_columns = 0; + while( getline( dummy, cur_line ) ) { + cur_line.erase(cur_line.find_last_not_of(" \t\n\r\f\v") + 1); + if( cur_line != "" && cur_line[ 0 ] != '#' ) + number_of_columns++; + + } + this->set_num_cols( number_of_columns ); + dummy.close(); + + std::ifstream input_stream( filename.c_str() ); + if( input_stream.fail() ) + return false; + + column temp_col; + index cur_col = -1; + while( getline( input_stream, cur_line ) ) { + cur_line.erase(cur_line.find_last_not_of(" \t\n\r\f\v") + 1); + if( cur_line != "" && cur_line[ 0 ] != '#' ) { + cur_col++; + std::stringstream ss( cur_line ); + + int64_t temp_dim; + ss >> temp_dim; + this->set_dim( cur_col, (dimension) temp_dim ); + + int64_t temp_index; + temp_col.clear(); + while( ss.good() ) { + ss >> temp_index; + temp_col.push_back( (index)temp_index ); + } + std::sort( temp_col.begin(), temp_col.end() ); + this->set_col( cur_col, temp_col ); + } + } + + input_stream.close(); + return true; + } + + // Saves the boundary_matrix to given file in ascii format + // Format: each line represents a column, first number is dimension, other numbers are the content of the column + bool save_ascii( std::string filename ) { + std::ofstream output_stream( filename.c_str() ); + if( output_stream.fail() ) + return false; + + const index nr_columns = this->get_num_cols(); + column tempCol; + for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) { + output_stream << (int64_t)this->get_dim( cur_col ); + this->get_col( cur_col, tempCol ); + for( index cur_row_idx = 0; cur_row_idx < (index)tempCol.size(); cur_row_idx++ ) + output_stream << " " << tempCol[ cur_row_idx ]; + output_stream << std::endl; + } + + output_stream.close(); + return true; + } + + // Loads boundary_matrix from given file + // Format: nr_columns % dim1 % N1 % row1 row2 % ...% rowN1 % dim2 % N2 % ... + bool load_binary( std::string filename ) + { + std::ifstream input_stream( filename.c_str( ), std::ios_base::binary | std::ios_base::in ); + if( input_stream.fail( ) ) + return false; + + int64_t nr_columns; + input_stream.read( (char*)&nr_columns, sizeof( int64_t ) ); + this->set_num_cols( (index)nr_columns ); + + column temp_col; + for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) { + int64_t cur_dim; + input_stream.read( (char*)&cur_dim, sizeof( int64_t ) ); + this->set_dim( cur_col, (dimension)cur_dim ); + int64_t nr_rows; + input_stream.read( (char*)&nr_rows, sizeof( int64_t ) ); + temp_col.resize( ( std::size_t )nr_rows ); + for( index idx = 0; idx < nr_rows; idx++ ) { + int64_t cur_row; + input_stream.read( (char*)&cur_row, sizeof( int64_t ) ); + temp_col[ idx ] = (index)cur_row; + } + this->set_col( cur_col, temp_col ); + } + + input_stream.close( ); + return true; + } + + // Saves the boundary_matrix to given file in binary format + // Format: nr_columns % dim1 % N1 % row1 row2 % ...% rowN1 % dim2 % N2 % ... + bool save_binary( std::string filename ) + { + std::ofstream output_stream( filename.c_str( ), std::ios_base::binary | std::ios_base::out ); + if( output_stream.fail( ) ) + return false; + + const int64_t nr_columns = this->get_num_cols( ); + output_stream.write( (char*)&nr_columns, sizeof( int64_t ) ); + column tempCol; + for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) { + int64_t cur_dim = this->get_dim( cur_col ); + output_stream.write( (char*)&cur_dim, sizeof( int64_t ) ); + this->get_col( cur_col, tempCol ); + int64_t cur_nr_rows = tempCol.size( ); + output_stream.write( (char*)&cur_nr_rows, sizeof( int64_t ) ); + for( index cur_row_idx = 0; cur_row_idx < (index)tempCol.size( ); cur_row_idx++ ) { + int64_t cur_row = tempCol[ cur_row_idx ]; + output_stream.write( (char*)&cur_row, sizeof( int64_t ) ); + } + } + + output_stream.close( ); + return true; + } + }; +} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/compute_persistence_pairs.h b/src/Zigzag_persistence/example/ext_zz/phat/compute_persistence_pairs.h new file mode 100644 index 0000000000..48be65c28e --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/compute_persistence_pairs.h @@ -0,0 +1,128 @@ +/* Copyright 2013 IST Austria + Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +#include +#include +#include +#include + +namespace phat { + // Extracts persistence pairs in separate dimensions from a reduced + // boundary matrix representing ``double`` filtration. The pairs + // give persistent relative homology of the pair of filtrations. + // TODO: Use it with standard reduction algorithm (no template option). + template< typename ReductionAlgorithm, typename Representation > + void compute_relative_persistence_pairs(std::vector& pairs, boundary_matrix& boundary_matrix, const std::map& L) { + ReductionAlgorithm reduce; + reduce(boundary_matrix); + std::map free; + std::map invL; + for (std::map::const_iterator it = L.begin(); it != L.end(); ++it) { invL[it->second] = it->first; } + for (std::vector::iterator it = pairs.begin(); it != pairs.end(); ++it) { it->clear(); } + for (index idx = 0; idx < boundary_matrix.get_num_cols(); ++idx) { + int dimension = boundary_matrix.get_dim(idx); + if (L.find(idx) != L.end()) { ++dimension; } + free[idx] = true; + if (!boundary_matrix.is_empty(idx)) { + index birth = boundary_matrix.get_max_index(idx); + index death = idx; + pairs[dimension-1].append_pair(birth, death); + free[birth] = false; + free[death] = false; + } else { + // This is an L-simplex and a (dimension+1)-dimensional cycle + if (L.find(idx) != L.end()) { + assert(dimension < pairs.size()); + pairs[dimension].append_pair(idx, -1); + } + } + } + for (std::map::iterator it = free.begin(); it != free.end(); ++it) { + if (it->second) { + int dimension = boundary_matrix.get_dim(it->first); + if (invL.find(it->first) == invL.end() && L.find(it->first) == L.end()) { + assert(dimension < pairs.size()); + pairs[dimension].append_pair(it->first, -1); + } + } + } + } + + // Extracts persistence pairs in separate dimensions; expects a d-dimensional vector of persistent_pairs + template< typename ReductionAlgorithm, typename Representation > + void compute_persistence_pairs(std::vector& pairs, boundary_matrix& boundary_matrix) { + ReductionAlgorithm reduce; + reduce(boundary_matrix); + std::map free; + for (std::vector::iterator it = pairs.begin(); it != pairs.end(); ++it) { it->clear(); } + for (index idx = 0; idx < boundary_matrix.get_num_cols(); ++idx) { + int dimension = boundary_matrix.get_dim(idx); + free[idx] = true; + if (!boundary_matrix.is_empty(idx)) { + index birth = boundary_matrix.get_max_index(idx); + index death = idx; + pairs[dimension-1].append_pair(birth, death); + // Cannot be of the form (a, infinity) + free[birth] = false; + free[death] = false; + } + } + for (std::map::iterator it = free.begin(); it != free.end(); ++it) { + if (it->second) { + int dimension = boundary_matrix.get_dim(it->first); + pairs[dimension].append_pair(it->first, -1); + } + } + } + + template< typename ReductionAlgorithm, typename Representation > + void compute_persistence_pairs( persistence_pairs& pairs, boundary_matrix< Representation >& boundary_matrix ) { + ReductionAlgorithm reduce; + reduce( boundary_matrix ); + pairs.clear(); + for( index idx = 0; idx < boundary_matrix.get_num_cols(); idx++ ) { + if( !boundary_matrix.is_empty( idx ) ) { + index birth = boundary_matrix.get_max_index( idx ); + index death = idx; + pairs.append_pair( birth, death ); + } + } + } + + template< typename ReductionAlgorithm, typename Representation > + void compute_persistence_pairs_dualized( persistence_pairs& pairs, boundary_matrix< Representation >& boundary_matrix ) { + + dualize( boundary_matrix ); + compute_persistence_pairs< ReductionAlgorithm >( pairs, boundary_matrix ); + dualize_persistence_pairs( pairs, boundary_matrix.get_num_cols() ); + } + + template< typename Representation > + void compute_persistence_pairs( persistence_pairs& pairs, boundary_matrix< Representation >& boundary_matrix ) { + phat::compute_persistence_pairs< twist_reduction >( pairs, boundary_matrix ); + } + + + template< typename Representation > + void compute_persistence_pairs_dualized( persistence_pairs& pairs, boundary_matrix< Representation >& boundary_matrix ) { + compute_persistence_pairs_dualized< twist_reduction >( pairs, boundary_matrix ); + } + +} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/helpers/dualize.h b/src/Zigzag_persistence/example/ext_zz/phat/helpers/dualize.h new file mode 100644 index 0000000000..3ffedf875f --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/helpers/dualize.h @@ -0,0 +1,74 @@ +/* Copyright 2013 IST Austria + Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +#include +#include +#include + + +namespace phat { + template< typename Representation > + void dualize( boundary_matrix< Representation >& boundary_matrix ) { + + std::vector< dimension > dual_dims; + std::vector< std::vector< index > > dual_matrix; + + index nr_of_columns = boundary_matrix.get_num_cols(); + dual_matrix.resize( nr_of_columns ); + dual_dims.resize( nr_of_columns ); + + std::vector< index > dual_sizes( nr_of_columns, 0 ); + + column temp_col; + for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) { + boundary_matrix.get_col( cur_col, temp_col ); + for( index idx = 0; idx < (index)temp_col.size(); idx++) + dual_sizes[ nr_of_columns - 1 - temp_col[ idx ] ]++; + } + + #pragma omp parallel for + for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) + dual_matrix[cur_col].reserve(dual_sizes[cur_col]); + + for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) { + boundary_matrix.get_col( cur_col, temp_col ); + for( index idx = 0; idx < (index)temp_col.size(); idx++) + dual_matrix[ nr_of_columns - 1 - temp_col[ idx ] ].push_back( nr_of_columns - 1 - cur_col ); + } + + const dimension max_dim = boundary_matrix.get_max_dim(); + #pragma omp parallel for + for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) + dual_dims[ nr_of_columns - 1 - cur_col ] = max_dim - boundary_matrix.get_dim( cur_col ); + + #pragma omp parallel for + for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) + std::reverse( dual_matrix[ cur_col ].begin(), dual_matrix[ cur_col ].end() ); + + boundary_matrix.load_vector_vector( dual_matrix, dual_dims ); + } + + void dualize_persistence_pairs( persistence_pairs& pairs, const index n ) { + for (index i = 0; i < pairs.get_num_pairs(); ++i) { + std::pair< index, index > pair = pairs.get_pair( i ); + pairs.set_pair( i , n - 1 - pair.second, n - 1 - pair.first); + } + } +} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/helpers/misc.h b/src/Zigzag_persistence/example/ext_zz/phat/helpers/misc.h new file mode 100644 index 0000000000..fb5c07acb0 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/helpers/misc.h @@ -0,0 +1,75 @@ +/* Copyright 2013 IST Austria + Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +// STL includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// VS2008 and below unfortunately do not support stdint.h +#if defined(_MSC_VER)&& _MSC_VER < 1600 + typedef __int8 int8_t; + typedef unsigned __int8 uint8_t; + typedef __int16 int16_t; + typedef unsigned __int16 uint16_t; + typedef __int32 int32_t; + typedef unsigned __int32 uint32_t; + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; +#else + #include +#endif + +// basic types. index can be changed to int32_t to save memory on small instances +namespace phat { + typedef int64_t index; + typedef int8_t dimension; + typedef std::vector< index > column; +} + +// OpenMP (proxy) functions +#if defined _OPENMP + #include +#else + #define omp_get_thread_num() 0 + #define omp_get_max_threads() 1 + #define omp_get_num_threads() 1 + void omp_set_num_threads( int ) {}; + #include + #define omp_get_wtime() (float)clock() / (float)CLOCKS_PER_SEC +#endif + +#include + + + diff --git a/src/Zigzag_persistence/example/ext_zz/phat/helpers/thread_local_storage.h b/src/Zigzag_persistence/example/ext_zz/phat/helpers/thread_local_storage.h new file mode 100644 index 0000000000..d0b5332bc1 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/helpers/thread_local_storage.h @@ -0,0 +1,52 @@ +/* Copyright 2013 IST Austria + Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +#include + +// should ideally be equal to the cache line size of the CPU +#define PHAT_TLS_SPACING_FACTOR 64 + +// ThreadLocalStorage with some spacing to avoid "false sharing" (see wikipedia) +template< typename T > +class thread_local_storage +{ +public: + + thread_local_storage() : per_thread_storage( omp_get_max_threads() * PHAT_TLS_SPACING_FACTOR ) {}; + + T& operator()() { + return per_thread_storage[ omp_get_thread_num() * PHAT_TLS_SPACING_FACTOR ]; + } + + const T& operator()() const { + return per_thread_storage[ omp_get_thread_num() * PHAT_TLS_SPACING_FACTOR ]; + } + + T& operator[]( int tid ) { + return per_thread_storage[ tid * PHAT_TLS_SPACING_FACTOR ]; + } + + const T& operator[]( int tid ) const { + return per_thread_storage[ tid * PHAT_TLS_SPACING_FACTOR ]; + } + +protected: + std::vector< T > per_thread_storage; +}; diff --git a/src/Zigzag_persistence/example/ext_zz/phat/persistence_pairs.h b/src/Zigzag_persistence/example/ext_zz/phat/persistence_pairs.h new file mode 100644 index 0000000000..eafc6389e2 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/persistence_pairs.h @@ -0,0 +1,155 @@ +/* Copyright 2013 IST Austria + Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +#include + +namespace phat { + class persistence_pairs { + + protected: + std::vector< std::pair< index, index > > pairs; + + public: + index get_num_pairs() const { + return (index)pairs.size(); + } + + void append_pair( index birth, index death ) { + pairs.push_back( std::make_pair( birth, death ) ); + } + + std::pair< index, index > get_pair( index idx ) const { + return pairs[ idx ]; + } + + void set_pair( index idx, index birth, index death ) { + pairs[ idx ] = std::make_pair( birth, death ); + } + + void clear() { + pairs.clear(); + } + + void sort() { + std::sort( pairs.begin(), pairs.end() ); + } + + // Loads the persistence pairs from given file in asci format + // Format: nr_pairs % newline % birth1 % death1 % newline % birth2 % death2 % newline ... + bool load_ascii( std::string filename ) { + std::ifstream input_stream( filename.c_str() ); + if( input_stream.fail() ) + return false; + + int64_t nr_pairs; + input_stream >> nr_pairs; + pairs.clear(); + for( index idx = 0; idx < nr_pairs; idx++ ) { + int64_t birth; + input_stream >> birth; + int64_t death; + input_stream >> death; + append_pair( (index)birth, (index)death ); + } + + input_stream.close(); + return true; + } + + // Saves the persistence pairs to given file in binary format + // Format: nr_pairs % newline % birth1 % death1 % newline % birth2 % death2 % newline ... + bool save_ascii( std::string filename ) { + std::ofstream output_stream( filename.c_str() ); + if( output_stream.fail() ) + return false; + + this->sort(); + output_stream << get_num_pairs() << std::endl; + for( std::size_t idx = 0; idx < pairs.size(); idx++ ) { + output_stream << pairs[idx].first << " " << pairs[idx].second << std::endl; + } + + output_stream.close(); + return true; + } + + // Loads the persistence pairs from given file in binary format + // Format: nr_pairs % birth1 % death1 % birth2 % death2 ... + bool load_binary( std::string filename ) { + std::ifstream input_stream( filename.c_str(), std::ios_base::binary | std::ios_base::in ); + if( input_stream.fail() ) + return false; + + int64_t nr_pairs; + input_stream.read( (char*)&nr_pairs, sizeof( int64_t ) ); + for( index idx = 0; idx < nr_pairs; idx++ ) { + int64_t birth; + input_stream.read( (char*)&birth, sizeof( int64_t ) ); + int64_t death; + input_stream.read( (char*)&death, sizeof( int64_t ) ); + append_pair( (index)birth, (index)death ); + } + + input_stream.close(); + return true; + } + + // Saves the persistence pairs to given file in binary format + // Format: nr_pairs % birth1 % death1 % birth2 % death2 ... + bool save_binary( std::string filename ) { + std::ofstream output_stream( filename.c_str(), std::ios_base::binary | std::ios_base::out ); + if( output_stream.fail() ) + return false; + + this->sort(); + int64_t nr_pairs = get_num_pairs(); + output_stream.write( (char*)&nr_pairs, sizeof( int64_t ) ); + for( std::size_t idx = 0; idx < pairs.size(); idx++ ) { + int64_t birth = pairs[ idx ].first; + output_stream.write( (char*)&birth, sizeof( int64_t ) ); + int64_t death = pairs[ idx ].second; + output_stream.write( (char*)&death, sizeof( int64_t ) ); + } + + output_stream.close(); + return true; + } + + bool operator==( persistence_pairs& other_pairs ) { + this->sort(); + other_pairs.sort(); + if( pairs.size() != (std::size_t)other_pairs.get_num_pairs() ) + return false; + + for( index idx = 0; idx < (index)pairs.size(); idx++ ) + if( get_pair( idx ) != other_pairs.get_pair( idx ) ) + return false; + + return true; + } + + bool operator!=( persistence_pairs& other_pairs ) { + return !( *this == other_pairs ); + } + }; + + + +} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/representations/abstract_pivot_column.h b/src/Zigzag_persistence/example/ext_zz/phat/representations/abstract_pivot_column.h new file mode 100644 index 0000000000..e16d7a5d13 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/representations/abstract_pivot_column.h @@ -0,0 +1,102 @@ +/* Copyright 2013 IST Austria + Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +#include +#include + +namespace phat { + + // Note: We could even make the rep generic in the underlying Const representation + // But I cannot imagine that anything else than vector> would + // make sense + template< typename PivotColumn > + class abstract_pivot_column : public vector_vector { + + protected: + typedef vector_vector Base; + typedef PivotColumn pivot_col; + + // For parallization purposes, it could be more than one full column + mutable thread_local_storage< pivot_col > pivot_cols; + mutable thread_local_storage< index > idx_of_pivot_cols; + + pivot_col& get_pivot_col() const { + return pivot_cols(); + } + + bool is_pivot_col( index idx ) const { + return idx_of_pivot_cols() == idx; + } + + void release_pivot_col() { + index idx = idx_of_pivot_cols(); + if( idx != -1 ) { + this->matrix[ idx ].clear(); + pivot_cols().get_col_and_clear( this->matrix[ idx ] ); + } + idx_of_pivot_cols() = -1; + } + + void make_pivot_col( index idx ) { + release_pivot_col(); + idx_of_pivot_cols() = idx; + get_pivot_col().add_col( matrix[ idx ] ); + } + + public: + + void _set_num_cols( index nr_of_cols ) { + #pragma omp parallel for + for( int tid = 0; tid < omp_get_num_threads(); tid++ ) { + pivot_cols[ tid ].init( nr_of_cols ); + idx_of_pivot_cols[ tid ] = -1; + } + Base::_set_num_cols( nr_of_cols ); + } + + void _add_to( index source, index target ) { + if( !is_pivot_col( target ) ) + make_pivot_col( target ); + get_pivot_col().add_col( matrix[source] ); + } + + void _sync() { + #pragma omp parallel for + for( int tid = 0; tid < omp_get_num_threads(); tid++ ) + release_pivot_col(); + } + + void _get_col( index idx, column& col ) const { is_pivot_col( idx ) ? get_pivot_col().get_col( col ) : Base::_get_col( idx, col ); } + + bool _is_empty( index idx ) const { return is_pivot_col( idx ) ? get_pivot_col().is_empty() : Base::_is_empty( idx ); } + + index _get_max_index( index idx ) const { return is_pivot_col( idx ) ? get_pivot_col().get_max_index() : Base::_get_max_index( idx ); } + + void _clear( index idx ) { is_pivot_col( idx ) ? get_pivot_col().clear() : Base::_clear( idx ); } + + void _set_col( index idx, const column& col ) { is_pivot_col( idx ) ? get_pivot_col().set_col( col ) : Base::_set_col( idx, col ); } + + void _remove_max( index idx ) { is_pivot_col( idx ) ? get_pivot_col().remove_max() : Base::_remove_max( idx ); } + + void finalize( index idx ) { Base::_finalize( idx ); } + }; +} + + diff --git a/src/Zigzag_persistence/example/ext_zz/phat/representations/bit_tree_pivot_column.h b/src/Zigzag_persistence/example/ext_zz/phat/representations/bit_tree_pivot_column.h new file mode 100644 index 0000000000..4d48e8853d --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/representations/bit_tree_pivot_column.h @@ -0,0 +1,165 @@ +/* Copyright 2013 IST Austria + Contributed by: Hubert Wagner + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +#include +#include + +namespace phat { + + // This is a bitset indexed with a 64-ary tree. Each node in the index + // has 64 bits; i-th bit says that the i-th subtree is non-empty. + // Supports practically O(1), inplace, zero-allocation: insert, remove, max_element + // and clear in O(number of ones in the bitset). + // 'add_index' is still the real bottleneck in practice. + class bit_tree_column + { + protected: + + size_t offset; // data[i + offset] = ith block of the data-bitset + typedef uint64_t block_type; + std::vector< block_type > data; + + + size_t debrujin_magic_table[ 64 ]; + + enum { block_size_in_bits = 64 }; + enum { block_shift = 6 }; + + // Some magic: http://graphics.stanford.edu/~seander/bithacks.html + // Gets the position of the rightmost bit of 'x'. 0 means the most significant bit. + // (-x)&x isolates the rightmost bit. + // The whole method is much faster than calling log2i, and very comparable to using ScanBitForward/Reverse intrinsic, + // which should be one CPU instruction, but is not portable. + size_t rightmost_pos( const block_type value ) const { + return 64 - 1 - debrujin_magic_table[ ( (value & (-(int64_t)value) ) * 0x07EDD5E59A4E28C2 ) >> 58 ]; + } + + public: + + void init( index num_cols ) { + int64_t n = 1; // in case of overflow + int64_t bottom_blocks_needed = ( num_cols + block_size_in_bits - 1 ) / block_size_in_bits; + int64_t upper_blocks = 1; + + // How many blocks/nodes of index needed to index the whole bitset? + while( n * block_size_in_bits < bottom_blocks_needed ) { + n *= block_size_in_bits; + upper_blocks += n; + } + + offset = upper_blocks; + data.resize( upper_blocks + bottom_blocks_needed, 0 ); + + std::size_t temp_array[ 64 ] = { + 63, 0, 58, 1, 59, 47, 53, 2, + 60, 39, 48, 27, 54, 33, 42, 3, + 61, 51, 37, 40, 49, 18, 28, 20, + 55, 30, 34, 11, 43, 14, 22, 4, + 62, 57, 46, 52, 38, 26, 32, 41, + 50, 36, 17, 19, 29, 10, 13, 21, + 56, 45, 25, 31, 35, 16, 9, 12, + 44, 24, 15, 8, 23, 7, 6, 5 }; + + std::copy( &temp_array[ 0 ], &temp_array[ 64 ], &debrujin_magic_table[ 0 ] ); + } + + index get_max_index() const { + if( !data[ 0 ] ) + return -1; + + size_t n = 0; + size_t newn = 0; + size_t index = 0; + while( newn < data.size() ) { + n = newn; + index = rightmost_pos( data[ n ] ); + newn = ( n << block_shift ) + index + 1; + } + + return ( ( n - offset ) << block_shift ) + index; + } + + bool is_empty() const { + return data[ 0 ] == 0; + } + + void add_index( const size_t entry ) { + const block_type ONE = 1; + const block_type block_modulo_mask = ( ONE << block_shift ) - 1; + size_t index_in_level = entry >> block_shift; + size_t address = index_in_level + offset; + size_t index_in_block = entry & block_modulo_mask; + + block_type mask = ( ONE << ( block_size_in_bits - index_in_block - 1 ) ); + + data[ address ] ^= mask; + + // Check if we reached the root. Also, if anyone else was in this block, we don't need to update the path up. + while( address && !( data[ address ] & ~mask ) ) { + index_in_block = index_in_level & block_modulo_mask; + index_in_level >>= block_shift; + --address; + address >>= block_shift; + mask = ( ONE << ( block_size_in_bits - index_in_block - 1 ) ); + data[ address ] ^= mask; + } + } + + void get_col_and_clear( column &out ) { + index mx = this->get_max_index(); + while( mx != -1 ) { + out.push_back( mx ); + add_index( mx ); + mx = this->get_max_index(); + } + + std::reverse( out.begin(), out.end() ); + } + + void add_col(const column &col) { + for( size_t i = 0; i < col.size(); ++i ) + add_index(col[i]); + } + + void clear() { + index mx = this->get_max_index(); + while( mx != -1 ) { + add_index( mx ); + mx = this->get_max_index(); + } + } + + void remove_max() { + add_index( get_max_index() ); + } + + void set_col( const column& col ) { + clear(); + add_col( col ); + } + + void get_col( column& col ) { + get_col_and_clear( col ); + add_col( col ); + } + }; + + typedef abstract_pivot_column bit_tree_pivot_column; +} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/representations/full_pivot_column.h b/src/Zigzag_persistence/example/ext_zz/phat/representations/full_pivot_column.h new file mode 100644 index 0000000000..c2e9e3c574 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/representations/full_pivot_column.h @@ -0,0 +1,100 @@ +/* Copyright 2013 IST Austria + Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +#include +#include + +namespace phat { + class full_column { + + protected: + std::priority_queue< index > history; + std::vector< char > is_in_history; + std::vector< char > col_bit_field; + + public: + void init( const index total_size ) { + col_bit_field.resize( total_size, false ); + is_in_history.resize( total_size, false ); + } + + void add_col( const column& col ) { + for( index idx = 0; idx < (index) col.size(); idx++ ) { + add_index( col[ idx ] ); + } + } + + void add_index( const index idx ) { + if( !is_in_history[ idx ] ) { + history.push( idx ); + is_in_history[ idx ] = true; + } + + col_bit_field[ idx ] = !col_bit_field[ idx ]; + } + + index get_max_index() { + while( history.size() > 0 ) { + index topIndex = history.top(); + if( col_bit_field[ topIndex ] ) { + return topIndex; + } else { + history.pop(); + is_in_history[ topIndex ] = false; + } + } + + return -1; + } + + void get_col_and_clear( column& col ) { + while( !is_empty() ) { + col.push_back( get_max_index() ); + add_index( get_max_index() ); + } + std::reverse( col.begin(), col.end() ); + } + + bool is_empty() { + return (get_max_index() == -1); + } + + void clear() { + while( !is_empty() ) + add_index( get_max_index() ); + } + + void remove_max() { + add_index( get_max_index() ); + } + + void set_col( const column& col ) { + clear(); + add_col( col ); + } + + void get_col( column& col ) { + get_col_and_clear( col ); + add_col( col ); + } + }; + + typedef abstract_pivot_column< full_column > full_pivot_column; +} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/representations/heap_pivot_column.h b/src/Zigzag_persistence/example/ext_zz/phat/representations/heap_pivot_column.h new file mode 100644 index 0000000000..33cd07b40d --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/representations/heap_pivot_column.h @@ -0,0 +1,126 @@ +/* Copyright 2013 IST Austria + Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +#include +#include + +namespace phat { + class heap_column { + + protected: + std::priority_queue< index > data; + + column temp_col; + index inserts_since_last_prune; + + void prune() + { + temp_col.clear( ); + index max_index = pop_max_index( ); + while( max_index != -1 ) { + temp_col.push_back( max_index ); + max_index = pop_max_index( ); + } + + for( index idx = 0; idx < (index)temp_col.size( ); idx++ ) + data.push( temp_col[ idx ] ); + + inserts_since_last_prune = 0; + } + + index pop_max_index() + { + if( data.empty( ) ) + return -1; + else { + index max_element = data.top( ); + data.pop(); + while( !data.empty( ) && data.top( ) == max_element ) { + data.pop( ); + if( data.empty( ) ) + return -1; + else { + max_element = data.top( ); + data.pop( ); + } + } + return max_element; + } + } + + public: + void init( const index total_size ) { + inserts_since_last_prune = 0; + clear(); + } + + void add_col( const column& col ) { + for( index idx = 0; idx < (index) col.size(); idx++ ) + data.push( col[ idx ] ); + inserts_since_last_prune += col.size( ); + if( 2 * inserts_since_last_prune >( index ) data.size( ) ) + prune(); + } + + index get_max_index() { + index max_element = pop_max_index( ); + if( max_element == -1 ) + return -1; + else { + data.push( max_element ); + return max_element; + } + } + + void get_col_and_clear( column& col ) { + col.clear(); + index max_index = pop_max_index( ); + while( max_index != -1 ) { + col.push_back( max_index ); + max_index = pop_max_index( ); + } + std::reverse( col.begin(), col.end() ); + } + + bool is_empty() { + return get_max_index() == -1; + } + + void clear() { + data = std::priority_queue< index >(); + } + + void remove_max() { + pop_max_index(); + } + + void set_col( const column& col ) { + clear(); + add_col( col ); + } + + void get_col( column& col ) { + get_col_and_clear( col ); + add_col( col ); + } + }; + + typedef abstract_pivot_column< heap_column > heap_pivot_column; +} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/representations/sparse_pivot_column.h b/src/Zigzag_persistence/example/ext_zz/phat/representations/sparse_pivot_column.h new file mode 100644 index 0000000000..390fd91a99 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/representations/sparse_pivot_column.h @@ -0,0 +1,79 @@ +/* Copyright 2013 IST Austria + Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +#include +#include + +namespace phat { + class sparse_column { + + protected: + std::set< index > data; + + void add_index( const index idx ) { + std::pair< std::set< index >::iterator, bool > result = data.insert( idx ); + if( result.second == false ) + data.erase( result.first ); + } + + public: + void init( const index total_size ) { + data.clear(); + } + + void add_col( const column& col ) { + for( index idx = 0; idx < (index) col.size(); idx++ ) + add_index( col[ idx ] ); + } + + index get_max_index() { + return data.empty() ? -1 : *data.rbegin(); + } + + void get_col_and_clear( column& col ) { + col.assign( data.begin(), data.end() ); + data.clear(); + } + + bool is_empty() { + return data.empty(); + } + + void clear() { + data.clear(); + } + + void remove_max() { + add_index( get_max_index() ); + } + + void set_col( const column& col ) { + clear(); + add_col( col ); + } + + void get_col( column& col ) { + get_col_and_clear( col ); + add_col( col ); + } + }; + + typedef abstract_pivot_column< sparse_column > sparse_pivot_column; +} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_heap.h b/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_heap.h new file mode 100644 index 0000000000..db0420ff23 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_heap.h @@ -0,0 +1,170 @@ +/* Copyright 2013 IST Austria +Contributed by: Jan Reininghaus + +This file is part of PHAT. + +PHAT is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +PHAT 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with PHAT. If not, see . */ + +#pragma once + +#include + +namespace phat { + class vector_heap { + + protected: + std::vector< dimension > dims; + std::vector< column > matrix; + + std::vector< index > inserts_since_last_prune; + + mutable thread_local_storage< column > temp_column_buffer; + + protected: + void _prune( index idx ) + { + column& col = matrix[ idx ]; + column& temp_col = temp_column_buffer(); + temp_col.clear(); + index max_index = _pop_max_index( col ); + while( max_index != -1 ) { + temp_col.push_back( max_index ); + max_index = _pop_max_index( col ); + } + col = temp_col; + std::reverse( col.begin( ), col.end( ) ); + std::make_heap( col.begin( ), col.end( ) ); + inserts_since_last_prune[ idx ] = 0; + } + + index _pop_max_index( index idx ) + { + return _pop_max_index( matrix[ idx ] ); + } + + index _pop_max_index( column& col ) const + { + if( col.empty( ) ) + return -1; + else { + index max_element = col.front( ); + std::pop_heap( col.begin( ), col.end( ) ); + col.pop_back( ); + while( !col.empty( ) && col.front( ) == max_element ) { + std::pop_heap( col.begin( ), col.end( ) ); + col.pop_back( ); + if( col.empty( ) ) + return -1; + else { + max_element = col.front( ); + std::pop_heap( col.begin( ), col.end( ) ); + col.pop_back( ); + } + } + return max_element; + } + } + + public: + // overall number of cells in boundary_matrix + index _get_num_cols( ) const + { + return (index)matrix.size( ); + } + void _set_num_cols( index nr_of_columns ) + { + dims.resize( nr_of_columns ); + matrix.resize( nr_of_columns ); + inserts_since_last_prune.assign( nr_of_columns, 0 ); + } + + // dimension of given index + dimension _get_dim( index idx ) const + { + return dims[ idx ]; + } + void _set_dim( index idx, dimension dim ) + { + dims[ idx ] = dim; + } + + // replaces(!) content of 'col' with boundary of given index + void _get_col( index idx, column& col ) const + { + temp_column_buffer( ) = matrix[ idx ]; + + index max_index = _pop_max_index( temp_column_buffer() ); + while( max_index != -1 ) { + col.push_back( max_index ); + max_index = _pop_max_index( temp_column_buffer( ) ); + } + std::reverse( col.begin( ), col.end( ) ); + } + void _set_col( index idx, const column& col ) + { + matrix[ idx ] = col; + std::make_heap( matrix[ idx ].begin( ), matrix[ idx ].end( ) ); + } + + // true iff boundary of given idx is empty + bool _is_empty( index idx ) const + { + return _get_max_index( idx ) == -1; + } + + // largest row index of given column idx (new name for lowestOne()) + index _get_max_index( index idx ) const + { + column& col = const_cast< column& >( matrix[ idx ] ); + index max_element = _pop_max_index( col ); + col.push_back( max_element ); + std::push_heap( col.begin( ), col.end( ) ); + return max_element; + } + + // removes the maximal index of a column + void _remove_max( index idx ) + { + _pop_max_index( idx ); + } + + // clears given column + void _clear( index idx ) + { + matrix[ idx ].clear( ); + } + + // syncronizes all data structures (essential for openmp stuff) + void _sync( ) {} + + // adds column 'source' to column 'target' + void _add_to( index source, index target ) + { + for( index idx = 0; idx < (index)matrix[ source ].size( ); idx++ ) { + matrix[ target ].push_back( matrix[ source ][ idx ] ); + std::push_heap( matrix[ target ].begin(), matrix[ target ].end() ); + } + inserts_since_last_prune[ target ] += matrix[ source ].size(); + + if( 2 * inserts_since_last_prune[ target ] > ( index )matrix[ target ].size() ) + _prune( target ); + } + + // finalizes given column + void _finalize( index idx ) { + _prune( idx ); + } + + }; +} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_list.h b/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_list.h new file mode 100644 index 0000000000..ca0b5b8e79 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_list.h @@ -0,0 +1,101 @@ +/* Copyright 2013 IST Austria + Contributed by: Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +#include + +namespace phat { + class vector_list { + + protected: + std::vector< dimension > dims; + std::vector< std::list< index > > matrix; + + public: + // overall number of cells in boundary_matrix + index _get_num_cols() const { + return (index)matrix.size(); + } + void _set_num_cols( index nr_of_columns ) { + dims.resize( nr_of_columns ); + matrix.resize( nr_of_columns ); + } + + // dimension of given index + dimension _get_dim( index idx ) const { + return dims[ idx ]; + } + void _set_dim( index idx, dimension dim ) { + dims[ idx ] = dim; + } + + // replaces(!) content of 'col' with boundary of given index + void _get_col( index idx, column& col ) const { + col.clear(); + col.reserve( matrix[idx].size() ); + std::copy (matrix[idx].begin(), matrix[idx].end(), std::back_inserter(col) ); + } + + void _set_col( index idx, const column& col ) { + matrix[ idx ].clear(); + matrix[ idx ].resize( col.size() ); + std::copy (col.begin(), col.end(), matrix[ idx ].begin() ); + } + + // true iff boundary of given idx is empty + bool _is_empty( index idx ) const { + return matrix[ idx ].empty(); + } + + // largest row index of given column idx (new name for lowestOne()) + index _get_max_index( index idx ) const { + return matrix[ idx ].empty() ? -1 : *matrix[ idx ].rbegin(); + } + + // removes the maximal index of a column + void _remove_max( index idx ) { + std::list< index >::iterator it = matrix[ idx ].end(); + it--; + matrix[ idx ].erase( it ); + } + + // clears given column + void _clear( index idx ) { + matrix[ idx ].clear(); + } + + // syncronizes all data structures (essential for openmp stuff) + void _sync() {} + + // adds column 'source' to column 'target' + void _add_to( index source, index target ) { + std::list< index >& source_col = matrix[ source ]; + std::list< index >& target_col = matrix[ target ]; + std::list< index > temp_col; + target_col.swap( temp_col ); + std::set_symmetric_difference( temp_col.begin(), temp_col.end(), + source_col.begin(), source_col.end(), + std::back_inserter( target_col ) ); + } + + // finalizes given column + void _finalize( index idx ) { + } + }; +} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_set.h b/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_set.h new file mode 100644 index 0000000000..6878a270c0 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_set.h @@ -0,0 +1,99 @@ +/* Copyright 2013 IST Austria + Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +#include + +namespace phat { + class vector_set { + + protected: + std::vector< dimension > dims; + std::vector< std::set< index > > matrix; + + public: + // overall number of cells in boundary_matrix + index _get_num_cols() const { + return (index)matrix.size(); + } + void _set_num_cols( index nr_of_columns ) { + dims.resize( nr_of_columns ); + matrix.resize( nr_of_columns ); + } + + // dimension of given index + dimension _get_dim( index idx ) const { + return dims[ idx ]; + } + void _set_dim( index idx, dimension dim ) { + dims[ idx ] = dim; + } + + // replaces(!) content of 'col' with boundary of given index + void _get_col( index idx, column& col ) const { + col.clear(); + col.reserve( matrix[idx].size() ); + std::copy (matrix[idx].begin(), matrix[idx].end(), std::back_inserter(col) ); + } + void _set_col( index idx, const column& col ) { + matrix[ idx ].clear(); + matrix[ idx ].insert( col.begin(), col.end() ); + } + + // true iff boundary of given idx is empty + bool _is_empty( index idx ) const { + return matrix[ idx ].empty(); + } + + // largest row index of given column idx (new name for lowestOne()) + index _get_max_index( index idx ) const { + return matrix[ idx ].empty() ? -1 : *matrix[ idx ].rbegin(); + } + + // removes the maximal index of a column + void _remove_max( index idx ) { + std::set< index >::iterator it = matrix[ idx ].end(); + it--; + matrix[ idx ].erase( it ); + } + + // clears given column + void _clear( index idx ) { + matrix[ idx ].clear(); + } + + // syncronizes all data structures (essential for openmp stuff) + void _sync() {} + + // adds column 'source' to column 'target' + void _add_to( index source, index target ) { + for( std::set< index >::iterator it = matrix[ source ].begin(); it != matrix[ source ].end(); it++ ) { + std::set< index >& col = matrix[ target ]; + std::pair< std::set< index >::iterator, bool > result = col.insert( *it ); + if( !result.second ) + col.erase( result.first ); + } + } + + // finalizes given column + void _finalize( index idx ) { + } + + }; +} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_vector.h b/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_vector.h new file mode 100644 index 0000000000..f111d6b572 --- /dev/null +++ b/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_vector.h @@ -0,0 +1,107 @@ +/* Copyright 2013 IST Austria + Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see . */ + +#pragma once + +#include + +namespace phat { + class vector_vector { + + protected: + std::vector< dimension > dims; + std::vector< column > matrix; + + thread_local_storage< column > temp_column_buffer; + + public: + // overall number of cells in boundary_matrix + index _get_num_cols() const { + return (index)matrix.size(); + } + void _set_num_cols( index nr_of_columns ) { + dims.resize( nr_of_columns ); + matrix.resize( nr_of_columns ); + } + + // dimension of given index + dimension _get_dim( index idx ) const { + return dims[ idx ]; + } + void _set_dim( index idx, dimension dim ) { + dims[ idx ] = dim; + } + + // replaces(!) content of 'col' with boundary of given index + void _get_col( index idx, column& col ) const { + col = matrix[ idx ]; + } + void _set_col( index idx, const column& col ) { + matrix[ idx ] = col; + } + + // true iff boundary of given idx is empty + bool _is_empty( index idx ) const { + return matrix[ idx ].empty(); + } + + // largest row index of given column idx (new name for lowestOne()) + index _get_max_index( index idx ) const { + return matrix[ idx ].empty() ? -1 : matrix[ idx ].back(); + } + + // removes the maximal index of a column + void _remove_max( index idx ) { + matrix[ idx ].pop_back(); + } + + // clears given column + void _clear( index idx ) { + matrix[ idx ].clear(); + } + + // syncronizes all data structures (essential for openmp stuff) + void _sync() {} + + // adds column 'source' to column 'target' + void _add_to( index source, index target ) { + column& source_col = matrix[ source ]; + column& target_col = matrix[ target ]; + column& temp_col = temp_column_buffer(); + + + size_t new_size = source_col.size() + target_col.size(); + + if (new_size > temp_col.size()) temp_col.resize(new_size); + + std::vector::iterator col_end = std::set_symmetric_difference( target_col.begin(), target_col.end(), + source_col.begin(), source_col.end(), + temp_col.begin() ); + temp_col.erase(col_end, temp_col.end()); + + + target_col.swap(temp_col); + } + + // finalizes given column + void _finalize( index idx ) { + column& col = matrix[ idx ]; + column(col.begin(), col.end()).swap(col); + } + }; +} diff --git a/src/Zigzag_persistence/example/rips-zigzag-dionysus.h b/src/Zigzag_persistence/example/rips-zigzag-dionysus.h new file mode 100644 index 0000000000..62db6d834d --- /dev/null +++ b/src/Zigzag_persistence/example/rips-zigzag-dionysus.h @@ -0,0 +1,211 @@ +#include +#include +#include +#include + +#include +namespace ba = boost::adaptors; + +#include +#include +#include +namespace d = dionysus; + +#include + +typedef std::vector Point; +typedef std::vector PointContainer; + +typedef d::PairwiseDistances> PairDistances; +typedef PairDistances::DistanceType DistanceType; +typedef PairDistances::IndexType Vertex; + +typedef d::Rips Generator; +typedef Generator::Simplex Simplex; +typedef std::set SimplexSet; + +typedef std::vector VertexVector; +typedef std::vector EpsilonVector; +typedef std::tuple Edge; +typedef std::vector EdgeVector; + +inline PointContainer compute_points(unsigned int numberOfPoints, int seed = -1) +{ + PointContainer finalPoints; + std::set points; + std::random_device dev; + std::mt19937 rng(dev()); + if (seed > -1) rng.seed(seed); + std::uniform_real_distribution dist(0,10); + + for (unsigned int i = 0; i < numberOfPoints; ++i){ + auto res = points.insert({dist(rng), dist(rng)}); + while(!res.second){ + res = points.insert({dist(rng), dist(rng)}); + } + finalPoints.push_back(*res.first); + } + + return finalPoints; +} + +inline void compute_vertices_and_epsilons(const PairDistances& distances, + VertexVector& vertices, + EpsilonVector& epsilons) +{ + DistanceType inf = std::numeric_limits::infinity(); + EpsilonVector dist(distances.size(), inf); + + vertices.push_back(distances.begin()); + // epsilons.push_back(inf); + while (vertices.size() < distances.size()) { + for (Vertex v = distances.begin(); v != distances.end(); ++v) + dist[v] = std::min(dist[v], distances(v, vertices.back())); + auto max = std::max_element(dist.begin(), dist.end()); + vertices.push_back(max - dist.begin()); + epsilons.push_back(*max); + } + epsilons.push_back(0); +} + +inline void compute_edges(const PairDistances& distances, + const VertexVector& vertices, + const EpsilonVector& epsilons, + const DistanceType& multiplier, + EdgeVector& edges) +{ + for (unsigned i = 0; i != vertices.size(); ++i) + for (unsigned j = i + 1; j != vertices.size(); ++j) { + Vertex u = vertices[i]; + Vertex v = vertices[j]; + if (distances(u, v) <= multiplier * epsilons[j - 1]) edges.emplace_back(u, v); + } + std::sort(edges.begin(), edges.end(), + [&distances](const Edge& e1, const Edge& e2) { + return distances(std::get<0>(e1), std::get<1>(e1)) < + distances(std::get<0>(e2), std::get<1>(e2)); + }); +} + +inline void compute_positive_cofaces( + const PairDistances& distances, + const VertexVector& vertices, + const EdgeVector& edges, + const EpsilonVector& epsilons, + const DistanceType& multiplier, + Generator& rips, + short unsigned& skeleton, + unsigned& ce, + unsigned& i, + SimplexSet& cofaces) +{ + cofaces.clear(); + + // Add anything else that needs to be inserted into the complex + while (ce < edges.size()) { + Vertex u, v; + std::tie(u, v) = edges[ce]; + if (distances(u, v) <= multiplier * epsilons[i - 1]) + ++ce; + else + break; + // std::cout << "Adding cofaces of " << u << ' ' << v << std::endl; + rips.edge_cofaces( + u, v, + skeleton, + multiplier * epsilons[i - 1], + [&cofaces](Simplex&& s) { cofaces.insert(s); }, + vertices.begin(), + vertices.begin() + i + 1); + } +} + +inline void compute_negative_cofaces( + const VertexVector& vertices, + const EpsilonVector& epsilons, + const DistanceType& multiplier, + Generator& rips, + short unsigned& skeleton, + unsigned& i, + SimplexSet& cofaces) +{ + cofaces.clear(); + rips.vertex_cofaces( + vertices[i], + skeleton, + multiplier * epsilons[i - 1], + [&cofaces](Simplex&& s) { cofaces.insert(s); }, + vertices.begin(), + vertices.begin() + i + 1); + // std::cout << "Total cofaces: " << cofaces.size() << std::endl; +} + +inline unsigned int build_rips_zigzag_filtration(std::vector > &simpls, + std::vector& dirs, + unsigned int numberOfPoints, + int seed = -1, + short unsigned skeleton = 2, + DistanceType multiplier = 6) +{ + // std::cout << "Building filtration" << std::endl; + unsigned int numberOfSimplices = 0; + + PointContainer points = compute_points(numberOfPoints, seed); + + // Construct distances and Rips generator + PairDistances distances(points); + Generator rips(distances); + + // Order vertices and epsilons (in maxmin fashion) + VertexVector vertices; + EpsilonVector epsilons; + EdgeVector edges; + + compute_vertices_and_epsilons(distances, vertices, epsilons); + + // Generate and sort all the edges + compute_edges(distances, vertices, epsilons, multiplier, edges); + + // Insert vertices + for (auto v : vertices) { + // Add a vertex + simpls.push_back({static_cast(v)}); + dirs.push_back(true); + ++numberOfSimplices; + } + + // Process vertices + dlog::progress progress(vertices.size()); + unsigned ce = 0; // index of the current one past last edge in the complex + SimplexSet cofaces; // record the cofaces of all the simplices that need to be removed and reinserted + + for (unsigned stage = 0; stage != vertices.size() - 1; ++stage) { + unsigned i = vertices.size() - 1 - stage; + + /* Increase epsilon */ + compute_positive_cofaces(distances, vertices, edges, epsilons, multiplier, rips, skeleton, ce, i, cofaces); + + for (auto& s : cofaces) { + // std::cout << "Inserting: " << s << std::endl; + simpls.emplace_back(s.begin(), s.end()); + dirs.push_back(true); + ++numberOfSimplices; + } + + /* Remove the vertex */ + // std::cout << "Removing vertex: " << vertices[i] << std::endl; + compute_negative_cofaces(vertices, epsilons, multiplier, rips, skeleton, i, cofaces); + + for (auto& s : cofaces | ba::reversed) { + // std::cout << "Removing: " << s << std::endl; + simpls.emplace_back(s.begin(), s.end()); + dirs.push_back(false); + } + + ++progress; + } + + std::cout << std::endl; + return numberOfSimplices; +} diff --git a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h new file mode 100644 index 0000000000..bccf73ab03 --- /dev/null +++ b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h @@ -0,0 +1,725 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Clément Maria + * + * Copyright (C) 2021 Inria + * + * Modification(s): + * - 2023/05 Hannah Schreiber: Rework of the interface, reorganization and debug + * - 2023/05 Hannah Schreiber: Addition of infinit bars + * - YYYY/MM Author: Description of the modification + */ + +#ifndef ZIGZAG_PERSISTENCE_H_ +#define ZIGZAG_PERSISTENCE_H_ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace Gudhi { +namespace zigzag_persistence { +//---------------------------------------------------------------------------------- +/** \class Zigzag_persistence Zigzag_persistence.h gudhi/Zigzag_persistence.h + * \brief Computation of the zigzag persistent homology of a zigzag + * filtered complex. + * + * \details The type ZigzagFilteredComplex::Simplex_key counts the number of + * insertions and + * deletions of simplices, which may be large in zigzag persistence and require + * more than 32 bits of storage. The type used (int, long, etc) should be chosen in + * consequence. Simplex_key must be signed. + * + * Over all insertions, the Simplex_key must be positive and strictly increasing + * when forward iterating along the zigzag filtration. + */ +template < typename ZigzagFilteredComplex + , typename ZigzagPersistenceOptions = Gudhi::persistence_matrix::Zigzag_options<> > +class Zigzag_persistence { +public: + typedef ZigzagFilteredComplex Complex; + typedef ZigzagPersistenceOptions Options; + /*** Types defined in the complex ***/ + // Data attached to each simplex to interface with a Property Map. + typedef typename Complex::Simplex_key Simplex_key;//must be signed + typedef typename Complex::Simplex_handle Simplex_handle; + typedef typename Complex::Vertex_handle Vertex_handle; + typedef typename Complex::Filtration_value Filtration_value; + // + + /** \brief Structure to store persistence intervals by their filtration values. + * + * \details By convention, interval \f$[b;d]\f$ are + * closed for finite indices b and d, and open for left-infinite and/or + * right-infinite endpoints.*/ + struct interval_filtration { + interval_filtration() {} + interval_filtration(int dim, Filtration_value b, Filtration_value d) : dim_(dim), b_(b), d_(d) {} + /** Returns the absolute length of the interval \f$|d-b|\f$. */ + Filtration_value length() { + if(b_ == d_) { return 0; } //otherwise inf - inf would return nan. + return std::abs(b_ - d_); + } + /** Returns the absolute length of the log values of birth and death, i.e. \f$|\log d - \log b|\f$.. */ + Filtration_value log_length() {//return the log-length + if(b_ == d_) { return 0; } //otherwise inf - inf would return nan. + return std::abs(log2((double)b_) - log2((double)d_)); + } + /** Returns the dimension of the homological feature corresponding to the + * interval. */ + int dim() const { return dim_; }//return the homological dimension of the interval + /** Returns the birth of the interval.*/ + Filtration_value birth() const { return b_; }//return the birth value + /** Returns the death of the interval.*/ + Filtration_value death() const { return d_; }//return the death value + /** Swaps the values of birth and death.*/ + void swap_birth_death() { std::swap(b_,d_); } + + private://note that we don't assume b_ <= d_ + int dim_; //homological dimension + Filtration_value b_; //filtration value associated to birth index + Filtration_value d_; //filtration value associated to death index + }; + + /** \brief Structure to store persistence intervals by their index values. + * + * \details By convention, interval [b;d] are + * closed for finite indices b and d, and open for left-infinite and/or + * right-infinite endpoints. + */ + struct interval_index { + interval_index() {} + interval_index(int dim, Simplex_key b, Simplex_key d) : dim_(dim), b_(b), d_(d) {} + /** Returns the dimension of the homological feature corresponding to the + * interval. */ + int dim() const { return dim_; }//return the homological dimension of the interval + /** Returns the birth index of the interval.*/ + Filtration_value birth() const { return b_; }//return the birth value + /** Returns the death index of the interval.*/ + Filtration_value death() const { return d_; }//return the death value + + private://note that we don't assume b_ <= d_ + int dim_; //homological dimension + Simplex_key b_; //filtration value associated to birth index + Simplex_key d_; //filtration value associated to death index + }; + +private: + /* Comparison function to sort intervals by decreasing log-length in the + * output persistence diagram, i.e., + * [f(b),f(d)]<[f(b'),f(d')] iff |log2(f(b))-log2(f(d))|> |log2(f(b'))-log2(f(d'))| + */ + struct cmp_intervals_by_log_length { + cmp_intervals_by_log_length(){} + bool operator()( interval_filtration p, interval_filtration q) + { + if(p.dim() != q.dim()) {return p.dim() < q.dim();}//lower dimension first + if(p.log_length() != q.log_length()) {return p.log_length() > q.log_length();} + if(p.birth() != q.birth()) {return p.birth() < q.birth();}//lex order + return p.death() < q.death(); + } + }; + /* Comparison function to sort intervals by decreasing length in the + * output persistence diagram, i.e., + * [f(b),f(d)]<[f(b'),f(d')] iff |f(b)-f(d)| > |f(b')-f(d')| + */ + struct cmp_intervals_by_length { + cmp_intervals_by_length(){} + bool operator()( interval_filtration p, interval_filtration q) + { + if(p.length() != q.length()) { return p.length() > q.length(); }//longest 1st + if(p.dim() != q.dim()) {return p.dim() < q.dim();}//lower dimension first + if(p.birth() != q.birth()) {return p.birth() < q.birth();}//lex order + return p.death() < q.death(); + } + }; + + using matrix_type = Gudhi::persistence_matrix::Matrix; + using index = Gudhi::persistence_matrix::index; + +public: + /** \brief Initialization of the Zigzag_persistence class. + * + * \param[in] cpx A model of ZigzagFilteredComplex. + * */ + Zigzag_persistence(unsigned int min_number_of_simplices = 0, int ignore_cycles_above_dim = -1) + : cpx_() + , dim_max_(ignore_cycles_above_dim) + , matrix_(min_number_of_simplices, + [this](index columnIndex1, index columnIndex2){ + return birth_ordering_.birth_order(births_.at(columnIndex1), births_.at(columnIndex2)); + }) + , birth_ordering_() + , persistence_diagram_() + , num_arrow_(-1) + , previous_filtration_value_(std::numeric_limits::infinity()) + , filtration_values_() {} + +private: + + /** Maintains the birth ordering <=b. Contains an std::map of size the number of + * non-zero rows of the homology matrix, at any time during the computation of + * zigzag persistence. + * + * By construction, we maintain the map satisfying + * 'birth_to_pos_[i] < birth_to_pos_[j]', + * with 0 <= i,j <= k indices in the quiver '0 \leftrightarrow ... \leftrightarrow i \leftrightarrow .. \leftrightarrow k' + * visited at time k of the algorithm (prefix of length k of the full zigzag + * filtration '0 \leftrightarrow ... \leftrightarrow i \leftrightarrow .. \leftrightarrow k \leftrightarrow ... \leftrightarrow n' that is studied), + * iff i k+1 forward, then j 0 -> 1 -> 2 <- 3 <- 4 -> 5 <- 6 etc + birth_ordering() : birth_to_pos_(), max_birth_pos_(0), min_birth_pos_(-1) {} + + //when the arrow key-1 -> key is forward, key is larger than any other index + //i < key in the birth ordering b k2 + bool reverse_birth_order(Simplex_key k1, Simplex_key k2) { + return birth_to_pos_[k1] > birth_to_pos_[k2]; + } + + private: + //birth_to_pos_[i] < birth_to_pos_[j] iff i birth_to_pos_; + //by construction, max_birth_pos_ (resp. min_birth_pos_) is strictly larger + //(resp. strictly smaller) than any value assigned to a key so far. + Simplex_key max_birth_pos_; + Simplex_key min_birth_pos_; + }; + +public: + /** \brief Computes the zigzag persistent homology of a zigzag filtered complex, + * using the reflection and transposition algorithm of \cite zigzag_reflection. + * + * \details After computation, the persistence diagram can be accessed via + * member method persistence_diagram, for the diagram with filtration + * values, or member method index_persistence_diagram, for the + * diagram with + * indices of paired simplices. + * + * + * matrix_, originally empty, maintains the set of chains, with a + * partition \f$ F \sqcup G \sqcup H\f$ + * representing a compatible homology basis as in \cite zigzag_reflection. + * + * Each simplex in the complex stores a key field that stores the index of + * its insertion in the zigzag filtration. + * + * The algorithm maintains a compatible homology basis for the zigzag filtration. + * + * \f$$\emptyset = K_0 \leftrightarrow (...) \leftrightarrow K_i \leftarrow ... \leftarrow \emptyset\f$$ + * + * where the prefix from \f$K_0\f$ to \f$K_i\f$ is equal to the i-th prefix of + * the input zigzag + * filtration given by cpx_.filtration_simplex_range(), and + * the suffix + * (from \f$K_i\f$ + * to the right) is a sequence of simplex removals. Due to the structure of + * reflection diamonds, the removals are in reverse order of the insertions, to + * reduce the amount of transposition diamonds. + * + * Consequently, using cpx_.key(zzsh) as indexing for the matrix + * rows/cells, + * with the natural order on integers, makes our homology matrix matrix_ upper + * triangular for the suffix \f$K_i \leftarrow ... \leftarrow 0\f$, seen as a + * standard persistence + * filtration. At \f$K_i\f$, the natural order on integers is also equivalent to the + * death-order \f$\leq_d\f$ (because all arrows in the suffix are backward). + * + * Insertion: cpx_.key(*zzit) is a strictly increasing sequence + * for zzit + * insertion of cells (does not need to be contiguous). However, for every forward + * arrow, we have cpx_.key(*zzit) == num_arrows_. + * Removal: cpx_.key(*zzit) gives the assigned key (during past + * insertion) of a + * cell == *zzit during a removal. We use num_arrows_ + * to record the deaths in the + * persistence diagram. + * Insertion and Removal: zzit.filtration() is totally monotone. + * Note that the + * iterator encodes the filtration, and not the cells within the complex structure. + */ + + template> + void insert_simplex(const VertexRange& simplex, Filtration_value filtration_value) + { + if (dim_max_ != -1 && simplex.size() > static_cast(dim_max_) + 1) return; + + ++num_arrow_; + + if (filtration_value != previous_filtration_value_) //check whether the filt value has changed + { //consecutive pairs (i,f), (j,f') mean simplices of index k in [i,j-1] have + previous_filtration_value_ = filtration_value; //filtration value f + filtration_values_.emplace_back(num_arrow_, previous_filtration_value_); + } + + std::pair res = cpx_.insert_simplex(simplex, filtration_value); + GUDHI_CHECK(res.second, "Zigzag_persistence::insert_simplex - insertion of a simplex already in the complex"); + cpx_.assign_key(res.first, num_arrow_); + forward_arrow(res.first); + } + + template> + void remove_simplex(const VertexRange& simplex, Filtration_value filtration_value) + { + if (dim_max_ != -1 && simplex.size() > static_cast(dim_max_) + 1) return; + + ++num_arrow_; + + Simplex_handle sh = cpx_.find(simplex); + GUDHI_CHECK(sh != cpx_.null_simplex(), "Zigzag_persistence::remove_simplex - removal of a simplex not in the complex"); + + if (filtration_value != previous_filtration_value_) //check whether the filt value has changed + { //consecutive pairs (i,f), (j,f') mean simplices of index k in [i,j-1] have + previous_filtration_value_ = filtration_value; //filtration value f + filtration_values_.emplace_back(num_arrow_, previous_filtration_value_); + } + + backward_arrow(sh); + cpx_.remove_maximal_simplex(sh); + } + + template>, + class FiltrationRange = std::initializer_list> + void insert_simplices_contiguously(const SimplexRange& simplices, const FiltrationRange& filtration_values) + { + auto simplexIt = simplices.begin(); + auto filIt = filtration_values.begin(); + for (; simplexIt != simplices.end(); ++simplexIt, ++filIt) { + insert_simplex(*simplexIt, *filIt); + } + } + + template>, + class FiltrationRange = std::initializer_list> + void remove_simplices_contiguously(const SimplexRange& simplices, const FiltrationRange& filtration_values) + { + auto simplexIt = simplices.begin(); + auto filIt = filtration_values.begin(); + for (; simplexIt != simplices.end(); ++simplexIt, ++filIt) { + remove_simplex(*simplexIt, *filIt); + } + } + + template + void insert_simplices_contiguously(SimplexRangeIterators simplex_range_start, + SimplexRangeIterators simplex_range_end, + FiltrationRangeIterators filtration_range_start) + { + for (; simplex_range_start != simplex_range_end; ++simplex_range_start, ++filtration_range_start) { + insert_simplex(*simplex_range_start, *filtration_range_start); + } + } + + template + void remove_simplices_contiguously(SimplexRangeIterators simplex_range_start, + SimplexRangeIterators simplex_range_end, + FiltrationRangeIterators filtration_range_start) + { + for (; simplex_range_start != simplex_range_end; ++simplex_range_start, ++filtration_range_start) { + remove_simplex(*simplex_range_start, *filtration_range_start); + } + } + + void print_current_complex(){ + for (auto& sh : cpx_.complex_simplex_range()){ + for (auto v : cpx_.simplex_vertex_range(sh)){ + std::cout << v << " "; + } + std::cout << " - " << cpx_.filtration(sh) << "\n"; + } + } + +private: + /** \brief Computes the boundary cycle of the new simplex zzsh, and express it as a + * sum of cycles. If all cycles are boundary cycles, i.e., columns with G-index + * in the matrix, then [\partial zzsh] = 0 and we apply an injective diamond to + * the zigzag module. Otherwise, we keep reducing with boundary- and live- cycles, + * i.e., columns with (F \cup G)-indices, and then apply a surjective diamond to + * the zigzag module. + */ + void forward_arrow( Simplex_handle zzsh ) + { //maintain the <=b order + birth_ordering_.add_birth_forward(num_arrow_); + + //Reduce the boundary of zzsh in the basis of cycles. + //Compute the simplex keys of the simplices of the boundary of zzsh. + std::set< Simplex_key > col_bsh; //set maintains the natural order on indices + for( auto b_sh : cpx_.boundary_simplex_range(zzsh) ) + { col_bsh.insert(cpx_.key(b_sh)); } + + std::vector chains_in_F; + matrix_.insert_boundary(num_arrow_, col_bsh, chains_in_F); + + if (!chains_in_F.empty()){ + births_.try_emplace(matrix_.get_column_with_pivot(num_arrow_), -2); + surjective_reflection_diamond(zzsh, chains_in_F); + } else { + births_.try_emplace(matrix_.get_column_with_pivot(num_arrow_), num_arrow_); + } + } + + /** The vector chains_in_F is sorted by decreasing lowest index values in the + * columns corresponding to the chains, due to its computation in the reduction of + * \partial zzsh in forward_arrow(...). It is equivalent to decreasing death index + * order w.r.t. the & chains_in_F) + { //fp is the largest death index for <=d + //Set col_fp: col_fp <- col_f1+...+col_fp (now in G); preserves lowest idx + auto chain_fp = chains_in_F.front(); //col_fp, with largest death bool + { return birth_ordering_.reverse_birth_order(k1,k2); };//true iff b(k1) >b b(k2) + + //available_birth: for all i by >d value of the d_i, + //contains at step i all b_j, j > i, and maybe b_i if not stolen + std::set< Simplex_key, decltype(cmp_birth) > available_birth(cmp_birth); + //for f1 to f_{p} (i by <=d), insertion in available_birth_to_fidx sorts by >=b + for(auto &chain_f : chains_in_F) { available_birth.insert(births_.at(chain_f)); } + + auto maxb_it = available_birth.begin();//max birth cycle + auto maxb = *maxb_it; //max birth value, for persistence diagram + available_birth.erase(maxb_it); //remove max birth cycle (stolen) + + auto last_modified_chain_it = chains_in_F.rbegin(); + + //consider all death indices by increasing the maximal availabe death. + //Let c_1 ... c_f be the chains s.t. <[c_1+...+c_f]> is the kernel and + // death(c_i) >d death(c_i-1). If the birth of c_i is not available, we set + //c_i <- c_i + c_i-1 + ... + c_1, which is [c_i + c_i-1 + ... + c_1] on + //the right (of death the maximali <=> the maxj>k, are indeed c_j + //set c_i <- c_i + (c_i-1) + ... + (c_k+1) + (c_k + ... + c_1) + for(auto chain_passed_it = last_modified_chain_it;//all with smaller modified_columns; + const auto& row = matrix_.get_row(cpx_.key(zzsh)); + modified_columns.reserve(row.size()); + std::transform(row.begin(), + row.end(), + std::back_inserter(modified_columns), + [](const auto& cell) { return cell.get_column_index(); }); + //Sort by left-to-right order in the matrix_ (no order maintained in rows) + std::stable_sort(modified_columns.begin(),modified_columns.end(), + [this](index i1, index i2){ + return matrix_.get_pivot(i1) < matrix_.get_pivot(i2); + }); + + //Modifies the pointer curr_col, not the other one. + for(auto other_col_it = std::next(modified_columns.begin()); + other_col_it != modified_columns.end(); ++other_col_it) + { + // index ci = other_col_it->get_column_index(); + // ++other_col_it; //vine swap unvalidates iterator + curr_col = matrix_.vine_swap_with_z_eq_1_case(curr_col, *other_col_it); + } + + //curr_col points to the column to remove by restriction of K to K-{\sigma} + if(!matrix_.get_column(curr_col).is_paired()) { // in F + int dim_zzsh = cpx_.dimension(zzsh); + if(dim_max_ == -1 || (dim_max_ != -1 && dim_zzsh < dim_max_)) { //don't record intervals of max dim + persistence_diagram_.emplace_back( dim_zzsh + , births_.at(curr_col) + , num_arrow_);// -1); + } + } + else { //in H -> paired with c_g, that now belongs to F now + births_.at(matrix_.get_column(curr_col).get_paired_chain_index()) = num_arrow_; + } + + //cannot be in G as the removed simplex is maximal + matrix_.remove_maximal_simplex(cpx_.key(zzsh)); + } + +public: + /** \brief Returns the index persistence diagram as an std::list of intervals.*/ + const std::list< interval_index > & index_persistence_diagram() const + { + return persistence_diagram_; + } + + /** \brief Returns the filtration values \f$[f(b),f(d)]\f$ (generally real-valued) + * associated to the indices \f$[b,d]\f$ (integer valued) of the insertion or + * deletion of a simplex in the zigzag filtration. + * + * \details Used to convert a persistent interval \f$[b,d]\f$, computed by the + * persistent homology algorithm, into its filtration valued version + * \f$[f(b),f(d)]\f$ used in the persistence barcode. The information + * index->filtration is stored in the member filtration_values_ of + * the class Zigzag_persistence. + * + * @param[in] b_key, d_key The indices of birth and death of a persistent + * interval. + * + * @param[out] std::pair A pair of real values \f$(f(b),f(d))\f$. + */ + std::pair index_to_filtration( + Simplex_key b_key, Simplex_key d_key) { + // filtration_values_ must be sorted by increasing keys. + auto it_b = //lower_bound(x) returns leftmost y s.t. x <= y + std::lower_bound( filtration_values_.begin(), filtration_values_.end() + , std::pair(b_key + , std::numeric_limits::infinity() ) + , []( std::pair p1 + , std::pair p2) + { return p1.first < p2.first; } + ); + if(it_b == filtration_values_.end() || it_b->first > b_key) { --it_b; } + //it points to the rightmost z such that z <= x + + auto it_d = // + std::lower_bound( filtration_values_.begin(), filtration_values_.end() + , std::pair(d_key + , std::numeric_limits::infinity() ) + , []( std::pair p1 + , std::pair p2) + { return p1.first < p2.first; } + ); + if(it_d == filtration_values_.end() || it_d->first > d_key) { --it_d; } + + return std::make_pair(it_b->second, it_d->second); + } + + /** \brief Writes the persistence diagram in a file. + * + * \details The filtration values are given by the zigzag persistence iterator, that assigns + * to any insertion or deletion of a simplex a filtration value ; we say that an + * arrow has an index \f$i\f$, and a corresponding filtration value \f$f(i)\f$. + * Reading a zigzag filtration from left to right, indices are strictly + * monotonically increasing, and the associated filtration values are monotonous + * (not necessarily + * strictly, either increasing or decreasing). + * + * Consider two consecutive arrows (insertion or deletion): + * + * \f$$K_1 \leftrightarrow K_2 \leftrightarrow K_3\f$$ + * + * with respectively indices \f$i\f$ (left) and \f$i+1\f$ (right), and associated + * filtration values \f$f(i)\f$ and \f$f(i+1)\f$ respectively. + * + * If, the arrow \f$K_2 \leftrightarrow K_3\f$ leads to the creation of a new + * homology feature in \f$K_3\f$, it creates an (indexed) persistent interval + * \f$[\f$i+1; \cdot\f$, and a corresponding (filtration) persistent interval + * \f$[f(i+1); \cdot]\f$ in the persistence diagram. + * + * If a homology feature in \f$K_2\f$ is destroyed by the arrow \f$K_2 \leftrightarrow K_3\f$, it closes an (indexed) + * interval \f$[\cdot ; i+1]\f$, and a corresponding (filtration) persistent + * interval \f$[\cdot ; f(i+1)]\f$ in the persistence diagram. + * + * For example, in an oscillating Rips zigzag filtration, if, in the following + * chunk of filtration: + * + * \f$R_{\eta \varepsilon_i}(P_i) \rightarrow \cdots \leftarrow R_{\eta \varepsilon_{i+1}}(P_{i+1}),\f$ + * + * if anything is created by any of the arrows above, it leads to an interval + * \f$[\varepsilon_{i+1}; \cdot]\f$. If anything is destroyed by any of the arrows + * above, if leads to an interval \f$[\cdot;\varepsilon_i]\f$. Note that we may + * have \f$\varepsilon_i > \varepsilon_{i+1}\f$. + * + * The bars are ordered by decreasing length. + * + * @param[in] os the output stream in which the diagram is written. + * @param[in] shortest_interval all intervals of lenght smaller or equal to + * this value are ignore. Default is 0. + */ + void persistence_diagram( std::ostream& os + , Filtration_value shortest_interval = 0.) { + + std::stable_sort(filtration_values_.begin(), filtration_values_.end(), + []( std::pair< Simplex_key, Filtration_value > p1 + , std::pair< Simplex_key, Filtration_value > p2 ) + { return p1.first < p2.first; } + ); + + std::vector< interval_filtration > tmp_diag; + tmp_diag.reserve(persistence_diagram_.size()); + for(auto bar : persistence_diagram_) + { + Filtration_value birth,death; + std::tie(birth,death) = index_to_filtration(bar.birth(), bar.death()); + + if( std::abs(birth - death) > shortest_interval ) { + tmp_diag.emplace_back(bar.dim(), birth, death ); + } + } + // cmp_intervals_by_length cmp; + std::stable_sort(tmp_diag.begin(), tmp_diag.end(), cmp_intervals_by_length()); + + os << "# dim birth death [length]\n"; + for(auto bar : tmp_diag) { + if(bar.birth() > bar.death()) { bar.swap_birth_death(); } + os << bar.dim() << " " << bar.birth() << " " << bar.death() << + " - [" << bar.length() << "] \n"; + } + } + + /** \brief Returns the persistence diagram as a vector of real-valued intervals. */ + std::vector< interval_filtration > + persistence_diagram(Filtration_value shortest_interval = 0., bool include_infinit_bars = false) + { + std::stable_sort(filtration_values_.begin(), filtration_values_.end(), + []( std::pair< Simplex_key, Filtration_value > p1 + , std::pair< Simplex_key, Filtration_value > p2 ) + { return p1.first < p2.first; } + ); + + std::vector< interval_filtration > diag; + diag.reserve(persistence_diagram_.size()); + for(auto bar : persistence_diagram_) + { + Filtration_value birth,death; + std::tie(birth,death) = index_to_filtration(bar.birth(), bar.death()); + + if( std::abs(birth - death) > shortest_interval ) { + diag.emplace_back(bar.dim(), birth, death ); + } + } + //put lower value as birth + for(auto &bar : diag) { + if( bar.birth() > bar.death() ) { bar.swap_birth_death(); } + } + std::stable_sort(diag.begin(), diag.end(), cmp_intervals_by_length()); + + auto birth = + [this](Simplex_key b_key) { + auto it_b = // lower_bound(x) returns leftmost y s.t. x <= y + std::lower_bound(filtration_values_.begin(), filtration_values_.end(), + std::pair( + b_key, std::numeric_limits::infinity()), + [](std::pair p1, + std::pair p2) { return p1.first < p2.first; }); + if (it_b == filtration_values_.end() || it_b->first > b_key) { + --it_b; + } + return it_b->second; + }; + + //TODO: better recording? + if (include_infinit_bars) { + for (unsigned int i = 0; i < matrix_.get_number_of_columns(); ++i) { + const auto& col = matrix_.get_column(i); + if (!col.is_paired()) + diag.emplace_back(col.get_dimension(), birth(col.get_pivot()), std::numeric_limits::infinity()); + } + } + + return diag; + } + +private: + Complex cpx_; // complex + int dim_max_;//max dim complex + matrix_type matrix_; // 0 ... m-1 + std::unordered_map births_; + birth_ordering birth_ordering_; + std::list< interval_index > persistence_diagram_; + Simplex_key num_arrow_; //current index + Filtration_value previous_filtration_value_; + // filtration_values stores consecutive pairs (i,f) , (j,f') with f != f', + // meaning that all inserted simplices with key in [i;j-1] have filtration value f + //i is the smallest simplex index whose simplex has filtration value f. + std::vector< std::pair< Simplex_key, Filtration_value > > filtration_values_; +};//end class Zigzag_persistence + +} //namespace zigzag_persistence + +} //namespace Gudhi + +#endif //ZIGZAG_PERSISTENCE_H_ + diff --git a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence_old.h b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence_old.h new file mode 100644 index 0000000000..c364fc10c2 --- /dev/null +++ b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence_old.h @@ -0,0 +1,1326 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Clément Maria + * + * Copyright (C) 2021 Inria + * + * Modification(s): + * - 2023/05 Hannah Schreiber: Rework of the interface, reorganization and debug + * - 2023/05 Hannah Schreiber: Addition of infinit bars + * - YYYY/MM Author: Description of the modification + */ + +#ifndef ZIGZAG_PERSISTENCE_H_ +#define ZIGZAG_PERSISTENCE_H_ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace Gudhi { +namespace zigzag_persistence { +//represent matrix columns with sets. +struct Zigzag_persistence_colset; +//---------------------------------------------------------------------------------- +/** \class Zigzag_persistence Zigzag_persistence.h gudhi/Zigzag_persistence.h + * \brief Computation of the zigzag persistent homology of a zigzag + * filtered complex. + * + * \details The type ZigzagFilteredComplex::Simplex_key counts the number of + * insertions and + * deletions of simplices, which may be large in zigzag persistence and require + * more than 32 bits of storage. The type used (int, long, etc) should be chosen in + * consequence. Simplex_key must be signed. + * + * Over all insertions, the Simplex_key must be positive and strictly increasing + * when forward iterating along the zigzag filtration. + */ +template < typename ZigzagFilteredComplex + , typename ZigzagPersistenceOptions = Zigzag_persistence_colset > +class Zigzag_persistence { +public: + typedef ZigzagFilteredComplex Complex; + typedef ZigzagPersistenceOptions Options; + /*** Types defined in the complex ***/ + // Data attached to each simplex to interface with a Property Map. + typedef typename Complex::Simplex_key Simplex_key;//must be signed + typedef typename Complex::Simplex_handle Simplex_handle; + typedef typename Complex::Vertex_handle Vertex_handle; + typedef typename Complex::Filtration_value Filtration_value; + // +private: + /*** Matrix cells and columns types ***/ + struct matrix_row_tag; // for horizontal traversal in the persistence matrix + struct matrix_column_tag; // for vertical traversal in the persistence matrix + typedef boost::intrusive::list_base_hook< + boost::intrusive::tag < matrix_row_tag > //allows .unlink() + , boost::intrusive::link_mode < boost::intrusive::auto_unlink > + > base_hook_matrix_row_list; + //hook for a column represented by an intrusive list + typedef boost::intrusive::list_base_hook < //faster hook, less safe + boost::intrusive::tag < matrix_column_tag > + //, boost::intrusive::link_mode < boost::intrusive::auto_unlink > + , boost::intrusive::link_mode < boost::intrusive::safe_link > + > base_hook_matrix_column_list; + //hook for a column represented by an intrusive set + typedef boost::intrusive::set_base_hook < //faster hook, less safe + boost::intrusive::tag < matrix_column_tag > + , boost::intrusive::optimize_size + //, boost::intrusive::link_mode < boost::intrusive::auto_unlink > + , boost::intrusive::link_mode < boost::intrusive::safe_link > + > base_hook_matrix_column_set; + //the data structure for columns is selected in Options::searchable_column + typedef typename std::conditional::type base_hook_matrix_column; + //the only option for rows is the intrusive list + typedef base_hook_matrix_row_list base_hook_matrix_row; + + /* Cell for the persistence matrix. Contains a key for the simplex index, and + * horizontal and vertical hooks for connections within sparse rows and columns. + */ + struct matrix_chain;//defined below, a chain contains a row, a column, and more + /** Type of cell in the sparse homology matrix. + * For now, only coefficients in Z/2Z, so only the row index (called key) is + * stored in the cell. + */ + struct Zigzag_persistence_cell + : public base_hook_matrix_row, public base_hook_matrix_column + { + Zigzag_persistence_cell(Simplex_key key, matrix_chain *self_chain) + : key_(key) + , self_chain_(self_chain) + {} + + Simplex_key key() const { return key_; } + //compare by increasing key value + friend bool operator<( const Zigzag_persistence_cell& c1 + , const Zigzag_persistence_cell& c2) { + return c1.key() < c2.key(); + } + /* In a matrix M, if M[i][j] == x not 0, we represent a cell with key_=i + * (the row index), + * self_chain_ points to the chain corresponding the j-th column, and x_=x. + * Currently, only Z/2Z coefficients are implemented, so x=1. + * + * A cell is connected to all cells of the same row, and all cells of the same + * column, via the two boost::intrusive hooks (row and column). + */ + Simplex_key key_; + matrix_chain * self_chain_; + }; + + //Homology matrix cell + typedef Zigzag_persistence_cell Cell; + // Remark: constant_time_size must be false because base_hook_matrix_row and + // base_hook_matrix_column have auto_unlink link_mode + //vertical list of cells, forming a matrix column stored as an intrusive list + typedef boost::intrusive::list < + Cell + , boost::intrusive::constant_time_size + , boost::intrusive::base_hook< base_hook_matrix_column_list > > Column_list; + //vertical list of cells, forming a matrix column stored as an intrusive set + typedef boost::intrusive::set < + Cell + , boost::intrusive::constant_time_size + , boost::intrusive::base_hook< base_hook_matrix_column_set > > Column_set; + //choice encoded in Options::searchable_column. a column can be + //iterated through, and keys are read in strictly increasing natural order. + typedef typename std::conditional< + Options::searchable_column, + Column_set, + Column_list >::type Column; + //horizontal list of cells, forming a matrix row, no particular order on keys. + typedef boost::intrusive::list < + Cell + , boost::intrusive::constant_time_size + , boost::intrusive::base_hook< base_hook_matrix_row > > Row_list; + //rows are encoded by lists. need to be sorted and traversed + typedef Row_list Row; + + /* Chain for zigzag persistence. A chain stores: + * - a matrix column (col_i) that represents the chain as a sum of simplices + * (represented by their unique key, stored in the cells of the sparse column), + * - a matrix row of all elements of index the lowest index of the column (row_i), + * - is paired with another chain, indicating its type F, G, or H, + * - has a direct access to its lowest index. + */ + struct matrix_chain { + /* Trivial constructor, birth == -3 */ + matrix_chain() : column_(nullptr), row_(nullptr), paired_col_(nullptr), + birth_(-3), lowest_idx_(-1) {} + + /* Creates a matrix chain of type F with one cell of index 'key'. */ + matrix_chain(Simplex_key key) + : paired_col_(nullptr), birth_(key), lowest_idx_(key) + { + // Cell *new_cell = new Cell(key, this); + Cell *new_cell = cellPool_.construct(key, this); + if constexpr(Options::searchable_column) { column_.insert(*new_cell); } + else { column_.push_back(*new_cell); } + row_.push_back(*new_cell); + } + /* Creates a matrix chain of type F with new cells of key indices given by a + * range. Birth and lowest indices are given by 'key'. + * The range [beg,end) must be sorted by increasing key values, the same + * order as the column_ when read from column_.begin() to column_.end(). + * + * SimplexKeyIterator value_type must be Simplex_key. + * KeyToMatrixChain must be of type + * std::map< Simplex_key, typename std::list::iterator > + */ + template< typename SimplexKeyIterator, typename KeyToMatrixChain > + matrix_chain(Simplex_key key, SimplexKeyIterator beg, SimplexKeyIterator end, KeyToMatrixChain &lowidx_to_matidx) + : paired_col_(nullptr), birth_(key), lowest_idx_(key) + { + for(SimplexKeyIterator it = beg; it != end; ++it) + { + // Cell *new_cell = new Cell(*it, this);//create a new cell + Cell *new_cell = cellPool_.construct(*it, this); + //insertion in the column + if constexpr(Options::searchable_column) { + column_.insert(column_.end(), *new_cell); //ordered range + } + else { column_.push_back(*new_cell); } + //insertion in a row, not corresponding to the row stored in this->row_. + lowidx_to_matidx[*it]->row_.push_back( *new_cell ); + } + //Add the bottom coefficient for the chain + // Cell *new_cell = new Cell(key, this); + Cell *new_cell = cellPool_.construct(key, this); + //insertion in the column, key is larger than any *it in [beg, end) above. + if constexpr(Options::searchable_column) { + column_.insert(column_.end(), *new_cell); + } + else { column_.push_back(*new_cell); } + //insertion of row_, that stores no particular order. + row_.push_back( *new_cell ); + } + + /* Creates a matrix chain of type H with new cells of key indices given by a + * range. Birth and lowest indices are given by 'key'. + * The range [beg,end) must be sorted by increasing key values, the same + * order as the column_ when read from column_.begin() to column_.end(). + * + * SimplexKeyIterator value_type must be Simplex_key. + * KeyToMatrixChain must be of type + * std::map< Simplex_key, typename std::list::iterator > + */ + template< typename SimplexKeyIterator, typename KeyToMatrixChain > + matrix_chain(Simplex_key key, matrix_chain *paired_col, SimplexKeyIterator beg, SimplexKeyIterator end, KeyToMatrixChain &lowidx_to_matidx) + : paired_col_(paired_col), birth_(-2), lowest_idx_(key) + { + for(SimplexKeyIterator it = beg; it != end; ++it) + { + // Cell * new_cell = new Cell(*it, this);//create a new cell + Cell *new_cell = cellPool_.construct(*it, this); + //insertion in the column + if constexpr(Options::searchable_column) { + column_.insert(column_.end(), *new_cell); //ordered range + } + else { column_.push_back(*new_cell); } + //insertion in a row, not corresponding to the row stored in this->row_. + lowidx_to_matidx[*it]->row_.push_back( *new_cell ); + } + //Add the bottom coefficient for the chain + // Cell * new_cell = new Cell(key, this); + Cell *new_cell = cellPool_.construct(key, this); + //insertion in the column, key is larger than any *it in [beg, end) above. + if constexpr(Options::searchable_column) { + column_.insert(column_.end(), *new_cell); + } + else { column_.push_back(*new_cell); } + //insertion of row_, that stores no particular order. + row_.push_back( *new_cell ); + } + + /* Erase the chain, all cells were allocated with operator new. */ + ~matrix_chain() + { //empty the column, call delete on all cells + for(typename Column::iterator c_it = column_.begin(); c_it != column_.end(); ) + { + auto tmp_it = c_it; ++c_it; + Cell * tmp_cell = &(*tmp_it); + tmp_it->base_hook_matrix_row::unlink(); //rm from row + column_.erase(tmp_it); + cellPool_.destroy(tmp_cell); + // delete tmp_cell; + } + } + + /* Returns the chain with which *this is paired in the F,G,H classification. + * If in F (i.e., paired with no other column), return nullptr.*/ + matrix_chain * paired_chain() const { return paired_col_; } + /* Assign a paired chain. */ + void assign_paired_chain(matrix_chain *other_col) { paired_col_ = other_col; } + /* Access the column. */ + Column & column() { return column_; } + /* Returns the birth index (b >= 0) of the chain if the column is in F. + * Returns -2 if the chain is in H, and -1 if the chain is in G. */ + Simplex_key birth() const { return birth_; } + /* Assign a birth index to the chain. */ + void assign_birth(Simplex_key b) { birth_ = b; } + void assign_birth(matrix_chain *other) { birth_ = other->birth_; } + /* Returns true iff the chain is indexed in F. */ + bool inF() const { return birth_ > -1; } + /* Returns true iff the chain is indexed in G. */ + bool inG() const { return birth_ == -1; } + /* Returns true iff the chain is indexed in H. */ + bool inH() const { return birth_ == -2; } + Simplex_key lowest_idx() const { return lowest_idx_; } + + Column column_ ; //col at index i, with lowest index i + Row row_ ; //row at index i + matrix_chain * paired_col_ ; //\in F -> nullptr, \in H -> g, \in G -> h + Simplex_key birth_ ; //\in F -> b, \in H -> -2 \in G -> -1 + Simplex_key lowest_idx_ ; //lowest_idx_ = i (upper triangular matrix) + inline static Simple_object_pool cellPool_; + }; + +public: + /** \brief Structure to store persistence intervals by their filtration values. + * + * \details By convention, interval \f$[b;d]\f$ are + * closed for finite indices b and d, and open for left-infinite and/or + * right-infinite endpoints.*/ + struct interval_filtration { + interval_filtration() {} + interval_filtration(int dim, Filtration_value b, Filtration_value d) : dim_(dim), b_(b), d_(d) {} + /** Returns the absolute length of the interval \f$|d-b|\f$. */ + Filtration_value length() { + if(b_ == d_) { return 0; } //otherwise inf - inf would return nan. + return std::abs(b_ - d_); + } + /** Returns the absolute length of the log values of birth and death, i.e. \f$|\log d - \log b|\f$.. */ + Filtration_value log_length() {//return the log-length + if(b_ == d_) { return 0; } //otherwise inf - inf would return nan. + return std::abs(log2((double)b_) - log2((double)d_)); + } + /** Returns the dimension of the homological feature corresponding to the + * interval. */ + int dim() const { return dim_; }//return the homological dimension of the interval + /** Returns the birth of the interval.*/ + Filtration_value birth() const { return b_; }//return the birth value + /** Returns the death of the interval.*/ + Filtration_value death() const { return d_; }//return the death value + /** Swaps the values of birth and death.*/ + void swap_birth_death() { std::swap(b_,d_); } + + private://note that we don't assume b_ <= d_ + int dim_; //homological dimension + Filtration_value b_; //filtration value associated to birth index + Filtration_value d_; //filtration value associated to death index + }; + + /** \brief Structure to store persistence intervals by their index values. + * + * \details By convention, interval [b;d] are + * closed for finite indices b and d, and open for left-infinite and/or + * right-infinite endpoints. + */ + struct interval_index { + interval_index() {} + interval_index(int dim, Simplex_key b, Simplex_key d) : dim_(dim), b_(b), d_(d) {} + /** Returns the dimension of the homological feature corresponding to the + * interval. */ + int dim() const { return dim_; }//return the homological dimension of the interval + /** Returns the birth index of the interval.*/ + Filtration_value birth() const { return b_; }//return the birth value + /** Returns the death index of the interval.*/ + Filtration_value death() const { return d_; }//return the death value + + private://note that we don't assume b_ <= d_ + int dim_; //homological dimension + Simplex_key b_; //filtration value associated to birth index + Simplex_key d_; //filtration value associated to death index + }; + +private: + /* Comparison function to sort intervals by decreasing log-length in the + * output persistence diagram, i.e., + * [f(b),f(d)]<[f(b'),f(d')] iff |log2(f(b))-log2(f(d))|> |log2(f(b'))-log2(f(d'))| + */ + struct cmp_intervals_by_log_length { + cmp_intervals_by_log_length(){} + bool operator()( interval_filtration p, interval_filtration q) + { + if(p.dim() != q.dim()) {return p.dim() < q.dim();}//lower dimension first + if(p.log_length() != q.log_length()) {return p.log_length() > q.log_length();} + if(p.birth() != q.birth()) {return p.birth() < q.birth();}//lex order + return p.death() < q.death(); + } + }; + /* Comparison function to sort intervals by decreasing length in the + * output persistence diagram, i.e., + * [f(b),f(d)]<[f(b'),f(d')] iff |f(b)-f(d)| > |f(b')-f(d')| + */ + struct cmp_intervals_by_length { + cmp_intervals_by_length(){} + bool operator()( interval_filtration p, interval_filtration q) + { + if(p.length() != q.length()) { return p.length() > q.length(); }//longest 1st + if(p.dim() != q.dim()) {return p.dim() < q.dim();}//lower dimension first + if(p.birth() != q.birth()) {return p.birth() < q.birth();}//lex order + return p.death() < q.death(); + } + }; + +public: + /** \brief Initialization of the Zigzag_persistence class. + * + * \param[in] cpx A model of ZigzagFilteredComplex. + * */ + Zigzag_persistence(int ignore_cycles_above_dim = -1) + : cpx_() + , dim_max_(ignore_cycles_above_dim) + , lowidx_to_matidx_() + , matrix_() + , birth_ordering_() + , persistence_diagram_() + , num_arrow_(-1) + , previous_filtration_value_(std::numeric_limits::infinity()) + , filtration_values_() {} + +private: + /* Set c1 <- c1 + c2, assuming canonical order of indices induced by the order in + * the vertical lists. self1 is the matrix_chain whose column is c1, for self + * reference of the new cells. + */ + void plus_equal_column(matrix_chain * self1, Column & c1, Column & c2) + { + //insert all elements of c2 in c1, in O(|c2| * log(|c1|+|c2|)) + if constexpr (Options::searchable_column) { + for(auto &cell : c2) { + auto it1 = c1.find(cell); + if(it1 != c1.end()) {//already there => remove as 1+1=0 + Cell * tmp_ptr = &(*it1); + it1->base_hook_matrix_row::unlink(); //unlink from row + c1.erase(it1); //remove from col + matrix_chain::cellPool_.destroy(tmp_ptr); + // delete tmp_ptr; + } + else {//not there, insert new cell + // Cell *new_cell = new Cell(cell.key(), self1); + Cell *new_cell = matrix_chain::cellPool_.construct(cell.key(), self1); + c1.insert(*new_cell); + lowidx_to_matidx_[cell.key()]->row_.push_back(*new_cell);//row link,no order + } + } + } + else {//traverse both columns doing a standard column addition, in O(|c1|+|c2|) + auto it1 = c1.begin(); auto it2 = c2.begin(); + while(it1 != c1.end() && it2 != c2.end()) + { + if(it1->key() < it2->key()) { ++it1; } + else { + if(it1->key() > it2->key()) { + // Cell * new_cell = new Cell(it2->key(), self1); + Cell *new_cell = matrix_chain::cellPool_.construct(it2->key(), self1); + c1.insert(it1, *new_cell); //col link, in order + lowidx_to_matidx_[it2->key()]->row_.push_back(*new_cell);//row link,no order + ++it2; + } + else { //it1->key() == it2->key() + auto tmp_it = it1; ++it1; ++it2; + Cell * tmp_ptr = &(*tmp_it); + tmp_it->base_hook_matrix_row::unlink(); //unlink from row + c1.erase(tmp_it); //remove from col + matrix_chain::cellPool_.destroy(tmp_ptr); + // delete tmp_ptr; + } + } + } + while(it2 != c2.end()) {//if it1 reached the end of its column, but not it2 + // Cell * new_cell = new Cell(it2->key(),self1); + Cell *new_cell = matrix_chain::cellPool_.construct(it2->key(), self1); + lowidx_to_matidx_[it2->key()]->row_.push_back(*new_cell); //row links + c1.push_back(*new_cell); + ++it2; + } + } + } + + /** Maintains the birth ordering <=b. Contains an std::map of size the number of + * non-zero rows of the homology matrix, at any time during the computation of + * zigzag persistence. + * + * By construction, we maintain the map satisfying + * 'birth_to_pos_[i] < birth_to_pos_[j]', + * with 0 <= i,j <= k indices in the quiver '0 \leftrightarrow ... \leftrightarrow i \leftrightarrow .. \leftrightarrow k' + * visited at time k of the algorithm (prefix of length k of the full zigzag + * filtration '0 \leftrightarrow ... \leftrightarrow i \leftrightarrow .. \leftrightarrow k \leftrightarrow ... \leftrightarrow n' that is studied), + * iff i k+1 forward, then j 0 -> 1 -> 2 <- 3 <- 4 -> 5 <- 6 etc + birth_ordering() : birth_to_pos_(), max_birth_pos_(0), min_birth_pos_(-1) {} + + //when the arrow key-1 -> key is forward, key is larger than any other index + //i < key in the birth ordering b k2 + bool reverse_birth_order(Simplex_key k1, Simplex_key k2) { + return birth_to_pos_[k1] > birth_to_pos_[k2]; + } + + private: + //birth_to_pos_[i] < birth_to_pos_[j] iff i birth_to_pos_; + //by construction, max_birth_pos_ (resp. min_birth_pos_) is strictly larger + //(resp. strictly smaller) than any value assigned to a key so far. + Simplex_key max_birth_pos_; + Simplex_key min_birth_pos_; + }; + +public: + /** \brief Computes the zigzag persistent homology of a zigzag filtered complex, + * using the reflection and transposition algorithm of \cite zigzag_reflection. + * + * \details After computation, the persistence diagram can be accessed via + * member method persistence_diagram, for the diagram with filtration + * values, or member method index_persistence_diagram, for the + * diagram with + * indices of paired simplices. + * + * + * matrix_, originally empty, maintains the set of chains, with a + * partition \f$ F \sqcup G \sqcup H\f$ + * representing a compatible homology basis as in \cite zigzag_reflection. + * + * Each simplex in the complex stores a key field that stores the index of + * its insertion in the zigzag filtration. + * + * The algorithm maintains a compatible homology basis for the zigzag filtration. + * + * \f$$\emptyset = K_0 \leftrightarrow (...) \leftrightarrow K_i \leftarrow ... \leftarrow \emptyset\f$$ + * + * where the prefix from \f$K_0\f$ to \f$K_i\f$ is equal to the i-th prefix of + * the input zigzag + * filtration given by cpx_.filtration_simplex_range(), and + * the suffix + * (from \f$K_i\f$ + * to the right) is a sequence of simplex removals. Due to the structure of + * reflection diamonds, the removals are in reverse order of the insertions, to + * reduce the amount of transposition diamonds. + * + * Consequently, using cpx_.key(zzsh) as indexing for the matrix + * rows/cells, + * with the natural order on integers, makes our homology matrix matrix_ upper + * triangular for the suffix \f$K_i \leftarrow ... \leftarrow 0\f$, seen as a + * standard persistence + * filtration. At \f$K_i\f$, the natural order on integers is also equivalent to the + * death-order \f$\leq_d\f$ (because all arrows in the suffix are backward). + * + * Insertion: cpx_.key(*zzit) is a strictly increasing sequence + * for zzit + * insertion of cells (does not need to be contiguous). However, for every forward + * arrow, we have cpx_.key(*zzit) == num_arrows_. + * Removal: cpx_.key(*zzit) gives the assigned key (during past + * insertion) of a + * cell == *zzit during a removal. We use num_arrows_ + * to record the deaths in the + * persistence diagram. + * Insertion and Removal: zzit.filtration() is totally monotone. + * Note that the + * iterator encodes the filtration, and not the cells within the complex structure. + */ +// void zigzag_persistent_homology() +// { //compute index persistence, interval are closed, i.e., [b,d) is stored as +// //[b,d-1]. The filtration values are maintained in field filtration_values_ +// Filtration_value prev_fil_, curr_fil_; + +// assert(num_arrow_ == 0); +// auto zzrg = cpx_.filtration_simplex_range(); +// auto zzit = zzrg.begin(); +// dim_max_ = zzit.dim_max(); + +// num_arrow_ = cpx_.key(*zzit);//should be 0 + +// prev_fil_ = zzit.filtration(); +// filtration_values_.emplace_back(num_arrow_, prev_fil_); + +// while( zzit != zzrg.end() ) +// { //insertion of a simplex +// if(zzit.arrow_direction()) { num_arrow_ = cpx_.key(*zzit); } +// else { ++num_arrow_; } //removal of a simplex, a simplex key corresponds to the index of its INSERTION +// curr_fil_ = zzit.filtration();//cpx_.filtration(*zzit) is invalid for (<-); +// if(curr_fil_ != prev_fil_) //check whether the filt value has changed +// { //consecutive pairs (i,f), (j,f') mean simplices of index k in [i,j-1] have +// prev_fil_ = curr_fil_; //filtration value f +// filtration_values_.emplace_back(num_arrow_, prev_fil_); +// } +// if(zzit.arrow_direction()) { //forward arrow, only consider critical cells +// forward_arrow(*zzit); +// } +// else { //backward arrow +// backward_arrow(*zzit); +// } +// ++zzit; +// } + +//// if(!matrix_.empty()) { +//// std::cout << "There remain " << matrix_.size() << " columns in the matrix.\n"; +//// } +// } + + template> + void insert_simplex(const VertexRange& simplex, Filtration_value filtration_value) + { + if (dim_max_ != -1 && simplex.size() > static_cast(dim_max_) + 1) return; + + ++num_arrow_; + + if (filtration_value != previous_filtration_value_) //check whether the filt value has changed + { //consecutive pairs (i,f), (j,f') mean simplices of index k in [i,j-1] have + previous_filtration_value_ = filtration_value; //filtration value f + filtration_values_.emplace_back(num_arrow_, previous_filtration_value_); + } + + std::pair res = cpx_.insert_simplex(simplex, filtration_value); + GUDHI_CHECK(res.second, "Zigzag_persistence::insert_simplex - insertion of a simplex already in the complex"); + cpx_.assign_key(res.first, num_arrow_); + forward_arrow(res.first); + } + + template> + void remove_simplex(const VertexRange& simplex, Filtration_value filtration_value) + { + if (dim_max_ != -1 && simplex.size() > static_cast(dim_max_) + 1) return; + + ++num_arrow_; + + Simplex_handle sh = cpx_.find(simplex); + GUDHI_CHECK(sh != cpx_.null_simplex(), "Zigzag_persistence::remove_simplex - removal of a simplex not in the complex"); + + if (filtration_value != previous_filtration_value_) //check whether the filt value has changed + { //consecutive pairs (i,f), (j,f') mean simplices of index k in [i,j-1] have + previous_filtration_value_ = filtration_value; //filtration value f + filtration_values_.emplace_back(num_arrow_, previous_filtration_value_); + } + + backward_arrow(sh); + cpx_.remove_maximal_simplex(sh); + } + + template>, + class FiltrationRange = std::initializer_list> + void insert_simplices_contiguously(const SimplexRange& simplices, const FiltrationRange& filtration_values) + { + auto simplexIt = simplices.begin(); + auto filIt = filtration_values.begin(); + for (; simplexIt != simplices.end(); ++simplexIt, ++filIt) { + insert_simplex(*simplexIt, *filIt); + } + } + + template>, + class FiltrationRange = std::initializer_list> + void remove_simplices_contiguously(const SimplexRange& simplices, const FiltrationRange& filtration_values) + { + auto simplexIt = simplices.begin(); + auto filIt = filtration_values.begin(); + for (; simplexIt != simplices.end(); ++simplexIt, ++filIt) { + remove_simplex(*simplexIt, *filIt); + } + } + + template + void insert_simplices_contiguously(SimplexRangeIterators simplex_range_start, + SimplexRangeIterators simplex_range_end, + FiltrationRangeIterators filtration_range_start) + { + for (; simplex_range_start != simplex_range_end; ++simplex_range_start, ++filtration_range_start) { + insert_simplex(*simplex_range_start, *filtration_range_start); + } + } + + template + void remove_simplices_contiguously(SimplexRangeIterators simplex_range_start, + SimplexRangeIterators simplex_range_end, + FiltrationRangeIterators filtration_range_start) + { + for (; simplex_range_start != simplex_range_end; ++simplex_range_start, ++filtration_range_start) { + remove_simplex(*simplex_range_start, *filtration_range_start); + } + } + + void print_current_complex(){ + for (auto& sh : cpx_.complex_simplex_range()){ + for (auto v : cpx_.simplex_vertex_range(sh)){ + std::cout << v << " "; + } + std::cout << " - " << cpx_.filtration(sh) << "\n"; + } + } + +private: + /** \brief Computes the boundary cycle of the new simplex zzsh, and express it as a + * sum of cycles. If all cycles are boundary cycles, i.e., columns with G-index + * in the matrix, then [\partial zzsh] = 0 and we apply an injective diamond to + * the zigzag module. Otherwise, we keep reducing with boundary- and live- cycles, + * i.e., columns with (F \cup G)-indices, and then apply a surjective diamond to + * the zigzag module. + */ + void forward_arrow( Simplex_handle zzsh ) + { //maintain the <=b order + birth_ordering_.add_birth_forward(num_arrow_); + + //Reduce the boundary of zzsh in the basis of cycles. + //Compute the simplex keys of the simplices of the boundary of zzsh. + std::set< Simplex_key > col_bsh; //set maintains the natural order on indices + for( auto b_sh : cpx_.boundary_simplex_range(zzsh) ) + { col_bsh.insert(cpx_.key(b_sh)); } + + //If empty boundary (e.g., when zzsh is a vertex in a simplicial complex) + //Add a non-trivial cycle [c = zzsh] to the matrix, lowidx_to_matidx_make it a creator in F. + if(col_bsh.empty()) // -> creator + { //New row and column with a bottom-right non-zero element, at index key(zzsh) + //i.e., create a new cycle in F, equal to *zzsh alone. + matrix_.emplace_front(num_arrow_); + auto new_chain_it = matrix_.begin();//the new chain + //Update the map [index idx -> chain with lowest index idx] in matrix_ + lowidx_to_matidx_[num_arrow_] = new_chain_it; + return; + } + + // col_bsh.rbegin()) is idx of lowest element in col_bsh, because it is a set. + matrix_chain *col_low = &(*lowidx_to_matidx_[*(col_bsh.rbegin())]); + auto paired_idx = col_low->paired_col_; //col with which col_low is paired + std::vector< matrix_chain * > chains_in_H; //for corresponding indices in H + std::vector< matrix_chain * > chains_in_G; + + //Reduce col_bsh with boundary cycles, i.e., indices in G. + std::pair< typename std::set< Simplex_key >::iterator, bool > res_insert; + while( paired_idx != nullptr ) + { + chains_in_H.push_back(paired_idx);//keep the col_h with which col_g is paired + chains_in_G.push_back(col_low); //keep the col_g + for(auto &cell : (col_low->column())) { //Reduce with the column col_g + res_insert = col_bsh.insert(cell.key()); + if( !res_insert.second ) { col_bsh.erase(res_insert.first); } //1+1 = 0 + //o.w. insertion has succeeded. + } + //If col_bsh is entirely reduced, \partial zzsh is a boundary cycle. + if(col_bsh.empty()) { + // if(cpx_.dimension(zzsh) >= max_dim_) {return;} we need max_dim creators + injective_reflection_diamond(zzsh, chains_in_H); + return; + } + //Continue the reduction + col_low = &(*lowidx_to_matidx_[*(col_bsh.rbegin())]);//curr low index col + paired_idx = col_low->paired_col_;//col with which col_low is paired + } + + //Continue reducing with boundary and 'live' cycles, i.e., indices in G U F. + std::vector< matrix_chain * > chains_in_F; + while(true) + { + if(paired_idx == nullptr) { chains_in_F.push_back(col_low); }//col_low is in F + else { chains_in_H.push_back(paired_idx); } //col_low in G, paired_idx is in H + //Reduce with the column col_g or col_f + for(auto &cell : (col_low->column())) { + res_insert = col_bsh.insert(cell.key()); + if( !res_insert.second ) { col_bsh.erase(res_insert.first); } //1+1 = 0 + //o.w. insertion has succeeded. + } + //If col_bsh is entirely reduced, i.e. col_bsh == \emptyset. + if(col_bsh.empty()) + { + surjective_reflection_diamond(zzsh, chains_in_F, chains_in_H); + return; + } + //Else, keep reducing. + col_low = &(*lowidx_to_matidx_[*(col_bsh.rbegin())]); //curr low index col + paired_idx = col_low->paired_col_;//col with which col_low is paired + } + } + + /** \brief Computes an injective diamond in the zigzag module, by inserting a new + * column for the chain zzsh - \sum col_h, for all col_h in chains_in_H, and a + * new row for the simplex zzsh. + */ + void injective_reflection_diamond ( Simplex_handle zzsh + , std::vector< matrix_chain * > & chains_in_H ) + { //Compute the chain zzsh + \sum col_h, for col_h \in chains_in_H + std::set< Simplex_key > col_bsh; + std::pair< typename std::set< Simplex_key >::iterator, bool > res_insert; + //produce the sum of all col_h in chains_in_H + for( matrix_chain *idx_h : chains_in_H ) { + for(auto &cell : (idx_h->column()) ) { + res_insert = col_bsh.insert(cell.key()); + if( !res_insert.second ) { col_bsh.erase(res_insert.first); } + } + } + //create a new cycle (in F) sigma - \sum col_h + matrix_.emplace_front(num_arrow_, col_bsh.begin(), col_bsh.end(), + lowidx_to_matidx_); + //Update the map 'index idx -> chain with lowest index idx' in matrix_ + auto chain_it = matrix_.begin(); + lowidx_to_matidx_[num_arrow_] = chain_it; + } + + /** The vector chains_in_F is sorted by decreasing lowest index values in the + * columns corresponding to the chains, due to its computation in the reduction of + * \partial zzsh in forward_arrow(...). It is equivalent to decreasing death index + * order w.r.t. the & chains_in_F + , std::vector< matrix_chain * > & chains_in_H ) + { //fp is the largest death index for <=d + //Set col_fp: col_fp <- col_f1+...+col_fp (now in G); preserves lowest idx + auto chain_fp = *(chains_in_F.begin()); //col_fp, with largest death column(), (*other_col_it)->column()); } + //doesn't change the lowest idx as chain_fp has maximal lowest idx of all + + //chains_in_F is ordered, from .begin() to end(), by decreasing lowest_idx_. The + //lowest_idx_ is also the death of the chain in the right suffix of the + //filtration (all backward arrows). Consequently, the chains in F are ordered by + //decreasing death for bool + { return birth_ordering_.reverse_birth_order(k1,k2); };//true iff b(k1) >b b(k2) + + //available_birth: for all i by >d value of the d_i, + //contains at step i all b_j, j > i, and maybe b_i if not stolen + std::set< Simplex_key, decltype(cmp_birth) > available_birth(cmp_birth); + //for f1 to f_{p} (i by <=d), insertion in available_birth_to_fidx sorts by >=b + for(auto &chain_f : chains_in_F) { available_birth.insert(chain_f->birth()); } + + auto maxb_it = available_birth.begin();//max birth cycle + auto maxb = *maxb_it; //max birth value, for persistence diagram + available_birth.erase(maxb_it); //remove max birth cycle (stolen) + + auto last_modified_chain_it = chains_in_F.rbegin(); + + //consider all death indices by increasing birth()); + if(birth_it == available_birth.end()) //birth is not available. *chain_f_it + { //must become the sum of all chains in F with smaller death index. + //this gives as birth the maximal birth of all chains with strictly larger + //death <=> the maximal availabe death. + //Let c_1 ... c_f be the chains s.t. <[c_1+...+c_f]> is the kernel and + // death(c_i) >d death(c_i-1). If the birth of c_i is not available, we set + //c_i <- c_i + c_i-1 + ... + c_1, which is [c_i + c_i-1 + ... + c_1] on + //the right (of death the maximali <=> the maxj>k, are indeed c_j + //set c_i <- c_i + (c_i-1) + ... + (c_k+1) + (c_k + ... + c_1) + for(auto chain_passed_it = last_modified_chain_it;//all with smaller column() + , (*chain_passed_it)->column() ); + } + last_modified_chain_it = chain_f_it;//new cumulated c_i+...+c_1 + //remove the max available death + auto max_avail_b_it = available_birth.begin();//max because order by deacr assign_birth(max_avail_b); //give new birth + available_birth.erase(max_avail_b_it); //remove birth from availability + } + else { available_birth.erase(birth_it); } //birth not available anymore, do not + } //modify *chain_f_it. + //Compute the new column zzsh + \sum col_h, for col_h in chains_in_H + std::set< Simplex_key > col_bsh; + std::pair< typename std::set< Simplex_key >::iterator, bool > res_insert; + for(auto other_col : chains_in_H) + { //Compute (\sum col_h) in a set + for(auto &cell : (other_col->column())) + { + res_insert = col_bsh.insert(cell.key()); + if( !res_insert.second ) { col_bsh.erase(res_insert.first); } //1+1=0 + } + } + //Create and insert (\sum col_h) + sigma (in H, paired with chain_fp) in matrix_ + matrix_.emplace_front(cpx_.key(zzsh), chain_fp, col_bsh.begin(), col_bsh.end(), lowidx_to_matidx_); + //record that the chain with lowest index key(zzsh) is the one just created + auto chain_it = matrix_.begin(); + lowidx_to_matidx_[cpx_.key(zzsh)] = chain_it;//new row + + chain_fp->assign_paired_chain( &(*chain_it) );//pair chain_fp with the new chain + chain_fp->assign_birth(-1); //now belongs to G now -> right interval [m-1,g] + + //Update persistence diagram with left interval [fil(b_max) ; fil(m)) + persistence_diagram_.emplace_back( cpx_.dimension(zzsh)-1 + , maxb + , cpx_.key(zzsh));//-1);// + } + + //cpx_.key(zzsh) is the key of the simplex we remove, not a new one + void backward_arrow( Simplex_handle zzsh ) + { + //maintain the <=b order + birth_ordering_.add_birth_backward(num_arrow_); + //column whose key is the one of the removed simplex + auto curr_col_it = lowidx_to_matidx_.find(cpx_.key(zzsh)); + //corresponding chain + matrix_chain * curr_col = &(*(curr_col_it->second)); + //Record all columns that get affected by the transpositions, i.e., have a coeff + std::vector< matrix_chain * > modified_columns;//in the row of idx key(zzsh) + for(auto & hcell : (curr_col->row_)) { + modified_columns.push_back(hcell.self_chain_); + } + //Sort by left-to-right order in the matrix_ (no order maintained in rows) + std::stable_sort( modified_columns.begin(),modified_columns.end() + , [](matrix_chain *mc1, matrix_chain *mc2) + { return mc1->lowest_idx_ < mc2->lowest_idx_;} ); + + //Modifies the pointer curr_col, not the other one. + for(auto other_col_it = modified_columns.begin()+1; + other_col_it != modified_columns.end(); ++other_col_it) { + curr_col = arrow_transposition_case_study(curr_col, *other_col_it); + } + + //curr_col points to the column to remove by restriction of K to K-{\sigma} + if( curr_col->paired_col_ == nullptr ) { // in F + int dim_zzsh = cpx_.dimension(zzsh); + if(dim_max_ == -1 || (dim_max_ != -1 && dim_zzsh < dim_max_)) { //don't record intervals of max dim + persistence_diagram_.emplace_back( dim_zzsh + , curr_col->birth() + , num_arrow_);// -1); + } + } + else { //in H -> paired with c_g, that now belongs to F now + curr_col->paired_col_->assign_paired_chain(nullptr); + curr_col->paired_col_->assign_birth(num_arrow_); //closed interval + } + + //cannot be in G as the removed simplex is maximal + matrix_.erase(curr_col_it->second); + lowidx_to_matidx_.erase(curr_col_it); + } + + /* Exchanges members of matrix_chains, except the column_ pointer. Modify + * also the lowidx_to_matidx_ data structure, considering that the matrix chains + * also exchange their lowest_idx_. Specifically, it is called by + * arrow_transposition_case_study when: + * c_s has originally birth b_s and low idx s, and c_t has birth b_t and low idx t + * however, c_s becomes c_s <- c_s+c_t with b_t lowest_idx_); + auto it_t = lowidx_to_matidx_.find(other_col->lowest_idx_); + + std::swap(it_s->second, it_t->second);//swap matrix_chain* in lowidx_to_matidx_ + std::swap(curr_col->row_, other_col->row_);//swap associated row of lowest idx + std::swap(curr_col->lowest_idx_, other_col->lowest_idx_);//swap lowest idx. + } + + /** + * Permutes s and t, s goes up, whose insertions are adjacent, i.e., the following + * transformation (from (a) to (b)) in the filtration: + * from (a) ... \leftrightarrow K \leftarrow ... \leftarrow K' U {s,t} \leftarrow K' U {s} \leftarrow K' \leftarrow ..., + * where K' is at matrix index i, K' U {s} at matrix index i+1 and K' U {s,t} at + * matrix index i+2, + * + * to (b) ... \leftrightarrow K \leftarrow ... \leftarrow K' U {s,t} \leftarrow K' U {t} \leftarrow K' \leftarrow ..., + * + * and the chain c_t has a non-trivial coefficient for s, i.e., + * the bloc matrix gives (and becomes): + * c_t c_t + * + + + * c_s c_t c_s c_s c_s c_t + * s 1 1 t 1 0 t 1 1 + * t 0 1 --> either s 0 1 or s 0 1 + * + * By construction, s is a simplex that we want to remove in the complex K. It is + * consequently maximal in K, and all complexes between K and K' U {s} in filtration + * (a). + * + * If c_s and c_t are both cycles (in F)that, before the permutation, are carried by + * respectively the closed intervals [b_s, i+1] and [b_t, i+2], then the sum + * c_s + c_t is a cycle carried by the interval + * [maxd i (i+1 \leftarrow i backward). + * If j \leftarrow ... \leftarrow k are both birth indices on the right part of the quiver (all + * backward arrows) then systematically k inF()) + {//case F x * + if(other_col->inH()) { // case F x H + plus_equal_column( other_col, other_col->column()//c_t <- c_s+c_t still in H + , curr_col->column() );//(birth -2) and low idx t + return curr_col; + }//end case F x H + else // case F x F + { //in F x F: c_s+c_t has max<=b birth between b_t and b_s: + if(birth_ordering_.birth_order(curr_col->birth(), other_col->birth())) + { //max<=b is the birth of other_col i.e., b_s column()//c_t <- c_s+c_t of birth + , curr_col->column() );//b_t and lowest idx t. (same) + //c_s still has birth b_s (minimal) and lowest idx s + return curr_col;//continue with c_s of smaller birth b_s and lowest idx s + }//endif + else + { //max<=b is the birth of curr_col, i.e., b_t column()//c_s <- c_s+c_t of birth + , other_col->column() );//b_s and of NEW lowest idx t + //now c_t has (same) birth b_t (minimal) but NEW lowest idx s, so + //exchange lowest_idx, the rows, and update lowidx_to_matidx structure + exchange_lowest_indices_chains(curr_col, other_col); + return other_col;//continue with c_t of (smaller) birth b_t and low idx s + }//end else + }//end case F x F + }//end case F x * + else {//curr_col->inH() == true, case H x * + if(other_col->inH()) {// case H x H + //Case H x H, c_s+c_t paired w/ c_gs+c_gt, of death + //maxpaired_col_; //c_s paired with c_gs, death d_gs + auto other_p_col = other_col->paired_col_;//c_t paired with c_gt, death d_gt + if( curr_p_col->lowest_idx_ < other_p_col->lowest_idx_)//<=> d_gs column()//c_gt <- c_gs+c_gt, + , curr_p_col->column() );//of death d_gt, low idx d_gt + //(same because bigger), paired with c_s+c_t (now &c_t, updated below) + plus_equal_column( other_col, other_col->column()//c_t <- c_t+c_s, still + , curr_col->column() );//in H, low idx t (same) + return curr_col;//continue with c_s, paired with c_gs of min death d_gs + } + else + {// d_gt column()//c_gs <- c_gs+c_gt, + , other_p_col->column() );//of death d_gs, low idx d_gs + //(same because bigger), paired with c_s+c_t (now &c_s, updated below) + plus_equal_column( curr_col, curr_col->column()//c_s <- c_s+c_t, of NEW + , other_col->column());//low idx t (still in H) + //now c_s is still in H (birth -2) but has NEW lowest idx t, and c_t has + //low idx s after transposition. + //exchange lowest_idx, the rows, and update lowidx_to_matidx structure + exchange_lowest_indices_chains(curr_col, other_col); + return other_col; //continue with c_t, paired w. c_g' of min death g' + } + }//end case H x H + else {//other_col->inF() == true, case H x F + plus_equal_column( curr_col, curr_col->column() //c_s <- c_s+c_t still in H, + , other_col->column()); //(birth -2) and NEW low idx t + //now c_t, still in F, has (same) birth b_t but NEW lowest idx s, so + //exchange lowest_idx, the rows, and update lowidx_to_matidx structure + exchange_lowest_indices_chains(curr_col, other_col); + return other_col; //continue with c_t, still in F, of birth b_t and low idx s + } + } + } + + +public: + /** \brief Returns the index persistence diagram as an std::list of intervals.*/ + const std::list< interval_index > & index_persistence_diagram() const + { + return persistence_diagram_; + } + + /** \brief Returns the filtration values \f$[f(b),f(d)]\f$ (generally real-valued) + * associated to the indices \f$[b,d]\f$ (integer valued) of the insertion or + * deletion of a simplex in the zigzag filtration. + * + * \details Used to convert a persistent interval \f$[b,d]\f$, computed by the + * persistent homology algorithm, into its filtration valued version + * \f$[f(b),f(d)]\f$ used in the persistence barcode. The information + * index->filtration is stored in the member filtration_values_ of + * the class Zigzag_persistence. + * + * @param[in] b_key, d_key The indices of birth and death of a persistent + * interval. + * + * @param[out] std::pair A pair of real values \f$(f(b),f(d))\f$. + */ + std::pair index_to_filtration( + Simplex_key b_key, Simplex_key d_key) { + // filtration_values_ must be sorted by increasing keys. + auto it_b = //lower_bound(x) returns leftmost y s.t. x <= y + std::lower_bound( filtration_values_.begin(), filtration_values_.end() + , std::pair(b_key + , std::numeric_limits::infinity() ) + , []( std::pair p1 + , std::pair p2) + { return p1.first < p2.first; } + ); + if(it_b == filtration_values_.end() || it_b->first > b_key) { --it_b; } + //it points to the rightmost z such that z <= x + + auto it_d = // + std::lower_bound( filtration_values_.begin(), filtration_values_.end() + , std::pair(d_key + , std::numeric_limits::infinity() ) + , []( std::pair p1 + , std::pair p2) + { return p1.first < p2.first; } + ); + if(it_d == filtration_values_.end() || it_d->first > d_key) { --it_d; } + + return std::make_pair(it_b->second, it_d->second); + } + + /** \brief Writes the persistence diagram in a file. + * + * \details The filtration values are given by the zigzag persistence iterator, that assigns + * to any insertion or deletion of a simplex a filtration value ; we say that an + * arrow has an index \f$i\f$, and a corresponding filtration value \f$f(i)\f$. + * Reading a zigzag filtration from left to right, indices are strictly + * monotonically increasing, and the associated filtration values are monotonous + * (not necessarily + * strictly, either increasing or decreasing). + * + * Consider two consecutive arrows (insertion or deletion): + * + * \f$$K_1 \leftrightarrow K_2 \leftrightarrow K_3\f$$ + * + * with respectively indices \f$i\f$ (left) and \f$i+1\f$ (right), and associated + * filtration values \f$f(i)\f$ and \f$f(i+1)\f$ respectively. + * + * If, the arrow \f$K_2 \leftrightarrow K_3\f$ leads to the creation of a new + * homology feature in \f$K_3\f$, it creates an (indexed) persistent interval + * \f$[\f$i+1; \cdot\f$, and a corresponding (filtration) persistent interval + * \f$[f(i+1); \cdot]\f$ in the persistence diagram. + * + * If a homology feature in \f$K_2\f$ is destroyed by the arrow \f$K_2 \leftrightarrow K_3\f$, it closes an (indexed) + * interval \f$[\cdot ; i+1]\f$, and a corresponding (filtration) persistent + * interval \f$[\cdot ; f(i+1)]\f$ in the persistence diagram. + * + * For example, in an oscillating Rips zigzag filtration, if, in the following + * chunk of filtration: + * + * \f$R_{\eta \varepsilon_i}(P_i) \rightarrow \cdots \leftarrow R_{\eta \varepsilon_{i+1}}(P_{i+1}),\f$ + * + * if anything is created by any of the arrows above, it leads to an interval + * \f$[\varepsilon_{i+1}; \cdot]\f$. If anything is destroyed by any of the arrows + * above, if leads to an interval \f$[\cdot;\varepsilon_i]\f$. Note that we may + * have \f$\varepsilon_i > \varepsilon_{i+1}\f$. + * + * The bars are ordered by decreasing length. + * + * @param[in] os the output stream in which the diagram is written. + * @param[in] shortest_interval all intervals of lenght smaller or equal to + * this value are ignore. Default is 0. + */ + void persistence_diagram( std::ostream& os + , Filtration_value shortest_interval = 0.) { + + std::stable_sort(filtration_values_.begin(), filtration_values_.end(), + []( std::pair< Simplex_key, Filtration_value > p1 + , std::pair< Simplex_key, Filtration_value > p2 ) + { return p1.first < p2.first; } + ); + + std::vector< interval_filtration > tmp_diag; + tmp_diag.reserve(persistence_diagram_.size()); + for(auto bar : persistence_diagram_) + { + Filtration_value birth,death; + std::tie(birth,death) = index_to_filtration(bar.birth(), bar.death()); + + if( std::abs(birth - death) > shortest_interval ) { + tmp_diag.emplace_back(bar.dim(), birth, death ); + } + } + // cmp_intervals_by_length cmp; + std::stable_sort(tmp_diag.begin(), tmp_diag.end(), cmp_intervals_by_length()); + + os << "# dim birth death [length]\n"; + for(auto bar : tmp_diag) { + if(bar.birth() > bar.death()) { bar.swap_birth_death(); } + os << bar.dim() << " " << bar.birth() << " " << bar.death() << + " - [" << bar.length() << "] \n"; + } + } + + /** \brief Returns the persistence diagram as a vector of real-valued intervals. */ + std::vector< interval_filtration > + persistence_diagram(Filtration_value shortest_interval = 0., bool include_infinit_bars = false) + { + std::stable_sort(filtration_values_.begin(), filtration_values_.end(), + []( std::pair< Simplex_key, Filtration_value > p1 + , std::pair< Simplex_key, Filtration_value > p2 ) + { return p1.first < p2.first; } + ); + + std::vector< interval_filtration > diag; + diag.reserve(persistence_diagram_.size()); + for(auto bar : persistence_diagram_) + { + Filtration_value birth,death; + std::tie(birth,death) = index_to_filtration(bar.birth(), bar.death()); + + if( std::abs(birth - death) > shortest_interval ) { + diag.emplace_back(bar.dim(), birth, death ); + } + } + //put lower value as birth + for(auto &bar : diag) { + if( bar.birth() > bar.death() ) { bar.swap_birth_death(); } + } + std::stable_sort(diag.begin(), diag.end(), cmp_intervals_by_length()); + + auto birth = + [this](Simplex_key b_key) { + auto it_b = // lower_bound(x) returns leftmost y s.t. x <= y + std::lower_bound(filtration_values_.begin(), filtration_values_.end(), + std::pair( + b_key, std::numeric_limits::infinity()), + [](std::pair p1, + std::pair p2) { return p1.first < p2.first; }); + if (it_b == filtration_values_.end() || it_b->first > b_key) { + --it_b; + } + return it_b->second; + }; + + //TODO: dimension value + if (include_infinit_bars) { + for (const matrix_chain &col : matrix_) { + if (col.inF()) + diag.emplace_back(-1, birth(col.birth()), std::numeric_limits::infinity()); + } + } + + return diag; + } + +private: + Complex cpx_; // complex + int dim_max_;//max dim complex + //idx -> chain with lowest element at index idx in matrix_ + std::map< Simplex_key, typename std::list::iterator > + lowidx_to_matidx_; + //arbitrary order for the matrix chains + std::list< matrix_chain > matrix_; // 0 ... m-1 + // birth_vector birth_vector_; //<=b order + birth_ordering birth_ordering_; + std::list< interval_index > persistence_diagram_; + Simplex_key num_arrow_; //current index + Filtration_value previous_filtration_value_; + // filtration_values stores consecutive pairs (i,f) , (j,f') with f != f', + // meaning that all inserted simplices with key in [i;j-1] have filtration value f + //i is the smallest simplex index whose simplex has filtration value f. + std::vector< std::pair< Simplex_key, Filtration_value > > filtration_values_; +};//end class Zigzag_persistence + + +/** ZigzagPersistenceOptions, represents matrix columns by intrusive lists.*/ +struct Zigzag_persistence_collist { + static const bool searchable_column = false; +}; +/** ZigzagPersistenceOptions, represents matrix columns by intrusive sets.*/ +struct Zigzag_persistence_colset { + static const bool searchable_column = true; +}; + +} //namespace zigzag_persistence + +} //namespace Gudhi + +#endif //ZIGZAG_PERSISTENCE_H_ + diff --git a/src/Zigzag_persistence/test/CMakeLists.txt b/src/Zigzag_persistence/test/CMakeLists.txt new file mode 100644 index 0000000000..74dac45186 --- /dev/null +++ b/src/Zigzag_persistence/test/CMakeLists.txt @@ -0,0 +1,16 @@ +project(Zigzag_persistence_tests) + +include(GUDHI_boost_test) + +add_executable ( Zigzag_persistence_unit_test zigzag_persistence_unit_test.cpp ) +if(TARGET TBB::tbb) + target_link_libraries(Zigzag_persistence_unit_test TBB::tbb) +endif() + +# Do not forget to copy test results files in current binary dir +#file(COPY "${CMAKE_SOURCE_DIR}/src/Persistent_cohomology/test/simplex_tree_file_for_unit_test.txt" +# DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) + +# Unitary tests +gudhi_add_boost_test(Zigzag_persistence_unit_test) + diff --git a/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp b/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp new file mode 100644 index 0000000000..49bb97b5a9 --- /dev/null +++ b/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp @@ -0,0 +1,468 @@ +#include +#include +#include +#include + +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE "zigzag_persistence" +#include + +#include +#include + +using namespace Gudhi; +using namespace boost::unit_test; +using ST = Gudhi::Simplex_tree; +using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; +using Vertex_handle = ST::Vertex_handle; +using Filtration_value = ST::Filtration_value; +using interval_index = ZP::interval_index; +using interval_filtration = ZP::interval_filtration; + +// TODO: +// void persistence_diagram(std::ostream& os, Filtration_value shortest_interval = 0.); + +struct cmp_intervals_by_length { + cmp_intervals_by_length() {} + bool operator()(interval_filtration p, interval_filtration q) { + if (p.length() != q.length()) { + return p.length() > q.length(); + } + if (p.dim() != q.dim()) { + return p.dim() < q.dim(); + } + if (p.birth() != q.birth()) { + return p.birth() < q.birth(); + } + return p.death() < q.death(); + } +}; + +BOOST_AUTO_TEST_CASE(constructor) { + BOOST_CHECK_NO_THROW(ZP zp); + BOOST_CHECK_NO_THROW(ZP zp(28)); + BOOST_CHECK_NO_THROW(ZP zp(28,2)); + ZP zp; + BOOST_CHECK(zp.persistence_diagram(0).empty()); +} + +void test_barcode(ZP& zp, std::vector& barcode) +{ + std::stable_sort(barcode.begin(), barcode.end(), cmp_intervals_by_length()); + auto it = barcode.begin(); + for (const auto& interval : zp.persistence_diagram()){ + BOOST_CHECK_EQUAL(interval.dim(), it->dim()); + BOOST_CHECK_EQUAL(interval.birth(), it->birth()); + BOOST_CHECK_EQUAL(interval.death(), it->death()); + ++it; + } + BOOST_CHECK(it == barcode.end()); +} + +void test_indices(ZP& zp, std::vector& indices, std::vector& indexToFil) +{ + auto it = indices.begin(); + for (const auto& interval : zp.index_persistence_diagram()){ + BOOST_CHECK_EQUAL(interval.dim(), it->dim()); + BOOST_CHECK_EQUAL(interval.birth(), it->birth()); + BOOST_CHECK_EQUAL(interval.death(), it->death()); + auto p = zp.index_to_filtration(interval.birth(), interval.death()); + BOOST_CHECK_EQUAL(p.first, indexToFil[interval.birth()]); + BOOST_CHECK_EQUAL(p.second, indexToFil[interval.death()]); + ++it; + } + BOOST_CHECK(it == indices.end()); +} + +std::vector > get_simplices() +{ + return { + {0}, + {1}, + {2}, + {0,1}, + {0,2}, + {3}, + {1,2}, + {4}, + {3,4}, + {5}, + {0,1,2}, + {4,5}, + {3,5}, + {3,4,5}, + {0,1,2}, //r + {3,4,5}, //r + {1,4}, + {0,1,2}, + {2,4}, + {3,4,5}, + {0,4}, + {0,2,4}, + {1,2,4}, + {0,1,4}, + {3,4,5}, //r + {3,4}, //r + {3,5}, //r + {0,1,2,4}}; +} + +std::vector get_filtration_values() +{ + return { + 0, 0, 0, + 1, 1, 1, + 2, 2, 2, + 3, 3, 3, 3, + 4, + 5, + 6, 6, 6, + 7, 7, 7, 7, 7, 7, + 8, + 9, 9, 9 + }; +} + +BOOST_AUTO_TEST_CASE(zigzag_persistence_single) { + ZP zp(28); + std::vector realIndices; + std::vector realBarcode; + realIndices.reserve(13); + realBarcode.reserve(9); + + std::vector > simplices = get_simplices(); + std::vector filValues = get_filtration_values(); + + for (unsigned int i = 0; i < 14; ++i){ + zp.insert_simplex(simplices[i], filValues[i]); + } + + realIndices.emplace_back(0, 1, 3); + realIndices.emplace_back(0, 2, 4); + realIndices.emplace_back(0, 7, 8); + realIndices.emplace_back(1, 6, 10); + realIndices.emplace_back(0, 9, 11); + realIndices.emplace_back(1, 12, 13); + + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(1, 2, 3); + realBarcode.emplace_back(1, 3, 4); + + for (unsigned int i = 14; i < 16; ++i){ + zp.remove_simplex(simplices[i], filValues[i]); + } + + for (unsigned int i = 16; i < 24; ++i){ + zp.insert_simplex(simplices[i], filValues[i]); + } + + realIndices.emplace_back(0, 5, 16); + realIndices.emplace_back(1, 14, 17); + realIndices.emplace_back(1, 15, 19); + realIndices.emplace_back(1, 20, 21); + realIndices.emplace_back(1, 18, 22); + + realBarcode.emplace_back(0, 1, 6); + realBarcode.emplace_back(1, 5, 6); + realBarcode.emplace_back(1, 6, 7); + + for (unsigned int i = 24; i < 27; ++i){ + zp.remove_simplex(simplices[i], filValues[i]); + } + + realIndices.emplace_back(1, 24, 25); + realBarcode.emplace_back(1, 8, 9); + + zp.insert_simplex(simplices[27], filValues[27]); + + realIndices.emplace_back(2, 23, 27); + realBarcode.emplace_back(2, 7, 9); + + test_indices(zp, realIndices, filValues); + test_barcode(zp, realBarcode); +} + +BOOST_AUTO_TEST_CASE(zigzag_persistence_single_max1) { + ZP zp(28, 1); + std::vector realIndices; + std::vector indexToFil(28); + std::vector realBarcode; + realIndices.reserve(5); + realBarcode.reserve(3); + + std::vector > simplices = get_simplices(); + std::vector filValues = get_filtration_values(); + unsigned int currIndex = 0; + + for (unsigned int i = 0; i < 14; ++i){ + zp.insert_simplex(simplices[i], filValues[i]); + if (simplices[i].size() < 3){ + indexToFil[currIndex++] = filValues[i]; + } + } + + realIndices.emplace_back(0, 1, 3); + realIndices.emplace_back(0, 2, 4); + realIndices.emplace_back(0, 7, 8); + realIndices.emplace_back(0, 9, 10); + + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(0, 0, 1); + + for (unsigned int i = 14; i < 16; ++i){ + zp.remove_simplex(simplices[i], filValues[i]); + if (simplices[i].size() < 3){ + indexToFil[currIndex++] = filValues[i]; + } + } + + for (unsigned int i = 16; i < 24; ++i){ + zp.insert_simplex(simplices[i], filValues[i]); + if (simplices[i].size() < 3){ + indexToFil[currIndex++] = filValues[i]; + } + } + + realIndices.emplace_back(0, 5, 12); + realBarcode.emplace_back(0, 1, 6); + + for (unsigned int i = 24; i < 27; ++i){ + zp.remove_simplex(simplices[i], filValues[i]); + if (simplices[i].size() < 3){ + indexToFil[currIndex++] = filValues[i]; + } + } + + zp.insert_simplex(simplices[27], filValues[27]); + + test_indices(zp, realIndices, indexToFil); + test_barcode(zp, realBarcode); +} + +BOOST_AUTO_TEST_CASE(zigzag_persistence_batch_with_iterators) { + ZP zp; + std::vector realIndices; + std::vector realBarcode; + realIndices.reserve(13); + realBarcode.reserve(9); + + std::vector > simplices = get_simplices(); + std::vector filValues = get_filtration_values(); + + zp.insert_simplices_contiguously(simplices.begin(), + simplices.begin() + 14, + filValues.begin()); + + realIndices.emplace_back(0, 1, 3); + realIndices.emplace_back(0, 2, 4); + realIndices.emplace_back(0, 7, 8); + realIndices.emplace_back(1, 6, 10); + realIndices.emplace_back(0, 9, 11); + realIndices.emplace_back(1, 12, 13); + + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(1, 2, 3); + realBarcode.emplace_back(1, 3, 4); + + zp.remove_simplices_contiguously(simplices.begin() + 14, + simplices.begin() + 16, + filValues.begin() + 14); + zp.insert_simplices_contiguously(simplices.begin() + 16, + simplices.begin() + 24, + filValues.begin() + 16); + + realIndices.emplace_back(0, 5, 16); + realIndices.emplace_back(1, 14, 17); + realIndices.emplace_back(1, 15, 19); + realIndices.emplace_back(1, 20, 21); + realIndices.emplace_back(1, 18, 22); + + realBarcode.emplace_back(0, 1, 6); + realBarcode.emplace_back(1, 5, 6); + realBarcode.emplace_back(1, 6, 7); + + zp.remove_simplices_contiguously(simplices.begin() + 24, + simplices.begin() + 27, + filValues.begin() + 24); + + realIndices.emplace_back(1, 24, 25); + realBarcode.emplace_back(1, 8, 9); + + zp.insert_simplices_contiguously(simplices.begin() + 27, + simplices.begin() + 28, + filValues.begin() + 27); + + realIndices.emplace_back(2, 23, 27); + realBarcode.emplace_back(2, 7, 9); + + test_indices(zp, realIndices, filValues); + test_barcode(zp, realBarcode); +} + +BOOST_AUTO_TEST_CASE(zigzag_persistence_batch_with_iterators_max1) { + ZP zp(28, 1); + std::vector realIndices; + std::vector indexToFil(28); + std::vector realBarcode; + realIndices.reserve(5); + realBarcode.reserve(3); + + std::vector > simplices = get_simplices(); + std::vector filValues = get_filtration_values(); + unsigned int currIndex = 0; + + for (unsigned int i = 0; i < 28; ++i){ + if (simplices[i].size() < 3){ + indexToFil[currIndex++] = filValues[i]; + } + } + + zp.insert_simplices_contiguously(simplices.begin(), + simplices.begin() + 14, + filValues.begin()); + + realIndices.emplace_back(0, 1, 3); + realIndices.emplace_back(0, 2, 4); + realIndices.emplace_back(0, 7, 8); + realIndices.emplace_back(0, 9, 10); + + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(0, 0, 1); + + zp.remove_simplices_contiguously(simplices.begin() + 14, + simplices.begin() + 16, + filValues.begin() + 14); + zp.insert_simplices_contiguously(simplices.begin() + 16, + simplices.begin() + 24, + filValues.begin() + 16); + + realIndices.emplace_back(0, 5, 12); + realBarcode.emplace_back(0, 1, 6); + + zp.remove_simplices_contiguously(simplices.begin() + 24, + simplices.begin() + 27, + filValues.begin() + 24); + zp.insert_simplices_contiguously(simplices.begin() + 27, + simplices.begin() + 28, + filValues.begin() + 27); + + test_indices(zp, realIndices, indexToFil); + test_barcode(zp, realBarcode); +} + +BOOST_AUTO_TEST_CASE(zigzag_persistence_batch) { + ZP zp; + std::vector realIndices; + std::vector realBarcode; + realIndices.reserve(13); + realBarcode.reserve(9); + + std::vector > simplices = get_simplices(); + std::vector filValues = get_filtration_values(); + + std::vector > subSimplices(simplices.begin(), simplices.begin() + 14); + std::vector subFilValues(filValues.begin(), filValues.begin() + 14); + zp.insert_simplices_contiguously(subSimplices, subFilValues); + + realIndices.emplace_back(0, 1, 3); + realIndices.emplace_back(0, 2, 4); + realIndices.emplace_back(0, 7, 8); + realIndices.emplace_back(1, 6, 10); + realIndices.emplace_back(0, 9, 11); + realIndices.emplace_back(1, 12, 13); + + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(1, 2, 3); + realBarcode.emplace_back(1, 3, 4); + + subSimplices = std::vector >(simplices.begin() + 14, simplices.begin() + 16); + subFilValues = std::vector(filValues.begin() + 14, filValues.begin() + 16); + zp.remove_simplices_contiguously(subSimplices, subFilValues); + + subSimplices = std::vector >(simplices.begin() + 16, simplices.begin() + 24); + subFilValues = std::vector(filValues.begin() + 16, filValues.begin() + 24); + zp.insert_simplices_contiguously(subSimplices, subFilValues); + + realIndices.emplace_back(0, 5, 16); + realIndices.emplace_back(1, 14, 17); + realIndices.emplace_back(1, 15, 19); + realIndices.emplace_back(1, 20, 21); + realIndices.emplace_back(1, 18, 22); + + realBarcode.emplace_back(0, 1, 6); + realBarcode.emplace_back(1, 5, 6); + realBarcode.emplace_back(1, 6, 7); + + subSimplices = std::vector >(simplices.begin() + 24, simplices.begin() + 27); + subFilValues = std::vector(filValues.begin() + 24, filValues.begin() + 27); + zp.remove_simplices_contiguously(subSimplices, subFilValues); + + realIndices.emplace_back(1, 24, 25); + realBarcode.emplace_back(1, 8, 9); + + subSimplices = std::vector >(simplices.begin() + 27, simplices.begin() + 28); + subFilValues = std::vector(filValues.begin() + 27, filValues.begin() + 28); + zp.insert_simplices_contiguously(subSimplices, subFilValues); + + realIndices.emplace_back(2, 23, 27); + realBarcode.emplace_back(2, 7, 9); + + test_indices(zp, realIndices, filValues); + test_barcode(zp, realBarcode); +} + +BOOST_AUTO_TEST_CASE(zigzag_persistence_batch_max1) { + ZP zp(28, 1); + std::vector realIndices; + std::vector indexToFil(28); + std::vector realBarcode; + realIndices.reserve(5); + realBarcode.reserve(3); + + std::vector > simplices = get_simplices(); + std::vector filValues = get_filtration_values(); + unsigned int currIndex = 0; + + for (unsigned int i = 0; i < 28; ++i){ + if (simplices[i].size() < 3){ + indexToFil[currIndex++] = filValues[i]; + } + } + + std::vector > subSimplices(simplices.begin(), simplices.begin() + 14); + std::vector subFilValues(filValues.begin(), filValues.begin() + 14); + zp.insert_simplices_contiguously(subSimplices, subFilValues); + + realIndices.emplace_back(0, 1, 3); + realIndices.emplace_back(0, 2, 4); + realIndices.emplace_back(0, 7, 8); + realIndices.emplace_back(0, 9, 10); + + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(0, 0, 1); + + subSimplices = std::vector >(simplices.begin() + 14, simplices.begin() + 16); + subFilValues = std::vector(filValues.begin() + 14, filValues.begin() + 16); + zp.remove_simplices_contiguously(subSimplices, subFilValues); + + subSimplices = std::vector >(simplices.begin() + 16, simplices.begin() + 24); + subFilValues = std::vector(filValues.begin() + 16, filValues.begin() + 24); + zp.insert_simplices_contiguously(subSimplices, subFilValues); + + realIndices.emplace_back(0, 5, 12); + realBarcode.emplace_back(0, 1, 6); + + subSimplices = std::vector >(simplices.begin() + 24, simplices.begin() + 27); + subFilValues = std::vector(filValues.begin() + 24, filValues.begin() + 27); + zp.remove_simplices_contiguously(subSimplices, subFilValues); + + subSimplices = std::vector >(simplices.begin() + 27, simplices.begin() + 28); + subFilValues = std::vector(filValues.begin() + 27, filValues.begin() + 28); + zp.insert_simplices_contiguously(subSimplices, subFilValues); + + test_indices(zp, realIndices, indexToFil); + test_barcode(zp, realBarcode); +} From 3f8409f7d6f757f4e10739ecc9e9a92574d6f558 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 21 Jul 2023 14:26:25 +0200 Subject: [PATCH 02/96] doc and concepts --- .../gudhi/chain_matrix/chain_rep_cycles.h | 1 + .../chain_matrix/custom_chain_vine_swap.h | 2 +- .../include/gudhi/options.h | 1 - .../benchmark/Zigzag_benchmark.cpp | 3 +- .../benchmark/Zigzag_old_benchmark.cpp | 4 +- .../concept/ZigzagFilteredComplex.h | 129 ++ .../concept/ZigzagPersistenceOptions.h | 90 ++ src/Zigzag_persistence/example/CMakeLists.txt | 23 +- .../example/comparison_for_tests.cpp | 6 +- .../example_rips_zigzag_filtration.cpp | 6 +- .../example_simple_zigzag_filtration.cpp | 245 +-- .../example_zzfiltration_from_file.cpp | 130 ++ .../example/zigzag_filtration_example.txt | 46 + .../include/gudhi/Zigzag_persistence.h | 1393 +++++++++-------- .../include/gudhi/Zigzag_persistence_old.h | 34 +- src/Zigzag_persistence/test/CMakeLists.txt | 5 - .../test/zigzag_persistence_unit_test.cpp | 854 +++++----- 17 files changed, 1734 insertions(+), 1238 deletions(-) create mode 100644 src/Zigzag_persistence/concept/ZigzagFilteredComplex.h create mode 100644 src/Zigzag_persistence/concept/ZigzagPersistenceOptions.h create mode 100644 src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp create mode 100644 src/Zigzag_persistence/example/zigzag_filtration_example.txt diff --git a/src/Persistence_matrix/include/gudhi/chain_matrix/chain_rep_cycles.h b/src/Persistence_matrix/include/gudhi/chain_matrix/chain_rep_cycles.h index 143ee6beb3..909896ca7c 100644 --- a/src/Persistence_matrix/include/gudhi/chain_matrix/chain_rep_cycles.h +++ b/src/Persistence_matrix/include/gudhi/chain_matrix/chain_rep_cycles.h @@ -13,6 +13,7 @@ #include #include +#include #include "../utilities/utilities.h" //type definitions #include "../options.h" diff --git a/src/Persistence_matrix/include/gudhi/chain_matrix/custom_chain_vine_swap.h b/src/Persistence_matrix/include/gudhi/chain_matrix/custom_chain_vine_swap.h index 276f04c551..88a85f8151 100644 --- a/src/Persistence_matrix/include/gudhi/chain_matrix/custom_chain_vine_swap.h +++ b/src/Persistence_matrix/include/gudhi/chain_matrix/custom_chain_vine_swap.h @@ -61,7 +61,7 @@ class Custom_chain_vine_swap index _negative_positive_vine_swap(index columnIndex1, index columnIndex2); index _negative_vine_swap(index columnIndex1, index columnIndex2); - std::function birthComp_; // for F x F & H x H + std::function birthComp_; // for F x F std::function deathComp_; // for G x G }; diff --git a/src/Persistence_matrix/include/gudhi/options.h b/src/Persistence_matrix/include/gudhi/options.h index c4b9f9473d..3e4ea6843f 100644 --- a/src/Persistence_matrix/include/gudhi/options.h +++ b/src/Persistence_matrix/include/gudhi/options.h @@ -57,7 +57,6 @@ struct Default_options{ template struct Zigzag_options : Default_options{ static const bool has_row_access = true; - static const bool has_column_pairings = false; static const bool has_vine_update = true; static const bool is_of_boundary_type = false; static const bool is_indexed_by_position = false; diff --git a/src/Zigzag_persistence/benchmark/Zigzag_benchmark.cpp b/src/Zigzag_persistence/benchmark/Zigzag_benchmark.cpp index 3edac39c8d..37b4edfb24 100644 --- a/src/Zigzag_persistence/benchmark/Zigzag_benchmark.cpp +++ b/src/Zigzag_persistence/benchmark/Zigzag_benchmark.cpp @@ -29,7 +29,6 @@ using ST = Gudhi::Simplex_tree; // using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; using Vertex_handle = ST::Vertex_handle; using Filtration_value = ST::Filtration_value; -// using interval_filtration = ZP::interval_filtration; using Gudhi::persistence_matrix::Zigzag_options; using CT = Gudhi::persistence_matrix::Column_types; @@ -43,7 +42,7 @@ std::vector< std::pair > print_indices(ZP& zp, unsig essentials.insert(essentials.end(), i); } - for (auto& bar : zp.index_persistence_diagram()){ + for (auto& bar : zp.get_index_persistence_diagram()){ res.emplace_back(bar.birth(), bar.death()); essentials.erase(bar.birth()); essentials.erase(bar.death()); diff --git a/src/Zigzag_persistence/benchmark/Zigzag_old_benchmark.cpp b/src/Zigzag_persistence/benchmark/Zigzag_old_benchmark.cpp index bb24be2942..ca079443c3 100644 --- a/src/Zigzag_persistence/benchmark/Zigzag_old_benchmark.cpp +++ b/src/Zigzag_persistence/benchmark/Zigzag_old_benchmark.cpp @@ -30,7 +30,7 @@ using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; // using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; using Vertex_handle = ST::Vertex_handle; using Filtration_value = ST::Filtration_value; -using interval_filtration = ZP::interval_filtration; +using interval_filtration = ZP::fil_interval; std::vector< std::pair > print_indices(ZP& zp, unsigned int numberOfSimplices){ std::set essentials; @@ -40,7 +40,7 @@ std::vector< std::pair > print_indices(ZP& zp, unsig essentials.insert(essentials.end(), i); } - for (auto& bar : zp.index_persistence_diagram()){ + for (auto& bar : zp.get_index_persistence_diagram()){ res.emplace_back(bar.birth(), bar.death()); essentials.erase(bar.birth()); essentials.erase(bar.death()); diff --git a/src/Zigzag_persistence/concept/ZigzagFilteredComplex.h b/src/Zigzag_persistence/concept/ZigzagFilteredComplex.h new file mode 100644 index 0000000000..7a6e416f1b --- /dev/null +++ b/src/Zigzag_persistence/concept/ZigzagFilteredComplex.h @@ -0,0 +1,129 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Hannah Schreiber + * + * Copyright (C) 2023 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +#ifndef CONCEPT_ZZ_COMPLEX_TYPE_H_ +#define CONCEPT_ZZ_COMPLEX_TYPE_H_ + +/** @file ZigzagFilteredComplex.h + * @brief Contains @ref Gudhi::zigzag_persistence::ZigzagFilteredComplex concept. + */ + +namespace Gudhi { +namespace zigzag_persistence { + +/** + * @brief Data structure storing the simplices in the current complex. + */ +class ZigzagFilteredComplex { + public: + /** + * @brief Signed integer type that needs to be long enough to store the numbers of arrows in the zigzag filtration. + */ + typename Simplex_key; + + /** + * @brief Handle to specify a simplex. + */ + typename Simplex_handle; + + /** + * @brief Handle to specify a vertex. Should be an integer type. + */ + typename Vertex_handle; + + /** + * @brief Type for filtration values. Usually 'double'. + */ + typename Filtration_value; + + /** + * @brief Range of simplex handles over the boundary of a simplex + */ + typename Boundary_simplex_range; + + /** + * @brief Constructor + */ + ZigzagFilteredComplex(); + + /** + * @brief Inserts the given simplex in the complex. + * + * @tparam VertexRange Range over the vertices of a simplex. + * @param simplex Simplex to insert represented by its vertices. + * @param filtration Filtration value at the insertion. + * @return A pair of a simplex handle and a boolean. + * The simplex handle represents the inserted simplex and + * the boolean if simplex was already contained in the complex or not. + */ + template + std::pair insert_simplex(const VertexRange& simplex, Filtration_value filtration); + + /** + * @brief Removes the given simplex. Assumes that the simplex is maximal and can be safely removed. + * + * @param sh Simplex handle representing the simplex to remove. + */ + void remove_maximal_simplex(Simplex_handle sh); + + /** + * @brief Returns the dimension of the given simplex. + * + * @param sh Simplex handle representing the simplex. + * @return Dimension of @a sh. + */ + int dimension(Simplex_handle sh); + + /** + * @brief Returns the key associated to the given simplex. + * + * @param sh Simplex handle representing the simplex. + * @return The key. + */ + Simplex_key key(Simplex_handle sh); + + /** + * @brief Assignes the given value to the given simplex as a key. + * + * @param sh Simplex handle representing the simplex. + * @param key Values to associate as key. + */ + void assign_key(Simplex_handle sh, Simplex_key key); + + /** + * @brief Finds the given simplex in the complex and returns the associated simplex handle. + * + * @tparam VertexRange Range over the vertices of a simplex. + * @param simplex Simplex to find represented by its vertices. + * @return The simplex handle associated to @a simplex if the simplex is found, @ref null_simplex() otherwise. + */ + template + Simplex_handle find(const VertexRange& simplex); + + /** + * @brief Returns a range of simplex handles representing the boundary of the given simplex. + * + * @param sh Simplex handle representing the simplex. + * @return Range of simplex handles. + */ + Boundary_simplex_range boundary_simplex_range(Simplex_handle sh); + + /** + * @brief Returns a simplex handle representing a non existing simplex. + * + * @return A simplex handle. + */ + Simplex_handle null_simplex(); +}; + +} // namespace zigzag_persistence +} // namespace Gudhi + +#endif // CONCEPT_ZZ_COMPLEX_TYPE_H_ diff --git a/src/Zigzag_persistence/concept/ZigzagPersistenceOptions.h b/src/Zigzag_persistence/concept/ZigzagPersistenceOptions.h new file mode 100644 index 0000000000..7ee9d9be7d --- /dev/null +++ b/src/Zigzag_persistence/concept/ZigzagPersistenceOptions.h @@ -0,0 +1,90 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Hannah Schreiber + * + * Copyright (C) 2023 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +#ifndef CONCEPT_ZZ_OPTIONS_TYPE_H_ +#define CONCEPT_ZZ_OPTIONS_TYPE_H_ + +/** @file ZigzagPersistenceOptions.h + * @brief Contains @ref Gudhi::zigzag_persistence::ZigzagPersistenceOptions concept. + */ + +namespace Gudhi { +namespace zigzag_persistence { + +/** + * @brief List of options used for the matrix maintained for the zigzag persistence computation. + */ +struct ZigzagPersistenceOptions { + /** + * @brief Type for the coefficient field type. Has to support \f$Z_2\f$. + */ + typename field_coeff_type; + + /** + * @brief Has to be set to true. Indicates that the computation will be made with \f$Z_2\f$ coefficients. + */ + static const bool is_z2 = true; + /** + * @brief Type of the columns in the matrix. + * The available column types are given by @ref Gudhi::persistence_matrix::Column_types. + * The column type has to support row access. + */ + static const Column_types column_type; + + /** + * @brief Has to be set to true. Indicates that the rows should be directly accessible in the matrix. + */ + static const bool has_row_access = true; + /** + * @brief Set to true, if the rows should be intrusive lists or to false if they should be sets. True is recommended. + * Note that intrusive rows are not compatible with certain column types. + */ + static const bool has_intrusive_rows; + /** + * @brief Has to set to true. Indicates that the rows of the matrix can be removed. + */ + static const bool has_removable_rows = true; + /** + * @brief Has to be set to false. Indicates that the matrix should not store birth/death pairs of its columns. + */ + static const bool has_column_pairings = false; + /** + * @brief Has to be set to true. Enables maintaining the matrix while switching columns. + */ + static const bool has_vine_update = true; + /** + * @brief If set to true, the matrix can retrieve the representative cycles for the cycle classes. + * This option is useless for zigzag computation and therefore it is recommended to set it to false. + */ + static const bool can_retrieve_representative_cycles; + /** + * @brief This value has to be defined but will be ignored. + */ + static const bool has_column_compression; + /** + * @brief Has to be set to false. + * Indicates that the matrix should represent the base of the chain complex and not of the boundary group. + */ + static const bool is_of_boundary_type = false; + /** + * @brief Has to be set to true. Indicates that the columns of the matrix can be removed. + */ + static const bool has_removable_columns = true; + /** + * @brief Has to be set to false. + * Indicates that the access to the columns will be done through simplex IDs instead of column positions. + */ + static const bool is_indexed_by_position = false; +}; + +} // namespace zigzag_persistence +} // namespace Gudhi + +#endif // CONCEPT_ZZ_OPTIONS_TYPE_H_ diff --git a/src/Zigzag_persistence/example/CMakeLists.txt b/src/Zigzag_persistence/example/CMakeLists.txt index 1a981ce998..c9814e2768 100644 --- a/src/Zigzag_persistence/example/CMakeLists.txt +++ b/src/Zigzag_persistence/example/CMakeLists.txt @@ -6,20 +6,27 @@ if(TARGET TBB::tbb) endif() add_test(NAME Zigzag_persistence_example_simple_zigzag_filtration COMMAND $) -add_executable ( comp comparison_for_tests.cpp ./ext_zz/fzz/fzz.cpp ) -target_include_directories(comp PUBLIC ./ext_zz) -target_compile_options(comp PUBLIC "-fopenmp") -target_link_options(comp PUBLIC "-fopenmp") +add_executable ( Zigzag_persistence_example_zzfiltration_from_file example_zzfiltration_from_file.cpp ) +if(TARGET TBB::tbb) + target_link_libraries(Zigzag_persistence_example_zzfiltration_from_file TBB::tbb) +endif() +file(COPY "zigzag_filtration_example.txt" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) +add_test(NAME Zigzag_persistence_example_zzfiltration_from_file COMMAND $ "${CMAKE_CURRENT_BINARY_DIR}/zigzag_filtration_example.txt") + +# add_executable ( comp comparison_for_tests.cpp ./ext_zz/fzz/fzz.cpp ) +# target_include_directories(comp PUBLIC ./ext_zz) +# target_compile_options(comp PUBLIC "-fopenmp") +# target_link_options(comp PUBLIC "-fopenmp") # add_executable ( Zigzag_persistence_example_rips_zigzag_filtration example_rips_zigzag_filtration.cpp ) # target_include_directories(Zigzag_persistence_example_rips_zigzag_filtration PUBLIC ./ext_zz) # target_compile_options(Zigzag_persistence_example_rips_zigzag_filtration PUBLIC "-fopenmp") # target_link_options(Zigzag_persistence_example_rips_zigzag_filtration PUBLIC "-fopenmp") -add_executable ( rips example_rips_zigzag_filtration.cpp ) -target_include_directories(rips PUBLIC ./ext_zz) -target_compile_options(rips PUBLIC "-fopenmp") -target_link_options(rips PUBLIC "-fopenmp") +# add_executable ( rips example_rips_zigzag_filtration.cpp ) +# target_include_directories(rips PUBLIC ./ext_zz) +# target_compile_options(rips PUBLIC "-fopenmp") +# target_link_options(rips PUBLIC "-fopenmp") # add_executable ( rips_old example_rips_zigzag_filtration.cpp ) # target_include_directories(rips_old PUBLIC ./ext_zz) diff --git a/src/Zigzag_persistence/example/comparison_for_tests.cpp b/src/Zigzag_persistence/example/comparison_for_tests.cpp index 2beded4910..a2f972966c 100644 --- a/src/Zigzag_persistence/example/comparison_for_tests.cpp +++ b/src/Zigzag_persistence/example/comparison_for_tests.cpp @@ -2,7 +2,7 @@ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. * Author(s): Hannah Schreiber * - * Copyright (C) 2014 Inria + * Copyright (C) 2023 Inria * * Modification(s): * - YYYY/MM Author: Description of the modification @@ -36,7 +36,7 @@ using CT = Gudhi::persistence_matrix::Column_types; using ZP = Gudhi::zigzag_persistence::Zigzag_persistence >; using Vertex_handle = ST::Vertex_handle; using Filtration_value = ST::Filtration_value; -using interval_filtration = ZP::interval_filtration; +using interval_filtration = ZP::filtration_value_interval; using DField = dionysus::Z2Field; using Simplex = dionysus::Simplex<>; @@ -72,7 +72,7 @@ std::vector< std::pair > print_indices(ZP& zp, unsig essentials.insert(essentials.end(), i); } - for (auto& bar : zp.index_persistence_diagram()){ + for (auto& bar : zp.get_index_persistence_diagram()){ // std::clog << bar.birth() << " - "; // std::clog << bar.death(); // std::clog << " (" << bar.dim() << ")\n"; diff --git a/src/Zigzag_persistence/example/example_rips_zigzag_filtration.cpp b/src/Zigzag_persistence/example/example_rips_zigzag_filtration.cpp index ed021faecc..88298890c7 100644 --- a/src/Zigzag_persistence/example/example_rips_zigzag_filtration.cpp +++ b/src/Zigzag_persistence/example/example_rips_zigzag_filtration.cpp @@ -2,7 +2,7 @@ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. * Author(s): Hannah Schreiber * - * Copyright (C) 2014 Inria + * Copyright (C) 2023 Inria * * Modification(s): * - YYYY/MM Author: Description of the modification @@ -34,7 +34,7 @@ using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; using Vertex_handle = ST::Vertex_handle; using Filtration_value = ST::Filtration_value; -using interval_filtration = ZP::interval_filtration; +using interval_filtration = ZP::filtration_value_interval; std::vector< std::pair > print_indices(ZP& zp, unsigned int numberOfSimplices){ std::set essentials; @@ -44,7 +44,7 @@ std::vector< std::pair > print_indices(ZP& zp, unsig essentials.insert(essentials.end(), i); } - for (auto& bar : zp.index_persistence_diagram()){ + for (auto& bar : zp.get_index_persistence_diagram()){ res.emplace_back(bar.birth(), bar.death()); essentials.erase(bar.birth()); essentials.erase(bar.death()); diff --git a/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp b/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp index 4750eb5358..82e20bba63 100644 --- a/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp +++ b/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp @@ -2,117 +2,176 @@ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. * Author(s): Hannah Schreiber * - * Copyright (C) 2014 Inria + * Copyright (C) 2023 Inria * * Modification(s): * - YYYY/MM Author: Description of the modification */ -#include -#include - #include -#include // for pair +#include #include +#include +#include + using ST = Gudhi::Simplex_tree; using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; using Vertex_handle = ST::Vertex_handle; using Filtration_value = ST::Filtration_value; -using interval_filtration = ZP::interval_filtration; +using interval_filtration = ZP::filtration_value_interval; + +// void print_complex(ZP& zp) { +// std::clog << std::endl << "Current complex:" << std::endl; +// const auto& cpx = zp.get_complex(); +// for (const auto& sh : cpx.complex_simplex_range()) { +// for (auto v : cpx.simplex_vertex_range(sh)) { +// std::cout << v << " "; +// } +// std::cout << " - " << cpx.filtration(sh) << "" << std::endl; +// } +// } + +void print_barcode(ZP& zp) { + std::clog << std::endl << "Current barcode:" << std::endl; + for (auto& bar : zp.get_persistence_diagram(0, true)) { + std::clog << std::floor(bar.birth()) << " - "; + if (bar.death() == std::numeric_limits::infinity()) { + std::clog << "inf"; + } else { + std::clog << std::floor(bar.death()); + } + std::clog << " (" << bar.dim() << ")" << std::endl; + } +} + +void print_indices(ZP& zp) { + std::clog << std::endl << "Current pairs:" << std::endl; + for (auto& bar : zp.get_index_persistence_diagram()) { + std::clog << bar.birth() << " - "; + std::clog << bar.death(); + std::clog << " (" << bar.dim() << ")" << std::endl; + } +} -void print_complex(ZP& zp){ - std::clog << std::endl << "Current complex:" << std::endl; - zp.print_current_complex(); +std::vector > get_simplices() { + return {{0}, + {1}, + {2}, + {0, 1}, + {0, 2}, + {3}, + {1, 2}, + {4}, + {3, 4}, + {5}, + {0, 1, 2}, + {4, 5}, + {3, 5}, + {3, 4, 5}, + {0, 1, 2}, // remove + {3, 4, 5}, // remove + {1, 4}, + {0, 1, 2}, + {2, 4}, + {3, 4, 5}, + {0, 4}, + {0, 2, 4}, + {1, 2, 4}, + {0, 1, 4}, + {3, 4, 5}, // remove + {3, 4}, // remove + {3, 5}, // remove + {0, 1, 2, 4}, + {0, 1, 2, 4}}; // remove } -void print_barcode(ZP& zp){ - std::clog << std::endl << "Current barcode:" << std::endl; - for (auto& bar : zp.persistence_diagram()){ - std::clog << std::floor(bar.birth()) << " - "; - if (bar.death() == std::numeric_limits::infinity()){ - std::clog << "inf"; - } else { - std::clog << std::floor(bar.death()); - } - std::clog << " (" << bar.dim() << ")\n"; - } +std::vector get_filtration_values() { + return {0, 0, 0, + 1, 1, 1, + 2, 2, 2, + 3, 3, 3, 3, + 4, + 5, + 6, 6, 6, + 7, 7, 7, 7, 7, 7, + 8, + 9, 9, 9, + 10}; } -void print_indices(ZP& zp){ - std::clog << std::endl << "Current pairs:" << std::endl; - for (auto& bar : zp.index_persistence_diagram()){ - std::clog << bar.birth() << " - "; - std::clog << bar.death(); - std::clog << " (" << bar.dim() << ")\n"; - } +std::vector get_directions() { + return {true, true, true, true, true, true, true, true, true, true, true, true, true, true, + false, false, + true, true, true, true, true, true, true, true, + false, false, false, + true, + false}; +} + +std::vector get_batch_sizes() { + return {14, 2, 8, 3, 1, 1}; +} + +void one_by_one() { + ZP zp; + + std::vector > simplices = get_simplices(); + std::vector fils = get_filtration_values(); + std::vector dirs = get_directions(); + + for (unsigned int i = 0; i < simplices.size(); ++i) { + if (i > 0 && dirs[i] != dirs[i - 1]) { + // print_complex(zp); + print_barcode(zp); + print_indices(zp); + } + if (dirs[i]) { + zp.insert_simplex(simplices[i], fils[i]); + } else { + zp.remove_simplex(simplices[i], fils[i]); + } + } + // print_complex(zp); + print_barcode(zp); + print_indices(zp); +} + +void in_batches() { + ZP zp; + + std::vector > simplices = get_simplices(); + std::vector fils = get_filtration_values(); + std::vector sizes = get_batch_sizes(); + + unsigned int start; + unsigned int end = 0; + bool dir = true; //first operation has to be an insertion + for (auto s : sizes){ + start = end; + end += s; + if (dir){ + zp.insert_simplices_contiguously(simplices.begin() + start, + simplices.begin() + end, + fils.begin() + start); + } else { + zp.remove_simplices_contiguously(simplices.begin() + start, + simplices.begin() + end, + fils.begin() + start); + } + dir = !dir; + // print_complex(zp); + print_barcode(zp); + print_indices(zp); + } } int main(int argc, char* const argv[]) { - ZP zp; - - std::vector > simplices{ - {0},{1},{2}, - {0,1},{0,2},{3}, - {1,2},{4},{3,4}, - {5},{0,1,2},{4,5},{3,5}}; - std::vector fils{0,0,0,1,1,1,2,2,2,3,3,3,3}; - zp.insert_simplices_contiguously(simplices, fils); - - print_complex(zp); - print_barcode(zp); - print_indices(zp); - - std::vector simplex{3,4,5}; - zp.insert_simplex(simplex, 4); - - print_complex(zp); - print_barcode(zp); - print_indices(zp); - - simplex[0] = 0; - simplex[1] = 1; - simplex[2] = 2; - zp.remove_simplex(simplex, 5); - - print_complex(zp); - print_barcode(zp); - print_indices(zp); - - simplex[0] = 3; - simplex[1] = 4; - simplex[2] = 5; - zp.remove_simplex(simplex, 6); - - print_complex(zp); - print_barcode(zp); - print_indices(zp); - - simplices = {{1,4},{0,1,2},{2,4},{3,4,5},{0,4},{0,2,4},{1,2,4},{0,1,4}}; - fils = {6,6,7,7,7,7,7,7}; - zp.insert_simplices_contiguously(simplices, fils); - - print_complex(zp); - print_barcode(zp); - print_indices(zp); - - simplices = {{3,4,5},{3,4},{3,5}}; - fils = {8,9,9}; - zp.remove_simplices_contiguously(simplices, fils); - - print_complex(zp); - print_barcode(zp); - print_indices(zp); - - simplex[0] = 0; - simplex[1] = 1; - simplex[2] = 2; - simplex.push_back(4); - zp.insert_simplex(simplex, 9); - - print_complex(zp); - print_barcode(zp); - print_indices(zp); - - return 0; + std::clog << "********** Example one_by_one **********" << std::endl; + one_by_one(); + + std::clog << std::endl << "********** Example in_batches **********" << std::endl; + in_batches(); + + return 0; } diff --git a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp new file mode 100644 index 0000000000..21bcfc1fde --- /dev/null +++ b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp @@ -0,0 +1,130 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Hannah Schreiber + * + * Copyright (C) 2023 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +#include +#include +#include + +#include +#include + +using ST = Gudhi::Simplex_tree; +using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; +using Vertex_handle = ST::Vertex_handle; +using Filtration_value = ST::Filtration_value; +using interval_filtration = ZP::filtration_value_interval; + +enum lineType : int { INCLUSION, REMOVAL, COMMENT }; + +void print_barcode(ZP& zp) { + std::clog << std::endl << "Current barcode:" << std::endl; + for (auto& bar : zp.get_persistence_diagram(0, true)) { + std::clog << std::floor(bar.birth()) << " - "; + if (bar.death() == std::numeric_limits::infinity()) { + std::clog << "inf"; + } else { + std::clog << std::floor(bar.death()); + } + std::clog << " (" << bar.dim() << ")" << std::endl; + } + std::clog << std::endl; +} + +lineType read_operation(std::string& line, std::vector& vertices, double& timestamp) { + lineType type; + vertices.clear(); + Vertex_handle num; + + size_t current = line.find_first_not_of(' ', 0); + if (current == std::string::npos) return COMMENT; + + if (line[current] == 'i') + type = INCLUSION; + else if (line[current] == 'r') + type = REMOVAL; + else if (line[current] == '#') + return COMMENT; + else { + std::clog << "Syntaxe error in file." << std::endl; + exit(0); + } + + current = line.find_first_not_of(' ', current + 1); + if (current == std::string::npos) { + std::clog << "Syntaxe error in file." << std::endl; + exit(0); + } + size_t next = line.find_first_of(' ', current); + timestamp = std::stod(line.substr(current, next - current)); + + current = line.find_first_not_of(' ', next); + if (current == std::string::npos) { + std::clog << "Syntaxe error in file." << std::endl; + exit(0); + } + + do { + next = line.find_first_of(' ', current); + num = std::stoi(line.substr(current, next - current)); + vertices.push_back(num); + current = line.find_first_not_of(' ', next); + } while (current != std::string::npos); + + return type; +} + +int main(int argc, char* const argv[]) { + if (argc != 2) { + if (argc < 2) + std::clog << "Missing argument: input file name is needed." << std::endl; + else + std::clog << "Too many arguments: only input file name is needed." << std::endl; + return 0; + } + + std::string line; + std::ifstream file(argv[1]); + ZP zp; + + if (file.is_open()) { + std::vector vertices; + double timestamp; + lineType type; + + while (getline(file, line, '\n') && read_operation(line, vertices, timestamp) == COMMENT); + double lastTimestamp = timestamp; + // first operation has to be an insertion. + zp.insert_simplex(vertices, timestamp); + std::cout << line << std::endl; + + while (getline(file, line, '\n')) { + type = read_operation(line, vertices, timestamp); + if (type != COMMENT && lastTimestamp != timestamp) { + print_barcode(zp); + lastTimestamp = timestamp; + } + if (type != COMMENT) std::cout << line << std::endl; + + if (type == INCLUSION) { + zp.insert_simplex(vertices, timestamp); + } else if (type == REMOVAL) { + zp.remove_simplex(vertices, timestamp); + } + } + print_barcode(zp); + + file.close(); + } else { + std::clog << "Unable to open input file." << std::endl; + file.setstate(std::ios::failbit); + } + + return 0; +} \ No newline at end of file diff --git a/src/Zigzag_persistence/example/zigzag_filtration_example.txt b/src/Zigzag_persistence/example/zigzag_filtration_example.txt new file mode 100644 index 0000000000..db02d5b2d8 --- /dev/null +++ b/src/Zigzag_persistence/example/zigzag_filtration_example.txt @@ -0,0 +1,46 @@ +# simple example of zigzag filtration +# i: inclusion +# r: removal +# first value: filtration value +# remaining values: vertices of the simplex to include/remove in ascending order +# #: comment line + +i 0 0 +i 0 1 +i 0 2 + +i 1 0 1 +i 1 0 2 +i 1 3 + +i 2 1 2 +i 2 4 +i 2 3 4 + +i 3 5 +i 3 0 1 2 +i 3 4 5 +i 3 3 5 + +i 4 3 4 5 + +r 5 0 1 2 + +r 6 3 4 5 +i 6 1 4 +i 6 0 1 2 + +i 7 2 4 +i 7 3 4 5 +i 7 0 4 +i 7 0 2 4 +i 7 1 2 4 +i 7 0 1 4 + +r 8 3 4 5 + +r 9 3 4 +r 9 3 5 +i 9 0 1 2 4 + +r 10 0 1 2 4 \ No newline at end of file diff --git a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h index bccf73ab03..51fd7f1c54 100644 --- a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h @@ -10,6 +10,12 @@ * - YYYY/MM Author: Description of the modification */ +/** + * @file Zigzag_persistence.h + * @author Clément Maria, Hannah Schreiber + * @brief Contains the implementation of the @ref Gudhi::zigzag_persistence::Zigzag_persistence class. + */ + #ifndef ZIGZAG_PERSISTENCE_H_ #define ZIGZAG_PERSISTENCE_H_ @@ -21,6 +27,7 @@ #include #include +#include #include #include #include @@ -29,6 +36,7 @@ #include #include #include +#include #include #include @@ -37,689 +45,704 @@ namespace Gudhi { namespace zigzag_persistence { -//---------------------------------------------------------------------------------- -/** \class Zigzag_persistence Zigzag_persistence.h gudhi/Zigzag_persistence.h - * \brief Computation of the zigzag persistent homology of a zigzag - * filtered complex. - * - * \details The type ZigzagFilteredComplex::Simplex_key counts the number of - * insertions and - * deletions of simplices, which may be large in zigzag persistence and require - * more than 32 bits of storage. The type used (int, long, etc) should be chosen in - * consequence. Simplex_key must be signed. - * - * Over all insertions, the Simplex_key must be positive and strictly increasing - * when forward iterating along the zigzag filtration. - */ -template < typename ZigzagFilteredComplex - , typename ZigzagPersistenceOptions = Gudhi::persistence_matrix::Zigzag_options<> > -class Zigzag_persistence { -public: - typedef ZigzagFilteredComplex Complex; - typedef ZigzagPersistenceOptions Options; - /*** Types defined in the complex ***/ - // Data attached to each simplex to interface with a Property Map. - typedef typename Complex::Simplex_key Simplex_key;//must be signed - typedef typename Complex::Simplex_handle Simplex_handle; - typedef typename Complex::Vertex_handle Vertex_handle; - typedef typename Complex::Filtration_value Filtration_value; - // - - /** \brief Structure to store persistence intervals by their filtration values. - * - * \details By convention, interval \f$[b;d]\f$ are - * closed for finite indices b and d, and open for left-infinite and/or - * right-infinite endpoints.*/ - struct interval_filtration { - interval_filtration() {} - interval_filtration(int dim, Filtration_value b, Filtration_value d) : dim_(dim), b_(b), d_(d) {} - /** Returns the absolute length of the interval \f$|d-b|\f$. */ - Filtration_value length() { - if(b_ == d_) { return 0; } //otherwise inf - inf would return nan. - return std::abs(b_ - d_); - } - /** Returns the absolute length of the log values of birth and death, i.e. \f$|\log d - \log b|\f$.. */ - Filtration_value log_length() {//return the log-length - if(b_ == d_) { return 0; } //otherwise inf - inf would return nan. - return std::abs(log2((double)b_) - log2((double)d_)); - } - /** Returns the dimension of the homological feature corresponding to the - * interval. */ - int dim() const { return dim_; }//return the homological dimension of the interval - /** Returns the birth of the interval.*/ - Filtration_value birth() const { return b_; }//return the birth value - /** Returns the death of the interval.*/ - Filtration_value death() const { return d_; }//return the death value - /** Swaps the values of birth and death.*/ - void swap_birth_death() { std::swap(b_,d_); } - - private://note that we don't assume b_ <= d_ - int dim_; //homological dimension - Filtration_value b_; //filtration value associated to birth index - Filtration_value d_; //filtration value associated to death index - }; - - /** \brief Structure to store persistence intervals by their index values. - * - * \details By convention, interval [b;d] are - * closed for finite indices b and d, and open for left-infinite and/or - * right-infinite endpoints. - */ - struct interval_index { - interval_index() {} - interval_index(int dim, Simplex_key b, Simplex_key d) : dim_(dim), b_(b), d_(d) {} - /** Returns the dimension of the homological feature corresponding to the - * interval. */ - int dim() const { return dim_; }//return the homological dimension of the interval - /** Returns the birth index of the interval.*/ - Filtration_value birth() const { return b_; }//return the birth value - /** Returns the death index of the interval.*/ - Filtration_value death() const { return d_; }//return the death value - - private://note that we don't assume b_ <= d_ - int dim_; //homological dimension - Simplex_key b_; //filtration value associated to birth index - Simplex_key d_; //filtration value associated to death index - }; - -private: - /* Comparison function to sort intervals by decreasing log-length in the - * output persistence diagram, i.e., - * [f(b),f(d)]<[f(b'),f(d')] iff |log2(f(b))-log2(f(d))|> |log2(f(b'))-log2(f(d'))| - */ - struct cmp_intervals_by_log_length { - cmp_intervals_by_log_length(){} - bool operator()( interval_filtration p, interval_filtration q) - { - if(p.dim() != q.dim()) {return p.dim() < q.dim();}//lower dimension first - if(p.log_length() != q.log_length()) {return p.log_length() > q.log_length();} - if(p.birth() != q.birth()) {return p.birth() < q.birth();}//lex order - return p.death() < q.death(); - } - }; - /* Comparison function to sort intervals by decreasing length in the - * output persistence diagram, i.e., - * [f(b),f(d)]<[f(b'),f(d')] iff |f(b)-f(d)| > |f(b')-f(d')| - */ - struct cmp_intervals_by_length { - cmp_intervals_by_length(){} - bool operator()( interval_filtration p, interval_filtration q) - { - if(p.length() != q.length()) { return p.length() > q.length(); }//longest 1st - if(p.dim() != q.dim()) {return p.dim() < q.dim();}//lower dimension first - if(p.birth() != q.birth()) {return p.birth() < q.birth();}//lex order - return p.death() < q.death(); - } - }; - - using matrix_type = Gudhi::persistence_matrix::Matrix; - using index = Gudhi::persistence_matrix::index; - -public: - /** \brief Initialization of the Zigzag_persistence class. - * - * \param[in] cpx A model of ZigzagFilteredComplex. - * */ - Zigzag_persistence(unsigned int min_number_of_simplices = 0, int ignore_cycles_above_dim = -1) - : cpx_() - , dim_max_(ignore_cycles_above_dim) - , matrix_(min_number_of_simplices, - [this](index columnIndex1, index columnIndex2){ - return birth_ordering_.birth_order(births_.at(columnIndex1), births_.at(columnIndex2)); - }) - , birth_ordering_() - , persistence_diagram_() - , num_arrow_(-1) - , previous_filtration_value_(std::numeric_limits::infinity()) - , filtration_values_() {} - -private: - - /** Maintains the birth ordering <=b. Contains an std::map of size the number of - * non-zero rows of the homology matrix, at any time during the computation of - * zigzag persistence. - * - * By construction, we maintain the map satisfying - * 'birth_to_pos_[i] < birth_to_pos_[j]', - * with 0 <= i,j <= k indices in the quiver '0 \leftrightarrow ... \leftrightarrow i \leftrightarrow .. \leftrightarrow k' - * visited at time k of the algorithm (prefix of length k of the full zigzag - * filtration '0 \leftrightarrow ... \leftrightarrow i \leftrightarrow .. \leftrightarrow k \leftrightarrow ... \leftrightarrow n' that is studied), - * iff i k+1 forward, then j 0 -> 1 -> 2 <- 3 <- 4 -> 5 <- 6 etc - birth_ordering() : birth_to_pos_(), max_birth_pos_(0), min_birth_pos_(-1) {} - - //when the arrow key-1 -> key is forward, key is larger than any other index - //i < key in the birth ordering b k2 - bool reverse_birth_order(Simplex_key k1, Simplex_key k2) { - return birth_to_pos_[k1] > birth_to_pos_[k2]; - } - - private: - //birth_to_pos_[i] < birth_to_pos_[j] iff i birth_to_pos_; - //by construction, max_birth_pos_ (resp. min_birth_pos_) is strictly larger - //(resp. strictly smaller) than any value assigned to a key so far. - Simplex_key max_birth_pos_; - Simplex_key min_birth_pos_; - }; - -public: - /** \brief Computes the zigzag persistent homology of a zigzag filtered complex, - * using the reflection and transposition algorithm of \cite zigzag_reflection. - * - * \details After computation, the persistence diagram can be accessed via - * member method persistence_diagram, for the diagram with filtration - * values, or member method index_persistence_diagram, for the - * diagram with - * indices of paired simplices. - * - * - * matrix_, originally empty, maintains the set of chains, with a - * partition \f$ F \sqcup G \sqcup H\f$ - * representing a compatible homology basis as in \cite zigzag_reflection. - * - * Each simplex in the complex stores a key field that stores the index of - * its insertion in the zigzag filtration. - * - * The algorithm maintains a compatible homology basis for the zigzag filtration. - * - * \f$$\emptyset = K_0 \leftrightarrow (...) \leftrightarrow K_i \leftarrow ... \leftarrow \emptyset\f$$ - * - * where the prefix from \f$K_0\f$ to \f$K_i\f$ is equal to the i-th prefix of - * the input zigzag - * filtration given by cpx_.filtration_simplex_range(), and - * the suffix - * (from \f$K_i\f$ - * to the right) is a sequence of simplex removals. Due to the structure of - * reflection diamonds, the removals are in reverse order of the insertions, to - * reduce the amount of transposition diamonds. - * - * Consequently, using cpx_.key(zzsh) as indexing for the matrix - * rows/cells, - * with the natural order on integers, makes our homology matrix matrix_ upper - * triangular for the suffix \f$K_i \leftarrow ... \leftarrow 0\f$, seen as a - * standard persistence - * filtration. At \f$K_i\f$, the natural order on integers is also equivalent to the - * death-order \f$\leq_d\f$ (because all arrows in the suffix are backward). - * - * Insertion: cpx_.key(*zzit) is a strictly increasing sequence - * for zzit - * insertion of cells (does not need to be contiguous). However, for every forward - * arrow, we have cpx_.key(*zzit) == num_arrows_. - * Removal: cpx_.key(*zzit) gives the assigned key (during past - * insertion) of a - * cell == *zzit during a removal. We use num_arrows_ - * to record the deaths in the - * persistence diagram. - * Insertion and Removal: zzit.filtration() is totally monotone. - * Note that the - * iterator encodes the filtration, and not the cells within the complex structure. - */ - - template> - void insert_simplex(const VertexRange& simplex, Filtration_value filtration_value) - { - if (dim_max_ != -1 && simplex.size() > static_cast(dim_max_) + 1) return; - - ++num_arrow_; - - if (filtration_value != previous_filtration_value_) //check whether the filt value has changed - { //consecutive pairs (i,f), (j,f') mean simplices of index k in [i,j-1] have - previous_filtration_value_ = filtration_value; //filtration value f - filtration_values_.emplace_back(num_arrow_, previous_filtration_value_); - } - - std::pair res = cpx_.insert_simplex(simplex, filtration_value); - GUDHI_CHECK(res.second, "Zigzag_persistence::insert_simplex - insertion of a simplex already in the complex"); - cpx_.assign_key(res.first, num_arrow_); - forward_arrow(res.first); - } - - template> - void remove_simplex(const VertexRange& simplex, Filtration_value filtration_value) - { - if (dim_max_ != -1 && simplex.size() > static_cast(dim_max_) + 1) return; - - ++num_arrow_; - - Simplex_handle sh = cpx_.find(simplex); - GUDHI_CHECK(sh != cpx_.null_simplex(), "Zigzag_persistence::remove_simplex - removal of a simplex not in the complex"); - - if (filtration_value != previous_filtration_value_) //check whether the filt value has changed - { //consecutive pairs (i,f), (j,f') mean simplices of index k in [i,j-1] have - previous_filtration_value_ = filtration_value; //filtration value f - filtration_values_.emplace_back(num_arrow_, previous_filtration_value_); - } - - backward_arrow(sh); - cpx_.remove_maximal_simplex(sh); - } - - template>, - class FiltrationRange = std::initializer_list> - void insert_simplices_contiguously(const SimplexRange& simplices, const FiltrationRange& filtration_values) - { - auto simplexIt = simplices.begin(); - auto filIt = filtration_values.begin(); - for (; simplexIt != simplices.end(); ++simplexIt, ++filIt) { - insert_simplex(*simplexIt, *filIt); - } - } - - template>, - class FiltrationRange = std::initializer_list> - void remove_simplices_contiguously(const SimplexRange& simplices, const FiltrationRange& filtration_values) - { - auto simplexIt = simplices.begin(); - auto filIt = filtration_values.begin(); - for (; simplexIt != simplices.end(); ++simplexIt, ++filIt) { - remove_simplex(*simplexIt, *filIt); - } - } - - template - void insert_simplices_contiguously(SimplexRangeIterators simplex_range_start, - SimplexRangeIterators simplex_range_end, - FiltrationRangeIterators filtration_range_start) - { - for (; simplex_range_start != simplex_range_end; ++simplex_range_start, ++filtration_range_start) { - insert_simplex(*simplex_range_start, *filtration_range_start); - } - } - - template - void remove_simplices_contiguously(SimplexRangeIterators simplex_range_start, - SimplexRangeIterators simplex_range_end, - FiltrationRangeIterators filtration_range_start) - { - for (; simplex_range_start != simplex_range_end; ++simplex_range_start, ++filtration_range_start) { - remove_simplex(*simplex_range_start, *filtration_range_start); - } - } - - void print_current_complex(){ - for (auto& sh : cpx_.complex_simplex_range()){ - for (auto v : cpx_.simplex_vertex_range(sh)){ - std::cout << v << " "; - } - std::cout << " - " << cpx_.filtration(sh) << "\n"; - } - } - -private: - /** \brief Computes the boundary cycle of the new simplex zzsh, and express it as a - * sum of cycles. If all cycles are boundary cycles, i.e., columns with G-index - * in the matrix, then [\partial zzsh] = 0 and we apply an injective diamond to - * the zigzag module. Otherwise, we keep reducing with boundary- and live- cycles, - * i.e., columns with (F \cup G)-indices, and then apply a surjective diamond to - * the zigzag module. - */ - void forward_arrow( Simplex_handle zzsh ) - { //maintain the <=b order - birth_ordering_.add_birth_forward(num_arrow_); - - //Reduce the boundary of zzsh in the basis of cycles. - //Compute the simplex keys of the simplices of the boundary of zzsh. - std::set< Simplex_key > col_bsh; //set maintains the natural order on indices - for( auto b_sh : cpx_.boundary_simplex_range(zzsh) ) - { col_bsh.insert(cpx_.key(b_sh)); } - - std::vector chains_in_F; - matrix_.insert_boundary(num_arrow_, col_bsh, chains_in_F); - - if (!chains_in_F.empty()){ - births_.try_emplace(matrix_.get_column_with_pivot(num_arrow_), -2); - surjective_reflection_diamond(zzsh, chains_in_F); - } else { - births_.try_emplace(matrix_.get_column_with_pivot(num_arrow_), num_arrow_); - } - } - - /** The vector chains_in_F is sorted by decreasing lowest index values in the - * columns corresponding to the chains, due to its computation in the reduction of - * \partial zzsh in forward_arrow(...). It is equivalent to decreasing death index - * order w.r.t. the & chains_in_F) - { //fp is the largest death index for <=d - //Set col_fp: col_fp <- col_f1+...+col_fp (now in G); preserves lowest idx - auto chain_fp = chains_in_F.front(); //col_fp, with largest death bool - { return birth_ordering_.reverse_birth_order(k1,k2); };//true iff b(k1) >b b(k2) - - //available_birth: for all i by >d value of the d_i, - //contains at step i all b_j, j > i, and maybe b_i if not stolen - std::set< Simplex_key, decltype(cmp_birth) > available_birth(cmp_birth); - //for f1 to f_{p} (i by <=d), insertion in available_birth_to_fidx sorts by >=b - for(auto &chain_f : chains_in_F) { available_birth.insert(births_.at(chain_f)); } - - auto maxb_it = available_birth.begin();//max birth cycle - auto maxb = *maxb_it; //max birth value, for persistence diagram - available_birth.erase(maxb_it); //remove max birth cycle (stolen) - - auto last_modified_chain_it = chains_in_F.rbegin(); - - //consider all death indices by increasing the maximal availabe death. - //Let c_1 ... c_f be the chains s.t. <[c_1+...+c_f]> is the kernel and - // death(c_i) >d death(c_i-1). If the birth of c_i is not available, we set - //c_i <- c_i + c_i-1 + ... + c_1, which is [c_i + c_i-1 + ... + c_1] on - //the right (of death the maximali <=> the maxj>k, are indeed c_j - //set c_i <- c_i + (c_i-1) + ... + (c_k+1) + (c_k + ... + c_1) - for(auto chain_passed_it = last_modified_chain_it;//all with smaller modified_columns; - const auto& row = matrix_.get_row(cpx_.key(zzsh)); - modified_columns.reserve(row.size()); - std::transform(row.begin(), - row.end(), - std::back_inserter(modified_columns), - [](const auto& cell) { return cell.get_column_index(); }); - //Sort by left-to-right order in the matrix_ (no order maintained in rows) - std::stable_sort(modified_columns.begin(),modified_columns.end(), - [this](index i1, index i2){ - return matrix_.get_pivot(i1) < matrix_.get_pivot(i2); - }); - - //Modifies the pointer curr_col, not the other one. - for(auto other_col_it = std::next(modified_columns.begin()); - other_col_it != modified_columns.end(); ++other_col_it) - { - // index ci = other_col_it->get_column_index(); - // ++other_col_it; //vine swap unvalidates iterator - curr_col = matrix_.vine_swap_with_z_eq_1_case(curr_col, *other_col_it); - } - - //curr_col points to the column to remove by restriction of K to K-{\sigma} - if(!matrix_.get_column(curr_col).is_paired()) { // in F - int dim_zzsh = cpx_.dimension(zzsh); - if(dim_max_ == -1 || (dim_max_ != -1 && dim_zzsh < dim_max_)) { //don't record intervals of max dim - persistence_diagram_.emplace_back( dim_zzsh - , births_.at(curr_col) - , num_arrow_);// -1); - } - } - else { //in H -> paired with c_g, that now belongs to F now - births_.at(matrix_.get_column(curr_col).get_paired_chain_index()) = num_arrow_; - } - - //cannot be in G as the removed simplex is maximal - matrix_.remove_maximal_simplex(cpx_.key(zzsh)); - } - -public: - /** \brief Returns the index persistence diagram as an std::list of intervals.*/ - const std::list< interval_index > & index_persistence_diagram() const - { - return persistence_diagram_; - } - - /** \brief Returns the filtration values \f$[f(b),f(d)]\f$ (generally real-valued) - * associated to the indices \f$[b,d]\f$ (integer valued) of the insertion or - * deletion of a simplex in the zigzag filtration. - * - * \details Used to convert a persistent interval \f$[b,d]\f$, computed by the - * persistent homology algorithm, into its filtration valued version - * \f$[f(b),f(d)]\f$ used in the persistence barcode. The information - * index->filtration is stored in the member filtration_values_ of - * the class Zigzag_persistence. - * - * @param[in] b_key, d_key The indices of birth and death of a persistent - * interval. - * - * @param[out] std::pair A pair of real values \f$(f(b),f(d))\f$. - */ - std::pair index_to_filtration( - Simplex_key b_key, Simplex_key d_key) { - // filtration_values_ must be sorted by increasing keys. - auto it_b = //lower_bound(x) returns leftmost y s.t. x <= y - std::lower_bound( filtration_values_.begin(), filtration_values_.end() - , std::pair(b_key - , std::numeric_limits::infinity() ) - , []( std::pair p1 - , std::pair p2) - { return p1.first < p2.first; } - ); - if(it_b == filtration_values_.end() || it_b->first > b_key) { --it_b; } - //it points to the rightmost z such that z <= x - - auto it_d = // - std::lower_bound( filtration_values_.begin(), filtration_values_.end() - , std::pair(d_key - , std::numeric_limits::infinity() ) - , []( std::pair p1 - , std::pair p2) - { return p1.first < p2.first; } - ); - if(it_d == filtration_values_.end() || it_d->first > d_key) { --it_d; } - - return std::make_pair(it_b->second, it_d->second); - } - - /** \brief Writes the persistence diagram in a file. - * - * \details The filtration values are given by the zigzag persistence iterator, that assigns - * to any insertion or deletion of a simplex a filtration value ; we say that an - * arrow has an index \f$i\f$, and a corresponding filtration value \f$f(i)\f$. - * Reading a zigzag filtration from left to right, indices are strictly - * monotonically increasing, and the associated filtration values are monotonous - * (not necessarily - * strictly, either increasing or decreasing). - * - * Consider two consecutive arrows (insertion or deletion): - * - * \f$$K_1 \leftrightarrow K_2 \leftrightarrow K_3\f$$ - * - * with respectively indices \f$i\f$ (left) and \f$i+1\f$ (right), and associated - * filtration values \f$f(i)\f$ and \f$f(i+1)\f$ respectively. - * - * If, the arrow \f$K_2 \leftrightarrow K_3\f$ leads to the creation of a new - * homology feature in \f$K_3\f$, it creates an (indexed) persistent interval - * \f$[\f$i+1; \cdot\f$, and a corresponding (filtration) persistent interval - * \f$[f(i+1); \cdot]\f$ in the persistence diagram. - * - * If a homology feature in \f$K_2\f$ is destroyed by the arrow \f$K_2 \leftrightarrow K_3\f$, it closes an (indexed) - * interval \f$[\cdot ; i+1]\f$, and a corresponding (filtration) persistent - * interval \f$[\cdot ; f(i+1)]\f$ in the persistence diagram. - * - * For example, in an oscillating Rips zigzag filtration, if, in the following - * chunk of filtration: - * - * \f$R_{\eta \varepsilon_i}(P_i) \rightarrow \cdots \leftarrow R_{\eta \varepsilon_{i+1}}(P_{i+1}),\f$ - * - * if anything is created by any of the arrows above, it leads to an interval - * \f$[\varepsilon_{i+1}; \cdot]\f$. If anything is destroyed by any of the arrows - * above, if leads to an interval \f$[\cdot;\varepsilon_i]\f$. Note that we may - * have \f$\varepsilon_i > \varepsilon_{i+1}\f$. - * - * The bars are ordered by decreasing length. - * - * @param[in] os the output stream in which the diagram is written. - * @param[in] shortest_interval all intervals of lenght smaller or equal to - * this value are ignore. Default is 0. - */ - void persistence_diagram( std::ostream& os - , Filtration_value shortest_interval = 0.) { - - std::stable_sort(filtration_values_.begin(), filtration_values_.end(), - []( std::pair< Simplex_key, Filtration_value > p1 - , std::pair< Simplex_key, Filtration_value > p2 ) - { return p1.first < p2.first; } - ); - - std::vector< interval_filtration > tmp_diag; - tmp_diag.reserve(persistence_diagram_.size()); - for(auto bar : persistence_diagram_) - { - Filtration_value birth,death; - std::tie(birth,death) = index_to_filtration(bar.birth(), bar.death()); - - if( std::abs(birth - death) > shortest_interval ) { - tmp_diag.emplace_back(bar.dim(), birth, death ); - } - } - // cmp_intervals_by_length cmp; - std::stable_sort(tmp_diag.begin(), tmp_diag.end(), cmp_intervals_by_length()); - - os << "# dim birth death [length]\n"; - for(auto bar : tmp_diag) { - if(bar.birth() > bar.death()) { bar.swap_birth_death(); } - os << bar.dim() << " " << bar.birth() << " " << bar.death() << - " - [" << bar.length() << "] \n"; - } - } - - /** \brief Returns the persistence diagram as a vector of real-valued intervals. */ - std::vector< interval_filtration > - persistence_diagram(Filtration_value shortest_interval = 0., bool include_infinit_bars = false) - { - std::stable_sort(filtration_values_.begin(), filtration_values_.end(), - []( std::pair< Simplex_key, Filtration_value > p1 - , std::pair< Simplex_key, Filtration_value > p2 ) - { return p1.first < p2.first; } - ); - - std::vector< interval_filtration > diag; - diag.reserve(persistence_diagram_.size()); - for(auto bar : persistence_diagram_) - { - Filtration_value birth,death; - std::tie(birth,death) = index_to_filtration(bar.birth(), bar.death()); - - if( std::abs(birth - death) > shortest_interval ) { - diag.emplace_back(bar.dim(), birth, death ); - } - } - //put lower value as birth - for(auto &bar : diag) { - if( bar.birth() > bar.death() ) { bar.swap_birth_death(); } - } - std::stable_sort(diag.begin(), diag.end(), cmp_intervals_by_length()); - - auto birth = - [this](Simplex_key b_key) { - auto it_b = // lower_bound(x) returns leftmost y s.t. x <= y - std::lower_bound(filtration_values_.begin(), filtration_values_.end(), - std::pair( - b_key, std::numeric_limits::infinity()), - [](std::pair p1, - std::pair p2) { return p1.first < p2.first; }); - if (it_b == filtration_values_.end() || it_b->first > b_key) { - --it_b; - } - return it_b->second; - }; - - //TODO: better recording? - if (include_infinit_bars) { - for (unsigned int i = 0; i < matrix_.get_number_of_columns(); ++i) { - const auto& col = matrix_.get_column(i); - if (!col.is_paired()) - diag.emplace_back(col.get_dimension(), birth(col.get_pivot()), std::numeric_limits::infinity()); - } - } - - return diag; - } - -private: - Complex cpx_; // complex - int dim_max_;//max dim complex - matrix_type matrix_; // 0 ... m-1 - std::unordered_map births_; - birth_ordering birth_ordering_; - std::list< interval_index > persistence_diagram_; - Simplex_key num_arrow_; //current index - Filtration_value previous_filtration_value_; - // filtration_values stores consecutive pairs (i,f) , (j,f') with f != f', - // meaning that all inserted simplices with key in [i;j-1] have filtration value f - //i is the smallest simplex index whose simplex has filtration value f. - std::vector< std::pair< Simplex_key, Filtration_value > > filtration_values_; -};//end class Zigzag_persistence - -} //namespace zigzag_persistence - -} //namespace Gudhi - -#endif //ZIGZAG_PERSISTENCE_H_ +/** \class Zigzag_persistence Zigzag_persistence.h gudhi/Zigzag_persistence.h + * \brief Class computating the zigzag persistent homology of a zigzag + * filtration. Algorithm based on \cite zigzag_reflection. + * + * \details The type ZigzagFilteredComplex::Simplex_key counts the number of + * insertions and + * deletions of simplices, which may be large in zigzag persistence and require + * more than 32 bits of storage. The type used (int, long, etc) should be chosen in + * consequence. Simplex_key must be signed. + * + * Over all insertions, the Simplex_key must be positive and strictly increasing + * when forward iterating along the zigzag filtration. + * + * \tparam ZigzagFilteredComplex Complex storing the current simplices. + * \tparam ZigzagPersistenceOptions Options for the matrix used to compute the persistence. + */ +template > +class Zigzag_persistence +{ + public: + using Complex = ZigzagFilteredComplex; /**< Complex type. */ + using Options = ZigzagPersistenceOptions; /**< Matrix options */ + /*** Types defined in the complex ***/ + using Simplex_key = typename Complex::Simplex_key; /**< Key type, must be signed. */ + using Simplex_handle = typename Complex::Simplex_handle; /**< Simplex ID type in the complex. */ + using Vertex_handle = typename Complex::Vertex_handle; /**< Vertex ID type in the complex. */ + using Filtration_value = typename Complex::Filtration_value; /**< Filtration value type. */ + + /** \brief Structure to store persistence intervals by their index values. + * + * \details By convention, interval [b;d] are + * closed for finite indices b and d, and open for left-infinite and/or + * right-infinite endpoints. + */ + template + struct interval { + interval() {} + interval(int dim, value_type b, value_type d) : dim_(dim), b_(b), d_(d) {} + /** Returns the dimension of the homological feature corresponding to the + * interval. */ + int dim() const { return dim_; } // return the homological dimension of the interval + /** Returns the birth index of the interval.*/ + value_type birth() const { return b_; } // return the birth value + /** Returns the death index of the interval.*/ + value_type death() const { return d_; } // return the death value + + protected: // note that we don't assume b_ <= d_ + int dim_; // homological dimension + value_type b_; // filtration value associated to birth index + value_type d_; // filtration value associated to death index + }; + using index_interval = interval; + + /** \brief Structure to store persistence intervals by their filtration values. + * + * \details By convention, interval \f$[b;d]\f$ are + * closed for finite indices b and d, and open for left-infinite and/or + * right-infinite endpoints. + */ + struct filtration_value_interval : interval + { + private: + using Base = interval; + + public: + /** + * @brief Default constructor + */ + filtration_value_interval() : Base() {} + /** + * @brief Construct a new interval with given parameters + * + * @param dim Dimension of the interval. + * @param b Start value of the interval. + * @param d End value of the interval. + */ + filtration_value_interval(int dim, Filtration_value b, Filtration_value d) + : Base(dim, b, d) {} + + /** + * @brief Returns the absolute length of the interval \f$|d-b|\f$. + */ + Filtration_value length() const { + if (Base::b_ == Base::d_) { + return 0; + } // otherwise inf - inf would return nan. + return std::abs(Base::b_ - Base::d_); + } + /** + * @brief Returns the absolute length of the log values of birth and death, i.e. \f$|\log d - \log b|\f$. + */ + Filtration_value log_length() const { + if (Base::b_ == Base::d_) { + return 0; + } // otherwise inf - inf would return nan. + return std::abs(std::log2(static_cast(Base::b_)) - std::log2(static_cast(Base::d_))); + } + }; + + private: + /** \brief Maintains the birth ordering \f$\leq_b\f$. + * + * \details Contains an std::map of size the number of + * non-zero rows of the homology matrix, at any time during the computation of + * zigzag persistence. + * + * By construction, we maintain the map satisfying + * 'birth_to_pos_[i] < birth_to_pos_[j]', with \f$0 <= i,j <= k\f$ indices in the quiver + * '\f$0 \leftrightarrow ... \leftrightarrow i \leftrightarrow ... \leftrightarrow k\f$' visited at time + * \f$k\f$ of the algorithm (prefix of length \f$k\f$ of the full zigzag filtration + * '\f$0 \leftrightarrow ... \leftrightarrow i \leftrightarrow ... + * \leftrightarrow k \leftrightarrow ... \leftrightarrow n\f$' + * that is studied), iff \f$i <_b j\f$ for the birth ordering. + * + * By construction, when adding index \f$k+1\f$ to '\f$0 \leftrightarrow ... \leftrightarrow i \leftrightarrow .. + * \leftrightarrow k \leftrightarrow k+1'\f$, we have: + * - if \f$k \rightarrow k+1\f$ forward, then \f$j <_b k+1\f$ for all indices \f$j < k+1\f$, otherwise + * - if \f$k \leftarrow k+1\f$ backward, then \f$k+1 <_b j\f$ for all indices \f$j < k+1\f$. + */ + struct birth_ordering { + /** + * @brief Default constructor + */ + birth_ordering() : birth_to_pos_(), max_birth_pos_(0), min_birth_pos_(-1) {} + + /** + * @brief Inserts arrow number in the ordering after an insertion. + * When the arrow key-1 -> key is forward, key is larger than any other index + * i < key in the birth ordering b k2. + * + * @param k1 + * @param k2 + * @return true if k1 >b k2, false otherwise. + */ + bool reverse_birth_order(Simplex_key k1, Simplex_key k2) const { return birth_to_pos_.at(k1) > birth_to_pos_.at(k2); } + + private: + std::unordered_map birth_to_pos_; /**< birth_to_pos_[i] < birth_to_pos_[j] iff i ; + using index = Gudhi::persistence_matrix::index; + + public: + /** + * @brief Constructor of the Zigzag_persistence class. + * @details After construction of the class, the zigzag filtration should be given in a streaming like way, i.e., + * call @ref insert_simplex or @ref remove_simplex for each step of the filtration in order of the filtration. + * If simplices are added (resp. removed) continuously, they can be inserted (resp. removed) in batches by using + * @ref insert_simplices_contiguously (resp. @ref remove_simplices_contiguously). + * To retrieve the current persistence diagram at any moment of the filtration, + * use @ref get_persistence_diagram or @ref get_index_persistence_diagram. + * + * @param min_number_of_simplices Minimum number of simplices that will be inserted at some point in the filtration. + * If the total number of simplices is known in advance, the memory allocation can be better optimized. + * Default value: 0. + * @param ignore_cycles_above_dim Ignores cycles in dimension larger or equal in the final diagram. + * If -1, no cycles are ignored. Default value: -1. + */ + Zigzag_persistence(unsigned int min_number_of_simplices = 0, int ignore_cycles_above_dim = -1) + : dim_max_(ignore_cycles_above_dim), + matrix_(min_number_of_simplices, + [this](index columnIndex1, index columnIndex2) { + return birth_ordering_.birth_order(births_.at(columnIndex1), births_.at(columnIndex2)); + }), + num_arrow_(-1), + previous_filtration_value_(std::numeric_limits::infinity()) {} + + /** + * @brief Updates the zigzag persistence diagram after the insertion of the given simplex. + * + * @tparam VertexRange Range type needing begin and end members. + * @param simplex Simplex to insert, represented by its vertices. + * @param filtration_value Filtration value associated to the simplex. + * Assumed to be larger or equal to previously used filtration values. + */ + template > + void insert_simplex(const VertexRange& simplex, Filtration_value filtration_value) { + if (dim_max_ != -1 && simplex.size() > static_cast(dim_max_) + 1) return; + + ++num_arrow_; + + if (filtration_value != previous_filtration_value_) // check whether the filt value has changed + { // consecutive pairs (i,f), (j,f') mean simplices of index k in [i,j-1] have + previous_filtration_value_ = filtration_value; // filtration value f + filtration_values_.emplace_back(num_arrow_, previous_filtration_value_); + } + + std::pair res = cpx_.insert_simplex(simplex, filtration_value); + GUDHI_CHECK(res.second, "Zigzag_persistence::insert_simplex - insertion of a simplex already in the complex"); + cpx_.assign_key(res.first, num_arrow_); + _process_forward_arrow(res.first); + } + + /** + * @brief Updates the zigzag persistence diagram after the removal of the given simplex. + * + * @tparam VertexRange Range type needing begin and end members. + * @param simplex Simplex to remove, represented by its vertices. + * @param filtration_value Filtration value associated to the removal. + * Assumed to be larger or equal to previously used filtration values. + */ + template > + void remove_simplex(const VertexRange& simplex, Filtration_value filtration_value) { + if (dim_max_ != -1 && simplex.size() > static_cast(dim_max_) + 1) return; + + ++num_arrow_; + + Simplex_handle sh = cpx_.find(simplex); + GUDHI_CHECK(sh != cpx_.null_simplex(), + "Zigzag_persistence::remove_simplex - removal of a simplex not in the complex"); + + if (filtration_value != previous_filtration_value_) // check whether the filt value has changed + { // consecutive pairs (i,f), (j,f') mean simplices of index k in [i,j-1] have + previous_filtration_value_ = filtration_value; // filtration value f + filtration_values_.emplace_back(num_arrow_, previous_filtration_value_); + } + + _process_backward_arrow(sh); + cpx_.remove_maximal_simplex(sh); + } + + /** + * @brief Updates the zigzag persistence diagram after the insertion of the given simplices. + * + * @tparam SimplexRange Range type needing begin and end members. + * @tparam FiltrationRange Range type needing begin and end members. + * @param simplices Simplices which are inserted, represented by their vertices. They have to be in the order they + * are inserted in the filtration and ``contiguous'' in the filtration, that is, no other simplex + * which is not in the range is inserted or removed between two simplices in the range. + * @param filtration_values Filtration values associated to the insertion of the given simplices. + * The order has to correspond to the order in @a simplices. Their values have to ascending in this order and + * they are assumed to be larger or equal to previously used filtration values. + */ + template >, + class FiltrationRange = std::initializer_list> + void insert_simplices_contiguously(const SimplexRange& simplices, const FiltrationRange& filtration_values) { + auto simplexIt = simplices.begin(); + auto filIt = filtration_values.begin(); + for (; simplexIt != simplices.end(); ++simplexIt, ++filIt) { + insert_simplex(*simplexIt, *filIt); + } + } + + /** + * @brief Updates the zigzag persistence diagram after the removal of the given simplices. + * + * @tparam SimplexRange Range type needing begin and end members. + * @tparam FiltrationRange Range type needing begin and end members. + * @param simplices Simplices which are removed, represented by their vertices. They have to be in the order they + * are removed in the filtration and ``contiguous'' in the filtration, that is, no other simplex + * which is not in the range is inserted or removed between two simplices in the range. + * @param filtration_values Filtration values associated to the removal of the given simplices. Has therefore the + * same size as @a simplices. The order has to correspond to the order in @a simplices. Their values have to + * ascending in this order and they are assumed to be larger or equal to previously used filtration values. + */ + template >, + class FiltrationRange = std::initializer_list> + void remove_simplices_contiguously(const SimplexRange& simplices, const FiltrationRange& filtration_values) { + auto simplexIt = simplices.begin(); + auto filIt = filtration_values.begin(); + for (; simplexIt != simplices.end(); ++simplexIt, ++filIt) { + remove_simplex(*simplexIt, *filIt); + } + } + + /** + * @brief Updates the zigzag persistence diagram after the insertion of the given simplices. + * + * @tparam SimplexRangeIterators Forward iterator of a range. + * @tparam FiltrationRangeIterators Forward iterator of a range. + * @param simplex_range_start Iterator pointing to the begining of the range of simplices to insert. + * The simplices should be represented by their vertices. They have to be in the order they + * are inserted in the filtration and ``contiguous'' in the filtration, that is, no other simplex + * which is not in the range is inserted or removed between two simplices in the range. + * @param simplex_range_end Iterator pointing to the end of the range of simplices to insert. + * @param filtration_range_start Iterator pointing to the begining of the range of filtration values. The range is + * assumed to end at the same time than the simplices range and has the same order. The filtration values should be + * ascending in this order and they are assumed to be larger or equal to previously used filtration values. + */ + template + void insert_simplices_contiguously(SimplexRangeIterators simplex_range_start, SimplexRangeIterators simplex_range_end, + FiltrationRangeIterators filtration_range_start) { + for (; simplex_range_start != simplex_range_end; ++simplex_range_start, ++filtration_range_start) { + insert_simplex(*simplex_range_start, *filtration_range_start); + } + } + + /** + * @brief Updates the zigzag persistence diagram after the removal of the given simplices. + * + * @tparam SimplexRangeIterators Forward iterator of a range. + * @tparam FiltrationRangeIterators Forward iterator of a range. + * @param simplex_range_start Iterator pointing to the begining of the range of simplices to remove. + * The simplices should be represented by their vertices. They have to be in the order they + * are removed in the filtration and ``contiguous'' in the filtration, that is, no other simplex + * which is not in the range is inserted or removed between two simplices in the range. + * @param simplex_range_end Iterator pointing to the end of the range of simplices to remove. + * @param filtration_range_start Iterator pointing to the begining of the range of filtration values. The range is + * assumed to end at the same time than the simplices range and has the same order. The filtration values should be + * ascending in this order and they are assumed to be larger or equal to previously used filtration values. + */ + template + void remove_simplices_contiguously(SimplexRangeIterators simplex_range_start, SimplexRangeIterators simplex_range_end, + FiltrationRangeIterators filtration_range_start) { + for (; simplex_range_start != simplex_range_end; ++simplex_range_start, ++filtration_range_start) { + remove_simplex(*simplex_range_start, *filtration_range_start); + } + } + + /** + * @brief Returns the ``index persistence diagram'' of the current filtration, that is, the pairs of atomic arrow + * numbers corresponding to a birth-death pair. Does not contain points at infinity, only the cycle classes which + * already died are represented. + * + * @return Reference to the list of intervals. + */ + const std::list& get_index_persistence_diagram() const { return persistence_diagram_; } + + /** + * @brief Returns the filtration values \f$[f(b),f(d)]\f$ associated to the indices \f$[b,d]\f$ which are retrieved + * by @ref get_index_persistence_diagram. + * + * @param b_key Birth index + * @param d_key Death index + * @return A pair of filtration values associated to the given indices. + */ + std::pair map_index_to_filtration_value( + Simplex_key b_key, Simplex_key d_key) const + { + // filtration_values_ must be sorted by increasing keys. + auto it_b = // lower_bound(x) returns leftmost y s.t. x <= y + std::lower_bound( + filtration_values_.begin(), filtration_values_.end(), + std::pair(b_key, std::numeric_limits::infinity()), + [](std::pair p1, std::pair p2) { + return p1.first < p2.first; + }); + if (it_b == filtration_values_.end() || it_b->first > b_key) { + --it_b; + } + // it points to the rightmost z such that z <= x + + auto it_d = // + std::lower_bound( + filtration_values_.begin(), filtration_values_.end(), + std::pair(d_key, std::numeric_limits::infinity()), + [](std::pair p1, std::pair p2) { + return p1.first < p2.first; + }); + if (it_d == filtration_values_.end() || it_d->first > d_key) { + --it_d; + } + + return std::make_pair(it_b->second, it_d->second); + } + + /** + * @brief Returns the current persistence diagram ordered first by length, than by dimension, + * than by birth value and finally by death value. + * + * @param shortest_interval Threshold. Every bar shorter than the given value will be ignored. Default value: 0. + * @param include_infinit_bars If set to true, infinit bars are included in the diagram. Default value: false. + * @return A vector of pairs of filtration values representing the persistence diagram. + */ + std::vector get_persistence_diagram(Filtration_value shortest_interval = 0., + bool include_infinit_bars = false) { + auto comp = [](filtration_value_interval p, filtration_value_interval q) { + if (p.length() != q.length()) { + return p.length() > q.length(); + } // longest 1st + if (p.dim() != q.dim()) { + return p.dim() < q.dim(); + } // lower dimension first + if (p.birth() != q.birth()) { + return p.birth() < q.birth(); + } // lex order + return p.death() < q.death(); + }; + + std::vector diag = _get_persistence_diagram(shortest_interval); + + if (include_infinit_bars) { + _retrieve_infinit_bars(diag); + } + + std::stable_sort(diag.begin(), diag.end(), comp); + + return diag; + } + + /** + * @brief Returns a reference to the complex storing the simplices. + * A simplex is added in a call of @ref insert_simplex and is removed in a call of @ref remove_simplex. + * + * @return Const reference to the complex. + */ +// const ZigzagFilteredComplex& get_complex() const{ +// return cpx_; +// } + + /** + * @brief Returns a reference to the complex storing the simplices. + * A simplex is added in a call of @ref insert_simplex and is removed in a call of @ref remove_simplex. + * @warning The complex is not const for now for technical reasons, but DO NOT modify it. + * + * @return Reference to the complex. + */ + ZigzagFilteredComplex& get_complex() const{ + return cpx_; + } + + /** + * @brief For debug purposes, to remove. + */ + void print_current_complex() const { + for (auto& sh : cpx_.complex_simplex_range()) { + for (auto v : cpx_.simplex_vertex_range(sh)) { + std::cout << v << " "; + } + std::cout << " - " << cpx_.filtration(sh) << "\n"; + } + } + + private: + /** + * @brief Computes the boundary cycle of the new simplex zzsh, and express it as a + * sum of cycles in a matrix. If some cycles are not boundary cycles, i.e., columns with F-index + * in the matrix, it applies a surjective diamond to the zigzag module. + * + * @param zzsh Simplex handle of the inserted simplex. + */ + void _process_forward_arrow(Simplex_handle zzsh) { // maintain the <=b order + // Reduce the boundary of zzsh in the basis of cycles. + // Compute the simplex keys of the simplices of the boundary of zzsh. + std::set col_bsh; // set maintains the natural order on indices + for (auto b_sh : cpx_.boundary_simplex_range(zzsh)) { + col_bsh.insert(cpx_.key(b_sh)); + } + + std::vector chains_in_F = matrix_.insert_boundary(num_arrow_, col_bsh); + + if (!chains_in_F.empty()) { + _apply_surjective_reflection_diamond(zzsh, chains_in_F); + } else { + birth_ordering_.add_birth_forward(num_arrow_); + births_.emplace_hint(births_.end(), matrix_.get_column_with_pivot(num_arrow_), num_arrow_); + } + } + + /** + * @brief Applies the surjective reflection diamond principle to the current filtration. + * + * @details The vector chains_in_F is sorted by decreasing lowest index values in the + * columns corresponding to the chains, due to its computation in the reduction of + * \partial zzsh in _process_forward_arrow(...). It is equivalent to decreasing death index + * order w.r.t. the & chains_in_F) { + // fp is the largest death index for <=d + // Set col_fp: col_fp <- col_f1+...+col_fp (now in G); preserves lowest idx + auto chain_fp = chains_in_F[0]; // col_fp, with largest death bool { + return birth_ordering_.reverse_birth_order(k1, k2); + }; // true iff b(k1) >b b(k2) + + // available_birth: for all i by >d value of the d_i, + // contains at step i all b_j, j > i, and maybe b_i if not stolen + std::set available_birth(cmp_birth); + // for f1 to f_{p} (i by <=d), insertion in available_birth_to_fidx sorts by >=b + for (auto& chain_f : chains_in_F) { + available_birth.insert(births_.at(chain_f)); + } + + auto maxb_it = available_birth.begin(); // max birth cycle + auto maxb = *maxb_it; // max birth value, for persistence diagram + available_birth.erase(maxb_it); // remove max birth cycle (stolen) + + auto last_modified_chain_it = chains_in_F.rbegin(); + + // consider all death indices by increasing the maximal availabe death. + // Let c_1 ... c_f be the chains s.t. <[c_1+...+c_f]> is the kernel and + // death(c_i) >d death(c_i-1). If the birth of c_i is not available, we set + // c_i <- c_i + c_i-1 + ... + c_1, which is [c_i + c_i-1 + ... + c_1] on + // the right (of death the maximali <=> the maxj>k, are indeed c_j + // set c_i <- c_i + (c_i-1) + ... + (c_k+1) + (c_k + ... + c_1) + for (auto chain_passed_it = last_modified_chain_it; // all with smaller modified_columns; + const auto& row = matrix_.get_row(simplexIndex); + modified_columns.reserve(row.size()); + std::transform(row.begin(), row.end(), std::back_inserter(modified_columns), + [](const auto& cell) { return cell.get_column_index(); }); + // Sort by left-to-right order in the matrix_ (no order maintained in rows) + std::stable_sort(modified_columns.begin(), modified_columns.end(), + [this](index i1, index i2) { return matrix_.get_pivot(i1) < matrix_.get_pivot(i2); }); + + // Modifies curr_col, not the other one. + for (auto other_col_it = std::next(modified_columns.begin()); other_col_it != modified_columns.end(); + ++other_col_it) { + curr_col = matrix_.vine_swap_with_z_eq_1_case(curr_col, *other_col_it); + } + + // curr_col points to the column to remove by restriction of K to K-{\sigma} + if (!matrix_.get_column(curr_col).is_paired()) { // in F + int dim_zzsh = cpx_.dimension(zzsh); + auto it = births_.find(curr_col); + if (dim_max_ == -1 || (dim_max_ != -1 && dim_zzsh < dim_max_)) { // don't record intervals of max dim + persistence_diagram_.emplace_back(dim_zzsh, it->second, num_arrow_); // -1); + } + //Following value can be erased, but it slowes the process down a bit, so I keep it as a remainder for now: + // birth_ordering_.remove_birth(it->second); + births_.erase(it); + } else { // in H -> paired with c_g, that now belongs to F now + // maintain the <=b order + birth_ordering_.add_birth_backward(num_arrow_); + births_.try_emplace(matrix_.get_column(curr_col).get_paired_chain_index(), num_arrow_); + } + + // cannot be in G as the removed simplex is maximal + matrix_.remove_maximal_simplex(simplexIndex); + } + + /** + * @brief Returns the current persistence diagram ordered by length without infinit bars. + * + * @param shortest_interval Intervals shorter than the given value are ignored. + * @return Vector of intervals. + */ + std::vector _get_persistence_diagram(Filtration_value shortest_interval) { + std::vector diag; + diag.reserve(persistence_diagram_.size()); + + std::stable_sort(filtration_values_.begin(), filtration_values_.end(), + [](std::pair p1, std::pair p2) { + return p1.first < p2.first; + }); + + for (auto bar : persistence_diagram_) { + Filtration_value birth, death; + std::tie(birth, death) = map_index_to_filtration_value(bar.birth(), bar.death()); + if (birth > death) { + std::swap(birth, death); + } + + if (death - birth > shortest_interval) { + diag.emplace_back(bar.dim(), birth, death); + } + } + + return diag; + } + + /** + * @brief Computes the births of the current essential cycles. + * + * @param diag Reference to vector where to store the infinit bars. + */ + void _retrieve_infinit_bars(std::vector& diag) const { + auto birth = [this](Simplex_key b_key) { + auto it_b = // lower_bound(x) returns leftmost y s.t. x <= y + std::lower_bound( + filtration_values_.begin(), filtration_values_.end(), + std::pair(b_key, std::numeric_limits::infinity()), + [](std::pair p1, std::pair p2) { + return p1.first < p2.first; + }); + if (it_b == filtration_values_.end() || it_b->first > b_key) { + --it_b; + } + return it_b->second; + }; + + for (auto& p : births_) { + auto dim = matrix_.get_column(matrix_.get_column_with_pivot(p.first)).get_dimension(); + if (dim_max_ == -1 || (dim_max_ != -1 && dim < dim_max_)) + diag.emplace_back(dim, birth(p.second), std::numeric_limits::infinity()); + } + } + + private: + Complex cpx_; /**< Complex in which the current simplices are stored. */ + int dim_max_; /**< Maximal dimension of a bar to record. */ + matrix_type matrix_; /**< Matrix storing a base of the current chain complex. */ + std::unordered_map births_; /**< Map simplex index in F to corresponding birth. */ + birth_ordering birth_ordering_; /**< Maintains persistence_diagram_; /**< Stores current closed persistence intervals. */ + Simplex_key num_arrow_; /**< Current arrow number. */ + Filtration_value previous_filtration_value_; /**< Filtration value of the previous arrow. */ + /** + * @brief filtration_values_ stores consecutive pairs (i,f) , (j,f') with f != f', + * meaning that all inserted simplices with key in [i;j-1] have filtration value f + * i is the smallest simplex index whose simplex has filtration value f. + */ + std::vector> filtration_values_; +}; // end class Zigzag_persistence + +} // namespace zigzag_persistence + +} // namespace Gudhi + +#endif // ZIGZAG_PERSISTENCE_H_ diff --git a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence_old.h b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence_old.h index c364fc10c2..aa93d75a21 100644 --- a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence_old.h +++ b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence_old.h @@ -300,9 +300,9 @@ class Zigzag_persistence { * \details By convention, interval \f$[b;d]\f$ are * closed for finite indices b and d, and open for left-infinite and/or * right-infinite endpoints.*/ - struct interval_filtration { - interval_filtration() {} - interval_filtration(int dim, Filtration_value b, Filtration_value d) : dim_(dim), b_(b), d_(d) {} + struct fil_interval { + fil_interval() {} + fil_interval(int dim, Filtration_value b, Filtration_value d) : dim_(dim), b_(b), d_(d) {} /** Returns the absolute length of the interval \f$|d-b|\f$. */ Filtration_value length() { if(b_ == d_) { return 0; } //otherwise inf - inf would return nan. @@ -359,7 +359,7 @@ class Zigzag_persistence { */ struct cmp_intervals_by_log_length { cmp_intervals_by_log_length(){} - bool operator()( interval_filtration p, interval_filtration q) + bool operator()( fil_interval p, fil_interval q) { if(p.dim() != q.dim()) {return p.dim() < q.dim();}//lower dimension first if(p.log_length() != q.log_length()) {return p.log_length() > q.log_length();} @@ -373,7 +373,7 @@ class Zigzag_persistence { */ struct cmp_intervals_by_length { cmp_intervals_by_length(){} - bool operator()( interval_filtration p, interval_filtration q) + bool operator()( fil_interval p, fil_interval q) { if(p.length() != q.length()) { return p.length() > q.length(); }//longest 1st if(p.dim() != q.dim()) {return p.dim() < q.dim();}//lower dimension first @@ -617,7 +617,7 @@ class Zigzag_persistence { std::pair res = cpx_.insert_simplex(simplex, filtration_value); GUDHI_CHECK(res.second, "Zigzag_persistence::insert_simplex - insertion of a simplex already in the complex"); cpx_.assign_key(res.first, num_arrow_); - forward_arrow(res.first); + _process_forward_arrow(res.first); } template> @@ -636,7 +636,7 @@ class Zigzag_persistence { filtration_values_.emplace_back(num_arrow_, previous_filtration_value_); } - backward_arrow(sh); + _process_backward_arrow(sh); cpx_.remove_maximal_simplex(sh); } @@ -699,7 +699,7 @@ class Zigzag_persistence { * i.e., columns with (F \cup G)-indices, and then apply a surjective diamond to * the zigzag module. */ - void forward_arrow( Simplex_handle zzsh ) + void _process_forward_arrow( Simplex_handle zzsh ) { //maintain the <=b order birth_ordering_.add_birth_forward(num_arrow_); @@ -899,7 +899,7 @@ class Zigzag_persistence { } //cpx_.key(zzsh) is the key of the simplex we remove, not a new one - void backward_arrow( Simplex_handle zzsh ) + void _process_backward_arrow( Simplex_handle zzsh ) { //maintain the <=b order birth_ordering_.add_birth_backward(num_arrow_); @@ -1117,7 +1117,7 @@ class Zigzag_persistence { public: /** \brief Returns the index persistence diagram as an std::list of intervals.*/ - const std::list< interval_index > & index_persistence_diagram() const + const std::list< interval_index > & get_index_persistence_diagram() const { return persistence_diagram_; } @@ -1137,7 +1137,7 @@ class Zigzag_persistence { * * @param[out] std::pair A pair of real values \f$(f(b),f(d))\f$. */ - std::pair index_to_filtration( + std::pair map_index_to_filtration_value( Simplex_key b_key, Simplex_key d_key) { // filtration_values_ must be sorted by increasing keys. auto it_b = //lower_bound(x) returns leftmost y s.t. x <= y @@ -1215,12 +1215,12 @@ class Zigzag_persistence { { return p1.first < p2.first; } ); - std::vector< interval_filtration > tmp_diag; + std::vector< fil_interval > tmp_diag; tmp_diag.reserve(persistence_diagram_.size()); for(auto bar : persistence_diagram_) { Filtration_value birth,death; - std::tie(birth,death) = index_to_filtration(bar.birth(), bar.death()); + std::tie(birth,death) = map_index_to_filtration_value(bar.birth(), bar.death()); if( std::abs(birth - death) > shortest_interval ) { tmp_diag.emplace_back(bar.dim(), birth, death ); @@ -1238,8 +1238,8 @@ class Zigzag_persistence { } /** \brief Returns the persistence diagram as a vector of real-valued intervals. */ - std::vector< interval_filtration > - persistence_diagram(Filtration_value shortest_interval = 0., bool include_infinit_bars = false) + std::vector< fil_interval > + get_persistence_diagram(Filtration_value shortest_interval = 0., bool include_infinit_bars = false) { std::stable_sort(filtration_values_.begin(), filtration_values_.end(), []( std::pair< Simplex_key, Filtration_value > p1 @@ -1247,12 +1247,12 @@ class Zigzag_persistence { { return p1.first < p2.first; } ); - std::vector< interval_filtration > diag; + std::vector< fil_interval > diag; diag.reserve(persistence_diagram_.size()); for(auto bar : persistence_diagram_) { Filtration_value birth,death; - std::tie(birth,death) = index_to_filtration(bar.birth(), bar.death()); + std::tie(birth,death) = map_index_to_filtration_value(bar.birth(), bar.death()); if( std::abs(birth - death) > shortest_interval ) { diag.emplace_back(bar.dim(), birth, death ); diff --git a/src/Zigzag_persistence/test/CMakeLists.txt b/src/Zigzag_persistence/test/CMakeLists.txt index 74dac45186..c5be1da0a9 100644 --- a/src/Zigzag_persistence/test/CMakeLists.txt +++ b/src/Zigzag_persistence/test/CMakeLists.txt @@ -7,10 +7,5 @@ if(TARGET TBB::tbb) target_link_libraries(Zigzag_persistence_unit_test TBB::tbb) endif() -# Do not forget to copy test results files in current binary dir -#file(COPY "${CMAKE_SOURCE_DIR}/src/Persistent_cohomology/test/simplex_tree_file_for_unit_test.txt" -# DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) - -# Unitary tests gudhi_add_boost_test(Zigzag_persistence_unit_test) diff --git a/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp b/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp index 49bb97b5a9..050bcd93b7 100644 --- a/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp +++ b/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp @@ -1,7 +1,18 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Hannah Schreiber + * + * Copyright (C) 2023 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + #include #include #include #include +#include #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MODULE "zigzag_persistence" @@ -16,453 +27,460 @@ using ST = Gudhi::Simplex_tree; using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; using Vertex_handle = ST::Vertex_handle; using Filtration_value = ST::Filtration_value; -using interval_index = ZP::interval_index; -using interval_filtration = ZP::interval_filtration; - -// TODO: -// void persistence_diagram(std::ostream& os, Filtration_value shortest_interval = 0.); +using interval_index = ZP::index_interval; +using interval_filtration = ZP::filtration_value_interval; struct cmp_intervals_by_length { - cmp_intervals_by_length() {} - bool operator()(interval_filtration p, interval_filtration q) { - if (p.length() != q.length()) { - return p.length() > q.length(); - } - if (p.dim() != q.dim()) { - return p.dim() < q.dim(); - } - if (p.birth() != q.birth()) { - return p.birth() < q.birth(); - } - return p.death() < q.death(); - } + cmp_intervals_by_length() {} + bool operator()(interval_filtration p, interval_filtration q) { + if (p.length() != q.length()) { + return p.length() > q.length(); + } + if (p.dim() != q.dim()) { + return p.dim() < q.dim(); + } + if (p.birth() != q.birth()) { + return p.birth() < q.birth(); + } + return p.death() < q.death(); + } }; BOOST_AUTO_TEST_CASE(constructor) { - BOOST_CHECK_NO_THROW(ZP zp); - BOOST_CHECK_NO_THROW(ZP zp(28)); - BOOST_CHECK_NO_THROW(ZP zp(28,2)); - ZP zp; - BOOST_CHECK(zp.persistence_diagram(0).empty()); + BOOST_CHECK_NO_THROW(ZP zp); + BOOST_CHECK_NO_THROW(ZP zp(28)); + BOOST_CHECK_NO_THROW(ZP zp(28, 2)); + ZP zp; + BOOST_CHECK(zp.get_persistence_diagram(0).empty()); } -void test_barcode(ZP& zp, std::vector& barcode) -{ - std::stable_sort(barcode.begin(), barcode.end(), cmp_intervals_by_length()); - auto it = barcode.begin(); - for (const auto& interval : zp.persistence_diagram()){ - BOOST_CHECK_EQUAL(interval.dim(), it->dim()); - BOOST_CHECK_EQUAL(interval.birth(), it->birth()); - BOOST_CHECK_EQUAL(interval.death(), it->death()); - ++it; - } - BOOST_CHECK(it == barcode.end()); +void test_barcode(ZP& zp, std::vector& barcode) { + std::stable_sort(barcode.begin(), barcode.end(), cmp_intervals_by_length()); + auto it = barcode.begin(); + for (const auto& interval : zp.get_persistence_diagram(0, true)) { + BOOST_CHECK_EQUAL(interval.dim(), it->dim()); + BOOST_CHECK_EQUAL(interval.birth(), it->birth()); + BOOST_CHECK_EQUAL(interval.death(), it->death()); + ++it; + } + BOOST_CHECK(it == barcode.end()); } -void test_indices(ZP& zp, std::vector& indices, std::vector& indexToFil) -{ - auto it = indices.begin(); - for (const auto& interval : zp.index_persistence_diagram()){ - BOOST_CHECK_EQUAL(interval.dim(), it->dim()); - BOOST_CHECK_EQUAL(interval.birth(), it->birth()); - BOOST_CHECK_EQUAL(interval.death(), it->death()); - auto p = zp.index_to_filtration(interval.birth(), interval.death()); - BOOST_CHECK_EQUAL(p.first, indexToFil[interval.birth()]); - BOOST_CHECK_EQUAL(p.second, indexToFil[interval.death()]); - ++it; - } - BOOST_CHECK(it == indices.end()); +void test_indices(ZP& zp, std::vector& indices, std::vector& indexToFil) { + auto it = indices.begin(); + for (const auto& interval : zp.get_index_persistence_diagram()) { + BOOST_CHECK_EQUAL(interval.dim(), it->dim()); + BOOST_CHECK_EQUAL(interval.birth(), it->birth()); + BOOST_CHECK_EQUAL(interval.death(), it->death()); + auto p = zp.map_index_to_filtration_value(interval.birth(), interval.death()); + BOOST_CHECK_EQUAL(p.first, indexToFil[interval.birth()]); + BOOST_CHECK_EQUAL(p.second, indexToFil[interval.death()]); + ++it; + } + BOOST_CHECK(it == indices.end()); } -std::vector > get_simplices() -{ - return { - {0}, - {1}, - {2}, - {0,1}, - {0,2}, - {3}, - {1,2}, - {4}, - {3,4}, - {5}, - {0,1,2}, - {4,5}, - {3,5}, - {3,4,5}, - {0,1,2}, //r - {3,4,5}, //r - {1,4}, - {0,1,2}, - {2,4}, - {3,4,5}, - {0,4}, - {0,2,4}, - {1,2,4}, - {0,1,4}, - {3,4,5}, //r - {3,4}, //r - {3,5}, //r - {0,1,2,4}}; +std::vector > get_simplices() { + return {{0}, + {1}, + {2}, + {0, 1}, + {0, 2}, + {3}, + {1, 2}, + {4}, + {3, 4}, + {5}, + {0, 1, 2}, + {4, 5}, + {3, 5}, + {3, 4, 5}, + {0, 1, 2}, // remove + {3, 4, 5}, // remove + {1, 4}, + {0, 1, 2}, + {2, 4}, + {3, 4, 5}, + {0, 4}, + {0, 2, 4}, + {1, 2, 4}, + {0, 1, 4}, + {3, 4, 5}, // remove + {3, 4}, // remove + {3, 5}, // remove + {0, 1, 2, 4}, + {0, 1, 2, 4}}; // remove } -std::vector get_filtration_values() -{ - return { - 0, 0, 0, - 1, 1, 1, - 2, 2, 2, - 3, 3, 3, 3, - 4, - 5, - 6, 6, 6, - 7, 7, 7, 7, 7, 7, - 8, - 9, 9, 9 - }; +std::vector get_filtration_values() { + return {0, 0, 0, + 1, 1, 1, + 2, 2, 2, + 3, 3, 3, 3, + 4, + 5, + 6, 6, 6, + 7, 7, 7, 7, 7, 7, + 8, + 9, 9, 9, + 10}; } BOOST_AUTO_TEST_CASE(zigzag_persistence_single) { - ZP zp(28); - std::vector realIndices; - std::vector realBarcode; - realIndices.reserve(13); - realBarcode.reserve(9); - - std::vector > simplices = get_simplices(); - std::vector filValues = get_filtration_values(); - - for (unsigned int i = 0; i < 14; ++i){ - zp.insert_simplex(simplices[i], filValues[i]); - } - - realIndices.emplace_back(0, 1, 3); - realIndices.emplace_back(0, 2, 4); - realIndices.emplace_back(0, 7, 8); - realIndices.emplace_back(1, 6, 10); - realIndices.emplace_back(0, 9, 11); - realIndices.emplace_back(1, 12, 13); - - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(1, 2, 3); - realBarcode.emplace_back(1, 3, 4); - - for (unsigned int i = 14; i < 16; ++i){ - zp.remove_simplex(simplices[i], filValues[i]); - } - - for (unsigned int i = 16; i < 24; ++i){ - zp.insert_simplex(simplices[i], filValues[i]); - } - - realIndices.emplace_back(0, 5, 16); - realIndices.emplace_back(1, 14, 17); - realIndices.emplace_back(1, 15, 19); - realIndices.emplace_back(1, 20, 21); - realIndices.emplace_back(1, 18, 22); - - realBarcode.emplace_back(0, 1, 6); - realBarcode.emplace_back(1, 5, 6); - realBarcode.emplace_back(1, 6, 7); - - for (unsigned int i = 24; i < 27; ++i){ - zp.remove_simplex(simplices[i], filValues[i]); - } - - realIndices.emplace_back(1, 24, 25); - realBarcode.emplace_back(1, 8, 9); - - zp.insert_simplex(simplices[27], filValues[27]); - - realIndices.emplace_back(2, 23, 27); - realBarcode.emplace_back(2, 7, 9); - - test_indices(zp, realIndices, filValues); - test_barcode(zp, realBarcode); + ZP zp(28); + std::vector realIndices; + std::vector realBarcode; + realIndices.reserve(13); + realBarcode.reserve(9); + + std::vector > simplices = get_simplices(); + std::vector filValues = get_filtration_values(); + + for (unsigned int i = 0; i < 14; ++i) { + zp.insert_simplex(simplices[i], filValues[i]); + } + + realIndices.emplace_back(0, 1, 3); + realIndices.emplace_back(0, 2, 4); + realIndices.emplace_back(0, 7, 8); + realIndices.emplace_back(1, 6, 10); + realIndices.emplace_back(0, 9, 11); + realIndices.emplace_back(1, 12, 13); + + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(1, 2, 3); + realBarcode.emplace_back(1, 3, 4); + + for (unsigned int i = 14; i < 16; ++i) { + zp.remove_simplex(simplices[i], filValues[i]); + } + + for (unsigned int i = 16; i < 24; ++i) { + zp.insert_simplex(simplices[i], filValues[i]); + } + + realIndices.emplace_back(0, 5, 16); + realIndices.emplace_back(1, 14, 17); + realIndices.emplace_back(1, 15, 19); + realIndices.emplace_back(1, 20, 21); + realIndices.emplace_back(1, 18, 22); + + realBarcode.emplace_back(0, 1, 6); + realBarcode.emplace_back(1, 5, 6); + realBarcode.emplace_back(1, 6, 7); + + for (unsigned int i = 24; i < 27; ++i) { + zp.remove_simplex(simplices[i], filValues[i]); + } + + realIndices.emplace_back(1, 24, 25); + realBarcode.emplace_back(1, 8, 9); + + zp.insert_simplex(simplices[27], filValues[27]); + + realIndices.emplace_back(2, 23, 27); + realBarcode.emplace_back(2, 7, 9); + + zp.remove_simplex(simplices[28], filValues[28]); + + realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); + realBarcode.emplace_back(2, 10, std::numeric_limits::infinity()); + + test_indices(zp, realIndices, filValues); + test_barcode(zp, realBarcode); } BOOST_AUTO_TEST_CASE(zigzag_persistence_single_max1) { - ZP zp(28, 1); - std::vector realIndices; - std::vector indexToFil(28); - std::vector realBarcode; - realIndices.reserve(5); - realBarcode.reserve(3); - - std::vector > simplices = get_simplices(); - std::vector filValues = get_filtration_values(); - unsigned int currIndex = 0; - - for (unsigned int i = 0; i < 14; ++i){ - zp.insert_simplex(simplices[i], filValues[i]); - if (simplices[i].size() < 3){ - indexToFil[currIndex++] = filValues[i]; - } - } - - realIndices.emplace_back(0, 1, 3); - realIndices.emplace_back(0, 2, 4); - realIndices.emplace_back(0, 7, 8); - realIndices.emplace_back(0, 9, 10); - - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(0, 0, 1); - - for (unsigned int i = 14; i < 16; ++i){ - zp.remove_simplex(simplices[i], filValues[i]); - if (simplices[i].size() < 3){ - indexToFil[currIndex++] = filValues[i]; - } - } - - for (unsigned int i = 16; i < 24; ++i){ - zp.insert_simplex(simplices[i], filValues[i]); - if (simplices[i].size() < 3){ - indexToFil[currIndex++] = filValues[i]; - } - } - - realIndices.emplace_back(0, 5, 12); - realBarcode.emplace_back(0, 1, 6); - - for (unsigned int i = 24; i < 27; ++i){ - zp.remove_simplex(simplices[i], filValues[i]); - if (simplices[i].size() < 3){ - indexToFil[currIndex++] = filValues[i]; - } - } - - zp.insert_simplex(simplices[27], filValues[27]); - - test_indices(zp, realIndices, indexToFil); - test_barcode(zp, realBarcode); + ZP zp(28, 1); + std::vector realIndices; + std::vector indexToFil(28); + std::vector realBarcode; + realIndices.reserve(5); + realBarcode.reserve(3); + + std::vector > simplices = get_simplices(); + std::vector filValues = get_filtration_values(); + unsigned int currIndex = 0; + + for (unsigned int i = 0; i < 14; ++i) { + zp.insert_simplex(simplices[i], filValues[i]); + if (simplices[i].size() < 3) { + indexToFil[currIndex++] = filValues[i]; + } + } + + realIndices.emplace_back(0, 1, 3); + realIndices.emplace_back(0, 2, 4); + realIndices.emplace_back(0, 7, 8); + realIndices.emplace_back(0, 9, 10); + + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(0, 0, 1); + + for (unsigned int i = 14; i < 16; ++i) { + zp.remove_simplex(simplices[i], filValues[i]); + if (simplices[i].size() < 3) { + indexToFil[currIndex++] = filValues[i]; + } + } + + for (unsigned int i = 16; i < 24; ++i) { + zp.insert_simplex(simplices[i], filValues[i]); + if (simplices[i].size() < 3) { + indexToFil[currIndex++] = filValues[i]; + } + } + + realIndices.emplace_back(0, 5, 12); + realBarcode.emplace_back(0, 1, 6); + + for (unsigned int i = 24; i < 27; ++i) { + zp.remove_simplex(simplices[i], filValues[i]); + if (simplices[i].size() < 3) { + indexToFil[currIndex++] = filValues[i]; + } + } + + zp.insert_simplex(simplices[27], filValues[27]); + zp.remove_simplex(simplices[28], filValues[28]); + + realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); + + test_indices(zp, realIndices, indexToFil); + test_barcode(zp, realBarcode); } BOOST_AUTO_TEST_CASE(zigzag_persistence_batch_with_iterators) { - ZP zp; - std::vector realIndices; - std::vector realBarcode; - realIndices.reserve(13); - realBarcode.reserve(9); - - std::vector > simplices = get_simplices(); - std::vector filValues = get_filtration_values(); - - zp.insert_simplices_contiguously(simplices.begin(), - simplices.begin() + 14, - filValues.begin()); - - realIndices.emplace_back(0, 1, 3); - realIndices.emplace_back(0, 2, 4); - realIndices.emplace_back(0, 7, 8); - realIndices.emplace_back(1, 6, 10); - realIndices.emplace_back(0, 9, 11); - realIndices.emplace_back(1, 12, 13); - - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(1, 2, 3); - realBarcode.emplace_back(1, 3, 4); - - zp.remove_simplices_contiguously(simplices.begin() + 14, - simplices.begin() + 16, - filValues.begin() + 14); - zp.insert_simplices_contiguously(simplices.begin() + 16, - simplices.begin() + 24, - filValues.begin() + 16); - - realIndices.emplace_back(0, 5, 16); - realIndices.emplace_back(1, 14, 17); - realIndices.emplace_back(1, 15, 19); - realIndices.emplace_back(1, 20, 21); - realIndices.emplace_back(1, 18, 22); - - realBarcode.emplace_back(0, 1, 6); - realBarcode.emplace_back(1, 5, 6); - realBarcode.emplace_back(1, 6, 7); - - zp.remove_simplices_contiguously(simplices.begin() + 24, - simplices.begin() + 27, - filValues.begin() + 24); - - realIndices.emplace_back(1, 24, 25); - realBarcode.emplace_back(1, 8, 9); - - zp.insert_simplices_contiguously(simplices.begin() + 27, - simplices.begin() + 28, - filValues.begin() + 27); - - realIndices.emplace_back(2, 23, 27); - realBarcode.emplace_back(2, 7, 9); - - test_indices(zp, realIndices, filValues); - test_barcode(zp, realBarcode); + ZP zp; + std::vector realIndices; + std::vector realBarcode; + realIndices.reserve(13); + realBarcode.reserve(9); + + std::vector > simplices = get_simplices(); + std::vector filValues = get_filtration_values(); + + zp.insert_simplices_contiguously(simplices.begin(), simplices.begin() + 14, filValues.begin()); + + realIndices.emplace_back(0, 1, 3); + realIndices.emplace_back(0, 2, 4); + realIndices.emplace_back(0, 7, 8); + realIndices.emplace_back(1, 6, 10); + realIndices.emplace_back(0, 9, 11); + realIndices.emplace_back(1, 12, 13); + + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(1, 2, 3); + realBarcode.emplace_back(1, 3, 4); + + zp.remove_simplices_contiguously(simplices.begin() + 14, simplices.begin() + 16, filValues.begin() + 14); + zp.insert_simplices_contiguously(simplices.begin() + 16, simplices.begin() + 24, filValues.begin() + 16); + + realIndices.emplace_back(0, 5, 16); + realIndices.emplace_back(1, 14, 17); + realIndices.emplace_back(1, 15, 19); + realIndices.emplace_back(1, 20, 21); + realIndices.emplace_back(1, 18, 22); + + realBarcode.emplace_back(0, 1, 6); + realBarcode.emplace_back(1, 5, 6); + realBarcode.emplace_back(1, 6, 7); + + zp.remove_simplices_contiguously(simplices.begin() + 24, simplices.begin() + 27, filValues.begin() + 24); + + realIndices.emplace_back(1, 24, 25); + realBarcode.emplace_back(1, 8, 9); + + zp.insert_simplices_contiguously(simplices.begin() + 27, simplices.begin() + 28, filValues.begin() + 27); + + realIndices.emplace_back(2, 23, 27); + realBarcode.emplace_back(2, 7, 9); + + zp.remove_simplices_contiguously(simplices.begin() + 28, simplices.begin() + 29, filValues.begin() + 28); + + realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); + realBarcode.emplace_back(2, 10, std::numeric_limits::infinity()); + + test_indices(zp, realIndices, filValues); + test_barcode(zp, realBarcode); } BOOST_AUTO_TEST_CASE(zigzag_persistence_batch_with_iterators_max1) { - ZP zp(28, 1); - std::vector realIndices; - std::vector indexToFil(28); - std::vector realBarcode; - realIndices.reserve(5); - realBarcode.reserve(3); - - std::vector > simplices = get_simplices(); - std::vector filValues = get_filtration_values(); - unsigned int currIndex = 0; - - for (unsigned int i = 0; i < 28; ++i){ - if (simplices[i].size() < 3){ - indexToFil[currIndex++] = filValues[i]; - } - } - - zp.insert_simplices_contiguously(simplices.begin(), - simplices.begin() + 14, - filValues.begin()); - - realIndices.emplace_back(0, 1, 3); - realIndices.emplace_back(0, 2, 4); - realIndices.emplace_back(0, 7, 8); - realIndices.emplace_back(0, 9, 10); - - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(0, 0, 1); - - zp.remove_simplices_contiguously(simplices.begin() + 14, - simplices.begin() + 16, - filValues.begin() + 14); - zp.insert_simplices_contiguously(simplices.begin() + 16, - simplices.begin() + 24, - filValues.begin() + 16); - - realIndices.emplace_back(0, 5, 12); - realBarcode.emplace_back(0, 1, 6); - - zp.remove_simplices_contiguously(simplices.begin() + 24, - simplices.begin() + 27, - filValues.begin() + 24); - zp.insert_simplices_contiguously(simplices.begin() + 27, - simplices.begin() + 28, - filValues.begin() + 27); - - test_indices(zp, realIndices, indexToFil); - test_barcode(zp, realBarcode); + ZP zp(28, 1); + std::vector realIndices; + std::vector indexToFil(28); + std::vector realBarcode; + realIndices.reserve(5); + realBarcode.reserve(3); + + std::vector > simplices = get_simplices(); + std::vector filValues = get_filtration_values(); + unsigned int currIndex = 0; + + for (unsigned int i = 0; i < 28; ++i) { + if (simplices[i].size() < 3) { + indexToFil[currIndex++] = filValues[i]; + } + } + + zp.insert_simplices_contiguously(simplices.begin(), simplices.begin() + 14, filValues.begin()); + + realIndices.emplace_back(0, 1, 3); + realIndices.emplace_back(0, 2, 4); + realIndices.emplace_back(0, 7, 8); + realIndices.emplace_back(0, 9, 10); + + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(0, 0, 1); + + zp.remove_simplices_contiguously(simplices.begin() + 14, simplices.begin() + 16, filValues.begin() + 14); + zp.insert_simplices_contiguously(simplices.begin() + 16, simplices.begin() + 24, filValues.begin() + 16); + + realIndices.emplace_back(0, 5, 12); + realBarcode.emplace_back(0, 1, 6); + + zp.remove_simplices_contiguously(simplices.begin() + 24, simplices.begin() + 27, filValues.begin() + 24); + zp.insert_simplices_contiguously(simplices.begin() + 27, simplices.begin() + 28, filValues.begin() + 27); + zp.remove_simplices_contiguously(simplices.begin() + 28, simplices.begin() + 29, filValues.begin() + 28); + + realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); + + test_indices(zp, realIndices, indexToFil); + test_barcode(zp, realBarcode); } BOOST_AUTO_TEST_CASE(zigzag_persistence_batch) { - ZP zp; - std::vector realIndices; - std::vector realBarcode; - realIndices.reserve(13); - realBarcode.reserve(9); - - std::vector > simplices = get_simplices(); - std::vector filValues = get_filtration_values(); - - std::vector > subSimplices(simplices.begin(), simplices.begin() + 14); - std::vector subFilValues(filValues.begin(), filValues.begin() + 14); - zp.insert_simplices_contiguously(subSimplices, subFilValues); - - realIndices.emplace_back(0, 1, 3); - realIndices.emplace_back(0, 2, 4); - realIndices.emplace_back(0, 7, 8); - realIndices.emplace_back(1, 6, 10); - realIndices.emplace_back(0, 9, 11); - realIndices.emplace_back(1, 12, 13); - - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(1, 2, 3); - realBarcode.emplace_back(1, 3, 4); - - subSimplices = std::vector >(simplices.begin() + 14, simplices.begin() + 16); - subFilValues = std::vector(filValues.begin() + 14, filValues.begin() + 16); - zp.remove_simplices_contiguously(subSimplices, subFilValues); - - subSimplices = std::vector >(simplices.begin() + 16, simplices.begin() + 24); - subFilValues = std::vector(filValues.begin() + 16, filValues.begin() + 24); - zp.insert_simplices_contiguously(subSimplices, subFilValues); - - realIndices.emplace_back(0, 5, 16); - realIndices.emplace_back(1, 14, 17); - realIndices.emplace_back(1, 15, 19); - realIndices.emplace_back(1, 20, 21); - realIndices.emplace_back(1, 18, 22); - - realBarcode.emplace_back(0, 1, 6); - realBarcode.emplace_back(1, 5, 6); - realBarcode.emplace_back(1, 6, 7); - - subSimplices = std::vector >(simplices.begin() + 24, simplices.begin() + 27); - subFilValues = std::vector(filValues.begin() + 24, filValues.begin() + 27); - zp.remove_simplices_contiguously(subSimplices, subFilValues); - - realIndices.emplace_back(1, 24, 25); - realBarcode.emplace_back(1, 8, 9); - - subSimplices = std::vector >(simplices.begin() + 27, simplices.begin() + 28); - subFilValues = std::vector(filValues.begin() + 27, filValues.begin() + 28); - zp.insert_simplices_contiguously(subSimplices, subFilValues); - - realIndices.emplace_back(2, 23, 27); - realBarcode.emplace_back(2, 7, 9); - - test_indices(zp, realIndices, filValues); - test_barcode(zp, realBarcode); + ZP zp; + std::vector realIndices; + std::vector realBarcode; + realIndices.reserve(13); + realBarcode.reserve(9); + + std::vector > simplices = get_simplices(); + std::vector filValues = get_filtration_values(); + + std::vector > subSimplices(simplices.begin(), simplices.begin() + 14); + std::vector subFilValues(filValues.begin(), filValues.begin() + 14); + zp.insert_simplices_contiguously(subSimplices, subFilValues); + + realIndices.emplace_back(0, 1, 3); + realIndices.emplace_back(0, 2, 4); + realIndices.emplace_back(0, 7, 8); + realIndices.emplace_back(1, 6, 10); + realIndices.emplace_back(0, 9, 11); + realIndices.emplace_back(1, 12, 13); + + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(1, 2, 3); + realBarcode.emplace_back(1, 3, 4); + + subSimplices = std::vector >(simplices.begin() + 14, simplices.begin() + 16); + subFilValues = std::vector(filValues.begin() + 14, filValues.begin() + 16); + zp.remove_simplices_contiguously(subSimplices, subFilValues); + + subSimplices = std::vector >(simplices.begin() + 16, simplices.begin() + 24); + subFilValues = std::vector(filValues.begin() + 16, filValues.begin() + 24); + zp.insert_simplices_contiguously(subSimplices, subFilValues); + + realIndices.emplace_back(0, 5, 16); + realIndices.emplace_back(1, 14, 17); + realIndices.emplace_back(1, 15, 19); + realIndices.emplace_back(1, 20, 21); + realIndices.emplace_back(1, 18, 22); + + realBarcode.emplace_back(0, 1, 6); + realBarcode.emplace_back(1, 5, 6); + realBarcode.emplace_back(1, 6, 7); + + subSimplices = std::vector >(simplices.begin() + 24, simplices.begin() + 27); + subFilValues = std::vector(filValues.begin() + 24, filValues.begin() + 27); + zp.remove_simplices_contiguously(subSimplices, subFilValues); + + realIndices.emplace_back(1, 24, 25); + realBarcode.emplace_back(1, 8, 9); + + subSimplices = std::vector >(simplices.begin() + 27, simplices.begin() + 28); + subFilValues = std::vector(filValues.begin() + 27, filValues.begin() + 28); + zp.insert_simplices_contiguously(subSimplices, subFilValues); + + realIndices.emplace_back(2, 23, 27); + realBarcode.emplace_back(2, 7, 9); + + subSimplices = std::vector >(simplices.begin() + 28, simplices.begin() + 29); + subFilValues = std::vector(filValues.begin() + 28, filValues.begin() + 29); + zp.remove_simplices_contiguously(subSimplices, subFilValues); + + realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); + realBarcode.emplace_back(2, 10, std::numeric_limits::infinity()); + + test_indices(zp, realIndices, filValues); + test_barcode(zp, realBarcode); } BOOST_AUTO_TEST_CASE(zigzag_persistence_batch_max1) { - ZP zp(28, 1); - std::vector realIndices; - std::vector indexToFil(28); - std::vector realBarcode; - realIndices.reserve(5); - realBarcode.reserve(3); - - std::vector > simplices = get_simplices(); - std::vector filValues = get_filtration_values(); - unsigned int currIndex = 0; - - for (unsigned int i = 0; i < 28; ++i){ - if (simplices[i].size() < 3){ - indexToFil[currIndex++] = filValues[i]; - } - } - - std::vector > subSimplices(simplices.begin(), simplices.begin() + 14); - std::vector subFilValues(filValues.begin(), filValues.begin() + 14); - zp.insert_simplices_contiguously(subSimplices, subFilValues); - - realIndices.emplace_back(0, 1, 3); - realIndices.emplace_back(0, 2, 4); - realIndices.emplace_back(0, 7, 8); - realIndices.emplace_back(0, 9, 10); - - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(0, 0, 1); - - subSimplices = std::vector >(simplices.begin() + 14, simplices.begin() + 16); - subFilValues = std::vector(filValues.begin() + 14, filValues.begin() + 16); - zp.remove_simplices_contiguously(subSimplices, subFilValues); - - subSimplices = std::vector >(simplices.begin() + 16, simplices.begin() + 24); - subFilValues = std::vector(filValues.begin() + 16, filValues.begin() + 24); - zp.insert_simplices_contiguously(subSimplices, subFilValues); - - realIndices.emplace_back(0, 5, 12); - realBarcode.emplace_back(0, 1, 6); - - subSimplices = std::vector >(simplices.begin() + 24, simplices.begin() + 27); - subFilValues = std::vector(filValues.begin() + 24, filValues.begin() + 27); - zp.remove_simplices_contiguously(subSimplices, subFilValues); - - subSimplices = std::vector >(simplices.begin() + 27, simplices.begin() + 28); - subFilValues = std::vector(filValues.begin() + 27, filValues.begin() + 28); - zp.insert_simplices_contiguously(subSimplices, subFilValues); - - test_indices(zp, realIndices, indexToFil); - test_barcode(zp, realBarcode); + ZP zp(28, 1); + std::vector realIndices; + std::vector indexToFil(28); + std::vector realBarcode; + realIndices.reserve(5); + realBarcode.reserve(3); + + std::vector > simplices = get_simplices(); + std::vector filValues = get_filtration_values(); + unsigned int currIndex = 0; + + for (unsigned int i = 0; i < 28; ++i) { + if (simplices[i].size() < 3) { + indexToFil[currIndex++] = filValues[i]; + } + } + + std::vector > subSimplices(simplices.begin(), simplices.begin() + 14); + std::vector subFilValues(filValues.begin(), filValues.begin() + 14); + zp.insert_simplices_contiguously(subSimplices, subFilValues); + + realIndices.emplace_back(0, 1, 3); + realIndices.emplace_back(0, 2, 4); + realIndices.emplace_back(0, 7, 8); + realIndices.emplace_back(0, 9, 10); + + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(0, 0, 1); + + subSimplices = std::vector >(simplices.begin() + 14, simplices.begin() + 16); + subFilValues = std::vector(filValues.begin() + 14, filValues.begin() + 16); + zp.remove_simplices_contiguously(subSimplices, subFilValues); + + subSimplices = std::vector >(simplices.begin() + 16, simplices.begin() + 24); + subFilValues = std::vector(filValues.begin() + 16, filValues.begin() + 24); + zp.insert_simplices_contiguously(subSimplices, subFilValues); + + realIndices.emplace_back(0, 5, 12); + realBarcode.emplace_back(0, 1, 6); + + subSimplices = std::vector >(simplices.begin() + 24, simplices.begin() + 27); + subFilValues = std::vector(filValues.begin() + 24, filValues.begin() + 27); + zp.remove_simplices_contiguously(subSimplices, subFilValues); + + subSimplices = std::vector >(simplices.begin() + 27, simplices.begin() + 28); + subFilValues = std::vector(filValues.begin() + 27, filValues.begin() + 28); + zp.insert_simplices_contiguously(subSimplices, subFilValues); + + subSimplices = std::vector >(simplices.begin() + 27, simplices.begin() + 28); + subFilValues = std::vector(filValues.begin() + 27, filValues.begin() + 28); + zp.remove_simplices_contiguously(subSimplices, subFilValues); + + realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); + + test_indices(zp, realIndices, indexToFil); + test_barcode(zp, realBarcode); } From 2e5a20bfcc35e9602f90d56599fca85660754860 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 21 Jul 2023 14:44:06 +0200 Subject: [PATCH 03/96] deleting files not wanted for the PR --- .../benchmark/CMakeLists.txt | 17 - .../benchmark/Zigzag_benchmark.cpp | 197 -- .../benchmark/Zigzag_old_benchmark.cpp | 112 - .../benchmark/Zigzag_other_benchmark.cpp | 144 - .../benchmark/rips-zigzag-dionysus.h | 211 -- src/Zigzag_persistence/example/CMakeLists.txt | 18 - .../example/comparison_for_tests.cpp | 440 --- .../example_rips_zigzag_filtration.cpp | 158 - .../example/ext_zz/dionysus/chain.h | 153 - .../example/ext_zz/dionysus/chain.hpp | 188 -- .../ext_zz/dionysus/clearing-reduction.h | 45 - .../ext_zz/dionysus/clearing-reduction.hpp | 60 - .../example/ext_zz/dionysus/cnpy.h | 241 -- .../ext_zz/dionysus/cohomology-persistence.h | 116 - .../dionysus/cohomology-persistence.hpp | 61 - .../example/ext_zz/dionysus/common.h | 25 - .../example/ext_zz/dionysus/diagram.h | 114 - .../example/ext_zz/dionysus/distances.h | 93 - .../example/ext_zz/dionysus/distances.hpp | 30 - .../example/ext_zz/dionysus/dlog/progress.h | 57 - .../example/ext_zz/dionysus/fields/q.h | 63 - .../example/ext_zz/dionysus/fields/z2.h | 31 - .../example/ext_zz/dionysus/fields/zp.h | 55 - .../example/ext_zz/dionysus/filtration.h | 124 - .../example/ext_zz/dionysus/format.h | 8 - .../example/ext_zz/dionysus/format/format.cc | 1156 -------- .../example/ext_zz/dionysus/format/format.h | 2546 ----------------- .../example/ext_zz/dionysus/grid/box.h | 136 - .../example/ext_zz/dionysus/grid/box.hpp | 141 - .../example/ext_zz/dionysus/grid/grid.h | 143 - .../example/ext_zz/dionysus/grid/point.h | 132 - .../example/ext_zz/dionysus/grid/vertices.h | 86 - .../ext_zz/dionysus/matrix-filtration.h | 120 - .../ext_zz/dionysus/omni-field-persistence.h | 145 - .../dionysus/omni-field-persistence.hpp | 250 -- .../example/ext_zz/dionysus/opts/opts.h | 499 ---- .../ext_zz/dionysus/ordinary-persistence.h | 64 - .../example/ext_zz/dionysus/pair-recorder.h | 78 - .../example/ext_zz/dionysus/reduced-matrix.h | 170 -- .../ext_zz/dionysus/reduced-matrix.hpp | 78 - .../example/ext_zz/dionysus/reduction.h | 109 - .../dionysus/relative-homology-zigzag.h | 84 - .../dionysus/relative-homology-zigzag.hpp | 122 - .../example/ext_zz/dionysus/rips.h | 147 - .../example/ext_zz/dionysus/rips.hpp | 162 -- .../example/ext_zz/dionysus/row-reduction.h | 54 - .../example/ext_zz/dionysus/row-reduction.hpp | 103 - .../example/ext_zz/dionysus/simplex.h | 280 -- .../ext_zz/dionysus/sparse-row-matrix.h | 184 -- .../ext_zz/dionysus/sparse-row-matrix.hpp | 103 - .../ext_zz/dionysus/standard-reduction.h | 44 - .../ext_zz/dionysus/standard-reduction.hpp | 47 - .../example/ext_zz/dionysus/trails-chains.h | 17 - .../ext_zz/dionysus/zigzag-persistence.h | 142 - .../ext_zz/dionysus/zigzag-persistence.hpp | 541 ---- .../example/ext_zz/fzz/fzz.cpp | 206 -- .../example/ext_zz/fzz/fzz.h | 87 - .../ext_zz/phat/algorithms/chunk_reduction.h | 223 -- .../ext_zz/phat/algorithms/row_reduction.h | 56 - .../algorithms/spectral_sequence_reduction.h | 80 - .../phat/algorithms/standard_reduction.h | 47 - .../ext_zz/phat/algorithms/twist_reduction.h | 51 - .../example/ext_zz/phat/boundary_matrix.h | 343 --- .../ext_zz/phat/compute_persistence_pairs.h | 128 - .../example/ext_zz/phat/helpers/dualize.h | 74 - .../example/ext_zz/phat/helpers/misc.h | 75 - .../phat/helpers/thread_local_storage.h | 52 - .../example/ext_zz/phat/persistence_pairs.h | 155 - .../representations/abstract_pivot_column.h | 102 - .../representations/bit_tree_pivot_column.h | 165 -- .../phat/representations/full_pivot_column.h | 100 - .../phat/representations/heap_pivot_column.h | 126 - .../representations/sparse_pivot_column.h | 79 - .../ext_zz/phat/representations/vector_heap.h | 170 -- .../ext_zz/phat/representations/vector_list.h | 101 - .../ext_zz/phat/representations/vector_set.h | 99 - .../phat/representations/vector_vector.h | 107 - .../example/rips-zigzag-dionysus.h | 211 -- .../include/gudhi/Zigzag_persistence_old.h | 1326 --------- 79 files changed, 14807 deletions(-) delete mode 100644 src/Zigzag_persistence/benchmark/CMakeLists.txt delete mode 100644 src/Zigzag_persistence/benchmark/Zigzag_benchmark.cpp delete mode 100644 src/Zigzag_persistence/benchmark/Zigzag_old_benchmark.cpp delete mode 100644 src/Zigzag_persistence/benchmark/Zigzag_other_benchmark.cpp delete mode 100644 src/Zigzag_persistence/benchmark/rips-zigzag-dionysus.h delete mode 100644 src/Zigzag_persistence/example/comparison_for_tests.cpp delete mode 100644 src/Zigzag_persistence/example/example_rips_zigzag_filtration.cpp delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/chain.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/chain.hpp delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/clearing-reduction.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/clearing-reduction.hpp delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/cnpy.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/cohomology-persistence.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/cohomology-persistence.hpp delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/common.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/diagram.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/distances.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/distances.hpp delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/dlog/progress.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/fields/q.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/fields/z2.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/fields/zp.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/filtration.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/format.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/format/format.cc delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/format/format.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/grid/box.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/grid/box.hpp delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/grid/grid.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/grid/point.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/grid/vertices.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/matrix-filtration.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/omni-field-persistence.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/omni-field-persistence.hpp delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/opts/opts.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/ordinary-persistence.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/pair-recorder.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/reduced-matrix.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/reduced-matrix.hpp delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/reduction.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/relative-homology-zigzag.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/relative-homology-zigzag.hpp delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/rips.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/rips.hpp delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/row-reduction.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/row-reduction.hpp delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/simplex.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/sparse-row-matrix.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/sparse-row-matrix.hpp delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/standard-reduction.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/standard-reduction.hpp delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/trails-chains.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/zigzag-persistence.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/dionysus/zigzag-persistence.hpp delete mode 100644 src/Zigzag_persistence/example/ext_zz/fzz/fzz.cpp delete mode 100644 src/Zigzag_persistence/example/ext_zz/fzz/fzz.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/algorithms/chunk_reduction.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/algorithms/row_reduction.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/algorithms/spectral_sequence_reduction.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/algorithms/standard_reduction.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/algorithms/twist_reduction.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/boundary_matrix.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/compute_persistence_pairs.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/helpers/dualize.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/helpers/misc.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/helpers/thread_local_storage.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/persistence_pairs.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/representations/abstract_pivot_column.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/representations/bit_tree_pivot_column.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/representations/full_pivot_column.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/representations/heap_pivot_column.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/representations/sparse_pivot_column.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/representations/vector_heap.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/representations/vector_list.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/representations/vector_set.h delete mode 100644 src/Zigzag_persistence/example/ext_zz/phat/representations/vector_vector.h delete mode 100644 src/Zigzag_persistence/example/rips-zigzag-dionysus.h delete mode 100644 src/Zigzag_persistence/include/gudhi/Zigzag_persistence_old.h diff --git a/src/Zigzag_persistence/benchmark/CMakeLists.txt b/src/Zigzag_persistence/benchmark/CMakeLists.txt deleted file mode 100644 index 1f0faeb542..0000000000 --- a/src/Zigzag_persistence/benchmark/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -project(Zigzag_benchmark) - -find_package(benchmark REQUIRED) - -add_executable(Zigzag_benchmark Zigzag_benchmark.cpp) -target_link_libraries(Zigzag_benchmark benchmark::benchmark) -target_include_directories(Zigzag_benchmark PUBLIC . ../example/ext_zz) - -add_executable(Zigzag_old_benchmark Zigzag_old_benchmark.cpp) -target_link_libraries(Zigzag_old_benchmark benchmark::benchmark) -target_include_directories(Zigzag_old_benchmark PUBLIC . ../example/ext_zz) - -add_executable(Zigzag_other_benchmark Zigzag_other_benchmark.cpp ../example/ext_zz/fzz/fzz.cpp) -target_link_libraries(Zigzag_other_benchmark benchmark::benchmark) -target_include_directories(Zigzag_other_benchmark PUBLIC . ../example/ext_zz) -target_compile_options(Zigzag_other_benchmark PUBLIC "-fopenmp") -target_link_options(Zigzag_other_benchmark PUBLIC "-fopenmp") diff --git a/src/Zigzag_persistence/benchmark/Zigzag_benchmark.cpp b/src/Zigzag_persistence/benchmark/Zigzag_benchmark.cpp deleted file mode 100644 index 37b4edfb24..0000000000 --- a/src/Zigzag_persistence/benchmark/Zigzag_benchmark.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. - * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. - * Author(s): Hannah Schreiber - * - * Copyright (C) 2022 Inria - * - * Modification(s): - * - YYYY/MM Author: Description of the modification - */ - -#include -#include -#include -#include -#include // for pair -#include -#include - -#include -#include - -#include -#include -#include - -#include "rips-zigzag-dionysus.h" - -using ST = Gudhi::Simplex_tree; -// using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; -using Vertex_handle = ST::Vertex_handle; -using Filtration_value = ST::Filtration_value; - -using Gudhi::persistence_matrix::Zigzag_options; -using CT = Gudhi::persistence_matrix::Column_types; - -template -std::vector< std::pair > print_indices(ZP& zp, unsigned int numberOfSimplices){ - std::set essentials; - std::vector< std::pair > res; - - for (unsigned int i = 0; i < numberOfSimplices; ++i){ - essentials.insert(essentials.end(), i); - } - - for (auto& bar : zp.get_index_persistence_diagram()){ - res.emplace_back(bar.birth(), bar.death()); - essentials.erase(bar.birth()); - essentials.erase(bar.death()); - } - - for (unsigned int v : essentials){ - res.emplace_back(v, numberOfSimplices); - } - - return res; -} - -template -std::vector< std::pair > compute_with_gudhi( - const std::vector >& simplices, - const std::vector& dirs) -{ - ZP zp(simplices.size()); - - // std::cout << "====================== Gudhi =====================\n"; - - std::vector filValues(simplices.size(), 1.0); - - auto start = simplices.begin(); - auto filIt = filValues.begin(); - unsigned int i = 0; - - while (start != simplices.end()){ - unsigned int c = 1; - auto end = start + 1; - ++i; - while (end != simplices.end() && dirs[i - 1] == dirs[i]) { - ++end; - ++i; - ++c; - } - - if (dirs[i - 1]){ - zp.insert_simplices_contiguously( - start, end, filIt); - } else { - zp.remove_simplices_contiguously( - start, end, filIt); - } - - start = end; - filIt += c; - } - - // std::cout << "==================================================\n"; - - return print_indices(zp, i); -} - -static void Compute_zigzag_with_gudhi_intrusive_list(benchmark::State& state) { - using ZP = Gudhi::zigzag_persistence::Zigzag_persistence >; - - unsigned int numberOfPoints = state.range(0); - int seed = numberOfPoints; - std::vector > simplices; - std::vector dirs; - - build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); - - for (auto _ : state){ - compute_with_gudhi(simplices, dirs); - } -} -BENCHMARK(Compute_zigzag_with_gudhi_intrusive_list)->RangeMultiplier(2)->Range(100, 1000)->Unit(benchmark::kMillisecond)->MinWarmUpTime(1); - -static void Compute_zigzag_with_gudhi_intrusive_set(benchmark::State& state) { - using ZP = Gudhi::zigzag_persistence::Zigzag_persistence >; - - unsigned int numberOfPoints = state.range(0); - int seed = numberOfPoints; - std::vector > simplices; - std::vector dirs; - - build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); - - for (auto _ : state){ - compute_with_gudhi(simplices, dirs); - } -} -BENCHMARK(Compute_zigzag_with_gudhi_intrusive_set)->RangeMultiplier(2)->Range(100, 1000)->Unit(benchmark::kMillisecond)->MinWarmUpTime(1); - -static void Compute_zigzag_with_gudhi_list(benchmark::State& state) { - using ZP = Gudhi::zigzag_persistence::Zigzag_persistence >; - - unsigned int numberOfPoints = state.range(0); - int seed = numberOfPoints; - std::vector > simplices; - std::vector dirs; - - build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); - - for (auto _ : state){ - compute_with_gudhi(simplices, dirs); - } -} -BENCHMARK(Compute_zigzag_with_gudhi_list)->RangeMultiplier(2)->Range(100, 1000)->Unit(benchmark::kMillisecond)->MinWarmUpTime(1); - -// static void Compute_zigzag_with_gudhi_set(benchmark::State& state) { -// using ZP = Gudhi::zigzag_persistence::Zigzag_persistence >; - -// unsigned int numberOfPoints = state.range(0); -// int seed = numberOfPoints; -// std::vector > simplices; -// std::vector dirs; - -// build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); - -// for (auto _ : state){ -// compute_with_gudhi(simplices, dirs); -// } -// } -// BENCHMARK(Compute_zigzag_with_gudhi_set)->RangeMultiplier(2)->Range(100, 1000)->Unit(benchmark::kMillisecond)->MinWarmUpTime(1); - -// static void Compute_zigzag_with_gudhi_unordered_set(benchmark::State& state) { -// using ZP = Gudhi::zigzag_persistence::Zigzag_persistence>; - -// unsigned int numberOfPoints = state.range(0); -// int seed = numberOfPoints; -// std::vector > simplices; -// std::vector dirs; - -// build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); - -// for (auto _ : state){ -// compute_with_gudhi(simplices, dirs); -// } -// } -// BENCHMARK(Compute_zigzag_with_gudhi_unordered_set)->RangeMultiplier(2)->Range(100, 1000)->Unit(benchmark::kMillisecond)->MinWarmUpTime(1); - -static void Compute_zigzag_with_gudhi_vector(benchmark::State& state) { - using ZP = Gudhi::zigzag_persistence::Zigzag_persistence>; - - unsigned int numberOfPoints = state.range(0); - int seed = numberOfPoints; - std::vector > simplices; - std::vector dirs; - - build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); - - for (auto _ : state){ - compute_with_gudhi(simplices, dirs); - } -} -BENCHMARK(Compute_zigzag_with_gudhi_vector)->RangeMultiplier(2)->Range(100, 1000)->Unit(benchmark::kMillisecond)->MinWarmUpTime(1); - -BENCHMARK_MAIN(); - diff --git a/src/Zigzag_persistence/benchmark/Zigzag_old_benchmark.cpp b/src/Zigzag_persistence/benchmark/Zigzag_old_benchmark.cpp deleted file mode 100644 index ca079443c3..0000000000 --- a/src/Zigzag_persistence/benchmark/Zigzag_old_benchmark.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. - * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. - * Author(s): Hannah Schreiber - * - * Copyright (C) 2022 Inria - * - * Modification(s): - * - YYYY/MM Author: Description of the modification - */ - -#include -#include -#include -#include -#include // for pair -#include -#include - -#include -#include - -#include -#include - -#include "rips-zigzag-dionysus.h" - -using ST = Gudhi::Simplex_tree; -using coltype = Gudhi::zigzag_persistence::Zigzag_persistence_collist; -using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; -// using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; -using Vertex_handle = ST::Vertex_handle; -using Filtration_value = ST::Filtration_value; -using interval_filtration = ZP::fil_interval; - -std::vector< std::pair > print_indices(ZP& zp, unsigned int numberOfSimplices){ - std::set essentials; - std::vector< std::pair > res; - - for (unsigned int i = 0; i < numberOfSimplices; ++i){ - essentials.insert(essentials.end(), i); - } - - for (auto& bar : zp.get_index_persistence_diagram()){ - res.emplace_back(bar.birth(), bar.death()); - essentials.erase(bar.birth()); - essentials.erase(bar.death()); - } - - for (unsigned int v : essentials){ - res.emplace_back(v, numberOfSimplices); - } - - return res; -} - -std::vector< std::pair > compute_with_gudhi( - const std::vector >& simplices, - const std::vector& dirs) -{ - ZP zp(simplices.size()); - - // std::cout << "====================== Gudhi =====================\n"; - - std::vector filValues(simplices.size(), 1.0); - - auto start = simplices.begin(); - auto filIt = filValues.begin(); - unsigned int i = 0; - - while (start != simplices.end()){ - unsigned int c = 1; - auto end = start + 1; - ++i; - while (end != simplices.end() && dirs[i - 1] == dirs[i]) { - ++end; - ++i; - ++c; - } - - if (dirs[i - 1]){ - zp.insert_simplices_contiguously( - start, end, filIt); - } else { - zp.remove_simplices_contiguously( - start, end, filIt); - } - - start = end; - filIt += c; - } - - // std::cout << "==================================================\n"; - - return print_indices(zp, i); -} - -static void Compute_zigzag_with_gudhi(benchmark::State& state) { - unsigned int numberOfPoints = state.range(0);; - int seed = numberOfPoints; - std::vector > simplices; - std::vector dirs; - - build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); - - for (auto _ : state){ - compute_with_gudhi(simplices, dirs); - } -} -BENCHMARK(Compute_zigzag_with_gudhi)->RangeMultiplier(2)->Range(100, 1000)->Unit(benchmark::kMillisecond)->MinWarmUpTime(1); - -BENCHMARK_MAIN(); - diff --git a/src/Zigzag_persistence/benchmark/Zigzag_other_benchmark.cpp b/src/Zigzag_persistence/benchmark/Zigzag_other_benchmark.cpp deleted file mode 100644 index 6e51854338..0000000000 --- a/src/Zigzag_persistence/benchmark/Zigzag_other_benchmark.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. - * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. - * Author(s): Hannah Schreiber - * - * Copyright (C) 2022 Inria - * - * Modification(s): - * - YYYY/MM Author: Description of the modification - */ - -#include -#include -#include -#include -#include // for pair -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "rips-zigzag-dionysus.h" - -using DField = dionysus::Z2Field; -using Simplex = dionysus::Simplex<>; -using DFiltration = dionysus::Filtration; -using DZZ = dionysus::ZigzagPersistence; -using DIndex = typename DZZ::Index; -using DChain = dionysus::ChainEntry; -using DIChain = dionysus::ChainEntry; -using Vertex_handle = int; - -std::vector< std::pair > compute_with_dionysus( - const std::vector >& simplices, - const std::vector& dirs) -{ - DField k; - std::unordered_map indices; - DZZ persistence(k); - std::vector< std::pair > res; - - // std::cout << "==================== Dionysus ====================\n"; - - std::set essentials; - - unsigned int op = 0; - unsigned int idx = 0; - - for (const std::vector& simplex : simplices){ - Simplex c(simplex); - DIndex pair; - if (dirs[op]) { - indices.try_emplace(c, idx++); - pair = persistence.add(c.boundary(persistence.field()) | - boost::adaptors::transformed([&indices](const DChain& e) { - return DIChain(e.element(), indices.find(e.index())->second); - })); - } else { - auto idxIt = indices.find(c); - pair = persistence.remove(idxIt->second); - indices.erase(idxIt); - } - - if (pair != DZZ::unpaired()) { - res.emplace_back(pair, op); - essentials.erase(pair); - } else { - essentials.insert(essentials.end(), op); - } - op++; - } - - for (unsigned int v : essentials){ - res.emplace_back(v, op); - } - - // std::cout << "==================================================\n"; - - return res; -} - -std::vector< std::tuple > compute_with_fzz( - const std::vector >& simplices, - const std::vector& dirs) -{ - std::vector< std::tuple > persistence; - FZZ::FastZigzag fzz; - - // std::cout << "======================= FZZ ======================\n"; - - fzz.compute(simplices, dirs, &persistence); - - std::sort(persistence.begin(), persistence.end(), - [](const std::tuple& p1, const std::tuple& p2){ - if (std::get<1>(p1) == std::get<1>(p2)){ - return std::get<0>(p1) < std::get<0>(p2); - } - - return std::get<1>(p1) < std::get<1>(p2); - }); - - // std::cout << "==================================================\n"; - - return persistence; -} - -static void Compute_zigzag_with_dionysus(benchmark::State& state) { - unsigned int numberOfPoints = state.range(0);; - int seed = numberOfPoints; - std::vector > simplices; - std::vector dirs; - - build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); - - for (auto _ : state){ - compute_with_dionysus(simplices, dirs); - } -} -BENCHMARK(Compute_zigzag_with_dionysus)->RangeMultiplier(2)->Range(100, 1000)->Unit(benchmark::kMillisecond)->MinWarmUpTime(1); - -static void Compute_zigzag_with_fzz(benchmark::State& state) { - unsigned int numberOfPoints = state.range(0);; - int seed = numberOfPoints; - std::vector > simplices; - std::vector dirs; - - build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); - - for (auto _ : state){ - compute_with_fzz(simplices, dirs); - } -} -BENCHMARK(Compute_zigzag_with_fzz)->RangeMultiplier(2)->Range(100, 1000)->Unit(benchmark::kMillisecond)->MinWarmUpTime(1); - -BENCHMARK_MAIN(); - diff --git a/src/Zigzag_persistence/benchmark/rips-zigzag-dionysus.h b/src/Zigzag_persistence/benchmark/rips-zigzag-dionysus.h deleted file mode 100644 index 5cd2c585c4..0000000000 --- a/src/Zigzag_persistence/benchmark/rips-zigzag-dionysus.h +++ /dev/null @@ -1,211 +0,0 @@ -#include -#include -#include -#include - -#include -namespace ba = boost::adaptors; - -#include -#include -#include -namespace d = dionysus; - -#include - -typedef std::vector Point; -typedef std::vector PointContainer; - -typedef d::PairwiseDistances> PairDistances; -typedef PairDistances::DistanceType DistanceType; -typedef PairDistances::IndexType Vertex; - -typedef d::Rips Generator; -typedef Generator::Simplex Simplex; -typedef std::set SimplexSet; - -typedef std::vector VertexVector; -typedef std::vector EpsilonVector; -typedef std::tuple Edge; -typedef std::vector EdgeVector; - -inline PointContainer compute_points(unsigned int numberOfPoints, int seed = -1) -{ - PointContainer finalPoints; - std::set points; - std::random_device dev; - std::mt19937 rng(dev()); - if (seed > -1) rng.seed(seed); - std::uniform_real_distribution dist(0,10); - - for (unsigned int i = 0; i < numberOfPoints; ++i){ - auto res = points.insert({dist(rng), dist(rng)}); - while(!res.second){ - res = points.insert({dist(rng), dist(rng)}); - } - finalPoints.push_back(*res.first); - } - - return finalPoints; -} - -inline void compute_vertices_and_epsilons(const PairDistances& distances, - VertexVector& vertices, - EpsilonVector& epsilons) -{ - DistanceType inf = std::numeric_limits::infinity(); - EpsilonVector dist(distances.size(), inf); - - vertices.push_back(distances.begin()); - // epsilons.push_back(inf); - while (vertices.size() < distances.size()) { - for (Vertex v = distances.begin(); v != distances.end(); ++v) - dist[v] = std::min(dist[v], distances(v, vertices.back())); - auto max = std::max_element(dist.begin(), dist.end()); - vertices.push_back(max - dist.begin()); - epsilons.push_back(*max); - } - epsilons.push_back(0); -} - -inline void compute_edges(const PairDistances& distances, - const VertexVector& vertices, - const EpsilonVector& epsilons, - const DistanceType& multiplier, - EdgeVector& edges) -{ - for (unsigned i = 0; i != vertices.size(); ++i) - for (unsigned j = i + 1; j != vertices.size(); ++j) { - Vertex u = vertices[i]; - Vertex v = vertices[j]; - if (distances(u, v) <= multiplier * epsilons[j - 1]) edges.emplace_back(u, v); - } - std::sort(edges.begin(), edges.end(), - [&distances](const Edge& e1, const Edge& e2) { - return distances(std::get<0>(e1), std::get<1>(e1)) < - distances(std::get<0>(e2), std::get<1>(e2)); - }); -} - -inline void compute_positive_cofaces( - const PairDistances& distances, - const VertexVector& vertices, - const EdgeVector& edges, - const EpsilonVector& epsilons, - const DistanceType& multiplier, - Generator& rips, - short unsigned& skeleton, - unsigned& ce, - unsigned& i, - SimplexSet& cofaces) -{ - cofaces.clear(); - - // Add anything else that needs to be inserted into the complex - while (ce < edges.size()) { - Vertex u, v; - std::tie(u, v) = edges[ce]; - if (distances(u, v) <= multiplier * epsilons[i - 1]) - ++ce; - else - break; - // std::cout << "Adding cofaces of " << u << ' ' << v << std::endl; - rips.edge_cofaces( - u, v, - skeleton, - multiplier * epsilons[i - 1], - [&cofaces](Simplex&& s) { cofaces.insert(s); }, - vertices.begin(), - vertices.begin() + i + 1); - } -} - -inline void compute_negative_cofaces( - const VertexVector& vertices, - const EpsilonVector& epsilons, - const DistanceType& multiplier, - Generator& rips, - short unsigned& skeleton, - unsigned& i, - SimplexSet& cofaces) -{ - cofaces.clear(); - rips.vertex_cofaces( - vertices[i], - skeleton, - multiplier * epsilons[i - 1], - [&cofaces](Simplex&& s) { cofaces.insert(s); }, - vertices.begin(), - vertices.begin() + i + 1); - // std::cout << "Total cofaces: " << cofaces.size() << std::endl; -} - -inline unsigned int build_rips_zigzag_filtration(std::vector > &simpls, - std::vector& dirs, - unsigned int numberOfPoints, - int seed = -1, - short unsigned skeleton = 2, - DistanceType multiplier = 6) -{ - // std::cout << "Building filtration" << std::endl; - unsigned int numberOfSimplices = 0; - - PointContainer points = compute_points(numberOfPoints, seed); - - // Construct distances and Rips generator - PairDistances distances(points); - Generator rips(distances); - - // Order vertices and epsilons (in maxmin fashion) - VertexVector vertices; - EpsilonVector epsilons; - EdgeVector edges; - - compute_vertices_and_epsilons(distances, vertices, epsilons); - - // Generate and sort all the edges - compute_edges(distances, vertices, epsilons, multiplier, edges); - - // Insert vertices - for (auto v : vertices) { - // Add a vertex - simpls.push_back({static_cast(v)}); - dirs.push_back(true); - ++numberOfSimplices; - } - - // Process vertices - // dlog::progress progress(vertices.size()); - unsigned ce = 0; // index of the current one past last edge in the complex - SimplexSet cofaces; // record the cofaces of all the simplices that need to be removed and reinserted - - for (unsigned stage = 0; stage != vertices.size() - 1; ++stage) { - unsigned i = vertices.size() - 1 - stage; - - /* Increase epsilon */ - compute_positive_cofaces(distances, vertices, edges, epsilons, multiplier, rips, skeleton, ce, i, cofaces); - - for (auto& s : cofaces) { - // std::cout << "Inserting: " << s << std::endl; - simpls.emplace_back(s.begin(), s.end()); - dirs.push_back(true); - ++numberOfSimplices; - } - - /* Remove the vertex */ - // std::cout << "Removing vertex: " << vertices[i] << std::endl; - compute_negative_cofaces(vertices, epsilons, multiplier, rips, skeleton, i, cofaces); - - for (auto& s : cofaces | ba::reversed) { - // std::cout << "Removing: " << s << std::endl; - simpls.emplace_back(s.begin(), s.end()); - dirs.push_back(false); - } - - // ++progress; - } - - return numberOfSimplices; - // std::cout << "Finished" << std::endl; -} diff --git a/src/Zigzag_persistence/example/CMakeLists.txt b/src/Zigzag_persistence/example/CMakeLists.txt index c9814e2768..dd1f88e1d2 100644 --- a/src/Zigzag_persistence/example/CMakeLists.txt +++ b/src/Zigzag_persistence/example/CMakeLists.txt @@ -13,24 +13,6 @@ endif() file(COPY "zigzag_filtration_example.txt" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) add_test(NAME Zigzag_persistence_example_zzfiltration_from_file COMMAND $ "${CMAKE_CURRENT_BINARY_DIR}/zigzag_filtration_example.txt") -# add_executable ( comp comparison_for_tests.cpp ./ext_zz/fzz/fzz.cpp ) -# target_include_directories(comp PUBLIC ./ext_zz) -# target_compile_options(comp PUBLIC "-fopenmp") -# target_link_options(comp PUBLIC "-fopenmp") -# add_executable ( Zigzag_persistence_example_rips_zigzag_filtration example_rips_zigzag_filtration.cpp ) -# target_include_directories(Zigzag_persistence_example_rips_zigzag_filtration PUBLIC ./ext_zz) -# target_compile_options(Zigzag_persistence_example_rips_zigzag_filtration PUBLIC "-fopenmp") -# target_link_options(Zigzag_persistence_example_rips_zigzag_filtration PUBLIC "-fopenmp") - -# add_executable ( rips example_rips_zigzag_filtration.cpp ) -# target_include_directories(rips PUBLIC ./ext_zz) -# target_compile_options(rips PUBLIC "-fopenmp") -# target_link_options(rips PUBLIC "-fopenmp") - -# add_executable ( rips_old example_rips_zigzag_filtration.cpp ) -# target_include_directories(rips_old PUBLIC ./ext_zz) -# target_compile_options(rips_old PUBLIC "-fopenmp") -# target_link_options(rips_old PUBLIC "-fopenmp") diff --git a/src/Zigzag_persistence/example/comparison_for_tests.cpp b/src/Zigzag_persistence/example/comparison_for_tests.cpp deleted file mode 100644 index a2f972966c..0000000000 --- a/src/Zigzag_persistence/example/comparison_for_tests.cpp +++ /dev/null @@ -1,440 +0,0 @@ -/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. - * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. - * Author(s): Hannah Schreiber - * - * Copyright (C) 2023 Inria - * - * Modification(s): - * - YYYY/MM Author: Description of the modification - */ - -#include -#include -#include -#include -#include // for pair -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rips-zigzag-dionysus.h" - -using ST = Gudhi::Simplex_tree; -using Gudhi::persistence_matrix::Zigzag_options; -using CT = Gudhi::persistence_matrix::Column_types; -using ZP = Gudhi::zigzag_persistence::Zigzag_persistence >; -using Vertex_handle = ST::Vertex_handle; -using Filtration_value = ST::Filtration_value; -using interval_filtration = ZP::filtration_value_interval; - -using DField = dionysus::Z2Field; -using Simplex = dionysus::Simplex<>; -using DFiltration = dionysus::Filtration; -using DZZ = dionysus::ZigzagPersistence; -using DIndex = typename DZZ::Index; -using DChain = dionysus::ChainEntry; -using DIChain = dionysus::ChainEntry; - -void print_complex(ZP& zp){ - std::clog << std::endl << "Current complex:" << std::endl; - zp.print_current_complex(); -} - -// void print_barcode(ZP& zp){ -// std::clog << std::endl << "Current barcode:" << std::endl; -// for (auto& bar : zp.persistence_diagram()){ -// std::clog << std::floor(bar.birth()) << " - "; -// if (bar.death() == std::numeric_limits::infinity()){ -// std::clog << "inf"; -// } else { -// std::clog << std::floor(bar.death()); -// } -// std::clog << " (" << bar.dim() << ")\n"; -// } -// } - -std::vector< std::pair > print_indices(ZP& zp, unsigned int numberOfSimplices){ - std::set essentials; - std::vector< std::pair > res; - - for (unsigned int i = 0; i < numberOfSimplices; ++i){ - essentials.insert(essentials.end(), i); - } - - for (auto& bar : zp.get_index_persistence_diagram()){ - // std::clog << bar.birth() << " - "; - // std::clog << bar.death(); - // std::clog << " (" << bar.dim() << ")\n"; - res.emplace_back(bar.birth(), bar.death()); - essentials.erase(bar.birth()); - essentials.erase(bar.death()); - } - - for (unsigned int v : essentials){ - // std::clog << v << " - "; - // std::clog << "inf\n"; - res.emplace_back(v, numberOfSimplices); - } - - return res; -} - -// std::vector > get_simplices() -// { -// return { -// {0}, -// {1}, -// {2}, -// {0,1}, -// {0,2}, -// {3}, -// {1,2}, -// {4}, -// {3,4}, -// {5}, -// {0,1,2}, -// {4,5}, -// {3,5}, -// {3,4,5}, -// {0,1,2}, //r -// {3,4,5}, //r -// {1,4}, -// {0,1,2}, -// {2,4}, -// {3,4,5}, -// {0,4}, -// {0,2,4}, -// {1,2,4}, -// {0,1,4}, -// {3,4,5}, //r -// {3,4}, //r -// {3,5}, //r -// {0,1,2,4}}; -// } - -// std::vector get_filtration_values() -// { -// return { -// 0, 0, 0, -// 1, 1, 1, -// 2, 2, 2, -// 3, 3, 3, 3, -// 4, -// 5, -// 6, 6, 6, -// 7, 7, 7, 7, 7, 7, -// 8, -// 9, 9, 9 -// }; -// } - -// std::vector get_directions() -// { -// return { -// true, -// true, -// true, -// true, -// true, -// true, -// true, -// true, -// true, -// true, -// true, -// true, -// true, -// true, -// false, -// false, -// true, -// true, -// true, -// true, -// true, -// true, -// true, -// true, -// false, -// false, -// false, -// true}; -// } - -std::vector< std::pair > compute_with_gudhi( - const std::vector >& simplices, - const std::vector& dirs) -{ - ZP zp(simplices.size()); - - std::cout << "====================== Gudhi =====================\n"; - - // std::vector filValues = get_filtration_values(); - std::vector filValues(simplices.size(), 1.0); - - auto start = simplices.begin(); - auto filIt = filValues.begin(); - unsigned int i = 0; - - while (start != simplices.end()){ - unsigned int c = 1; - auto end = start + 1; - ++i; - while (end != simplices.end() && dirs[i - 1] == dirs[i]) { - ++end; - ++i; - ++c; - } - - if (dirs[i - 1]){ - zp.insert_simplices_contiguously( - start, end, filIt); - } else { - zp.remove_simplices_contiguously( - start, end, filIt); - } - - start = end; - filIt += c; - // print_complex(zp); - } - - std::cout << "==================================================\n"; - - // print_complex(zp); - // print_barcode(zp); - return print_indices(zp, i); -} - -std::vector< std::pair > compute_with_dionysus( - const std::vector >& simplices, - const std::vector& dirs) -{ - DField k; - std::unordered_map indices; - DZZ persistence(k); - std::vector< std::pair > res; - - std::cout << "==================== Dionysus ====================\n"; - - std::set essentials; - - unsigned int op = 0; - unsigned int idx = 0; - - for (const std::vector& simplex : simplices){ - Simplex c(simplex); - DIndex pair; - if (dirs[op]) { - indices.try_emplace(c, idx++); - // int dim = boost::distance(c.boundary(persistence.field())); - // dim = dim == 0 ? 0 : dim -1; - // fmt::print("[{}] Adding: {} : {}\n", op, c, dim); - pair = persistence.add(c.boundary(persistence.field()) | - boost::adaptors::transformed([&indices](const DChain& e) { - return DIChain(e.element(), indices.find(e.index())->second); - })); - } else { - // fmt::print("[{}] Removing: {} : {}\n", op, c, boost::distance(c.boundary(persistence.field())) - 1); - auto idxIt = indices.find(c); - pair = persistence.remove(idxIt->second); - indices.erase(idxIt); - } - - if (pair != DZZ::unpaired()) { - // fmt::print("{} - {}\n", pair, op); - res.emplace_back(pair, op); - essentials.erase(pair); - } else { - essentials.insert(essentials.end(), op); - } - op++; - } - - for (unsigned int v : essentials){ - // fmt::print("{} - inf\n", v); - res.emplace_back(v, op); - } - - std::cout << "==================================================\n"; - - return res; -} - -std::vector< std::tuple > compute_with_fzz( - const std::vector >& simplices, - const std::vector& dirs) -{ - std::vector< std::tuple > persistence; - // std::vector< std::pair > res; - FZZ::FastZigzag fzz; - - std::cout << "======================= FZZ ======================\n"; - - fzz.compute(simplices, dirs, &persistence); - - std::sort(persistence.begin(), persistence.end(), - [](const std::tuple& p1, const std::tuple& p2){ - if (std::get<1>(p1) == std::get<1>(p2)){ - return std::get<0>(p1) < std::get<0>(p2); - } - - return std::get<1>(p1) < std::get<1>(p2); - }); - - // for (auto& t : persistence) - // res.emplace_back(std::get<0>(t), std::get<1>(t)); - - // for (const auto& e : persistence) { - // std::cout << (std::get<0>(e) - 1) << " - "; - // if (static_cast(std::get<1>(e)) == simplices.size()) std::cout << "inf"; - // else std::cout << std::get<1>(e); - // std::cout << " (" << std::get<2>(e) << ")" << std::endl; - // } - - std::cout << "==================================================\n"; - - return persistence; -} - -bool are_equal(const std::vector >& gudhiRes, - const std::vector >& dioRes) -{ - if (gudhiRes.size() != dioRes.size()) return false; - - for (unsigned int i = 0; i < gudhiRes.size(); ++i){ - if (gudhiRes[i].first != dioRes[i].first || gudhiRes[i].second != dioRes[i].second) - return false; - } - - return true; -} - -bool are_equal(const std::vector >& gudhiRes, - const std::vector >& fzzRes) -{ - if (gudhiRes.size() != fzzRes.size()) return false; - - for (unsigned int i = 0; i < gudhiRes.size(); ++i){ - if (static_cast(gudhiRes[i].first) != std::get<0>(fzzRes[i]) - 1 || static_cast(gudhiRes[i].second) != std::get<1>(fzzRes[i])) - return false; - } - - return true; -} - -void print(const std::vector >& res, unsigned int infValue){ - for (const auto& p : res) { - std::cout << p.first << " - "; - if (p.second == infValue) std::cout << "inf"; - else std::cout << p.second; - std::cout << std::endl; - } -} - -void print(const std::vector >& res, int infValue){ - for (const auto& e : res) { - std::cout << (std::get<0>(e) - 1) << " - "; - if (std::get<1>(e) == infValue) std::cout << "inf"; - else std::cout << std::get<1>(e); - std::cout << std::endl; - } -} - -void print_differences(const std::vector >& gudhiRes, - const std::vector >& dioRes, - unsigned int infValue) -{ - for (unsigned int i = 0; i < gudhiRes.size(); ++i){ - if (gudhiRes[i].first != dioRes[i].first || gudhiRes[i].second != dioRes[i].second){ - std::string dg = gudhiRes[i].second == infValue ? "inf" : std::to_string(gudhiRes[i].second); - std::string dd = dioRes[i].second == infValue ? "inf" : std::to_string(dioRes[i].second); - std::cout << "[" << i << "] " - << gudhiRes[i].first << " - " << dg - << " / " - << dioRes[i].first << " - " << dd - << "\n"; - } - } -} - -void print_differences(const std::vector >& gudhiRes, - const std::vector >& fzzRes, - int infValue) -{ - for (unsigned int i = 0; i < gudhiRes.size(); ++i){ - if (static_cast(gudhiRes[i].first) != std::get<0>(fzzRes[i]) || static_cast(gudhiRes[i].second) != std::get<1>(fzzRes[i])){ - std::string dg = static_cast(gudhiRes[i].second) == infValue ? "inf" : std::to_string(gudhiRes[i].second); - std::string dd = std::get<1>(fzzRes[i]) == infValue ? "inf" : std::to_string(std::get<1>(fzzRes[i])); - std::cout << "[" << i << "] " - << gudhiRes[i].first << " - " << dg - << " / " - << std::get<0>(fzzRes[i]) << " - " << dd - << "\n"; - } - } -} - - - -int main(int argc, char* const argv[]) { - if (argc < 2 || argc > 3) { - std::cout << "Wrong arguments.\n"; - return 0; - } - - // std::vector > simplices = get_simplices(); - // std::vector dirs = get_directions(); - std::vector > simplices; - std::vector dirs; - - unsigned int numberOfPoints = std::stoi(argv[1]); - int seed = -1; - - if (argc == 3) - seed = std::stoi(argv[2]); - - unsigned int numberOfSimplices = build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); - std::cout << "\n" << "numberOfSimplices: " << numberOfSimplices << "\n"; - - auto gudhiRes = compute_with_gudhi(simplices, dirs); - auto dioRes = compute_with_dionysus(simplices, dirs); - auto fzzRes = compute_with_fzz(simplices, dirs); - - std::cout << "Res sizes: " << gudhiRes.size() << ", " << dioRes.size() << ", " << fzzRes.size() << "\n"; - - bool firstRes = are_equal(gudhiRes, dioRes); - if (!firstRes){ - std::cout << "------------------------ Gudhi and Dionysus results are not equal!\n"; - // print(gudhiRes, numberOfSimplices); - // std::cout << "------------------------\n"; - // print(dioRes, numberOfSimplices); - print_differences(gudhiRes, dioRes, numberOfSimplices); - } else { - std::cout << "+++++++++++++++++++++++++ Gudhi and Dionysus results are equal.\n"; - } - - if (!are_equal(gudhiRes, fzzRes)){ - std::cout << "------------------------ Gudhi and FZZ results are not equal!\n"; - // if (firstRes) { - // print(gudhiRes, numberOfSimplices); - // std::cout << "------------------------\n"; - // } - // print(fzzRes, numberOfSimplices); - } else { - std::cout << "+++++++++++++++++++++++++ Gudhi and FZZ results are equal.\n"; - } - - return 0; -} diff --git a/src/Zigzag_persistence/example/example_rips_zigzag_filtration.cpp b/src/Zigzag_persistence/example/example_rips_zigzag_filtration.cpp deleted file mode 100644 index 88298890c7..0000000000 --- a/src/Zigzag_persistence/example/example_rips_zigzag_filtration.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. - * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. - * Author(s): Hannah Schreiber - * - * Copyright (C) 2023 Inria - * - * Modification(s): - * - YYYY/MM Author: Description of the modification - */ - -#include // atoi, getenv -#include // size_t -#include // printf -#include // strcmp -#include // read, write -#include -#include - -#include -#include -#include - -#include -#include // for pair -#include - -#include "rips-zigzag-dionysus.h" - -using ST = Gudhi::Simplex_tree; -using Gudhi::persistence_matrix::Zigzag_options; -using CT = Gudhi::persistence_matrix::Column_types; -using ZP = Gudhi::zigzag_persistence::Zigzag_persistence >; -// using coltype = Gudhi::zigzag_persistence::Zigzag_persistence_collist; -// using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; -using Vertex_handle = ST::Vertex_handle; -using Filtration_value = ST::Filtration_value; -using interval_filtration = ZP::filtration_value_interval; - -std::vector< std::pair > print_indices(ZP& zp, unsigned int numberOfSimplices){ - std::set essentials; - std::vector< std::pair > res; - - for (unsigned int i = 0; i < numberOfSimplices; ++i){ - essentials.insert(essentials.end(), i); - } - - for (auto& bar : zp.get_index_persistence_diagram()){ - res.emplace_back(bar.birth(), bar.death()); - essentials.erase(bar.birth()); - essentials.erase(bar.death()); - } - - for (unsigned int v : essentials){ - res.emplace_back(v, numberOfSimplices); - } - - return res; -} - -std::vector< std::pair > compute_with_gudhi( - const std::vector >& simplices, - const std::vector& dirs) -{ - ZP zp(simplices.size()); - - // std::cout << "====================== Gudhi =====================\n"; - - std::vector filValues(simplices.size(), 1.0); - - auto start = simplices.begin(); - auto filIt = filValues.begin(); - unsigned int i = 0; - - while (start != simplices.end()){ - unsigned int c = 1; - auto end = start + 1; - ++i; - while (end != simplices.end() && dirs[i - 1] == dirs[i]) { - ++end; - ++i; - ++c; - } - - if (dirs[i - 1]){ - zp.insert_simplices_contiguously( - start, end, filIt); - } else { - zp.remove_simplices_contiguously( - start, end, filIt); - } - - start = end; - filIt += c; - } - - // std::cout << "==================================================\n"; - - return print_indices(zp, i); -} - -int main(int argc, char* const argv[]) { - if (argc < 2 || argc > 3) { - std::cout << "Wrong arguments.\n"; - return 0; - } - - int perf_ctl_fd = open("/tmp/perf_ctl.fifo",O_WRONLY); - int perf_ctl_ack_fd = open("/tmp/perf_ctl_ack.fifo",O_RDONLY); - char ack[5]; - std::cout << "perf_ctl_fd: " << perf_ctl_fd << "\n"; - std::cout << "perf_ctl_ack_fd: " << perf_ctl_ack_fd << "\n"; - - unsigned int numberOfPoints = std::stoi(argv[1]); - int seed = -1; - if (argc == 3) - seed = std::stoi(argv[2]); - - std::vector > simplices; - std::vector dirs; - - unsigned int numberOfSimplices = build_rips_zigzag_filtration(simplices, dirs, numberOfPoints, seed); - std::cout << "Filtration size: " << simplices.size() << "\n"; - std::cout << "Number of simplices: " << numberOfSimplices << "\n"; - - // Start the performance counter and read the ack - if (perf_ctl_fd != -1){ - write(perf_ctl_fd, "enable\n", 8); - read(perf_ctl_ack_fd, ack, 5); - if(std::strcmp(ack, "ack\n") != 0){ - std::cout << "No acknowledgment\n"; - return 1; - } - } - - Gudhi::Clock time("Zigzag Rips"); - /* auto res = */compute_with_gudhi(simplices, dirs); - time.end(); - std::cout << time; - - // Stop the performance counter and read the ack - if (perf_ctl_fd != -1){ - write(perf_ctl_fd, "disable\n", 9); - read(perf_ctl_ack_fd, ack, 5); - if(std::strcmp(ack, "ack\n") != 0){ - std::cout << "No acknowledgment\n"; - return 1; - } - } - - // for (const auto& p : res) { - // std::cout << p.first << " - "; - // if (p.second == numberOfSimplices) std::cout << "inf"; - // else std::cout << p.second; - // std::cout << std::endl; - // } - - return 0; -} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/chain.h b/src/Zigzag_persistence/example/ext_zz/dionysus/chain.h deleted file mode 100644 index 00c983623a..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/chain.h +++ /dev/null @@ -1,153 +0,0 @@ -#ifndef DIONYSUS_CHAIN_H -#define DIONYSUS_CHAIN_H - -#include -#include -#include - -#include "fields/z2.h" - -namespace dionysus -{ - -template -struct FieldElement -{ - typedef typename Field::Element Element; - FieldElement(Element e_): - e(e_) {} - Element element() const { return e; } - void set_element(Element e_) { e = e_; } - Element e; -}; - -template<> -struct FieldElement -{ - typedef Z2Field::Element Element; - FieldElement(Element) {} - Element element() const { return Z2Field::id(); } - void set_element(Element) {} -}; - -template -struct ChainEntry: public FieldElement, public Extra... -{ - typedef Field_ Field; - typedef Index_ Index; - - typedef FieldElement Parent; - typedef typename Parent::Element Element; - - ChainEntry(): Parent(Element()), i(Index()) {} // need for serialization - - ChainEntry(ChainEntry&& other) = default; - ChainEntry(const ChainEntry& other) = default; - ChainEntry& operator=(ChainEntry&& other) = default; - - ChainEntry(Element e_, const Index& i_): - Parent(e_), i(i_) {} - - ChainEntry(Element e_, Index&& i_): - Parent(e_), i(std::move(i_)) {} - - const Index& index() const { return i; } - Index& index() { return i; } - - // debug - bool operator==(const ChainEntry& other) const { return i == other.i; } - - Index i; -}; - -template -struct Chain -{ - struct Visitor - { - template - void first(Iter it) const {} - - template - void second(Iter it) const {} - - template - void equal_keep(Iter it) const {} - - template - void equal_drop(Iter it) const {} - }; - - // x += a*y - template - static void addto(C1& x, typename Field::Element a, const C2& y, const Field& field, const Cmp& cmp, const Visitor_& = Visitor_()); -}; - -template -struct Chain> -{ - struct Visitor - { - template - void first(Iter it) const {} - - template - void second(Iter it) const {} - - template - void equal_keep(Iter it) const {} - - template - void equal_drop(Iter it) const {} - }; - - // x += a*y - template - static void addto(std::list& x, typename Field::Element a, const C2& y, - const Field& field, const Cmp& cmp, const Visitor_& visitor = Visitor_()); -}; - - -template -struct Chain> -{ - struct Visitor - { - template - void first(Iter it) const {} - - template - void second(Iter it) const {} - - template - void equal_keep(Iter it) const {} - - template - void equal_drop(Iter it) const {} - }; - - // x += a*y - template - static void addto(std::set& x, typename Field::Element a, const C2& y, - const Field& field, const Cmp& cmp, const Visitor_& = Visitor_()); - - template - static void addto(std::set& x, typename Field::Element a, T&& y, - const Field& field, const Cmp& cmp, const Visitor_& = Visitor_()); -}; - -} - -//namespace std -//{ -// template -// void swap(::dionysus::ChainEntry& x, ::dionysus::ChainEntry& y) -// { -// std::swap(x.e, y.e); -// std::swap(x.i, y.i); -// } -//} - -#include "chain.hpp" - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/chain.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/chain.hpp deleted file mode 100644 index 4da9f44615..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/chain.hpp +++ /dev/null @@ -1,188 +0,0 @@ -template -template -void -dionysus::Chain>:: -addto(std::list& x, typename Field::Element a, const C2& y, const Field& field, const Cmp& cmp, const Visitor_& visitor) -{ - typedef typename Field::Element Element; - - auto cur_x = std::begin(x), - end_x = std::end(x); - auto cur_y = std::begin(y), - end_y = std::end(y); - - while (cur_x != end_x && cur_y != end_y) - { - if (cmp(cur_x->index(), cur_y->index())) - { - visitor.first(cur_x++); - } else if (cmp(cur_y->index(), cur_x->index())) - { - // multiply and add - Element ay = field.mul(a, cur_y->element()); - auto nw_x = x.insert(cur_x, *cur_y); - nw_x->set_element(ay); - ++cur_y; - visitor.second(nw_x); - } else - { - Element ay = field.mul(a, cur_y->element()); - Element r = field.add(cur_x->element(), ay); - if (field.is_zero(r)) - { - visitor.equal_drop(cur_x); - x.erase(cur_x++); - } - else - { - cur_x->set_element(r); - visitor.equal_keep(cur_x); - ++cur_x; - } - ++cur_y; - } - } - - for (auto it = cur_y; it != end_y; ++it) - { - Element ay = field.mul(a, it->element()); - x.push_back(*it); - x.back().set_element(ay); - visitor.second(--x.end()); - } -} - -template -template -void -dionysus::Chain>:: -addto(std::set& x, typename Field::Element a, const C2& y, const Field& field, const Cmp&, const Visitor_& visitor) -{ - typedef typename Field::Element Element; - - auto cur_y = std::begin(y), - end_y = std::end(y); - - while (cur_y != end_y) - { - auto cur_x = x.find(*cur_y); - if (cur_x == x.end()) - { - auto nw = x.insert(*cur_y).first; - Element ay = field.mul(a, nw->element()); - const_cast(*nw).set_element(ay); - visitor.second(nw); - } else - { - Element ay = field.mul(a, cur_y->element()); - Element r = field.add(cur_x->element(), ay); - if (field.is_zero(r)) - { - visitor.equal_drop(cur_x); - x.erase(cur_x); - } - else - { - const_cast(*cur_x).set_element(r); - visitor.equal_keep(cur_x); - } - } - ++cur_y; - } -} - -template -template -void -dionysus::Chain>:: -addto(std::set& x, typename Field::Element a, T&& y, const Field& field, const Cmp&, const Visitor_& visitor) -{ - typedef typename Field::Element Element; - - auto cur_x = x.find(y); - if (cur_x == x.end()) - { - auto nw = x.insert(std::move(y)).first; - Element ay = field.mul(a, nw->element()); - const_cast(*nw).set_element(ay); - visitor.second(nw); - } else - { - Element ay = field.mul(a, y.element()); - Element r = field.add(cur_x->element(), ay); - if (field.is_zero(r)) - { - visitor.equal_drop(cur_x); - x.erase(cur_x); - } - else - { - const_cast(*cur_x).set_element(r); - visitor.equal_keep(cur_x); - } - } -} - -template -template -void -dionysus::Chain:: -addto(C1& x, typename Field::Element a, const C2& y, const Field& field, const Cmp& cmp, const Visitor_& visitor) -{ - typedef typename Field::Element Element; - - C1 res; - - auto cur_x = std::begin(x), - end_x = std::end(x); - auto cur_y = std::begin(y), - end_y = std::end(y); - - while (cur_x != end_x && cur_y != end_y) - { - if (cmp(*cur_x, *cur_y)) - { - res.emplace_back(std::move(*cur_x)); - visitor.first(--res.end()); - ++cur_x; - } else if (cmp(*cur_y, *cur_x)) - { - // multiply and add - Element ay = field.mul(a, cur_y->element()); - res.emplace_back(ay, cur_y->index()); - visitor.second(--res.end()); - ++cur_y; - } else - { - Element ay = field.mul(a, cur_y->element()); - Element r = field.add(cur_x->element(), ay); - if (field.is_zero(r)) - visitor.equal_drop(cur_x); - else - { - res.emplace_back(std::move(*cur_x)); - res.back().set_element(r); - visitor.equal_keep(--res.end()); - } - ++cur_x; - ++cur_y; - } - } - - while (cur_y != end_y) - { - Element ay = field.mul(a, cur_y->element()); - res.emplace_back(ay, cur_y->index()); - visitor.second(--res.end()); - ++cur_y; - } - - while (cur_x != end_x) - { - res.emplace_back(std::move(*cur_x)); - visitor.first(--res.end()); - ++cur_x; - } - - x.swap(res); -} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/clearing-reduction.h b/src/Zigzag_persistence/example/ext_zz/dionysus/clearing-reduction.h deleted file mode 100644 index 8651e9a69a..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/clearing-reduction.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef DIONYSUS_CLEARING_REDUCTION_H -#define DIONYSUS_CLEARING_REDUCTION_H - -namespace dionysus -{ - -// Mid-level interface -template -class ClearingReduction -{ - public: - using Persistence = Persistence_; - using Field = typename Persistence::Field; - using Index = typename Persistence::Index; - - public: - ClearingReduction(Persistence& persistence): - persistence_(persistence) {} - - template - void operator()(const Filtration& f, const Relative& relative, const ReportPair& report_pair, const Progress& progress); - - template - void operator()(const Filtration& f, const ReportPair& report_pair); - - template - void operator()(const Filtration& f) { return (*this)(f, &no_report_pair); } - - static void no_report_pair(int, Index, Index) {} - static void no_progress() {} - - const Persistence& - persistence() const { return persistence_; } - Persistence& persistence() { return persistence_; } - - private: - Persistence& persistence_; -}; - -} - -#include "clearing-reduction.hpp" - -#endif - diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/clearing-reduction.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/clearing-reduction.hpp deleted file mode 100644 index ceac11879d..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/clearing-reduction.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include - -#include -namespace ba = boost::adaptors; - -template -template -void -dionysus::ClearingReduction

:: -operator()(const Filtration& filtration, const ReportPair& report_pair) -{ - using Cell = typename Filtration::Cell; - (*this)(filtration, [](const Cell&) { return false; }, report_pair, &no_progress); -} - -template -template -void -dionysus::ClearingReduction

:: -operator()(const Filtration& filtration, const Relative& relative, const ReportPair& report_pair, const Progress& progress) -{ - persistence_.resize(filtration.size()); - - // sort indices by decreasing dimension - std::vector indices(filtration.size()); - std::iota(indices.begin(), indices.end(), 0); - std::stable_sort(indices.begin(), indices.end(), - [&filtration](size_t x, size_t y) - { return filtration[x].dimension() > filtration[y].dimension(); }); - - typedef typename Filtration::Cell Cell; - typedef ChainEntry CellChainEntry; - typedef ChainEntry ChainEntry; - - for(size_t i : indices) - { - progress(); - const auto& c = filtration[i]; - - if (relative(c)) - { - persistence_.set_skip(i); - continue; - } - - if (persistence_.pair(i) != persistence_.unpaired()) - continue; - - persistence_.set(i, c.boundary(persistence_.field()) | - ba::filtered([relative](const CellChainEntry& e) { return !relative(e.index()); }) | - ba::transformed([this,&filtration](const CellChainEntry& e) - { return ChainEntry(e.element(), filtration.index(e.index())); })); - - Index pair = persistence_.reduce(i); - if (pair != persistence_.unpaired()) - report_pair(c.dimension(), pair, i); - } -} - diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/cnpy.h b/src/Zigzag_persistence/example/ext_zz/dionysus/cnpy.h deleted file mode 100644 index b11013b9d7..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/cnpy.h +++ /dev/null @@ -1,241 +0,0 @@ -//Copyright (C) 2011 Carl Rogers -//Released under MIT License -//license available in LICENSE file, or at http://www.opensource.org/licenses/mit-license.php - -#ifndef LIBCNPY_H_ -#define LIBCNPY_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace cnpy { - - struct NpyArray { - char* data; - std::vector shape; - unsigned int word_size; - bool fortran_order; - void destruct() {delete[] data;} - }; - - struct npz_t : public std::map - { - void destruct() - { - npz_t::iterator it = this->begin(); - for(; it != this->end(); ++it) (*it).second.destruct(); - } - }; - - char BigEndianTest(); - char map_type(const std::type_info& t); - template std::vector create_npy_header(const T* data, const unsigned int* shape, const unsigned int ndims); - void parse_npy_header(FILE* fp,unsigned int& word_size, unsigned int*& shape, unsigned int& ndims, bool& fortran_order); - void parse_zip_footer(FILE* fp, unsigned short& nrecs, unsigned int& global_header_size, unsigned int& global_header_offset); - npz_t npz_load(std::string fname); - NpyArray npz_load(std::string fname, std::string varname); - NpyArray npy_load(std::string fname); - - template std::vector& operator+=(std::vector& lhs, const T rhs) { - //write in little endian - for(char byte = 0; byte < sizeof(T); byte++) { - char val = *((char*)&rhs+byte); - lhs.push_back(val); - } - return lhs; - } - - template<> std::vector& operator+=(std::vector& lhs, const std::string rhs); - template<> std::vector& operator+=(std::vector& lhs, const char* rhs); - - - template std::string tostring(T i, int pad = 0, char padval = ' ') { - std::stringstream s; - s << i; - return s.str(); - } - - template void npy_save(std::string fname, const T* data, const unsigned int* shape, const unsigned int ndims, std::string mode = "w") { - FILE* fp = NULL; - - if(mode == "a") fp = fopen(fname.c_str(),"r+b"); - - if(fp) { - //file exists. we need to append to it. read the header, modify the array size - unsigned int word_size, tmp_dims; - unsigned int* tmp_shape = 0; - bool fortran_order; - parse_npy_header(fp,word_size,tmp_shape,tmp_dims,fortran_order); - assert(!fortran_order); - - if(word_size != sizeof(T)) { - std::cout<<"libnpy error: "< header = create_npy_header(data,tmp_shape,ndims); - fwrite(&header[0],sizeof(char),header.size(),fp); - fseek(fp,0,SEEK_END); - - delete[] tmp_shape; - } - else { - fp = fopen(fname.c_str(),"wb"); - std::vector header = create_npy_header(data,shape,ndims); - fwrite(&header[0],sizeof(char),header.size(),fp); - } - - unsigned int nels = 1; - for(int i = 0;i < ndims;i++) nels *= shape[i]; - - fwrite(data,sizeof(T),nels,fp); - fclose(fp); - } - - template void npz_save(std::string zipname, std::string fname, const T* data, const unsigned int* shape, const unsigned int ndims, std::string mode = "w") - { - //first, append a .npy to the fname - fname += ".npy"; - - //now, on with the show - FILE* fp = NULL; - unsigned short nrecs = 0; - unsigned int global_header_offset = 0; - std::vector global_header; - - if(mode == "a") fp = fopen(zipname.c_str(),"r+b"); - - if(fp) { - //zip file exists. we need to add a new npy file to it. - //first read the footer. this gives us the offset and size of the global header - //then read and store the global header. - //below, we will write the the new data at the start of the global header then append the global header and footer below it - unsigned int global_header_size; - parse_zip_footer(fp,nrecs,global_header_size,global_header_offset); - fseek(fp,global_header_offset,SEEK_SET); - global_header.resize(global_header_size); - size_t res = fread(&global_header[0],sizeof(char),global_header_size,fp); - if(res != global_header_size){ - throw std::runtime_error("npz_save: header read error while adding to existing zip"); - } - fseek(fp,global_header_offset,SEEK_SET); - } - else { - fp = fopen(zipname.c_str(),"wb"); - } - - std::vector npy_header = create_npy_header(data,shape,ndims); - - unsigned long nels = 1; - for (int m=0; m local_header; - local_header += "PK"; //first part of sig - local_header += (unsigned short) 0x0403; //second part of sig - local_header += (unsigned short) 20; //min version to extract - local_header += (unsigned short) 0; //general purpose bit flag - local_header += (unsigned short) 0; //compression method - local_header += (unsigned short) 0; //file last mod time - local_header += (unsigned short) 0; //file last mod date - local_header += (unsigned int) crc; //crc - local_header += (unsigned int) nbytes; //compressed size - local_header += (unsigned int) nbytes; //uncompressed size - local_header += (unsigned short) fname.size(); //fname length - local_header += (unsigned short) 0; //extra field length - local_header += fname; - - //build global header - global_header += "PK"; //first part of sig - global_header += (unsigned short) 0x0201; //second part of sig - global_header += (unsigned short) 20; //version made by - global_header.insert(global_header.end(),local_header.begin()+4,local_header.begin()+30); - global_header += (unsigned short) 0; //file comment length - global_header += (unsigned short) 0; //disk number where file starts - global_header += (unsigned short) 0; //internal file attributes - global_header += (unsigned int) 0; //external file attributes - global_header += (unsigned int) global_header_offset; //relative offset of local file header, since it begins where the global header used to begin - global_header += fname; - - //build footer - std::vector footer; - footer += "PK"; //first part of sig - footer += (unsigned short) 0x0605; //second part of sig - footer += (unsigned short) 0; //number of this disk - footer += (unsigned short) 0; //disk where footer starts - footer += (unsigned short) (nrecs+1); //number of records on this disk - footer += (unsigned short) (nrecs+1); //total number of records - footer += (unsigned int) global_header.size(); //nbytes of global headers - footer += (unsigned int) (global_header_offset + nbytes + local_header.size()); //offset of start of global headers, since global header now starts after newly written array - footer += (unsigned short) 0; //zip file comment length - - //write everything - fwrite(&local_header[0],sizeof(char),local_header.size(),fp); - fwrite(&npy_header[0],sizeof(char),npy_header.size(),fp); - fwrite(data,sizeof(T),nels,fp); - fwrite(&global_header[0],sizeof(char),global_header.size(),fp); - fwrite(&footer[0],sizeof(char),footer.size(),fp); - fclose(fp); - } - - template std::vector create_npy_header(const T* data, const unsigned int* shape, const unsigned int ndims) { - - std::vector dict; - dict += "{'descr': '"; - dict += BigEndianTest(); - dict += map_type(typeid(T)); - dict += tostring(sizeof(T)); - dict += "', 'fortran_order': False, 'shape': ("; - dict += tostring(shape[0]); - for(int i = 1;i < ndims;i++) { - dict += ", "; - dict += tostring(shape[i]); - } - if(ndims == 1) dict += ","; - dict += "), }"; - //pad with spaces so that preamble+dict is modulo 16 bytes. preamble is 10 bytes. dict needs to end with \n - int remainder = 16 - (10 + dict.size()) % 16; - dict.insert(dict.end(),remainder,' '); - dict.back() = '\n'; - - std::vector header; - header += (char) 0x93; - header += "NUMPY"; - header += (char) 0x01; //major version of numpy format - header += (char) 0x00; //minor version of numpy format - header += (unsigned short) dict.size(); - header.insert(header.end(),dict.begin(),dict.end()); - - return header; - } - - -} - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/cohomology-persistence.h b/src/Zigzag_persistence/example/ext_zz/dionysus/cohomology-persistence.h deleted file mode 100644 index 8d2019e89d..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/cohomology-persistence.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef DIONYSUS_COHOMOLOGY_PERSISTENCE_H -#define DIONYSUS_COHOMOLOGY_PERSISTENCE_H - -#include -#include - -#include -namespace bi = boost::intrusive; - -#include "reduction.h" -#include "chain.h" - -namespace dionysus -{ - -template> -class CohomologyPersistence -{ - public: - typedef Field_ Field; - typedef Index_ Index; - typedef Comparison_ Comparison; - - typedef typename Field::Element FieldElement; - - typedef bi::list_base_hook> auto_unlink_hook; - struct Entry; - struct ColumnHead; - - typedef std::vector Column; - typedef bi::list> Row; - typedef std::list Columns; - typedef typename Columns::iterator ColumnsIterator; - typedef Column Chain; - - using IndexColumn = std::tuple; - - CohomologyPersistence(const Field& field, - const Comparison& cmp = Comparison()): - field_(field), cmp_(cmp) {} - - CohomologyPersistence(Field&& field, - const Comparison& cmp = Comparison()): - field_(std::move(field)), - cmp_(cmp) {} - - CohomologyPersistence(CohomologyPersistence&& other): - field_(std::move(other.field_)), - cmp_(std::move(other.cmp_)), - columns_(std::move(other.columns_)), - rows_(std::move(other.rows_)) {} - - template - Index add(const ChainRange& chain); - - template - IndexColumn add(const ChainRange& chain, bool keep_cocycle); - - // TODO: no skip support for now - bool skip(Index) const { return false; } - void add_skip() {} - void set_skip(Index, bool flag = true) {} - - const Field& field() const { return field_; } - const Columns& columns() const { return columns_; } - void reserve(size_t s) { rows_.reserve(s); } - - struct AddtoVisitor; - - static const Index unpaired() { return Reduction::unpaired; } - - private: - Field field_; - Comparison cmp_; - Columns columns_; - std::vector rows_; -}; - - -template -struct CohomologyPersistence::ColumnHead -{ - ColumnHead(Index i): index_(i) {} - - Index index() const { return index_; } - - Index index_; - Column chain; -}; - -template -struct CohomologyPersistence::Entry: - public ChainEntry -{ - typedef ChainEntry Parent; - - Entry(FieldElement e, const Index& i): // slightly dangerous - Parent(e,i) {} - - Entry(FieldElement e, const Index& i, ColumnsIterator it): - Parent(e,i), column(it) {} - - Entry(const Entry& other) = default; - Entry(Entry&& other) = default; - - void unlink() { auto_unlink_hook::unlink(); } - bool is_linked() const { return auto_unlink_hook::is_linked(); } - - ColumnsIterator column; // TODO: I really don't like this overhead -}; - -} - -#include "cohomology-persistence.hpp" - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/cohomology-persistence.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/cohomology-persistence.hpp deleted file mode 100644 index b2334f99e1..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/cohomology-persistence.hpp +++ /dev/null @@ -1,61 +0,0 @@ -template -template -typename dionysus::CohomologyPersistence::Index -dionysus::CohomologyPersistence:: -add(const ChainRange& chain) -{ - return std::get<0>(add(chain, false)); // return just the index -} - - -template -template -typename dionysus::CohomologyPersistence::IndexColumn -dionysus::CohomologyPersistence:: -add(const ChainRange& chain, bool keep_cocycle) -{ - auto entry_cmp = [this](const Entry& e1, const Entry& e2) { return this->cmp_(e1.index(), e2.index()); }; - std::set row_sum(entry_cmp); - for (auto it = std::begin(chain); it != std::end(chain); ++it) - for (auto& re : rows_[it->index()]) - dionysus::Chain::addto(row_sum, it->element(), Entry(re.element(), re.column->index(), re.column), field_, cmp_); - - if (row_sum.empty()) // Birth - { - columns_.emplace_back(rows_.size()); - auto before_end = columns_.end(); - --before_end; - columns_.back().chain.push_back(Entry(field_.id(), rows_.size(), before_end)); - rows_.emplace_back(); - rows_.back().push_back(columns_.back().chain.front()); - return std::make_tuple(unpaired(), Column()); - } else // Death - { - // Select front element in terms of comparison (rows are unsorted) - auto it = std::max_element(std::begin(row_sum), std::end(row_sum), entry_cmp); - - Entry first = std::move(*it); - row_sum.erase(it); - - for (auto& ce : row_sum) - { - FieldElement ay = field_.neg(field_.div(ce.element(), first.element())); - dionysus::Chain::addto(ce.column->chain, ay, first.column->chain, field_, - [this](const Entry& e1, const Entry& e2) - { return this->cmp_(e1.index(), e2.index()); }); - - for (auto& x : ce.column->chain) - { - x.column = ce.column; - rows_[x.index()].push_back(x); - } - } - Index pair = first.column->index(); - Column cocycle; - if (keep_cocycle) - cocycle = std::move(first.column->chain); - columns_.erase(first.column); - rows_.emplace_back(); // useless row; only present to make indices match - return std::make_tuple(pair, cocycle); - } -} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/common.h b/src/Zigzag_persistence/example/ext_zz/dionysus/common.h deleted file mode 100644 index e012b10539..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/common.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef DIONYSUS_EXAMPLES_COMMON_H -#define DIONYSUS_EXAMPLES_COMMON_H - -#include -#include - -template -void read_points(const std::string& infilename, PointContainer& points) -{ - typedef typename PointContainer::value_type Point; - - std::ifstream in(infilename.c_str()); - std::string line; - while(std::getline(in, line)) - { - if (line[0] == '#') continue; // comment line in the file - std::stringstream linestream(line); - double x; - points.push_back(Point()); - while (linestream >> x) - points.back().push_back(x); - } -} - -#endif // DIONYSUS_EXAMPLES_COMMON_H diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/diagram.h b/src/Zigzag_persistence/example/ext_zz/dionysus/diagram.h deleted file mode 100644 index 04eb29a927..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/diagram.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef DIONYSUS_DIAGRAM_H -#define DIONYSUS_DIAGRAM_H - -#include -#include -#include - -namespace dionysus -{ - -template -class Diagram -{ - public: - using Value = Value_; - using Data = Data_; - struct Point: public std::pair - { - using Parent = std::pair; - - Point(Value b, Value d, Data dd): - Parent(b,d), data(dd) {} - - Value birth() const { return Parent::first; } - Value death() const { return Parent::second; } - - // FIXME: temporary hack - Value operator[](size_t i) const { if (i == 0) return birth(); return death(); } - - Data data; - }; - - using Points = std::vector; - using iterator = typename Points::iterator; - using const_iterator = typename Points::const_iterator; - using value_type = Point; - - public: - const_iterator begin() const { return points.begin(); } - const_iterator end() const { return points.end(); } - iterator begin() { return points.begin(); } - iterator end() { return points.end(); } - - const Point& operator[](size_t i) const { return points[i]; } - - size_t size() const { return points.size(); } - void push_back(const Point& p) { points.push_back(p); } - template - void emplace_back(Args&&... args) { points.emplace_back(std::forward(args)...); } - - private: - std::vector points; -}; - -namespace detail -{ - template - struct Diagrams - { - using Value = decltype(std::declval()(std::declval())); - using Data = decltype(std::declval()(std::declval())); - using type = std::vector>; - }; -} - -template -typename detail::Diagrams::type -init_diagrams(const ReducedMatrix& m, const Filtration& f, const GetValue& get_value, const GetData& get_data) -{ - using Result = typename detail::Diagrams::type; - - Result diagrams; - for (typename ReducedMatrix::Index i = 0; i < m.size(); ++i) - { - if (m.skip(i)) - continue; - - auto s = f[i]; - auto d = s.dimension(); - - while (d + 1 > diagrams.size()) - diagrams.emplace_back(); - - auto pair = m.pair(i); - if (pair == m.unpaired()) - { - auto birth = get_value(s); - using Value = decltype(birth); - Value death = std::numeric_limits::infinity(); - diagrams[d].emplace_back(birth, death, get_data(i)); - } else if (pair > i) // positive - { - auto birth = get_value(s); - auto death = get_value(f[pair]); - - // hack to work with coboundaries - auto pd = f[pair].dimension(); - if (pd < d) - { - d = pd; - std::swap(birth, death); - } - - if (birth != death) // skip diagonal - diagrams[d].emplace_back(birth, death, get_data(i)); - } // else negative: do nothing - } - - return diagrams; -} - -} - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/distances.h b/src/Zigzag_persistence/example/ext_zz/dionysus/distances.h deleted file mode 100644 index 29cac601af..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/distances.h +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef DIONYSUS_DISTANCES_H -#define DIONYSUS_DISTANCES_H - -#include -#include - -namespace dionysus -{ - -/** - * Class: ExplicitDistances - * Stores the pairwise distances of Distances_ instance passed at construction. - * It's a protypical Distances template argument for the Rips complex. - */ -template -class ExplicitDistances -{ - public: - typedef Distances_ Distances; - typedef size_t IndexType; - typedef typename Distances::DistanceType DistanceType; - - ExplicitDistances(IndexType size): - size_(size), - distances_(size*(size + 1)/2 + size) {} - ExplicitDistances(const Distances& distances); - - DistanceType operator()(IndexType a, IndexType b) const; - DistanceType& operator()(IndexType a, IndexType b); - - size_t size() const { return size_; } - IndexType begin() const { return 0; } - IndexType end() const { return size(); } - - private: - std::vector distances_; - size_t size_; -}; - - -/** - * Class: PairwiseDistances - * Given a Container_ of points and a Distance_, it computes distances between elements - * in the container (given as instances of Index_ defaulted to unsigned) using the Distance_ functor. - * - * Container_ is assumed to be an std::vector. That simplifies a number of things. - */ -template -class PairwiseDistances -{ - public: - typedef Container_ Container; - typedef Distance_ Distance; - typedef Index_ IndexType; - typedef typename Distance::result_type DistanceType; - - - PairwiseDistances(const Container& container, - const Distance& distance = Distance()): - container_(container), distance_(distance) {} - - DistanceType operator()(IndexType a, IndexType b) const { return distance_(container_[a], container_[b]); } - - size_t size() const { return container_.size(); } - IndexType begin() const { return 0; } - IndexType end() const { return size(); } - - private: - const Container& container_; - Distance distance_; -}; - -template -struct L2Distance -{ - typedef Point_ Point; - typedef decltype(Point()[0] + 0) result_type; - - result_type operator()(const Point& p1, const Point& p2) const - { - result_type sum = 0; - for (size_t i = 0; i < p1.size(); ++i) - sum += (p1[i] - p2[i])*(p1[i] - p2[i]); - - return sqrt(sum); - } -}; - -} - -#include "distances.hpp" - -#endif // DIONYSUS_DISTANCES_H diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/distances.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/distances.hpp deleted file mode 100644 index 9b1f20aa2b..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/distances.hpp +++ /dev/null @@ -1,30 +0,0 @@ -template -dionysus::ExplicitDistances:: -ExplicitDistances(const Distances& distances): - size_(distances.size()), distances_((distances.size() * (distances.size() + 1))/2) -{ - IndexType i = 0; - for (typename Distances::IndexType a = distances.begin(); a != distances.end(); ++a) - for (typename Distances::IndexType b = a; b != distances.end(); ++b) - { - distances_[i++] = distances(a,b); - } -} - -template -typename dionysus::ExplicitDistances::DistanceType -dionysus::ExplicitDistances:: -operator()(IndexType a, IndexType b) const -{ - if (a > b) std::swap(a,b); - return distances_[a*size_ - ((a*(a-1))/2) + (b-a)]; -} - -template -typename dionysus::ExplicitDistances::DistanceType& -dionysus::ExplicitDistances:: -operator()(IndexType a, IndexType b) -{ - if (a > b) std::swap(a,b); - return distances_[a*size_ - ((a*(a-1))/2) + (b-a)]; -} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/dlog/progress.h b/src/Zigzag_persistence/example/ext_zz/dionysus/dlog/progress.h deleted file mode 100644 index 12bf86a4a2..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/dlog/progress.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef DLOG_PROGRESS_H -#define DLOG_PROGRESS_H - -#include -#include -#include -#include - -namespace dlog -{ - -struct progress -{ - progress(size_t total): - current_(0), total_(total) { show_progress(); } - - progress& operator++() { current_++; if (current_ * 100 / total_ > (current_ - 1) * 100 / total_) show_progress(); check_done(); return *this; } - progress& operator=(size_t cur) { current_ = cur; show_progress(); check_done(); return *this; } - progress& operator()(const std::string& s) { message_ = s; show_progress(); check_done(); return *this; } - template - progress& operator()(const T& x) { std::ostringstream oss; oss << x; return (*this)(oss.str()); } - - inline void show_progress() const; - void check_done() const { if (current_ >= total_) std::cout << "\n" << std::flush; } - - private: - size_t current_, total_; - std::string message_; -}; - -} - -void -dlog::progress:: -show_progress() const -{ - int barWidth = 70; - - std::cout << "["; - int pos = barWidth * current_ / total_; - for (int i = 0; i < barWidth; ++i) - { - if (i < pos) - std::cout << "="; - else if (i == pos) - std::cout << ">"; - else - std::cout << " "; - } - std::cout << "] " << std::setw(3) << current_ * 100 / total_ << "%"; - if (!message_.empty()) - std::cout << " (" << message_ << ")"; - std::cout << "\r"; - std::cout.flush(); -} - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/fields/q.h b/src/Zigzag_persistence/example/ext_zz/dionysus/fields/q.h deleted file mode 100644 index 8972ae2b5a..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/fields/q.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef DIONYSUS_Q_H -#define DIONYSUS_Q_H - -#include - -// TODO: eventually need to be able to adaptively switch to arbitrary precision arithmetic - -namespace dionysus -{ - -template -class Q -{ - public: - using BaseElement = Element_; - struct Element - { - BaseElement numerator, denominator; - - bool operator==(Element o) const { return numerator == o.numerator && denominator == o.denominator; } - bool operator!=(Element o) const { return !((*this) == o); } - - friend - std::ostream& operator<<(std::ostream& out, Element e) { out << e.numerator << '/' << e.denominator; return out; } - }; - - Element id() const { return { 1,1 }; } - Element zero() const { return { 0,1 }; } - Element init(BaseElement a) const { return { a,1 }; } - - Element neg(Element a) const { return { -a.numerator, a.denominator }; } - Element add(Element a, Element b) const { Element x { a.numerator*b.denominator + b.numerator*a.denominator, a.denominator*b.denominator }; normalize(x); return x; } - - Element inv(Element a) const { return { a.denominator, a.numerator }; } - Element mul(Element a, Element b) const { Element x { a.numerator*b.numerator, a.denominator*b.denominator }; normalize(x); return x; } - Element div(Element a, Element b) const { return mul(a, inv(b)); } - - bool is_zero(Element a) const { return a.numerator == 0; } - - BaseElement numerator(const Element& x) const { return x.numerator; } - BaseElement denominator(const Element& x) const { return x.denominator; } - - static void normalize(Element& x) - { - BaseElement q = gcd(abs(x.numerator), abs(x.denominator)); - x.numerator /= q; - x.denominator /= q; - if (x.denominator < 0) - { - x.numerator = -x.numerator; - x.denominator = -x.denominator; - } - } - - static BaseElement abs(BaseElement x) { if (x < 0) return -x; return x; } - static BaseElement gcd(BaseElement a, BaseElement b) { if (b < a) return gcd(b,a); while (a != 0) { b %= a; std::swap(a,b); } return b; } - - static bool is_prime(BaseElement x) { return false; } // Ok, since is_prime is only used as a shortcut -}; - -} - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/fields/z2.h b/src/Zigzag_persistence/example/ext_zz/dionysus/fields/z2.h deleted file mode 100644 index 6317ace6df..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/fields/z2.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef DIONYSUS_Z2_H -#define DIONYSUS_Z2_H - -namespace dionysus -{ - -class Z2Field -{ - public: - typedef short Element; - - Z2Field() {} - - static Element id() { return 1; } - static Element zero() { return 0; } - static Element init(int a) { return (a % 2 + 2) % 2; } - - Element neg(Element a) const { return 2 - a; } - Element add(Element a, Element b) const { return (a+b) % 2; } - - Element inv(Element a) const { return a; } - Element mul(Element a, Element b) const { return a*b; } - Element div(Element a, Element b) const { return a; } - - bool is_zero(Element a) const { return a == 0; } -}; - -} - -#endif - diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/fields/zp.h b/src/Zigzag_persistence/example/ext_zz/dionysus/fields/zp.h deleted file mode 100644 index c70c61cc87..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/fields/zp.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef DIONYSUS_ZP_H -#define DIONYSUS_ZP_H - -#include - -namespace dionysus -{ - -template -class ZpField -{ - public: - typedef Element_ Element; - - ZpField(Element p); - ZpField(const ZpField& other) = default; - ZpField(ZpField&& other) = default; - - Element id() const { return 1; } - Element zero() const { return 0; } - Element init(int a) const { return (a % p_ + p_) % p_; } - - Element neg(Element a) const { return p_ - a; } - Element add(Element a, Element b) const { return (a+b) % p_; } - - Element inv(Element a) const { while (a < 0) a += p_; return inverses_[a]; } - Element mul(Element a, Element b) const { return (a*b) % p_; } - Element div(Element a, Element b) const { return mul(a, inv(b)); } - - bool is_zero(Element a) const { return (a % p_) == 0; } - - Element prime() const { return p_; } - - private: - Element p_; - std::vector inverses_; -}; - -template -ZpField:: -ZpField(Element p): - p_(p), inverses_(p_) -{ - for (Element i = 1; i < p_; ++i) - for (Element j = 1; j < p_; ++j) - if (mul(i,j) == 1) - { - inverses_[i] = j; - break; - } -} - -} - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/filtration.h b/src/Zigzag_persistence/example/ext_zz/dionysus/filtration.h deleted file mode 100644 index caf871cdfb..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/filtration.h +++ /dev/null @@ -1,124 +0,0 @@ -#ifndef DIONYSUS_FILTRATION_H -#define DIONYSUS_FILTRATION_H - -#include -#include - -#include -#include -#include -#include - -namespace b = boost; -namespace bmi = boost::multi_index; - -namespace dionysus -{ - -// Filtration stores a filtered cell complex as boost::multi_index_container<...>. -// It allows for bidirectional translation between a cell and its index. -template>, - bool checked_index = false> -class Filtration -{ - public: - struct order {}; - - typedef Cell_ Cell; - typedef CellLookupIndex_ CellLookupIndex; - - typedef b::multi_index_container> - >> Container; - typedef typename Container::value_type value_type; - - typedef typename Container::template nth_index<0>::type Complex; - typedef typename Container::template nth_index<1>::type Order; - typedef typename Order::const_iterator OrderConstIterator; - typedef typename Order::iterator OrderIterator; - - - public: - Filtration() = default; - Filtration(Filtration&& other) = default; - Filtration& operator=(Filtration&& other) = default; - - Filtration(const std::initializer_list& cells): - Filtration(std::begin(cells), std::end(cells)) {} - - template - Filtration(Iterator bg, Iterator end): - cells_(bg, end) {} - - template - Filtration(const CellRange& cells): - Filtration(std::begin(cells), std::end(cells)) {} - - // Lookup - const Cell& operator[](size_t i) const { return cells_.template get()[i]; } - OrderConstIterator iterator(const Cell& s) const { return bmi::project(cells_, cells_.find(s)); } - size_t index(const Cell& s) const; - bool contains(const Cell& s) const { return cells_.find(s) != cells_.end(); } - - void push_back(const Cell& s) { cells_.template get().push_back(s); } - void push_back(Cell&& s) { cells_.template get().push_back(s); } - - void replace(size_t i, const Cell& s) { cells_.template get().replace(begin() + i, s); } - - // return index of the cell, adding it, if necessary - size_t add(const Cell& s) { size_t i = (iterator(s) - begin()); if (i == size()) emplace_back(s); return i; } - size_t add(Cell&& s) { size_t i = (iterator(s) - begin()); if (i == size()) emplace_back(std::move(s)); return i; } - - template - void emplace_back(Args&&... args) { cells_.template get().emplace_back(std::forward(args)...); } - - template> - void sort(const Cmp& cmp = Cmp()) { cells_.template get().sort(cmp); } - - void rearrange(const std::vector& indices); - - OrderConstIterator begin() const { return cells_.template get().begin(); } - OrderConstIterator end() const { return cells_.template get().end(); } - OrderIterator begin() { return cells_.template get().begin(); } - OrderIterator end() { return cells_.template get().end(); } - size_t size() const { return cells_.size(); } - void clear() { return Container().swap(cells_); } - - Cell& back() { return const_cast(cells_.template get().back()); } - const Cell& back() const { return cells_.template get().back(); } - - private: - Container cells_; -}; - -} - -template -size_t -dionysus::Filtration:: -index(const Cell& s) const -{ - auto it = iterator(s); - if (checked_index && it == end()) - { - std::ostringstream oss; - oss << "Trying to access non-existent cell: " << s; - throw std::runtime_error(oss.str()); - } - return it - begin(); -} - -template -void -dionysus::Filtration:: -rearrange(const std::vector& indices) -{ - std::vector> references; references.reserve(indices.size()); - for (size_t i : indices) - references.push_back(std::cref((*this)[i])); - cells_.template get().rearrange(references.begin()); -} - - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/format.h b/src/Zigzag_persistence/example/ext_zz/dionysus/format.h deleted file mode 100644 index 7f7ba83318..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/format.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef DIONYSUS_FORMAT_H -#define DIONYSUS_FORMAT_H - -#define FMT_HEADER_ONLY - -#include "format/format.h" - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/format/format.cc b/src/Zigzag_persistence/example/ext_zz/dionysus/format/format.cc deleted file mode 100644 index a01e272fd7..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/format/format.cc +++ /dev/null @@ -1,1156 +0,0 @@ -/* - Formatting library for C++ - - Copyright (c) 2012 - 2014, Victor Zverovich - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "format.h" - -#include - -#include -#include -#include -#include -#include - -#ifdef _WIN32 -# ifdef __MINGW32__ -# include -# endif -# include -#endif - -using fmt::internal::Arg; - -// Check if exceptions are disabled. -#if __GNUC__ && !__EXCEPTIONS -# define FMT_EXCEPTIONS 0 -#endif -#if _MSC_VER && !_HAS_EXCEPTIONS -# define FMT_EXCEPTIONS 0 -#endif -#ifndef FMT_EXCEPTIONS -# define FMT_EXCEPTIONS 1 -#endif - -#if FMT_EXCEPTIONS -# define FMT_TRY try -# define FMT_CATCH(x) catch (x) -#else -# define FMT_TRY if (true) -# define FMT_CATCH(x) if (false) -#endif - -#ifndef FMT_THROW -# if FMT_EXCEPTIONS -# define FMT_THROW(x) throw x -# define FMT_RETURN_AFTER_THROW(x) -# else -# define FMT_THROW(x) assert(false) -# define FMT_RETURN_AFTER_THROW(x) return x -# endif -#endif - -#ifdef FMT_HEADER_ONLY -# define FMT_FUNC inline -#else -# define FMT_FUNC -#endif - -#if _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4127) // conditional expression is constant -# pragma warning(disable: 4702) // unreachable code -#endif - -namespace { - -#ifndef _MSC_VER -# define FMT_SNPRINTF snprintf -#else // _MSC_VER -inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { - va_list args; - va_start(args, format); - int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); - va_end(args); - return result; -} -# define FMT_SNPRINTF fmt_snprintf -#endif // _MSC_VER - -// Checks if a value fits in int - used to avoid warnings about comparing -// signed and unsigned integers. -template -struct IntChecker { - template - static bool fits_in_int(T value) { - unsigned max = INT_MAX; - return value <= max; - } -}; - -template <> -struct IntChecker { - template - static bool fits_in_int(T value) { - return value >= INT_MIN && value <= INT_MAX; - } -}; - -const char RESET_COLOR[] = "\x1b[0m"; - -typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef); - -// Portable thread-safe version of strerror. -// Sets buffer to point to a string describing the error code. -// This can be either a pointer to a string stored in buffer, -// or a pointer to some static immutable string. -// Returns one of the following values: -// 0 - success -// ERANGE - buffer is not large enough to store the error message -// other - failure -// Buffer should be at least of size 1. -int safe_strerror( - int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { - assert(buffer != 0 && buffer_size != 0); - int result = 0; -#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || __ANDROID__ - // XSI-compliant version of strerror_r. - result = strerror_r(error_code, buffer, buffer_size); - if (result != 0) - result = errno; -#elif _GNU_SOURCE - // GNU-specific version of strerror_r. - char *message = strerror_r(error_code, buffer, buffer_size); - // If the buffer is full then the message is probably truncated. - if (message == buffer && strlen(buffer) == buffer_size - 1) - result = ERANGE; - buffer = message; -#elif __MINGW32__ - errno = 0; - (void)buffer_size; - buffer = strerror(error_code); - result = errno; -#elif _WIN32 - result = strerror_s(buffer, buffer_size, error_code); - // If the buffer is full then the message is probably truncated. - if (result == 0 && std::strlen(buffer) == buffer_size - 1) - result = ERANGE; -#else - result = strerror_r(error_code, buffer, buffer_size); - if (result == -1) - result = errno; // glibc versions before 2.13 return result in errno. -#endif - return result; -} - -void format_error_code(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT { - // Report error code making sure that the output fits into - // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential - // bad_alloc. - out.clear(); - static const char SEP[] = ": "; - static const char ERR[] = "error "; - fmt::internal::IntTraits::MainType ec_value = error_code; - // Subtract 2 to account for terminating null characters in SEP and ERR. - std::size_t error_code_size = - sizeof(SEP) + sizeof(ERR) + fmt::internal::count_digits(ec_value) - 2; - if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size) - out << message << SEP; - out << ERR << error_code; - assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE); -} - -void report_error(FormatFunc func, - int error_code, fmt::StringRef message) FMT_NOEXCEPT { - fmt::MemoryWriter full_message; - func(full_message, error_code, message); - // Use Writer::data instead of Writer::c_str to avoid potential memory - // allocation. - std::fwrite(full_message.data(), full_message.size(), 1, stderr); - std::fputc('\n', stderr); -} - -// IsZeroInt::visit(arg) returns true iff arg is a zero integer. -class IsZeroInt : public fmt::internal::ArgVisitor { - public: - template - bool visit_any_int(T value) { return value == 0; } -}; - -// Parses an unsigned integer advancing s to the end of the parsed input. -// This function assumes that the first character of s is a digit. -template -int parse_nonnegative_int(const Char *&s) { - assert('0' <= *s && *s <= '9'); - unsigned value = 0; - do { - unsigned new_value = value * 10 + (*s++ - '0'); - // Check if value wrapped around. - if (new_value < value) { - value = UINT_MAX; - break; - } - value = new_value; - } while ('0' <= *s && *s <= '9'); - if (value > INT_MAX) - FMT_THROW(fmt::FormatError("number is too big")); - return value; -} - -inline void require_numeric_argument(const Arg &arg, char spec) { - if (arg.type > Arg::LAST_NUMERIC_TYPE) { - std::string message = - fmt::format("format specifier '{}' requires numeric argument", spec); - FMT_THROW(fmt::FormatError(message)); - } -} - -template -void check_sign(const Char *&s, const Arg &arg) { - char sign = static_cast(*s); - require_numeric_argument(arg, sign); - if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { - FMT_THROW(fmt::FormatError(fmt::format( - "format specifier '{}' requires signed argument", sign))); - } - ++s; -} - -// Checks if an argument is a valid printf width specifier and sets -// left alignment if it is negative. -class WidthHandler : public fmt::internal::ArgVisitor { - private: - fmt::FormatSpec &spec_; - - FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); - - public: - explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {} - - unsigned visit_unhandled_arg() { - FMT_THROW(fmt::FormatError("width is not integer")); - FMT_RETURN_AFTER_THROW(0); - } - - template - unsigned visit_any_int(T value) { - typedef typename fmt::internal::IntTraits::MainType UnsignedType; - UnsignedType width = value; - if (fmt::internal::is_negative(value)) { - spec_.align_ = fmt::ALIGN_LEFT; - width = 0 - width; - } - if (width > INT_MAX) - FMT_THROW(fmt::FormatError("number is too big")); - return static_cast(width); - } -}; - -class PrecisionHandler : - public fmt::internal::ArgVisitor { - public: - unsigned visit_unhandled_arg() { - FMT_THROW(fmt::FormatError("precision is not integer")); - FMT_RETURN_AFTER_THROW(0); - } - - template - int visit_any_int(T value) { - if (!IntChecker::is_signed>::fits_in_int(value)) - FMT_THROW(fmt::FormatError("number is too big")); - return static_cast(value); - } -}; - -// Converts an integer argument to an integral type T for printf. -template -class ArgConverter : public fmt::internal::ArgVisitor, void> { - private: - fmt::internal::Arg &arg_; - wchar_t type_; - - FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); - - public: - ArgConverter(fmt::internal::Arg &arg, wchar_t type) - : arg_(arg), type_(type) {} - - template - void visit_any_int(U value) { - bool is_signed = type_ == 'd' || type_ == 'i'; - using fmt::internal::Arg; - if (sizeof(T) <= sizeof(int)) { - // Extra casts are used to silence warnings. - if (is_signed) { - arg_.type = Arg::INT; - arg_.int_value = static_cast(static_cast(value)); - } else { - arg_.type = Arg::UINT; - arg_.uint_value = static_cast( - static_cast::Type>(value)); - } - } else { - if (is_signed) { - arg_.type = Arg::LONG_LONG; - arg_.long_long_value = - static_cast::Type>(value); - } else { - arg_.type = Arg::ULONG_LONG; - arg_.ulong_long_value = - static_cast::Type>(value); - } - } - } -}; - -// Converts an integer argument to char for printf. -class CharConverter : public fmt::internal::ArgVisitor { - private: - fmt::internal::Arg &arg_; - - FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); - - public: - explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {} - - template - void visit_any_int(T value) { - arg_.type = Arg::CHAR; - arg_.int_value = static_cast(value); - } -}; - -// This function template is used to prevent compile errors when handling -// incompatible string arguments, e.g. handling a wide string in a narrow -// string formatter. -template -Arg::StringValue ignore_incompatible_str(Arg::StringValue); - -template <> -inline Arg::StringValue ignore_incompatible_str( - Arg::StringValue) { return Arg::StringValue(); } - -template <> -inline Arg::StringValue ignore_incompatible_str( - Arg::StringValue s) { return s; } -} // namespace - -FMT_FUNC void fmt::SystemError::init( - int err_code, StringRef format_str, ArgList args) { - error_code_ = err_code; - MemoryWriter w; - internal::format_system_error(w, err_code, format(format_str, args)); - std::runtime_error &base = *this; - base = std::runtime_error(w.str()); -} - -template -int fmt::internal::CharTraits::format_float( - char *buffer, std::size_t size, const char *format, - unsigned width, int precision, T value) { - if (width == 0) { - return precision < 0 ? - FMT_SNPRINTF(buffer, size, format, value) : - FMT_SNPRINTF(buffer, size, format, precision, value); - } - return precision < 0 ? - FMT_SNPRINTF(buffer, size, format, width, value) : - FMT_SNPRINTF(buffer, size, format, width, precision, value); -} - -template -int fmt::internal::CharTraits::format_float( - wchar_t *buffer, std::size_t size, const wchar_t *format, - unsigned width, int precision, T value) { - if (width == 0) { - return precision < 0 ? - swprintf(buffer, size, format, value) : - swprintf(buffer, size, format, precision, value); - } - return precision < 0 ? - swprintf(buffer, size, format, width, value) : - swprintf(buffer, size, format, width, precision, value); -} - -template -const char fmt::internal::BasicData::DIGITS[] = - "0001020304050607080910111213141516171819" - "2021222324252627282930313233343536373839" - "4041424344454647484950515253545556575859" - "6061626364656667686970717273747576777879" - "8081828384858687888990919293949596979899"; - -#define FMT_POWERS_OF_10(factor) \ - factor * 10, \ - factor * 100, \ - factor * 1000, \ - factor * 10000, \ - factor * 100000, \ - factor * 1000000, \ - factor * 10000000, \ - factor * 100000000, \ - factor * 1000000000 - -template -const uint32_t fmt::internal::BasicData::POWERS_OF_10_32[] = { - 0, FMT_POWERS_OF_10(1) -}; - -template -const uint64_t fmt::internal::BasicData::POWERS_OF_10_64[] = { - 0, - FMT_POWERS_OF_10(1), - FMT_POWERS_OF_10(fmt::ULongLong(1000000000)), - // Multiply several constants instead of using a single long long constant - // to avoid warnings about C++98 not supporting long long. - fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10 -}; - -FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) { - if (std::isprint(static_cast(code))) { - FMT_THROW(fmt::FormatError( - fmt::format("unknown format code '{}' for {}", code, type))); - } - FMT_THROW(fmt::FormatError( - fmt::format("unknown format code '\\x{:02x}' for {}", - static_cast(code), type))); -} - -#ifdef _WIN32 - -FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { - int length = MultiByteToWideChar( - CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0); - static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; - if (length == 0) - FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); - buffer_.resize(length); - length = MultiByteToWideChar( - CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length); - if (length == 0) - FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); -} - -FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { - if (int error_code = convert(s)) { - FMT_THROW(WindowsError(error_code, - "cannot convert string from UTF-16 to UTF-8")); - } -} - -FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) { - int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0); - if (length == 0) - return GetLastError(); - buffer_.resize(length); - length = WideCharToMultiByte( - CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0); - if (length == 0) - return GetLastError(); - return 0; -} - -FMT_FUNC void fmt::WindowsError::init( - int err_code, StringRef format_str, ArgList args) { - error_code_ = err_code; - MemoryWriter w; - internal::format_windows_error(w, err_code, format(format_str, args)); - std::runtime_error &base = *this; - base = std::runtime_error(w.str()); -} - -#endif - -FMT_FUNC void fmt::internal::format_system_error( - fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT { - FMT_TRY { - MemoryBuffer buffer; - buffer.resize(INLINE_BUFFER_SIZE); - for (;;) { - char *system_message = &buffer[0]; - int result = safe_strerror(error_code, system_message, buffer.size()); - if (result == 0) { - out << message << ": " << system_message; - return; - } - if (result != ERANGE) - break; // Can't get error message, report error code instead. - buffer.resize(buffer.size() * 2); - } - } FMT_CATCH(...) {} - format_error_code(out, error_code, message); -} - -#ifdef _WIN32 -FMT_FUNC void fmt::internal::format_windows_error( - fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT { - class String { - private: - LPWSTR str_; - - public: - String() : str_() {} - ~String() { LocalFree(str_); } - LPWSTR *ptr() { return &str_; } - LPCWSTR c_str() const { return str_; } - }; - FMT_TRY { - String system_message; - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, - error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - reinterpret_cast(system_message.ptr()), 0, 0)) { - UTF16ToUTF8 utf8_message; - if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) { - out << message << ": " << utf8_message; - return; - } - } - } FMT_CATCH(...) {} - format_error_code(out, error_code, message); -} -#endif - -// An argument formatter. -template -class fmt::internal::ArgFormatter : - public fmt::internal::ArgVisitor, void> { - private: - fmt::BasicFormatter &formatter_; - fmt::BasicWriter &writer_; - fmt::FormatSpec &spec_; - const Char *format_; - - FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatter); - - public: - ArgFormatter( - fmt::BasicFormatter &f,fmt::FormatSpec &s, const Char *fmt) - : formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {} - - template - void visit_any_int(T value) { writer_.write_int(value, spec_); } - - template - void visit_any_double(T value) { writer_.write_double(value, spec_); } - - void visit_char(int value) { - if (spec_.type_ && spec_.type_ != 'c') { - spec_.flags_ |= CHAR_FLAG; - writer_.write_int(value, spec_); - return; - } - if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) - FMT_THROW(FormatError("invalid format specifier for char")); - typedef typename fmt::BasicWriter::CharPtr CharPtr; - Char fill = static_cast(spec_.fill()); - if (spec_.precision_ == 0) { - std::fill_n(writer_.grow_buffer(spec_.width_), spec_.width_, fill); - return; - } - CharPtr out = CharPtr(); - if (spec_.width_ > 1) { - out = writer_.grow_buffer(spec_.width_); - if (spec_.align_ == fmt::ALIGN_RIGHT) { - std::fill_n(out, spec_.width_ - 1, fill); - out += spec_.width_ - 1; - } else if (spec_.align_ == fmt::ALIGN_CENTER) { - out = writer_.fill_padding(out, spec_.width_, 1, fill); - } else { - std::fill_n(out + 1, spec_.width_ - 1, fill); - } - } else { - out = writer_.grow_buffer(1); - } - *out = static_cast(value); - } - - void visit_string(Arg::StringValue value) { - writer_.write_str(value, spec_); - } - void visit_wstring(Arg::StringValue value) { - writer_.write_str(ignore_incompatible_str(value), spec_); - } - - void visit_pointer(const void *value) { - if (spec_.type_ && spec_.type_ != 'p') - fmt::internal::report_unknown_type(spec_.type_, "pointer"); - spec_.flags_ = fmt::HASH_FLAG; - spec_.type_ = 'x'; - writer_.write_int(reinterpret_cast(value), spec_); - } - - void visit_custom(Arg::CustomValue c) { - c.format(&formatter_, c.value, &format_); - } -}; - -template -template -void fmt::BasicWriter::write_str( - const Arg::StringValue &s, const FormatSpec &spec) { - // Check if StrChar is convertible to Char. - internal::CharTraits::convert(StrChar()); - if (spec.type_ && spec.type_ != 's') - internal::report_unknown_type(spec.type_, "string"); - const StrChar *str_value = s.value; - std::size_t str_size = s.size; - if (str_size == 0) { - if (!str_value) - FMT_THROW(FormatError("string pointer is null")); - if (*str_value) - str_size = std::char_traits::length(str_value); - } - std::size_t precision = spec.precision_; - if (spec.precision_ >= 0 && precision < str_size) - str_size = spec.precision_; - write_str(str_value, str_size, spec); -} - -template -inline Arg fmt::BasicFormatter::parse_arg_index(const Char *&s) { - const char *error = 0; - Arg arg = *s < '0' || *s > '9' ? - next_arg(error) : get_arg(parse_nonnegative_int(s), error); - if (error) { - FMT_THROW(FormatError( - *s != '}' && *s != ':' ? "invalid format string" : error)); - } - return arg; -} - -FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( - unsigned arg_index, const char *&error) { - Arg arg = args_[arg_index]; - if (arg.type == Arg::NONE) - error = "argument index out of range"; - return arg; -} - -inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) { - if (next_arg_index_ >= 0) - return do_get_arg(next_arg_index_++, error); - error = "cannot switch from manual to automatic argument indexing"; - return Arg(); -} - -inline Arg fmt::internal::FormatterBase::get_arg( - unsigned arg_index, const char *&error) { - if (next_arg_index_ <= 0) { - next_arg_index_ = -1; - return do_get_arg(arg_index, error); - } - error = "cannot switch from automatic to manual argument indexing"; - return Arg(); -} - -template -void fmt::internal::PrintfFormatter::parse_flags( - FormatSpec &spec, const Char *&s) { - for (;;) { - switch (*s++) { - case '-': - spec.align_ = ALIGN_LEFT; - break; - case '+': - spec.flags_ |= SIGN_FLAG | PLUS_FLAG; - break; - case '0': - spec.fill_ = '0'; - break; - case ' ': - spec.flags_ |= SIGN_FLAG; - break; - case '#': - spec.flags_ |= HASH_FLAG; - break; - default: - --s; - return; - } - } -} - -template -Arg fmt::internal::PrintfFormatter::get_arg( - const Char *s, unsigned arg_index) { - const char *error = 0; - Arg arg = arg_index == UINT_MAX ? - next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); - if (error) - FMT_THROW(FormatError(!*s ? "invalid format string" : error)); - return arg; -} - -template -unsigned fmt::internal::PrintfFormatter::parse_header( - const Char *&s, FormatSpec &spec) { - unsigned arg_index = UINT_MAX; - Char c = *s; - if (c >= '0' && c <= '9') { - // Parse an argument index (if followed by '$') or a width possibly - // preceded with '0' flag(s). - unsigned value = parse_nonnegative_int(s); - if (*s == '$') { // value is an argument index - ++s; - arg_index = value; - } else { - if (c == '0') - spec.fill_ = '0'; - if (value != 0) { - // Nonzero value means that we parsed width and don't need to - // parse it or flags again, so return now. - spec.width_ = value; - return arg_index; - } - } - } - parse_flags(spec, s); - // Parse width. - if (*s >= '0' && *s <= '9') { - spec.width_ = parse_nonnegative_int(s); - } else if (*s == '*') { - ++s; - spec.width_ = WidthHandler(spec).visit(get_arg(s)); - } - return arg_index; -} - -template -void fmt::internal::PrintfFormatter::format( - BasicWriter &writer, BasicStringRef format_str, - const ArgList &args) { - const Char *start = format_str.c_str(); - set_args(args); - const Char *s = start; - while (*s) { - Char c = *s++; - if (c != '%') continue; - if (*s == c) { - write(writer, start, s); - start = ++s; - continue; - } - write(writer, start, s - 1); - - FormatSpec spec; - spec.align_ = ALIGN_RIGHT; - - // Parse argument index, flags and width. - unsigned arg_index = parse_header(s, spec); - - // Parse precision. - if (*s == '.') { - ++s; - if ('0' <= *s && *s <= '9') { - spec.precision_ = parse_nonnegative_int(s); - } else if (*s == '*') { - ++s; - spec.precision_ = PrecisionHandler().visit(get_arg(s)); - } - } - - Arg arg = get_arg(s, arg_index); - if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg)) - spec.flags_ &= ~HASH_FLAG; - if (spec.fill_ == '0') { - if (arg.type <= Arg::LAST_NUMERIC_TYPE) - spec.align_ = ALIGN_NUMERIC; - else - spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. - } - - // Parse length and convert the argument to the required type. - switch (*s++) { - case 'h': - if (*s == 'h') - ArgConverter(arg, *++s).visit(arg); - else - ArgConverter(arg, *s).visit(arg); - break; - case 'l': - if (*s == 'l') - ArgConverter(arg, *++s).visit(arg); - else - ArgConverter(arg, *s).visit(arg); - break; - case 'j': - ArgConverter(arg, *s).visit(arg); - break; - case 'z': - ArgConverter(arg, *s).visit(arg); - break; - case 't': - ArgConverter(arg, *s).visit(arg); - break; - case 'L': - // printf produces garbage when 'L' is omitted for long double, no - // need to do the same. - break; - default: - --s; - ArgConverter(arg, *s).visit(arg); - } - - // Parse type. - if (!*s) - FMT_THROW(FormatError("invalid format string")); - spec.type_ = static_cast(*s++); - if (arg.type <= Arg::LAST_INTEGER_TYPE) { - // Normalize type. - switch (spec.type_) { - case 'i': case 'u': - spec.type_ = 'd'; - break; - case 'c': - // TODO: handle wchar_t - CharConverter(arg).visit(arg); - break; - } - } - - start = s; - - // Format argument. - switch (arg.type) { - case Arg::INT: - writer.write_int(arg.int_value, spec); - break; - case Arg::UINT: - writer.write_int(arg.uint_value, spec); - break; - case Arg::LONG_LONG: - writer.write_int(arg.long_long_value, spec); - break; - case Arg::ULONG_LONG: - writer.write_int(arg.ulong_long_value, spec); - break; - case Arg::CHAR: { - if (spec.type_ && spec.type_ != 'c') - writer.write_int(arg.int_value, spec); - typedef typename BasicWriter::CharPtr CharPtr; - CharPtr out = CharPtr(); - if (spec.width_ > 1) { - Char fill = ' '; - out = writer.grow_buffer(spec.width_); - if (spec.align_ != ALIGN_LEFT) { - std::fill_n(out, spec.width_ - 1, fill); - out += spec.width_ - 1; - } else { - std::fill_n(out + 1, spec.width_ - 1, fill); - } - } else { - out = writer.grow_buffer(1); - } - *out = static_cast(arg.int_value); - break; - } - case Arg::DOUBLE: - writer.write_double(arg.double_value, spec); - break; - case Arg::LONG_DOUBLE: - writer.write_double(arg.long_double_value, spec); - break; - case Arg::CSTRING: - arg.string.size = 0; - writer.write_str(arg.string, spec); - break; - case Arg::STRING: - writer.write_str(arg.string, spec); - break; - case Arg::WSTRING: - writer.write_str(ignore_incompatible_str(arg.wstring), spec); - break; - case Arg::POINTER: - if (spec.type_ && spec.type_ != 'p') - internal::report_unknown_type(spec.type_, "pointer"); - spec.flags_= HASH_FLAG; - spec.type_ = 'x'; - writer.write_int(reinterpret_cast(arg.pointer), spec); - break; - case Arg::CUSTOM: { - if (spec.type_) - internal::report_unknown_type(spec.type_, "object"); - const void *str_format = "s"; - arg.custom.format(&writer, arg.custom.value, &str_format); - break; - } - default: - assert(false); - break; - } - } - write(writer, start, s); -} - -template -const Char *fmt::BasicFormatter::format( - const Char *&format_str, const Arg &arg) { - const Char *s = format_str; - FormatSpec spec; - if (*s == ':') { - if (arg.type == Arg::CUSTOM) { - arg.custom.format(this, arg.custom.value, &s); - return s; - } - ++s; - // Parse fill and alignment. - if (Char c = *s) { - const Char *p = s + 1; - spec.align_ = ALIGN_DEFAULT; - do { - switch (*p) { - case '<': - spec.align_ = ALIGN_LEFT; - break; - case '>': - spec.align_ = ALIGN_RIGHT; - break; - case '=': - spec.align_ = ALIGN_NUMERIC; - break; - case '^': - spec.align_ = ALIGN_CENTER; - break; - } - if (spec.align_ != ALIGN_DEFAULT) { - if (p != s) { - if (c == '}') break; - if (c == '{') - FMT_THROW(FormatError("invalid fill character '{'")); - s += 2; - spec.fill_ = c; - } else ++s; - if (spec.align_ == ALIGN_NUMERIC) - require_numeric_argument(arg, '='); - break; - } - } while (--p >= s); - } - - // Parse sign. - switch (*s) { - case '+': - check_sign(s, arg); - spec.flags_ |= SIGN_FLAG | PLUS_FLAG; - break; - case '-': - check_sign(s, arg); - spec.flags_ |= MINUS_FLAG; - break; - case ' ': - check_sign(s, arg); - spec.flags_ |= SIGN_FLAG; - break; - } - - if (*s == '#') { - require_numeric_argument(arg, '#'); - spec.flags_ |= HASH_FLAG; - ++s; - } - - // Parse width and zero flag. - if ('0' <= *s && *s <= '9') { - if (*s == '0') { - require_numeric_argument(arg, '0'); - spec.align_ = ALIGN_NUMERIC; - spec.fill_ = '0'; - } - // Zero may be parsed again as a part of the width, but it is simpler - // and more efficient than checking if the next char is a digit. - spec.width_ = parse_nonnegative_int(s); - } - - // Parse precision. - if (*s == '.') { - ++s; - spec.precision_ = 0; - if ('0' <= *s && *s <= '9') { - spec.precision_ = parse_nonnegative_int(s); - } else if (*s == '{') { - ++s; - const Arg &precision_arg = parse_arg_index(s); - if (*s++ != '}') - FMT_THROW(FormatError("invalid format string")); - ULongLong value = 0; - switch (precision_arg.type) { - case Arg::INT: - if (precision_arg.int_value < 0) - FMT_THROW(FormatError("negative precision")); - value = precision_arg.int_value; - break; - case Arg::UINT: - value = precision_arg.uint_value; - break; - case Arg::LONG_LONG: - if (precision_arg.long_long_value < 0) - FMT_THROW(FormatError("negative precision")); - value = precision_arg.long_long_value; - break; - case Arg::ULONG_LONG: - value = precision_arg.ulong_long_value; - break; - default: - FMT_THROW(FormatError("precision is not integer")); - } - if (value > INT_MAX) - FMT_THROW(FormatError("number is too big")); - spec.precision_ = static_cast(value); - } else { - FMT_THROW(FormatError("missing precision specifier")); - } - if (arg.type < Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) { - FMT_THROW(FormatError( - fmt::format("precision not allowed in {} format specifier", - arg.type == Arg::POINTER ? "pointer" : "integer"))); - } - } - - // Parse type. - if (*s != '}' && *s) - spec.type_ = static_cast(*s++); - } - - if (*s++ != '}') - FMT_THROW(FormatError("missing '}' in format string")); - start_ = s; - - // Format argument. - internal::ArgFormatter(*this, spec, s - 1).visit(arg); - return s; -} - -template -void fmt::BasicFormatter::format( - BasicStringRef format_str, const ArgList &args) { - const Char *s = start_ = format_str.c_str(); - set_args(args); - while (*s) { - Char c = *s++; - if (c != '{' && c != '}') continue; - if (*s == c) { - write(writer_, start_, s); - start_ = ++s; - continue; - } - if (c == '}') - FMT_THROW(FormatError("unmatched '}' in format string")); - write(writer_, start_, s - 1); - Arg arg = parse_arg_index(s); - s = format(s, arg); - } - write(writer_, start_, s); -} - -FMT_FUNC void fmt::report_system_error( - int error_code, fmt::StringRef message) FMT_NOEXCEPT { - report_error(internal::format_system_error, error_code, message); -} - -#ifdef _WIN32 -FMT_FUNC void fmt::report_windows_error( - int error_code, fmt::StringRef message) FMT_NOEXCEPT { - report_error(internal::format_windows_error, error_code, message); -} -#endif - -FMT_FUNC void fmt::print(std::FILE *f, StringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - std::fwrite(w.data(), 1, w.size(), f); -} - -FMT_FUNC void fmt::print(StringRef format_str, ArgList args) { - print(stdout, format_str, args); -} - -FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - os.write(w.data(), w.size()); -} - -FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) { - char escape[] = "\x1b[30m"; - escape[3] = '0' + static_cast(c); - std::fputs(escape, stdout); - print(format, args); - std::fputs(RESET_COLOR, stdout); -} - -FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) { - MemoryWriter w; - printf(w, format, args); - std::size_t size = w.size(); - return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast(size); -} - -// Explicit instantiations for char. - -template const char *fmt::BasicFormatter::format( - const char *&format_str, const fmt::internal::Arg &arg); - -template void fmt::BasicFormatter::format( - BasicStringRef format, const ArgList &args); - -template void fmt::internal::PrintfFormatter::format( - BasicWriter &writer, BasicStringRef format, const ArgList &args); - -template int fmt::internal::CharTraits::format_float( - char *buffer, std::size_t size, const char *format, - unsigned width, int precision, double value); - -template int fmt::internal::CharTraits::format_float( - char *buffer, std::size_t size, const char *format, - unsigned width, int precision, long double value); - -// Explicit instantiations for wchar_t. - -template const wchar_t *fmt::BasicFormatter::format( - const wchar_t *&format_str, const fmt::internal::Arg &arg); - -template void fmt::BasicFormatter::format( - BasicStringRef format, const ArgList &args); - -template void fmt::internal::PrintfFormatter::format( - BasicWriter &writer, BasicStringRef format, - const ArgList &args); - -template int fmt::internal::CharTraits::format_float( - wchar_t *buffer, std::size_t size, const wchar_t *format, - unsigned width, int precision, double value); - -template int fmt::internal::CharTraits::format_float( - wchar_t *buffer, std::size_t size, const wchar_t *format, - unsigned width, int precision, long double value); - -#if _MSC_VER -# pragma warning(pop) -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/format/format.h b/src/Zigzag_persistence/example/ext_zz/dionysus/format/format.h deleted file mode 100644 index 03ed685383..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/format/format.h +++ /dev/null @@ -1,2546 +0,0 @@ -/* - Formatting library for C++ - - Copyright (c) 2012 - 2014, Victor Zverovich - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FMT_FORMAT_H_ -#define FMT_FORMAT_H_ - -#include - -#include -#include -#include // for std::ptrdiff_t -#include -#include -#include -#include -#include -#include - -#if _SECURE_SCL -# include -#endif - -#ifdef _MSC_VER -# include // _BitScanReverse, _BitScanReverse64 - -namespace fmt { -namespace internal { -# pragma intrinsic(_BitScanReverse) -inline uint32_t clz(uint32_t x) { - unsigned long r = 0; - _BitScanReverse(&r, x); - return 31 - r; -} -# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) -inline uint32_t clzll(uint64_t x) { - unsigned long r = 0; -# ifdef _WIN64 -# pragma intrinsic(_BitScanReverse64) - _BitScanReverse64(&r, x); -# else - // Scan the high 32 bits. - if (_BitScanReverse(&r, static_cast(x >> 32))) - return 63 - (r + 32); - - // Scan the low 32 bits. - _BitScanReverse(&r, static_cast(x)); -# endif - return 63 - r; -} -# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) -} -} -#endif - -#ifdef __GNUC__ -# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# define FMT_GCC_EXTENSION __extension__ -# if FMT_GCC_VERSION >= 406 -# pragma GCC diagnostic push -// Disable the warning about "long long" which is sometimes reported even -// when using __extension__. -# pragma GCC diagnostic ignored "-Wlong-long" -// Disable the warning about declaration shadowing because it affects too -// many valid cases. -# pragma GCC diagnostic ignored "-Wshadow" -# endif -# if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__ -# define FMT_HAS_GXX_CXX11 1 -# endif -#else -# define FMT_GCC_EXTENSION -#endif - -#ifdef __clang__ -# pragma clang diagnostic ignored "-Wdocumentation-unknown-command" -#endif - -#ifdef __GNUC_LIBSTD__ -# define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__) -#endif - -#ifdef __has_feature -# define FMT_HAS_FEATURE(x) __has_feature(x) -#else -# define FMT_HAS_FEATURE(x) 0 -#endif - -#ifdef __has_builtin -# define FMT_HAS_BUILTIN(x) __has_builtin(x) -#else -# define FMT_HAS_BUILTIN(x) 0 -#endif - -#ifdef __has_cpp_attribute -# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) -#else -# define FMT_HAS_CPP_ATTRIBUTE(x) 0 -#endif - -#ifndef FMT_USE_VARIADIC_TEMPLATES -// Variadic templates are available in GCC since version 4.4 -// (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++ -// since version 2013. -# define FMT_USE_VARIADIC_TEMPLATES \ - (FMT_HAS_FEATURE(cxx_variadic_templates) || \ - (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800) -#endif - -#ifndef FMT_USE_RVALUE_REFERENCES -// Don't use rvalue references when compiling with clang and an old libstdc++ -// as the latter doesn't provide std::move. -# if defined(FMT_GNUC_LIBSTD_VERSION) && FMT_GNUC_LIBSTD_VERSION <= 402 -# define FMT_USE_RVALUE_REFERENCES 0 -# else -# define FMT_USE_RVALUE_REFERENCES \ - (FMT_HAS_FEATURE(cxx_rvalue_references) || \ - (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600) -# endif -#endif - -#if FMT_USE_RVALUE_REFERENCES -# include // for std::move -#endif - -// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature). -#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) -# define FMT_NOEXCEPT noexcept -#else -# define FMT_NOEXCEPT throw() -#endif - -// A macro to disallow the copy constructor and operator= functions -// This should be used in the private: declarations for a class -#if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \ - (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800 -# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&) = delete; \ - TypeName& operator=(const TypeName&) = delete -#else -# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - TypeName& operator=(const TypeName&) -#endif - -namespace fmt { - -// Fix the warning about long long on older versions of GCC -// that don't support the diagnostic pragma. -FMT_GCC_EXTENSION typedef long long LongLong; -FMT_GCC_EXTENSION typedef unsigned long long ULongLong; - -#if FMT_USE_RVALUE_REFERENCES -using std::move; -#endif - -template -class BasicWriter; - -typedef BasicWriter Writer; -typedef BasicWriter WWriter; - -template -class BasicFormatter; - -template -void format(BasicFormatter &f, const Char *&format_str, const T &value); - -/** - \rst - A string reference. It can be constructed from a C string or - ``std::string``. - - You can use one of the following typedefs for common character types: - - +------------+-------------------------+ - | Type | Definition | - +============+=========================+ - | StringRef | BasicStringRef | - +------------+-------------------------+ - | WStringRef | BasicStringRef | - +------------+-------------------------+ - - This class is most useful as a parameter type to allow passing - different types of strings to a function, for example:: - - template - std::string format(StringRef format_str, const Args & ... args); - - format("{}", 42); - format(std::string("{}"), 42); - \endrst - */ -template -class BasicStringRef { - private: - const Char *data_; - std::size_t size_; - - public: - /** - Constructs a string reference object from a C string and a size. - */ - BasicStringRef(const Char *s, std::size_t size) : data_(s), size_(size) {} - - /** - Constructs a string reference object from a C string computing - the size with ``std::char_traits::length``. - */ - BasicStringRef(const Char *s) - : data_(s), size_(std::char_traits::length(s)) {} - - /** - Constructs a string reference from an `std::string` object. - */ - BasicStringRef(const std::basic_string &s) - : data_(s.c_str()), size_(s.size()) {} - - /** - Converts a string reference to an `std::string` object. - */ - operator std::basic_string() const { - return std::basic_string(data_, size()); - } - - /** - Returns the pointer to a C string. - */ - const Char *c_str() const { return data_; } - - /** - Returns the string size. - */ - std::size_t size() const { return size_; } - - friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { - return lhs.data_ == rhs.data_; - } - friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) { - return lhs.data_ != rhs.data_; - } -}; - -typedef BasicStringRef StringRef; -typedef BasicStringRef WStringRef; - -/** - A formatting error such as invalid format string. -*/ -class FormatError : public std::runtime_error { -public: - explicit FormatError(StringRef message) - : std::runtime_error(message.c_str()) {} -}; - -namespace internal { - -// The number of characters to store in the MemoryBuffer object itself -// to avoid dynamic memory allocation. -enum { INLINE_BUFFER_SIZE = 500 }; - -#if _SECURE_SCL -// Use checked iterator to avoid warnings on MSVC. -template -inline stdext::checked_array_iterator make_ptr(T *ptr, std::size_t size) { - return stdext::checked_array_iterator(ptr, size); -} -#else -template -inline T *make_ptr(T *ptr, std::size_t) { return ptr; } -#endif - -// A buffer for POD types. It supports a subset of std::vector's operations. -template -class Buffer { - private: - FMT_DISALLOW_COPY_AND_ASSIGN(Buffer); - - protected: - T *ptr_; - std::size_t size_; - std::size_t capacity_; - - Buffer(T *ptr = 0, std::size_t capacity = 0) - : ptr_(ptr), size_(0), capacity_(capacity) {} - - virtual void grow(std::size_t size) = 0; - - public: - virtual ~Buffer() {} - - // Returns the size of this buffer. - std::size_t size() const { return size_; } - - // Returns the capacity of this buffer. - std::size_t capacity() const { return capacity_; } - - // Resizes the buffer. If T is a POD type new elements are not initialized. - void resize(std::size_t new_size) { - if (new_size > capacity_) - grow(new_size); - size_ = new_size; - } - - // Reserves space to store at least capacity elements. - void reserve(std::size_t capacity) { - if (capacity > capacity_) - grow(capacity); - } - - void clear() FMT_NOEXCEPT { size_ = 0; } - - void push_back(const T &value) { - if (size_ == capacity_) - grow(size_ + 1); - ptr_[size_++] = value; - } - - // Appends data to the end of the buffer. - void append(const T *begin, const T *end); - - T &operator[](std::size_t index) { return ptr_[index]; } - const T &operator[](std::size_t index) const { return ptr_[index]; } -}; - -template -void Buffer::append(const T *begin, const T *end) { - std::ptrdiff_t num_elements = end - begin; - if (size_ + num_elements > capacity_) - grow(size_ + num_elements); - std::copy(begin, end, make_ptr(ptr_, capacity_) + size_); - size_ += num_elements; -} - -// A memory buffer for POD types with the first SIZE elements stored in -// the object itself. -template > -class MemoryBuffer : private Allocator, public Buffer { - private: - T data_[SIZE]; - - // Free memory allocated by the buffer. - void free() { - if (this->ptr_ != data_) this->deallocate(this->ptr_, this->capacity_); - } - - protected: - void grow(std::size_t size); - - public: - explicit MemoryBuffer(const Allocator &alloc = Allocator()) - : Allocator(alloc), Buffer(data_, SIZE) {} - ~MemoryBuffer() { free(); } - -#if FMT_USE_RVALUE_REFERENCES - private: - // Move data from other to this buffer. - void move(MemoryBuffer &other) { - Allocator &this_alloc = *this, &other_alloc = other; - this_alloc = std::move(other_alloc); - this->size_ = other.size_; - this->capacity_ = other.capacity_; - if (other.ptr_ == other.data_) { - this->ptr_ = data_; - std::copy(other.data_, - other.data_ + this->size_, make_ptr(data_, this->capacity_)); - } else { - this->ptr_ = other.ptr_; - // Set pointer to the inline array so that delete is not called - // when freeing. - other.ptr_ = other.data_; - } - } - - public: - MemoryBuffer(MemoryBuffer &&other) { - move(other); - } - - MemoryBuffer &operator=(MemoryBuffer &&other) { - assert(this != &other); - free(); - move(other); - return *this; - } -#endif - - // Returns a copy of the allocator associated with this buffer. - Allocator get_allocator() const { return *this; } -}; - -template -void MemoryBuffer::grow(std::size_t size) { - std::size_t new_capacity = - (std::max)(size, this->capacity_ + this->capacity_ / 2); - T *new_ptr = this->allocate(new_capacity); - // The following code doesn't throw, so the raw pointer above doesn't leak. - std::copy(this->ptr_, - this->ptr_ + this->size_, make_ptr(new_ptr, new_capacity)); - std::size_t old_capacity = this->capacity_; - T *old_ptr = this->ptr_; - this->capacity_ = new_capacity; - this->ptr_ = new_ptr; - // deallocate may throw (at least in principle), but it doesn't matter since - // the buffer already uses the new storage and will deallocate it in case - // of exception. - if (old_ptr != data_) - this->deallocate(old_ptr, old_capacity); -} - -#ifndef _MSC_VER -// Portable version of signbit. -inline int getsign(double x) { - // When compiled in C++11 mode signbit is no longer a macro but a function - // defined in namespace std and the macro is undefined. -# ifdef signbit - return signbit(x); -# else - return std::signbit(x); -# endif -} - -// Portable version of isinf. -# ifdef isinf -inline int isinfinity(double x) { return isinf(x); } -inline int isinfinity(long double x) { return isinf(x); } -# else -inline int isinfinity(double x) { return std::isinf(x); } -inline int isinfinity(long double x) { return std::isinf(x); } -# endif -#else -inline int getsign(double value) { - if (value < 0) return 1; - if (value == value) return 0; - int dec = 0, sign = 0; - char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail. - _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign); - return sign; -} -inline int isinfinity(double x) { return !_finite(x); } -inline int isinfinity(long double x) { return !_finite(static_cast(x)); } -#endif - -template -class BasicCharTraits { - public: -#if _SECURE_SCL - typedef stdext::checked_array_iterator CharPtr; -#else - typedef Char *CharPtr; -#endif -}; - -template -class CharTraits; - -template <> -class CharTraits : public BasicCharTraits { - private: - // Conversion from wchar_t to char is not allowed. - static char convert(wchar_t); - -public: - typedef const wchar_t *UnsupportedStrType; - - static char convert(char value) { return value; } - - // Formats a floating-point number. - template - static int format_float(char *buffer, std::size_t size, - const char *format, unsigned width, int precision, T value); -}; - -template <> -class CharTraits : public BasicCharTraits { - public: - typedef const char *UnsupportedStrType; - - static wchar_t convert(char value) { return value; } - static wchar_t convert(wchar_t value) { return value; } - - template - static int format_float(wchar_t *buffer, std::size_t size, - const wchar_t *format, unsigned width, int precision, T value); -}; - -// Checks if a number is negative - used to avoid warnings. -template -struct SignChecker { - template - static bool is_negative(T value) { return value < 0; } -}; - -template <> -struct SignChecker { - template - static bool is_negative(T) { return false; } -}; - -// Returns true if value is negative, false otherwise. -// Same as (value < 0) but doesn't produce warnings if T is an unsigned type. -template -inline bool is_negative(T value) { - return SignChecker::is_signed>::is_negative(value); -} - -// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise. -template -struct TypeSelector { typedef uint32_t Type; }; - -template <> -struct TypeSelector { typedef uint64_t Type; }; - -template -struct IntTraits { - // Smallest of uint32_t and uint64_t that is large enough to represent - // all values of T. - typedef typename - TypeSelector::digits <= 32>::Type MainType; -}; - -// MakeUnsigned::Type gives an unsigned type corresponding to integer type T. -template -struct MakeUnsigned { typedef T Type; }; - -#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \ - template <> \ - struct MakeUnsigned { typedef U Type; } - -FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char); -FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char); -FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short); -FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned); -FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long); -FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong); - -void report_unknown_type(char code, const char *type); - -// Static data is placed in this class template to allow header-only -// configuration. -template -struct BasicData { - static const uint32_t POWERS_OF_10_32[]; - static const uint64_t POWERS_OF_10_64[]; - static const char DIGITS[]; -}; - -typedef BasicData<> Data; - -#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) -# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) -#endif - -#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) -# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) -#endif - -#ifdef FMT_BUILTIN_CLZLL -// Returns the number of decimal digits in n. Leading zeros are not counted -// except for n == 0 in which case count_digits returns 1. -inline unsigned count_digits(uint64_t n) { - // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 - // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. - unsigned t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; - return t - (n < Data::POWERS_OF_10_64[t]) + 1; -} -#else -// Fallback version of count_digits used when __builtin_clz is not available. -inline unsigned count_digits(uint64_t n) { - unsigned count = 1; - for (;;) { - // Integer division is slow so do it for a group of four digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - if (n < 10) return count; - if (n < 100) return count + 1; - if (n < 1000) return count + 2; - if (n < 10000) return count + 3; - n /= 10000u; - count += 4; - } -} -#endif - -#ifdef FMT_BUILTIN_CLZ -// Optional version of count_digits for better performance on 32-bit platforms. -inline unsigned count_digits(uint32_t n) { - uint32_t t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; - return t - (n < Data::POWERS_OF_10_32[t]) + 1; -} -#endif - -// Formats a decimal unsigned integer value writing into buffer. -template -inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { - --num_digits; - while (value >= 100) { - // Integer division is slow so do it for a group of two digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - unsigned index = (value % 100) * 2; - value /= 100; - buffer[num_digits] = Data::DIGITS[index + 1]; - buffer[num_digits - 1] = Data::DIGITS[index]; - num_digits -= 2; - } - if (value < 10) { - *buffer = static_cast('0' + value); - return; - } - unsigned index = static_cast(value * 2); - buffer[1] = Data::DIGITS[index + 1]; - buffer[0] = Data::DIGITS[index]; -} - -#ifdef _WIN32 -// A converter from UTF-8 to UTF-16. -// It is only provided for Windows since other systems support UTF-8 natively. -class UTF8ToUTF16 { - private: - MemoryBuffer buffer_; - - public: - explicit UTF8ToUTF16(StringRef s); - operator WStringRef() const { return WStringRef(&buffer_[0], size()); } - size_t size() const { return buffer_.size() - 1; } - const wchar_t *c_str() const { return &buffer_[0]; } - std::wstring str() const { return std::wstring(&buffer_[0], size()); } -}; - -// A converter from UTF-16 to UTF-8. -// It is only provided for Windows since other systems support UTF-8 natively. -class UTF16ToUTF8 { - private: - MemoryBuffer buffer_; - - public: - UTF16ToUTF8() {} - explicit UTF16ToUTF8(WStringRef s); - operator StringRef() const { return StringRef(&buffer_[0], size()); } - size_t size() const { return buffer_.size() - 1; } - const char *c_str() const { return &buffer_[0]; } - std::string str() const { return std::string(&buffer_[0], size()); } - - // Performs conversion returning a system error code instead of - // throwing exception on conversion error. This method may still throw - // in case of memory allocation error. - int convert(WStringRef s); -}; -#endif - -void format_system_error(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT; - -#ifdef _WIN32 -void format_windows_error(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT; -#endif - -// Computes max(Arg, 1) at compile time. It is used to avoid errors about -// allocating an array of 0 size. -template -struct NonZero { - enum { VALUE = Arg }; -}; - -template <> -struct NonZero<0> { - enum { VALUE = 1 }; -}; - -// The value of a formatting argument. It is a POD type to allow storage in -// internal::MemoryBuffer. -struct Value { - template - struct StringValue { - const Char *value; - std::size_t size; - }; - - typedef void (*FormatFunc)( - void *formatter, const void *arg, void *format_str_ptr); - - struct CustomValue { - const void *value; - FormatFunc format; - }; - - union { - int int_value; - unsigned uint_value; - LongLong long_long_value; - ULongLong ulong_long_value; - double double_value; - long double long_double_value; - const void *pointer; - StringValue string; - StringValue sstring; - StringValue ustring; - StringValue wstring; - CustomValue custom; - }; -}; - -struct Arg : Value { - enum Type { - NONE, - // Integer types should go first, - INT, UINT, LONG_LONG, ULONG_LONG, CHAR, LAST_INTEGER_TYPE = CHAR, - // followed by floating-point types. - DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, - CSTRING, STRING, WSTRING, POINTER, CUSTOM - }; - Type type; -}; - -// Makes a Value object from any type. -template -class MakeValue : public Value { - private: - // The following two methods are private to disallow formatting of - // arbitrary pointers. If you want to output a pointer cast it to - // "void *" or "const void *". In particular, this forbids formatting - // of "[const] volatile char *" which is printed as bool by iostreams. - // Do not implement! - template - MakeValue(const T *value); - template - MakeValue(T *value); - - void set_string(StringRef str) { - string.value = str.c_str(); - string.size = str.size(); - } - - void set_string(WStringRef str) { - CharTraits::convert(wchar_t()); - wstring.value = str.c_str(); - wstring.size = str.size(); - } - - // Formats an argument of a custom type, such as a user-defined class. - template - static void format_custom_arg( - void *formatter, const void *arg, void *format_str_ptr) { - format(*static_cast*>(formatter), - *static_cast(format_str_ptr), - *static_cast(arg)); - } - -public: - MakeValue() {} - -#define FMT_MAKE_VALUE(Type, field, TYPE) \ - MakeValue(Type value) { field = value; } \ - static uint64_t type(Type) { return Arg::TYPE; } - - FMT_MAKE_VALUE(bool, int_value, INT) - FMT_MAKE_VALUE(short, int_value, INT) - FMT_MAKE_VALUE(unsigned short, uint_value, UINT) - FMT_MAKE_VALUE(int, int_value, INT) - FMT_MAKE_VALUE(unsigned, uint_value, UINT) - - MakeValue(long value) { - // To minimize the number of types we need to deal with, long is - // translated either to int or to long long depending on its size. - if (sizeof(long) == sizeof(int)) - int_value = static_cast(value); - else - long_long_value = value; - } - static uint64_t type(long) { - return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; - } - - MakeValue(unsigned long value) { - if (sizeof(unsigned long) == sizeof(unsigned)) - uint_value = static_cast(value); - else - ulong_long_value = value; - } - static uint64_t type(unsigned long) { - return sizeof(unsigned long) == sizeof(unsigned) ? - Arg::UINT : Arg::ULONG_LONG; - } - - FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG) - FMT_MAKE_VALUE(ULongLong, ulong_long_value, ULONG_LONG) - FMT_MAKE_VALUE(float, double_value, DOUBLE) - FMT_MAKE_VALUE(double, double_value, DOUBLE) - FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE) - FMT_MAKE_VALUE(signed char, int_value, CHAR) - FMT_MAKE_VALUE(unsigned char, int_value, CHAR) - FMT_MAKE_VALUE(char, int_value, CHAR) - - MakeValue(wchar_t value) { - int_value = internal::CharTraits::convert(value); - } - static uint64_t type(wchar_t) { return Arg::CHAR; } - -#define FMT_MAKE_STR_VALUE(Type, TYPE) \ - MakeValue(Type value) { set_string(value); } \ - static uint64_t type(Type) { return Arg::TYPE; } - - FMT_MAKE_VALUE(char *, string.value, CSTRING) - FMT_MAKE_VALUE(const char *, string.value, CSTRING) - FMT_MAKE_VALUE(const signed char *, sstring.value, CSTRING) - FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) - FMT_MAKE_STR_VALUE(const std::string &, STRING) - FMT_MAKE_STR_VALUE(StringRef, STRING) - - FMT_MAKE_STR_VALUE(wchar_t *, WSTRING) - FMT_MAKE_STR_VALUE(const wchar_t *, WSTRING) - FMT_MAKE_STR_VALUE(const std::wstring &, WSTRING) - FMT_MAKE_STR_VALUE(WStringRef, WSTRING) - - FMT_MAKE_VALUE(void *, pointer, POINTER) - FMT_MAKE_VALUE(const void *, pointer, POINTER) - - template - MakeValue(const T &value) { - custom.value = &value; - custom.format = &format_custom_arg; - } - template - static uint64_t type(const T &) { return Arg::CUSTOM; } -}; - -#define FMT_DISPATCH(call) static_cast(this)->call - -// An argument visitor. -// To use ArgVisitor define a subclass that implements some or all of the -// visit methods with the same signatures as the methods in ArgVisitor, -// for example, visit_int(int). -// Specify the subclass name as the Impl template parameter. Then calling -// ArgVisitor::visit for some argument will dispatch to a visit method -// specific to the argument type. For example, if the argument type is -// double then visit_double(double) method of a subclass will be called. -// If the subclass doesn't contain a method with this signature, then -// a corresponding method of ArgVisitor will be called. -// -// Example: -// class MyArgVisitor : public ArgVisitor { -// public: -// void visit_int(int value) { print("{}", value); } -// void visit_double(double value) { print("{}", value ); } -// }; -// -// ArgVisitor uses the curiously recurring template pattern: -// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern -template -class ArgVisitor { - public: - Result visit_unhandled_arg() { return Result(); } - - Result visit_int(int value) { - return FMT_DISPATCH(visit_any_int(value)); - } - Result visit_long_long(LongLong value) { - return FMT_DISPATCH(visit_any_int(value)); - } - Result visit_uint(unsigned value) { - return FMT_DISPATCH(visit_any_int(value)); - } - Result visit_ulong_long(ULongLong value) { - return FMT_DISPATCH(visit_any_int(value)); - } - Result visit_char(int value) { - return FMT_DISPATCH(visit_any_int(value)); - } - template - Result visit_any_int(T) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - Result visit_double(double value) { - return FMT_DISPATCH(visit_any_double(value)); - } - Result visit_long_double(long double value) { - return FMT_DISPATCH(visit_any_double(value)); - } - template - Result visit_any_double(T) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - Result visit_string(Arg::StringValue) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - Result visit_wstring(Arg::StringValue) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - Result visit_pointer(const void *) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - Result visit_custom(Arg::CustomValue) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - Result visit(const Arg &arg) { - switch (arg.type) { - default: - assert(false); - return Result(); - case Arg::INT: - return FMT_DISPATCH(visit_int(arg.int_value)); - case Arg::UINT: - return FMT_DISPATCH(visit_uint(arg.uint_value)); - case Arg::LONG_LONG: - return FMT_DISPATCH(visit_long_long(arg.long_long_value)); - case Arg::ULONG_LONG: - return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value)); - case Arg::DOUBLE: - return FMT_DISPATCH(visit_double(arg.double_value)); - case Arg::LONG_DOUBLE: - return FMT_DISPATCH(visit_long_double(arg.long_double_value)); - case Arg::CHAR: - return FMT_DISPATCH(visit_char(arg.int_value)); - case Arg::CSTRING: { - Value::StringValue str = arg.string; - str.size = 0; - return FMT_DISPATCH(visit_string(str)); - } - case Arg::STRING: - return FMT_DISPATCH(visit_string(arg.string)); - case Arg::WSTRING: - return FMT_DISPATCH(visit_wstring(arg.wstring)); - case Arg::POINTER: - return FMT_DISPATCH(visit_pointer(arg.pointer)); - case Arg::CUSTOM: - return FMT_DISPATCH(visit_custom(arg.custom)); - } - } -}; - -class RuntimeError : public std::runtime_error { - protected: - RuntimeError() : std::runtime_error("") {} -}; - -template -class ArgFormatter; -} // namespace internal - -/** - An argument list. - */ -class ArgList { - private: - uint64_t types_; - const internal::Value *values_; - - public: - // Maximum number of arguments that can be passed in ArgList. - enum { MAX_ARGS = 16 }; - - ArgList() : types_(0) {} - ArgList(ULongLong types, const internal::Value *values) - : types_(types), values_(values) {} - - /** - Returns the argument at specified index. - */ - internal::Arg operator[](unsigned index) const { - using internal::Arg; - Arg arg; - if (index >= MAX_ARGS) { - arg.type = Arg::NONE; - return arg; - } - unsigned shift = index * 4; - uint64_t mask = 0xf; - Arg::Type type = - static_cast((types_ & (mask << shift)) >> shift); - arg.type = type; - if (type != Arg::NONE) { - internal::Value &value = arg; - value = values_[index]; - } - return arg; - } -}; - -struct FormatSpec; - -namespace internal { - -class FormatterBase { - private: - ArgList args_; - int next_arg_index_; - - // Returns the argument with specified index. - Arg do_get_arg(unsigned arg_index, const char *&error); - - protected: - void set_args(const ArgList &args) { - args_ = args; - next_arg_index_ = 0; - } - - // Returns the next argument. - Arg next_arg(const char *&error); - - // Checks if manual indexing is used and returns the argument with - // specified index. - Arg get_arg(unsigned arg_index, const char *&error); - - template - void write(BasicWriter &w, const Char *start, const Char *end) { - if (start != end) - w << BasicStringRef(start, end - start); - } -}; - -// A printf formatter. -template -class PrintfFormatter : private FormatterBase { - private: - void parse_flags(FormatSpec &spec, const Char *&s); - - // Returns the argument with specified index or, if arg_index is equal - // to the maximum unsigned value, the next argument. - Arg get_arg(const Char *s, - unsigned arg_index = (std::numeric_limits::max)()); - - // Parses argument index, flags and width and returns the argument index. - unsigned parse_header(const Char *&s, FormatSpec &spec); - - public: - void format(BasicWriter &writer, - BasicStringRef format_str, const ArgList &args); -}; -} // namespace internal - -// A formatter. -template -class BasicFormatter : private internal::FormatterBase { - private: - BasicWriter &writer_; - const Char *start_; - - FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter); - - // Parses argument index and returns corresponding argument. - internal::Arg parse_arg_index(const Char *&s); - - public: - explicit BasicFormatter(BasicWriter &w) : writer_(w) {} - - BasicWriter &writer() { return writer_; } - - void format(BasicStringRef format_str, const ArgList &args); - - const Char *format(const Char *&format_str, const internal::Arg &arg); -}; - -enum Alignment { - ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC -}; - -// Flags. -enum { - SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8, - CHAR_FLAG = 0x10 // Argument has char type - used in error reporting. -}; - -// An empty format specifier. -struct EmptySpec {}; - -// A type specifier. -template -struct TypeSpec : EmptySpec { - Alignment align() const { return ALIGN_DEFAULT; } - unsigned width() const { return 0; } - int precision() const { return -1; } - bool flag(unsigned) const { return false; } - char type() const { return TYPE; } - char fill() const { return ' '; } -}; - -// A width specifier. -struct WidthSpec { - unsigned width_; - // Fill is always wchar_t and cast to char if necessary to avoid having - // two specialization of WidthSpec and its subclasses. - wchar_t fill_; - - WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {} - - unsigned width() const { return width_; } - wchar_t fill() const { return fill_; } -}; - -// An alignment specifier. -struct AlignSpec : WidthSpec { - Alignment align_; - - AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT) - : WidthSpec(width, fill), align_(align) {} - - Alignment align() const { return align_; } - - int precision() const { return -1; } -}; - -// An alignment and type specifier. -template -struct AlignTypeSpec : AlignSpec { - AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {} - - bool flag(unsigned) const { return false; } - char type() const { return TYPE; } -}; - -// A full format specifier. -struct FormatSpec : AlignSpec { - unsigned flags_; - int precision_; - char type_; - - FormatSpec( - unsigned width = 0, char type = 0, wchar_t fill = ' ') - : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} - - bool flag(unsigned f) const { return (flags_ & f) != 0; } - int precision() const { return precision_; } - char type() const { return type_; } -}; - -// An integer format specifier. -template , typename Char = char> -class IntFormatSpec : public SpecT { - private: - T value_; - - public: - IntFormatSpec(T val, const SpecT &spec = SpecT()) - : SpecT(spec), value_(val) {} - - T value() const { return value_; } -}; - -// A string format specifier. -template -class StrFormatSpec : public AlignSpec { - private: - const T *str_; - - public: - StrFormatSpec(const T *str, unsigned width, wchar_t fill) - : AlignSpec(width, fill), str_(str) {} - - const T *str() const { return str_; } -}; - -/** - Returns an integer format specifier to format the value in base 2. - */ -IntFormatSpec > bin(int value); - -/** - Returns an integer format specifier to format the value in base 8. - */ -IntFormatSpec > oct(int value); - -/** - Returns an integer format specifier to format the value in base 16 using - lower-case letters for the digits above 9. - */ -IntFormatSpec > hex(int value); - -/** - Returns an integer formatter format specifier to format in base 16 using - upper-case letters for the digits above 9. - */ -IntFormatSpec > hexu(int value); - -/** - \rst - Returns an integer format specifier to pad the formatted argument with the - fill character to the specified width using the default (right) numeric - alignment. - - **Example**:: - - MemoryWriter out; - out << pad(hex(0xcafe), 8, '0'); - // out.str() == "0000cafe" - - \endrst - */ -template -IntFormatSpec, Char> pad( - int value, unsigned width, Char fill = ' '); - -#define FMT_DEFINE_INT_FORMATTERS(TYPE) \ -inline IntFormatSpec > bin(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'b'>()); \ -} \ - \ -inline IntFormatSpec > oct(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'o'>()); \ -} \ - \ -inline IntFormatSpec > hex(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'x'>()); \ -} \ - \ -inline IntFormatSpec > hexu(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'X'>()); \ -} \ - \ -template \ -inline IntFormatSpec > pad( \ - IntFormatSpec > f, unsigned width) { \ - return IntFormatSpec >( \ - f.value(), AlignTypeSpec(width, ' ')); \ -} \ - \ -/* For compatibility with older compilers we provide two overloads for pad, */ \ -/* one that takes a fill character and one that doesn't. In the future this */ \ -/* can be replaced with one overload making the template argument Char */ \ -/* default to char (C++11). */ \ -template \ -inline IntFormatSpec, Char> pad( \ - IntFormatSpec, Char> f, \ - unsigned width, Char fill) { \ - return IntFormatSpec, Char>( \ - f.value(), AlignTypeSpec(width, fill)); \ -} \ - \ -inline IntFormatSpec > pad( \ - TYPE value, unsigned width) { \ - return IntFormatSpec >( \ - value, AlignTypeSpec<0>(width, ' ')); \ -} \ - \ -template \ -inline IntFormatSpec, Char> pad( \ - TYPE value, unsigned width, Char fill) { \ - return IntFormatSpec, Char>( \ - value, AlignTypeSpec<0>(width, fill)); \ -} - -FMT_DEFINE_INT_FORMATTERS(int) -FMT_DEFINE_INT_FORMATTERS(long) -FMT_DEFINE_INT_FORMATTERS(unsigned) -FMT_DEFINE_INT_FORMATTERS(unsigned long) -FMT_DEFINE_INT_FORMATTERS(LongLong) -FMT_DEFINE_INT_FORMATTERS(ULongLong) - -/** - \rst - Returns a string formatter that pads the formatted argument with the fill - character to the specified width using the default (left) string alignment. - - **Example**:: - - std::string s = str(MemoryWriter() << pad("abc", 8)); - // s == "abc " - - \endrst - */ -template -inline StrFormatSpec pad( - const Char *str, unsigned width, Char fill = ' ') { - return StrFormatSpec(str, width, fill); -} - -inline StrFormatSpec pad( - const wchar_t *str, unsigned width, char fill = ' ') { - return StrFormatSpec(str, width, fill); -} - -// Generates a comma-separated list with results of applying f to -// numbers 0..n-1. -# define FMT_GEN(n, f) FMT_GEN##n(f) -# define FMT_GEN1(f) f(0) -# define FMT_GEN2(f) FMT_GEN1(f), f(1) -# define FMT_GEN3(f) FMT_GEN2(f), f(2) -# define FMT_GEN4(f) FMT_GEN3(f), f(3) -# define FMT_GEN5(f) FMT_GEN4(f), f(4) -# define FMT_GEN6(f) FMT_GEN5(f), f(5) -# define FMT_GEN7(f) FMT_GEN6(f), f(6) -# define FMT_GEN8(f) FMT_GEN7(f), f(7) -# define FMT_GEN9(f) FMT_GEN8(f), f(8) -# define FMT_GEN10(f) FMT_GEN9(f), f(9) -# define FMT_GEN11(f) FMT_GEN10(f), f(10) -# define FMT_GEN12(f) FMT_GEN11(f), f(11) -# define FMT_GEN13(f) FMT_GEN12(f), f(12) -# define FMT_GEN14(f) FMT_GEN13(f), f(13) -# define FMT_GEN15(f) FMT_GEN14(f), f(14) - -namespace internal { -inline uint64_t make_type() { return 0; } - -template -inline uint64_t make_type(const T &arg) { return MakeValue::type(arg); } - -#if FMT_USE_VARIADIC_TEMPLATES -template -inline uint64_t make_type(const Arg &first, const Args & ... tail) { - return make_type(first) | (make_type(tail...) << 4); -} -#else - -struct ArgType { - uint64_t type; - - ArgType() : type(0) {} - - template - ArgType(const T &arg) : type(make_type(arg)) {} -}; - -# define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType() - -inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { - return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) | - (t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) | - (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) | - (t12.type << 48) | (t13.type << 52) | (t14.type << 56); -} -#endif -} // namespace internal - -# define FMT_MAKE_TEMPLATE_ARG(n) typename T##n -# define FMT_MAKE_ARG_TYPE(n) T##n -# define FMT_MAKE_ARG(n) const T##n &v##n -# define FMT_MAKE_REF_char(n) fmt::internal::MakeValue(v##n) -# define FMT_MAKE_REF_wchar_t(n) fmt::internal::MakeValue(v##n) - -#if FMT_USE_VARIADIC_TEMPLATES -// Defines a variadic function returning void. -# define FMT_VARIADIC_VOID(func, arg_type) \ - template \ - void func(arg_type arg1, const Args & ... args) { \ - const fmt::internal::Value values[ \ - fmt::internal::NonZero::VALUE] = { \ - fmt::internal::MakeValue(args)... \ - }; \ - func(arg1, ArgList(fmt::internal::make_type(args...), values)); \ - } - -// Defines a variadic constructor. -# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ - template \ - ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ - using fmt::internal::MakeValue; \ - const fmt::internal::Value values[ \ - fmt::internal::NonZero::VALUE] = { \ - MakeValue(args)... \ - }; \ - func(arg0, arg1, ArgList(fmt::internal::make_type(args...), values)); \ - } - -#else - -# define FMT_MAKE_REF(n) fmt::internal::MakeValue(v##n) -# define FMT_MAKE_REF2(n) v##n - -// Defines a wrapper for a function taking one argument of type arg_type -// and n additional arguments of arbitrary types. -# define FMT_WRAP1(func, arg_type, n) \ - template \ - inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ - func(arg1, fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ - } - -// Emulates a variadic function returning void on a pre-C++11 compiler. -# define FMT_VARIADIC_VOID(func, arg_type) \ - inline void func(arg_type arg) { func(arg, fmt::ArgList()); } \ - FMT_WRAP1(func, arg_type, 1) FMT_WRAP1(func, arg_type, 2) \ - FMT_WRAP1(func, arg_type, 3) FMT_WRAP1(func, arg_type, 4) \ - FMT_WRAP1(func, arg_type, 5) FMT_WRAP1(func, arg_type, 6) \ - FMT_WRAP1(func, arg_type, 7) FMT_WRAP1(func, arg_type, 8) \ - FMT_WRAP1(func, arg_type, 9) FMT_WRAP1(func, arg_type, 10) - -# define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \ - template \ - ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ - func(arg0, arg1, fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ - } - -// Emulates a variadic constructor on a pre-C++11 compiler. -# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 1) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 2) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 3) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 4) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 5) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 6) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 7) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 8) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 9) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 10) -#endif - -// Generates a comma-separated list with results of applying f to pairs -// (argument, index). -#define FMT_FOR_EACH1(f, x0) f(x0, 0) -#define FMT_FOR_EACH2(f, x0, x1) \ - FMT_FOR_EACH1(f, x0), f(x1, 1) -#define FMT_FOR_EACH3(f, x0, x1, x2) \ - FMT_FOR_EACH2(f, x0 ,x1), f(x2, 2) -#define FMT_FOR_EACH4(f, x0, x1, x2, x3) \ - FMT_FOR_EACH3(f, x0, x1, x2), f(x3, 3) -#define FMT_FOR_EACH5(f, x0, x1, x2, x3, x4) \ - FMT_FOR_EACH4(f, x0, x1, x2, x3), f(x4, 4) -#define FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5) \ - FMT_FOR_EACH5(f, x0, x1, x2, x3, x4), f(x5, 5) -#define FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6) \ - FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5), f(x6, 6) -#define FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7) \ - FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6), f(x7, 7) -#define FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8) \ - FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7), f(x8, 8) -#define FMT_FOR_EACH10(f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) \ - FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8), f(x9, 9) - -/** - An error returned by an operating system or a language runtime, - for example a file opening error. -*/ -class SystemError : public internal::RuntimeError { - private: - void init(int err_code, StringRef format_str, ArgList args); - - protected: - int error_code_; - - typedef char Char; // For FMT_VARIADIC_CTOR. - - SystemError() {} - - public: - /** - \rst - Constructs a :class:`fmt::SystemError` object with the description - of the form - - .. parsed-literal:: - **: ** - - where ** is the formatted message and ** is - the system message corresponding to the error code. - *error_code* is a system error code as given by ``errno``. - If *error_code* is not a valid error code such as -1, the system message - may look like "Unknown error -1" and is platform-dependent. - - **Example**:: - - // This throws a SystemError with the description - // cannot open file 'madeup': No such file or directory - // or similar (system message may vary). - const char *filename = "madeup"; - std::FILE *file = std::fopen(filename, "r"); - if (!file) - throw fmt::SystemError(errno, "cannot open file '{}'", filename); - \endrst - */ - SystemError(int error_code, StringRef message) { - init(error_code, message, ArgList()); - } - FMT_VARIADIC_CTOR(SystemError, init, int, StringRef) - - int error_code() const { return error_code_; } -}; - -/** - \rst - This template provides operations for formatting and writing data into - a character stream. The output is stored in a buffer provided by a subclass - such as :class:`fmt::BasicMemoryWriter`. - - You can use one of the following typedefs for common character types: - - +---------+----------------------+ - | Type | Definition | - +=========+======================+ - | Writer | BasicWriter | - +---------+----------------------+ - | WWriter | BasicWriter | - +---------+----------------------+ - - \endrst - */ -template -class BasicWriter { - private: - // Output buffer. - internal::Buffer &buffer_; - - FMT_DISALLOW_COPY_AND_ASSIGN(BasicWriter); - - typedef typename internal::CharTraits::CharPtr CharPtr; - -#if _SECURE_SCL - // Returns pointer value. - static Char *get(CharPtr p) { return p.base(); } -#else - static Char *get(Char *p) { return p; } -#endif - - // Fills the padding around the content and returns the pointer to the - // content area. - static CharPtr fill_padding(CharPtr buffer, - unsigned total_size, std::size_t content_size, wchar_t fill); - - // Grows the buffer by n characters and returns a pointer to the newly - // allocated area. - CharPtr grow_buffer(std::size_t n) { - std::size_t size = buffer_.size(); - buffer_.resize(size + n); - return internal::make_ptr(&buffer_[size], n); - } - - // Prepare a buffer for integer formatting. - CharPtr prepare_int_buffer(unsigned num_digits, - const EmptySpec &, const char *prefix, unsigned prefix_size) { - unsigned size = prefix_size + num_digits; - CharPtr p = grow_buffer(size); - std::copy(prefix, prefix + prefix_size, p); - return p + size - 1; - } - - template - CharPtr prepare_int_buffer(unsigned num_digits, - const Spec &spec, const char *prefix, unsigned prefix_size); - - // Formats an integer. - template - void write_int(T value, Spec spec); - - // Formats a floating-point number (double or long double). - template - void write_double(T value, const FormatSpec &spec); - - // Writes a formatted string. - template - CharPtr write_str( - const StrChar *s, std::size_t size, const AlignSpec &spec); - - template - void write_str( - const internal::Arg::StringValue &str, const FormatSpec &spec); - - // This method is private to disallow writing a wide string to a - // char stream and vice versa. If you want to print a wide string - // as a pointer as std::ostream does, cast it to const void*. - // Do not implement! - void operator<<(typename internal::CharTraits::UnsupportedStrType); - - // Appends floating-point length specifier to the format string. - // The second argument is only used for overload resolution. - void append_float_length(Char *&format_ptr, long double) { - *format_ptr++ = 'L'; - } - - template - void append_float_length(Char *&, T) {} - - friend class internal::ArgFormatter; - friend class internal::PrintfFormatter; - - protected: - /** - Constructs a ``BasicWriter`` object. - */ - explicit BasicWriter(internal::Buffer &b) : buffer_(b) {} - - public: - /** - Destroys a ``BasicWriter`` object. - */ - virtual ~BasicWriter() {} - - /** - Returns the total number of characters written. - */ - std::size_t size() const { return buffer_.size(); } - - /** - Returns a pointer to the output buffer content. No terminating null - character is appended. - */ - const Char *data() const FMT_NOEXCEPT { return &buffer_[0]; } - - /** - Returns a pointer to the output buffer content with terminating null - character appended. - */ - const Char *c_str() const { - std::size_t size = buffer_.size(); - buffer_.reserve(size + 1); - buffer_[size] = '\0'; - return &buffer_[0]; - } - - /** - Returns the content of the output buffer as an `std::string`. - */ - std::basic_string str() const { - return std::basic_string(&buffer_[0], buffer_.size()); - } - - /** - \rst - Writes formatted data. - - *args* is an argument list representing arbitrary arguments. - - **Example**:: - - MemoryWriter out; - out.write("Current point:\n"); - out.write("({:+f}, {:+f})", -3.14, 3.14); - - This will write the following output to the ``out`` object: - - .. code-block:: none - - Current point: - (-3.140000, +3.140000) - - The output can be accessed using :func:`data()`, :func:`c_str` or - :func:`str` methods. - - See also :ref:`syntax`. - \endrst - */ - void write(BasicStringRef format, ArgList args) { - BasicFormatter(*this).format(format, args); - } - FMT_VARIADIC_VOID(write, BasicStringRef) - - BasicWriter &operator<<(int value) { - return *this << IntFormatSpec(value); - } - BasicWriter &operator<<(unsigned value) { - return *this << IntFormatSpec(value); - } - BasicWriter &operator<<(long value) { - return *this << IntFormatSpec(value); - } - BasicWriter &operator<<(unsigned long value) { - return *this << IntFormatSpec(value); - } - BasicWriter &operator<<(LongLong value) { - return *this << IntFormatSpec(value); - } - - /** - Formats *value* and writes it to the stream. - */ - BasicWriter &operator<<(ULongLong value) { - return *this << IntFormatSpec(value); - } - - BasicWriter &operator<<(double value) { - write_double(value, FormatSpec()); - return *this; - } - - /** - Formats *value* using the general format for floating-point numbers - (``'g'``) and writes it to the stream. - */ - BasicWriter &operator<<(long double value) { - write_double(value, FormatSpec()); - return *this; - } - - /** - Writes a character to the stream. - */ - BasicWriter &operator<<(char value) { - buffer_.push_back(value); - return *this; - } - - BasicWriter &operator<<(wchar_t value) { - buffer_.push_back(internal::CharTraits::convert(value)); - return *this; - } - - /** - Writes *value* to the stream. - */ - BasicWriter &operator<<(fmt::BasicStringRef value) { - const Char *str = value.c_str(); - buffer_.append(str, str + value.size()); - return *this; - } - - template - BasicWriter &operator<<(IntFormatSpec spec) { - internal::CharTraits::convert(FillChar()); - write_int(spec.value(), spec); - return *this; - } - - template - BasicWriter &operator<<(const StrFormatSpec &spec) { - const StrChar *s = spec.str(); - // TODO: error if fill is not convertible to Char - write_str(s, std::char_traits::length(s), spec); - return *this; - } - - void clear() FMT_NOEXCEPT { buffer_.clear(); } -}; - -template -template -typename BasicWriter::CharPtr BasicWriter::write_str( - const StrChar *s, std::size_t size, const AlignSpec &spec) { - CharPtr out = CharPtr(); - if (spec.width() > size) { - out = grow_buffer(spec.width()); - Char fill = static_cast(spec.fill()); - if (spec.align() == ALIGN_RIGHT) { - std::fill_n(out, spec.width() - size, fill); - out += spec.width() - size; - } else if (spec.align() == ALIGN_CENTER) { - out = fill_padding(out, spec.width(), size, fill); - } else { - std::fill_n(out + size, spec.width() - size, fill); - } - } else { - out = grow_buffer(size); - } - std::copy(s, s + size, out); - return out; -} - -template -typename BasicWriter::CharPtr - BasicWriter::fill_padding( - CharPtr buffer, unsigned total_size, - std::size_t content_size, wchar_t fill) { - std::size_t padding = total_size - content_size; - std::size_t left_padding = padding / 2; - Char fill_char = static_cast(fill); - std::fill_n(buffer, left_padding, fill_char); - buffer += left_padding; - CharPtr content = buffer; - std::fill_n(buffer + content_size, padding - left_padding, fill_char); - return content; -} - -template -template -typename BasicWriter::CharPtr - BasicWriter::prepare_int_buffer( - unsigned num_digits, const Spec &spec, - const char *prefix, unsigned prefix_size) { - unsigned width = spec.width(); - Alignment align = spec.align(); - Char fill = static_cast(spec.fill()); - if (spec.precision() > static_cast(num_digits)) { - // Octal prefix '0' is counted as a digit, so ignore it if precision - // is specified. - if (prefix_size > 0 && prefix[prefix_size - 1] == '0') - --prefix_size; - unsigned number_size = prefix_size + spec.precision(); - AlignSpec subspec(number_size, '0', ALIGN_NUMERIC); - if (number_size >= width) - return prepare_int_buffer(num_digits, subspec, prefix, prefix_size); - buffer_.reserve(width); - unsigned fill_size = width - number_size; - if (align != ALIGN_LEFT) { - CharPtr p = grow_buffer(fill_size); - std::fill(p, p + fill_size, fill); - } - CharPtr result = prepare_int_buffer( - num_digits, subspec, prefix, prefix_size); - if (align == ALIGN_LEFT) { - CharPtr p = grow_buffer(fill_size); - std::fill(p, p + fill_size, fill); - } - return result; - } - unsigned size = prefix_size + num_digits; - if (width <= size) { - CharPtr p = grow_buffer(size); - std::copy(prefix, prefix + prefix_size, p); - return p + size - 1; - } - CharPtr p = grow_buffer(width); - CharPtr end = p + width; - if (align == ALIGN_LEFT) { - std::copy(prefix, prefix + prefix_size, p); - p += size; - std::fill(p, end, fill); - } else if (align == ALIGN_CENTER) { - p = fill_padding(p, width, size, fill); - std::copy(prefix, prefix + prefix_size, p); - p += size; - } else { - if (align == ALIGN_NUMERIC) { - if (prefix_size != 0) { - p = std::copy(prefix, prefix + prefix_size, p); - size -= prefix_size; - } - } else { - std::copy(prefix, prefix + prefix_size, end - size); - } - std::fill(p, end - size, fill); - p = end; - } - return p - 1; -} - -template -template -void BasicWriter::write_int(T value, Spec spec) { - unsigned prefix_size = 0; - typedef typename internal::IntTraits::MainType UnsignedType; - UnsignedType abs_value = value; - char prefix[4] = ""; - if (internal::is_negative(value)) { - prefix[0] = '-'; - ++prefix_size; - abs_value = 0 - abs_value; - } else if (spec.flag(SIGN_FLAG)) { - prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' '; - ++prefix_size; - } - switch (spec.type()) { - case 0: case 'd': { - unsigned num_digits = internal::count_digits(abs_value); - CharPtr p = prepare_int_buffer( - num_digits, spec, prefix, prefix_size) + 1 - num_digits; - internal::format_decimal(get(p), abs_value, num_digits); - break; - } - case 'x': case 'X': { - UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) { - prefix[prefix_size++] = '0'; - prefix[prefix_size++] = spec.type(); - } - unsigned num_digits = 0; - do { - ++num_digits; - } while ((n >>= 4) != 0); - Char *p = get(prepare_int_buffer( - num_digits, spec, prefix, prefix_size)); - n = abs_value; - const char *digits = spec.type() == 'x' ? - "0123456789abcdef" : "0123456789ABCDEF"; - do { - *p-- = digits[n & 0xf]; - } while ((n >>= 4) != 0); - break; - } - case 'b': case 'B': { - UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) { - prefix[prefix_size++] = '0'; - prefix[prefix_size++] = spec.type(); - } - unsigned num_digits = 0; - do { - ++num_digits; - } while ((n >>= 1) != 0); - Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); - n = abs_value; - do { - *p-- = '0' + (n & 1); - } while ((n >>= 1) != 0); - break; - } - case 'o': { - UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) - prefix[prefix_size++] = '0'; - unsigned num_digits = 0; - do { - ++num_digits; - } while ((n >>= 3) != 0); - Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); - n = abs_value; - do { - *p-- = '0' + (n & 7); - } while ((n >>= 3) != 0); - break; - } - default: - internal::report_unknown_type( - spec.type(), spec.flag(CHAR_FLAG) ? "char" : "integer"); - break; - } -} - -template -template -void BasicWriter::write_double( - T value, const FormatSpec &spec) { - // Check type. - char type = spec.type(); - bool upper = false; - switch (type) { - case 0: - type = 'g'; - break; - case 'e': case 'f': case 'g': case 'a': - break; - case 'F': -#ifdef _MSC_VER - // MSVC's printf doesn't support 'F'. - type = 'f'; -#endif - // Fall through. - case 'E': case 'G': case 'A': - upper = true; - break; - default: - internal::report_unknown_type(type, "double"); - break; - } - - char sign = 0; - // Use getsign instead of value < 0 because the latter is always - // false for NaN. - if (internal::getsign(static_cast(value))) { - sign = '-'; - value = -value; - } else if (spec.flag(SIGN_FLAG)) { - sign = spec.flag(PLUS_FLAG) ? '+' : ' '; - } - - if (value != value) { - // Format NaN ourselves because sprintf's output is not consistent - // across platforms. - std::size_t nan_size = 4; - const char *nan = upper ? " NAN" : " nan"; - if (!sign) { - --nan_size; - ++nan; - } - CharPtr out = write_str(nan, nan_size, spec); - if (sign) - *out = sign; - return; - } - - if (internal::isinfinity(value)) { - // Format infinity ourselves because sprintf's output is not consistent - // across platforms. - std::size_t inf_size = 4; - const char *inf = upper ? " INF" : " inf"; - if (!sign) { - --inf_size; - ++inf; - } - CharPtr out = write_str(inf, inf_size, spec); - if (sign) - *out = sign; - return; - } - - std::size_t offset = buffer_.size(); - unsigned width = spec.width(); - if (sign) { - buffer_.reserve(buffer_.size() + (std::max)(width, 1u)); - if (width > 0) - --width; - ++offset; - } - - // Build format string. - enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg - Char format[MAX_FORMAT_SIZE]; - Char *format_ptr = format; - *format_ptr++ = '%'; - unsigned width_for_sprintf = width; - if (spec.flag(HASH_FLAG)) - *format_ptr++ = '#'; - if (spec.align() == ALIGN_CENTER) { - width_for_sprintf = 0; - } else { - if (spec.align() == ALIGN_LEFT) - *format_ptr++ = '-'; - if (width != 0) - *format_ptr++ = '*'; - } - if (spec.precision() >= 0) { - *format_ptr++ = '.'; - *format_ptr++ = '*'; - } - - append_float_length(format_ptr, value); - *format_ptr++ = type; - *format_ptr = '\0'; - - // Format using snprintf. - Char fill = static_cast(spec.fill()); - for (;;) { - std::size_t buffer_size = buffer_.capacity() - offset; -#if _MSC_VER - // MSVC's vsnprintf_s doesn't work with zero size, so reserve - // space for at least one extra character to make the size non-zero. - // Note that the buffer's capacity will increase by more than 1. - if (buffer_size == 0) { - buffer_.reserve(offset + 1); - buffer_size = buffer_.capacity() - offset; - } -#endif - Char *start = &buffer_[offset]; - int n = internal::CharTraits::format_float( - start, buffer_size, format, width_for_sprintf, spec.precision(), value); - if (n >= 0 && offset + n < buffer_.capacity()) { - if (sign) { - if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || - *start != ' ') { - *(start - 1) = sign; - sign = 0; - } else { - *(start - 1) = fill; - } - ++n; - } - if (spec.align() == ALIGN_CENTER && - spec.width() > static_cast(n)) { - width = spec.width(); - CharPtr p = grow_buffer(width); - std::copy(p, p + n, p + (width - n) / 2); - fill_padding(p, spec.width(), n, fill); - return; - } - if (spec.fill() != ' ' || sign) { - while (*start == ' ') - *start++ = fill; - if (sign) - *(start - 1) = sign; - } - grow_buffer(n); - return; - } - // If n is negative we ask to increase the capacity by at least 1, - // but as std::vector, the buffer grows exponentially. - buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1); - } -} - -/** - \rst - This template provides operations for formatting and writing data into - a character stream. The output is stored in a memory buffer that grows - dynamically. - - You can use one of the following typedefs for common character types - and the standard allocator: - - +---------------+-----------------------------------------------+ - | Type | Definition | - +===============+===============================================+ - | MemoryWriter | BasicWriter> | - +---------------+-----------------------------------------------+ - | WMemoryWriter | BasicWriter> | - +---------------+-----------------------------------------------+ - - **Example**:: - - MemoryWriter out; - out << "The answer is " << 42 << "\n"; - out.write("({:+f}, {:+f})", -3.14, 3.14); - - This will write the following output to the ``out`` object: - - .. code-block:: none - - The answer is 42 - (-3.140000, +3.140000) - - The output can be converted to an ``std::string`` with ``out.str()`` or - accessed as a C string with ``out.c_str()``. - \endrst - */ -template > -class BasicMemoryWriter : public BasicWriter { - private: - internal::MemoryBuffer buffer_; - - public: - explicit BasicMemoryWriter(const Allocator& alloc = Allocator()) - : BasicWriter(buffer_), buffer_(alloc) {} - -#if FMT_USE_RVALUE_REFERENCES - /** - Constructs a :class:`fmt::BasicMemoryWriter` object moving the content - of the other object to it. - */ - BasicMemoryWriter(BasicMemoryWriter &&other) - : BasicWriter(buffer_), buffer_(std::move(other.buffer_)) { - } - - /** - Moves the content of the other ``BasicMemoryWriter`` object to this one. - */ - BasicMemoryWriter &operator=(BasicMemoryWriter &&other) { - buffer_ = std::move(other.buffer_); - return *this; - } -#endif -}; - -typedef BasicMemoryWriter MemoryWriter; -typedef BasicMemoryWriter WMemoryWriter; - -// Formats a value. -template -void format(BasicFormatter &f, const Char *&format_str, const T &value) { - std::basic_ostringstream os; - os << value; - internal::Arg arg; - internal::Value &arg_value = arg; - std::basic_string str = os.str(); - arg_value = internal::MakeValue(str); - arg.type = static_cast(internal::MakeValue::type(str)); - format_str = f.format(format_str, arg); -} - -// Reports a system error without throwing an exception. -// Can be used to report errors from destructors. -void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT; - -#ifdef _WIN32 - -/** A Windows error. */ -class WindowsError : public SystemError { - private: - void init(int error_code, StringRef format_str, ArgList args); - - public: - /** - \rst - Constructs a :class:`fmt::WindowsError` object with the description - of the form - - .. parsed-literal:: - **: ** - - where ** is the formatted message and ** is the system - message corresponding to the error code. - *error_code* is a Windows error code as given by ``GetLastError``. - If *error_code* is not a valid error code such as -1, the system message - will look like "error -1". - - **Example**:: - - // This throws a WindowsError with the description - // cannot open file 'madeup': The system cannot find the file specified. - // or similar (system message may vary). - const char *filename = "madeup"; - LPOFSTRUCT of = LPOFSTRUCT(); - HFILE file = OpenFile(filename, &of, OF_READ); - if (file == HFILE_ERROR) - throw fmt::WindowsError(GetLastError(), "cannot open file '{}'", filename); - \endrst - */ - WindowsError(int error_code, StringRef message) { - init(error_code, message, ArgList()); - } - FMT_VARIADIC_CTOR(WindowsError, init, int, StringRef) -}; - -// Reports a Windows error without throwing an exception. -// Can be used to report errors from destructors. -void report_windows_error(int error_code, StringRef message) FMT_NOEXCEPT; - -#endif - -enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; - -/** - Formats a string and prints it to stdout using ANSI escape sequences - to specify color (experimental). - Example: - PrintColored(fmt::RED, "Elapsed time: {0:.2f} seconds") << 1.23; - */ -void print_colored(Color c, StringRef format, ArgList args); - -/** - \rst - Formats arguments and returns the result as a string. - - **Example**:: - - std::string message = format("The answer is {}", 42); - \endrst -*/ -inline std::string format(StringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - return w.str(); -} - -inline std::wstring format(WStringRef format_str, ArgList args) { - WMemoryWriter w; - w.write(format_str, args); - return w.str(); -} - -/** - \rst - Prints formatted data to the file *f*. - - **Example**:: - - print(stderr, "Don't {}!", "panic"); - \endrst - */ -void print(std::FILE *f, StringRef format_str, ArgList args); - -/** - \rst - Prints formatted data to ``stdout``. - - **Example**:: - - print("Elapsed time: {0:.2f} seconds", 1.23); - \endrst - */ -void print(StringRef format_str, ArgList args); - -/** - \rst - Prints formatted data to the stream *os*. - - **Example**:: - - print(cerr, "Don't {}!", "panic"); - \endrst - */ -void print(std::ostream &os, StringRef format_str, ArgList args); - -template -void printf(BasicWriter &w, BasicStringRef format, ArgList args) { - internal::PrintfFormatter().format(w, format, args); -} - -/** - \rst - Formats arguments and returns the result as a string. - - **Example**:: - - std::string message = fmt::sprintf("The answer is %d", 42); - \endrst -*/ -inline std::string sprintf(StringRef format, ArgList args) { - MemoryWriter w; - printf(w, format, args); - return w.str(); -} - -/** - \rst - Prints formatted data to the file *f*. - - **Example**:: - - fmt::fprintf(stderr, "Don't %s!", "panic"); - \endrst - */ -int fprintf(std::FILE *f, StringRef format, ArgList args); - -/** - \rst - Prints formatted data to ``stdout``. - - **Example**:: - - fmt::printf("Elapsed time: %.2f seconds", 1.23); - \endrst - */ -inline int printf(StringRef format, ArgList args) { - return fprintf(stdout, format, args); -} - -/** - Fast integer formatter. - */ -class FormatInt { - private: - // Buffer should be large enough to hold all digits (digits10 + 1), - // a sign and a null character. - enum {BUFFER_SIZE = std::numeric_limits::digits10 + 3}; - mutable char buffer_[BUFFER_SIZE]; - char *str_; - - // Formats value in reverse and returns the number of digits. - char *format_decimal(ULongLong value) { - char *buffer_end = buffer_ + BUFFER_SIZE - 1; - while (value >= 100) { - // Integer division is slow so do it for a group of two digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - unsigned index = (value % 100) * 2; - value /= 100; - *--buffer_end = internal::Data::DIGITS[index + 1]; - *--buffer_end = internal::Data::DIGITS[index]; - } - if (value < 10) { - *--buffer_end = static_cast('0' + value); - return buffer_end; - } - unsigned index = static_cast(value * 2); - *--buffer_end = internal::Data::DIGITS[index + 1]; - *--buffer_end = internal::Data::DIGITS[index]; - return buffer_end; - } - - void FormatSigned(LongLong value) { - ULongLong abs_value = static_cast(value); - bool negative = value < 0; - if (negative) - abs_value = 0 - abs_value; - str_ = format_decimal(abs_value); - if (negative) - *--str_ = '-'; - } - - public: - explicit FormatInt(int value) { FormatSigned(value); } - explicit FormatInt(long value) { FormatSigned(value); } - explicit FormatInt(LongLong value) { FormatSigned(value); } - explicit FormatInt(unsigned value) : str_(format_decimal(value)) {} - explicit FormatInt(unsigned long value) : str_(format_decimal(value)) {} - explicit FormatInt(ULongLong value) : str_(format_decimal(value)) {} - - /** - Returns the number of characters written to the output buffer. - */ - std::size_t size() const { return buffer_ - str_ + BUFFER_SIZE - 1; } - - /** - Returns a pointer to the output buffer content. No terminating null - character is appended. - */ - const char *data() const { return str_; } - - /** - Returns a pointer to the output buffer content with terminating null - character appended. - */ - const char *c_str() const { - buffer_[BUFFER_SIZE - 1] = '\0'; - return str_; - } - - /** - Returns the content of the output buffer as an `std::string`. - */ - std::string str() const { return std::string(str_, size()); } -}; - -// Formats a decimal integer value writing into buffer and returns -// a pointer to the end of the formatted string. This function doesn't -// write a terminating null character. -template -inline void format_decimal(char *&buffer, T value) { - typename internal::IntTraits::MainType abs_value = value; - if (internal::is_negative(value)) { - *buffer++ = '-'; - abs_value = 0 - abs_value; - } - if (abs_value < 100) { - if (abs_value < 10) { - *buffer++ = static_cast('0' + abs_value); - return; - } - unsigned index = static_cast(abs_value * 2); - *buffer++ = internal::Data::DIGITS[index]; - *buffer++ = internal::Data::DIGITS[index + 1]; - return; - } - unsigned num_digits = internal::count_digits(abs_value); - internal::format_decimal(buffer, abs_value, num_digits); - buffer += num_digits; -} -} - -#if FMT_GCC_VERSION -// Use the system_header pragma to suppress warnings about variadic macros -// because suppressing -Wvariadic-macros with the diagnostic pragma doesn't -// work. It is used at the end because we want to suppress as little warnings -// as possible. -# pragma GCC system_header -#endif - -// This is used to work around VC++ bugs in handling variadic macros. -#define FMT_EXPAND(args) args - -// Returns the number of arguments. -// Based on https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s. -#define FMT_NARG(...) FMT_NARG_(__VA_ARGS__, FMT_RSEQ_N()) -#define FMT_NARG_(...) FMT_EXPAND(FMT_ARG_N(__VA_ARGS__)) -#define FMT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N -#define FMT_RSEQ_N() 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 - -#define FMT_CONCAT(a, b) a##b -#define FMT_FOR_EACH_(N, f, ...) \ - FMT_EXPAND(FMT_CONCAT(FMT_FOR_EACH, N)(f, __VA_ARGS__)) -#define FMT_FOR_EACH(f, ...) \ - FMT_EXPAND(FMT_FOR_EACH_(FMT_NARG(__VA_ARGS__), f, __VA_ARGS__)) - -#define FMT_ADD_ARG_NAME(type, index) type arg##index -#define FMT_GET_ARG_NAME(type, index) arg##index - -#if FMT_USE_VARIADIC_TEMPLATES -# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ - template \ - ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ - const Args & ... args) { \ - using fmt::internal::Value; \ - const Value values[fmt::internal::NonZero::VALUE] = { \ - fmt::internal::MakeValue(args)... \ - }; \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ - fmt::internal::make_type(args...), values)); \ - } -#else -// Defines a wrapper for a function taking __VA_ARGS__ arguments -// and n additional arguments of arbitrary types. -# define FMT_WRAP(Char, ReturnType, func, call, n, ...) \ - template \ - inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ - FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF_##Char)}; \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ - } - -# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ - inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) { \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList()); \ - } \ - FMT_WRAP(Char, ReturnType, func, call, 1, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 2, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 3, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 4, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 5, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 6, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 7, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 8, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 9, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 10, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 11, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 12, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 13, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 14, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 15, __VA_ARGS__) -#endif // FMT_USE_VARIADIC_TEMPLATES - -/** - \rst - Defines a variadic function with the specified return type, function name - and argument types passed as variable arguments to this macro. - - **Example**:: - - void print_error(const char *file, int line, const char *format, - fmt::ArgList args) { - fmt::print("{}: {}: ", file, line); - fmt::print(format, args); - } - FMT_VARIADIC(void, print_error, const char *, int, const char *) - - ``FMT_VARIADIC`` is used for compatibility with legacy C++ compilers that - don't implement variadic templates. You don't have to use this macro if - you don't need legacy compiler support and can use variadic templates - directly:: - - template - void print_error(const char *file, int line, const char *format, - const Args & ... args) { - fmt::print("{}: {}: ", file, line); - fmt::print(format, args...); - } - \endrst - */ -#define FMT_VARIADIC(ReturnType, func, ...) \ - FMT_VARIADIC_(char, ReturnType, func, return func, __VA_ARGS__) - -#define FMT_VARIADIC_W(ReturnType, func, ...) \ - FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__) - -namespace fmt { -FMT_VARIADIC(std::string, format, StringRef) -FMT_VARIADIC_W(std::wstring, format, WStringRef) -FMT_VARIADIC(void, print, StringRef) -FMT_VARIADIC(void, print, std::FILE *, StringRef) -FMT_VARIADIC(void, print, std::ostream &, StringRef) -FMT_VARIADIC(void, print_colored, Color, StringRef) -FMT_VARIADIC(std::string, sprintf, StringRef) -FMT_VARIADIC(int, printf, StringRef) -FMT_VARIADIC(int, fprintf, std::FILE *, StringRef) -} - -// Restore warnings. -#if FMT_GCC_VERSION >= 406 -# pragma GCC diagnostic pop -#endif - -#ifdef __clang__ -# pragma clang diagnostic pop -#endif - -#ifdef FMT_HEADER_ONLY -# include "format.cc" -#endif - -#endif // FMT_FORMAT_H_ diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/grid/box.h b/src/Zigzag_persistence/example/ext_zz/dionysus/grid/box.h deleted file mode 100644 index 5602141cb8..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/grid/box.h +++ /dev/null @@ -1,136 +0,0 @@ -#ifndef BOX_H -#define BOX_H - -#include -#include - -#include "grid.h" -#include "vertices.h" - -namespace grid -{ - -namespace ba = boost::adaptors; - -template -class Box -{ - public: - typedef GridRef GridProxy; - typedef typename GridProxy::Vertex Position; - - struct InternalTest; - struct BoundaryTest; - struct BoundsTest; - struct PositionToVertex; - - class FreudenthalLinkIterator; - typedef boost::iterator_range FreudenthalLinkRange; - - typedef VerticesIterator VI; - typedef boost::transformed_range - > VertexRange; - - // Topology interface - typedef typename GridProxy::Index Vertex; - typedef boost::transformed_range - > Link; - - - Box(): g_(0, Position()) {} - Box(const Position& shape): - g_(0, shape), to_(shape - Position::one()) {} - Box(const Position& shape, - const Position& from, - const Position& to): - g_(0, shape), from_(from), to_(to) {} - - - const Position& from() const { return from_; } - const Position& to() const { return to_; } - Position& from() { return from_; } - Position& to() { return to_; } - Position shape() const { return to_ - from_ + Position::one(); } - const Position& grid_shape() const { return g_.shape(); } - static unsigned dimension() { return D; } - - size_t size() const { size_t c = 1; for (unsigned i = 0; i < D; ++i) c *= (to_[i] - from_[i] + 1); return c; } - - VertexRange vertices() const { return boost::iterator_range(VI::begin(from_, to_), VI::end(from_, to_)) - | ba::transformed(position_to_vertex()); } - Link link(const Position& p) const { return FreudenthalLinkRange(FreudenthalLinkIterator::begin(p), FreudenthalLinkIterator::end(p)) - | ba::filtered(bounds_test()) - | ba::transformed(position_to_vertex()); } - Link link(const Vertex& v) const { return link(position(v)); } - - Box intersect(const Box& other) const; - bool intersects(const Box& other) const; - void merge(const Box& other); - - bool contains(const Position& p) const; - bool contains(const Vertex& v) const { return contains(position(v)); } - - bool boundary(const Position& p, bool degenerate = false) const; - bool boundary(const Vertex& v, bool deg = false) const { return boundary(position(v), deg); } - Box side(unsigned axis, bool upper) const; - - InternalTest internal_test() const { return InternalTest(*this); } - BoundaryTest boundary_test() const { return BoundaryTest(*this); } - BoundsTest bounds_test() const { return BoundsTest(*this); } - PositionToVertex position_to_vertex() const { return PositionToVertex(*this); } - - - void swap(Box& other) { g_.swap(other.g_); std::swap(from_, other.from_); std::swap(to_, other.to_); } - - bool operator==(const Box& other) const { return from_ == other.from_ && to_ == other.to_; } - - template - friend std::basic_ostream& - operator<<(std::basic_ostream& out, const Box& b) { out << "Box: " << b.from_ << " - " << b.to_ << " inside " << b.g_.shape(); return out; } - - struct InternalTest - { - InternalTest(const Box& box): box_(box) {} - bool operator()(const Vertex& v) const { return !box_.boundary(v); } - const Box& box_; - }; - - struct BoundaryTest - { - BoundaryTest(const Box& box): box_(box) {} - bool operator()(const Vertex& v) const { return box_.boundary(v); } - const Box& box_; - }; - - struct BoundsTest - { - BoundsTest(const Box& box): box_(box) {} - bool operator()(const Position& p) const { return box_.contains(p); } - bool operator()(const Vertex& v) const { return box_.contains(v); } - const Box& box_; - }; - - struct PositionToVertex - { - typedef Vertex result_type; - PositionToVertex(const Box& box): box_(box) {} - Vertex operator()(Position p) const { for (unsigned i = 0; i < D; ++i) p[i] %= box_.grid_shape()[i]; return box_.g_.index(p); } - const Box& box_; - }; - - // computes position inside the box (adjusted for the wrap-around, if need be) - Position position(const Vertex& v) const { Position p = g_.vertex(v); for (unsigned i = 0; i < D; ++i) if (p[i] < from()[i]) p[i] += grid_shape()[i]; return p; } - - private: - GridProxy g_; - Position from_, to_; -}; - -} - -#include "box.hpp" - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/grid/box.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/grid/box.hpp deleted file mode 100644 index f3af50c047..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/grid/box.hpp +++ /dev/null @@ -1,141 +0,0 @@ -template -grid::Box -grid::Box:: -intersect(const Box& other) const -{ - Position from, to; - for (unsigned i = 0; i < D; ++i) - { - from[i] = std::max(from_[i], other.from_[i]); - to[i] = std::min(to_[i], other.to_[i]); - } - - return Box(g_, from, to); -} - -template -bool -grid::Box:: -intersects(const Box& other) const -{ - for (unsigned i = 0; i < D; ++i) - if (std::max(from_[i], other.from_[i]) > std::min(to_[i], other.to_[i])) - return false; - - return true; -} - -template -bool -grid::Box:: -contains(const Position& p) const -{ - for (unsigned i = 0; i < D; ++i) - if (p[i] > to_[i] || p[i] < from_[i]) - return false; - return true; -} - -template -bool -grid::Box:: -boundary(const Position& p, bool degenerate) const -{ - for (unsigned i = 0; i < D; ++i) - { - if (degenerate && from_[i] == to_[i]) continue; - if (p[i] == from_[i] || p[i] == to_[i]) - return true; - } - - return false; -} - -template -grid::Box -grid::Box:: -side(unsigned axis, bool upper) const -{ - Box res(*this); - - if (upper) - res.from()[axis] = res.to()[axis]; - else - res.to()[axis] = res.from()[axis]; - - return res; -} - -template -void -grid::Box:: -merge(const Box& other) -{ - for (unsigned i = 0; i < D; ++i) - { - from_[i] = std::min(from_[i], other.from_[i]); - to_[i] = std::max(to_[i], other.to_[i]); - } -} - -/* Box::FreudenthalLinkIterator */ -template -class grid::Box::FreudenthalLinkIterator: - public boost::iterator_facade -{ - typedef boost::iterator_facade Parent; - - - public: - typedef typename Parent::value_type value_type; - typedef typename Parent::difference_type difference_type; - typedef typename Parent::reference reference; - - FreudenthalLinkIterator(): loc_(0), dir_(0) {} - FreudenthalLinkIterator(const Position& p, int loc = 0, int dir = 1): - p_(p), v_(p), loc_(loc), dir_(dir) {} - - static FreudenthalLinkIterator - begin(const Position& p) { FreudenthalLinkIterator it(p); ++it; return it; } - static FreudenthalLinkIterator - end(const Position& p) { return FreudenthalLinkIterator(p, 0, -1); } - - private: - void increment(); - bool equal(const FreudenthalLinkIterator& other) const { return v_ == other.v_; } - reference dereference() const { return v_; } - - friend class ::boost::iterator_core_access; - - private: - Position p_, v_; - int loc_; - int dir_; -}; - -template -void -grid::Box::FreudenthalLinkIterator:: -increment() -{ - loc_ += dir_; - if (loc_ == (1 << D)) - { - dir_ = -1; - loc_ += dir_; - } - - for (unsigned i = 0; i < D; ++i) - if (loc_ & (1 << i)) - v_[i] = p_[i] + dir_; - else - v_[i] = p_[i]; -} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/grid/grid.h b/src/Zigzag_persistence/example/ext_zz/dionysus/grid/grid.h deleted file mode 100644 index c63fc7c598..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/grid/grid.h +++ /dev/null @@ -1,143 +0,0 @@ -#ifndef GRID_H -#define GRID_H - -#include "point.h" - -namespace grid -{ - -template -struct Grid; - -template -struct GridRef -{ - public: - typedef C Value; - - typedef Point Vertex; - typedef size_t Index; - - public: - template - GridRef(C* data, const Point& shape, bool c_order = true): - data_(data), shape_(shape), c_order_(c_order) { set_stride(); } - - GridRef(Grid& g): - data_(g.data()), shape_(g.shape()), - c_order_(g.c_order()) { set_stride(); } - - template - C operator()(const Point& v) const { return data_[v*stride_]; } - - template - C& operator()(const Point& v) { return data_[v*stride_]; } - - C operator()(Index i) const { return data_[i]; } - C& operator()(Index i) { return data_[i]; } - - const Vertex& - shape() const { return shape_; } - - const C* - data() const { return data_; } - C* data() { return data_; } - - // Set every element to the given value - GridRef& operator=(C value) { Index s = size(); for (Index i = 0; i < s; ++i) data_[i] = value; return *this; } - GridRef& operator/=(C value) { Index s = size(); for (Index i = 0; i < s; ++i) data_[i] /= value; return *this; } - - Vertex vertex(Index idx) const { Vertex v; for (unsigned i = 0; i < D; ++i) { v[i] = idx / stride_[i]; idx %= stride_[i]; } return v; } - Index index(const Vertex& v) const { return v*stride_; } - - Index size() const { return size(shape()); } - void swap(GridRef& other) { std::swap(data_, other.data_); std::swap(shape_, other.shape_); std::swap(stride_, other.stride_); } - - bool c_order() const { return c_order_; } - - protected: - static Index - size(const Vertex& v) { Index res = 1; for (unsigned i = 0; i < D; ++i) res *= v[i]; return res; } - - void set_stride() - { - Index cur = 1; - if (c_order_) - for (unsigned i = D; i > 0; --i) { stride_[i-1] = cur; cur *= shape_[i-1]; } - else - for (unsigned i = 0; i < D; ++i) { stride_[i] = cur; cur *= shape_[i]; } - - } - void set_shape(const Vertex& v) { shape_ = v; set_stride(); } - void set_data(C* data) { data_ = data; } - void set_c_order(bool order) { c_order_ = order; } - - private: - C* data_; - Vertex shape_; - Vertex stride_; - bool c_order_; -}; - - -template -struct Grid: public GridRef -{ - public: - typedef GridRef Parent; - typedef typename Parent::Value Value; - typedef typename Parent::Index Index; - typedef Parent Reference; - - template - struct rebind { typedef Grid type; }; - - public: - template - Grid(const Point& shape, bool c_order = true): - Parent(new C[size(shape)], shape, c_order) - {} - - Grid(const Parent& g): - Parent(new C[size(g.shape())], g.shape(), - g.c_order()) { copy_data(g.data()); } - - template - Grid(const OtherGrid& g): - Parent(new C[size(g.shape())], - g.shape(), - g.c_order()) { copy_data(g.data()); } - - ~Grid() { delete[] Parent::data(); } - - template - Grid& operator=(const GridRef& other) - { - delete[] Parent::data(); - Parent::set_c_order(other.c_order()); // NB: order needs to be set before the shape, to set the stride correctly - Parent::set_shape(other.shape()); - Index s = size(shape()); - Parent::set_data(new C[s]); - copy_data(other.data()); - return *this; - } - - using Parent::data; - using Parent::shape; - using Parent::operator(); - using Parent::operator=; - using Parent::size; - - private: - template - void copy_data(const OC* data) - { - Index s = size(shape()); - for (Index i = 0; i < s; ++i) - Parent::data()[i] = data[i]; - } -}; - -} - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/grid/point.h b/src/Zigzag_persistence/example/ext_zz/dionysus/grid/point.h deleted file mode 100644 index 0e867c34aa..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/grid/point.h +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef POINT_H -#define POINT_H - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -namespace grid -{ - -template -class Point: public boost::array, - private boost::addable< Point // Point + Point - , boost::subtractable< Point // Point - Point - , boost::dividable2< Point, Coordinate_ // Point / Coordinate - , boost::multipliable2< Point, Coordinate_ // Point * Coordinate, Coordinate * Point - > > > > -{ - public: - typedef Coordinate_ Coordinate; - typedef boost::array ArrayParent; - - typedef Point LPoint; - typedef Point UPoint; - - template - struct rebind { typedef Point type; }; - - public: - Point() { for (unsigned i = 0; i < D; ++i) (*this)[i] = 0; } - Point(const ArrayParent& a): - ArrayParent(a) {} - template Point(const Point& p) { for (size_t i = 0; i < D; ++i) (*this)[i] = p[i]; } - template Point(const T* a) { for (unsigned i = 0; i < D; ++i) (*this)[i] = a[i]; } - template Point(const std::vector& a) { for (unsigned i = 0; i < D; ++i) (*this)[i] = a[i]; } - - static - unsigned dimension() { return D; } - - static Point zero() { return Point(); } - static Point one() { Point p; for (unsigned i = 0; i < D; ++i) p[i] = 1; return p; } - - LPoint drop(int dim) const { LPoint p; unsigned c = 0; for (unsigned i = 0; i < D; ++i) { if (i == dim) continue; p[c++] = (*this)[i]; } return p; } - UPoint lift(int dim, Coordinate x) const { UPoint p; for (unsigned i = 0; i < D+1; ++i) { if (i < dim) p[i] = (*this)[i]; else if (i == dim) p[i] = x; else if (i > dim) p[i] = (*this)[i-1]; } return p; } - - using ArrayParent::operator[]; - - Point& operator+=(const Point& y) { for (unsigned i = 0; i < D; ++i) (*this)[i] += y[i]; return *this; } - Point& operator-=(const Point& y) { for (unsigned i = 0; i < D; ++i) (*this)[i] -= y[i]; return *this; } - Point& operator*=(Coordinate a) { for (unsigned i = 0; i < D; ++i) (*this)[i] *= a; return *this; } - Point& operator/=(Coordinate a) { for (unsigned i = 0; i < D; ++i) (*this)[i] /= a; return *this; } - - Point operator-() const { Point res; for (unsigned i = 0; i < D; ++i) res[i] = -(*this)[i]; return res; } - - Coordinate norm() const { return (*this)*(*this); } - - std::ostream& operator<<(std::ostream& out) const { out << (*this)[0]; for (unsigned i = 1; i < D; ++i) out << " " << (*this)[i]; return out; } - std::istream& operator>>(std::istream& in); - - friend - Coordinate operator*(const Point& x, const Point& y) { Coordinate n = 0; for (size_t i = 0; i < D; ++i) n += x[i] * y[i]; return n; } - - template - friend - Coordinate operator*(const Point& x, const Point& y) { Coordinate n = 0; for (size_t i = 0; i < D; ++i) n += x[i] * y[i]; return n; } - - private: - friend class boost::serialization::access; - - template - void serialize(Archive& ar, const unsigned int version) { ar & boost::serialization::base_object(*this); } -}; - -template -std::istream& -Point:: -operator>>(std::istream& in) -{ - std::string point_str; - in >> point_str; // read until ' ' - std::stringstream ps(point_str); - - char x; - for (unsigned i = 0; i < dimension(); ++i) - { - ps >> (*this)[i]; - ps >> x; - } - - return in; -} - - -template -Coordinate norm2(const Point& p) -{ Coordinate res = 0; for (unsigned i = 0; i < D; ++i) res += p[i]*p[i]; return res; } - -template -std::ostream& -operator<<(std::ostream& out, const Point& p) -{ return p.operator<<(out); } - -template -std::istream& -operator>>(std::istream& in, Point& p) -{ return p.operator>>(in); } - -} - -namespace opts -{ - template - struct Traits; - - template - struct Traits< grid::Point > - { - static - std::string type_string() { return "POINT"; } - }; -} - - -#endif // POINT_H diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/grid/vertices.h b/src/Zigzag_persistence/example/ext_zz/dionysus/grid/vertices.h deleted file mode 100644 index 339782e8c4..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/grid/vertices.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef VERTICES_H -#define VERTICES_H - -#include - -namespace grid -{ - -template -class VerticesIterator: - public boost::iterator_facade, - Vertex_, - boost::forward_traversal_tag, - Vertex_, - std::ptrdiff_t> -{ - typedef boost::iterator_facade Parent; - - - public: - typedef typename Parent::value_type value_type; - typedef typename Parent::difference_type difference_type; - typedef typename Parent::reference reference; - - typedef value_type Vertex; - typedef typename Vertex::Coordinate Coordinate; - - // upper bounds are non-inclusive - VerticesIterator(const Vertex& bounds): - to_(bounds - Vertex::one()) {} - - VerticesIterator(const Vertex& pos, - const Vertex& bounds): - pos_(pos), to_(bounds - Vertex::one()) {} - - VerticesIterator(const Vertex& pos, - const Vertex& from, - const Vertex& to): - pos_(pos), from_(from), - to_(to) {} - - - static VerticesIterator - begin(const Vertex& bounds) { return VerticesIterator(bounds); } - static VerticesIterator - end(const Vertex& bounds) { Vertex e; e[0] = bounds[0]; return VerticesIterator(e, bounds); } - - static VerticesIterator - begin(const Vertex& from, const Vertex& to) { return VerticesIterator(from, from, to); } - static VerticesIterator - end(const Vertex& from, const Vertex& to) { Vertex e = from; e[0] = to[0] + 1; return VerticesIterator(e, from, to); } - - private: - void increment(); - bool equal(const VerticesIterator& other) const { return pos_ == other.pos_; } - reference dereference() const { return pos_; } - - friend class ::boost::iterator_core_access; - - private: - Vertex pos_; - Vertex from_; - Vertex to_; -}; - -} - -template -void -grid::VerticesIterator:: -increment() -{ - unsigned j = Vertex::dimension() - 1; - while (j > 0 && pos_[j] == to_[j]) - { - pos_[j] = from_[j]; - --j; - } - ++pos_[j]; -} - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/matrix-filtration.h b/src/Zigzag_persistence/example/ext_zz/dionysus/matrix-filtration.h deleted file mode 100644 index 516f27b2d1..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/matrix-filtration.h +++ /dev/null @@ -1,120 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace dionysus -{ - - -template -class MatrixFiltrationCell; - - -// adapt Matrix as a Filtration to make it possible to feed into reduction algorithms -template -class MatrixFiltration -{ - public: - using Matrix = Matrix_; - using CellValue = CellValue_; - using Dimensions = std::vector; - using Values = std::vector; - using Cell = MatrixFiltrationCell; - - - public: - MatrixFiltration(Matrix m, Dimensions dimensions, Values values): - m_(std::move(m)), - dimensions_(dimensions), - values_(values) { assert(m_->size() == dimensions_.size()); assert(m_->size() == values_.size()); } - - Cell operator[](size_t i) const { return Cell(this, i); } - size_t size() const { return m_.size(); } - - size_t index(const Cell& c) const; - - Cell begin() const { return Cell(this, 0); } - Cell end() const { return Cell(this, size()); } - - const Dimensions& dimensions() const { return dimensions_; } - const Values& values() const { return values_; } - - private: - Matrix m_; - Dimensions dimensions_; - Values values_; - - friend class MatrixFiltrationCell; -}; - - -template -class MatrixFiltrationCell -{ - public: - using MatrixFiltration = MatrixFiltration_; - using Matrix = typename MatrixFiltration::Matrix; - using Data = typename MatrixFiltration::CellValue; - using Field = typename Matrix::Field; - - template - using Entry = ChainEntry; - - template - using BoundaryChain = std::vector>; - - public: - MatrixFiltrationCell(const MatrixFiltration* mf, size_t i): - mf_(mf), i_(i) {} - - short unsigned dimension() const { return mf_->dimensions_[i_]; } - const Data& data() const { return mf_->values_[i_]; } - - bool operator==(const MatrixFiltrationCell& other) const { return i_ == other.i_; } - bool operator!=(const MatrixFiltrationCell& other) const { return i_ != other.i_; } - - BoundaryChain<> boundary() const - { - BoundaryChain<> bdry; - for (auto& entry : (mf_->m_)[i_]) - bdry.emplace_back(Entry<> { entry.e, MatrixFiltrationCell(mf_, entry.i) }); - return bdry; - } - - template - BoundaryChain boundary(const Field_& field) const - { - BoundaryChain bdry; - for (auto& entry : (mf_->m_)[i_]) - bdry.emplace_back(Entry { field.init(entry.e), MatrixFiltrationCell(mf_, entry.i) }); - return bdry; - } - - // iterator interface - MatrixFiltrationCell operator++(int) { MatrixFiltrationCell copy = *this; i_++; return copy; } - MatrixFiltrationCell& operator++() { ++i_; return *this; } - - const MatrixFiltrationCell& operator*() const { return *this; } - MatrixFiltrationCell& operator*() { return *this; } - - size_t i() const { return i_; } - - friend - std::ostream& operator<<(std::ostream& out, const MatrixFiltrationCell& c) - { out << c.i_; return out; } - - private: - const MatrixFiltration* mf_ = nullptr; - size_t i_; -}; - -template -size_t -MatrixFiltration::index(const Cell& c) const -{ - return c.i(); -} - -} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/omni-field-persistence.h b/src/Zigzag_persistence/example/ext_zz/dionysus/omni-field-persistence.h deleted file mode 100644 index 3d83d4ae44..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/omni-field-persistence.h +++ /dev/null @@ -1,145 +0,0 @@ -#ifndef DIONYSUS_OMNI_FIELD_REDUCTION_H -#define DIONYSUS_OMNI_FIELD_REDUCTION_H - -#include -#include - -#include "reduction.h" // for unpaired -#include "fields/q.h" -#include "fields/zp.h" -#include "chain.h" - -namespace dionysus -{ - -template, class Q_ = ::dionysus::Q<>, class Zp_ = ::dionysus::ZpField> -class OmniFieldPersistence -{ - public: - using Index = Index_; - using Q = Q_; - using Field = Q; - using Comparison = Comparison_; - - using BaseElement = typename Q::BaseElement; - using Zp = Zp_; - using Zps = std::unordered_map; - - using QElement = typename Q::Element; - using QEntry = ChainEntry; - using QChain = std::vector; - - using ZpElement = typename Zp::Element; - using ZpEntry = ChainEntry; - using ZpChain = std::vector; - - using QChains = std::vector; - using ZpChains = std::unordered_map>; - - using QLows = std::unordered_map; - using ZpLows = std::unordered_map>; - - using QPairs = std::vector; - using ZpPairs = std::unordered_map>; - - using Factors = std::vector; - - using Specials = std::unordered_map>; - - const Field& field() const { return q_; } - - void sort(QChain& c) { std::sort(c.begin(), c.end(), - [this](const QEntry& e1, const QEntry& e2) - { return this->cmp_(e1.index(), e2.index()); }); } - - template - void add(const ChainRange& chain) { return add(QChain(std::begin(chain), std::end(chain))); } - void add(QChain&& chain); - - void reserve(size_t s) { q_chains_.reserve(s); q_pairs_.reserve(s); } - size_t size() const { return q_pairs_.size(); } - - void reduce(ZpChain& zp_chain, BaseElement p); - ZpChain convert(const QChain& c, const Zp& field) const; - bool special(Index i, BaseElement p) const { auto it = zp_chains_.find(i); if (it == zp_chains_.end()) return false; if (it->second.find(p) == it->second.end()) return false; return true; } - Specials specials() const - { - Specials specials; - for (auto& x : zp_chains_) - for (auto& y : x.second) - specials[x.first].push_back(y.first); - return specials; - } - - const Zp& zp(BaseElement p) const { auto it = zps_.find(p); if (it != zps_.end()) return it->second; return zps_.emplace(p, Zp(p)).first->second; } - - static Factors factor(BaseElement x); - - const QChains& q_chains() const { return q_chains_; } - const ZpChains& zp_chains() const { return zp_chains_; } - - // This is a bit of a hack; it takes advantage of the fact that zp(p) - // generates field on-demand and memoizes them. So there is an entry in - // zps_ only if something special happened over the prime. - Factors primes() const { Factors result; result.reserve(zps_.size()); for (auto& x : zps_) result.push_back(x.first); return result; } - - // TODO: no skip support for now - bool skip(Index) const { return false; } - void add_skip() {} - void set_skip(Index, bool flag = true) {} - - Index pair(Index i, BaseElement p) const; - void set_pair(Index i, Index j); - void set_pair(Index i, Index j, BaseElement p); - static const Index unpaired() { return Reduction::unpaired; } - - private: - QChains q_chains_; - ZpChains zp_chains_; - - QLows q_lows_; - ZpLows zp_lows_; - - QPairs q_pairs_; - ZpPairs zp_pairs_; - - Q q_; - mutable Zps zps_; - - Comparison cmp_; -}; - -// Make OmniFieldPersistence act like a ReducedMatrix (e.g., for the purpose of constructing a persistence diagram) -template -struct PrimeAdapter -{ - using Persistence = OmniFieldPersistence; - using Prime = typename Persistence::BaseElement; - using Index = typename Persistence::Index; - - PrimeAdapter(const Persistence& persistence, Prime p): - persistence_(persistence), p_(p) {} - - bool skip(Index i) const { return persistence_.skip(i); } - - size_t size() const { return persistence_.size(); } - Index pair(Index i) const { return persistence_.pair(i, p_); } - static const Index unpaired() { return Persistence::unpaired(); } - - const Persistence& persistence_; - Prime p_; -}; - -template -PrimeAdapter -prime_adapter(const OmniFieldPersistence& persistence, - typename PrimeAdapter::Prime p) -{ - return PrimeAdapter(persistence, p); -} - -} // dionysus - -#include "omni-field-persistence.hpp" - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/omni-field-persistence.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/omni-field-persistence.hpp deleted file mode 100644 index 68d5fbede7..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/omni-field-persistence.hpp +++ /dev/null @@ -1,250 +0,0 @@ -template -void -dionysus::OmniFieldPersistence:: -add(QChain&& chain) -{ - sort(chain); - - q_chains_.emplace_back(std::move(chain)); - q_pairs_.emplace_back(unpaired()); - Index i = q_chains_.size() - 1; - - QChain& c = q_chains_.back(); - - auto reduce = [this,&c,i](BaseElement p) - { - auto zp_chain = convert(c, zp(p)); - - this->reduce(zp_chain, p); - - if (!zp_chain.empty()) - { - auto l = zp_chain.back().index(); - zp_lows_[l].emplace(p,i); - set_pair(l,i,p); - } - - zp_chains_[i].emplace(p, std::move(zp_chain)); // empty chain is still a valid indicator that we don't need to bother with this field - }; - - // reduce - auto entry_cmp = [this](const QEntry& e1, const QEntry& e2) { return this->cmp_(e1.index(), e2.index()); }; - while (!c.empty()) - { - auto& low = c.back(); - - auto e = low.element(); - auto l = low.index(); - assert(!q_.is_zero(e)); - if (e != q_.id()) - { - auto factors = factor(q_.numerator(e)); - for (auto p : factors) - { - if (!special(i, p)) // there is already a dedicated column over p - reduce(p); - } - } - - auto it_zp = zp_lows_.find(l); - if (it_zp != zp_lows_.end()) - for (auto& x : it_zp->second) - { - auto p = x.first; - if (!special(i,p)) - reduce(p); - } - - auto it_q = q_lows_.find(l); - if (it_q != q_lows_.end()) - { - Index j = it_q->second; - - // add the primes from j to i - auto it_zp = zp_chains_.find(j); - if (it_zp != zp_chains_.end()) - for (auto& x : it_zp->second) - { - auto p = x.first; - if (!special(i,p)) - reduce(p); - } - - // reduce over Q - auto j_chain = q_chains_[j]; - auto j_e = j_chain.back().element(); - - auto m = q_.neg(q_.div(e,j_e)); - Chain::addto(c, m, j_chain, q_, entry_cmp); - assert(c.empty() || !q_.is_zero(c.back().element())); - } else - { - q_lows_.emplace(l,i); - set_pair(l,i); - break; - } - } -} - -template -void -dionysus::OmniFieldPersistence:: -reduce(ZpChain& zp_chain, BaseElement p) -{ - auto& field = zp(p); - - auto entry_cmp = [this](const ZpEntry& e1, const ZpEntry& e2) { return this->cmp_(e1.index(), e2.index()); }; - - while (!zp_chain.empty()) - { - auto& low = zp_chain.back(); - auto j = low.index(); - - auto it = zp_lows_.find(j); - if (it != zp_lows_.end()) - { - auto it2 = it->second.find(p); - if (it2 != it->second.end()) - { - const ZpChain& co = zp_chains_[it2->second][p]; - - auto m = field.neg(field.div(low.element(), co.back().element())); - assert(m < p); - Chain::addto(zp_chain, m, co, field, entry_cmp); - continue; - } - } - - auto qit = q_lows_.find(j); - if (qit == q_lows_.end() || special(qit->second, p)) // no valid pivot over Q - return; - - // TODO: this could be optimized (add and convert on the fly) - auto& q_chain = q_chains_[qit->second]; - assert(q_chain.empty() || !q_.is_zero(q_chain.back().element())); - - auto co = convert(q_chain, field); - auto m = field.neg(field.div(low.element(), co.back().element())); - Chain::addto(zp_chain, m, co, field, entry_cmp); - - assert(!zp_chain.empty() || zp_chain.back().index() != j); - } -} - -template -typename dionysus::OmniFieldPersistence::ZpChain -dionysus::OmniFieldPersistence:: -convert(const QChain& c, const Zp& field) const -{ - ZpChain result; - result.reserve(c.size()); - auto p = field.prime(); - for (auto& x : c) - { - auto num = q_.numerator(x.element()) % p; - if (num != 0) - { - while (num < 0) num += p; - auto denom = q_.denominator(x.element()) % p; - while (denom < 0) denom += p; - assert(denom % p != 0); - result.emplace_back(field.div(num, denom), x.index()); - } - } - return result; -} - - -template -typename dionysus::OmniFieldPersistence::Factors -dionysus::OmniFieldPersistence:: -factor(BaseElement x) -{ - if (x < 0) - x = -x; - Factors result; - - if (Q::is_prime(x)) - { - result.push_back(x); - return result; - } - - BaseElement p { 2 }; - while (p*p <= x) - { - if (x % p == 0) - { - result.push_back(p); - do { x /= p; } while (x % p == 0); - if (Q::is_prime(x)) - { - result.push_back(x); - break; - } - } - ++p; - } - if (x > 1) - result.push_back(x); - - return result; -} - -template -typename dionysus::OmniFieldPersistence::Index -dionysus::OmniFieldPersistence:: -pair(Index i, BaseElement p) const -{ - if (p == 1) - return q_pairs_[i]; - else - { - auto it = zp_pairs_.find(p); - if (it == zp_pairs_.end()) - return q_pairs_[i]; - else - { - auto pit = it->second.find(i); - if (pit == it->second.end()) - return q_pairs_[i]; - else - return pit->second; - } - } -} - -template -void -dionysus::OmniFieldPersistence:: -set_pair(Index i, Index j, BaseElement p) -{ - auto& pairs = zp_pairs_[p]; - pairs[i] = j; - pairs[j] = i; -} - -template -void -dionysus::OmniFieldPersistence:: -set_pair(Index i, Index j) -{ - q_pairs_[i] = j; - q_pairs_[j] = i; - - auto it = zp_chains_.find(j); - if (it == zp_chains_.end()) - return; - - auto& chains = it->second; - for (auto& x : chains) - { - auto p = x.first; - auto& chain = x.second; - if (chain.empty()) - { - zp_pairs_[p][j] = unpaired(); - zp_pairs_[p][i] = unpaired(); - } - } -} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/opts/opts.h b/src/Zigzag_persistence/example/ext_zz/dionysus/opts/opts.h deleted file mode 100644 index 1a9bbf71bf..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/opts/opts.h +++ /dev/null @@ -1,499 +0,0 @@ -/** - * Author: Dmitriy Morozov - * The interface is heavily influenced by GetOptPP (https://code.google.com/p/getoptpp/). - * The parsing logic is from ProgramOptions.hxx (https://github.com/Fytch/ProgramOptions.hxx). - * - * History: - * - 2015-06-01: added Traits<...>::type_string() for long, unsigned long - * - ... - * - 2018-04-27: replace parsing logic with the one from ProgramOptions.hxx to - * make the parser compliant with [GNU Program Argument Syntax - * Conventions](https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html) - * - 2018-05-11: add dashed_non_option(), to accept arguments that are negative numbers - */ - -#ifndef OPTS_OPTS_H -#define OPTS_OPTS_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace opts { - -// Converters -template -struct Converter -{ - Converter() {} - static - bool convert(const std::string& val, T& res) - { - std::istringstream iss(val); - iss >> res; - return !iss.fail() && iss.eof(); - } -}; - -// Type -template -struct Traits -{ - static std::string type_string() { return "UNKNOWN TYPE"; } -}; - -template<> -struct Traits -{ - static std::string type_string() { return "INT"; } -}; - -template<> -struct Traits -{ - static std::string type_string() { return "SHORT INT"; } -}; - -template<> -struct Traits -{ - static std::string type_string() { return "LONG"; } -}; - -template<> -struct Traits -{ - static std::string type_string() { return "UNSIGNED INT"; } -}; - -template<> -struct Traits -{ - static std::string type_string() { return "SHORT UNSIGNED INT"; } -}; - -template<> -struct Traits -{ - static std::string type_string() { return "UNSIGNED LONG"; } -}; - -template<> -struct Traits -{ - static std::string type_string() { return "FLOAT"; } -}; - -template<> -struct Traits -{ - static std::string type_string() { return "DOUBLE"; } -}; - -template<> -struct Traits -{ - static std::string type_string() { return "STRING"; } -}; - - -struct BasicOption -{ - using IsShort = std::function; - - BasicOption(char s_, - std::string l_, - std::string default_, - std::string type_, - std::string help_): - s(s_), l(l_), d(default_), t(type_), help(help_) {} - virtual ~BasicOption() {} - - int long_size() const { return l.size() + 1 + t.size(); } - - void output(std::ostream& out, int max_long) const - { - out << " "; - if (s) - out << '-' << s << ", "; - else - out << " "; - - out << "--" << l << ' '; - - if (!t.empty()) - out << t; - - for (int i = long_size(); i < max_long; ++i) - out << ' '; - - out << " " << help; - - if (!d.empty()) - { - out << " [default: " << d << "]"; - } - out << '\n'; - } - - virtual bool flag() const { return false; } - virtual bool parse(int argc, char** argv, int& i, int j, IsShort is_short); - virtual bool set(std::string arg) =0; - - char s; - std::string l; - std::string d; - std::string t; - std::string help; -}; - -// Option -template -struct OptionContainer: public BasicOption -{ - OptionContainer(char s_, - const std::string& l_, - T& var_, - const std::string& help_, - const std::string& type_ = Traits::type_string()): - BasicOption(s_, l_, default_value(var_), type_, help_), - var(&var_) {} - - static - std::string default_value(const T& def) - { - std::ostringstream oss; - oss << def; - return oss.str(); - } - - bool set(std::string s) override { return Converter::convert(s, *var); } - - T* var; -}; - -template<> -struct OptionContainer: public BasicOption -{ - OptionContainer(char s_, - const std::string& l_, - bool& var_, - const std::string& help_): - BasicOption(s_, l_, "", "", help_), - var(&var_) { *var = false; } - - bool parse(int, char**, int&, int, IsShort) override { *var = true; return true; } - bool set(std::string) override { return true; } - bool flag() const override { return true; } - - bool* var; -}; - -template -struct OptionContainer< std::vector >: public BasicOption -{ - OptionContainer(char s_, - const std::string& l_, - std::vector& var_, - const std::string& help_, - const std::string& type_ = "SEQUENCE"): - BasicOption(s_, l_, default_value(var_), type_, help_), - var(&var_), first(true) { } - - static - std::string default_value(const std::vector& def) - { - std::ostringstream oss; - oss << "("; - if (def.size()) - oss << def[0]; - for (size_t i = 1; i < def.size(); ++i) - oss << ", " << def[i]; - oss << ")"; - return oss.str(); - } - - bool set(std::string s) override - { - if (first) - { - var->clear(); - first = false; - } - - T x; - bool result = Converter::convert(s,x); - var->emplace_back(std::move(x)); - return result; - } - - std::vector* var; - mutable bool first; -}; - - -template -std::unique_ptr -Option(char s, const std::string& l, T& var, const std::string& help) { return std::unique_ptr{new OptionContainer(s, l, var, help)}; } - -template -std::unique_ptr -Option(char s, const std::string& l, T& var, - const std::string& type, const std::string& help) { return std::unique_ptr{new OptionContainer(s, l, var, help, type)}; } - -template -std::unique_ptr -Option(const std::string& l, T& var, const std::string& help) { return std::unique_ptr{new OptionContainer(0, l, var, help)}; } - -template -std::unique_ptr -Option(const std::string& l, T& var, - const std::string& type, const std::string& help) { return std::unique_ptr{new OptionContainer(0, l, var, help, type)}; } - -// PosOption -template -struct PosOptionContainer -{ - PosOptionContainer(T& var_): - var(&var_) {} - - bool parse(std::list& args) const - { - if (args.empty()) - return false; - - bool result = Converter::convert(args.front(), *var); - if (!result) - std::cerr << "error: failed to parse " << args.front() << '\n'; - args.pop_front(); - return result; - } - - T* var; -}; - -template -PosOptionContainer -PosOption(T& var) { return PosOptionContainer(var); } - - -// Options -struct Options -{ - Options(): - failed(false) {} - - inline - Options& operator>>(std::unique_ptr opt); - template - Options& operator>>(const PosOptionContainer& poc); - - operator bool() { return !failed; } - - - friend - std::ostream& - operator<<(std::ostream& out, const Options& ops) - { - int max_long = 0; - for (auto& cur : ops.options) - { - int cur_long = cur->long_size(); - if (cur_long > max_long) - max_long = cur_long; - } - - out << "Options:\n"; - for (auto& cur : ops.options) - cur->output(out, max_long); - - return out; - } - - bool parse(int argc, char** argv); - - void unrecognized_option(std::string arg) const - { - std::cerr << "error: unrecognized option " << arg << '\n'; - } - - static bool dashed_non_option(char* arg, BasicOption::IsShort is_short) - { - return arg[ 0 ] == '-' - && (std::isdigit(arg[ 1 ]) || arg[ 1 ] == '.') - && !is_short(arg[ 1 ]); - } - - private: - std::list args; - std::list> options; - bool failed; -}; - -bool -BasicOption::parse(int argc, char** argv, int& i, int j, IsShort is_short) -{ - char* argument; - char* cur_arg = argv[i]; - // -v... - if (argv[i][j] == '\0') - { - // -v data - if (i + 1 < argc && (argv[i+1][0] != '-' || Options::dashed_non_option(argv[i+1], is_short))) - { - ++i; - argument = argv[i]; - } else - { - std::cerr << "error: cannot find the argument; ignoring " << argv[i] << '\n'; - return false; - } - } else if (argv[i][j] == '=') - { - // -v=data - argument = &argv[i][j+1]; - } else if( j == 2 ) { // only for short options - // -vdata - argument = &argv[i][j]; - } else - { - std::cerr << "error: unexpected character \'" << argv[i][j] << "\' ignoring " << argv[i] << '\n'; - return false; - } - bool result = set(argument); - if (!result) - std::cerr << "error: failed to parse " << argument << " in " << cur_arg << '\n'; - return result; -} - -bool -Options::parse(int argc, char** argv) -{ - std::map short_opts; - std::map long_opts; - - for (auto& opt : options) - { - if (opt->s) - short_opts[opt->s] = opt.get(); - - long_opts[opt->l] = opt.get(); - } - - auto is_short = [&short_opts](char c) -> bool { return short_opts.find(c) != short_opts.end(); }; - - for (int i = 1; i < argc; ++i) - { - if( argv[ i ][ 0 ] == '\0' ) - continue; - if( argv[ i ][ 0 ] != '-' || dashed_non_option(argv[i], is_short)) - args.push_back(argv[i]); - else - { - // -... - if( argv[ i ][ 1 ] == '\0' ) - { - // - - args.push_back(argv[i]); - } else if( argv[ i ][ 1 ] == '-' ) - { - if( argv[ i ][ 2 ] == '\0' ) - { - // -- - while( ++i < argc ) - args.push_back(argv[i]); - } else { - // --... - char* first = &argv[ i ][ 2 ]; - char* last = first; - for(; *last != '=' && *last != '\0'; ++last); - if (first == last) - { - failed = true; - unrecognized_option(argv[i]); - } else - { - auto opt_it = long_opts.find(std::string{first,last}); - if (opt_it == long_opts.end()) - { - failed = true; - unrecognized_option(argv[i]); - } else - { - failed |= !opt_it->second->parse(argc, argv, i, last - argv[i], is_short); - } - } - } - } else - { - // -f... - auto opt_it = short_opts.find(argv[i][1]); - if (opt_it == short_opts.end()) - { - failed = true; - unrecognized_option(argv[i]); - } else if (opt_it->second->flag()) - { - opt_it->second->parse(argc, argv, i, 0, is_short); // arguments are meaningless; just sets the flag - - // -fgh - char c; - for(int j = 1; (c = argv[i][j]) != '\0'; ++j) - { - if (!std::isprint(c) || c == '-') - { - failed = true; - std::cerr << "error: invalid character\'" << c << " ignoring " << &argv[i][j] << '\n'; - break; - } - opt_it = short_opts.find(c); - if (opt_it == short_opts.end()) - { - failed = true; - unrecognized_option("-" + std::string(1, c)); - continue; - } - if (!opt_it->second->flag()) - { - failed = true; - std::cerr << "error: non-void options not allowed in option packs; ignoring " << c << '\n'; - continue; - } - opt_it->second->parse(argc, argv, i, 0, is_short); // arguments are meaningless; just sets the flag - } - } else - { - failed |= !opt_it->second->parse(argc, argv, i, 2, is_short); - } - } - } - } - - return !failed; -} - -Options& -Options::operator>>(std::unique_ptr opt) -{ - options.emplace_back(std::move(opt)); - return *this; -} - -template -Options& -Options::operator>>(const PosOptionContainer& poc) -{ - if (!failed) - failed = !poc.parse(args); - return *this; -} - -} - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/ordinary-persistence.h b/src/Zigzag_persistence/example/ext_zz/dionysus/ordinary-persistence.h deleted file mode 100644 index 5f26bd2a1b..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/ordinary-persistence.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef DIONYSUS_ORDINARY_PERSISTENCE_H -#define DIONYSUS_ORDINARY_PERSISTENCE_H - -#include "reduced-matrix.h" - -namespace dionysus -{ - -/* Move this into a ReducedMatrix class */ - -// Ordinary D -> R reduction -template, - template class... Visitors> -using OrdinaryPersistence = ReducedMatrix; - -// No negative optimization -template> -struct NoNegative -{ - template - struct Visitor: public EmptyVisitor - { - template - void chain_initialized(Self* matrix, Chain& c) - { - for (auto cur = std::begin(c); cur != std::end(c); ++cur) - { - Index i = cur->index(); - Index p = matrix->pair(i); - if (!(p == Self::unpaired() || (*matrix)[i].empty())) - c.erase(cur--); - } - } - }; - - template - using V2 = EmptyVisitor; -}; - -template, - template class... Visitors> -using OrdinaryPersistenceNoNegative = ReducedMatrix::template Visitor, - Visitors...>; - -// TODO: add clearing optimization (possibly bake it into the code itself) - -template, - template class... Visitors> -using FastPersistence = ReducedMatrix::template Visitor, - //Clearing::template Visitor, // FIXME - Visitors...>; - - -} - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/pair-recorder.h b/src/Zigzag_persistence/example/ext_zz/dionysus/pair-recorder.h deleted file mode 100644 index 81c066bda6..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/pair-recorder.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef DIONYSUS_PAIR_RECORDER_H -#define DIONYSUS_PAIR_RECORDER_H - -namespace dionysus -{ - -template -struct PairRecorder: public Persistence_ -{ - typedef Persistence_ Persistence; - typedef typename Persistence::Index Index; - - - using Persistence::Persistence; - - template - Index add(const ChainRange& chain) - { - Index p = Persistence::add(chain); - pairs_.push_back(p); - if (p != unpaired()) - pairs_[p] = pairs_.size() - 1; - - return p; - } - - Index pair(Index i) const { return pairs_[i]; } - - void resize(size_t s) { Persistence::resize(s); pairs_.resize(s, unpaired()); } - size_t size() const { return pairs_.size(); } - static const Index unpaired() { return Reduction::unpaired; } - - std::vector pairs_; -}; - -template -struct PairChainRecorder: public PairRecorder -{ - using Persistence = Persistence_; - using Parent = PairRecorder; - using Index = typename Persistence_::Index; - using Chain = typename Persistence_::Chain; - - using Parent::Parent; - - template - Index add(const ChainRange& chain) - { - auto p_chain = Persistence::add(chain, keep_cocycles); - Index p = std::get<0>(p_chain); - - pairs_.push_back(p); - chains_.emplace_back(); - - if (p != unpaired()) - { - pairs_[p] = pairs_.size() - 1; - chains_[p] = std::move(std::get<1>(p_chain)); - } - - return p; - } - - using Parent::unpaired; - - Index pair(Index i) const { return pairs_[i]; } - const Chain& chain(Index i) const { return chains_[i]; } // chain that dies at i - void resize(size_t s) { Parent::resize(s); chains_.resize(s); } - - std::vector chains_; - using Parent::pairs_; - - bool keep_cocycles = true; -}; - -} - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/reduced-matrix.h b/src/Zigzag_persistence/example/ext_zz/dionysus/reduced-matrix.h deleted file mode 100644 index f7a04b130d..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/reduced-matrix.h +++ /dev/null @@ -1,170 +0,0 @@ -#ifndef DIONYSUS_REDUCED_MATRIX_H -#define DIONYSUS_REDUCED_MATRIX_H - -#include -#include - -#include "chain.h" -#include "reduction.h" - -namespace dionysus -{ - -template, template class... Visitors> -class ReducedMatrix -{ - public: - typedef ReducedMatrix Self; - - typedef Field_ Field; - typedef Index_ Index; - typedef Comparison_ Comparison; - - typedef std::tuple...> VisitorsTuple; - template - using Visitor = std::tuple_element; - - typedef typename Field::Element FieldElement; - typedef ChainEntry Entry; - typedef std::vector Chain; - - typedef std::vector Chains; - typedef std::vector Indices; - typedef std::vector SkipFlags; - - public: - ReducedMatrix(const Field& field): - field_(field) {} - - ReducedMatrix(const Field& field, - const Comparison& cmp, - const Visitors&... visitors): - field_(field), - cmp_(cmp), - visitors_(visitors...) {} - - ReducedMatrix(Field&& field, - Comparison&& cmp, - Visitors&&... visitors): - field_(std::move(field)), - cmp_(std::move(cmp)), - visitors_(visitors...) {} - - ReducedMatrix(Self&& m) = default; - ReducedMatrix(const Self& m) = default; - - template class... OtherVisitors> - ReducedMatrix(ReducedMatrix&& other): - field_(other.field_), - cmp_(other.cmp_), - reduced_(std::move(other.reduced_)), - pairs_(std::move(other.pairs_)), - skip_(std::move(other.skip_)) {} - - template - Index add(const ChainRange& chain) { return add(Chain(std::begin(chain), std::end(chain))); } - Index add(Chain&& chain); - - template - void set(Index i, const ChainRange& chain) { return set(i, Chain(std::begin(chain), std::end(chain))); } - void set(Index i, Chain&& chain); - - Index reduce(Index i); - Index reduce(Chain& c) { return reduce(c, reduced_, pairs_); } - template - Index reduce(Chain& c, const ChainsLookup& chains, const LowLookup& low); - - Index reduce_upto(Index i); // TODO - - size_t size() const { return pairs_.size(); } - void clear() { Chains().swap(reduced_); Indices().swap(pairs_); } - - void sort(Chain& c) { std::sort(c.begin(), c.end(), [this](const Entry& e1, const Entry& e2) { return this->cmp_(e1.index(), e2.index()); }); } - - const Chain& operator[](Index i) const { return reduced_[i]; } - Index pair(Index i) const { return pairs_[i]; } - void set_pair(Index i, Index j) { pairs_[i] = j; pairs_[j] = i; } - - Chain& column(Index i) { return reduced_[i]; } - - bool skip(Index i) const { return skip_[i]; } - void add_skip(); - void set_skip(Index i, bool flag = true) { skip_[i] = flag; } - - const Field& field() const { return field_; } - const Comparison& cmp() const { return cmp_; } - void reserve(size_t s) { reduced_.reserve(s); pairs_.reserve(s); } - void resize(size_t s); - - const Chains& columns() const { return reduced_; } - - template - Visitor& visitor() { return std::get(visitors_); } - - static const Index unpaired() { return Reduction::unpaired; } - - private: - template class... Vs> - friend class ReducedMatrix; // let's all be friends - - public: - // Visitors::chain_initialized(c) - template - typename std::enable_if::type - visitors_chain_initialized(Chain& c) {} - - template - typename std::enable_if::type - visitors_chain_initialized(Chain& c) { std::get(visitors_).chain_initialized(this, c); visitors_chain_initialized(c); } - - // Visitors::addto(m, cl) - template - typename std::enable_if::type - visitors_addto(FieldElement m, Index cl) {} - - template - typename std::enable_if::type - visitors_addto(FieldElement m, Index cl) { std::get(visitors_).addto(this, m, cl); visitors_addto(m, cl); } - - // Visitors::reduction_finished(m, cl) - template - typename std::enable_if::type - visitors_reduction_finished() {} - - template - typename std::enable_if::type - visitors_reduction_finished() { std::get(visitors_).reduction_finished(this); visitors_reduction_finished(); } - - private: - Field field_; - Comparison cmp_; - Chains reduced_; // matrix R - Indices pairs_; - SkipFlags skip_; // indicates whether the column should be skipped (e.g., for relative homology) - VisitorsTuple visitors_; -}; - -/* Visitors */ - -// The prototypical visitor. Others may (and probably should) inherit from it. -template -struct EmptyVisitor -{ - EmptyVisitor() = default; - - template - EmptyVisitor(const EmptyVisitor&) {} - - - template - void chain_initialized(Self*, Chain& c) {} - - void addto(Self*, typename Field::Element m, Index cl) {} - void reduction_finished(Self*) {} -}; - -} - -#include "reduced-matrix.hpp" - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/reduced-matrix.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/reduced-matrix.hpp deleted file mode 100644 index 3e4aca8f29..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/reduced-matrix.hpp +++ /dev/null @@ -1,78 +0,0 @@ -template class... V> -void -dionysus::ReducedMatrix:: -resize(size_t s) -{ - reduced_.resize(s); - pairs_.resize(s, unpaired()); - skip_.resize(s, false); -} - -template class... V> -typename dionysus::ReducedMatrix::Index -dionysus::ReducedMatrix:: -add(Chain&& chain) -{ - // TODO: skip the computation entirely if we already know this is positive (in case of the clearing optimization) - Index i = pairs_.size(); - pairs_.emplace_back(unpaired()); - reduced_.emplace_back(); - skip_.push_back(false); - - set(i, std::move(chain)); - - return reduce(i); -} - -template class... V> -void -dionysus::ReducedMatrix:: -add_skip() -{ - pairs_.emplace_back(unpaired()); - reduced_.emplace_back(); - skip_.push_back(true); -} - -template class... V> -void -dionysus::ReducedMatrix:: -set(Index i, Chain&& c) -{ - sort(c); - visitors_chain_initialized(c); - reduced_[i] = std::move(c); -} - -template class... V> -typename dionysus::ReducedMatrix::Index -dionysus::ReducedMatrix:: -reduce(Index i) -{ - Chain& c = column(i); - Index pair = reduce(c); - - if (pair != unpaired()) - pairs_[pair] = i; - - pairs_[i] = pair; - visitors_reduction_finished<>(); - - return pair; -} - -template class... V> -template -typename dionysus::ReducedMatrix::Index -dionysus::ReducedMatrix:: -reduce( Chain& c, - const ChainsLookup& chains, - const LowLookup& lows) -{ - auto entry_cmp = [this](const Entry& e1, const Entry& e2) { return this->cmp_(e1.index(), e2.index()); }; - return Reduction::reduce(c, chains, lows, field_, - [this](FieldElement m, Index cl) - { this->visitors_addto<>(m, cl); }, - entry_cmp); -} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/reduction.h b/src/Zigzag_persistence/example/ext_zz/dionysus/reduction.h deleted file mode 100644 index 2afd333d41..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/reduction.h +++ /dev/null @@ -1,109 +0,0 @@ -#ifndef DIONYSUS_REDUCTION_H -#define DIONYSUS_REDUCTION_H - -#include -#include -#include -#include -#include "chain.h" - -namespace dionysus -{ - -namespace detail -{ - -template -struct Unpaired -{ static constexpr Index value() { return std::numeric_limits::max(); } }; - -} - -template -struct Reduction -{ - typedef Index_ Index; - - template - using AddtoVisitor = std::function; - - template - struct CallToSub; - - static const Index unpaired; - - template> - static - Index reduce(Chain1& c, - const ChainsLookup& chains, - const LowLookup& lows, - const Field& field, - const AddtoVisitor& visitor = [](typename Field::Element, Index) {}, - const Comparison& cmp = Comparison()) - { - typedef typename Field::Element FieldElement; - - while (!c.empty()) - { - //auto& low = c.back(); - auto& low = *(std::prev(c.end())); - Index l = low.index(); - Index cl = lows(l); - // std::cout << "idx: " << std::get<0>(cl) << ", " << std::get<1>(cl) << "\n"; - if (cl == unpaired) - return l; - else - { - // Reduce further - auto& co = chains(cl); - auto& co_low = co.back(); - FieldElement m = field.neg(field.div(low.element(), co_low.element())); - // c += m*co - Chain::addto(c, m, co, field, cmp); - visitor(m, cl); - } - } - return unpaired; - } - - template> - static - Index reduce(Chain1& c, - const std::vector& chains, - const std::vector& lows, - const Field& field, - const AddtoVisitor& visitor = [](typename Field::Element, Index) {}, - const Comparison& cmp = Comparison()) - { - return reduce(c, - CallToSub(chains), - CallToSub(lows), - field, visitor, cmp); - } - - // This is a work-around a bug in GCC (should really be a lambda function) - template - struct CallToSub - { - CallToSub(const std::vector& items_): - items(items_) {} - const Item& operator()(Index i) const { return items[i]; } - const std::vector& items; - }; -}; - - -template -const Index -Reduction::unpaired = detail::Unpaired::value(); - -} - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/relative-homology-zigzag.h b/src/Zigzag_persistence/example/ext_zz/dionysus/relative-homology-zigzag.h deleted file mode 100644 index 167a32779d..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/relative-homology-zigzag.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef RELATIVE_HOMOLOGY_ZIGZAG_H -#define RELATIVE_HOMOLOGY_ZIGZAG_H - -#include -#include - -#include "zigzag-persistence.h" - -namespace dionysus -{ - -namespace ba = boost::adaptors; - -template> -class RelativeHomologyZigzag -{ - public: - typedef Field_ Field; - typedef Index_ Index; - typedef Comparison_ Comparison; - - typedef ZigzagPersistence ZZP; - typedef typename ZZP::IndexChain IndexChain; - typedef typename ZZP::FieldElement FieldElement; - typedef typename IndexChain::value_type ChainEntry; - - - typedef Comparison Cmp; - - RelativeHomologyZigzag(const Field& field, - const Comparison& cmp = Comparison()): - zzp_(field, cmp) - { - zzp_.add( IndexChain() ); // vertex w - ++zzp_op_; - ++zzp_cell_; - } - - template - void add_both(const ChainRange& chain); - - void remove_both(Index cell); - - // index of the absolute cell; chain = its boundary - template - Index add(Index cell, const ChainRange& chain); // add to the relative part - - Index remove(Index cell); // remove from the relative part - - const Field& field() const { return zzp_.field(); } - const Cmp& cmp() const { return zzp_.cmp(); } - - size_t alive_size() const { return zzp_.alive_size() - 1; } // -1 for the cone vertex - - static - const Index unpaired() { return ZZP::unpaired(); } - - private: - template - IndexChain relative_chain(Index cell, const ChainRange& chain) const; - - template - IndexChain absolute_chain(const ChainRange& chain) const; - - Index abs_index(Index idx) const { return absolute_.left.find(idx)->second; } - Index rel_index(Index idx) const { return relative_.left.find(idx)->second; } - Index decode_pair(Index pair); - - private: - ZZP zzp_; // underlying (cone) implementation - boost::bimap absolute_; // bimap between our cells and zzp absolute cells - boost::bimap relative_; // bimap between our cells and zzp relative cells - std::unordered_map op_map_; // map from zzp_op to our op - Index op_ = 0, - zzp_op_ = 0, - cell_ = 0, - zzp_cell_ = 0; -}; - -} - -#include "relative-homology-zigzag.hpp" - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/relative-homology-zigzag.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/relative-homology-zigzag.hpp deleted file mode 100644 index 499807106c..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/relative-homology-zigzag.hpp +++ /dev/null @@ -1,122 +0,0 @@ -template -template -void -dionysus::RelativeHomologyZigzag:: -add_both(const ChainRange& chain) -{ - zzp_.add(absolute_chain(chain)); - op_map_.insert( { zzp_op_++, op_ } ); - absolute_.left.insert( { cell_, zzp_cell_++ } ); - - zzp_.add(relative_chain(cell_, chain)); - op_map_.insert( { zzp_op_++, op_ } ); - relative_.left.insert( { cell_, zzp_cell_++ } ); - - cell_++; - op_++; -} - -template -void -dionysus::RelativeHomologyZigzag:: -remove_both(Index cell) -{ - Index abs_cell = absolute_.left.find(cell)->second; - Index rel_cell = relative_.left.find(cell)->second; - - zzp_.remove(rel_cell); - zzp_.remove(abs_cell); - - absolute_.left.erase(cell); - relative_.left.erase(cell); - - op_map_.insert( { zzp_op_++, op_ } ); - op_map_.insert( { zzp_op_++, op_ } ); - - op_++; -} - -template -template -typename dionysus::RelativeHomologyZigzag::Index -dionysus::RelativeHomologyZigzag:: -add(Index cell, const ChainRange& chain) -{ - Index pair = zzp_.add(relative_chain(cell, chain)); - op_map_.insert( { zzp_op_++, op_++ } ); - relative_.left.insert( { cell, zzp_cell_++ } ); - - return decode_pair(pair); -} - - -template -typename dionysus::RelativeHomologyZigzag::Index -dionysus::RelativeHomologyZigzag:: -decode_pair(Index pair) -{ - if (pair == unpaired()) - return pair; - - Index decoded = op_map_.find(pair)->second; - op_map_.erase(pair); - return decoded; -} - -template -template -typename dionysus::RelativeHomologyZigzag::IndexChain -dionysus::RelativeHomologyZigzag:: -absolute_chain(const ChainRange& chain) const -{ - IndexChain res; - for (const auto& e : chain) - res.push_back(ChainEntry(e.element(), abs_index(e.index()))); - return res; -} - -template -template -typename dionysus::RelativeHomologyZigzag::IndexChain -dionysus::RelativeHomologyZigzag:: -relative_chain(Index cell, const ChainRange& chain) const -{ - // NB: to compute the signs correctly, - // this assumes that the cone vertex w is the last vertex in some total order - - typedef typename IndexChain::value_type ChainEntry; - - IndexChain res; - if (!chain.empty()) - { - for (const auto& e : chain) - res.push_back(ChainEntry(e.element(), rel_index(e.index()))); - - FieldElement a = field().id(); - if (chain.size() % 2 == 0) // TODO: double-check - a = field().neg(a); - res.push_back(ChainEntry(a, abs_index(cell))); // add the base space cell - } else - { - res.reserve(2); - res.push_back(ChainEntry(field().id(), abs_index(cell))); - res.push_back(ChainEntry(field().neg(field().id()), 0)); - } - return res; -} - - -template -typename dionysus::RelativeHomologyZigzag::Index -dionysus::RelativeHomologyZigzag:: -remove(Index cell) -{ - Index rel_cell = rel_index(cell); - Index pair = zzp_.remove(rel_cell); - pair = decode_pair(pair); - - op_map_.insert( { zzp_op_++, op_++ } ); - relative_.left.erase(cell); - - return pair; -} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/rips.h b/src/Zigzag_persistence/example/ext_zz/dionysus/rips.h deleted file mode 100644 index c7ccb1189e..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/rips.h +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef DIONYSUS_RIPS_H -#define DIONYSUS_RIPS_H - -#include -#include - -#include - -#include "simplex.h" - -namespace dionysus -{ - -/** - * Rips class - * - * Class providing basic operations to work with Rips complexes. It implements Bron-Kerbosch algorithm, - * and provides simple wrappers for various functions. - * - * Distances_ is expected to define types IndexType and DistanceType as well as - * provide operator()(...) which given two IndexTypes should return - * the distance between them. There should be methods begin() and end() - * for iterating over IndexTypes as well as a method size(). - */ -template > -class Rips -{ - public: - typedef Distances_ Distances; - typedef typename Distances::IndexType IndexType; - typedef typename Distances::DistanceType DistanceType; - - typedef Simplex_ Simplex; - typedef typename Simplex::Vertex Vertex; // should be the same as IndexType - typedef std::vector VertexContainer; - - typedef short unsigned Dimension; - - class Evaluator; - class Comparison; - - public: - Rips(const Distances& distances): - distances_(distances) {} - - // Calls functor f on each simplex in the k-skeleton of the Rips complex - template - void generate(Dimension k, DistanceType max, const Functor& f, - Iterator candidates_begin, Iterator candidates_end) const; - - // Calls functor f on all the simplices of the Rips complex that contain the given vertex v - template - void vertex_cofaces(IndexType v, Dimension k, DistanceType max, const Functor& f, - Iterator candidates_begin, Iterator candidates_end) const; - - // Calls functor f on all the simplices of the Rips complex that contain the given edge [u,v] - template - void edge_cofaces(IndexType u, IndexType v, Dimension k, DistanceType max, const Functor& f, - Iterator candidates_begin, Iterator candidates_end) const; - - // Calls functor f on all the simplices of the Rips complex that contain the given Simplex s - // (unlike the previous methods it does not call the functor on the Simplex s itself) - template - void cofaces(const Simplex& s, Dimension k, DistanceType max, const Functor& f, - Iterator candidates_begin, Iterator candidates_end) const; - - - /* No Iterator argument means Iterator = IndexType and the range is [distances().begin(), distances().end()) */ - template - void generate(Dimension k, DistanceType max, const Functor& f) const - { generate(k, max, f, boost::make_counting_iterator(distances().begin()), boost::make_counting_iterator(distances().end())); } - - template - void vertex_cofaces(IndexType v, Dimension k, DistanceType max, const Functor& f) const - { vertex_cofaces(v, k, max, f, boost::make_counting_iterator(distances().begin()), boost::make_counting_iterator(distances().end())); } - - template - void edge_cofaces(IndexType u, IndexType v, Dimension k, DistanceType max, const Functor& f) const - { edge_cofaces(u, v, k, max, f, boost::make_counting_iterator(distances().begin()), boost::make_counting_iterator(distances().end())); } - - template - void cofaces(const Simplex& s, Dimension k, DistanceType max, const Functor& f) const - { cofaces(s, k, max, f, boost::make_counting_iterator(distances().begin()), boost::make_counting_iterator(distances().end())); } - - - const Distances& distances() const { return distances_; } - DistanceType max_distance() const; - - DistanceType distance(const Simplex& s1, const Simplex& s2) const; - - - template - static void bron_kerbosch(VertexContainer& current, - const VertexContainer& candidates, - typename VertexContainer::const_iterator excluded, - Dimension max_dim, - const NeighborTest& neighbor, - const Functor& functor, - bool check_initial = true); - - protected: - const Distances& distances_; -}; - -template -class Rips::Evaluator -{ - public: - typedef Simplex_ Simplex; - - Evaluator(const Distances& distances): - distances_(distances) {} - - DistanceType operator()(const Simplex& s) const; - - protected: - const Distances& distances_; -}; - -template -class Rips::Comparison -{ - public: - typedef Simplex_ Simplex; - - Comparison(const Distances& distances): - eval_(distances) {} - - bool operator()(const Simplex& s1, const Simplex& s2) const - { - DistanceType e1 = eval_(s1), - e2 = eval_(s2); - if (e1 == e2) - return s1.dimension() < s2.dimension(); - - return e1 < e2; - } - - protected: - Evaluator eval_; -}; - -} - -#include "rips.hpp" - -#endif // DIONYSUS_RIPS_H diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/rips.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/rips.hpp deleted file mode 100644 index 2fdda34a7a..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/rips.hpp +++ /dev/null @@ -1,162 +0,0 @@ -#include -#include -#include -#include - -#include -#include - -template -template -void -dionysus::Rips:: -generate(Dimension k, DistanceType max, const Functor& f, Iterator bg, Iterator end) const -{ - auto neighbor = [this, max](Vertex u, Vertex v) { return this->distances()(u,v) <= max; }; - - // current = empty - // candidates = everything - VertexContainer current; - VertexContainer candidates(bg, end); - bron_kerbosch(current, candidates, std::prev(candidates.begin()), k, neighbor, f); -} - -template -template -void -dionysus::Rips:: -vertex_cofaces(IndexType v, Dimension k, DistanceType max, const Functor& f, Iterator bg, Iterator end) const -{ - auto neighbor = [this, max](Vertex u, Vertex v) { return this->distances()(u,v) <= max; }; - - // current = [v] - // candidates = everything - [v] - VertexContainer current; current.push_back(v); - VertexContainer candidates; - for (Iterator cur = bg; cur != end; ++cur) - if (*cur != v && neighbor(v, *cur)) - candidates.push_back(*cur); - - bron_kerbosch(current, candidates, std::prev(candidates.begin()), k, neighbor, f); -} - -template -template -void -dionysus::Rips:: -edge_cofaces(IndexType u, IndexType v, Dimension k, DistanceType max, const Functor& f, Iterator bg, Iterator end) const -{ - auto neighbor = [this, max](Vertex u, Vertex v) { return this->distances()(u,v) <= max; }; - - // current = [u,v] - // candidates = everything - [u,v] - VertexContainer current; current.push_back(u); current.push_back(v); - - VertexContainer candidates; - for (Iterator cur = bg; cur != end; ++cur) - if (*cur != u && *cur != v && neighbor(v,*cur) && neighbor(u,*cur)) - candidates.push_back(*cur); - - bron_kerbosch(current, candidates, std::prev(candidates.begin()), k, neighbor, f); -} - -template -template -void -dionysus::Rips:: -cofaces(const Simplex& s, Dimension k, DistanceType max, const Functor& f, Iterator bg, Iterator end) const -{ - namespace ba = boost::adaptors; - - auto neighbor = [this, max](Vertex u, Vertex v) { return this->distances()(u,v) <= max; }; - - // current = s - VertexContainer current(s.begin(), s.end()); - - // candidates = everything - s that is a neighbor of every vertex in the simplex - VertexContainer candidates; - boost::set_difference(std::make_pair(bg, end) | - ba::filtered([this,&s,&neighbor](Vertex cur) - { for (auto& v : s) - if (!neighbor(v, cur)) - return false; - }), - s, - std::back_inserter(candidates)); - - bron_kerbosch(current, candidates, std::prev(candidates.begin()), k, neighbor, f, false); -} - - -template -template -void -dionysus::Rips:: -bron_kerbosch(VertexContainer& current, - const VertexContainer& candidates, - typename VertexContainer::const_iterator excluded, - Dimension max_dim, - const NeighborTest& neighbor, - const Functor& functor, - bool check_initial) -{ - if (check_initial && !current.empty()) - functor(Simplex(current)); - - if (current.size() == static_cast(max_dim) + 1) - return; - - for (auto cur = std::next(excluded); cur != candidates.end(); ++cur) - { - current.push_back(*cur); - - VertexContainer new_candidates; - for (auto ccur = candidates.begin(); ccur != cur; ++ccur) - if (neighbor(*ccur, *cur)) - new_candidates.push_back(*ccur); - size_t ex = new_candidates.size(); - for (auto ccur = std::next(cur); ccur != candidates.end(); ++ccur) - if (neighbor(*ccur, *cur)) - new_candidates.push_back(*ccur); - excluded = new_candidates.begin() + (ex - 1); - - bron_kerbosch(current, new_candidates, excluded, max_dim, neighbor, functor); - current.pop_back(); - } -} - -template -typename dionysus::Rips::DistanceType -dionysus::Rips:: -distance(const Simplex& s1, const Simplex& s2) const -{ - DistanceType mx = 0; - for (auto a : s1) - for (auto b : s2) - mx = std::max(mx, distances_(a,b)); - return mx; -} - -template -typename dionysus::Rips::DistanceType -dionysus::Rips:: -max_distance() const -{ - DistanceType mx = 0; - for (IndexType a = distances_.begin(); a != distances_.end(); ++a) - for (IndexType b = std::next(a); b != distances_.end(); ++b) - mx = std::max(mx, distances_(a,b)); - return mx; -} - -template -typename dionysus::Rips::DistanceType -dionysus::Rips::Evaluator:: -operator()(const Simplex& s) const -{ - DistanceType mx = 0; - for (auto a = s.begin(); a != s.end(); ++a) - for (auto b = std::next(a); b != s.end(); ++b) - mx = std::max(mx, distances_(*a,*b)); - return mx; -} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/row-reduction.h b/src/Zigzag_persistence/example/ext_zz/dionysus/row-reduction.h deleted file mode 100644 index e2481ce080..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/row-reduction.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef DIONYSUS_ROW_REDUCTION_H -#define DIONYSUS_ROW_REDUCTION_H - -#include "reduced-matrix.h" - -namespace dionysus -{ - -// Mid-level interface -template, template class... Visitors> -class RowReduction -{ - public: - typedef Field_ Field; - typedef Index_ Index; - typedef Comparison_ Comparison; - - typedef ReducedMatrix Persistence; - - public: - RowReduction(const Field& field): - persistence_(field) {} - - RowReduction(const Field& field, - const Comparison& cmp, - const Visitors&... visitors): - persistence_(field, cmp, visitors...) {} - - template - void operator()(const Filtration& f, const Relative& relative, const ReportPair& report_pair, const Progress& progress); - - template - void operator()(const Filtration& f, const ReportPair& report_pair); - - template - void operator()(const Filtration& f) { return (*this)(f, &no_report_pair); } - - static void no_report_pair(int, Index, Index) {} - static void no_progress() {} - - const Persistence& - persistence() const { return persistence_; } - Persistence& persistence() { return persistence_; } - - private: - Persistence persistence_; -}; - -} - -#include "row-reduction.hpp" - -#endif - diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/row-reduction.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/row-reduction.hpp deleted file mode 100644 index edb1652872..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/row-reduction.hpp +++ /dev/null @@ -1,103 +0,0 @@ -#include -namespace ba = boost::adaptors; - -template class... V> -template -void -dionysus::RowReduction:: -operator()(const Filtration& filtration, const ReportPair& report_pair) -{ - using Cell = typename Filtration::Cell; - (*this)(filtration, [](const Cell&) { return false; }, report_pair, &no_progress); -} - -template class... V> -template -void -dionysus::RowReduction:: -operator()(const Filtration& filtration, const Relative& relative, const ReportPair& report_pair, const Progress& progress) -{ - persistence_.resize(filtration.size()); - - typedef typename Persistence::Index Index; - typedef typename Persistence::FieldElement Element; - typedef typename Persistence::Chain Chain; - typedef typename Filtration::Cell Cell; - typedef ChainEntry CellChainEntry; - typedef ChainEntry ChainEntry; - - std::vector rows(persistence_.size()); - - auto& field = persistence_.field(); - - // fill the matrix - Index i = 0; - for(auto& c : filtration) - { - progress(); - - if (relative(c)) - { - persistence_.set_skip(i); - ++i; - continue; - } - - persistence_.set(i, c.boundary(field) | - ba::filtered([relative](const CellChainEntry& e) { return !relative(e.index()); }) | - ba::transformed([this,&filtration](const CellChainEntry& e) - { return ChainEntry(e.element(), filtration.index(e.index())); })); - if (!persistence_[i].empty()) - { - auto& x = persistence_[i].back(); - rows[x.index()].emplace_back(x.element(),i); - } - ++i; - } - - auto entry_cmp = [this](const ChainEntry& e1, const ChainEntry& e2) { return this->persistence_.cmp()(e1.index(), e2.index()); }; - - // reduce the matrix from the bottom up - for (auto it = rows.rbegin(); it != rows.rend(); ++it) - { - auto& row = *it; - Index r = rows.rend() - it - 1; - - if (row.empty()) - continue; - - // add the first column to every other column - Index c = row.front().index(); - Element e = row.front().element(); - Chain& first = persistence_.column(c); - for (size_t i = 1; i < row.size(); ++i) - { - Index cur_idx = row[i].index(); - Element cur_elem = row[i].element(); - Chain& cur = persistence_.column(cur_idx); - if (cur.empty()) // zeroed out by the clearing optimization - continue; - - Element m = field.neg(field.div(cur_elem, e)); - // cur += m*first - ::dionysus::Chain::addto(cur, m, first, field, entry_cmp); - - // update row - if (!cur.empty()) - { - ChainEntry ce = cur.back(); - auto& new_row = rows[ce.index()]; - new_row.emplace_back(ce.element(), cur_idx); - if (entry_cmp(new_row.back(), new_row.front())) - std::swap(new_row.back(), new_row.front()); - } - } - - persistence_.set_pair(r,c); - report_pair(filtration[r].dimension(), r, c); - - // zero out the corresponding column (the clearing optimization) - persistence_.column(r).clear(); - } -} - diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/simplex.h b/src/Zigzag_persistence/example/ext_zz/dionysus/simplex.h deleted file mode 100644 index 4ac5cb6945..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/simplex.h +++ /dev/null @@ -1,280 +0,0 @@ -#ifndef DIONYSUS_SIMPLEX_H -#define DIONYSUS_SIMPLEX_H - -#include -#include - -//#include -#include -#include -#include - -#include "chain.h" - -namespace dionysus -{ - -struct Empty {}; - -template -class Simplex -{ - public: - typedef Vertex_ Vertex; - typedef T Data; - typedef std::unique_ptr Vertices; - - template - struct BoundaryChainIterator; - struct BoundaryIterator; - - template - using BoundaryChainRange = boost::iterator_range>; - using BoundaryRange = boost::iterator_range; - - template - using Entry = ChainEntry; - - public: - Simplex(const Data& d = Data()): - dim_(-1), data_(d) {} - - Simplex(const std::initializer_list& vertices, - Data&& d = Data()): - Simplex(vertices.size() - 1, vertices.begin(), vertices.end(), std::move(d)) - {} - - Simplex(const std::initializer_list& vertices, - const Data& d): - Simplex(vertices.size() - 1, vertices.begin(), vertices.end(), d) {} - - Simplex(short unsigned dim, Vertices&& vertices, Data&& data = Data()): - dim_(dim), vertices_(std::move(vertices)), data_(std::move(data)) { std::sort(begin(), end()); } - - template - Simplex(const VertexRange& vertices, - Data&& d = Data()): - Simplex(vertices.size() - 1, vertices.begin(), vertices.end(), std::move(d)) - {} - - template - Simplex(const VertexRange& vertices, - const Data& d): - Simplex(vertices.size() - 1, vertices.begin(), vertices.end(), d) {} - - Simplex(const Simplex& other): - Simplex(other.dim_, other.begin(), other.end(), other.data_) {} - Simplex& operator=(const Simplex& other) { dim_ = other.dim_; vertices_ = Vertices(new Vertex[dim_+1]); std::copy(other.begin(), other.end(), begin()); data_ = other.data_; return *this; } - - Simplex(Simplex&& other) noexcept: - dim_(other.dim_), - vertices_(std::move(other.vertices_)), - data_(std::move(other.data_)) {} - Simplex& operator=(Simplex&& other) = default; - - template - Simplex(short unsigned dim, - Iterator b, Iterator e, - Data&& d = Data()): - dim_(dim), - vertices_(new Vertex[dim_+1]), - data_(std::move(d)) { std::copy(b, e, begin()); std::sort(begin(), end()); } - - template - Simplex(short unsigned dim, - Iterator b, Iterator e, - const Data& d): - dim_(dim), - vertices_(new Vertex[dim_+1]), - data_(d) { std::copy(b, e, begin()); std::sort(begin(), end()); } - - short unsigned dimension() const { return dim_; } - - BoundaryRange boundary() const { return BoundaryRange(boundary_begin(), boundary_end()); } - BoundaryIterator boundary_begin() const; - BoundaryIterator boundary_end() const; - - template - BoundaryChainRange - boundary(const Field& field) const { return BoundaryChainRange(boundary_begin(field), boundary_end(field)); } - - template - BoundaryChainIterator - boundary_begin(const Field& field) const; - template - BoundaryChainIterator - boundary_end(const Field& field) const; - - const Vertex* begin() const { return vertices_.get(); } - const Vertex* end() const { return begin() + dim_ + 1; } - size_t size() const { return dim_ + 1; } - - std::pair - range() const { return std::make_pair(begin(), end()); } - - Simplex join(const Vertex& v) const { Vertices vertices(new Vertex[dim_+2]); std::copy(begin(), end(), vertices.get()); vertices[dim_+1] = v; return Simplex(dim_ + 1, std::move(vertices), Data(data_)); } - - bool operator==(const Simplex& other) const { return dim_ == other.dim_ && std::equal(begin(), end(), other.begin()); } - bool operator!=(const Simplex& other) const { return !operator==(other); } - bool operator<(const Simplex& other) const { return dim_ < other.dim_ || (dim_ == other.dim_ && std::lexicographical_compare(begin(), end(), other.begin(), other.end())); } - bool operator>(const Simplex& other) const { return other < (*this); } - - Vertex operator[](short unsigned i) const { return vertices_[i]; } - const Data& data() const { return data_; } - Data& data() { return data_; } - - friend - std::ostream& operator<<(std::ostream& out, const Simplex& s) - { out << '<' << *s.begin(); for (auto it = s.begin() + 1; it != s.end(); ++it) out << ',' << *it; out << '>'; return out; } - - private: - Vertex* begin() { return vertices_.get(); } - Vertex* end() { return begin() + dim_ + 1; } - - private: - short unsigned dim_; - //boost::compressed_pair vertices_data_; - Vertices vertices_; - Data data_; // TODO: optimize -}; - -template -size_t hash_value(const Simplex& s) { return boost::hash_range(s.begin(), s.end()); } - - -template -struct Simplex::BoundaryIterator: - public boost::iterator_adaptor, // Value - boost::use_default, - Simplex> // Reference -{ - public: - typedef const V* Iterator; - typedef Simplex Value; - - typedef boost::iterator_adaptor Parent; - - BoundaryIterator() {} - explicit BoundaryIterator(short unsigned dim, Iterator iter, Iterator bg, Iterator end): - Parent(iter), dim_(dim), bg_(bg), end_(end) {} - - Iterator begin() const { return bg_; } - - private: - friend class boost::iterator_core_access; - Value dereference() const - { - typedef std::not_equal_to NotEqualVertex; - - using std::placeholders::_1; - return Simplex(dim_ - 1, - boost::make_filter_iterator(std::bind(NotEqualVertex(), _1, *(this->base())), bg_, end_), - boost::make_filter_iterator(std::bind(NotEqualVertex(), _1, *(this->base())), end_, end_)); - } - - short unsigned dim_; - Iterator bg_; - Iterator end_; -}; - -template -template -struct Simplex::BoundaryChainIterator: - public boost::iterator_adaptor, // Derived - BoundaryIterator, - ChainEntry>, // Value - boost::use_default, - ChainEntry>> // Reference -{ - public: - typedef F Field; - typedef BoundaryIterator Iterator; - typedef ChainEntry> Value; - - typedef boost::iterator_adaptor Parent; - - BoundaryChainIterator() {} - explicit BoundaryChainIterator(const Field& field, Iterator iter): - Parent(iter), field_(&field) {} - - private: - friend class boost::iterator_core_access; - Value dereference() const - { - return Value(((this->base().base() - this->base().begin()) % 2 == 0)? field_->id() : field_->neg(field_->id()), - *(this->base())); - } - - const Field* field_ = nullptr; -}; - - -/* Simplex */ -template -typename Simplex::BoundaryIterator -Simplex:: -boundary_begin() const -{ - if (dimension() == 0) return boundary_end(); - return BoundaryIterator(dimension(), begin(), begin(), end()); -} - -template -typename Simplex::BoundaryIterator -Simplex:: -boundary_end() const -{ - return BoundaryIterator(dimension(), end(), begin(), end()); -} - -template -template -#if defined(_MSC_VER) -typename Simplex::BoundaryChainIterator -#else -typename Simplex::template BoundaryChainIterator -#endif -Simplex:: -boundary_begin(const F& field) const -{ - if (dimension() == 0) return boundary_end(field); - return BoundaryChainIterator(field, boundary_begin()); -} - -template -template -#if defined(_MSC_VER) -typename Simplex::BoundaryChainIterator -#else -typename Simplex::template BoundaryChainIterator -#endif -Simplex:: -boundary_end(const F& field) const -{ - return BoundaryChainIterator(field, boundary_end()); -} - -} // dionysus - -namespace std -{ - -template -struct hash> -{ - size_t operator()(const dionysus::Simplex& s) const { return hash_value(s); } -}; - -} // std - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/sparse-row-matrix.h b/src/Zigzag_persistence/example/ext_zz/dionysus/sparse-row-matrix.h deleted file mode 100644 index fb1e929e02..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/sparse-row-matrix.h +++ /dev/null @@ -1,184 +0,0 @@ -#ifndef DIONYSUS_SPARSE_ROW_MATRIX_H -#define DIONYSUS_SPARSE_ROW_MATRIX_H - -#include -#include -#include -#include // for debugging output - -#include - -#include "chain.h" -#include "reduction.h" - -namespace dionysus -{ - -namespace bi = boost::intrusive; - -namespace detail -{ - typedef bi::list_base_hook> auto_unlink_hook; - - template - struct SparseRowMatrixEntry: - public ChainEntry, auto_unlink_hook> - { - typedef I Index; - typedef typename F::Element FieldElement; - typedef std::tuple IndexPair; // (id, pair) - typedef ChainEntry Parent; - typedef SparseRowMatrixEntry Entry; - - SparseRowMatrixEntry(FieldElement e, const IndexPair& ip): - Parent(e,ip) {} - - SparseRowMatrixEntry(FieldElement e, const Index& r, const Index& c): - Parent(e,IndexPair(r,c)) {} - - SparseRowMatrixEntry(const Entry& other) = default; - SparseRowMatrixEntry(Entry&& other) = default; - Entry& operator=(Entry&& other) = default; - - void unlink() { auto_unlink_hook::unlink(); } - bool is_linked() const { return auto_unlink_hook::is_linked(); } - }; -} - -template, - template class Column_ = std::vector> -class SparseRowMatrix -{ - public: - typedef Field_ Field; - typedef Index_ Index; - typedef Comparison_ Comparison; - - typedef typename Field::Element FieldElement; - - typedef detail::SparseRowMatrixEntry Entry; - typedef Column_ Column; - typedef typename Entry::IndexPair IndexPair; - typedef bi::list> Row; - - typedef std::vector> IndexChain; - - typedef std::unordered_map Columns; - typedef std::unordered_map Rows; - typedef std::unordered_map LowMap; - - public: - SparseRowMatrix(const Field& field, - const Comparison& cmp = Comparison()): - field_(field), cmp_(cmp) {} - - SparseRowMatrix(SparseRowMatrix&& other) = default; - - - template - Column reduce(const ChainRange& chain, IndexChain& trail); - - Index set(Index i, Column&& chain); // returns previous column with this low - void fix(Index c, Column& column); - void fix(Index c) { fix(c, col(c)); } - - const Row& prepend_row(Index r, FieldElement m, const Row& chain); // could be horribly inefficient if Column is chosen poorly - - void drop_row(Index r) { rows_.erase(r); if (is_low(r)) lows_.erase(r); } - void drop_col(Index c) - { - auto cit = columns_.find(c); - Column& column = cit->second; - if (!column.empty()) - { - Index rlow = std::get<0>(column.back().index()); - auto it = lows_.find(rlow); - if (it != lows_.end() && it->second == c) - lows_.erase(it); - } - columns_.erase(cit); - } - void drop_low(Index r) { lows_.erase(r); } - - // accessors - Row& row(Index r) { return rows_[r]; } - Column& col(Index c) { assert(col_exists(c)); return columns_.find(c)->second; } - const Column& col(Index c) const { assert(col_exists(c)); return columns_.find(c)->second; } - Index low(Index r) const { return lows_.find(r)->second; } - bool is_low(Index r) const { return lows_.find(r) != lows_.end(); } - void update_low(Index c) { lows_[std::get<0>(col(c).back().index())] = c; } - - const Field& field() const { return field_; } - void reserve(size_t) {} // here for compatibility only - const Comparison& cmp() const { return cmp_; } - - // debug - bool col_exists(Index c) const { return columns_.find(c) != columns_.end(); } - const Columns& columns() const { return columns_; } - void check_columns() const - { - for (auto& x : columns_) - { - Index c = x.first; - if (x.second.empty()) - std::cout << "Warning: empty column " << c << std::endl; - Index rl = std::get<0>(x.second.back().index()); - if (!is_low(rl) || low(rl) != c) - { - std::cout << "Columns don't check out: lows don't match" << std::endl; - std::cout << " " << c << ' ' << rl << ' ' << ' ' << low(rl) << std::endl; - std::cout << "---\n"; - for (auto& x : col(c)) - std::cout << " " << x.element() << ' ' << std::get<0>(x.index()) << ' ' << std::get<1>(x.index()) << '\n'; - std::cout << "---\n"; - for (auto& x : col(low(rl))) - std::cout << " " << x.element() << ' ' << std::get<0>(x.index()) << ' ' << std::get<1>(x.index()) << '\n'; - assert(0); - } - - for (auto& x : lows_) - { - if (!col_exists(x.second)) - { - std::cout << "Still keeping low of a removed column" << std::endl; - assert(0); - } - else if (std::get<0>(col(x.second).back().index()) != x.first) - { - std::cout << "Low mismatch: " << x.second << ' ' << std::get<0>(col(x.second).back().index()) << ' ' << x.first << '\n'; - assert(0); - } - } - } - } - - private: - Field field_; - Comparison cmp_; - - Columns columns_; - Rows rows_; - LowMap lows_; // column that has this low -}; - - -namespace detail -{ - -template -struct Unpaired> -{ - static - constexpr std::tuple - value() - { return std::make_tuple(std::numeric_limits::max(), - std::numeric_limits::max()); } -}; - -} - -} - -#include "sparse-row-matrix.hpp" - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/sparse-row-matrix.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/sparse-row-matrix.hpp deleted file mode 100644 index 10f4808c17..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/sparse-row-matrix.hpp +++ /dev/null @@ -1,103 +0,0 @@ -template class Col> -template -typename dionysus::SparseRowMatrix::Column -dionysus::SparseRowMatrix:: -reduce(const ChainRange& chain_, IndexChain& trail) -{ - auto row_cmp = [this](const Entry& e1, const Entry& e2) - { return this->cmp_(std::get<0>(e1.index()), std::get<0>(e2.index())); }; - -#define __DIONYSUS_USE_VECTOR_CHAINS 1 - -#if !(__DIONYSUS_USE_VECTOR_CHAINS) - std::set chain(row_cmp); - for (auto x : chain_) - chain.insert(Entry(x.element(), IndexPair(x.index(), 0))); -#else - Column chain; - for (auto x : chain_) - chain.emplace_back(x.element(), IndexPair(x.index(), 0)); - std::sort(chain.begin(), chain.end(), row_cmp); -#endif - - typedef Reduction ReductionIP; - - auto chains = [this](const IndexPair& rc) -> const Column& { return this->col(std::get<1>(rc)); }; - auto lows = [this](const IndexPair& rc) -> IndexPair - { - Index r = std::get<0>(rc); - auto it = this->lows_.find(r); - if (it == this->lows_.end()) - return ReductionIP::unpaired; - else - { - Index rr = std::get<0>(col(it->second).back().index()); - if (rr != r) - std::cout << "Mismatch: " << rr << ' ' << r << std::endl; - return IndexPair(r, it->second); - } - }; - - auto addto = [&trail](FieldElement m, const IndexPair& rc) { trail.emplace_back(m, std::get<1>(rc)); }; - - ReductionIP::reduce(chain, - chains, lows, - field_, addto, row_cmp); - -#if !(__DIONYSUS_USE_VECTOR_CHAINS) - return Column(std::begin(chain), std::end(chain)); -#else - return chain; -#endif -} - -template class Col> -typename dionysus::SparseRowMatrix::Index -dionysus::SparseRowMatrix:: -set(Index col, Column&& chain) -{ - Column& column = columns_.emplace(col, std::move(chain)).first->second; - - fix(col, column); - - Index r = std::get<0>(column.back().index()); - Index res; - if (is_low(r)) - res = low(r); - else - res = col; - lows_[r] = col; - - return res; -} - -template class Col> -void -dionysus::SparseRowMatrix:: -fix(Index col, Column& column) -{ - for (auto& x : column) - { - std::get<1>(x.index()) = col; - Index r = std::get<0>(x.index()); - row(r).push_back(x); - } -} - -template class Col> -const typename dionysus::SparseRowMatrix::Row& -dionysus::SparseRowMatrix:: -prepend_row(Index r, FieldElement m, const Row& chain) -{ - Row& new_row = row(r); - - for (auto& x : chain) - { - Index c = std::get<1>(x.index()); - Column& column = col(c); - auto it = column.emplace(column.begin(), field().mul(x.element(), m), r, c); - new_row.push_back(*it); - } - - return new_row; -} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/standard-reduction.h b/src/Zigzag_persistence/example/ext_zz/dionysus/standard-reduction.h deleted file mode 100644 index 0477d4683f..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/standard-reduction.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef DIONYSUS_STANDARD_REDUCTION_H -#define DIONYSUS_STANDARD_REDUCTION_H - -namespace dionysus -{ - -// Mid-level interface -template -class StandardReduction -{ - public: - typedef Persistence_ Persistence; - typedef typename Persistence::Field Field; - typedef typename Persistence::Index Index; - - public: - StandardReduction(Persistence& persistence): - persistence_(persistence) {} - - template - void operator()(const Filtration& f, const Relative& relative, const ReportPair& report_pair, const Progress& progress); - - template - void operator()(const Filtration& f, const ReportPair& report_pair); - - template - void operator()(const Filtration& f) { return (*this)(f, &no_report_pair); } - - static void no_report_pair(int, Index, Index) {} - static void no_progress() {} - - const Persistence& - persistence() const { return persistence_; } - Persistence& persistence() { return persistence_; } - - private: - Persistence& persistence_; -}; - -} - -#include "standard-reduction.hpp" - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/standard-reduction.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/standard-reduction.hpp deleted file mode 100644 index 9aa3396a8c..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/standard-reduction.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#include -namespace ba = boost::adaptors; - -template -template -void -dionysus::StandardReduction

:: -operator()(const Filtration& filtration, const ReportPair& report_pair) -{ - using Cell = typename Filtration::Cell; - (*this)(filtration, [](const Cell&) { return false; }, report_pair, no_progress); -} - -template -template -void -dionysus::StandardReduction

:: -operator()(const Filtration& filtration, const Relative& relative, const ReportPair& report_pair, const Progress& progress) -{ - persistence_.reserve(filtration.size()); - - typedef typename Filtration::Cell Cell; - typedef ChainEntry CellChainEntry; - typedef ChainEntry ChainEntry; - - unsigned i = 0; - for(auto& c : filtration) - { - progress(); - - if (relative(c)) - { - ++i; - persistence_.add_skip(); - continue; - } - - //std::cout << "Adding: " << c << " : " << boost::distance(c.boundary(persistence_.field())) << std::endl; - Index pair = persistence_.add(c.boundary(persistence_.field()) | - ba::filtered([relative](const CellChainEntry& e) { return !relative(e.index()); }) | - ba::transformed([this,&filtration](const CellChainEntry& e) - { return ChainEntry(e.element(), filtration.index(e.index())); })); - if (pair != persistence_.unpaired()) - report_pair(c.dimension(), pair, i); - ++i; - } -} diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/trails-chains.h b/src/Zigzag_persistence/example/ext_zz/dionysus/trails-chains.h deleted file mode 100644 index f18ff897e4..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/trails-chains.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef DIONYSUS_TRAILS_CHAINS_H -#define DIONYSUS_TRAILS_CHAINS_H - -#include "ordinary-persistence.h" - -template -struct ChainsVisitor: public EmptyVisitor -{ - template - void chain_initialized(Chain& c) { } - - void addto(typename Field::Element m, Index cl) {} - void reduction_finished() {} -}; - - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/zigzag-persistence.h b/src/Zigzag_persistence/example/ext_zz/dionysus/zigzag-persistence.h deleted file mode 100644 index e9423099aa..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/zigzag-persistence.h +++ /dev/null @@ -1,142 +0,0 @@ -#ifndef DIONYSUS_ZIGZAG_PERSISTENCE_H -#define DIONYSUS_ZIGZAG_PERSISTENCE_H - -#include -#include -#include - -#include -#include - -#include "sparse-row-matrix.h" - -namespace dionysus -{ - -namespace ba = boost::adaptors; - -template> -class ZigzagPersistence -{ - static_assert(std::is_signed::value, "Index type used in ZigzagPersistence must be a *signed* integer"); - - public: - typedef Field_ Field; - typedef Index_ Index; - typedef Comparison_ Comparison; - - typedef SparseRowMatrix RowMatrix; - typedef SparseRowMatrix DequeRowMatrix; - typedef typename RowMatrix::IndexPair IndexPair; - typedef typename RowMatrix::FieldElement FieldElement; - typedef typename RowMatrix::IndexChain IndexChain; - typedef typename RowMatrix::Column Column; - typedef typename RowMatrix::Row Row; - typedef typename DequeRowMatrix::Column DequeColumn; - typedef typename DequeRowMatrix::Row DequeRow; - - typedef std::unordered_map BirthIndexMap; - - - ZigzagPersistence(const Field& field, - const Comparison& cmp = Comparison()): - Z(field, cmp), C(field, cmp), B(field, cmp), - operations(0), - cell_indices(0), - z_indicies_last(0), - z_indicies_first(-1), - b_indices(0) {} - - template - Index add(const ChainRange& chain) // returns the id of the dying cycle (or unpaired) - { - Index res = add_impl(chain); -#ifdef DIONYSUS_ZIGZAG_DEBUG - check_sorted(); - check_b_cols(); - Z.check_columns(); -#endif - return res; - } - Index remove(Index cell) - { - Index res = remove_impl(cell); -#ifdef DIONYSUS_ZIGZAG_DEBUG - check_sorted(); - check_b_cols(); - Z.check_columns(); -#endif - return res; - } - - struct IsAlive - { - IsAlive(const ZigzagPersistence& zz_): zz(&zz_) {} - bool operator()(const std::pair& x) const { return zz->is_alive(x.first); } - const ZigzagPersistence* zz; - }; - - bool is_alive(Index x) const { return !B.is_low(x); } - - auto alive_ops() const -> decltype(BirthIndexMap() | ba::filtered(IsAlive(*this)) | ba::map_values) - { return birth_index | ba::filtered(IsAlive(*this)) | ba::map_values; } - - auto alive_cycles() const -> decltype(BirthIndexMap() | ba::filtered(IsAlive(*this)) | ba::map_keys) - { return birth_index | ba::filtered(IsAlive(*this)) | ba::map_keys; } - - size_t alive_size() const { return Z.columns().size() - B.columns().size(); } - - void reserve(size_t) {} // here for compatibility only - const Field& field() const { return Z.field(); } - const Comparison& cmp() const { return Z.cmp(); } - - template - static Index row(const Entry& e) { return std::get<0>(e.index()); } - template - static Index col(const Entry& e) { return std::get<1>(e.index()); } - - static - const Index unpaired() { return Reduction::unpaired; } - - const Column& cycle(Index i) const { return Z.col(i); } - - // debug - void check_b_cols() const; - - template - void check_boundaries(const SimplexToIndex& s2i, const IndexToSimplex& i2s) const; - template - void check_cycles(const SimplexToIndex& s2i, const IndexToSimplex& i2s) const; - - Column zb_dot(Index c) const; - - template - Column dc_dot(Index c, const SimplexToIndex& s2i, const IndexToSimplex& i2s) const; - - template - Column boundary(Index i, const SimplexToIndex& s2i, const IndexToSimplex& i2s) const; - - void check_sorted() const; - - private: - template - Index add_impl(const ChainRange& chain); - Index remove_impl(Index cell); - - private: - RowMatrix Z, C; - DequeRowMatrix B; - - BirthIndexMap birth_index; - Index operations; - Index cell_indices; - Index z_indicies_last, z_indicies_first; - Index b_indices; -}; - -} - -#include "zigzag-persistence.hpp" - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/dionysus/zigzag-persistence.hpp b/src/Zigzag_persistence/example/ext_zz/dionysus/zigzag-persistence.hpp deleted file mode 100644 index 96331a3b15..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/dionysus/zigzag-persistence.hpp +++ /dev/null @@ -1,541 +0,0 @@ -#include - -template -template -typename dionysus::ZigzagPersistence::Index -dionysus::ZigzagPersistence:: -add_impl(const ChainRange& chain_) -{ - // std::cout << "add(" << cell_indices << ")" << std::endl; - Index op = operations++; - - IndexChain cycles; // chain_ -> Z*cycles - Column z_remainder = Z.reduce(chain_, cycles); - // std::cout << "cycle: "; - // for (auto& v : cycles){ - // std::cout << v.index() << " "; - // } - // std::cout << "\n"; - assert(z_remainder.empty()); - - IndexChain boundaries; - DequeColumn b_remainder = B.reduce(cycles, boundaries); - - // add up columns of C indexed by boundaries - typedef typename Column::value_type Entry; - auto row_cmp = [this](const Entry& e1, const Entry& e2) - { return this->cmp()(row(e1), row(e2)); }; - Column chain; - for (auto& x : boundaries) - Chain::addto(chain, x.element(), C.col(x.index()), field(), row_cmp); - chain.push_back(Entry(field().neg(field().id()), IndexPair(cell_indices++,0))); - - if (b_remainder.empty()) // birth - { - // std::cout << " birth" << std::endl; - Index z_col = z_indicies_last++; - Z.set(z_col, std::move(chain)); - birth_index[z_col] = op; - return unpaired(); - } - else // death - { - // std::cout << " death" << std::endl; - Index b_col = b_indices++; - Index pair = row(b_remainder.back()); - B.set(b_col, std::move(b_remainder)); - C.set(b_col, std::move(chain)); - return birth_index[pair]; - } -} - -template -typename dionysus::ZigzagPersistence::Index -dionysus::ZigzagPersistence:: -remove_impl(Index cell) -{ - //std::cout << "remove(" << cell << ")" << std::endl; - - Index op = operations++; - - typedef typename Column::value_type Entry; - auto row_cmp = [this](const Entry& e1, const Entry& e2) - { return this->cmp()(row(e1), row(e2)); }; - typedef typename DequeColumn::value_type DequeEntry; - auto b_row_cmp = [this](const DequeEntry& e1, const DequeEntry& e2) - { return this->cmp()(row(e1), row(e2)); }; - - IndexChain z_row; - for (auto& x : Z.row(cell)) - z_row.emplace_back(x.element(), col(x)); - - if (z_row.empty()) // birth - { - //std::cout << " birth" << std::endl; - Row& c_row = C.row(cell); - // c_row.front() may not be the first column in order, but that doesn't really matter, does it? (TODO) - auto& c_front = c_row.front(); - - Index j = col(c_front); - Index l = row(B.col(j).back()); - - //std::cout << j << ' ' << l << std::endl; - - // cycle = ZB[j] = DC[j] - Column cycle; - for (auto& x : B.col(j)) - Chain::addto(cycle, x.element(), Z.col(row(x)), field(), row_cmp); - - //std::cout << "Cycle:" << std::endl; - //for (auto& x : cycle) - // std::cout << x.element() << ' ' << row(x) << std::endl; - - // 1: prepend the cycle - Index znew = z_indicies_first--; - Index oth = Z.set(znew, std::move(cycle)); // oth records our collision (used in step 6) - birth_index[znew] = op; - - //std::cout << "znew oth: " << znew << ' ' << oth << std::endl; - //std::cout << "oth column:" << std::endl; - //for (auto& x : Z.col(oth)) - // std::cout << x.element() << ' ' << row(x) << std::endl; - - // 2: prepend the row to B - FieldElement m = field().neg(field().inv(c_front.element())); // m = -1/c - const DequeRow& b_row = B.prepend_row(znew, m, c_row); - //std::cout << "Prepended row with multiplier: " << m << " (" << b_row.size() << ")" << std::endl; - - // 3: subtract C[j] from every C[k] - const Column& Cj = C.col(j); - - // use the copy of c_row in B, since c_row will be modified in the following loop - for (auto it = std::next(b_row.begin()); it != b_row.end(); ++it) - { - Index c = col(*it); - assert(c != j); - //std::cout << "adding to " << c << " in C" << std::endl; - Chain::addto(C.col(c), it->element(), Cj, field(), row_cmp); // using it->element() since b_row = m*c_row - C.fix(c); // old elements got removed via auto_unlink_hook - // we don't need lows in C, so not updating them - } - //std::cout << "Done with step 3" << std::endl; - - // 4: subtract B[j] from every B[k] that has l - // (we don't need to update C because ZB[j] = 0 after step 2) - DequeColumn& Bj = B.col(j); - FieldElement bm = field().neg(field().inv(Bj.back().element())); // bm = -1/B[l,j] - IndexChain Bl_row; // make a copy of Bl_row, since it will be changing - for (auto& x : B.row(l)) - { - if (col(x) == j) - continue; - Bl_row.emplace_back(x.element(), col(x)); - } - for (auto& x : Bl_row) - { - Index c = x.index(); - assert(c != j); - Chain::addto(B.col(c), field().mul(bm, x.element()), Bj, field(), b_row_cmp); - B.fix(c); // old elements got removed via auto_unlink_hook - // l cannot be the low in c, so no need to update lows - } - //std::cout << "Done with step 4" << std::endl; - - // 5: drop row l and column j from B; drop column l from Z; drop column j from C - B.drop_col(j); - assert(B.row(l).empty()); - B.drop_row(l); - Index Zl_low = row(Z.col(l).back()); - Z.drop_col(l); - birth_index.erase(l); - C.drop_col(j); - assert(Z.row(cell).empty()); - assert(C.row(cell).empty()); - C.drop_row(cell); - Z.drop_row(cell); - //std::cout << "Done with step 5" << std::endl; - if (oth == l) // we just dropped our collision in Z - oth = znew; - else - Z.drop_low(Zl_low); - - // 6: reduce Z - std::unordered_map b_changes; // the columns to add in B to apply row changes - Index cur = znew; - while (oth != cur) - { - Column& cur_col = Z.col(cur); - Column& oth_col = Z.col(oth); - assert(row(cur_col.back()) == row(oth_col.back())); - //std::cout << "--- " << cur << " (" << cur_col.size() << ") " << oth << " (" << oth_col.size() << ")" << std::endl; - FieldElement m1 = cur_col.back().element(); - FieldElement m2 = oth_col.back().element(); - FieldElement m2_div_m1 = field().div(m2, m1); - Chain::addto(oth_col, field().neg(m2_div_m1), cur_col, field(), row_cmp); - Z.fix(oth, oth_col); - - // record the changes we need to make in B; - // because there is only one collision in the matrix during the reduction, - // once we use a row as the source, we never revisit it. This means once the row is updated in B, - // we never touch it again, so below record is fine. - for (auto& x : this->B.row(oth)) - b_changes[col(x)].emplace_back(field().mul(x.element(), m2_div_m1), cur, col(x)); - - cur = oth; - Index low = row(oth_col.back()); - if (Z.is_low(low)) - oth = Z.low(low); - //std::cout << "--- -- new low: " << low << ' ' << cur << ' ' << oth << std::endl; - - if (cmp()(oth, cur)) - std::swap(oth, cur); - else - Z.update_low(cur); - } - - // apply changes in B (the complexity here could get ugly) - for (auto& bx : b_changes) - { - std::sort(bx.second.begin(), bx.second.end(), b_row_cmp); - Chain::addto(B.col(bx.first), field().id(), bx.second, field(), b_row_cmp); - B.fix(bx.first); - // no need to update low (additions from bottom up) - } - //std::cout << "Done with step 6" << std::endl; - - return unpaired(); - } - else // death - { - //std::cout << " death" << std::endl; - - auto index_chain_cmp = [this](const typename IndexChain::value_type& e1, const typename IndexChain::value_type& e2) - { return this->cmp()(e1.index(), e2.index()); }; - - // 1: change basis to clear z_row - std::sort(z_row.begin(), z_row.end(), index_chain_cmp); // this adds a log factor, but it makes life easier - Index j = z_row.front().index(); - FieldElement e = z_row.front().element(); - - if (z_row.size() > 1) - { - // figure out the columns we use for reduction - typedef typename IndexChain::const_iterator RowIterator; - std::vector reducers; - reducers.push_back(z_row.begin()); - for (RowIterator it = std::next(z_row.begin()); it != z_row.end(); ++it) - { - Index c = it->index(); - - assert(Z.col_exists(c)); - assert(Z.col_exists(reducers.back()->index())); - if (cmp()(row(Z.col(c).back()), - row(Z.col(reducers.back()->index()).back()))) - reducers.push_back(it); - } - reducers.push_back(z_row.end()); - //std::cout << "reducers.size(): " << reducers.size() << std::endl; - //std::cout << "z_row.size(): " << z_row.size() << std::endl; - - - std::map b_changes; // the rows to add to B - auto add_in_z = [this,&b_changes,&row_cmp,&index_chain_cmp](Index to, Index from, FieldElement m, FieldElement e) - { - //std::cout << " add_in_z: " << from << ' ' << to << std::endl; - - FieldElement mult = this->field().mul(m, e); - assert(Z.col_exists(to)); - assert(Z.col_exists(from)); - Chain::addto(Z.col(to), mult, Z.col(from), this->field(), row_cmp); - assert(!Z.col(to).empty()); - this->Z.fix(to); // NB: rows will be linked in the back, so the iterators are Ok - this->Z.update_low(to); - - // subtract B.row(to) from B.row(from) - IndexChain Bto_row; - for (auto& x : this->B.row(to)) - Bto_row.emplace_back(x.element(), col(x)); - std::sort(Bto_row.begin(), Bto_row.end(), index_chain_cmp); - -#if 0 - for (auto& x : this->B.row(to)) - std::cout << x.element() << ' ' << row(x) << ' ' << col(x) << std::endl; - - std::cout << "---\n"; - - for (auto& x : this->B.row(from)) - std::cout << x.element() << ' ' << row(x) << ' ' << col(x) << std::endl; -#endif - - Chain::addto(b_changes[from], this->field().neg(mult), Bto_row, this->field(), index_chain_cmp); - - // if there is b_changes[to] add it, too - auto it = b_changes.find(to); - if (it != b_changes.end()) - Chain::addto(b_changes[from], this->field().neg(mult), it->second, this->field(), index_chain_cmp); - }; - Index last_low = row(Z.col(reducers[reducers.size() - 2]->index()).back()); - for (int i = reducers.size() - 2; i >= 0; --i) - { - auto rit = reducers[i]; - FieldElement m = field().neg(field().inv(rit->element())); - - for (auto it = std::next(rit); it != reducers[i+1]; ++it) - add_in_z(it->index(), rit->index(), m, it->element()); - - if (static_cast(i + 1) != reducers.size() - 1) - { - auto it = reducers[i+1]; - add_in_z(it->index(), rit->index(), m, it->element()); - } - } - if (reducers.size() > 2) - Z.drop_low(last_low); - - // apply changes in b (the complexity here could get ugly) - // Specifically, transpose b_changes and add it in - std::unordered_map b_changes_transposed; - for (auto& b_row : b_changes) - for (auto& bx : b_row.second) - b_changes_transposed[bx.index()].emplace_back(bx.element(), b_row.first, bx.index()); - - for (auto& b_col : b_changes_transposed) - { -#if 0 - std::cout << "Adding:" << std::endl; - for (auto& x : b_col.second) - std::cout << x.element() << ' ' << row(x) << ' ' << col(x) << std::endl; -#endif - Chain::addto(B.col(b_col.first), field().id(), b_col.second, field(), b_row_cmp); - assert(!B.col(b_col.first).empty()); - B.fix(b_col.first); - // no need to update low (additions from bottom up) - } - } // z_row.size() > 1 - - // 2: subtract cycle from every chain in C - const Column& Zj = Z.col(j); - //std::cout << "Zj:" << std::endl; - //for (auto& x : Zj) - // std::cout << x.element() << " * " << row(x) << std::endl; - - IndexChain Ccols; // save the columns in C, we'll be modifying C.row(cell) - for (auto& x : C.row(cell)) - Ccols.emplace_back(x.element(), col(x)); - - for (auto& x : Ccols) - { - Index c = x.index(); - FieldElement m = field().neg(field().div(x.element(), e)); // m = -C[k][cell]/Z[j][cell] - //std::cout << "Adding to C: " << c << std::endl; - Chain::addto(C.col(c), m, Zj, field(), row_cmp); - C.fix(c); - // we don't care about lows in C, so don't update them - } - - // 3: drop - assert(Z.row(cell).size() == 1); - Z.drop_col(j); - assert(Z.row(cell).empty()); - assert(C.row(cell).empty()); - Z.drop_row(cell); - C.drop_row(cell); - assert(B.row(j).empty()); - B.drop_row(j); - - Index birth = birth_index[j]; - birth_index.erase(j); - - return birth; - } -} - - -/* debug routines */ -template -void -dionysus::ZigzagPersistence:: -check_b_cols() const -{ - // check that entries in B refer to existing Z columns - bool stop = false; - for (auto& b : B.columns()) - for (auto& x : b.second) - if (!Z.col_exists(row(x))) - { - std::cout << "B refers to a non-existent column in Z: " << row(x) << std::endl; - stop = true; - } - if (stop) - assert(0); -} - -template -template -void -dionysus::ZigzagPersistence:: -check_cycles(const SimplexToIndex& s2i, const IndexToSimplex& i2s) const -{ - typedef typename Column::value_type Entry; - auto row_cmp = [this](const Entry& e1, const Entry& e2) - { return this->cmp()(row(e1), row(e2)); }; - - for (auto& z : Z.columns()) - { - Column res; - for (auto& x : z.second) - { - Column bdry = boundary(row(x), s2i, i2s); - Chain::addto(res, x.element(), bdry, field(), row_cmp); - } - assert(res.empty()); - } -} - -template -template -void -dionysus::ZigzagPersistence:: -check_boundaries(const SimplexToIndex& s2i, const IndexToSimplex& i2s) const -{ - check_cycles(s2i, i2s); - - for (auto& x : B.columns()) - if (!C.col_exists(x.first)) - { - std::cout << x.first << " in B, but not in C" << std::endl; - assert(0); - } - - for (auto& x : C.columns()) - if (!B.col_exists(x.first)) - { - std::cout << x.first << " in B, but not in C" << std::endl; - assert(0); - } - - for (auto& x : B.columns()) - { - auto zb = zb_dot(x.first); - auto dc = dc_dot(x.first, s2i, i2s); - - auto it_zb = zb.begin(), - it_dc = dc.begin(); - for (; it_zb != zb.end(); ++it_zb, ++it_dc) - { - if (it_zb->element() != it_dc->element() || row(*it_zb) != row(*it_dc)) - { - std::cout << "Boundary mismatch: " << x.first << std::endl; - std::cout << "===" << std::endl; - for (auto& x : zb) - std::cout << " " << x.element() << ' ' << row(x) << std::endl; - for (auto& y : B.col(x.first)) - { - std::cout << " " << y.element() << " * " << row(y) << std::endl; - for (auto& z : Z.col(row(y))) - std::cout << " " << z.element() << ' ' << row(z) << std::endl; - std::cout << " ---" << std::endl; - } - std::cout << "===" << std::endl; - for (auto& x : dc) - std::cout << " " << x.element() << ' ' << row(x) << std::endl; - for (auto& y : C.col(x.first)) - { - std::cout << " " << y.element() << " * " << row(y) << std::endl; - for (auto& z : boundary(row(y), s2i, i2s)) - std::cout << " " << z.element() << ' ' << row(z) << std::endl; - std::cout << " ---" << std::endl; - } - assert(0); - } - } - if (it_zb != zb.end() || it_dc != dc.end()) - { - std::cout << "zb.end() doesn't match dc.end()" << std::endl; - assert(0); - } - } -} - -template -typename dionysus::ZigzagPersistence::Column -dionysus::ZigzagPersistence:: -zb_dot(Index c) const -{ - typedef typename Column::value_type Entry; - auto row_cmp = [this](const Entry& e1, const Entry& e2) - { return this->cmp()(row(e1), row(e2)); }; - Column res; - for (auto& x : B.col(c)) - Chain::addto(res, x.element(), Z.col(row(x)), field(), row_cmp); - - return res; -} - -template -template -typename dionysus::ZigzagPersistence::Column -dionysus::ZigzagPersistence:: -dc_dot(Index c, const SimplexToIndex& s2i, const IndexToSimplex& i2s) const -{ - typedef typename Column::value_type Entry; - auto row_cmp = [this](const Entry& e1, const Entry& e2) - { return this->cmp()(row(e1), row(e2)); }; - Column res; - for (auto& x : C.col(c)) - { - Column bdry = boundary(row(x), s2i, i2s); - Chain::addto(res, x.element(), bdry, field(), row_cmp); - } - return res; -} - -template -template -typename dionysus::ZigzagPersistence::Column -dionysus::ZigzagPersistence:: -boundary(Index i, const SimplexToIndex& s2i, const IndexToSimplex& i2s) const -{ - typedef typename Column::value_type Entry; - auto row_cmp = [this](const Entry& e1, const Entry& e2) - { return this->cmp()(row(e1), row(e2)); }; - Column bdry; - auto s = i2s(i); - for (auto y : s.boundary(field())) - bdry.emplace_back(y.element(), s2i(y.index()), 0); - std::sort(bdry.begin(), bdry.end(), row_cmp); - return bdry; -} - -template -void -dionysus::ZigzagPersistence:: -check_sorted() const -{ - typedef typename Column::value_type Entry; - auto row_cmp = [this](const Entry& e1, const Entry& e2) - { return this->cmp()(row(e1), row(e2)); }; - typedef typename DequeColumn::value_type DequeEntry; - auto b_row_cmp = [this](const DequeEntry& e1, const DequeEntry& e2) - { return this->cmp()(row(e1), row(e2)); }; - - for (auto& x : Z.columns()) - if (!std::is_sorted(x.second.begin(), x.second.end(), row_cmp)) - { - std::cout << "Z column not sorted: " << x.first << std::endl; - assert(0); - } - for (auto& x : C.columns()) - if (!std::is_sorted(x.second.begin(), x.second.end(), row_cmp)) - { - std::cout << "C column not sorted: " << x.first << std::endl; - assert(0); - } - for (auto& x : B.columns()) - if (!std::is_sorted(x.second.begin(), x.second.end(), b_row_cmp)) - { - std::cout << "B column not sorted: " << x.first << std::endl; - assert(0); - } -} - diff --git a/src/Zigzag_persistence/example/ext_zz/fzz/fzz.cpp b/src/Zigzag_persistence/example/ext_zz/fzz/fzz.cpp deleted file mode 100644 index 5217a4f38c..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/fzz/fzz.cpp +++ /dev/null @@ -1,206 +0,0 @@ -#include "fzz.h" - -#include - -// phat headers -// wrapper algorithm that computes the persistence pairs of a given boundary matrix using a specified algorithm -#include - -// main data structure (choice affects performance) -#include -#include - -// algorithm (choice affects performance) -#include -#include -#include -#include - -namespace FZZ { - -template -class VecHash { -public: - size_t operator()(const std::vector& v) const; -}; - -template -size_t VecHash - ::operator()(const std::vector& v) const { - - std::size_t seed = 0; - - for (auto e : v) { boost::hash_combine(seed, e); } - - return seed; -} - -template -class VecEqual { -public: - bool operator()(const std::vector& v1, - const std::vector& v2) const; -}; - -template -bool VecEqual - ::operator()(const std::vector& v1, - const std::vector& v2) const { - - if (v1.size() != v2.size()) { return false; } - - for (unsigned int i = 0; i < v1.size(); i ++) { - if (v1[i] != v2[i]) { - return false; - } - } - - return true; -} - -typedef std::unordered_map< Simplex, Integer, - VecHash, VecEqual > SimplexIdMap; - -void getBoundaryChainPhat(const std::vector &id_maps, - const Simplex &simp, std::vector &bound_c) { - - bound_c.clear(); - - if (simp.size() <= 1) { return; } - - bound_c.reserve(simp.size()); - - Simplex bound_simp(simp.begin()+1, simp.end()); - bound_c.push_back(id_maps.at(bound_simp.size() - 1).at(bound_simp)); - - for (unsigned int i = 0; i < simp.size()-1; ++i) { - bound_simp[i] = simp[i]; - bound_c.push_back(id_maps.at(bound_simp.size() - 1).at(bound_simp)); - } - - std::sort(bound_c.begin(), bound_c.end()); -} - -inline Integer getDim(const std::vector &bound_c) { - if (bound_c.size() == 0) { return 0; } - return bound_c.size() - 1; -} - -void FastZigzag::compute(const std::vector &filt_simp, - const std::vector &filt_op, - std::vector< std::tuple > *persistence) { - - orig_f_add_id.clear(); - orig_f_del_id.clear(); - persistence->clear(); - - simp_num = 0; - Integer max_dim = 0; - for (unsigned int i = 0; i < filt_op.size(); ++i) { - if (filt_op[i]) { - ++simp_num; - if (static_cast(filt_simp[i].size()) - 1 > max_dim) { max_dim = filt_simp[i].size() - 1; } - } - } - - std::vector bound_c; - // phat::boundary_matrix< phat::vector_vector > bound_chains; - phat::boundary_matrix< phat::bit_tree_pivot_column > bound_chains; - bound_chains.set_num_cols(simp_num * 2 + 1); - - // Add the Omega vertex for the coning - bound_chains.set_col(0, bound_c); - bound_chains.set_dim(0, 0); - - orig_f_add_id.reserve(simp_num); - orig_f_del_id.reserve(simp_num); - - std::vector del_ids; - del_ids.reserve(simp_num); - - std::vector *p_id_maps = new std::vector(max_dim+1); - std::vector &id_maps = *p_id_maps; - - Integer orig_f_id = 0; - Integer s_id = 1; - - for (unsigned int i = 0; i < filt_simp.size(); ++i) { - const Simplex &simp = filt_simp[i]; - - if (filt_op[i]) { - getBoundaryChainPhat(id_maps, simp, bound_c); - bound_chains.set_col(s_id, bound_c); - bound_chains.set_dim(s_id, getDim(bound_c)); - - // assert(s_id == bound_chains.size()-1); - id_maps.at(simp.size() - 1)[simp] = s_id; - orig_f_add_id.push_back(orig_f_id); - s_id ++; - } else { - del_ids.push_back(id_maps.at(simp.size() - 1)[simp]); - id_maps.at(simp.size() - 1).erase(simp); - orig_f_del_id.push_back(orig_f_id); - } - - orig_f_id ++; - } - - for (Integer i = id_maps.size() - 1; i >= 0; -- i) { - for (const auto &it : id_maps.at(i)) { - del_ids.push_back(it.second); - orig_f_del_id.push_back(orig_f_id); - orig_f_id ++; - } - } - - assert(del_ids.size() == s_id-1); - delete p_id_maps; - - assert(simp_num == del_ids.size()); - - std::vector cone_sid(simp_num+1); - - for (auto del_id_it = del_ids.rbegin(); del_id_it != del_ids.rend(); ++del_id_it) { - bound_c.clear(); - bound_c.push_back(*del_id_it); - - std::vector orig_bound_c; - bound_chains.get_col(*del_id_it, orig_bound_c); - - if (orig_bound_c.size() == 0) { - bound_c.push_back(0); - } else { - for (auto bsimp : orig_bound_c) { - // assert(cone_sid[bsimp] >= 0); - bound_c.push_back(cone_sid[bsimp]); - } - } - - std::sort(bound_c.begin(), bound_c.end()); - - bound_chains.set_col(s_id, bound_c); - bound_chains.set_dim(s_id, getDim(bound_c)); - - cone_sid[*del_id_it] = s_id; - - s_id ++; - } - - phat::persistence_pairs pairs; - phat::compute_persistence_pairs< phat::twist_reduction >( pairs, bound_chains ); - - for (phat::index idx = 0; idx < pairs.get_num_pairs(); idx++) { - Integer b = pairs.get_pair(idx).first; - Integer d = pairs.get_pair(idx).second - 1; - Integer p = bound_chains.get_dim(b); - - if (d < simp_num) { mapOrdIntv(b, d); } - else { mapRelExtIntv(p, b, d); } - - if (b > static_cast(filt_simp.size())) { continue; } - if (d > static_cast(filt_simp.size())) { d = filt_simp.size(); } - persistence->emplace_back(b, d, p); - } -} - -} // namespace FZZ { diff --git a/src/Zigzag_persistence/example/ext_zz/fzz/fzz.h b/src/Zigzag_persistence/example/ext_zz/fzz/fzz.h deleted file mode 100644 index 8613bc3793..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/fzz/fzz.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef _FZZ_H_ -#define _FZZ_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace FZZ { - -typedef int Integer; -typedef std::vector Simplex; - -class FastZigzag { -public: - /* - 'filt_simp' and 'filt_op' should have the same length which altogether - specify the input zigzag filtration. 'filt_simp' specifies the simplices - being added or deleted (following the order of the filtration) and - 'filt_op' specifies whether it's an addition (true) or deletion (false). - 'persistence' returns the barcode, with the first element of the tuple - being the birth, the second element being the death, and the third - being the dimension. - */ - void compute( - const std::vector &filt_simp, - const std::vector &filt_op, - std::vector< std::tuple > *persistence); - -private: - void mapOrdIntv(Integer &b, Integer &d) { - // assert(b-1 > 0); - // assert(d < orig_f_add_id.size()); - - // Up-down interval is same, - // so directly map to interval of input filtration - b = orig_f_add_id[b-1] + 1; - d = orig_f_add_id[d]; - } - - void mapRelExtIntv(Integer &p, Integer &b, Integer &d) { - // assert(d >= simp_num); - - if (b > simp_num) { // Open-closed - // Map to up-down interval - std::swap(b, d); - b = 3*simp_num - b; - d = 3*simp_num - d; - p --; - - // Map to interval of input filtration - b = orig_f_del_id[b-1-simp_num] + 1; - d = orig_f_del_id[d-simp_num]; - } else { // Closed-closed - // Map to up-down interval - d = 3*simp_num - d-1; - - // Map to interval of input filtration - b = orig_f_add_id[b-1]; - d = orig_f_del_id[d-simp_num]; - - if (b < d) { - b = b+1; - } else { - std::swap(b, d); - b = b+1; - p = p-1; - } - } - } - -private: - // 'orig_f_add_id' and 'orig_f_del_id' form a mapping - // from the up-down filtration to the original filtration - std::vector orig_f_add_id; - std::vector orig_f_del_id; - - Integer simp_num; -}; - -} - -#endif diff --git a/src/Zigzag_persistence/example/ext_zz/phat/algorithms/chunk_reduction.h b/src/Zigzag_persistence/example/ext_zz/phat/algorithms/chunk_reduction.h deleted file mode 100644 index 179702312f..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/algorithms/chunk_reduction.h +++ /dev/null @@ -1,223 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -#include -#include - -namespace phat { - class chunk_reduction { - public: - enum column_type { GLOBAL - , LOCAL_POSITIVE - , LOCAL_NEGATIVE }; - - public: - template< typename Representation > - void operator() ( boundary_matrix< Representation >& boundary_matrix ) { - - - const index nr_columns = boundary_matrix.get_num_cols(); - if( omp_get_max_threads( ) > nr_columns ) - omp_set_num_threads( 1 ); - - const dimension max_dim = boundary_matrix.get_max_dim(); - - std::vector< index > lowest_one_lookup( nr_columns, -1 ); - std::vector < column_type > column_type( nr_columns, GLOBAL ); - std::vector< char > is_active( nr_columns, false ); - - const index chunk_size = omp_get_max_threads() == 1 ? (index)sqrt( (double)nr_columns ) : nr_columns / omp_get_max_threads(); - - std::vector< index > chunk_boundaries; - for( index cur_boundary = 0; cur_boundary < nr_columns; cur_boundary += chunk_size ) - chunk_boundaries.push_back( cur_boundary ); - chunk_boundaries.push_back( nr_columns ); - - for( dimension cur_dim = max_dim; cur_dim >= 1; cur_dim-- ) { - // Phase 1: Reduce chunks locally -- 1st pass - #pragma omp parallel for schedule( guided, 1 ) - for( index chunk_id = 0; chunk_id < (index)chunk_boundaries.size() - 1; chunk_id++ ) - _local_chunk_reduction( boundary_matrix, lowest_one_lookup, column_type, cur_dim, - chunk_boundaries[ chunk_id ], chunk_boundaries[ chunk_id + 1 ], chunk_boundaries[ chunk_id ] ); - boundary_matrix.sync(); - - // Phase 1: Reduce chunks locally -- 2nd pass - #pragma omp parallel for schedule( guided, 1 ) - for( index chunk_id = 1; chunk_id < (index)chunk_boundaries.size( ) - 1; chunk_id++ ) - _local_chunk_reduction( boundary_matrix, lowest_one_lookup, column_type, cur_dim, - chunk_boundaries[ chunk_id ], chunk_boundaries[ chunk_id + 1 ], chunk_boundaries[ chunk_id - 1 ] ); - boundary_matrix.sync( ); - } - - // get global columns - std::vector< index > global_columns; - for( index cur_col_idx = 0; cur_col_idx < nr_columns; cur_col_idx++ ) - if( column_type[ cur_col_idx ] == GLOBAL ) - global_columns.push_back( cur_col_idx ); - - // get active columns - #pragma omp parallel for - for( index idx = 0; idx < (index)global_columns.size(); idx++ ) - is_active[ global_columns[ idx ] ] = true; - _get_active_columns( boundary_matrix, lowest_one_lookup, column_type, global_columns, is_active ); - - // Phase 2+3: Simplify columns and reduce them - for( dimension cur_dim = max_dim; cur_dim >= 1; cur_dim-- ) { - // Phase 2: Simplify columns - std::vector< index > temp_col; - #pragma omp parallel for schedule( guided, 1 ), private( temp_col ) - for( index idx = 0; idx < (index)global_columns.size(); idx++ ) - if( boundary_matrix.get_dim( global_columns[ idx ] ) == cur_dim ) - _global_column_simplification( global_columns[ idx ], boundary_matrix, lowest_one_lookup, column_type, is_active, temp_col ); - boundary_matrix.sync(); - - // Phase 3: Reduce columns - for( index idx = 0; idx < (index)global_columns.size(); idx++ ) { - index cur_col = global_columns[ idx ]; - if( boundary_matrix.get_dim( cur_col ) == cur_dim && column_type[ cur_col ] == GLOBAL ) { - index lowest_one = boundary_matrix.get_max_index( cur_col ); - while( lowest_one != -1 && lowest_one_lookup[ lowest_one ] != -1 ) { - boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col ); - lowest_one = boundary_matrix.get_max_index( cur_col ); - } - if( lowest_one != -1 ) { - lowest_one_lookup[ lowest_one ] = cur_col; - boundary_matrix.clear( lowest_one ); - } - boundary_matrix.finalize( cur_col ); - } - } - } - - boundary_matrix.sync(); - } - - protected: - template< typename Representation > - void _local_chunk_reduction( boundary_matrix< Representation >& boundary_matrix - , std::vector& lowest_one_lookup - , std::vector< column_type >& column_type - , const dimension cur_dim - , const index chunk_begin - , const index chunk_end - , const index row_begin ) { - - for( index cur_col = chunk_begin; cur_col < chunk_end; cur_col++ ) { - if( column_type[ cur_col ] == GLOBAL && boundary_matrix.get_dim( cur_col ) == cur_dim ) { - index lowest_one = boundary_matrix.get_max_index( cur_col ); - while( lowest_one != -1 && lowest_one >= row_begin && lowest_one_lookup[ lowest_one ] != -1 ) { - boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col ); - lowest_one = boundary_matrix.get_max_index( cur_col ); - } - if( lowest_one >= row_begin ) { - lowest_one_lookup[ lowest_one ] = cur_col; - column_type[ cur_col ] = LOCAL_NEGATIVE; - column_type[ lowest_one ] = LOCAL_POSITIVE; - boundary_matrix.clear( lowest_one ); - boundary_matrix.finalize( cur_col ); - } - } - } - } - - template< typename Representation > - void _get_active_columns( const boundary_matrix< Representation >& boundary_matrix - , const std::vector< index >& lowest_one_lookup - , const std::vector< column_type >& column_type - , const std::vector< index >& global_columns - , std::vector< char >& is_active ) { - - const index nr_columns = boundary_matrix.get_num_cols(); - std::vector< char > finished( nr_columns, false ); - - std::vector< std::pair < index, index > > stack; - std::vector< index > cur_col_values; - #pragma omp parallel for schedule( guided, 1 ), private( stack, cur_col_values ) - for( index idx = 0; idx < (index)global_columns.size(); idx++ ) { - bool pop_next = false; - index start_col = global_columns[ idx ]; - stack.push_back( std::pair< index, index >( start_col, -1 ) ); - while( !stack.empty() ) { - index cur_col = stack.back().first; - index prev_col = stack.back().second; - if( pop_next ) { - stack.pop_back(); - pop_next = false; - if( prev_col != -1 ) { - if( is_active[ cur_col ] ) { - is_active[ prev_col ] = true; - } - if( prev_col == stack.back().first ) { - finished[ prev_col ] = true; - pop_next = true; - } - } - } else { - pop_next = true; - boundary_matrix.get_col( cur_col, cur_col_values ); - for( index idx = 0; idx < (index) cur_col_values.size(); idx++ ) { - index cur_row = cur_col_values[ idx ]; - if( ( column_type[ cur_row ] == GLOBAL ) ) { - is_active[ cur_col ] = true; - } else if( column_type[ cur_row ] == LOCAL_POSITIVE ) { - index next_col = lowest_one_lookup[ cur_row ]; - if( next_col != cur_col && !finished[ cur_col ] ) { - stack.push_back( std::make_pair( next_col, cur_col ) ); - pop_next = false; - } - } - } - } - } - } - } - - template< typename Representation > - void _global_column_simplification( const index col_idx - , boundary_matrix< Representation >& boundary_matrix - , const std::vector< index >& lowest_one_lookup - , const std::vector< column_type >& column_type - , const std::vector< char >& is_active - , std::vector< index >& temp_col ) - { - temp_col.clear(); - while( !boundary_matrix.is_empty( col_idx ) ) { - index cur_row = boundary_matrix.get_max_index( col_idx ); - switch( column_type[ cur_row ] ) { - case GLOBAL: - temp_col.push_back( cur_row ); - boundary_matrix.remove_max( col_idx ); - break; - case LOCAL_NEGATIVE: - boundary_matrix.remove_max( col_idx ); - break; - case LOCAL_POSITIVE: - if( is_active[ lowest_one_lookup[ cur_row ] ] ) - boundary_matrix.add_to( lowest_one_lookup[ cur_row ], col_idx ); - else - boundary_matrix.remove_max( col_idx ); - break; - } - } - std::reverse( temp_col.begin(), temp_col.end() ); - boundary_matrix.set_col( col_idx, temp_col ); - } - }; -} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/algorithms/row_reduction.h b/src/Zigzag_persistence/example/ext_zz/phat/algorithms/row_reduction.h deleted file mode 100644 index cdd1a8fd18..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/algorithms/row_reduction.h +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -#include -#include - -namespace phat { - class row_reduction { - public: - template< typename Representation > - void operator() ( boundary_matrix< Representation >& boundary_matrix ) { - - const index nr_columns = boundary_matrix.get_num_cols(); - std::vector< std::vector< index > > lowest_one_lookup( nr_columns ); - - for( index cur_col = nr_columns - 1; cur_col >= 0; cur_col-- ) { - if( !boundary_matrix.is_empty( cur_col ) ) - lowest_one_lookup[ boundary_matrix.get_max_index( cur_col ) ].push_back( cur_col ); - - if( !lowest_one_lookup[ cur_col ].empty() ) { - boundary_matrix.clear( cur_col ); - boundary_matrix.finalize( cur_col ); - std::vector< index >& cols_with_cur_lowest = lowest_one_lookup[ cur_col ]; - index source = *min_element( cols_with_cur_lowest.begin(), cols_with_cur_lowest.end() ); - for( index idx = 0; idx < (index)cols_with_cur_lowest.size(); idx++ ) { - index target = cols_with_cur_lowest[ idx ]; - if( target != source && !boundary_matrix.is_empty( target ) ) { - boundary_matrix.add_to( source, target ); - if( !boundary_matrix.is_empty( target ) ) { - index lowest_one_of_target = boundary_matrix.get_max_index( target ); - lowest_one_lookup[ lowest_one_of_target ].push_back( target ); - } - } - } - } - } - } - }; -} \ No newline at end of file diff --git a/src/Zigzag_persistence/example/ext_zz/phat/algorithms/spectral_sequence_reduction.h b/src/Zigzag_persistence/example/ext_zz/phat/algorithms/spectral_sequence_reduction.h deleted file mode 100644 index bf442e6089..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/algorithms/spectral_sequence_reduction.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Jan Reininghaus - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -#include -#include - -namespace phat { - class spectral_sequence_reduction { - public: - template< typename Representation > - void operator () ( boundary_matrix< Representation >& boundary_matrix ) { - - const index nr_columns = boundary_matrix.get_num_cols(); - std::vector< index > lowest_one_lookup( nr_columns, -1 ); - - //const index num_stripes = (index) sqrt( (double)nr_columns ); - const index num_stripes = omp_get_max_threads(); - - index block_size = ( nr_columns % num_stripes == 0 ) ? nr_columns / num_stripes : block_size = nr_columns / num_stripes + 1; - - std::vector< std::vector< index > > unreduced_cols_cur_pass( num_stripes ); - std::vector< std::vector< index > > unreduced_cols_next_pass( num_stripes ); - - for( index cur_dim = boundary_matrix.get_max_dim(); cur_dim >= 1 ; cur_dim-- ) { - #pragma omp parallel for schedule( guided, 1 ) - for( index cur_stripe = 0; cur_stripe < num_stripes; cur_stripe++ ) { - index col_begin = cur_stripe * block_size; - index col_end = std::min( (cur_stripe+1) * block_size, nr_columns ); - for( index cur_col = col_begin; cur_col < col_end; cur_col++ ) - if( boundary_matrix.get_dim( cur_col ) == cur_dim && boundary_matrix.get_max_index( cur_col ) != -1 ) - unreduced_cols_cur_pass[ cur_stripe ].push_back( cur_col ); - } - for( index cur_pass = 0; cur_pass < num_stripes; cur_pass++ ) { - boundary_matrix.sync(); - #pragma omp parallel for schedule( guided, 1 ) - for( int cur_stripe = 0; cur_stripe < num_stripes; cur_stripe++ ) { - index row_begin = (cur_stripe - cur_pass) * block_size; - index row_end = row_begin + block_size; - unreduced_cols_next_pass[ cur_stripe ].clear(); - for( index idx = 0; idx < (index)unreduced_cols_cur_pass[ cur_stripe ].size(); idx++ ) { - index cur_col = unreduced_cols_cur_pass[ cur_stripe ][ idx ]; - index lowest_one = boundary_matrix.get_max_index( cur_col ); - while( lowest_one != -1 && lowest_one >= row_begin && lowest_one < row_end && lowest_one_lookup[ lowest_one ] != -1 ) { - boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col ); - lowest_one = boundary_matrix.get_max_index( cur_col ); - } - if( lowest_one != -1 ) { - if( lowest_one >= row_begin && lowest_one < row_end ) { - lowest_one_lookup[ lowest_one ] = cur_col; - boundary_matrix.clear( lowest_one ); - boundary_matrix.finalize( cur_col ); - } else { - unreduced_cols_next_pass[ cur_stripe ].push_back( cur_col ); - } - } - } - unreduced_cols_next_pass[ cur_stripe ].swap( unreduced_cols_cur_pass[ cur_stripe ] ); - } - } - } - } - }; -} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/algorithms/standard_reduction.h b/src/Zigzag_persistence/example/ext_zz/phat/algorithms/standard_reduction.h deleted file mode 100644 index e490a5e0d1..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/algorithms/standard_reduction.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -#include -#include - -namespace phat { - class standard_reduction { - public: - template< typename Representation > - void operator() ( boundary_matrix< Representation >& boundary_matrix ) { - - const index nr_columns = boundary_matrix.get_num_cols(); - std::vector< index > lowest_one_lookup( nr_columns, -1 ); - - for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) { - index lowest_one = boundary_matrix.get_max_index( cur_col ); - while( lowest_one != -1 && lowest_one_lookup[ lowest_one ] != -1 ) { - boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col ); - lowest_one = boundary_matrix.get_max_index( cur_col ); - } - if( lowest_one != -1 ) { - lowest_one_lookup[ lowest_one ] = cur_col; - } - boundary_matrix.finalize( cur_col ); - } - } - }; -} - diff --git a/src/Zigzag_persistence/example/ext_zz/phat/algorithms/twist_reduction.h b/src/Zigzag_persistence/example/ext_zz/phat/algorithms/twist_reduction.h deleted file mode 100644 index 2357df0256..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/algorithms/twist_reduction.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -#include -#include - -namespace phat { - class twist_reduction { - public: - template< typename Representation > - void operator () ( boundary_matrix< Representation >& boundary_matrix ) { - - const index nr_columns = boundary_matrix.get_num_cols(); - std::vector< index > lowest_one_lookup( nr_columns, -1 ); - - for( index cur_dim = boundary_matrix.get_max_dim(); cur_dim >= 1 ; cur_dim-- ) { - for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) { - if( boundary_matrix.get_dim( cur_col ) == cur_dim ) { - index lowest_one = boundary_matrix.get_max_index( cur_col ); - while( lowest_one != -1 && lowest_one_lookup[ lowest_one ] != -1 ) { - boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col ); - lowest_one = boundary_matrix.get_max_index( cur_col ); - } - if( lowest_one != -1 ) { - lowest_one_lookup[ lowest_one ] = cur_col; - boundary_matrix.clear( lowest_one ); - } - boundary_matrix.finalize( cur_col ); - } - } - } - } - }; -} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/boundary_matrix.h b/src/Zigzag_persistence/example/ext_zz/phat/boundary_matrix.h deleted file mode 100644 index 10c66cca13..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/boundary_matrix.h +++ /dev/null @@ -1,343 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -#include -#include - -// interface class for the main data structure -- implementations of the interface can be found in ./representations -namespace phat { - template< class Representation = bit_tree_pivot_column > - class boundary_matrix - { - - protected: - Representation rep; - - // interface functions -- actual implementation and complexity depends on chosen @Representation template - public: - // get overall number of columns in boundary_matrix - index get_num_cols() const { return rep._get_num_cols(); } - - // set overall number of columns in boundary_matrix - void set_num_cols( index nr_of_columns ) { rep._set_num_cols( nr_of_columns ); } - - // get dimension of given index - dimension get_dim( index idx ) const { return rep._get_dim( idx ); } - - // set dimension of given index - void set_dim( index idx, dimension dim ) { rep._set_dim( idx, dim ); } - - // replaces content of @col with boundary of given index - void get_col( index idx, column& col ) const { col.clear(); rep._get_col( idx, col ); } - - // set column @idx to the values contained in @col - void set_col( index idx, const column& col ) { rep._set_col( idx, col ); } - - // true iff boundary of given column is empty - bool is_empty( index idx ) const { return rep._is_empty( idx ); } - - // largest index of given column (new name for lowestOne()) -- NOT thread-safe - index get_max_index( index idx ) const { return rep._get_max_index( idx ); } - - // removes maximal index from given column - void remove_max( index idx ) { rep._remove_max( idx ); } - - // adds column @source to column @target' - void add_to( index source, index target ) { rep._add_to( source, target ); } - - // clears given column - void clear( index idx ) { rep._clear( idx ); } - - // finalizes given column - void finalize( index idx ) { rep._finalize( idx ); } - - // syncronizes all internal data structures -- has to be called before and after any multithreaded access! - void sync() { rep._sync(); } - - // info functions -- independent of chosen 'Representation' - public: - // maximal dimension - dimension get_max_dim() const { - dimension cur_max_dim = 0; - for( index idx = 0; idx < get_num_cols(); idx++ ) - cur_max_dim = get_dim( idx ) > cur_max_dim ? get_dim( idx ) : cur_max_dim; - return cur_max_dim; - } - - // number of nonzero rows for given column @idx - index get_num_rows( index idx ) const { - column cur_col; - get_col( idx, cur_col ); - return cur_col.size(); - } - - // maximal number of nonzero rows of all columns - index get_max_col_entries() const { - index max_col_entries = -1; - const index nr_of_columns = get_num_cols(); - for( index idx = 0; idx < nr_of_columns; idx++ ) - max_col_entries = get_num_rows( idx ) > max_col_entries ? get_num_rows( idx ) : max_col_entries; - return max_col_entries; - } - - // maximal number of nonzero cols of all rows - index get_max_row_entries() const { - size_t max_row_entries = 0; - const index nr_of_columns = get_num_cols(); - std::vector< std::vector< index > > transposed_matrix( nr_of_columns ); - column temp_col; - for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) { - get_col( cur_col, temp_col ); - for( index idx = 0; idx < (index)temp_col.size(); idx++) - transposed_matrix[ temp_col[ idx ] ].push_back( cur_col ); - } - for( index idx = 0; idx < nr_of_columns; idx++ ) - max_row_entries = transposed_matrix[ idx ].size() > max_row_entries ? transposed_matrix[ idx ].size() : max_row_entries; - return max_row_entries; - } - - // overall number of entries in the matrix - index get_num_entries() const { - index number_of_nonzero_entries = 0; - const index nr_of_columns = get_num_cols(); - for( index idx = 0; idx < nr_of_columns; idx++ ) - number_of_nonzero_entries += get_num_rows( idx ); - return number_of_nonzero_entries; - } - - // operators / constructors - public: - boundary_matrix() {}; - - template< class OtherRepresentation > - boundary_matrix( const boundary_matrix< OtherRepresentation >& other ) { - *this = other; - } - - template< typename OtherRepresentation > - bool operator==( const boundary_matrix< OtherRepresentation >& other_boundary_matrix ) const { - const index number_of_columns = this->get_num_cols(); - - if( number_of_columns != other_boundary_matrix.get_num_cols() ) - return false; - - column temp_col; - column other_temp_col; - for( index idx = 0; idx < number_of_columns; idx++ ) { - this->get_col( idx, temp_col ); - other_boundary_matrix.get_col( idx, other_temp_col ); - if( temp_col != other_temp_col || this->get_dim( idx ) != other_boundary_matrix.get_dim( idx ) ) - return false; - } - return true; - } - - template< typename OtherRepresentation > - bool operator!=( const boundary_matrix< OtherRepresentation >& other_boundary_matrix ) const { - return !( *this == other_boundary_matrix ); - } - - template< typename OtherRepresentation > - boundary_matrix< Representation >& operator=( const boundary_matrix< OtherRepresentation >& other ) - { - const index nr_of_columns = other.get_num_cols(); - this->set_num_cols( nr_of_columns ); - column temp_col; - for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) { - this->set_dim( cur_col, other.get_dim( cur_col ) ); - other.get_col( cur_col, temp_col ); - this->set_col( cur_col, temp_col ); - } - - // by convention, always return *this - return *this; - } - - // I/O -- independent of chosen 'Representation' - public: - - // initializes boundary_matrix from (vector, vector) pair -- untested - template< typename index_type, typename dimemsion_type > - void load_vector_vector( const std::vector< std::vector< index_type > >& input_matrix, const std::vector< dimemsion_type >& input_dims ) { - const index nr_of_columns = (index)input_matrix.size(); - this->set_num_cols( nr_of_columns ); - column temp_col; - #pragma omp parallel for private( temp_col ) - for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) { - this->set_dim( cur_col, (dimension)input_dims[ cur_col ] ); - - index num_rows = input_matrix[ cur_col ].size(); - temp_col.resize( num_rows ); - for( index cur_row = 0; cur_row < num_rows; cur_row++ ) - temp_col[ cur_row ] = (index)input_matrix[ cur_col ][ cur_row ]; - this->set_col( cur_col, temp_col ); - } - } - - template< typename index_type, typename dimemsion_type > - void save_vector_vector( std::vector< std::vector< index_type > >& output_matrix, std::vector< dimemsion_type >& output_dims ) { - const index nr_of_columns = get_num_cols(); - output_matrix.resize( nr_of_columns ); - output_dims.resize( nr_of_columns ); - column temp_col; - for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) { - output_dims[ cur_col ] = (dimemsion_type)get_dim( cur_col ); - get_col( cur_col, temp_col ); - index num_rows = temp_col.size(); - output_matrix[ cur_col ].clear(); - output_matrix[ cur_col ].resize( num_rows ); - for( index cur_row = 0; cur_row < num_rows; cur_row++ ) - output_matrix[ cur_col ][ cur_row ] = (index_type)temp_col[ cur_row ]; - } - } - - - // Loads the boundary_matrix from given file in ascii format - // Format: each line represents a column, first number is dimension, other numbers are the content of the column. - // Ignores empty lines and lines starting with a '#'. - bool load_ascii( std::string filename ) { - // first count number of columns: - std::string cur_line; - std::ifstream dummy( filename .c_str() ); - if( dummy.fail() ) - return false; - - index number_of_columns = 0; - while( getline( dummy, cur_line ) ) { - cur_line.erase(cur_line.find_last_not_of(" \t\n\r\f\v") + 1); - if( cur_line != "" && cur_line[ 0 ] != '#' ) - number_of_columns++; - - } - this->set_num_cols( number_of_columns ); - dummy.close(); - - std::ifstream input_stream( filename.c_str() ); - if( input_stream.fail() ) - return false; - - column temp_col; - index cur_col = -1; - while( getline( input_stream, cur_line ) ) { - cur_line.erase(cur_line.find_last_not_of(" \t\n\r\f\v") + 1); - if( cur_line != "" && cur_line[ 0 ] != '#' ) { - cur_col++; - std::stringstream ss( cur_line ); - - int64_t temp_dim; - ss >> temp_dim; - this->set_dim( cur_col, (dimension) temp_dim ); - - int64_t temp_index; - temp_col.clear(); - while( ss.good() ) { - ss >> temp_index; - temp_col.push_back( (index)temp_index ); - } - std::sort( temp_col.begin(), temp_col.end() ); - this->set_col( cur_col, temp_col ); - } - } - - input_stream.close(); - return true; - } - - // Saves the boundary_matrix to given file in ascii format - // Format: each line represents a column, first number is dimension, other numbers are the content of the column - bool save_ascii( std::string filename ) { - std::ofstream output_stream( filename.c_str() ); - if( output_stream.fail() ) - return false; - - const index nr_columns = this->get_num_cols(); - column tempCol; - for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) { - output_stream << (int64_t)this->get_dim( cur_col ); - this->get_col( cur_col, tempCol ); - for( index cur_row_idx = 0; cur_row_idx < (index)tempCol.size(); cur_row_idx++ ) - output_stream << " " << tempCol[ cur_row_idx ]; - output_stream << std::endl; - } - - output_stream.close(); - return true; - } - - // Loads boundary_matrix from given file - // Format: nr_columns % dim1 % N1 % row1 row2 % ...% rowN1 % dim2 % N2 % ... - bool load_binary( std::string filename ) - { - std::ifstream input_stream( filename.c_str( ), std::ios_base::binary | std::ios_base::in ); - if( input_stream.fail( ) ) - return false; - - int64_t nr_columns; - input_stream.read( (char*)&nr_columns, sizeof( int64_t ) ); - this->set_num_cols( (index)nr_columns ); - - column temp_col; - for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) { - int64_t cur_dim; - input_stream.read( (char*)&cur_dim, sizeof( int64_t ) ); - this->set_dim( cur_col, (dimension)cur_dim ); - int64_t nr_rows; - input_stream.read( (char*)&nr_rows, sizeof( int64_t ) ); - temp_col.resize( ( std::size_t )nr_rows ); - for( index idx = 0; idx < nr_rows; idx++ ) { - int64_t cur_row; - input_stream.read( (char*)&cur_row, sizeof( int64_t ) ); - temp_col[ idx ] = (index)cur_row; - } - this->set_col( cur_col, temp_col ); - } - - input_stream.close( ); - return true; - } - - // Saves the boundary_matrix to given file in binary format - // Format: nr_columns % dim1 % N1 % row1 row2 % ...% rowN1 % dim2 % N2 % ... - bool save_binary( std::string filename ) - { - std::ofstream output_stream( filename.c_str( ), std::ios_base::binary | std::ios_base::out ); - if( output_stream.fail( ) ) - return false; - - const int64_t nr_columns = this->get_num_cols( ); - output_stream.write( (char*)&nr_columns, sizeof( int64_t ) ); - column tempCol; - for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) { - int64_t cur_dim = this->get_dim( cur_col ); - output_stream.write( (char*)&cur_dim, sizeof( int64_t ) ); - this->get_col( cur_col, tempCol ); - int64_t cur_nr_rows = tempCol.size( ); - output_stream.write( (char*)&cur_nr_rows, sizeof( int64_t ) ); - for( index cur_row_idx = 0; cur_row_idx < (index)tempCol.size( ); cur_row_idx++ ) { - int64_t cur_row = tempCol[ cur_row_idx ]; - output_stream.write( (char*)&cur_row, sizeof( int64_t ) ); - } - } - - output_stream.close( ); - return true; - } - }; -} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/compute_persistence_pairs.h b/src/Zigzag_persistence/example/ext_zz/phat/compute_persistence_pairs.h deleted file mode 100644 index 48be65c28e..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/compute_persistence_pairs.h +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -#include -#include -#include -#include - -namespace phat { - // Extracts persistence pairs in separate dimensions from a reduced - // boundary matrix representing ``double`` filtration. The pairs - // give persistent relative homology of the pair of filtrations. - // TODO: Use it with standard reduction algorithm (no template option). - template< typename ReductionAlgorithm, typename Representation > - void compute_relative_persistence_pairs(std::vector& pairs, boundary_matrix& boundary_matrix, const std::map& L) { - ReductionAlgorithm reduce; - reduce(boundary_matrix); - std::map free; - std::map invL; - for (std::map::const_iterator it = L.begin(); it != L.end(); ++it) { invL[it->second] = it->first; } - for (std::vector::iterator it = pairs.begin(); it != pairs.end(); ++it) { it->clear(); } - for (index idx = 0; idx < boundary_matrix.get_num_cols(); ++idx) { - int dimension = boundary_matrix.get_dim(idx); - if (L.find(idx) != L.end()) { ++dimension; } - free[idx] = true; - if (!boundary_matrix.is_empty(idx)) { - index birth = boundary_matrix.get_max_index(idx); - index death = idx; - pairs[dimension-1].append_pair(birth, death); - free[birth] = false; - free[death] = false; - } else { - // This is an L-simplex and a (dimension+1)-dimensional cycle - if (L.find(idx) != L.end()) { - assert(dimension < pairs.size()); - pairs[dimension].append_pair(idx, -1); - } - } - } - for (std::map::iterator it = free.begin(); it != free.end(); ++it) { - if (it->second) { - int dimension = boundary_matrix.get_dim(it->first); - if (invL.find(it->first) == invL.end() && L.find(it->first) == L.end()) { - assert(dimension < pairs.size()); - pairs[dimension].append_pair(it->first, -1); - } - } - } - } - - // Extracts persistence pairs in separate dimensions; expects a d-dimensional vector of persistent_pairs - template< typename ReductionAlgorithm, typename Representation > - void compute_persistence_pairs(std::vector& pairs, boundary_matrix& boundary_matrix) { - ReductionAlgorithm reduce; - reduce(boundary_matrix); - std::map free; - for (std::vector::iterator it = pairs.begin(); it != pairs.end(); ++it) { it->clear(); } - for (index idx = 0; idx < boundary_matrix.get_num_cols(); ++idx) { - int dimension = boundary_matrix.get_dim(idx); - free[idx] = true; - if (!boundary_matrix.is_empty(idx)) { - index birth = boundary_matrix.get_max_index(idx); - index death = idx; - pairs[dimension-1].append_pair(birth, death); - // Cannot be of the form (a, infinity) - free[birth] = false; - free[death] = false; - } - } - for (std::map::iterator it = free.begin(); it != free.end(); ++it) { - if (it->second) { - int dimension = boundary_matrix.get_dim(it->first); - pairs[dimension].append_pair(it->first, -1); - } - } - } - - template< typename ReductionAlgorithm, typename Representation > - void compute_persistence_pairs( persistence_pairs& pairs, boundary_matrix< Representation >& boundary_matrix ) { - ReductionAlgorithm reduce; - reduce( boundary_matrix ); - pairs.clear(); - for( index idx = 0; idx < boundary_matrix.get_num_cols(); idx++ ) { - if( !boundary_matrix.is_empty( idx ) ) { - index birth = boundary_matrix.get_max_index( idx ); - index death = idx; - pairs.append_pair( birth, death ); - } - } - } - - template< typename ReductionAlgorithm, typename Representation > - void compute_persistence_pairs_dualized( persistence_pairs& pairs, boundary_matrix< Representation >& boundary_matrix ) { - - dualize( boundary_matrix ); - compute_persistence_pairs< ReductionAlgorithm >( pairs, boundary_matrix ); - dualize_persistence_pairs( pairs, boundary_matrix.get_num_cols() ); - } - - template< typename Representation > - void compute_persistence_pairs( persistence_pairs& pairs, boundary_matrix< Representation >& boundary_matrix ) { - phat::compute_persistence_pairs< twist_reduction >( pairs, boundary_matrix ); - } - - - template< typename Representation > - void compute_persistence_pairs_dualized( persistence_pairs& pairs, boundary_matrix< Representation >& boundary_matrix ) { - compute_persistence_pairs_dualized< twist_reduction >( pairs, boundary_matrix ); - } - -} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/helpers/dualize.h b/src/Zigzag_persistence/example/ext_zz/phat/helpers/dualize.h deleted file mode 100644 index 3ffedf875f..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/helpers/dualize.h +++ /dev/null @@ -1,74 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -#include -#include -#include - - -namespace phat { - template< typename Representation > - void dualize( boundary_matrix< Representation >& boundary_matrix ) { - - std::vector< dimension > dual_dims; - std::vector< std::vector< index > > dual_matrix; - - index nr_of_columns = boundary_matrix.get_num_cols(); - dual_matrix.resize( nr_of_columns ); - dual_dims.resize( nr_of_columns ); - - std::vector< index > dual_sizes( nr_of_columns, 0 ); - - column temp_col; - for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) { - boundary_matrix.get_col( cur_col, temp_col ); - for( index idx = 0; idx < (index)temp_col.size(); idx++) - dual_sizes[ nr_of_columns - 1 - temp_col[ idx ] ]++; - } - - #pragma omp parallel for - for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) - dual_matrix[cur_col].reserve(dual_sizes[cur_col]); - - for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) { - boundary_matrix.get_col( cur_col, temp_col ); - for( index idx = 0; idx < (index)temp_col.size(); idx++) - dual_matrix[ nr_of_columns - 1 - temp_col[ idx ] ].push_back( nr_of_columns - 1 - cur_col ); - } - - const dimension max_dim = boundary_matrix.get_max_dim(); - #pragma omp parallel for - for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) - dual_dims[ nr_of_columns - 1 - cur_col ] = max_dim - boundary_matrix.get_dim( cur_col ); - - #pragma omp parallel for - for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) - std::reverse( dual_matrix[ cur_col ].begin(), dual_matrix[ cur_col ].end() ); - - boundary_matrix.load_vector_vector( dual_matrix, dual_dims ); - } - - void dualize_persistence_pairs( persistence_pairs& pairs, const index n ) { - for (index i = 0; i < pairs.get_num_pairs(); ++i) { - std::pair< index, index > pair = pairs.get_pair( i ); - pairs.set_pair( i , n - 1 - pair.second, n - 1 - pair.first); - } - } -} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/helpers/misc.h b/src/Zigzag_persistence/example/ext_zz/phat/helpers/misc.h deleted file mode 100644 index fb5c07acb0..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/helpers/misc.h +++ /dev/null @@ -1,75 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -// STL includes -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// VS2008 and below unfortunately do not support stdint.h -#if defined(_MSC_VER)&& _MSC_VER < 1600 - typedef __int8 int8_t; - typedef unsigned __int8 uint8_t; - typedef __int16 int16_t; - typedef unsigned __int16 uint16_t; - typedef __int32 int32_t; - typedef unsigned __int32 uint32_t; - typedef __int64 int64_t; - typedef unsigned __int64 uint64_t; -#else - #include -#endif - -// basic types. index can be changed to int32_t to save memory on small instances -namespace phat { - typedef int64_t index; - typedef int8_t dimension; - typedef std::vector< index > column; -} - -// OpenMP (proxy) functions -#if defined _OPENMP - #include -#else - #define omp_get_thread_num() 0 - #define omp_get_max_threads() 1 - #define omp_get_num_threads() 1 - void omp_set_num_threads( int ) {}; - #include - #define omp_get_wtime() (float)clock() / (float)CLOCKS_PER_SEC -#endif - -#include - - - diff --git a/src/Zigzag_persistence/example/ext_zz/phat/helpers/thread_local_storage.h b/src/Zigzag_persistence/example/ext_zz/phat/helpers/thread_local_storage.h deleted file mode 100644 index d0b5332bc1..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/helpers/thread_local_storage.h +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -#include - -// should ideally be equal to the cache line size of the CPU -#define PHAT_TLS_SPACING_FACTOR 64 - -// ThreadLocalStorage with some spacing to avoid "false sharing" (see wikipedia) -template< typename T > -class thread_local_storage -{ -public: - - thread_local_storage() : per_thread_storage( omp_get_max_threads() * PHAT_TLS_SPACING_FACTOR ) {}; - - T& operator()() { - return per_thread_storage[ omp_get_thread_num() * PHAT_TLS_SPACING_FACTOR ]; - } - - const T& operator()() const { - return per_thread_storage[ omp_get_thread_num() * PHAT_TLS_SPACING_FACTOR ]; - } - - T& operator[]( int tid ) { - return per_thread_storage[ tid * PHAT_TLS_SPACING_FACTOR ]; - } - - const T& operator[]( int tid ) const { - return per_thread_storage[ tid * PHAT_TLS_SPACING_FACTOR ]; - } - -protected: - std::vector< T > per_thread_storage; -}; diff --git a/src/Zigzag_persistence/example/ext_zz/phat/persistence_pairs.h b/src/Zigzag_persistence/example/ext_zz/phat/persistence_pairs.h deleted file mode 100644 index eafc6389e2..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/persistence_pairs.h +++ /dev/null @@ -1,155 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -#include - -namespace phat { - class persistence_pairs { - - protected: - std::vector< std::pair< index, index > > pairs; - - public: - index get_num_pairs() const { - return (index)pairs.size(); - } - - void append_pair( index birth, index death ) { - pairs.push_back( std::make_pair( birth, death ) ); - } - - std::pair< index, index > get_pair( index idx ) const { - return pairs[ idx ]; - } - - void set_pair( index idx, index birth, index death ) { - pairs[ idx ] = std::make_pair( birth, death ); - } - - void clear() { - pairs.clear(); - } - - void sort() { - std::sort( pairs.begin(), pairs.end() ); - } - - // Loads the persistence pairs from given file in asci format - // Format: nr_pairs % newline % birth1 % death1 % newline % birth2 % death2 % newline ... - bool load_ascii( std::string filename ) { - std::ifstream input_stream( filename.c_str() ); - if( input_stream.fail() ) - return false; - - int64_t nr_pairs; - input_stream >> nr_pairs; - pairs.clear(); - for( index idx = 0; idx < nr_pairs; idx++ ) { - int64_t birth; - input_stream >> birth; - int64_t death; - input_stream >> death; - append_pair( (index)birth, (index)death ); - } - - input_stream.close(); - return true; - } - - // Saves the persistence pairs to given file in binary format - // Format: nr_pairs % newline % birth1 % death1 % newline % birth2 % death2 % newline ... - bool save_ascii( std::string filename ) { - std::ofstream output_stream( filename.c_str() ); - if( output_stream.fail() ) - return false; - - this->sort(); - output_stream << get_num_pairs() << std::endl; - for( std::size_t idx = 0; idx < pairs.size(); idx++ ) { - output_stream << pairs[idx].first << " " << pairs[idx].second << std::endl; - } - - output_stream.close(); - return true; - } - - // Loads the persistence pairs from given file in binary format - // Format: nr_pairs % birth1 % death1 % birth2 % death2 ... - bool load_binary( std::string filename ) { - std::ifstream input_stream( filename.c_str(), std::ios_base::binary | std::ios_base::in ); - if( input_stream.fail() ) - return false; - - int64_t nr_pairs; - input_stream.read( (char*)&nr_pairs, sizeof( int64_t ) ); - for( index idx = 0; idx < nr_pairs; idx++ ) { - int64_t birth; - input_stream.read( (char*)&birth, sizeof( int64_t ) ); - int64_t death; - input_stream.read( (char*)&death, sizeof( int64_t ) ); - append_pair( (index)birth, (index)death ); - } - - input_stream.close(); - return true; - } - - // Saves the persistence pairs to given file in binary format - // Format: nr_pairs % birth1 % death1 % birth2 % death2 ... - bool save_binary( std::string filename ) { - std::ofstream output_stream( filename.c_str(), std::ios_base::binary | std::ios_base::out ); - if( output_stream.fail() ) - return false; - - this->sort(); - int64_t nr_pairs = get_num_pairs(); - output_stream.write( (char*)&nr_pairs, sizeof( int64_t ) ); - for( std::size_t idx = 0; idx < pairs.size(); idx++ ) { - int64_t birth = pairs[ idx ].first; - output_stream.write( (char*)&birth, sizeof( int64_t ) ); - int64_t death = pairs[ idx ].second; - output_stream.write( (char*)&death, sizeof( int64_t ) ); - } - - output_stream.close(); - return true; - } - - bool operator==( persistence_pairs& other_pairs ) { - this->sort(); - other_pairs.sort(); - if( pairs.size() != (std::size_t)other_pairs.get_num_pairs() ) - return false; - - for( index idx = 0; idx < (index)pairs.size(); idx++ ) - if( get_pair( idx ) != other_pairs.get_pair( idx ) ) - return false; - - return true; - } - - bool operator!=( persistence_pairs& other_pairs ) { - return !( *this == other_pairs ); - } - }; - - - -} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/representations/abstract_pivot_column.h b/src/Zigzag_persistence/example/ext_zz/phat/representations/abstract_pivot_column.h deleted file mode 100644 index e16d7a5d13..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/representations/abstract_pivot_column.h +++ /dev/null @@ -1,102 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -#include -#include - -namespace phat { - - // Note: We could even make the rep generic in the underlying Const representation - // But I cannot imagine that anything else than vector> would - // make sense - template< typename PivotColumn > - class abstract_pivot_column : public vector_vector { - - protected: - typedef vector_vector Base; - typedef PivotColumn pivot_col; - - // For parallization purposes, it could be more than one full column - mutable thread_local_storage< pivot_col > pivot_cols; - mutable thread_local_storage< index > idx_of_pivot_cols; - - pivot_col& get_pivot_col() const { - return pivot_cols(); - } - - bool is_pivot_col( index idx ) const { - return idx_of_pivot_cols() == idx; - } - - void release_pivot_col() { - index idx = idx_of_pivot_cols(); - if( idx != -1 ) { - this->matrix[ idx ].clear(); - pivot_cols().get_col_and_clear( this->matrix[ idx ] ); - } - idx_of_pivot_cols() = -1; - } - - void make_pivot_col( index idx ) { - release_pivot_col(); - idx_of_pivot_cols() = idx; - get_pivot_col().add_col( matrix[ idx ] ); - } - - public: - - void _set_num_cols( index nr_of_cols ) { - #pragma omp parallel for - for( int tid = 0; tid < omp_get_num_threads(); tid++ ) { - pivot_cols[ tid ].init( nr_of_cols ); - idx_of_pivot_cols[ tid ] = -1; - } - Base::_set_num_cols( nr_of_cols ); - } - - void _add_to( index source, index target ) { - if( !is_pivot_col( target ) ) - make_pivot_col( target ); - get_pivot_col().add_col( matrix[source] ); - } - - void _sync() { - #pragma omp parallel for - for( int tid = 0; tid < omp_get_num_threads(); tid++ ) - release_pivot_col(); - } - - void _get_col( index idx, column& col ) const { is_pivot_col( idx ) ? get_pivot_col().get_col( col ) : Base::_get_col( idx, col ); } - - bool _is_empty( index idx ) const { return is_pivot_col( idx ) ? get_pivot_col().is_empty() : Base::_is_empty( idx ); } - - index _get_max_index( index idx ) const { return is_pivot_col( idx ) ? get_pivot_col().get_max_index() : Base::_get_max_index( idx ); } - - void _clear( index idx ) { is_pivot_col( idx ) ? get_pivot_col().clear() : Base::_clear( idx ); } - - void _set_col( index idx, const column& col ) { is_pivot_col( idx ) ? get_pivot_col().set_col( col ) : Base::_set_col( idx, col ); } - - void _remove_max( index idx ) { is_pivot_col( idx ) ? get_pivot_col().remove_max() : Base::_remove_max( idx ); } - - void finalize( index idx ) { Base::_finalize( idx ); } - }; -} - - diff --git a/src/Zigzag_persistence/example/ext_zz/phat/representations/bit_tree_pivot_column.h b/src/Zigzag_persistence/example/ext_zz/phat/representations/bit_tree_pivot_column.h deleted file mode 100644 index 4d48e8853d..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/representations/bit_tree_pivot_column.h +++ /dev/null @@ -1,165 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Hubert Wagner - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -#include -#include - -namespace phat { - - // This is a bitset indexed with a 64-ary tree. Each node in the index - // has 64 bits; i-th bit says that the i-th subtree is non-empty. - // Supports practically O(1), inplace, zero-allocation: insert, remove, max_element - // and clear in O(number of ones in the bitset). - // 'add_index' is still the real bottleneck in practice. - class bit_tree_column - { - protected: - - size_t offset; // data[i + offset] = ith block of the data-bitset - typedef uint64_t block_type; - std::vector< block_type > data; - - - size_t debrujin_magic_table[ 64 ]; - - enum { block_size_in_bits = 64 }; - enum { block_shift = 6 }; - - // Some magic: http://graphics.stanford.edu/~seander/bithacks.html - // Gets the position of the rightmost bit of 'x'. 0 means the most significant bit. - // (-x)&x isolates the rightmost bit. - // The whole method is much faster than calling log2i, and very comparable to using ScanBitForward/Reverse intrinsic, - // which should be one CPU instruction, but is not portable. - size_t rightmost_pos( const block_type value ) const { - return 64 - 1 - debrujin_magic_table[ ( (value & (-(int64_t)value) ) * 0x07EDD5E59A4E28C2 ) >> 58 ]; - } - - public: - - void init( index num_cols ) { - int64_t n = 1; // in case of overflow - int64_t bottom_blocks_needed = ( num_cols + block_size_in_bits - 1 ) / block_size_in_bits; - int64_t upper_blocks = 1; - - // How many blocks/nodes of index needed to index the whole bitset? - while( n * block_size_in_bits < bottom_blocks_needed ) { - n *= block_size_in_bits; - upper_blocks += n; - } - - offset = upper_blocks; - data.resize( upper_blocks + bottom_blocks_needed, 0 ); - - std::size_t temp_array[ 64 ] = { - 63, 0, 58, 1, 59, 47, 53, 2, - 60, 39, 48, 27, 54, 33, 42, 3, - 61, 51, 37, 40, 49, 18, 28, 20, - 55, 30, 34, 11, 43, 14, 22, 4, - 62, 57, 46, 52, 38, 26, 32, 41, - 50, 36, 17, 19, 29, 10, 13, 21, - 56, 45, 25, 31, 35, 16, 9, 12, - 44, 24, 15, 8, 23, 7, 6, 5 }; - - std::copy( &temp_array[ 0 ], &temp_array[ 64 ], &debrujin_magic_table[ 0 ] ); - } - - index get_max_index() const { - if( !data[ 0 ] ) - return -1; - - size_t n = 0; - size_t newn = 0; - size_t index = 0; - while( newn < data.size() ) { - n = newn; - index = rightmost_pos( data[ n ] ); - newn = ( n << block_shift ) + index + 1; - } - - return ( ( n - offset ) << block_shift ) + index; - } - - bool is_empty() const { - return data[ 0 ] == 0; - } - - void add_index( const size_t entry ) { - const block_type ONE = 1; - const block_type block_modulo_mask = ( ONE << block_shift ) - 1; - size_t index_in_level = entry >> block_shift; - size_t address = index_in_level + offset; - size_t index_in_block = entry & block_modulo_mask; - - block_type mask = ( ONE << ( block_size_in_bits - index_in_block - 1 ) ); - - data[ address ] ^= mask; - - // Check if we reached the root. Also, if anyone else was in this block, we don't need to update the path up. - while( address && !( data[ address ] & ~mask ) ) { - index_in_block = index_in_level & block_modulo_mask; - index_in_level >>= block_shift; - --address; - address >>= block_shift; - mask = ( ONE << ( block_size_in_bits - index_in_block - 1 ) ); - data[ address ] ^= mask; - } - } - - void get_col_and_clear( column &out ) { - index mx = this->get_max_index(); - while( mx != -1 ) { - out.push_back( mx ); - add_index( mx ); - mx = this->get_max_index(); - } - - std::reverse( out.begin(), out.end() ); - } - - void add_col(const column &col) { - for( size_t i = 0; i < col.size(); ++i ) - add_index(col[i]); - } - - void clear() { - index mx = this->get_max_index(); - while( mx != -1 ) { - add_index( mx ); - mx = this->get_max_index(); - } - } - - void remove_max() { - add_index( get_max_index() ); - } - - void set_col( const column& col ) { - clear(); - add_col( col ); - } - - void get_col( column& col ) { - get_col_and_clear( col ); - add_col( col ); - } - }; - - typedef abstract_pivot_column bit_tree_pivot_column; -} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/representations/full_pivot_column.h b/src/Zigzag_persistence/example/ext_zz/phat/representations/full_pivot_column.h deleted file mode 100644 index c2e9e3c574..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/representations/full_pivot_column.h +++ /dev/null @@ -1,100 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -#include -#include - -namespace phat { - class full_column { - - protected: - std::priority_queue< index > history; - std::vector< char > is_in_history; - std::vector< char > col_bit_field; - - public: - void init( const index total_size ) { - col_bit_field.resize( total_size, false ); - is_in_history.resize( total_size, false ); - } - - void add_col( const column& col ) { - for( index idx = 0; idx < (index) col.size(); idx++ ) { - add_index( col[ idx ] ); - } - } - - void add_index( const index idx ) { - if( !is_in_history[ idx ] ) { - history.push( idx ); - is_in_history[ idx ] = true; - } - - col_bit_field[ idx ] = !col_bit_field[ idx ]; - } - - index get_max_index() { - while( history.size() > 0 ) { - index topIndex = history.top(); - if( col_bit_field[ topIndex ] ) { - return topIndex; - } else { - history.pop(); - is_in_history[ topIndex ] = false; - } - } - - return -1; - } - - void get_col_and_clear( column& col ) { - while( !is_empty() ) { - col.push_back( get_max_index() ); - add_index( get_max_index() ); - } - std::reverse( col.begin(), col.end() ); - } - - bool is_empty() { - return (get_max_index() == -1); - } - - void clear() { - while( !is_empty() ) - add_index( get_max_index() ); - } - - void remove_max() { - add_index( get_max_index() ); - } - - void set_col( const column& col ) { - clear(); - add_col( col ); - } - - void get_col( column& col ) { - get_col_and_clear( col ); - add_col( col ); - } - }; - - typedef abstract_pivot_column< full_column > full_pivot_column; -} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/representations/heap_pivot_column.h b/src/Zigzag_persistence/example/ext_zz/phat/representations/heap_pivot_column.h deleted file mode 100644 index 33cd07b40d..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/representations/heap_pivot_column.h +++ /dev/null @@ -1,126 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -#include -#include - -namespace phat { - class heap_column { - - protected: - std::priority_queue< index > data; - - column temp_col; - index inserts_since_last_prune; - - void prune() - { - temp_col.clear( ); - index max_index = pop_max_index( ); - while( max_index != -1 ) { - temp_col.push_back( max_index ); - max_index = pop_max_index( ); - } - - for( index idx = 0; idx < (index)temp_col.size( ); idx++ ) - data.push( temp_col[ idx ] ); - - inserts_since_last_prune = 0; - } - - index pop_max_index() - { - if( data.empty( ) ) - return -1; - else { - index max_element = data.top( ); - data.pop(); - while( !data.empty( ) && data.top( ) == max_element ) { - data.pop( ); - if( data.empty( ) ) - return -1; - else { - max_element = data.top( ); - data.pop( ); - } - } - return max_element; - } - } - - public: - void init( const index total_size ) { - inserts_since_last_prune = 0; - clear(); - } - - void add_col( const column& col ) { - for( index idx = 0; idx < (index) col.size(); idx++ ) - data.push( col[ idx ] ); - inserts_since_last_prune += col.size( ); - if( 2 * inserts_since_last_prune >( index ) data.size( ) ) - prune(); - } - - index get_max_index() { - index max_element = pop_max_index( ); - if( max_element == -1 ) - return -1; - else { - data.push( max_element ); - return max_element; - } - } - - void get_col_and_clear( column& col ) { - col.clear(); - index max_index = pop_max_index( ); - while( max_index != -1 ) { - col.push_back( max_index ); - max_index = pop_max_index( ); - } - std::reverse( col.begin(), col.end() ); - } - - bool is_empty() { - return get_max_index() == -1; - } - - void clear() { - data = std::priority_queue< index >(); - } - - void remove_max() { - pop_max_index(); - } - - void set_col( const column& col ) { - clear(); - add_col( col ); - } - - void get_col( column& col ) { - get_col_and_clear( col ); - add_col( col ); - } - }; - - typedef abstract_pivot_column< heap_column > heap_pivot_column; -} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/representations/sparse_pivot_column.h b/src/Zigzag_persistence/example/ext_zz/phat/representations/sparse_pivot_column.h deleted file mode 100644 index 390fd91a99..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/representations/sparse_pivot_column.h +++ /dev/null @@ -1,79 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -#include -#include - -namespace phat { - class sparse_column { - - protected: - std::set< index > data; - - void add_index( const index idx ) { - std::pair< std::set< index >::iterator, bool > result = data.insert( idx ); - if( result.second == false ) - data.erase( result.first ); - } - - public: - void init( const index total_size ) { - data.clear(); - } - - void add_col( const column& col ) { - for( index idx = 0; idx < (index) col.size(); idx++ ) - add_index( col[ idx ] ); - } - - index get_max_index() { - return data.empty() ? -1 : *data.rbegin(); - } - - void get_col_and_clear( column& col ) { - col.assign( data.begin(), data.end() ); - data.clear(); - } - - bool is_empty() { - return data.empty(); - } - - void clear() { - data.clear(); - } - - void remove_max() { - add_index( get_max_index() ); - } - - void set_col( const column& col ) { - clear(); - add_col( col ); - } - - void get_col( column& col ) { - get_col_and_clear( col ); - add_col( col ); - } - }; - - typedef abstract_pivot_column< sparse_column > sparse_pivot_column; -} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_heap.h b/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_heap.h deleted file mode 100644 index db0420ff23..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_heap.h +++ /dev/null @@ -1,170 +0,0 @@ -/* Copyright 2013 IST Austria -Contributed by: Jan Reininghaus - -This file is part of PHAT. - -PHAT is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -PHAT 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 Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with PHAT. If not, see . */ - -#pragma once - -#include - -namespace phat { - class vector_heap { - - protected: - std::vector< dimension > dims; - std::vector< column > matrix; - - std::vector< index > inserts_since_last_prune; - - mutable thread_local_storage< column > temp_column_buffer; - - protected: - void _prune( index idx ) - { - column& col = matrix[ idx ]; - column& temp_col = temp_column_buffer(); - temp_col.clear(); - index max_index = _pop_max_index( col ); - while( max_index != -1 ) { - temp_col.push_back( max_index ); - max_index = _pop_max_index( col ); - } - col = temp_col; - std::reverse( col.begin( ), col.end( ) ); - std::make_heap( col.begin( ), col.end( ) ); - inserts_since_last_prune[ idx ] = 0; - } - - index _pop_max_index( index idx ) - { - return _pop_max_index( matrix[ idx ] ); - } - - index _pop_max_index( column& col ) const - { - if( col.empty( ) ) - return -1; - else { - index max_element = col.front( ); - std::pop_heap( col.begin( ), col.end( ) ); - col.pop_back( ); - while( !col.empty( ) && col.front( ) == max_element ) { - std::pop_heap( col.begin( ), col.end( ) ); - col.pop_back( ); - if( col.empty( ) ) - return -1; - else { - max_element = col.front( ); - std::pop_heap( col.begin( ), col.end( ) ); - col.pop_back( ); - } - } - return max_element; - } - } - - public: - // overall number of cells in boundary_matrix - index _get_num_cols( ) const - { - return (index)matrix.size( ); - } - void _set_num_cols( index nr_of_columns ) - { - dims.resize( nr_of_columns ); - matrix.resize( nr_of_columns ); - inserts_since_last_prune.assign( nr_of_columns, 0 ); - } - - // dimension of given index - dimension _get_dim( index idx ) const - { - return dims[ idx ]; - } - void _set_dim( index idx, dimension dim ) - { - dims[ idx ] = dim; - } - - // replaces(!) content of 'col' with boundary of given index - void _get_col( index idx, column& col ) const - { - temp_column_buffer( ) = matrix[ idx ]; - - index max_index = _pop_max_index( temp_column_buffer() ); - while( max_index != -1 ) { - col.push_back( max_index ); - max_index = _pop_max_index( temp_column_buffer( ) ); - } - std::reverse( col.begin( ), col.end( ) ); - } - void _set_col( index idx, const column& col ) - { - matrix[ idx ] = col; - std::make_heap( matrix[ idx ].begin( ), matrix[ idx ].end( ) ); - } - - // true iff boundary of given idx is empty - bool _is_empty( index idx ) const - { - return _get_max_index( idx ) == -1; - } - - // largest row index of given column idx (new name for lowestOne()) - index _get_max_index( index idx ) const - { - column& col = const_cast< column& >( matrix[ idx ] ); - index max_element = _pop_max_index( col ); - col.push_back( max_element ); - std::push_heap( col.begin( ), col.end( ) ); - return max_element; - } - - // removes the maximal index of a column - void _remove_max( index idx ) - { - _pop_max_index( idx ); - } - - // clears given column - void _clear( index idx ) - { - matrix[ idx ].clear( ); - } - - // syncronizes all data structures (essential for openmp stuff) - void _sync( ) {} - - // adds column 'source' to column 'target' - void _add_to( index source, index target ) - { - for( index idx = 0; idx < (index)matrix[ source ].size( ); idx++ ) { - matrix[ target ].push_back( matrix[ source ][ idx ] ); - std::push_heap( matrix[ target ].begin(), matrix[ target ].end() ); - } - inserts_since_last_prune[ target ] += matrix[ source ].size(); - - if( 2 * inserts_since_last_prune[ target ] > ( index )matrix[ target ].size() ) - _prune( target ); - } - - // finalizes given column - void _finalize( index idx ) { - _prune( idx ); - } - - }; -} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_list.h b/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_list.h deleted file mode 100644 index ca0b5b8e79..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_list.h +++ /dev/null @@ -1,101 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Jan Reininghaus - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -#include - -namespace phat { - class vector_list { - - protected: - std::vector< dimension > dims; - std::vector< std::list< index > > matrix; - - public: - // overall number of cells in boundary_matrix - index _get_num_cols() const { - return (index)matrix.size(); - } - void _set_num_cols( index nr_of_columns ) { - dims.resize( nr_of_columns ); - matrix.resize( nr_of_columns ); - } - - // dimension of given index - dimension _get_dim( index idx ) const { - return dims[ idx ]; - } - void _set_dim( index idx, dimension dim ) { - dims[ idx ] = dim; - } - - // replaces(!) content of 'col' with boundary of given index - void _get_col( index idx, column& col ) const { - col.clear(); - col.reserve( matrix[idx].size() ); - std::copy (matrix[idx].begin(), matrix[idx].end(), std::back_inserter(col) ); - } - - void _set_col( index idx, const column& col ) { - matrix[ idx ].clear(); - matrix[ idx ].resize( col.size() ); - std::copy (col.begin(), col.end(), matrix[ idx ].begin() ); - } - - // true iff boundary of given idx is empty - bool _is_empty( index idx ) const { - return matrix[ idx ].empty(); - } - - // largest row index of given column idx (new name for lowestOne()) - index _get_max_index( index idx ) const { - return matrix[ idx ].empty() ? -1 : *matrix[ idx ].rbegin(); - } - - // removes the maximal index of a column - void _remove_max( index idx ) { - std::list< index >::iterator it = matrix[ idx ].end(); - it--; - matrix[ idx ].erase( it ); - } - - // clears given column - void _clear( index idx ) { - matrix[ idx ].clear(); - } - - // syncronizes all data structures (essential for openmp stuff) - void _sync() {} - - // adds column 'source' to column 'target' - void _add_to( index source, index target ) { - std::list< index >& source_col = matrix[ source ]; - std::list< index >& target_col = matrix[ target ]; - std::list< index > temp_col; - target_col.swap( temp_col ); - std::set_symmetric_difference( temp_col.begin(), temp_col.end(), - source_col.begin(), source_col.end(), - std::back_inserter( target_col ) ); - } - - // finalizes given column - void _finalize( index idx ) { - } - }; -} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_set.h b/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_set.h deleted file mode 100644 index 6878a270c0..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_set.h +++ /dev/null @@ -1,99 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -#include - -namespace phat { - class vector_set { - - protected: - std::vector< dimension > dims; - std::vector< std::set< index > > matrix; - - public: - // overall number of cells in boundary_matrix - index _get_num_cols() const { - return (index)matrix.size(); - } - void _set_num_cols( index nr_of_columns ) { - dims.resize( nr_of_columns ); - matrix.resize( nr_of_columns ); - } - - // dimension of given index - dimension _get_dim( index idx ) const { - return dims[ idx ]; - } - void _set_dim( index idx, dimension dim ) { - dims[ idx ] = dim; - } - - // replaces(!) content of 'col' with boundary of given index - void _get_col( index idx, column& col ) const { - col.clear(); - col.reserve( matrix[idx].size() ); - std::copy (matrix[idx].begin(), matrix[idx].end(), std::back_inserter(col) ); - } - void _set_col( index idx, const column& col ) { - matrix[ idx ].clear(); - matrix[ idx ].insert( col.begin(), col.end() ); - } - - // true iff boundary of given idx is empty - bool _is_empty( index idx ) const { - return matrix[ idx ].empty(); - } - - // largest row index of given column idx (new name for lowestOne()) - index _get_max_index( index idx ) const { - return matrix[ idx ].empty() ? -1 : *matrix[ idx ].rbegin(); - } - - // removes the maximal index of a column - void _remove_max( index idx ) { - std::set< index >::iterator it = matrix[ idx ].end(); - it--; - matrix[ idx ].erase( it ); - } - - // clears given column - void _clear( index idx ) { - matrix[ idx ].clear(); - } - - // syncronizes all data structures (essential for openmp stuff) - void _sync() {} - - // adds column 'source' to column 'target' - void _add_to( index source, index target ) { - for( std::set< index >::iterator it = matrix[ source ].begin(); it != matrix[ source ].end(); it++ ) { - std::set< index >& col = matrix[ target ]; - std::pair< std::set< index >::iterator, bool > result = col.insert( *it ); - if( !result.second ) - col.erase( result.first ); - } - } - - // finalizes given column - void _finalize( index idx ) { - } - - }; -} diff --git a/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_vector.h b/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_vector.h deleted file mode 100644 index f111d6b572..0000000000 --- a/src/Zigzag_persistence/example/ext_zz/phat/representations/vector_vector.h +++ /dev/null @@ -1,107 +0,0 @@ -/* Copyright 2013 IST Austria - Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus - - This file is part of PHAT. - - PHAT is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - PHAT 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PHAT. If not, see . */ - -#pragma once - -#include - -namespace phat { - class vector_vector { - - protected: - std::vector< dimension > dims; - std::vector< column > matrix; - - thread_local_storage< column > temp_column_buffer; - - public: - // overall number of cells in boundary_matrix - index _get_num_cols() const { - return (index)matrix.size(); - } - void _set_num_cols( index nr_of_columns ) { - dims.resize( nr_of_columns ); - matrix.resize( nr_of_columns ); - } - - // dimension of given index - dimension _get_dim( index idx ) const { - return dims[ idx ]; - } - void _set_dim( index idx, dimension dim ) { - dims[ idx ] = dim; - } - - // replaces(!) content of 'col' with boundary of given index - void _get_col( index idx, column& col ) const { - col = matrix[ idx ]; - } - void _set_col( index idx, const column& col ) { - matrix[ idx ] = col; - } - - // true iff boundary of given idx is empty - bool _is_empty( index idx ) const { - return matrix[ idx ].empty(); - } - - // largest row index of given column idx (new name for lowestOne()) - index _get_max_index( index idx ) const { - return matrix[ idx ].empty() ? -1 : matrix[ idx ].back(); - } - - // removes the maximal index of a column - void _remove_max( index idx ) { - matrix[ idx ].pop_back(); - } - - // clears given column - void _clear( index idx ) { - matrix[ idx ].clear(); - } - - // syncronizes all data structures (essential for openmp stuff) - void _sync() {} - - // adds column 'source' to column 'target' - void _add_to( index source, index target ) { - column& source_col = matrix[ source ]; - column& target_col = matrix[ target ]; - column& temp_col = temp_column_buffer(); - - - size_t new_size = source_col.size() + target_col.size(); - - if (new_size > temp_col.size()) temp_col.resize(new_size); - - std::vector::iterator col_end = std::set_symmetric_difference( target_col.begin(), target_col.end(), - source_col.begin(), source_col.end(), - temp_col.begin() ); - temp_col.erase(col_end, temp_col.end()); - - - target_col.swap(temp_col); - } - - // finalizes given column - void _finalize( index idx ) { - column& col = matrix[ idx ]; - column(col.begin(), col.end()).swap(col); - } - }; -} diff --git a/src/Zigzag_persistence/example/rips-zigzag-dionysus.h b/src/Zigzag_persistence/example/rips-zigzag-dionysus.h deleted file mode 100644 index 62db6d834d..0000000000 --- a/src/Zigzag_persistence/example/rips-zigzag-dionysus.h +++ /dev/null @@ -1,211 +0,0 @@ -#include -#include -#include -#include - -#include -namespace ba = boost::adaptors; - -#include -#include -#include -namespace d = dionysus; - -#include - -typedef std::vector Point; -typedef std::vector PointContainer; - -typedef d::PairwiseDistances> PairDistances; -typedef PairDistances::DistanceType DistanceType; -typedef PairDistances::IndexType Vertex; - -typedef d::Rips Generator; -typedef Generator::Simplex Simplex; -typedef std::set SimplexSet; - -typedef std::vector VertexVector; -typedef std::vector EpsilonVector; -typedef std::tuple Edge; -typedef std::vector EdgeVector; - -inline PointContainer compute_points(unsigned int numberOfPoints, int seed = -1) -{ - PointContainer finalPoints; - std::set points; - std::random_device dev; - std::mt19937 rng(dev()); - if (seed > -1) rng.seed(seed); - std::uniform_real_distribution dist(0,10); - - for (unsigned int i = 0; i < numberOfPoints; ++i){ - auto res = points.insert({dist(rng), dist(rng)}); - while(!res.second){ - res = points.insert({dist(rng), dist(rng)}); - } - finalPoints.push_back(*res.first); - } - - return finalPoints; -} - -inline void compute_vertices_and_epsilons(const PairDistances& distances, - VertexVector& vertices, - EpsilonVector& epsilons) -{ - DistanceType inf = std::numeric_limits::infinity(); - EpsilonVector dist(distances.size(), inf); - - vertices.push_back(distances.begin()); - // epsilons.push_back(inf); - while (vertices.size() < distances.size()) { - for (Vertex v = distances.begin(); v != distances.end(); ++v) - dist[v] = std::min(dist[v], distances(v, vertices.back())); - auto max = std::max_element(dist.begin(), dist.end()); - vertices.push_back(max - dist.begin()); - epsilons.push_back(*max); - } - epsilons.push_back(0); -} - -inline void compute_edges(const PairDistances& distances, - const VertexVector& vertices, - const EpsilonVector& epsilons, - const DistanceType& multiplier, - EdgeVector& edges) -{ - for (unsigned i = 0; i != vertices.size(); ++i) - for (unsigned j = i + 1; j != vertices.size(); ++j) { - Vertex u = vertices[i]; - Vertex v = vertices[j]; - if (distances(u, v) <= multiplier * epsilons[j - 1]) edges.emplace_back(u, v); - } - std::sort(edges.begin(), edges.end(), - [&distances](const Edge& e1, const Edge& e2) { - return distances(std::get<0>(e1), std::get<1>(e1)) < - distances(std::get<0>(e2), std::get<1>(e2)); - }); -} - -inline void compute_positive_cofaces( - const PairDistances& distances, - const VertexVector& vertices, - const EdgeVector& edges, - const EpsilonVector& epsilons, - const DistanceType& multiplier, - Generator& rips, - short unsigned& skeleton, - unsigned& ce, - unsigned& i, - SimplexSet& cofaces) -{ - cofaces.clear(); - - // Add anything else that needs to be inserted into the complex - while (ce < edges.size()) { - Vertex u, v; - std::tie(u, v) = edges[ce]; - if (distances(u, v) <= multiplier * epsilons[i - 1]) - ++ce; - else - break; - // std::cout << "Adding cofaces of " << u << ' ' << v << std::endl; - rips.edge_cofaces( - u, v, - skeleton, - multiplier * epsilons[i - 1], - [&cofaces](Simplex&& s) { cofaces.insert(s); }, - vertices.begin(), - vertices.begin() + i + 1); - } -} - -inline void compute_negative_cofaces( - const VertexVector& vertices, - const EpsilonVector& epsilons, - const DistanceType& multiplier, - Generator& rips, - short unsigned& skeleton, - unsigned& i, - SimplexSet& cofaces) -{ - cofaces.clear(); - rips.vertex_cofaces( - vertices[i], - skeleton, - multiplier * epsilons[i - 1], - [&cofaces](Simplex&& s) { cofaces.insert(s); }, - vertices.begin(), - vertices.begin() + i + 1); - // std::cout << "Total cofaces: " << cofaces.size() << std::endl; -} - -inline unsigned int build_rips_zigzag_filtration(std::vector > &simpls, - std::vector& dirs, - unsigned int numberOfPoints, - int seed = -1, - short unsigned skeleton = 2, - DistanceType multiplier = 6) -{ - // std::cout << "Building filtration" << std::endl; - unsigned int numberOfSimplices = 0; - - PointContainer points = compute_points(numberOfPoints, seed); - - // Construct distances and Rips generator - PairDistances distances(points); - Generator rips(distances); - - // Order vertices and epsilons (in maxmin fashion) - VertexVector vertices; - EpsilonVector epsilons; - EdgeVector edges; - - compute_vertices_and_epsilons(distances, vertices, epsilons); - - // Generate and sort all the edges - compute_edges(distances, vertices, epsilons, multiplier, edges); - - // Insert vertices - for (auto v : vertices) { - // Add a vertex - simpls.push_back({static_cast(v)}); - dirs.push_back(true); - ++numberOfSimplices; - } - - // Process vertices - dlog::progress progress(vertices.size()); - unsigned ce = 0; // index of the current one past last edge in the complex - SimplexSet cofaces; // record the cofaces of all the simplices that need to be removed and reinserted - - for (unsigned stage = 0; stage != vertices.size() - 1; ++stage) { - unsigned i = vertices.size() - 1 - stage; - - /* Increase epsilon */ - compute_positive_cofaces(distances, vertices, edges, epsilons, multiplier, rips, skeleton, ce, i, cofaces); - - for (auto& s : cofaces) { - // std::cout << "Inserting: " << s << std::endl; - simpls.emplace_back(s.begin(), s.end()); - dirs.push_back(true); - ++numberOfSimplices; - } - - /* Remove the vertex */ - // std::cout << "Removing vertex: " << vertices[i] << std::endl; - compute_negative_cofaces(vertices, epsilons, multiplier, rips, skeleton, i, cofaces); - - for (auto& s : cofaces | ba::reversed) { - // std::cout << "Removing: " << s << std::endl; - simpls.emplace_back(s.begin(), s.end()); - dirs.push_back(false); - } - - ++progress; - } - - std::cout << std::endl; - return numberOfSimplices; -} diff --git a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence_old.h b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence_old.h deleted file mode 100644 index aa93d75a21..0000000000 --- a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence_old.h +++ /dev/null @@ -1,1326 +0,0 @@ -/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. - * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. - * Author(s): Clément Maria - * - * Copyright (C) 2021 Inria - * - * Modification(s): - * - 2023/05 Hannah Schreiber: Rework of the interface, reorganization and debug - * - 2023/05 Hannah Schreiber: Addition of infinit bars - * - YYYY/MM Author: Description of the modification - */ - -#ifndef ZIGZAG_PERSISTENCE_H_ -#define ZIGZAG_PERSISTENCE_H_ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace Gudhi { -namespace zigzag_persistence { -//represent matrix columns with sets. -struct Zigzag_persistence_colset; -//---------------------------------------------------------------------------------- -/** \class Zigzag_persistence Zigzag_persistence.h gudhi/Zigzag_persistence.h - * \brief Computation of the zigzag persistent homology of a zigzag - * filtered complex. - * - * \details The type ZigzagFilteredComplex::Simplex_key counts the number of - * insertions and - * deletions of simplices, which may be large in zigzag persistence and require - * more than 32 bits of storage. The type used (int, long, etc) should be chosen in - * consequence. Simplex_key must be signed. - * - * Over all insertions, the Simplex_key must be positive and strictly increasing - * when forward iterating along the zigzag filtration. - */ -template < typename ZigzagFilteredComplex - , typename ZigzagPersistenceOptions = Zigzag_persistence_colset > -class Zigzag_persistence { -public: - typedef ZigzagFilteredComplex Complex; - typedef ZigzagPersistenceOptions Options; - /*** Types defined in the complex ***/ - // Data attached to each simplex to interface with a Property Map. - typedef typename Complex::Simplex_key Simplex_key;//must be signed - typedef typename Complex::Simplex_handle Simplex_handle; - typedef typename Complex::Vertex_handle Vertex_handle; - typedef typename Complex::Filtration_value Filtration_value; - // -private: - /*** Matrix cells and columns types ***/ - struct matrix_row_tag; // for horizontal traversal in the persistence matrix - struct matrix_column_tag; // for vertical traversal in the persistence matrix - typedef boost::intrusive::list_base_hook< - boost::intrusive::tag < matrix_row_tag > //allows .unlink() - , boost::intrusive::link_mode < boost::intrusive::auto_unlink > - > base_hook_matrix_row_list; - //hook for a column represented by an intrusive list - typedef boost::intrusive::list_base_hook < //faster hook, less safe - boost::intrusive::tag < matrix_column_tag > - //, boost::intrusive::link_mode < boost::intrusive::auto_unlink > - , boost::intrusive::link_mode < boost::intrusive::safe_link > - > base_hook_matrix_column_list; - //hook for a column represented by an intrusive set - typedef boost::intrusive::set_base_hook < //faster hook, less safe - boost::intrusive::tag < matrix_column_tag > - , boost::intrusive::optimize_size - //, boost::intrusive::link_mode < boost::intrusive::auto_unlink > - , boost::intrusive::link_mode < boost::intrusive::safe_link > - > base_hook_matrix_column_set; - //the data structure for columns is selected in Options::searchable_column - typedef typename std::conditional::type base_hook_matrix_column; - //the only option for rows is the intrusive list - typedef base_hook_matrix_row_list base_hook_matrix_row; - - /* Cell for the persistence matrix. Contains a key for the simplex index, and - * horizontal and vertical hooks for connections within sparse rows and columns. - */ - struct matrix_chain;//defined below, a chain contains a row, a column, and more - /** Type of cell in the sparse homology matrix. - * For now, only coefficients in Z/2Z, so only the row index (called key) is - * stored in the cell. - */ - struct Zigzag_persistence_cell - : public base_hook_matrix_row, public base_hook_matrix_column - { - Zigzag_persistence_cell(Simplex_key key, matrix_chain *self_chain) - : key_(key) - , self_chain_(self_chain) - {} - - Simplex_key key() const { return key_; } - //compare by increasing key value - friend bool operator<( const Zigzag_persistence_cell& c1 - , const Zigzag_persistence_cell& c2) { - return c1.key() < c2.key(); - } - /* In a matrix M, if M[i][j] == x not 0, we represent a cell with key_=i - * (the row index), - * self_chain_ points to the chain corresponding the j-th column, and x_=x. - * Currently, only Z/2Z coefficients are implemented, so x=1. - * - * A cell is connected to all cells of the same row, and all cells of the same - * column, via the two boost::intrusive hooks (row and column). - */ - Simplex_key key_; - matrix_chain * self_chain_; - }; - - //Homology matrix cell - typedef Zigzag_persistence_cell Cell; - // Remark: constant_time_size must be false because base_hook_matrix_row and - // base_hook_matrix_column have auto_unlink link_mode - //vertical list of cells, forming a matrix column stored as an intrusive list - typedef boost::intrusive::list < - Cell - , boost::intrusive::constant_time_size - , boost::intrusive::base_hook< base_hook_matrix_column_list > > Column_list; - //vertical list of cells, forming a matrix column stored as an intrusive set - typedef boost::intrusive::set < - Cell - , boost::intrusive::constant_time_size - , boost::intrusive::base_hook< base_hook_matrix_column_set > > Column_set; - //choice encoded in Options::searchable_column. a column can be - //iterated through, and keys are read in strictly increasing natural order. - typedef typename std::conditional< - Options::searchable_column, - Column_set, - Column_list >::type Column; - //horizontal list of cells, forming a matrix row, no particular order on keys. - typedef boost::intrusive::list < - Cell - , boost::intrusive::constant_time_size - , boost::intrusive::base_hook< base_hook_matrix_row > > Row_list; - //rows are encoded by lists. need to be sorted and traversed - typedef Row_list Row; - - /* Chain for zigzag persistence. A chain stores: - * - a matrix column (col_i) that represents the chain as a sum of simplices - * (represented by their unique key, stored in the cells of the sparse column), - * - a matrix row of all elements of index the lowest index of the column (row_i), - * - is paired with another chain, indicating its type F, G, or H, - * - has a direct access to its lowest index. - */ - struct matrix_chain { - /* Trivial constructor, birth == -3 */ - matrix_chain() : column_(nullptr), row_(nullptr), paired_col_(nullptr), - birth_(-3), lowest_idx_(-1) {} - - /* Creates a matrix chain of type F with one cell of index 'key'. */ - matrix_chain(Simplex_key key) - : paired_col_(nullptr), birth_(key), lowest_idx_(key) - { - // Cell *new_cell = new Cell(key, this); - Cell *new_cell = cellPool_.construct(key, this); - if constexpr(Options::searchable_column) { column_.insert(*new_cell); } - else { column_.push_back(*new_cell); } - row_.push_back(*new_cell); - } - /* Creates a matrix chain of type F with new cells of key indices given by a - * range. Birth and lowest indices are given by 'key'. - * The range [beg,end) must be sorted by increasing key values, the same - * order as the column_ when read from column_.begin() to column_.end(). - * - * SimplexKeyIterator value_type must be Simplex_key. - * KeyToMatrixChain must be of type - * std::map< Simplex_key, typename std::list::iterator > - */ - template< typename SimplexKeyIterator, typename KeyToMatrixChain > - matrix_chain(Simplex_key key, SimplexKeyIterator beg, SimplexKeyIterator end, KeyToMatrixChain &lowidx_to_matidx) - : paired_col_(nullptr), birth_(key), lowest_idx_(key) - { - for(SimplexKeyIterator it = beg; it != end; ++it) - { - // Cell *new_cell = new Cell(*it, this);//create a new cell - Cell *new_cell = cellPool_.construct(*it, this); - //insertion in the column - if constexpr(Options::searchable_column) { - column_.insert(column_.end(), *new_cell); //ordered range - } - else { column_.push_back(*new_cell); } - //insertion in a row, not corresponding to the row stored in this->row_. - lowidx_to_matidx[*it]->row_.push_back( *new_cell ); - } - //Add the bottom coefficient for the chain - // Cell *new_cell = new Cell(key, this); - Cell *new_cell = cellPool_.construct(key, this); - //insertion in the column, key is larger than any *it in [beg, end) above. - if constexpr(Options::searchable_column) { - column_.insert(column_.end(), *new_cell); - } - else { column_.push_back(*new_cell); } - //insertion of row_, that stores no particular order. - row_.push_back( *new_cell ); - } - - /* Creates a matrix chain of type H with new cells of key indices given by a - * range. Birth and lowest indices are given by 'key'. - * The range [beg,end) must be sorted by increasing key values, the same - * order as the column_ when read from column_.begin() to column_.end(). - * - * SimplexKeyIterator value_type must be Simplex_key. - * KeyToMatrixChain must be of type - * std::map< Simplex_key, typename std::list::iterator > - */ - template< typename SimplexKeyIterator, typename KeyToMatrixChain > - matrix_chain(Simplex_key key, matrix_chain *paired_col, SimplexKeyIterator beg, SimplexKeyIterator end, KeyToMatrixChain &lowidx_to_matidx) - : paired_col_(paired_col), birth_(-2), lowest_idx_(key) - { - for(SimplexKeyIterator it = beg; it != end; ++it) - { - // Cell * new_cell = new Cell(*it, this);//create a new cell - Cell *new_cell = cellPool_.construct(*it, this); - //insertion in the column - if constexpr(Options::searchable_column) { - column_.insert(column_.end(), *new_cell); //ordered range - } - else { column_.push_back(*new_cell); } - //insertion in a row, not corresponding to the row stored in this->row_. - lowidx_to_matidx[*it]->row_.push_back( *new_cell ); - } - //Add the bottom coefficient for the chain - // Cell * new_cell = new Cell(key, this); - Cell *new_cell = cellPool_.construct(key, this); - //insertion in the column, key is larger than any *it in [beg, end) above. - if constexpr(Options::searchable_column) { - column_.insert(column_.end(), *new_cell); - } - else { column_.push_back(*new_cell); } - //insertion of row_, that stores no particular order. - row_.push_back( *new_cell ); - } - - /* Erase the chain, all cells were allocated with operator new. */ - ~matrix_chain() - { //empty the column, call delete on all cells - for(typename Column::iterator c_it = column_.begin(); c_it != column_.end(); ) - { - auto tmp_it = c_it; ++c_it; - Cell * tmp_cell = &(*tmp_it); - tmp_it->base_hook_matrix_row::unlink(); //rm from row - column_.erase(tmp_it); - cellPool_.destroy(tmp_cell); - // delete tmp_cell; - } - } - - /* Returns the chain with which *this is paired in the F,G,H classification. - * If in F (i.e., paired with no other column), return nullptr.*/ - matrix_chain * paired_chain() const { return paired_col_; } - /* Assign a paired chain. */ - void assign_paired_chain(matrix_chain *other_col) { paired_col_ = other_col; } - /* Access the column. */ - Column & column() { return column_; } - /* Returns the birth index (b >= 0) of the chain if the column is in F. - * Returns -2 if the chain is in H, and -1 if the chain is in G. */ - Simplex_key birth() const { return birth_; } - /* Assign a birth index to the chain. */ - void assign_birth(Simplex_key b) { birth_ = b; } - void assign_birth(matrix_chain *other) { birth_ = other->birth_; } - /* Returns true iff the chain is indexed in F. */ - bool inF() const { return birth_ > -1; } - /* Returns true iff the chain is indexed in G. */ - bool inG() const { return birth_ == -1; } - /* Returns true iff the chain is indexed in H. */ - bool inH() const { return birth_ == -2; } - Simplex_key lowest_idx() const { return lowest_idx_; } - - Column column_ ; //col at index i, with lowest index i - Row row_ ; //row at index i - matrix_chain * paired_col_ ; //\in F -> nullptr, \in H -> g, \in G -> h - Simplex_key birth_ ; //\in F -> b, \in H -> -2 \in G -> -1 - Simplex_key lowest_idx_ ; //lowest_idx_ = i (upper triangular matrix) - inline static Simple_object_pool cellPool_; - }; - -public: - /** \brief Structure to store persistence intervals by their filtration values. - * - * \details By convention, interval \f$[b;d]\f$ are - * closed for finite indices b and d, and open for left-infinite and/or - * right-infinite endpoints.*/ - struct fil_interval { - fil_interval() {} - fil_interval(int dim, Filtration_value b, Filtration_value d) : dim_(dim), b_(b), d_(d) {} - /** Returns the absolute length of the interval \f$|d-b|\f$. */ - Filtration_value length() { - if(b_ == d_) { return 0; } //otherwise inf - inf would return nan. - return std::abs(b_ - d_); - } - /** Returns the absolute length of the log values of birth and death, i.e. \f$|\log d - \log b|\f$.. */ - Filtration_value log_length() {//return the log-length - if(b_ == d_) { return 0; } //otherwise inf - inf would return nan. - return std::abs(log2((double)b_) - log2((double)d_)); - } - /** Returns the dimension of the homological feature corresponding to the - * interval. */ - int dim() const { return dim_; }//return the homological dimension of the interval - /** Returns the birth of the interval.*/ - Filtration_value birth() const { return b_; }//return the birth value - /** Returns the death of the interval.*/ - Filtration_value death() const { return d_; }//return the death value - /** Swaps the values of birth and death.*/ - void swap_birth_death() { std::swap(b_,d_); } - - private://note that we don't assume b_ <= d_ - int dim_; //homological dimension - Filtration_value b_; //filtration value associated to birth index - Filtration_value d_; //filtration value associated to death index - }; - - /** \brief Structure to store persistence intervals by their index values. - * - * \details By convention, interval [b;d] are - * closed for finite indices b and d, and open for left-infinite and/or - * right-infinite endpoints. - */ - struct interval_index { - interval_index() {} - interval_index(int dim, Simplex_key b, Simplex_key d) : dim_(dim), b_(b), d_(d) {} - /** Returns the dimension of the homological feature corresponding to the - * interval. */ - int dim() const { return dim_; }//return the homological dimension of the interval - /** Returns the birth index of the interval.*/ - Filtration_value birth() const { return b_; }//return the birth value - /** Returns the death index of the interval.*/ - Filtration_value death() const { return d_; }//return the death value - - private://note that we don't assume b_ <= d_ - int dim_; //homological dimension - Simplex_key b_; //filtration value associated to birth index - Simplex_key d_; //filtration value associated to death index - }; - -private: - /* Comparison function to sort intervals by decreasing log-length in the - * output persistence diagram, i.e., - * [f(b),f(d)]<[f(b'),f(d')] iff |log2(f(b))-log2(f(d))|> |log2(f(b'))-log2(f(d'))| - */ - struct cmp_intervals_by_log_length { - cmp_intervals_by_log_length(){} - bool operator()( fil_interval p, fil_interval q) - { - if(p.dim() != q.dim()) {return p.dim() < q.dim();}//lower dimension first - if(p.log_length() != q.log_length()) {return p.log_length() > q.log_length();} - if(p.birth() != q.birth()) {return p.birth() < q.birth();}//lex order - return p.death() < q.death(); - } - }; - /* Comparison function to sort intervals by decreasing length in the - * output persistence diagram, i.e., - * [f(b),f(d)]<[f(b'),f(d')] iff |f(b)-f(d)| > |f(b')-f(d')| - */ - struct cmp_intervals_by_length { - cmp_intervals_by_length(){} - bool operator()( fil_interval p, fil_interval q) - { - if(p.length() != q.length()) { return p.length() > q.length(); }//longest 1st - if(p.dim() != q.dim()) {return p.dim() < q.dim();}//lower dimension first - if(p.birth() != q.birth()) {return p.birth() < q.birth();}//lex order - return p.death() < q.death(); - } - }; - -public: - /** \brief Initialization of the Zigzag_persistence class. - * - * \param[in] cpx A model of ZigzagFilteredComplex. - * */ - Zigzag_persistence(int ignore_cycles_above_dim = -1) - : cpx_() - , dim_max_(ignore_cycles_above_dim) - , lowidx_to_matidx_() - , matrix_() - , birth_ordering_() - , persistence_diagram_() - , num_arrow_(-1) - , previous_filtration_value_(std::numeric_limits::infinity()) - , filtration_values_() {} - -private: - /* Set c1 <- c1 + c2, assuming canonical order of indices induced by the order in - * the vertical lists. self1 is the matrix_chain whose column is c1, for self - * reference of the new cells. - */ - void plus_equal_column(matrix_chain * self1, Column & c1, Column & c2) - { - //insert all elements of c2 in c1, in O(|c2| * log(|c1|+|c2|)) - if constexpr (Options::searchable_column) { - for(auto &cell : c2) { - auto it1 = c1.find(cell); - if(it1 != c1.end()) {//already there => remove as 1+1=0 - Cell * tmp_ptr = &(*it1); - it1->base_hook_matrix_row::unlink(); //unlink from row - c1.erase(it1); //remove from col - matrix_chain::cellPool_.destroy(tmp_ptr); - // delete tmp_ptr; - } - else {//not there, insert new cell - // Cell *new_cell = new Cell(cell.key(), self1); - Cell *new_cell = matrix_chain::cellPool_.construct(cell.key(), self1); - c1.insert(*new_cell); - lowidx_to_matidx_[cell.key()]->row_.push_back(*new_cell);//row link,no order - } - } - } - else {//traverse both columns doing a standard column addition, in O(|c1|+|c2|) - auto it1 = c1.begin(); auto it2 = c2.begin(); - while(it1 != c1.end() && it2 != c2.end()) - { - if(it1->key() < it2->key()) { ++it1; } - else { - if(it1->key() > it2->key()) { - // Cell * new_cell = new Cell(it2->key(), self1); - Cell *new_cell = matrix_chain::cellPool_.construct(it2->key(), self1); - c1.insert(it1, *new_cell); //col link, in order - lowidx_to_matidx_[it2->key()]->row_.push_back(*new_cell);//row link,no order - ++it2; - } - else { //it1->key() == it2->key() - auto tmp_it = it1; ++it1; ++it2; - Cell * tmp_ptr = &(*tmp_it); - tmp_it->base_hook_matrix_row::unlink(); //unlink from row - c1.erase(tmp_it); //remove from col - matrix_chain::cellPool_.destroy(tmp_ptr); - // delete tmp_ptr; - } - } - } - while(it2 != c2.end()) {//if it1 reached the end of its column, but not it2 - // Cell * new_cell = new Cell(it2->key(),self1); - Cell *new_cell = matrix_chain::cellPool_.construct(it2->key(), self1); - lowidx_to_matidx_[it2->key()]->row_.push_back(*new_cell); //row links - c1.push_back(*new_cell); - ++it2; - } - } - } - - /** Maintains the birth ordering <=b. Contains an std::map of size the number of - * non-zero rows of the homology matrix, at any time during the computation of - * zigzag persistence. - * - * By construction, we maintain the map satisfying - * 'birth_to_pos_[i] < birth_to_pos_[j]', - * with 0 <= i,j <= k indices in the quiver '0 \leftrightarrow ... \leftrightarrow i \leftrightarrow .. \leftrightarrow k' - * visited at time k of the algorithm (prefix of length k of the full zigzag - * filtration '0 \leftrightarrow ... \leftrightarrow i \leftrightarrow .. \leftrightarrow k \leftrightarrow ... \leftrightarrow n' that is studied), - * iff i k+1 forward, then j 0 -> 1 -> 2 <- 3 <- 4 -> 5 <- 6 etc - birth_ordering() : birth_to_pos_(), max_birth_pos_(0), min_birth_pos_(-1) {} - - //when the arrow key-1 -> key is forward, key is larger than any other index - //i < key in the birth ordering b k2 - bool reverse_birth_order(Simplex_key k1, Simplex_key k2) { - return birth_to_pos_[k1] > birth_to_pos_[k2]; - } - - private: - //birth_to_pos_[i] < birth_to_pos_[j] iff i birth_to_pos_; - //by construction, max_birth_pos_ (resp. min_birth_pos_) is strictly larger - //(resp. strictly smaller) than any value assigned to a key so far. - Simplex_key max_birth_pos_; - Simplex_key min_birth_pos_; - }; - -public: - /** \brief Computes the zigzag persistent homology of a zigzag filtered complex, - * using the reflection and transposition algorithm of \cite zigzag_reflection. - * - * \details After computation, the persistence diagram can be accessed via - * member method persistence_diagram, for the diagram with filtration - * values, or member method index_persistence_diagram, for the - * diagram with - * indices of paired simplices. - * - * - * matrix_, originally empty, maintains the set of chains, with a - * partition \f$ F \sqcup G \sqcup H\f$ - * representing a compatible homology basis as in \cite zigzag_reflection. - * - * Each simplex in the complex stores a key field that stores the index of - * its insertion in the zigzag filtration. - * - * The algorithm maintains a compatible homology basis for the zigzag filtration. - * - * \f$$\emptyset = K_0 \leftrightarrow (...) \leftrightarrow K_i \leftarrow ... \leftarrow \emptyset\f$$ - * - * where the prefix from \f$K_0\f$ to \f$K_i\f$ is equal to the i-th prefix of - * the input zigzag - * filtration given by cpx_.filtration_simplex_range(), and - * the suffix - * (from \f$K_i\f$ - * to the right) is a sequence of simplex removals. Due to the structure of - * reflection diamonds, the removals are in reverse order of the insertions, to - * reduce the amount of transposition diamonds. - * - * Consequently, using cpx_.key(zzsh) as indexing for the matrix - * rows/cells, - * with the natural order on integers, makes our homology matrix matrix_ upper - * triangular for the suffix \f$K_i \leftarrow ... \leftarrow 0\f$, seen as a - * standard persistence - * filtration. At \f$K_i\f$, the natural order on integers is also equivalent to the - * death-order \f$\leq_d\f$ (because all arrows in the suffix are backward). - * - * Insertion: cpx_.key(*zzit) is a strictly increasing sequence - * for zzit - * insertion of cells (does not need to be contiguous). However, for every forward - * arrow, we have cpx_.key(*zzit) == num_arrows_. - * Removal: cpx_.key(*zzit) gives the assigned key (during past - * insertion) of a - * cell == *zzit during a removal. We use num_arrows_ - * to record the deaths in the - * persistence diagram. - * Insertion and Removal: zzit.filtration() is totally monotone. - * Note that the - * iterator encodes the filtration, and not the cells within the complex structure. - */ -// void zigzag_persistent_homology() -// { //compute index persistence, interval are closed, i.e., [b,d) is stored as -// //[b,d-1]. The filtration values are maintained in field filtration_values_ -// Filtration_value prev_fil_, curr_fil_; - -// assert(num_arrow_ == 0); -// auto zzrg = cpx_.filtration_simplex_range(); -// auto zzit = zzrg.begin(); -// dim_max_ = zzit.dim_max(); - -// num_arrow_ = cpx_.key(*zzit);//should be 0 - -// prev_fil_ = zzit.filtration(); -// filtration_values_.emplace_back(num_arrow_, prev_fil_); - -// while( zzit != zzrg.end() ) -// { //insertion of a simplex -// if(zzit.arrow_direction()) { num_arrow_ = cpx_.key(*zzit); } -// else { ++num_arrow_; } //removal of a simplex, a simplex key corresponds to the index of its INSERTION -// curr_fil_ = zzit.filtration();//cpx_.filtration(*zzit) is invalid for (<-); -// if(curr_fil_ != prev_fil_) //check whether the filt value has changed -// { //consecutive pairs (i,f), (j,f') mean simplices of index k in [i,j-1] have -// prev_fil_ = curr_fil_; //filtration value f -// filtration_values_.emplace_back(num_arrow_, prev_fil_); -// } -// if(zzit.arrow_direction()) { //forward arrow, only consider critical cells -// forward_arrow(*zzit); -// } -// else { //backward arrow -// backward_arrow(*zzit); -// } -// ++zzit; -// } - -//// if(!matrix_.empty()) { -//// std::cout << "There remain " << matrix_.size() << " columns in the matrix.\n"; -//// } -// } - - template> - void insert_simplex(const VertexRange& simplex, Filtration_value filtration_value) - { - if (dim_max_ != -1 && simplex.size() > static_cast(dim_max_) + 1) return; - - ++num_arrow_; - - if (filtration_value != previous_filtration_value_) //check whether the filt value has changed - { //consecutive pairs (i,f), (j,f') mean simplices of index k in [i,j-1] have - previous_filtration_value_ = filtration_value; //filtration value f - filtration_values_.emplace_back(num_arrow_, previous_filtration_value_); - } - - std::pair res = cpx_.insert_simplex(simplex, filtration_value); - GUDHI_CHECK(res.second, "Zigzag_persistence::insert_simplex - insertion of a simplex already in the complex"); - cpx_.assign_key(res.first, num_arrow_); - _process_forward_arrow(res.first); - } - - template> - void remove_simplex(const VertexRange& simplex, Filtration_value filtration_value) - { - if (dim_max_ != -1 && simplex.size() > static_cast(dim_max_) + 1) return; - - ++num_arrow_; - - Simplex_handle sh = cpx_.find(simplex); - GUDHI_CHECK(sh != cpx_.null_simplex(), "Zigzag_persistence::remove_simplex - removal of a simplex not in the complex"); - - if (filtration_value != previous_filtration_value_) //check whether the filt value has changed - { //consecutive pairs (i,f), (j,f') mean simplices of index k in [i,j-1] have - previous_filtration_value_ = filtration_value; //filtration value f - filtration_values_.emplace_back(num_arrow_, previous_filtration_value_); - } - - _process_backward_arrow(sh); - cpx_.remove_maximal_simplex(sh); - } - - template>, - class FiltrationRange = std::initializer_list> - void insert_simplices_contiguously(const SimplexRange& simplices, const FiltrationRange& filtration_values) - { - auto simplexIt = simplices.begin(); - auto filIt = filtration_values.begin(); - for (; simplexIt != simplices.end(); ++simplexIt, ++filIt) { - insert_simplex(*simplexIt, *filIt); - } - } - - template>, - class FiltrationRange = std::initializer_list> - void remove_simplices_contiguously(const SimplexRange& simplices, const FiltrationRange& filtration_values) - { - auto simplexIt = simplices.begin(); - auto filIt = filtration_values.begin(); - for (; simplexIt != simplices.end(); ++simplexIt, ++filIt) { - remove_simplex(*simplexIt, *filIt); - } - } - - template - void insert_simplices_contiguously(SimplexRangeIterators simplex_range_start, - SimplexRangeIterators simplex_range_end, - FiltrationRangeIterators filtration_range_start) - { - for (; simplex_range_start != simplex_range_end; ++simplex_range_start, ++filtration_range_start) { - insert_simplex(*simplex_range_start, *filtration_range_start); - } - } - - template - void remove_simplices_contiguously(SimplexRangeIterators simplex_range_start, - SimplexRangeIterators simplex_range_end, - FiltrationRangeIterators filtration_range_start) - { - for (; simplex_range_start != simplex_range_end; ++simplex_range_start, ++filtration_range_start) { - remove_simplex(*simplex_range_start, *filtration_range_start); - } - } - - void print_current_complex(){ - for (auto& sh : cpx_.complex_simplex_range()){ - for (auto v : cpx_.simplex_vertex_range(sh)){ - std::cout << v << " "; - } - std::cout << " - " << cpx_.filtration(sh) << "\n"; - } - } - -private: - /** \brief Computes the boundary cycle of the new simplex zzsh, and express it as a - * sum of cycles. If all cycles are boundary cycles, i.e., columns with G-index - * in the matrix, then [\partial zzsh] = 0 and we apply an injective diamond to - * the zigzag module. Otherwise, we keep reducing with boundary- and live- cycles, - * i.e., columns with (F \cup G)-indices, and then apply a surjective diamond to - * the zigzag module. - */ - void _process_forward_arrow( Simplex_handle zzsh ) - { //maintain the <=b order - birth_ordering_.add_birth_forward(num_arrow_); - - //Reduce the boundary of zzsh in the basis of cycles. - //Compute the simplex keys of the simplices of the boundary of zzsh. - std::set< Simplex_key > col_bsh; //set maintains the natural order on indices - for( auto b_sh : cpx_.boundary_simplex_range(zzsh) ) - { col_bsh.insert(cpx_.key(b_sh)); } - - //If empty boundary (e.g., when zzsh is a vertex in a simplicial complex) - //Add a non-trivial cycle [c = zzsh] to the matrix, lowidx_to_matidx_make it a creator in F. - if(col_bsh.empty()) // -> creator - { //New row and column with a bottom-right non-zero element, at index key(zzsh) - //i.e., create a new cycle in F, equal to *zzsh alone. - matrix_.emplace_front(num_arrow_); - auto new_chain_it = matrix_.begin();//the new chain - //Update the map [index idx -> chain with lowest index idx] in matrix_ - lowidx_to_matidx_[num_arrow_] = new_chain_it; - return; - } - - // col_bsh.rbegin()) is idx of lowest element in col_bsh, because it is a set. - matrix_chain *col_low = &(*lowidx_to_matidx_[*(col_bsh.rbegin())]); - auto paired_idx = col_low->paired_col_; //col with which col_low is paired - std::vector< matrix_chain * > chains_in_H; //for corresponding indices in H - std::vector< matrix_chain * > chains_in_G; - - //Reduce col_bsh with boundary cycles, i.e., indices in G. - std::pair< typename std::set< Simplex_key >::iterator, bool > res_insert; - while( paired_idx != nullptr ) - { - chains_in_H.push_back(paired_idx);//keep the col_h with which col_g is paired - chains_in_G.push_back(col_low); //keep the col_g - for(auto &cell : (col_low->column())) { //Reduce with the column col_g - res_insert = col_bsh.insert(cell.key()); - if( !res_insert.second ) { col_bsh.erase(res_insert.first); } //1+1 = 0 - //o.w. insertion has succeeded. - } - //If col_bsh is entirely reduced, \partial zzsh is a boundary cycle. - if(col_bsh.empty()) { - // if(cpx_.dimension(zzsh) >= max_dim_) {return;} we need max_dim creators - injective_reflection_diamond(zzsh, chains_in_H); - return; - } - //Continue the reduction - col_low = &(*lowidx_to_matidx_[*(col_bsh.rbegin())]);//curr low index col - paired_idx = col_low->paired_col_;//col with which col_low is paired - } - - //Continue reducing with boundary and 'live' cycles, i.e., indices in G U F. - std::vector< matrix_chain * > chains_in_F; - while(true) - { - if(paired_idx == nullptr) { chains_in_F.push_back(col_low); }//col_low is in F - else { chains_in_H.push_back(paired_idx); } //col_low in G, paired_idx is in H - //Reduce with the column col_g or col_f - for(auto &cell : (col_low->column())) { - res_insert = col_bsh.insert(cell.key()); - if( !res_insert.second ) { col_bsh.erase(res_insert.first); } //1+1 = 0 - //o.w. insertion has succeeded. - } - //If col_bsh is entirely reduced, i.e. col_bsh == \emptyset. - if(col_bsh.empty()) - { - surjective_reflection_diamond(zzsh, chains_in_F, chains_in_H); - return; - } - //Else, keep reducing. - col_low = &(*lowidx_to_matidx_[*(col_bsh.rbegin())]); //curr low index col - paired_idx = col_low->paired_col_;//col with which col_low is paired - } - } - - /** \brief Computes an injective diamond in the zigzag module, by inserting a new - * column for the chain zzsh - \sum col_h, for all col_h in chains_in_H, and a - * new row for the simplex zzsh. - */ - void injective_reflection_diamond ( Simplex_handle zzsh - , std::vector< matrix_chain * > & chains_in_H ) - { //Compute the chain zzsh + \sum col_h, for col_h \in chains_in_H - std::set< Simplex_key > col_bsh; - std::pair< typename std::set< Simplex_key >::iterator, bool > res_insert; - //produce the sum of all col_h in chains_in_H - for( matrix_chain *idx_h : chains_in_H ) { - for(auto &cell : (idx_h->column()) ) { - res_insert = col_bsh.insert(cell.key()); - if( !res_insert.second ) { col_bsh.erase(res_insert.first); } - } - } - //create a new cycle (in F) sigma - \sum col_h - matrix_.emplace_front(num_arrow_, col_bsh.begin(), col_bsh.end(), - lowidx_to_matidx_); - //Update the map 'index idx -> chain with lowest index idx' in matrix_ - auto chain_it = matrix_.begin(); - lowidx_to_matidx_[num_arrow_] = chain_it; - } - - /** The vector chains_in_F is sorted by decreasing lowest index values in the - * columns corresponding to the chains, due to its computation in the reduction of - * \partial zzsh in forward_arrow(...). It is equivalent to decreasing death index - * order w.r.t. the & chains_in_F - , std::vector< matrix_chain * > & chains_in_H ) - { //fp is the largest death index for <=d - //Set col_fp: col_fp <- col_f1+...+col_fp (now in G); preserves lowest idx - auto chain_fp = *(chains_in_F.begin()); //col_fp, with largest death column(), (*other_col_it)->column()); } - //doesn't change the lowest idx as chain_fp has maximal lowest idx of all - - //chains_in_F is ordered, from .begin() to end(), by decreasing lowest_idx_. The - //lowest_idx_ is also the death of the chain in the right suffix of the - //filtration (all backward arrows). Consequently, the chains in F are ordered by - //decreasing death for bool - { return birth_ordering_.reverse_birth_order(k1,k2); };//true iff b(k1) >b b(k2) - - //available_birth: for all i by >d value of the d_i, - //contains at step i all b_j, j > i, and maybe b_i if not stolen - std::set< Simplex_key, decltype(cmp_birth) > available_birth(cmp_birth); - //for f1 to f_{p} (i by <=d), insertion in available_birth_to_fidx sorts by >=b - for(auto &chain_f : chains_in_F) { available_birth.insert(chain_f->birth()); } - - auto maxb_it = available_birth.begin();//max birth cycle - auto maxb = *maxb_it; //max birth value, for persistence diagram - available_birth.erase(maxb_it); //remove max birth cycle (stolen) - - auto last_modified_chain_it = chains_in_F.rbegin(); - - //consider all death indices by increasing birth()); - if(birth_it == available_birth.end()) //birth is not available. *chain_f_it - { //must become the sum of all chains in F with smaller death index. - //this gives as birth the maximal birth of all chains with strictly larger - //death <=> the maximal availabe death. - //Let c_1 ... c_f be the chains s.t. <[c_1+...+c_f]> is the kernel and - // death(c_i) >d death(c_i-1). If the birth of c_i is not available, we set - //c_i <- c_i + c_i-1 + ... + c_1, which is [c_i + c_i-1 + ... + c_1] on - //the right (of death the maximali <=> the maxj>k, are indeed c_j - //set c_i <- c_i + (c_i-1) + ... + (c_k+1) + (c_k + ... + c_1) - for(auto chain_passed_it = last_modified_chain_it;//all with smaller column() - , (*chain_passed_it)->column() ); - } - last_modified_chain_it = chain_f_it;//new cumulated c_i+...+c_1 - //remove the max available death - auto max_avail_b_it = available_birth.begin();//max because order by deacr assign_birth(max_avail_b); //give new birth - available_birth.erase(max_avail_b_it); //remove birth from availability - } - else { available_birth.erase(birth_it); } //birth not available anymore, do not - } //modify *chain_f_it. - //Compute the new column zzsh + \sum col_h, for col_h in chains_in_H - std::set< Simplex_key > col_bsh; - std::pair< typename std::set< Simplex_key >::iterator, bool > res_insert; - for(auto other_col : chains_in_H) - { //Compute (\sum col_h) in a set - for(auto &cell : (other_col->column())) - { - res_insert = col_bsh.insert(cell.key()); - if( !res_insert.second ) { col_bsh.erase(res_insert.first); } //1+1=0 - } - } - //Create and insert (\sum col_h) + sigma (in H, paired with chain_fp) in matrix_ - matrix_.emplace_front(cpx_.key(zzsh), chain_fp, col_bsh.begin(), col_bsh.end(), lowidx_to_matidx_); - //record that the chain with lowest index key(zzsh) is the one just created - auto chain_it = matrix_.begin(); - lowidx_to_matidx_[cpx_.key(zzsh)] = chain_it;//new row - - chain_fp->assign_paired_chain( &(*chain_it) );//pair chain_fp with the new chain - chain_fp->assign_birth(-1); //now belongs to G now -> right interval [m-1,g] - - //Update persistence diagram with left interval [fil(b_max) ; fil(m)) - persistence_diagram_.emplace_back( cpx_.dimension(zzsh)-1 - , maxb - , cpx_.key(zzsh));//-1);// - } - - //cpx_.key(zzsh) is the key of the simplex we remove, not a new one - void _process_backward_arrow( Simplex_handle zzsh ) - { - //maintain the <=b order - birth_ordering_.add_birth_backward(num_arrow_); - //column whose key is the one of the removed simplex - auto curr_col_it = lowidx_to_matidx_.find(cpx_.key(zzsh)); - //corresponding chain - matrix_chain * curr_col = &(*(curr_col_it->second)); - //Record all columns that get affected by the transpositions, i.e., have a coeff - std::vector< matrix_chain * > modified_columns;//in the row of idx key(zzsh) - for(auto & hcell : (curr_col->row_)) { - modified_columns.push_back(hcell.self_chain_); - } - //Sort by left-to-right order in the matrix_ (no order maintained in rows) - std::stable_sort( modified_columns.begin(),modified_columns.end() - , [](matrix_chain *mc1, matrix_chain *mc2) - { return mc1->lowest_idx_ < mc2->lowest_idx_;} ); - - //Modifies the pointer curr_col, not the other one. - for(auto other_col_it = modified_columns.begin()+1; - other_col_it != modified_columns.end(); ++other_col_it) { - curr_col = arrow_transposition_case_study(curr_col, *other_col_it); - } - - //curr_col points to the column to remove by restriction of K to K-{\sigma} - if( curr_col->paired_col_ == nullptr ) { // in F - int dim_zzsh = cpx_.dimension(zzsh); - if(dim_max_ == -1 || (dim_max_ != -1 && dim_zzsh < dim_max_)) { //don't record intervals of max dim - persistence_diagram_.emplace_back( dim_zzsh - , curr_col->birth() - , num_arrow_);// -1); - } - } - else { //in H -> paired with c_g, that now belongs to F now - curr_col->paired_col_->assign_paired_chain(nullptr); - curr_col->paired_col_->assign_birth(num_arrow_); //closed interval - } - - //cannot be in G as the removed simplex is maximal - matrix_.erase(curr_col_it->second); - lowidx_to_matidx_.erase(curr_col_it); - } - - /* Exchanges members of matrix_chains, except the column_ pointer. Modify - * also the lowidx_to_matidx_ data structure, considering that the matrix chains - * also exchange their lowest_idx_. Specifically, it is called by - * arrow_transposition_case_study when: - * c_s has originally birth b_s and low idx s, and c_t has birth b_t and low idx t - * however, c_s becomes c_s <- c_s+c_t with b_t lowest_idx_); - auto it_t = lowidx_to_matidx_.find(other_col->lowest_idx_); - - std::swap(it_s->second, it_t->second);//swap matrix_chain* in lowidx_to_matidx_ - std::swap(curr_col->row_, other_col->row_);//swap associated row of lowest idx - std::swap(curr_col->lowest_idx_, other_col->lowest_idx_);//swap lowest idx. - } - - /** - * Permutes s and t, s goes up, whose insertions are adjacent, i.e., the following - * transformation (from (a) to (b)) in the filtration: - * from (a) ... \leftrightarrow K \leftarrow ... \leftarrow K' U {s,t} \leftarrow K' U {s} \leftarrow K' \leftarrow ..., - * where K' is at matrix index i, K' U {s} at matrix index i+1 and K' U {s,t} at - * matrix index i+2, - * - * to (b) ... \leftrightarrow K \leftarrow ... \leftarrow K' U {s,t} \leftarrow K' U {t} \leftarrow K' \leftarrow ..., - * - * and the chain c_t has a non-trivial coefficient for s, i.e., - * the bloc matrix gives (and becomes): - * c_t c_t - * + + - * c_s c_t c_s c_s c_s c_t - * s 1 1 t 1 0 t 1 1 - * t 0 1 --> either s 0 1 or s 0 1 - * - * By construction, s is a simplex that we want to remove in the complex K. It is - * consequently maximal in K, and all complexes between K and K' U {s} in filtration - * (a). - * - * If c_s and c_t are both cycles (in F)that, before the permutation, are carried by - * respectively the closed intervals [b_s, i+1] and [b_t, i+2], then the sum - * c_s + c_t is a cycle carried by the interval - * [maxd i (i+1 \leftarrow i backward). - * If j \leftarrow ... \leftarrow k are both birth indices on the right part of the quiver (all - * backward arrows) then systematically k inF()) - {//case F x * - if(other_col->inH()) { // case F x H - plus_equal_column( other_col, other_col->column()//c_t <- c_s+c_t still in H - , curr_col->column() );//(birth -2) and low idx t - return curr_col; - }//end case F x H - else // case F x F - { //in F x F: c_s+c_t has max<=b birth between b_t and b_s: - if(birth_ordering_.birth_order(curr_col->birth(), other_col->birth())) - { //max<=b is the birth of other_col i.e., b_s column()//c_t <- c_s+c_t of birth - , curr_col->column() );//b_t and lowest idx t. (same) - //c_s still has birth b_s (minimal) and lowest idx s - return curr_col;//continue with c_s of smaller birth b_s and lowest idx s - }//endif - else - { //max<=b is the birth of curr_col, i.e., b_t column()//c_s <- c_s+c_t of birth - , other_col->column() );//b_s and of NEW lowest idx t - //now c_t has (same) birth b_t (minimal) but NEW lowest idx s, so - //exchange lowest_idx, the rows, and update lowidx_to_matidx structure - exchange_lowest_indices_chains(curr_col, other_col); - return other_col;//continue with c_t of (smaller) birth b_t and low idx s - }//end else - }//end case F x F - }//end case F x * - else {//curr_col->inH() == true, case H x * - if(other_col->inH()) {// case H x H - //Case H x H, c_s+c_t paired w/ c_gs+c_gt, of death - //maxpaired_col_; //c_s paired with c_gs, death d_gs - auto other_p_col = other_col->paired_col_;//c_t paired with c_gt, death d_gt - if( curr_p_col->lowest_idx_ < other_p_col->lowest_idx_)//<=> d_gs column()//c_gt <- c_gs+c_gt, - , curr_p_col->column() );//of death d_gt, low idx d_gt - //(same because bigger), paired with c_s+c_t (now &c_t, updated below) - plus_equal_column( other_col, other_col->column()//c_t <- c_t+c_s, still - , curr_col->column() );//in H, low idx t (same) - return curr_col;//continue with c_s, paired with c_gs of min death d_gs - } - else - {// d_gt column()//c_gs <- c_gs+c_gt, - , other_p_col->column() );//of death d_gs, low idx d_gs - //(same because bigger), paired with c_s+c_t (now &c_s, updated below) - plus_equal_column( curr_col, curr_col->column()//c_s <- c_s+c_t, of NEW - , other_col->column());//low idx t (still in H) - //now c_s is still in H (birth -2) but has NEW lowest idx t, and c_t has - //low idx s after transposition. - //exchange lowest_idx, the rows, and update lowidx_to_matidx structure - exchange_lowest_indices_chains(curr_col, other_col); - return other_col; //continue with c_t, paired w. c_g' of min death g' - } - }//end case H x H - else {//other_col->inF() == true, case H x F - plus_equal_column( curr_col, curr_col->column() //c_s <- c_s+c_t still in H, - , other_col->column()); //(birth -2) and NEW low idx t - //now c_t, still in F, has (same) birth b_t but NEW lowest idx s, so - //exchange lowest_idx, the rows, and update lowidx_to_matidx structure - exchange_lowest_indices_chains(curr_col, other_col); - return other_col; //continue with c_t, still in F, of birth b_t and low idx s - } - } - } - - -public: - /** \brief Returns the index persistence diagram as an std::list of intervals.*/ - const std::list< interval_index > & get_index_persistence_diagram() const - { - return persistence_diagram_; - } - - /** \brief Returns the filtration values \f$[f(b),f(d)]\f$ (generally real-valued) - * associated to the indices \f$[b,d]\f$ (integer valued) of the insertion or - * deletion of a simplex in the zigzag filtration. - * - * \details Used to convert a persistent interval \f$[b,d]\f$, computed by the - * persistent homology algorithm, into its filtration valued version - * \f$[f(b),f(d)]\f$ used in the persistence barcode. The information - * index->filtration is stored in the member filtration_values_ of - * the class Zigzag_persistence. - * - * @param[in] b_key, d_key The indices of birth and death of a persistent - * interval. - * - * @param[out] std::pair A pair of real values \f$(f(b),f(d))\f$. - */ - std::pair map_index_to_filtration_value( - Simplex_key b_key, Simplex_key d_key) { - // filtration_values_ must be sorted by increasing keys. - auto it_b = //lower_bound(x) returns leftmost y s.t. x <= y - std::lower_bound( filtration_values_.begin(), filtration_values_.end() - , std::pair(b_key - , std::numeric_limits::infinity() ) - , []( std::pair p1 - , std::pair p2) - { return p1.first < p2.first; } - ); - if(it_b == filtration_values_.end() || it_b->first > b_key) { --it_b; } - //it points to the rightmost z such that z <= x - - auto it_d = // - std::lower_bound( filtration_values_.begin(), filtration_values_.end() - , std::pair(d_key - , std::numeric_limits::infinity() ) - , []( std::pair p1 - , std::pair p2) - { return p1.first < p2.first; } - ); - if(it_d == filtration_values_.end() || it_d->first > d_key) { --it_d; } - - return std::make_pair(it_b->second, it_d->second); - } - - /** \brief Writes the persistence diagram in a file. - * - * \details The filtration values are given by the zigzag persistence iterator, that assigns - * to any insertion or deletion of a simplex a filtration value ; we say that an - * arrow has an index \f$i\f$, and a corresponding filtration value \f$f(i)\f$. - * Reading a zigzag filtration from left to right, indices are strictly - * monotonically increasing, and the associated filtration values are monotonous - * (not necessarily - * strictly, either increasing or decreasing). - * - * Consider two consecutive arrows (insertion or deletion): - * - * \f$$K_1 \leftrightarrow K_2 \leftrightarrow K_3\f$$ - * - * with respectively indices \f$i\f$ (left) and \f$i+1\f$ (right), and associated - * filtration values \f$f(i)\f$ and \f$f(i+1)\f$ respectively. - * - * If, the arrow \f$K_2 \leftrightarrow K_3\f$ leads to the creation of a new - * homology feature in \f$K_3\f$, it creates an (indexed) persistent interval - * \f$[\f$i+1; \cdot\f$, and a corresponding (filtration) persistent interval - * \f$[f(i+1); \cdot]\f$ in the persistence diagram. - * - * If a homology feature in \f$K_2\f$ is destroyed by the arrow \f$K_2 \leftrightarrow K_3\f$, it closes an (indexed) - * interval \f$[\cdot ; i+1]\f$, and a corresponding (filtration) persistent - * interval \f$[\cdot ; f(i+1)]\f$ in the persistence diagram. - * - * For example, in an oscillating Rips zigzag filtration, if, in the following - * chunk of filtration: - * - * \f$R_{\eta \varepsilon_i}(P_i) \rightarrow \cdots \leftarrow R_{\eta \varepsilon_{i+1}}(P_{i+1}),\f$ - * - * if anything is created by any of the arrows above, it leads to an interval - * \f$[\varepsilon_{i+1}; \cdot]\f$. If anything is destroyed by any of the arrows - * above, if leads to an interval \f$[\cdot;\varepsilon_i]\f$. Note that we may - * have \f$\varepsilon_i > \varepsilon_{i+1}\f$. - * - * The bars are ordered by decreasing length. - * - * @param[in] os the output stream in which the diagram is written. - * @param[in] shortest_interval all intervals of lenght smaller or equal to - * this value are ignore. Default is 0. - */ - void persistence_diagram( std::ostream& os - , Filtration_value shortest_interval = 0.) { - - std::stable_sort(filtration_values_.begin(), filtration_values_.end(), - []( std::pair< Simplex_key, Filtration_value > p1 - , std::pair< Simplex_key, Filtration_value > p2 ) - { return p1.first < p2.first; } - ); - - std::vector< fil_interval > tmp_diag; - tmp_diag.reserve(persistence_diagram_.size()); - for(auto bar : persistence_diagram_) - { - Filtration_value birth,death; - std::tie(birth,death) = map_index_to_filtration_value(bar.birth(), bar.death()); - - if( std::abs(birth - death) > shortest_interval ) { - tmp_diag.emplace_back(bar.dim(), birth, death ); - } - } - // cmp_intervals_by_length cmp; - std::stable_sort(tmp_diag.begin(), tmp_diag.end(), cmp_intervals_by_length()); - - os << "# dim birth death [length]\n"; - for(auto bar : tmp_diag) { - if(bar.birth() > bar.death()) { bar.swap_birth_death(); } - os << bar.dim() << " " << bar.birth() << " " << bar.death() << - " - [" << bar.length() << "] \n"; - } - } - - /** \brief Returns the persistence diagram as a vector of real-valued intervals. */ - std::vector< fil_interval > - get_persistence_diagram(Filtration_value shortest_interval = 0., bool include_infinit_bars = false) - { - std::stable_sort(filtration_values_.begin(), filtration_values_.end(), - []( std::pair< Simplex_key, Filtration_value > p1 - , std::pair< Simplex_key, Filtration_value > p2 ) - { return p1.first < p2.first; } - ); - - std::vector< fil_interval > diag; - diag.reserve(persistence_diagram_.size()); - for(auto bar : persistence_diagram_) - { - Filtration_value birth,death; - std::tie(birth,death) = map_index_to_filtration_value(bar.birth(), bar.death()); - - if( std::abs(birth - death) > shortest_interval ) { - diag.emplace_back(bar.dim(), birth, death ); - } - } - //put lower value as birth - for(auto &bar : diag) { - if( bar.birth() > bar.death() ) { bar.swap_birth_death(); } - } - std::stable_sort(diag.begin(), diag.end(), cmp_intervals_by_length()); - - auto birth = - [this](Simplex_key b_key) { - auto it_b = // lower_bound(x) returns leftmost y s.t. x <= y - std::lower_bound(filtration_values_.begin(), filtration_values_.end(), - std::pair( - b_key, std::numeric_limits::infinity()), - [](std::pair p1, - std::pair p2) { return p1.first < p2.first; }); - if (it_b == filtration_values_.end() || it_b->first > b_key) { - --it_b; - } - return it_b->second; - }; - - //TODO: dimension value - if (include_infinit_bars) { - for (const matrix_chain &col : matrix_) { - if (col.inF()) - diag.emplace_back(-1, birth(col.birth()), std::numeric_limits::infinity()); - } - } - - return diag; - } - -private: - Complex cpx_; // complex - int dim_max_;//max dim complex - //idx -> chain with lowest element at index idx in matrix_ - std::map< Simplex_key, typename std::list::iterator > - lowidx_to_matidx_; - //arbitrary order for the matrix chains - std::list< matrix_chain > matrix_; // 0 ... m-1 - // birth_vector birth_vector_; //<=b order - birth_ordering birth_ordering_; - std::list< interval_index > persistence_diagram_; - Simplex_key num_arrow_; //current index - Filtration_value previous_filtration_value_; - // filtration_values stores consecutive pairs (i,f) , (j,f') with f != f', - // meaning that all inserted simplices with key in [i;j-1] have filtration value f - //i is the smallest simplex index whose simplex has filtration value f. - std::vector< std::pair< Simplex_key, Filtration_value > > filtration_values_; -};//end class Zigzag_persistence - - -/** ZigzagPersistenceOptions, represents matrix columns by intrusive lists.*/ -struct Zigzag_persistence_collist { - static const bool searchable_column = false; -}; -/** ZigzagPersistenceOptions, represents matrix columns by intrusive sets.*/ -struct Zigzag_persistence_colset { - static const bool searchable_column = true; -}; - -} //namespace zigzag_persistence - -} //namespace Gudhi - -#endif //ZIGZAG_PERSISTENCE_H_ - From bfc564291dbafc1290c8bfe0fa7f77e488eebcb2 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 21 Jul 2023 19:29:21 +0200 Subject: [PATCH 04/96] doc main page --- biblio/bibliography.bib | 34 ++++++++++-- src/Zigzag_persistence/doc/COPYRIGHT | 12 ++++ .../doc/Intro_zigzag_persistence.h | 52 ++++++++++++++++++ src/Zigzag_persistence/doc/zigzag_ex.png | Bin 0 -> 2547 bytes .../include/gudhi/Zigzag_persistence.h | 2 + src/common/doc/examples.h | 3 + src/common/doc/main_page.md | 25 +++++++++ 7 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 src/Zigzag_persistence/doc/COPYRIGHT create mode 100644 src/Zigzag_persistence/doc/Intro_zigzag_persistence.h create mode 100644 src/Zigzag_persistence/doc/zigzag_ex.png diff --git a/biblio/bibliography.bib b/biblio/bibliography.bib index 03b46ff564..907391c607 100644 --- a/biblio/bibliography.bib +++ b/biblio/bibliography.bib @@ -38,10 +38,36 @@ @article{Carriere16 year = {2017} } -@inproceedings{zigzag_reflection, - author = {Jean-Daniel Boissonnat and Cl\'ement Maria and Steve Oudot}, - title = {Zigzag Persistent Homology Algorithm via Reflections}, - year = {2014 $\ \ \ \ \ \ \ \ \ \ \ $ \emph{In Preparation}}, +@inproceedings{zigzag, + author = {Cl{\'{e}}ment Maria and + Steve Y. Oudot}, + editor = {Piotr Indyk}, + title = {Zigzag Persistence via Reflections and Transpositions}, + booktitle = {Proceedings of the Twenty-Sixth Annual {ACM-SIAM} Symposium on Discrete + Algorithms, {SODA} 2015, San Diego, CA, USA, January 4-6, 2015}, + pages = {181--199}, + publisher = {{SIAM}}, + year = {2015}, + url = {https://doi.org/10.1137/1.9781611973730.14}, + doi = {10.1137/1.9781611973730.14} +} + +@inproceedings{zigzag_morse, + author = {Cl{\'{e}}ment Maria and + Hannah Schreiber}, + editor = {Zachary Friggstad and + J{\"{o}}rg{-}R{\"{u}}diger Sack and + Mohammad R. Salavatipour}, + title = {Discrete Morse Theory for Computing Zigzag Persistence}, + booktitle = {Algorithms and Data Structures - 16th International Symposium, {WADS} + 2019, Edmonton, AB, Canada, August 5-7, 2019, Proceedings}, + series = {Lecture Notes in Computer Science}, + volume = {11646}, + pages = {538--552}, + publisher = {Springer}, + year = {2019}, + url = {https://doi.org/10.1007/978-3-030-24766-9\_39}, + doi = {10.1007/978-3-030-24766-9\_39} } @article{Cohen-Steiner2009, diff --git a/src/Zigzag_persistence/doc/COPYRIGHT b/src/Zigzag_persistence/doc/COPYRIGHT new file mode 100644 index 0000000000..61f17f6da1 --- /dev/null +++ b/src/Zigzag_persistence/doc/COPYRIGHT @@ -0,0 +1,12 @@ +The files of this directory are part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. +See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + +Author(s): Vincent Rouvreau + +Copyright (C) 2015 Inria + +This gives everyone the freedoms to use openFrameworks in any context: +commercial or non-commercial, public or private, open or closed source. + +You should have received a copy of the MIT License along with this program. +If not, see https://opensource.org/licenses/MIT. \ No newline at end of file diff --git a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h new file mode 100644 index 0000000000..5fe392a659 --- /dev/null +++ b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h @@ -0,0 +1,52 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Hannah Schreiber + * + * Copyright (C) 2023 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +#ifndef DOC_ZIGZAG_PERSISTENCE_INTRO_ZIGZAG_PERSISTENCE_H_ +#define DOC_ZIGZAG_PERSISTENCE_INTRO_ZIGZAG_PERSISTENCE_H_ + +// needs namespace for Doxygen to link on classes +namespace Gudhi { +namespace zigzag_persistence { + +/** \defgroup zigzag_persistence Zigzag Persistence + * @{ + * \author Clément Maria, Hannah Schreiber + * + * We refer to the introduction page \ref persistent_cohomology for persistent (co)homology for an introduction + * to the topic. + * Zigzag persistence is a generalization of the latter. While standard persistence only allows to grow the filtered + * complex by adding simplices, zigzag persistence also allows removals. Hence the name "zigzag", as the module + * diagram will have arrows alterning between forward and backward. + * + * The implementation is based on the algorithm introduced in \cite zigzag. + * + * \subsection zigzaginterface Stream-like interface + * + * As removals are possible in zigzag filtration, the maximal size of the complex does not depend on the length of the + * filtration anymore. This makes it possible to build very long fine tuned filtrations with relatively small complexes + * which can be processed without overreaching memory space. For this purpose, it is possible to feed the module with + * information about the filtration "on the fly" to avoid loading the whole filtration at once. Information about the + * current complex and current barcode can be retrieved between any steps. + * + * \subsection zigzagexamples Examples + * + * Here is a list of zigzag persistence examples : + * \li \gudhi_example_link{Zigzag_persistence,example_simple_zigzag_filtration.cpp} - A simple example to showcase how + * to use the \ref Zigzag_persistence class. + * + * \li \gudhi_example_link{Zigzag_persistence,example_zzfiltration_from_file.cpp} - An example of a "stream-like" usage + * by reading of the filtration from a file. + * + * @} + */ +} // namespace zigzag_persistence +} // namespace Gudhi + +#endif // DOC_ZIGZAG_PERSISTENCE_INTRO_ZIGZAG_PERSISTENCE_H_ diff --git a/src/Zigzag_persistence/doc/zigzag_ex.png b/src/Zigzag_persistence/doc/zigzag_ex.png new file mode 100644 index 0000000000000000000000000000000000000000..a58cc6ed5470ec17ce16cbf34cb96a15a4972c9e GIT binary patch literal 2547 zcmZ{k2UJt(62~vH8pU-jh`6AD(w=025Dg$GQF<2wEK&pmL>6Kwf`n#*0-}q+Mu<}6 z&}%3vWK~*LT}2TLH4&sJ6s?$fsZ0R979$`iq&?N2#QO9ARchVO+nCQ1O&~ThaiJY z2$BuC*Wh>pY;5weu`q>%Nonm2U~LPrbPEHkrRXw$jW+@}uy89oGuR|dX7|r}zrfK% z;M(PjwT}SeY6z0_0k##mu50neC=j&O!^-rubL7D6(1TQEmwhkicP5xVlt|Qlw@XGM zM>fsDFDLr&rox$wcFh}c$$hj)5%J(%nu4s^^vZ(d(?_+Y?~a8 zsq_>o?&-`f;C=mc^igbT&Yv3x{qA?`xyA72AI&SWiY+GGr&EgE;kdRXcVc`?#AjOT zv4plH2T3jCQg=-AYI(15%ER5BhRc1va>f%T<=A?od9CxO6o^I|OXW1jZ#I^-&gW;> zy)QRfHRO3VVs!G`)-2tk9$V~ZT;Kj&qPw)qx|YcgUd(4}(dBF>){Co7^eWprK2Q7z z^|PnC5RxMYnwd+D5fy!~GxyguIO>E6tO7P$PU}b5t0bw3=;{f3T8DE4$(mGT>yn1I zDGBWGAQ3B`)O1jpF8B+TO;f9(nQe^*8D4o7zg1(Ooh>B&Rw3WlfT^(#Rw9OfGDG^1N}s)(dyBkm8rVbjs4E(IG#1-E zLZELuF+?wuoxw|T?_W7yJIH_E(@Y;2qy|!RYcNxP;s$~k%ggL#PE6K580XG8cpjl9 z24CLf(7c#5-`k4SxLb_Dlwz{#SJw*Q;bd0l3ciQFmoZ8v3hcVOMU#ym*QDAj{KOX)nub+DY2H^#b8>f>G1{28TE2Z^kP5YdlCczR zSH@JfJtwJF_BAHGldx-wGnYQsu1{n-TecZAU)#I9cB+aR47*;I@^|c_>%^$7c}qXzmV=@F^Hm^8ZD^MLy~?Y_s3 zzqV~&QTXn8{npentBYDIv`!%&NjDX=Y@rA<$>j@|q&jSgq4B+Yr^wQ!Xz$hq{}egJ_26gR$xo3$ z>02aH=Cct1E$pqc2L5C6@S>$@&09LLN}EtM`*t#WL=C-l=XpLunV~`DU~HOhM$8~r}AO5(wt2hw64Cmv9)Itbpn$t zBPut5OHsNgpnV|DY9B@mB78f@*D?hWB_yeXy2ANd$JSio_^n7@vdZip?Qp@EcTuXL z@a9K)u(!^FqEHTX5VV@za^=PAJdXM7?*cs^-lB{;xka817tf%I-^wtzix(YNMtcM3 zlrNg)3()SFBjR>H28}wID2_1%?QRvfdlWn zY{I;mpyl?s;^O4h$gxSv*TZD*@txm(BR8z3IoZ*R8Tekp zfdxV$kViEUdYVWbXB|BQ9esmi$KVKr0RmxBBklQ(fDr5#a3Sjd3v?H0AAsOr|H}{_ zK){8CV+kSOX^msmUvZbh0)m4e2UBxR9W9iTuKQE44OyAlo7NbgzxE&arSYo( literal 0 HcmV?d00001 diff --git a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h index 51fd7f1c54..a263aede5a 100644 --- a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h @@ -50,6 +50,8 @@ namespace zigzag_persistence { * \brief Class computating the zigzag persistent homology of a zigzag * filtration. Algorithm based on \cite zigzag_reflection. * + * \ingroup zigzag_persistence + * * \details The type ZigzagFilteredComplex::Simplex_key counts the number of * insertions and * deletions of simplices, which may be large in zigzag persistence and require diff --git a/src/common/doc/examples.h b/src/common/doc/examples.h index 1634b19e32..913d95b0f8 100644 --- a/src/common/doc/examples.h +++ b/src/common/doc/examples.h @@ -129,5 +129,8 @@ * @example example_one_skeleton_rips_from_distance_matrix.cpp * @example example_one_skeleton_rips_from_points.cpp * @example example_rips_complex_from_off_file.cpp + * \section Zigzag_persistence_example_section Zigzag_persistence + * @example example_simple_zigzag_filtration.cpp + * @example example_zzfiltration_from_file.cpp */ diff --git a/src/common/doc/main_page.md b/src/common/doc/main_page.md index cd173f6819..167c224aa0 100644 --- a/src/common/doc/main_page.md +++ b/src/common/doc/main_page.md @@ -383,6 +383,31 @@ +### Zigzag Persistent Homology + + + + + + + + + + +
+ \image html "zigzag_ex.png" + + Zigzag filtrations are a generalization of (standard) filtrations: the inclusion maps can not only go forward, + but also backward. In other words, simplices can also be removed from the complex which is build. + The implemented algorithm is from \cite zigzag. + + Author: Clément Maria, Hannah Schreiber
+ Introduced in: GUDHI 3.9.0
+ Copyright: MIT
+
+ User manual: \ref zigzag_persistence +
+ ## Topological descriptors tools {#TopologicalDescriptorsTools} ### Bottleneck distance From 688b3817e99052b9023bacae49db34ac6414b5cc Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 21 Jul 2023 19:55:36 +0200 Subject: [PATCH 05/96] restore cmake files --- CMakeLists.txt | 24 ++++++++++++------------ src/CMakeLists.txt | 2 +- src/cmake/modules/GUDHI_options.cmake | 1 - 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2113c71f42..4bb7e6cb03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,8 +16,8 @@ set(GUDHI_PYTHON_PATH "src/python") include(GUDHI_submodules) if (WITH_GUDHI_THIRD_PARTY) - # For third parties libraries management - To be done last as CGAL updates CMAKE_MODULE_PATH - include(GUDHI_third_party_libraries NO_POLICY_SCOPE) + # For third parties libraries management - To be done last as CGAL updates CMAKE_MODULE_PATH + include(GUDHI_third_party_libraries NO_POLICY_SCOPE) endif() include(GUDHI_compilation_flags) @@ -51,23 +51,23 @@ add_gudhi_module(Persistence_matrix) # Include module CMake subdirectories # GUDHI_SUB_DIRECTORIES is managed in CMAKE_MODULE_PATH/GUDHI_modules.cmake foreach(GUDHI_MODULE ${GUDHI_MODULES}) - foreach(GUDHI_SUB_DIRECTORY ${GUDHI_SUB_DIRECTORIES}) - if(EXISTS ${CMAKE_SOURCE_DIR}/src/${GUDHI_MODULE}/${GUDHI_SUB_DIRECTORY}/CMakeLists.txt) - add_subdirectory(src/${GUDHI_MODULE}/${GUDHI_SUB_DIRECTORY}/) - endif() - endforeach() + foreach(GUDHI_SUB_DIRECTORY ${GUDHI_SUB_DIRECTORIES}) + if(EXISTS ${CMAKE_SOURCE_DIR}/src/${GUDHI_MODULE}/${GUDHI_SUB_DIRECTORY}/CMakeLists.txt) + add_subdirectory(src/${GUDHI_MODULE}/${GUDHI_SUB_DIRECTORY}/) + endif() + endforeach() endforeach() if (WITH_GUDHI_UI) - add_subdirectory(src/GudhUI) + add_subdirectory(src/GudhUI) endif() if (WITH_GUDHI_PYTHON) - # specific for cython module - add_subdirectory(${GUDHI_PYTHON_PATH}) + # specific for cython module + add_subdirectory(${GUDHI_PYTHON_PATH}) else() - message("++ Python module will not be compiled because WITH_GUDHI_PYTHON is set to OFF") - set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python") + message("++ Python module will not be compiled because WITH_GUDHI_PYTHON is set to OFF") + set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python") endif() # For "make user_version" - Requires GUDHI_modules to be performed diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 608cdf663b..ba8f398bd9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -73,7 +73,7 @@ foreach(GUDHI_MODULE ${GUDHI_MODULES}) endforeach() endforeach() -if (WITH_GUDHI_UI) +if (WITH_GUDHI_THIRD_PARTY) add_subdirectory(GudhUI) endif() diff --git a/src/cmake/modules/GUDHI_options.cmake b/src/cmake/modules/GUDHI_options.cmake index 11a1f2e1f8..8379e3c63f 100644 --- a/src/cmake/modules/GUDHI_options.cmake +++ b/src/cmake/modules/GUDHI_options.cmake @@ -5,7 +5,6 @@ option(WITH_GUDHI_PYTHON "Activate/deactivate python module compilation and inst option(WITH_GUDHI_TEST "Activate/deactivate examples compilation and installation" ON) option(WITH_GUDHI_UTILITIES "Activate/deactivate utilities compilation and installation" ON) option(WITH_GUDHI_THIRD_PARTY "Activate/deactivate third party libraries cmake detection. When set to OFF, it is useful for doxygen or user_version i.e." ON) -option(WITH_GUDHI_UI "Activate/deactivate compilation of UI module." OFF) if (NOT WITH_GUDHI_THIRD_PARTY) set (WITH_GUDHI_BENCHMARK OFF) From f7087fc6a7748623dd5ce014141c57a8bad1bbde Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 21 Jul 2023 19:56:40 +0200 Subject: [PATCH 06/96] restore cmake files --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bb7e6cb03..c122ed66d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,7 @@ foreach(GUDHI_MODULE ${GUDHI_MODULES}) endforeach() endforeach() -if (WITH_GUDHI_UI) +if (WITH_GUDHI_THIRD_PARTY) add_subdirectory(src/GudhUI) endif() From 15fbc5302d9679758f20b7ab8829a0f30c1a82b3 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 21 Jul 2023 19:57:21 +0200 Subject: [PATCH 07/96] restore cmake files --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c122ed66d6..3021e9a14a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,7 +59,7 @@ foreach(GUDHI_MODULE ${GUDHI_MODULES}) endforeach() if (WITH_GUDHI_THIRD_PARTY) - add_subdirectory(src/GudhUI) + add_subdirectory(src/GudhUI) endif() if (WITH_GUDHI_PYTHON) From d8d07c5402f3b61c29db91416e843592733ea47b Mon Sep 17 00:00:00 2001 From: hschreiber Date: Mon, 21 Aug 2023 11:05:35 +0200 Subject: [PATCH 08/96] simplex tree options correction --- .../include/gudhi/column_types/cell.h | 6 +- .../include/gudhi/column_types/row_access.h | 2 +- src/Simplex_tree/include/gudhi/Simplex_tree.h | 62 +++++++++---------- ...igzagFilteredComplex.h => ZigzagComplex.h} | 11 ++-- .../example_simple_zigzag_filtration.cpp | 2 +- .../example_zzfiltration_from_file.cpp | 2 +- .../include/gudhi/Zigzag_persistence.h | 20 +++--- .../test/zigzag_persistence_unit_test.cpp | 2 +- 8 files changed, 49 insertions(+), 58 deletions(-) rename src/Zigzag_persistence/concept/{ZigzagFilteredComplex.h => ZigzagComplex.h} (92%) diff --git a/src/Persistence_matrix/include/gudhi/column_types/cell.h b/src/Persistence_matrix/include/gudhi/column_types/cell.h index 5f605eda6b..52c4ae468b 100644 --- a/src/Persistence_matrix/include/gudhi/column_types/cell.h +++ b/src/Persistence_matrix/include/gudhi/column_types/cell.h @@ -14,9 +14,7 @@ #include #include -//#include "../options.h" #include "../utilities/utilities.h" -//#include "../utilities/Zp_field.h" namespace Gudhi { namespace persistence_matrix { @@ -128,7 +126,7 @@ struct Z2_intrusive_row_cell : public Z2_row_cell, public base_hook_matrix_row return *this; }; - using base_hook_matrix_row = base_hook_matrix_row; //why ????? + // using base_hook_matrix_row = base_hook_matrix_row; //why ????? }; template @@ -228,7 +226,7 @@ struct Intrusive_row_cell : public Row_cell, public base_hoo return *this; }; - using base_hook_matrix_row = base_hook_matrix_row; //why ????? + // using base_hook_matrix_row = base_hook_matrix_row; //why ????? }; struct Z2_intrusive_list_cell : public Z2_base_cell, public base_hook_matrix_list_column diff --git a/src/Persistence_matrix/include/gudhi/column_types/row_access.h b/src/Persistence_matrix/include/gudhi/column_types/row_access.h index 80b9bfa7f2..8d6b645b1f 100644 --- a/src/Persistence_matrix/include/gudhi/column_types/row_access.h +++ b/src/Persistence_matrix/include/gudhi/column_types/row_access.h @@ -15,7 +15,7 @@ #include #include "../utilities/utilities.h" -//#include "cell.h" //why?? +#include "cell.h" namespace Gudhi { namespace persistence_matrix { diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h index d724c8f53d..0704b435ea 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h @@ -2458,38 +2458,6 @@ struct Simplex_tree_options_full_featured { static const bool link_nodes_by_label = false; }; -/** Model of SimplexTreeOptions, same as `Simplex_tree_options_full_featured` - * but the possibility of much bigger keys and in particular of negative keys. - * - * Maximum number of simplices to compute persistence is std::numeric_limits::max() - * (way enough simplices). */ -struct Simplex_tree_options_wide_indexation { - typedef linear_indexing_tag Indexing_tag; - typedef int Vertex_handle; - typedef double Filtration_value; - typedef std::int64_t Simplex_key; - static const bool store_key = true; - static const bool store_filtration = true; - static const bool contiguous_vertices = false; - static const bool link_nodes_by_label = false; -}; - -/** Model of SimplexTreeOptions, same as `Simplex_tree_options_full_featured` - * but with the possibility of negative keys. - * - * Maximum number of simplices to compute persistence is std::numeric_limits::max() - * (about 2 billions of simplices). */ -struct Simplex_tree_options_negative_indexation { - typedef linear_indexing_tag Indexing_tag; - typedef int Vertex_handle; - typedef double Filtration_value; - typedef std::int32_t Simplex_key; - static const bool store_key = true; - static const bool store_filtration = true; - static const bool contiguous_vertices = false; - static const bool link_nodes_by_label = false; -}; - /** Model of SimplexTreeOptions, faster than `Simplex_tree_options_full_featured` but note the unsafe * `contiguous_vertices` option. * @@ -2523,6 +2491,36 @@ struct Simplex_tree_options_fast_cofaces { static const bool link_nodes_by_label = true; }; +/** Model of SimplexTreeOptions, fitting the requirement of the @ref ZigzagComplex concept. + * + * Maximum number of arrows in the filtration is std::numeric_limits::max() + * (about 2 billions of arrows). */ +struct Simplex_tree_options_zigzag_persistence { + typedef linear_indexing_tag Indexing_tag; + typedef int Vertex_handle; + typedef double Filtration_value; + typedef std::int32_t Simplex_key; + static const bool store_key = true; + static const bool store_filtration = false; + static const bool contiguous_vertices = false; + static const bool link_nodes_by_label = false; +}; + +/** Model of SimplexTreeOptions, same as `Simplex_tree_options_zigzag_persistence` + * but with much bigger keys for particularly long filtrations. + * + * Maximum number of arrows is std::numeric_limits::max(). */ +struct Simplex_tree_options_zigzag_persistence_long { + typedef linear_indexing_tag Indexing_tag; + typedef int Vertex_handle; + typedef double Filtration_value; + typedef std::int64_t Simplex_key; + static const bool store_key = true; + static const bool store_filtration = false; + static const bool contiguous_vertices = false; + static const bool link_nodes_by_label = false; +}; + /** @}*/ // end addtogroup simplex_tree } // namespace Gudhi diff --git a/src/Zigzag_persistence/concept/ZigzagFilteredComplex.h b/src/Zigzag_persistence/concept/ZigzagComplex.h similarity index 92% rename from src/Zigzag_persistence/concept/ZigzagFilteredComplex.h rename to src/Zigzag_persistence/concept/ZigzagComplex.h index 7a6e416f1b..a8b03a209a 100644 --- a/src/Zigzag_persistence/concept/ZigzagFilteredComplex.h +++ b/src/Zigzag_persistence/concept/ZigzagComplex.h @@ -11,8 +11,8 @@ #ifndef CONCEPT_ZZ_COMPLEX_TYPE_H_ #define CONCEPT_ZZ_COMPLEX_TYPE_H_ -/** @file ZigzagFilteredComplex.h - * @brief Contains @ref Gudhi::zigzag_persistence::ZigzagFilteredComplex concept. +/** @file ZigzagComplex.h + * @brief Contains @ref Gudhi::zigzag_persistence::ZigzagComplex concept. */ namespace Gudhi { @@ -21,7 +21,7 @@ namespace zigzag_persistence { /** * @brief Data structure storing the simplices in the current complex. */ -class ZigzagFilteredComplex { +class ZigzagComplex { public: /** * @brief Signed integer type that needs to be long enough to store the numbers of arrows in the zigzag filtration. @@ -51,20 +51,19 @@ class ZigzagFilteredComplex { /** * @brief Constructor */ - ZigzagFilteredComplex(); + ZigzagComplex(); /** * @brief Inserts the given simplex in the complex. * * @tparam VertexRange Range over the vertices of a simplex. * @param simplex Simplex to insert represented by its vertices. - * @param filtration Filtration value at the insertion. * @return A pair of a simplex handle and a boolean. * The simplex handle represents the inserted simplex and * the boolean if simplex was already contained in the complex or not. */ template - std::pair insert_simplex(const VertexRange& simplex, Filtration_value filtration); + std::pair insert_simplex(const VertexRange& simplex); /** * @brief Removes the given simplex. Assumes that the simplex is maximal and can be safely removed. diff --git a/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp b/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp index 82e20bba63..0493952c1b 100644 --- a/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp +++ b/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp @@ -15,7 +15,7 @@ #include #include -using ST = Gudhi::Simplex_tree; +using ST = Gudhi::Simplex_tree; using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; using Vertex_handle = ST::Vertex_handle; using Filtration_value = ST::Filtration_value; diff --git a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp index 21bcfc1fde..3cdd5d4023 100644 --- a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp +++ b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp @@ -15,7 +15,7 @@ #include #include -using ST = Gudhi::Simplex_tree; +using ST = Gudhi::Simplex_tree; using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; using Vertex_handle = ST::Vertex_handle; using Filtration_value = ST::Filtration_value; diff --git a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h index a263aede5a..539331170f 100644 --- a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h @@ -52,24 +52,20 @@ namespace zigzag_persistence { * * \ingroup zigzag_persistence * - * \details The type ZigzagFilteredComplex::Simplex_key counts the number of - * insertions and - * deletions of simplices, which may be large in zigzag persistence and require + * \details The type ZigzagComplex::Simplex_key counts the number of + * insertions and deletions of simplices, which may be large in zigzag persistence and require * more than 32 bits of storage. The type used (int, long, etc) should be chosen in * consequence. Simplex_key must be signed. * - * Over all insertions, the Simplex_key must be positive and strictly increasing - * when forward iterating along the zigzag filtration. - * - * \tparam ZigzagFilteredComplex Complex storing the current simplices. + * \tparam ZigzagComplex Complex storing the current simplices. * \tparam ZigzagPersistenceOptions Options for the matrix used to compute the persistence. */ -template > class Zigzag_persistence { public: - using Complex = ZigzagFilteredComplex; /**< Complex type. */ + using Complex = ZigzagComplex; /**< Complex type. */ using Options = ZigzagPersistenceOptions; /**< Matrix options */ /*** Types defined in the complex ***/ using Simplex_key = typename Complex::Simplex_key; /**< Key type, must be signed. */ @@ -276,7 +272,7 @@ class Zigzag_persistence filtration_values_.emplace_back(num_arrow_, previous_filtration_value_); } - std::pair res = cpx_.insert_simplex(simplex, filtration_value); + std::pair res = cpx_.insert_simplex(simplex); GUDHI_CHECK(res.second, "Zigzag_persistence::insert_simplex - insertion of a simplex already in the complex"); cpx_.assign_key(res.first, num_arrow_); _process_forward_arrow(res.first); @@ -485,7 +481,7 @@ class Zigzag_persistence * * @return Const reference to the complex. */ -// const ZigzagFilteredComplex& get_complex() const{ +// const ZigzagComplex& get_complex() const{ // return cpx_; // } @@ -496,7 +492,7 @@ class Zigzag_persistence * * @return Reference to the complex. */ - ZigzagFilteredComplex& get_complex() const{ + ZigzagComplex& get_complex() const{ return cpx_; } diff --git a/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp b/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp index 050bcd93b7..d4443b043f 100644 --- a/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp +++ b/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp @@ -23,7 +23,7 @@ using namespace Gudhi; using namespace boost::unit_test; -using ST = Gudhi::Simplex_tree; +using ST = Gudhi::Simplex_tree; using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; using Vertex_handle = ST::Vertex_handle; using Filtration_value = ST::Filtration_value; From 394e33e444cfa7e7d10992e20921871edb9cefd8 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Mon, 21 Aug 2023 14:05:05 +0200 Subject: [PATCH 09/96] doc --- src/Simplex_tree/include/gudhi/Simplex_tree.h | 2 +- .../test/simplex_tree_edge_expansion_unit_test.cpp | 4 ++-- src/Zigzag_persistence/concept/ZigzagComplex.h | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h index 3176397199..4e8d291944 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h @@ -2497,7 +2497,7 @@ struct Simplex_tree_options_fast_cofaces { static const bool link_nodes_by_label = true; }; -/** Model of SimplexTreeOptions, fitting the requirement of the @ref ZigzagComplex concept. +/** Model of SimplexTreeOptions, fitting the requirement of the @ref Gudhi::zigzag_persistence::ZigzagComplex concept. * * Maximum number of arrows in the filtration is std::numeric_limits::max() * (about 2 billions of arrows). */ diff --git a/src/Simplex_tree/test/simplex_tree_edge_expansion_unit_test.cpp b/src/Simplex_tree/test/simplex_tree_edge_expansion_unit_test.cpp index 1b43930909..70fb6f6254 100644 --- a/src/Simplex_tree/test/simplex_tree_edge_expansion_unit_test.cpp +++ b/src/Simplex_tree/test/simplex_tree_edge_expansion_unit_test.cpp @@ -1,8 +1,8 @@ /* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. - * Author(s): Vincent Rouvreau + * Author(s): Hannah Schreiber * - * Copyright (C) 2014 Inria + * Copyright (C) 2023 Inria * * Modification(s): * - YYYY/MM Author: Description of the modification diff --git a/src/Zigzag_persistence/concept/ZigzagComplex.h b/src/Zigzag_persistence/concept/ZigzagComplex.h index a8b03a209a..6b0faa757b 100644 --- a/src/Zigzag_persistence/concept/ZigzagComplex.h +++ b/src/Zigzag_persistence/concept/ZigzagComplex.h @@ -19,7 +19,9 @@ namespace Gudhi { namespace zigzag_persistence { /** - * @brief Data structure storing the simplices in the current complex. + * @brief Data structure storing the simplices in the current complex. + * The concept is realized for example by @ref Gudhi::Simplex_tree < Gudhi::Simplex_tree_options_zigzag_persistence > + * or @ref Gudhi::Simplex_tree < Gudhi::Simplex_tree_options_zigzag_persistence_long >. */ class ZigzagComplex { public: From 2c79bc2bed36d79d2a35d6c4e543cdd2d8fde90f Mon Sep 17 00:00:00 2001 From: hschreiber Date: Mon, 21 Aug 2023 14:55:18 +0200 Subject: [PATCH 10/96] merge error fix --- src/Simplex_tree/include/gudhi/Simplex_tree.h | 101 ++++++++++++------ 1 file changed, 67 insertions(+), 34 deletions(-) diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h index c26ab24efe..128f117381 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h @@ -5,8 +5,10 @@ * Copyright (C) 2014 Inria * * Modification(s): - * - 2020/09 Clément Maria: option to link all simplex tree nodes with same label in an intrusive list. + * - 2020/09 Clément Maria: Option to link all simplex tree nodes with same label in an intrusive list + * - 2020/09 Clément Maria: Edge insertion method for flag complexes * - 2023/02 Vincent Rouvreau: Add de/serialize methods for pickle feature + * - 2023/05 Hannah Schreiber: Factorization of expansion methods * - YYYY/MM Author: Description of the modification */ @@ -534,32 +536,37 @@ class Simplex_tree { template friend class Simplex_tree; /** \brief Checks if two simplex trees are equal. */ - bool operator==(Simplex_tree& st2) { + template + bool operator==(Simplex_tree& st2) { if ((null_vertex_ != st2.null_vertex_) || (dimension_ != st2.dimension_ && !dimension_to_be_lowered_ && !st2.dimension_to_be_lowered_)) return false; - return rec_equal(&root_, &st2.root_); + return rec_equal(&root_, &st2.root_); } /** \brief Checks if two simplex trees are different. */ - bool operator!=(Simplex_tree& st2) { + template + bool operator!=(Simplex_tree& st2) { return (!(*this == st2)); } private: /** rec_equal: Checks recursively whether or not two simplex trees are equal, using depth first search. */ - bool rec_equal(Siblings* s1, Siblings* s2) { + template + bool rec_equal(Siblings* s1, typename Simplex_tree::Siblings* s2) { if (s1->members().size() != s2->members().size()) return false; - for (auto sh1 = s1->members().begin(), sh2 = s2->members().begin(); - (sh1 != s1->members().end() && sh2 != s2->members().end()); ++sh1, ++sh2) { + auto sh2 = s2->members().begin(); + for (auto sh1 = s1->members().begin(); + (sh1 != s1->members().end() && sh2 != s2->members().end()); + ++sh1, ++sh2) { if (sh1->first != sh2->first || sh1->second.filtration() != sh2->second.filtration()) return false; if (has_children(sh1) != has_children(sh2)) return false; // Recursivity on children only if both have children else if (has_children(sh1)) - if (!rec_equal(sh1->second.children(), sh2->second.children())) + if (!rec_equal(sh1->second.children(), sh2->second.children())) return false; } return true; @@ -1539,38 +1546,60 @@ class Simplex_tree { thread_local std::vector > inter; for (Dictionary_it s_h = siblings->members().begin(); - s_h != siblings->members().end(); ++s_h, ++next) { - Simplex_handle root_sh = find_vertex(s_h->first); - if (has_children(root_sh)) { - intersection( - inter, // output intersection - next, // begin - siblings->members().end(), // end - root_sh->second.children()->members().begin(), - root_sh->second.children()->members().end(), - s_h->second.filtration()); - if (inter.size() != 0) { - Siblings * new_sib = new Siblings(siblings, // oncles - s_h->first, // parent - inter); // boost::container::ordered_unique_range_t - for (auto it = new_sib->members().begin(); it != new_sib->members().end(); ++it) { - update_simplex_tree_after_node_insertion(it); - } + s_h != siblings->members().end(); ++s_h, ++next) + { + create_expansion(siblings, s_h, inter, next, s_h->second.filtration(), k); + } + } - inter.clear(); - s_h->second.assign_children(new_sib); - siblings_expansion(new_sib, k - 1); - } else { - // ensure the children property - s_h->second.assign_children(siblings); - inter.clear(); + /** \brief Recursive expansion of the simplex tree.*/ + template + void create_expansion(Siblings * siblings, + Dictionary_it& s_h, + std::vector >& inter, + Dictionary_it& next, + Filtration_value fil, + int k, + std::vector* added_simplices = nullptr) + { + Simplex_handle root_sh = find_vertex(s_h->first); + + if (!has_children(root_sh)) return; + + intersection( + inter, // output intersection + next, // begin + siblings->members().end(), // end + root_sh->second.children()->members().begin(), + root_sh->second.children()->members().end(), + fil); + if (inter.size() != 0) { + Siblings * new_sib = new Siblings(siblings, // oncles + s_h->first, // parent + inter); // boost::container::ordered_unique_range_t + for (auto it = new_sib->members().begin(); it != new_sib->members().end(); ++it) { + update_simplex_tree_after_node_insertion(it); + if constexpr (force_filtration_value){ + added_simplices->push_back(it); } } + inter.clear(); + s_h->second.assign_children(new_sib); + if constexpr (force_filtration_value){ + siblings_expansion(new_sib, fil, k - 1, *added_simplices); + } else { + siblings_expansion(new_sib, k - 1); + } + } else { + // ensure the children property + s_h->second.assign_children(siblings); + inter.clear(); } } /** \brief Intersects Dictionary 1 [begin1;end1) with Dictionary 2 [begin2,end2) * and assigns the maximal possible Filtration_value to the Nodes. */ + template static void intersection(std::vector >& intersection, Dictionary_it begin1, Dictionary_it end1, Dictionary_it begin2, Dictionary_it end2, @@ -1579,8 +1608,12 @@ class Simplex_tree { return; // ----->> while (true) { if (begin1->first == begin2->first) { - Filtration_value filt = (std::max)({begin1->second.filtration(), begin2->second.filtration(), filtration_}); - intersection.emplace_back(begin1->first, Node(nullptr, filt)); + if constexpr (force_filtration_value){ + intersection.emplace_back(begin1->first, Node(nullptr, filtration_)); + } else { + Filtration_value filt = (std::max)({begin1->second.filtration(), begin2->second.filtration(), filtration_}); + intersection.emplace_back(begin1->first, Node(nullptr, filt)); + } if (++begin1 == end1 || ++begin2 == end2) return; // ----->> } else if (begin1->first < begin2->first) { From f85ffb92bc1271c5a1727165ac2cef392994415d Mon Sep 17 00:00:00 2001 From: hschreiber Date: Mon, 21 Aug 2023 15:34:36 +0200 Subject: [PATCH 11/96] removal of useless simplex tree options --- src/Simplex_tree/include/gudhi/Simplex_tree.h | 18 ++---------------- src/Zigzag_persistence/concept/ZigzagComplex.h | 3 +-- .../example_simple_zigzag_filtration.cpp | 2 +- .../example/example_zzfiltration_from_file.cpp | 2 +- .../include/gudhi/Zigzag_persistence.h | 12 ++++++------ .../test/zigzag_persistence_unit_test.cpp | 2 +- 6 files changed, 12 insertions(+), 27 deletions(-) diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h index 128f117381..d5efcb4cb8 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h @@ -2476,7 +2476,8 @@ struct Simplex_tree_options_fast_cofaces { /** Model of SimplexTreeOptions, fitting the requirement of the @ref Gudhi::zigzag_persistence::ZigzagComplex concept. * * Maximum number of arrows in the filtration is std::numeric_limits::max() - * (about 2 billions of arrows). */ + * (about 2 billions of arrows). If more arrows are needed, just inherit from this structure and redefine + * the type `Simplex_key`, for example as `std::int64_t`.*/ struct Simplex_tree_options_zigzag_persistence { typedef linear_indexing_tag Indexing_tag; typedef int Vertex_handle; @@ -2488,21 +2489,6 @@ struct Simplex_tree_options_zigzag_persistence { static const bool link_nodes_by_label = false; }; -/** Model of SimplexTreeOptions, same as `Simplex_tree_options_zigzag_persistence` - * but with much bigger keys for particularly long filtrations. - * - * Maximum number of arrows is std::numeric_limits::max(). */ -struct Simplex_tree_options_zigzag_persistence_long { - typedef linear_indexing_tag Indexing_tag; - typedef int Vertex_handle; - typedef double Filtration_value; - typedef std::int64_t Simplex_key; - static const bool store_key = true; - static const bool store_filtration = false; - static const bool contiguous_vertices = false; - static const bool link_nodes_by_label = false; -}; - /** @}*/ // end addtogroup simplex_tree } // namespace Gudhi diff --git a/src/Zigzag_persistence/concept/ZigzagComplex.h b/src/Zigzag_persistence/concept/ZigzagComplex.h index 6b0faa757b..0a76441a4b 100644 --- a/src/Zigzag_persistence/concept/ZigzagComplex.h +++ b/src/Zigzag_persistence/concept/ZigzagComplex.h @@ -20,8 +20,7 @@ namespace zigzag_persistence { /** * @brief Data structure storing the simplices in the current complex. - * The concept is realized for example by @ref Gudhi::Simplex_tree < Gudhi::Simplex_tree_options_zigzag_persistence > - * or @ref Gudhi::Simplex_tree < Gudhi::Simplex_tree_options_zigzag_persistence_long >. + * The concept is realized for example by @ref Gudhi::Simplex_tree < Gudhi::Simplex_tree_options_zigzag_persistence >. */ class ZigzagComplex { public: diff --git a/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp b/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp index 0493952c1b..0b804b0547 100644 --- a/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp +++ b/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp @@ -15,7 +15,7 @@ #include #include -using ST = Gudhi::Simplex_tree; +using ST = Gudhi::Simplex_tree; using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; using Vertex_handle = ST::Vertex_handle; using Filtration_value = ST::Filtration_value; diff --git a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp index 3cdd5d4023..29d4f67d3b 100644 --- a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp +++ b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp @@ -15,7 +15,7 @@ #include #include -using ST = Gudhi::Simplex_tree; +using ST = Gudhi::Simplex_tree; using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; using Vertex_handle = ST::Vertex_handle; using Filtration_value = ST::Filtration_value; diff --git a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h index 539331170f..8c1e66d1ee 100644 --- a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h @@ -65,13 +65,13 @@ template ; +using ST = Gudhi::Simplex_tree; using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; using Vertex_handle = ST::Vertex_handle; using Filtration_value = ST::Filtration_value; From 0c7d3e6e2be4f36df8b01c807abfc26b7abecc8c Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 31 May 2024 15:18:07 +0200 Subject: [PATCH 12/96] generalized to faces instead of simplices --- .../example_simple_zigzag_filtration.cpp | 138 ++-- .../example_zzfiltration_from_file.cpp | 37 +- .../example/zigzag_filtration_example.txt | 57 +- .../include/gudhi/Zigzag_persistence.h | 676 ++++++++---------- .../test/zigzag_persistence_unit_test.cpp | 359 ++-------- 5 files changed, 453 insertions(+), 814 deletions(-) diff --git a/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp b/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp index c58276b7f3..a13b998906 100644 --- a/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp +++ b/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp @@ -12,34 +12,17 @@ #include #include -#include -struct Simplex_tree_options_zigzag_persistence : Gudhi::Simplex_tree_options_minimal { - static const bool store_key = true; -}; - -using ST = Gudhi::Simplex_tree; -using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; -using Vertex_handle = ST::Vertex_handle; -using Filtration_value = ST::Filtration_value; -using interval_filtration = ZP::filtration_value_interval; - -// void print_complex(ZP& zp) { -// std::clog << std::endl << "Current complex:" << std::endl; -// const auto& cpx = zp.get_complex(); -// for (const auto& sh : cpx.complex_simplex_range()) { -// for (auto v : cpx.simplex_vertex_range(sh)) { -// std::cout << v << " "; -// } -// std::cout << " - " << cpx.filtration(sh) << "" << std::endl; -// } -// } +using ZP = Gudhi::zigzag_persistence::Zigzag_persistence<>; +using face_handle = ZP::face_key; +using filtration_value = ZP::filtration_value; +using Interval_filtration = ZP::Filtration_value_interval; void print_barcode(ZP& zp) { std::clog << std::endl << "Current barcode:" << std::endl; for (auto& bar : zp.get_persistence_diagram(0, true)) { std::clog << std::floor(bar.birth()) << " - "; - if (bar.death() == std::numeric_limits::infinity()) { + if (bar.death() == std::numeric_limits::infinity()) { std::clog << "inf"; } else { std::clog << std::floor(bar.death()); @@ -57,39 +40,39 @@ void print_indices(ZP& zp) { } } -std::vector > get_simplices() { - return {{0}, - {1}, - {2}, +std::vector > get_boundaries() { + return {{}, + {}, + {}, {0, 1}, {0, 2}, - {3}, + {}, {1, 2}, - {4}, - {3, 4}, - {5}, - {0, 1, 2}, - {4, 5}, - {3, 5}, - {3, 4, 5}, - {0, 1, 2}, // remove - {3, 4, 5}, // remove - {1, 4}, - {0, 1, 2}, - {2, 4}, - {3, 4, 5}, - {0, 4}, - {0, 2, 4}, - {1, 2, 4}, - {0, 1, 4}, - {3, 4, 5}, // remove - {3, 4}, // remove - {3, 5}, // remove - {0, 1, 2, 4}, - {0, 1, 2, 4}}; // remove + {}, + {5, 7}, + {}, + {3, 4, 6}, + {7, 9}, + {5, 9}, + {8, 11, 12}, + {10}, // remove + {13}, // remove + {1, 7}, + {3, 4, 6}, + {2, 7}, + {8, 11, 12}, + {0, 7}, + {4, 18, 20}, + {6, 16, 18}, + {3, 16, 20}, + {19}, // remove + {8}, // remove + {12}, // remove + {17, 21, 22, 23}, + {27}}; // remove } -std::vector get_filtration_values() { +std::vector get_filtration_values() { return {0, 0, 0, 1, 1, 1, 2, 2, 2, @@ -116,65 +99,32 @@ std::vector get_batch_sizes() { return {14, 2, 8, 3, 1, 1}; } -void one_by_one() { +int main(int argc, char* const argv[]) { + std::clog << "********** Example **********" << std::endl; + ZP zp; - std::vector > simplices = get_simplices(); - std::vector fils = get_filtration_values(); + std::vector > simplices = get_boundaries(); + std::vector fils = get_filtration_values(); std::vector dirs = get_directions(); for (unsigned int i = 0; i < simplices.size(); ++i) { if (i > 0 && dirs[i] != dirs[i - 1]) { - // print_complex(zp); print_barcode(zp); print_indices(zp); } if (dirs[i]) { - zp.insert_simplex(simplices[i], fils[i]); + int dim = simplices[i].size() == 0 ? 0 : simplices[i].size() - 1; + zp.insert_face(i, simplices[i], dim, fils[i]); } else { - zp.remove_simplex(simplices[i], fils[i]); + auto id = simplices[i][0]; + int dim = simplices[id].size() == 0 ? 0 : simplices[id].size() - 1; + zp.remove_face(id, dim, fils[i]); } } - // print_complex(zp); + print_barcode(zp); print_indices(zp); -} - -void in_batches() { - ZP zp; - - std::vector > simplices = get_simplices(); - std::vector fils = get_filtration_values(); - std::vector sizes = get_batch_sizes(); - - unsigned int start; - unsigned int end = 0; - bool dir = true; //first operation has to be an insertion - for (auto s : sizes){ - start = end; - end += s; - if (dir){ - zp.insert_simplices_contiguously(simplices.begin() + start, - simplices.begin() + end, - fils.begin() + start); - } else { - zp.remove_simplices_contiguously(simplices.begin() + start, - simplices.begin() + end, - fils.begin() + start); - } - dir = !dir; - // print_complex(zp); - print_barcode(zp); - print_indices(zp); - } -} - -int main(int argc, char* const argv[]) { - std::clog << "********** Example one_by_one **********" << std::endl; - one_by_one(); - - std::clog << std::endl << "********** Example in_batches **********" << std::endl; - in_batches(); return 0; } diff --git a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp index ac5c1817c8..37ebf7185f 100644 --- a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp +++ b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp @@ -10,20 +10,15 @@ #include #include +#include #include #include -#include -struct Simplex_tree_options_zigzag_persistence : Gudhi::Simplex_tree_options_minimal { - static const bool store_key = true; -}; - -using ST = Gudhi::Simplex_tree; -using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; -using Vertex_handle = ST::Vertex_handle; -using Filtration_value = ST::Filtration_value; -using interval_filtration = ZP::filtration_value_interval; +using ZP = Gudhi::zigzag_persistence::Zigzag_persistence<>; +using id_handle = ZP::face_key; +using filtration_value = ZP::filtration_value; +using Interval_filtration = ZP::Filtration_value_interval; enum lineType : int { INCLUSION, REMOVAL, COMMENT }; @@ -31,7 +26,7 @@ void print_barcode(ZP& zp) { std::clog << std::endl << "Current barcode:" << std::endl; for (auto& bar : zp.get_persistence_diagram(0, true)) { std::clog << std::floor(bar.birth()) << " - "; - if (bar.death() == std::numeric_limits::infinity()) { + if (bar.death() == std::numeric_limits::infinity()) { std::clog << "inf"; } else { std::clog << std::floor(bar.death()); @@ -41,10 +36,10 @@ void print_barcode(ZP& zp) { std::clog << std::endl; } -lineType read_operation(std::string& line, std::vector& vertices, double& timestamp) { +lineType read_operation(std::string& line, std::vector& vertices, double& timestamp) { lineType type; vertices.clear(); - Vertex_handle num; + id_handle num; size_t current = line.find_first_not_of(' ', 0); if (current == std::string::npos) return COMMENT; @@ -98,18 +93,19 @@ int main(int argc, char* const argv[]) { ZP zp; if (file.is_open()) { - std::vector vertices; + std::vector data; + unsigned int id = 0; double timestamp; lineType type; - while (getline(file, line, '\n') && read_operation(line, vertices, timestamp) == COMMENT); + while (getline(file, line, '\n') && read_operation(line, data, timestamp) == COMMENT); double lastTimestamp = timestamp; // first operation has to be an insertion. - zp.insert_simplex(vertices, timestamp); + zp.insert_face(id, data, 0, timestamp); std::cout << line << std::endl; while (getline(file, line, '\n')) { - type = read_operation(line, vertices, timestamp); + type = read_operation(line, data, timestamp); if (type != COMMENT && lastTimestamp != timestamp) { print_barcode(zp); lastTimestamp = timestamp; @@ -117,9 +113,12 @@ int main(int argc, char* const argv[]) { if (type != COMMENT) std::cout << line << std::endl; if (type == INCLUSION) { - zp.insert_simplex(vertices, timestamp); + ++id; + int dim = data.size() == 0 ? 0 : data.size() - 1; + zp.insert_face(id, data, dim, timestamp); } else if (type == REMOVAL) { - zp.remove_simplex(vertices, timestamp); + ++id; + zp.remove_face(data[0], data[1], timestamp); } } print_barcode(zp); diff --git a/src/Zigzag_persistence/example/zigzag_filtration_example.txt b/src/Zigzag_persistence/example/zigzag_filtration_example.txt index db02d5b2d8..e0fd923d9a 100644 --- a/src/Zigzag_persistence/example/zigzag_filtration_example.txt +++ b/src/Zigzag_persistence/example/zigzag_filtration_example.txt @@ -2,45 +2,48 @@ # i: inclusion # r: removal # first value: filtration value -# remaining values: vertices of the simplex to include/remove in ascending order +# remaining values: if inclusion, boundary of the simplex to include in ascending order, +# a number corresponds to the id of the simplex in the boundary +# the ids start at 0 and corresponds to their "arrow number" +# If removal: id of the simplex to remove + dimension # #: comment line -i 0 0 -i 0 1 -i 0 2 +i 0 +i 0 +i 0 i 1 0 1 i 1 0 2 -i 1 3 +i 1 i 2 1 2 -i 2 4 -i 2 3 4 +i 2 +i 2 5 7 -i 3 5 -i 3 0 1 2 -i 3 4 5 -i 3 3 5 +i 3 +i 3 3 4 6 +i 3 7 9 +i 3 5 9 -i 4 3 4 5 +i 4 8 11 12 -r 5 0 1 2 +r 5 10 2 -r 6 3 4 5 -i 6 1 4 -i 6 0 1 2 +r 6 13 2 +i 6 1 7 +i 6 3 4 6 -i 7 2 4 -i 7 3 4 5 -i 7 0 4 -i 7 0 2 4 -i 7 1 2 4 -i 7 0 1 4 +i 7 2 7 +i 7 8 11 12 +i 7 0 7 +i 7 4 18 20 +i 7 6 16 18 +i 7 3 16 20 -r 8 3 4 5 +r 8 19 2 -r 9 3 4 -r 9 3 5 -i 9 0 1 2 4 +r 9 8 1 +r 9 12 1 +i 9 17 21 22 23 -r 10 0 1 2 4 \ No newline at end of file +r 10 27 3 \ No newline at end of file diff --git a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h index 00e2d0f0bf..b9a686e0a8 100644 --- a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h @@ -19,24 +19,13 @@ #ifndef ZIGZAG_PERSISTENCE_H_ #define ZIGZAG_PERSISTENCE_H_ -#include -#include -#include -#include -#include -#include - #include -#include #include -#include #include -#include #include -#include +#include #include #include -#include #include #include @@ -44,32 +33,56 @@ namespace Gudhi { namespace zigzag_persistence { +/** + * @brief Options for the internal matrix of @ref Zigzag_persistence. + * + * @tparam column_type Column type of the matrix. + */ +template +struct Zigzag_matrix_options : Gudhi::persistence_matrix::Default_options { + static const bool has_row_access = true; + static const bool has_column_pairings = false; + static const bool has_vine_update = true; + static const bool is_of_boundary_type = false; + static const bool has_map_column_container = true; + static const bool has_removable_columns = true; + static const bool has_removable_rows = true; +}; + +/** + * @brief Default options for @ref Zigzag_persistence. + */ +struct Default_zigzag_options { + using internal_key = int; /**< Face ID used internaly, must be signed. */ + using face_key = int; /**< Face ID used in the given boundaries. */ + using filtration_value = double; /**< Filtration value type. */ + using dimension_type = int; /**< Dimension value type. */ + /** + * @brief Column type use by the internal matrix. + */ + static const Gudhi::persistence_matrix::Column_types column_type = + Gudhi::persistence_matrix::Column_types::INTRUSIVE_LIST; +}; + +//TODO: add the possibility of something else than Z2. Which means that the possibility of vineyards without Z2 +//also needs to be implemented. The theory needs to be done first. /** \class Zigzag_persistence Zigzag_persistence.h gudhi/Zigzag_persistence.h * \brief Class computating the zigzag persistent homology of a zigzag * filtration. Algorithm based on \cite zigzag_reflection. * * \ingroup zigzag_persistence * - * \details The type ZigzagComplex::Simplex_key counts the number of - * insertions and deletions of simplices, which may be large in zigzag persistence and require - * more than 32 bits of storage. The type used (int, long, etc) should be chosen in - * consequence. Simplex_key must be signed. - * - * \tparam ZigzagComplex Complex storing the current simplices. - * \tparam ZigzagPersistenceOptions Options for the matrix used to compute the persistence. + * \tparam ZigzagOptions TODO: concept */ -template > -class Zigzag_persistence -{ +template +class Zigzag_persistence { public: - using Complex = ZigzagComplex; /**< Complex type. */ - using Options = ZigzagPersistenceOptions; /**< Matrix options */ - /*** Types defined in the complex ***/ - using Simplex_key = typename Complex::Simplex_key; /**< Key type, must be signed. */ - using Simplex_handle = typename Complex::Simplex_handle; /**< Simplex ID type in the complex. */ - using Vertex_handle = typename Complex::Vertex_handle; /**< Vertex ID type in the complex. */ - using Filtration_value = typename Complex::Filtration_value; /**< Filtration value type. */ + using Options = ZigzagOptions; + using Matrix_options = Zigzag_matrix_options; /**< Matrix options */ + using internal_key = typename Options::internal_key; + using face_key = typename Options::face_key; + using filtration_value = typename Options::filtration_value; + using dimension_type = typename Options::dimension_type; /** \brief Structure to store persistence intervals by their index values. * @@ -77,24 +90,23 @@ class Zigzag_persistence * closed for finite indices b and d, and open for left-infinite and/or * right-infinite endpoints. */ - template - struct interval { - interval() {} - interval(int dim, value_type b, value_type d) : dim_(dim), b_(b), d_(d) {} - /** Returns the dimension of the homological feature corresponding to the - * interval. */ - int dim() const { return dim_; } // return the homological dimension of the interval + template + struct Interval { + Interval() {} + Interval(int dim, value_type b, value_type d) : dim_(dim), b_(b), d_(d) {} + /** Returns the dimension of the homological feature corresponding to the interval. */ + int dim() const { return dim_; } /** Returns the birth index of the interval.*/ - value_type birth() const { return b_; } // return the birth value + value_type birth() const { return b_; } /** Returns the death index of the interval.*/ - value_type death() const { return d_; } // return the death value + value_type death() const { return d_; } - protected: // note that we don't assume b_ <= d_ - int dim_; // homological dimension + protected: + int dim_; // homological dimension value_type b_; // filtration value associated to birth index value_type d_; // filtration value associated to death index }; - using index_interval = interval; + using Index_interval = Interval; /** \brief Structure to store persistence intervals by their filtration values. * @@ -102,16 +114,15 @@ class Zigzag_persistence * closed for finite indices b and d, and open for left-infinite and/or * right-infinite endpoints. */ - struct filtration_value_interval : interval - { + struct Filtration_value_interval : Interval { private: - using Base = interval; + using Base = Interval; public: /** * @brief Default constructor */ - filtration_value_interval() : Base() {} + Filtration_value_interval() : Base() {} /** * @brief Construct a new interval with given parameters * @@ -119,13 +130,12 @@ class Zigzag_persistence * @param b Start value of the interval. * @param d End value of the interval. */ - filtration_value_interval(int dim, Filtration_value b, Filtration_value d) - : Base(dim, b, d) {} + Filtration_value_interval(int dim, filtration_value b, filtration_value d) : Base(dim, b, d) {} /** * @brief Returns the absolute length of the interval \f$|d-b|\f$. */ - Filtration_value length() const { + filtration_value length() const { if (Base::b_ == Base::d_) { return 0; } // otherwise inf - inf would return nan. @@ -134,7 +144,7 @@ class Zigzag_persistence /** * @brief Returns the absolute length of the log values of birth and death, i.e. \f$|\log d - \log b|\f$. */ - Filtration_value log_length() const { + filtration_value log_length() const { if (Base::b_ == Base::d_) { return 0; } // otherwise inf - inf would return nan. @@ -150,10 +160,10 @@ class Zigzag_persistence * zigzag persistence. * * By construction, we maintain the map satisfying - * 'birth_to_pos_[i] < birth_to_pos_[j]', with \f$0 <= i,j <= k\f$ indices in the quiver - * '\f$0 \leftrightarrow ... \leftrightarrow i \leftrightarrow ... \leftrightarrow k\f$' visited at time - * \f$k\f$ of the algorithm (prefix of length \f$k\f$ of the full zigzag filtration - * '\f$0 \leftrightarrow ... \leftrightarrow i \leftrightarrow ... + * 'birthToPos_[i] < birthToPos_[j]', with \f$0 <= i,j <= k\f$ indices in the quiver + * '\f$0 \leftrightarrow ... \leftrightarrow i \leftrightarrow ... \leftrightarrow k\f$' visited at time + * \f$k\f$ of the algorithm (prefix of length \f$k\f$ of the full zigzag filtration + * '\f$0 \leftrightarrow ... \leftrightarrow i \leftrightarrow ... * \leftrightarrow k \leftrightarrow ... \leftrightarrow n\f$' * that is studied), iff \f$i <_b j\f$ for the birth ordering. * @@ -162,11 +172,11 @@ class Zigzag_persistence * - if \f$k \rightarrow k+1\f$ forward, then \f$j <_b k+1\f$ for all indices \f$j < k+1\f$, otherwise * - if \f$k \leftarrow k+1\f$ backward, then \f$k+1 <_b j\f$ for all indices \f$j < k+1\f$. */ - struct birth_ordering { + struct Birth_ordering { /** * @brief Default constructor */ - birth_ordering() : birth_to_pos_(), max_birth_pos_(0), min_birth_pos_(-1) {} + Birth_ordering() : birthToPos_(), maxBirthPos_(0), minBirthPos_(-1) {} /** * @brief Inserts arrow number in the ordering after an insertion. @@ -175,9 +185,9 @@ class Zigzag_persistence * * @param arrow_number Forward arrow number. */ - void add_birth_forward(Simplex_key arrow_number) { // amortized constant time - birth_to_pos_.emplace_hint(birth_to_pos_.end(), arrow_number, max_birth_pos_); - ++max_birth_pos_; + void add_birth_forward(internal_key arrow_number) { // amortized constant time + birthToPos_.emplace_hint(birthToPos_.end(), arrow_number, maxBirthPos_); + ++maxBirthPos_; } /** * @brief Inserts arrow number in the ordering after a removal. @@ -186,19 +196,19 @@ class Zigzag_persistence * * @param arrow_number Backward arrow number. */ - void add_birth_backward(Simplex_key arrow_number) { // amortized constant time - birth_to_pos_.emplace_hint(birth_to_pos_.end(), arrow_number, min_birth_pos_); - --min_birth_pos_; + void add_birth_backward(internal_key arrow_number) { // amortized constant time + birthToPos_.emplace_hint(birthToPos_.end(), arrow_number, minBirthPos_); + --minBirthPos_; } /** * @brief Removes the birth from the ordering. - * When the row at index @a birth is removed from the homology matrix, we do not need + * When the row at index @p birth is removed from the homology matrix, we do not need * to maintain its position in b k2. * @@ -214,248 +224,173 @@ class Zigzag_persistence * @param k2 * @return true if k1 >b k2, false otherwise. */ - bool reverse_birth_order(Simplex_key k1, Simplex_key k2) const { return birth_to_pos_.at(k1) > birth_to_pos_.at(k2); } + bool reverse_birth_order(internal_key k1, internal_key k2) const { + return birthToPos_.at(k1) > birthToPos_.at(k2); + } private: - std::unordered_map birth_to_pos_; /**< birth_to_pos_[i] < birth_to_pos_[j] iff i birthToPos_; /**< birth_to_pos_[i] < birth_to_pos_[j] iff i ; - using index = typename matrix_type::index; + using Matrix_type = Gudhi::persistence_matrix::Matrix; + using index = typename Matrix_type::index; public: /** * @brief Constructor of the Zigzag_persistence class. - * @details After construction of the class, the zigzag filtration should be given in a streaming like way, i.e., - * call @ref insert_simplex or @ref remove_simplex for each step of the filtration in order of the filtration. - * If simplices are added (resp. removed) continuously, they can be inserted (resp. removed) in batches by using - * @ref insert_simplices_contiguously (resp. @ref remove_simplices_contiguously). - * To retrieve the current persistence diagram at any moment of the filtration, + * @details After construction of the class, the zigzag filtration should be given in a streaming like way, i.e., + * call @ref insert_face or @ref remove_face for each step of the filtration in order of the filtration. + * To retrieve the current persistence diagram at any moment of the filtration, * use @ref get_persistence_diagram or @ref get_index_persistence_diagram. * - * @param min_number_of_simplices Minimum number of simplices that will be inserted at some point in the filtration. - * If the total number of simplices is known in advance, the memory allocation can be better optimized. + * @param min_number_of_faces Minimum number of faces that will be inserted at some point in the filtration. + * If the total number of faces is known in advance, the memory allocation can be better optimized. * Default value: 0. - * @param ignore_cycles_above_dim Ignores cycles in dimension larger or equal in the final diagram. + * @param ignore_cycles_above_dim Ignores cycles in dimension larger or equal in the final diagram. * If -1, no cycles are ignored. Default value: -1. */ - Zigzag_persistence(unsigned int min_number_of_simplices = 0, int ignore_cycles_above_dim = -1) - : dim_max_(ignore_cycles_above_dim), - matrix_(min_number_of_simplices, - [this](index columnIndex1, index columnIndex2)->bool { - if (matrix_.get_column(columnIndex1).is_paired()){ - return matrix_.get_pivot(columnIndex1) < matrix_.get_pivot(columnIndex2); - } - return birth_ordering_.birth_order(births_.at(columnIndex1), births_.at(columnIndex2)); - }, - [this](index columnIndex1, index columnIndex2)->bool { - return false; - }), - num_arrow_(-1), - previous_filtration_value_(std::numeric_limits::infinity()) {} + Zigzag_persistence(unsigned int minNumberOfFaces = 0, int ignoreCyclesAboveDim = -1) + : dimMax_(ignoreCyclesAboveDim), + matrix_( + minNumberOfFaces, + [this](index columnIndex1, index columnIndex2) -> bool { + if (matrix_.get_column(columnIndex1).is_paired()) { + return matrix_.get_pivot(columnIndex1) < matrix_.get_pivot(columnIndex2); + } + return birthOrdering_.birth_order(births_.at(columnIndex1), births_.at(columnIndex2)); + }, + [this](index columnIndex1, index columnIndex2) -> bool { return false; }), + numArrow_(-1), + previousFiltrationValue_(std::numeric_limits::infinity()) {} /** - * @brief Updates the zigzag persistence diagram after the insertion of the given simplex. - * - * @tparam VertexRange Range type needing begin and end members. - * @param simplex Simplex to insert, represented by its vertices. - * @param filtration_value Filtration value associated to the simplex. + * @brief Updates the zigzag persistence diagram after the insertion of the given face. + * + * @tparam BoundaryRange Range type needing begin and end members. + * @param faceID ID representing the inserted face. + * @param boundary Boundary of the inserted face. The range should be composed of the IDs of all faces contained in + * the boundary (i.e. with non-zero coefficients), using the ID specified as `faceID` when the corresponding face + * was previously inserted (recall that the faces should be inserted in order of filtration). + * @param dimension Dimension of the inserted face. + * @param filtrationValue Filtration value associated to the face. * Assumed to be larger or equal to previously used filtration values. */ - template > - void insert_simplex(const VertexRange& simplex, Filtration_value filtration_value) { - if (dim_max_ != -1 && simplex.size() > static_cast(dim_max_) + 1) return; - - ++num_arrow_; - - if (filtration_value != previous_filtration_value_) // check whether the filt value has changed - { // consecutive pairs (i,f), (j,f') mean simplices of index k in [i,j-1] have - previous_filtration_value_ = filtration_value; // filtration value f - filtration_values_.emplace_back(num_arrow_, previous_filtration_value_); + template > + void insert_face(face_key faceID, + const BoundaryRange& boundary, + dimension_type dimension, + filtration_value filtrationValue) { + if (dimMax_ != -1 && dimension > dimMax_) return; + + ++numArrow_; + + //TODO: to make it really stream like, we should stream out finished bars and remove unnecessary filtration values + //from memory. + if (filtrationValue != previousFiltrationValue_) // check whether the filt value has changed + { // consecutive pairs (i,f), (j,f') mean faces of index k in [i,j-1] have + previousFiltrationValue_ = filtrationValue; // filtration value f + filtrationValues_.emplace_back(numArrow_, previousFiltrationValue_); } - std::pair res = cpx_.insert_simplex(simplex); - GUDHI_CHECK(res.second, "Zigzag_persistence::insert_simplex - insertion of a simplex already in the complex"); - cpx_.assign_key(res.first, num_arrow_); - _process_forward_arrow(res.first); - } + [[maybe_unused]] auto res = handleToKey_.try_emplace(faceID, numArrow_); - /** - * @brief Updates the zigzag persistence diagram after the removal of the given simplex. - * - * @tparam VertexRange Range type needing begin and end members. - * @param simplex Simplex to remove, represented by its vertices. - * @param filtration_value Filtration value associated to the removal. - * Assumed to be larger or equal to previously used filtration values. - */ - template > - void remove_simplex(const VertexRange& simplex, Filtration_value filtration_value) { - if (dim_max_ != -1 && simplex.size() > static_cast(dim_max_) + 1) return; - - ++num_arrow_; + GUDHI_CHECK(res.second, "Zigzag_persistence::insert_face - face already in the complex"); - Simplex_handle sh = cpx_.find(simplex); - GUDHI_CHECK(sh != cpx_.null_simplex(), - "Zigzag_persistence::remove_simplex - removal of a simplex not in the complex"); - - if (filtration_value != previous_filtration_value_) // check whether the filt value has changed - { // consecutive pairs (i,f), (j,f') mean simplices of index k in [i,j-1] have - previous_filtration_value_ = filtration_value; // filtration value f - filtration_values_.emplace_back(num_arrow_, previous_filtration_value_); + // Reduce the boundary of zzsh in the basis of cycles. + // Compute the keys of the faces of the boundary of zzsh. + std::set col_bsh; // set maintains the natural order on indices + for (auto b_sh : boundary) { + col_bsh.insert(handleToKey_.at(b_sh)); // TODO: add possibilities of coefficients } - _process_backward_arrow(sh); - cpx_.remove_maximal_simplex(sh); + _process_forward_arrow(col_bsh, dimension); } /** - * @brief Updates the zigzag persistence diagram after the insertion of the given simplices. - * - * @tparam SimplexRange Range type needing begin and end members. - * @tparam FiltrationRange Range type needing begin and end members. - * @param simplices Simplices which are inserted, represented by their vertices. They have to be in the order they - * are inserted in the filtration and ``contiguous'' in the filtration, that is, no other simplex - * which is not in the range is inserted or removed between two simplices in the range. - * @param filtration_values Filtration values associated to the insertion of the given simplices. - * The order has to correspond to the order in @a simplices. Their values have to ascending in this order and - * they are assumed to be larger or equal to previously used filtration values. + * @brief Updates the zigzag persistence diagram after the removal of the given face. + * + * @param faceID ID representing the face to remove. Should be the same than the one used to insert it. + * @param dimension Dimension of the face. + * @param filtrationValue Filtration value associated to the removal. + * Assumed to be larger or equal to previously used filtration values. */ - template >, - class FiltrationRange = std::initializer_list> - void insert_simplices_contiguously(const SimplexRange& simplices, const FiltrationRange& filtration_values) { - auto simplexIt = simplices.begin(); - auto filIt = filtration_values.begin(); - for (; simplexIt != simplices.end(); ++simplexIt, ++filIt) { - insert_simplex(*simplexIt, *filIt); - } - } + void remove_face(face_key faceID, dimension_type dimension, filtration_value filtrationValue) { + if (dimMax_ != -1 && dimension > dimMax_) return; - /** - * @brief Updates the zigzag persistence diagram after the removal of the given simplices. - * - * @tparam SimplexRange Range type needing begin and end members. - * @tparam FiltrationRange Range type needing begin and end members. - * @param simplices Simplices which are removed, represented by their vertices. They have to be in the order they - * are removed in the filtration and ``contiguous'' in the filtration, that is, no other simplex - * which is not in the range is inserted or removed between two simplices in the range. - * @param filtration_values Filtration values associated to the removal of the given simplices. Has therefore the - * same size as @a simplices. The order has to correspond to the order in @a simplices. Their values have to - * ascending in this order and they are assumed to be larger or equal to previously used filtration values. - */ - template >, - class FiltrationRange = std::initializer_list> - void remove_simplices_contiguously(const SimplexRange& simplices, const FiltrationRange& filtration_values) { - auto simplexIt = simplices.begin(); - auto filIt = filtration_values.begin(); - for (; simplexIt != simplices.end(); ++simplexIt, ++filIt) { - remove_simplex(*simplexIt, *filIt); - } - } + ++numArrow_; - /** - * @brief Updates the zigzag persistence diagram after the insertion of the given simplices. - * - * @tparam SimplexRangeIterators Forward iterator of a range. - * @tparam FiltrationRangeIterators Forward iterator of a range. - * @param simplex_range_start Iterator pointing to the begining of the range of simplices to insert. - * The simplices should be represented by their vertices. They have to be in the order they - * are inserted in the filtration and ``contiguous'' in the filtration, that is, no other simplex - * which is not in the range is inserted or removed between two simplices in the range. - * @param simplex_range_end Iterator pointing to the end of the range of simplices to insert. - * @param filtration_range_start Iterator pointing to the begining of the range of filtration values. The range is - * assumed to end at the same time than the simplices range and has the same order. The filtration values should be - * ascending in this order and they are assumed to be larger or equal to previously used filtration values. - */ - template - void insert_simplices_contiguously(SimplexRangeIterators simplex_range_start, SimplexRangeIterators simplex_range_end, - FiltrationRangeIterators filtration_range_start) { - for (; simplex_range_start != simplex_range_end; ++simplex_range_start, ++filtration_range_start) { - insert_simplex(*simplex_range_start, *filtration_range_start); - } - } + auto it = handleToKey_.find(faceID); + GUDHI_CHECK(it != handleToKey_.end(), "Zigzag_persistence::remove_face - face not in the complex"); - /** - * @brief Updates the zigzag persistence diagram after the removal of the given simplices. - * - * @tparam SimplexRangeIterators Forward iterator of a range. - * @tparam FiltrationRangeIterators Forward iterator of a range. - * @param simplex_range_start Iterator pointing to the begining of the range of simplices to remove. - * The simplices should be represented by their vertices. They have to be in the order they - * are removed in the filtration and ``contiguous'' in the filtration, that is, no other simplex - * which is not in the range is inserted or removed between two simplices in the range. - * @param simplex_range_end Iterator pointing to the end of the range of simplices to remove. - * @param filtration_range_start Iterator pointing to the begining of the range of filtration values. The range is - * assumed to end at the same time than the simplices range and has the same order. The filtration values should be - * ascending in this order and they are assumed to be larger or equal to previously used filtration values. - */ - template - void remove_simplices_contiguously(SimplexRangeIterators simplex_range_start, SimplexRangeIterators simplex_range_end, - FiltrationRangeIterators filtration_range_start) { - for (; simplex_range_start != simplex_range_end; ++simplex_range_start, ++filtration_range_start) { - remove_simplex(*simplex_range_start, *filtration_range_start); + if (filtrationValue != previousFiltrationValue_) // check whether the filt value has changed + { // consecutive pairs (i,f), (j,f') mean faces of index k in [i,j-1] have + previousFiltrationValue_ = filtrationValue; // filtration value f + filtrationValues_.emplace_back(numArrow_, previousFiltrationValue_); } + + _process_backward_arrow(it->second, dimension); + handleToKey_.erase(it); } /** - * @brief Returns the ``index persistence diagram'' of the current filtration, that is, the pairs of atomic arrow - * numbers corresponding to a birth-death pair. Does not contain points at infinity, only the cycle classes which + * @brief Returns the ``index persistence diagram'' of the current filtration, that is, the pairs of atomic arrow + * numbers corresponding to a birth-death pair. Does not contain points at infinity, only the cycle classes which * already died are represented. * * @return Reference to the list of intervals. */ - const std::list& get_index_persistence_diagram() const { return persistence_diagram_; } + const std::list& get_index_persistence_diagram() const { return persistenceDiagram_; } /** * @brief Returns the filtration values \f$[f(b),f(d)]\f$ associated to the indices \f$[b,d]\f$ which are retrieved * by @ref get_index_persistence_diagram. * - * @param b_key Birth index - * @param d_key Death index + * @param birthKey Birth index + * @param deathKey Death index * @return A pair of filtration values associated to the given indices. */ - std::pair map_index_to_filtration_value( - Simplex_key b_key, Simplex_key d_key) const - { + std::pair map_index_to_filtration_value(internal_key birthKey, + internal_key deathKey) const { // filtration_values_ must be sorted by increasing keys. - auto it_b = // lower_bound(x) returns leftmost y s.t. x <= y + auto itBirth = // lower_bound(x) returns leftmost y s.t. x <= y std::lower_bound( - filtration_values_.begin(), filtration_values_.end(), - std::pair(b_key, std::numeric_limits::infinity()), - [](std::pair p1, std::pair p2) { + filtrationValues_.begin(), filtrationValues_.end(), + std::pair(birthKey, std::numeric_limits::infinity()), + [](std::pair p1, std::pair p2) { return p1.first < p2.first; }); - if (it_b == filtration_values_.end() || it_b->first > b_key) { - --it_b; + if (itBirth == filtrationValues_.end() || itBirth->first > birthKey) { + --itBirth; } // it points to the rightmost z such that z <= x - auto it_d = // + auto itDeath = // std::lower_bound( - filtration_values_.begin(), filtration_values_.end(), - std::pair(d_key, std::numeric_limits::infinity()), - [](std::pair p1, std::pair p2) { + filtrationValues_.begin(), filtrationValues_.end(), + std::pair(deathKey, std::numeric_limits::infinity()), + [](std::pair p1, std::pair p2) { return p1.first < p2.first; }); - if (it_d == filtration_values_.end() || it_d->first > d_key) { - --it_d; + if (itDeath == filtrationValues_.end() || itDeath->first > deathKey) { + --itDeath; } - return std::make_pair(it_b->second, it_d->second); + return std::make_pair(itBirth->second, itDeath->second); } /** - * @brief Returns the current persistence diagram ordered first by length, than by dimension, + * @brief Returns the current persistence diagram ordered first by length, than by dimension, * than by birth value and finally by death value. - * - * @param shortest_interval Threshold. Every bar shorter than the given value will be ignored. Default value: 0. - * @param include_infinit_bars If set to true, infinit bars are included in the diagram. Default value: false. + * + * @param shortestInterval Threshold. Every bar shorter than the given value will be ignored. Default value: 0. + * @param includeInfinitBars If set to true, infinit bars are included in the diagram. Default value: false. * @return A vector of pairs of filtration values representing the persistence diagram. */ - std::vector get_persistence_diagram(Filtration_value shortest_interval = 0., - bool include_infinit_bars = false) { - auto comp = [](filtration_value_interval p, filtration_value_interval q) { + std::vector get_persistence_diagram(filtration_value shortestInterval = 0., + bool includeInfinitBars = false) { + auto comp = [](Filtration_value_interval p, Filtration_value_interval q) { if (p.length() != q.length()) { return p.length() > q.length(); } // longest 1st @@ -468,9 +403,9 @@ class Zigzag_persistence return p.death() < q.death(); }; - std::vector diag = _get_persistence_diagram(shortest_interval); + std::vector diag = _get_persistence_diagram(shortestInterval); - if (include_infinit_bars) { + if (includeInfinitBars) { _retrieve_infinit_bars(diag); } @@ -479,113 +414,74 @@ class Zigzag_persistence return diag; } - /** - * @brief Returns a reference to the complex storing the simplices. - * A simplex is added in a call of @ref insert_simplex and is removed in a call of @ref remove_simplex. - * - * @return Const reference to the complex. - */ -// const ZigzagComplex& get_complex() const{ -// return cpx_; -// } - - /** - * @brief Returns a reference to the complex storing the simplices. - * A simplex is added in a call of @ref insert_simplex and is removed in a call of @ref remove_simplex. - * @warning The complex is not const for now for technical reasons, but DO NOT modify it. - * - * @return Reference to the complex. - */ - ZigzagComplex& get_complex() const{ - return cpx_; - } - - /** - * @brief For debug purposes, to remove. - */ - void print_current_complex() const { - for (auto& sh : cpx_.complex_simplex_range()) { - for (auto v : cpx_.simplex_vertex_range(sh)) { - std::cout << v << " "; - } - std::cout << " - " << cpx_.filtration(sh) << "\n"; - } - } - private: + /** - * @brief Computes the boundary cycle of the new simplex zzsh, and express it as a - * sum of cycles in a matrix. If some cycles are not boundary cycles, i.e., columns with F-index + * @brief Express the boundary cycle of the new face as a sum of cycles in a matrix. + * If some cycles are not boundary cycles, i.e., columns with F-index * in the matrix, it applies a surjective diamond to the zigzag module. - * - * @param zzsh Simplex handle of the inserted simplex. + * + * @param boundary Boundary of the inserted face. + * @param dim Dimension of the inserted face. */ - void _process_forward_arrow(Simplex_handle zzsh) { // maintain the <=b order - // Reduce the boundary of zzsh in the basis of cycles. - // Compute the simplex keys of the simplices of the boundary of zzsh. - std::set col_bsh; // set maintains the natural order on indices - for (auto b_sh : cpx_.boundary_simplex_range(zzsh)) { - col_bsh.insert(cpx_.key(b_sh)); - } - - std::vector chains_in_F = matrix_.insert_boundary(num_arrow_, col_bsh); + void _process_forward_arrow(const std::set& boundary, dimension_type dim) { + std::vector chainsInF = matrix_.insert_boundary(numArrow_, boundary); - if (!chains_in_F.empty()) { - _apply_surjective_reflection_diamond(zzsh, chains_in_F); + if (!chainsInF.empty()) { + _apply_surjective_reflection_diamond(dim, chainsInF); } else { - birth_ordering_.add_birth_forward(num_arrow_); - births_.emplace_hint(births_.end(), matrix_.get_column_with_pivot(num_arrow_), num_arrow_); + birthOrdering_.add_birth_forward(numArrow_); + births_.emplace_hint(births_.end(), matrix_.get_column_with_pivot(numArrow_), numArrow_); } } /** * @brief Applies the surjective reflection diamond principle to the current filtration. - * - * @details The vector chains_in_F is sorted by decreasing lowest index values in the + * + * @details The vector chainsInF is sorted by decreasing lowest index values in the * columns corresponding to the chains, due to its computation in the reduction of - * \partial zzsh in _process_forward_arrow(...). It is equivalent to decreasing death index + * the boundary in _process_forward_arrow(...). It is equivalent to decreasing death index * order w.r.t. the & chains_in_F) { + void _apply_surjective_reflection_diamond(dimension_type dim, const std::vector& chainsInF) { // fp is the largest death index for <=d // Set col_fp: col_fp <- col_f1+...+col_fp (now in G); preserves lowest idx - auto chain_fp = chains_in_F[0]; // col_fp, with largest death bool { - return birth_ordering_.reverse_birth_order(k1, k2); + auto cmp_birth = [this](internal_key k1, internal_key k2) -> bool { + return birthOrdering_.reverse_birth_order(k1, k2); }; // true iff b(k1) >b b(k2) // available_birth: for all i by >d value of the d_i, // contains at step i all b_j, j > i, and maybe b_i if not stolen - std::set available_birth(cmp_birth); + std::set availableBirth(cmp_birth); // for f1 to f_{p} (i by <=d), insertion in available_birth_to_fidx sorts by >=b - for (auto& chain_f : chains_in_F) { - available_birth.insert(births_.at(chain_f)); + for (auto& chainF : chainsInF) { + availableBirth.insert(births_.at(chainF)); } - auto maxb_it = available_birth.begin(); // max birth cycle - auto maxb = *maxb_it; // max birth value, for persistence diagram - available_birth.erase(maxb_it); // remove max birth cycle (stolen) + auto maxbIt = availableBirth.begin(); // max birth cycle + auto maxb = *maxbIt; // max birth value, for persistence diagram + availableBirth.erase(maxbIt); // remove max birth cycle (stolen) - auto last_modified_chain_it = chains_in_F.rbegin(); + auto lastModifiedChainIt = chainsInF.rbegin(); // consider all death indices by increasing the maximal availabe death. // Let c_1 ... c_f be the chains s.t. <[c_1+...+c_f]> is the kernel and @@ -600,99 +496,97 @@ class Zigzag_persistence // last_modified is equal to c_k+...+c_1, all c_j, i>j>k, are indeed c_j // set c_i <- c_i + (c_i-1) + ... + (c_k+1) + (c_k + ... + c_1) - for (auto chain_passed_it = last_modified_chain_it; // all with smaller modified_columns; - const auto& row = matrix_.get_row(simplexIndex); - modified_columns.reserve(row.size()); - std::transform(row.begin(), row.end(), std::back_inserter(modified_columns), + std::vector modifiedColumns; + const auto& row = matrix_.get_row(faceID); + modifiedColumns.reserve(row.size()); + std::transform(row.begin(), row.end(), std::back_inserter(modifiedColumns), [](const auto& cell) { return cell.get_column_index(); }); // Sort by left-to-right order in the matrix_ (no order maintained in rows) - std::stable_sort(modified_columns.begin(), modified_columns.end(), + std::stable_sort(modifiedColumns.begin(), modifiedColumns.end(), [this](index i1, index i2) { return matrix_.get_pivot(i1) < matrix_.get_pivot(i2); }); // Modifies curr_col, not the other one. - for (auto other_col_it = std::next(modified_columns.begin()); other_col_it != modified_columns.end(); - ++other_col_it) { - curr_col = matrix_.vine_swap_with_z_eq_1_case(curr_col, *other_col_it); + for (auto otherColIt = std::next(modifiedColumns.begin()); otherColIt != modifiedColumns.end(); ++otherColIt) { + currCol = matrix_.vine_swap_with_z_eq_1_case(currCol, *otherColIt); } // curr_col points to the column to remove by restriction of K to K-{\sigma} - if (!matrix_.get_column(curr_col).is_paired()) { // in F - int dim_zzsh = cpx_.dimension(zzsh); - auto it = births_.find(curr_col); - if (dim_max_ == -1 || (dim_max_ != -1 && dim_zzsh < dim_max_)) { // don't record intervals of max dim - persistence_diagram_.emplace_back(dim_zzsh, it->second, num_arrow_); // -1); + if (!matrix_.get_column(currCol).is_paired()) { // in F + auto it = births_.find(currCol); + if (dimMax_ == -1 || (dimMax_ != -1 && dim < dimMax_)) { // don't record intervals over max dim + persistenceDiagram_.emplace_back(dim, it->second, numArrow_); } - //Following value can be erased, but it slowes the process down a bit, so I keep it as a remainder for now: - // birth_ordering_.remove_birth(it->second); + // Following value can be erased, but it slowes the process down a bit, so I keep it as a remainder for now: + // birthOrdering_.remove_birth(it->second); births_.erase(it); } else { // in H -> paired with c_g, that now belongs to F now // maintain the <=b order - birth_ordering_.add_birth_backward(num_arrow_); - births_.try_emplace(matrix_.get_column(curr_col).get_paired_chain_index(), num_arrow_); + birthOrdering_.add_birth_backward(numArrow_); + births_.try_emplace(matrix_.get_column(currCol).get_paired_chain_index(), numArrow_); } - // cannot be in G as the removed simplex is maximal - matrix_.remove_maximal_face(simplexIndex, {}); + // cannot be in G as the removed face is maximal + matrix_.remove_maximal_face(faceID, {}); } /** * @brief Returns the current persistence diagram ordered by length without infinit bars. * - * @param shortest_interval Intervals shorter than the given value are ignored. + * @param shortestInterval Intervals shorter than the given value are ignored. * @return Vector of intervals. */ - std::vector _get_persistence_diagram(Filtration_value shortest_interval) { - std::vector diag; - diag.reserve(persistence_diagram_.size()); + std::vector _get_persistence_diagram(filtration_value shortestInterval) { + std::vector diag; + diag.reserve(persistenceDiagram_.size()); - std::stable_sort(filtration_values_.begin(), filtration_values_.end(), - [](std::pair p1, std::pair p2) { + std::stable_sort(filtrationValues_.begin(), filtrationValues_.end(), + [](std::pair p1, std::pair p2) { return p1.first < p2.first; }); - for (auto bar : persistence_diagram_) { - Filtration_value birth, death; + for (auto bar : persistenceDiagram_) { + filtration_value birth, death; std::tie(birth, death) = map_index_to_filtration_value(bar.birth(), bar.death()); if (birth > death) { std::swap(birth, death); } - if (death - birth > shortest_interval) { + if (death - birth > shortestInterval) { diag.emplace_back(bar.dim(), birth, death); } } @@ -705,43 +599,43 @@ class Zigzag_persistence * * @param diag Reference to vector where to store the infinit bars. */ - void _retrieve_infinit_bars(std::vector& diag) const { - auto birth = [this](Simplex_key b_key) { - auto it_b = // lower_bound(x) returns leftmost y s.t. x <= y + void _retrieve_infinit_bars(std::vector& diag) const { + auto birth = [this](internal_key birthKey) { + auto itBirth = // lower_bound(x) returns leftmost y s.t. x <= y std::lower_bound( - filtration_values_.begin(), filtration_values_.end(), - std::pair(b_key, std::numeric_limits::infinity()), - [](std::pair p1, std::pair p2) { + filtrationValues_.begin(), filtrationValues_.end(), + std::pair(birthKey, std::numeric_limits::infinity()), + [](std::pair p1, std::pair p2) { return p1.first < p2.first; }); - if (it_b == filtration_values_.end() || it_b->first > b_key) { - --it_b; + if (itBirth == filtrationValues_.end() || itBirth->first > birthKey) { + --itBirth; } - return it_b->second; + return itBirth->second; }; for (auto& p : births_) { auto dim = matrix_.get_column(matrix_.get_column_with_pivot(p.first)).get_dimension(); - if (dim_max_ == -1 || (dim_max_ != -1 && dim < dim_max_)) - diag.emplace_back(dim, birth(p.second), std::numeric_limits::infinity()); + if (dimMax_ == -1 || (dimMax_ != -1 && dim < dimMax_)) + diag.emplace_back(dim, birth(p.second), std::numeric_limits::infinity()); } } private: - Complex cpx_; /**< Complex in which the current simplices are stored. */ - int dim_max_; /**< Maximal dimension of a bar to record. */ - matrix_type matrix_; /**< Matrix storing a base of the current chain complex. */ - std::unordered_map births_; /**< Map simplex index in F to corresponding birth. */ - birth_ordering birth_ordering_; /**< Maintains persistence_diagram_; /**< Stores current closed persistence intervals. */ - Simplex_key num_arrow_; /**< Current arrow number. */ - Filtration_value previous_filtration_value_; /**< Filtration value of the previous arrow. */ + std::unordered_map handleToKey_; /**< Map from input keys to internal keys. */ + dimension_type dimMax_; /**< Maximal dimension of a bar to record. */ + Matrix_type matrix_; /**< Matrix storing a base of the current chain complex. */ + std::unordered_map births_; /**< Map face index in F to corresponding birth. */ + Birth_ordering birthOrdering_; /**< Maintains persistenceDiagram_; /**< Stores current closed persistence intervals. */ + internal_key numArrow_; /**< Current arrow number. */ + filtration_value previousFiltrationValue_; /**< Filtration value of the previous arrow. */ /** - * @brief filtration_values_ stores consecutive pairs (i,f) , (j,f') with f != f', - * meaning that all inserted simplices with key in [i;j-1] have filtration value f - * i is the smallest simplex index whose simplex has filtration value f. + * @brief filtrationValues_ stores consecutive pairs (i,f) , (j,f') with f != f', + * meaning that all inserted faces with key in [i;j-1] have filtration value f, + * i is the smallest face index whose face has filtration value f. */ - std::vector> filtration_values_; + std::vector > filtrationValues_; }; // end class Zigzag_persistence } // namespace zigzag_persistence diff --git a/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp b/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp index d09699d750..65e80323dc 100644 --- a/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp +++ b/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp @@ -8,9 +8,6 @@ * - YYYY/MM Author: Description of the modification */ -#include -#include -#include #include #include @@ -19,26 +16,16 @@ #include #include -#include - -using namespace Gudhi; -using namespace boost::unit_test; - -struct Simplex_tree_options_zigzag_persistence : Gudhi::Simplex_tree_options_minimal { - static const bool store_key = true; -}; - -using ST = Gudhi::Simplex_tree; -using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; -using Vertex_handle = ST::Vertex_handle; -using Filtration_value = ST::Filtration_value; -using interval_index = ZP::index_interval; -using interval_filtration = ZP::filtration_value_interval; +using ZP = Gudhi::zigzag_persistence::Zigzag_persistence<>; +using face_handle = ZP::face_key; +using filtration_value = ZP::filtration_value; +using Interval_index = ZP::Index_interval; +using Interval_filtration = ZP::Filtration_value_interval; struct cmp_intervals_by_length { cmp_intervals_by_length() {} - bool operator()(interval_filtration p, interval_filtration q) { + bool operator()(Interval_filtration p, Interval_filtration q) { if (p.length() != q.length()) { return p.length() > q.length(); } @@ -60,7 +47,7 @@ BOOST_AUTO_TEST_CASE(constructor) { BOOST_CHECK(zp.get_persistence_diagram(0).empty()); } -void test_barcode(ZP& zp, std::vector& barcode) { +void test_barcode(ZP& zp, std::vector& barcode) { std::stable_sort(barcode.begin(), barcode.end(), cmp_intervals_by_length()); auto it = barcode.begin(); for (const auto& interval : zp.get_persistence_diagram(0, true)) { @@ -72,7 +59,7 @@ void test_barcode(ZP& zp, std::vector& barcode) { BOOST_CHECK(it == barcode.end()); } -void test_indices(ZP& zp, std::vector& indices, std::vector& indexToFil) { +void test_indices(ZP& zp, std::vector& indices, std::vector& indexToFil) { auto it = indices.begin(); for (const auto& interval : zp.get_index_persistence_diagram()) { BOOST_CHECK_EQUAL(interval.dim(), it->dim()); @@ -86,7 +73,7 @@ void test_indices(ZP& zp, std::vector& indices, std::vector > get_simplices() { +std::vector > get_simplices() { return {{0}, {1}, {2}, @@ -118,7 +105,39 @@ std::vector > get_simplices() { {0, 1, 2, 4}}; // remove } -std::vector get_filtration_values() { +std::vector > get_boundaries() { + return {{}, + {}, + {}, + {0, 1}, + {0, 2}, + {}, + {1, 2}, + {}, + {5, 7}, + {}, + {3, 4, 6}, + {7, 9}, + {5, 9}, + {8, 11, 12}, + {10}, // remove + {13}, // remove + {1, 7}, + {3, 4, 6}, + {2, 7}, + {8, 11, 12}, + {0, 7}, + {4, 18, 20}, + {6, 16, 18}, + {3, 16, 20}, + {19}, // remove + {8}, // remove + {12}, // remove + {17, 21, 22, 23}, + {27}}; // remove +} + +std::vector get_filtration_values() { return {0, 0, 0, 1, 1, 1, 2, 2, 2, @@ -134,16 +153,16 @@ std::vector get_filtration_values() { BOOST_AUTO_TEST_CASE(zigzag_persistence_single) { ZP zp(28); - std::vector realIndices; - std::vector realBarcode; + std::vector realIndices; + std::vector realBarcode; realIndices.reserve(13); realBarcode.reserve(9); - std::vector > simplices = get_simplices(); - std::vector filValues = get_filtration_values(); + std::vector > simplices = get_boundaries(); + std::vector filValues = get_filtration_values(); for (unsigned int i = 0; i < 14; ++i) { - zp.insert_simplex(simplices[i], filValues[i]); + zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); } realIndices.emplace_back(0, 1, 3); @@ -159,11 +178,12 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single) { realBarcode.emplace_back(1, 3, 4); for (unsigned int i = 14; i < 16; ++i) { - zp.remove_simplex(simplices[i], filValues[i]); + auto id = simplices[i][0]; + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); } for (unsigned int i = 16; i < 24; ++i) { - zp.insert_simplex(simplices[i], filValues[i]); + zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); } realIndices.emplace_back(0, 5, 16); @@ -177,22 +197,24 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single) { realBarcode.emplace_back(1, 6, 7); for (unsigned int i = 24; i < 27; ++i) { - zp.remove_simplex(simplices[i], filValues[i]); + auto id = simplices[i][0]; + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); } realIndices.emplace_back(1, 24, 25); realBarcode.emplace_back(1, 8, 9); - zp.insert_simplex(simplices[27], filValues[27]); + zp.insert_face(27, simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1, filValues[27]); realIndices.emplace_back(2, 23, 27); realBarcode.emplace_back(2, 7, 9); - zp.remove_simplex(simplices[28], filValues[28]); + auto id = simplices[28][0]; + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[28]); - realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); - realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); - realBarcode.emplace_back(2, 10, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); + realBarcode.emplace_back(2, 10, std::numeric_limits::infinity()); test_indices(zp, realIndices, filValues); test_barcode(zp, realBarcode); @@ -200,18 +222,18 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single) { BOOST_AUTO_TEST_CASE(zigzag_persistence_single_max1) { ZP zp(28, 1); - std::vector realIndices; - std::vector indexToFil(28); - std::vector realBarcode; + std::vector realIndices; + std::vector indexToFil(28); + std::vector realBarcode; realIndices.reserve(5); realBarcode.reserve(3); - std::vector > simplices = get_simplices(); - std::vector filValues = get_filtration_values(); + std::vector > simplices = get_boundaries(); + std::vector filValues = get_filtration_values(); unsigned int currIndex = 0; for (unsigned int i = 0; i < 14; ++i) { - zp.insert_simplex(simplices[i], filValues[i]); + zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); if (simplices[i].size() < 3) { indexToFil[currIndex++] = filValues[i]; } @@ -226,14 +248,15 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single_max1) { realBarcode.emplace_back(0, 0, 1); for (unsigned int i = 14; i < 16; ++i) { - zp.remove_simplex(simplices[i], filValues[i]); - if (simplices[i].size() < 3) { + auto id = simplices[i][0]; + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + if (simplices[id].size() < 3) { indexToFil[currIndex++] = filValues[i]; } } for (unsigned int i = 16; i < 24; ++i) { - zp.insert_simplex(simplices[i], filValues[i]); + zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); if (simplices[i].size() < 3) { indexToFil[currIndex++] = filValues[i]; } @@ -243,249 +266,19 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single_max1) { realBarcode.emplace_back(0, 1, 6); for (unsigned int i = 24; i < 27; ++i) { - zp.remove_simplex(simplices[i], filValues[i]); - if (simplices[i].size() < 3) { + auto id = simplices[i][0]; + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + if (simplices[id].size() < 3) { indexToFil[currIndex++] = filValues[i]; } } - zp.insert_simplex(simplices[27], filValues[27]); - zp.remove_simplex(simplices[28], filValues[28]); - - realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); - realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); - - test_indices(zp, realIndices, indexToFil); - test_barcode(zp, realBarcode); -} - -BOOST_AUTO_TEST_CASE(zigzag_persistence_batch_with_iterators) { - ZP zp; - std::vector realIndices; - std::vector realBarcode; - realIndices.reserve(13); - realBarcode.reserve(9); - - std::vector > simplices = get_simplices(); - std::vector filValues = get_filtration_values(); - - zp.insert_simplices_contiguously(simplices.begin(), simplices.begin() + 14, filValues.begin()); - - realIndices.emplace_back(0, 1, 3); - realIndices.emplace_back(0, 2, 4); - realIndices.emplace_back(0, 7, 8); - realIndices.emplace_back(1, 6, 10); - realIndices.emplace_back(0, 9, 11); - realIndices.emplace_back(1, 12, 13); - - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(1, 2, 3); - realBarcode.emplace_back(1, 3, 4); - - zp.remove_simplices_contiguously(simplices.begin() + 14, simplices.begin() + 16, filValues.begin() + 14); - zp.insert_simplices_contiguously(simplices.begin() + 16, simplices.begin() + 24, filValues.begin() + 16); - - realIndices.emplace_back(0, 5, 16); - realIndices.emplace_back(1, 14, 17); - realIndices.emplace_back(1, 15, 19); - realIndices.emplace_back(1, 20, 21); - realIndices.emplace_back(1, 18, 22); - - realBarcode.emplace_back(0, 1, 6); - realBarcode.emplace_back(1, 5, 6); - realBarcode.emplace_back(1, 6, 7); - - zp.remove_simplices_contiguously(simplices.begin() + 24, simplices.begin() + 27, filValues.begin() + 24); - - realIndices.emplace_back(1, 24, 25); - realBarcode.emplace_back(1, 8, 9); - - zp.insert_simplices_contiguously(simplices.begin() + 27, simplices.begin() + 28, filValues.begin() + 27); - - realIndices.emplace_back(2, 23, 27); - realBarcode.emplace_back(2, 7, 9); - - zp.remove_simplices_contiguously(simplices.begin() + 28, simplices.begin() + 29, filValues.begin() + 28); - - realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); - realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); - realBarcode.emplace_back(2, 10, std::numeric_limits::infinity()); - - test_indices(zp, realIndices, filValues); - test_barcode(zp, realBarcode); -} - -BOOST_AUTO_TEST_CASE(zigzag_persistence_batch_with_iterators_max1) { - ZP zp(28, 1); - std::vector realIndices; - std::vector indexToFil(28); - std::vector realBarcode; - realIndices.reserve(5); - realBarcode.reserve(3); - - std::vector > simplices = get_simplices(); - std::vector filValues = get_filtration_values(); - unsigned int currIndex = 0; - - for (unsigned int i = 0; i < 28; ++i) { - if (simplices[i].size() < 3) { - indexToFil[currIndex++] = filValues[i]; - } - } - - zp.insert_simplices_contiguously(simplices.begin(), simplices.begin() + 14, filValues.begin()); - - realIndices.emplace_back(0, 1, 3); - realIndices.emplace_back(0, 2, 4); - realIndices.emplace_back(0, 7, 8); - realIndices.emplace_back(0, 9, 10); - - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(0, 0, 1); - - zp.remove_simplices_contiguously(simplices.begin() + 14, simplices.begin() + 16, filValues.begin() + 14); - zp.insert_simplices_contiguously(simplices.begin() + 16, simplices.begin() + 24, filValues.begin() + 16); - - realIndices.emplace_back(0, 5, 12); - realBarcode.emplace_back(0, 1, 6); - - zp.remove_simplices_contiguously(simplices.begin() + 24, simplices.begin() + 27, filValues.begin() + 24); - zp.insert_simplices_contiguously(simplices.begin() + 27, simplices.begin() + 28, filValues.begin() + 27); - zp.remove_simplices_contiguously(simplices.begin() + 28, simplices.begin() + 29, filValues.begin() + 28); - - realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); - realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); - - test_indices(zp, realIndices, indexToFil); - test_barcode(zp, realBarcode); -} - -BOOST_AUTO_TEST_CASE(zigzag_persistence_batch) { - ZP zp; - std::vector realIndices; - std::vector realBarcode; - realIndices.reserve(13); - realBarcode.reserve(9); - - std::vector > simplices = get_simplices(); - std::vector filValues = get_filtration_values(); - - std::vector > subSimplices(simplices.begin(), simplices.begin() + 14); - std::vector subFilValues(filValues.begin(), filValues.begin() + 14); - zp.insert_simplices_contiguously(subSimplices, subFilValues); - - realIndices.emplace_back(0, 1, 3); - realIndices.emplace_back(0, 2, 4); - realIndices.emplace_back(0, 7, 8); - realIndices.emplace_back(1, 6, 10); - realIndices.emplace_back(0, 9, 11); - realIndices.emplace_back(1, 12, 13); - - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(1, 2, 3); - realBarcode.emplace_back(1, 3, 4); - - subSimplices = std::vector >(simplices.begin() + 14, simplices.begin() + 16); - subFilValues = std::vector(filValues.begin() + 14, filValues.begin() + 16); - zp.remove_simplices_contiguously(subSimplices, subFilValues); - - subSimplices = std::vector >(simplices.begin() + 16, simplices.begin() + 24); - subFilValues = std::vector(filValues.begin() + 16, filValues.begin() + 24); - zp.insert_simplices_contiguously(subSimplices, subFilValues); - - realIndices.emplace_back(0, 5, 16); - realIndices.emplace_back(1, 14, 17); - realIndices.emplace_back(1, 15, 19); - realIndices.emplace_back(1, 20, 21); - realIndices.emplace_back(1, 18, 22); - - realBarcode.emplace_back(0, 1, 6); - realBarcode.emplace_back(1, 5, 6); - realBarcode.emplace_back(1, 6, 7); - - subSimplices = std::vector >(simplices.begin() + 24, simplices.begin() + 27); - subFilValues = std::vector(filValues.begin() + 24, filValues.begin() + 27); - zp.remove_simplices_contiguously(subSimplices, subFilValues); - - realIndices.emplace_back(1, 24, 25); - realBarcode.emplace_back(1, 8, 9); - - subSimplices = std::vector >(simplices.begin() + 27, simplices.begin() + 28); - subFilValues = std::vector(filValues.begin() + 27, filValues.begin() + 28); - zp.insert_simplices_contiguously(subSimplices, subFilValues); - - realIndices.emplace_back(2, 23, 27); - realBarcode.emplace_back(2, 7, 9); - - subSimplices = std::vector >(simplices.begin() + 28, simplices.begin() + 29); - subFilValues = std::vector(filValues.begin() + 28, filValues.begin() + 29); - zp.remove_simplices_contiguously(subSimplices, subFilValues); - - realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); - realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); - realBarcode.emplace_back(2, 10, std::numeric_limits::infinity()); - - test_indices(zp, realIndices, filValues); - test_barcode(zp, realBarcode); -} - -BOOST_AUTO_TEST_CASE(zigzag_persistence_batch_max1) { - ZP zp(28, 1); - std::vector realIndices; - std::vector indexToFil(28); - std::vector realBarcode; - realIndices.reserve(5); - realBarcode.reserve(3); - - std::vector > simplices = get_simplices(); - std::vector filValues = get_filtration_values(); - unsigned int currIndex = 0; - - for (unsigned int i = 0; i < 28; ++i) { - if (simplices[i].size() < 3) { - indexToFil[currIndex++] = filValues[i]; - } - } - - std::vector > subSimplices(simplices.begin(), simplices.begin() + 14); - std::vector subFilValues(filValues.begin(), filValues.begin() + 14); - zp.insert_simplices_contiguously(subSimplices, subFilValues); - - realIndices.emplace_back(0, 1, 3); - realIndices.emplace_back(0, 2, 4); - realIndices.emplace_back(0, 7, 8); - realIndices.emplace_back(0, 9, 10); - - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(0, 0, 1); - - subSimplices = std::vector >(simplices.begin() + 14, simplices.begin() + 16); - subFilValues = std::vector(filValues.begin() + 14, filValues.begin() + 16); - zp.remove_simplices_contiguously(subSimplices, subFilValues); - - subSimplices = std::vector >(simplices.begin() + 16, simplices.begin() + 24); - subFilValues = std::vector(filValues.begin() + 16, filValues.begin() + 24); - zp.insert_simplices_contiguously(subSimplices, subFilValues); - - realIndices.emplace_back(0, 5, 12); - realBarcode.emplace_back(0, 1, 6); - - subSimplices = std::vector >(simplices.begin() + 24, simplices.begin() + 27); - subFilValues = std::vector(filValues.begin() + 24, filValues.begin() + 27); - zp.remove_simplices_contiguously(subSimplices, subFilValues); - - subSimplices = std::vector >(simplices.begin() + 27, simplices.begin() + 28); - subFilValues = std::vector(filValues.begin() + 27, filValues.begin() + 28); - zp.insert_simplices_contiguously(subSimplices, subFilValues); - - subSimplices = std::vector >(simplices.begin() + 27, simplices.begin() + 28); - subFilValues = std::vector(filValues.begin() + 27, filValues.begin() + 28); - zp.remove_simplices_contiguously(subSimplices, subFilValues); + zp.insert_face(27, simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1, filValues[27]); + auto id = simplices[28][0]; + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[28]); - realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); - realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); test_indices(zp, realIndices, indexToFil); test_barcode(zp, realBarcode); From ece12948d6b1aabf9a34a217c396a82d489f63b7 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 31 May 2024 15:30:24 +0200 Subject: [PATCH 13/96] updates concepts --- .../concept/ZigzagComplex.h | 128 ------------------ ...agPersistenceOptions.h => ZigzagOptions.h} | 0 2 files changed, 128 deletions(-) delete mode 100644 src/Zigzag_persistence/concept/ZigzagComplex.h rename src/Zigzag_persistence/concept/{ZigzagPersistenceOptions.h => ZigzagOptions.h} (100%) diff --git a/src/Zigzag_persistence/concept/ZigzagComplex.h b/src/Zigzag_persistence/concept/ZigzagComplex.h deleted file mode 100644 index a8b03a209a..0000000000 --- a/src/Zigzag_persistence/concept/ZigzagComplex.h +++ /dev/null @@ -1,128 +0,0 @@ -/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. - * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. - * Author(s): Hannah Schreiber - * - * Copyright (C) 2023 Inria - * - * Modification(s): - * - YYYY/MM Author: Description of the modification - */ - -#ifndef CONCEPT_ZZ_COMPLEX_TYPE_H_ -#define CONCEPT_ZZ_COMPLEX_TYPE_H_ - -/** @file ZigzagComplex.h - * @brief Contains @ref Gudhi::zigzag_persistence::ZigzagComplex concept. - */ - -namespace Gudhi { -namespace zigzag_persistence { - -/** - * @brief Data structure storing the simplices in the current complex. - */ -class ZigzagComplex { - public: - /** - * @brief Signed integer type that needs to be long enough to store the numbers of arrows in the zigzag filtration. - */ - typename Simplex_key; - - /** - * @brief Handle to specify a simplex. - */ - typename Simplex_handle; - - /** - * @brief Handle to specify a vertex. Should be an integer type. - */ - typename Vertex_handle; - - /** - * @brief Type for filtration values. Usually 'double'. - */ - typename Filtration_value; - - /** - * @brief Range of simplex handles over the boundary of a simplex - */ - typename Boundary_simplex_range; - - /** - * @brief Constructor - */ - ZigzagComplex(); - - /** - * @brief Inserts the given simplex in the complex. - * - * @tparam VertexRange Range over the vertices of a simplex. - * @param simplex Simplex to insert represented by its vertices. - * @return A pair of a simplex handle and a boolean. - * The simplex handle represents the inserted simplex and - * the boolean if simplex was already contained in the complex or not. - */ - template - std::pair insert_simplex(const VertexRange& simplex); - - /** - * @brief Removes the given simplex. Assumes that the simplex is maximal and can be safely removed. - * - * @param sh Simplex handle representing the simplex to remove. - */ - void remove_maximal_simplex(Simplex_handle sh); - - /** - * @brief Returns the dimension of the given simplex. - * - * @param sh Simplex handle representing the simplex. - * @return Dimension of @a sh. - */ - int dimension(Simplex_handle sh); - - /** - * @brief Returns the key associated to the given simplex. - * - * @param sh Simplex handle representing the simplex. - * @return The key. - */ - Simplex_key key(Simplex_handle sh); - - /** - * @brief Assignes the given value to the given simplex as a key. - * - * @param sh Simplex handle representing the simplex. - * @param key Values to associate as key. - */ - void assign_key(Simplex_handle sh, Simplex_key key); - - /** - * @brief Finds the given simplex in the complex and returns the associated simplex handle. - * - * @tparam VertexRange Range over the vertices of a simplex. - * @param simplex Simplex to find represented by its vertices. - * @return The simplex handle associated to @a simplex if the simplex is found, @ref null_simplex() otherwise. - */ - template - Simplex_handle find(const VertexRange& simplex); - - /** - * @brief Returns a range of simplex handles representing the boundary of the given simplex. - * - * @param sh Simplex handle representing the simplex. - * @return Range of simplex handles. - */ - Boundary_simplex_range boundary_simplex_range(Simplex_handle sh); - - /** - * @brief Returns a simplex handle representing a non existing simplex. - * - * @return A simplex handle. - */ - Simplex_handle null_simplex(); -}; - -} // namespace zigzag_persistence -} // namespace Gudhi - -#endif // CONCEPT_ZZ_COMPLEX_TYPE_H_ diff --git a/src/Zigzag_persistence/concept/ZigzagPersistenceOptions.h b/src/Zigzag_persistence/concept/ZigzagOptions.h similarity index 100% rename from src/Zigzag_persistence/concept/ZigzagPersistenceOptions.h rename to src/Zigzag_persistence/concept/ZigzagOptions.h From 20ae2490f27a1d3399cb24b431ee1c2fdbc8a025 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 31 May 2024 15:31:59 +0200 Subject: [PATCH 14/96] updates concepts --- .../concept/ZigzagOptions.h | 70 +++++-------------- 1 file changed, 17 insertions(+), 53 deletions(-) diff --git a/src/Zigzag_persistence/concept/ZigzagOptions.h b/src/Zigzag_persistence/concept/ZigzagOptions.h index 7ee9d9be7d..181116adc4 100644 --- a/src/Zigzag_persistence/concept/ZigzagOptions.h +++ b/src/Zigzag_persistence/concept/ZigzagOptions.h @@ -2,7 +2,7 @@ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. * Author(s): Hannah Schreiber * - * Copyright (C) 2023 Inria + * Copyright (C) 2024 Inria * * Modification(s): * - YYYY/MM Author: Description of the modification @@ -11,77 +11,41 @@ #ifndef CONCEPT_ZZ_OPTIONS_TYPE_H_ #define CONCEPT_ZZ_OPTIONS_TYPE_H_ -/** @file ZigzagPersistenceOptions.h - * @brief Contains @ref Gudhi::zigzag_persistence::ZigzagPersistenceOptions concept. +/** @file ZigzagOptions.h + * @brief Contains @ref Gudhi::zigzag_persistence::ZigzagOptions concept. */ namespace Gudhi { namespace zigzag_persistence { /** - * @brief List of options used for the matrix maintained for the zigzag persistence computation. + * @brief List of options used for the zigzag persistence computation. */ -struct ZigzagPersistenceOptions { +struct ZigzagOptions { /** - * @brief Type for the coefficient field type. Has to support \f$Z_2\f$. + * @brief Type for the face IDs used internally and other indexations. It must be signed. */ - typename field_coeff_type; + using internal_key = unspecified; /** - * @brief Has to be set to true. Indicates that the computation will be made with \f$Z_2\f$ coefficients. + * @brief Type for the face IDs used at insertion and in the boundaries given as argument. */ - static const bool is_z2 = true; - /** - * @brief Type of the columns in the matrix. - * The available column types are given by @ref Gudhi::persistence_matrix::Column_types. - * The column type has to support row access. - */ - static const Column_types column_type; + using face_key = unspecified; /** - * @brief Has to be set to true. Indicates that the rows should be directly accessible in the matrix. - */ - static const bool has_row_access = true; - /** - * @brief Set to true, if the rows should be intrusive lists or to false if they should be sets. True is recommended. - * Note that intrusive rows are not compatible with certain column types. - */ - static const bool has_intrusive_rows; - /** - * @brief Has to set to true. Indicates that the rows of the matrix can be removed. - */ - static const bool has_removable_rows = true; - /** - * @brief Has to be set to false. Indicates that the matrix should not store birth/death pairs of its columns. - */ - static const bool has_column_pairings = false; - /** - * @brief Has to be set to true. Enables maintaining the matrix while switching columns. - */ - static const bool has_vine_update = true; - /** - * @brief If set to true, the matrix can retrieve the representative cycles for the cycle classes. - * This option is useless for zigzag computation and therefore it is recommended to set it to false. - */ - static const bool can_retrieve_representative_cycles; - /** - * @brief This value has to be defined but will be ignored. + * @brief Type for filtration values. */ - static const bool has_column_compression; - /** - * @brief Has to be set to false. - * Indicates that the matrix should represent the base of the chain complex and not of the boundary group. - */ - static const bool is_of_boundary_type = false; + using filtration_value = unspecified; + /** - * @brief Has to be set to true. Indicates that the columns of the matrix can be removed. + * @brief Type for the dimension values. */ - static const bool has_removable_columns = true; + using dimension_type = unspecified; + /** - * @brief Has to be set to false. - * Indicates that the access to the columns will be done through simplex IDs instead of column positions. + * @brief Column type used by the internal matrix. */ - static const bool is_indexed_by_position = false; + static const Gudhi::persistence_matrix::Column_types column_type; }; } // namespace zigzag_persistence From df39f9c0318ac3eab84838becedd1e7aa042b1ab Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 31 May 2024 15:48:19 +0200 Subject: [PATCH 15/96] zigzag doc update --- .../doc/Intro_zigzag_persistence.h | 2 +- .../include/gudhi/Zigzag_persistence.h | 22 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h index 5fe392a659..afa843fcbd 100644 --- a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h +++ b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h @@ -33,7 +33,7 @@ namespace zigzag_persistence { * filtration anymore. This makes it possible to build very long fine tuned filtrations with relatively small complexes * which can be processed without overreaching memory space. For this purpose, it is possible to feed the module with * information about the filtration "on the fly" to avoid loading the whole filtration at once. Information about the - * current complex and current barcode can be retrieved between any steps. + * current barcode can be retrieved between any steps. * * \subsection zigzagexamples Examples * diff --git a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h index b9a686e0a8..527ec44903 100644 --- a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h @@ -68,21 +68,21 @@ struct Default_zigzag_options { //also needs to be implemented. The theory needs to be done first. /** \class Zigzag_persistence Zigzag_persistence.h gudhi/Zigzag_persistence.h * \brief Class computating the zigzag persistent homology of a zigzag - * filtration. Algorithm based on \cite zigzag_reflection. + * filtration. Algorithm based on \cite zigzag. * * \ingroup zigzag_persistence * - * \tparam ZigzagOptions TODO: concept + * \tparam ZigzagOptions Structure following the @ref ZigzagOptions concept. Default value: @ref Default_zigzag_options. */ template class Zigzag_persistence { public: - using Options = ZigzagOptions; - using Matrix_options = Zigzag_matrix_options; /**< Matrix options */ - using internal_key = typename Options::internal_key; - using face_key = typename Options::face_key; - using filtration_value = typename Options::filtration_value; - using dimension_type = typename Options::dimension_type; + using Options = ZigzagOptions; /**< Zigzag options. */ + using Matrix_options = Zigzag_matrix_options; /**< Matrix options. */ + using internal_key = typename Options::internal_key; /**< Key and index type, has to be signed. */ + using face_key = typename Options::face_key; /**< Face ID type from external inputs. */ + using filtration_value = typename Options::filtration_value; /**< Type for filtration values. */ + using dimension_type = typename Options::dimension_type; /**< Type for dimension values. */ /** \brief Structure to store persistence intervals by their index values. * @@ -245,10 +245,10 @@ class Zigzag_persistence { * To retrieve the current persistence diagram at any moment of the filtration, * use @ref get_persistence_diagram or @ref get_index_persistence_diagram. * - * @param min_number_of_faces Minimum number of faces that will be inserted at some point in the filtration. + * @param minNumberOfFaces Minimum number of faces that will be inserted at some point in the filtration. * If the total number of faces is known in advance, the memory allocation can be better optimized. * Default value: 0. - * @param ignore_cycles_above_dim Ignores cycles in dimension larger or equal in the final diagram. + * @param ignoreCyclesAboveDim Ignores cycles in dimension larger or equal in the final diagram. * If -1, no cycles are ignored. Default value: -1. */ Zigzag_persistence(unsigned int minNumberOfFaces = 0, int ignoreCyclesAboveDim = -1) @@ -335,7 +335,7 @@ class Zigzag_persistence { } /** - * @brief Returns the ``index persistence diagram'' of the current filtration, that is, the pairs of atomic arrow + * @brief Returns the "index persistence diagram" of the current filtration, that is, the pairs of atomic arrow * numbers corresponding to a birth-death pair. Does not contain points at infinity, only the cycle classes which * already died are represented. * From 03e7b7de371a15f06d64097a5f7b0338bf702d67 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 31 May 2024 16:56:45 +0200 Subject: [PATCH 16/96] small fixes --- .../example_zzfiltration_from_file.cpp | 23 +++----- .../example/zigzag_filtration_example.txt | 58 +++++++++---------- .../include/gudhi/Zigzag_persistence.h | 43 +++++++------- .../test/zigzag_persistence_unit_test.cpp | 4 +- 4 files changed, 62 insertions(+), 66 deletions(-) diff --git a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp index 37ebf7185f..21f3e56f4e 100644 --- a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp +++ b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp @@ -25,20 +25,20 @@ enum lineType : int { INCLUSION, REMOVAL, COMMENT }; void print_barcode(ZP& zp) { std::clog << std::endl << "Current barcode:" << std::endl; for (auto& bar : zp.get_persistence_diagram(0, true)) { - std::clog << std::floor(bar.birth()) << " - "; + std::clog << bar.birth() << " - "; if (bar.death() == std::numeric_limits::infinity()) { std::clog << "inf"; } else { - std::clog << std::floor(bar.death()); + std::clog << bar.death(); } std::clog << " (" << bar.dim() << ")" << std::endl; } std::clog << std::endl; } -lineType read_operation(std::string& line, std::vector& vertices, double& timestamp) { +lineType read_operation(std::string& line, std::vector& faces, double& timestamp) { lineType type; - vertices.clear(); + faces.clear(); id_handle num; size_t current = line.find_first_not_of(' ', 0); @@ -51,30 +51,25 @@ lineType read_operation(std::string& line, std::vector& vertices, dou else if (line[current] == '#') return COMMENT; else { - std::clog << "Syntaxe error in file." << std::endl; + std::clog << "(1) Syntaxe error in file." << std::endl; exit(0); } current = line.find_first_not_of(' ', current + 1); if (current == std::string::npos) { - std::clog << "Syntaxe error in file." << std::endl; + std::clog << "(2) Syntaxe error in file." << std::endl; exit(0); } size_t next = line.find_first_of(' ', current); timestamp = std::stod(line.substr(current, next - current)); current = line.find_first_not_of(' ', next); - if (current == std::string::npos) { - std::clog << "Syntaxe error in file." << std::endl; - exit(0); - } - - do { + while (current != std::string::npos) { next = line.find_first_of(' ', current); num = std::stoi(line.substr(current, next - current)); - vertices.push_back(num); + faces.push_back(num); current = line.find_first_not_of(' ', next); - } while (current != std::string::npos); + } return type; } diff --git a/src/Zigzag_persistence/example/zigzag_filtration_example.txt b/src/Zigzag_persistence/example/zigzag_filtration_example.txt index e0fd923d9a..e34c23d027 100644 --- a/src/Zigzag_persistence/example/zigzag_filtration_example.txt +++ b/src/Zigzag_persistence/example/zigzag_filtration_example.txt @@ -8,42 +8,42 @@ # If removal: id of the simplex to remove + dimension # #: comment line -i 0 -i 0 -i 0 +i 0. +i 0. +i 0. -i 1 0 1 -i 1 0 2 -i 1 +i 1. 0 1 +i 1. 0 2 +i 1. -i 2 1 2 -i 2 -i 2 5 7 +i 2. 1 2 +i 2. +i 2. 5 7 -i 3 -i 3 3 4 6 -i 3 7 9 -i 3 5 9 +i 3. +i 3. 3 4 6 +i 3. 7 9 +i 3. 5 9 -i 4 8 11 12 +i 4. 8 11 12 -r 5 10 2 +r 5. 10 2 -r 6 13 2 -i 6 1 7 -i 6 3 4 6 +r 6. 13 2 +i 6. 1 7 +i 6. 3 4 6 -i 7 2 7 -i 7 8 11 12 -i 7 0 7 -i 7 4 18 20 -i 7 6 16 18 -i 7 3 16 20 +i 7. 2 7 +i 7. 8 11 12 +i 7. 0 7 +i 7. 4 18 20 +i 7. 6 16 18 +i 7. 3 16 20 -r 8 19 2 +r 8. 19 2 -r 9 8 1 -r 9 12 1 -i 9 17 21 22 23 +r 9. 8 1 +r 9. 12 1 +i 9. 17 21 22 23 -r 10 27 3 \ No newline at end of file +r 10. 27 3 \ No newline at end of file diff --git a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h index 527ec44903..c2331e9dca 100644 --- a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h @@ -96,15 +96,15 @@ class Zigzag_persistence { Interval(int dim, value_type b, value_type d) : dim_(dim), b_(b), d_(d) {} /** Returns the dimension of the homological feature corresponding to the interval. */ int dim() const { return dim_; } - /** Returns the birth index of the interval.*/ + /** Returns the birth value of the interval.*/ value_type birth() const { return b_; } - /** Returns the death index of the interval.*/ + /** Returns the death value of the interval.*/ value_type death() const { return d_; } protected: - int dim_; // homological dimension - value_type b_; // filtration value associated to birth index - value_type d_; // filtration value associated to death index + int dim_; /**< Homological dimension. */ + value_type b_; /**< Value associated to the interval birth. */ + value_type d_; /**< Value associated to the interval death. */ }; using Index_interval = Interval; @@ -155,7 +155,7 @@ class Zigzag_persistence { private: /** \brief Maintains the birth ordering \f$\leq_b\f$. * - * \details Contains an std::map of size the number of + * \details Contains a map of size the number of * non-zero rows of the homology matrix, at any time during the computation of * zigzag persistence. * @@ -381,8 +381,7 @@ class Zigzag_persistence { } /** - * @brief Returns the current persistence diagram ordered first by length, than by dimension, - * than by birth value and finally by death value. + * @brief Returns the current persistence diagram. * * @param shortestInterval Threshold. Every bar shorter than the given value will be ignored. Default value: 0. * @param includeInfinitBars If set to true, infinit bars are included in the diagram. Default value: false. @@ -390,18 +389,18 @@ class Zigzag_persistence { */ std::vector get_persistence_diagram(filtration_value shortestInterval = 0., bool includeInfinitBars = false) { - auto comp = [](Filtration_value_interval p, Filtration_value_interval q) { - if (p.length() != q.length()) { - return p.length() > q.length(); - } // longest 1st - if (p.dim() != q.dim()) { - return p.dim() < q.dim(); - } // lower dimension first - if (p.birth() != q.birth()) { - return p.birth() < q.birth(); - } // lex order - return p.death() < q.death(); - }; + // auto comp = [](Filtration_value_interval p, Filtration_value_interval q) { + // if (p.length() != q.length()) { + // return p.length() > q.length(); + // } // longest 1st + // if (p.dim() != q.dim()) { + // return p.dim() < q.dim(); + // } // lower dimension first + // if (p.birth() != q.birth()) { + // return p.birth() < q.birth(); + // } // lex order + // return p.death() < q.death(); + // }; std::vector diag = _get_persistence_diagram(shortestInterval); @@ -409,7 +408,7 @@ class Zigzag_persistence { _retrieve_infinit_bars(diag); } - std::stable_sort(diag.begin(), diag.end(), comp); + // std::stable_sort(diag.begin(), diag.end(), comp); return diag; } @@ -625,7 +624,7 @@ class Zigzag_persistence { std::unordered_map handleToKey_; /**< Map from input keys to internal keys. */ dimension_type dimMax_; /**< Maximal dimension of a bar to record. */ Matrix_type matrix_; /**< Matrix storing a base of the current chain complex. */ - std::unordered_map births_; /**< Map face index in F to corresponding birth. */ + std::unordered_map births_; /**< Map face index in F to corresponding birth. */ Birth_ordering birthOrdering_; /**< Maintains persistenceDiagram_; /**< Stores current closed persistence intervals. */ internal_key numArrow_; /**< Current arrow number. */ diff --git a/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp b/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp index 65e80323dc..f1596e714d 100644 --- a/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp +++ b/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp @@ -48,9 +48,11 @@ BOOST_AUTO_TEST_CASE(constructor) { } void test_barcode(ZP& zp, std::vector& barcode) { + auto bars = zp.get_persistence_diagram(0, true); + std::stable_sort(bars.begin(), bars.end(), cmp_intervals_by_length()); std::stable_sort(barcode.begin(), barcode.end(), cmp_intervals_by_length()); auto it = barcode.begin(); - for (const auto& interval : zp.get_persistence_diagram(0, true)) { + for (const auto& interval : bars) { BOOST_CHECK_EQUAL(interval.dim(), it->dim()); BOOST_CHECK_EQUAL(interval.birth(), it->birth()); BOOST_CHECK_EQUAL(interval.death(), it->death()); From 26161a7be7f5401150d997db767114d16e53579a Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 31 May 2024 17:21:22 +0200 Subject: [PATCH 17/96] persistence diagram: list -> vector --- .../include/gudhi/Zigzag_persistence.h | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h index c2331e9dca..413ba61297 100644 --- a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h @@ -341,7 +341,7 @@ class Zigzag_persistence { * * @return Reference to the list of intervals. */ - const std::list& get_index_persistence_diagram() const { return persistenceDiagram_; } + const std::vector& get_index_persistence_diagram() const { return persistenceDiagram_; } /** * @brief Returns the filtration values \f$[f(b),f(d)]\f$ associated to the indices \f$[b,d]\f$ which are retrieved @@ -389,18 +389,18 @@ class Zigzag_persistence { */ std::vector get_persistence_diagram(filtration_value shortestInterval = 0., bool includeInfinitBars = false) { - // auto comp = [](Filtration_value_interval p, Filtration_value_interval q) { - // if (p.length() != q.length()) { - // return p.length() > q.length(); - // } // longest 1st - // if (p.dim() != q.dim()) { - // return p.dim() < q.dim(); - // } // lower dimension first - // if (p.birth() != q.birth()) { - // return p.birth() < q.birth(); - // } // lex order - // return p.death() < q.death(); - // }; + auto comp = [](Filtration_value_interval p, Filtration_value_interval q) { + if (p.length() != q.length()) { + return p.length() > q.length(); + } // longest 1st + if (p.dim() != q.dim()) { + return p.dim() < q.dim(); + } // lower dimension first + if (p.birth() != q.birth()) { + return p.birth() < q.birth(); + } // lex order + return p.death() < q.death(); + }; std::vector diag = _get_persistence_diagram(shortestInterval); @@ -408,7 +408,7 @@ class Zigzag_persistence { _retrieve_infinit_bars(diag); } - // std::stable_sort(diag.begin(), diag.end(), comp); + std::stable_sort(diag.begin(), diag.end(), comp); return diag; } @@ -516,7 +516,7 @@ class Zigzag_persistence { births_.erase(chainFp); // Update persistence diagram with left interval [fil(b_max) ; fil(m)) - persistenceDiagram_.emplace_back(dim - 1, maxb, numArrow_); //-1);// + persistenceDiagram_.emplace_back(dim - 1, maxb, numArrow_); } /** @@ -626,7 +626,7 @@ class Zigzag_persistence { Matrix_type matrix_; /**< Matrix storing a base of the current chain complex. */ std::unordered_map births_; /**< Map face index in F to corresponding birth. */ Birth_ordering birthOrdering_; /**< Maintains persistenceDiagram_; /**< Stores current closed persistence intervals. */ + std::vector persistenceDiagram_; /**< Stores current closed persistence intervals. */ internal_key numArrow_; /**< Current arrow number. */ filtration_value previousFiltrationValue_; /**< Filtration value of the previous arrow. */ /** From 9c444097c7ebc2ca658cd6e4c1cc57ee2032753d Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 31 May 2024 17:51:38 +0200 Subject: [PATCH 18/96] removal of useless abs --- .../include/gudhi/Zigzag_persistence.h | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h index 413ba61297..c3b02d50d2 100644 --- a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h @@ -139,7 +139,7 @@ class Zigzag_persistence { if (Base::b_ == Base::d_) { return 0; } // otherwise inf - inf would return nan. - return std::abs(Base::b_ - Base::d_); + return Base::d_ - Base::b_; } /** * @brief Returns the absolute length of the log values of birth and death, i.e. \f$|\log d - \log b|\f$. @@ -148,7 +148,7 @@ class Zigzag_persistence { if (Base::b_ == Base::d_) { return 0; } // otherwise inf - inf would return nan. - return std::abs(std::log2(static_cast(Base::b_)) - std::log2(static_cast(Base::d_))); + return std::log2(static_cast(Base::d_)) - std::log2(static_cast(Base::b_)); } }; @@ -389,18 +389,18 @@ class Zigzag_persistence { */ std::vector get_persistence_diagram(filtration_value shortestInterval = 0., bool includeInfinitBars = false) { - auto comp = [](Filtration_value_interval p, Filtration_value_interval q) { - if (p.length() != q.length()) { - return p.length() > q.length(); - } // longest 1st - if (p.dim() != q.dim()) { - return p.dim() < q.dim(); - } // lower dimension first - if (p.birth() != q.birth()) { - return p.birth() < q.birth(); - } // lex order - return p.death() < q.death(); - }; + // auto comp = [](Filtration_value_interval p, Filtration_value_interval q) { + // if (p.length() != q.length()) { + // return p.length() > q.length(); + // } // longest 1st + // if (p.dim() != q.dim()) { + // return p.dim() < q.dim(); + // } // lower dimension first + // if (p.birth() != q.birth()) { + // return p.birth() < q.birth(); + // } // lex order + // return p.death() < q.death(); + // }; std::vector diag = _get_persistence_diagram(shortestInterval); @@ -408,7 +408,7 @@ class Zigzag_persistence { _retrieve_infinit_bars(diag); } - std::stable_sort(diag.begin(), diag.end(), comp); + // std::stable_sort(diag.begin(), diag.end(), comp); return diag; } From 2b46f1396c108609f7ccb8252110eec9bb3bd5bc Mon Sep 17 00:00:00 2001 From: hschreiber Date: Thu, 20 Jun 2024 12:17:37 +0200 Subject: [PATCH 19/96] split of zigzag computation and filtration values management --- .../concept/ZigzagOptions.h | 31 +- .../example_simple_zigzag_filtration.cpp | 4 +- .../example_zzfiltration_from_file.cpp | 40 +- .../gudhi/Filtered_zigzag_persistence.h | 553 ++++++++++++++++++ .../include/gudhi/Zigzag_persistence.h | 501 +++++----------- src/Zigzag_persistence/test/CMakeLists.txt | 11 +- .../filtered_zigzag_persistence_unit_test.cpp | 477 +++++++++++++++ .../test/zigzag_persistence_unit_test.cpp | 232 +++----- 8 files changed, 1308 insertions(+), 541 deletions(-) create mode 100644 src/Zigzag_persistence/include/gudhi/Filtered_zigzag_persistence.h create mode 100644 src/Zigzag_persistence/test/filtered_zigzag_persistence_unit_test.cpp diff --git a/src/Zigzag_persistence/concept/ZigzagOptions.h b/src/Zigzag_persistence/concept/ZigzagOptions.h index 181116adc4..712d5df2a1 100644 --- a/src/Zigzag_persistence/concept/ZigzagOptions.h +++ b/src/Zigzag_persistence/concept/ZigzagOptions.h @@ -12,16 +12,19 @@ #define CONCEPT_ZZ_OPTIONS_TYPE_H_ /** @file ZigzagOptions.h - * @brief Contains @ref Gudhi::zigzag_persistence::ZigzagOptions concept. + * @brief Contains @ref Gudhi::zigzag_persistence::ZigzagOptions and + * @ref Gudhi::zigzag_persistence::FilteredZigzagOptions concept. */ namespace Gudhi { namespace zigzag_persistence { /** - * @brief List of options used for the zigzag persistence computation. + * @ingroup zigzag_persistence + * + * @brief List of options used for the filtered zigzag persistence computation. */ -struct ZigzagOptions { +struct FilteredZigzagOptions { /** * @brief Type for the face IDs used internally and other indexations. It must be signed. */ @@ -48,6 +51,28 @@ struct ZigzagOptions { static const Gudhi::persistence_matrix::Column_types column_type; }; +/** + * @ingroup zigzag_persistence + * + * @brief List of options used for the zigzag persistence computation. + */ +struct ZigzagOptions { + /** + * @brief Type for the face IDs used internally and other indexations. It must be signed. + */ + using internal_key = unspecified; + + /** + * @brief Type for the dimension values. + */ + using dimension_type = unspecified; + + /** + * @brief Column type used by the internal matrix. + */ + static const Gudhi::persistence_matrix::Column_types column_type; +}; + } // namespace zigzag_persistence } // namespace Gudhi diff --git a/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp b/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp index a13b998906..f99fd9bc59 100644 --- a/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp +++ b/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp @@ -11,9 +11,9 @@ #include #include -#include +#include -using ZP = Gudhi::zigzag_persistence::Zigzag_persistence<>; +using ZP = Gudhi::zigzag_persistence::Filtered_zigzag_persistence_with_storage<>; using face_handle = ZP::face_key; using filtration_value = ZP::filtration_value; using Interval_filtration = ZP::Filtration_value_interval; diff --git a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp index 21f3e56f4e..bd2cb61bdf 100644 --- a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp +++ b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp @@ -13,29 +13,15 @@ #include #include -#include +#include -using ZP = Gudhi::zigzag_persistence::Zigzag_persistence<>; +using ZP = Gudhi::zigzag_persistence::Filtered_zigzag_persistence<>; using id_handle = ZP::face_key; using filtration_value = ZP::filtration_value; -using Interval_filtration = ZP::Filtration_value_interval; +using dimension_type = ZP::dimension_type; enum lineType : int { INCLUSION, REMOVAL, COMMENT }; -void print_barcode(ZP& zp) { - std::clog << std::endl << "Current barcode:" << std::endl; - for (auto& bar : zp.get_persistence_diagram(0, true)) { - std::clog << bar.birth() << " - "; - if (bar.death() == std::numeric_limits::infinity()) { - std::clog << "inf"; - } else { - std::clog << bar.death(); - } - std::clog << " (" << bar.dim() << ")" << std::endl; - } - std::clog << std::endl; -} - lineType read_operation(std::string& line, std::vector& faces, double& timestamp) { lineType type; faces.clear(); @@ -85,7 +71,13 @@ int main(int argc, char* const argv[]) { std::string line; std::ifstream file(argv[1]); - ZP zp; + + //std::clog could be replaced by any other output stream + ZP zp([](dimension_type dim, filtration_value birth, filtration_value death) { + std::clog << "[" << dim << "] "; + std::clog << birth << " - " << death; + std::clog << std::endl; + }); if (file.is_open()) { std::vector data; @@ -97,15 +89,12 @@ int main(int argc, char* const argv[]) { double lastTimestamp = timestamp; // first operation has to be an insertion. zp.insert_face(id, data, 0, timestamp); - std::cout << line << std::endl; while (getline(file, line, '\n')) { type = read_operation(line, data, timestamp); if (type != COMMENT && lastTimestamp != timestamp) { - print_barcode(zp); lastTimestamp = timestamp; } - if (type != COMMENT) std::cout << line << std::endl; if (type == INCLUSION) { ++id; @@ -116,7 +105,6 @@ int main(int argc, char* const argv[]) { zp.remove_face(data[0], data[1], timestamp); } } - print_barcode(zp); file.close(); } else { @@ -124,5 +112,13 @@ int main(int argc, char* const argv[]) { file.setstate(std::ios::failbit); } + //retrieve infinit bars remaining at the end + //again std::clog could be replaced by any other output stream + zp.get_current_infinit_intervals([](dimension_type dim, filtration_value birth) { + std::clog << "[" << dim << "] "; + std::clog << birth << " - inf"; + std::clog << std::endl; + }); + return 0; } \ No newline at end of file diff --git a/src/Zigzag_persistence/include/gudhi/Filtered_zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/Filtered_zigzag_persistence.h new file mode 100644 index 0000000000..e7735ac1d0 --- /dev/null +++ b/src/Zigzag_persistence/include/gudhi/Filtered_zigzag_persistence.h @@ -0,0 +1,553 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Clément Maria + * + * Copyright (C) 2021 Inria + * + * Modification(s): + * - 2023/05 Hannah Schreiber: Rework of the interface, reorganization and debug + * - 2023/05 Hannah Schreiber: Addition of infinit bars + * - 2024/06 Hannah Schreiber: Separation of the zigzag algorithm from the filtration value management + * - YYYY/MM Author: Description of the modification + */ + +/** + * @file Filtered_zigzag_persistence.h + * @author Clément Maria, Hannah Schreiber + * @brief Contains the implementation of the @ref Interval structure and the + * @ref Gudhi::zigzag_persistence::Filtered_zigzag_persistence_with_storage and + * @ref Gudhi::zigzag_persistence::Filtered_zigzag_persistence classes. + */ + +#ifndef FILTERED_ZIGZAG_PERSISTENCE_H_ +#define FILTERED_ZIGZAG_PERSISTENCE_H_ + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace Gudhi { +namespace zigzag_persistence { + +/** + * @ingroup zigzag_persistence + * + * @brief Structure to store persistence intervals by their birth and death values. + * + * @tparam value_type Type for the birth and death indices. + */ +template +struct Interval { + /** + * @brief Default constructor. All values are initialized with default values. + */ + Interval() {} + /** + * @brief Constructor. + * + * @param dim Dimension of the cycle. + * @param b Birth index or value of the cycle. + * @param d Death index or value of the cycle. + */ + Interval(int dim, value_type b, value_type d) : dim_(dim), b_(b), d_(d) {} + /** + * @brief Returns the dimension of the homological feature corresponding to the interval. + * + * @return Stored dimension. + */ + int dim() const { return dim_; } + /** + * @brief Returns the birth value of the interval. + * + * @return The stored birth. + */ + value_type birth() const { return b_; } + /** + * @brief Returns the death value of the interval. + * + * @return The stored death. + */ + value_type death() const { return d_; } + + protected: + int dim_; /**< Homological dimension. */ + value_type b_; /**< Value associated to the interval birth. */ + value_type d_; /**< Value associated to the interval death. */ +}; + +/** + * @ingroup zigzag_persistence + * + * @brief Default options for @ref Filtered_zigzag_persistence_with_storage and @ref Filtered_zigzag_persistence. + */ +struct Default_filtered_zigzag_options { + using internal_key = int; /**< Face ID used internaly, must be signed. */ + using face_key = int; /**< Face ID used in the given boundaries. */ + using filtration_value = double; /**< Filtration value type. */ + using dimension_type = int; /**< Dimension value type. */ + /** + * @brief Column type use by the internal matrix. + */ + static const Gudhi::persistence_matrix::Column_types column_type = + Gudhi::persistence_matrix::Column_types::INTRUSIVE_LIST; +}; + +/** + * @ingroup zigzag_persistence + * + * @brief Class computating the zigzag persistent homology of a zigzag filtration. Algorithm based on \cite zigzag. + * Eventhough the insertions and removals are given in a "stream-like" way, the barcode and other values are + * stored during the whole process and not removed. It is therefore suited for smaller filtrations where the clean + * ups produce a higher overhead than the memory consumption. + * + * @tparam FilteredZigzagOptions Structure following the @ref FilteredZigzagOptions concept. + * Default value: @ref Default_filtered_zigzag_options. + */ +template +class Filtered_zigzag_persistence_with_storage +{ + public: + using Options = FilteredZigzagOptions; /**< Zigzag options. */ + using internal_key = typename Options::internal_key; /**< Key and index type, has to be signed. */ + using face_key = typename Options::face_key; /**< Face ID type from external inputs. */ + using filtration_value = typename Options::filtration_value; /**< Type for filtration values. */ + using dimension_type = typename Options::dimension_type; /**< Type for dimension values. */ + using Index_interval = Interval; /**< Persistence interval type. */ + + /** \brief Structure to store persistence intervals by their filtration values. + * + * \details By convention, interval \f$[b;d]\f$ are + * closed for finite indices b and d, and open for left-infinite and/or + * right-infinite endpoints. + */ + struct Filtration_value_interval : Interval { + private: + using Base = Interval; + + public: + /** + * @brief Default constructor + */ + Filtration_value_interval() : Base() {} + /** + * @brief Construct a new interval with given parameters + * + * @param dim Dimension of the interval. + * @param b Start value of the interval. + * @param d End value of the interval. + */ + Filtration_value_interval(int dim, filtration_value b, filtration_value d) : Base(dim, b, d) {} + + /** + * @brief Returns the absolute length of the interval \f$|d-b|\f$. + */ + filtration_value length() const { + if (Base::b_ == Base::d_) { + return 0; + } // otherwise inf - inf would return nan. + return Base::d_ - Base::b_; + } + /** + * @brief Returns the absolute length of the log values of birth and death, i.e. \f$|\log d - \log b|\f$. + */ + filtration_value log_length() const { + if (Base::b_ == Base::d_) { + return 0; + } // otherwise inf - inf would return nan. + return std::log2(static_cast(Base::d_)) - std::log2(static_cast(Base::b_)); + } + }; + + /** + * @brief Constructor. + * @details After construction of the class, the zigzag filtration should be given in a streaming like way, i.e., + * call @ref insert_face, @ref remove_face or @ref apply_identity for each step of the filtration in order of + * the filtration. To retrieve the current persistence diagram at any moment of the filtration, + * use @ref get_persistence_diagram or @ref get_index_persistence_diagram. + * + * @param minNumberOfFaces Minimum number of faces that will be in a complex at some point in the filtration. + * If the maximal number of faces is known in advance, the memory allocation can be better optimized. + * Default value: 0. + * @param ignoreCyclesAboveDim Ignores cycles in dimension larger or equal in the final diagram. + * If -1, no cycles are ignored. Default value: -1. + */ + Filtered_zigzag_persistence_with_storage(unsigned int minNumberOfFaces = 0, int ignoreCyclesAboveDim = -1) + : dimMax_(ignoreCyclesAboveDim), + persistenceDiagram_(), + numArrow_(-1), + previousFiltrationValue_(std::numeric_limits::infinity()), + pers_( + [&](dimension_type dim, internal_key birth, internal_key death) { + if (dimMax_ == -1 || (dimMax_ != -1 && dim < dimMax_)) { // don't record intervals over max dim + persistenceDiagram_.emplace_back(dim, birth, death); + } + }, + minNumberOfFaces) {} + + /** + * @brief Updates the zigzag persistence diagram after the insertion of the given face. + * + * @tparam BoundaryRange Range type needing begin and end members. + * @param faceID ID representing the inserted face. + * @param boundary Boundary of the inserted face. The range should be composed of the IDs of all faces contained in + * the boundary (i.e. with non-zero coefficients), using the ID specified as `faceID` when the corresponding face + * was previously inserted (recall that the faces should be inserted in order of filtration). + * @param dimension Dimension of the inserted face. + * @param filtrationValue Filtration value associated to the face. + * Assumed to be larger or equal to previously used filtration values. + */ + template > + void insert_face(face_key faceID, + const BoundaryRange& boundary, + dimension_type dimension, + filtration_value filtrationValue) { + ++numArrow_; + + if (dimMax_ != -1 && dimension > dimMax_) { + pers_.apply_identity(); + return; + } + + if (filtrationValue != previousFiltrationValue_) // check whether the filt value has changed + { // consecutive pairs (i,f), (j,f') mean faces of index k in [i,j-1] have + previousFiltrationValue_ = filtrationValue; // filtration value f + filtrationValues_.emplace_back(numArrow_, previousFiltrationValue_); + } + + [[maybe_unused]] auto res = handleToKey_.try_emplace(faceID, numArrow_); + + GUDHI_CHECK(res.second, "Zigzag_persistence::insert_face - face already in the complex"); + + // Reduce the boundary of zzsh in the basis of cycles. + // Compute the keys of the faces of the boundary of zzsh. + std::set translatedBoundary; // set maintains the natural order on indices + for (auto b : boundary) { + translatedBoundary.insert(handleToKey_.at(b)); // TODO: add possibilities of coefficients + } + + pers_.insert_face(translatedBoundary, dimension); + } + + /** + * @brief Updates the zigzag persistence diagram after the removal of the given face. + * + * @param faceID ID representing the face to remove. Should be the same than the one used to insert it. + * @param dimension Dimension of the face. + * @param filtrationValue Filtration value associated to the removal. + * Assumed to be larger or equal to previously used filtration values. + */ + void remove_face(face_key faceID, dimension_type dimension, filtration_value filtrationValue) { + ++numArrow_; + + if (dimMax_ != -1 && dimension > dimMax_) { + pers_.apply_identity(); + return; + } + + auto it = handleToKey_.find(faceID); + GUDHI_CHECK(it != handleToKey_.end(), "Zigzag_persistence::remove_face - face not in the complex"); + + if (filtrationValue != previousFiltrationValue_) // check whether the filt value has changed + { // consecutive pairs (i,f), (j,f') mean faces of index k in [i,j-1] have + previousFiltrationValue_ = filtrationValue; // filtration value f + filtrationValues_.emplace_back(numArrow_, previousFiltrationValue_); + } + + pers_.remove_face(it->second, dimension); + handleToKey_.erase(it); + } + + /** + * @brief To use when a face is neither inserted nor removed, but the filtration moves along the identity operator + * on homology level. Useful to keep the birth/death indices aligned when insertions/removals are purposly skipped + * to avoid useless computation. + */ + void apply_identity() { + ++numArrow_; + pers_.apply_identity(); + } + + /** + * @brief Returns the "index persistence diagram" of the current filtration, that is, the pairs of atomic arrow + * numbers corresponding to a birth-death pair. Does not contain points at infinity, only the cycle classes which + * already died are represented. + * + * @return Reference to the list of intervals. + */ + const std::vector& get_index_persistence_diagram() const { return persistenceDiagram_; } + + /** + * @brief Returns the filtration values \f$[f(b),f(d)]\f$ associated to the indices \f$[b,d]\f$ which are retrieved + * by @ref get_index_persistence_diagram. + * + * @param birthKey Birth index + * @param deathKey Death index + * @return A pair of filtration values associated to the given indices. + */ + std::pair map_index_to_filtration_value(internal_key birthKey, + internal_key deathKey) const { + // filtration_values_ must be sorted by increasing keys. + auto itBirth = // lower_bound(x) returns leftmost y s.t. x <= y + std::lower_bound( + filtrationValues_.begin(), filtrationValues_.end(), + std::pair(birthKey, std::numeric_limits::infinity()), + [](std::pair p1, std::pair p2) { + return p1.first < p2.first; + }); + if (itBirth == filtrationValues_.end() || itBirth->first > birthKey) { + --itBirth; + } + // it points to the rightmost z such that z <= x + + auto itDeath = // + std::lower_bound( + filtrationValues_.begin(), filtrationValues_.end(), + std::pair(deathKey, std::numeric_limits::infinity()), + [](std::pair p1, std::pair p2) { + return p1.first < p2.first; + }); + if (itDeath == filtrationValues_.end() || itDeath->first > deathKey) { + --itDeath; + } + + return std::make_pair(itBirth->second, itDeath->second); + } + + /** + * @brief Returns the current persistence diagram. + * + * @param shortestInterval Threshold. Every bar shorter than the given value will be ignored. Default value: 0. + * @param includeInfinitBars If set to true, infinit bars are included in the diagram. Default value: false. + * @return A vector of pairs of filtration values representing the persistence diagram. + */ + std::vector get_persistence_diagram(filtration_value shortestInterval = 0., + bool includeInfinitBars = false) { + std::vector diag = _get_persistence_diagram(shortestInterval); + + if (includeInfinitBars) { + _retrieve_infinit_bars(diag); + } + + return diag; + } + + private: + std::unordered_map handleToKey_; /**< Map from input keys to internal keys. */ + dimension_type dimMax_; /**< Maximal dimension of a bar to record. */ + std::vector persistenceDiagram_; /**< Stores current closed persistence intervals. */ + internal_key numArrow_; /**< Current arrow number. */ + filtration_value previousFiltrationValue_; /**< Filtration value of the previous arrow. */ + /** + * @brief filtrationValues_ stores consecutive pairs (i,f) , (j,f') with f != f', + * meaning that all inserted faces with key in [i;j-1] have filtration value f, + * i is the smallest face index whose face has filtration value f. + */ + std::vector > filtrationValues_; + Zigzag_persistence pers_; /**< Class computing the pairs. */ + + /** + * @brief Returns the current persistence diagram without infinit bars. + * + * @param shortestInterval Intervals shorter than the given value are ignored. + * @return Vector of intervals. + */ + std::vector _get_persistence_diagram(filtration_value shortestInterval) { + std::vector diag; + diag.reserve(persistenceDiagram_.size()); + + std::stable_sort(filtrationValues_.begin(), filtrationValues_.end(), + [](std::pair p1, std::pair p2) { + return p1.first < p2.first; + }); + + for (auto bar : persistenceDiagram_) { + filtration_value birth, death; + std::tie(birth, death) = map_index_to_filtration_value(bar.birth(), bar.death()); + if (birth > death) { + std::swap(birth, death); + } + + if (death - birth > shortestInterval) { + diag.emplace_back(bar.dim(), birth, death); + } + } + + return diag; + } + + /** + * @brief Computes the births of the current essential cycles. + * + * @param diag Reference to vector where to store the infinit bars. + */ + void _retrieve_infinit_bars(std::vector& diag) { + auto birth = [this](internal_key birthKey) { + auto itBirth = // lower_bound(x) returns leftmost y s.t. x <= y + std::lower_bound( + filtrationValues_.begin(), filtrationValues_.end(), + std::pair(birthKey, std::numeric_limits::infinity()), + [](std::pair p1, std::pair p2) { + return p1.first < p2.first; + }); + if (itBirth == filtrationValues_.end() || itBirth->first > birthKey) { + --itBirth; + } + return itBirth->second; + }; + + auto stream_infinit_interval = [&](dimension_type dim, internal_key birthIndex) { + if (dimMax_ == -1 || (dimMax_ != -1 && dim < dimMax_)) + diag.emplace_back(dim, birth(birthIndex), std::numeric_limits::infinity()); + }; + + pers_.get_current_infinit_intervals(stream_infinit_interval); + } +}; // end class Filtered_zigzag_persistence_with_storage + +/** + * @ingroup zigzag_persistence + * + * @brief Class computating the zigzag persistent homology of a zigzag filtration. Algorithm based on \cite zigzag. + * + * @tparam FilteredZigzagOptions Structure following the @ref FilteredZigzagOptions concept. + * Default value: @ref Default_filtered_zigzag_options. + */ +template +class Filtered_zigzag_persistence { + public: + using Options = FilteredZigzagOptions; /**< Zigzag options. */ + using internal_key = typename Options::internal_key; /**< Key and index type, has to be signed. */ + using face_key = typename Options::face_key; /**< Face ID type from external inputs. */ + using filtration_value = typename Options::filtration_value; /**< Type for filtration values. */ + using dimension_type = typename Options::dimension_type; /**< Type for dimension values. */ + + /** + * @brief Constructor. + * @details After construction of the class, the zigzag filtration should be given in a streaming like way, i.e., + * call @ref insert_face, @ref remove_face or @ref apply_identity for each step of the filtration in order of + * the filtration. The bars of the diagram are retrieved via the given callback method every time + * a pair with non-zero length is closed. To retrieve the open/infinit bars, use @ref get_current_infinit_intervals. + * + * @param stream_interval Callback method to process the birth and death values of a persistence bar. + * Has to take three arguments as input: first the dimension of the cycle, then the birth value of the cycle + * and third the death value of the cycle. The values corresponds to the filtration values which were given at + * insertions or removals. + * @param minNumberOfFaces Minimum number of faces that will be in a complex at some point in the filtration. + * If the maximal number of faces is known in advance, the memory allocation can be better optimized. + * Default value: 0. + */ + Filtered_zigzag_persistence(std::function stream_interval, + unsigned int minNumberOfFaces = 0) + : handleToKey_(minNumberOfFaces), + numArrow_(-1), + keyToFiltrationValue_(minNumberOfFaces), + stream_interval_(std::move(stream_interval)), + pers_( + [&](dimension_type dim, internal_key birth, internal_key death) { + auto itB = keyToFiltrationValue_.find(birth); + auto itD = keyToFiltrationValue_.find(death); + if (itB->second != itD->second) stream_interval_(dim, itB->second, itD->second); + keyToFiltrationValue_.erase(itB); + keyToFiltrationValue_.erase(itD); + }, + minNumberOfFaces) {} + + /** + * @brief Updates the zigzag persistence diagram after the insertion of the given face. + * + * @tparam BoundaryRange Range type needing begin and end members. + * @param faceID ID representing the inserted face. + * @param boundary Boundary of the inserted face. The range should be composed of the IDs of all faces contained in + * the boundary (i.e. with non-zero coefficients), using the ID specified as `faceID` when the corresponding face + * was previously inserted (recall that the faces should be inserted in order of filtration). + * @param dimension Dimension of the inserted face. + * @param filtrationValue Filtration value associated to the face. + * Assumed to be larger or equal to previously used filtration values. + */ + template > + void insert_face(face_key faceID, + const BoundaryRange& boundary, + dimension_type dimension, + filtration_value filtrationValue) { + ++numArrow_; + + [[maybe_unused]] auto res = handleToKey_.try_emplace(faceID, numArrow_); + + GUDHI_CHECK(res.second, "Zigzag_persistence::insert_face - face already in the complex"); + + keyToFiltrationValue_.try_emplace(numArrow_, filtrationValue); + + // Reduce the boundary of zzsh in the basis of cycles. + // Compute the keys of the faces of the boundary of zzsh. + std::set translatedBoundary; // set maintains the natural order on indices + for (auto b : boundary) { + translatedBoundary.insert(handleToKey_.at(b)); // TODO: add possibilities of coefficients + } + + pers_.insert_face(translatedBoundary, dimension); + } + + /** + * @brief Updates the zigzag persistence diagram after the removal of the given face. + * + * @param faceID ID representing the face to remove. Should be the same than the one used to insert it. + * @param dimension Dimension of the face. + * @param filtrationValue Filtration value associated to the removal. + * Assumed to be larger or equal to previously used filtration values. + */ + void remove_face(face_key faceID, dimension_type dimension, filtration_value filtrationValue) { + ++numArrow_; + + auto it = handleToKey_.find(faceID); + GUDHI_CHECK(it != handleToKey_.end(), "Zigzag_persistence::remove_face - face not in the complex"); + + keyToFiltrationValue_.try_emplace(numArrow_, filtrationValue); + + pers_.remove_face(it->second, dimension); + handleToKey_.erase(it); + } + + /** + * @brief To use when a face is neither inserted nor removed, but the filtration moves along the identity operator + * on homology level. Useful to keep the birth/death indices aligned when insertions/removals are purposly skipped + * to avoid useless computation. + */ + void apply_identity() { + ++numArrow_; + pers_.apply_identity(); + } + + /** + * @brief Outputs through the given callback method all current infinit bars. + * + * @tparam F Type of the callback method. Takes two arguments: the dimension of the cycle and the birth value + * of the cycle. + * @param stream_infinit_interval Method processing the unpaired birth values. + */ + template + void get_current_infinit_intervals(F&& stream_infinit_interval) { + pers_.get_current_infinit_intervals( + [&](dimension_type dim, internal_key birth) { stream_infinit_interval(dim, keyToFiltrationValue_.at(birth)); }); + } + + private: + template + using dictionnary = std::unordered_map; // TODO: benchmark with other map types + + dictionnary handleToKey_; /**< Map from input keys to internal keys. */ + internal_key numArrow_; /**< Current arrow number. */ + dictionnary keyToFiltrationValue_; /**< Face Key to filtration value map. */ + std::function stream_interval_; /**< Callback method for finite bars. */ + Zigzag_persistence pers_; /**< Class computing the pairs. */ +}; // end class Filtered_zigzag_persistence + +} // namespace zigzag_persistence +} // namespace Gudhi + +#endif // FILTERED_ZIGZAG_PERSISTENCE_H_ diff --git a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h index c3b02d50d2..651f9bbf2d 100644 --- a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h @@ -7,6 +7,7 @@ * Modification(s): * - 2023/05 Hannah Schreiber: Rework of the interface, reorganization and debug * - 2023/05 Hannah Schreiber: Addition of infinit bars + * - 2024/06 Hannah Schreiber: Separation of the zigzag algorithm from the filtration value management * - YYYY/MM Author: Description of the modification */ @@ -20,22 +21,21 @@ #define ZIGZAG_PERSISTENCE_H_ #include -#include -#include #include #include #include #include -#include #include namespace Gudhi { namespace zigzag_persistence { /** + * @ingroup zigzag_persistence + * * @brief Options for the internal matrix of @ref Zigzag_persistence. - * + * * @tparam column_type Column type of the matrix. */ template @@ -50,109 +50,46 @@ struct Zigzag_matrix_options : Gudhi::persistence_matrix::Default_options -class Zigzag_persistence { +template +class Zigzag_persistence +{ public: - using Options = ZigzagOptions; /**< Zigzag options. */ - using Matrix_options = Zigzag_matrix_options; /**< Matrix options. */ - using internal_key = typename Options::internal_key; /**< Key and index type, has to be signed. */ - using face_key = typename Options::face_key; /**< Face ID type from external inputs. */ - using filtration_value = typename Options::filtration_value; /**< Type for filtration values. */ - using dimension_type = typename Options::dimension_type; /**< Type for dimension values. */ - - /** \brief Structure to store persistence intervals by their index values. - * - * \details By convention, interval [b;d] are - * closed for finite indices b and d, and open for left-infinite and/or - * right-infinite endpoints. - */ - template - struct Interval { - Interval() {} - Interval(int dim, value_type b, value_type d) : dim_(dim), b_(b), d_(d) {} - /** Returns the dimension of the homological feature corresponding to the interval. */ - int dim() const { return dim_; } - /** Returns the birth value of the interval.*/ - value_type birth() const { return b_; } - /** Returns the death value of the interval.*/ - value_type death() const { return d_; } - - protected: - int dim_; /**< Homological dimension. */ - value_type b_; /**< Value associated to the interval birth. */ - value_type d_; /**< Value associated to the interval death. */ - }; - using Index_interval = Interval; - - /** \brief Structure to store persistence intervals by their filtration values. - * - * \details By convention, interval \f$[b;d]\f$ are - * closed for finite indices b and d, and open for left-infinite and/or - * right-infinite endpoints. - */ - struct Filtration_value_interval : Interval { - private: - using Base = Interval; - - public: - /** - * @brief Default constructor - */ - Filtration_value_interval() : Base() {} - /** - * @brief Construct a new interval with given parameters - * - * @param dim Dimension of the interval. - * @param b Start value of the interval. - * @param d End value of the interval. - */ - Filtration_value_interval(int dim, filtration_value b, filtration_value d) : Base(dim, b, d) {} - - /** - * @brief Returns the absolute length of the interval \f$|d-b|\f$. - */ - filtration_value length() const { - if (Base::b_ == Base::d_) { - return 0; - } // otherwise inf - inf would return nan. - return Base::d_ - Base::b_; - } - /** - * @brief Returns the absolute length of the log values of birth and death, i.e. \f$|\log d - \log b|\f$. - */ - filtration_value log_length() const { - if (Base::b_ == Base::d_) { - return 0; - } // otherwise inf - inf would return nan. - return std::log2(static_cast(Base::d_)) - std::log2(static_cast(Base::b_)); - } - }; + using Options = ZigzagOptions; /**< Zigzag options. */ + using index = typename Options::internal_key; /**< Key and index type, has to be signed. */ + using dimension_type = typename Options::dimension_type; /**< Type for dimension values. */ private: + using birth_dictionnary = std::unordered_map; /**< Dictionnary type. */ + using Matrix_options = Zigzag_matrix_options; /**< Matrix options. */ + using Matrix_type = Gudhi::persistence_matrix::Matrix; /**< Matrix. */ + using matrix_index = typename Matrix_type::index; /**< Matrix indexation type. */ + /** \brief Maintains the birth ordering \f$\leq_b\f$. * * \details Contains a map of size the number of @@ -183,10 +120,10 @@ class Zigzag_persistence { * When the arrow key-1 -> key is forward, key is larger than any other index * i < key in the birth ordering b k2. * @@ -224,213 +161,130 @@ class Zigzag_persistence { * @param k2 * @return true if k1 >b k2, false otherwise. */ - bool reverse_birth_order(internal_key k1, internal_key k2) const { - return birthToPos_.at(k1) > birthToPos_.at(k2); - } + bool reverse_birth_order(index k1, index k2) const { return birthToPos_.at(k1) > birthToPos_.at(k2); } private: - std::unordered_map birthToPos_; /**< birth_to_pos_[i] < birth_to_pos_[j] iff i ; - using index = typename Matrix_type::index; - public: /** * @brief Constructor of the Zigzag_persistence class. * @details After construction of the class, the zigzag filtration should be given in a streaming like way, i.e., - * call @ref insert_face or @ref remove_face for each step of the filtration in order of the filtration. - * To retrieve the current persistence diagram at any moment of the filtration, - * use @ref get_persistence_diagram or @ref get_index_persistence_diagram. + * call @ref insert_face, @ref remove_face or @ref apply_identity for each step of the filtration in order of + * the filtration. The pairs of birth and death indices are retrieved via the given callback method every time + * a pair is closed. To retrieve the open pairs (corresponding to infinit bars), + * use @ref get_current_infinit_intervals. * - * @param minNumberOfFaces Minimum number of faces that will be inserted at some point in the filtration. - * If the total number of faces is known in advance, the memory allocation can be better optimized. + * @param stream_interval Callback method to process the birth and death index pairs. Has to take three arguments + * as input: first the dimension of the cycle, then the birth index of the cycle and third the death index of the + * cycle. An index always corresponds to the arrow number the event occured (one call to @ref insert_face, + * @ref remove_face or @ref apply_identity is equal to one arrow and increases the arrow count by one). + * @param minNumberOfFaces Minimum number of faces that will be in a complex at some point in the filtration. + * If the maximal number of faces is known in advance, the memory allocation can be better optimized. * Default value: 0. - * @param ignoreCyclesAboveDim Ignores cycles in dimension larger or equal in the final diagram. - * If -1, no cycles are ignored. Default value: -1. */ - Zigzag_persistence(unsigned int minNumberOfFaces = 0, int ignoreCyclesAboveDim = -1) - : dimMax_(ignoreCyclesAboveDim), - matrix_( + Zigzag_persistence(std::function stream_interval, + unsigned int minNumberOfFaces = 0) + : matrix_( minNumberOfFaces, - [this](index columnIndex1, index columnIndex2) -> bool { + [this](matrix_index columnIndex1, matrix_index columnIndex2) -> bool { if (matrix_.get_column(columnIndex1).is_paired()) { return matrix_.get_pivot(columnIndex1) < matrix_.get_pivot(columnIndex2); } return birthOrdering_.birth_order(births_.at(columnIndex1), births_.at(columnIndex2)); }, - [this](index columnIndex1, index columnIndex2) -> bool { return false; }), + [this](matrix_index columnIndex1, matrix_index columnIndex2) -> bool { return false; }), numArrow_(-1), - previousFiltrationValue_(std::numeric_limits::infinity()) {} - + stream_interval_(std::move(stream_interval)) {} /** * @brief Updates the zigzag persistence diagram after the insertion of the given face. - * + * * @tparam BoundaryRange Range type needing begin and end members. - * @param faceID ID representing the inserted face. - * @param boundary Boundary of the inserted face. The range should be composed of the IDs of all faces contained in - * the boundary (i.e. with non-zero coefficients), using the ID specified as `faceID` when the corresponding face - * was previously inserted (recall that the faces should be inserted in order of filtration). + * @param boundary Boundary of the inserted face. The boundary should be represented by all the faces with + * non-zero coefficients generating it. A face should be represented by the arrow number when the face appeared for + * the first time in the filtration (if a face was inserted and then removed and reinserted etc., only the last + * insertion counts). The face range should be ordered by increasing arrow numbers. * @param dimension Dimension of the inserted face. - * @param filtrationValue Filtration value associated to the face. - * Assumed to be larger or equal to previously used filtration values. */ - template > - void insert_face(face_key faceID, - const BoundaryRange& boundary, - dimension_type dimension, - filtration_value filtrationValue) { - if (dimMax_ != -1 && dimension > dimMax_) return; - + template > + void insert_face(const BoundaryRange& boundary, dimension_type dimension) { ++numArrow_; - - //TODO: to make it really stream like, we should stream out finished bars and remove unnecessary filtration values - //from memory. - if (filtrationValue != previousFiltrationValue_) // check whether the filt value has changed - { // consecutive pairs (i,f), (j,f') mean faces of index k in [i,j-1] have - previousFiltrationValue_ = filtrationValue; // filtration value f - filtrationValues_.emplace_back(numArrow_, previousFiltrationValue_); - } - - [[maybe_unused]] auto res = handleToKey_.try_emplace(faceID, numArrow_); - - GUDHI_CHECK(res.second, "Zigzag_persistence::insert_face - face already in the complex"); - - // Reduce the boundary of zzsh in the basis of cycles. - // Compute the keys of the faces of the boundary of zzsh. - std::set col_bsh; // set maintains the natural order on indices - for (auto b_sh : boundary) { - col_bsh.insert(handleToKey_.at(b_sh)); // TODO: add possibilities of coefficients - } - - _process_forward_arrow(col_bsh, dimension); + _process_forward_arrow(boundary, dimension); } /** * @brief Updates the zigzag persistence diagram after the removal of the given face. - * - * @param faceID ID representing the face to remove. Should be the same than the one used to insert it. - * @param dimension Dimension of the face. - * @param filtrationValue Filtration value associated to the removal. - * Assumed to be larger or equal to previously used filtration values. + * + * @param arrowNumber Arrow number of when the face to remove was inserted for the last time. + * @param dimension Dimension of the face to remove. */ - void remove_face(face_key faceID, dimension_type dimension, filtration_value filtrationValue) { - if (dimMax_ != -1 && dimension > dimMax_) return; - + void remove_face(index arrowNumber, dimension_type dimension) { ++numArrow_; - - auto it = handleToKey_.find(faceID); - GUDHI_CHECK(it != handleToKey_.end(), "Zigzag_persistence::remove_face - face not in the complex"); - - if (filtrationValue != previousFiltrationValue_) // check whether the filt value has changed - { // consecutive pairs (i,f), (j,f') mean faces of index k in [i,j-1] have - previousFiltrationValue_ = filtrationValue; // filtration value f - filtrationValues_.emplace_back(numArrow_, previousFiltrationValue_); - } - - _process_backward_arrow(it->second, dimension); - handleToKey_.erase(it); + _process_backward_arrow(arrowNumber, dimension); } /** - * @brief Returns the "index persistence diagram" of the current filtration, that is, the pairs of atomic arrow - * numbers corresponding to a birth-death pair. Does not contain points at infinity, only the cycle classes which - * already died are represented. - * - * @return Reference to the list of intervals. - */ - const std::vector& get_index_persistence_diagram() const { return persistenceDiagram_; } - - /** - * @brief Returns the filtration values \f$[f(b),f(d)]\f$ associated to the indices \f$[b,d]\f$ which are retrieved - * by @ref get_index_persistence_diagram. - * - * @param birthKey Birth index - * @param deathKey Death index - * @return A pair of filtration values associated to the given indices. + * @brief To use when a face is neither inserted nor removed, but the filtration moves along the identity operator + * on homology level. Useful to keep the birth/death indices aligned when insertions/removals are purposly skipped + * to avoid useless computation. Increases the arrow number by one. */ - std::pair map_index_to_filtration_value(internal_key birthKey, - internal_key deathKey) const { - // filtration_values_ must be sorted by increasing keys. - auto itBirth = // lower_bound(x) returns leftmost y s.t. x <= y - std::lower_bound( - filtrationValues_.begin(), filtrationValues_.end(), - std::pair(birthKey, std::numeric_limits::infinity()), - [](std::pair p1, std::pair p2) { - return p1.first < p2.first; - }); - if (itBirth == filtrationValues_.end() || itBirth->first > birthKey) { - --itBirth; - } - // it points to the rightmost z such that z <= x - - auto itDeath = // - std::lower_bound( - filtrationValues_.begin(), filtrationValues_.end(), - std::pair(deathKey, std::numeric_limits::infinity()), - [](std::pair p1, std::pair p2) { - return p1.first < p2.first; - }); - if (itDeath == filtrationValues_.end() || itDeath->first > deathKey) { - --itDeath; - } - - return std::make_pair(itBirth->second, itDeath->second); - } + void apply_identity() { ++numArrow_; } /** - * @brief Returns the current persistence diagram. - * - * @param shortestInterval Threshold. Every bar shorter than the given value will be ignored. Default value: 0. - * @param includeInfinitBars If set to true, infinit bars are included in the diagram. Default value: false. - * @return A vector of pairs of filtration values representing the persistence diagram. + * @brief Outputs through the given callback method all birth indices which are currently not paired with + * a death index. + * + * @tparam F Type of the callback method. Takes two arguments: the dimension of the cycle and the birth index + * of the cycle. + * @param stream_infinit_interval Method processing the unpaired birth indices. */ - std::vector get_persistence_diagram(filtration_value shortestInterval = 0., - bool includeInfinitBars = false) { - // auto comp = [](Filtration_value_interval p, Filtration_value_interval q) { - // if (p.length() != q.length()) { - // return p.length() > q.length(); - // } // longest 1st - // if (p.dim() != q.dim()) { - // return p.dim() < q.dim(); - // } // lower dimension first - // if (p.birth() != q.birth()) { - // return p.birth() < q.birth(); - // } // lex order - // return p.death() < q.death(); - // }; - - std::vector diag = _get_persistence_diagram(shortestInterval); - - if (includeInfinitBars) { - _retrieve_infinit_bars(diag); + template + void get_current_infinit_intervals(F&& stream_infinit_interval) { + for (auto& p : births_) { + if constexpr (erase_birth_history) { + auto& col = matrix_.get_column(p.first); + stream_infinit_interval(col.get_dimension(), p.second); + } else { + try { + auto& col = matrix_.get_column(p.first); + if (!col.is_paired()) { + stream_infinit_interval(col.get_dimension(), p.second); + } + } catch (const std::out_of_range& e) { + continue; + } + } } - - // std::stable_sort(diag.begin(), diag.end(), comp); - - return diag; } private: - /** * @brief Express the boundary cycle of the new face as a sum of cycles in a matrix. * If some cycles are not boundary cycles, i.e., columns with F-index * in the matrix, it applies a surjective diamond to the zigzag module. - * + * * @param boundary Boundary of the inserted face. * @param dim Dimension of the inserted face. */ - void _process_forward_arrow(const std::set& boundary, dimension_type dim) { - std::vector chainsInF = matrix_.insert_boundary(numArrow_, boundary); + template + void _process_forward_arrow(const BoundaryRange& boundary, dimension_type dim) { + std::vector chainsInF = matrix_.insert_boundary(numArrow_, boundary); if (!chainsInF.empty()) { _apply_surjective_reflection_diamond(dim, chainsInF); } else { birthOrdering_.add_birth_forward(numArrow_); - births_.emplace_hint(births_.end(), matrix_.get_column_with_pivot(numArrow_), numArrow_); + if constexpr (erase_birth_history) { + births_.emplace_hint(births_.end(), matrix_.get_column_with_pivot(numArrow_), numArrow_); + } else { + auto res = births_.try_emplace(matrix_.get_column_with_pivot(numArrow_), numArrow_); + if (!res.second) { + res.first->second = numArrow_; + } + } } } @@ -441,11 +295,11 @@ class Zigzag_persistence { * columns corresponding to the chains, due to its computation in the reduction of * the boundary in _process_forward_arrow(...). It is equivalent to decreasing death index * order w.r.t. the & chainsInF) { + void _apply_surjective_reflection_diamond(dimension_type dim, const std::vector& chainsInF) { // fp is the largest death index for <=d // Set col_fp: col_fp <- col_f1+...+col_fp (now in G); preserves lowest idx auto chainFp = chainsInF[0]; // col_fp, with largest death bool { + auto cmp_birth = [this](index k1, index k2) -> bool { return birthOrdering_.reverse_birth_order(k1, k2); }; // true iff b(k1) >b b(k2) // available_birth: for all i by >d value of the d_i, // contains at step i all b_j, j > i, and maybe b_i if not stolen - std::set availableBirth(cmp_birth); + std::set availableBirth(cmp_birth); // for f1 to f_{p} (i by <=d), insertion in available_birth_to_fidx sorts by >=b for (auto& chainF : chainsInF) { availableBirth.insert(births_.at(chainF)); @@ -475,9 +329,9 @@ class Zigzag_persistence { auto lastModifiedChainIt = chainsInF.rbegin(); // consider all death indices by increasing modifiedColumns; + std::vector modifiedColumns; const auto& row = matrix_.get_row(faceID); modifiedColumns.reserve(row.size()); std::transform(row.begin(), row.end(), std::back_inserter(modifiedColumns), [](const auto& cell) { return cell.get_column_index(); }); // Sort by left-to-right order in the matrix_ (no order maintained in rows) - std::stable_sort(modifiedColumns.begin(), modifiedColumns.end(), - [this](index i1, index i2) { return matrix_.get_pivot(i1) < matrix_.get_pivot(i2); }); + std::stable_sort(modifiedColumns.begin(), modifiedColumns.end(), [this](matrix_index i1, matrix_index i2) { + return matrix_.get_pivot(i1) < matrix_.get_pivot(i2); + }); // Modifies curr_col, not the other one. for (auto otherColIt = std::next(modifiedColumns.begin()); otherColIt != modifiedColumns.end(); ++otherColIt) { @@ -547,98 +403,37 @@ class Zigzag_persistence { // curr_col points to the column to remove by restriction of K to K-{\sigma} if (!matrix_.get_column(currCol).is_paired()) { // in F auto it = births_.find(currCol); - if (dimMax_ == -1 || (dimMax_ != -1 && dim < dimMax_)) { // don't record intervals over max dim - persistenceDiagram_.emplace_back(dim, it->second, numArrow_); + stream_interval_(dim, it->second, numArrow_); + if constexpr (erase_birth_history) { + birthOrdering_.remove_birth(it->second); + births_.erase(it); } - // Following value can be erased, but it slowes the process down a bit, so I keep it as a remainder for now: - // birthOrdering_.remove_birth(it->second); - births_.erase(it); } else { // in H -> paired with c_g, that now belongs to F now // maintain the <=b order birthOrdering_.add_birth_backward(numArrow_); - births_.try_emplace(matrix_.get_column(currCol).get_paired_chain_index(), numArrow_); - } - - // cannot be in G as the removed face is maximal - matrix_.remove_maximal_face(faceID, {}); - } - - /** - * @brief Returns the current persistence diagram ordered by length without infinit bars. - * - * @param shortestInterval Intervals shorter than the given value are ignored. - * @return Vector of intervals. - */ - std::vector _get_persistence_diagram(filtration_value shortestInterval) { - std::vector diag; - diag.reserve(persistenceDiagram_.size()); - - std::stable_sort(filtrationValues_.begin(), filtrationValues_.end(), - [](std::pair p1, std::pair p2) { - return p1.first < p2.first; - }); - - for (auto bar : persistenceDiagram_) { - filtration_value birth, death; - std::tie(birth, death) = map_index_to_filtration_value(bar.birth(), bar.death()); - if (birth > death) { - std::swap(birth, death); - } - - if (death - birth > shortestInterval) { - diag.emplace_back(bar.dim(), birth, death); + if constexpr (erase_birth_history) { + births_.try_emplace(matrix_.get_column(currCol).get_paired_chain_index(), numArrow_); + } else { + auto res = births_.try_emplace(matrix_.get_column(currCol).get_paired_chain_index(), numArrow_); + if (!res.second) { + res.first->second = numArrow_; + } } } - return diag; - } - - /** - * @brief Computes the births of the current essential cycles. - * - * @param diag Reference to vector where to store the infinit bars. - */ - void _retrieve_infinit_bars(std::vector& diag) const { - auto birth = [this](internal_key birthKey) { - auto itBirth = // lower_bound(x) returns leftmost y s.t. x <= y - std::lower_bound( - filtrationValues_.begin(), filtrationValues_.end(), - std::pair(birthKey, std::numeric_limits::infinity()), - [](std::pair p1, std::pair p2) { - return p1.first < p2.first; - }); - if (itBirth == filtrationValues_.end() || itBirth->first > birthKey) { - --itBirth; - } - return itBirth->second; - }; - - for (auto& p : births_) { - auto dim = matrix_.get_column(matrix_.get_column_with_pivot(p.first)).get_dimension(); - if (dimMax_ == -1 || (dimMax_ != -1 && dim < dimMax_)) - diag.emplace_back(dim, birth(p.second), std::numeric_limits::infinity()); - } + // cannot be in G as the removed face is maximal + matrix_.remove_maximal_face(faceID, {}); // also unpaires c_g if in H } private: - std::unordered_map handleToKey_; /**< Map from input keys to internal keys. */ - dimension_type dimMax_; /**< Maximal dimension of a bar to record. */ - Matrix_type matrix_; /**< Matrix storing a base of the current chain complex. */ - std::unordered_map births_; /**< Map face index in F to corresponding birth. */ - Birth_ordering birthOrdering_; /**< Maintains persistenceDiagram_; /**< Stores current closed persistence intervals. */ - internal_key numArrow_; /**< Current arrow number. */ - filtration_value previousFiltrationValue_; /**< Filtration value of the previous arrow. */ - /** - * @brief filtrationValues_ stores consecutive pairs (i,f) , (j,f') with f != f', - * meaning that all inserted faces with key in [i;j-1] have filtration value f, - * i is the smallest face index whose face has filtration value f. - */ - std::vector > filtrationValues_; + Matrix_type matrix_; /**< Matrix storing a base of the current chain complex. */ + birth_dictionnary births_; /**< Map face index in F to corresponding birth. */ + Birth_ordering birthOrdering_; /**< Maintains stream_interval_; /**< Callback method for closed pairs. */ }; // end class Zigzag_persistence } // namespace zigzag_persistence - } // namespace Gudhi #endif // ZIGZAG_PERSISTENCE_H_ diff --git a/src/Zigzag_persistence/test/CMakeLists.txt b/src/Zigzag_persistence/test/CMakeLists.txt index c5be1da0a9..b14024ad1d 100644 --- a/src/Zigzag_persistence/test/CMakeLists.txt +++ b/src/Zigzag_persistence/test/CMakeLists.txt @@ -2,10 +2,11 @@ project(Zigzag_persistence_tests) include(GUDHI_boost_test) -add_executable ( Zigzag_persistence_unit_test zigzag_persistence_unit_test.cpp ) -if(TARGET TBB::tbb) - target_link_libraries(Zigzag_persistence_unit_test TBB::tbb) -endif() - +add_executable_with_targets(Zigzag_persistence_unit_test zigzag_persistence_unit_test.cpp TBB::tbb) gudhi_add_boost_test(Zigzag_persistence_unit_test) +add_executable_with_targets(Filtered_zigzag_persistence_unit_test filtered_zigzag_persistence_unit_test.cpp TBB::tbb) +gudhi_add_boost_test(Filtered_zigzag_persistence_unit_test) + + + diff --git a/src/Zigzag_persistence/test/filtered_zigzag_persistence_unit_test.cpp b/src/Zigzag_persistence/test/filtered_zigzag_persistence_unit_test.cpp new file mode 100644 index 0000000000..20d28c72b8 --- /dev/null +++ b/src/Zigzag_persistence/test/filtered_zigzag_persistence_unit_test.cpp @@ -0,0 +1,477 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Hannah Schreiber + * + * Copyright (C) 2023 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +#include +#include +#include + +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE "zigzag_persistence" +#include + +#include + +struct cmp_intervals_by_length { + cmp_intervals_by_length() {} + template + bool operator()(const Interval_filtration& p, const Interval_filtration& q) { + if (p.length() != q.length()) { + return p.length() > q.length(); + } + if (p.dim() != q.dim()) { + return p.dim() < q.dim(); + } + if (p.birth() != q.birth()) { + return p.birth() < q.birth(); + } + return p.death() < q.death(); + } +}; + +BOOST_AUTO_TEST_CASE(constructor) { + using ZP1 = Gudhi::zigzag_persistence::Filtered_zigzag_persistence_with_storage<>; + BOOST_CHECK_NO_THROW(ZP1 zp); + BOOST_CHECK_NO_THROW(ZP1 zp(28)); + BOOST_CHECK_NO_THROW(ZP1 zp(28, 2)); + ZP1 zp1; + BOOST_CHECK(zp1.get_persistence_diagram(0).empty()); + + using ZP2 = Gudhi::zigzag_persistence::Filtered_zigzag_persistence<>; + std::vector > pairs; + auto stream = [&](int dim, double birth, double death){ pairs.emplace_back(dim, birth, death); }; + BOOST_CHECK_NO_THROW(ZP2 zp(stream)); + BOOST_CHECK_NO_THROW(ZP2 zp(stream, 28)); + + ZP2 zp2(stream); + BOOST_CHECK(pairs.empty()); +} + +template +void test_barcode(ZP& zp, std::vector& barcode) { + auto bars = zp.get_persistence_diagram(0, true); + std::stable_sort(bars.begin(), bars.end(), cmp_intervals_by_length()); + std::stable_sort(barcode.begin(), barcode.end(), cmp_intervals_by_length()); + auto it = barcode.begin(); + for (const auto& interval : bars) { + BOOST_CHECK_EQUAL(interval.dim(), it->dim()); + BOOST_CHECK_EQUAL(interval.birth(), it->birth()); + BOOST_CHECK_EQUAL(interval.death(), it->death()); + ++it; + } + BOOST_CHECK(it == barcode.end()); +} + +template +void test_indices(ZP& zp, std::vector& indices, + std::vector& indexToFil) { + auto it = indices.begin(); + for (const auto& interval : zp.get_index_persistence_diagram()) { + BOOST_CHECK_EQUAL(interval.dim(), it->dim()); + BOOST_CHECK_EQUAL(interval.birth(), it->birth()); + BOOST_CHECK_EQUAL(interval.death(), it->death()); + auto p = zp.map_index_to_filtration_value(interval.birth(), interval.death()); + BOOST_CHECK_EQUAL(p.first, indexToFil[interval.birth()]); + BOOST_CHECK_EQUAL(p.second, indexToFil[interval.death()]); + ++it; + } + BOOST_CHECK(it == indices.end()); +} + +std::vector > get_boundaries() { + return {{}, + {}, + {}, + {0, 1}, + {0, 2}, + {}, + {1, 2}, + {}, + {5, 7}, + {}, + {3, 4, 6}, + {7, 9}, + {5, 9}, + {8, 11, 12}, + {10}, // remove + {13}, // remove + {1, 7}, + {3, 4, 6}, + {2, 7}, + {8, 11, 12}, + {0, 7}, + {4, 18, 20}, + {6, 16, 18}, + {3, 16, 20}, + {19}, // remove + {8}, // remove + {12}, // remove + {17, 21, 22, 23}, + {27}}; // remove +} + +std::vector get_filtration_values() { + return {0, 0, 0, + 1, 1, 1, + 2, 2, 2, + 3, 3, 3, 3, + 4, + 5, + 6, 6, 6, + 7, 7, 7, 7, 7, 7, + 8, + 9, 9, 9, + 10}; +} + +template +void test_filtered_zigzag_with_storage() { + using face_handle = typename ZP::face_key; + using filtration_value = typename ZP::filtration_value; + using Interval_index = typename ZP::Index_interval; + using Interval_filtration = typename ZP::Filtration_value_interval; + + ZP zp(28); + std::vector realIndices; + std::vector realBarcode; + realIndices.reserve(13); + realBarcode.reserve(9); + + std::vector > simplices = get_boundaries(); + std::vector filValues = get_filtration_values(); + + for (unsigned int i = 0; i < 14; ++i) { + zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); + } + + realIndices.emplace_back(0, 1, 3); + realIndices.emplace_back(0, 2, 4); + realIndices.emplace_back(0, 7, 8); + realIndices.emplace_back(1, 6, 10); + realIndices.emplace_back(0, 9, 11); + realIndices.emplace_back(1, 12, 13); + + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(1, 2, 3); + realBarcode.emplace_back(1, 3, 4); + + for (unsigned int i = 14; i < 16; ++i) { + auto id = simplices[i][0]; + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + } + + for (unsigned int i = 16; i < 24; ++i) { + zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); + } + + realIndices.emplace_back(0, 5, 16); + realIndices.emplace_back(1, 14, 17); + realIndices.emplace_back(1, 15, 19); + realIndices.emplace_back(1, 20, 21); + realIndices.emplace_back(1, 18, 22); + + realBarcode.emplace_back(0, 1, 6); + realBarcode.emplace_back(1, 5, 6); + realBarcode.emplace_back(1, 6, 7); + + for (unsigned int i = 24; i < 27; ++i) { + auto id = simplices[i][0]; + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + } + + realIndices.emplace_back(1, 24, 25); + realBarcode.emplace_back(1, 8, 9); + + zp.insert_face(27, simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1, filValues[27]); + + realIndices.emplace_back(2, 23, 27); + realBarcode.emplace_back(2, 7, 9); + + auto id = simplices[28][0]; + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[28]); + + realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); + realBarcode.emplace_back(2, 10, std::numeric_limits::infinity()); + + test_indices(zp, realIndices, filValues); + test_barcode(zp, realBarcode); +} + +template +void test_filtered_zigzag_with_storage_max1() { + using face_handle = typename ZP::face_key; + using filtration_value = typename ZP::filtration_value; + using Interval_index = typename ZP::Index_interval; + using Interval_filtration = typename ZP::Filtration_value_interval; + + ZP zp(28, 1); + std::vector realIndices; + std::vector realBarcode; + realIndices.reserve(5); + realBarcode.reserve(3); + + std::vector > simplices = get_boundaries(); + std::vector filValues = get_filtration_values(); + + for (unsigned int i = 0; i < 14; ++i) { + zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); + } + + realIndices.emplace_back(0, 1, 3); + realIndices.emplace_back(0, 2, 4); + realIndices.emplace_back(0, 7, 8); + realIndices.emplace_back(0, 9, 11); + + realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back(0, 0, 1); + + for (unsigned int i = 14; i < 16; ++i) { + auto id = simplices[i][0]; + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + } + + for (unsigned int i = 16; i < 24; ++i) { + zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); + } + + realIndices.emplace_back(0, 5, 16); + realBarcode.emplace_back(0, 1, 6); + + for (unsigned int i = 24; i < 27; ++i) { + auto id = simplices[i][0]; + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + } + + zp.insert_face(27, simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1, filValues[27]); + auto id = simplices[28][0]; + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[28]); + + realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); + + test_indices(zp, realIndices, filValues); + test_barcode(zp, realBarcode); +} + +BOOST_AUTO_TEST_CASE(filtered_zigzag_persistence_with_storage) { + test_filtered_zigzag_with_storage >(); + test_filtered_zigzag_with_storage_max1 >(); +} + +template +void test_filtered_zigzag() { + using face_handle = typename ZP::face_key; + using filtration_value = typename ZP::filtration_value; + using dimension_type = typename ZP::dimension_type; + using Interval = std::tuple; + + Interval interval; + ZP zp([&](dimension_type dim, filtration_value birth, filtration_value death){ + BOOST_CHECK_EQUAL(std::get<0>(interval), dim); + BOOST_CHECK_EQUAL(std::get<1>(interval), birth); + BOOST_CHECK_EQUAL(std::get<2>(interval), death); + },28); + + std::vector realBarcode; + realBarcode.reserve(28); + realBarcode.emplace_back(3, 0, 0); //dummy + realBarcode.emplace_back(3, 0, 1); //dummy + realBarcode.emplace_back(3, 0, 2); //dummy + realBarcode.emplace_back(0, 0, 1); //1-3 + realBarcode.emplace_back(0, 0, 1); //2-4 + realBarcode.emplace_back(3, 0, 5); //dummy + realBarcode.emplace_back(3, 0, 6); //dummy + realBarcode.emplace_back(3, 0, 7); //dummy + realBarcode.emplace_back(0, 7, 8); //dummy + realBarcode.emplace_back(3, 0, 9); //dummy + realBarcode.emplace_back(1, 2, 3); //6-10 + realBarcode.emplace_back(0, 9, 11); //dummy + realBarcode.emplace_back(3, 0, 12); //dummy + realBarcode.emplace_back(1, 3, 4); //12-13 + realBarcode.emplace_back(3, 0, 14); //dummy + realBarcode.emplace_back(3, 0, 15); //dummy + realBarcode.emplace_back(0, 1, 6); //5-16 + realBarcode.emplace_back(1, 5, 6); //14-17 + realBarcode.emplace_back(3, 0, 18); //dummy + realBarcode.emplace_back(1, 6, 7); //15-19 + realBarcode.emplace_back(3, 0, 20); //dummy + realBarcode.emplace_back(1, 20, 21); //dummy + realBarcode.emplace_back(1, 18, 22); //dummy + realBarcode.emplace_back(3, 0, 23); //dummy + realBarcode.emplace_back(3, 0, 24); //dummy + realBarcode.emplace_back(1, 8, 9); //24-25 + realBarcode.emplace_back(3, 0, 26); //dummy + realBarcode.emplace_back(2, 7, 9); //23-27 + realBarcode.emplace_back(3, 0, 28); //dummy + + std::vector > simplices = get_boundaries(); + std::vector filValues = get_filtration_values(); + + for (unsigned int i = 0; i < 14; ++i) { + interval = realBarcode[i]; + zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); + } + + for (unsigned int i = 14; i < 16; ++i) { + interval = realBarcode[i]; + auto id = simplices[i][0]; + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + } + + for (unsigned int i = 16; i < 24; ++i) { + interval = realBarcode[i]; + zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); + } + + for (unsigned int i = 24; i < 27; ++i) { + interval = realBarcode[i]; + auto id = simplices[i][0]; + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + } + + interval = realBarcode[27]; + zp.insert_face(27, simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1, filValues[27]); + + interval = realBarcode[28]; + auto id = simplices[28][0]; + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[28]); + + //there is no real garantee on the order of the infinite bars + std::vector infiniteBars; + zp.get_current_infinit_intervals([&](dimension_type dim, filtration_value birth) { + infiniteBars.emplace_back(dim, birth, std::numeric_limits::infinity()); + }); + + realBarcode.clear(); + realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); + realBarcode.emplace_back(2, 10, std::numeric_limits::infinity()); + + std::sort(infiniteBars.begin(), infiniteBars.end()); + std::sort(realBarcode.begin(), realBarcode.end()); + auto it = realBarcode.begin(); + for (const auto& interval : infiniteBars) { + BOOST_CHECK_EQUAL(std::get<0>(interval), std::get<0>(*it)); + BOOST_CHECK_EQUAL(std::get<1>(interval), std::get<1>(*it)); + ++it; + } + BOOST_CHECK(it == realBarcode.end()); +} + +template +void test_filtered_zigzag_max1() { + using face_handle = typename ZP::face_key; + using filtration_value = typename ZP::filtration_value; + using dimension_type = typename ZP::dimension_type; + using Interval = std::tuple; + + Interval interval; + ZP zp([&](dimension_type dim, filtration_value birth, filtration_value death){ + if (dim < 1){ + BOOST_CHECK_EQUAL(std::get<0>(interval), dim); + BOOST_CHECK_EQUAL(std::get<1>(interval), birth); + BOOST_CHECK_EQUAL(std::get<2>(interval), death); + } else { + BOOST_CHECK_NE(std::get<0>(interval), 0); + } + },28); + + std::vector realBarcode; + realBarcode.reserve(28); + realBarcode.emplace_back(1, 0, 0); //dummy + realBarcode.emplace_back(1, 0, 1); //dummy + realBarcode.emplace_back(1, 0, 2); //dummy + realBarcode.emplace_back(0, 0, 1); //1-3 + realBarcode.emplace_back(0, 0, 1); //2-4 + realBarcode.emplace_back(1, 0, 5); //dummy + realBarcode.emplace_back(1, 0, 6); //dummy + realBarcode.emplace_back(1, 0, 7); //dummy + realBarcode.emplace_back(1, 7, 8); //dummy + realBarcode.emplace_back(1, 0, 9); //dummy + realBarcode.emplace_back(1, 2, 3); //6-10 + realBarcode.emplace_back(1, 9, 11); //dummy + realBarcode.emplace_back(1, 0, 12); //dummy + realBarcode.emplace_back(1, 3, 4); //12-13 + realBarcode.emplace_back(1, 0, 14); //dummy + realBarcode.emplace_back(1, 0, 15); //dummy + realBarcode.emplace_back(0, 1, 6); //5-16 + realBarcode.emplace_back(1, 5, 6); //14-17 + realBarcode.emplace_back(1, 0, 18); //dummy + realBarcode.emplace_back(1, 6, 7); //15-19 + realBarcode.emplace_back(1, 0, 20); //dummy + realBarcode.emplace_back(1, 20, 21); //dummy + realBarcode.emplace_back(1, 18, 22); //dummy + realBarcode.emplace_back(1, 0, 23); //dummy + realBarcode.emplace_back(1, 0, 24); //dummy + realBarcode.emplace_back(1, 8, 9); //24-25 + realBarcode.emplace_back(1, 0, 26); //dummy + realBarcode.emplace_back(2, 7, 9); //23-27 + realBarcode.emplace_back(1, 0, 28); //dummy + + std::vector > simplices = get_boundaries(); + std::vector filValues = get_filtration_values(); + + for (unsigned int i = 0; i < 14; ++i) { + interval = realBarcode[i]; + zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); + } + + for (unsigned int i = 14; i < 16; ++i) { + interval = realBarcode[i]; + auto id = simplices[i][0]; + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + } + + for (unsigned int i = 16; i < 24; ++i) { + interval = realBarcode[i]; + zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); + } + + for (unsigned int i = 24; i < 27; ++i) { + interval = realBarcode[i]; + auto id = simplices[i][0]; + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + } + + interval = realBarcode[27]; + zp.insert_face(27, simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1, filValues[27]); + + interval = realBarcode[28]; + auto id = simplices[28][0]; + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[28]); + + //there is no real garantee on the order of the infinite bars + std::vector infiniteBars; + zp.get_current_infinit_intervals([&](dimension_type dim, filtration_value birth) { + if (dim < 1){ + infiniteBars.emplace_back(dim, birth, std::numeric_limits::infinity()); + } + }); + + realBarcode.clear(); + realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); + + std::sort(infiniteBars.begin(), infiniteBars.end()); + std::sort(realBarcode.begin(), realBarcode.end()); + auto it = realBarcode.begin(); + for (const auto& interval : infiniteBars) { + BOOST_CHECK_EQUAL(std::get<0>(interval), std::get<0>(*it)); + BOOST_CHECK_EQUAL(std::get<1>(interval), std::get<1>(*it)); + ++it; + } + BOOST_CHECK(it == realBarcode.end()); +} + +BOOST_AUTO_TEST_CASE(filtered_zigzag_persistence) { + test_filtered_zigzag >(); + test_filtered_zigzag_max1 >(); +} diff --git a/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp b/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp index f1596e714d..e255179150 100644 --- a/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp +++ b/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp @@ -9,7 +9,6 @@ */ #include -#include #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MODULE "zigzag_persistence" @@ -18,96 +17,44 @@ #include using ZP = Gudhi::zigzag_persistence::Zigzag_persistence<>; -using face_handle = ZP::face_key; -using filtration_value = ZP::filtration_value; -using Interval_index = ZP::Index_interval; -using Interval_filtration = ZP::Filtration_value_interval; - -struct cmp_intervals_by_length { - cmp_intervals_by_length() {} - bool operator()(Interval_filtration p, Interval_filtration q) { - if (p.length() != q.length()) { - return p.length() > q.length(); - } - if (p.dim() != q.dim()) { - return p.dim() < q.dim(); - } - if (p.birth() != q.birth()) { - return p.birth() < q.birth(); - } - return p.death() < q.death(); - } +// using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; + +struct Interval { + Interval() {} + Interval(int dim, ZP::index b, ZP::index d) : dim_(dim), b_(b), d_(d) {} + + int dim() const { return dim_; } + int birth() const { return b_; } + int death() const { return d_; } + +private: + int dim_; + ZP::index b_; + ZP::index d_; }; BOOST_AUTO_TEST_CASE(constructor) { - BOOST_CHECK_NO_THROW(ZP zp); - BOOST_CHECK_NO_THROW(ZP zp(28)); - BOOST_CHECK_NO_THROW(ZP zp(28, 2)); - ZP zp; - BOOST_CHECK(zp.get_persistence_diagram(0).empty()); -} + std::vector pairs; + auto stream = [&](int dim, ZP::index birth, ZP::index death){ pairs.emplace_back(dim, birth, death); }; + BOOST_CHECK_NO_THROW(ZP zp(stream)); + BOOST_CHECK_NO_THROW(ZP zp(stream, 28)); -void test_barcode(ZP& zp, std::vector& barcode) { - auto bars = zp.get_persistence_diagram(0, true); - std::stable_sort(bars.begin(), bars.end(), cmp_intervals_by_length()); - std::stable_sort(barcode.begin(), barcode.end(), cmp_intervals_by_length()); - auto it = barcode.begin(); - for (const auto& interval : bars) { - BOOST_CHECK_EQUAL(interval.dim(), it->dim()); - BOOST_CHECK_EQUAL(interval.birth(), it->birth()); - BOOST_CHECK_EQUAL(interval.death(), it->death()); - ++it; - } - BOOST_CHECK(it == barcode.end()); + ZP zp(stream); + BOOST_CHECK(pairs.empty()); } -void test_indices(ZP& zp, std::vector& indices, std::vector& indexToFil) { - auto it = indices.begin(); - for (const auto& interval : zp.get_index_persistence_diagram()) { +void test_indices(std::vector& zp_indices, std::vector& witness_indices) { + auto it = witness_indices.begin(); + for (const Interval& interval : zp_indices) { BOOST_CHECK_EQUAL(interval.dim(), it->dim()); BOOST_CHECK_EQUAL(interval.birth(), it->birth()); BOOST_CHECK_EQUAL(interval.death(), it->death()); - auto p = zp.map_index_to_filtration_value(interval.birth(), interval.death()); - BOOST_CHECK_EQUAL(p.first, indexToFil[interval.birth()]); - BOOST_CHECK_EQUAL(p.second, indexToFil[interval.death()]); ++it; } - BOOST_CHECK(it == indices.end()); -} - -std::vector > get_simplices() { - return {{0}, - {1}, - {2}, - {0, 1}, - {0, 2}, - {3}, - {1, 2}, - {4}, - {3, 4}, - {5}, - {0, 1, 2}, - {4, 5}, - {3, 5}, - {3, 4, 5}, - {0, 1, 2}, // remove - {3, 4, 5}, // remove - {1, 4}, - {0, 1, 2}, - {2, 4}, - {3, 4, 5}, - {0, 4}, - {0, 2, 4}, - {1, 2, 4}, - {0, 1, 4}, - {3, 4, 5}, // remove - {3, 4}, // remove - {3, 5}, // remove - {0, 1, 2, 4}, - {0, 1, 2, 4}}; // remove + BOOST_CHECK(it == witness_indices.end()); } -std::vector > get_boundaries() { +std::vector > get_boundaries() { return {{}, {}, {}, @@ -139,32 +86,18 @@ std::vector > get_boundaries() { {27}}; // remove } -std::vector get_filtration_values() { - return {0, 0, 0, - 1, 1, 1, - 2, 2, 2, - 3, 3, 3, 3, - 4, - 5, - 6, 6, 6, - 7, 7, 7, 7, 7, 7, - 8, - 9, 9, 9, - 10}; -} - BOOST_AUTO_TEST_CASE(zigzag_persistence_single) { - ZP zp(28); - std::vector realIndices; - std::vector realBarcode; + std::vector pairs; + auto stream = [&](int dim, ZP::index birth, ZP::index death) { pairs.emplace_back(dim, birth, death); }; + auto stream_inf = [&](int dim, ZP::index birth) { pairs.emplace_back(dim, birth, -1); }; + ZP zp(stream, 28); + std::vector realIndices; realIndices.reserve(13); - realBarcode.reserve(9); - std::vector > simplices = get_boundaries(); - std::vector filValues = get_filtration_values(); + std::vector > simplices = get_boundaries(); for (unsigned int i = 0; i < 14; ++i) { - zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); + zp.insert_face(simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1); } realIndices.emplace_back(0, 1, 3); @@ -174,18 +107,13 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single) { realIndices.emplace_back(0, 9, 11); realIndices.emplace_back(1, 12, 13); - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(1, 2, 3); - realBarcode.emplace_back(1, 3, 4); - for (unsigned int i = 14; i < 16; ++i) { auto id = simplices[i][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1); } for (unsigned int i = 16; i < 24; ++i) { - zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); + zp.insert_face(simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1); } realIndices.emplace_back(0, 5, 16); @@ -194,94 +122,86 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single) { realIndices.emplace_back(1, 20, 21); realIndices.emplace_back(1, 18, 22); - realBarcode.emplace_back(0, 1, 6); - realBarcode.emplace_back(1, 5, 6); - realBarcode.emplace_back(1, 6, 7); - for (unsigned int i = 24; i < 27; ++i) { auto id = simplices[i][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1); } realIndices.emplace_back(1, 24, 25); - realBarcode.emplace_back(1, 8, 9); - zp.insert_face(27, simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1, filValues[27]); + zp.insert_face(simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1); realIndices.emplace_back(2, 23, 27); - realBarcode.emplace_back(2, 7, 9); auto id = simplices[28][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[28]); + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1); + + realIndices.emplace_back(0, 0, -1); + realIndices.emplace_back(0, 26, -1); + realIndices.emplace_back(2, 28, -1); - realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); - realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); - realBarcode.emplace_back(2, 10, std::numeric_limits::infinity()); + auto start = pairs.size(); + zp.get_current_infinit_intervals(stream_inf); + std::sort(pairs.begin() + start, pairs.end(), [](const Interval& i1, const Interval& i2){ + if (i1.dim() != i2.dim()) return i1.dim() < i2.dim(); + return i1.birth() < i2.birth(); + }); - test_indices(zp, realIndices, filValues); - test_barcode(zp, realBarcode); + test_indices(pairs, realIndices); } BOOST_AUTO_TEST_CASE(zigzag_persistence_single_max1) { - ZP zp(28, 1); - std::vector realIndices; - std::vector indexToFil(28); - std::vector realBarcode; + std::vector pairs; + auto stream = [&](int dim, ZP::index birth, ZP::index death) { + if (dim < 1) pairs.emplace_back(dim, birth, death); + }; + auto stream_inf = [&](int dim, ZP::index birth) { + if (dim < 1) pairs.emplace_back(dim, birth, -1); + }; + ZP zp(stream, 28); + std::vector realIndices; realIndices.reserve(5); - realBarcode.reserve(3); - std::vector > simplices = get_boundaries(); - std::vector filValues = get_filtration_values(); - unsigned int currIndex = 0; + std::vector > simplices = get_boundaries(); for (unsigned int i = 0; i < 14; ++i) { - zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); - if (simplices[i].size() < 3) { - indexToFil[currIndex++] = filValues[i]; - } + zp.insert_face(simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1); } realIndices.emplace_back(0, 1, 3); realIndices.emplace_back(0, 2, 4); realIndices.emplace_back(0, 7, 8); - realIndices.emplace_back(0, 9, 10); - - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(0, 0, 1); + realIndices.emplace_back(0, 9, 11); for (unsigned int i = 14; i < 16; ++i) { auto id = simplices[i][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); - if (simplices[id].size() < 3) { - indexToFil[currIndex++] = filValues[i]; - } + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1); } for (unsigned int i = 16; i < 24; ++i) { - zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); - if (simplices[i].size() < 3) { - indexToFil[currIndex++] = filValues[i]; - } + zp.insert_face(simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1); } - realIndices.emplace_back(0, 5, 12); - realBarcode.emplace_back(0, 1, 6); + realIndices.emplace_back(0, 5, 16); for (unsigned int i = 24; i < 27; ++i) { auto id = simplices[i][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); - if (simplices[id].size() < 3) { - indexToFil[currIndex++] = filValues[i]; - } + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1); } - zp.insert_face(27, simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1, filValues[27]); + zp.insert_face(simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1); auto id = simplices[28][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[28]); + zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1); + + realIndices.emplace_back(0, 0, -1); + realIndices.emplace_back(0, 26, -1); - realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); - realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); + auto start = pairs.size(); + zp.get_current_infinit_intervals(stream_inf); + std::sort(pairs.begin() + start, pairs.end(), [](const Interval& i1, const Interval& i2){ + if (i1.dim() != i2.dim()) return i1.dim() < i2.dim(); + return i1.birth() < i2.birth(); + }); - test_indices(zp, realIndices, indexToFil); - test_barcode(zp, realBarcode); + test_indices(pairs, realIndices); } From dfdaaacf98486bca6a11ab8dccbcf70db716977c Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 21 Jun 2024 15:59:57 +0200 Subject: [PATCH 20/96] change of default values --- .../include/gudhi/Filtered_zigzag_persistence.h | 2 +- .../include/gudhi/Zigzag_persistence.h | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Zigzag_persistence/include/gudhi/Filtered_zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/Filtered_zigzag_persistence.h index e7735ac1d0..c3159d7264 100644 --- a/src/Zigzag_persistence/include/gudhi/Filtered_zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/Filtered_zigzag_persistence.h @@ -95,7 +95,7 @@ struct Default_filtered_zigzag_options { * @brief Column type use by the internal matrix. */ static const Gudhi::persistence_matrix::Column_types column_type = - Gudhi::persistence_matrix::Column_types::INTRUSIVE_LIST; + Gudhi::persistence_matrix::Column_types::NAIVE_VECTOR; }; /** diff --git a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h index 651f9bbf2d..a306ff58e9 100644 --- a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h @@ -22,10 +22,13 @@ #include #include -#include +// #include #include #include +#include +// #include + #include namespace Gudhi { @@ -61,7 +64,7 @@ struct Default_zigzag_options { * @brief Column type use by the internal matrix. */ static const Gudhi::persistence_matrix::Column_types column_type = - Gudhi::persistence_matrix::Column_types::INTRUSIVE_LIST; // TODO: benchmark different column types + Gudhi::persistence_matrix::Column_types::NAIVE_VECTOR; //TODO: redo benchmark with oscillating rips }; // TODO: add the possibility of something else than Z2. Which means that the possibility of vineyards without Z2 @@ -85,7 +88,9 @@ class Zigzag_persistence using dimension_type = typename Options::dimension_type; /**< Type for dimension values. */ private: - using birth_dictionnary = std::unordered_map; /**< Dictionnary type. */ + // using birth_dictionnary = std::unordered_map; /**< Dictionnary type. */ + using birth_dictionnary = boost::unordered_flat_map; /**< Dictionnary type. */ + // using birth_dictionnary = boost::unordered_map; /**< Dictionnary type. */ using Matrix_options = Zigzag_matrix_options; /**< Matrix options. */ using Matrix_type = Gudhi::persistence_matrix::Matrix; /**< Matrix. */ using matrix_index = typename Matrix_type::index; /**< Matrix indexation type. */ From e51a1f3f82c3a8d8c16a24c804f97c02f50280d7 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 28 Jun 2024 12:32:14 +0200 Subject: [PATCH 21/96] change of barcode + minor corrections --- .../doc/Intro_zigzag_persistence.h | 23 ++- .../example_simple_zigzag_filtration.cpp | 36 ++-- .../example_zzfiltration_from_file.cpp | 19 +- .../gudhi/Filtered_zigzag_persistence.h | 163 +++++++----------- .../include/gudhi/Zigzag_persistence.h | 4 +- .../filtered_zigzag_persistence_unit_test.cpp | 53 +++--- .../test/zigzag_persistence_unit_test.cpp | 4 +- 7 files changed, 149 insertions(+), 153 deletions(-) diff --git a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h index afa843fcbd..bf7f52fe01 100644 --- a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h +++ b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h @@ -25,6 +25,23 @@ namespace zigzag_persistence { * complex by adding simplices, zigzag persistence also allows removals. Hence the name "zigzag", as the module * diagram will have arrows alterning between forward and backward. * + * The module is partitioned in two types of classes: filtered and non-filtered. + * - There is one non-filtered class: + * @ref Zigzag_persistence. It computes the persistence by considering only the atomic operations in the filtration. + * If the order in which the operations are made still matters, the filtration values associated to an operation + * is not token into account. For example, if a cycle is born at operation number 6 and dies at operation number 7, it + * will output a bar starting at 6 and ending at 7, even if both operations have the same filtration value and therefore + * the "real" bar has length 0. + * - There are two filtered classes: @ref Filtered_zigzag_persistence and @ref Filtered_zigzag_persistence_with_storage. + * They are both based on @ref Zigzag_persistence and manage additionnaly the filtration values which are ignored by + * @ref Zigzag_persistence. They automatically translate the operation numbers into their corresponding filtration + * values and remove bars below a given length threshold. They also have more flexible inputs (the boundaries do not + * have to be ordered, nor identified continously from 0). The two classes diverge on the way they manage the memory: + * @ref Filtered_zigzag_persistence removes systematically all unnecessary information and outputs a pair as soon + * it is closed, while @ref Filtered_zigzag_persistence_with_storage will store all informations about filtration values + * and bars until the end and output the pairs only when asked. Depending on the use and the length of the filtration, + * one will be more efficiant than the other and vice versa. + * * The implementation is based on the algorithm introduced in \cite zigzag. * * \subsection zigzaginterface Stream-like interface @@ -33,16 +50,16 @@ namespace zigzag_persistence { * filtration anymore. This makes it possible to build very long fine tuned filtrations with relatively small complexes * which can be processed without overreaching memory space. For this purpose, it is possible to feed the module with * information about the filtration "on the fly" to avoid loading the whole filtration at once. Information about the - * current barcode can be retrieved between any steps. + * current barcode can be retrieved between any steps via callback methods. * * \subsection zigzagexamples Examples * * Here is a list of zigzag persistence examples : * \li \gudhi_example_link{Zigzag_persistence,example_simple_zigzag_filtration.cpp} - A simple example to showcase how - * to use the \ref Zigzag_persistence class. + * to use the @ref Filtered_zigzag_persistence_with_storage class. * * \li \gudhi_example_link{Zigzag_persistence,example_zzfiltration_from_file.cpp} - An example of a "stream-like" usage - * by reading of the filtration from a file. + * with @ref Filtered_zigzag_persistence by reading off the filtration from a file. * * @} */ diff --git a/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp b/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp index f99fd9bc59..6a35fed140 100644 --- a/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp +++ b/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp @@ -19,24 +19,34 @@ using filtration_value = ZP::filtration_value; using Interval_filtration = ZP::Filtration_value_interval; void print_barcode(ZP& zp) { - std::clog << std::endl << "Current barcode:" << std::endl; - for (auto& bar : zp.get_persistence_diagram(0, true)) { - std::clog << std::floor(bar.birth()) << " - "; - if (bar.death() == std::numeric_limits::infinity()) { - std::clog << "inf"; - } else { - std::clog << std::floor(bar.death()); - } - std::clog << " (" << bar.dim() << ")" << std::endl; + std::cout << std::endl << "Current barcode:" << std::endl; + for (Interval_filtration& bar : zp.get_persistence_diagram(0, true)) { + //stream out content of bar + std::cout << bar << std::endl; + //to access the content of the bar, it can either be used as a struct: + // bar.birth + // bar.death + // bar.dim + //or as a tuple + // std::get<0>(bar) <- birth + // std::get<1>(bar) <- death + // std::get<2>(bar) <- dim } } void print_indices(ZP& zp) { - std::clog << std::endl << "Current pairs:" << std::endl; + std::cout << std::endl << "Current pairs:" << std::endl; for (auto& bar : zp.get_index_persistence_diagram()) { - std::clog << bar.birth() << " - "; - std::clog << bar.death(); - std::clog << " (" << bar.dim() << ")" << std::endl; + //stream out content of bar + std::cout << bar << std::endl; + //to access the content of the bar, it can either be used as a struct: + // bar.birth + // bar.death + // bar.dim + //or as a tuple: + // std::get<0>(bar) <- birth + // std::get<1>(bar) <- death + // std::get<2>(bar) <- dim } } diff --git a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp index bd2cb61bdf..d0d41171b6 100644 --- a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp +++ b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp @@ -60,6 +60,7 @@ lineType read_operation(std::string& line, std::vector& faces, double return type; } +//example of input file: example/zigzag_filtration_example.txt int main(int argc, char* const argv[]) { if (argc != 2) { if (argc < 2) @@ -72,11 +73,11 @@ int main(int argc, char* const argv[]) { std::string line; std::ifstream file(argv[1]); - //std::clog could be replaced by any other output stream + //std::cout could be replaced by any other output stream ZP zp([](dimension_type dim, filtration_value birth, filtration_value death) { - std::clog << "[" << dim << "] "; - std::clog << birth << " - " << death; - std::clog << std::endl; + std::cout << "[" << dim << "] "; + std::cout << birth << " - " << death; + std::cout << std::endl; }); if (file.is_open()) { @@ -113,11 +114,11 @@ int main(int argc, char* const argv[]) { } //retrieve infinit bars remaining at the end - //again std::clog could be replaced by any other output stream - zp.get_current_infinit_intervals([](dimension_type dim, filtration_value birth) { - std::clog << "[" << dim << "] "; - std::clog << birth << " - inf"; - std::clog << std::endl; + //again std::cout could be replaced by any other output stream + zp.get_current_infinite_intervals([](dimension_type dim, filtration_value birth) { + std::cout << "[" << dim << "] "; + std::cout << birth << " - inf"; + std::cout << std::endl; }); return 0; diff --git a/src/Zigzag_persistence/include/gudhi/Filtered_zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/Filtered_zigzag_persistence.h index c3159d7264..93e9251ea8 100644 --- a/src/Zigzag_persistence/include/gudhi/Filtered_zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/Filtered_zigzag_persistence.h @@ -31,56 +31,11 @@ #include #include +#include namespace Gudhi { namespace zigzag_persistence { -/** - * @ingroup zigzag_persistence - * - * @brief Structure to store persistence intervals by their birth and death values. - * - * @tparam value_type Type for the birth and death indices. - */ -template -struct Interval { - /** - * @brief Default constructor. All values are initialized with default values. - */ - Interval() {} - /** - * @brief Constructor. - * - * @param dim Dimension of the cycle. - * @param b Birth index or value of the cycle. - * @param d Death index or value of the cycle. - */ - Interval(int dim, value_type b, value_type d) : dim_(dim), b_(b), d_(d) {} - /** - * @brief Returns the dimension of the homological feature corresponding to the interval. - * - * @return Stored dimension. - */ - int dim() const { return dim_; } - /** - * @brief Returns the birth value of the interval. - * - * @return The stored birth. - */ - value_type birth() const { return b_; } - /** - * @brief Returns the death value of the interval. - * - * @return The stored death. - */ - value_type death() const { return d_; } - - protected: - int dim_; /**< Homological dimension. */ - value_type b_; /**< Value associated to the interval birth. */ - value_type d_; /**< Value associated to the interval death. */ -}; - /** * @ingroup zigzag_persistence * @@ -118,51 +73,67 @@ class Filtered_zigzag_persistence_with_storage using face_key = typename Options::face_key; /**< Face ID type from external inputs. */ using filtration_value = typename Options::filtration_value; /**< Type for filtration values. */ using dimension_type = typename Options::dimension_type; /**< Type for dimension values. */ - using Index_interval = Interval; /**< Persistence interval type. */ - /** \brief Structure to store persistence intervals by their filtration values. - * - * \details By convention, interval \f$[b;d]\f$ are - * closed for finite indices b and d, and open for left-infinite and/or - * right-infinite endpoints. + /** + * @brief Persistence index interval type. */ - struct Filtration_value_interval : Interval { - private: - using Base = Interval; - - public: - /** - * @brief Default constructor - */ - Filtration_value_interval() : Base() {} - /** - * @brief Construct a new interval with given parameters - * - * @param dim Dimension of the interval. - * @param b Start value of the interval. - * @param d End value of the interval. - */ - Filtration_value_interval(int dim, filtration_value b, filtration_value d) : Base(dim, b, d) {} - - /** - * @brief Returns the absolute length of the interval \f$|d-b|\f$. - */ - filtration_value length() const { - if (Base::b_ == Base::d_) { - return 0; - } // otherwise inf - inf would return nan. - return Base::d_ - Base::b_; - } - /** - * @brief Returns the absolute length of the log values of birth and death, i.e. \f$|\log d - \log b|\f$. - */ - filtration_value log_length() const { - if (Base::b_ == Base::d_) { - return 0; - } // otherwise inf - inf would return nan. - return std::log2(static_cast(Base::d_)) - std::log2(static_cast(Base::b_)); - } - }; + using Index_interval = Gudhi::persistence_matrix::Persistence_interval; + /** + * @brief Persistence filtration interval type. + */ + using Filtration_value_interval = Gudhi::persistence_matrix::Persistence_interval; + + // /** \brief Structure to store persistence intervals by their filtration values. + // * + // * \details By convention, interval \f$[b;d]\f$ are + // * closed for finite indices b and d, and open for left-infinite and/or + // * right-infinite endpoints. + // */ + // struct Filtration_value_interval + // : public Gudhi::persistence_matrix::Persistence_interval { + // private: + // using Base = Gudhi::persistence_matrix::Persistence_interval; + + // public: + // /** + // * @brief Default constructor + // */ + // Filtration_value_interval() : Base() {} + // /** + // * @brief Construct a new infinit interval with given parameters. + // * + // * @param dim Dimension of the interval. + // * @param b Start value of the interval. + // */ + // Filtration_value_interval(int dim, filtration_value b) : Base(dim, b) {} + // /** + // * @brief Construct a new interval with given parameters + // * + // * @param dim Dimension of the interval. + // * @param b Start value of the interval. + // * @param d End value of the interval. + // */ + // Filtration_value_interval(int dim, filtration_value b, filtration_value d) : Base(dim, b, d) {} + + // /** + // * @brief Returns the absolute length of the interval \f$|d-b|\f$. + // */ + // filtration_value length() const { + // if (Base::birth == Base::death) { + // return 0; + // } // otherwise inf - inf would return nan. + // return Base::death - Base::birth; + // } + // /** + // * @brief Returns the absolute length of the log values of birth and death, i.e. \f$|\log d - \log b|\f$. + // */ + // filtration_value log_length() const { + // if (Base::birth == Base::death) { + // return 0; + // } // otherwise inf - inf would return nan. + // return std::log2(static_cast(Base::death)) - std::log2(static_cast(Base::birth)); + // } + // }; /** * @brief Constructor. @@ -368,13 +339,13 @@ class Filtered_zigzag_persistence_with_storage for (auto bar : persistenceDiagram_) { filtration_value birth, death; - std::tie(birth, death) = map_index_to_filtration_value(bar.birth(), bar.death()); + std::tie(birth, death) = map_index_to_filtration_value(bar.birth, bar.death); if (birth > death) { std::swap(birth, death); } if (death - birth > shortestInterval) { - diag.emplace_back(bar.dim(), birth, death); + diag.emplace_back(bar.dim, birth, death); } } @@ -403,10 +374,10 @@ class Filtered_zigzag_persistence_with_storage auto stream_infinit_interval = [&](dimension_type dim, internal_key birthIndex) { if (dimMax_ == -1 || (dimMax_ != -1 && dim < dimMax_)) - diag.emplace_back(dim, birth(birthIndex), std::numeric_limits::infinity()); + diag.emplace_back(dim, birth(birthIndex)); }; - pers_.get_current_infinit_intervals(stream_infinit_interval); + pers_.get_current_infinite_intervals(stream_infinit_interval); } }; // end class Filtered_zigzag_persistence_with_storage @@ -432,7 +403,7 @@ class Filtered_zigzag_persistence { * @details After construction of the class, the zigzag filtration should be given in a streaming like way, i.e., * call @ref insert_face, @ref remove_face or @ref apply_identity for each step of the filtration in order of * the filtration. The bars of the diagram are retrieved via the given callback method every time - * a pair with non-zero length is closed. To retrieve the open/infinit bars, use @ref get_current_infinit_intervals. + * a pair with non-zero length is closed. To retrieve the open/infinit bars, use @ref get_current_infinite_intervals. * * @param stream_interval Callback method to process the birth and death values of a persistence bar. * Has to take three arguments as input: first the dimension of the cycle, then the birth value of the cycle @@ -531,8 +502,8 @@ class Filtered_zigzag_persistence { * @param stream_infinit_interval Method processing the unpaired birth values. */ template - void get_current_infinit_intervals(F&& stream_infinit_interval) { - pers_.get_current_infinit_intervals( + void get_current_infinite_intervals(F&& stream_infinit_interval) { + pers_.get_current_infinite_intervals( [&](dimension_type dim, internal_key birth) { stream_infinit_interval(dim, keyToFiltrationValue_.at(birth)); }); } diff --git a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h index a306ff58e9..f27d51d87c 100644 --- a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h @@ -181,7 +181,7 @@ class Zigzag_persistence * call @ref insert_face, @ref remove_face or @ref apply_identity for each step of the filtration in order of * the filtration. The pairs of birth and death indices are retrieved via the given callback method every time * a pair is closed. To retrieve the open pairs (corresponding to infinit bars), - * use @ref get_current_infinit_intervals. + * use @ref get_current_infinite_intervals. * * @param stream_interval Callback method to process the birth and death index pairs. Has to take three arguments * as input: first the dimension of the cycle, then the birth index of the cycle and third the death index of the @@ -247,7 +247,7 @@ class Zigzag_persistence * @param stream_infinit_interval Method processing the unpaired birth indices. */ template - void get_current_infinit_intervals(F&& stream_infinit_interval) { + void get_current_infinite_intervals(F&& stream_infinit_interval) { for (auto& p : births_) { if constexpr (erase_birth_history) { auto& col = matrix_.get_column(p.first); diff --git a/src/Zigzag_persistence/test/filtered_zigzag_persistence_unit_test.cpp b/src/Zigzag_persistence/test/filtered_zigzag_persistence_unit_test.cpp index 20d28c72b8..8cecbddf07 100644 --- a/src/Zigzag_persistence/test/filtered_zigzag_persistence_unit_test.cpp +++ b/src/Zigzag_persistence/test/filtered_zigzag_persistence_unit_test.cpp @@ -18,20 +18,17 @@ #include -struct cmp_intervals_by_length { - cmp_intervals_by_length() {} +struct Interval_comparator { + Interval_comparator() {} template bool operator()(const Interval_filtration& p, const Interval_filtration& q) { - if (p.length() != q.length()) { - return p.length() > q.length(); + if (p.dim != q.dim) { + return p.dim < q.dim; } - if (p.dim() != q.dim()) { - return p.dim() < q.dim(); + if (p.birth != q.birth) { + return p.birth < q.birth; } - if (p.birth() != q.birth()) { - return p.birth() < q.birth(); - } - return p.death() < q.death(); + return p.death < q.death; } }; @@ -56,13 +53,13 @@ BOOST_AUTO_TEST_CASE(constructor) { template void test_barcode(ZP& zp, std::vector& barcode) { auto bars = zp.get_persistence_diagram(0, true); - std::stable_sort(bars.begin(), bars.end(), cmp_intervals_by_length()); - std::stable_sort(barcode.begin(), barcode.end(), cmp_intervals_by_length()); + std::stable_sort(bars.begin(), bars.end(), Interval_comparator()); + std::stable_sort(barcode.begin(), barcode.end(), Interval_comparator()); auto it = barcode.begin(); for (const auto& interval : bars) { - BOOST_CHECK_EQUAL(interval.dim(), it->dim()); - BOOST_CHECK_EQUAL(interval.birth(), it->birth()); - BOOST_CHECK_EQUAL(interval.death(), it->death()); + BOOST_CHECK_EQUAL(interval.dim, it->dim); + BOOST_CHECK_EQUAL(interval.birth, it->birth); + BOOST_CHECK_EQUAL(interval.death, it->death); ++it; } BOOST_CHECK(it == barcode.end()); @@ -73,12 +70,12 @@ void test_indices(ZP& zp, std::vector& indices, std::vector& indexToFil) { auto it = indices.begin(); for (const auto& interval : zp.get_index_persistence_diagram()) { - BOOST_CHECK_EQUAL(interval.dim(), it->dim()); - BOOST_CHECK_EQUAL(interval.birth(), it->birth()); - BOOST_CHECK_EQUAL(interval.death(), it->death()); - auto p = zp.map_index_to_filtration_value(interval.birth(), interval.death()); - BOOST_CHECK_EQUAL(p.first, indexToFil[interval.birth()]); - BOOST_CHECK_EQUAL(p.second, indexToFil[interval.death()]); + BOOST_CHECK_EQUAL(interval.dim, it->dim); + BOOST_CHECK_EQUAL(interval.birth, it->birth); + BOOST_CHECK_EQUAL(interval.death, it->death); + auto p = zp.map_index_to_filtration_value(interval.birth, interval.death); + BOOST_CHECK_EQUAL(p.first, indexToFil[interval.birth]); + BOOST_CHECK_EQUAL(p.second, indexToFil[interval.death]); ++it; } BOOST_CHECK(it == indices.end()); @@ -197,9 +194,9 @@ void test_filtered_zigzag_with_storage() { auto id = simplices[28][0]; zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[28]); - realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); - realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); - realBarcode.emplace_back(2, 10, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 0); + realBarcode.emplace_back(0, 9); + realBarcode.emplace_back(2, 10); test_indices(zp, realIndices, filValues); test_barcode(zp, realBarcode); @@ -254,8 +251,8 @@ void test_filtered_zigzag_with_storage_max1() { auto id = simplices[28][0]; zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[28]); - realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); - realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 0); + realBarcode.emplace_back(0, 9); test_indices(zp, realIndices, filValues); test_barcode(zp, realBarcode); @@ -346,7 +343,7 @@ void test_filtered_zigzag() { //there is no real garantee on the order of the infinite bars std::vector infiniteBars; - zp.get_current_infinit_intervals([&](dimension_type dim, filtration_value birth) { + zp.get_current_infinite_intervals([&](dimension_type dim, filtration_value birth) { infiniteBars.emplace_back(dim, birth, std::numeric_limits::infinity()); }); @@ -450,7 +447,7 @@ void test_filtered_zigzag_max1() { //there is no real garantee on the order of the infinite bars std::vector infiniteBars; - zp.get_current_infinit_intervals([&](dimension_type dim, filtration_value birth) { + zp.get_current_infinite_intervals([&](dimension_type dim, filtration_value birth) { if (dim < 1){ infiniteBars.emplace_back(dim, birth, std::numeric_limits::infinity()); } diff --git a/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp b/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp index e255179150..273f3cbbbe 100644 --- a/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp +++ b/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp @@ -141,7 +141,7 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single) { realIndices.emplace_back(2, 28, -1); auto start = pairs.size(); - zp.get_current_infinit_intervals(stream_inf); + zp.get_current_infinite_intervals(stream_inf); std::sort(pairs.begin() + start, pairs.end(), [](const Interval& i1, const Interval& i2){ if (i1.dim() != i2.dim()) return i1.dim() < i2.dim(); return i1.birth() < i2.birth(); @@ -197,7 +197,7 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single_max1) { realIndices.emplace_back(0, 26, -1); auto start = pairs.size(); - zp.get_current_infinit_intervals(stream_inf); + zp.get_current_infinite_intervals(stream_inf); std::sort(pairs.begin() + start, pairs.end(), [](const Interval& i1, const Interval& i2){ if (i1.dim() != i2.dim()) return i1.dim() < i2.dim(); return i1.birth() < i2.birth(); From 585432cbd234b1ccdb2b9dc4fd23f7e8164f4954 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 28 Jun 2024 13:59:30 +0200 Subject: [PATCH 22/96] update example cmake --- src/Zigzag_persistence/example/CMakeLists.txt | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Zigzag_persistence/example/CMakeLists.txt b/src/Zigzag_persistence/example/CMakeLists.txt index dd1f88e1d2..0cb6521839 100644 --- a/src/Zigzag_persistence/example/CMakeLists.txt +++ b/src/Zigzag_persistence/example/CMakeLists.txt @@ -1,18 +1,11 @@ project(Zigzag_persistence_examples) -add_executable ( Zigzag_persistence_example_simple_zigzag_filtration example_simple_zigzag_filtration.cpp ) -if(TARGET TBB::tbb) - target_link_libraries(Zigzag_persistence_example_simple_zigzag_filtration TBB::tbb) -endif() +add_executable_with_targets(Zigzag_persistence_example_simple_zigzag_filtration example_simple_zigzag_filtration.cpp TBB::tbb) add_test(NAME Zigzag_persistence_example_simple_zigzag_filtration COMMAND $) -add_executable ( Zigzag_persistence_example_zzfiltration_from_file example_zzfiltration_from_file.cpp ) -if(TARGET TBB::tbb) - target_link_libraries(Zigzag_persistence_example_zzfiltration_from_file TBB::tbb) -endif() +add_executable_with_targets(Zigzag_persistence_example_zzfiltration_from_file example_zzfiltration_from_file.cpp TBB::tbb) file(COPY "zigzag_filtration_example.txt" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) add_test(NAME Zigzag_persistence_example_zzfiltration_from_file COMMAND $ "${CMAKE_CURRENT_BINARY_DIR}/zigzag_filtration_example.txt") - From 55d510a224187f95d1ccff78ad6f7e13288a2b2b Mon Sep 17 00:00:00 2001 From: hschreiber Date: Mon, 8 Jul 2024 17:44:19 +0200 Subject: [PATCH 23/96] rename files to gudhi convention --- .../example/example_simple_zigzag_filtration.cpp | 2 +- .../example/example_zzfiltration_from_file.cpp | 2 +- ...zigzag_persistence.h => filtered_zigzag_persistence.h} | 4 ++-- .../gudhi/{Zigzag_persistence.h => zigzag_persistence.h} | 4 ++-- src/Zigzag_persistence/test/CMakeLists.txt | 8 ++++---- ...unit_test.cpp => test_filtered_zigzag_persistence.cpp} | 2 +- ...sistence_unit_test.cpp => test_zigzag_persistence.cpp} | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) rename src/Zigzag_persistence/include/gudhi/{Filtered_zigzag_persistence.h => filtered_zigzag_persistence.h} (99%) rename src/Zigzag_persistence/include/gudhi/{Zigzag_persistence.h => zigzag_persistence.h} (99%) rename src/Zigzag_persistence/test/{filtered_zigzag_persistence_unit_test.cpp => test_filtered_zigzag_persistence.cpp} (99%) rename src/Zigzag_persistence/test/{zigzag_persistence_unit_test.cpp => test_zigzag_persistence.cpp} (99%) diff --git a/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp b/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp index 6a35fed140..012893adf5 100644 --- a/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp +++ b/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include using ZP = Gudhi::zigzag_persistence::Filtered_zigzag_persistence_with_storage<>; using face_handle = ZP::face_key; diff --git a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp index d0d41171b6..04b2469866 100644 --- a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp +++ b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include using ZP = Gudhi::zigzag_persistence::Filtered_zigzag_persistence<>; using id_handle = ZP::face_key; diff --git a/src/Zigzag_persistence/include/gudhi/Filtered_zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h similarity index 99% rename from src/Zigzag_persistence/include/gudhi/Filtered_zigzag_persistence.h rename to src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h index 93e9251ea8..bc9cba844f 100644 --- a/src/Zigzag_persistence/include/gudhi/Filtered_zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h @@ -12,7 +12,7 @@ */ /** - * @file Filtered_zigzag_persistence.h + * @file filtered_zigzag_persistence.h * @author Clément Maria, Hannah Schreiber * @brief Contains the implementation of the @ref Interval structure and the * @ref Gudhi::zigzag_persistence::Filtered_zigzag_persistence_with_storage and @@ -30,7 +30,7 @@ #include #include -#include +#include #include namespace Gudhi { diff --git a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h similarity index 99% rename from src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h rename to src/Zigzag_persistence/include/gudhi/zigzag_persistence.h index f27d51d87c..3cf3895211 100644 --- a/src/Zigzag_persistence/include/gudhi/Zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h @@ -12,7 +12,7 @@ */ /** - * @file Zigzag_persistence.h + * @file zigzag_persistence.h * @author Clément Maria, Hannah Schreiber * @brief Contains the implementation of the @ref Gudhi::zigzag_persistence::Zigzag_persistence class. */ @@ -72,7 +72,7 @@ struct Default_zigzag_options { // TODO: erase_birth_history will be moved to the options if it is proven to be useful. In the meantime // it stays here undocumented to ease benchmarks. /** - * @class Zigzag_persistence Zigzag_persistence.h gudhi/Zigzag_persistence.h + * @class Zigzag_persistence zigzag_persistence.h gudhi/zigzag_persistence.h * @brief Class computating the zigzag persistent homology of a zigzag sequence. Algorithm based on \cite zigzag. * * @ingroup zigzag_persistence diff --git a/src/Zigzag_persistence/test/CMakeLists.txt b/src/Zigzag_persistence/test/CMakeLists.txt index b14024ad1d..ee0fe2c4e9 100644 --- a/src/Zigzag_persistence/test/CMakeLists.txt +++ b/src/Zigzag_persistence/test/CMakeLists.txt @@ -2,11 +2,11 @@ project(Zigzag_persistence_tests) include(GUDHI_boost_test) -add_executable_with_targets(Zigzag_persistence_unit_test zigzag_persistence_unit_test.cpp TBB::tbb) -gudhi_add_boost_test(Zigzag_persistence_unit_test) +add_executable_with_targets(Zigzag_persistence_test_zigzag_persistence test_zigzag_persistence.cpp TBB::tbb) +gudhi_add_boost_test(Zigzag_persistence_test_zigzag_persistence) -add_executable_with_targets(Filtered_zigzag_persistence_unit_test filtered_zigzag_persistence_unit_test.cpp TBB::tbb) -gudhi_add_boost_test(Filtered_zigzag_persistence_unit_test) +add_executable_with_targets(Zigzag_persistence_test_filtered_zigzag_persistence test_filtered_zigzag_persistence.cpp TBB::tbb) +gudhi_add_boost_test(Zigzag_persistence_test_filtered_zigzag_persistence) diff --git a/src/Zigzag_persistence/test/filtered_zigzag_persistence_unit_test.cpp b/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp similarity index 99% rename from src/Zigzag_persistence/test/filtered_zigzag_persistence_unit_test.cpp rename to src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp index 8cecbddf07..e91e386b4d 100644 --- a/src/Zigzag_persistence/test/filtered_zigzag_persistence_unit_test.cpp +++ b/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp @@ -16,7 +16,7 @@ #define BOOST_TEST_MODULE "zigzag_persistence" #include -#include +#include struct Interval_comparator { Interval_comparator() {} diff --git a/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp b/src/Zigzag_persistence/test/test_zigzag_persistence.cpp similarity index 99% rename from src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp rename to src/Zigzag_persistence/test/test_zigzag_persistence.cpp index 273f3cbbbe..8dd3a7b032 100644 --- a/src/Zigzag_persistence/test/zigzag_persistence_unit_test.cpp +++ b/src/Zigzag_persistence/test/test_zigzag_persistence.cpp @@ -14,7 +14,7 @@ #define BOOST_TEST_MODULE "zigzag_persistence" #include -#include +#include using ZP = Gudhi::zigzag_persistence::Zigzag_persistence<>; // using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; From bf19ed54120e110e0cea7b8806efa1893639d669 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Tue, 9 Jul 2024 16:58:12 +0200 Subject: [PATCH 24/96] fix version problem with boost::unordered_flat_map --- .../include/gudhi/zigzag_persistence.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h index 3cf3895211..37b41e9413 100644 --- a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h @@ -22,12 +22,16 @@ #include #include -// #include #include #include -#include +#include +#if BOOST_VERSION >= 108100 +#include //don't exist for lower versions of boost // #include +#else +#include +#endif #include @@ -88,9 +92,12 @@ class Zigzag_persistence using dimension_type = typename Options::dimension_type; /**< Type for dimension values. */ private: - // using birth_dictionnary = std::unordered_map; /**< Dictionnary type. */ +#if BOOST_VERSION >= 108100 using birth_dictionnary = boost::unordered_flat_map; /**< Dictionnary type. */ // using birth_dictionnary = boost::unordered_map; /**< Dictionnary type. */ +#else + using birth_dictionnary = std::unordered_map; /**< Dictionnary type. */ +#endif using Matrix_options = Zigzag_matrix_options; /**< Matrix options. */ using Matrix_type = Gudhi::persistence_matrix::Matrix; /**< Matrix. */ using matrix_index = typename Matrix_type::index; /**< Matrix indexation type. */ From c42a26384b6454012642e08a35a784c87629eddb Mon Sep 17 00:00:00 2001 From: hschreiber Date: Wed, 10 Jul 2024 18:10:19 +0200 Subject: [PATCH 25/96] corrections from merge with upstream --- .../gudhi/filtered_zigzag_persistence.h | 6 +- .../test/test_filtered_zigzag_persistence.cpp | 72 +++++++++---------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h index bc9cba844f..c5f2714c63 100644 --- a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h @@ -156,7 +156,7 @@ class Filtered_zigzag_persistence_with_storage pers_( [&](dimension_type dim, internal_key birth, internal_key death) { if (dimMax_ == -1 || (dimMax_ != -1 && dim < dimMax_)) { // don't record intervals over max dim - persistenceDiagram_.emplace_back(dim, birth, death); + persistenceDiagram_.emplace_back(birth, death, dim); } }, minNumberOfFaces) {} @@ -345,7 +345,7 @@ class Filtered_zigzag_persistence_with_storage } if (death - birth > shortestInterval) { - diag.emplace_back(bar.dim, birth, death); + diag.emplace_back(birth, death, bar.dim); } } @@ -374,7 +374,7 @@ class Filtered_zigzag_persistence_with_storage auto stream_infinit_interval = [&](dimension_type dim, internal_key birthIndex) { if (dimMax_ == -1 || (dimMax_ != -1 && dim < dimMax_)) - diag.emplace_back(dim, birth(birthIndex)); + diag.emplace_back(birth(birthIndex), Filtration_value_interval::inf, dim); }; pers_.get_current_infinite_intervals(stream_infinit_interval); diff --git a/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp b/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp index e91e386b4d..702590aa46 100644 --- a/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp +++ b/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp @@ -147,17 +147,17 @@ void test_filtered_zigzag_with_storage() { zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); } - realIndices.emplace_back(0, 1, 3); - realIndices.emplace_back(0, 2, 4); - realIndices.emplace_back(0, 7, 8); - realIndices.emplace_back(1, 6, 10); - realIndices.emplace_back(0, 9, 11); - realIndices.emplace_back(1, 12, 13); - - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(1, 2, 3); - realBarcode.emplace_back(1, 3, 4); + realIndices.emplace_back(1, 3, 0); + realIndices.emplace_back(2, 4, 0); + realIndices.emplace_back(7, 8, 0); + realIndices.emplace_back(6, 10, 1); + realIndices.emplace_back(9, 11, 0); + realIndices.emplace_back(12, 13, 1); + + realBarcode.emplace_back(0, 1, 0); + realBarcode.emplace_back(0, 1, 0); + realBarcode.emplace_back(2, 3, 1); + realBarcode.emplace_back(3, 4, 1); for (unsigned int i = 14; i < 16; ++i) { auto id = simplices[i][0]; @@ -168,35 +168,35 @@ void test_filtered_zigzag_with_storage() { zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); } - realIndices.emplace_back(0, 5, 16); - realIndices.emplace_back(1, 14, 17); - realIndices.emplace_back(1, 15, 19); - realIndices.emplace_back(1, 20, 21); - realIndices.emplace_back(1, 18, 22); + realIndices.emplace_back(5, 16, 0); + realIndices.emplace_back(14, 17, 1); + realIndices.emplace_back(15, 19, 1); + realIndices.emplace_back(20, 21, 1); + realIndices.emplace_back(18, 22, 1); - realBarcode.emplace_back(0, 1, 6); - realBarcode.emplace_back(1, 5, 6); - realBarcode.emplace_back(1, 6, 7); + realBarcode.emplace_back(1, 6, 0); + realBarcode.emplace_back(5, 6, 1); + realBarcode.emplace_back(6, 7, 1); for (unsigned int i = 24; i < 27; ++i) { auto id = simplices[i][0]; zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); } - realIndices.emplace_back(1, 24, 25); - realBarcode.emplace_back(1, 8, 9); + realIndices.emplace_back(24, 25, 1); + realBarcode.emplace_back(8, 9, 1); zp.insert_face(27, simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1, filValues[27]); - realIndices.emplace_back(2, 23, 27); - realBarcode.emplace_back(2, 7, 9); + realIndices.emplace_back(23, 27, 2); + realBarcode.emplace_back(7, 9, 2); auto id = simplices[28][0]; zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[28]); - realBarcode.emplace_back(0, 0); - realBarcode.emplace_back(0, 9); - realBarcode.emplace_back(2, 10); + realBarcode.emplace_back(0, Interval_filtration::inf, 0); + realBarcode.emplace_back(9, Interval_filtration::inf, 0); + realBarcode.emplace_back(10, Interval_filtration::inf, 2); test_indices(zp, realIndices, filValues); test_barcode(zp, realBarcode); @@ -222,13 +222,13 @@ void test_filtered_zigzag_with_storage_max1() { zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); } - realIndices.emplace_back(0, 1, 3); - realIndices.emplace_back(0, 2, 4); - realIndices.emplace_back(0, 7, 8); - realIndices.emplace_back(0, 9, 11); + realIndices.emplace_back(1, 3, 0); + realIndices.emplace_back(2, 4, 0); + realIndices.emplace_back(7, 8, 0); + realIndices.emplace_back(9, 11, 0); - realBarcode.emplace_back(0, 0, 1); - realBarcode.emplace_back(0, 0, 1); + realBarcode.emplace_back( 0, 1, 0); + realBarcode.emplace_back(0, 1, 0); for (unsigned int i = 14; i < 16; ++i) { auto id = simplices[i][0]; @@ -239,8 +239,8 @@ void test_filtered_zigzag_with_storage_max1() { zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); } - realIndices.emplace_back(0, 5, 16); - realBarcode.emplace_back(0, 1, 6); + realIndices.emplace_back(5, 16, 0); + realBarcode.emplace_back(1, 6, 0); for (unsigned int i = 24; i < 27; ++i) { auto id = simplices[i][0]; @@ -251,8 +251,8 @@ void test_filtered_zigzag_with_storage_max1() { auto id = simplices[28][0]; zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[28]); - realBarcode.emplace_back(0, 0); - realBarcode.emplace_back(0, 9); + realBarcode.emplace_back(0, Interval_filtration::inf, 0); + realBarcode.emplace_back(9, Interval_filtration::inf, 0); test_indices(zp, realIndices, filValues); test_barcode(zp, realBarcode); From efa25461a2ac8aaed066f5bd354dd6aa708d728f Mon Sep 17 00:00:00 2001 From: hschreiber Date: Thu, 11 Jul 2024 11:29:20 +0200 Subject: [PATCH 26/96] remove doxygen warnings --- .../doc/Intro_zigzag_persistence.h | 2 + .../gudhi/filtered_zigzag_persistence.h | 56 +------------------ 2 files changed, 4 insertions(+), 54 deletions(-) diff --git a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h index bf7f52fe01..dc5f77b861 100644 --- a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h +++ b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h @@ -19,6 +19,8 @@ namespace zigzag_persistence { * @{ * \author Clément Maria, Hannah Schreiber * + * \section zigzagintro Zigzag Persistence + * * We refer to the introduction page \ref persistent_cohomology for persistent (co)homology for an introduction * to the topic. * Zigzag persistence is a generalization of the latter. While standard persistence only allows to grow the filtered diff --git a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h index c5f2714c63..d98f51c820 100644 --- a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h @@ -14,8 +14,8 @@ /** * @file filtered_zigzag_persistence.h * @author Clément Maria, Hannah Schreiber - * @brief Contains the implementation of the @ref Interval structure and the - * @ref Gudhi::zigzag_persistence::Filtered_zigzag_persistence_with_storage and + * @brief Contains the implementation of the @ref Gudhi::zigzag_persistence::Default_filtered_zigzag_options structure + * and the @ref Gudhi::zigzag_persistence::Filtered_zigzag_persistence_with_storage and * @ref Gudhi::zigzag_persistence::Filtered_zigzag_persistence classes. */ @@ -83,58 +83,6 @@ class Filtered_zigzag_persistence_with_storage */ using Filtration_value_interval = Gudhi::persistence_matrix::Persistence_interval; - // /** \brief Structure to store persistence intervals by their filtration values. - // * - // * \details By convention, interval \f$[b;d]\f$ are - // * closed for finite indices b and d, and open for left-infinite and/or - // * right-infinite endpoints. - // */ - // struct Filtration_value_interval - // : public Gudhi::persistence_matrix::Persistence_interval { - // private: - // using Base = Gudhi::persistence_matrix::Persistence_interval; - - // public: - // /** - // * @brief Default constructor - // */ - // Filtration_value_interval() : Base() {} - // /** - // * @brief Construct a new infinit interval with given parameters. - // * - // * @param dim Dimension of the interval. - // * @param b Start value of the interval. - // */ - // Filtration_value_interval(int dim, filtration_value b) : Base(dim, b) {} - // /** - // * @brief Construct a new interval with given parameters - // * - // * @param dim Dimension of the interval. - // * @param b Start value of the interval. - // * @param d End value of the interval. - // */ - // Filtration_value_interval(int dim, filtration_value b, filtration_value d) : Base(dim, b, d) {} - - // /** - // * @brief Returns the absolute length of the interval \f$|d-b|\f$. - // */ - // filtration_value length() const { - // if (Base::birth == Base::death) { - // return 0; - // } // otherwise inf - inf would return nan. - // return Base::death - Base::birth; - // } - // /** - // * @brief Returns the absolute length of the log values of birth and death, i.e. \f$|\log d - \log b|\f$. - // */ - // filtration_value log_length() const { - // if (Base::birth == Base::death) { - // return 0; - // } // otherwise inf - inf would return nan. - // return std::log2(static_cast(Base::death)) - std::log2(static_cast(Base::birth)); - // } - // }; - /** * @brief Constructor. * @details After construction of the class, the zigzag filtration should be given in a streaming like way, i.e., From cfdc161606e36dfef9fd1ca524c31cda6be317fe Mon Sep 17 00:00:00 2001 From: hschreiber Date: Thu, 11 Jul 2024 14:08:51 +0200 Subject: [PATCH 27/96] dox fix --- .../doc/Intro_zigzag_persistence.h | 32 +++++------ .../example_zzfiltration_from_file.cpp | 2 +- .../gudhi/filtered_zigzag_persistence.h | 54 +++++++++---------- .../include/gudhi/zigzag_persistence.h | 40 +++++++------- 4 files changed, 63 insertions(+), 65 deletions(-) diff --git a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h index dc5f77b861..f39d02f8c3 100644 --- a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h +++ b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h @@ -24,25 +24,25 @@ namespace zigzag_persistence { * We refer to the introduction page \ref persistent_cohomology for persistent (co)homology for an introduction * to the topic. * Zigzag persistence is a generalization of the latter. While standard persistence only allows to grow the filtered - * complex by adding simplices, zigzag persistence also allows removals. Hence the name "zigzag", as the module - * diagram will have arrows alterning between forward and backward. + * complex by adding faces, zigzag persistence also allows removals. Hence the name "zigzag", as the module + * diagram will have arrows alternating between forward and backward. * - * The module is partitioned in two types of classes: filtered and non-filtered. - * - There is one non-filtered class: - * @ref Zigzag_persistence. It computes the persistence by considering only the atomic operations in the filtration. - * If the order in which the operations are made still matters, the filtration values associated to an operation - * is not token into account. For example, if a cycle is born at operation number 6 and dies at operation number 7, it - * will output a bar starting at 6 and ending at 7, even if both operations have the same filtration value and therefore - * the "real" bar has length 0. + * The module is partitioned in two types of classes: filtered by filtration values and filtered by the atomic + * operations. + * - There is one atomic class: + * @ref Zigzag_persistence. It computes the persistence by considering only the index of an atomic operations in the + * filtration and not its possibly associated filtration value. For example, if a cycle is born at operation number 6 + * and dies at operation number 7, it will output a bar starting at 6 and ending at 7, even if both operations have + * the same filtration value in the zigzag filtration and therefore the "real" bar has length 0. * - There are two filtered classes: @ref Filtered_zigzag_persistence and @ref Filtered_zigzag_persistence_with_storage. - * They are both based on @ref Zigzag_persistence and manage additionnaly the filtration values which are ignored by + * They are both based on @ref Zigzag_persistence and manage additionally the filtration values which are ignored by * @ref Zigzag_persistence. They automatically translate the operation numbers into their corresponding filtration - * values and remove bars below a given length threshold. They also have more flexible inputs (the boundaries do not - * have to be ordered, nor identified continously from 0). The two classes diverge on the way they manage the memory: - * @ref Filtered_zigzag_persistence removes systematically all unnecessary information and outputs a pair as soon - * it is closed, while @ref Filtered_zigzag_persistence_with_storage will store all informations about filtration values - * and bars until the end and output the pairs only when asked. Depending on the use and the length of the filtration, - * one will be more efficiant than the other and vice versa. + * values. They also have more flexible inputs (the boundaries do not have to be ordered, nor identified continuously + * from 0). The two classes diverge on the way they manage the memory: @ref Filtered_zigzag_persistence removes + * systematically all unnecessary information and outputs a pair as soon it is closed, while + * @ref Filtered_zigzag_persistence_with_storage will store all informations about filtration values and bars until the + * end and output the pairs only when asked. Depending on the use and the length of the filtration, one will be more + * efficient than the other and vice versa. * * The implementation is based on the algorithm introduced in \cite zigzag. * diff --git a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp index 04b2469866..e4da46e969 100644 --- a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp +++ b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp @@ -113,7 +113,7 @@ int main(int argc, char* const argv[]) { file.setstate(std::ios::failbit); } - //retrieve infinit bars remaining at the end + //retrieve infinite bars remaining at the end //again std::cout could be replaced by any other output stream zp.get_current_infinite_intervals([](dimension_type dim, filtration_value birth) { std::cout << "[" << dim << "] "; diff --git a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h index d98f51c820..0235597fbb 100644 --- a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h @@ -6,7 +6,7 @@ * * Modification(s): * - 2023/05 Hannah Schreiber: Rework of the interface, reorganization and debug - * - 2023/05 Hannah Schreiber: Addition of infinit bars + * - 2023/05 Hannah Schreiber: Addition of infinite bars * - 2024/06 Hannah Schreiber: Separation of the zigzag algorithm from the filtration value management * - YYYY/MM Author: Description of the modification */ @@ -42,7 +42,7 @@ namespace zigzag_persistence { * @brief Default options for @ref Filtered_zigzag_persistence_with_storage and @ref Filtered_zigzag_persistence. */ struct Default_filtered_zigzag_options { - using internal_key = int; /**< Face ID used internaly, must be signed. */ + using internal_key = int; /**< Face ID used internally, must be signed. */ using face_key = int; /**< Face ID used in the given boundaries. */ using filtration_value = double; /**< Filtration value type. */ using dimension_type = int; /**< Dimension value type. */ @@ -56,8 +56,8 @@ struct Default_filtered_zigzag_options { /** * @ingroup zigzag_persistence * - * @brief Class computating the zigzag persistent homology of a zigzag filtration. Algorithm based on \cite zigzag. - * Eventhough the insertions and removals are given in a "stream-like" way, the barcode and other values are + * @brief Class computing the zigzag persistent homology of a zigzag filtration. Algorithm based on \cite zigzag. + * Even though the insertions and removals are given in a "stream-like" way, the barcode and other values are * stored during the whole process and not removed. It is therefore suited for smaller filtrations where the clean * ups produce a higher overhead than the memory consumption. * @@ -143,8 +143,7 @@ class Filtered_zigzag_persistence_with_storage GUDHI_CHECK(res.second, "Zigzag_persistence::insert_face - face already in the complex"); - // Reduce the boundary of zzsh in the basis of cycles. - // Compute the keys of the faces of the boundary of zzsh. + // Compute the keys of the faces of the boundary. std::set translatedBoundary; // set maintains the natural order on indices for (auto b : boundary) { translatedBoundary.insert(handleToKey_.at(b)); // TODO: add possibilities of coefficients @@ -184,7 +183,7 @@ class Filtered_zigzag_persistence_with_storage /** * @brief To use when a face is neither inserted nor removed, but the filtration moves along the identity operator - * on homology level. Useful to keep the birth/death indices aligned when insertions/removals are purposly skipped + * on homology level. Useful to keep the birth/death indices aligned when insertions/removals are purposely skipped * to avoid useless computation. */ void apply_identity() { @@ -242,15 +241,15 @@ class Filtered_zigzag_persistence_with_storage * @brief Returns the current persistence diagram. * * @param shortestInterval Threshold. Every bar shorter than the given value will be ignored. Default value: 0. - * @param includeInfinitBars If set to true, infinit bars are included in the diagram. Default value: false. + * @param includeInfiniteBars If set to true, infinite bars are included in the diagram. Default value: false. * @return A vector of pairs of filtration values representing the persistence diagram. */ std::vector get_persistence_diagram(filtration_value shortestInterval = 0., - bool includeInfinitBars = false) { + bool includeInfiniteBars = false) { std::vector diag = _get_persistence_diagram(shortestInterval); - if (includeInfinitBars) { - _retrieve_infinit_bars(diag); + if (includeInfiniteBars) { + _retrieve_infinite_bars(diag); } return diag; @@ -271,7 +270,7 @@ class Filtered_zigzag_persistence_with_storage Zigzag_persistence pers_; /**< Class computing the pairs. */ /** - * @brief Returns the current persistence diagram without infinit bars. + * @brief Returns the current persistence diagram without infinite bars. * * @param shortestInterval Intervals shorter than the given value are ignored. * @return Vector of intervals. @@ -303,9 +302,9 @@ class Filtered_zigzag_persistence_with_storage /** * @brief Computes the births of the current essential cycles. * - * @param diag Reference to vector where to store the infinit bars. + * @param diag Reference to vector where to store the infinite bars. */ - void _retrieve_infinit_bars(std::vector& diag) { + void _retrieve_infinite_bars(std::vector& diag) { auto birth = [this](internal_key birthKey) { auto itBirth = // lower_bound(x) returns leftmost y s.t. x <= y std::lower_bound( @@ -320,19 +319,19 @@ class Filtered_zigzag_persistence_with_storage return itBirth->second; }; - auto stream_infinit_interval = [&](dimension_type dim, internal_key birthIndex) { + auto stream_infinite_interval = [&](dimension_type dim, internal_key birthIndex) { if (dimMax_ == -1 || (dimMax_ != -1 && dim < dimMax_)) diag.emplace_back(birth(birthIndex), Filtration_value_interval::inf, dim); }; - pers_.get_current_infinite_intervals(stream_infinit_interval); + pers_.get_current_infinite_intervals(stream_infinite_interval); } }; // end class Filtered_zigzag_persistence_with_storage /** * @ingroup zigzag_persistence * - * @brief Class computating the zigzag persistent homology of a zigzag filtration. Algorithm based on \cite zigzag. + * @brief Class computing the zigzag persistent homology of a zigzag filtration. Algorithm based on \cite zigzag. * * @tparam FilteredZigzagOptions Structure following the @ref FilteredZigzagOptions concept. * Default value: @ref Default_filtered_zigzag_options. @@ -351,7 +350,7 @@ class Filtered_zigzag_persistence { * @details After construction of the class, the zigzag filtration should be given in a streaming like way, i.e., * call @ref insert_face, @ref remove_face or @ref apply_identity for each step of the filtration in order of * the filtration. The bars of the diagram are retrieved via the given callback method every time - * a pair with non-zero length is closed. To retrieve the open/infinit bars, use @ref get_current_infinite_intervals. + * a pair with non-zero length is closed. To retrieve the open/infinite bars, use @ref get_current_infinite_intervals. * * @param stream_interval Callback method to process the birth and death values of a persistence bar. * Has to take three arguments as input: first the dimension of the cycle, then the birth value of the cycle @@ -402,8 +401,7 @@ class Filtered_zigzag_persistence { keyToFiltrationValue_.try_emplace(numArrow_, filtrationValue); - // Reduce the boundary of zzsh in the basis of cycles. - // Compute the keys of the faces of the boundary of zzsh. + // Compute the keys of the faces of the boundary. std::set translatedBoundary; // set maintains the natural order on indices for (auto b : boundary) { translatedBoundary.insert(handleToKey_.at(b)); // TODO: add possibilities of coefficients @@ -434,7 +432,7 @@ class Filtered_zigzag_persistence { /** * @brief To use when a face is neither inserted nor removed, but the filtration moves along the identity operator - * on homology level. Useful to keep the birth/death indices aligned when insertions/removals are purposly skipped + * on homology level. Useful to keep the birth/death indices aligned when insertions/removals are purposely skipped * to avoid useless computation. */ void apply_identity() { @@ -443,25 +441,25 @@ class Filtered_zigzag_persistence { } /** - * @brief Outputs through the given callback method all current infinit bars. + * @brief Outputs through the given callback method all current infinite bars. * * @tparam F Type of the callback method. Takes two arguments: the dimension of the cycle and the birth value * of the cycle. - * @param stream_infinit_interval Method processing the unpaired birth values. + * @param stream_infinite_interval Method processing the unpaired birth values. */ template - void get_current_infinite_intervals(F&& stream_infinit_interval) { + void get_current_infinite_intervals(F&& stream_infinite_interval) { pers_.get_current_infinite_intervals( - [&](dimension_type dim, internal_key birth) { stream_infinit_interval(dim, keyToFiltrationValue_.at(birth)); }); + [&](dimension_type dim, internal_key birth) { stream_infinite_interval(dim, keyToFiltrationValue_.at(birth)); }); } private: template - using dictionnary = std::unordered_map; // TODO: benchmark with other map types + using dictionary = std::unordered_map; // TODO: benchmark with other map types - dictionnary handleToKey_; /**< Map from input keys to internal keys. */ + dictionary handleToKey_; /**< Map from input keys to internal keys. */ internal_key numArrow_; /**< Current arrow number. */ - dictionnary keyToFiltrationValue_; /**< Face Key to filtration value map. */ + dictionary keyToFiltrationValue_; /**< Face Key to filtration value map. */ std::function stream_interval_; /**< Callback method for finite bars. */ Zigzag_persistence pers_; /**< Class computing the pairs. */ }; // end class Filtered_zigzag_persistence diff --git a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h index 37b41e9413..850a3b4a98 100644 --- a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h @@ -6,7 +6,7 @@ * * Modification(s): * - 2023/05 Hannah Schreiber: Rework of the interface, reorganization and debug - * - 2023/05 Hannah Schreiber: Addition of infinit bars + * - 2023/05 Hannah Schreiber: Addition of infinite bars * - 2024/06 Hannah Schreiber: Separation of the zigzag algorithm from the filtration value management * - YYYY/MM Author: Description of the modification */ @@ -62,7 +62,7 @@ struct Zigzag_matrix_options : Gudhi::persistence_matrix::Default_options= 108100 - using birth_dictionnary = boost::unordered_flat_map; /**< Dictionnary type. */ - // using birth_dictionnary = boost::unordered_map; /**< Dictionnary type. */ + using birth_dictionary = boost::unordered_flat_map; /**< Dictionary type. */ + // using birth_dictionary = boost::unordered_map; /**< Dictionary type. */ #else - using birth_dictionnary = std::unordered_map; /**< Dictionnary type. */ + using birth_dictionary = std::unordered_map; /**< Dictionary type. */ #endif using Matrix_options = Zigzag_matrix_options; /**< Matrix options. */ using Matrix_type = Gudhi::persistence_matrix::Matrix; /**< Matrix. */ @@ -176,7 +176,7 @@ class Zigzag_persistence bool reverse_birth_order(index k1, index k2) const { return birthToPos_.at(k1) > birthToPos_.at(k2); } private: - birth_dictionnary birthToPos_; /**< birth_to_pos_[i] < birth_to_pos_[j] iff i - void get_current_infinite_intervals(F&& stream_infinit_interval) { + void get_current_infinite_intervals(F&& stream_infinite_interval) { for (auto& p : births_) { if constexpr (erase_birth_history) { auto& col = matrix_.get_column(p.first); - stream_infinit_interval(col.get_dimension(), p.second); + stream_infinite_interval(col.get_dimension(), p.second); } else { try { auto& col = matrix_.get_column(p.first); if (!col.is_paired()) { - stream_infinit_interval(col.get_dimension(), p.second); + stream_infinite_interval(col.get_dimension(), p.second); } } catch (const std::out_of_range& e) { continue; @@ -326,10 +326,10 @@ class Zigzag_persistence return birthOrdering_.reverse_birth_order(k1, k2); }; // true iff b(k1) >b b(k2) - // available_birth: for all i by >d value of the d_i, + // availableBirth: for all i by >d value of the d_i, // contains at step i all b_j, j > i, and maybe b_i if not stolen std::set availableBirth(cmp_birth); - // for f1 to f_{p} (i by <=d), insertion in available_birth_to_fidx sorts by >=b + // for f1 to f_{p} (i by <=d), insertion in availableBirth sorts by >=b for (auto& chainF : chainsInF) { availableBirth.insert(births_.at(chainF)); } @@ -348,7 +348,7 @@ class Zigzag_persistence if (birthIt == availableBirth.end()) // birth is not available. *chain_f_it { // must become the sum of all chains in F with smaller death index. // this gives as birth the maximal birth of all chains with strictly larger - // death <=> the maximal availabe death. + // death <=> the maximal available death. // Let c_1 ... c_f be the chains s.t. <[c_1+...+c_f]> is the kernel and // death(c_i) >d death(c_i-1). If the birth of c_i is not available, we set // c_i <- c_i + c_i-1 + ... + c_1, which is [c_i + c_i-1 + ... + c_1] on @@ -367,7 +367,7 @@ class Zigzag_persistence } lastModifiedChainIt = chainFIt; // new cumulated c_i+...+c_1 // remove the max available death - auto maxAvailBirthIt = availableBirth.begin(); // max because order by deacr stream_interval_; /**< Callback method for closed pairs. */ From e025cecb20147568946147408f4c774f8a759053 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Thu, 11 Jul 2024 18:39:07 +0200 Subject: [PATCH 28/96] doc fix --- .../doc/Intro_zigzag_persistence.h | 7 ++++--- .../include/gudhi/filtered_zigzag_persistence.h | 4 ++-- .../include/gudhi/zigzag_persistence.h | 13 +++++++++---- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h index f39d02f8c3..26dfffe0b2 100644 --- a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h +++ b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h @@ -27,14 +27,15 @@ namespace zigzag_persistence { * complex by adding faces, zigzag persistence also allows removals. Hence the name "zigzag", as the module * diagram will have arrows alternating between forward and backward. * - * The module is partitioned in two types of classes: filtered by filtration values and filtered by the atomic + * The module is partitioned in two types of classes: filtered by filtration values and filtered by the elementary * operations. - * - There is one atomic class: + * - For the latter, there is one class: * @ref Zigzag_persistence. It computes the persistence by considering only the index of an atomic operations in the * filtration and not its possibly associated filtration value. For example, if a cycle is born at operation number 6 * and dies at operation number 7, it will output a bar starting at 6 and ending at 7, even if both operations have * the same filtration value in the zigzag filtration and therefore the "real" bar has length 0. - * - There are two filtered classes: @ref Filtered_zigzag_persistence and @ref Filtered_zigzag_persistence_with_storage. + * - For the other type, there are two classes: @ref Filtered_zigzag_persistence and + * @ref Filtered_zigzag_persistence_with_storage. * They are both based on @ref Zigzag_persistence and manage additionally the filtration values which are ignored by * @ref Zigzag_persistence. They automatically translate the operation numbers into their corresponding filtration * values. They also have more flexible inputs (the boundaries do not have to be ordered, nor identified continuously diff --git a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h index 0235597fbb..94bd4f67f7 100644 --- a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h @@ -112,7 +112,7 @@ class Filtered_zigzag_persistence_with_storage /** * @brief Updates the zigzag persistence diagram after the insertion of the given face. * - * @tparam BoundaryRange Range type needing begin and end members. + * @tparam BoundaryRange Range type needing size, begin and end members. * @param faceID ID representing the inserted face. * @param boundary Boundary of the inserted face. The range should be composed of the IDs of all faces contained in * the boundary (i.e. with non-zero coefficients), using the ID specified as `faceID` when the corresponding face @@ -379,7 +379,7 @@ class Filtered_zigzag_persistence { /** * @brief Updates the zigzag persistence diagram after the insertion of the given face. * - * @tparam BoundaryRange Range type needing begin and end members. + * @tparam BoundaryRange Range type needing size, begin and end members. * @param faceID ID representing the inserted face. * @param boundary Boundary of the inserted face. The range should be composed of the IDs of all faces contained in * the boundary (i.e. with non-zero coefficients), using the ID specified as `faceID` when the corresponding face diff --git a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h index 850a3b4a98..63020d2a63 100644 --- a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h @@ -78,6 +78,11 @@ struct Default_zigzag_options { /** * @class Zigzag_persistence zigzag_persistence.h gudhi/zigzag_persistence.h * @brief Class computing the zigzag persistent homology of a zigzag sequence. Algorithm based on \cite zigzag. + * @details After construction of the class, the zigzag filtration should be given in a streaming like way, i.e., + * call @ref insert_face, @ref remove_face or @ref apply_identity for each step of the filtration in order of + * the filtration. The pairs of birth and death indices are retrieved via the given callback method every time + * a pair is closed. To retrieve the open pairs (corresponding to infinite bars), + * use @ref get_current_infinite_intervals. * * @ingroup zigzag_persistence * @@ -194,8 +199,8 @@ class Zigzag_persistence * as input: first the dimension of the cycle, then the birth index of the cycle and third the death index of the * cycle. An index always corresponds to the arrow number the event occurred (one call to @ref insert_face, * @ref remove_face or @ref apply_identity is equal to one arrow and increases the arrow count by one). - * @param minNumberOfFaces Minimum number of faces that will be in a complex at some point in the filtration. - * If the maximal number of faces is known in advance, the memory allocation can be better optimized. + * @param minNumberOfFaces Maximal value among the minimum numbers of faces known to be at the same time in each + * complex of the filtration. It will be used to optimize the memory allocation. * Default value: 0. */ Zigzag_persistence(std::function stream_interval, @@ -214,7 +219,7 @@ class Zigzag_persistence /** * @brief Updates the zigzag persistence diagram after the insertion of the given face. * - * @tparam BoundaryRange Range type needing begin and end members. + * @tparam BoundaryRange Range type needing size, begin and end members. * @param boundary Boundary of the inserted face. The boundary should be represented by all the faces with * non-zero coefficients generating it. A face should be represented by the arrow number when the face appeared for * the first time in the filtration (if a face was inserted and then removed and reinserted etc., only the last @@ -355,7 +360,7 @@ class Zigzag_persistence // the right (of death the maximali <=> the max Date: Thu, 18 Jul 2024 15:01:29 +0200 Subject: [PATCH 29/96] small changes --- .../doc/Intro_zigzag_persistence.h | 26 ++--- .../gudhi/filtered_zigzag_persistence.h | 103 +++++++++++------- .../include/gudhi/zigzag_persistence.h | 17 ++- 3 files changed, 85 insertions(+), 61 deletions(-) diff --git a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h index 26dfffe0b2..e04112092b 100644 --- a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h +++ b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h @@ -27,20 +27,18 @@ namespace zigzag_persistence { * complex by adding faces, zigzag persistence also allows removals. Hence the name "zigzag", as the module * diagram will have arrows alternating between forward and backward. * - * The module is partitioned in two types of classes: filtered by filtration values and filtered by the elementary - * operations. - * - For the latter, there is one class: - * @ref Zigzag_persistence. It computes the persistence by considering only the index of an atomic operations in the - * filtration and not its possibly associated filtration value. For example, if a cycle is born at operation number 6 - * and dies at operation number 7, it will output a bar starting at 6 and ending at 7, even if both operations have - * the same filtration value in the zigzag filtration and therefore the "real" bar has length 0. - * - For the other type, there are two classes: @ref Filtered_zigzag_persistence and - * @ref Filtered_zigzag_persistence_with_storage. - * They are both based on @ref Zigzag_persistence and manage additionally the filtration values which are ignored by - * @ref Zigzag_persistence. They automatically translate the operation numbers into their corresponding filtration - * values. They also have more flexible inputs (the boundaries do not have to be ordered, nor identified continuously - * from 0). The two classes diverge on the way they manage the memory: @ref Filtered_zigzag_persistence removes - * systematically all unnecessary information and outputs a pair as soon it is closed, while + * The module consists of the @ref Zigzag_persistence class and two wrappers @ref Filtered_zigzag_persistence and + * @ref Filtered_zigzag_persistence_with_storage "": + * - @ref Zigzag_persistence computes the persistence of a sequence of insertions and removals. A face can be inserted + * or removed one at a time and the returned persistence pairs / bars are indexed on the operation numbers. + * For example, if a cycle is born at operation number 6 and dies at operation number 7, it will output a bar starting + * at 6 and ending at 7. + * - @ref Filtered_zigzag_persistence and @ref Filtered_zigzag_persistence_with_storage are adding the notion of + * "filtration value" to @ref Zigzag_persistence. At each call, an operation can be associated to a filtration value, + * which will be used to index the returned bars instead (bars with new length 0 are then ignored). The two classes + * also have more flexible inputs (the boundaries do not have to be ordered, nor identified continuously + * from 0). The difference between both classes is on the way they manage the memory: @ref Filtered_zigzag_persistence + * removes systematically all unnecessary information and outputs a pair as soon it is closed, while * @ref Filtered_zigzag_persistence_with_storage will store all informations about filtration values and bars until the * end and output the pairs only when asked. Depending on the use and the length of the filtration, one will be more * efficient than the other and vice versa. diff --git a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h index 94bd4f67f7..70413c5986 100644 --- a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h @@ -60,6 +60,10 @@ struct Default_filtered_zigzag_options { * Even though the insertions and removals are given in a "stream-like" way, the barcode and other values are * stored during the whole process and not removed. It is therefore suited for smaller filtrations where the clean * ups produce a higher overhead than the memory consumption. + * @details After construction of the class, the zigzag filtration should be given in a streaming like way, i.e., + * call @ref insert_face, @ref remove_face or @ref apply_identity for each step of the filtration in order of + * the filtration. To retrieve the current persistence diagram at any moment of the filtration, + * use @ref get_persistence_diagram or @ref get_index_persistence_diagram. * * @tparam FilteredZigzagOptions Structure following the @ref FilteredZigzagOptions concept. * Default value: @ref Default_filtered_zigzag_options. @@ -90,13 +94,14 @@ class Filtered_zigzag_persistence_with_storage * the filtration. To retrieve the current persistence diagram at any moment of the filtration, * use @ref get_persistence_diagram or @ref get_index_persistence_diagram. * - * @param minNumberOfFaces Minimum number of faces that will be in a complex at some point in the filtration. - * If the maximal number of faces is known in advance, the memory allocation can be better optimized. - * Default value: 0. + * @param preallocationSize Space for @p preallocationSize faces are reserved in the underlying structure. + * Theoretically, any values works therefore, but for better performances, it is better to be as close as possible + * to the maximal value of the number of faces stored at the same time. At a same time are stored faces which were + * inserted before that time but not removed until that time. Default value: 0. * @param ignoreCyclesAboveDim Ignores cycles in dimension larger or equal in the final diagram. * If -1, no cycles are ignored. Default value: -1. */ - Filtered_zigzag_persistence_with_storage(unsigned int minNumberOfFaces = 0, int ignoreCyclesAboveDim = -1) + Filtered_zigzag_persistence_with_storage(unsigned int preallocationSize = 0, int ignoreCyclesAboveDim = -1) : dimMax_(ignoreCyclesAboveDim), persistenceDiagram_(), numArrow_(-1), @@ -107,7 +112,7 @@ class Filtered_zigzag_persistence_with_storage persistenceDiagram_.emplace_back(birth, death, dim); } }, - minNumberOfFaces) {} + preallocationSize) {} /** * @brief Updates the zigzag persistence diagram after the insertion of the given face. @@ -119,18 +124,21 @@ class Filtered_zigzag_persistence_with_storage * was previously inserted (recall that the faces should be inserted in order of filtration). * @param dimension Dimension of the inserted face. * @param filtrationValue Filtration value associated to the face. - * Assumed to be larger or equal to previously used filtration values. + * Assumed to be always larger or equal to previously used filtration values or always smaller or equal than previous + * values, ie. the changes are monotonous. + * @return Number of the operation. */ template > - void insert_face(face_key faceID, - const BoundaryRange& boundary, - dimension_type dimension, - filtration_value filtrationValue) { + internal_key insert_face(face_key faceID, + const BoundaryRange& boundary, + dimension_type dimension, + filtration_value filtrationValue) + { ++numArrow_; if (dimMax_ != -1 && dimension > dimMax_) { pers_.apply_identity(); - return; + return numArrow_; } if (filtrationValue != previousFiltrationValue_) // check whether the filt value has changed @@ -150,6 +158,8 @@ class Filtered_zigzag_persistence_with_storage } pers_.insert_face(translatedBoundary, dimension); + + return numArrow_; } /** @@ -158,14 +168,16 @@ class Filtered_zigzag_persistence_with_storage * @param faceID ID representing the face to remove. Should be the same than the one used to insert it. * @param dimension Dimension of the face. * @param filtrationValue Filtration value associated to the removal. - * Assumed to be larger or equal to previously used filtration values. + * Assumed to be always larger or equal to previously used filtration values or always smaller or equal than previous + * values, ie. the changes are monotonous. + * @return Number of the operation. */ - void remove_face(face_key faceID, dimension_type dimension, filtration_value filtrationValue) { + internal_key remove_face(face_key faceID, dimension_type dimension, filtration_value filtrationValue) { ++numArrow_; if (dimMax_ != -1 && dimension > dimMax_) { pers_.apply_identity(); - return; + return numArrow_; } auto it = handleToKey_.find(faceID); @@ -179,16 +191,20 @@ class Filtered_zigzag_persistence_with_storage pers_.remove_face(it->second, dimension); handleToKey_.erase(it); + + return numArrow_; } /** * @brief To use when a face is neither inserted nor removed, but the filtration moves along the identity operator * on homology level. Useful to keep the birth/death indices aligned when insertions/removals are purposely skipped * to avoid useless computation. + * @return Number of the operation. */ - void apply_identity() { + internal_key apply_identity() { ++numArrow_; pers_.apply_identity(); + return numArrow_; } /** @@ -214,9 +230,9 @@ class Filtered_zigzag_persistence_with_storage auto itBirth = // lower_bound(x) returns leftmost y s.t. x <= y std::lower_bound( filtrationValues_.begin(), filtrationValues_.end(), - std::pair(birthKey, std::numeric_limits::infinity()), - [](std::pair p1, std::pair p2) { - return p1.first < p2.first; + birthKey, + [](std::pair p, internal_key k) { + return p.first < k; }); if (itBirth == filtrationValues_.end() || itBirth->first > birthKey) { --itBirth; @@ -226,9 +242,9 @@ class Filtered_zigzag_persistence_with_storage auto itDeath = // std::lower_bound( filtrationValues_.begin(), filtrationValues_.end(), - std::pair(deathKey, std::numeric_limits::infinity()), - [](std::pair p1, std::pair p2) { - return p1.first < p2.first; + deathKey, + [](std::pair p, internal_key k) { + return p.first < k; }); if (itDeath == filtrationValues_.end() || itDeath->first > deathKey) { --itDeath; @@ -279,10 +295,10 @@ class Filtered_zigzag_persistence_with_storage std::vector diag; diag.reserve(persistenceDiagram_.size()); - std::stable_sort(filtrationValues_.begin(), filtrationValues_.end(), - [](std::pair p1, std::pair p2) { - return p1.first < p2.first; - }); + // std::stable_sort(filtrationValues_.begin(), filtrationValues_.end(), + // [](std::pair p1, std::pair p2) { + // return p1.first < p2.first; + // }); for (auto bar : persistenceDiagram_) { filtration_value birth, death; @@ -309,10 +325,10 @@ class Filtered_zigzag_persistence_with_storage auto itBirth = // lower_bound(x) returns leftmost y s.t. x <= y std::lower_bound( filtrationValues_.begin(), filtrationValues_.end(), - std::pair(birthKey, std::numeric_limits::infinity()), - [](std::pair p1, std::pair p2) { - return p1.first < p2.first; - }); + birthKey, + [](std::pair p, internal_key k) { + return p.first < k; + }); if (itBirth == filtrationValues_.end() || itBirth->first > birthKey) { --itBirth; } @@ -332,6 +348,10 @@ class Filtered_zigzag_persistence_with_storage * @ingroup zigzag_persistence * * @brief Class computing the zigzag persistent homology of a zigzag filtration. Algorithm based on \cite zigzag. + * @details After construction of the class, the zigzag filtration should be given in a streaming like way, i.e., + * call @ref insert_face, @ref remove_face or @ref apply_identity for each step of the filtration in order of + * the filtration. The bars of the diagram are retrieved via the given callback method every time + * a pair with non-zero length is closed. To retrieve the open/infinite bars, use @ref get_current_infinite_intervals. * * @tparam FilteredZigzagOptions Structure following the @ref FilteredZigzagOptions concept. * Default value: @ref Default_filtered_zigzag_options. @@ -356,25 +376,25 @@ class Filtered_zigzag_persistence { * Has to take three arguments as input: first the dimension of the cycle, then the birth value of the cycle * and third the death value of the cycle. The values corresponds to the filtration values which were given at * insertions or removals. - * @param minNumberOfFaces Minimum number of faces that will be in a complex at some point in the filtration. + * @param preallocationSize Minimum number of faces that will be in a complex at some point in the filtration. * If the maximal number of faces is known in advance, the memory allocation can be better optimized. * Default value: 0. + * @tparam F Type of callback method. */ - Filtered_zigzag_persistence(std::function stream_interval, - unsigned int minNumberOfFaces = 0) - : handleToKey_(minNumberOfFaces), + template + Filtered_zigzag_persistence(F&& stream_interval, unsigned int preallocationSize = 0) + : handleToKey_(preallocationSize), numArrow_(-1), - keyToFiltrationValue_(minNumberOfFaces), - stream_interval_(std::move(stream_interval)), + keyToFiltrationValue_(preallocationSize), pers_( - [&](dimension_type dim, internal_key birth, internal_key death) { + [&,stream_interval](dimension_type dim, internal_key birth, internal_key death) { auto itB = keyToFiltrationValue_.find(birth); auto itD = keyToFiltrationValue_.find(death); - if (itB->second != itD->second) stream_interval_(dim, itB->second, itD->second); + if (itB->second != itD->second) stream_interval(dim, itB->second, itD->second); keyToFiltrationValue_.erase(itB); keyToFiltrationValue_.erase(itD); }, - minNumberOfFaces) {} + preallocationSize) {} /** * @brief Updates the zigzag persistence diagram after the insertion of the given face. @@ -386,7 +406,8 @@ class Filtered_zigzag_persistence { * was previously inserted (recall that the faces should be inserted in order of filtration). * @param dimension Dimension of the inserted face. * @param filtrationValue Filtration value associated to the face. - * Assumed to be larger or equal to previously used filtration values. + * Assumed to be always larger or equal to previously used filtration values or always smaller or equal than previous + * values, ie. the changes are monotonous. */ template > void insert_face(face_key faceID, @@ -416,7 +437,8 @@ class Filtered_zigzag_persistence { * @param faceID ID representing the face to remove. Should be the same than the one used to insert it. * @param dimension Dimension of the face. * @param filtrationValue Filtration value associated to the removal. - * Assumed to be larger or equal to previously used filtration values. + * Assumed to be always larger or equal to previously used filtration values or always smaller or equal than previous + * values, ie. the changes are monotonous. */ void remove_face(face_key faceID, dimension_type dimension, filtration_value filtrationValue) { ++numArrow_; @@ -460,7 +482,6 @@ class Filtered_zigzag_persistence { dictionary handleToKey_; /**< Map from input keys to internal keys. */ internal_key numArrow_; /**< Current arrow number. */ dictionary keyToFiltrationValue_; /**< Face Key to filtration value map. */ - std::function stream_interval_; /**< Callback method for finite bars. */ Zigzag_persistence pers_; /**< Class computing the pairs. */ }; // end class Filtered_zigzag_persistence diff --git a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h index 63020d2a63..b99bec84a3 100644 --- a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h @@ -199,14 +199,14 @@ class Zigzag_persistence * as input: first the dimension of the cycle, then the birth index of the cycle and third the death index of the * cycle. An index always corresponds to the arrow number the event occurred (one call to @ref insert_face, * @ref remove_face or @ref apply_identity is equal to one arrow and increases the arrow count by one). - * @param minNumberOfFaces Maximal value among the minimum numbers of faces known to be at the same time in each + * @param preallocationSize Maximal value among the minimum numbers of faces known to be at the same time in each * complex of the filtration. It will be used to optimize the memory allocation. * Default value: 0. */ Zigzag_persistence(std::function stream_interval, - unsigned int minNumberOfFaces = 0) + unsigned int preallocationSize = 0) : matrix_( - minNumberOfFaces, + preallocationSize, [this](matrix_index columnIndex1, matrix_index columnIndex2) -> bool { if (matrix_.get_column(columnIndex1).is_paired()) { return matrix_.get_pivot(columnIndex1) < matrix_.get_pivot(columnIndex2); @@ -225,11 +225,13 @@ class Zigzag_persistence * the first time in the filtration (if a face was inserted and then removed and reinserted etc., only the last * insertion counts). The face range should be ordered by increasing arrow numbers. * @param dimension Dimension of the inserted face. + * @return Number of the operation. */ template > - void insert_face(const BoundaryRange& boundary, dimension_type dimension) { + index insert_face(const BoundaryRange& boundary, dimension_type dimension) { ++numArrow_; _process_forward_arrow(boundary, dimension); + return numArrow_; } /** @@ -237,18 +239,21 @@ class Zigzag_persistence * * @param arrowNumber Arrow number of when the face to remove was inserted for the last time. * @param dimension Dimension of the face to remove. + * @return Number of the operation. */ - void remove_face(index arrowNumber, dimension_type dimension) { + index remove_face(index arrowNumber, dimension_type dimension) { ++numArrow_; _process_backward_arrow(arrowNumber, dimension); + return numArrow_; } /** * @brief To use when a face is neither inserted nor removed, but the filtration moves along the identity operator * on homology level. Useful to keep the birth/death indices aligned when insertions/removals are purposely skipped * to avoid useless computation. Increases the arrow number by one. + * @return Number of the operation. */ - void apply_identity() { ++numArrow_; } + index apply_identity() { return ++numArrow_; } /** * @brief Outputs through the given callback method all birth indices which are currently not paired with From 6dc421933f550205977a0f956afe9bab383589be Mon Sep 17 00:00:00 2001 From: hschreiber <48448038+hschreiber@users.noreply.github.com> Date: Thu, 18 Jul 2024 15:42:02 +0200 Subject: [PATCH 30/96] Update src/Zigzag_persistence/include/gudhi/zigzag_persistence.h Co-authored-by: Marc Glisse --- src/Zigzag_persistence/include/gudhi/zigzag_persistence.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h index b99bec84a3..837fde39d0 100644 --- a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h @@ -302,10 +302,7 @@ class Zigzag_persistence if constexpr (erase_birth_history) { births_.emplace_hint(births_.end(), matrix_.get_column_with_pivot(numArrow_), numArrow_); } else { - auto res = births_.try_emplace(matrix_.get_column_with_pivot(numArrow_), numArrow_); - if (!res.second) { - res.first->second = numArrow_; - } + births_[matrix_.get_column_with_pivot(numArrow_)] = numArrow_; } } } From 9446badaf87adcc52f64b2d996b53fe3e47933b5 Mon Sep 17 00:00:00 2001 From: hschreiber <48448038+hschreiber@users.noreply.github.com> Date: Thu, 18 Jul 2024 15:42:22 +0200 Subject: [PATCH 31/96] Update src/Zigzag_persistence/include/gudhi/zigzag_persistence.h Co-authored-by: Marc Glisse --- src/Zigzag_persistence/include/gudhi/zigzag_persistence.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h index 837fde39d0..20731df242 100644 --- a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h @@ -275,7 +275,7 @@ class Zigzag_persistence if (!col.is_paired()) { stream_infinite_interval(col.get_dimension(), p.second); } - } catch (const std::out_of_range& e) { + } catch (const std::out_of_range&) { continue; } } From bbd3d90d862e2455f37e3d70c3a9f64ef56317f3 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 19 Jul 2024 15:19:19 +0200 Subject: [PATCH 32/96] doc --- .../doc/Intro_zigzag_persistence.h | 142 +++++++++++++++++- .../gudhi/filtered_zigzag_persistence.h | 2 +- .../include/gudhi/zigzag_persistence.h | 2 +- 3 files changed, 141 insertions(+), 5 deletions(-) diff --git a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h index e04112092b..ed9d4fc540 100644 --- a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h +++ b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h @@ -53,11 +53,147 @@ namespace zigzag_persistence { * information about the filtration "on the fly" to avoid loading the whole filtration at once. Information about the * current barcode can be retrieved between any steps via callback methods. * - * \subsection zigzagexamples Examples + * \section zigzagexamples Examples + * + * \subsection zzminusage Minimalistic example of usage + * + * ### Includes + * + * #### Zigzag_persistence + * ``` + * #include + * ``` + * #### Filtered_zigzag_persistence and Filtered_zigzag_persistence_with_storage + * ``` + * #include + * ``` + * + * ### Useful aliases + * + * ``` + * using Zigzag_persistence = Gudhi::zigzag_persistence::Zigzag_persistence<>; + * using Filtered_zigzag_persistence = Gudhi::zigzag_persistence::Filtered_zigzag_persistence<>; + * using Filtered_zigzag_persistence_with_storage = Gudhi::zigzag_persistence::Filtered_zigzag_persistence_with_storage<>; + * + * using dimension_type = Zigzag_persistence::dimension_type; + * using index_type = Zigzag_persistence::index; + * using filtration_value_type = Filtered_zigzag_persistence::filtration_value; + * ``` + * + * ### Construction with default values + * + * #### Zigzag_persistence + * ``` + * //Zigzag_persistence(callback) with for example callback method as a anonymous lambda + * Zigzag_persistence zp([](dimension_type dim, index_type birth, index_type death) { + * std::cout << "[" << dim << "] " << birth << " - " << death << std::endl; + * }); + * ``` + * + * #### Filtered_zigzag_persistence + * ``` + * //Filtered_zigzag_persistence(callback) with for example callback method as a anonymous lambda + * Filtered_zigzag_persistence zp([](dimension_type dim, filtration_value_type birth, filtration_value_type death) { + * std::cout << "[" << dim << "] " << birth << " - " << death << std::endl; + * }); + * ``` + * + * #### Filtered_zigzag_persistence_with_storage + * ``` + * Filtered_zigzag_persistence_with_storage zp; + * ``` + * + * ### Input of the zigzag sequence/filtration + * + * In all cases, it is important that the operations of insertions and removals are made **in the same order** + * as in the zigzag filtration ones wants to compute the barcode from. + * + * #### Zigzag_persistence + * + * A face has to be identified in the boundaries by the operation number the face was inserted with in the sequence. + * + * ``` + * //inserts vertex 0 -> birth at 0 of 0-cycle + * zp.insert_face({}, 0); + * //inserts vertex 1 -> birth at 1 of 0-cycle + * zp.insert_face({}, 0); + * //inserts edge 2 = (0,1) -> death at 2 -> outputs (0, 1, 2) + * zp.insert_face({0, 1}, 1); + * //inserts vertex 3 -> birth at 3 of 0-cycle + * zp.insert_face({}, 0); + * //inserts edge 4 = (0,3) -> death at 4 -> outputs (0, 3, 4) + * zp.insert_face({0, 3}, 1); + * //inserts edge 5 = (1,3) -> birth at 5 of 1-cycle + * zp.insert_face({1, 3}, 1); + * //removes edge 4 -> death at 6 -> outputs (1, 5, 6) + * zp.remove_face(4, 1); + * //removes edge 2 -> birth at 7 of 0-cycle + * zp.remove_face(2, 1); + * ``` + * + * #### Filtered_zigzag_persistence and Filtered_zigzag_persistence_with_storage + * + * A face can be identified in the boundaries by any given numerical label, it is just important that the given + * filtration values are monotonous (ie., either only increasing or only decreasing). + * + * ``` + * //inserts vertex 2 at filtration value 0.1 -> birth at 0.1 of 0-cycle + * zp.insert_face(2, {}, 0, 0.1); + * //inserts vertex 4 at filtration value 0.1 -> birth at 0.1 of 0-cycle + * zp.insert_face(4, {}, 0, 0.1); + * //inserts edge 5 = (2,4) at filtration value 0.3 -> death at 0.3 -> outputs/stores (0, 0.1, 0.3) + * zp.insert_face(5, {2, 4}, 1, 0.3); + * //inserts vertex 3 at filtration value 0.4 -> birth at 0.4 of 0-cycle + * zp.insert_face(3, {}, 0, 0.4); + * //inserts edge 6 = (2,3) at filtration value 0.4 -> death at 0.4 of the cycle born at 0.4 -> outputs/stores nothing + * zp.insert_face(6, {2, 3}, 1, 0.4); + * //inserts edge 9 = (3,4) at filtration value 1.2 -> birth at 1.2 of 1-cycle + * zp.insert_face(9, {4, 3}, 1, 1.2); + * //removes edge 6 at filtration value 1.5 -> death at 1.5 -> outputs/stores (1, 1.2, 1.5) + * zp.remove_face(6, 1, 1.5); + * //removes edge 5 at filtration value 2.0 -> birth at 2.0 of 0-cycle + * zp.remove_face(5, 1, 2.0); + * ``` + * + * ### Finalizations + * + * For Zigzag_persistence and Filtered_zigzag_persistence, only the closed bars where output so far, so + * the open/infinite bars still need to be retrieved. For Filtered_zigzag_persistence_with_storage, the bars are + * stored within the class and where not output at all for now. + * + * #### Zigzag_persistence + * ``` + * //retrieve infinite bars, that is cycles which were born but did not die. + * //in this example, outputs (0, 0) and (0, 7) + * zp.get_current_infinite_intervals([](dimension_type dim, index_type birth){ + * std::cout << "[" << dim << "] " << birth << " - inf" << std::endl; + * }); + * ``` + * + * #### Filtered_zigzag_persistence + * ``` + * //retrieve infinite bars, that is cycles which were born but did not die. + * //in this example, outputs (0, 0.1) and (0, 2.0) + * zp.get_current_infinite_intervals([](dimension_type dim, filtration_value_type birth){ + * std::cout << "[" << dim << "] " << birth << " - inf" << std::endl; + * }); + * ``` + * + * #### Filtered_zigzag_persistence_with_storage + * ``` + * //get all bars in a vector + * auto barcode = zp.get_persistence_diagram(); + * + * //do something with the vector, e.g., stream out content: + * for (auto& bar : barcode) { + * std::cout << bar << std::endl; + * } + * ``` + * + * \subsection zzexamples More elaborate examples * - * Here is a list of zigzag persistence examples : * \li \gudhi_example_link{Zigzag_persistence,example_simple_zigzag_filtration.cpp} - A simple example to showcase how - * to use the @ref Filtered_zigzag_persistence_with_storage class. + * to use the @ref Filtered_zigzag_persistence_with_storage class within an input loop. * * \li \gudhi_example_link{Zigzag_persistence,example_zzfiltration_from_file.cpp} - An example of a "stream-like" usage * with @ref Filtered_zigzag_persistence by reading off the filtration from a file. diff --git a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h index 70413c5986..c246c1bb63 100644 --- a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h @@ -261,7 +261,7 @@ class Filtered_zigzag_persistence_with_storage * @return A vector of pairs of filtration values representing the persistence diagram. */ std::vector get_persistence_diagram(filtration_value shortestInterval = 0., - bool includeInfiniteBars = false) { + bool includeInfiniteBars = true) { std::vector diag = _get_persistence_diagram(shortestInterval); if (includeInfiniteBars) { diff --git a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h index 20731df242..e70582b1c7 100644 --- a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h @@ -446,7 +446,7 @@ class Zigzag_persistence private: Matrix_type matrix_; /**< Matrix storing a base of the current chain complex. */ - birth_dictionary births_; /**< Map face index in F to corresponding birth. */ + birth_dictionary births_; /**< Map face index in F to corresponding birth. */ Birth_ordering birthOrdering_; /**< Maintains stream_interval_; /**< Callback method for closed pairs. */ From c7edb9108afdaf346b2d298463f9967e89debcd5 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 19 Jul 2024 15:53:15 +0200 Subject: [PATCH 33/96] replacing map_index_to_filtration_value->pair with get_filtration_value_from_index->value --- .../gudhi/filtered_zigzag_persistence.h | 122 +++++++----------- .../test/test_filtered_zigzag_persistence.cpp | 5 +- 2 files changed, 51 insertions(+), 76 deletions(-) diff --git a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h index c246c1bb63..b981f825b0 100644 --- a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h @@ -141,11 +141,7 @@ class Filtered_zigzag_persistence_with_storage return numArrow_; } - if (filtrationValue != previousFiltrationValue_) // check whether the filt value has changed - { // consecutive pairs (i,f), (j,f') mean faces of index k in [i,j-1] have - previousFiltrationValue_ = filtrationValue; // filtration value f - filtrationValues_.emplace_back(numArrow_, previousFiltrationValue_); - } + _store_filtration_value(filtrationValue); [[maybe_unused]] auto res = handleToKey_.try_emplace(faceID, numArrow_); @@ -183,11 +179,7 @@ class Filtered_zigzag_persistence_with_storage auto it = handleToKey_.find(faceID); GUDHI_CHECK(it != handleToKey_.end(), "Zigzag_persistence::remove_face - face not in the complex"); - if (filtrationValue != previousFiltrationValue_) // check whether the filt value has changed - { // consecutive pairs (i,f), (j,f') mean faces of index k in [i,j-1] have - previousFiltrationValue_ = filtrationValue; // filtration value f - filtrationValues_.emplace_back(numArrow_, previousFiltrationValue_); - } + _store_filtration_value(filtrationValue); pers_.remove_face(it->second, dimension); handleToKey_.erase(it); @@ -217,47 +209,30 @@ class Filtered_zigzag_persistence_with_storage const std::vector& get_index_persistence_diagram() const { return persistenceDiagram_; } /** - * @brief Returns the filtration values \f$[f(b),f(d)]\f$ associated to the indices \f$[b,d]\f$ which are retrieved + * @brief Returns the filtration value \f$f(idx)\f$ associated to the index \f$idx\f$ returned * by @ref get_index_persistence_diagram. - * - * @param birthKey Birth index - * @param deathKey Death index - * @return A pair of filtration values associated to the given indices. + * + * @param idx Birth or death index + * @return filtration_value Filtration value associated to @p idx. */ - std::pair map_index_to_filtration_value(internal_key birthKey, - internal_key deathKey) const { - // filtration_values_ must be sorted by increasing keys. - auto itBirth = // lower_bound(x) returns leftmost y s.t. x <= y - std::lower_bound( - filtrationValues_.begin(), filtrationValues_.end(), - birthKey, - [](std::pair p, internal_key k) { - return p.first < k; - }); - if (itBirth == filtrationValues_.end() || itBirth->first > birthKey) { + filtration_value get_filtration_value_from_index(internal_key idx) { + // lower_bound(x) returns leftmost y s.t. x <= y + auto itBirth = + std::lower_bound(filtrationValues_.begin(), + filtrationValues_.end(), + idx, + [](std::pair p, internal_key k) { return p.first < k; }); + if (itBirth == filtrationValues_.end() || itBirth->first > idx) { --itBirth; } - // it points to the rightmost z such that z <= x - - auto itDeath = // - std::lower_bound( - filtrationValues_.begin(), filtrationValues_.end(), - deathKey, - [](std::pair p, internal_key k) { - return p.first < k; - }); - if (itDeath == filtrationValues_.end() || itDeath->first > deathKey) { - --itDeath; - } - - return std::make_pair(itBirth->second, itDeath->second); - } + return itBirth->second; + }; /** * @brief Returns the current persistence diagram. * * @param shortestInterval Threshold. Every bar shorter than the given value will be ignored. Default value: 0. - * @param includeInfiniteBars If set to true, infinite bars are included in the diagram. Default value: false. + * @param includeInfiniteBars If set to true, infinite bars are included in the diagram. Default value: true. * @return A vector of pairs of filtration values representing the persistence diagram. */ std::vector get_persistence_diagram(filtration_value shortestInterval = 0., @@ -272,11 +247,11 @@ class Filtered_zigzag_persistence_with_storage } private: - std::unordered_map handleToKey_; /**< Map from input keys to internal keys. */ - dimension_type dimMax_; /**< Maximal dimension of a bar to record. */ - std::vector persistenceDiagram_; /**< Stores current closed persistence intervals. */ - internal_key numArrow_; /**< Current arrow number. */ - filtration_value previousFiltrationValue_; /**< Filtration value of the previous arrow. */ + std::unordered_map handleToKey_; /**< Map from input keys to internal keys. */ + dimension_type dimMax_; /**< Maximal dimension of a bar to record. */ + std::vector persistenceDiagram_; /**< Stores current closed persistence intervals. */ + internal_key numArrow_; /**< Current arrow number. */ + filtration_value previousFiltrationValue_; /**< Filtration value of the previous arrow. */ /** * @brief filtrationValues_ stores consecutive pairs (i,f) , (j,f') with f != f', * meaning that all inserted faces with key in [i;j-1] have filtration value f, @@ -285,6 +260,21 @@ class Filtered_zigzag_persistence_with_storage std::vector > filtrationValues_; Zigzag_persistence pers_; /**< Class computing the pairs. */ + /** + * @brief Stores the filtration value if the value is new. Assumes that the given value is either greater (or equal) + * than previous ones or smaller (or equal) than previous ones. + * + * @param filtrationValue Filtration value to store. + */ + void _store_filtration_value(filtration_value filtrationValue) { + if (filtrationValue != previousFiltrationValue_) // check whether the filt value has changed + { + // consecutive pairs (i,f), (j,f') mean faces of index k in [i,j-1] have filtration value f + previousFiltrationValue_ = filtrationValue; + filtrationValues_.emplace_back(numArrow_, previousFiltrationValue_); + } + } + /** * @brief Returns the current persistence diagram without infinite bars. * @@ -301,8 +291,8 @@ class Filtered_zigzag_persistence_with_storage // }); for (auto bar : persistenceDiagram_) { - filtration_value birth, death; - std::tie(birth, death) = map_index_to_filtration_value(bar.birth, bar.death); + filtration_value birth = get_filtration_value_from_index(bar.birth); + filtration_value death = get_filtration_value_from_index(bar.death); if (birth > death) { std::swap(birth, death); } @@ -321,23 +311,9 @@ class Filtered_zigzag_persistence_with_storage * @param diag Reference to vector where to store the infinite bars. */ void _retrieve_infinite_bars(std::vector& diag) { - auto birth = [this](internal_key birthKey) { - auto itBirth = // lower_bound(x) returns leftmost y s.t. x <= y - std::lower_bound( - filtrationValues_.begin(), filtrationValues_.end(), - birthKey, - [](std::pair p, internal_key k) { - return p.first < k; - }); - if (itBirth == filtrationValues_.end() || itBirth->first > birthKey) { - --itBirth; - } - return itBirth->second; - }; - auto stream_infinite_interval = [&](dimension_type dim, internal_key birthIndex) { if (dimMax_ == -1 || (dimMax_ != -1 && dim < dimMax_)) - diag.emplace_back(birth(birthIndex), Filtration_value_interval::inf, dim); + diag.emplace_back(get_filtration_value_from_index(birthIndex), Filtration_value_interval::inf, dim); }; pers_.get_current_infinite_intervals(stream_infinite_interval); @@ -359,11 +335,11 @@ class Filtered_zigzag_persistence_with_storage template class Filtered_zigzag_persistence { public: - using Options = FilteredZigzagOptions; /**< Zigzag options. */ - using internal_key = typename Options::internal_key; /**< Key and index type, has to be signed. */ - using face_key = typename Options::face_key; /**< Face ID type from external inputs. */ - using filtration_value = typename Options::filtration_value; /**< Type for filtration values. */ - using dimension_type = typename Options::dimension_type; /**< Type for dimension values. */ + using Options = FilteredZigzagOptions; /**< Zigzag options. */ + using internal_key = typename Options::internal_key; /**< Key and index type, has to be signed. */ + using face_key = typename Options::face_key; /**< Face ID type from external inputs. */ + using filtration_value = typename Options::filtration_value; /**< Type for filtration values. */ + using dimension_type = typename Options::dimension_type; /**< Type for dimension values. */ /** * @brief Constructor. @@ -479,10 +455,10 @@ class Filtered_zigzag_persistence { template using dictionary = std::unordered_map; // TODO: benchmark with other map types - dictionary handleToKey_; /**< Map from input keys to internal keys. */ - internal_key numArrow_; /**< Current arrow number. */ - dictionary keyToFiltrationValue_; /**< Face Key to filtration value map. */ - Zigzag_persistence pers_; /**< Class computing the pairs. */ + dictionary handleToKey_; /**< Map from input keys to internal keys. */ + internal_key numArrow_; /**< Current arrow number. */ + dictionary keyToFiltrationValue_; /**< Face Key to filtration value map. */ + Zigzag_persistence pers_; /**< Class computing the pairs. */ }; // end class Filtered_zigzag_persistence } // namespace zigzag_persistence diff --git a/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp b/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp index 702590aa46..111892bc85 100644 --- a/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp +++ b/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp @@ -73,9 +73,8 @@ void test_indices(ZP& zp, std::vector& indices, BOOST_CHECK_EQUAL(interval.dim, it->dim); BOOST_CHECK_EQUAL(interval.birth, it->birth); BOOST_CHECK_EQUAL(interval.death, it->death); - auto p = zp.map_index_to_filtration_value(interval.birth, interval.death); - BOOST_CHECK_EQUAL(p.first, indexToFil[interval.birth]); - BOOST_CHECK_EQUAL(p.second, indexToFil[interval.death]); + BOOST_CHECK_EQUAL(zp.get_filtration_value_from_index(interval.birth), indexToFil[interval.birth]); + BOOST_CHECK_EQUAL(zp.get_filtration_value_from_index(interval.death), indexToFil[interval.death]); ++it; } BOOST_CHECK(it == indices.end()); From 34721602983d2c6b8ca650aa37b40b8e6409b49e Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 19 Jul 2024 17:37:14 +0200 Subject: [PATCH 34/96] doc --- src/Zigzag_persistence/concept/ZigzagOptions.h | 1 + .../include/gudhi/filtered_zigzag_persistence.h | 13 ++++++++----- .../include/gudhi/zigzag_persistence.h | 13 +++++-------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/Zigzag_persistence/concept/ZigzagOptions.h b/src/Zigzag_persistence/concept/ZigzagOptions.h index 712d5df2a1..af9636a720 100644 --- a/src/Zigzag_persistence/concept/ZigzagOptions.h +++ b/src/Zigzag_persistence/concept/ZigzagOptions.h @@ -32,6 +32,7 @@ struct FilteredZigzagOptions { /** * @brief Type for the face IDs used at insertion and in the boundaries given as argument. + * Has to be usable as key in a hashtable, so "hashable" and comparable. */ using face_key = unspecified; diff --git a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h index b981f825b0..f0a0a92f48 100644 --- a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h @@ -352,18 +352,21 @@ class Filtered_zigzag_persistence { * Has to take three arguments as input: first the dimension of the cycle, then the birth value of the cycle * and third the death value of the cycle. The values corresponds to the filtration values which were given at * insertions or removals. - * @param preallocationSize Minimum number of faces that will be in a complex at some point in the filtration. - * If the maximal number of faces is known in advance, the memory allocation can be better optimized. - * Default value: 0. + * @param preallocationSize Space for @p preallocationSize faces are reserved in the underlying structure. + * Theoretically, any values works therefore, but for better performances, it is better to be as close as possible + * to the maximal value of the number of faces stored at the same time. At a same time are stored faces which were + * inserted before that time but not removed until that time. Default value: 0. * @tparam F Type of callback method. */ - template + template Filtered_zigzag_persistence(F&& stream_interval, unsigned int preallocationSize = 0) : handleToKey_(preallocationSize), numArrow_(-1), keyToFiltrationValue_(preallocationSize), pers_( - [&,stream_interval](dimension_type dim, internal_key birth, internal_key death) { + [&, stream_interval = std::forward(stream_interval)](dimension_type dim, + internal_key birth, + internal_key death) { auto itB = keyToFiltrationValue_.find(birth); auto itD = keyToFiltrationValue_.find(death); if (itB->second != itD->second) stream_interval(dim, itB->second, itD->second); diff --git a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h index e70582b1c7..d266935867 100644 --- a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h @@ -199,9 +199,10 @@ class Zigzag_persistence * as input: first the dimension of the cycle, then the birth index of the cycle and third the death index of the * cycle. An index always corresponds to the arrow number the event occurred (one call to @ref insert_face, * @ref remove_face or @ref apply_identity is equal to one arrow and increases the arrow count by one). - * @param preallocationSize Maximal value among the minimum numbers of faces known to be at the same time in each - * complex of the filtration. It will be used to optimize the memory allocation. - * Default value: 0. + * @param preallocationSize Space for @p preallocationSize faces are reserved in the underlying structure. + * Theoretically, any values works therefore, but for better performances, it is better to be as close as possible + * to the maximal value of the number of faces stored at the same time. At a same time are stored faces which were + * inserted before that time but not removed until that time. Default value: 0. */ Zigzag_persistence(std::function stream_interval, unsigned int preallocationSize = 0) @@ -299,11 +300,7 @@ class Zigzag_persistence _apply_surjective_reflection_diamond(dim, chainsInF); } else { birthOrdering_.add_birth_forward(numArrow_); - if constexpr (erase_birth_history) { - births_.emplace_hint(births_.end(), matrix_.get_column_with_pivot(numArrow_), numArrow_); - } else { - births_[matrix_.get_column_with_pivot(numArrow_)] = numArrow_; - } + births_[matrix_.get_column_with_pivot(numArrow_)] = numArrow_; } } From 744ac4702749246e4114a67c1f5636e3e8033576 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Mon, 22 Jul 2024 14:38:23 +0200 Subject: [PATCH 35/96] dim bug fix --- .../concept/ZigzagOptions.h | 4 +- .../doc/Intro_zigzag_persistence.h | 8 ++-- .../example_simple_zigzag_filtration.cpp | 3 +- .../example_zzfiltration_from_file.cpp | 2 +- .../gudhi/filtered_zigzag_persistence.h | 47 ++++++++++--------- .../include/gudhi/zigzag_persistence.h | 18 +++---- .../test/test_filtered_zigzag_persistence.cpp | 28 +++++------ .../test/test_zigzag_persistence.cpp | 12 ++--- 8 files changed, 62 insertions(+), 60 deletions(-) diff --git a/src/Zigzag_persistence/concept/ZigzagOptions.h b/src/Zigzag_persistence/concept/ZigzagOptions.h index af9636a720..cc83a8285e 100644 --- a/src/Zigzag_persistence/concept/ZigzagOptions.h +++ b/src/Zigzag_persistence/concept/ZigzagOptions.h @@ -26,7 +26,7 @@ namespace zigzag_persistence { */ struct FilteredZigzagOptions { /** - * @brief Type for the face IDs used internally and other indexations. It must be signed. + * @brief Numerical type for the face IDs used internally and other indexations. It must be signed. */ using internal_key = unspecified; @@ -59,7 +59,7 @@ struct FilteredZigzagOptions { */ struct ZigzagOptions { /** - * @brief Type for the face IDs used internally and other indexations. It must be signed. + * @brief Numerical type for the face IDs used internally and other indexations. It must be signed. */ using internal_key = unspecified; diff --git a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h index ed9d4fc540..0524713c7f 100644 --- a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h +++ b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h @@ -126,9 +126,9 @@ namespace zigzag_persistence { * //inserts edge 5 = (1,3) -> birth at 5 of 1-cycle * zp.insert_face({1, 3}, 1); * //removes edge 4 -> death at 6 -> outputs (1, 5, 6) - * zp.remove_face(4, 1); + * zp.remove_face(4); * //removes edge 2 -> birth at 7 of 0-cycle - * zp.remove_face(2, 1); + * zp.remove_face(2); * ``` * * #### Filtered_zigzag_persistence and Filtered_zigzag_persistence_with_storage @@ -150,9 +150,9 @@ namespace zigzag_persistence { * //inserts edge 9 = (3,4) at filtration value 1.2 -> birth at 1.2 of 1-cycle * zp.insert_face(9, {4, 3}, 1, 1.2); * //removes edge 6 at filtration value 1.5 -> death at 1.5 -> outputs/stores (1, 1.2, 1.5) - * zp.remove_face(6, 1, 1.5); + * zp.remove_face(6, 1.5); * //removes edge 5 at filtration value 2.0 -> birth at 2.0 of 0-cycle - * zp.remove_face(5, 1, 2.0); + * zp.remove_face(5, 2.0); * ``` * * ### Finalizations diff --git a/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp b/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp index 012893adf5..17dcdb816f 100644 --- a/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp +++ b/src/Zigzag_persistence/example/example_simple_zigzag_filtration.cpp @@ -128,8 +128,7 @@ int main(int argc, char* const argv[]) { zp.insert_face(i, simplices[i], dim, fils[i]); } else { auto id = simplices[i][0]; - int dim = simplices[id].size() == 0 ? 0 : simplices[id].size() - 1; - zp.remove_face(id, dim, fils[i]); + zp.remove_face(id, fils[i]); } } diff --git a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp index e4da46e969..5f85f2a900 100644 --- a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp +++ b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp @@ -103,7 +103,7 @@ int main(int argc, char* const argv[]) { zp.insert_face(id, data, dim, timestamp); } else if (type == REMOVAL) { ++id; - zp.remove_face(data[0], data[1], timestamp); + zp.remove_face(data[0], timestamp); } } diff --git a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h index f0a0a92f48..01ec87d042 100644 --- a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h @@ -134,13 +134,12 @@ class Filtered_zigzag_persistence_with_storage dimension_type dimension, filtration_value filtrationValue) { - ++numArrow_; - if (dimMax_ != -1 && dimension > dimMax_) { - pers_.apply_identity(); - return numArrow_; + return apply_identity(); } + ++numArrow_; + _store_filtration_value(filtrationValue); [[maybe_unused]] auto res = handleToKey_.try_emplace(faceID, numArrow_); @@ -159,29 +158,28 @@ class Filtered_zigzag_persistence_with_storage } /** - * @brief Updates the zigzag persistence diagram after the removal of the given face. + * @brief Updates the zigzag persistence diagram after the removal of the given face if the face was contained + * in the current complex (note that it will not contain faces of dimension > ignoreCyclesAboveDim if the latter was + * non negative at construction of the class). Otherwise, just increases the operation count by one. * * @param faceID ID representing the face to remove. Should be the same than the one used to insert it. - * @param dimension Dimension of the face. * @param filtrationValue Filtration value associated to the removal. * Assumed to be always larger or equal to previously used filtration values or always smaller or equal than previous * values, ie. the changes are monotonous. * @return Number of the operation. */ - internal_key remove_face(face_key faceID, dimension_type dimension, filtration_value filtrationValue) { - ++numArrow_; + internal_key remove_face(face_key faceID, filtration_value filtrationValue) { + auto it = handleToKey_.find(faceID); - if (dimMax_ != -1 && dimension > dimMax_) { - pers_.apply_identity(); - return numArrow_; + if (it == handleToKey_.end()) { + return apply_identity(); } - auto it = handleToKey_.find(faceID); - GUDHI_CHECK(it != handleToKey_.end(), "Zigzag_persistence::remove_face - face not in the complex"); + ++numArrow_; _store_filtration_value(filtrationValue); - pers_.remove_face(it->second, dimension); + pers_.remove_face(it->second); handleToKey_.erase(it); return numArrow_; @@ -389,10 +387,11 @@ class Filtered_zigzag_persistence { * values, ie. the changes are monotonous. */ template > - void insert_face(face_key faceID, - const BoundaryRange& boundary, - dimension_type dimension, - filtration_value filtrationValue) { + internal_key insert_face(face_key faceID, + const BoundaryRange& boundary, + dimension_type dimension, + filtration_value filtrationValue) + { ++numArrow_; [[maybe_unused]] auto res = handleToKey_.try_emplace(faceID, numArrow_); @@ -408,18 +407,19 @@ class Filtered_zigzag_persistence { } pers_.insert_face(translatedBoundary, dimension); + + return numArrow_; } /** * @brief Updates the zigzag persistence diagram after the removal of the given face. * * @param faceID ID representing the face to remove. Should be the same than the one used to insert it. - * @param dimension Dimension of the face. * @param filtrationValue Filtration value associated to the removal. * Assumed to be always larger or equal to previously used filtration values or always smaller or equal than previous * values, ie. the changes are monotonous. */ - void remove_face(face_key faceID, dimension_type dimension, filtration_value filtrationValue) { + internal_key remove_face(face_key faceID, filtration_value filtrationValue) { ++numArrow_; auto it = handleToKey_.find(faceID); @@ -427,8 +427,10 @@ class Filtered_zigzag_persistence { keyToFiltrationValue_.try_emplace(numArrow_, filtrationValue); - pers_.remove_face(it->second, dimension); + pers_.remove_face(it->second); handleToKey_.erase(it); + + return numArrow_; } /** @@ -436,9 +438,10 @@ class Filtered_zigzag_persistence { * on homology level. Useful to keep the birth/death indices aligned when insertions/removals are purposely skipped * to avoid useless computation. */ - void apply_identity() { + internal_key apply_identity() { ++numArrow_; pers_.apply_identity(); + return numArrow_; } /** diff --git a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h index d266935867..3bca4df194 100644 --- a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h @@ -239,12 +239,11 @@ class Zigzag_persistence * @brief Updates the zigzag persistence diagram after the removal of the given face. * * @param arrowNumber Arrow number of when the face to remove was inserted for the last time. - * @param dimension Dimension of the face to remove. * @return Number of the operation. */ - index remove_face(index arrowNumber, dimension_type dimension) { + index remove_face(index arrowNumber) { ++numArrow_; - _process_backward_arrow(arrowNumber, dimension); + _process_backward_arrow(arrowNumber); return numArrow_; } @@ -294,7 +293,7 @@ class Zigzag_persistence */ template void _process_forward_arrow(const BoundaryRange& boundary, dimension_type dim) { - std::vector chainsInF = matrix_.insert_boundary(numArrow_, boundary); + std::vector chainsInF = matrix_.insert_boundary(numArrow_, boundary, dim); if (!chainsInF.empty()) { _apply_surjective_reflection_diamond(dim, chainsInF); @@ -396,7 +395,7 @@ class Zigzag_persistence * @param faceID Internal ID of the face to remove. * @param dim Dimension of the face to remove. */ - void _process_backward_arrow(index faceID, dimension_type dim) { + void _process_backward_arrow(index faceID) { // column whose key is the one of the removed face matrix_index currCol = matrix_.get_column_with_pivot(faceID); @@ -417,9 +416,10 @@ class Zigzag_persistence } // curr_col points to the column to remove by restriction of K to K-{\sigma} - if (!matrix_.get_column(currCol).is_paired()) { // in F + auto& col = matrix_.get_column(currCol); + if (!col.is_paired()) { // in F auto it = births_.find(currCol); - stream_interval_(dim, it->second, numArrow_); + stream_interval_(col.get_dimension(), it->second, numArrow_); if constexpr (erase_birth_history) { birthOrdering_.remove_birth(it->second); births_.erase(it); @@ -428,9 +428,9 @@ class Zigzag_persistence // maintain the <=b order birthOrdering_.add_birth_backward(numArrow_); if constexpr (erase_birth_history) { - births_.try_emplace(matrix_.get_column(currCol).get_paired_chain_index(), numArrow_); + births_.try_emplace(col.get_paired_chain_index(), numArrow_); } else { - auto res = births_.try_emplace(matrix_.get_column(currCol).get_paired_chain_index(), numArrow_); + auto res = births_.try_emplace(col.get_paired_chain_index(), numArrow_); if (!res.second) { res.first->second = numArrow_; } diff --git a/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp b/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp index 111892bc85..6219f63bdd 100644 --- a/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp +++ b/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp @@ -160,7 +160,7 @@ void test_filtered_zigzag_with_storage() { for (unsigned int i = 14; i < 16; ++i) { auto id = simplices[i][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + zp.remove_face(id, filValues[i]); } for (unsigned int i = 16; i < 24; ++i) { @@ -179,7 +179,7 @@ void test_filtered_zigzag_with_storage() { for (unsigned int i = 24; i < 27; ++i) { auto id = simplices[i][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + zp.remove_face(id, filValues[i]); } realIndices.emplace_back(24, 25, 1); @@ -191,7 +191,7 @@ void test_filtered_zigzag_with_storage() { realBarcode.emplace_back(7, 9, 2); auto id = simplices[28][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[28]); + zp.remove_face(id, filValues[28]); realBarcode.emplace_back(0, Interval_filtration::inf, 0); realBarcode.emplace_back(9, Interval_filtration::inf, 0); @@ -231,7 +231,7 @@ void test_filtered_zigzag_with_storage_max1() { for (unsigned int i = 14; i < 16; ++i) { auto id = simplices[i][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + zp.remove_face(id, filValues[i]); } for (unsigned int i = 16; i < 24; ++i) { @@ -243,12 +243,12 @@ void test_filtered_zigzag_with_storage_max1() { for (unsigned int i = 24; i < 27; ++i) { auto id = simplices[i][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + zp.remove_face(id, filValues[i]); } zp.insert_face(27, simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1, filValues[27]); auto id = simplices[28][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[28]); + zp.remove_face(id, filValues[28]); realBarcode.emplace_back(0, Interval_filtration::inf, 0); realBarcode.emplace_back(9, Interval_filtration::inf, 0); @@ -319,7 +319,7 @@ void test_filtered_zigzag() { for (unsigned int i = 14; i < 16; ++i) { interval = realBarcode[i]; auto id = simplices[i][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + zp.remove_face(id, filValues[i]); } for (unsigned int i = 16; i < 24; ++i) { @@ -330,7 +330,7 @@ void test_filtered_zigzag() { for (unsigned int i = 24; i < 27; ++i) { interval = realBarcode[i]; auto id = simplices[i][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + zp.remove_face(id, filValues[i]); } interval = realBarcode[27]; @@ -338,9 +338,9 @@ void test_filtered_zigzag() { interval = realBarcode[28]; auto id = simplices[28][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[28]); + zp.remove_face(id, filValues[28]); - //there is no real garantee on the order of the infinite bars + //there is no real guarantee on the order of the infinite bars std::vector infiniteBars; zp.get_current_infinite_intervals([&](dimension_type dim, filtration_value birth) { infiniteBars.emplace_back(dim, birth, std::numeric_limits::infinity()); @@ -423,7 +423,7 @@ void test_filtered_zigzag_max1() { for (unsigned int i = 14; i < 16; ++i) { interval = realBarcode[i]; auto id = simplices[i][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + zp.remove_face(id, filValues[i]); } for (unsigned int i = 16; i < 24; ++i) { @@ -434,7 +434,7 @@ void test_filtered_zigzag_max1() { for (unsigned int i = 24; i < 27; ++i) { interval = realBarcode[i]; auto id = simplices[i][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[i]); + zp.remove_face(id, filValues[i]); } interval = realBarcode[27]; @@ -442,9 +442,9 @@ void test_filtered_zigzag_max1() { interval = realBarcode[28]; auto id = simplices[28][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1, filValues[28]); + zp.remove_face(id, filValues[28]); - //there is no real garantee on the order of the infinite bars + //there is no real guarantee on the order of the infinite bars std::vector infiniteBars; zp.get_current_infinite_intervals([&](dimension_type dim, filtration_value birth) { if (dim < 1){ diff --git a/src/Zigzag_persistence/test/test_zigzag_persistence.cpp b/src/Zigzag_persistence/test/test_zigzag_persistence.cpp index 8dd3a7b032..99eb62f375 100644 --- a/src/Zigzag_persistence/test/test_zigzag_persistence.cpp +++ b/src/Zigzag_persistence/test/test_zigzag_persistence.cpp @@ -109,7 +109,7 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single) { for (unsigned int i = 14; i < 16; ++i) { auto id = simplices[i][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1); + zp.remove_face(id); } for (unsigned int i = 16; i < 24; ++i) { @@ -124,7 +124,7 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single) { for (unsigned int i = 24; i < 27; ++i) { auto id = simplices[i][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1); + zp.remove_face(id); } realIndices.emplace_back(1, 24, 25); @@ -134,7 +134,7 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single) { realIndices.emplace_back(2, 23, 27); auto id = simplices[28][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1); + zp.remove_face(id); realIndices.emplace_back(0, 0, -1); realIndices.emplace_back(0, 26, -1); @@ -175,7 +175,7 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single_max1) { for (unsigned int i = 14; i < 16; ++i) { auto id = simplices[i][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1); + zp.remove_face(id); } for (unsigned int i = 16; i < 24; ++i) { @@ -186,12 +186,12 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single_max1) { for (unsigned int i = 24; i < 27; ++i) { auto id = simplices[i][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1); + zp.remove_face(id); } zp.insert_face(simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1); auto id = simplices[28][0]; - zp.remove_face(id, simplices[id].size() == 0 ? 0 : simplices[id].size() - 1); + zp.remove_face(id); realIndices.emplace_back(0, 0, -1); realIndices.emplace_back(0, 26, -1); From 7d84dbfa984c79c6f4bb5da8b34206d3ea161859 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Mon, 22 Jul 2024 18:05:02 +0200 Subject: [PATCH 36/96] doc --- .../doc/Intro_zigzag_persistence.h | 154 ++---------------- src/Zigzag_persistence/example/CMakeLists.txt | 14 +- ...ample_zigzag_filtration_as_input_loop.cpp} | 0 .../gudhi/filtered_zigzag_persistence.h | 136 ++++++++++++++-- .../include/gudhi/zigzag_persistence.h | 76 +++++++-- src/common/doc/examples.h | 5 +- 6 files changed, 222 insertions(+), 163 deletions(-) rename src/Zigzag_persistence/example/{example_simple_zigzag_filtration.cpp => example_zigzag_filtration_as_input_loop.cpp} (100%) diff --git a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h index 0524713c7f..9c5537b230 100644 --- a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h +++ b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h @@ -55,146 +55,28 @@ namespace zigzag_persistence { * * \section zigzagexamples Examples * - * \subsection zzminusage Minimalistic example of usage - * - * ### Includes - * - * #### Zigzag_persistence - * ``` - * #include - * ``` - * #### Filtered_zigzag_persistence and Filtered_zigzag_persistence_with_storage - * ``` - * #include - * ``` - * - * ### Useful aliases - * - * ``` - * using Zigzag_persistence = Gudhi::zigzag_persistence::Zigzag_persistence<>; - * using Filtered_zigzag_persistence = Gudhi::zigzag_persistence::Filtered_zigzag_persistence<>; - * using Filtered_zigzag_persistence_with_storage = Gudhi::zigzag_persistence::Filtered_zigzag_persistence_with_storage<>; - * - * using dimension_type = Zigzag_persistence::dimension_type; - * using index_type = Zigzag_persistence::index; - * using filtration_value_type = Filtered_zigzag_persistence::filtration_value; - * ``` - * - * ### Construction with default values - * - * #### Zigzag_persistence - * ``` - * //Zigzag_persistence(callback) with for example callback method as a anonymous lambda - * Zigzag_persistence zp([](dimension_type dim, index_type birth, index_type death) { - * std::cout << "[" << dim << "] " << birth << " - " << death << std::endl; - * }); - * ``` - * - * #### Filtered_zigzag_persistence - * ``` - * //Filtered_zigzag_persistence(callback) with for example callback method as a anonymous lambda - * Filtered_zigzag_persistence zp([](dimension_type dim, filtration_value_type birth, filtration_value_type death) { - * std::cout << "[" << dim << "] " << birth << " - " << death << std::endl; - * }); - * ``` - * - * #### Filtered_zigzag_persistence_with_storage - * ``` - * Filtered_zigzag_persistence_with_storage zp; - * ``` - * - * ### Input of the zigzag sequence/filtration - * - * In all cases, it is important that the operations of insertions and removals are made **in the same order** - * as in the zigzag filtration ones wants to compute the barcode from. - * - * #### Zigzag_persistence - * - * A face has to be identified in the boundaries by the operation number the face was inserted with in the sequence. - * - * ``` - * //inserts vertex 0 -> birth at 0 of 0-cycle - * zp.insert_face({}, 0); - * //inserts vertex 1 -> birth at 1 of 0-cycle - * zp.insert_face({}, 0); - * //inserts edge 2 = (0,1) -> death at 2 -> outputs (0, 1, 2) - * zp.insert_face({0, 1}, 1); - * //inserts vertex 3 -> birth at 3 of 0-cycle - * zp.insert_face({}, 0); - * //inserts edge 4 = (0,3) -> death at 4 -> outputs (0, 3, 4) - * zp.insert_face({0, 3}, 1); - * //inserts edge 5 = (1,3) -> birth at 5 of 1-cycle - * zp.insert_face({1, 3}, 1); - * //removes edge 4 -> death at 6 -> outputs (1, 5, 6) - * zp.remove_face(4); - * //removes edge 2 -> birth at 7 of 0-cycle - * zp.remove_face(2); - * ``` - * - * #### Filtered_zigzag_persistence and Filtered_zigzag_persistence_with_storage - * - * A face can be identified in the boundaries by any given numerical label, it is just important that the given - * filtration values are monotonous (ie., either only increasing or only decreasing). - * - * ``` - * //inserts vertex 2 at filtration value 0.1 -> birth at 0.1 of 0-cycle - * zp.insert_face(2, {}, 0, 0.1); - * //inserts vertex 4 at filtration value 0.1 -> birth at 0.1 of 0-cycle - * zp.insert_face(4, {}, 0, 0.1); - * //inserts edge 5 = (2,4) at filtration value 0.3 -> death at 0.3 -> outputs/stores (0, 0.1, 0.3) - * zp.insert_face(5, {2, 4}, 1, 0.3); - * //inserts vertex 3 at filtration value 0.4 -> birth at 0.4 of 0-cycle - * zp.insert_face(3, {}, 0, 0.4); - * //inserts edge 6 = (2,3) at filtration value 0.4 -> death at 0.4 of the cycle born at 0.4 -> outputs/stores nothing - * zp.insert_face(6, {2, 3}, 1, 0.4); - * //inserts edge 9 = (3,4) at filtration value 1.2 -> birth at 1.2 of 1-cycle - * zp.insert_face(9, {4, 3}, 1, 1.2); - * //removes edge 6 at filtration value 1.5 -> death at 1.5 -> outputs/stores (1, 1.2, 1.5) - * zp.remove_face(6, 1.5); - * //removes edge 5 at filtration value 2.0 -> birth at 2.0 of 0-cycle - * zp.remove_face(5, 2.0); - * ``` - * - * ### Finalizations - * - * For Zigzag_persistence and Filtered_zigzag_persistence, only the closed bars where output so far, so - * the open/infinite bars still need to be retrieved. For Filtered_zigzag_persistence_with_storage, the bars are - * stored within the class and where not output at all for now. - * - * #### Zigzag_persistence - * ``` - * //retrieve infinite bars, that is cycles which were born but did not die. - * //in this example, outputs (0, 0) and (0, 7) - * zp.get_current_infinite_intervals([](dimension_type dim, index_type birth){ - * std::cout << "[" << dim << "] " << birth << " - inf" << std::endl; - * }); - * ``` - * - * #### Filtered_zigzag_persistence - * ``` - * //retrieve infinite bars, that is cycles which were born but did not die. - * //in this example, outputs (0, 0.1) and (0, 2.0) - * zp.get_current_infinite_intervals([](dimension_type dim, filtration_value_type birth){ - * std::cout << "[" << dim << "] " << birth << " - inf" << std::endl; - * }); - * ``` - * - * #### Filtered_zigzag_persistence_with_storage - * ``` - * //get all bars in a vector - * auto barcode = zp.get_persistence_diagram(); - * - * //do something with the vector, e.g., stream out content: - * for (auto& bar : barcode) { - * std::cout << bar << std::endl; - * } - * ``` + * \subsection zzminusage Minimalistic examples + * + * \li \gudhi_example_link{Zigzag_persistence,example_usage_zigzag_persistence.cpp} - A simple example to showcase how + * to use the @ref Zigzag_persistence class to compute a barcode. + *

+ * @include example_usage_zigzag_persistence.cpp + *
+ * \li \gudhi_example_link{Zigzag_persistence,example_usage_filtered_zigzag_persistence.cpp} - A simple example to + * showcase how to use the @ref Filtered_zigzag_persistence class to compute a barcode. + *
+ * @include example_usage_filtered_zigzag_persistence.cpp + *
+ * \li \gudhi_example_link{Zigzag_persistence,example_usage_filtered_zigzag_persistence_with_storage.cpp} - A simple + * example to showcase how to use the @ref Filtered_zigzag_persistence_with_storage class to compute a barcode. + *
+ * @include example_usage_filtered_zigzag_persistence_with_storage.cpp + *
* * \subsection zzexamples More elaborate examples * - * \li \gudhi_example_link{Zigzag_persistence,example_simple_zigzag_filtration.cpp} - A simple example to showcase how + * \li \gudhi_example_link{Zigzag_persistence,example_zigzag_filtration_as_input_loop.cpp} - A simple example to showcase how * to use the @ref Filtered_zigzag_persistence_with_storage class within an input loop. - * * \li \gudhi_example_link{Zigzag_persistence,example_zzfiltration_from_file.cpp} - An example of a "stream-like" usage * with @ref Filtered_zigzag_persistence by reading off the filtration from a file. * diff --git a/src/Zigzag_persistence/example/CMakeLists.txt b/src/Zigzag_persistence/example/CMakeLists.txt index 0cb6521839..ac434df9e6 100644 --- a/src/Zigzag_persistence/example/CMakeLists.txt +++ b/src/Zigzag_persistence/example/CMakeLists.txt @@ -1,7 +1,16 @@ project(Zigzag_persistence_examples) -add_executable_with_targets(Zigzag_persistence_example_simple_zigzag_filtration example_simple_zigzag_filtration.cpp TBB::tbb) -add_test(NAME Zigzag_persistence_example_simple_zigzag_filtration COMMAND $) +add_executable_with_targets(Zigzag_persistence_example_usage_zigzag_persistence example_usage_zigzag_persistence.cpp TBB::tbb) +add_test(NAME Zigzag_persistence_example_usage_zigzag_persistence COMMAND $) + +add_executable_with_targets(Zigzag_persistence_example_usage_filtered_zigzag_persistence example_usage_filtered_zigzag_persistence.cpp TBB::tbb) +add_test(NAME Zigzag_persistence_example_usage_filtered_zigzag_persistence COMMAND $) + +add_executable_with_targets(Zigzag_persistence_example_usage_filtered_zigzag_persistence_with_storage example_usage_filtered_zigzag_persistence_with_storage.cpp TBB::tbb) +add_test(NAME Zigzag_persistence_example_usage_filtered_zigzag_persistence_with_storage COMMAND $) + +add_executable_with_targets(Zigzag_persistence_example_zigzag_filtration_as_input_loop example_zigzag_filtration_as_input_loop.cpp TBB::tbb) +add_test(NAME Zigzag_persistence_example_zigzag_filtration_as_input_loop COMMAND $) add_executable_with_targets(Zigzag_persistence_example_zzfiltration_from_file example_zzfiltration_from_file.cpp TBB::tbb) file(COPY "zigzag_filtration_example.txt" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) @@ -9,3 +18,4 @@ add_test(NAME Zigzag_persistence_example_zzfiltration_from_file COMMAND $ + * ``` + * + * #### Useful aliases + * ``` + * using Filtered_zigzag_persistence_with_storage = Gudhi::zigzag_persistence::Filtered_zigzag_persistence_with_storage<>; + * ``` + * + * #### Construction with default values + * ``` + * Filtered_zigzag_persistence_with_storage zp; + * ``` + * + * #### Input of the zigzag sequence/filtration + * ``` + * // In all cases, it is important that the operations of insertions and removals are made **in the same order** + * // as in the zigzag filtration ones wants to compute the barcode from. + * + * // A face can be identified in the boundaries by any given numerical label, it is just important that the given + * // filtration values are monotonous (ie., either only increasing or only decreasing). + * + * //inserts vertex 2 at filtration value 0.1 -> birth at 0.1 of 0-cycle + * zp.insert_face(2, {}, 0, 0.1); + * //inserts vertex 4 at filtration value 0.1 -> birth at 0.1 of 0-cycle + * zp.insert_face(4, {}, 0, 0.1); + * //inserts edge 5 = (2,4) at filtration value 0.3 -> death at 0.3 -> outputs/stores (0, 0.1, 0.3) + * zp.insert_face(5, {2, 4}, 1, 0.3); + * //inserts vertex 3 at filtration value 0.4 -> birth at 0.4 of 0-cycle + * zp.insert_face(3, {}, 0, 0.4); + * //inserts edge 6 = (2,3) at filtration value 0.4 -> death at 0.4 of the cycle born at 0.4 -> outputs/stores nothing + * zp.insert_face(6, {2, 3}, 1, 0.4); + * //inserts edge 9 = (3,4) at filtration value 1.2 -> birth at 1.2 of 1-cycle + * zp.insert_face(9, {4, 3}, 1, 1.2); + * //removes edge 6 at filtration value 1.5 -> death at 1.5 -> outputs/stores (1, 1.2, 1.5) + * zp.remove_face(6, 1.5); + * //removes edge 5 at filtration value 2.0 -> birth at 2.0 of 0-cycle + * zp.remove_face(5, 2.0); + * ``` + * + * #### Finalizations + * ``` + * // The bars are stored within the class and where not output at all for now. + * + * //get all bars in a vector + * auto barcode = zp.get_persistence_diagram(); + * + * //do something with the vector, e.g., stream out content: + * for (auto& bar : barcode) { + * std::cout << bar << std::endl; + * } + * ``` * * @tparam FilteredZigzagOptions Structure following the @ref FilteredZigzagOptions concept. * Default value: @ref Default_filtered_zigzag_options. @@ -94,10 +150,10 @@ class Filtered_zigzag_persistence_with_storage * the filtration. To retrieve the current persistence diagram at any moment of the filtration, * use @ref get_persistence_diagram or @ref get_index_persistence_diagram. * - * @param preallocationSize Space for @p preallocationSize faces are reserved in the underlying structure. - * Theoretically, any values works therefore, but for better performances, it is better to be as close as possible - * to the maximal value of the number of faces stored at the same time. At a same time are stored faces which were - * inserted before that time but not removed until that time. Default value: 0. + * @param preallocationSize Reserves space for @p preallocationSize faces in the internal data structure. + * This is optional and just helps skip a few reallocations. The optimal value (no reallocation, no wasted space) is + * the number of faces in the biggest complex of the filtration. + * Default value: 0. * @param ignoreCyclesAboveDim Ignores cycles in dimension larger or equal in the final diagram. * If -1, no cycles are ignored. Default value: -1. */ @@ -229,7 +285,7 @@ class Filtered_zigzag_persistence_with_storage /** * @brief Returns the current persistence diagram. * - * @param shortestInterval Threshold. Every bar shorter than the given value will be ignored. Default value: 0. + * @param shortestInterval Threshold. Every bar shorter than the given value will not be returned. Default value: 0. * @param includeInfiniteBars If set to true, infinite bars are included in the diagram. Default value: true. * @return A vector of pairs of filtration values representing the persistence diagram. */ @@ -326,6 +382,64 @@ class Filtered_zigzag_persistence_with_storage * call @ref insert_face, @ref remove_face or @ref apply_identity for each step of the filtration in order of * the filtration. The bars of the diagram are retrieved via the given callback method every time * a pair with non-zero length is closed. To retrieve the open/infinite bars, use @ref get_current_infinite_intervals. + * + * ### Minimalistic example of usage + * + * #### Includes + * ``` + * #include + * ``` + * + * #### Useful aliases + * ``` + * using Filtered_zigzag_persistence = Gudhi::zigzag_persistence::Filtered_zigzag_persistence<>; + * using dimension_type = Filtered_zigzag_persistence::dimension_type; + * using filtration_value_type = Filtered_zigzag_persistence::filtration_value; + * ``` + * + * #### Construction with default values + * ``` + * //Filtered_zigzag_persistence(callback) with for example callback method as a anonymous lambda + * Filtered_zigzag_persistence zp([](dimension_type dim, filtration_value_type birth, filtration_value_type death) { + * std::cout << "[" << dim << "] " << birth << " - " << death << std::endl; + * }); + * ``` + * + * #### Input of the zigzag sequence/filtration + * ``` + * // In all cases, it is important that the operations of insertions and removals are made **in the same order** + * // as in the zigzag filtration ones wants to compute the barcode from. + * + * // A face can be identified in the boundaries by any given numerical label, it is just important that the given + * // filtration values are monotonous (ie., either only increasing or only decreasing). + * + * //inserts vertex 2 at filtration value 0.1 -> birth at 0.1 of 0-cycle + * zp.insert_face(2, {}, 0, 0.1); + * //inserts vertex 4 at filtration value 0.1 -> birth at 0.1 of 0-cycle + * zp.insert_face(4, {}, 0, 0.1); + * //inserts edge 5 = (2,4) at filtration value 0.3 -> death at 0.3 -> outputs/stores (0, 0.1, 0.3) + * zp.insert_face(5, {2, 4}, 1, 0.3); + * //inserts vertex 3 at filtration value 0.4 -> birth at 0.4 of 0-cycle + * zp.insert_face(3, {}, 0, 0.4); + * //inserts edge 6 = (2,3) at filtration value 0.4 -> death at 0.4 of the cycle born at 0.4 -> outputs/stores nothing + * zp.insert_face(6, {2, 3}, 1, 0.4); + * //inserts edge 9 = (3,4) at filtration value 1.2 -> birth at 1.2 of 1-cycle + * zp.insert_face(9, {4, 3}, 1, 1.2); + * //removes edge 6 at filtration value 1.5 -> death at 1.5 -> outputs/stores (1, 1.2, 1.5) + * zp.remove_face(6, 1.5); + * //removes edge 5 at filtration value 2.0 -> birth at 2.0 of 0-cycle + * zp.remove_face(5, 2.0); + * ``` + * + * #### Finalizations + * ``` + * // Only the closed bars where output so far, so the open/infinite bars still need to be retrieved. + * + * //in this example, outputs (0, 0.1) and (0, 2.0) + * zp.get_current_infinite_intervals([](dimension_type dim, filtration_value_type birth){ + * std::cout << "[" << dim << "] " << birth << " - inf" << std::endl; + * }); + * ``` * * @tparam FilteredZigzagOptions Structure following the @ref FilteredZigzagOptions concept. * Default value: @ref Default_filtered_zigzag_options. @@ -349,11 +463,11 @@ class Filtered_zigzag_persistence { * @param stream_interval Callback method to process the birth and death values of a persistence bar. * Has to take three arguments as input: first the dimension of the cycle, then the birth value of the cycle * and third the death value of the cycle. The values corresponds to the filtration values which were given at - * insertions or removals. - * @param preallocationSize Space for @p preallocationSize faces are reserved in the underlying structure. - * Theoretically, any values works therefore, but for better performances, it is better to be as close as possible - * to the maximal value of the number of faces stored at the same time. At a same time are stored faces which were - * inserted before that time but not removed until that time. Default value: 0. + * insertions or removals. Note that bars of length 0 will not be token into account. + * @param preallocationSize Reserves space for @p preallocationSize faces in the internal data structure. + * This is optional and just helps skip a few reallocations. The optimal value (no reallocation, no wasted space) is + * the number of faces in the biggest complex of the filtration. + * Default value: 0. * @tparam F Type of callback method. */ template @@ -413,7 +527,7 @@ class Filtered_zigzag_persistence { /** * @brief Updates the zigzag persistence diagram after the removal of the given face. - * + *preallocationSize * @param faceID ID representing the face to remove. Should be the same than the one used to insert it. * @param filtrationValue Filtration value associated to the removal. * Assumed to be always larger or equal to previously used filtration values or always smaller or equal than previous diff --git a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h index 3bca4df194..7485424a81 100644 --- a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h @@ -84,6 +84,64 @@ struct Default_zigzag_options { * a pair is closed. To retrieve the open pairs (corresponding to infinite bars), * use @ref get_current_infinite_intervals. * + * ### Minimalistic example of usage + * + * #### Includes + * ``` + * #include + * ``` + * + * #### Useful aliases + * ``` + * using Zigzag_persistence = Gudhi::zigzag_persistence::Zigzag_persistence<>; + * + * using dimension_type = Zigzag_persistence::dimension_type; + * using index = Zigzag_persistence::index; + * ``` + * + * #### Construction with default values + * ``` + * //Zigzag_persistence(callback) with for example callback method as a anonymous lambda + * Zigzag_persistence zp([](dimension_type dim, index birth, index death) { + * std::cout << "[" << dim << "] " << birth << " - " << death << std::endl; + * }); + * ``` + * + * #### Input of the zigzag sequence/filtration + * ``` + * // In all cases, it is important that the operations of insertions and removals are made **in the same order** + * // as in the zigzag filtration ones wants to compute the barcode from. + * + * // A face has to be identified in the boundaries by the operation number the face was inserted with in the sequence. + * + * //inserts vertex 0 -> birth at 0 of 0-cycle + * zp.insert_face({}, 0); + * //inserts vertex 1 -> birth at 1 of 0-cycle + * zp.insert_face({}, 0); + * //inserts edge 2 = (0,1) -> death at 2 -> outputs (0, 1, 2) + * zp.insert_face({0, 1}, 1); + * //inserts vertex 3 -> birth at 3 of 0-cycle + * zp.insert_face({}, 0); + * //inserts edge 4 = (0,3) -> death at 4 -> outputs (0, 3, 4) + * zp.insert_face({0, 3}, 1); + * //inserts edge 5 = (1,3) -> birth at 5 of 1-cycle + * zp.insert_face({1, 3}, 1); + * //removes edge 4 -> death at 6 -> outputs (1, 5, 6) + * zp.remove_face(4); + * //removes edge 2 -> birth at 7 of 0-cycle + * zp.remove_face(2); + * ``` + * + * #### Finalizations + * ``` + * // Only the closed bars where output so far, so the open/infinite bars still need to be retrieved. + * + * //in this example, outputs (0, 0) and (0, 7) + * zp.get_current_infinite_intervals([](dimension_type dim, index birth){ + * std::cout << "[" << dim << "] " << birth << " - inf" << std::endl; + * }); + * ``` + * * @ingroup zigzag_persistence * * @tparam ZigzagOptions Structure following the @ref ZigzagOptions concept. Default value: @ref Default_zigzag_options. @@ -199,10 +257,10 @@ class Zigzag_persistence * as input: first the dimension of the cycle, then the birth index of the cycle and third the death index of the * cycle. An index always corresponds to the arrow number the event occurred (one call to @ref insert_face, * @ref remove_face or @ref apply_identity is equal to one arrow and increases the arrow count by one). - * @param preallocationSize Space for @p preallocationSize faces are reserved in the underlying structure. - * Theoretically, any values works therefore, but for better performances, it is better to be as close as possible - * to the maximal value of the number of faces stored at the same time. At a same time are stored faces which were - * inserted before that time but not removed until that time. Default value: 0. + * @param preallocationSize Reserves space for @p preallocationSize faces in the internal data structure. + * This is optional and just helps skip a few reallocations. The optimal value (no reallocation, no wasted space) is + * the number of faces in the biggest complex of the filtration. + * Default value: 0. */ Zigzag_persistence(std::function stream_interval, unsigned int preallocationSize = 0) @@ -393,7 +451,6 @@ class Zigzag_persistence * @brief Removes the given face by pushing up the matrix the corresponding column and erasing it. * * @param faceID Internal ID of the face to remove. - * @param dim Dimension of the face to remove. */ void _process_backward_arrow(index faceID) { // column whose key is the one of the removed face @@ -427,14 +484,7 @@ class Zigzag_persistence } else { // in H -> paired with c_g, that now belongs to F now // maintain the <=b order birthOrdering_.add_birth_backward(numArrow_); - if constexpr (erase_birth_history) { - births_.try_emplace(col.get_paired_chain_index(), numArrow_); - } else { - auto res = births_.try_emplace(col.get_paired_chain_index(), numArrow_); - if (!res.second) { - res.first->second = numArrow_; - } - } + births_[col.get_paired_chain_index()] = numArrow_; } // cannot be in G as the removed face is maximal diff --git a/src/common/doc/examples.h b/src/common/doc/examples.h index ef146fd44c..dd2464afa8 100644 --- a/src/common/doc/examples.h +++ b/src/common/doc/examples.h @@ -130,7 +130,10 @@ * @example example_one_skeleton_rips_from_points.cpp * @example example_rips_complex_from_off_file.cpp * \section Zigzag_persistence_example_section Zigzag_persistence - * @example example_simple_zigzag_filtration.cpp + * @example example_usage_zigzag_persistence.cpp + * @example example_usage_filtered_zigzag_persistence.cpp + * @example example_usage_filtered_zigzag_persistence_with_storage.cpp + * @example example_zigzag_filtration_as_input_loop.cpp * @example example_zzfiltration_from_file.cpp * \section Persistence_matrix_example_section Persistence_matrix * @example representative_cycles_from_matrix.cpp From 564f751a96fd324f8441afb333981c0cec477be8 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Mon, 22 Jul 2024 18:13:05 +0200 Subject: [PATCH 37/96] doc --- ...mple_usage_filtered_zigzag_persistence.cpp | 57 +++++++++++++++++++ ...ltered_zigzag_persistence_with_storage.cpp | 55 ++++++++++++++++++ .../example_usage_zigzag_persistence.cpp | 55 ++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp create mode 100644 src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence_with_storage.cpp create mode 100644 src/Zigzag_persistence/example/example_usage_zigzag_persistence.cpp diff --git a/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp b/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp new file mode 100644 index 0000000000..1e6c43ea84 --- /dev/null +++ b/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp @@ -0,0 +1,57 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Hannah Schreiber + * + * Copyright (C) 2024 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +#include + +#include + +using Zigzag_persistence = Gudhi::zigzag_persistence::Filtered_zigzag_persistence<>; +using dimension_type = Zigzag_persistence::dimension_type; +using filtration_value_type = Zigzag_persistence::filtration_value; + +int main(int argc, char* const argv[]) { + std::clog << "********* Minimalistic example of usage of the Filtered_zigzag_persistence class ********" << std::endl; + + // Filtered_zigzag_persistence(callback) with for example callback method as a anonymous lambda + Zigzag_persistence zp([](dimension_type dim, filtration_value_type birth, filtration_value_type death) { + std::cout << "[" << dim << "] " << birth << " - " << death << std::endl; + }); + + // It is important that the operations of insertions and removals are made **in the same order** as in the zigzag + // filtration ones wants to compute the barcode from. + // A face can be identified in the boundaries by any given numerical label, it is just important that the given + // filtration values are monotonous (ie., either only increasing or only decreasing). + + // inserts vertex 2 at filtration value 0.1 -> birth at 0.1 of 0-cycle + zp.insert_face(2, {}, 0, 0.1); + // inserts vertex 4 at filtration value 0.1 -> birth at 0.1 of 0-cycle + zp.insert_face(4, {}, 0, 0.1); + // inserts edge 5 = (2,4) at filtration value 0.3 -> death at 0.3 -> outputs/stores (0, 0.1, 0.3) + zp.insert_face(5, {2, 4}, 1, 0.3); + // inserts vertex 3 at filtration value 0.4 -> birth at 0.4 of 0-cycle + zp.insert_face(3, {}, 0, 0.4); + // inserts edge 6 = (2,3) at filtration value 0.4 -> death at 0.4 of the cycle born at 0.4 -> outputs/stores nothing + zp.insert_face(6, {2, 3}, 1, 0.4); + // inserts edge 9 = (3,4) at filtration value 1.2 -> birth at 1.2 of 1-cycle + zp.insert_face(9, {4, 3}, 1, 1.2); + // removes edge 6 at filtration value 1.5 -> death at 1.5 -> outputs/stores (1, 1.2, 1.5) + zp.remove_face(6, 1.5); + // removes edge 5 at filtration value 2.0 -> birth at 2.0 of 0-cycle + zp.remove_face(5, 2.0); + + // Only the closed bars where output so far, so the open/infinite bars still need to be retrieved. + + // in this example, outputs (0, 0.1) and (0, 2.0) + zp.get_current_infinite_intervals([](dimension_type dim, filtration_value_type birth) { + std::cout << "[" << dim << "] " << birth << " - inf" << std::endl; + }); + + return 0; +} diff --git a/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence_with_storage.cpp b/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence_with_storage.cpp new file mode 100644 index 0000000000..8c897cc087 --- /dev/null +++ b/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence_with_storage.cpp @@ -0,0 +1,55 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Hannah Schreiber + * + * Copyright (C) 2024 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +#include + +#include + +using Zigzag_persistence = Gudhi::zigzag_persistence::Filtered_zigzag_persistence_with_storage<>; + +int main(int argc, char* const argv[]) { + std::clog << "** Minimalistic example of usage of the Filtered_zigzag_persistence_with_storage class **" << std::endl; + + Zigzag_persistence zp; + + // It is important that the operations of insertions and removals are made **in the same order** as in the zigzag + // filtration ones wants to compute the barcode from. + // A face can be identified in the boundaries by any given numerical label, it is just important that the given + // filtration values are monotonous (ie., either only increasing or only decreasing). + + // inserts vertex 2 at filtration value 0.1 -> birth at 0.1 of 0-cycle + zp.insert_face(2, {}, 0, 0.1); + // inserts vertex 4 at filtration value 0.1 -> birth at 0.1 of 0-cycle + zp.insert_face(4, {}, 0, 0.1); + // inserts edge 5 = (2,4) at filtration value 0.3 -> death at 0.3 -> outputs/stores (0, 0.1, 0.3) + zp.insert_face(5, {2, 4}, 1, 0.3); + // inserts vertex 3 at filtration value 0.4 -> birth at 0.4 of 0-cycle + zp.insert_face(3, {}, 0, 0.4); + // inserts edge 6 = (2,3) at filtration value 0.4 -> death at 0.4 of the cycle born at 0.4 -> outputs/stores nothing + zp.insert_face(6, {2, 3}, 1, 0.4); + // inserts edge 9 = (3,4) at filtration value 1.2 -> birth at 1.2 of 1-cycle + zp.insert_face(9, {4, 3}, 1, 1.2); + // removes edge 6 at filtration value 1.5 -> death at 1.5 -> outputs/stores (1, 1.2, 1.5) + zp.remove_face(6, 1.5); + // removes edge 5 at filtration value 2.0 -> birth at 2.0 of 0-cycle + zp.remove_face(5, 2.0); + + // The bars are stored within the class and where not output at all for now. + + // get all bars in a vector + auto barcode = zp.get_persistence_diagram(); + + // do something with the vector, e.g., stream out content: + for (auto& bar : barcode) { + std::cout << bar << std::endl; + } + + return 0; +} diff --git a/src/Zigzag_persistence/example/example_usage_zigzag_persistence.cpp b/src/Zigzag_persistence/example/example_usage_zigzag_persistence.cpp new file mode 100644 index 0000000000..a024cfe0af --- /dev/null +++ b/src/Zigzag_persistence/example/example_usage_zigzag_persistence.cpp @@ -0,0 +1,55 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Hannah Schreiber + * + * Copyright (C) 2024 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +#include + +#include + +using Zigzag_persistence = Gudhi::zigzag_persistence::Zigzag_persistence<>; +using dimension_type = Zigzag_persistence::dimension_type; +using index_type = Zigzag_persistence::index; + +int main(int argc, char* const argv[]) { + std::clog << "************* Minimalistic example of usage of the Zigzag_persistence class *************" << std::endl; + + // Zigzag_persistence(callback) with for example callback method as a anonymous lambda + Zigzag_persistence zp([](dimension_type dim, index_type birth, index_type death) { + std::cout << "[" << dim << "] " << birth << " - " << death << std::endl; + }); + + // It is important that the operations of insertions and removals are made **in the same order** as in the zigzag + // filtration ones wants to compute the barcode from. + // A face has to be identified in the boundaries by the operation number the face was inserted with in the sequence. + + // inserts vertex 0 -> birth at 0 of 0-cycle + zp.insert_face({}, 0); + // inserts vertex 1 -> birth at 1 of 0-cycle + zp.insert_face({}, 0); + // inserts edge 2 = (0,1) -> death at 2 -> outputs (0, 1, 2) + zp.insert_face({0, 1}, 1); + // inserts vertex 3 -> birth at 3 of 0-cycle + zp.insert_face({}, 0); + // inserts edge 4 = (0,3) -> death at 4 -> outputs (0, 3, 4) + zp.insert_face({0, 3}, 1); + // inserts edge 5 = (1,3) -> birth at 5 of 1-cycle + zp.insert_face({1, 3}, 1); + // removes edge 4 -> death at 6 -> outputs (1, 5, 6) + zp.remove_face(4); + // removes edge 2 -> birth at 7 of 0-cycle + zp.remove_face(2); + + // Only the closed bars where output so far, so the open/infinite bars still need to be retrieved. + + // in this example, outputs (0, 0) and (0, 7) + zp.get_current_infinite_intervals( + [](dimension_type dim, index_type birth) { std::cout << "[" << dim << "] " << birth << " - inf" << std::endl; }); + + return 0; +} From bd6d9b565bd61e5414f964e245c02e8ab731933b Mon Sep 17 00:00:00 2001 From: hschreiber Date: Tue, 23 Jul 2024 13:54:29 +0200 Subject: [PATCH 38/96] doc --- .../doc/Intro_zigzag_persistence.h | 15 ++++++++++++--- .../example_usage_filtered_zigzag_persistence.cpp | 4 ++-- ...e_filtered_zigzag_persistence_with_storage.cpp | 2 +- .../example/example_usage_zigzag_persistence.cpp | 6 +++--- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h index 9c5537b230..0e7ddac996 100644 --- a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h +++ b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h @@ -60,17 +60,26 @@ namespace zigzag_persistence { * \li \gudhi_example_link{Zigzag_persistence,example_usage_zigzag_persistence.cpp} - A simple example to showcase how * to use the @ref Zigzag_persistence class to compute a barcode. *
- * @include example_usage_zigzag_persistence.cpp + * @dontinclude example_usage_zigzag_persistence.cpp + * @skip #include + * @until return 0; + * @skipline } *
* \li \gudhi_example_link{Zigzag_persistence,example_usage_filtered_zigzag_persistence.cpp} - A simple example to * showcase how to use the @ref Filtered_zigzag_persistence class to compute a barcode. *
- * @include example_usage_filtered_zigzag_persistence.cpp + * @dontinclude example_usage_filtered_zigzag_persistence.cpp + * @skip #include + * @until return 0; + * @skipline } *
* \li \gudhi_example_link{Zigzag_persistence,example_usage_filtered_zigzag_persistence_with_storage.cpp} - A simple * example to showcase how to use the @ref Filtered_zigzag_persistence_with_storage class to compute a barcode. *
- * @include example_usage_filtered_zigzag_persistence_with_storage.cpp + * @dontinclude example_usage_filtered_zigzag_persistence_with_storage.cpp + * @skip #include + * @until return 0; + * @skipline } *
* * \subsection zzexamples More elaborate examples diff --git a/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp b/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp index 1e6c43ea84..e15d8e8c08 100644 --- a/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp +++ b/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp @@ -16,7 +16,7 @@ using Zigzag_persistence = Gudhi::zigzag_persistence::Filtered_zigzag_persistenc using dimension_type = Zigzag_persistence::dimension_type; using filtration_value_type = Zigzag_persistence::filtration_value; -int main(int argc, char* const argv[]) { +int main() { std::clog << "********* Minimalistic example of usage of the Filtered_zigzag_persistence class ********" << std::endl; // Filtered_zigzag_persistence(callback) with for example callback method as a anonymous lambda @@ -48,7 +48,7 @@ int main(int argc, char* const argv[]) { // Only the closed bars where output so far, so the open/infinite bars still need to be retrieved. - // in this example, outputs (0, 0.1) and (0, 2.0) + // in this example, computes (0, 0.1) and (0, 2.0) zp.get_current_infinite_intervals([](dimension_type dim, filtration_value_type birth) { std::cout << "[" << dim << "] " << birth << " - inf" << std::endl; }); diff --git a/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence_with_storage.cpp b/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence_with_storage.cpp index 8c897cc087..5136d5eb2a 100644 --- a/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence_with_storage.cpp +++ b/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence_with_storage.cpp @@ -14,7 +14,7 @@ using Zigzag_persistence = Gudhi::zigzag_persistence::Filtered_zigzag_persistence_with_storage<>; -int main(int argc, char* const argv[]) { +int main() { std::clog << "** Minimalistic example of usage of the Filtered_zigzag_persistence_with_storage class **" << std::endl; Zigzag_persistence zp; diff --git a/src/Zigzag_persistence/example/example_usage_zigzag_persistence.cpp b/src/Zigzag_persistence/example/example_usage_zigzag_persistence.cpp index a024cfe0af..26946e1ece 100644 --- a/src/Zigzag_persistence/example/example_usage_zigzag_persistence.cpp +++ b/src/Zigzag_persistence/example/example_usage_zigzag_persistence.cpp @@ -16,7 +16,7 @@ using Zigzag_persistence = Gudhi::zigzag_persistence::Zigzag_persistence<>; using dimension_type = Zigzag_persistence::dimension_type; using index_type = Zigzag_persistence::index; -int main(int argc, char* const argv[]) { +int main() { std::clog << "************* Minimalistic example of usage of the Zigzag_persistence class *************" << std::endl; // Zigzag_persistence(callback) with for example callback method as a anonymous lambda @@ -45,9 +45,9 @@ int main(int argc, char* const argv[]) { // removes edge 2 -> birth at 7 of 0-cycle zp.remove_face(2); - // Only the closed bars where output so far, so the open/infinite bars still need to be retrieved. + // Only the closed bars were output so far, so the open/infinite bars still need to be retrieved. - // in this example, outputs (0, 0) and (0, 7) + // in this example, computes (0, 0) and (0, 7) zp.get_current_infinite_intervals( [](dimension_type dim, index_type birth) { std::cout << "[" << dim << "] " << birth << " - inf" << std::endl; }); From fc4bae09317ba9231780c81bfa3ba94dd539e108 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Mon, 3 Jul 2023 13:24:35 +0200 Subject: [PATCH 39/96] Use Ripser in RipsPersistence --- CMakeLists.txt | 1 + .../tore3D_1307_distance_matrix.csv | 4 +- src/CMakeLists.txt | 1 + src/Ripser/include/gudhi/ripser.h | 1419 +++++++++++++++++ src/Ripser/utilities/CMakeLists.txt | 3 + src/Ripser/utilities/ripser.cc | 391 +++++ src/common/include/gudhi/uint128.h | 147 ++ src/python/CMakeLists.txt | 1 + src/python/gudhi/_ripser.cc | 200 +++ src/python/gudhi/sklearn/rips_persistence.py | 136 +- .../test/test_sklearn_rips_persistence.py | 12 + 11 files changed, 2276 insertions(+), 39 deletions(-) create mode 100644 src/Ripser/include/gudhi/ripser.h create mode 100644 src/Ripser/utilities/CMakeLists.txt create mode 100644 src/Ripser/utilities/ripser.cc create mode 100644 src/common/include/gudhi/uint128.h create mode 100644 src/python/gudhi/_ripser.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index ccd0635dd5..9e3abd84c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,7 @@ add_gudhi_module(Hasse_complex) add_gudhi_module(Persistence_representations) add_gudhi_module(Persistent_cohomology) add_gudhi_module(Rips_complex) +add_gudhi_module(Ripser) add_gudhi_module(Simplex_tree) add_gudhi_module(Skeleton_blocker) add_gudhi_module(Spatial_searching) diff --git a/data/distance_matrix/tore3D_1307_distance_matrix.csv b/data/distance_matrix/tore3D_1307_distance_matrix.csv index afab863435..8df9e05ae8 100644 --- a/data/distance_matrix/tore3D_1307_distance_matrix.csv +++ b/data/distance_matrix/tore3D_1307_distance_matrix.csv @@ -1,4 +1,4 @@ -0. + 0.485593 0.738424 0.885478 0.188641 0.420709 0.67781 @@ -1304,4 +1304,4 @@ 1.8113 1.83101 1.40725 1.85421 1.59879 0.734918 1.35786 1.48372 1.35527 0.738936 1.87299 1.62667 1.15888 1.06351 1.01194 1.43559 1.64675 1.775 0.974258 1.48989 1.41247 0.854514 1.2493 0.271864 0.811688 1.23359 0.960687 1.67431 0.727966 0.737152 0.79253 0.683712 0.639196 0.667212 0.682323 1.14862 1.22595 1.26012 1.27812 1.37573 1.33697 1.25392 1.19951 1.39057 1.33256 1.97046 1.95145 1.80436 1.8655 1.82531 1.85551 1.88924 1.99138 2.02134 1.99613 1.96933 1.40568 1.67377 1.58185 1.7263 1.60619 1.42651 1.49596 1.49267 1.42953 1.72673 1.81775 1.93221 1.85297 1.80766 1.85765 1.96055 1.93289 2.00576 1.96405 1.86285 1.8234 1.96457 1.93582 2.02526 2.00864 2.00286 2.01824 2.02595 2.02237 2.00903 2.01265 1.7845 1.81151 1.9112 1.97035 1.98978 1.96702 1.86384 1.95143 2.01551 2.00217 2.01875 2.00244 1.98826 2.01706 1.66968 1.70363 1.68626 1.47424 1.46825 1.5299 1.63291 1.58239 1.51358 1.42563 1.4352 1.45417 1.45202 1.68629 1.75018 1.85174 1.83792 1.91947 1.9758 1.94166 1.89838 1.70397 1.74889 1.84373 1.9068 1.95718 1.96579 1.84538 1.90322 1.58901 1.52726 1.72796 1.67983 1.75682 1.76784 1.57751 1.6655 1.93873 1.87171 1.94515 1.96446 1.99388 1.99073 2.00265 2.00664 1.97896 1.96138 1.97654 1.97877 1.96627 1.95171 1.89771 1.95369 1.42061 1.43024 1.46063 1.61039 1.71344 1.55997 1.85248 1.91893 1.92685 1.86898 1.78178 1.77835 1.89548 1.84493 1.89157 1.8296 1.9435 1.93811 1.68545 1.57623 1.74553 1.75844 1.59212 1.86675 1.91556 1.90257 1.91678 1.87993 1.91166 1.90129 1.93324 1.92074 1.94322 1.9691 1.98546 1.93603 1.95789 1.72598 1.76881 1.89665 1.90364 1.86919 1.8385 1.86261 1.84555 1.80667 1.72776 1.71629 1.76025 1.98268 1.92722 1.93867 1.9793 1.89189 1.88906 1.78215 1.85157 1.36816 1.44855 1.43386 1.64106 1.54476 1.87489 1.86016 1.75828 1.67845 1.7556 1.82112 1.80523 1.70747 1.532 1.45531 1.65536 1.62925 1.77515 1.76142 1.54888 1.74794 1.75403 1.44406 1.52462 1.36109 1.36598 1.31429 1.25768 1.33653 1.34458 1.42112 1.61191 1.58118 1.54378 1.61754 1.32259 1.26893 1.39248 1.3482 1.35749 1.41012 1.43227 1.62882 1.5242 1.5245 1.6006 1.83633 1.70594 1.63731 1.59898 1.77485 1.71038 1.0668 1.05746 1.16435 1.10789 1.15585 1.09257 0.969334 1.01022 0.991799 0.943252 0.887349 0.964135 1.79384 1.76752 1.77415 1.80313 1.64305 1.44631 1.45004 1.25433 1.25515 1.35517 1.76848 1.76948 1.68333 1.71417 1.81893 1.71534 1.79983 1.35689 1.09527 1.1546 1.43486 1.34593 1.27261 1.71953 1.64948 1.67351 1.59911 1.51536 1.57753 1.62504 1.6471 1.67441 1.45793 1.54317 1.47098 1.66935 1.64055 1.50134 1.70298 1.73519 1.72391 1.659 1.70996 1.58477 1.56706 1.37889 1.39795 1.27385 1.18131 1.2227 1.27722 1.5255 1.57151 1.6708 1.6555 1.60871 1.57448 1.53082 1.62625 1.6071 1.57204 1.51411 1.55341 0.873697 1.06431 0.997937 0.971373 0.960128 1.0965 1.02087 1.52002 1.50205 1.54809 1.09773 1.0766 1.24163 1.09525 1.24611 1.18575 1.03101 0.93392 0.912656 0.976079 1.0423 1.07896 1.41822 1.29191 1.3674 1.42345 1.49788 1.38438 1.3147 1.41888 1.44542 1.16303 1.12012 1.16752 1.18438 1.51145 1.57805 1.60372 1.57632 1.50968 1.5669 1.23548 1.23372 1.22455 1.12944 1.05352 1.0912 1.17433 1.36255 1.2636 1.38944 1.33043 1.51052 1.47754 1.4605 1.37448 1.35176 1.32133 1.17785 1.22136 1.21835 1.17859 1.16144 1.47635 1.41482 1.49736 1.52457 1.36895 1.31967 1.2967 1.35086 1.04093 0.916437 0.929274 0.79795 0.859095 0.695163 1.14828 1.05845 0.949859 1.1118 1.13279 1.26424 1.26561 1.19127 1.132 1.09552 1.20813 1.177 0.930393 0.91014 0.989762 0.980488 1.43423 1.4442 1.29022 1.37393 1.43576 1.40385 1.30426 1.37744 1.21372 1.22102 1.14048 1.03928 1.19242 1.30868 1.33738 1.2659 1.12811 1.02895 1.11244 1.1618 1.1638 1.10346 1.15013 1.06763 1.01931 1.04773 1.133 1.18901 1.00868 0.984821 1.07414 1.08318 1.2976 1.21636 1.15483 1.15539 1.08717 1.00725 1.07828 1.01964 1.04081 0.913429 0.979598 0.988745 0.938433 0.892117 0.963176 0.85066 0.83968 0.796097 0.890168 0.934945 0.889839 0.788952 0.715328 0.748381 0.80791 0.86644 0.809344 0.850741 0.663995 0.742685 1.2793 1.21112 1.30508 1.24767 1.21934 1.22921 1.29952 1.34351 0.808688 0.740942 0.92246 0.897505 0.650656 0.642831 0.569524 0.465291 0.604859 0.48917 0.40529 0.612826 0.588742 1.07992 1.01122 0.872725 0.776768 0.913865 0.931939 0.863055 0.888094 0.861099 0.811209 0.799629 0.850497 0.72409 0.68026 0.552046 0.455959 0.579881 0.601431 0.867201 0.837127 0.692761 0.798585 1.20295 1.18306 1.11343 1.16146 0.476312 0.574951 0.703217 0.76394 0.597126 0.621667 0.764241 0.765179 0.688236 0.624801 0.678343 0.712825 1.06596 0.986578 1.09304 1.11838 0.796594 0.773031 0.667449 0.74529 0.66354 0.715221 0.423705 0.502116 0.396115 0.482944 0.625745 0.523279 0.771323 0.816987 0.738525 0.683228 0.785948 1.02157 1.03283 0.97919 0.126503 0.211205 0.291484 0.272291 0.290479 0.396017 0.326337 0.37907 0.36418 0.121886 0.2308 0.300104 0.314049 0.30922 0.121067 0.235705 0.609519 0.632652 0.590344 0.564364 0.496134 0.423377 0.453326 0.557537 0.659466 0.70029 0.719593 0.685578 0.642449 0.648685 0.627906 0.597771 0.614412 0.84144 0.783122 0.749231 0.613206 0.606897 0.598438 0.564964 0.602098 0.587168 0.427922 0.380698 0.52745 0.497667 0.503691 0.537161 0.516879 0.442823 0.384398 0.431576 0.680797 0.636572 0.511195 0.417376 0.53458 0.130915 0.240805 0.389947 0.45873 0.336373 0.311546 0.703108 0.671967 0.754937 0.763575 0.69352 0.589324 0.570873 0.510442 0.437927 0.441057 0.527846 0.605883 0.656054 0.596806 0.578645 0.311169 0.133036 0.626541 0.430062 0.472189 0.563565 0.49529 0.568428 0.536673 0.566394 0.594521 0.623209 0.654513 0.609384 0.610891 0.227386 0.11966 0.118102 0.226183 0.277791 0.283032 0.723218 0.728508 0.661142 0.62411 0.641573 0.676011 0.527855 0.438778 0.427401 0.5025 0.586256 0.601419 0.843361 0.893317 0.868497 0.779933 0.706338 0.753861 1.00819 1.03844 0.954903 1.66379 1.59253 1.5083 1.49317 1.57343 1.6681 1.53212 1.5951 1.55187 1.46302 1.41187 1.44564 1.45099 1.4179 1.43501 1.50856 1.56921 1.53176 1.57713 1.5509 1.64333 1.71746 1.68028 1.47928 1.55795 1.55689 1.47512 0.662094 0.742351 0.760192 0.681638 1.18916 1.22139 1.29108 0.843934 0.832544 0.896884 0.915947 0.802527 0.83659 0.825165 0.609357 0.604068 0.550072 0.544923 0.919838 0.914328 0.861435 0.913015 0.882821 0.792672 0.771442 0.847163 1.53605 1.60794 1.64368 1.57263 1.7035 1.61916 1.62335 1.70878 1.39883 1.41615 1.38875 1.74505 1.72135 1.78414 1.45472 1.44102 1.49336 1.30846 1.32934 1.35699 1.37155 1.35146 1.04037 1.06041 0.99604 1.38613 1.3326 1.38906 1.43806 1.83752 1.83194 1.8553 1.86498 1.73835 1.78416 1.73976 1.41622 1.39727 1.3805 1.40672 0.937361 0.837279 0.794736 0.853857 0.934672 1.36452 1.4044 1.49135 1.51055 1.43757 1.48617 1.44294 1.38089 1.41762 1.32601 1.36839 1.44329 1.39769 1.55685 1.62659 1.63069 1.56643 1.70919 1.62524 1.68616 0.394551 0.387226 0.296244 0.310481 0.705857 0.658655 0.703345 0.746256 1.27347 1.27913 1.22296 1.1966 1.24175 1.37872 1.42792 1.37406 1.289 1.29399 0.984593 1.03172 1.69945 1.613 1.68874 1.45192 1.42745 1.42022 1.84972 1.80964 1.81454 1.87124 1.78626 1.83223 1.12101 1.14246 1.21939 1.193 1.39589 1.34172 1.46308 1.21451 1.26527 1.22129 1.16622 0.238796 0.305216 0.35907 0.305265 0.495571 0.435718 0.489897 0.543145 0.837877 0.805183 0.850178 0.885425 0.575302 0.552404 0.469227 0.499093 1.0018 0.972536 1.0347 1.05513 0.534851 0.530583 0.567363 0.586379 0.578315 0.883779 0.938304 0.965812 0.914616 0.873708 0.9183 0.557698 1.01313 0.522482 0.846213 0.488525 0.302506 1.21519 1.17006 1.3516 1.23849 0.702858 0.343768 1.59976 1.38259 1.43091 1.43892 0.867951 1.39702 1.8504 1.38613 1.33755 1.75607 1.66274 1.5882 0.838831 0.578259 0.844001 0.875418 0.709374 1.51594 1.62831 1.476 1.49588 1.58597 0.961611 0.80177 0.510185 0.680305 0.189329 0.638388 0.582976 0.509809 0.573873 0.210348 0.620164 0.512624 0.676809 0.640611 0.393932 0.227141 0.41504 0.583688 0.467249 0.461949 0.554513 0.592052 0.593682 0.774987 0.774444 0.777393 0.569256 0.613528 0.677729 0.506252 0.525899 0.209868 0.20758 0.35218 0.43679 0.462101 0.346819 0.348812 0.200512 0.201095 0.966618 0.712409 0.747531 0.846645 0.579578 0.474287 0.401887 0.658253 0.729157 1.04843 0.656196 0.722866 0.682722 0.528892 1.14933 0.766365 0.520436 0.650643 0.810672 0.831851 0.840755 1.00022 0.512294 0.396505 0.487879 0.556706 0.831526 1.28064 1.24413 0.649285 0.758711 0.723748 0.844258 0.778549 0.92804 0.911689 0.968153 0.994372 1.08416 1.22427 0.989852 0.925608 1.10676 1.09703 1.04067 1.22705 1.12678 1.37002 1.29923 1.36018 0.919901 0.958454 0.851302 1.15144 1.21746 1.10454 1.04888 0.844568 0.694397 0.767827 0.86556 0.980617 1.08262 1.31725 1.46937 1.09044 1.11985 1.26921 1.40823 1.42798 1.28868 1.15187 1.15685 1.5536 1.51233 1.10716 1.37959 1.46217 1.31709 1.30689 0.986266 1.13962 1.30143 0.999937 1.46598 1.03615 1.05236 0.938564 0.900284 1.47898 1.57527 1.63715 1.56484 1.53493 1.19577 1.28398 1.48085 1.65486 1.69909 1.59229 1.48292 1.57024 1.5572 1.6255 1.69598 1.33858 1.15377 1.13921 1.29261 1.2931 1.74361 1.73675 1.26317 1.35356 1.54501 1.74707 1.80651 0.915041 0.922697 1.06789 1.16358 1.11405 1.00361 1.69392 1.76369 1.61341 1.53719 1.33235 1.29067 1.32992 1.49801 1.65659 1.51305 1.43062 1.29705 1.44477 1.29123 1.8146 1.66462 1.52032 1.65892 1.54019 1.7309 1.78485 1.53059 1.37613 1.37891 1.83538 1.93643 1.68674 1.76378 1.82047 1.8784 1.81127 1.66094 1.9693 1.92927 1.92276 1.88183 1.88465 1.84905 1.51395 1.65576 1.89773 1.83057 1.85675 1.67984 1.52724 1.39222 1.93219 1.9389 1.96286 1.99783 1.91415 1.97858 1.67713 1.62578 1.91097 1.83746 1.63779 1.95608 1.90004 1.77654 1.64913 1.41657 1.51088 1.5599 1.60043 1.99721 2.0142 1.92637 1.88933 1.98024 2.02369 2.00853 1.9033 1.98674 1.98617 1.89529 1.76604 1.77442 1.43972 1.4305 1.64259 1.69519 1.57292 1.46244 1.41279 1.39296 2.01166 1.94185 1.78671 1.75622 1.90229 2.0042 1.30602 1.39861 1.32163 1.21035 1.16667 0.629723 0.731106 0.792859 0.732444 1.28782 1.92318 1.49696 1.89986 2.01196 2.0223 1.74832 1.45826 1.97937 1.81801 1.947 1.647 1.76425 1.98477 1.97858 1.49632 1.79124 1.93008 1.97107 1.78628 1.93483 1.95442 1.8012 1.99941 1.89196 1.47112 1.46997 1.60294 1.83798 1.75768 1.8013 1.3839 1.6879 1.37723 1.46375 1.04013 1.83361 1.88389 1.46488 1.73401 1.86193 1.4093 1.2111 1.7433 1.67131 1.61855 1.69166 1.74829 1.56965 1.36641 1.43024 1.6412 1.60272 1.13546 1.45595 1.2152 1.61296 1.03545 1.44008 1.2017 1.27208 1.52851 1.39262 1.46009 0.93886 1.44622 1.21179 1.22769 1.08537 1.14407 1.03808 0.851871 1.06503 0.96875 0.833911 1.35211 1.41836 1.22869 1.23445 0.893315 0.980055 0.686534 0.585535 0.949308 0.894314 0.629484 0.921146 1.20268 0.650772 0.750682 1.16368 1.31811 1.13942 0.820043 0.581968 0.895501 0.359771 0.665476 0.651668 0.889529 0.628317 0.476551 0.593194 0.326165 0.616672 0.584721 0.347747 1.06882 0.748825 0.559261 0.401563 0.604459 0.570964 0.341348 0.818873 0.697751 0.519713 1.89976 1.92976 1.61101 1.97065 1.84013 0.585472 1.02538 1.74986 1.02428 1.00864 1.74242 1.74854 1.47774 1.38265 1.33031 1.37387 1.81119 1.53898 0.663134 1.75274 1.32086 0.566972 1.40414 0.49327 1.06903 1.50145 1.19234 1.79895 0.427452 0.447907 0.490767 0.386815 0.349789 0.344431 0.372258 1.43033 1.50653 1.56281 1.56863 1.66472 1.62173 1.52247 1.45446 1.65399 1.60459 1.9136 1.88231 1.74451 1.794 1.74042 1.73967 1.79181 1.91282 1.9491 1.89131 1.87567 1.28006 1.62927 1.52955 1.64067 1.53192 1.35271 1.45772 1.47867 1.39523 1.71658 1.80559 1.88417 1.80446 1.77105 1.83228 1.92312 1.9068 1.98958 1.94939 1.86319 1.83898 1.9749 1.93437 1.96846 1.9574 1.96384 1.98913 1.99435 1.97647 1.90977 1.93084 1.72726 1.73498 1.82562 1.89546 1.94379 1.93521 1.8144 1.89398 2.01066 2.01051 2.01219 2.0075 1.96757 1.99725 1.64951 1.66962 1.62765 1.40822 1.42284 1.49334 1.58895 1.57039 1.4958 1.41332 1.43548 1.47286 1.44836 1.52041 1.59905 1.67564 1.68123 1.7927 1.85458 1.78863 1.7544 1.57145 1.63265 1.81128 1.88052 1.94765 1.96917 1.84283 1.89071 1.59374 1.5492 1.74671 1.68447 1.73631 1.76299 1.5699 1.64128 1.96316 1.89973 1.99404 1.99982 2.02657 2.03396 2.02084 2.0263 2.03484 2.02034 2.00661 2.02117 2.03029 2.03006 1.95532 2.00884 1.44603 1.4941 1.5006 1.62267 1.72357 1.59278 1.86392 1.93375 1.95595 1.91141 1.81986 1.7992 1.9496 1.88935 1.96095 1.90881 2.02676 2.00984 1.72238 1.61689 1.81567 1.80916 1.43101 1.94174 2.00203 2.00682 2.01477 2.00609 2.02172 1.72144 1.76551 1.74086 1.77433 1.82264 1.85363 1.78284 1.80164 1.52368 1.55045 1.70179 1.71093 1.66884 1.62372 1.65228 1.62291 1.56787 1.49323 1.45483 1.51395 1.87231 1.82343 1.80081 1.85236 1.71386 1.72473 1.59391 1.66179 1.24183 1.51694 1.52362 1.71799 1.60652 1.74288 1.74592 1.65295 1.56358 1.58448 1.6613 1.66272 1.57335 1.39835 1.31497 1.4916 1.4853 1.8558 1.86182 1.68288 1.90048 1.89009 1.27983 1.35248 1.16943 1.19204 1.14586 1.07344 1.19054 1.19582 1.60647 1.81001 1.40464 1.33065 1.41987 1.15531 1.08315 1.55114 1.52279 1.49976 1.51783 1.55971 1.72462 1.62569 1.64361 1.72718 1.96312 1.81521 1.77463 1.75046 1.91326 1.84496 0.756405 0.754721 0.844978 0.799579 0.852077 0.792356 0.689739 0.723022 0.705148 0.670649 0.62237 0.683976 1.95464 1.92143 1.94997 1.96384 1.37781 1.17582 1.19759 1.04831 1.00593 1.11503 1.94433 1.95226 1.87995 1.89678 1.6089 1.52938 1.60855 1.45742 1.28581 1.32617 1.56321 1.46672 1.40823 1.45107 1.36517 1.39217 1.31991 1.23366 1.27783 1.33695 1.44752 1.45367 1.25766 1.35258 1.25222 1.40934 1.36598 1.24795 1.90763 1.93145 1.90813 1.86796 1.90756 1.79067 1.75457 1.15254 1.15487 1.05488 0.951015 1.02226 1.07438 1.78251 1.82044 1.88888 1.87632 1.84145 1.82128 1.78172 1.85365 1.84504 1.79768 1.75347 1.76425 1.11898 1.26733 1.21648 1.2098 1.20882 1.32049 1.2499 1.73983 1.75037 1.78251 1.35274 1.34568 1.48312 1.29417 1.4564 1.41164 1.27404 1.18252 1.15252 1.20017 1.25862 1.30644 1.66804 1.55355 1.63046 1.70595 1.76519 1.66033 1.60115 1.70417 1.72119 0.946521 0.890032 0.927185 0.963718 1.24217 1.29937 1.30916 1.27289 1.2119 1.27535 1.51732 1.48814 1.46366 1.36528 1.30282 1.35346 1.43581 1.08518 0.994765 1.09715 1.02855 1.20686 1.18347 1.1466 1.0603 1.02164 0.998503 0.851113 0.901407 0.921543 0.899154 0.854026 1.15703 1.08719 1.18751 1.21219 1.66355 1.61673 1.60297 1.64888 1.37442 1.24641 1.25272 1.11145 1.17401 0.993017 1.43531 1.33418 1.22901 1.43297 1.43266 1.57708 1.57268 1.50056 1.45793 1.42724 1.52877 1.49952 1.23545 1.1734 1.26133 1.26474 1.15959 1.15487 1.00704 1.08057 1.12059 1.07793 0.996749 1.071 0.929315 0.9256 0.846718 0.757281 0.948462 1.0588 1.07252 0.995482 0.854151 0.75486 0.857745 0.896512 1.48772 1.43443 1.46701 1.3844 1.32558 1.3432 1.42807 1.49526 0.750264 0.698615 0.801338 0.829396 0.962377 0.882478 0.815843 0.819338 0.762241 0.674601 0.746523 1.34417 1.37288 1.24667 1.31563 1.32621 1.27422 1.23113 1.30215 1.1847 1.17636 1.10568 1.20283 1.25681 1.21668 1.11827 1.04357 1.06502 1.13228 1.1251 1.06766 1.12248 0.944634 1.01238 0.941713 0.871932 0.971484 0.916614 0.896463 0.913364 0.981336 1.01631 0.492834 0.415509 0.593734 0.578687 0.968102 0.966598 0.882431 0.785052 0.906137 0.786625 0.702988 0.906156 0.880837 0.741953 0.675398 0.54136 0.44693 0.585741 0.59868 1.20057 1.22422 1.18852 1.13046 1.12511 1.18136 1.02837 0.978844 0.84232 0.742937 0.864328 0.892447 0.596583 0.574617 0.42249 0.527373 0.870338 0.846219 0.791284 0.835812 0.798432 0.898876 1.0332 1.09755 0.916463 0.947185 1.07983 1.07861 0.986908 0.911964 0.969386 1.01487 0.730831 0.658742 0.766762 0.784179 1.12945 1.09878 0.988422 1.07609 0.973469 1.02862 0.740115 0.811251 0.663768 0.770546 0.88984 0.74808 0.53223 0.49758 0.413304 0.401242 0.48617 0.716332 0.716269 0.66304 0.378291 0.426847 0.549959 0.448938 0.404577 0.585684 0.519325 0.303656 0.123078 0.437357 0.527613 0.608858 0.627273 0.593238 0.453747 0.563523 0.313843 0.311934 0.262998 0.258096 0.205533 0.109298 0.119418 0.226016 0.936666 1.00032 1.02289 0.975581 0.9024 0.919348 0.903643 0.872793 0.874827 0.593511 0.57138 0.597714 0.839721 0.811968 0.753321 0.767503 0.829072 0.718385 0.570167 0.471562 0.594751 0.626645 0.73919 0.798959 0.789079 0.715111 0.637813 0.656496 0.464339 0.394907 0.245398 0.134382 0.315482 0.403578 0.491496 0.612007 0.654785 0.440084 0.505489 0.584998 0.421342 0.506934 0.530626 0.492162 0.496829 0.535255 0.528074 0.458478 0.39342 0.42726 0.586811 0.599234 0.667859 0.621129 0.125434 0.296582 0.471014 0.500414 0.600203 0.551609 0.484497 0.611954 0.64387 0.713888 0.717654 0.657736 0.624754 0.634343 0.672646 0.302234 0.289002 0.223569 0.115406 0.127413 0.242525 0.595509 0.569054 0.534066 0.56121 0.604826 0.609968 0.378872 0.29279 0.222576 0.259429 0.357068 0.409877 1.11695 1.17826 1.16421 1.07905 0.999101 1.03134 1.31766 1.33901 1.24647 1.83887 1.77612 1.68576 1.65499 1.72549 1.82814 1.41985 1.46476 1.40651 1.31551 1.27563 1.33033 1.37211 1.32428 1.32541 1.39357 1.46428 1.44677 1.48052 1.47345 1.57108 1.63165 1.58015 1.55633 1.63568 1.6519 1.57021 0.949919 1.02962 1.03947 0.96345 1.35655 1.39481 1.45312 0.550942 0.559435 0.612787 0.614794 0.6056 0.615993 0.602859 0.901921 0.879346 0.811607 0.826357 0.636692 0.640365 0.583055 1.21763 1.17872 1.08659 1.07157 1.15427 1.28998 1.35595 1.40561 1.34168 1.77017 1.68489 1.67125 1.75809 1.30316 1.31085 1.28033 1.48678 1.46657 1.53947 1.72774 1.70776 1.76142 1.41644 1.42312 1.43071 1.44829 1.45031 0.723714 0.753728 0.696957 1.63666 1.57472 1.62139 1.67859 1.98934 1.9841 1.9939 2.00304 1.50949 1.56136 1.4975 1.45146 1.43462 1.43733 1.46153 0.666788 0.563562 0.514905 0.578304 0.667117 1.52618 1.58507 1.66777 1.66694 1.58435 1.315 1.28521 1.21195 1.23605 1.11656 1.14652 1.23257 1.1992 1.3262 1.39431 1.38255 1.32038 1.87201 1.80365 1.8625 0.710437 0.70826 0.622863 0.631167 0.561919 0.524092 0.525357 0.562161 1.40093 1.42168 1.38303 1.3541 1.37932 1.61245 1.64604 1.57449 1.49621 1.52197 1.3079 1.35827 1.82523 1.71883 1.79832 1.40542 1.38091 1.35788 1.97823 1.9373 1.92693 1.97235 1.89224 1.945 1.32175 1.35262 1.41986 1.38254 1.6148 1.55166 1.67248 1.39028 1.44576 1.41669 1.35727 0.285157 0.342956 0.293416 0.224778 0.338607 0.333127 0.415699 0.416083 0.612896 0.590918 0.60905 0.634768 0.868003 0.851834 0.775783 0.799003 0.746745 0.710876 0.782773 0.811097 0.752243 0.70099 0.735328 0.79719 0.811916 0.634516 0.665414 0.677781 0.638161 0.622599 0.649066 0.758977 0.760111 0.822159 0.612584 0.373601 0.283994 1.40085 1.37005 1.56899 1.38317 0.542007 0.66555 1.36018 1.17226 1.26134 1.60281 0.595102 1.44299 1.99583 1.62775 1.42762 1.50805 1.72 1.3465 1.1394 0.857072 0.616846 0.58641 0.993357 1.60223 1.54211 1.37895 1.36552 1.75429 1.26185 1.08855 0.316263 0.581165 0.19967 0.636431 0.669517 0.564404 0.491533 0.196831 0.627311 0.471639 0.45119 0.55519 0.549196 0.388766 0.23404 0.397092 0.720979 0.542088 0.666232 0.771291 0.777359 0.593581 0.591085 0.559983 0.823001 0.858332 0.962947 0.178561 0.213594 0.515162 0.535007 0.209786 0.174983 0.356915 0.499957 0.572928 0.463258 0.369152 0.666897 0.40318 0.480283 0.592262 0.825462 0.726339 0.700272 0.951583 1.05311 0.720672 0.945463 1.02684 1.01067 0.849326 0.818267 0.50429 0.803434 0.945275 1.13392 1.16477 0.511371 0.665732 0.80533 0.705093 0.799179 0.877294 0.505089 0.954394 0.907533 0.936592 1.02919 1.04729 1.16305 1.11142 1.26696 1.24914 1.29822 0.670114 0.747587 0.886176 0.721367 0.658375 1.41373 1.4225 0.775288 0.96983 0.843286 1.05191 1.0037 1.08074 1.19503 1.25385 1.15562 1.47857 1.53358 1.41591 1.33816 1.1297 0.98756 1.07385 1.18785 1.31213 1.41 1.62122 1.14955 0.798081 0.802813 0.939656 1.08525 1.1235 1.00211 1.40197 1.43004 1.25074 1.22815 0.871748 1.66644 1.73828 1.56493 1.58057 1.21905 1.34901 1.52774 1.25763 1.70096 1.27325 1.26882 1.16995 1.14654 1.70397 1.81363 1.86715 1.80902 1.79315 0.980084 1.04945 1.68007 1.84729 1.90788 1.32968 1.24647 1.35749 1.26499 1.3324 1.42561 1.48111 1.33194 1.32417 1.47562 1.40938 1.53476 1.92722 1.03609 1.09381 1.27993 1.91647 1.97319 0.649024 0.647993 0.776775 0.851091 0.798371 0.710234 1.8426 1.88617 1.7264 1.67456 1.4543 1.45187 1.14107 1.30601 1.84406 1.70793 1.60196 1.13093 1.26311 1.1051 1.95808 1.80583 1.63389 1.7466 1.38547 1.57795 1.66055 1.61309 1.45308 1.25329 1.6596 1.81507 1.43634 1.50948 1.59293 1.67144 1.60804 1.44159 1.82705 1.76215 1.74159 1.99478 2.00765 1.94493 1.35627 1.71245 1.98327 1.89238 1.88311 1.70976 1.58421 1.44452 2.00205 1.98187 2.03214 2.02873 1.95331 2.02441 1.67145 1.64719 1.91187 1.82066 1.52298 1.81853 1.73685 1.60549 1.50148 1.43049 1.51269 1.50309 1.57241 1.98916 2.02082 1.88522 1.82203 1.8873 1.98123 1.97555 1.91603 1.98363 1.95911 1.8581 1.74233 1.77707 1.4132 1.37615 1.54754 1.62991 1.54323 1.33795 1.33388 1.28405 1.92316 1.8321 1.68686 1.68422 1.843 1.93983 1.56276 1.67533 1.61806 1.50402 1.43475 0.318625 0.417016 0.505004 0.451636 1.56732 1.84056 1.4344 1.88641 1.94936 2.00427 1.70104 1.43322 1.93273 1.68303 1.92663 1.6397 1.72596 2.00654 2.03088 1.50915 1.79831 1.99088 1.98788 1.81869 2.02862 1.79588 1.57079 1.88342 1.70328 1.38003 1.51326 1.47853 1.74234 1.87648 1.85995 1.22808 1.50441 1.23017 1.60936 0.745087 1.97653 1.73506 1.23415 1.90213 1.66767 1.49578 1.36404 1.83403 1.39593 1.43949 1.44992 1.93624 1.73842 1.15728 1.53987 1.85358 1.824 1.37634 1.71942 1.01323 1.32754 1.24348 1.15631 1.42168 0.960762 1.21836 1.68314 1.71425 1.25327 1.14325 0.936667 1.54218 0.841101 0.812869 1.37439 1.18183 1.34791 1.2321 1.0925 1.0188 1.15925 0.922342 1.53114 0.592153 1.29513 0.993443 0.875952 0.616202 1.22721 0.924001 0.647294 0.875602 0.977511 1.06027 0.903469 1.51169 0.800863 1.15651 0.886894 0.580977 0.683731 0.335251 0.92988 0.639245 0.874124 0.666531 0.330129 0.572623 0.465032 0.315736 0.631683 0.751818 1.06444 0.573822 0.393734 0.701527 0.847469 0.362623 0.567206 0.604514 0.690462 0.339427 2.42085 2.4499 2.09679 2.49161 2.30944 0.398883 1.09951 2.19391 1.07661 1.44905 2.17696 2.26402 1.82802 1.71608 1.65548 1.86769 2.31644 1.85537 0.897208 2.20131 1.79876 0.897271 1.91374 0.822265 1.52322 1.92892 1.6637 2.31338 0.762653 0.781448 0.810082 0.728869 0.692905 0.65486 0.708024 1.84621 1.92616 1.95576 1.9787 2.08173 2.04153 1.95613 1.90055 2.09754 2.0376 2.39868 2.36031 2.22551 2.26907 2.20719 2.18548 2.25118 2.38665 2.42806 2.3488 2.33945 1.73843 2.12268 2.02179 2.11271 2.0129 1.8396 1.95863 1.98763 1.8996 2.21879 2.3073 2.37266 2.29144 2.26315 2.32948 2.41722 2.40505 2.49388 2.45286 2.36954 2.34907 2.48662 2.44166 2.45582 2.44661 2.45857 2.48882 2.49366 2.46954 2.37232 2.40468 2.21378 2.21142 2.29686 2.37327 2.43663 2.43395 2.30455 2.38092 2.51948 2.52298 2.52093 2.51973 2.47098 2.50132 2.14883 2.16317 2.11011 1.89532 1.91992 1.99062 2.07951 2.07437 2.00052 1.92488 1.95023 1.98915 1.96022 1.92171 2.01456 2.06777 2.09225 2.23135 2.29948 2.2062 2.17829 2.00395 2.07781 2.30862 2.38074 2.45457 2.4803 2.35055 2.39587 2.10224 2.0631 2.25695 2.19142 2.23803 2.2697 2.07803 2.14256 2.47784 2.41358 2.51389 2.51779 2.54513 2.55472 2.53663 2.54226 2.5572 2.54232 2.5247 2.54168 2.5535 2.55406 2.47621 2.53074 1.96583 2.01608 2.0206 2.13493 2.23433 2.10945 2.37557 2.44718 2.47283 2.42965 2.33626 2.31241 2.46871 2.40579 2.48172 2.42857 2.55051 2.53241 2.23617 2.13231 2.33335 2.32519 1.8394 2.46342 2.52547 2.52988 2.53792 2.5267 2.54467 2.11175 2.16943 2.13448 2.17859 2.24759 2.29131 2.20334 2.21855 1.89541 1.90085 2.07662 2.09002 2.04012 1.97718 2.00753 1.96402 1.88555 1.82163 1.73796 1.82249 2.32745 2.28311 2.23479 2.29493 2.1103 2.13514 1.9808 2.04593 1.70134 2.03715 2.04313 2.23522 2.12419 2.18184 2.19835 2.11227 2.01782 1.98976 2.0766 2.09355 2.01254 1.84382 1.75922 1.90638 1.91857 2.37587 2.38142 2.19557 2.41289 2.40583 1.69326 1.75185 1.55743 1.60208 1.56961 1.48863 1.63676 1.63635 2.10154 2.30337 1.80949 1.69513 1.80019 1.58508 1.49887 2.05711 2.0228 2.01173 2.03675 2.07437 2.24139 2.14228 2.15777 2.24027 2.48184 2.3319 2.28625 2.25817 2.42828 2.35865 0.628148 0.672942 0.807961 0.769041 0.916378 0.823412 0.834948 0.785506 0.629618 0.524458 0.666409 0.693211 2.46671 2.43334 2.45688 2.47583 1.65691 1.45384 1.50892 1.44366 1.34039 1.45394 2.45141 2.45709 2.37651 2.39969 1.96165 1.90853 1.98276 1.97826 1.78422 1.83252 2.07636 1.98389 1.9241 1.71792 1.59361 1.63251 1.57219 1.4842 1.47849 1.56642 1.81021 1.78785 1.62553 1.72903 1.59189 1.68161 1.61005 1.52584 2.40158 2.43003 2.41011 2.35733 2.40418 2.27808 2.24951 1.48488 1.45465 1.41146 1.30175 1.42022 1.45734 2.23646 2.2832 2.37511 2.36004 2.31615 2.28602 2.24163 2.33302 2.31714 2.27579 2.22073 2.24968 1.5828 1.75819 1.69875 1.67236 1.65926 1.79166 1.71971 2.21742 2.20891 2.25275 1.79873 1.77613 1.94163 1.78746 1.93804 1.88285 1.7337 1.64056 1.6208 1.67975 1.7416 1.77877 2.12095 1.99007 2.0695 2.13256 2.20959 2.08843 2.01299 2.12677 2.15429 1.33432 1.25951 1.28676 1.34798 1.48767 1.52951 1.51168 1.45711 1.39149 1.47731 1.92872 1.92971 1.9196 1.82446 1.74894 1.78354 1.86828 1.35486 1.29211 1.32967 1.23919 1.40098 1.4062 1.30976 1.22795 1.11663 1.13449 0.976811 1.05717 1.15799 1.18496 1.06503 1.29382 1.18485 1.33625 1.36605 2.07205 2.01709 1.99256 2.05306 1.67288 1.50653 1.54111 1.37607 1.46814 1.31886 1.83419 1.74531 1.63255 1.77115 1.81081 1.95286 1.95496 1.87048 1.79188 1.74451 1.8862 1.84752 1.61005 1.61523 1.68958 1.67539 1.38921 1.34766 1.20465 1.25377 1.24047 1.16168 1.10644 1.20289 1.11636 1.06575 0.971171 0.928664 1.26544 1.34882 1.32487 1.23314 1.0819 0.984495 1.15957 1.15561 1.83639 1.7596 1.82951 1.74133 1.70034 1.73727 1.82547 1.87865 1.07064 1.00486 1.11877 1.1795 1.02266 0.958791 0.821315 0.874752 0.90723 0.764858 0.844179 1.67972 1.68923 1.54158 1.60911 1.601 1.5293 1.47891 1.57406 1.46274 1.42815 1.46948 1.55979 1.59246 1.53315 1.4104 1.32642 1.40816 1.4499 1.56789 1.51875 1.5427 1.37316 1.45517 0.961522 0.859776 0.992026 0.903773 0.892224 0.952101 1.04578 1.06933 0.763599 0.666302 0.737845 0.801072 1.30966 1.27198 1.25106 1.13876 1.30579 1.17703 1.07682 1.25384 1.2608 0.722126 0.699549 0.646352 0.601173 0.524282 0.617731 1.4237 1.4534 1.42353 1.36364 1.30899 1.39534 1.29346 1.27392 1.17251 1.08414 1.13451 1.18999 0.782609 0.708623 0.714718 0.786426 0.822143 0.793198 0.681415 0.766574 1.10403 1.18384 1.28346 1.32966 1.11817 1.19102 1.25363 1.28034 1.22111 1.14975 1.14222 1.21673 0.649797 0.537568 0.636974 0.691589 1.3242 1.26801 1.16107 1.27422 1.10492 1.16266 1.00681 1.0132 0.822079 0.920105 0.937478 0.769093 0.125517 0.445846 0.500331 0.301496 0.337182 0.53178 0.536444 0.469929 0.757387 0.780372 0.889111 0.769575 0.7161 0.827248 0.810389 0.616894 0.572715 0.815022 0.899045 0.988793 0.912122 0.82217 0.807378 0.904815 0.378175 0.466745 0.601391 0.631371 0.601945 0.55833 0.509163 0.525009 1.0124 1.11438 1.1637 1.11656 0.977977 1.03485 1.07875 1.08292 1.0131 0.596665 0.125757 0.320407 0.88238 0.80473 0.700344 0.741578 0.829495 0.689357 0.764093 0.7076 0.655075 0.739381 0.941097 1.02495 1.05829 1.02233 0.939454 0.899611 0.119091 0.226388 0.371523 0.448588 0.29239 0.711634 0.724041 0.717246 0.682676 0.535245 0.651771 0.409574 0.667887 0.664429 0.606692 0.572535 0.548691 0.562907 0.623703 0.64894 0.617521 0.583604 0.532394 0.450896 0.597162 0.595339 0.480692 0.619081 0.125671 0.473789 0.557772 0.328009 0.352669 0.42427 0.531819 0.626568 0.609887 0.504587 0.420592 0.414891 0.50621 0.671836 0.684226 0.619618 0.556637 0.581017 0.624618 0.244717 0.124104 0.125432 0.24305 0.314468 0.317892 0.591064 0.601254 0.595208 0.610875 0.626046 0.595641 1.5482 1.58951 1.55726 1.46825 1.40717 1.4629 1.66309 1.7068 1.62583 2.34256 2.27478 2.18504 2.15977 2.23403 2.33642 1.87435 1.9019 1.83211 1.74458 1.71965 1.7885 1.85692 1.80255 1.79308 1.85382 1.92862 1.92461 1.9439 1.94994 2.04717 2.09822 2.03792 2.07673 2.15485 2.17024 2.08946 1.34343 1.41655 1.44979 1.37881 1.86306 1.89674 1.95815 0.306262 0.236141 0.312723 0.368711 0.300691 0.362474 0.230918 1.00462 0.947753 0.875501 0.931107 0.963231 0.979866 0.91828 1.5613 1.54301 1.45044 1.40694 1.47715 1.60712 1.6602 1.73105 1.68041 2.28893 2.20354 2.18874 2.27552 1.78058 1.7791 1.74977 1.76919 1.75139 1.84522 2.16551 2.15062 2.20549 1.93842 1.94635 1.95482 1.97184 1.9723 0.918867 0.984319 0.966593 2.09089 2.03408 2.08927 2.14215 2.50475 2.49939 2.51238 2.52181 1.83391 1.89615 1.8026 1.97183 1.95639 1.96068 1.98341 0.939336 0.848575 0.834229 0.902683 0.973756 2.02986 2.08039 2.1656 2.1721 2.09248 1.72995 1.71543 1.63603 1.64488 1.50102 1.51102 1.60599 1.59083 1.64468 1.71052 1.67301 1.61278 2.37967 2.30378 2.36542 1.09859 1.07934 0.989402 1.01351 0.45701 0.510953 0.522539 0.477575 1.91973 1.93567 1.8923 1.86542 1.89618 2.07597 2.12152 2.05954 1.97688 1.98795 1.61387 1.66848 2.34124 2.23619 2.31604 1.90499 1.88133 1.85168 2.49788 2.45582 2.44705 2.49374 2.41089 2.46466 1.81095 1.8338 1.90582 1.87631 2.09161 2.0333 2.15615 1.89252 1.94427 1.908 1.85275 0.531152 0.493263 0.419397 0.463708 0.290096 0.346309 0.303473 0.231337 0.430251 0.471513 0.52903 0.494761 1.28486 1.26132 1.17665 1.20371 1.09137 1.05846 1.1399 1.17137 0.896742 0.7977 0.776821 0.863551 0.932482 0.359976 0.446967 0.447118 0.341776 0.295 0.375365 0.853748 1.11393 1.23131 0.479127 0.292731 0.472145 1.89788 1.85773 2.04329 1.89787 0.491107 1.04377 1.66422 1.55072 1.6813 2.10516 0.897373 1.96514 2.51297 2.08885 1.95122 1.80599 2.23809 1.66832 1.48481 0.941533 0.303228 0.304571 1.39557 2.12157 2.01034 1.85233 1.80778 2.2582 1.62253 1.50081 0.603648 0.211077 0.620443 0.408331 0.5166 0.437369 0.227503 0.540241 0.513615 0.596979 0.622485 0.494174 0.598681 0.608157 0.3829 0.20234 0.979522 0.690338 0.690223 0.719009 0.785011 0.21221 0.398819 0.537536 0.998148 0.951074 1.07107 0.569488 0.446569 0.812727 0.909783 0.598587 0.587288 0.601848 0.76635 0.865524 0.82675 0.729842 0.425188 0.398255 0.217283 0.222495 0.852563 0.814462 0.914905 1.04494 1.21687 0.582439 1.15036 1.19767 1.22501 1.09924 0.731753 0.722463 1.10765 1.21167 1.33971 1.36551 0.550215 0.621463 1.16878 1.09723 1.18784 1.20662 0.70053 0.977453 0.890308 1.36026 1.46254 1.3619 1.5019 1.37512 1.51649 1.52122 1.61267 0.83442 0.787328 0.917788 1.06123 0.992426 1.79133 1.76253 1.05194 1.24769 1.02483 1.14296 1.15914 1.29432 1.62033 1.64669 1.53129 1.81621 1.89737 1.77125 1.72739 1.5204 1.34929 1.37386 1.4507 1.59542 1.73064 2.01405 1.27085 1.06669 0.982728 1.04379 1.2145 1.31989 1.25747 1.84656 1.84803 1.42719 1.44032 1.24391 2.08364 2.17311 2.01524 2.00566 1.69052 1.83348 1.99846 1.70259 2.16686 1.73374 1.749 1.64426 1.60507 2.17912 2.28423 2.34529 2.27426 2.24748 1.35725 1.37497 2.16745 2.34337 2.39953 1.59268 1.55611 1.70334 1.48839 1.5452 1.68363 1.99229 1.83519 1.82327 1.97057 1.92998 1.88645 2.4282 1.40364 1.39962 1.5633 2.42391 2.48416 0.592115 0.74738 0.877537 0.860233 0.720028 0.556952 2.35319 2.40296 2.24162 2.18511 1.97249 1.95861 1.549 1.69838 2.34318 2.19997 2.10306 1.56194 1.65631 1.51014 2.47444 2.3185 2.15032 2.2654 1.81298 2.00085 2.10611 2.13103 1.97588 1.71041 2.05911 2.26218 1.7407 1.80217 1.92414 2.03327 1.97706 1.79335 2.2568 2.16923 2.13247 2.5163 2.529 2.46668 1.77178 2.22868 2.50535 2.41084 2.39822 2.22461 2.10364 1.96761 2.52499 2.50161 2.55558 2.54735 2.47047 2.54498 2.17837 2.1587 2.42138 2.32376 1.9712 2.24985 2.14337 2.00146 1.92149 1.94829 2.02303 1.9902 2.07038 2.49721 2.53352 2.37952 2.30346 2.35427 2.4754 2.47432 2.42682 2.49192 2.45846 2.35088 2.23961 2.28321 1.92044 1.8723 2.0157 2.11344 2.04462 1.79389 1.82009 1.75417 2.39202 2.28412 2.14374 2.15866 2.32524 2.42213 2.00926 2.10676 2.02304 1.90673 1.86695 0.669275 0.726899 0.838679 0.767602 1.99062 2.31006 1.92515 2.3888 2.43412 2.50878 2.18835 1.93855 2.42316 2.11317 2.42959 2.14366 2.22096 2.52206 2.55291 2.0243 2.30834 2.51194 2.50282 2.3321 2.55263 2.20959 1.90315 2.33382 2.08788 1.85307 2.03188 1.92809 2.20734 2.3946 2.37917 1.6563 1.89837 1.67384 2.11908 0.729667 2.49315 2.15985 1.5789 2.41026 2.04079 2.01736 1.87634 2.35221 1.65274 1.82751 1.7533 2.4382 2.24041 1.51924 2.05688 2.34149 2.30453 1.83562 2.16355 1.41538 1.54798 1.73289 1.40618 1.89379 1.14583 1.38829 2.0989 2.16851 1.57345 1.29898 1.15901 1.91429 1.18295 0.911735 1.67227 1.48115 1.76071 1.66181 1.54467 1.07505 1.42472 1.01091 1.92385 0.883755 1.65025 1.3693 1.28361 0.692144 1.46512 1.24326 0.873691 0.839257 1.25063 1.29336 1.23065 2.00274 0.756375 1.37981 1.03491 0.417383 1.01604 0.569144 1.07799 0.427723 0.909686 0.839438 0.309316 0.746737 0.557928 0.65004 0.981991 0.60237 1.21484 0.593454 0.409931 0.599778 1.09035 0.658104 0.649401 0.354569 0.649851 0.712571 0.524131 -2.40859 2.42069 1.99303 2.45586 2.16306 0.466146 1.40423 2.02177 1.37759 1.29686 2.32016 2.22623 1.59334 1.47611 1.41387 1.95853 2.23253 2.07792 1.14877 2.03789 1.9058 1.10339 1.8427 0.676623 1.38191 1.75157 1.53567 2.26161 0.956311 0.966318 1.01918 0.909112 0.856988 0.857398 0.900106 1.67252 1.75152 1.7529 1.79088 1.89184 1.85869 1.79385 1.75354 1.93707 1.86946 2.49051 2.46053 2.31417 2.36798 2.31475 2.31693 2.37013 2.49597 2.53526 2.47881 2.45904 1.87341 2.20969 2.11226 2.2306 2.11977 1.93475 2.03631 2.04817 1.96867 2.26966 2.36125 2.45637 2.37304 2.33487 2.39411 2.49409 2.47243 2.55713 2.51288 2.41525 2.38257 2.52804 2.49078 2.55158 2.53629 2.53868 2.56266 2.57115 2.55841 2.50065 2.52058 2.31186 2.32399 2.4169 2.48524 2.52681 2.5138 2.39764 2.48009 2.57525 2.56793 2.57967 2.57047 2.54208 2.57071 2.20628 2.23106 2.19544 1.98421 1.9949 2.05896 2.15363 2.12532 2.05571 1.979 1.99809 2.01907 2.00641 2.08417 2.16842 2.24508 2.25381 2.37373 2.44083 2.37051 2.33289 2.14266 2.20605 2.38898 2.45671 2.51762 2.53333 2.40858 2.46147 2.14113 2.0896 2.28657 2.23092 2.30878 2.32897 2.13647 2.21471 2.50776 2.43884 2.52585 2.54065 2.57189 2.57443 2.57683 2.57969 2.56663 2.54772 2.55659 2.56349 2.55781 2.54686 2.48776 2.54314 1.9958 2.02021 2.04234 2.17967 2.28199 2.13847 2.42305 2.49192 2.50644 2.45335 2.36339 2.35256 2.47501 2.41813 2.47642 2.41425 2.53744 2.52716 2.25183 2.1448 2.32456 2.33129 1.99522 2.46151 2.51322 2.50295 2.51245 2.47894 2.51096 2.29513 2.34527 2.32223 2.35741 2.40919 2.44255 2.3725 2.38875 2.09904 2.11709 2.27275 2.28665 2.24331 2.19081 2.21423 2.18192 2.11514 2.04941 1.98537 2.0589 2.46512 2.41657 2.39298 2.44442 2.29761 2.31266 2.17496 2.24182 1.83326 2.02998 2.01973 2.2204 2.12095 2.33578 2.33914 2.24512 2.15591 2.17084 2.25039 2.25441 2.16538 1.99095 1.9078 2.07963 2.07652 2.37014 2.36009 2.14839 2.34855 2.35541 1.84708 1.91335 1.7272 1.76054 1.72434 1.6534 1.7805 1.77951 2.01338 2.20135 1.98987 1.90169 1.99757 1.74498 1.6683 1.99087 1.94407 1.95811 2.00919 2.03228 2.21199 2.10861 2.11019 2.18658 2.43135 2.2925 2.22415 2.18448 2.36715 2.2994 0.921016 0.943901 1.09546 1.03911 1.17128 1.07429 1.04511 1.0134 0.876638 0.767961 0.863664 0.916852 2.39376 2.35994 2.3672 2.39864 1.90683 1.7022 1.74251 1.62829 1.56003 1.67271 2.36538 2.36328 2.27406 2.30938 2.16464 2.08718 2.16942 1.9485 1.69115 1.75296 2.02227 1.93796 1.86885 1.96905 1.85376 1.89308 1.83237 1.74451 1.75432 1.83346 1.99633 1.99173 1.80452 1.9043 1.78479 1.9187 1.85908 1.74748 2.2902 2.3243 2.31181 2.23751 2.29515 2.15917 2.14591 1.67918 1.66245 1.59607 1.4898 1.59297 1.63189 2.07354 2.12954 2.25118 2.23118 2.17587 2.13621 2.08986 2.20208 2.17537 2.14874 2.08169 2.13715 1.44875 1.65314 1.583 1.53536 1.51111 1.66272 1.58971 2.08589 2.05227 2.10906 1.65424 1.61819 1.80663 1.69011 1.83085 1.76312 1.60197 1.5061 1.49281 1.56286 1.63139 1.65948 1.9617 1.81894 1.89735 1.94828 2.03783 1.90435 1.81724 1.93696 1.97262 1.51643 1.44627 1.49163 1.53784 1.72372 1.77838 1.77939 1.7342 1.65573 1.7386 1.73664 1.76618 1.77155 1.68214 1.59522 1.61425 1.69817 1.60519 1.52902 1.59464 1.51047 1.67987 1.67601 1.59695 1.51335 1.41873 1.4274 1.26842 1.34222 1.41759 1.4249 1.3315 1.58535 1.4839 1.61391 1.64984 1.87165 1.81139 1.78224 1.85143 1.41377 1.23572 1.28436 1.11923 1.22059 1.1015 1.63605 1.56124 1.44706 1.53121 1.5974 1.7319 1.73759 1.64764 1.54837 1.4935 1.65526 1.61082 1.41521 1.46847 1.5319 1.50437 1.62565 1.59893 1.44043 1.5051 1.52111 1.45616 1.37077 1.46936 1.34843 1.31064 1.20984 1.14583 1.46275 1.55703 1.54689 1.4555 1.29772 1.19223 1.35931 1.36659 1.60386 1.5149 1.6101 1.52475 1.50057 1.55061 1.63655 1.6735 1.26593 1.23053 1.34254 1.38705 1.33082 1.26316 1.1371 1.18163 1.19009 1.05688 1.13846 1.4515 1.44519 1.29613 1.35584 1.33296 1.25427 1.20696 1.30827 1.2133 1.16483 1.27431 1.35545 1.37122 1.30322 1.1747 1.09224 1.20363 1.22706 1.41469 1.37369 1.37265 1.21425 1.30594 1.27381 1.17723 1.29725 1.20674 1.18131 1.22749 1.32525 1.36381 0.99314 0.895302 1.01117 1.05181 1.10974 1.05492 1.06791 0.954517 1.13588 1.00348 0.902975 1.05319 1.07678 1.03979 1.00584 0.924274 0.857178 0.838316 0.919027 1.14097 1.17011 1.14528 1.09003 1.01359 1.10807 1.04498 1.0437 0.969828 0.895438 0.906761 0.969393 0.97212 0.890419 0.875994 0.965695 1.13218 1.1118 0.987432 1.06901 0.900416 0.963048 1.03413 1.06441 0.859519 0.947445 0.958639 0.997954 0.963872 0.903585 0.862093 0.942282 0.974858 0.865043 0.955997 1.01493 1.03529 0.969639 0.879974 0.994124 0.806821 0.857301 0.795112 0.76853 0.588516 0.66225 0.617074 0.46742 0.463771 0.745808 0.762521 0.571364 0.646343 0.834444 0.856978 0.800609 0.641365 0.653902 0.729197 0.640529 0.611183 0.651506 0.657849 0.606901 0.635317 0.67961 0.746359 0.826262 0.721338 0.623145 0.662814 0.737936 0.602237 0.692315 0.783984 0.78705 0.726866 0.665266 0.644363 0.709107 0.696187 0.804021 0.861776 0.822207 0.670157 0.740309 0.810351 0.832509 0.736739 0.776815 0.416347 0.403869 0.577968 0.485719 0.389377 0.416903 0.502974 0.416868 0.595791 0.587723 0.488449 0.544219 0.714945 0.792584 0.840766 0.827026 0.756213 0.702387 0.404749 0.471008 0.535968 0.561959 0.453718 0.575201 0.552031 0.482822 0.411567 0.382131 0.463977 0.424512 0.811639 0.821861 0.756482 0.683141 0.538913 0.488643 0.513511 0.560952 0.58337 0.586828 0.41882 0.367017 0.362679 0.417801 0.520671 0.526956 0.288852 0.281494 0.289711 0.0942476 0.207717 0.0973594 0.215389 0.294184 0.283215 0.263503 0.266901 0.0922615 0.200502 0.602362 0.601147 0.559238 0.556836 0.597546 0.60068 0.292273 0.297969 0.215011 0.0974517 0.0948727 0.207196 0.635848 0.63623 0.660427 0.713264 0.738437 0.683064 1.39401 1.42125 1.37743 1.28879 1.23998 1.30855 1.43454 1.49138 1.42302 2.26013 2.18604 2.10263 2.09048 2.17216 2.26692 1.99481 2.03609 1.97572 1.88764 1.85469 1.91015 1.96103 1.91495 1.91829 1.98653 2.05636 2.03675 2.05428 2.04674 2.1415 2.20365 2.15276 2.07244 2.1509 2.15328 2.07189 1.16289 1.22872 1.27569 1.21043 1.78402 1.81036 1.8792 0.638157 0.572696 0.641422 0.702138 0.475627 0.559772 0.484245 0.705091 0.637532 0.5764 0.645757 1.17618 1.18222 1.1157 1.33794 1.33426 1.24654 1.18857 1.24633 1.83904 1.89903 1.95996 1.90173 2.29408 2.20902 2.20754 2.29389 1.89181 1.8945 1.8684 2.01069 1.98722 2.07688 1.99171 1.98491 2.03513 1.90775 1.92414 1.94815 1.96501 1.94982 1.1855 1.24079 1.20707 1.9439 1.89656 1.95992 2.00388 2.43651 2.43245 2.45693 2.46533 2.04787 2.10773 2.02825 1.99085 1.97563 1.96533 1.98784 1.1353 1.03524 1.02071 1.09492 1.16813 1.94941 1.98308 2.07126 2.09439 2.0233 1.90262 1.87612 1.80151 1.82191 1.69379 1.71607 1.8064 1.77954 1.85069 1.92131 1.89726 1.83177 2.29793 2.20822 2.27242 0.930677 0.906179 0.821882 0.849448 0.509934 0.548438 0.613512 0.58519 1.87495 1.88107 1.8243 1.79784 1.84237 1.93149 1.99114 1.94532 1.85787 1.84954 1.36274 1.41643 2.2999 2.21104 2.28779 1.9863 1.96043 1.94078 2.45187 2.41154 2.41545 2.46386 2.37517 2.42473 1.70392 1.71651 1.7948 1.77639 1.97454 1.92507 2.04656 1.81311 1.86124 1.81338 1.76171 0.462452 0.406968 0.403334 0.459287 0.379784 0.363519 0.276845 0.296857 0.614411 0.626711 0.714204 0.70578 1.12179 1.09629 1.00991 1.03663 1.28599 1.25728 1.33893 1.36408 0.653365 0.56334 0.514732 0.583156 0.665286 0.610661 0.712619 0.740626 0.648766 0.574461 0.657646 0.595651 1.30992 1.0662 0.664572 0.329527 0.428537 1.81096 1.74899 1.91401 1.84057 0.563963 0.875866 1.87959 1.74764 1.85011 2.02174 1.08788 1.97705 2.45099 1.95067 1.93357 2.03814 2.25021 1.89852 1.26739 0.642227 0.53429 0.639755 1.21813 2.11089 2.11427 1.97073 1.93993 2.18268 1.40687 1.33487 0.678511 0.184162 0.583467 0.167915 0.179722 0.178038 0.187225 0.508262 0.341121 0.54484 0.74929 0.466582 0.377821 0.476812 0.459126 0.374403 0.770702 0.546569 0.466401 0.388917 0.490698 0.391096 0.521396 0.681341 0.745317 0.661602 0.764545 0.718939 0.623743 0.645095 0.755011 0.62248 0.680102 0.610338 0.623412 0.696206 0.687785 0.625295 0.744738 0.6678 0.532793 0.539812 0.535555 0.543322 0.691639 0.732928 0.922597 0.909668 0.886712 0.908162 0.960647 0.868711 1.04681 0.890709 0.899559 0.97269 1.053 1.0745 0.837778 0.939272 0.982485 0.930167 1.01621 1.00659 0.953345 1.27029 1.20318 1.20099 1.30424 1.14345 1.28908 1.12478 1.2406 1.26179 1.37459 1.10736 1.09451 1.23036 1.27025 1.18798 1.58782 1.53034 1.25373 1.45668 1.24997 1.42444 1.40855 1.53083 1.46153 1.46335 1.34096 1.57503 1.6691 1.54312 1.5268 1.33039 1.14996 1.13741 1.18608 1.33171 1.4816 1.80321 1.56032 1.31092 1.25725 1.34331 1.50961 1.59761 1.51189 1.68887 1.66549 1.70046 1.6905 1.43731 1.88969 1.9938 1.85763 1.82253 1.56803 1.72826 1.87631 1.55828 2.02148 1.5941 1.6304 1.52026 1.46497 2.0549 2.14404 2.20967 2.12319 2.08626 1.5375 1.57057 2.05365 2.23678 2.28216 1.82742 1.76307 1.89616 1.75842 1.81459 1.93296 1.92855 1.75312 1.7307 1.87325 1.89076 2.08431 2.32944 1.6058 1.63434 1.81077 2.3379 2.40412 0.806985 0.952027 1.11007 1.13192 1.00907 0.831896 2.28255 2.35405 2.19875 2.12287 1.93347 1.89043 1.72615 1.88708 2.24988 2.10249 2.02642 1.71714 1.82191 1.67498 2.41639 2.26481 2.11909 2.25432 1.97578 2.16801 2.25329 2.11207 1.96435 1.83932 2.24471 2.40847 1.97985 2.04304 2.14272 2.23998 2.18252 2.00834 2.41712 2.34817 2.31939 2.47805 2.48613 2.4481 1.92292 2.22931 2.48812 2.40975 2.43435 2.25728 2.11461 1.97793 2.52602 2.52415 2.55413 2.57719 2.48855 2.56103 2.23722 2.18549 2.4768 2.39244 2.0955 2.40275 2.31311 2.17136 2.06945 1.9838 2.06428 2.07279 2.13286 2.55835 2.58159 2.46662 2.40993 2.4794 2.55997 2.55421 2.46438 2.5444 2.52875 2.42529 2.30104 2.32541 1.98693 1.95463 2.13852 2.21592 2.11871 1.93134 1.92075 1.87553 2.51072 2.41458 2.26113 2.25501 2.41627 2.52149 1.8579 1.93116 1.82598 1.71718 1.70748 0.848009 0.935968 1.03321 0.944095 1.81543 2.41923 2.02 2.44573 2.53607 2.57528 2.26661 1.99966 2.50777 2.2575 2.50095 2.19157 2.30487 2.556 2.5664 2.06613 2.35891 2.5144 2.54528 2.35235 2.53268 2.37988 2.12806 2.47392 2.28261 1.95878 2.0433 2.07101 2.33426 2.35843 2.39052 1.80358 2.08713 1.82271 2.06295 0.978232 2.43053 2.32613 1.79583 2.33252 2.2334 2.00508 1.80971 2.32761 1.91035 1.99718 1.97552 2.33834 2.15245 1.70089 2.01789 2.22526 2.1731 1.70349 1.99253 1.59201 1.80607 1.62738 1.66567 1.76492 1.42381 1.67232 1.90509 2.01583 1.33412 1.56516 1.38195 1.69517 1.37503 1.20865 1.41488 1.24411 1.58827 1.49578 1.40368 1.38017 1.64656 1.27087 1.71601 1.11123 1.43896 1.1853 1.1141 0.983238 1.18515 1.02856 1.07072 1.13856 1.01757 1.027 1.45215 1.90873 1.07791 1.10304 0.757211 0.744648 0.832295 0.790778 0.794591 0.657492 0.590052 0.629502 0.524636 0.540425 0.61166 0.787705 0.809366 0.911711 0.911612 0.463617 0.324233 0.310889 0.855359 0.593239 0.822955 0.319989 0.341667 0.602168 0.593494 0.339723 \ No newline at end of file +2.40859 2.42069 1.99303 2.45586 2.16306 0.466146 1.40423 2.02177 1.37759 1.29686 2.32016 2.22623 1.59334 1.47611 1.41387 1.95853 2.23253 2.07792 1.14877 2.03789 1.9058 1.10339 1.8427 0.676623 1.38191 1.75157 1.53567 2.26161 0.956311 0.966318 1.01918 0.909112 0.856988 0.857398 0.900106 1.67252 1.75152 1.7529 1.79088 1.89184 1.85869 1.79385 1.75354 1.93707 1.86946 2.49051 2.46053 2.31417 2.36798 2.31475 2.31693 2.37013 2.49597 2.53526 2.47881 2.45904 1.87341 2.20969 2.11226 2.2306 2.11977 1.93475 2.03631 2.04817 1.96867 2.26966 2.36125 2.45637 2.37304 2.33487 2.39411 2.49409 2.47243 2.55713 2.51288 2.41525 2.38257 2.52804 2.49078 2.55158 2.53629 2.53868 2.56266 2.57115 2.55841 2.50065 2.52058 2.31186 2.32399 2.4169 2.48524 2.52681 2.5138 2.39764 2.48009 2.57525 2.56793 2.57967 2.57047 2.54208 2.57071 2.20628 2.23106 2.19544 1.98421 1.9949 2.05896 2.15363 2.12532 2.05571 1.979 1.99809 2.01907 2.00641 2.08417 2.16842 2.24508 2.25381 2.37373 2.44083 2.37051 2.33289 2.14266 2.20605 2.38898 2.45671 2.51762 2.53333 2.40858 2.46147 2.14113 2.0896 2.28657 2.23092 2.30878 2.32897 2.13647 2.21471 2.50776 2.43884 2.52585 2.54065 2.57189 2.57443 2.57683 2.57969 2.56663 2.54772 2.55659 2.56349 2.55781 2.54686 2.48776 2.54314 1.9958 2.02021 2.04234 2.17967 2.28199 2.13847 2.42305 2.49192 2.50644 2.45335 2.36339 2.35256 2.47501 2.41813 2.47642 2.41425 2.53744 2.52716 2.25183 2.1448 2.32456 2.33129 1.99522 2.46151 2.51322 2.50295 2.51245 2.47894 2.51096 2.29513 2.34527 2.32223 2.35741 2.40919 2.44255 2.3725 2.38875 2.09904 2.11709 2.27275 2.28665 2.24331 2.19081 2.21423 2.18192 2.11514 2.04941 1.98537 2.0589 2.46512 2.41657 2.39298 2.44442 2.29761 2.31266 2.17496 2.24182 1.83326 2.02998 2.01973 2.2204 2.12095 2.33578 2.33914 2.24512 2.15591 2.17084 2.25039 2.25441 2.16538 1.99095 1.9078 2.07963 2.07652 2.37014 2.36009 2.14839 2.34855 2.35541 1.84708 1.91335 1.7272 1.76054 1.72434 1.6534 1.7805 1.77951 2.01338 2.20135 1.98987 1.90169 1.99757 1.74498 1.6683 1.99087 1.94407 1.95811 2.00919 2.03228 2.21199 2.10861 2.11019 2.18658 2.43135 2.2925 2.22415 2.18448 2.36715 2.2994 0.921016 0.943901 1.09546 1.03911 1.17128 1.07429 1.04511 1.0134 0.876638 0.767961 0.863664 0.916852 2.39376 2.35994 2.3672 2.39864 1.90683 1.7022 1.74251 1.62829 1.56003 1.67271 2.36538 2.36328 2.27406 2.30938 2.16464 2.08718 2.16942 1.9485 1.69115 1.75296 2.02227 1.93796 1.86885 1.96905 1.85376 1.89308 1.83237 1.74451 1.75432 1.83346 1.99633 1.99173 1.80452 1.9043 1.78479 1.9187 1.85908 1.74748 2.2902 2.3243 2.31181 2.23751 2.29515 2.15917 2.14591 1.67918 1.66245 1.59607 1.4898 1.59297 1.63189 2.07354 2.12954 2.25118 2.23118 2.17587 2.13621 2.08986 2.20208 2.17537 2.14874 2.08169 2.13715 1.44875 1.65314 1.583 1.53536 1.51111 1.66272 1.58971 2.08589 2.05227 2.10906 1.65424 1.61819 1.80663 1.69011 1.83085 1.76312 1.60197 1.5061 1.49281 1.56286 1.63139 1.65948 1.9617 1.81894 1.89735 1.94828 2.03783 1.90435 1.81724 1.93696 1.97262 1.51643 1.44627 1.49163 1.53784 1.72372 1.77838 1.77939 1.7342 1.65573 1.7386 1.73664 1.76618 1.77155 1.68214 1.59522 1.61425 1.69817 1.60519 1.52902 1.59464 1.51047 1.67987 1.67601 1.59695 1.51335 1.41873 1.4274 1.26842 1.34222 1.41759 1.4249 1.3315 1.58535 1.4839 1.61391 1.64984 1.87165 1.81139 1.78224 1.85143 1.41377 1.23572 1.28436 1.11923 1.22059 1.1015 1.63605 1.56124 1.44706 1.53121 1.5974 1.7319 1.73759 1.64764 1.54837 1.4935 1.65526 1.61082 1.41521 1.46847 1.5319 1.50437 1.62565 1.59893 1.44043 1.5051 1.52111 1.45616 1.37077 1.46936 1.34843 1.31064 1.20984 1.14583 1.46275 1.55703 1.54689 1.4555 1.29772 1.19223 1.35931 1.36659 1.60386 1.5149 1.6101 1.52475 1.50057 1.55061 1.63655 1.6735 1.26593 1.23053 1.34254 1.38705 1.33082 1.26316 1.1371 1.18163 1.19009 1.05688 1.13846 1.4515 1.44519 1.29613 1.35584 1.33296 1.25427 1.20696 1.30827 1.2133 1.16483 1.27431 1.35545 1.37122 1.30322 1.1747 1.09224 1.20363 1.22706 1.41469 1.37369 1.37265 1.21425 1.30594 1.27381 1.17723 1.29725 1.20674 1.18131 1.22749 1.32525 1.36381 0.99314 0.895302 1.01117 1.05181 1.10974 1.05492 1.06791 0.954517 1.13588 1.00348 0.902975 1.05319 1.07678 1.03979 1.00584 0.924274 0.857178 0.838316 0.919027 1.14097 1.17011 1.14528 1.09003 1.01359 1.10807 1.04498 1.0437 0.969828 0.895438 0.906761 0.969393 0.97212 0.890419 0.875994 0.965695 1.13218 1.1118 0.987432 1.06901 0.900416 0.963048 1.03413 1.06441 0.859519 0.947445 0.958639 0.997954 0.963872 0.903585 0.862093 0.942282 0.974858 0.865043 0.955997 1.01493 1.03529 0.969639 0.879974 0.994124 0.806821 0.857301 0.795112 0.76853 0.588516 0.66225 0.617074 0.46742 0.463771 0.745808 0.762521 0.571364 0.646343 0.834444 0.856978 0.800609 0.641365 0.653902 0.729197 0.640529 0.611183 0.651506 0.657849 0.606901 0.635317 0.67961 0.746359 0.826262 0.721338 0.623145 0.662814 0.737936 0.602237 0.692315 0.783984 0.78705 0.726866 0.665266 0.644363 0.709107 0.696187 0.804021 0.861776 0.822207 0.670157 0.740309 0.810351 0.832509 0.736739 0.776815 0.416347 0.403869 0.577968 0.485719 0.389377 0.416903 0.502974 0.416868 0.595791 0.587723 0.488449 0.544219 0.714945 0.792584 0.840766 0.827026 0.756213 0.702387 0.404749 0.471008 0.535968 0.561959 0.453718 0.575201 0.552031 0.482822 0.411567 0.382131 0.463977 0.424512 0.811639 0.821861 0.756482 0.683141 0.538913 0.488643 0.513511 0.560952 0.58337 0.586828 0.41882 0.367017 0.362679 0.417801 0.520671 0.526956 0.288852 0.281494 0.289711 0.0942476 0.207717 0.0973594 0.215389 0.294184 0.283215 0.263503 0.266901 0.0922615 0.200502 0.602362 0.601147 0.559238 0.556836 0.597546 0.60068 0.292273 0.297969 0.215011 0.0974517 0.0948727 0.207196 0.635848 0.63623 0.660427 0.713264 0.738437 0.683064 1.39401 1.42125 1.37743 1.28879 1.23998 1.30855 1.43454 1.49138 1.42302 2.26013 2.18604 2.10263 2.09048 2.17216 2.26692 1.99481 2.03609 1.97572 1.88764 1.85469 1.91015 1.96103 1.91495 1.91829 1.98653 2.05636 2.03675 2.05428 2.04674 2.1415 2.20365 2.15276 2.07244 2.1509 2.15328 2.07189 1.16289 1.22872 1.27569 1.21043 1.78402 1.81036 1.8792 0.638157 0.572696 0.641422 0.702138 0.475627 0.559772 0.484245 0.705091 0.637532 0.5764 0.645757 1.17618 1.18222 1.1157 1.33794 1.33426 1.24654 1.18857 1.24633 1.83904 1.89903 1.95996 1.90173 2.29408 2.20902 2.20754 2.29389 1.89181 1.8945 1.8684 2.01069 1.98722 2.07688 1.99171 1.98491 2.03513 1.90775 1.92414 1.94815 1.96501 1.94982 1.1855 1.24079 1.20707 1.9439 1.89656 1.95992 2.00388 2.43651 2.43245 2.45693 2.46533 2.04787 2.10773 2.02825 1.99085 1.97563 1.96533 1.98784 1.1353 1.03524 1.02071 1.09492 1.16813 1.94941 1.98308 2.07126 2.09439 2.0233 1.90262 1.87612 1.80151 1.82191 1.69379 1.71607 1.8064 1.77954 1.85069 1.92131 1.89726 1.83177 2.29793 2.20822 2.27242 0.930677 0.906179 0.821882 0.849448 0.509934 0.548438 0.613512 0.58519 1.87495 1.88107 1.8243 1.79784 1.84237 1.93149 1.99114 1.94532 1.85787 1.84954 1.36274 1.41643 2.2999 2.21104 2.28779 1.9863 1.96043 1.94078 2.45187 2.41154 2.41545 2.46386 2.37517 2.42473 1.70392 1.71651 1.7948 1.77639 1.97454 1.92507 2.04656 1.81311 1.86124 1.81338 1.76171 0.462452 0.406968 0.403334 0.459287 0.379784 0.363519 0.276845 0.296857 0.614411 0.626711 0.714204 0.70578 1.12179 1.09629 1.00991 1.03663 1.28599 1.25728 1.33893 1.36408 0.653365 0.56334 0.514732 0.583156 0.665286 0.610661 0.712619 0.740626 0.648766 0.574461 0.657646 0.595651 1.30992 1.0662 0.664572 0.329527 0.428537 1.81096 1.74899 1.91401 1.84057 0.563963 0.875866 1.87959 1.74764 1.85011 2.02174 1.08788 1.97705 2.45099 1.95067 1.93357 2.03814 2.25021 1.89852 1.26739 0.642227 0.53429 0.639755 1.21813 2.11089 2.11427 1.97073 1.93993 2.18268 1.40687 1.33487 0.678511 0.184162 0.583467 0.167915 0.179722 0.178038 0.187225 0.508262 0.341121 0.54484 0.74929 0.466582 0.377821 0.476812 0.459126 0.374403 0.770702 0.546569 0.466401 0.388917 0.490698 0.391096 0.521396 0.681341 0.745317 0.661602 0.764545 0.718939 0.623743 0.645095 0.755011 0.62248 0.680102 0.610338 0.623412 0.696206 0.687785 0.625295 0.744738 0.6678 0.532793 0.539812 0.535555 0.543322 0.691639 0.732928 0.922597 0.909668 0.886712 0.908162 0.960647 0.868711 1.04681 0.890709 0.899559 0.97269 1.053 1.0745 0.837778 0.939272 0.982485 0.930167 1.01621 1.00659 0.953345 1.27029 1.20318 1.20099 1.30424 1.14345 1.28908 1.12478 1.2406 1.26179 1.37459 1.10736 1.09451 1.23036 1.27025 1.18798 1.58782 1.53034 1.25373 1.45668 1.24997 1.42444 1.40855 1.53083 1.46153 1.46335 1.34096 1.57503 1.6691 1.54312 1.5268 1.33039 1.14996 1.13741 1.18608 1.33171 1.4816 1.80321 1.56032 1.31092 1.25725 1.34331 1.50961 1.59761 1.51189 1.68887 1.66549 1.70046 1.6905 1.43731 1.88969 1.9938 1.85763 1.82253 1.56803 1.72826 1.87631 1.55828 2.02148 1.5941 1.6304 1.52026 1.46497 2.0549 2.14404 2.20967 2.12319 2.08626 1.5375 1.57057 2.05365 2.23678 2.28216 1.82742 1.76307 1.89616 1.75842 1.81459 1.93296 1.92855 1.75312 1.7307 1.87325 1.89076 2.08431 2.32944 1.6058 1.63434 1.81077 2.3379 2.40412 0.806985 0.952027 1.11007 1.13192 1.00907 0.831896 2.28255 2.35405 2.19875 2.12287 1.93347 1.89043 1.72615 1.88708 2.24988 2.10249 2.02642 1.71714 1.82191 1.67498 2.41639 2.26481 2.11909 2.25432 1.97578 2.16801 2.25329 2.11207 1.96435 1.83932 2.24471 2.40847 1.97985 2.04304 2.14272 2.23998 2.18252 2.00834 2.41712 2.34817 2.31939 2.47805 2.48613 2.4481 1.92292 2.22931 2.48812 2.40975 2.43435 2.25728 2.11461 1.97793 2.52602 2.52415 2.55413 2.57719 2.48855 2.56103 2.23722 2.18549 2.4768 2.39244 2.0955 2.40275 2.31311 2.17136 2.06945 1.9838 2.06428 2.07279 2.13286 2.55835 2.58159 2.46662 2.40993 2.4794 2.55997 2.55421 2.46438 2.5444 2.52875 2.42529 2.30104 2.32541 1.98693 1.95463 2.13852 2.21592 2.11871 1.93134 1.92075 1.87553 2.51072 2.41458 2.26113 2.25501 2.41627 2.52149 1.8579 1.93116 1.82598 1.71718 1.70748 0.848009 0.935968 1.03321 0.944095 1.81543 2.41923 2.02 2.44573 2.53607 2.57528 2.26661 1.99966 2.50777 2.2575 2.50095 2.19157 2.30487 2.556 2.5664 2.06613 2.35891 2.5144 2.54528 2.35235 2.53268 2.37988 2.12806 2.47392 2.28261 1.95878 2.0433 2.07101 2.33426 2.35843 2.39052 1.80358 2.08713 1.82271 2.06295 0.978232 2.43053 2.32613 1.79583 2.33252 2.2334 2.00508 1.80971 2.32761 1.91035 1.99718 1.97552 2.33834 2.15245 1.70089 2.01789 2.22526 2.1731 1.70349 1.99253 1.59201 1.80607 1.62738 1.66567 1.76492 1.42381 1.67232 1.90509 2.01583 1.33412 1.56516 1.38195 1.69517 1.37503 1.20865 1.41488 1.24411 1.58827 1.49578 1.40368 1.38017 1.64656 1.27087 1.71601 1.11123 1.43896 1.1853 1.1141 0.983238 1.18515 1.02856 1.07072 1.13856 1.01757 1.027 1.45215 1.90873 1.07791 1.10304 0.757211 0.744648 0.832295 0.790778 0.794591 0.657492 0.590052 0.629502 0.524636 0.540425 0.61166 0.787705 0.809366 0.911711 0.911612 0.463617 0.324233 0.310889 0.855359 0.593239 0.822955 0.319989 0.341667 0.602168 0.593494 0.339723 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b7992e03b8..9ea1392e0a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,6 +36,7 @@ add_gudhi_module(Hasse_complex) add_gudhi_module(Persistence_representations) add_gudhi_module(Persistent_cohomology) add_gudhi_module(Rips_complex) +add_gudhi_module(Ripser) add_gudhi_module(Simplex_tree) add_gudhi_module(Skeleton_blocker) add_gudhi_module(Spatial_searching) diff --git a/src/Ripser/include/gudhi/ripser.h b/src/Ripser/include/gudhi/ripser.h new file mode 100644 index 0000000000..1e712b397e --- /dev/null +++ b/src/Ripser/include/gudhi/ripser.h @@ -0,0 +1,1419 @@ +/* Based on Ripser commit 140670f2c76997404601e43d8054151f46be9fd7 + * Modification(s): + * - YYYY/MM Author: Description of the modification + * - 2024 Marc Glisse: Heavy refactoring +*/ + +/* + + Ripser: a lean C++ code for computation of Vietoris-Rips persistence barcodes + + MIT License + + Copyright (c) 2015–2021 Ulrich Bauer + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + You are under no obligation whatsoever to provide any bug fixes, patches, or + upgrades to the features, functionality or performance of the source code + ("Enhancements") to anyone; however, if you choose to make your Enhancements + available either publicly, or directly to the author of this software, without + imposing a separate written license agreement for such Enhancements, then you + hereby grant the following license: a non-exclusive, royalty-free perpetual + license to install, use, modify, prepare derivative works, incorporate into + other computer software, distribute, and sublicense such enhancements or + derivative works thereof, in binary and source code form. + +*/ + +//#define GUDHI_INDICATE_PROGRESS + +// #define GUDHI_RIPSER_USE_BOOST_HEAP // only useful when heap::push dominates? +// #define GUDHI_RIPSER_USE_HASHMAP_FOR_SPARSE_DIST_MAT // only useful in cases where edge-collapse is more important? + +/* TODO: + * from branch representative-cocycles + - for vertices: brute force check all vertices that are in the same connected component (could do better, but there is already quadraticness elsewhere in most cases, even the output for dim 0 may be quadratic) + - for others: print_chain just calls iteratively get_pivot on working_reduction_column + * from branch representative-cycles + - dim 0: trivial + - parametrize a number of functions (like add_coboundary) by the (co)boundary iterator so they can be also used for homology + - once cohomology is computed for some dim, assemble the relevant simplices (don't forget the essential ones) and reduce them homology-style. I think we have 2 choices: reduce the birth and check which columns we add (only possibility for essential classes, but do we really need to do cohomology first if we are going to do that?), or reduce the death and look at the column after reduction (Ripser(er) chose this). + * check out the persistence image branch + + * allow non-0 filtration value on vertices, so we can handle all flag-type filtrations, not just plain Rips. cf scikit-tda +*/ + +#ifndef GUDHI_RIPSER_H +#define GUDHI_RIPSER_H + +#include +#include // sqrt +#include +#include +#include +#include +#ifdef GUDHI_INDICATE_PROGRESS +#include +#endif + +#include +#include +#if BOOST_VERSION >= 108100 +#include +#else +#include +#endif + +#ifdef GUDHI_RIPSER_USE_BOOST_HEAP +#include +#endif + +#include +#include + + +namespace Gudhi::ripser { + +#define GUDHI_assert(X) GUDHI_CHECK(X, std::logic_error("")) + +#ifdef GUDHI_RIPSER_USE_BOOST_HEAP +template +using Heap = boost::heap::d_ary_heap, boost::heap::compare>; +#else +template +struct Heap : std::priority_queue { + typedef std::priority_queue Base; + using Base::Base; + void clear() { this->c.clear(); } +}; +#endif + +template +class Union_find { + public: + typedef vertex_t_ vertex_t; + private: + std::vector parent; + std::vector rank; + public: + Union_find(const vertex_t n) : parent(n), rank(n, 0) { + for (vertex_t i = 0; i < n; ++i) parent[i] = i; + } + + // TODO: check which one is faster (probably doesn't matter) + vertex_t find(vertex_t x) { +#if 0 + vertex_t y = x, z; + while ((z = parent[y]) != y) y = z; + while ((z = parent[x]) != y) { + parent[x] = y; + x = z; + } + return z; +#else + // Path halving + vertex_t y = parent[x]; + vertex_t z = parent[y]; + while (y != z) + { + parent[x] = z; + x = z; + y = parent[x]; + z = parent[y]; + } + return y; +#endif + } + + void link(vertex_t x, vertex_t y) { + // this line is redundant, the caller already does it + if ((x = find(x)) == (y = find(y))) return; + if (rank[x] > rank[y]) + parent[y] = x; + else { + parent[x] = y; + if (rank[x] == rank[y]) ++rank[y]; + } + } +}; + +template +bool is_prime(const coefficient_t n) { + if (!(n & 1) || n < 2) return n == 2; + for (coefficient_t p = 3; p * p <= n; p += 2) + if (!(n % p)) return false; + return true; +} + +// For pretty printing, modulo 11, we prefer -1 to 10. +template +coefficient_t normalize(const coefficient_t n, const coefficient_t modulus) { + return n > modulus / 2 ? n - modulus : n; +} + +template +std::vector multiplicative_inverse_vector(const coefficient_t m) { + std::vector inverse(m); + if (!is_prime(m)) + throw std::domain_error("Modulus must be a prime number"); + if ((m - 1) != (coefficient_storage_t)(m - 1)) + throw std::overflow_error("Modulus is too large"); + inverse[1] = 1; + // m = a * (m / a) + m % a + // Multipying with inverse(a) * inverse(m % a): + // 0 = inverse(m % a) * (m / a) + inverse(a) (mod m) + for (coefficient_t a = 2; a < m; ++a) inverse[a] = m - (inverse[m % a] * (m / a)) % m; + return inverse; +} + +#ifdef GUDHI_INDICATE_PROGRESS +constexpr std::chrono::milliseconds time_step(40); +constexpr const char* clear_line="\r\033[K"; +#endif + +/* concept DistanceMatrix +struct DistanceMatrix { + typedef Category; + typedef vertex_t; + typedef value_t; + value_t operator()(vertex_t i, vertex_t j) const; + vertex_t size() const; + // Optional: + static const bool is_sparse; + vector> neighbors; +}; +*/ + +class Tag_dense {}; // Use directly, iterate on vertices +class Tag_sparse {}; // Use directly, iterate on edges +class Tag_other {}; // Could use directly as dense, but prefer converting it. + +template +struct Full_distance_matrix { + public: + typedef Tag_dense Category; + typedef typename Params::vertex_t vertex_t; + typedef typename Params::value_t value_t; + std::vector distances; // TODO: private + private: + vertex_t n; + public: + //Full_distance_matrix(std::vector&& _distances) + // : distances(std::move(_distances)), n(std::sqrt(_distances.size())) {} + + template + Full_distance_matrix(const DistanceMatrix& mat) + : distances(static_cast(mat.size()) * mat.size()), n(mat.size()) { // vertex_t is meant for vertices. Using it for edges could be unsafe, so we cast to size_t. + for (vertex_t i = 0; i < size(); ++i) + for (vertex_t j = 0; j < size(); ++j) + distances[i * n + j] = mat(i, j); // If mat::operator() involves computations, should we try to take advantage of the symmetry? + } + + // Confusing: why is the order j,i significantly faster than i,j? + value_t operator()(const vertex_t j, const vertex_t i) const { + return distances[i * n + j]; + } + vertex_t size() const { return n; } +}; + +enum Compressed_matrix_layout { LOWER_TRIANGULAR, UPPER_TRIANGULAR }; + +template +struct Compressed_distance_matrix { + public: + typedef Tag_dense Category; + typedef typename Params::vertex_t vertex_t; + typedef typename Params::value_t value_t; + std::vector distances; // TODO: private + private: + std::vector rows; // Surprisingly, this is more efficient than computing i*(i-1)/2 + + public: + Compressed_distance_matrix(std::vector&& _distances) + : distances(std::move(_distances)), rows((1 + std::sqrt(1 + 8 * distances.size())) / 2) { + GUDHI_assert(distances.size() == (std::size_t)size() * (size() - 1) / 2); + init_rows(); + } + + template + Compressed_distance_matrix(const DistanceMatrix& mat) + : distances(static_cast(mat.size()) * (mat.size() - 1) / 2), rows(mat.size()) { // vertex_t is meant for vertices. Using it for edges could be unsafe, so we cast to size_t. + init_rows(); + + for (vertex_t i = 1; i < size(); ++i) + for (vertex_t j = 0; j < i; ++j) rows[i][j] = mat(i, j); + } + + value_t operator()(const vertex_t i, const vertex_t j) const { + if (i == j) return 0; + if ((Layout == LOWER_TRIANGULAR) ? (i < j) : (i > j)) + return rows[j][i]; + else + return rows[i][j]; + } + vertex_t size() const { return rows.size(); } + private: + void init_rows() { + if constexpr (Layout == LOWER_TRIANGULAR) { + value_t* pointer = &distances[0]; + for (vertex_t i = 1; i < size(); ++i) { + rows[i] = pointer; + pointer += i; + } + } else { // UPPER_TRIANGULAR + value_t* pointer = &distances[0] - 1; + for (vertex_t i = 0; i < size() - 1; ++i) { + rows[i] = pointer; + pointer += size() - i - 2; + } + } + } +}; + +template +struct Sparse_distance_matrix { + public: + typedef Tag_sparse Category; + static constexpr bool is_sparse = true; + typedef typename Params::vertex_t vertex_t; + typedef typename Params::value_t value_t; + struct vertex_diameter_t { + vertex_diameter_t() =default; + vertex_diameter_t(vertex_t i_, value_t d_) : i(i_), d(d_) {} +#if 1 + // gcc is faster with those 2 lines (or with a std::pair) :-( + vertex_diameter_t(vertex_diameter_t const&o)noexcept :i(o.i),d(o.d){} + vertex_diameter_t&operator=(vertex_diameter_t const&o) noexcept{i=o.i;d=o.d;return*this;} +#endif + vertex_t i; value_t d; + friend vertex_t get_vertex(const vertex_diameter_t& i) { return i.i; } + friend value_t get_diameter(const vertex_diameter_t& i) { return i.d; } + friend bool operator<(vertex_diameter_t const& a, vertex_diameter_t const& b) { + if (a.i < b.i) return true; + if (a.i > b.i) return false; + return a.d < b.d; + } + }; + + std::vector> neighbors; + std::size_t num_edges; // TODO: useless, remove + + private: +#ifdef GUDHI_RIPSER_USE_HASHMAP_FOR_SPARSE_DIST_MAT +#if BOOST_VERSION >= 108100 + boost::unordered_flat_map,value_t> m; +#else + boost::unordered_map,value_t> m; +#endif + // Would a vector (one map per vertex) have any advantage? +#endif + + public: + Sparse_distance_matrix(std::vector>&& _neighbors, + std::size_t _num_edges = 0) + : neighbors(std::move(_neighbors)), num_edges(_num_edges) {init();} + + template + Sparse_distance_matrix(const DistanceMatrix& mat, const value_t threshold) + : neighbors(mat.size()), num_edges(0) { + + for (vertex_t i = 0; i < size(); ++i) + for (vertex_t j = 0; j < size(); ++j) + if (i != j) { + auto d = mat(i, j); + if (d <= threshold) { + ++num_edges; + neighbors[i].emplace_back(j, d); + } + } + init(); + } + + value_t operator()(const vertex_t i, const vertex_t j) const { +#ifdef GUDHI_RIPSER_USE_HASHMAP_FOR_SPARSE_DIST_MAT + // We could insert in both orders to save the minmax for each query. + return m.at(std::minmax(i,j)); + //// We never hit the infinity case? + // auto it = m.find(std::minmax(i,j)); + // return (it != m.end()) ? *it : std::numeric_limits::infinity(); +#else + auto neighbor = + std::lower_bound(neighbors[i].begin(), neighbors[i].end(), vertex_diameter_t{j, 0}); + return (neighbor != neighbors[i].end() && get_vertex(*neighbor) == j) + ? get_diameter(*neighbor) + : std::numeric_limits::infinity(); +#endif + } + vertex_t size() const { return neighbors.size(); } + private: + void init() { +#ifdef GUDHI_RIPSER_USE_HASHMAP_FOR_SPARSE_DIST_MAT + for(vertex_t i=0; i +struct Euclidean_distance_matrix { + public: + typedef Tag_other Category; + typedef typename Params::vertex_t vertex_t; + typedef typename Params::value_t value_t; + + Euclidean_distance_matrix(std::vector>&& _points) + : points(std::move(_points)) { + for (auto p : points) { GUDHI_assert(p.size() == points.front().size()); } + } + + value_t operator()(const vertex_t i, const vertex_t j) const { + GUDHI_assert((std::size_t)i < points.size()); + GUDHI_assert((std::size_t)j < points.size()); + return std::sqrt(std::inner_product( + points[i].begin(), points[i].end(), points[j].begin(), value_t(), std::plus(), + [](value_t u, value_t v) { return (u - v) * (u - v); })); + } + + vertex_t size() const { return points.size(); } + private: + std::vector> points; +}; + +// The gratuitous restrictions on what can be specialized in C++ are annoying. +template > struct Is_sparse_impl : std::bool_constant {}; +template struct Is_sparse_impl> : std::bool_constant {}; +template constexpr bool is_sparse () { return Is_sparse_impl::value; } + +template class Compressed_sparse_matrix_ { + std::vector bounds; + std::vector entries; + + typedef typename std::vector::const_iterator iterator; + typedef boost::iterator_range iterator_pair; + + public: + iterator_pair subrange(const size_t index) const { + return {entries.begin() + (index == 0 ? 0 : bounds[index - 1]), + entries.begin() + bounds[index]}; + } + + // Close the current column, the next push_back will be for a new column + void append_column() { bounds.push_back(entries.size()); } + + void push_back(const ValueType e) { + GUDHI_assert(0 < bounds.size()); + entries.push_back(e); + ++bounds.back(); + } +}; + +/* concept SimplexEncoding +struct SimplexEncoding { + typedef dimension_t; + typedef vertex_t; + typedef simplex_t; // has to be an integer + SimplexEncoding(vertex_t n_vertices, dimension_t max_dim_plus_one); // max_vertices_per_simplex + simplex_t operator()(vertex_t v, dimension_t position) const; // position starts at 1? + vertex_t get_max_vertex(simplex_t s, dimension_t position, vertex_t n_vertices) const; + int num_extra_bits() const; +}; +*/ + +// number of bits necessary to store x with 0 <= x < n +template +constexpr int log2up(vertex_t n) { + --n; + int k = 0; + while(n>0) { n>>=1; ++k; } + return k; +} + +template +class Cns_encoding { + public: + typedef typename Params::dimension_t dimension_t; + typedef typename Params::vertex_t vertex_t; + typedef typename Params::simplex_t simplex_t; + + private: + std::vector> B; // table of binomial coefficients + int extra_bits; + + public: + Cns_encoding(vertex_t n, dimension_t k) : B(k + 1, std::vector(n + 1, 0)) { + static_assert(std::numeric_limits::radix == 2); + const int available_bits = std::numeric_limits::digits; + simplex_t max_simplex_index = 0; + for (vertex_t i = 0; i <= n; ++i) { + B[0][i] = 1; + for (dimension_t j = 1; (vertex_t)j < std::min(i, k + 1); ++j) + B[j][i] = B[j - 1][i - 1] + B[j][i - 1]; + if (i <= k) B[i][i] = 1; + vertex_t mi = std::min(i >> 1, (vertex_t)k); // max + max_simplex_index = B[mi][i]; + if (i > 1 && max_simplex_index < B[mi][i-1]) { // overflow + throw std::overflow_error("cannot encode all simplices of dimension " + std::to_string(k) + " with " + std::to_string(n) + " vertices using only " + std::to_string(available_bits) + " bits"); + } + } + extra_bits = available_bits - log2up(max_simplex_index + 1); + } + + simplex_t operator()(vertex_t n, dimension_t k) const { + GUDHI_assert(n >= k - 1); + return B[k][n]; + } + + // We could get `n` from B and avoid passing it as argument + vertex_t get_max_vertex(const simplex_t idx, const dimension_t k, const vertex_t n) const { + return get_max(n, k - 1, [&](vertex_t w) -> bool { return (*this)(w, k) <= idx; }); + } + + int num_extra_bits() const { return extra_bits; } + + private: + template + static vertex_t get_max(vertex_t top, const vertex_t bottom, const Predicate pred) { + if (!pred(top)) { + vertex_t count = top - bottom; + while (count > 0) { + vertex_t step = count >> 1, mid = top - step; + if (!pred(mid)) { + top = mid - 1; + count -= step + 1; + } else + count = step; + } + } + return top; + } +}; + +template +class Bitfield_encoding { + public: + typedef typename Params::dimension_t dimension_t; + typedef typename Params::vertex_t vertex_t; + typedef typename Params::simplex_t simplex_t; + + private: + int bits_per_vertex; + int extra_bits; + + public: + Bitfield_encoding(vertex_t n, dimension_t k) : bits_per_vertex(log2up(n)) { + static_assert(std::numeric_limits::radix == 2); + const int available_bits = std::numeric_limits::digits; + extra_bits = available_bits - bits_per_vertex * k; + if (extra_bits < 0) + throw std::overflow_error("cannot encode all simplices of dimension " + std::to_string(k - 1) + " with " + std::to_string(n) + " vertices using only " + std::to_string(available_bits) + " bits"); + // The message is a bit misleading, it is tuples that we cannot encode, and just with this representation. + } + + simplex_t operator()(vertex_t n, dimension_t k) const { + if(k==0) return 1; // because of odd use in (co)boundary... + --k; + // USE_N_MINUS_K only useful if it somehow helps remove the test k==0 above +#ifdef USE_N_MINUS_K + return (simplex_t)(n - k) << (bits_per_vertex * k); +#else + return (simplex_t)n << (bits_per_vertex * k); +#endif + } + + vertex_t get_max_vertex(const simplex_t idx, dimension_t k, const vertex_t) const { + GUDHI_assert(k > 0); + --k; +#ifdef USE_N_MINUS_K + return static_cast(idx >> (bits_per_vertex * k)) + k; +#else + return static_cast(idx >> (bits_per_vertex * k)); +#endif + } + + int num_extra_bits() const { return extra_bits; } +}; + +template struct Rips_filtration { + using size_t = typename Params::size_t; + using vertex_t = typename SimplexEncoding::vertex_t; + // static_assert(std::is_same_v); // too strict + using simplex_t = typename SimplexEncoding::simplex_t; + using dimension_t = typename SimplexEncoding::dimension_t; + using value_t = typename DistanceMatrix::value_t; + using coefficient_storage_t = typename Params::coefficient_storage_t; + using coefficient_t = typename Params::coefficient_t; + static constexpr bool use_coefficients = Params::use_coefficients; + + // The definition of entry_t could be added in some intermediate layer between SimplexEncoding and here + struct entry_with_coeff_t { + simplex_t content; + entry_with_coeff_t(simplex_t _index, coefficient_t _coefficient, int bits_for_coeff) + : content((_index << bits_for_coeff) | (_coefficient - 1)) { GUDHI_assert(_coefficient != 0); } + entry_with_coeff_t() {} + // We never store a coefficient of 0, so we can store coef-1 so %2 requires 0 bit and %3 only 1 bit + friend const entry_with_coeff_t& get_entry(const entry_with_coeff_t& e) { return e; } + }; + simplex_t get_index(const entry_with_coeff_t& e) const { return e.content >> num_bits_for_coeff(); } + coefficient_t get_coefficient(const entry_with_coeff_t& e) const { return static_cast(e.content & (((simplex_t)1 << num_bits_for_coeff()) - 1)) + 1; } + void set_coefficient(entry_with_coeff_t& e, const coefficient_t c) const { GUDHI_assert(c!=0); e.content = (e.content & ((simplex_t)(-1) << num_bits_for_coeff())) | (c - 1); } + // Should we cache the masks derived from num_bits_for_coeff? + + struct entry_plain_t { + simplex_t index; + entry_plain_t(simplex_t _index, coefficient_t, int) : index(_index) {} + entry_plain_t() {} + friend const entry_plain_t& get_entry(const entry_plain_t& e) { return e; } + }; + static simplex_t get_index(const entry_plain_t& i) { return i.index; } + static coefficient_t get_coefficient(const entry_plain_t& i) { return 1; } + static void set_coefficient(entry_plain_t& e, const coefficient_t c) { GUDHI_assert(c==1); } + + typedef std::conditional_t entry_t; + entry_t make_entry(simplex_t i, coefficient_t c) const { return entry_t(i, c, num_bits_for_coeff()); } + + static_assert(sizeof(entry_t) == sizeof(simplex_t), "size of entry_t is not the same as simplex_t"); + + // TODO: avoid storing filtp when !use_coefficients (same for Equal_index and greater_*) + struct Entry_hash { + Entry_hash(Rips_filtration const& filt) : filtp(&filt) {} + Rips_filtration const* filtp; + std::size_t operator()(const entry_t& e) const { return boost::hash()(filtp->get_index(e)); } + }; + + struct Equal_index { + Equal_index(Rips_filtration const& filt) : filtp(&filt) {} + Rips_filtration const* filtp; + bool operator()(const entry_t& e, const entry_t& f) const { + return filtp->get_index(e) == filtp->get_index(f); + } + }; + + struct diameter_simplex_t { + value_t diameter; + simplex_t index; + friend value_t get_diameter(const diameter_simplex_t& i) { return i.diameter; } + }; + static simplex_t get_index(const diameter_simplex_t& i) { return i.index; } + + struct diameter_entry_t : std::pair { + using std::pair::pair; + friend const entry_t& get_entry(const diameter_entry_t& p) { return p.second; } + friend entry_t& get_entry(diameter_entry_t& p) { return p.second; } + friend value_t get_diameter(const diameter_entry_t& p) { return p.first; } + }; + simplex_t get_index(const diameter_entry_t& p) const { return get_index(get_entry(p)); } + coefficient_t get_coefficient(const diameter_entry_t& p) const { + return get_coefficient(get_entry(p)); + } + void set_coefficient(diameter_entry_t& p, const coefficient_t c) const { + set_coefficient(get_entry(p), c); + } + diameter_entry_t make_diameter_entry(value_t diameter, simplex_t index, coefficient_t coefficient) const { + return diameter_entry_t(diameter, make_entry(index, coefficient)); + } + diameter_entry_t make_diameter_entry(const diameter_simplex_t& diameter_index, coefficient_t coefficient) const { + return diameter_entry_t(get_diameter(diameter_index), make_entry(get_index(diameter_index), coefficient)); + } + + template struct Greater_diameter_or_smaller_index { + Greater_diameter_or_smaller_index(Rips_filtration const& filt) : filtp(&filt) {} + Rips_filtration const* filtp; + bool operator()(const Entry& a, const Entry& b) const { + return (get_diameter(a) > get_diameter(b)) || + ((get_diameter(a) == get_diameter(b)) && (filtp->get_index(a) < filtp->get_index(b))); + } + }; + + const DistanceMatrix dist; // only store a reference instead? + const vertex_t n; // redundant with dist? + const dimension_t dim_max; + const value_t threshold; // It would be nice if this was only in DistanceMatrix, but inconvenient. Only used to list the edges of dense distance matrices. + const coefficient_t modulus; + const SimplexEncoding simplex_encoding; // only store a reference instead? + mutable std::vector vertices; // we must not have several threads looking at the same complex + int bits_for_coeff; + + Rips_filtration(DistanceMatrix&& _dist, dimension_t _dim_max, value_t _threshold, coefficient_t _modulus) + : dist(std::move(_dist)), n(dist.size()), + dim_max(std::min(_dim_max, dist.size() - 2)), threshold(_threshold), + modulus(_modulus), simplex_encoding(n, dim_max + 2), bits_for_coeff(log2up(modulus-1)) { + // See entry_with_coeff_t for the logic for log2up(modulus-1) (storing coeff-1) + if (use_coefficients && simplex_encoding.num_extra_bits() < num_bits_for_coeff()) + // TODO: include relevant numbers in the message + throw std::overflow_error("Not enough spare bits in the simplex encoding to store a coefficient"); + } + + vertex_t num_vertices() const { return n; } + int num_bits_for_coeff() const { return bits_for_coeff; } + + simplex_t get_edge_index(const vertex_t i, const vertex_t j) const { + return simplex_encoding(i, 2) + j; + } + + template + OutputIterator get_simplex_vertices(simplex_t idx, const dimension_t dim, vertex_t n, + OutputIterator out) const { + --n; + for (dimension_t k = dim + 1; k > 1; --k) { + n = simplex_encoding.get_max_vertex(idx, k, n); + *out++ = n; + idx -= simplex_encoding(n, k); + } + *out = static_cast(idx); + return out; + } + + value_t compute_diameter(const simplex_t index, const dimension_t dim) const { + value_t diam = -std::numeric_limits::infinity(); + + vertices.resize(dim + 1); + get_simplex_vertices(index, dim, dist.size(), vertices.rbegin()); + + for (dimension_t i = 0; i <= dim; ++i) + for (dimension_t j = 0; j < i; ++j) { + diam = std::max(diam, dist(vertices[i], vertices[j])); + } + return diam; + } + + std::vector get_edges() { + if constexpr (!std::is_same_v) { // Compressed_lower_distance_matrix + // TODO: it would be convenient to have DistanceMatrix provide a range of neighbors at dist<=threshold even in the dense case (as a filtered_range) + std::vector edges; + for (vertex_t i = 0; i < n; ++i) { + for (vertex_t j = 0; j < i; ++j) { + value_t length = dist(i, j); + if (length <= threshold) edges.push_back({length, get_edge_index(i, j)}); + } + } + return edges; + } else { // Sparse_distance_matrix + std::vector edges; + for (vertex_t i = 0; i < n; ++i) + for (auto n : dist.neighbors[i]) { + vertex_t j = get_vertex(n); + if (i > j) edges.push_back({get_diameter(n), get_edge_index(i, j)}); + } + return edges; + } + } + + // TODO: document in what way (if any) the order matters + template class Simplex_coboundary_enumerator_ { // Compressed_lower_distance_matrix + simplex_t idx_below, idx_above; + vertex_t j; + dimension_t k; + std::vector vertices; + diameter_entry_t simplex; + const DistanceMatrix2& dist; + const SimplexEncoding& simplex_encoding; + const Rips_filtration& parent; // for n and get_simplex_vertices + // at least dist and simplex_encoding are redundant with parent, but using parent.dist and parent.simplex_encoding seems to have a bad impact on performance. + + public: + Simplex_coboundary_enumerator_(const Rips_filtration& _parent) : dist(_parent.dist), + simplex_encoding(_parent.simplex_encoding), parent(_parent) {} + + void set_simplex(const diameter_entry_t _simplex, const dimension_t _dim) { + idx_below = parent.get_index(_simplex); + idx_above = 0; + j = dist.size() - 1; + k = _dim + 1; + simplex = _simplex; + vertices.resize(_dim + 1); + parent.get_simplex_vertices(parent.get_index(_simplex), _dim, dist.size(), vertices.rbegin()); + } + + bool has_next(bool all_cofacets = true) { + return (j >= k && (all_cofacets || simplex_encoding(j, k) > idx_below)); + } + + std::optional next_raw(bool all_cofacets = true) { + if (!has_next(all_cofacets)) return std::nullopt; + // this requires simplex_encoding(x,0)>0 + while (simplex_encoding(j, k) <= idx_below) { + idx_below -= simplex_encoding(j, k); + idx_above += simplex_encoding(j, k + 1); + --j; + --k; + GUDHI_assert(k != -1); + } + value_t cofacet_diameter = get_diameter(simplex); + // The order of j and i matters for performance + for (vertex_t i : vertices) cofacet_diameter = std::max(cofacet_diameter, dist(j, i)); + simplex_t cofacet_index = idx_above + simplex_encoding(j--, k + 1) + idx_below; + coefficient_t cofacet_coefficient = parent.get_coefficient(simplex); + if (k & 1) cofacet_coefficient = parent.modulus - cofacet_coefficient; + return parent.make_diameter_entry(cofacet_diameter, cofacet_index, cofacet_coefficient); + } + std::optional next(bool all_cofacets = true) { + while(true) { + std::optional res = next_raw(all_cofacets); + if(!res || get_diameter(*res) <= parent.threshold) return res; + } + } + }; + + template class Simplex_coboundary_enumerator_ { + typedef typename DistanceMatrix2::vertex_diameter_t vertex_diameter_t; + simplex_t idx_below, idx_above; + dimension_t k; + std::vector vertices; + diameter_entry_t simplex; + const DistanceMatrix2& dist; + const SimplexEncoding& simplex_encoding; + std::vector::const_reverse_iterator> neighbor_it; + std::vector::const_reverse_iterator> neighbor_end; + vertex_diameter_t neighbor; + const Rips_filtration& parent; // for n and get_simplex_vertices + + public: + Simplex_coboundary_enumerator_(const Rips_filtration& _parent) + : dist(_parent.dist), + simplex_encoding(_parent.simplex_encoding), parent(_parent) {} + + void set_simplex(const diameter_entry_t _simplex, const dimension_t _dim) { + idx_below = parent.get_index(_simplex); + idx_above = 0; + k = _dim + 1; + simplex = _simplex; + vertices.resize(_dim + 1); + parent.get_simplex_vertices(idx_below, _dim, dist.size(), vertices.rbegin()); + + neighbor_it.resize(_dim + 1); + neighbor_end.resize(_dim + 1); + for (dimension_t i = 0; i <= _dim; ++i) { + auto v = vertices[i]; + neighbor_it[i] = dist.neighbors[v].rbegin(); + neighbor_end[i] = dist.neighbors[v].rend(); + } + } + + bool has_next(bool all_cofacets = true) { + for (auto &it0 = neighbor_it[0], &end0 = neighbor_end[0]; it0 != end0; ++it0) { + neighbor = *it0; + for (size_t idx = 1; idx < neighbor_it.size(); ++idx) { + auto &it = neighbor_it[idx], end = neighbor_end[idx]; + while (get_vertex(*it) > get_vertex(neighbor)) + if (++it == end) return false; + if (get_vertex(*it) != get_vertex(neighbor)) + goto continue_outer; + else + neighbor = std::max(neighbor, *it); + } + while (k > 0 && vertices[k - 1] > get_vertex(neighbor)) { + if (!all_cofacets) return false; + idx_below -= simplex_encoding(vertices[k - 1], k); + idx_above += simplex_encoding(vertices[k - 1], k + 1); + --k; + } + return true; +continue_outer:; + } + return false; + } + + std::optional next_raw(bool all_cofacets = true) { + if (!has_next(all_cofacets)) return std::nullopt; + ++neighbor_it[0]; + value_t cofacet_diameter = std::max(get_diameter(simplex), get_diameter(neighbor)); + simplex_t cofacet_index = idx_above + simplex_encoding(get_vertex(neighbor), k + 1) + idx_below; + const coefficient_t modulus = parent.modulus; + coefficient_t cofacet_coefficient = + (k & 1 ? modulus - 1 : 1) * parent.get_coefficient(simplex) % modulus; + return parent.make_diameter_entry(cofacet_diameter, cofacet_index, cofacet_coefficient); + } + std::optional next(bool all_cofacets = true) { + return next_raw(all_cofacets); + } + }; + + typedef Simplex_coboundary_enumerator_ Simplex_coboundary_enumerator; + + class Simplex_boundary_enumerator { + private: + simplex_t idx_below, idx_above; + vertex_t j; + dimension_t k; + diameter_entry_t simplex; + dimension_t dim; + const SimplexEncoding& simplex_encoding; + const Rips_filtration& parent; // for n, get_max_vertex, compute_diameter + + public: + Simplex_boundary_enumerator(const Rips_filtration& _parent) + : simplex_encoding(_parent.simplex_encoding), parent(_parent) {} + + void set_simplex(const diameter_entry_t _simplex, const dimension_t _dim) { + idx_below = parent.get_index(_simplex); + idx_above = 0; + j = parent.n - 1; + k = _dim; + simplex = _simplex; + dim = _dim; + } + + bool has_next() { return (k >= 0); } + + std::optional next() { + if (!has_next()) return std::nullopt; + j = simplex_encoding.get_max_vertex(idx_below, k + 1, j); + + simplex_t face_index = idx_above - simplex_encoding(j, k + 1) + idx_below; + + // It would make sense to extract the vertices once in set_simplex + // and pass the proper subset to compute_diameter, but even in cases + // where this dominates it does not seem to help (probably because we + // stop at the first coface). + value_t face_diameter = parent.compute_diameter(face_index, dim - 1); + + const coefficient_t modulus = parent.modulus; + coefficient_t face_coefficient = + (k & 1 ? -1 + modulus : 1) * parent.get_coefficient(simplex) % modulus; + + idx_below -= simplex_encoding(j, k + 1); + idx_above += simplex_encoding(j, k); + + --k; + + return parent.make_diameter_entry(face_diameter, face_index, face_coefficient); + } + }; +}; + +#if BOOST_VERSION >= 108100 +template using Hash_map = boost::unordered_flat_map; +#else +template using Hash_map = boost::unordered_map; +#endif + +template class Persistent_cohomology { + using size_t = typename Filtration::size_t; + using coefficient_t = typename Filtration::coefficient_t; + using coefficient_storage_t = typename Filtration::coefficient_storage_t; + using dimension_t = typename Filtration::dimension_t; + using value_t = typename Filtration::value_t; + using vertex_t = typename Filtration::vertex_t; + using simplex_t = typename Filtration::simplex_t; + using diameter_simplex_t = typename Filtration::diameter_simplex_t; + using entry_t = typename Filtration::entry_t; + using diameter_entry_t = typename Filtration::diameter_entry_t; + using Entry_hash = typename Filtration::Entry_hash; + using Equal_index = typename Filtration::Equal_index; + using Simplex_boundary_enumerator = typename Filtration::Simplex_boundary_enumerator; + using Simplex_coboundary_enumerator = typename Filtration::Simplex_coboundary_enumerator; + templateusing Greater_diameter_or_smaller_index = typename Filtration::template Greater_diameter_or_smaller_index; + + typedef Compressed_sparse_matrix_ Compressed_sparse_matrix; + typedef Hash_map entry_hash_map; + + Filtration filt; + const vertex_t n; + const dimension_t dim_max; + const coefficient_t modulus; + const std::vector multiplicative_inverse_; + mutable std::vector cofacet_entries; + mutable std::vector vertices; + Simplex_boundary_enumerator facets; + // Creating a new one in each function that needs it wastes a bit of time, but we may need 2 at the same time. + Simplex_coboundary_enumerator cofacets1, cofacets2; + + coefficient_t multiplicative_inverse(coefficient_t c) const { + return multiplicative_inverse_[c]; + } + public: + Persistent_cohomology(Filtration&& _filt, dimension_t _dim_max, coefficient_t _modulus) + : filt(std::move(_filt)), n(filt.num_vertices()), + dim_max(std::min(_dim_max, n - 2)), + modulus(_modulus), + multiplicative_inverse_(multiplicative_inverse_vector(_modulus)), + facets(filt), cofacets1(filt), cofacets2(filt) + { + } + + + std::optional get_zero_pivot_facet(const diameter_entry_t simplex, const dimension_t dim) { + facets.set_simplex(simplex, dim); + while(true) { + std::optional facet = facets.next(); + if (!facet) break; + if (get_diameter(*facet) == get_diameter(simplex)) return *facet; + } + return std::nullopt; + } + + std::optional get_zero_pivot_cofacet(const diameter_entry_t simplex, const dimension_t dim) { + cofacets1.set_simplex(simplex, dim); + while(true) { + std::optional cofacet = cofacets1.next_raw(); + if (!cofacet) break; + if (get_diameter(*cofacet) == get_diameter(simplex)) return *cofacet; + } + return std::nullopt; + } + + // Apparent pairs are implicit in Ripser. + // pro: we don't need to store them + // con: we may have to recompute them many times, and each test is more expensive than emergent pairs + std::optional get_zero_apparent_facet(const diameter_entry_t simplex, const dimension_t dim) { + std::optional facet = get_zero_pivot_facet(simplex, dim); + if (!facet) return std::nullopt; + std::optional cofacet = get_zero_pivot_cofacet(*facet, dim - 1); + if (!cofacet || filt.get_index(*cofacet) != filt.get_index(simplex)) return std::nullopt; + return *facet; + } + + std::optional get_zero_apparent_cofacet(const diameter_entry_t simplex, const dimension_t dim) { + std::optional cofacet = get_zero_pivot_cofacet(simplex, dim); + if (!cofacet) return std::nullopt; + std::optional facet = get_zero_pivot_facet(*cofacet, dim + 1); + if (!facet || filt.get_index(*facet) != filt.get_index(simplex)) return std::nullopt; + return *cofacet; + } + + bool is_in_zero_apparent_pair(const diameter_entry_t simplex, const dimension_t dim) { + return get_zero_apparent_cofacet(simplex, dim) || get_zero_apparent_facet(simplex, dim); + } + + void assemble_columns_to_reduce(std::vector& simplices, + std::vector& columns_to_reduce, + entry_hash_map& pivot_column_index, dimension_t dim) { + +#ifdef GUDHI_INDICATE_PROGRESS + std::cerr << clear_line << "assembling columns" << std::flush; + std::chrono::steady_clock::time_point next = std::chrono::steady_clock::now() + time_step; +#endif + + columns_to_reduce.clear(); + std::vector next_simplices; + + for (diameter_simplex_t& simplex : simplices) { + cofacets2.set_simplex(filt.make_diameter_entry(simplex, 1), dim - 1); + + while(true) { + std::optional cofacet = cofacets2.next(false); + if (!cofacet) break; +#ifdef GUDHI_INDICATE_PROGRESS + if (std::chrono::steady_clock::now() > next) { + std::cerr << clear_line << "assembling " << next_simplices.size() + << " columns (processing " << std::distance(&simplices[0], &simplex) + << "/" << simplices.size() << " simplices)" << std::flush; + next = std::chrono::steady_clock::now() + time_step; + } +#endif + if (dim < dim_max) next_simplices.push_back({get_diameter(*cofacet), filt.get_index(*cofacet)}); + // Wouldn't it be cheaper in the reverse order? Seems negligible + if (!is_in_zero_apparent_pair(*cofacet, dim) && + (pivot_column_index.find(get_entry(*cofacet)) == pivot_column_index.end())) + columns_to_reduce.push_back({get_diameter(*cofacet), filt.get_index(*cofacet)}); + } + } + + if (dim < dim_max) simplices.swap(next_simplices); + +#ifdef GUDHI_INDICATE_PROGRESS + std::cerr << clear_line << "sorting " << columns_to_reduce.size() << " columns" + << std::flush; +#endif + + std::sort(columns_to_reduce.begin(), columns_to_reduce.end(), + Greater_diameter_or_smaller_index(filt)); +#ifdef GUDHI_INDICATE_PROGRESS + std::cerr << clear_line << std::flush; +#endif + } + + template + void compute_dim_0_pairs(std::vector& edges, + std::vector& columns_to_reduce, OutPair& output_pair) { + Union_find dset(n); + + edges = filt.get_edges(); + std::sort(edges.rbegin(), edges.rend(), + Greater_diameter_or_smaller_index(filt)); + std::vector vertices_of_edge(2); + for (auto e : edges) { + // Should we work with pairs of vertices instead of edges, to skip get_simplex_vertices? + filt.get_simplex_vertices(filt.get_index(e), 1, n, vertices_of_edge.rbegin()); + vertex_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]); + + if (u != v) { + if (get_diameter(e) != 0) + output_pair(0, get_diameter(e)); + dset.link(u, v); + } else if ((dim_max > 0) && !get_zero_apparent_cofacet(filt.make_diameter_entry(e, 1), 1)) + columns_to_reduce.push_back(e); + } + if (dim_max > 0) std::reverse(columns_to_reduce.begin(), columns_to_reduce.end()); + + for (vertex_t i = 0; i < n; ++i) + if (dset.find(i) == i) output_pair(0, std::numeric_limits::infinity()); + } + + template std::optional pop_pivot(Column& column) { + while(!column.empty()) { // At this stage the partial sum is 0 + diameter_entry_t pivot = column.top(); + column.pop(); + while(true) { // At this stage the partial sum is led by pivot + if (column.empty() || filt.get_index(column.top()) != filt.get_index(pivot)) return pivot; + coefficient_t sum = (filt.get_coefficient(pivot) + filt.get_coefficient(column.top())) % modulus; + column.pop(); + if (sum == 0) { + break; + } + filt.set_coefficient(pivot, sum); + } + } + return std::nullopt; + } + + template std::optional get_pivot(Column& column) { + // We could look for the pivot without needing to push it back, but it does not seem to help in benchmarks. + std::optional result = pop_pivot(column); + if (result) column.push(*result); + return result; + } + + // Either return the pivot in an emergent pair, or fill working_coboundary with the full coboundary (and return its pivot) + template + std::optional init_coboundary_and_get_pivot(const diameter_entry_t simplex, + Column& working_coboundary, const dimension_t dim, + entry_hash_map& pivot_column_index) { + bool check_for_emergent_pair = true; + cofacet_entries.clear(); + cofacets2.set_simplex(simplex, dim); + while(true) { + std::optional cofacet = cofacets2.next(); + if (!cofacet) break; + cofacet_entries.push_back(*cofacet); + if (check_for_emergent_pair && (get_diameter(simplex) == get_diameter(*cofacet))) { + if ((pivot_column_index.find(get_entry(*cofacet)) == pivot_column_index.end()) && + !get_zero_apparent_facet(*cofacet, dim + 1)) + return *cofacet; + check_for_emergent_pair = false; + } + } + for (auto cofacet : cofacet_entries) working_coboundary.push(cofacet); + return get_pivot(working_coboundary); + } + + // Beyond apparent/emergent pairs, Ripser does the column reduction eagerly. + // To keep with the lazy paradigm, it would be possible to represent a column as a heap of coboundary_iterator, using the order of the current simplices pointed to by the iterators. The equivalent of `pop` would be ++ on the top iterator, which decreases its priority (or removes it if it reached the end). If we do it right, it could also help us notice if we have twice the same iterator and avoid computing its full coboundary twice (although we may still end up computing the first simplex of the coboundary for both, since it may be the easiest way to detect duplicates without maintaining yet another structure on the side). Another advantage is that its size would be bounded by the number of simplices of dimension d instead of d+1 currently. (Dory seems to do something related but too complicated for me.) + template + void add_simplex_coboundary(const diameter_entry_t simplex, const dimension_t dim, + Column& working_reduction_column, Column& working_coboundary) { + working_reduction_column.push(simplex); + cofacets1.set_simplex(simplex, dim); + while(true) { // stupid C++ + std::optional cofacet = cofacets1.next(); + if (!cofacet) break; + working_coboundary.push(*cofacet); + } + } + + // add an already reduced column, i.e. add all the simplex coboundaries that were involved in that reduction + template + void add_coboundary(Compressed_sparse_matrix& reduction_matrix, + const std::vector& columns_to_reduce, + const size_t index_column_to_add, const coefficient_t factor, + const dimension_t dim, Column& working_reduction_column, + Column& working_coboundary) { + diameter_entry_t column_to_add = filt.make_diameter_entry(columns_to_reduce[index_column_to_add], factor); + add_simplex_coboundary(column_to_add, dim, working_reduction_column, working_coboundary); + + for (diameter_entry_t simplex : reduction_matrix.subrange(index_column_to_add)) { + filt.set_coefficient(simplex, filt.get_coefficient(simplex) * factor % modulus); + add_simplex_coboundary(simplex, dim, working_reduction_column, working_coboundary); + } + } + + template + void compute_pairs(const std::vector& columns_to_reduce, + entry_hash_map& pivot_column_index, const dimension_t dim, OutPair& output_pair) { + Compressed_sparse_matrix reduction_matrix; + Greater_diameter_or_smaller_index cmp(filt); + Heap, + Greater_diameter_or_smaller_index> + working_reduction_column(cmp), working_coboundary(cmp); + +#ifdef GUDHI_INDICATE_PROGRESS + std::chrono::steady_clock::time_point next = std::chrono::steady_clock::now() + time_step; +#endif + for (size_t index_column_to_reduce = 0; index_column_to_reduce < columns_to_reduce.size(); + ++index_column_to_reduce) { + + diameter_entry_t column_to_reduce = filt.make_diameter_entry(columns_to_reduce[index_column_to_reduce], 1); + value_t diameter = get_diameter(column_to_reduce); + + reduction_matrix.append_column(); + + working_reduction_column.clear(); working_coboundary.clear(); + + std::optional pivot = init_coboundary_and_get_pivot( + column_to_reduce, working_coboundary, dim, pivot_column_index); + // When we found an emergent pair, we could avoid checking again below, but it does not seem to gain anything in practice. + + while (true) { +#ifdef GUDHI_INDICATE_PROGRESS + if (std::chrono::steady_clock::now() > next) { + std::cerr << clear_line << "reducing column " << index_column_to_reduce + 1 + << "/" << columns_to_reduce.size() << " (diameter " << diameter << ")" + << std::flush; + next = std::chrono::steady_clock::now() + time_step; + } +#endif + if (pivot) { + auto pair = pivot_column_index.find(get_entry(*pivot)); + if (pair != pivot_column_index.end()) { + entry_t other_pivot = pair->first; + size_t index_column_to_add = pair->second; + coefficient_t factor = + modulus - filt.get_coefficient(*pivot) * + multiplicative_inverse(filt.get_coefficient(other_pivot)) % + modulus; + + // It saves a little bit (3% on an example, 0% on another) if we pass pivot to add_coboundary and avoid pushing entries smaller than pivot in working_coboundary + add_coboundary(reduction_matrix, columns_to_reduce, index_column_to_add, + factor, dim, working_reduction_column, working_coboundary); + + pivot = get_pivot(working_coboundary); + } else if (std::optional e = get_zero_apparent_facet(*pivot, dim + 1); e) { + filt.set_coefficient(*e, modulus - filt.get_coefficient(*e)); + + add_simplex_coboundary(*e, dim, working_reduction_column, working_coboundary); + + pivot = get_pivot(working_coboundary); + } else { + value_t death = get_diameter(*pivot); + output_pair(diameter, death); + pivot_column_index.insert({get_entry(*pivot), index_column_to_reduce}); + // CubicalRipser suggests caching the column here, at least if it took many operations to reduce it. + + while (true) { + std::optional e = pop_pivot(working_reduction_column); + if (!e) break; + GUDHI_assert(filt.get_coefficient(*e) > 0); + reduction_matrix.push_back(*e); + } + break; + } + } else { + output_pair(diameter, std::numeric_limits::infinity()); + break; + } + } + } +#ifdef GUDHI_INDICATE_PROGRESS + std::cerr << clear_line << std::flush; +#endif + } + + // Add a separate output_essential? + // TODO: Should output_pair also take a simplex_t argument? + template + void compute_barcodes(OutDim&& output_dim, OutPair&& output_pair) { + std::vector simplices, columns_to_reduce; + + output_dim(0); + compute_dim_0_pairs(simplices, columns_to_reduce, output_pair); + + for (dimension_t dim = 1; dim <= dim_max; ++dim) { + entry_hash_map pivot_column_index(0, filt, filt); + pivot_column_index.reserve(columns_to_reduce.size()); + + output_dim(dim); + compute_pairs(columns_to_reduce, pivot_column_index, dim, output_pair); + + if (dim < dim_max) + assemble_columns_to_reduce(simplices, columns_to_reduce, pivot_column_index, + dim + 1); + // If for some odd reason one wanted all the infinite intervals in the last dimension, assemble_columns_to_reduce should give us that. + } + } +}; + +// An example of what Params can be +#if 0 +struct Params1 { + // size_t (not always from Params...) is used for counting (ok) and storage for the index of columns in a Hash_map. + // To gain on a pair by reducing size_t, simplex_t has to be smaller than size_t I guess, which is very small, not worth it. + typedef std::size_t size_t; + typedef float value_t; + typedef int8_t dimension_t; // Does it need to be signed? Experimentally no. + typedef int vertex_t; // Currently needs to be signed for Simplex_coboundary_enumerator_::has_next. Reducing to int16_t helps perf a bit. + typedef Gudhi::numbers::uint128_t simplex_t; + // We could introduce a smaller edge_t, but it is not trivial to separate and probably not worth it + typedef uint16_t coefficient_storage_t; // For the table of multiplicative inverses + typedef uint_least32_t coefficient_t; // We need x * y % z to work, but promotion from uint16_t to int is not enough + static const bool use_coefficients = false; + + // Assumptions used in the code: + // * dimension_t smaller than vertex_t + // Check which ones need to be signed, and which ones could be unsigned instead +}; +#endif + +// Trying to write a magic function +template +void help2(DistanceMatrix&& dist, int dim_max, typename DistanceMatrix::value_t threshold, unsigned modulus, OutDim&& output_dim, OutPair&& output_pair) { + typedef Rips_filtration Filt; + typedef Persistent_cohomology Pcoh; + Filt filt(std::move(dist), dim_max, threshold, modulus); + Pcoh(std::move(filt), dim_max, modulus).compute_barcodes(output_dim, output_pair); +} +template struct TParams { + // hardcode most options + typedef std::size_t size_t; + typedef value_t_ value_t; + typedef int8_t dimension_t; + typedef int vertex_t; + typedef simplex_t_ simplex_t; + typedef uint16_t coefficient_storage_t; + typedef uint_least32_t coefficient_t; + static const bool use_coefficients = use_coefficients_; +}; +template struct TParams2 { + typedef int vertex_t; + typedef value_t_ value_t; +}; +// Choose simplex encoding +template +void help1(DistanceMatrix&& dist, int dim_max, typename DistanceMatrix::value_t threshold, unsigned modulus, OutDim&& output_dim, OutPair&& output_pair) { + auto n = dist.size(); + // TODO: if n>=3 we could even go to n-3, because the Rips cannot have homology in dimension n-2 + // (e.g. for 3 points, there is no 1-homology) + if (dim_max > n - 2) dim_max = n - 2; // FIXME: duplicated. problem if n unsigned and 0 or 1. + int bits_per_vertex = log2up(n); + int bits_for_coeff = log2up(modulus - 1); // duplicating logic :-( Also, if modulus is something absurd, the diagnostic is too late + int bitfield_size = bits_per_vertex * (dim_max + 2) + bits_for_coeff; + if (bitfield_size <= 64) { // use bitfield-64 + typedef TParams P; + help2>(std::move(dist), dim_max, threshold, modulus, output_dim, output_pair); + } else if (bitfield_size <= 128) { // use bitfield-128 + typedef TParams P; + help2>(std::move(dist), dim_max, threshold, modulus, output_dim, output_pair); + } else { // use cns-128 + typedef TParams P; + help2>(std::move(dist), dim_max, threshold, modulus, output_dim, output_pair); + } + // Does cns-64 have its place? +} +// Select hardcoded Z/2Z or runtime Z/pZ +template +void ripser(DistanceMatrix dist, int dim_max, typename DistanceMatrix::value_t threshold, unsigned modulus, OutDim&& output_dim, OutPair&& output_pair) { + if (modulus == 2) + help1(std::move(dist), dim_max, threshold, modulus, output_dim, output_pair); + else + help1(std::move(dist), dim_max, threshold, modulus, output_dim, output_pair); +} +#if 0 +template +void ripser_auto(Sparse_distance_matrix dist, int dim_max, typename DMParams::value_t threshold, unsigned modulus, OutDim&& output_dim, OutPair&& output_pair) { + ripser(std::move(dist), dim_max, threshold, modulus, output_dim, output_pair); +} +template +void ripser_auto(Compressed_distance_matrix dist, int dim_max, typename DMParams::value_t threshold, unsigned modulus, OutDim&& output_dim, OutPair&& output_pair) { + typedef typename DMParams::value_t value_t; + typedef typename DMParams::vertex_t vertex_t; + if (threshold < std::numeric_limits::max()) { // or infinity() + Sparse_distance_matrix new_dist(dist, threshold); + ripser(std::move(new_dist), dim_max, threshold, modulus, output_dim, output_pair); + } else { + for (vertex_t i = 0; i < dist.size(); ++i) { + value_t r_i = -std::numeric_limits::infinity(); + for (vertex_t j = 0; j < dist.size(); ++j) + r_i = std::max(r_i, dist(i, j)); + threshold = std::min(threshold, r_i); + // Should we also compute this when an explicit threshold is passed, in case the user passed an unnecessarily large threshold? + } + ripser(std::move(dist), dim_max, threshold, modulus, output_dim, output_pair); + } +} +// Other = Euclidean. TODO: more robust dispatching... (how?) +template +void ripser_auto(DistanceMatrix dist, int dim_max, typename DistanceMatrix::value_t threshold, unsigned modulus, OutDim&& output_dim, OutPair&& output_pair) { + typedef typename DistanceMatrix::value_t value_t; + typedef TParams2 P; + if (threshold < std::numeric_limits::max()) { // or infinity() + Sparse_distance_matrix

new_dist(dist, threshold); + ripser(std::move(new_dist), dim_max, threshold, modulus, output_dim, output_pair); + } else { + Compressed_distance_matrix new_dist(dist); + ripser(std::move(new_dist), dim_max, threshold, modulus, output_dim, output_pair); + } +} +#endif +template +void ripser_auto(DistanceMatrix dist, int dim_max, typename DistanceMatrix::value_t threshold, unsigned modulus, OutDim&& output_dim, OutPair&& output_pair) { + typedef typename DistanceMatrix::vertex_t vertex_t; + typedef typename DistanceMatrix::value_t value_t; + typedef TParams2 P; + if constexpr (std::is_same_v) { + ripser(std::move(dist), dim_max, threshold, modulus, output_dim, output_pair); + } else if (threshold < std::numeric_limits::max()) { // or infinity() + Sparse_distance_matrix

new_dist(dist, threshold); + ripser(std::move(new_dist), dim_max, threshold, modulus, output_dim, output_pair); + } else if constexpr (std::is_same_v) { + for (vertex_t i = 0; i < dist.size(); ++i) { + value_t r_i = -std::numeric_limits::infinity(); + for (vertex_t j = 0; j < dist.size(); ++j) + r_i = std::max(r_i, dist(i, j)); + threshold = std::min(threshold, r_i); + // Should we also compute this when an explicit threshold is passed, in case the user passed an unnecessarily large threshold? + } + ripser(std::move(dist), dim_max, threshold, modulus, output_dim, output_pair); + } else { + Compressed_distance_matrix new_dist(dist); + ripser_auto(std::move(new_dist), dim_max, threshold, modulus, output_dim, output_pair); + } +} +// - sparse input -> sparse matrix +// - euclidean input & threshold -> sparse matrix (don't build dense matrix) +// - euclidean input & !threshold -> dense matrix +// - dense matrix & threshold -> sparse matrix +// - dense matrix & !threshold -> compute minmax, keep dense +} +#undef GUDHI_assert +#endif // GUDHI_RIPSER_H + +/* Relevant benchmarks where different functions dominate the profile +# push +ripser --format point-cloud ripser/examples/o3_1024.txt +# pop +ripser --format point-cloud ripser/examples/o3_4096.txt --threshold 1.6 +# apparent_pair (get_simplex_vertices + dist) - edge_collapse would help +ripser --format point-cloud --dim 2 --threshold .7 tore +# apparent_pair (get_simplex_vertices) - no edge collapse possible +ripser --format point-cloud circle24 --dim 25 + +where equivalent datasets can be obtained through + tore -> tore3D_1307.off + circle24: + t=np.linspace(0, 2*np.pi, 24, endpoint=False) + np.stack((np.cos(t),np.sin(t))).T + OR + gudhi.datasets.generators.points.torus(24,1,'grid') + o3 (?): + scipy.stats.ortho_group.rvs(3,4096).reshape(-1,9) +*/ diff --git a/src/Ripser/utilities/CMakeLists.txt b/src/Ripser/utilities/CMakeLists.txt new file mode 100644 index 0000000000..fac8513523 --- /dev/null +++ b/src/Ripser/utilities/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(ripser ripser.cc) +install(TARGETS ripser DESTINATION bin) +add_test(NAME ripser_lower COMMAND $ --format lower --dim 2 --threshold .7 "${CMAKE_SOURCE_DIR}/data/distance_matrix/tore3D_1307_distance_matrix.csv") diff --git a/src/Ripser/utilities/ripser.cc b/src/Ripser/utilities/ripser.cc new file mode 100644 index 0000000000..6dabba826b --- /dev/null +++ b/src/Ripser/utilities/ripser.cc @@ -0,0 +1,391 @@ +/* Based on Ripser commit 140670f2c76997404601e43d8054151f46be9fd7 + * Modification(s): + * - YYYY/MM Author: Description of the modification + * - 2024 Marc Glisse: Heavy refactoring +*/ + +/* + + Ripser: a lean C++ code for computation of Vietoris-Rips persistence barcodes + + MIT License + + Copyright (c) 2015–2021 Ulrich Bauer + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + You are under no obligation whatsoever to provide any bug fixes, patches, or + upgrades to the features, functionality or performance of the source code + ("Enhancements") to anyone; however, if you choose to make your Enhancements + available either publicly, or directly to the author of this software, without + imposing a separate written license agreement for such Enhancements, then you + hereby grant the following license: a non-exclusive, royalty-free perpetual + license to install, use, modify, prepare derivative works, incorporate into + other computer software, distribute, and sublicense such enhancements or + derivative works thereof, in binary and source code form. + +*/ + +//#define GUDHI_INDICATE_PROGRESS + +#include +#include +#include +#include + +using Gudhi::ripser::ripser; + +struct Params { + typedef float value_t; + typedef int8_t dimension_t; + typedef int vertex_t; + typedef uint_least32_t coefficient_t; +}; + +typedef Params::value_t value_t; +typedef Params::dimension_t dimension_t; +typedef Params::vertex_t vertex_t; +typedef Params::coefficient_t coefficient_t; + +typedef Gudhi::ripser::Full_distance_matrix Full_distance_matrix; +typedef Gudhi::ripser::Compressed_distance_matrix Compressed_lower_distance_matrix; +typedef Gudhi::ripser::Compressed_distance_matrix Compressed_upper_distance_matrix; +typedef Gudhi::ripser::Sparse_distance_matrix Sparse_distance_matrix; +typedef Gudhi::ripser::Euclidean_distance_matrix Euclidean_distance_matrix; + +enum file_format { + LOWER_DISTANCE_MATRIX, + UPPER_DISTANCE_MATRIX, + DISTANCE_MATRIX, + POINT_CLOUD, + DIPHA, + SPARSE, + BINARY +}; + +static constexpr uint16_t endian_check=0xff00; +static bool is_big_endian() { return *reinterpret_cast(&endian_check); } + +template T read(std::istream& input_stream) { + T result; + char* p = reinterpret_cast(&result); + if (input_stream.read(p, sizeof(T)).gcount() != sizeof(T)) return T(); + if (is_big_endian()) std::reverse(p, p + sizeof(T)); + return result; +} + +Euclidean_distance_matrix read_point_cloud(std::istream& input_stream) { + std::vector> points; + + std::string line; + value_t value; + while (std::getline(input_stream, line)) { + std::vector point; + std::istringstream s(line); + while (s >> value) { + point.push_back(value); + s.ignore(); + } + if (!point.empty()) points.push_back(point); + assert(point.size() == points.front().size()); + } + + std::size_t d = points.front().size(); + Euclidean_distance_matrix eucl_dist(std::move(points)); + vertex_t n = eucl_dist.size(); + std::cout << "point cloud with " << n << " points in dimension " + << d << std::endl; + + return eucl_dist; +} + +Sparse_distance_matrix read_sparse_distance_matrix(std::istream& input_stream) { + typedef typename Sparse_distance_matrix::vertex_diameter_t vertex_diameter_t; + std::vector> neighbors; + std::size_t num_edges = 0; + + std::string line; + while (std::getline(input_stream, line)) { + std::istringstream s(line); + std::size_t i, j; + value_t value; + s >> i; + s.ignore(); + s >> j; + s.ignore(); + s >> value; + s.ignore(); + if (i != j) { + neighbors.resize(std::max({neighbors.size(), i + 1, j + 1})); + neighbors[i].emplace_back(j, value); + neighbors[j].emplace_back(i, value); + ++num_edges; + } + } + + for (std::size_t i = 0; i < neighbors.size(); ++i) + std::sort(neighbors[i].begin(), neighbors[i].end()); + + return Sparse_distance_matrix(std::move(neighbors), num_edges); +} + +Compressed_lower_distance_matrix read_lower_distance_matrix(std::istream& input_stream) { + std::vector distances; + value_t value; + while (input_stream >> value) { + distances.push_back(value); + input_stream.ignore(); + } + + return Compressed_lower_distance_matrix(std::move(distances)); +} + +Compressed_lower_distance_matrix read_upper_distance_matrix(std::istream& input_stream) { + std::vector distances; + value_t value; + while (input_stream >> value) { + distances.push_back(value); + input_stream.ignore(); + } + + return Compressed_lower_distance_matrix(Compressed_upper_distance_matrix(std::move(distances))); +} + +Compressed_lower_distance_matrix read_distance_matrix(std::istream& input_stream) { + std::vector distances; + + std::string line; + value_t value; + for (int i = 0; std::getline(input_stream, line); ++i) { + std::istringstream s(line); + for (int j = 0; j < i && s >> value; ++j) { + distances.push_back(value); + s.ignore(); + } + } + + return Compressed_lower_distance_matrix(std::move(distances)); +} + +Compressed_lower_distance_matrix read_dipha(std::istream& input_stream) { + if (read(input_stream) != 8067171840) { + std::cerr << "input is not a Dipha file (magic number: 8067171840)" << std::endl; + exit(-1); + } + + if (read(input_stream) != 7) { + std::cerr << "input is not a Dipha distance matrix (file type: 7)" << std::endl; + exit(-1); + } + + vertex_t n = read(input_stream); + + std::vector distances; + + for (vertex_t i = 0; i < n; ++i) + for (vertex_t j = 0; j < n; ++j) + if (i > j) + distances.push_back(read(input_stream)); + else + read(input_stream); + + return Compressed_lower_distance_matrix(std::move(distances)); +} + +Compressed_lower_distance_matrix read_binary(std::istream& input_stream) { + std::vector distances; + while (!input_stream.eof()) distances.push_back(read(input_stream)); + return Compressed_lower_distance_matrix(std::move(distances)); +} + +Compressed_lower_distance_matrix read_file(std::istream& input_stream, const file_format format) { + switch (format) { + case LOWER_DISTANCE_MATRIX: + return read_lower_distance_matrix(input_stream); + case UPPER_DISTANCE_MATRIX: + return read_upper_distance_matrix(input_stream); + case DISTANCE_MATRIX: + return read_distance_matrix(input_stream); + case POINT_CLOUD: + return read_point_cloud(input_stream); + case DIPHA: + return read_dipha(input_stream); + default: + return read_binary(input_stream); + } +} + +void print_usage_and_exit(int exit_code) { + std::cerr + << "Usage: " + << "ripser " + << "[options] [filename]" << std::endl + << std::endl + << "Options:" << std::endl + << std::endl + << " --help print this screen" << std::endl + << " --format use the specified file format for the input. Options are:" + << std::endl + << " lower-distance (lower triangular distance matrix)" + << std::endl + << " upper-distance (upper triangular distance matrix)" << std::endl + << " (default:) distance (distance matrix; only lower triangular part is read)" << std::endl + << " point-cloud (point cloud in Euclidean space)" << std::endl + << " dipha (distance matrix in DIPHA file format)" << std::endl + << " sparse (sparse distance matrix in sparse triplet format)" + << std::endl + << " binary (lower triangular distance matrix in binary format)" + << std::endl + << " --dim compute persistent homology up to dimension k" << std::endl + << " --threshold compute Rips complexes up to diameter t" << std::endl + << " --modulus

compute homology with coefficients in the prime field Z/pZ" + << std::endl + << " --ratio only show persistence pairs with death/birth ratio > r" << std::endl + << std::endl; + exit(exit_code); +} + +int main(int argc, char** argv) { + const char* filename = nullptr; + + file_format format = DISTANCE_MATRIX; + + dimension_t dim_max = 1; + value_t threshold = std::numeric_limits::max(); + float ratio = 1; + coefficient_t modulus = 2; + + for (int i = 1; i < argc; ++i) { + const std::string arg(argv[i]); + if (arg == "--help") { + print_usage_and_exit(0); + } else if (arg == "--dim") { + std::string parameter = std::string(argv[++i]); + std::size_t next_pos; + dim_max = std::stol(parameter, &next_pos); + if (next_pos != parameter.size()) print_usage_and_exit(-1); + } else if (arg == "--threshold") { + std::string parameter = std::string(argv[++i]); + std::size_t next_pos; + threshold = std::stof(parameter, &next_pos); + if (next_pos != parameter.size()) print_usage_and_exit(-1); + } else if (arg == "--ratio") { + std::string parameter = std::string(argv[++i]); + std::size_t next_pos; + ratio = std::stof(parameter, &next_pos); + if (next_pos != parameter.size()) print_usage_and_exit(-1); + } else if (arg == "--format") { + std::string parameter = std::string(argv[++i]); + if (parameter.rfind("lower", 0) == 0) + format = LOWER_DISTANCE_MATRIX; + else if (parameter.rfind("upper", 0) == 0) + format = UPPER_DISTANCE_MATRIX; + else if (parameter.rfind("dist", 0) == 0) + format = DISTANCE_MATRIX; + else if (parameter.rfind("point", 0) == 0) + format = POINT_CLOUD; + else if (parameter == "dipha") + format = DIPHA; + else if (parameter == "sparse") + format = SPARSE; + else if (parameter == "binary") + format = BINARY; + else + print_usage_and_exit(-1); + } else if (arg == "--modulus") { + std::string parameter = std::string(argv[++i]); + std::size_t next_pos; + modulus = std::stol(parameter, &next_pos); + if (next_pos != parameter.size() || !Gudhi::ripser::is_prime(modulus)) print_usage_and_exit(-1); + } else { + if (filename) { print_usage_and_exit(-1); } + filename = argv[i]; + } + } + + std::ifstream file_stream(filename); + if (filename && file_stream.fail()) { + std::cerr << "couldn't open file " << filename << std::endl; + exit(-1); + } + + auto output_dim = [](dimension_t dim) { + std::cout << "persistence intervals in dim " << (int)dim << ":" << std::endl; + }; + auto output_pair = [ratio](value_t birth, value_t death) { +#ifdef GUDHI_INDICATE_PROGRESS + // Not necessary if we redirect stdout + std::cerr << Gudhi::ripser::clear_line << std::flush; +#endif + if (death == std::numeric_limits::infinity()) + std::cout << " [" << birth << ", )" << std::endl; + else if (death > birth * ratio) + std::cout << " [" << birth << "," << death << ")" << std::endl; + }; + if (format == SPARSE) { + Sparse_distance_matrix dist = + read_sparse_distance_matrix(filename ? file_stream : std::cin); + std::cout << "sparse distance matrix with " << dist.size() << " points and " + << dist.num_edges << "/" << (dist.size() * (dist.size() - 1)) / 2 << " entries" + << std::endl; + + ripser(std::move(dist), dim_max, threshold, modulus, output_dim, output_pair); + } else if (format == POINT_CLOUD && threshold < std::numeric_limits::max()) { + Sparse_distance_matrix dist(read_point_cloud(filename ? file_stream : std::cin), threshold); + ripser(std::move(dist), dim_max, threshold, modulus, output_dim, output_pair); + } else { + Compressed_lower_distance_matrix dist = + read_file(filename ? file_stream : std::cin, format); + + value_t min = std::numeric_limits::infinity(), + max = -std::numeric_limits::infinity(), max_finite = max; + std::size_t num_edges = 0; + + value_t enclosing_radius = std::numeric_limits::infinity(); + if (threshold >= std::numeric_limits::max()) { + for (vertex_t i = 0; i < dist.size(); ++i) { + value_t r_i = -std::numeric_limits::infinity(); + for (vertex_t j = 0; j < dist.size(); ++j) r_i = std::max(r_i, dist(i, j)); + enclosing_radius = std::min(enclosing_radius, r_i); + } + } + + for (auto d : dist.distances) { + min = std::min(min, d); + max = std::max(max, d); + if (d != std::numeric_limits::infinity()) max_finite = std::max(max_finite, d); + if (d <= threshold) ++num_edges; + } + std::cout << "value range: [" << min << "," << max_finite << "]" << std::endl; + + if (threshold >= std::numeric_limits::max()) { + std::cout << "distance matrix with " << dist.size() + << " points, using threshold at enclosing radius " << enclosing_radius + << std::endl; + ripser(std::move(dist), dim_max, enclosing_radius, modulus, output_dim, output_pair); + } else { + std::cout << "sparse distance matrix with " << dist.size() << " points and " + << num_edges << "/" << (dist.size() * (dist.size() - 1)) / 2 << " entries" + << std::endl; + + ripser(Sparse_distance_matrix(std::move(dist), threshold), dim_max, threshold, modulus, output_dim, output_pair); + } + } + return 0; +} diff --git a/src/common/include/gudhi/uint128.h b/src/common/include/gudhi/uint128.h new file mode 100644 index 0000000000..2a9407205c --- /dev/null +++ b/src/common/include/gudhi/uint128.h @@ -0,0 +1,147 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Marc Glisse + * + * Copyright (C) 2024 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +#ifndef GUDHI_UINT128_H_ +#define GUDHI_UINT128_H_ +#include +#include +#include +#include + +// GUDHI_FORCE_FAKE_UINT128 is only used for tests +#if !defined __SIZEOF_INT128__ || defined GUDHI_FORCE_FAKE_UINT128 +namespace Gudhi::numbers { +class Fake_uint128 { + // Debug + #ifdef __SIZEOF_INT128__ + unsigned __int128 native() const { return ((unsigned __int128)high << 64) + low; } + #define GUDHI_VERIF(X) GUDHI_CHECK(res.native() == (X), "") + #else + #define GUDHI_VERIF(X) + #endif + public: + constexpr Fake_uint128(): high(0), low(0) {} + constexpr Fake_uint128(std::uint64_t a): high(0), low(a) {} + // Arithmetic + // (multiplication and division are not needed for now) + friend Fake_uint128 operator+(Fake_uint128 a, Fake_uint128 b){ + Fake_uint128 res; + res.low = a.low + b.low; + res.high = a.high + b.high + (res.low < a.low); + GUDHI_VERIF (a.native() + b.native()); + return res; + } + friend Fake_uint128 operator-(Fake_uint128 a, Fake_uint128 b){ + Fake_uint128 res; + res.low = a.low - b.low; + res.high = a.high - b.high - (res.low > a.low); + GUDHI_VERIF (a.native() - b.native()); + return res; + } + friend Fake_uint128 operator<<(Fake_uint128 a, uint8_t b){ + Fake_uint128 res; + GUDHI_CHECK(b < 128, ""); + if (b >= 64) { res.low = 0; res.high = a.low << (b-64); } + else if (b == 0) { res = a; } + else { res.low = a.low << b; res.high = a.high << b | a.low >> (64-b); } + GUDHI_VERIF (a.native() << b); + return res; + } + friend Fake_uint128 operator>>(Fake_uint128 a, uint8_t b){ + Fake_uint128 res; + GUDHI_CHECK(b < 128, ""); + if (b >= 64) { res.high = 0; res.low = a.high >> (b-64); } + else if (b == 0) { res = a; } + else { res.high = a.high >> b; res.low = a.low >> b | a.high << (64-b); } + GUDHI_VERIF (a.native() >> b); + return res; + } + friend Fake_uint128 operator&(Fake_uint128 a, Fake_uint128 b){ + Fake_uint128 res; + res.low = a.low & b.low; + res.high = a.high & b.high; + GUDHI_VERIF (a.native() & b.native()); + return res; + } + friend Fake_uint128 operator|(Fake_uint128 a, Fake_uint128 b){ + Fake_uint128 res; + res.low = a.low | b.low; + res.high = a.high | b.high; + GUDHI_VERIF (a.native() | b.native()); + return res; + } + friend Fake_uint128 operator~(Fake_uint128 a){ + Fake_uint128 res; + res.low = ~a.low; + res.high = ~a.high; + return res; + } + // In-place arithmetic + Fake_uint128& operator+=(Fake_uint128 a) { *this = *this + a; return *this; } + Fake_uint128& operator-=(Fake_uint128 a) { *this = *this - a; return *this; } + Fake_uint128& operator++() { if (++low == 0) ++high; return *this; } + Fake_uint128& operator--() { if (low-- == 0) --high; return *this; } + Fake_uint128& operator<<=(uint8_t a) { *this = *this << a; return *this; } + Fake_uint128& operator>>=(uint8_t a) { *this = *this >> a; return *this; } + Fake_uint128& operator&=(Fake_uint128 a) { *this = *this & a; return *this; } + Fake_uint128& operator|=(Fake_uint128 a) { *this = *this | a; return *this; } + // Comparisons + friend bool operator==(Fake_uint128 a, Fake_uint128 b){ + return a.low == b.low && a.high == b.high; + } + friend bool operator!=(Fake_uint128 a, Fake_uint128 b){ + return a.low != b.low || a.high != b.high; + } + friend bool operator<(Fake_uint128 a, Fake_uint128 b){ + return a.high < b.high || (a.high == b.high && a.low < b.low); + } + friend bool operator>(Fake_uint128 a, Fake_uint128 b){ + return a.high > b.high || (a.high == b.high && a.low > b.low); + } + friend bool operator<=(Fake_uint128 a, Fake_uint128 b){ + return a.high < b.high || (a.high == b.high && a.low <= b.low); + } + friend bool operator>=(Fake_uint128 a, Fake_uint128 b){ + return a.high > b.high || (a.high == b.high && a.low >= b.low); + } + // Misc + friend std::size_t hash_value(Fake_uint128 a) { + typedef std::pair P; + return boost::hash_value(P(a.high, a.low)); + } + template >> + explicit operator T() const { + GUDHI_CHECK(high == 0 && low <= std::numeric_limits::max(), ""); + return static_cast(low); + } + private: + std::uint64_t high, low; // does the order matter? + #undef GUDHI_VERIF +}; +typedef Fake_uint128 uint128_t; +} // namespace Gudhi::numbers +template<> class std::numeric_limits { + public: + static constexpr bool is_specialized = true; + static constexpr bool is_signed = false; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool is_modulo = true; + static constexpr int digits = 128; + static constexpr int radix = 2; + // etc +}; +#else +namespace Gudhi::numbers { +typedef unsigned __int128 uint128_t; +} // namespace Gudhi::numbers +#endif +#endif // GUDHI_UINT128_H_ diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index e953fee2b7..e09b741820 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -187,6 +187,7 @@ if(PYTHONINTERP_FOUND) endif () set(GUDHI_PYBIND11_MODULES "${GUDHI_PYBIND11_MODULES}'_pers_cub_low_dim', ") set(GUDHI_PYBIND11_MODULES "${GUDHI_PYBIND11_MODULES}'_edge_collapse', ") + set(GUDHI_PYBIND11_MODULES "${GUDHI_PYBIND11_MODULES}'_ripser', ") # from windows vcpkg eigen 3.4.0#2 : build fails with # error C2440: '': cannot convert from 'Eigen::EigenBase::Index' to '__gmp_expr' diff --git a/src/python/gudhi/_ripser.cc b/src/python/gudhi/_ripser.cc new file mode 100644 index 0000000000..56e528f248 --- /dev/null +++ b/src/python/gudhi/_ripser.cc @@ -0,0 +1,200 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Marc Glisse + * + * Copyright (C) 2024 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include + +using namespace Gudhi::ripser; + +namespace py = pybind11; +typedef std::vector< int> Vi; +typedef std::vector Vd; +typedef std::vector> V2f; +typedef std::vector> V2d; +PYBIND11_MAKE_OPAQUE(Vi); +PYBIND11_MAKE_OPAQUE(Vd); +PYBIND11_MAKE_OPAQUE(V2f); +PYBIND11_MAKE_OPAQUE(V2d); + +templatestruct Full { + typedef Tag_dense Category; + typedef int vertex_t; + typedef T value_t; + decltype(std::declval&>().template unchecked<2>()) data; + int size() const { return data.shape(0); } + T operator()(int i, int j) const { + return data(i, j); + } +}; + +templatestruct DParams { + typedef vertex_t_ vertex_t; + typedef value_t_ value_t; +}; + +template +py::list doit(DistanceMatrix&& dist, int max_dimension, typename DistanceMatrix::value_t max_edge_length, unsigned homology_coeff_field) { + //static_assert(!std::is_lvalue_reference_v); + typedef typename DistanceMatrix::value_t T; + // We could put everything in a single vector, and return slices of it, but I don't think there is much advantage. + std::vector>> dgms; + { + py::gil_scoped_release release; + auto output = [&](T birth, T death){ + // Skip empty intervals + if (birth < death) + dgms.back().push_back({birth, death}); + }; + auto switch_dim = [&](int new_dim){ + dgms.emplace_back(); + }; + ripser_auto(std::move(dist), max_dimension, max_edge_length, homology_coeff_field, switch_dim, output); + } + py::list ret; + for (auto&& dgm : dgms) + ret.append(py::array(py::cast(std::move(dgm)))); + return ret; +} + +template +py::list full(py::array_t matrix, int max_dimension, T max_edge_length, unsigned homology_coeff_field) { + Full dist{matrix.template unchecked<2>()}; + if(dist.data.ndim() != 2 || dist.data.shape(0) != dist.data.shape(1)) + throw std::runtime_error("Distance matrix must be a square 2-dimensional array"); + return doit(std::move(dist), max_dimension, max_edge_length, homology_coeff_field); +} + +py::list lower(py::object low_mat, int max_dimension, double max_edge_length, unsigned homology_coeff_field) { + using Dist = Compressed_distance_matrix, LOWER_TRIANGULAR>; + std::vector distances; + int rowi = 0; + for (auto&& row : low_mat) { + if (rowi == 0) { ++rowi; continue; } + int coli = 0; + for (auto&& elem : row) { + distances.push_back(elem.cast()); // need a cast? + if (++coli == rowi) break; + } + if (coli < rowi) throw std::invalid_argument("Not enough elements for a lower triangular matrix"); + ++rowi; + }; + + // optional as a trick to allow destruction where I want it + std::optional release_local(std::in_place); + Dist dist(std::move(distances)); + release_local.reset(); + + return doit(std::move(dist), max_dimension, max_edge_length, homology_coeff_field); +} + +template +py::list sparse(py::array_t is_, py::array_t js_, py::array_t fs_, int num_vertices, int max_dimension, T max_edge_length, unsigned homology_coeff_field) { + // Duplicate entries and self loops are forbidden + auto is = is_.unchecked(); + auto js = js_.unchecked(); + auto fs = fs_.unchecked(); + if (is.ndim() != 1 || js.ndim() != 1 || fs.ndim() != 1) + throw std::runtime_error("vertices and filtrations must be 1-dimensional arrays"); + if (is.shape(0) != js.shape(0) || is.shape(0) != js.shape(0)) + throw std::runtime_error("vertices and filtrations must have the same shape"); + + typedef DParams P; + typedef Sparse_distance_matrix

Dist; + typedef typename Dist::vertex_diameter_t vertex_diameter_t; + + std::optional release_local(std::in_place); + std::vector> neighbors(num_vertices); + for (py::ssize_t e = 0; e < is.shape(0); ++e) { + neighbors[is(e)].emplace_back(js(e), fs(e)); + neighbors[js(e)].emplace_back(is(e), fs(e)); + } + // We could easily parallelize this loop, but it is unlikely to be worth it. + for (size_t i = 0; i < neighbors.size(); ++i) + std::sort(neighbors[i].begin(), neighbors[i].end()); + Dist dist(std::move(neighbors)); + release_local.reset(); + + return doit(std::move(dist), max_dimension, max_edge_length, homology_coeff_field); +} + +py::list lower_to_coo(py::object low_mat, double max_edge_length) { + // Cannot release the GIL since we keep accessing Python objects. + // TODO: full_to_coo for numpy arrays? + // Should we compute the cone radius at the same time? + std::vector is, js; + std::vector fs; + int rowi = 0; + for (auto&& row : low_mat) { + if (rowi == 0) { ++rowi; continue; } + int coli = 0; + for (auto&& elem : row) { + double d = elem.cast(); // need a cast? + if (d <= max_edge_length) { + is.push_back(rowi); + js.push_back(coli); + fs.push_back(d); + } + if (++coli == rowi) break; + } + if (coli < rowi) throw std::invalid_argument("Not enough elements for a lower triangular matrix"); + ++rowi; + }; + return py::make_tuple( + py::array(py::cast(std::move(is))), + py::array(py::cast(std::move(js))), + py::array(py::cast(std::move(fs)))); +} + +double lower_cone_radius(py::object low_mat) { + // It would be more efficient to read the matrix only once + auto n = py::len(low_mat); + std::vector maxs(n, -std::numeric_limits::infinity()); + int rowi = 0; + for (auto&& row : low_mat) { + if (rowi == 0) { ++rowi; continue; } + int coli = 0; + for (auto&& elem : row) { + double d = elem.cast(); + maxs[rowi] = std::max(maxs[rowi], d); + maxs[coli] = std::max(maxs[coli], d); + if (++coli == rowi) break; + } + if (coli < rowi) throw std::invalid_argument("Not enough elements for a lower triangular matrix"); + ++rowi; + }; + return *std::max_element(maxs.begin(), maxs.end()); +} + +PYBIND11_MODULE(_ripser, m) { + py::bind_vector(m, "VectorInt" , py::buffer_protocol()); + py::bind_vector(m, "VectorDouble" , py::buffer_protocol()); + py::bind_vector(m, "VectorPairFloat" , py::buffer_protocol()); + py::bind_vector(m, "VectorPairDouble", py::buffer_protocol()); + // Remove the default for max_dimension? + m.def("_full", full, py::arg("matrix").noconvert(), py::arg("max_dimension") = std::numeric_limits::max(), py::arg("max_edge_length") = std::numeric_limits::infinity(), py::arg("homology_coeff_field") = 2); + m.def("_full", full, py::arg("matrix"), py::arg("max_dimension") = std::numeric_limits::max(), py::arg("max_edge_length") = std::numeric_limits::infinity(), py::arg("homology_coeff_field") = 2); + m.def("_lower", lower, py::arg("matrix"), py::arg("max_dimension") = std::numeric_limits::max(), py::arg("max_edge_length") = std::numeric_limits::infinity(), py::arg("homology_coeff_field") = 2); + // We could do a version with long, but copying the arrays of integers shouldn't be too costly + m.def("_sparse", sparse, py::arg("row"), py::arg("col"), py::arg("data").noconvert(), py::arg("num_vertices"), py::arg("max_dimension") = std::numeric_limits::max(), py::arg("max_edge_length") = std::numeric_limits::infinity(), py::arg("homology_coeff_field") = 2); + m.def("_sparse", sparse, py::arg("row"), py::arg("col"), py::arg("data"), py::arg("num_vertices"), py::arg("max_dimension") = std::numeric_limits::max(), py::arg("max_edge_length") = std::numeric_limits::infinity(), py::arg("homology_coeff_field") = 2); + // Not directly an interface to Ripser... + m.def("_lower_to_coo", lower_to_coo, py::arg("matrix"), py::arg("max_edge_length")); + m.def("_lower_cone_radius", lower_cone_radius, py::arg("matrix")); +} + +// We could also create a RipsComplex class, that allows looking at a simplex, querying its (co)boundary, etc. But I am not convinced it is worth the effort. diff --git a/src/python/gudhi/sklearn/rips_persistence.py b/src/python/gudhi/sklearn/rips_persistence.py index f34af5a464..73a98e4300 100644 --- a/src/python/gudhi/sklearn/rips_persistence.py +++ b/src/python/gudhi/sklearn/rips_persistence.py @@ -7,8 +7,14 @@ # Modification(s): # - YYYY/MM Author: Description of the modification -from .. import RipsComplex +from .._ripser import _lower, _full, _sparse, _lower_to_coo, _lower_cone_radius +from ..flag_filtration.edge_collapse import reduce_graph +import math +import numpy as np from sklearn.base import BaseEstimator, TransformerMixin +from scipy.sparse import coo_matrix +from scipy.spatial import cKDTree +from scipy.spatial.distance import pdist, squareform # joblib is required by scikit-learn from joblib import Parallel, delayed @@ -38,7 +44,7 @@ def __init__( homology_dimensions, threshold=float('inf'), input_type='point cloud', - num_collapses=1, + num_collapses='auto', homology_coeff_field=11, n_jobs=None, ): @@ -49,12 +55,14 @@ def __init__( homology_dimensions (int or list of int): The returned persistence diagrams dimension(s). Short circuit the use of :class:`~gudhi.representations.preprocessing.DimensionSelector` when only one dimension matters (in other words, when `homology_dimensions` is an int). - threshold (float): Rips maximal edge length value. Default is +Inf. - input_type (str): Can be 'point cloud' when inputs are point clouds, or 'lower distance matrix', when - inputs are lower triangular distance matrix (can be full square, but the upper part of the distance - matrix will not be considered). Default is 'point cloud'. - num_collapses (int): Specify the number of :func:`~gudhi.SimplexTree.collapse_edges` iterations to perform - on the SimplexTree. Default value is 1 (a relatively good enough number of iterations). + threshold (float): Rips maximal edge length value. Default is +Inf. Ignored if input_type is 'distance coo_matrix'. + input_type (str): Can be 'point cloud' when inputs are point clouds, 'full distance matrix', + 'lower distance matrix' when inputs are lower triangular distance matrix (can be full square, + but the upper part will not be considered), or 'distance coo_matrix' for a distance matrix in SciPy's + sparse format, which should contain each edge at most once (avoid the symmetric) and no diagonal entry. + Default is 'point cloud'. + num_collapses (int|str): Specify the number of iterations of :func:`~gudhi.flag_filtration.edge_collapse.reduce_graph` + (edge collapse) to perform on the graph. Default value is 'auto'. homology_coeff_field (int): The homology coefficient field. Must be a prime number. Default value is 11. n_jobs (int): Number of jobs to run in parallel. `None` (default value) means `n_jobs = 1` unless in a joblib.parallel_backend context. `-1` means using all processors. cf. @@ -73,36 +81,90 @@ def fit(self, X, Y=None): """ return self - def __transform(self, inputs): - max_dimension = max(self.dim_list_) + 1 - - if self.input_type == 'point cloud': - rips = RipsComplex(points=inputs, max_edge_length = self.threshold) - elif self.input_type == 'lower distance matrix': - rips = RipsComplex(distance_matrix=inputs, max_edge_length = self.threshold) + def __transform(self, inp): + # TODO: give the user more control over the strategy + # Should we use threshold in the sparse case? + num_collapses = self.num_collapses + input_type = self.input_type + threshold = self.threshold + n = inp.shape[0] if input_type == 'distance coo_matrix' else len(inp) + max_dimension = min(max(self.dim_list_), max(0, n-3)) + # Ripser needs to encode simplices and coefficients in 128 bits, which may not always fit + # Instead of a 256 bit version which may not always suffice either, fall back to SimplexTree + use_simplex_tree = math.comb(n, min(n // 2, max_dimension + 2)) >= (1 << (128 - (self.homology_coeff_field - 2).bit_length())) + if num_collapses == 'auto': + num_collapses = 1 if max_dimension > (not use_simplex_tree) else 0 + # or num_collapses=max_dimension-1 maybe? + elif max_dimension == 0: + num_collapses = 0 + + # Points -> distance matrix + if input_type == 'point cloud': + if threshold < float('inf'): + # Hope that the user gave a useful threshold + tree = cKDTree(inp) + + ## V1: Returns self-loops and every edge twice (symmetry) + # inp = tree.sparse_distance_matrix(tree, max_distance=threshold, output_type="coo_matrix") + # mask = inp.row < inp.col + # inp = coo_matrix((inp.data[mask], (inp.row[mask], inp.col[mask])), shape=inp.shape) + + # V2: Gets the right edges, but forgets the distances + pairs = tree.query_pairs(r=threshold, output_type='ndarray') + data = np.ravel(np.linalg.norm(np.diff(inp[pairs], axis=1), axis=-1)) + inp = coo_matrix((data, (pairs[:,0], pairs[:,1])), shape=(n,)*2) + + input_type = 'distance coo_matrix' + else: + inp = squareform(pdist(inp)) + input_type = 'full distance matrix' + + # Dense -> sparse + if input_type in ('full distance matrix', 'lower distance matrix'): + # After this filtration value, all complexes are cones, nothing happens + if input_type == 'full distance matrix': + inp = np.asarray(inp) + cone_radius = inp.max(-1).min() + else: + cone_radius = _lower_cone_radius(inp) + sparsify = use_simplex_tree or num_collapses > 0 or threshold < cone_radius # heuristic + threshold = min(threshold, cone_radius) + if sparsify: + # For 'full' we could use i, j = np.triu_indices_from(inp, k=1), etc + i, j, f = _lower_to_coo(inp, threshold) + inp = coo_matrix((f, (i, j)), shape=(n,) * 2) + input_type = 'distance coo_matrix' + + if num_collapses > 0: + assert input_type == 'distance coo_matrix' + inp = reduce_graph(inp, num_collapses) + + if use_simplex_tree: + from gudhi import SimplexTree + st = SimplexTree() + # Use create_from_array in case of full matrix? + # (not important since this fallback mostly matters in high dimension, where we use edge-collapse anyway) + st.insert_batch(np.arange(n).reshape(1,-1), np.zeros(n)) + st.insert_edges_from_coo_matrix(inp) + st.expansion(max_dimension + 1) + st.compute_persistence(homology_coeff_field=self.homology_coeff_field, persistence_dim_max=max_dimension>=st.dimension()) + return [ st.persistence_intervals_in_dimension(dim) for dim in self.dim_list_ ] + + if input_type == 'full distance matrix': + ## Possibly transpose for performance? + # if inp.strides[0] > inp.strides[1]: # or the reverse? + # inp = inp.T + dgm = _full(inp, max_dimension=max_dimension, max_edge_length=threshold, homology_coeff_field=self.homology_coeff_field) + elif input_type == 'lower distance matrix': + dgm = _lower(inp, max_dimension=max_dimension, max_edge_length=threshold, homology_coeff_field=self.homology_coeff_field) + elif input_type == 'distance coo_matrix': + # Switch to coo_array (danger: row/col seem deprecated)? + dgm = _sparse(inp.row, inp.col, inp.data, inp.shape[0], max_dimension=max_dimension, max_edge_length=threshold, homology_coeff_field=self.homology_coeff_field) else: - raise ValueError("Only 'point cloud' and 'lower distance matrix' are valid input_type") + raise ValueError("Only 'point cloud', 'lower distance matrix', 'full distance matrix' and 'distance coo_matrix' are valid input_type") # move to __init__? - if max_dimension > 1: - stree = rips.create_simplex_tree(max_dimension=1) - stree.collapse_edges(nb_iterations = self.num_collapses) - stree.expansion(max_dimension) - else: - stree = rips.create_simplex_tree(max_dimension=max_dimension) - - persistence_dim_max = False - # Specific case where, despite expansion(max_dimension), stree has a lower dimension - if max_dimension > stree.dimension(): - persistence_dim_max = True - - stree.compute_persistence( - homology_coeff_field=self.homology_coeff_field, - persistence_dim_max=persistence_dim_max - ) - - return [ - stree.persistence_intervals_in_dimension(dim) for dim in self.dim_list_ - ] + # dgm stops at n-2 + return [dgm[dim] if dim < len(dgm) else np.empty((0,2)) for dim in self.dim_list_] def transform(self, X, Y=None): """Compute all the Vietoris-Rips complexes and their associated persistence diagrams. @@ -117,7 +179,7 @@ def transform(self, X, Y=None): `[[array( Hi(X[0]) ), array( Hj(X[0]) )], [array( Hi(X[1]) ), array( Hj(X[1]) )], ...]` :rtype: list of numpy ndarray of shape (,2) or list of list of numpy ndarray of shape (,2) """ - # Depends on homology_dimensions is an integer or a list of integer (else case) + # Depends if homology_dimensions is an integer or a list of integers (else case) if isinstance(self.homology_dimensions, int): unwrap = True self.dim_list_ = [ self.homology_dimensions ] diff --git a/src/python/test/test_sklearn_rips_persistence.py b/src/python/test/test_sklearn_rips_persistence.py index 2ca0c313e0..8687292b8c 100644 --- a/src/python/test/test_sklearn_rips_persistence.py +++ b/src/python/test/test_sklearn_rips_persistence.py @@ -10,6 +10,7 @@ from gudhi.datasets.generators import points from gudhi.sklearn.rips_persistence import RipsPersistence +import numpy as np import random import pytest @@ -73,3 +74,14 @@ def test_set_output(): assert len(diags_pandas.index) == NB_PC except ImportError: print("Missing pandas, skipping set_output test") + + +def test_big(): + # A circle + many isolated points + n=1000000 + X=np.zeros((n,2)) + X[:,0]=np.arange(n)*100 + X[:24]=points.torus(24,1,'grid') + # Ripser cannot handle it, have to fall back to SimplexTree + # Computing the full distance matrix would require too much memory -> kd-tree + RipsPersistence(range(25), threshold=10).fit_transform([X]) From 01ea034ca93734a08f162a5d643fad12d4628a55 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Mon, 12 Aug 2024 17:14:48 +0200 Subject: [PATCH 40/96] PersistenceLengths and its unitary tests --- .../gudhi/representations/vector_methods.py | 63 ++++++++++++++++++- src/python/test/test_representations.py | 15 ++++- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/python/gudhi/representations/vector_methods.py b/src/python/gudhi/representations/vector_methods.py index 14d2802e71..112b372438 100644 --- a/src/python/gudhi/representations/vector_methods.py +++ b/src/python/gudhi/representations/vector_methods.py @@ -729,7 +729,7 @@ class Atol(BaseEstimator, TransformerMixin): This class allows to vectorise measures (e.g. point clouds, persistence diagrams, etc) after a quantisation step. ATOL paper: :cite:`royer2019atol` - +:paramref:`~gudhi.representations.PersistenceLengths. Example -------- >>> from sklearn.cluster import KMeans @@ -885,3 +885,64 @@ def transform(self, X, sample_weight=None): def get_feature_names_out(self): return self._running_transform_names + +class PersistenceLengths(BaseEstimator, TransformerMixin): + """ + This is a class that returns the N-longest persistence lengths. + """ + def __init__(self, num_lengths=5): + """ + Constructor for the PersistenceLengths class. + + Parameters: + num_lengths (int): number of persistence lengths to return (default 5). + """ + self.num_lengths = num_lengths + + def fit(self, X, y=None): + """ + Fit the PersistenceLengths class on a list of persistence diagrams (this function actually does nothing but is + useful when PersistenceLengths is included in a scikit-learn Pipeline). + + Parameters: + X (list of n x 2 or n x 1 numpy arrays): input persistence diagrams. + y (n x 1 array): persistence diagram lengths (unused). + """ + return self + + def transform(self, X): + """ + Compute the persistence landscape for each persistence diagram individually and concatenate the results. + + Parameters: + X (list of n x 2 numpy arrays): input persistence diagrams. + + Returns: + numpy array with shape (number of diagrams) x (num_lengths): output persistence lengths. + """ + + pers_lengths = [] + for pd in X: + # Sort in reverse order persistence lengths (where length = death - birth) + lengths = np.flip(np.sort(pd[:,1] - pd[:,0])) + if len(lengths) >= self.num_lengths: + pers_lengths.append(lengths[:self.num_lengths]) + else: + # Fill with zeros if necessary + lengths_with_zeros = np.zeros((self.num_lengths)) + lengths_with_zeros[:len(lengths)] = lengths + pers_lengths.append(lengths_with_zeros) + + return pers_lengths + + def __call__(self, diag): + """ + Apply PersistenceLengths on a single persistence diagram and outputs the result. + + Parameters: + diag (n x 2 numpy array): input persistence diagram. + + Returns: + numpy 1d array of length num_lengths: output persistence landscape. + """ + return self.transform([diag])[0] diff --git a/src/python/test/test_representations.py b/src/python/test/test_representations.py index 594be4e64c..e1695cc4a4 100644 --- a/src/python/test/test_representations.py +++ b/src/python/test/test_representations.py @@ -9,7 +9,7 @@ # Vectorization from gudhi.representations import (Landscape, Silhouette, BettiCurve, ComplexPolynomial,\ - TopologicalVector, PersistenceImage, Entropy) + TopologicalVector, PersistenceImage, Entropy, PersistenceLengths) # Preprocessing from gudhi.representations import (BirthPersistenceTransform, Clamping, DiagramScaler, Padding, ProminentPoints, \ @@ -318,3 +318,16 @@ def test_endpoints(): def test_get_params(): for vec in [ Landscape(), Silhouette(), BettiCurve(), Entropy(mode="vector") ]: vec.get_params() + +def test_persistence_lengths(): + diag = np.array([[3., 5.], [0, np.inf], [4., 4.], [2., 6.]]) + for nl in range(6): + pl = PersistenceLengths(num_lengths=nl)(diag) + # test the result is sorted + assert np.all(sorted(pl, reverse=True) == pl) + if len(pl) > 0: + assert np.isinf(pl[0]) + for idx in range(len(pl)): + if idx >= len(diag): + # test it is filled with zeros when going further the input + assert pl[idx] == 0. From d30299f9f78f05630c356acb2c4faeb77830d2a7 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Mon, 12 Aug 2024 17:56:58 +0200 Subject: [PATCH 41/96] typo --- src/python/gudhi/representations/vector_methods.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/gudhi/representations/vector_methods.py b/src/python/gudhi/representations/vector_methods.py index 112b372438..4f0e4f6f38 100644 --- a/src/python/gudhi/representations/vector_methods.py +++ b/src/python/gudhi/representations/vector_methods.py @@ -729,7 +729,7 @@ class Atol(BaseEstimator, TransformerMixin): This class allows to vectorise measures (e.g. point clouds, persistence diagrams, etc) after a quantisation step. ATOL paper: :cite:`royer2019atol` -:paramref:`~gudhi.representations.PersistenceLengths. + Example -------- >>> from sklearn.cluster import KMeans From 2956d4c85911870bf7183832b43e072415e9dda0 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Tue, 13 Aug 2024 18:01:17 +0200 Subject: [PATCH 42/96] add new copy constructor to simplex tree --- src/Simplex_tree/include/gudhi/Simplex_tree.h | 86 ++++++++++--- .../Simplex_tree_node_explicit_storage.h | 16 +-- .../simplex_tree_ctor_and_move_unit_test.cpp | 119 +++++++++++++++--- .../test/simplex_tree_unit_test.cpp | 22 +--- 4 files changed, 187 insertions(+), 56 deletions(-) diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h index a6fbe9cba1..dee66fc513 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h @@ -245,7 +245,7 @@ class Simplex_tree { typedef boost::iterator_range Simplex_vertex_range; /** \brief Range over the cofaces of a simplex. */ typedef typename std::conditional>::type Cofaces_simplex_range; /** \private @@ -345,7 +345,7 @@ class Simplex_tree { /** \brief Returns a range over the vertices of a simplex. * * The order in which the vertices are visited is the decreasing order for < on Vertex_handles, - * which is consequenlty + * which is consequently * equal to \f$(-1)^{\text{dim} \sigma}\f$ the canonical orientation on the simplex. */ Simplex_vertex_range simplex_vertex_range(Simplex_handle sh) const { @@ -402,6 +402,29 @@ class Simplex_tree { filtration_vect_(), dimension_(-1) { } + /** + * @brief Construct the simplex tree as the copy of a given simplex tree with eventually different template + * parameters. + * Therefore, should provide a method converting the filtration values of one tree to the another. All other values + * are already implicitly convertible if the concept of @ref SimplexTreeOptions is respected (note that there is + * an eventual loss of precision or an undefined behaviour if a value is converted into a new type too small to + * contain it). Any extra data (@ref Simplex_data) stored in the simplices are ignored in the copy for now. + * + * @tparam OtherSimplexTreeOptions Options of the given simplex tree. + * @tparam F Method taking an OtherSimplexTreeOptions::Filtration_value as input and returning an + * Options::Filtration_value. + * @param complex_source Simplex tree to copy. + * @param translate_filtration_value Method taking an OtherSimplexTreeOptions::Filtration_value from the source tree + * as input and returning the corresponding Options::Filtration_value in the new tree. + */ + template + Simplex_tree(const Simplex_tree& complex_source, F&& translate_filtration_value) { +#ifdef DEBUG_TRACES + std::clog << "Simplex_tree custom copy constructor" << std::endl; +#endif // DEBUG_TRACES + copy_from(complex_source, translate_filtration_value); + } + /** \brief User-defined copy constructor reproduces the whole tree structure. */ Simplex_tree(const Simplex_tree& complex_source) { #ifdef DEBUG_TRACES @@ -471,27 +494,58 @@ class Simplex_tree { 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()); + 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); + rec_copy( + &root_, &root_source, [](const Filtration_value& fil) -> const Filtration_value& { return fil; }); + } + + // Copy from complex_source to "this" + template + void copy_from(const Simplex_tree& complex_source, F&& translate_filtration_value) { + null_vertex_ = complex_source.null_vertex_; + filtration_vect_.clear(); + dimension_ = complex_source.dimension_; + auto root_source = complex_source.root_; + + // root members copy + for (auto& p : root_source.members()){ + auto it = root_.members().try_emplace(root_.members().end(), p.first); + it->second.assign_children(&root_); + it->second.assign_filtration(translate_filtration_value(p.second.filtration())); + if constexpr (Options::store_key && OtherSimplexTreeOptions::store_key) it->second.assign_key(p.second.key()); + } + + rec_copy(&root_, &root_source, translate_filtration_value); } /** \brief depth first search, inserts simplices when reaching a leaf. */ - void rec_copy(Siblings *sib, Siblings *sib_source) { - for (auto sh = sib->members().begin(), sh_source = sib_source->members().begin(); - sh != sib->members().end(); ++sh, ++sh_source) { + template + void rec_copy(Siblings *sib, OtherSiblings *sib_source, F&& translate_filtration_value) { + auto sh_source = sib_source->members().begin(); + for (auto sh = sib->members().begin(); sh != sib->members().end(); ++sh, ++sh_source) { update_simplex_tree_after_node_insertion(sh); if (has_children(sh_source)) { Siblings * newsib = new Siblings(sib, sh_source->first); if constexpr (!Options::stable_simplex_handles) { newsib->members_.reserve(sh_source->second.children()->members().size()); } - for (auto & child : sh_source->second.children()->members()) - newsib->members_.emplace_hint(newsib->members_.end(), child.first, Node(newsib, child.second.filtration())); - rec_copy(newsib, sh_source->second.children()); + for (auto & child : sh_source->second.children()->members()){ + if constexpr (store_key) + newsib->members_.emplace_hint( + newsib->members_.end(), + child.first, + Node(newsib, translate_filtration_value(child.second.filtration()), child.second.key())); + else + newsib->members_.emplace_hint(newsib->members_.end(), + child.first, + Node(newsib, translate_filtration_value(child.second.filtration()))); + } + rec_copy(newsib, sh_source->second.children(), translate_filtration_value); sh->second.assign_children(newsib); } } @@ -1432,9 +1486,9 @@ class Simplex_tree { * * Nodes with label @p u get affected only if a Node with label @p v is in their same * siblings set. - * We then try to insert "ponctually" @p v all over the subtree rooted + * We then try to insert "punctually" @p v all over the subtree rooted * at `Node(u)`. Each insertion of a Node with @p v label induces a local - * expansion at this Node (as explained above) and a sequence of "ponctual" + * expansion at this Node (as explained above) and a sequence of "punctual" * insertion of `Node(v)` in the subtree rooted at sibling nodes of the new node, * on its left. */ @@ -1479,7 +1533,7 @@ class Simplex_tree { //for all siblings containing a Node labeled with u (including the root), run //compute_punctual_expansion - //todo parallelise + //todo parallelize List_max_vertex* nodes_with_label_u = nodes_by_label(u);//all Nodes with u label GUDHI_CHECK(nodes_with_label_u != nullptr, @@ -1798,7 +1852,7 @@ class Simplex_tree { if (blocker_result) { blocked_new_sib_vertex_list.push_back(new_sib_member->first); // update data structures for all deleted simplices - // can be done in the loop as part of another datastructure + // can be done in the loop as part of another data structure update_simplex_tree_before_node_removal(new_sib_member); } } @@ -1972,7 +2026,7 @@ class Simplex_tree { return true; }; - //TODO: `if constexpr` replacable by `std::erase_if` in C++20? Has a risk of additional runtime, + //TODO: `if constexpr` replaceable by `std::erase_if` in C++20? Has a risk of additional runtime, //so to benchmark first. if constexpr (Options::stable_simplex_handles) { modified = false; @@ -2312,7 +2366,7 @@ class Simplex_tree { static Simplex_handle simplex_handle_from_node(Node& node) { if constexpr (Options::stable_simplex_handles){ //Relies on the Dictionary type to be boost::container::map. - //If the type changes or boost fondamentally changes something on the structure of their map, + //If the type changes or boost fundamentally changes something on the structure of their map, //a safer/more general but much slower version is: // if (node.children()->parent() == label) { // verifies if node is a leaf // return children->oncles()->find(label); diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h index 2d5ab0f6b1..fa9dd50fe1 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h @@ -18,7 +18,6 @@ #define GUDHI_EMPTY_BASE_CLASS_OPTIMIZATION #endif -#include #include namespace Gudhi { @@ -33,20 +32,23 @@ namespace Gudhi { * * It stores explicitly its own filtration value and its own Simplex_key. */ -template -struct GUDHI_EMPTY_BASE_CLASS_OPTIMIZATION Simplex_tree_node_explicit_storage : SimplexTree::Filtration_simplex_base, - SimplexTree::Key_simplex_base, - SimplexTree::Hooks_simplex_base, - boost::empty_value { +template +struct GUDHI_EMPTY_BASE_CLASS_OPTIMIZATION Simplex_tree_node_explicit_storage + : SimplexTree::Filtration_simplex_base, + SimplexTree::Key_simplex_base, + SimplexTree::Hooks_simplex_base, + boost::empty_value { typedef typename SimplexTree::Siblings Siblings; typedef typename SimplexTree::Filtration_value Filtration_value; typedef typename SimplexTree::Simplex_key Simplex_key; typedef typename SimplexTree::Simplex_data Simplex_data; Simplex_tree_node_explicit_storage(Siblings * sib = nullptr, - Filtration_value filtration = 0) + Filtration_value filtration = 0, + [[maybe_unused]] Simplex_key key = -1) : children_(sib) { this->assign_filtration(filtration); + if constexpr (SimplexTree::Options::store_key) this->assign_key(key); } /* 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 index 46d3bbc14a..ae8ba70cb0 100644 --- 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 @@ -26,22 +26,20 @@ using namespace Gudhi; -struct Simplex_tree_options_stable_simplex_handles { - typedef linear_indexing_tag Indexing_tag; - typedef int Vertex_handle; - typedef double Filtration_value; - typedef std::uint32_t Simplex_key; - static const bool store_key = true; - static const bool store_filtration = true; - static const bool contiguous_vertices = false; - static const bool link_nodes_by_label = true; - static const bool stable_simplex_handles = true; -}; - typedef boost::mpl::list, Simplex_tree, - Simplex_tree, - Simplex_tree > list_of_tested_variants; + Simplex_tree > list_of_tested_variants; + +std::string print_filtration_value(double fil){ + return std::to_string(fil); +} + +std::string print_filtration_value(std::vector fil){ + std::string ss; + for (auto val : fil) ss += std::to_string(val) + " "; + ss.pop_back(); + return ss; +} template void print_simplex_filtration(Simplex_tree& st, const std::string& msg) { @@ -55,7 +53,7 @@ void print_simplex_filtration(Simplex_tree& st, const std::string& msg) { std::clog << "* Iterator on Simplices in the filtration, with [filtration value]:\n"; for (auto f_simplex : st.filtration_simplex_range()) { std::clog << " " - << "[" << st.filtration(f_simplex) << "] "; + << "[" << print_filtration_value(st.filtration(f_simplex)) << "] "; for (auto vertex : st.simplex_vertex_range(f_simplex)) std::clog << "(" << vertex << ")"; std::clog << std::endl; } @@ -179,6 +177,97 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_copy_constructor, Simplex_tree, list_of_te } +struct Simplex_tree_options_custom_fil_values_default { + typedef linear_indexing_tag Indexing_tag; + typedef std::int16_t Vertex_handle; + typedef std::vector Filtration_value; + typedef std::int32_t Simplex_key; + static const bool store_key = false; + static const bool store_filtration = true; + static const bool contiguous_vertices = false; + static const bool link_nodes_by_label = false; + static const bool stable_simplex_handles = false; +}; + +struct Simplex_tree_options_custom_fil_values_fast_persistence { + typedef linear_indexing_tag Indexing_tag; + typedef std::int16_t Vertex_handle; + typedef std::vector Filtration_value; + typedef std::int32_t Simplex_key; + static const bool store_key = true; + static const bool store_filtration = true; + static const bool contiguous_vertices = true; + static const bool link_nodes_by_label = false; + static const bool stable_simplex_handles = false; +}; + +struct Simplex_tree_options_custom_fil_values_full_featured { + typedef linear_indexing_tag Indexing_tag; + typedef std::int16_t Vertex_handle; + typedef std::vector Filtration_value; + typedef std::int32_t Simplex_key; + static const bool store_key = true; + static const bool store_filtration = true; + static const bool contiguous_vertices = false; + static const bool link_nodes_by_label = true; + static const bool stable_simplex_handles = true; +}; + +typedef boost::mpl::list, + Simplex_tree, + Simplex_tree > + list_of_custom_fil_variants; + +BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_custom_copy_constructor, typeST, list_of_custom_fil_variants) { + typeST st; + Simplex_tree<> st_witness; + + st.insert_simplex_and_subfaces({2, 1, 0}, {3, 1}); + st.insert_simplex_and_subfaces({0, 1, 6, 7}, {4, 1}); + st.insert_simplex_and_subfaces({3, 0}, {2, 1}); + st.insert_simplex_and_subfaces({3, 4, 5}, {3, 1}); + st.insert_simplex_and_subfaces({8}, {1, 1}); + + st_witness.insert_simplex_and_subfaces({2, 1, 0}, 3.0); + st_witness.insert_simplex_and_subfaces({0, 1, 6, 7}, 4.0); + st_witness.insert_simplex_and_subfaces({3, 0}, 2.0); + st_witness.insert_simplex_and_subfaces({3, 4, 5}, 3.0); + st_witness.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, "Simplex_tree is initialized"); + + std::clog << "********************************************************************" << std::endl; + std::clog << "TEST OF CUSTOM COPY CONSTRUCTOR" << std::endl; + + auto trans = [](const typename typeST::Filtration_value& fil) -> Simplex_tree<>::Filtration_value { + return fil[0]; + }; + + Simplex_tree<> st1(st, trans); + Simplex_tree<> st2(st, trans); + print_simplex_filtration(st1, "First custom copy constructor from the Simplex_tree"); + print_simplex_filtration(st2, "Second custom copy constructor from the Simplex_tree"); + // Cross check + BOOST_CHECK(st1 == st2); + BOOST_CHECK(st_witness == st2); + BOOST_CHECK(st1 == st_witness); +} + template std::vector> get_star(Simplex_tree& st) { std::vector> output; diff --git a/src/Simplex_tree/test/simplex_tree_unit_test.cpp b/src/Simplex_tree/test/simplex_tree_unit_test.cpp index 04b5f1671d..d0dc0140ec 100644 --- a/src/Simplex_tree/test/simplex_tree_unit_test.cpp +++ b/src/Simplex_tree/test/simplex_tree_unit_test.cpp @@ -31,22 +31,9 @@ using namespace Gudhi; -struct Simplex_tree_options_stable_simplex_handles { - typedef linear_indexing_tag Indexing_tag; - typedef int Vertex_handle; - typedef double Filtration_value; - typedef std::uint32_t Simplex_key; - static const bool store_key = true; - static const bool store_filtration = true; - static const bool contiguous_vertices = false; - static const bool link_nodes_by_label = true; - static const bool stable_simplex_handles = true; -}; - typedef boost::mpl::list, Simplex_tree, - Simplex_tree, - Simplex_tree > list_of_tested_variants; + Simplex_tree > list_of_tested_variants; template void test_empty_simplex_tree(typeST& tst) { @@ -933,7 +920,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_insert_graph, Graph, list_of_graph_va st1.insert_graph(g); BOOST_CHECK(st1.num_simplices() == 6); - Simplex_tree sst1; + Simplex_tree sst1; sst1.insert_graph(g); BOOST_CHECK(sst1.num_simplices() == 6); @@ -948,7 +935,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_insert_graph, Graph, list_of_graph_va st2.insert_graph(g); BOOST_CHECK(st2.num_simplices() == 6); - Simplex_tree sst2; + Simplex_tree sst2; sst2.insert_graph(g); BOOST_CHECK(sst2.num_simplices() == 6); @@ -1157,8 +1144,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_boundaries_and_opposite_vertex_iterat } typedef boost::mpl::list, - Simplex_tree, - Simplex_tree > + Simplex_tree > list_of_tested_variants_wo_fast_persistence; BOOST_AUTO_TEST_CASE_TEMPLATE(batch_vertices, typeST, list_of_tested_variants_wo_fast_persistence) { From 41672ed29270b4ee5ac1150a17e889b3d9e3e222 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Mon, 19 Aug 2024 16:53:09 +0200 Subject: [PATCH 43/96] doc --- src/Simplex_tree/include/gudhi/Simplex_tree.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h index dee66fc513..d7e7c50c13 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h @@ -10,6 +10,7 @@ * - 2023/05 Clément Maria: Edge insertion method for flag complexes * - 2023/05 Hannah Schreiber: Factorization of expansion methods * - 2023/08 Hannah Schreiber (& Clément Maria): Add possibility of stable simplex handles. + * - 2024/08 Hannah Schreiber: Addition of customable copy constructor. * - YYYY/MM Author: Description of the modification */ From 9317d458fe7892f2125234911318ec791f043281 Mon Sep 17 00:00:00 2001 From: hschreiber <48448038+hschreiber@users.noreply.github.com> Date: Fri, 23 Aug 2024 14:52:04 +0200 Subject: [PATCH 44/96] Update src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h Co-authored-by: Marc Glisse --- .../gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h index fa9dd50fe1..c01a25f00f 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h @@ -45,7 +45,7 @@ struct GUDHI_EMPTY_BASE_CLASS_OPTIMIZATION Simplex_tree_node_explicit_storage Simplex_tree_node_explicit_storage(Siblings * sib = nullptr, Filtration_value filtration = 0, - [[maybe_unused]] Simplex_key key = -1) + [[maybe_unused]] Simplex_key key = SimplexTree::null_key()) : children_(sib) { this->assign_filtration(filtration); if constexpr (SimplexTree::Options::store_key) this->assign_key(key); From 3672877d206bd2c427e4a9fd18ee7acc9dd343c7 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 23 Aug 2024 15:43:22 +0200 Subject: [PATCH 45/96] small fixes --- src/Simplex_tree/include/gudhi/Simplex_tree.h | 20 ++++++++++++++----- .../Simplex_tree_node_explicit_storage.h | 6 ++---- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h index d7e7c50c13..852e313b67 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h @@ -10,7 +10,7 @@ * - 2023/05 Clément Maria: Edge insertion method for flag complexes * - 2023/05 Hannah Schreiber: Factorization of expansion methods * - 2023/08 Hannah Schreiber (& Clément Maria): Add possibility of stable simplex handles. - * - 2024/08 Hannah Schreiber: Addition of customable copy constructor. + * - 2024/08 Hannah Schreiber: Addition of customizable copy constructor. * - YYYY/MM Author: Description of the modification */ @@ -133,6 +133,7 @@ class Simplex_tree { struct Key_simplex_base_real { Key_simplex_base_real() : key_(-1) {} + Key_simplex_base_real(Simplex_key k) : key_(k) {} void assign_key(Simplex_key k) { key_ = k; } Simplex_key key() const { return key_; } private: @@ -140,6 +141,7 @@ class Simplex_tree { }; struct Key_simplex_base_dummy { Key_simplex_base_dummy() {} + Key_simplex_base_dummy([[maybe_unused]] Simplex_key k) {} // Undefined so it will not link void assign_key(Simplex_key); Simplex_key key() const; @@ -155,6 +157,7 @@ class Simplex_tree { struct Filtration_simplex_base_real { Filtration_simplex_base_real() : filt_(0) {} + Filtration_simplex_base_real(Filtration_value f) : filt_(f) {} void assign_filtration(Filtration_value f) { filt_ = f; } Filtration_value filtration() const { return filt_; } private: @@ -162,6 +165,7 @@ class Simplex_tree { }; struct Filtration_simplex_base_dummy { Filtration_simplex_base_dummy() {} + Filtration_simplex_base_dummy([[maybe_unused]] Filtration_value f) {} void assign_filtration(Filtration_value GUDHI_CHECK_code(f)) { GUDHI_CHECK(f == 0, "filtration value specified for a complex that does not store them"); } Filtration_value filtration() const { return 0; } }; @@ -514,11 +518,17 @@ class Simplex_tree { auto root_source = complex_source.root_; // root members copy + root_.members().reserve(root_source.size()); for (auto& p : root_source.members()){ - auto it = root_.members().try_emplace(root_.members().end(), p.first); - it->second.assign_children(&root_); - it->second.assign_filtration(translate_filtration_value(p.second.filtration())); - if constexpr (Options::store_key && OtherSimplexTreeOptions::store_key) it->second.assign_key(p.second.key()); + if constexpr (Options::store_key && OtherSimplexTreeOptions::store_key) { + auto it = root_.members().try_emplace( + root_.members().end(), + p.first, + Node(&root_, translate_filtration_value(p.second.filtration()), p.second.key())); + } else { + auto it = root_.members().try_emplace( + root_.members().end(), p.first, Node(&root_, translate_filtration_value(p.second.filtration()))); + } } rec_copy(&root_, &root_source, translate_filtration_value); diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h index c01a25f00f..5ca77ea9b5 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h @@ -46,10 +46,8 @@ struct GUDHI_EMPTY_BASE_CLASS_OPTIMIZATION Simplex_tree_node_explicit_storage Simplex_tree_node_explicit_storage(Siblings * sib = nullptr, Filtration_value filtration = 0, [[maybe_unused]] Simplex_key key = SimplexTree::null_key()) - : children_(sib) { - this->assign_filtration(filtration); - if constexpr (SimplexTree::Options::store_key) this->assign_key(key); - } + : SimplexTree::Filtration_simplex_base(filtration), SimplexTree::Key_simplex_base(key), children_(sib) + {} /* * Assign children to the node From 8cab8c9e3695846278f3b8fd8095715bbc8e5950 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 23 Aug 2024 18:50:38 +0200 Subject: [PATCH 46/96] Add type hints --- src/python/gudhi/sklearn/rips_persistence.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/python/gudhi/sklearn/rips_persistence.py b/src/python/gudhi/sklearn/rips_persistence.py index 73a98e4300..54bf969611 100644 --- a/src/python/gudhi/sklearn/rips_persistence.py +++ b/src/python/gudhi/sklearn/rips_persistence.py @@ -11,6 +11,7 @@ from ..flag_filtration.edge_collapse import reduce_graph import math import numpy as np +from typing import Union, Iterable, Literal, Optional from sklearn.base import BaseEstimator, TransformerMixin from scipy.sparse import coo_matrix from scipy.spatial import cKDTree @@ -41,12 +42,14 @@ class RipsPersistence(BaseEstimator, TransformerMixin): def __init__( self, - homology_dimensions, - threshold=float('inf'), - input_type='point cloud', - num_collapses='auto', - homology_coeff_field=11, - n_jobs=None, + homology_dimensions: Union[int, Iterable[int]], + threshold: float = float('inf'), + input_type: Literal[ + "point cloud", "full distance matrix", "lower distance matrix", "distance coo_matrix" + ] = 'point cloud', + num_collapses: Union[int, Literal["auto"]] = 'auto', + homology_coeff_field: int = 11, + n_jobs: Optional[int] = None, ): """ Constructor for the RipsPersistence class. @@ -64,7 +67,7 @@ def __init__( num_collapses (int|str): Specify the number of iterations of :func:`~gudhi.flag_filtration.edge_collapse.reduce_graph` (edge collapse) to perform on the graph. Default value is 'auto'. homology_coeff_field (int): The homology coefficient field. Must be a prime number. Default value is 11. - n_jobs (int): Number of jobs to run in parallel. `None` (default value) means `n_jobs = 1` unless in a + n_jobs (Optional[int]): Number of jobs to run in parallel. `None` (default value) means `n_jobs = 1` unless in a joblib.parallel_backend context. `-1` means using all processors. cf. https://joblib.readthedocs.io/en/latest/generated/joblib.Parallel.html for more details. """ From d2cfe75bac3db770f94c42ef624b7a6ba8f888a1 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 30 Aug 2024 14:42:22 +0200 Subject: [PATCH 47/96] add gudhi_check for dummies --- src/Simplex_tree/include/gudhi/Simplex_tree.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h index 852e313b67..caa05d5f6a 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h @@ -141,11 +141,14 @@ class Simplex_tree { }; struct Key_simplex_base_dummy { Key_simplex_base_dummy() {} - Key_simplex_base_dummy([[maybe_unused]] Simplex_key k) {} + Key_simplex_base_dummy(Simplex_key k) { + GUDHI_CHECK(k == -1, "key value specified for a complex that does not store them"); + } // Undefined so it will not link void assign_key(Simplex_key); Simplex_key key() const; }; + struct Extended_filtration_data { Filtration_value minval; Filtration_value maxval; @@ -165,8 +168,12 @@ class Simplex_tree { }; struct Filtration_simplex_base_dummy { Filtration_simplex_base_dummy() {} - Filtration_simplex_base_dummy([[maybe_unused]] Filtration_value f) {} - void assign_filtration(Filtration_value GUDHI_CHECK_code(f)) { GUDHI_CHECK(f == 0, "filtration value specified for a complex that does not store them"); } + Filtration_simplex_base_dummy(Filtration_value f) { + GUDHI_CHECK(f == 0, "filtration value specified for a complex that does not store them"); + } + void assign_filtration(Filtration_value GUDHI_CHECK_code(f)) { + GUDHI_CHECK(f == 0, "filtration value specified for a complex that does not store them"); + } Filtration_value filtration() const { return 0; } }; typedef typename std::conditional Date: Fri, 30 Aug 2024 14:45:23 +0200 Subject: [PATCH 48/96] code review: use numpy partition and bad/copy paste/replace of documentation --- .../gudhi/representations/vector_methods.py | 71 ++++++++++--------- src/python/test/test_representations.py | 14 ++-- 2 files changed, 47 insertions(+), 38 deletions(-) diff --git a/src/python/gudhi/representations/vector_methods.py b/src/python/gudhi/representations/vector_methods.py index 4f0e4f6f38..e9314d18ca 100644 --- a/src/python/gudhi/representations/vector_methods.py +++ b/src/python/gudhi/representations/vector_methods.py @@ -73,7 +73,7 @@ def transform(self, X): Parameters: X (list of n x 2 numpy arrays): input persistence diagrams. - + Returns: numpy array with shape (number of diagrams) x (number of pixels = **resolution[0]** x **resolution[1]**): output persistence images. """ @@ -196,7 +196,7 @@ def transform(self, X): Parameters: X (list of n x 2 numpy arrays): input persistence diagrams. - + Returns: numpy array with shape (number of diagrams) x (number of samples = **num_landscapes** x **resolution**): output persistence landscapes. """ @@ -271,7 +271,7 @@ def transform(self, X): Parameters: X (list of n x 2 numpy arrays): input persistence diagrams. - + Returns: numpy array with shape (number of diagrams) x (**resolution**): output persistence silhouettes. """ @@ -363,7 +363,7 @@ def fit(self, X, y = None): if self.predefined_grid is None: if self.resolution is None: # Flexible/exact version - self.grid_ = np.unique(np.concatenate([pd.ravel() for pd in X] + [[-np.inf]], axis=0)) + self.grid_ = np.unique(np.concatenate([pd.ravel() for pd in X] + [[-np.inf]], axis=0)) else: _grid_from_sample_range(self, X) else: @@ -391,7 +391,7 @@ def transform(self, X): print("Empty list: output has shape [0, len(grid)]") return np.zeros((N, len(self.grid_))) - + else: events = np.concatenate([pd.ravel(order="F") for pd in X], axis=0) @@ -413,7 +413,7 @@ def transform(self, X): i += 1 for k in range(0, N): bettis[k].append(bettis[k][-1]) - + return np.array(bettis, dtype=int)[:, 0:-1] def fit_transform(self, X, y = None): @@ -485,7 +485,7 @@ def __init__(self, mode="scalar", normalized=True, resolution=100, sample_range= Parameters: mode (string): what entropy to compute: either "scalar" for computing the entropy statistics, or "vector" for computing the entropy summary functions (default "scalar"). - normalized (bool): whether to normalize the entropy summary function (default True). Used only if **mode** = "vector". + normalized (bool): whether to normalize the entropy summary function (default True). Used only if **mode** = "vector". resolution (int): number of sample for the entropy summary function (default 100). Used only if **mode** = "vector". sample_range ([double, double]): minimum and maximum of the entropy summary function domain, of the form [x_min, x_max] (default [numpy.nan, numpy.nan]). It is the interval on which samples will be drawn evenly. If one of the values is numpy.nan, it can be computed from the persistence diagrams with the fit() method. Used only if **mode** = "vector". keep_endpoints (bool): when computing `sample_range`, use the exact extremities. This is mostly useful for plotting, the default is to use a slightly smaller range. @@ -515,16 +515,16 @@ def transform(self, X): Parameters: X (list of n x 2 numpy arrays): input persistence diagrams. - + Returns: numpy array with shape (number of diagrams) x (1 if **mode** = "scalar" else **resolution**): output entropy. """ num_diag, Xfit = len(X), [] - new_X = BirthPersistenceTransform().fit_transform(X) + new_X = BirthPersistenceTransform().fit_transform(X) for i in range(num_diag): orig_diagram, new_diagram, num_pts_in_diag = X[i], new_X[i], X[i].shape[0] - + p = new_diagram[:,1] p = p/np.sum(p) if self.mode == "scalar": @@ -566,7 +566,7 @@ def __init__(self, threshold=10): Constructor for the TopologicalVector class. Parameters: - threshold (int): number of distances to keep (default 10). This is the dimension of the topological vector. If -1, this threshold is computed from the list of persistence diagrams by considering the one with the largest number of points and using the dimension of its corresponding topological vector as threshold. + threshold (int): number of distances to keep (default 10). This is the dimension of the topological vector. If -1, this threshold is computed from the list of persistence diagrams by considering the one with the largest number of points and using the dimension of its corresponding topological vector as threshold. """ self.threshold = threshold @@ -586,7 +586,7 @@ def transform(self, X): Parameters: X (list of n x 2 numpy arrays): input persistence diagrams. - + Returns: numpy array with shape (number of diagrams) x (**threshold**): output topological vectors. """ @@ -638,7 +638,7 @@ def __init__(self, polynomial_type="R", threshold=10): Parameters: polynomial_type (char): either "R", "S" or "T" (default "R"). Type of complex polynomial that is going to be computed (explained in https://link.springer.com/chapter/10.1007%2F978-3-319-23231-7_27). - threshold (int): number of coefficients (default 10). This is the dimension of the complex vector of coefficients, i.e. the number of coefficients corresponding to the largest degree terms of the polynomial. If -1, this threshold is computed from the list of persistence diagrams by considering the one with the largest number of points and using the dimension of its corresponding complex vector of coefficients as threshold. + threshold (int): number of coefficients (default 10). This is the dimension of the complex vector of coefficients, i.e. the number of coefficients corresponding to the largest degree terms of the polynomial. If -1, this threshold is computed from the list of persistence diagrams by considering the one with the largest number of points and using the dimension of its corresponding complex vector of coefficients as threshold. """ self.threshold, self.polynomial_type = threshold, polynomial_type @@ -658,7 +658,7 @@ def transform(self, X): Parameters: X (list of n x 2 numpy arrays): input persistence diagrams. - + Returns: numpy array with shape (number of diagrams) x (**threshold**): output complex vectors of coefficients. """ @@ -681,9 +681,9 @@ def transform(self, X): roots = np.multiply( (D[:,1]-D[:,0])/2, np.cos(alpha) - np.sin(alpha) + 1j * (np.cos(alpha) + np.sin(alpha)) ) coeff = [0] * (N+1) coeff[N] = 1 - for i in range(1, N+1): - for j in range(N-i-1, N): - coeff[j] += ((-1) * roots[i-1] * coeff[j+1]) + for i in range(1, N+1): + for j in range(N-i-1, N): + coeff[j] += ((-1) * roots[i-1] * coeff[j+1]) coeff = np.array(coeff[::-1])[1:] Xfit[d, :min(thresh, coeff.shape[0])] = coeff[:min(thresh, coeff.shape[0])] return Xfit @@ -888,16 +888,22 @@ def get_feature_names_out(self): class PersistenceLengths(BaseEstimator, TransformerMixin): """ - This is a class that returns the N-longest persistence lengths. + This is a class that returns the sorted N-longest persistence lengths. If the input does not contain enough values, + the output will be filled with zeros. """ + def __init__(self, num_lengths=5): """ Constructor for the PersistenceLengths class. Parameters: num_lengths (int): number of persistence lengths to return (default 5). + + :raises ValueError: If num_lengths is lower or equal to 0. """ - self.num_lengths = num_lengths + if num_lengths <= 0: + raise ValueError("num_lengths must be greater than 0.") + self.num_lengths = num_lengths def fit(self, X, y=None): """ @@ -912,28 +918,29 @@ def fit(self, X, y=None): def transform(self, X): """ - Compute the persistence landscape for each persistence diagram individually and concatenate the results. + Compute the persistence lengths for each persistence diagram individually and concatenate the results. Parameters: X (list of n x 2 numpy arrays): input persistence diagrams. - + Returns: numpy array with shape (number of diagrams) x (num_lengths): output persistence lengths. """ - pers_lengths = [] + pers_length_list = [] for pd in X: - # Sort in reverse order persistence lengths (where length = death - birth) - lengths = np.flip(np.sort(pd[:,1] - pd[:,0])) - if len(lengths) >= self.num_lengths: - pers_lengths.append(lengths[:self.num_lengths]) + pl = pd[:, 1] - pd[:, 0] + if len(pl) >= self.num_lengths: + pers_length = np.partition(pl, -self.num_lengths)[-self.num_lengths :] else: # Fill with zeros if necessary - lengths_with_zeros = np.zeros((self.num_lengths)) - lengths_with_zeros[:len(lengths)] = lengths - pers_lengths.append(lengths_with_zeros) - - return pers_lengths + pers_length = np.zeros((self.num_lengths)) + pers_length[: len(pl)] = pl + + # Sort in reverse order persistence lengths (where length = death - birth) + pers_length_list.append(np.flip(np.sort(pers_length))) + + return pers_length_list def __call__(self, diag): """ @@ -943,6 +950,6 @@ def __call__(self, diag): diag (n x 2 numpy array): input persistence diagram. Returns: - numpy 1d array of length num_lengths: output persistence landscape. + numpy 1d array of length num_lengths: output persistence lengths. """ return self.transform([diag])[0] diff --git a/src/python/test/test_representations.py b/src/python/test/test_representations.py index e1695cc4a4..e219adea5e 100644 --- a/src/python/test/test_representations.py +++ b/src/python/test/test_representations.py @@ -128,8 +128,8 @@ def test_atol_doc(): # Check the center of the first_cluster and second_cluster are in Atol centers centers = atol_vectoriser.fit(X=[a, b, c]).centers - np.isclose(centers, first_cluster.mean(axis=0)).all(1).any() - np.isclose(centers, second_cluster.mean(axis=0)).all(1).any() + np.isclose(centers, first_cluster.mean(axis=0)).all(1).any() + np.isclose(centers, second_cluster.mean(axis=0)).all(1).any() vectorization = atol_vectoriser.transform(X=[a, b, c]) assert np.allclose(vectorization[0], atol_vectoriser(a)) @@ -203,7 +203,7 @@ def test_vectorization_empty_diagrams(): scv = Entropy(mode="vector", normalized=False, resolution=random_resolution)(empty_diag) assert not np.any(scv) assert scv.shape[0] == random_resolution - + def test_entropy_miscalculation(): diag_ex = np.array([[0.0,1.0], [0.0,1.0], [0.0,2.0]]) def pe(pd): @@ -215,14 +215,14 @@ def pe(pd): sce = Entropy(mode="vector", resolution=4, normalized=False, keep_endpoints=True) pef = [-1/4*np.log(1/4)-1/4*np.log(1/4)-1/2*np.log(1/2), -1/4*np.log(1/4)-1/4*np.log(1/4)-1/2*np.log(1/2), - -1/2*np.log(1/2), + -1/2*np.log(1/2), 0.0] assert all(([pef] == sce.fit_transform([diag_ex]))[0]) sce = Entropy(mode="vector", resolution=4, normalized=True) pefN = (sce.fit_transform([diag_ex]))[0] area = np.linalg.norm(pefN, ord=1) assert area==pytest.approx(1) - + def test_kernel_empty_diagrams(): empty_diag = np.empty(shape = [0, 2]) assert SlicedWassersteinDistance(num_directions=100)(empty_diag, empty_diag) == 0. @@ -321,7 +321,7 @@ def test_get_params(): def test_persistence_lengths(): diag = np.array([[3., 5.], [0, np.inf], [4., 4.], [2., 6.]]) - for nl in range(6): + for nl in range(1, 6): pl = PersistenceLengths(num_lengths=nl)(diag) # test the result is sorted assert np.all(sorted(pl, reverse=True) == pl) @@ -331,3 +331,5 @@ def test_persistence_lengths(): if idx >= len(diag): # test it is filled with zeros when going further the input assert pl[idx] == 0. + with pytest.raises(ValueError): + pl = PersistenceLengths(num_lengths=0)(diag) From 2633e1b13b9d70c99ebb5563530b37018be84431 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Mon, 2 Sep 2024 18:04:42 +0200 Subject: [PATCH 49/96] fix reserve for stable simplex handle --- src/Simplex_tree/include/gudhi/Simplex_tree.h | 2 +- .../simplex_tree_ctor_and_move_unit_test.cpp | 68 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h index caa05d5f6a..d8d500d7dc 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h @@ -525,7 +525,7 @@ class Simplex_tree { auto root_source = complex_source.root_; // root members copy - root_.members().reserve(root_source.size()); + if constexpr (!Options::stable_simplex_handles) root_.members().reserve(root_source.size()); for (auto& p : root_source.members()){ if constexpr (Options::store_key && OtherSimplexTreeOptions::store_key) { auto it = root_.members().try_emplace( 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 index ae8ba70cb0..1d370adfef 100644 --- 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 @@ -268,6 +268,74 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_custom_copy_constructor, typeST, list BOOST_CHECK(st1 == st_witness); } +BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_custom_copy_constructor_key, typeST, list_of_custom_fil_variants) +{ + std::clog << "********************************************************************" << std::endl; + std::clog << "TEST OF CUSTOM COPY CONSTRUCTOR WITH KEY VALUES" << std::endl; + + typeST st; + + st.insert_simplex_and_subfaces({2, 1, 0}, {3, 1}); + st.insert_simplex_and_subfaces({0, 1, 6, 7}, {4, 1}); + st.insert_simplex_and_subfaces({3, 0}, {2, 1}); + st.insert_simplex_and_subfaces({3, 4, 5}, {3, 1}); + st.insert_simplex_and_subfaces({8}, {1, 1}); + + /* 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] */ + + if constexpr (typeST::Options::store_key){ + for (auto f_simplex : st.complex_simplex_range()) { + std::int32_t key = 1; + for (auto filt : st.filtration(f_simplex)) { + key *= filt; + } + st.assign_key(f_simplex, key); + } + } + + auto trans = [](const typename typeST::Filtration_value& fil) + -> Simplex_tree::Filtration_value { + Simplex_tree::Filtration_value copy(std::begin(fil), + std::end(fil)); + std::sort(copy.begin(), copy.end()); + return copy; + }; + + Simplex_tree st_trans(st, trans); + for (auto f_simplex : st_trans.complex_simplex_range()) { + auto filtrations = st_trans.filtration(f_simplex); + BOOST_CHECK(std::is_sorted(std::begin(filtrations), std::end(filtrations))); + + if constexpr (typeST::Options::store_key){ + std::int32_t key = 1; + for (auto filt : st_trans.filtration(f_simplex)) { + key *= filt; + } + std::clog << "key = " << st_trans.key(f_simplex) << " vs " << key << std::endl; + + BOOST_CHECK(st_trans.key(f_simplex) == key); + } else { + std::clog << "No key stored initially: key = " << st_trans.key(f_simplex) << std::endl; + + BOOST_CHECK(st_trans.key(f_simplex) == -1); + } + } +} + template std::vector> get_star(Simplex_tree& st) { std::vector> output; From 1f1309d60e2308858a92aeb435ff12ab0f76d73b Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Mon, 2 Sep 2024 18:36:16 +0200 Subject: [PATCH 50/96] Move import to toplevel --- src/python/gudhi/sklearn/rips_persistence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/gudhi/sklearn/rips_persistence.py b/src/python/gudhi/sklearn/rips_persistence.py index 54bf969611..68f0646e14 100644 --- a/src/python/gudhi/sklearn/rips_persistence.py +++ b/src/python/gudhi/sklearn/rips_persistence.py @@ -9,6 +9,7 @@ from .._ripser import _lower, _full, _sparse, _lower_to_coo, _lower_cone_radius from ..flag_filtration.edge_collapse import reduce_graph +from .. import SimplexTree import math import numpy as np from typing import Union, Iterable, Literal, Optional @@ -143,7 +144,6 @@ def __transform(self, inp): inp = reduce_graph(inp, num_collapses) if use_simplex_tree: - from gudhi import SimplexTree st = SimplexTree() # Use create_from_array in case of full matrix? # (not important since this fallback mostly matters in high dimension, where we use edge-collapse anyway) From aa4410a22a577262408feb1260ce6218ef5be732 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Mon, 2 Sep 2024 18:59:52 +0200 Subject: [PATCH 51/96] comment about boost::multiprecision::uint128_t --- src/common/include/gudhi/uint128.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/common/include/gudhi/uint128.h b/src/common/include/gudhi/uint128.h index 2a9407205c..1907314b96 100644 --- a/src/common/include/gudhi/uint128.h +++ b/src/common/include/gudhi/uint128.h @@ -15,6 +15,16 @@ #include #include +/* What about boost::multiprecision::uint128_t? + * It works on linux, mac, windows, etc. + * On linux x86_64, it has low overhead since it delegates to unsigned __int128. + * It is a bit slower than Fake_uint128, probably because of checks in << and >>, but I only noticed a 10% + * overhead compared to unsigned __int128 on 1 testcase. + * On windows, it is implemented as { size_t; uint64_t[2]; }, that's 50% overhead on storage. On the same + * testcase, forcing linux-gcc to use the windows code led to 4x slowdown. Other testcases were not affected. + * The pathological testcase is computing homology in all dimensions for the vertices of a regular 24-gon. + */ + // GUDHI_FORCE_FAKE_UINT128 is only used for tests #if !defined __SIZEOF_INT128__ || defined GUDHI_FORCE_FAKE_UINT128 namespace Gudhi::numbers { From 3bbd3af834902e79e83b990ae246dc9f1469e2d7 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Tue, 3 Sep 2024 15:56:35 +0200 Subject: [PATCH 52/96] code review: PersistenceLengths to return numpy array. Some doc also --- .../gudhi/representations/vector_methods.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/python/gudhi/representations/vector_methods.py b/src/python/gudhi/representations/vector_methods.py index e9314d18ca..da76acc405 100644 --- a/src/python/gudhi/representations/vector_methods.py +++ b/src/python/gudhi/representations/vector_methods.py @@ -918,7 +918,7 @@ def fit(self, X, y=None): def transform(self, X): """ - Compute the persistence lengths for each persistence diagram individually and concatenate the results. + Compute the persistence lengths for each persistence diagram individually. Parameters: X (list of n x 2 numpy arrays): input persistence diagrams. @@ -926,21 +926,21 @@ def transform(self, X): Returns: numpy array with shape (number of diagrams) x (num_lengths): output persistence lengths. """ - - pers_length_list = [] + pers_length_array = np.zeros((len(X), self.num_lengths)) + idx = 0 for pd in X: pl = pd[:, 1] - pd[:, 0] if len(pl) >= self.num_lengths: - pers_length = np.partition(pl, -self.num_lengths)[-self.num_lengths :] - else: - # Fill with zeros if necessary - pers_length = np.zeros((self.num_lengths)) - pers_length[: len(pl)] = pl + # Select the num_lengths biggest persistence bars length + pl = np.partition(pl, -self.num_lengths)[-self.num_lengths :] # Sort in reverse order persistence lengths (where length = death - birth) - pers_length_list.append(np.flip(np.sort(pers_length))) + pl = np.flip(np.sort(pl)) + # Filled with zeros if not enough values + pers_length_array[idx][:len(pl)] = pl + idx = idx + 1 - return pers_length_list + return pers_length_array def __call__(self, diag): """ From af4175427275a7fc82632d657962b3093c402fba Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Tue, 3 Sep 2024 17:05:24 +0200 Subject: [PATCH 53/96] code review: enumerate instead of for loop + index increment --- src/python/gudhi/representations/vector_methods.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/python/gudhi/representations/vector_methods.py b/src/python/gudhi/representations/vector_methods.py index da76acc405..246e9b803b 100644 --- a/src/python/gudhi/representations/vector_methods.py +++ b/src/python/gudhi/representations/vector_methods.py @@ -927,8 +927,7 @@ def transform(self, X): numpy array with shape (number of diagrams) x (num_lengths): output persistence lengths. """ pers_length_array = np.zeros((len(X), self.num_lengths)) - idx = 0 - for pd in X: + for idx, pd in enumerate(X): pl = pd[:, 1] - pd[:, 0] if len(pl) >= self.num_lengths: # Select the num_lengths biggest persistence bars length @@ -938,7 +937,6 @@ def transform(self, X): pl = np.flip(np.sort(pl)) # Filled with zeros if not enough values pers_length_array[idx][:len(pl)] = pl - idx = idx + 1 return pers_length_array From 009748ca5b3ad81712c33bfcd169239c5a4f0cd5 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Tue, 3 Sep 2024 17:49:23 +0200 Subject: [PATCH 54/96] doc review: no need to be that specific for a fit that does nothing --- src/python/gudhi/representations/vector_methods.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/gudhi/representations/vector_methods.py b/src/python/gudhi/representations/vector_methods.py index 246e9b803b..8790c73e30 100644 --- a/src/python/gudhi/representations/vector_methods.py +++ b/src/python/gudhi/representations/vector_methods.py @@ -912,7 +912,7 @@ def fit(self, X, y=None): Parameters: X (list of n x 2 or n x 1 numpy arrays): input persistence diagrams. - y (n x 1 array): persistence diagram lengths (unused). + y (None): Ignored. """ return self From e984496218c0ee4b463a57e3ca6ceb2ffabe1945 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Tue, 3 Sep 2024 17:51:01 +0200 Subject: [PATCH 55/96] doc review: bad input description for fit --- src/python/gudhi/representations/vector_methods.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/gudhi/representations/vector_methods.py b/src/python/gudhi/representations/vector_methods.py index 8790c73e30..97892c7af8 100644 --- a/src/python/gudhi/representations/vector_methods.py +++ b/src/python/gudhi/representations/vector_methods.py @@ -911,7 +911,7 @@ def fit(self, X, y=None): useful when PersistenceLengths is included in a scikit-learn Pipeline). Parameters: - X (list of n x 2 or n x 1 numpy arrays): input persistence diagrams. + X (list of n x 2 numpy arrays): input persistence diagrams. y (None): Ignored. """ return self From 0dd084c3271b938e4bd8f83dbf833ced1f523690 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 6 Sep 2024 16:16:07 +0200 Subject: [PATCH 56/96] minor fixes --- .../include/gudhi/Multi_critical_filtration.h | 6 ++++-- .../include/gudhi/Multi_persistence/Line.h | 6 +++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Multi_filtration/include/gudhi/Multi_critical_filtration.h b/src/Multi_filtration/include/gudhi/Multi_critical_filtration.h index 8e665b47b7..3ca198a185 100644 --- a/src/Multi_filtration/include/gudhi/Multi_critical_filtration.h +++ b/src/Multi_filtration/include/gudhi/Multi_critical_filtration.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -240,8 +241,9 @@ class Multi_critical_filtration { * and if there is no generator, the method will segfault. */ operator Generator() { - GUDHI_CHECK(num_generators() == 1, "Casting a " + std::to_string(num_generators()) + - "-critical filtration value into an 1-critical filtration value."); + if (num_generators() != 1) + throw std::logic_error("Casting a " + std::to_string(num_generators()) + + "-critical filtration value into an 1-critical filtration value."); return multi_filtration_[0]; } diff --git a/src/Multi_persistence/include/gudhi/Multi_persistence/Line.h b/src/Multi_persistence/include/gudhi/Multi_persistence/Line.h index 702ab958aa..2afdabbbbf 100644 --- a/src/Multi_persistence/include/gudhi/Multi_persistence/Line.h +++ b/src/Multi_persistence/include/gudhi/Multi_persistence/Line.h @@ -82,6 +82,9 @@ class Line { * the number of coordinates. */ Point operator[](T t) const { + GUDHI_CHECK(direction_.empty() || direction_.size() == basePoint_.size(), + "Direction and base point do not have the same dimension."); + Point x(basePoint_.size()); if (direction_.size() > 0) { @@ -227,9 +230,10 @@ class Line { * @param box Box to intersect. * @return A pair representing the two bounding points of the intersection, such that the first element is the * smallest of the two. If the box and the line do not intersect, returns the pair {inf, inf}. + * If the box is trivial, returns {NaN, NaN}. */ std::pair get_bounds(const Box &box) const { - if (box.is_trivial()) return {Point::inf(), Point::inf()}; + if (box.is_trivial()) return {Point::nan(), Point::nan()}; T bottom = compute_forward_intersection(box.get_lower_corner()); T top = compute_backward_intersection(box.get_upper_corner()); From 9e5d652beffc93a2ef2a6fd066c2cc3295e90a3c Mon Sep 17 00:00:00 2001 From: hschreiber Date: Thu, 12 Sep 2024 02:24:02 +0200 Subject: [PATCH 57/96] remove node key constructor from dummy --- src/Simplex_tree/include/gudhi/Simplex_tree.h | 14 +++++--------- .../Simplex_tree_node_explicit_storage.h | 9 ++++++--- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h index d8d500d7dc..7fce37e0fc 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h @@ -141,9 +141,6 @@ class Simplex_tree { }; struct Key_simplex_base_dummy { Key_simplex_base_dummy() {} - Key_simplex_base_dummy(Simplex_key k) { - GUDHI_CHECK(k == -1, "key value specified for a complex that does not store them"); - } // Undefined so it will not link void assign_key(Simplex_key); Simplex_key key() const; @@ -529,12 +526,10 @@ class Simplex_tree { for (auto& p : root_source.members()){ if constexpr (Options::store_key && OtherSimplexTreeOptions::store_key) { auto it = root_.members().try_emplace( - root_.members().end(), - p.first, - Node(&root_, translate_filtration_value(p.second.filtration()), p.second.key())); + root_.members().end(), p.first, &root_, translate_filtration_value(p.second.filtration()), p.second.key()); } else { auto it = root_.members().try_emplace( - root_.members().end(), p.first, Node(&root_, translate_filtration_value(p.second.filtration()))); + root_.members().end(), p.first, &root_, translate_filtration_value(p.second.filtration())); } } @@ -553,15 +548,16 @@ class Simplex_tree { newsib->members_.reserve(sh_source->second.children()->members().size()); } for (auto & child : sh_source->second.children()->members()){ - if constexpr (store_key) + if constexpr (store_key && Options::store_key) { newsib->members_.emplace_hint( newsib->members_.end(), child.first, Node(newsib, translate_filtration_value(child.second.filtration()), child.second.key())); - else + } else { newsib->members_.emplace_hint(newsib->members_.end(), child.first, Node(newsib, translate_filtration_value(child.second.filtration()))); + } } rec_copy(newsib, sh_source->second.children(), translate_filtration_value); sh->second.assign_children(newsib); diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h index 5ca77ea9b5..738f13b817 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h @@ -43,9 +43,12 @@ struct GUDHI_EMPTY_BASE_CLASS_OPTIMIZATION Simplex_tree_node_explicit_storage typedef typename SimplexTree::Simplex_key Simplex_key; typedef typename SimplexTree::Simplex_data Simplex_data; - Simplex_tree_node_explicit_storage(Siblings * sib = nullptr, - Filtration_value filtration = 0, - [[maybe_unused]] Simplex_key key = SimplexTree::null_key()) + Simplex_tree_node_explicit_storage(Siblings* sib = nullptr, Filtration_value filtration = 0) + : SimplexTree::Filtration_simplex_base(filtration), children_(sib) + {} + + //will fail to compile when called with SimplexTree::Options::store_key is false. + Simplex_tree_node_explicit_storage(Siblings* sib, Filtration_value filtration, Simplex_key key) : SimplexTree::Filtration_simplex_base(filtration), SimplexTree::Key_simplex_base(key), children_(sib) {} From d813c89ede6a11e88b3c516eecf0c6a6b36a5c88 Mon Sep 17 00:00:00 2001 From: hschreiber <48448038+hschreiber@users.noreply.github.com> Date: Thu, 12 Sep 2024 23:27:46 +0200 Subject: [PATCH 58/96] Update src/Simplex_tree/include/gudhi/Simplex_tree.h Co-authored-by: Marc Glisse --- src/Simplex_tree/include/gudhi/Simplex_tree.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h index 7fce37e0fc..45a955dd87 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h @@ -165,7 +165,7 @@ class Simplex_tree { }; struct Filtration_simplex_base_dummy { Filtration_simplex_base_dummy() {} - Filtration_simplex_base_dummy(Filtration_value f) { + Filtration_simplex_base_dummy(Filtration_value GUDHI_CHECK_code(f)) { GUDHI_CHECK(f == 0, "filtration value specified for a complex that does not store them"); } void assign_filtration(Filtration_value GUDHI_CHECK_code(f)) { From 7a282a1ed567f52b855b560550ab2dc86cdafb0c Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 13 Sep 2024 21:49:07 +0200 Subject: [PATCH 59/96] reformat test file with black --- .../test/test_sklearn_rips_persistence.py | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/python/test/test_sklearn_rips_persistence.py b/src/python/test/test_sklearn_rips_persistence.py index 8687292b8c..ff06dd9b6b 100644 --- a/src/python/test/test_sklearn_rips_persistence.py +++ b/src/python/test/test_sklearn_rips_persistence.py @@ -37,12 +37,12 @@ def test_h1_only_rips_persistence_of_points_on_a_circle(): rips = RipsPersistence(homology_dimensions=1, n_jobs=-2) diags = rips.fit_transform([points.sphere(n_samples=150, ambient_dim=2)])[0] assert len(diags) == 1 - assert 0. < diags[0][0] < 0.6 - assert 1. < diags[0][1] < 2. + assert 0.0 < diags[0][0] < 0.6 + assert 1.0 < diags[0][1] < 2.0 def test_invalid_input_type(): - rips = RipsPersistence(homology_dimensions=0, input_type='whatsoever') + rips = RipsPersistence(homology_dimensions=0, input_type="whatsoever") with pytest.raises(ValueError): rips.fit_transform([points.sphere(n_samples=10, ambient_dim=2)]) @@ -50,13 +50,14 @@ def test_invalid_input_type(): def test_distance_matrix_rips_persistence_of_points_on_a_circle(): try: from scipy.spatial.distance import cdist + pts = points.sphere(n_samples=150, ambient_dim=2) distance_matrix = cdist(pts, pts) - rips = RipsPersistence(homology_dimensions=1, input_type='lower distance matrix') + rips = RipsPersistence(homology_dimensions=1, input_type="lower distance matrix") diags = rips.fit_transform([distance_matrix])[0] assert len(diags) == 1 - assert 0. < diags[0][0] < 0.6 - assert 1. < diags[0][1] < 2. + assert 0.0 < diags[0][0] < 0.6 + assert 1.0 < diags[0][1] < 2.0 except ValueError: pass @@ -64,13 +65,14 @@ def test_distance_matrix_rips_persistence_of_points_on_a_circle(): def test_set_output(): try: import pandas + NB_PC = 5 point_clouds = [points.sphere(n_samples=random.randint(100, 150), ambient_dim=2) for _ in range(NB_PC)] rips = RipsPersistence(homology_dimensions=[0, 2], n_jobs=-2) diags_pandas = rips.set_output(transform="pandas").fit_transform(point_clouds) - assert 'H0' == diags_pandas.columns[0] - assert 'H2' == diags_pandas.columns[1] + assert "H0" == diags_pandas.columns[0] + assert "H2" == diags_pandas.columns[1] assert len(diags_pandas.index) == NB_PC except ImportError: print("Missing pandas, skipping set_output test") @@ -78,10 +80,10 @@ def test_set_output(): def test_big(): # A circle + many isolated points - n=1000000 - X=np.zeros((n,2)) - X[:,0]=np.arange(n)*100 - X[:24]=points.torus(24,1,'grid') + n = 1000000 + X = np.zeros((n, 2)) + X[:, 0] = np.arange(n) * 100 + X[:24] = points.torus(24, 1, "grid") # Ripser cannot handle it, have to fall back to SimplexTree # Computing the full distance matrix would require too much memory -> kd-tree RipsPersistence(range(25), threshold=10).fit_transform([X]) From 30b194c1449946bf1c722642063ee68e37691f73 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 13 Sep 2024 22:08:52 +0200 Subject: [PATCH 60/96] Import Vincent's test --- .../test/test_sklearn_rips_persistence.py | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/python/test/test_sklearn_rips_persistence.py b/src/python/test/test_sklearn_rips_persistence.py index ff06dd9b6b..74971ac56b 100644 --- a/src/python/test/test_sklearn_rips_persistence.py +++ b/src/python/test/test_sklearn_rips_persistence.py @@ -10,6 +10,11 @@ from gudhi.datasets.generators import points from gudhi.sklearn.rips_persistence import RipsPersistence +from gudhi import RipsComplex, SimplexTree +from gudhi._ripser import _lower, _full, _sparse, _lower_to_coo, _lower_cone_radius +from scipy.sparse import coo_matrix +from scipy.spatial.distance import pdist, squareform +from scipy.spatial import cKDTree import numpy as np import random import pytest @@ -87,3 +92,58 @@ def test_big(): # Ripser cannot handle it, have to fall back to SimplexTree # Computing the full distance matrix would require too much memory -> kd-tree RipsPersistence(range(25), threshold=10).fit_transform([X]) + + +def test_ripser_interfaces(): + primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] + random_prime = primes[random.randint(0, 9)] + print(f"random prime = {random_prime}") + + point_cloud = points.sphere(n_samples=random.randint(100, 150), ambient_dim=2) + print(f"nb points = {len(point_cloud)}") + inp = squareform(pdist(point_cloud)) + + # Check cone radius + assert inp.max(-1).min() < 2.0 + assert _lower_cone_radius(inp) < 2.0 + + ## As there is no easy way to force the use of SimplexTree, let's build it + stree = RipsComplex(distance_matrix=inp).create_simplex_tree(max_dimension=2) + stree.compute_persistence(homology_coeff_field=random_prime, persistence_dim_max=True) + dgm0 = stree.persistence_intervals_in_dimension(0) + dgm1 = stree.persistence_intervals_in_dimension(1) + + dgm = _full(inp, max_dimension=2, max_edge_length=float("inf"), homology_coeff_field=random_prime) + np.testing.assert_almost_equal(dgm0, dgm[0]) + np.testing.assert_almost_equal(dgm1, dgm[1]) + + dgm = _lower(inp, max_dimension=2, max_edge_length=float("inf"), homology_coeff_field=random_prime) + np.testing.assert_almost_equal(dgm0, dgm[0]) + np.testing.assert_almost_equal(dgm1, dgm[1]) + + # From a coo matrix + n = len(point_cloud) + tree = cKDTree(point_cloud) + pairs = tree.query_pairs(r=float("inf"), output_type="ndarray") + data = np.ravel(np.linalg.norm(np.diff(point_cloud[pairs], axis=1), axis=-1)) + inp = coo_matrix((data, (pairs[:, 0], pairs[:, 1])), shape=(n,) * 2) + ## As there is no easy way to force the use of SimplexTree, let's build it + stree = SimplexTree() + stree.insert_batch(np.arange(n).reshape(1, -1), np.zeros(n)) + stree.insert_edges_from_coo_matrix(inp) + stree.expansion(2) + stree.compute_persistence(homology_coeff_field=random_prime, persistence_dim_max=True) + dgm0 = stree.persistence_intervals_in_dimension(0) + dgm1 = stree.persistence_intervals_in_dimension(1) + + dgm = _sparse( + inp.row, + inp.col, + inp.data, + inp.shape[0], + max_dimension=2, + max_edge_length=float("inf"), + homology_coeff_field=random_prime, + ) + np.testing.assert_almost_equal(dgm0, dgm[0]) + np.testing.assert_almost_equal(dgm1, dgm[1]) From e0f413606d508261d57d6d492b67abe3fc6a7c10 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 13 Sep 2024 22:45:42 +0200 Subject: [PATCH 61/96] improve ripser test, fix cone radius --- src/python/gudhi/_ripser.cc | 2 +- .../test/test_sklearn_rips_persistence.py | 61 ++++++++++--------- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/python/gudhi/_ripser.cc b/src/python/gudhi/_ripser.cc index 56e528f248..36e84ae9ec 100644 --- a/src/python/gudhi/_ripser.cc +++ b/src/python/gudhi/_ripser.cc @@ -177,7 +177,7 @@ double lower_cone_radius(py::object low_mat) { if (coli < rowi) throw std::invalid_argument("Not enough elements for a lower triangular matrix"); ++rowi; }; - return *std::max_element(maxs.begin(), maxs.end()); + return *std::min_element(maxs.begin(), maxs.end()); } PYBIND11_MODULE(_ripser, m) { diff --git a/src/python/test/test_sklearn_rips_persistence.py b/src/python/test/test_sklearn_rips_persistence.py index 74971ac56b..8865f0ff01 100644 --- a/src/python/test/test_sklearn_rips_persistence.py +++ b/src/python/test/test_sklearn_rips_persistence.py @@ -13,7 +13,7 @@ from gudhi import RipsComplex, SimplexTree from gudhi._ripser import _lower, _full, _sparse, _lower_to_coo, _lower_cone_radius from scipy.sparse import coo_matrix -from scipy.spatial.distance import pdist, squareform +from scipy.spatial.distance import cdist from scipy.spatial import cKDTree import numpy as np import random @@ -96,54 +96,57 @@ def test_big(): def test_ripser_interfaces(): primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] - random_prime = primes[random.randint(0, 9)] - print(f"random prime = {random_prime}") + field = primes[random.randint(0, 9)] + print(f"random prime = {field}") point_cloud = points.sphere(n_samples=random.randint(100, 150), ambient_dim=2) - print(f"nb points = {len(point_cloud)}") - inp = squareform(pdist(point_cloud)) + # point_cloud = np.random.rand(random.randint(100, 150), random.randint(2, 3)) + print(f"nb points = {len(point_cloud)}, dim = {point_cloud.shape[1]}") + dists = cdist(point_cloud, point_cloud) # Check cone radius - assert inp.max(-1).min() < 2.0 - assert _lower_cone_radius(inp) < 2.0 + cr = dists.max(-1).min() + assert cr == _lower_cone_radius(dists) + assert cr < 2.0 ## As there is no easy way to force the use of SimplexTree, let's build it - stree = RipsComplex(distance_matrix=inp).create_simplex_tree(max_dimension=2) - stree.compute_persistence(homology_coeff_field=random_prime, persistence_dim_max=True) + stree = RipsComplex(distance_matrix=dists).create_simplex_tree(max_dimension=2) + stree.compute_persistence(homology_coeff_field=field, persistence_dim_max=True) dgm0 = stree.persistence_intervals_in_dimension(0) dgm1 = stree.persistence_intervals_in_dimension(1) - dgm = _full(inp, max_dimension=2, max_edge_length=float("inf"), homology_coeff_field=random_prime) + dgm = _full(dists, max_dimension=1, max_edge_length=float("inf"), homology_coeff_field=field) np.testing.assert_almost_equal(dgm0, dgm[0]) np.testing.assert_almost_equal(dgm1, dgm[1]) - dgm = _lower(inp, max_dimension=2, max_edge_length=float("inf"), homology_coeff_field=random_prime) + dgm = _lower(dists, max_dimension=1, max_edge_length=float("inf"), homology_coeff_field=field) np.testing.assert_almost_equal(dgm0, dgm[0]) np.testing.assert_almost_equal(dgm1, dgm[1]) # From a coo matrix n = len(point_cloud) - tree = cKDTree(point_cloud) - pairs = tree.query_pairs(r=float("inf"), output_type="ndarray") - data = np.ravel(np.linalg.norm(np.diff(point_cloud[pairs], axis=1), axis=-1)) - inp = coo_matrix((data, (pairs[:, 0], pairs[:, 1])), shape=(n,) * 2) + dists_copy = np.array(dists, copy=True) + dists_copy[np.triu_indices_from(dists_copy)] = 0 # Keep only the lower entries + dists_sparse = coo_matrix(dists_copy) ## As there is no easy way to force the use of SimplexTree, let's build it stree = SimplexTree() stree.insert_batch(np.arange(n).reshape(1, -1), np.zeros(n)) - stree.insert_edges_from_coo_matrix(inp) + stree.insert_edges_from_coo_matrix(dists_sparse) stree.expansion(2) - stree.compute_persistence(homology_coeff_field=random_prime, persistence_dim_max=True) - dgm0 = stree.persistence_intervals_in_dimension(0) - dgm1 = stree.persistence_intervals_in_dimension(1) - - dgm = _sparse( - inp.row, - inp.col, - inp.data, - inp.shape[0], - max_dimension=2, + stree.compute_persistence(homology_coeff_field=field, persistence_dim_max=True) + sp_dgm0 = stree.persistence_intervals_in_dimension(0) + sp_dgm1 = stree.persistence_intervals_in_dimension(1) + + sp_dgm = _sparse( + dists_sparse.row, + dists_sparse.col, + dists_sparse.data, + dists_sparse.shape[0], + max_dimension=1, max_edge_length=float("inf"), - homology_coeff_field=random_prime, + homology_coeff_field=field, ) - np.testing.assert_almost_equal(dgm0, dgm[0]) - np.testing.assert_almost_equal(dgm1, dgm[1]) + np.testing.assert_almost_equal(sp_dgm0, sp_dgm[0]) + np.testing.assert_almost_equal(sp_dgm1, sp_dgm[1]) + np.testing.assert_almost_equal(sp_dgm0, dgm0) + np.testing.assert_almost_equal(sp_dgm1, dgm1) From 896ba1042068951b489ca0bd81bae91f8862e3b3 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 13 Sep 2024 23:32:47 +0200 Subject: [PATCH 62/96] More tweaks to ripser test --- .../test/test_sklearn_rips_persistence.py | 46 ++++++++++++------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/src/python/test/test_sklearn_rips_persistence.py b/src/python/test/test_sklearn_rips_persistence.py index 8865f0ff01..928c82c313 100644 --- a/src/python/test/test_sklearn_rips_persistence.py +++ b/src/python/test/test_sklearn_rips_persistence.py @@ -12,9 +12,9 @@ from gudhi.sklearn.rips_persistence import RipsPersistence from gudhi import RipsComplex, SimplexTree from gudhi._ripser import _lower, _full, _sparse, _lower_to_coo, _lower_cone_radius +from gudhi import bottleneck_distance from scipy.sparse import coo_matrix from scipy.spatial.distance import cdist -from scipy.spatial import cKDTree import numpy as np import random import pytest @@ -94,13 +94,11 @@ def test_big(): RipsPersistence(range(25), threshold=10).fit_transform([X]) -def test_ripser_interfaces(): - primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] - field = primes[random.randint(0, 9)] +def cmp_rips(point_cloud): + primes = [2, 3, 11, 17, 29] # Small list so 2 is often selected + field = random.choice(primes) print(f"random prime = {field}") - point_cloud = points.sphere(n_samples=random.randint(100, 150), ambient_dim=2) - # point_cloud = np.random.rand(random.randint(100, 150), random.randint(2, 3)) print(f"nb points = {len(point_cloud)}, dim = {point_cloud.shape[1]}") dists = cdist(point_cloud, point_cloud) @@ -109,26 +107,34 @@ def test_ripser_interfaces(): assert cr == _lower_cone_radius(dists) assert cr < 2.0 - ## As there is no easy way to force the use of SimplexTree, let's build it + ## Compute with the SimplexTree stree = RipsComplex(distance_matrix=dists).create_simplex_tree(max_dimension=2) stree.compute_persistence(homology_coeff_field=field, persistence_dim_max=True) dgm0 = stree.persistence_intervals_in_dimension(0) dgm1 = stree.persistence_intervals_in_dimension(1) + # Compute with Ripser dgm = _full(dists, max_dimension=1, max_edge_length=float("inf"), homology_coeff_field=field) - np.testing.assert_almost_equal(dgm0, dgm[0]) - np.testing.assert_almost_equal(dgm1, dgm[1]) + # The order of the intervals may differ, so we cannot compare the arrays with np.testing.assert_almost_equal + assert bottleneck_distance(dgm0, dgm[0]) < 1e-8 + assert bottleneck_distance(dgm1, dgm[1]) < 1e-8 dgm = _lower(dists, max_dimension=1, max_edge_length=float("inf"), homology_coeff_field=field) - np.testing.assert_almost_equal(dgm0, dgm[0]) - np.testing.assert_almost_equal(dgm1, dgm[1]) + assert bottleneck_distance(dgm0, dgm[0]) < 1e-8 + assert bottleneck_distance(dgm1, dgm[1]) < 1e-8 - # From a coo matrix + # Convert to coo matrix n = len(point_cloud) dists_copy = np.array(dists, copy=True) dists_copy[np.triu_indices_from(dists_copy)] = 0 # Keep only the lower entries dists_sparse = coo_matrix(dists_copy) - ## As there is no easy way to force the use of SimplexTree, let's build it + s1 = _lower_to_coo(dists, float("inf")) + s2 = _lower_to_coo(dists_copy, float("inf")) + s1 = coo_matrix((s1[2], (s1[0], s1[1])), shape=(n, n)) + s2 = coo_matrix((s2[2], (s2[0], s2[1])), shape=(n, n)) + assert np.array_equal(s1.toarray(), s2.toarray()) + assert np.array_equal(dists_sparse.toarray(), s1.toarray()) + ## Compute with the SimplexTree stree = SimplexTree() stree.insert_batch(np.arange(n).reshape(1, -1), np.zeros(n)) stree.insert_edges_from_coo_matrix(dists_sparse) @@ -137,6 +143,7 @@ def test_ripser_interfaces(): sp_dgm0 = stree.persistence_intervals_in_dimension(0) sp_dgm1 = stree.persistence_intervals_in_dimension(1) + # Compute with Ripser sp_dgm = _sparse( dists_sparse.row, dists_sparse.col, @@ -146,7 +153,12 @@ def test_ripser_interfaces(): max_edge_length=float("inf"), homology_coeff_field=field, ) - np.testing.assert_almost_equal(sp_dgm0, sp_dgm[0]) - np.testing.assert_almost_equal(sp_dgm1, sp_dgm[1]) - np.testing.assert_almost_equal(sp_dgm0, dgm0) - np.testing.assert_almost_equal(sp_dgm1, dgm1) + assert bottleneck_distance(sp_dgm0, sp_dgm[0]) < 1e-8 + assert bottleneck_distance(sp_dgm1, sp_dgm[1]) < 1e-8 + assert bottleneck_distance(sp_dgm0, dgm0) < 1e-8 + assert bottleneck_distance(sp_dgm1, dgm1) < 1e-8 + + +def test_ripser_interfaces(): + cmp_rips(points.sphere(n_samples=random.randint(100, 150), ambient_dim=2)) + cmp_rips(np.random.rand(random.randint(100, 150), random.randint(2, 3))) From ff3750f115c0588d9e3b923827476a0c40e5833c Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Tue, 17 Sep 2024 16:43:56 +0200 Subject: [PATCH 63/96] Symbolic links for cython and pybind11 compilation --- .../new_gudhi_version_creation.md | 4 ++-- .github/workflows/pip-packaging-linux.yml | 5 ----- .gitignore | 3 --- src/python/CMakeLists.txt | 22 ++++++++++++++++--- src/python/setup.py.in | 2 +- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/.github/for_maintainers/new_gudhi_version_creation.md b/.github/for_maintainers/new_gudhi_version_creation.md index 1bb6382bba..d094615bdd 100644 --- a/.github/for_maintainers/new_gudhi_version_creation.md +++ b/.github/for_maintainers/new_gudhi_version_creation.md @@ -25,7 +25,7 @@ nor [unlabelled closed PRs](https://github.com/GUDHI/gudhi-devel/pulls?q=is%3Apr **Edit the file CMakeGUDHIVersion.txt**, and increment major, minor, or patch version number, in function of the version new delivery. ```bash # cf. .gitignore - ignore this if it is a fresh clone version -rm -rf 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 src/python/test/__pycache__ src/python/gudhi/*.cpp +rm -rf 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 src/python/test/__pycache__ ``` Checkin the modifications, build and test the version: @@ -154,4 +154,4 @@ Send version mail to the following lists : **Edit the file CMakeGUDHIVersion.txt**, and increment major, minor, or patch version number, in function of the future version (something like `3.X+1.0a0`). -Reset [.github/next_release.md](.github/next_release.md) with [.github/for_maintainers/next_release_template.md](.github/for_maintainers/next_release_template.md). \ No newline at end of file +Reset [.github/next_release.md](.github/next_release.md) with [.github/for_maintainers/next_release_template.md](.github/for_maintainers/next_release_template.md). diff --git a/.github/workflows/pip-packaging-linux.yml b/.github/workflows/pip-packaging-linux.yml index bec8e4a62b..f93d4fbf85 100644 --- a/.github/workflows/pip-packaging-linux.yml +++ b/.github/workflows/pip-packaging-linux.yml @@ -19,7 +19,6 @@ jobs: # numpy~=1.21.4 means any numpy=1.21.*, but also numpy>=1.21.4 (numpy~=1.21 do not work as it means any numpy==1.*) - name: Build wheel for Python 3.8 run: | - rm -rf src/python/gudhi/*.cpp mkdir build_38 cd build_38 cmake -DCMAKE_BUILD_TYPE=Release -DPython_EXECUTABLE=$PYTHON38/bin/python .. @@ -38,7 +37,6 @@ jobs: $PYTHON38/bin/python -m pytest -v src/python/test/test_rips_complex.py - name: Build wheel for Python 3.9 run: | - rm -rf src/python/gudhi/*.cpp mkdir build_39 cd build_39 cmake -DCMAKE_BUILD_TYPE=Release -DPython_EXECUTABLE=$PYTHON39/bin/python .. @@ -61,7 +59,6 @@ jobs: $PYTHON39/bin/python -m pytest -v src/python/test/test_rips_complex.py - name: Build wheel for Python 3.10 run: | - rm -rf src/python/gudhi/*.cpp mkdir build_310 cd build_310 cmake -DCMAKE_BUILD_TYPE=Release -DPython_EXECUTABLE=$PYTHON310/bin/python .. @@ -80,7 +77,6 @@ jobs: $PYTHON310/bin/python -m pytest -v src/python/test/test_rips_complex.py - name: Build wheel for Python 3.11 run: | - rm -rf src/python/gudhi/*.cpp mkdir build_311 cd build_311 cmake -DCMAKE_BUILD_TYPE=Release -DPython_EXECUTABLE=$PYTHON311/bin/python .. @@ -99,7 +95,6 @@ jobs: $PYTHON311/bin/python -m pytest -v src/python/test/test_rips_complex.py - name: Build wheel for Python 3.12 run: | - rm -rf src/python/gudhi/*.cpp mkdir build_312 cd build_312 cmake -DCMAKE_BUILD_TYPE=Release -DPython_EXECUTABLE=$PYTHON312/bin/python .. diff --git a/.gitignore b/.gitignore index 14e4a62e89..bcf839cb8b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,6 @@ # Classical CMake build directory /*build* -# Generated by Cython -src/python/gudhi/*.cpp - # Generated by tests data/points/COIL_database/lucky_cat.off_dist data/points/COIL_database/lucky_cat.off_sc.dot diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index c60f7b9460..273a4c6c2b 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -56,6 +56,14 @@ function( add_gudhi_py_test THE_TEST ) endif() endfunction( add_gudhi_py_test ) +function( add_gudhi_symbolic_links GLOBBING_EXPRESSION ) + file(GLOB GUDHI_GLOB_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${GLOBBING_EXPRESSION}) + foreach(GUDHI_GLOB_FILENAME ${GUDHI_GLOB_FILES}) + message("link ${CMAKE_CURRENT_SOURCE_DIR}/${GUDHI_GLOB_FILENAME} to ${CMAKE_CURRENT_BINARY_DIR}/${GUDHI_GLOB_FILENAME}") + file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/${GUDHI_GLOB_FILENAME}" "${CMAKE_CURRENT_BINARY_DIR}/${GUDHI_GLOB_FILENAME}" SYMBOLIC) + endforeach() +endfunction( add_gudhi_symbolic_links ) + # Set gudhi.__debug_info__ # WARNING : to be done before setup.py.in configure_file function( add_gudhi_debug_info DEBUG_INFO ) @@ -382,6 +390,14 @@ file(COPY "gudhi/flag_filtration" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/gudhi # Some files for pip package file(COPY "pyproject.toml" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/") +# Symbolic links to cython and Pybind11 sources to be built. "MAKE_DIRECTORY gudhi" must be done before +add_gudhi_symbolic_links("gudhi/*.pxd") +add_gudhi_symbolic_links("gudhi/*.pyx") +add_gudhi_symbolic_links("gudhi/*.cc") +add_gudhi_symbolic_links("gudhi/clustering/_tomato.cc") +add_gudhi_symbolic_links("gudhi/hera/*.cc") +add_gudhi_symbolic_links("gudhi/datasets/generators/_points.cc") + add_custom_command( OUTPUT gudhi.so WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} @@ -438,7 +454,7 @@ add_test(NAME random_cubical_complex_persistence_example_py_test add_gudhi_py_test(test_cubical_complex) -# Datasets are fetched for these tests +# Datasets are fetched for these tests if(SKLEARN_FOUND AND WITH_GUDHI_REMOTE_TEST) add_gudhi_py_test(test_sklearn_cubical_persistence) @@ -574,7 +590,7 @@ if(SKLEARN_FOUND) add_gudhi_py_test(test_sklearn_rips_persistence) endif() - # Datasets are fetched for these tests + # Datasets are fetched for these tests if(WITH_GUDHI_REMOTE_TEST) add_test(NAME rips_complex_sklearn_itf_py_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} @@ -690,4 +706,4 @@ if(MATPLOTLIB_FOUND) endif() # Set missing or not modules -set(GUDHI_MODULES ${GUDHI_MODULES} "python" CACHE INTERNAL "GUDHI_MODULES") \ No newline at end of file +set(GUDHI_MODULES ${GUDHI_MODULES} "python" CACHE INTERNAL "GUDHI_MODULES") diff --git a/src/python/setup.py.in b/src/python/setup.py.in index 0746536e12..3bc8d0805e 100644 --- a/src/python/setup.py.in +++ b/src/python/setup.py.in @@ -17,7 +17,7 @@ import pybind11 cython_modules = [@GUDHI_CYTHON_MODULES@] pybind11_modules = [@GUDHI_PYBIND11_MODULES@] -source_dir='@CMAKE_CURRENT_SOURCE_DIR@/gudhi/' +source_dir='gudhi/' extra_compile_args=[@GUDHI_PYTHON_EXTRA_COMPILE_ARGS@] extra_link_args=[@GUDHI_PYTHON_EXTRA_LINK_ARGS@] libraries=[@GUDHI_PYTHON_LIBRARIES@] From 4f40d8bf25c61798d53ae213d90b4d3aa76cd211 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Tue, 17 Sep 2024 17:42:08 +0200 Subject: [PATCH 64/96] upstream merge --- src/Zigzag_persistence/include/gudhi/zigzag_persistence.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h index 7485424a81..7d6d20c6d8 100644 --- a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h @@ -33,7 +33,7 @@ #include #endif -#include +#include namespace Gudhi { namespace zigzag_persistence { @@ -163,7 +163,7 @@ class Zigzag_persistence #endif using Matrix_options = Zigzag_matrix_options; /**< Matrix options. */ using Matrix_type = Gudhi::persistence_matrix::Matrix; /**< Matrix. */ - using matrix_index = typename Matrix_type::index; /**< Matrix indexation type. */ + using matrix_index = typename Matrix_type::Index; /**< Matrix indexation type. */ /** \brief Maintains the birth ordering \f$\leq_b\f$. * From 6a0fad29a151774ebb4e91ac88784867a8669525 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Tue, 17 Sep 2024 18:04:21 +0200 Subject: [PATCH 65/96] renaming after Gudhi convention --- .../concept/ZigzagOptions.h | 12 +- ...mple_usage_filtered_zigzag_persistence.cpp | 8 +- .../example_usage_zigzag_persistence.cpp | 8 +- ...xample_zigzag_filtration_as_input_loop.cpp | 12 +- .../example_zzfiltration_from_file.cpp | 16 +-- .../gudhi/filtered_zigzag_persistence.h | 114 +++++++++--------- .../include/gudhi/zigzag_persistence.h | 88 +++++++------- .../test/test_filtered_zigzag_persistence.cpp | 56 ++++----- .../test/test_zigzag_persistence.cpp | 16 +-- 9 files changed, 165 insertions(+), 165 deletions(-) diff --git a/src/Zigzag_persistence/concept/ZigzagOptions.h b/src/Zigzag_persistence/concept/ZigzagOptions.h index cc83a8285e..79ee25995a 100644 --- a/src/Zigzag_persistence/concept/ZigzagOptions.h +++ b/src/Zigzag_persistence/concept/ZigzagOptions.h @@ -28,23 +28,23 @@ struct FilteredZigzagOptions { /** * @brief Numerical type for the face IDs used internally and other indexations. It must be signed. */ - using internal_key = unspecified; + using Internal_key = unspecified; /** * @brief Type for the face IDs used at insertion and in the boundaries given as argument. * Has to be usable as key in a hashtable, so "hashable" and comparable. */ - using face_key = unspecified; + using Face_key = unspecified; /** * @brief Type for filtration values. */ - using filtration_value = unspecified; + using Filtration_value = unspecified; /** * @brief Type for the dimension values. */ - using dimension_type = unspecified; + using Dimension = unspecified; /** * @brief Column type used by the internal matrix. @@ -61,12 +61,12 @@ struct ZigzagOptions { /** * @brief Numerical type for the face IDs used internally and other indexations. It must be signed. */ - using internal_key = unspecified; + using Internal_key = unspecified; /** * @brief Type for the dimension values. */ - using dimension_type = unspecified; + using Dimension = unspecified; /** * @brief Column type used by the internal matrix. diff --git a/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp b/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp index e15d8e8c08..50bc50f894 100644 --- a/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp +++ b/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp @@ -13,14 +13,14 @@ #include using Zigzag_persistence = Gudhi::zigzag_persistence::Filtered_zigzag_persistence<>; -using dimension_type = Zigzag_persistence::dimension_type; -using filtration_value_type = Zigzag_persistence::filtration_value; +using Dimension = Zigzag_persistence::Dimension; +using Filtration_value = Zigzag_persistence::Filtration_value; int main() { std::clog << "********* Minimalistic example of usage of the Filtered_zigzag_persistence class ********" << std::endl; // Filtered_zigzag_persistence(callback) with for example callback method as a anonymous lambda - Zigzag_persistence zp([](dimension_type dim, filtration_value_type birth, filtration_value_type death) { + Zigzag_persistence zp([](Dimension dim, Filtration_value birth, Filtration_value death) { std::cout << "[" << dim << "] " << birth << " - " << death << std::endl; }); @@ -49,7 +49,7 @@ int main() { // Only the closed bars where output so far, so the open/infinite bars still need to be retrieved. // in this example, computes (0, 0.1) and (0, 2.0) - zp.get_current_infinite_intervals([](dimension_type dim, filtration_value_type birth) { + zp.get_current_infinite_intervals([](Dimension dim, Filtration_value birth) { std::cout << "[" << dim << "] " << birth << " - inf" << std::endl; }); diff --git a/src/Zigzag_persistence/example/example_usage_zigzag_persistence.cpp b/src/Zigzag_persistence/example/example_usage_zigzag_persistence.cpp index 26946e1ece..e987b90ef4 100644 --- a/src/Zigzag_persistence/example/example_usage_zigzag_persistence.cpp +++ b/src/Zigzag_persistence/example/example_usage_zigzag_persistence.cpp @@ -13,14 +13,14 @@ #include using Zigzag_persistence = Gudhi::zigzag_persistence::Zigzag_persistence<>; -using dimension_type = Zigzag_persistence::dimension_type; -using index_type = Zigzag_persistence::index; +using Dimension = Zigzag_persistence::Dimension; +using Index = Zigzag_persistence::Index; int main() { std::clog << "************* Minimalistic example of usage of the Zigzag_persistence class *************" << std::endl; // Zigzag_persistence(callback) with for example callback method as a anonymous lambda - Zigzag_persistence zp([](dimension_type dim, index_type birth, index_type death) { + Zigzag_persistence zp([](Dimension dim, Index birth, Index death) { std::cout << "[" << dim << "] " << birth << " - " << death << std::endl; }); @@ -49,7 +49,7 @@ int main() { // in this example, computes (0, 0) and (0, 7) zp.get_current_infinite_intervals( - [](dimension_type dim, index_type birth) { std::cout << "[" << dim << "] " << birth << " - inf" << std::endl; }); + [](Dimension dim, Index birth) { std::cout << "[" << dim << "] " << birth << " - inf" << std::endl; }); return 0; } diff --git a/src/Zigzag_persistence/example/example_zigzag_filtration_as_input_loop.cpp b/src/Zigzag_persistence/example/example_zigzag_filtration_as_input_loop.cpp index 17dcdb816f..046e599b88 100644 --- a/src/Zigzag_persistence/example/example_zigzag_filtration_as_input_loop.cpp +++ b/src/Zigzag_persistence/example/example_zigzag_filtration_as_input_loop.cpp @@ -14,8 +14,8 @@ #include using ZP = Gudhi::zigzag_persistence::Filtered_zigzag_persistence_with_storage<>; -using face_handle = ZP::face_key; -using filtration_value = ZP::filtration_value; +using Face_handle = ZP::Face_key; +using Filtration_value = ZP::Filtration_value; using Interval_filtration = ZP::Filtration_value_interval; void print_barcode(ZP& zp) { @@ -50,7 +50,7 @@ void print_indices(ZP& zp) { } } -std::vector > get_boundaries() { +std::vector > get_boundaries() { return {{}, {}, {}, @@ -82,7 +82,7 @@ std::vector > get_boundaries() { {27}}; // remove } -std::vector get_filtration_values() { +std::vector get_filtration_values() { return {0, 0, 0, 1, 1, 1, 2, 2, 2, @@ -114,8 +114,8 @@ int main(int argc, char* const argv[]) { ZP zp; - std::vector > simplices = get_boundaries(); - std::vector fils = get_filtration_values(); + std::vector > simplices = get_boundaries(); + std::vector fils = get_filtration_values(); std::vector dirs = get_directions(); for (unsigned int i = 0; i < simplices.size(); ++i) { diff --git a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp index 5f85f2a900..333194be6f 100644 --- a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp +++ b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp @@ -16,16 +16,16 @@ #include using ZP = Gudhi::zigzag_persistence::Filtered_zigzag_persistence<>; -using id_handle = ZP::face_key; -using filtration_value = ZP::filtration_value; -using dimension_type = ZP::dimension_type; +using ID_handle = ZP::Face_key; +using Filtration_value = ZP::Filtration_value; +using Dimension = ZP::Dimension; enum lineType : int { INCLUSION, REMOVAL, COMMENT }; -lineType read_operation(std::string& line, std::vector& faces, double& timestamp) { +lineType read_operation(std::string& line, std::vector& faces, double& timestamp) { lineType type; faces.clear(); - id_handle num; + ID_handle num; size_t current = line.find_first_not_of(' ', 0); if (current == std::string::npos) return COMMENT; @@ -74,14 +74,14 @@ int main(int argc, char* const argv[]) { std::ifstream file(argv[1]); //std::cout could be replaced by any other output stream - ZP zp([](dimension_type dim, filtration_value birth, filtration_value death) { + ZP zp([](Dimension dim, Filtration_value birth, Filtration_value death) { std::cout << "[" << dim << "] "; std::cout << birth << " - " << death; std::cout << std::endl; }); if (file.is_open()) { - std::vector data; + std::vector data; unsigned int id = 0; double timestamp; lineType type; @@ -115,7 +115,7 @@ int main(int argc, char* const argv[]) { //retrieve infinite bars remaining at the end //again std::cout could be replaced by any other output stream - zp.get_current_infinite_intervals([](dimension_type dim, filtration_value birth) { + zp.get_current_infinite_intervals([](Dimension dim, Filtration_value birth) { std::cout << "[" << dim << "] "; std::cout << birth << " - inf"; std::cout << std::endl; diff --git a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h index f820ae1f3b..dabaf31cf5 100644 --- a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h @@ -42,10 +42,10 @@ namespace zigzag_persistence { * @brief Default options for @ref Filtered_zigzag_persistence_with_storage and @ref Filtered_zigzag_persistence. */ struct Default_filtered_zigzag_options { - using internal_key = int; /**< Face ID used internally, must be signed. */ - using face_key = int; /**< Face ID used in the given boundaries. */ - using filtration_value = double; /**< Filtration value type. */ - using dimension_type = int; /**< Dimension value type. */ + using Internal_key = int; /**< Face ID used internally, must be signed. */ + using Face_key = int; /**< Face ID used in the given boundaries. */ + using Filtration_value = double; /**< Filtration value type. */ + using Dimension = int; /**< Dimension value type. */ /** * @brief Column type use by the internal matrix. */ @@ -129,19 +129,19 @@ class Filtered_zigzag_persistence_with_storage { public: using Options = FilteredZigzagOptions; /**< Zigzag options. */ - using internal_key = typename Options::internal_key; /**< Key and index type, has to be signed. */ - using face_key = typename Options::face_key; /**< Face ID type from external inputs. */ - using filtration_value = typename Options::filtration_value; /**< Type for filtration values. */ - using dimension_type = typename Options::dimension_type; /**< Type for dimension values. */ + using Internal_key = typename Options::Internal_key; /**< Key and index type, has to be signed. */ + using Face_key = typename Options::Face_key; /**< Face ID type from external inputs. */ + using Filtration_value = typename Options::Filtration_value; /**< Type for filtration values. */ + using Dimension = typename Options::Dimension; /**< Type for dimension values. */ /** * @brief Persistence index interval type. */ - using Index_interval = Gudhi::persistence_matrix::Persistence_interval; + using Index_interval = Gudhi::persistence_matrix::Persistence_interval; /** * @brief Persistence filtration interval type. */ - using Filtration_value_interval = Gudhi::persistence_matrix::Persistence_interval; + using Filtration_value_interval = Gudhi::persistence_matrix::Persistence_interval; /** * @brief Constructor. @@ -161,9 +161,9 @@ class Filtered_zigzag_persistence_with_storage : dimMax_(ignoreCyclesAboveDim), persistenceDiagram_(), numArrow_(-1), - previousFiltrationValue_(std::numeric_limits::infinity()), + previousFiltrationValue_(std::numeric_limits::infinity()), pers_( - [&](dimension_type dim, internal_key birth, internal_key death) { + [&](Dimension dim, Internal_key birth, Internal_key death) { if (dimMax_ == -1 || (dimMax_ != -1 && dim < dimMax_)) { // don't record intervals over max dim persistenceDiagram_.emplace_back(birth, death, dim); } @@ -184,11 +184,11 @@ class Filtered_zigzag_persistence_with_storage * values, ie. the changes are monotonous. * @return Number of the operation. */ - template > - internal_key insert_face(face_key faceID, + template > + Internal_key insert_face(Face_key faceID, const BoundaryRange& boundary, - dimension_type dimension, - filtration_value filtrationValue) + Dimension dimension, + Filtration_value filtrationValue) { if (dimMax_ != -1 && dimension > dimMax_) { return apply_identity(); @@ -203,7 +203,7 @@ class Filtered_zigzag_persistence_with_storage GUDHI_CHECK(res.second, "Zigzag_persistence::insert_face - face already in the complex"); // Compute the keys of the faces of the boundary. - std::set translatedBoundary; // set maintains the natural order on indices + std::set translatedBoundary; // set maintains the natural order on indices for (auto b : boundary) { translatedBoundary.insert(handleToKey_.at(b)); // TODO: add possibilities of coefficients } @@ -224,7 +224,7 @@ class Filtered_zigzag_persistence_with_storage * values, ie. the changes are monotonous. * @return Number of the operation. */ - internal_key remove_face(face_key faceID, filtration_value filtrationValue) { + Internal_key remove_face(Face_key faceID, Filtration_value filtrationValue) { auto it = handleToKey_.find(faceID); if (it == handleToKey_.end()) { @@ -247,7 +247,7 @@ class Filtered_zigzag_persistence_with_storage * to avoid useless computation. * @return Number of the operation. */ - internal_key apply_identity() { + Internal_key apply_identity() { ++numArrow_; pers_.apply_identity(); return numArrow_; @@ -267,15 +267,15 @@ class Filtered_zigzag_persistence_with_storage * by @ref get_index_persistence_diagram. * * @param idx Birth or death index - * @return filtration_value Filtration value associated to @p idx. + * @return Filtration_value Filtration value associated to @p idx. */ - filtration_value get_filtration_value_from_index(internal_key idx) { + Filtration_value get_filtration_value_from_index(Internal_key idx) { // lower_bound(x) returns leftmost y s.t. x <= y auto itBirth = std::lower_bound(filtrationValues_.begin(), filtrationValues_.end(), idx, - [](std::pair p, internal_key k) { return p.first < k; }); + [](std::pair p, Internal_key k) { return p.first < k; }); if (itBirth == filtrationValues_.end() || itBirth->first > idx) { --itBirth; } @@ -289,7 +289,7 @@ class Filtered_zigzag_persistence_with_storage * @param includeInfiniteBars If set to true, infinite bars are included in the diagram. Default value: true. * @return A vector of pairs of filtration values representing the persistence diagram. */ - std::vector get_persistence_diagram(filtration_value shortestInterval = 0., + std::vector get_persistence_diagram(Filtration_value shortestInterval = 0., bool includeInfiniteBars = true) { std::vector diag = _get_persistence_diagram(shortestInterval); @@ -301,17 +301,17 @@ class Filtered_zigzag_persistence_with_storage } private: - std::unordered_map handleToKey_; /**< Map from input keys to internal keys. */ - dimension_type dimMax_; /**< Maximal dimension of a bar to record. */ + std::unordered_map handleToKey_; /**< Map from input keys to internal keys. */ + Dimension dimMax_; /**< Maximal dimension of a bar to record. */ std::vector persistenceDiagram_; /**< Stores current closed persistence intervals. */ - internal_key numArrow_; /**< Current arrow number. */ - filtration_value previousFiltrationValue_; /**< Filtration value of the previous arrow. */ + Internal_key numArrow_; /**< Current arrow number. */ + Filtration_value previousFiltrationValue_; /**< Filtration value of the previous arrow. */ /** * @brief filtrationValues_ stores consecutive pairs (i,f) , (j,f') with f != f', * meaning that all inserted faces with key in [i;j-1] have filtration value f, * i is the smallest face index whose face has filtration value f. */ - std::vector > filtrationValues_; + std::vector > filtrationValues_; Zigzag_persistence pers_; /**< Class computing the pairs. */ /** @@ -320,7 +320,7 @@ class Filtered_zigzag_persistence_with_storage * * @param filtrationValue Filtration value to store. */ - void _store_filtration_value(filtration_value filtrationValue) { + void _store_filtration_value(Filtration_value filtrationValue) { if (filtrationValue != previousFiltrationValue_) // check whether the filt value has changed { // consecutive pairs (i,f), (j,f') mean faces of index k in [i,j-1] have filtration value f @@ -335,18 +335,18 @@ class Filtered_zigzag_persistence_with_storage * @param shortestInterval Intervals shorter than the given value are ignored. * @return Vector of intervals. */ - std::vector _get_persistence_diagram(filtration_value shortestInterval) { + std::vector _get_persistence_diagram(Filtration_value shortestInterval) { std::vector diag; diag.reserve(persistenceDiagram_.size()); // std::stable_sort(filtrationValues_.begin(), filtrationValues_.end(), - // [](std::pair p1, std::pair p2) { + // [](std::pair p1, std::pair p2) { // return p1.first < p2.first; // }); for (auto bar : persistenceDiagram_) { - filtration_value birth = get_filtration_value_from_index(bar.birth); - filtration_value death = get_filtration_value_from_index(bar.death); + Filtration_value birth = get_filtration_value_from_index(bar.birth); + Filtration_value death = get_filtration_value_from_index(bar.death); if (birth > death) { std::swap(birth, death); } @@ -365,7 +365,7 @@ class Filtered_zigzag_persistence_with_storage * @param diag Reference to vector where to store the infinite bars. */ void _retrieve_infinite_bars(std::vector& diag) { - auto stream_infinite_interval = [&](dimension_type dim, internal_key birthIndex) { + auto stream_infinite_interval = [&](Dimension dim, Internal_key birthIndex) { if (dimMax_ == -1 || (dimMax_ != -1 && dim < dimMax_)) diag.emplace_back(get_filtration_value_from_index(birthIndex), Filtration_value_interval::inf, dim); }; @@ -393,14 +393,14 @@ class Filtered_zigzag_persistence_with_storage * #### Useful aliases * ``` * using Filtered_zigzag_persistence = Gudhi::zigzag_persistence::Filtered_zigzag_persistence<>; - * using dimension_type = Filtered_zigzag_persistence::dimension_type; - * using filtration_value_type = Filtered_zigzag_persistence::filtration_value; + * using Dimension = Filtered_zigzag_persistence::Dimension; + * using filtration_value_type = Filtered_zigzag_persistence::Filtration_value; * ``` * * #### Construction with default values * ``` * //Filtered_zigzag_persistence(callback) with for example callback method as a anonymous lambda - * Filtered_zigzag_persistence zp([](dimension_type dim, filtration_value_type birth, filtration_value_type death) { + * Filtered_zigzag_persistence zp([](Dimension dim, filtration_value_type birth, filtration_value_type death) { * std::cout << "[" << dim << "] " << birth << " - " << death << std::endl; * }); * ``` @@ -436,7 +436,7 @@ class Filtered_zigzag_persistence_with_storage * // Only the closed bars where output so far, so the open/infinite bars still need to be retrieved. * * //in this example, outputs (0, 0.1) and (0, 2.0) - * zp.get_current_infinite_intervals([](dimension_type dim, filtration_value_type birth){ + * zp.get_current_infinite_intervals([](Dimension dim, filtration_value_type birth){ * std::cout << "[" << dim << "] " << birth << " - inf" << std::endl; * }); * ``` @@ -448,10 +448,10 @@ template class Filtered_zigzag_persistence { public: using Options = FilteredZigzagOptions; /**< Zigzag options. */ - using internal_key = typename Options::internal_key; /**< Key and index type, has to be signed. */ - using face_key = typename Options::face_key; /**< Face ID type from external inputs. */ - using filtration_value = typename Options::filtration_value; /**< Type for filtration values. */ - using dimension_type = typename Options::dimension_type; /**< Type for dimension values. */ + using Internal_key = typename Options::Internal_key; /**< Key and index type, has to be signed. */ + using Face_key = typename Options::Face_key; /**< Face ID type from external inputs. */ + using Filtration_value = typename Options::Filtration_value; /**< Type for filtration values. */ + using Dimension = typename Options::Dimension; /**< Type for dimension values. */ /** * @brief Constructor. @@ -476,9 +476,9 @@ class Filtered_zigzag_persistence { numArrow_(-1), keyToFiltrationValue_(preallocationSize), pers_( - [&, stream_interval = std::forward(stream_interval)](dimension_type dim, - internal_key birth, - internal_key death) { + [&, stream_interval = std::forward(stream_interval)](Dimension dim, + Internal_key birth, + Internal_key death) { auto itB = keyToFiltrationValue_.find(birth); auto itD = keyToFiltrationValue_.find(death); if (itB->second != itD->second) stream_interval(dim, itB->second, itD->second); @@ -500,11 +500,11 @@ class Filtered_zigzag_persistence { * Assumed to be always larger or equal to previously used filtration values or always smaller or equal than previous * values, ie. the changes are monotonous. */ - template > - internal_key insert_face(face_key faceID, + template > + Internal_key insert_face(Face_key faceID, const BoundaryRange& boundary, - dimension_type dimension, - filtration_value filtrationValue) + Dimension dimension, + Filtration_value filtrationValue) { ++numArrow_; @@ -515,7 +515,7 @@ class Filtered_zigzag_persistence { keyToFiltrationValue_.try_emplace(numArrow_, filtrationValue); // Compute the keys of the faces of the boundary. - std::set translatedBoundary; // set maintains the natural order on indices + std::set translatedBoundary; // set maintains the natural order on indices for (auto b : boundary) { translatedBoundary.insert(handleToKey_.at(b)); // TODO: add possibilities of coefficients } @@ -533,7 +533,7 @@ class Filtered_zigzag_persistence { * Assumed to be always larger or equal to previously used filtration values or always smaller or equal than previous * values, ie. the changes are monotonous. */ - internal_key remove_face(face_key faceID, filtration_value filtrationValue) { + Internal_key remove_face(Face_key faceID, Filtration_value filtrationValue) { ++numArrow_; auto it = handleToKey_.find(faceID); @@ -552,7 +552,7 @@ class Filtered_zigzag_persistence { * on homology level. Useful to keep the birth/death indices aligned when insertions/removals are purposely skipped * to avoid useless computation. */ - internal_key apply_identity() { + Internal_key apply_identity() { ++numArrow_; pers_.apply_identity(); return numArrow_; @@ -568,16 +568,16 @@ class Filtered_zigzag_persistence { template void get_current_infinite_intervals(F&& stream_infinite_interval) { pers_.get_current_infinite_intervals( - [&](dimension_type dim, internal_key birth) { stream_infinite_interval(dim, keyToFiltrationValue_.at(birth)); }); + [&](Dimension dim, Internal_key birth) { stream_infinite_interval(dim, keyToFiltrationValue_.at(birth)); }); } private: template - using dictionary = std::unordered_map; // TODO: benchmark with other map types + using Dictionary = std::unordered_map; // TODO: benchmark with other map types - dictionary handleToKey_; /**< Map from input keys to internal keys. */ - internal_key numArrow_; /**< Current arrow number. */ - dictionary keyToFiltrationValue_; /**< Face Key to filtration value map. */ + Dictionary handleToKey_; /**< Map from input keys to internal keys. */ + Internal_key numArrow_; /**< Current arrow number. */ + Dictionary keyToFiltrationValue_; /**< Face Key to filtration value map. */ Zigzag_persistence pers_; /**< Class computing the pairs. */ }; // end class Filtered_zigzag_persistence diff --git a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h index 7d6d20c6d8..cdb32a6fe1 100644 --- a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h @@ -62,8 +62,8 @@ struct Zigzag_matrix_options : Gudhi::persistence_matrix::Default_options; * - * using dimension_type = Zigzag_persistence::dimension_type; - * using index = Zigzag_persistence::index; + * using Dimension = Zigzag_persistence::Dimension; + * using Index = Zigzag_persistence::Index; * ``` * * #### Construction with default values * ``` * //Zigzag_persistence(callback) with for example callback method as a anonymous lambda - * Zigzag_persistence zp([](dimension_type dim, index birth, index death) { + * Zigzag_persistence zp([](Dimension dim, Index birth, Index death) { * std::cout << "[" << dim << "] " << birth << " - " << death << std::endl; * }); * ``` @@ -137,7 +137,7 @@ struct Default_zigzag_options { * // Only the closed bars where output so far, so the open/infinite bars still need to be retrieved. * * //in this example, outputs (0, 0) and (0, 7) - * zp.get_current_infinite_intervals([](dimension_type dim, index birth){ + * zp.get_current_infinite_intervals([](Dimension dim, Index birth){ * std::cout << "[" << dim << "] " << birth << " - inf" << std::endl; * }); * ``` @@ -150,20 +150,20 @@ template = 108100 - using birth_dictionary = boost::unordered_flat_map; /**< Dictionary type. */ - // using birth_dictionary = boost::unordered_map; /**< Dictionary type. */ + using Birth_dictionary = boost::unordered_flat_map; /**< Dictionary type. */ + // using Birth_dictionary = boost::unordered_map; /**< Dictionary type. */ #else - using birth_dictionary = std::unordered_map; /**< Dictionary type. */ + using Birth_dictionary = std::unordered_map; /**< Dictionary type. */ #endif - using Matrix_options = Zigzag_matrix_options; /**< Matrix options. */ - using Matrix_type = Gudhi::persistence_matrix::Matrix; /**< Matrix. */ - using matrix_index = typename Matrix_type::Index; /**< Matrix indexation type. */ + using Matrix_options = Zigzag_matrix_options; /**< Matrix options. */ + using Matrix = Gudhi::persistence_matrix::Matrix; /**< Matrix. */ + using Matrix_index = typename Matrix::Index; /**< Matrix indexation type. */ /** \brief Maintains the birth ordering \f$\leq_b\f$. * @@ -197,7 +197,7 @@ class Zigzag_persistence * * @param arrowNumber Forward arrow number. */ - void add_birth_forward(index arrowNumber) { // amortized constant time + void add_birth_forward(Index arrowNumber) { // amortized constant time birthToPos_.emplace_hint(birthToPos_.end(), arrowNumber, maxBirthPos_); ++maxBirthPos_; } @@ -208,7 +208,7 @@ class Zigzag_persistence * * @param arrowNumber Backward arrow number. */ - void add_birth_backward(index arrowNumber) { // amortized constant time + void add_birth_backward(Index arrowNumber) { // amortized constant time birthToPos_.emplace_hint(birthToPos_.end(), arrowNumber, minBirthPos_); --minBirthPos_; } @@ -220,7 +220,7 @@ class Zigzag_persistence * * @param birth Birth to remove. */ - void remove_birth(index birth) { birthToPos_.erase(birth); } + void remove_birth(Index birth) { birthToPos_.erase(birth); } /** * @brief Increasing birth order <=b, true iff k1 b k2. * @@ -236,12 +236,12 @@ class Zigzag_persistence * @param k2 * @return true if k1 >b k2, false otherwise. */ - bool reverse_birth_order(index k1, index k2) const { return birthToPos_.at(k1) > birthToPos_.at(k2); } + bool reverse_birth_order(Index k1, Index k2) const { return birthToPos_.at(k1) > birthToPos_.at(k2); } private: - birth_dictionary birthToPos_; /**< birth_to_pos_[i] < birth_to_pos_[j] iff i stream_interval, + Zigzag_persistence(std::function stream_interval, unsigned int preallocationSize = 0) : matrix_( preallocationSize, - [this](matrix_index columnIndex1, matrix_index columnIndex2) -> bool { + [this](Matrix_index columnIndex1, Matrix_index columnIndex2) -> bool { if (matrix_.get_column(columnIndex1).is_paired()) { return matrix_.get_pivot(columnIndex1) < matrix_.get_pivot(columnIndex2); } return birthOrdering_.birth_order(births_.at(columnIndex1), births_.at(columnIndex2)); }, - [this](matrix_index columnIndex1, matrix_index columnIndex2) -> bool { return false; }), + [this](Matrix_index columnIndex1, Matrix_index columnIndex2) -> bool { return false; }), numArrow_(-1), stream_interval_(std::move(stream_interval)) {} /** @@ -286,8 +286,8 @@ class Zigzag_persistence * @param dimension Dimension of the inserted face. * @return Number of the operation. */ - template > - index insert_face(const BoundaryRange& boundary, dimension_type dimension) { + template > + Index insert_face(const BoundaryRange& boundary, Dimension dimension) { ++numArrow_; _process_forward_arrow(boundary, dimension); return numArrow_; @@ -299,7 +299,7 @@ class Zigzag_persistence * @param arrowNumber Arrow number of when the face to remove was inserted for the last time. * @return Number of the operation. */ - index remove_face(index arrowNumber) { + Index remove_face(Index arrowNumber) { ++numArrow_; _process_backward_arrow(arrowNumber); return numArrow_; @@ -311,7 +311,7 @@ class Zigzag_persistence * to avoid useless computation. Increases the arrow number by one. * @return Number of the operation. */ - index apply_identity() { return ++numArrow_; } + Index apply_identity() { return ++numArrow_; } /** * @brief Outputs through the given callback method all birth indices which are currently not paired with @@ -350,8 +350,8 @@ class Zigzag_persistence * @param dim Dimension of the inserted face. */ template - void _process_forward_arrow(const BoundaryRange& boundary, dimension_type dim) { - std::vector chainsInF = matrix_.insert_boundary(numArrow_, boundary, dim); + void _process_forward_arrow(const BoundaryRange& boundary, Dimension dim) { + std::vector chainsInF = matrix_.insert_boundary(numArrow_, boundary, dim); if (!chainsInF.empty()) { _apply_surjective_reflection_diamond(dim, chainsInF); @@ -372,7 +372,7 @@ class Zigzag_persistence * @param dim Dimension of the inserted face. * @param chainsInF Indices of the non paired columns in the matrix. */ - void _apply_surjective_reflection_diamond(dimension_type dim, const std::vector& chainsInF) { + void _apply_surjective_reflection_diamond(Dimension dim, const std::vector& chainsInF) { // fp is the largest death index for <=d // Set col_fp: col_fp <- col_f1+...+col_fp (now in G); preserves lowest idx auto chainFp = chainsInF[0]; // col_fp, with largest death bool { + auto cmp_birth = [this](Index k1, Index k2) -> bool { return birthOrdering_.reverse_birth_order(k1, k2); }; // true iff b(k1) >b b(k2) // availableBirth: for all i by >d value of the d_i, // contains at step i all b_j, j > i, and maybe b_i if not stolen - std::set availableBirth(cmp_birth); + std::set availableBirth(cmp_birth); // for f1 to f_{p} (i by <=d), insertion in availableBirth sorts by >=b for (auto& chainF : chainsInF) { availableBirth.insert(births_.at(chainF)); @@ -429,7 +429,7 @@ class Zigzag_persistence lastModifiedChainIt = chainFIt; // new cumulated c_i+...+c_1 // remove the max available death auto maxAvailBirthIt = availableBirth.begin(); // max because order by decreasing modifiedColumns; + std::vector modifiedColumns; const auto& row = matrix_.get_row(faceID); modifiedColumns.reserve(row.size()); std::transform(row.begin(), row.end(), std::back_inserter(modifiedColumns), [](const auto& cell) { return cell.get_column_index(); }); // Sort by left-to-right order in the matrix_ (no order maintained in rows) - std::stable_sort(modifiedColumns.begin(), modifiedColumns.end(), [this](matrix_index i1, matrix_index i2) { + std::stable_sort(modifiedColumns.begin(), modifiedColumns.end(), [this](Matrix_index i1, Matrix_index i2) { return matrix_.get_pivot(i1) < matrix_.get_pivot(i2); }); @@ -492,11 +492,11 @@ class Zigzag_persistence } private: - Matrix_type matrix_; /**< Matrix storing a base of the current chain complex. */ - birth_dictionary births_; /**< Map face index in F to corresponding birth. */ + Matrix matrix_; /**< Matrix storing a base of the current chain complex. */ + Birth_dictionary births_; /**< Map face index in F to corresponding birth. */ Birth_ordering birthOrdering_; /**< Maintains stream_interval_; /**< Callback method for closed pairs. */ + Index numArrow_; /**< Current arrow number. */ + std::function stream_interval_; /**< Callback method for closed pairs. */ }; // end class Zigzag_persistence } // namespace zigzag_persistence diff --git a/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp b/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp index 6219f63bdd..4e20047a51 100644 --- a/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp +++ b/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp @@ -67,7 +67,7 @@ void test_barcode(ZP& zp, std::vector& b template void test_indices(ZP& zp, std::vector& indices, - std::vector& indexToFil) { + std::vector& indexToFil) { auto it = indices.begin(); for (const auto& interval : zp.get_index_persistence_diagram()) { BOOST_CHECK_EQUAL(interval.dim, it->dim); @@ -128,8 +128,8 @@ std::vector get_filtration_values() { template void test_filtered_zigzag_with_storage() { - using face_handle = typename ZP::face_key; - using filtration_value = typename ZP::filtration_value; + using face_handle = typename ZP::Face_key; + using Filtration_value = typename ZP::Filtration_value; using Interval_index = typename ZP::Index_interval; using Interval_filtration = typename ZP::Filtration_value_interval; @@ -140,7 +140,7 @@ void test_filtered_zigzag_with_storage() { realBarcode.reserve(9); std::vector > simplices = get_boundaries(); - std::vector filValues = get_filtration_values(); + std::vector filValues = get_filtration_values(); for (unsigned int i = 0; i < 14; ++i) { zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); @@ -203,8 +203,8 @@ void test_filtered_zigzag_with_storage() { template void test_filtered_zigzag_with_storage_max1() { - using face_handle = typename ZP::face_key; - using filtration_value = typename ZP::filtration_value; + using face_handle = typename ZP::Face_key; + using Filtration_value = typename ZP::Filtration_value; using Interval_index = typename ZP::Index_interval; using Interval_filtration = typename ZP::Filtration_value_interval; @@ -215,7 +215,7 @@ void test_filtered_zigzag_with_storage_max1() { realBarcode.reserve(3); std::vector > simplices = get_boundaries(); - std::vector filValues = get_filtration_values(); + std::vector filValues = get_filtration_values(); for (unsigned int i = 0; i < 14; ++i) { zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); @@ -264,13 +264,13 @@ BOOST_AUTO_TEST_CASE(filtered_zigzag_persistence_with_storage) { template void test_filtered_zigzag() { - using face_handle = typename ZP::face_key; - using filtration_value = typename ZP::filtration_value; - using dimension_type = typename ZP::dimension_type; - using Interval = std::tuple; + using face_handle = typename ZP::Face_key; + using Filtration_value = typename ZP::Filtration_value; + using Dimension = typename ZP::Dimension; + using Interval = std::tuple; Interval interval; - ZP zp([&](dimension_type dim, filtration_value birth, filtration_value death){ + ZP zp([&](Dimension dim, Filtration_value birth, Filtration_value death){ BOOST_CHECK_EQUAL(std::get<0>(interval), dim); BOOST_CHECK_EQUAL(std::get<1>(interval), birth); BOOST_CHECK_EQUAL(std::get<2>(interval), death); @@ -309,7 +309,7 @@ void test_filtered_zigzag() { realBarcode.emplace_back(3, 0, 28); //dummy std::vector > simplices = get_boundaries(); - std::vector filValues = get_filtration_values(); + std::vector filValues = get_filtration_values(); for (unsigned int i = 0; i < 14; ++i) { interval = realBarcode[i]; @@ -342,14 +342,14 @@ void test_filtered_zigzag() { //there is no real guarantee on the order of the infinite bars std::vector infiniteBars; - zp.get_current_infinite_intervals([&](dimension_type dim, filtration_value birth) { - infiniteBars.emplace_back(dim, birth, std::numeric_limits::infinity()); + zp.get_current_infinite_intervals([&](Dimension dim, Filtration_value birth) { + infiniteBars.emplace_back(dim, birth, std::numeric_limits::infinity()); }); realBarcode.clear(); - realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); - realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); - realBarcode.emplace_back(2, 10, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); + realBarcode.emplace_back(2, 10, std::numeric_limits::infinity()); std::sort(infiniteBars.begin(), infiniteBars.end()); std::sort(realBarcode.begin(), realBarcode.end()); @@ -364,13 +364,13 @@ void test_filtered_zigzag() { template void test_filtered_zigzag_max1() { - using face_handle = typename ZP::face_key; - using filtration_value = typename ZP::filtration_value; - using dimension_type = typename ZP::dimension_type; - using Interval = std::tuple; + using face_handle = typename ZP::Face_key; + using Filtration_value = typename ZP::Filtration_value; + using Dimension = typename ZP::Dimension; + using Interval = std::tuple; Interval interval; - ZP zp([&](dimension_type dim, filtration_value birth, filtration_value death){ + ZP zp([&](Dimension dim, Filtration_value birth, Filtration_value death){ if (dim < 1){ BOOST_CHECK_EQUAL(std::get<0>(interval), dim); BOOST_CHECK_EQUAL(std::get<1>(interval), birth); @@ -413,7 +413,7 @@ void test_filtered_zigzag_max1() { realBarcode.emplace_back(1, 0, 28); //dummy std::vector > simplices = get_boundaries(); - std::vector filValues = get_filtration_values(); + std::vector filValues = get_filtration_values(); for (unsigned int i = 0; i < 14; ++i) { interval = realBarcode[i]; @@ -446,15 +446,15 @@ void test_filtered_zigzag_max1() { //there is no real guarantee on the order of the infinite bars std::vector infiniteBars; - zp.get_current_infinite_intervals([&](dimension_type dim, filtration_value birth) { + zp.get_current_infinite_intervals([&](Dimension dim, Filtration_value birth) { if (dim < 1){ - infiniteBars.emplace_back(dim, birth, std::numeric_limits::infinity()); + infiniteBars.emplace_back(dim, birth, std::numeric_limits::infinity()); } }); realBarcode.clear(); - realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); - realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 0, std::numeric_limits::infinity()); + realBarcode.emplace_back(0, 9, std::numeric_limits::infinity()); std::sort(infiniteBars.begin(), infiniteBars.end()); std::sort(realBarcode.begin(), realBarcode.end()); diff --git a/src/Zigzag_persistence/test/test_zigzag_persistence.cpp b/src/Zigzag_persistence/test/test_zigzag_persistence.cpp index 99eb62f375..c589fa57b6 100644 --- a/src/Zigzag_persistence/test/test_zigzag_persistence.cpp +++ b/src/Zigzag_persistence/test/test_zigzag_persistence.cpp @@ -21,7 +21,7 @@ using ZP = Gudhi::zigzag_persistence::Zigzag_persistence<>; struct Interval { Interval() {} - Interval(int dim, ZP::index b, ZP::index d) : dim_(dim), b_(b), d_(d) {} + Interval(int dim, ZP::Index b, ZP::Index d) : dim_(dim), b_(b), d_(d) {} int dim() const { return dim_; } int birth() const { return b_; } @@ -29,13 +29,13 @@ struct Interval { private: int dim_; - ZP::index b_; - ZP::index d_; + ZP::Index b_; + ZP::Index d_; }; BOOST_AUTO_TEST_CASE(constructor) { std::vector pairs; - auto stream = [&](int dim, ZP::index birth, ZP::index death){ pairs.emplace_back(dim, birth, death); }; + auto stream = [&](int dim, ZP::Index birth, ZP::Index death){ pairs.emplace_back(dim, birth, death); }; BOOST_CHECK_NO_THROW(ZP zp(stream)); BOOST_CHECK_NO_THROW(ZP zp(stream, 28)); @@ -88,8 +88,8 @@ std::vector > get_boundaries() { BOOST_AUTO_TEST_CASE(zigzag_persistence_single) { std::vector pairs; - auto stream = [&](int dim, ZP::index birth, ZP::index death) { pairs.emplace_back(dim, birth, death); }; - auto stream_inf = [&](int dim, ZP::index birth) { pairs.emplace_back(dim, birth, -1); }; + auto stream = [&](int dim, ZP::Index birth, ZP::Index death) { pairs.emplace_back(dim, birth, death); }; + auto stream_inf = [&](int dim, ZP::Index birth) { pairs.emplace_back(dim, birth, -1); }; ZP zp(stream, 28); std::vector realIndices; realIndices.reserve(13); @@ -152,10 +152,10 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single) { BOOST_AUTO_TEST_CASE(zigzag_persistence_single_max1) { std::vector pairs; - auto stream = [&](int dim, ZP::index birth, ZP::index death) { + auto stream = [&](int dim, ZP::Index birth, ZP::Index death) { if (dim < 1) pairs.emplace_back(dim, birth, death); }; - auto stream_inf = [&](int dim, ZP::index birth) { + auto stream_inf = [&](int dim, ZP::Index birth) { if (dim < 1) pairs.emplace_back(dim, birth, -1); }; ZP zp(stream, 28); From 2b2a569a463cc5324def5d61dc1004afd9c17095 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Tue, 17 Sep 2024 18:17:20 +0200 Subject: [PATCH 66/96] doc --- .../example/example_usage_filtered_zigzag_persistence.cpp | 6 +++--- ...ample_usage_filtered_zigzag_persistence_with_storage.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp b/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp index 50bc50f894..0419dd79f9 100644 --- a/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp +++ b/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp @@ -33,15 +33,15 @@ int main() { zp.insert_face(2, {}, 0, 0.1); // inserts vertex 4 at filtration value 0.1 -> birth at 0.1 of 0-cycle zp.insert_face(4, {}, 0, 0.1); - // inserts edge 5 = (2,4) at filtration value 0.3 -> death at 0.3 -> outputs/stores (0, 0.1, 0.3) + // inserts edge 5 = (2,4) at filtration value 0.3 -> death at 0.3 -> outputs (0, 0.1, 0.3) zp.insert_face(5, {2, 4}, 1, 0.3); // inserts vertex 3 at filtration value 0.4 -> birth at 0.4 of 0-cycle zp.insert_face(3, {}, 0, 0.4); - // inserts edge 6 = (2,3) at filtration value 0.4 -> death at 0.4 of the cycle born at 0.4 -> outputs/stores nothing + // inserts edge 6 = (2,3) at filtration value 0.4 -> death at 0.4 of the cycle born at 0.4 -> outputs nothing zp.insert_face(6, {2, 3}, 1, 0.4); // inserts edge 9 = (3,4) at filtration value 1.2 -> birth at 1.2 of 1-cycle zp.insert_face(9, {4, 3}, 1, 1.2); - // removes edge 6 at filtration value 1.5 -> death at 1.5 -> outputs/stores (1, 1.2, 1.5) + // removes edge 6 at filtration value 1.5 -> death at 1.5 -> outputs (1, 1.2, 1.5) zp.remove_face(6, 1.5); // removes edge 5 at filtration value 2.0 -> birth at 2.0 of 0-cycle zp.remove_face(5, 2.0); diff --git a/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence_with_storage.cpp b/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence_with_storage.cpp index 5136d5eb2a..7cc0c866e9 100644 --- a/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence_with_storage.cpp +++ b/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence_with_storage.cpp @@ -28,15 +28,15 @@ int main() { zp.insert_face(2, {}, 0, 0.1); // inserts vertex 4 at filtration value 0.1 -> birth at 0.1 of 0-cycle zp.insert_face(4, {}, 0, 0.1); - // inserts edge 5 = (2,4) at filtration value 0.3 -> death at 0.3 -> outputs/stores (0, 0.1, 0.3) + // inserts edge 5 = (2,4) at filtration value 0.3 -> death at 0.3 -> stores (0, 0.1, 0.3) zp.insert_face(5, {2, 4}, 1, 0.3); // inserts vertex 3 at filtration value 0.4 -> birth at 0.4 of 0-cycle zp.insert_face(3, {}, 0, 0.4); - // inserts edge 6 = (2,3) at filtration value 0.4 -> death at 0.4 of the cycle born at 0.4 -> outputs/stores nothing + // inserts edge 6 = (2,3) at filtration value 0.4 -> death at 0.4 of the cycle born at 0.4 -> stores nothing zp.insert_face(6, {2, 3}, 1, 0.4); // inserts edge 9 = (3,4) at filtration value 1.2 -> birth at 1.2 of 1-cycle zp.insert_face(9, {4, 3}, 1, 1.2); - // removes edge 6 at filtration value 1.5 -> death at 1.5 -> outputs/stores (1, 1.2, 1.5) + // removes edge 6 at filtration value 1.5 -> death at 1.5 -> stores (1, 1.2, 1.5) zp.remove_face(6, 1.5); // removes edge 5 at filtration value 2.0 -> birth at 2.0 of 0-cycle zp.remove_face(5, 2.0); From 1e31a4b2a2966251f50ae070d35f40a867cc2cea Mon Sep 17 00:00:00 2001 From: hschreiber Date: Wed, 18 Sep 2024 14:07:36 +0200 Subject: [PATCH 67/96] doc --- src/Zigzag_persistence/doc/zigzag_ex.png | Bin 2547 -> 3629 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/Zigzag_persistence/doc/zigzag_ex.png b/src/Zigzag_persistence/doc/zigzag_ex.png index a58cc6ed5470ec17ce16cbf34cb96a15a4972c9e..ba7cb7011a86731a2526c2c070cff0f2e0bde025 100644 GIT binary patch literal 3629 zcmb7Hdpwiv|DQt^vK;!VXjDRoo?=eJo-%|GC5MPcPBX`9-YEXb>FZ1zTek%eXh^@`h4Ek=f3a4L*8y`Dmp44 z5J=7a0MZWxk{gshr>|9#Uj5F!yCuCTp*-D?AV79p?`tARM>5@!`;Md$=RRb#ojjR7 zu)qtE%ir7-uJK=c?d^pd5@B6+0}#u!=VfWnH9r~FUc7(wn8(hzaY�U)YA%sz{T< zKv-$uUwhg|o0}Eg_U(D`dLqztjmsKjZR*06=o(^HQAW+ZACp}EWA17;evp{@!)fKw z9d`HhJ(|D?U3I!y)mXu;L-?+byjb5^^N87{o0DO`DWJ5S-03Y`9w9^P2ksYTt!9vE z@J#{G2MGcq6imFuM1ym8%dg}b%X44ot*mEEBwUziAuj2*->T)wZD5X)(S^z=tt6*; zHB^&m4MTbrF6!5o>8o0^*_-wA?%0Oj|}Vx#%J;hfJ@ulfPMVy-oH z62eF)cWQz2XbON=BnLEa#HdA9-`7e!_?R~E=dm(Dw!tF%JUIb{PkVN8K(ax&VZqzM zV-BE*2AD7h}s7$*piof*B&Tc-lEU6j^&c#o+&dJH zt88)nw1fdUd06$m2aALABJ34~Xhyr*V|GtSclwltqNKKw=2T?6a@HxyC<*C_XfiYT zW)oKq9?Wh7e>1WNI*f)w3GoI-OHE_(#(bZ`*EH74qft|9#T!S73uhVQ0smOocU=5s7&OQ*gm9CsnkRqYQ!C7X;=Bx7BiRh1dX zDbUpx?!*2Df43?OWIhGe7o+Mq#a=ml{7ySYvX<#rN|WbR%nR-M&)}>GG~r|U%%VVS z6+4dEwj5U8K6MK5cP>26Vac^FPvF4>zGyP>mE$Sz|C^fA1gdGYrES(9rS<~ zP^<$@SN9#>Xt~4SK-_Qr68U zGrG}Eq>i9&(P)3r(>k+4onjC^&0ln)V)( zyOSrCTN4HF0wY4Q7ffU1_6X0|6ilz?3$X>3w_|M(X^7-A#}_Rr1_^cZ5C220q5+!G zz8e*I29*A4hqLj}Wc4h=`FQ58G@InDedRrum@ej5Iy zO-@o?__h$kSjxp}Vc5qCVRu~+QKI%X_JS#M*P^6?O1D~G$*xDih(^E^^c4o(q6kl?8RD2Ur+PJhJh3?7HzBL%B$MRNeE8qFSH} zCpvH0rLUN&oVF=R?eDxfGOYmUu0Oz`gk!$h*kSVPdWk-b@{iqgfDBkL=WU^+fpvk8I@=nhJZ-V-tH52vb~dJT(E{W1slp0OyZikw zM=I!$3Ic25RMy3vBFxqy3qU~})@e}j;o~WsBl8i(n9^}Z%ggA>EY{W~O+M+v=T8H2 zVR~7aJCnck%P;oE4nX&3U$(%+gGUB+u)Pp6Kdh$y492F+`@(wAb|EzoZ0LZh#4G6Khyv1yfY~n4l6>L`QA_ucbI-*ju+V`W zb~0Jg`O%c|DWc|KQY-!v2e8pDOo(j@FZY1s zwGzOQym@t<+iZydrxpO(J(r>G=VQbI)-nGyQ48e?aNj<(N6Ue8mlhq>Tfk#{oWgw1 zw|s-sLn6|-(=nxOra%UK%U^F`96)8F*8jG>s5{-wnI#U(;})9+Rf(q_)z{9Rl2DVq zUfbXGIBElQc*Ye-83g7Z9gG?Tx{!nZIx4?y@6FKJP_^??9v#j%BhiDT5xCC9X*Lit zv7_C&H4;5S;^KAWe-BRQ^Qy2V@PCmYQBah^{_R#vM&f}7O5&6L)9u6&N#b)hlr`|1 z^Po6`17*GVjlRf85^VumF%lX)>pmtkwsTLA_+Wk+yGlX{M=XAGe)p1uo%Wsm7g3}f zJ<6qw2ghq0A@{0qmDrNo4IE&@FUp}a^o$-;e+uxQHt7OF*>pH>C+uIuk*>C}Uqrgl zzHg<%(QRKG6ko7yT#el z{4*S|<~93dad2L}A%we-c6?(oj%GN1bpyY~iu=km$W*jMfzLXdihRnXIos7JTX9EY z2@rWQDF0}ywOk_DdyVyXc*#U#8L*`iYpouX4*wgg zxR@OrIwbOW8boGgt>5pioASvUBBHjZ54@<#oGAv5r#oKqDD#xX@?Ei~B;(WKAErUx zq9s~XOROD>WFw0^Q6{W6cZqxi;fD4TaI)j2yRHvdbVvZqq+5)oNRv^9mZYMmeJfH% zaM7~7+Q~9GV#X0;qi&s!X}Lg@iIH8JDnVC9|CCT!h9var8;2Asjw>7Q{147TDx$L& zih-lj_zzwvk;=xZbsLKWb9qzSX!3u!EQt0~`p&~r=~p~|#i!d!(>bXwkWxHCQy0*8 z%HScHzu8T35?%igXt0juj4ZvT&JU7>sm{MtQ^ZQ)4;J=6hL@C(4#nH}7C!;{A8ojJnpk&Y_ z_F?VwoAn+dyx5G)=T>HH$-7|A`qk*;L3q(cK1ohICA9RvU&5D}n?SRCbbfEZ?NSfD zz13Fn)4m>f+nBS(CH&DJ4JV{~cVc+oSYAU(=M7^uX^|j!Ln`!kG=98>eSJ$>ZanK8 z;E~g1KF*fIn0{>mNr=All9bY2Cf>al(7Hr_lO>KKy*|`t9qW+ykN7k>^$$R&+Fpc} zblw7G>i1~b6kkX*TR<0EZ1?c9(IgptO?XMVkmx7Dof7~zU#!PVD*h;C$C5+)-(403 z#A*w8V#Ilp&tXGLz_eV{`Q-dD=}W0Kk{yO`2wGjIz5Evaqxh?r^#2d!?&6K?*dKoG Ee~960SO5S3 literal 2547 zcmZ{k2UJt(62~vH8pU-jh`6AD(w=025Dg$GQF<2wEK&pmL>6Kwf`n#*0-}q+Mu<}6 z&}%3vWK~*LT}2TLH4&sJ6s?$fsZ0R979$`iq&?N2#QO9ARchVO+nCQ1O&~ThaiJY z2$BuC*Wh>pY;5weu`q>%Nonm2U~LPrbPEHkrRXw$jW+@}uy89oGuR|dX7|r}zrfK% z;M(PjwT}SeY6z0_0k##mu50neC=j&O!^-rubL7D6(1TQEmwhkicP5xVlt|Qlw@XGM zM>fsDFDLr&rox$wcFh}c$$hj)5%J(%nu4s^^vZ(d(?_+Y?~a8 zsq_>o?&-`f;C=mc^igbT&Yv3x{qA?`xyA72AI&SWiY+GGr&EgE;kdRXcVc`?#AjOT zv4plH2T3jCQg=-AYI(15%ER5BhRc1va>f%T<=A?od9CxO6o^I|OXW1jZ#I^-&gW;> zy)QRfHRO3VVs!G`)-2tk9$V~ZT;Kj&qPw)qx|YcgUd(4}(dBF>){Co7^eWprK2Q7z z^|PnC5RxMYnwd+D5fy!~GxyguIO>E6tO7P$PU}b5t0bw3=;{f3T8DE4$(mGT>yn1I zDGBWGAQ3B`)O1jpF8B+TO;f9(nQe^*8D4o7zg1(Ooh>B&Rw3WlfT^(#Rw9OfGDG^1N}s)(dyBkm8rVbjs4E(IG#1-E zLZELuF+?wuoxw|T?_W7yJIH_E(@Y;2qy|!RYcNxP;s$~k%ggL#PE6K580XG8cpjl9 z24CLf(7c#5-`k4SxLb_Dlwz{#SJw*Q;bd0l3ciQFmoZ8v3hcVOMU#ym*QDAj{KOX)nub+DY2H^#b8>f>G1{28TE2Z^kP5YdlCczR zSH@JfJtwJF_BAHGldx-wGnYQsu1{n-TecZAU)#I9cB+aR47*;I@^|c_>%^$7c}qXzmV=@F^Hm^8ZD^MLy~?Y_s3 zzqV~&QTXn8{npentBYDIv`!%&NjDX=Y@rA<$>j@|q&jSgq4B+Yr^wQ!Xz$hq{}egJ_26gR$xo3$ z>02aH=Cct1E$pqc2L5C6@S>$@&09LLN}EtM`*t#WL=C-l=XpLunV~`DU~HOhM$8~r}AO5(wt2hw64Cmv9)Itbpn$t zBPut5OHsNgpnV|DY9B@mB78f@*D?hWB_yeXy2ANd$JSio_^n7@vdZip?Qp@EcTuXL z@a9K)u(!^FqEHTX5VV@za^=PAJdXM7?*cs^-lB{;xka817tf%I-^wtzix(YNMtcM3 zlrNg)3()SFBjR>H28}wID2_1%?QRvfdlWn zY{I;mpyl?s;^O4h$gxSv*TZD*@txm(BR8z3IoZ*R8Tekp zfdxV$kViEUdYVWbXB|BQ9esmi$KVKr0RmxBBklQ(fDr5#a3Sjd3v?H0AAsOr|H}{_ zK){8CV+kSOX^msmUvZbh0)m4e2UBxR9W9iTuKQE44OyAlo7NbgzxE&arSYo( From 1e15367716624ee743f6b1ca627504d74218a9d2 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Thu, 19 Sep 2024 14:14:15 +0200 Subject: [PATCH 68/96] Manage case where python module is built in sources. No need to create symbolic link (and cmake fails to link a file to itself) --- src/python/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index 273a4c6c2b..cce1ea77de 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -57,9 +57,12 @@ function( add_gudhi_py_test THE_TEST ) endfunction( add_gudhi_py_test ) function( add_gudhi_symbolic_links GLOBBING_EXPRESSION ) + # No symbolic links if build in sources (aka. 'cmake .' in sources) + if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) + return() + endif() file(GLOB GUDHI_GLOB_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${GLOBBING_EXPRESSION}) foreach(GUDHI_GLOB_FILENAME ${GUDHI_GLOB_FILES}) - message("link ${CMAKE_CURRENT_SOURCE_DIR}/${GUDHI_GLOB_FILENAME} to ${CMAKE_CURRENT_BINARY_DIR}/${GUDHI_GLOB_FILENAME}") file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/${GUDHI_GLOB_FILENAME}" "${CMAKE_CURRENT_BINARY_DIR}/${GUDHI_GLOB_FILENAME}" SYMBOLIC) endforeach() endfunction( add_gudhi_symbolic_links ) From 51e658713ba186b31d6b96d4d043d2094778f2f7 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Fri, 20 Sep 2024 16:20:36 +0200 Subject: [PATCH 69/96] copy_on_error if symbolic link failed to be created --- src/python/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index cce1ea77de..c6c8ab9db0 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -63,7 +63,9 @@ function( add_gudhi_symbolic_links GLOBBING_EXPRESSION ) endif() file(GLOB GUDHI_GLOB_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${GLOBBING_EXPRESSION}) foreach(GUDHI_GLOB_FILENAME ${GUDHI_GLOB_FILES}) - file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/${GUDHI_GLOB_FILENAME}" "${CMAKE_CURRENT_BINARY_DIR}/${GUDHI_GLOB_FILENAME}" SYMBOLIC) + # COPY_ON_ERROR is activated because on windows, user needs to be root or in dev mode to be able to make symbolic links + # This case can be problematic, because if you modify the sources, build is still done on the copy + file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/${GUDHI_GLOB_FILENAME}" "${CMAKE_CURRENT_BINARY_DIR}/${GUDHI_GLOB_FILENAME}" COPY_ON_ERROR SYMBOLIC) endforeach() endfunction( add_gudhi_symbolic_links ) From bfdbaeca78a5fd1b281720300ee98cdc59612167 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau <10407034+VincentRouvreau@users.noreply.github.com> Date: Mon, 23 Sep 2024 10:33:55 +0200 Subject: [PATCH 70/96] [comment review] symlinks creation restriction is only for win10 cf. https://www.howtogeek.com/16226/complete-guide-to-symbolic-links-symlinks-on-windows-or-linux/ Co-authored-by: Marc Glisse --- src/python/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index c6c8ab9db0..e913af6b3f 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -63,7 +63,7 @@ function( add_gudhi_symbolic_links GLOBBING_EXPRESSION ) endif() file(GLOB GUDHI_GLOB_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${GLOBBING_EXPRESSION}) foreach(GUDHI_GLOB_FILENAME ${GUDHI_GLOB_FILES}) - # COPY_ON_ERROR is activated because on windows, user needs to be root or in dev mode to be able to make symbolic links + # COPY_ON_ERROR is activated because on windows 10, user needs to be root or in dev mode to be able to make symbolic links # This case can be problematic, because if you modify the sources, build is still done on the copy file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/${GUDHI_GLOB_FILENAME}" "${CMAKE_CURRENT_BINARY_DIR}/${GUDHI_GLOB_FILENAME}" COPY_ON_ERROR SYMBOLIC) endforeach() From 7dd5177936b1a17562cd1d035a96730694205b64 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Mon, 23 Sep 2024 11:01:00 +0200 Subject: [PATCH 71/96] renaming matrix cell as matrix entry --- .../concept/PersistenceMatrixColumn.h | 134 ++++--- .../concept/PersistenceMatrixOptions.h | 6 +- src/Persistence_matrix/include/gudhi/Matrix.h | 249 ++++++------ .../gudhi/Persistence_matrix/Base_matrix.h | 126 +++--- .../Base_matrix_with_column_compression.h | 101 ++--- .../Persistence_matrix/Boundary_matrix.h | 75 ++-- .../gudhi/Persistence_matrix/Chain_matrix.h | 107 ++--- .../Persistence_matrix/Id_to_index_overlay.h | 93 ++--- .../Position_to_index_overlay.h | 49 +-- .../gudhi/Persistence_matrix/RU_matrix.h | 79 ++-- .../allocators/cell_constructors.h | 139 ------- .../allocators/entry_constructors.h | 139 +++++++ .../gudhi/Persistence_matrix/base_swap.h | 4 +- .../Persistence_matrix/chain_vine_swap.h | 8 +- .../Persistence_matrix/columns/cell_types.h | 327 ---------------- .../columns/column_utilities.h | 126 +++--- .../Persistence_matrix/columns/entry_types.h | 327 ++++++++++++++++ .../Persistence_matrix/columns/heap_column.h | 324 ++++++++-------- .../columns/intrusive_list_column.h | 220 +++++------ .../columns/intrusive_set_column.h | 244 ++++++------ .../Persistence_matrix/columns/list_column.h | 286 +++++++------- .../columns/naive_vector_column.h | 328 ++++++++-------- .../Persistence_matrix/columns/row_access.h | 48 +-- .../Persistence_matrix/columns/set_column.h | 266 ++++++------- .../columns/unordered_set_column.h | 344 ++++++++-------- .../columns/vector_column.h | 366 +++++++++--------- .../Persistence_matrix/matrix_row_access.h | 4 +- .../gudhi/Persistence_matrix/ru_rep_cycles.h | 8 +- .../gudhi/Persistence_matrix/ru_vine_swap.h | 18 +- .../gudhi/persistence_matrix_options.h | 16 +- src/Persistence_matrix/test/pm_column_tests.h | 238 ++++++------ .../test/pm_column_tests_mastermatrix.h | 59 +-- src/Persistence_matrix/test/pm_matrix_tests.h | 84 ++-- .../test/pm_test_utilities.h | 40 +- ...test_persistence_matrix_matrix_z2_base.cpp | 2 +- ...rsistence_matrix_matrix_z2_compression.cpp | 2 +- ...test_persistence_matrix_matrix_zp_base.cpp | 2 +- ...rsistence_matrix_matrix_zp_compression.cpp | 2 +- 38 files changed, 2510 insertions(+), 2480 deletions(-) delete mode 100644 src/Persistence_matrix/include/gudhi/Persistence_matrix/allocators/cell_constructors.h create mode 100644 src/Persistence_matrix/include/gudhi/Persistence_matrix/allocators/entry_constructors.h delete mode 100644 src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/cell_types.h create mode 100644 src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/entry_types.h diff --git a/src/Persistence_matrix/concept/PersistenceMatrixColumn.h b/src/Persistence_matrix/concept/PersistenceMatrixColumn.h index dbbca9bdbb..6eaf75f7c9 100644 --- a/src/Persistence_matrix/concept/PersistenceMatrixColumn.h +++ b/src/Persistence_matrix/concept/PersistenceMatrixColumn.h @@ -63,18 +63,18 @@ class PersistenceMatrixColumn : using Master = unspecified; /**< Master matrix, that is a templated @ref Matrix. */ using Index = unspecified; /**< Type of @ref MatIdx index. */ using ID_index = unspecified; /**< Type of @ref IDIdx index. */ - using Dimension = unspecified; /**< Type for dimension value. */ - using Field_element = unspecified; /**< Type of a field element. */ - using Cell = unspecified; /**< @ref Cell. */ + using Dimension = unspecified; /**< Type for dimension value. */ + using Field_element = unspecified; /**< Type of a field element. */ + using Entry = unspecified; /**< @ref Entry. */ using Column_settings = unspecified; /**< Structure giving access to external classes eventually necessary, - like a cell pool for example. */ + like an entry pool for example. */ using iterator = unspecified; /**< Column iterator type. */ using const_iterator = unspecified; /**< Column const_iterator type. */ using reverse_iterator = unspecified; /**< Column reverse_iterator type. */ using const_reverse_iterator = unspecified; /**< Column const_reverse_iterator type. */ /** - * @brief Constructs an empty column. If @p cellConstructor is not specified or is set to `nullptr`, the column + * @brief Constructs an empty column. If @p entryConstructor is not specified or is set to `nullptr`, the column * can only be used as a dummy, i.e., no modifying method should be used or there will be a segmentation fault. * Same goes for @p operators if @ref PersistenceMatrixOptions::is_z2 is false. * @@ -85,12 +85,13 @@ class PersistenceMatrixColumn : */ PersistenceMatrixColumn(Column_settings* colSettings = nullptr); /** - * @brief Constructs a column from the given range of @ref Matrix::Cell_representative. If the dimension is stored, + * @brief Constructs a column from the given range of @ref Matrix::Entry_representative. If the dimension is stored, * the face is assumed to be simplicial and its dimension to be `nonZeroRowIndices length - 1` or `0`. * Otherwise, the dimension should be specified with another constructor. * - * @tparam Container Range of @ref Matrix::Cell_representative. Assumed to have a %begin(), %end() and %size() method. - * @param nonZeroRowIndices Range of @ref Matrix::Cell_representative representing all rows with non zero values. + * @tparam Container Range of @ref Matrix::Entry_representative. Assumed to have a %begin(), %end() and %size() + * method. + * @param nonZeroRowIndices Range of @ref Matrix::Entry_representative representing all rows with non zero values. * @param colSettings Pointer to an existing setting structure. The structure should contain all the necessary * classes specific to the column type, such as custom allocators. The specificities are this way hidden behind * a commun interface for all column types. @@ -99,16 +100,17 @@ class PersistenceMatrixColumn : PersistenceMatrixColumn(const Container& nonZeroRowIndices, Column_settings* colSettings); /** - * @brief Constructs a column from the given range of @ref Matrix::Cell_representative such that the rows can be accessed. - * Each new cell in the column is also inserted in a row using @ref Row_access::insert_cell. + * @brief Constructs a column from the given range of @ref Matrix::Entry_representative such that the rows can be + * accessed. Each new entry in the column is also inserted in a row using @ref Row_access::insert_entry. * If the dimension is stored, the face is assumed to be simplicial and its dimension to be * `nonZeroRowIndices length - 1` or `0`. Otherwise, the dimension should be specified with another constructor. * - * @tparam Container Range of @ref Matrix::Cell_representative. Assumed to have a %begin(), %end() and %size() method. + * @tparam Container Range of @ref Matrix::Entry_representative. Assumed to have a %begin(), %end() and %size() + * method. * @tparam Row_container Either std::map if @ref PersistenceMatrixOptions::has_removable_rows is true or * std::vector. - * @param columnIndex @ref MatIdx column index that should be specified to the cells. - * @param nonZeroRowIndices Range of @ref Matrix::Cell_representative representing all rows with non zero values. + * @param columnIndex @ref MatIdx column index that should be specified to the entries. + * @param nonZeroRowIndices Range of @ref Matrix::Entry_representative representing all rows with non zero values. * @param rowContainer Pointer to the row container that will be forwarded to @ref Row_access at construction. * @param colSettings Pointer to an existing setting structure. The structure should contain all the necessary * classes specific to the column type, such as custom allocators. The specificities are this way hidden behind @@ -120,11 +122,13 @@ class PersistenceMatrixColumn : Row_container* rowContainer, Column_settings* colSettings); /** - * @brief Constructs a column from the given range of @ref Matrix::Cell_representative and stores the given dimension + * @brief Constructs a column from the given range of @ref Matrix::Entry_representative and stores the given dimension * if @ref Column_dimension_option is not a dummy. * - * @tparam Container Range of @ref Matrix::Cell_representative. Assumed to have a %begin(), %end() and %size() method. - * @param nonZeroChainRowIndices Range of @ref Matrix::Cell_representative representing all rows with non zero values. + * @tparam Container Range of @ref Matrix::Entry_representative. Assumed to have a %begin(), %end() and %size() + * method. + * @param nonZeroChainRowIndices Range of @ref Matrix::Entry_representative representing all rows with non zero + * values. * @param dimension Dimension of the column. Is ignored if the dimension is not stored. * @param colSettings Pointer to an existing setting structure. The structure should contain all the necessary * classes specific to the column type, such as custom allocators. The specificities are this way hidden behind @@ -135,15 +139,17 @@ class PersistenceMatrixColumn : Dimension dimension, Column_settings* colSettings); /** - * @brief Constructs a column from the given range of @ref Matrix::Cell_representative such that the rows can be accessed. - * Each new cell in the column is also inserted in a row using @ref Row_access::insert_cell. + * @brief Constructs a column from the given range of @ref Matrix::Entry_representative such that the rows can be + * accessed. Each new entry in the column is also inserted in a row using @ref Row_access::insert_entry. * Stores the given dimension if @ref Column_dimension_option is not a dummy. * - * @tparam Container Range of @ref Matrix::Cell_representative. Assumed to have a %begin(), %end() and %size() method. + * @tparam Container Range of @ref Matrix::Entry_representative. Assumed to have a %begin(), %end() and %size() + * method. * @tparam Row_container Either std::map if @ref PersistenceMatrixOptions::has_removable_rows is true or * std::vector. - * @param columnIndex @ref MatIdx column index that should be specified to the cells. - * @param nonZeroChainRowIndices Range of @ref Matrix::Cell_representative representing all rows with non zero values. + * @param columnIndex @ref MatIdx column index that should be specified to the entries. + * @param nonZeroChainRowIndices Range of @ref Matrix::Entry_representative representing all rows with non zero + * values. * @param dimension Dimension of the column. Is ignored if the dimension is not stored. * @param rowContainer Pointer to the row container that will be forwarded to @ref Row_access at construction. * @param colSettings Pointer to an existing setting structure. The structure should contain all the necessary @@ -157,7 +163,7 @@ class PersistenceMatrixColumn : Row_container* rowContainer, Column_settings* colSettings); /** - * @brief Copy constructor. If @p operators or @p cellConstructor is not a null pointer, its value is kept + * @brief Copy constructor. If @p operators or @p entryConstructor is not a null pointer, its value is kept * instead of the one in the copied column. * * @param column Column to copy. @@ -170,7 +176,7 @@ class PersistenceMatrixColumn : Column_settings* colSettings = nullptr); /** * @brief Copy constructor with row access. - * If @p operators or @p cellConstructor is not a null pointer, its value is kept + * If @p operators or @p entryConstructor stored in @p colSettings is not a null pointer, its value is kept * instead of the one in the copied column. * * @tparam Row_container Either std::map if @ref PersistenceMatrixOptions::has_removable_rows is true or @@ -209,10 +215,10 @@ class PersistenceMatrixColumn : */ std::vector get_content(int columnLength = -1) const; /** - * @brief Indicates if the cell at given row index has value zero. + * @brief Indicates if the entry at given row index has value zero. * * @param rowIndex Row index to look at. - * @return true If the cell has value zero. + * @return true If the entry has value zero. * @return false Otherwise. */ bool is_non_zero(ID_index rowIndex) const; @@ -226,7 +232,7 @@ class PersistenceMatrixColumn : /** * @brief Returns the size of the underlying container. * - * @warning Depending of the column type, the container does not have to contain only the non-zero cells. + * @warning Depending of the column type, the container does not have to contain only the non-zero entries. * Even if for most of the types, the size of the container will correspond to the number of non-zero values * in the column, it is not always the case. See description of the actual Column class for more details. * @@ -236,12 +242,12 @@ class PersistenceMatrixColumn : /** * @brief Reorders the column with the given map of row indices. Also changes the column index stored in the - * cells if row access is enabled and @p columnIndex is not -1. + * entries if row access is enabled and @p columnIndex is not -1. * * Only useful for @ref basematrix "base" and @ref boundarymatrix "boundary matrices" using lazy swaps. * * @tparam Row_index_map Map with an %at() method. - * @param valueMap Map such that `valueMap.at(i)` indicates the new row index of the cell + * @param valueMap Map such that `valueMap.at(i)` indicates the new row index of the entry * at current row index `i`. * @param columnIndex New @ref MatIdx column index of the column. If -1, the index does not change. Ignored if * the row access is not enabled. Default value: -1. @@ -256,15 +262,15 @@ class PersistenceMatrixColumn : */ void clear(); /** - * @brief Zeros the cell at given row index. + * @brief Zeros the entry at given row index. * * Only useful for @ref basematrix "base" and @ref boundarymatrix "boundary matrices". - * Used in @ref Matrix::zero_cell and during vine swaps. + * Used in @ref Matrix::zero_entry and during vine swaps. * - * @warning For @ref Vector_column, do not clear a cell that was already at zero or the results of @ref size and + * @warning For @ref Vector_column, do not clear an entry that was already at zero or the results of @ref size and * @ref is_empty will be wrong. * - * @param rowIndex Row index of the cell to zero. + * @param rowIndex Row index of the entry to zero. */ void clear(ID_index rowIndex); @@ -288,92 +294,94 @@ class PersistenceMatrixColumn : Field_element get_pivot_value(); /** - * @brief Returns a begin @ref Cell iterator to iterate over all cells contained in the underlying container. + * @brief Returns a begin @ref Entry iterator to iterate over all entries contained in the underlying container. * * @warning The iterators really just iterate over the underlying container. Depending of the column type, * neither the content nor the order is guaranteed. See description of the actual Column class for more details. * - * @return @ref Cell iterator. + * @return @ref Entry iterator. */ iterator begin() noexcept; /** - * @brief Returns a begin @ref Cell const iterator to iterate over all cells contained in the underlying container. + * @brief Returns a begin @ref Entry const iterator to iterate over all entries contained in the underlying container. * * @warning The iterators really just iterate over the underlying container. Depending of the column type, * neither the content nor the order is guaranteed. See description of the actual Column class for more details. * - * @return @ref Cell const iterator. + * @return @ref Entry const iterator. */ const_iterator begin() const noexcept; /** - * @brief Returns a end @ref Cell iterator, iterating over all cells contained in the underlying container. + * @brief Returns an end @ref Entry iterator, iterating over all entries contained in the underlying container. * * @warning The iterators really just iterate over the underlying container. Depending of the column type, * neither the content nor the order is guaranteed. See description of the actual Column class for more details. * - * @return @ref Cell iterator. + * @return @ref Entry iterator. */ iterator end() noexcept; /** - * @brief Returns a end @ref Cell const iterator, iterating over all cells contained in the underlying container. + * @brief Returns an end @ref Entry const iterator, iterating over all entries contained in the underlying container. * * @warning The iterators really just iterate over the underlying container. Depending of the column type, * neither the content nor the order is guaranteed. See description of the actual Column class for more details. * - * @return @ref Cell const iterator. + * @return @ref Entry const iterator. */ const_iterator end() const noexcept; /** - * @brief Returns a begin @ref Cell reverse iterator to iterate over all cells contained in the underlying container. + * @brief Returns a begin @ref Entry reverse iterator to iterate over all entries contained in the underlying + * container. * * @warning The iterators really just iterate over the underlying container. Depending of the column type, * neither the content nor the order is guaranteed. See description of the actual Column class for more details. * - * @return @ref Cell reverse iterator. + * @return @ref Entry reverse iterator. */ reverse_iterator rbegin() noexcept; /** - * @brief Returns a begin @ref Cell const reverse iterator to iterate over all cells contained in the underlying + * @brief Returns a begin @ref Entry const reverse iterator to iterate over all entries contained in the underlying * container. * * @warning The iterators really just iterate over the underlying container. Depending of the column type, * neither the content nor the order is guaranteed. See description of the actual Column class for more details. * - * @return @ref Cell const reverse iterator. + * @return @ref Entry const reverse iterator. */ const_reverse_iterator rbegin() const noexcept; /** - * @brief Returns a end @ref Cell reverse iterator, iterating over all cells contained in the underlying container. + * @brief Returns an end @ref Entry reverse iterator, iterating over all entries contained in the underlying + * container. * * @warning The iterators really just iterate over the underlying container. Depending of the column type, * neither the content nor the order is guaranteed. See description of the actual Column class for more details. * - * @return @ref Cell reverse iterator. + * @return @ref Entry reverse iterator. */ reverse_iterator rend() noexcept; /** - * @brief Returns a end @ref Cell const reverse iterator, iterating over all cells contained in the underlying + * @brief Returns an end @ref Entry const reverse iterator, iterating over all entries contained in the underlying * container. * * @warning The iterators really just iterate over the underlying container. Depending of the column type, * neither the content nor the order is guaranteed. See description of the actual Column class for more details. * - * @return @ref Cell const reverse iterator. + * @return @ref Entry const reverse iterator. */ const_reverse_iterator rend() const noexcept; /** - * @brief Adds the given @ref Cell range onto the column. + * @brief Adds the given @ref Entry range onto the column. * - * @tparam Cell_range @ref Cell range with %begin() and %end() method. + * @tparam Entry_range @ref Entry range with %begin() and %end() method. * Has to be ordered by row index if not specified otherwise. - * @param column @ref Cell range. Only the stored row index and the stored element value + * @param column @ref Entry range. Only the stored row index and the stored element value * (if @ref PersistenceMatrixOptions::is_z2 is false) are token into account for this method. * Even if @ref PersistenceMatrixOptions::has_row_access is true, the column index does not need to be correct. * @return Reference to this column. */ - template - PersistenceMatrixColumn& operator+=(const Cell_range& column); + template + PersistenceMatrixColumn& operator+=(const Entry_range& column); /** * @brief Adds the given column onto this column. * @@ -393,35 +401,35 @@ class PersistenceMatrixColumn : /** * @brief `this = val * this + column` * - * @tparam Cell_range @ref Cell range with %begin() and %end() method. + * @tparam Entry_range @ref Entry range with %begin() and %end() method. * Has to be ordered by row index if not specified otherwise. * @param val Value to multiply. - * @param column @ref Cell range. Only the stored row index and the stored element value + * @param column @ref Entry range. Only the stored row index and the stored element value * (if @ref PersistenceMatrixOptions::is_z2 is false) are token into account for this method. * Even if @ref PersistenceMatrixOptions::has_row_access is true, the column index does not need to be correct. * @return Reference to this column. */ - template - PersistenceMatrixColumn& multiply_target_and_add(const Field_element& val, const Cell_range& column); + template + PersistenceMatrixColumn& multiply_target_and_add(const Field_element& val, const Entry_range& column); /** * @brief `this = this + column * val` * - * @tparam Cell_range @ref Cell range with %begin() and %end() method. + * @tparam Entry_range @ref Entry range with %begin() and %end() method. * Has to be ordered by row index if not specified otherwise. - * @param column @ref Cell range. Only the stored row index and the stored element value + * @param column @ref Entry range. Only the stored row index and the stored element value * (if @ref PersistenceMatrixOptions::is_z2 is false) are token into account for this method. * Even if @ref PersistenceMatrixOptions::has_row_access is true, the column index does not need to be correct. * @param val Value to multiply. * @return Reference to this column. */ - template - PersistenceMatrixColumn& multiply_source_and_add(const Cell_range& column, const Field_element& val); + template + PersistenceMatrixColumn& multiply_source_and_add(const Entry_range& column, const Field_element& val); /** * @brief Equality comparator. Equal in the sense that what is "supposed" to be contained in the columns is equal, * not what is actually stored in the underlying container. For example, the underlying container of - * @ref Vector_column can contain cells which were erased explicitly by @ref clear(Index). Those cells should not + * @ref Vector_column can contain entries which were erased explicitly by @ref clear(Index). Those entries should not * be taken into account while comparing. * * @param c1 First column to compare. @@ -434,7 +442,7 @@ class PersistenceMatrixColumn : * @brief "Strictly smaller than" comparator. Usually a lexicographical order, but what matters is that the * order is total. The order should apply on what is "supposed" to be contained in the columns, * not what is actually stored in the underlying container. For example, the underlying container of - * @ref Vector_column can contain cells which were erased explicitly by @ref clear(Index). Those cells should not + * @ref Vector_column can contain entries which were erased explicitly by @ref clear(Index). Those entries should not * be taken into account while comparing. * * @param c1 First column to compare. diff --git a/src/Persistence_matrix/concept/PersistenceMatrixOptions.h b/src/Persistence_matrix/concept/PersistenceMatrixOptions.h index 3d42555dc4..b4d72dc82b 100644 --- a/src/Persistence_matrix/concept/PersistenceMatrixOptions.h +++ b/src/Persistence_matrix/concept/PersistenceMatrixOptions.h @@ -74,7 +74,7 @@ struct PersistenceMatrixOptions * Note that some methods of the @ref basematrix "base matrix" are not available when true: * - @ref Matrix::insert_column(const Container&, Index) "insert_column(const Container&, Index)", * - @ref Matrix::zero_column(Index) "zero_column(Index)", - * - @ref Matrix::zero_cell(Index, Index) "zero_cell(Index, ID_index)", + * - @ref Matrix::zero_entry(Index, Index) "zero_entry(Index, ID_index)", * - @ref Matrix::swap_columns(Index, Index) "swap_columns(Index, Index)", * - @ref Matrix::swap_rows(Index, Index) "swap_rows(Index, Index)", * - @ref Matrix::remove_column(Index) "remove_column(Index)", @@ -111,8 +111,8 @@ struct PersistenceMatrixOptions static const bool has_row_access; /** * @brief Only enabled if @ref has_row_access is true, ignored otherwise. - * If set to true, the underlying container representing a row is an boost::intrusive::list. - * If set to false, the container is a std::set. It is usually recommended to set it to true. + * If set to true, the underlying container representing a row is an boost::intrusive::list. + * If set to false, the container is a std::set. It is usually recommended to set it to true. */ static const bool has_intrusive_rows; /** diff --git a/src/Persistence_matrix/include/gudhi/Matrix.h b/src/Persistence_matrix/include/gudhi/Matrix.h index 1c9b8fa8be..a403ccaa81 100644 --- a/src/Persistence_matrix/include/gudhi/Matrix.h +++ b/src/Persistence_matrix/include/gudhi/Matrix.h @@ -51,8 +51,8 @@ #include #include -#include -#include +#include +#include #include #include @@ -168,7 +168,7 @@ class Matrix { */ using Bar = Persistence_interval; - //tags for boost to associate a row and a column to a same cell + //tags for boost to associate a row and a column to a same entry struct Matrix_row_tag; struct Matrix_column_tag; @@ -182,7 +182,7 @@ class Matrix { boost::intrusive::set_base_hook, boost::intrusive::link_mode >; - //Two dummies are necessary to avoid double inheritance as a cell can inherit both a row and a column hook. + //Two dummies are necessary to avoid double inheritance as an entry can inherit both a row and a column hook. struct Dummy_row_hook {}; struct Dummy_column_hook {}; @@ -200,69 +200,69 @@ class Matrix { >::type >::type; - //Option to store the column index within the cell (additionally to the row index). Necessary only with row access. - using Cell_column_index_option = + //Option to store the column index within the entry (additionally to the row index). Necessary only with row access. + using Entry_column_index_option = typename std::conditional, - Dummy_cell_column_index_mixin + Entry_column_index, + Dummy_entry_column_index_mixin >::type; - //Option to store the value of the cell. - //Unnecessary for values in Z_2 as there are always 1 (0-valued cells are never stored). - using Cell_field_element_option = + //Option to store the value of the entry. + //Unnecessary for values in Z_2 as there are always 1 (0-valued entries are never stored). + using Entry_field_element_option = typename std::conditional + Dummy_entry_field_element_mixin, + Entry_field_element >::type; /** - * @brief Type of a matrix cell. See @ref Cell for a more detailed description. + * @brief Type of a matrix entry. See @ref Entry for a more detailed description. */ - using Matrix_cell = Cell >; + using Matrix_entry = Entry >; /** - * @brief Default cell constructor/destructor, using classic new and delete. + * @brief Default entry constructor/destructor, using classic new and delete. * For now, only used as default value for columns constructed independently outside of the matrix by the user. * Could be used in the future when parallel options are implemented, as usual pools are not thread safe. */ - inline static New_cell_constructor defaultCellConstructor; + inline static New_entry_constructor defaultEntryConstructor; /** - * @brief Cell constructor/destructor used by the matrix. Uses a pool of cells to accelerate memory management, - * as cells are constructed and destroyed a lot during reduction, swaps or additions. + * @brief Entry constructor/destructor used by the matrix. Uses a pool of entries to accelerate memory management, + * as entries are constructed and destroyed a lot during reduction, swaps or additions. */ - using Cell_constructor = Pool_cell_constructor; + using Entry_constructor = Pool_entry_constructor; /** - * @brief Type used to identify a cell, for example when inserting a boundary. + * @brief Type used to identify an entry, for example when inserting a boundary. * If @ref PersistenceMatrixOptions::is_z2 is true, the type is an @ref IDIdx and corresponds to the row index of the - * cell (the cell value is assumed to be 1). If @ref PersistenceMatrixOptions::is_z2 is false, the type is a pair - * whose first element is the row index of the cell and the second element is the value of the cell (which again is + * entry (the entry value is assumed to be 1). If @ref PersistenceMatrixOptions::is_z2 is false, the type is a pair + * whose first element is the row index of the entry and the second element is the value of the entry (which again is * assumed to be non-zero). The column index of the row is always deduced from the context in which the type is used. */ - using Cell_representative = typename std::conditional >::type; /** - * @brief Compares two cells by their position in the row. They are assume to be in the same row. + * @brief Compares two entries by their position in the row. They are assume to be in the same row. */ - struct RowCellComp { - bool operator()(const Matrix_cell& c1, const Matrix_cell& c2) const { + struct RowEntryComp { + bool operator()(const Matrix_entry& c1, const Matrix_entry& c2) const { return c1.get_column_index() < c2.get_column_index(); } }; /** - * @brief Type of the rows stored in the matrix. Is either an intrusive list of @ref Matrix_cell (not ordered) if - * @ref PersistenceMatrixOptions::has_intrusive_rows is true, or a set of @ref Matrix_cell (ordered by + * @brief Type of the rows stored in the matrix. Is either an intrusive list of @ref Matrix_entry (not ordered) if + * @ref PersistenceMatrixOptions::has_intrusive_rows is true, or a set of @ref Matrix_entry (ordered by * column index) otherwise. */ using Row = typename std::conditional, boost::intrusive::base_hook >, - std::set + std::set >::type; using Row_container = @@ -355,43 +355,43 @@ class Matrix { >::type; struct Column_z2_settings{ - Column_z2_settings() : cellConstructor() {} - Column_z2_settings([[maybe_unused]] Characteristic characteristic) : cellConstructor() {} - Column_z2_settings(const Column_z2_settings& toCopy) : cellConstructor() {} + Column_z2_settings() : entryConstructor() {} + Column_z2_settings([[maybe_unused]] Characteristic characteristic) : entryConstructor() {} + Column_z2_settings(const Column_z2_settings& toCopy) : entryConstructor() {} - Cell_constructor cellConstructor; //will be replaced by more specific allocators depending on the column type. + Entry_constructor entryConstructor; //will be replaced by more specific allocators depending on the column type. }; struct Column_zp_settings { - Column_zp_settings() : operators(), cellConstructor() {} + Column_zp_settings() : operators(), entryConstructor() {} //purposely triggers operators() instead of operators(characteristic) as the "dummy" values for the different //operators can be different from -1. - Column_zp_settings(Characteristic characteristic) : operators(), cellConstructor() { + Column_zp_settings(Characteristic characteristic) : operators(), entryConstructor() { if (characteristic != static_cast(-1)) operators.set_characteristic(characteristic); } Column_zp_settings(const Column_zp_settings& toCopy) - : operators(toCopy.operators.get_characteristic()), cellConstructor() {} + : operators(toCopy.operators.get_characteristic()), entryConstructor() {} Field_operators operators; - Cell_constructor cellConstructor; //will be replaced by more specific allocators depending on the column type. + Entry_constructor entryConstructor; //will be replaced by more specific allocators depending on the column type. }; // struct Column_z2_with_rows_settings { - // Column_z2_with_rows_settings() : cellConstructor(), rows(nullptr) {} + // Column_z2_with_rows_settings() : entryConstructor(), rows(nullptr) {} // Column_z2_with_rows_settings([[maybe_unused]] Characteristic characteristic) - // : cellConstructor(), rows(nullptr) {} + // : entryConstructor(), rows(nullptr) {} - // Cell_constructor cellConstructor; + // Entry_constructor entryConstructor; // Row_container* rows; // }; // struct Column_zp_with_rows_settings { - // Column_zp_with_rows_settings() : operators(), cellConstructor(), rows(nullptr) {} + // Column_zp_with_rows_settings() : operators(), entryConstructor(), rows(nullptr) {} // Column_zp_with_rows_settings(Characteristic characteristic) - // : operators(characteristic), cellConstructor(), rows(nullptr) {} + // : operators(characteristic), entryConstructor(), rows(nullptr) {} // Field_operators operators; - // Cell_constructor cellConstructor; + // Entry_constructor entryConstructor; // Row_container* rows; // }; @@ -548,7 +548,7 @@ class Matrix { PersistenceMatrixOptions::column_indexation_type == Column_indexation_types::POSITION, void, - std::vector + std::vector >::type; /** @@ -556,14 +556,14 @@ class Matrix { */ Matrix(); /** - * @brief Constructs a new matrix from the given ranges of @ref Cell_representative. Each range corresponds to a column (the - * order of the ranges are preserved). The content of the ranges is assumed to be sorted by increasing IDs. If the - * columns are representing a boundary matrix, the IDs of the simplices are also assumed to be consecutive, ordered by - * filtration value, starting with 0. + * @brief Constructs a new matrix from the given ranges of @ref Entry_representative. Each range corresponds to a + * column (the order of the ranges are preserved). The content of the ranges is assumed to be sorted by increasing + * IDs. If the columns are representing a boundary matrix, the IDs of the simplices are also assumed to be + * consecutive, ordered by filtration value, starting with 0. * * See @ref mp_matrices "matrix descriptions" for further details on how the given matrix is handled. * - * @tparam Container Range type for @ref Cell_representative ranges. Assumed to have a begin(), end() and size() + * @tparam Container Range type for @ref Entry_representative ranges. Assumed to have a begin(), end() and size() * method. * @param columns For a @ref basematrix "base matrix", the columns are copied as is. If options related to homology * are activated, @p columns is interpreted as a boundary matrix of a **simplicial** complex. In this case, @@ -629,7 +629,8 @@ class Matrix { * @ref Matrix(const std::function&, const std::function&) * for more information about the comparators. * - * @tparam Boundary_range Range type for @ref Cell_representative ranges. Assumed to have a begin(), end() and size() method. + * @tparam Boundary_range Range type for @ref Entry_representative ranges. Assumed to have a begin(), end() and size() + * method. * @param orderedBoundaries Vector of ordered boundaries in filtration order. Indexed continuously starting at 0. * @param birthComparator Method taking two @ref PosIdx indices as parameter and returns true if and only if the first * face is associated to a bar with strictly smaller birth than the bar associated to the second one. @@ -697,7 +698,7 @@ class Matrix { * Do not change the value of the characteristic once used. * * @warning The coefficient values stored in the matrix are stored after computing the corresponding modulo. - * Therefore, changing the characteristic after is very likely to invalidate all cell values. + * Therefore, changing the characteristic after is very likely to invalidate all entry values. * * @param characteristic The characteristic to set. */ @@ -706,25 +707,25 @@ class Matrix { // (TODO: if there is no row access and the column type corresponds to the internal column type of the matrix, // moving the column instead of copying it should be possible. Is it worth implementing it?) /** - * @brief Inserts a new ordered column at the end of the matrix by copying the given range of @ref Cell_representative. - * The content of the range is assumed to be sorted by increasing ID value. + * @brief Inserts a new ordered column at the end of the matrix by copying the given range of + * @ref Entry_representative. The content of the range is assumed to be sorted by increasing ID value. * * Only available for @ref basematrix "base matrices". * Otherwise use @ref insert_boundary which will deduce a new column from the boundary given. * - * @tparam Container Range of @ref Cell_representative. Assumed to have a begin(), end() and size() method. + * @tparam Container Range of @ref Entry_representative. Assumed to have a begin(), end() and size() method. * @param column Column to be inserted. */ template void insert_column(const Container& column); /** - * @brief Inserts a new ordered column at the given index by copying the given range of @ref Cell_representative. + * @brief Inserts a new ordered column at the given index by copying the given range of @ref Entry_representative. * There should not be any other column inserted at that index which was not explicitly removed before. * The content of the range is assumed to be sorted by increasing ID value. * * Only available for @ref basematrix "base matrices" without column compression and without row access. * - * @tparam Container Range of @ref Cell_representative. Assumed to have a begin(), end() and size() method. + * @tparam Container Range of @ref Entry_representative. Assumed to have a begin(), end() and size() method. * @param column Column to be inserted. * @param columnIndex @ref MatIdx index to which the column has to be inserted. */ @@ -741,7 +742,7 @@ class Matrix { * instead by indicating the face ID used in the boundaries when the face is inserted. * * Different to the constructor, the boundaries do not have to come from a simplicial complex, but also from - * a more general cell complex. This includes cubical complexes or Morse complexes for example. + * a more general entry complex. This includes cubical complexes or Morse complexes for example. * * The content of the new column will vary depending on the underlying @ref mp_matrices "type of the matrix": * - If it is a @ref basematrix "basic matrix" type, the boundary is copied as it is, i.e., the method is equivalent @@ -756,7 +757,7 @@ class Matrix { * older column IDIdxs`, where the combination is deduced while reducing the given boundary. If the barcode is stored, * it will also be updated. * - * @tparam Boundary_range Range of @ref Cell_representative. Assumed to have a begin(), end() and size() method. + * @tparam Boundary_range Range of @ref Entry_representative. Assumed to have a begin(), end() and size() method. * @param boundary Boundary generating the new column. The content should be ordered by ID. * @param dim Dimension of the face whose boundary is given. If the complex is simplicial, * this parameter can be omitted as it can be deduced from the size of the boundary. @@ -775,7 +776,7 @@ class Matrix { * for @ref mp_matrices "non-basic matrices", the faces are inserted by order of filtration), it is sufficient to * indicate the ID of the face being inserted. * - * @tparam Boundary_range Range of @ref Cell_representative. Assumed to have a begin(), end() and size() method. + * @tparam Boundary_range Range of @ref Entry_representative. Assumed to have a begin(), end() and size() method. * @param faceIndex @ref IDIdx index to use to identify the new face. * @param boundary Boundary generating the new column. The indices of the boundary have to correspond to the * @p faceIndex values of precedent calls of the method for the corresponding faces and should be ordered in @@ -859,8 +860,8 @@ class Matrix { /** * @brief Only available for @ref basematrix "base matrices" without column compression and if * @ref PersistenceMatrixOptions::has_map_column_container is true. Otherwise, see @ref remove_last. Erases the given - * column from the matrix. If @ref PersistenceMatrixOptions::has_row_access is also true, the deleted column cells are - * also automatically removed from their respective rows. + * column from the matrix. If @ref PersistenceMatrixOptions::has_row_access is also true, the deleted column entries + * are also automatically removed from their respective rows. * * @param columnIndex @ref MatIdx index of the column to remove. */ @@ -879,11 +880,11 @@ class Matrix { * - @ref chainmatrix "chain matrix": only available if @ref PersistenceMatrixOptions::has_row_access and * @ref PersistenceMatrixOptions::has_removable_rows are true. Assumes that the row is empty and removes it. * - * @warning The removed rows are always assumed to be empty. If it is not the case, the deleted row cells are not + * @warning The removed rows are always assumed to be empty. If it is not the case, the deleted row entries are not * removed from their columns. And in the case of intrusive rows, this will generate a segmentation fault when - * the column cells are destroyed later. The row access is just meant as a "read only" access to the rows and the + * the column entries are destroyed later. The row access is just meant as a "read only" access to the rows and the * @ref erase_empty_row method just as a way to specify that a row is empty and can therefore be removed from - * dictionaries. This allows to avoid testing the emptiness of a row at each column cell removal, what can be quite + * dictionaries. This allows to avoid testing the emptiness of a row at each column entry removal, what can be quite * frequent. * * @param rowIndex @ref rowindex "Row index" of the empty row to remove. @@ -992,19 +993,19 @@ class Matrix { std::enable_if_t > add_to(Integer_index sourceColumnIndex, Integer_index targetColumnIndex); /** - * @brief Adds the given range of @ref Cell onto the column at @p targetColumnIndex in the matrix. Only available + * @brief Adds the given range of @ref Entry onto the column at @p targetColumnIndex in the matrix. Only available * for @ref basematrix "basic matrices". * * For @ref basematrix "basic matrices" with column compression, the range is summed onto the representative, which * means that all column compressed together with the target column are affected by the change, not only the target. * - * @tparam Cell_range Range of @ref Cell. Needs a begin() and end() method. A column index does not need to be - * stored in the cells, even if @ref PersistenceMatrixOptions::has_row_access is true. - * @param sourceColumn Source @ref Cell range. + * @tparam Entry_range Range of @ref Entry. Needs a begin() and end() method. A column index does not need to be + * stored in the entries, even if @ref PersistenceMatrixOptions::has_row_access is true. + * @param sourceColumn Source @ref Entry range. * @param targetColumnIndex @ref MatIdx index of the target column. */ - template - std::enable_if_t > add_to(const Cell_range& sourceColumn, Index targetColumnIndex); + template + std::enable_if_t > add_to(const Entry_range& sourceColumn, Index targetColumnIndex); /** * @brief Multiplies the target column with the coefficient and then adds the source column to it. @@ -1027,21 +1028,21 @@ class Matrix { int coefficient, Integer_index targetColumnIndex); /** - * @brief Multiplies the target column with the coefficient and then adds the given range of @ref Cell to it. + * @brief Multiplies the target column with the coefficient and then adds the given range of @ref Entry to it. * That is: `targetColumn = (targetColumn * coefficient) + sourceColumn`. Only available for * @ref basematrix "basic matrices". * * For @ref basematrix "basic matrices" with column compression, the range is summed onto the representative, which * means that all column compressed together with the target column are affected by the change, not only the target. * - * @tparam Cell_range Range of @ref Cell. Needs a begin() and end() method. A column index does not need to be - * stored in the cells, even if @ref PersistenceMatrixOptions::has_row_access is true. - * @param sourceColumn Source @ref Cell range. + * @tparam Entry_range Range of @ref Entry. Needs a begin() and end() method. A column index does not need to be + * stored in the entries, even if @ref PersistenceMatrixOptions::has_row_access is true. + * @param sourceColumn Source @ref Entry range. * @param coefficient Value to multiply. * @param targetColumnIndex @ref MatIdx index of the target column. */ - template - std::enable_if_t > multiply_target_and_add_to(const Cell_range& sourceColumn, + template + std::enable_if_t > multiply_target_and_add_to(const Entry_range& sourceColumn, int coefficient, Index targetColumnIndex); @@ -1073,40 +1074,40 @@ class Matrix { * For @ref basematrix "basic matrices" with column compression, the range is summed onto the representative, which * means that all column compressed together with the target column are affected by the change, not only the target. * - * @tparam Cell_range Range of @ref Cell. Needs a begin() and end() method. A column index does not need to be - * stored in the cells, even if @ref PersistenceMatrixOptions::has_row_access is true. + * @tparam Entry_range Range of @ref Entry. Needs a begin() and end() method. A column index does not need to be + * stored in the entries, even if @ref PersistenceMatrixOptions::has_row_access is true. * @param coefficient Value to multiply. - * @param sourceColumn Source @ref Cell range. + * @param sourceColumn Source @ref Entry range. * @param targetColumnIndex @ref MatIdx index of the target column. */ - template - std::enable_if_t > multiply_source_and_add_to(int coefficient, - const Cell_range& sourceColumn, + template + std::enable_if_t > multiply_source_and_add_to(int coefficient, + const Entry_range& sourceColumn, Index targetColumnIndex); /** - * @brief Zeroes the cell at the given coordinates. Not available for @ref chainmatrix "chain matrices" and for + * @brief Zeroes the entry at the given coordinates. Not available for @ref chainmatrix "chain matrices" and for * @ref basematrix "base matrices" with column compression. In general, should be used with care with * @ref mp_matrices "non-basic matrices" to not destroy the validity of the persistence related properties of the * matrix. * * For @ref boundarymatrix "RU matrices", equivalent to - * @ref zero_cell(Index columnIndex, ID_index rowIndex, bool inR) "zero_cell(columnIndex, rowIndex, true)". + * @ref zero_entry(Index columnIndex, ID_index rowIndex, bool inR) "zero_entry(columnIndex, rowIndex, true)". * - * @param columnIndex @ref MatIdx index of the column of the cell. - * @param rowIndex @ref rowindex "Row index" of the row of the cell. + * @param columnIndex @ref MatIdx index of the column of the entry. + * @param rowIndex @ref rowindex "Row index" of the row of the entry. */ - void zero_cell(Index columnIndex, ID_index rowIndex); + void zero_entry(Index columnIndex, ID_index rowIndex); /** - * @brief Only available for @ref boundarymatrix "RU matrices". Zeroes the cell at the given coordinates in \f$ R \f$ + * @brief Only available for @ref boundarymatrix "RU matrices". Zeroes the entry at the given coordinates in \f$ R \f$ * if @p inR is true or in \f$ U \f$ if @p inR is false. Should be used with care to not destroy the validity of the * persistence related properties of the matrix. * - * @param columnIndex @ref MatIdx index of the column of the cell. - * @param rowIndex @ref rowindex "Row index" of the row of the cell. + * @param columnIndex @ref MatIdx index of the column of the entry. + * @param rowIndex @ref rowindex "Row index" of the row of the entry. * @param inR Boolean indicating in which matrix to zero: if true in \f$ R \f$ and if false in \f$ U \f$. */ - void zero_cell(Index columnIndex, ID_index rowIndex, bool inR); + void zero_entry(Index columnIndex, ID_index rowIndex, bool inR); /** * @brief Zeroes the column at the given index. Not available for @ref chainmatrix "chain matrices" and for * @ref basematrix "base matrices" with column compression. In general, should be used with care with @@ -1129,29 +1130,29 @@ class Matrix { */ void zero_column(Index columnIndex, bool inR); /** - * @brief Indicates if the cell at given coordinates has value zero. + * @brief Indicates if the entry at given coordinates has value zero. * * For @ref boundarymatrix "RU matrices", equivalent to - * @ref is_zero_cell(Index columnIndex, ID_index rowIndex, bool inR) const - * "is_zero_cell(columnIndex, rowIndex, true)". + * @ref is_zero_entry(Index columnIndex, ID_index rowIndex, bool inR) const + * "is_zero_entry(columnIndex, rowIndex, true)". * - * @param columnIndex @ref MatIdx index of the column of the cell. - * @param rowIndex @ref rowindex "Row index" of the row of the cell. - * @return true If the cell has value zero. + * @param columnIndex @ref MatIdx index of the column of the entry. + * @param rowIndex @ref rowindex "Row index" of the row of the entry. + * @return true If the entry has value zero. * @return false Otherwise. */ - bool is_zero_cell(Index columnIndex, ID_index rowIndex); + bool is_zero_entry(Index columnIndex, ID_index rowIndex); /** - * @brief Only available for @ref boundarymatrix "RU matrices". Indicates if the cell at given coordinates has value + * @brief Only available for @ref boundarymatrix "RU matrices". Indicates if the entry at given coordinates has value * zero in \f$ R \f$ if @p inR is true or in \f$ U \f$ if @p inR is false. * - * @param columnIndex @ref MatIdx index of the column of the cell. - * @param rowIndex @ref rowindex "Row index" of the row of the cell. + * @param columnIndex @ref MatIdx index of the column of the entry. + * @param rowIndex @ref rowindex "Row index" of the row of the entry. * @param inR Boolean indicating in which matrix to look: if true in \f$ R \f$ and if false in \f$ U \f$. - * @return true If the cell has value zero. + * @return true If the entry has value zero. * @return false Otherwise. */ - bool is_zero_cell(Index columnIndex, ID_index rowIndex, bool inR) const; + bool is_zero_entry(Index columnIndex, ID_index rowIndex, bool inR) const; /** * @brief Indicates if the column at given index has value zero. * @@ -1394,7 +1395,7 @@ class Matrix { >::type; // Field_operators* operators_; - // Cell_constructor* cellPool_; + // Entry_constructor* entryPool_; Column_settings* colSettings_; //pointer because the of swap operator on matrix_ which also stores the pointer Underlying_matrix matrix_; @@ -1746,9 +1747,9 @@ inline std::enable_if_t > Matrix -template -inline std::enable_if_t > Matrix::add_to( - const Cell_range& sourceColumn, Index targetColumnIndex) +template +inline std::enable_if_t > Matrix::add_to( + const Entry_range& sourceColumn, Index targetColumnIndex) { static_assert(!isNonBasic, "For boundary or chain matrices, only additions with columns inside the matrix is allowed to maintain " @@ -1771,9 +1772,9 @@ inline std::enable_if_t > Matrix -template -inline std::enable_if_t > Matrix::multiply_target_and_add_to( - const Cell_range& sourceColumn, int coefficient, Index targetColumnIndex) +template +inline std::enable_if_t > Matrix::multiply_target_and_add_to( + const Entry_range& sourceColumn, int coefficient, Index targetColumnIndex) { static_assert(!isNonBasic, "For boundary or chain matrices, only additions with columns inside the matrix is allowed to maintain " @@ -1801,9 +1802,9 @@ inline std::enable_if_t > Matrix -template -inline std::enable_if_t > Matrix::multiply_source_and_add_to( - int coefficient, const Cell_range& sourceColumn, Index targetColumnIndex) +template +inline std::enable_if_t > Matrix::multiply_source_and_add_to( + int coefficient, const Entry_range& sourceColumn, Index targetColumnIndex) { static_assert(!isNonBasic, "For boundary or chain matrices, only additions with columns inside the matrix is allowed to maintain " @@ -1818,16 +1819,16 @@ inline std::enable_if_t > Matrix -inline void Matrix::zero_cell(Index columnIndex, ID_index rowIndex) +inline void Matrix::zero_entry(Index columnIndex, ID_index rowIndex) { static_assert(PersistenceMatrixOptions::is_of_boundary_type && !PersistenceMatrixOptions::has_column_compression, - "'zero_cell' is not available for the chosen options."); + "'zero_entry' is not available for the chosen options."); - return matrix_.zero_cell(columnIndex, rowIndex); + return matrix_.zero_entry(columnIndex, rowIndex); } template -inline void Matrix::zero_cell(Index columnIndex, ID_index rowIndex, bool inR) +inline void Matrix::zero_entry(Index columnIndex, ID_index rowIndex, bool inR) { // TODO: I don't think there is a particular reason why the indexation is forced, should be removed. static_assert( @@ -1836,7 +1837,7 @@ inline void Matrix::zero_cell(Index columnIndex, ID_in PersistenceMatrixOptions::column_indexation_type != Column_indexation_types::IDENTIFIER, "Only enabled for RU matrices."); - return matrix_.zero_cell(columnIndex, rowIndex, inR); + return matrix_.zero_entry(columnIndex, rowIndex, inR); } template @@ -1862,13 +1863,13 @@ inline void Matrix::zero_column(Index columnIndex, boo } template -inline bool Matrix::is_zero_cell(Index columnIndex, ID_index rowIndex) +inline bool Matrix::is_zero_entry(Index columnIndex, ID_index rowIndex) { - return matrix_.is_zero_cell(columnIndex, rowIndex); + return matrix_.is_zero_entry(columnIndex, rowIndex); } template -inline bool Matrix::is_zero_cell(Index columnIndex, ID_index rowIndex, bool inR) const +inline bool Matrix::is_zero_entry(Index columnIndex, ID_index rowIndex, bool inR) const { // TODO: I don't think there is a particular reason why the indexation is forced, should be removed. static_assert( @@ -1877,7 +1878,7 @@ inline bool Matrix::is_zero_cell(Index columnIndex, ID PersistenceMatrixOptions::column_indexation_type != Column_indexation_types::IDENTIFIER, "Only enabled for RU matrices."); - return matrix_.is_zero_cell(columnIndex, rowIndex, inR); + return matrix_.is_zero_entry(columnIndex, rowIndex, inR); } template diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Base_matrix.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Base_matrix.h index 9eff178fc5..c78cf41107 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Base_matrix.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Base_matrix.h @@ -29,7 +29,7 @@ namespace persistence_matrix { * @ingroup persistence_matrix * * @brief A @ref basematrix "basic matrix" structure allowing to easily manipulate and access entire columns and rows, - * but not individual cells. + * but not individual entries. * * @tparam Master_matrix An instantiation of @ref Matrix from which all types and options are deduced. */ @@ -44,14 +44,14 @@ class Base_matrix : public Master_matrix::template Base_swap_option void insert_column(const Container& column); /** - * @brief Inserts a new ordered column at the given index by copying the given range of @ref Matrix::Cell_representative. + * @brief Inserts a new ordered column at the given index by copying the given range of + * @ref Matrix::Entry_representative. * There should not be any other column inserted at that index which was not explicitly removed before. * The content of the range is assumed to be sorted by increasing ID value. * Not available when row access is enabled. * - * @tparam Container Range of @ref Matrix::Cell_representative. Assumed to have a begin(), end() and size() method. - * @param column Range of @ref Matrix::Cell_representative from which the column has to be constructed. Assumed to be + * @tparam Container Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() method. + * @param column Range of @ref Matrix::Entry_representative from which the column has to be constructed. Assumed to be * ordered by increasing ID value. * @param columnIndex @ref MatIdx index to which the column has to be inserted. */ @@ -125,9 +126,10 @@ class Base_matrix : public Master_matrix::template Base_swap_option @@ -136,7 +138,7 @@ class Base_matrix : public Master_matrix::template Base_swap_option - void add_to(const Cell_range_or_column_index& sourceColumn, Index targetColumnIndex); + template + void add_to(const Entry_range_or_column_index& sourceColumn, Index targetColumnIndex); /** * @brief Multiplies the target column with the coefficient and then adds the source column to it. * That is: `targetColumn = (targetColumn * coefficient) + sourceColumn`. * - * @tparam Cell_range_or_column_index Either a range of @ref Cell with a begin() and end() method, + * @tparam Entry_range_or_column_index Either a range of @ref Entry with a begin() and end() method, * or any integer type. - * @param sourceColumn Either a cell range or the @ref MatIdx index of the column to add. + * @param sourceColumn Either an entry range or the @ref MatIdx index of the column to add. * @param coefficient Value to multiply. * @param targetColumnIndex @ref MatIdx index of the target column. */ - template - void multiply_target_and_add_to(const Cell_range_or_column_index& sourceColumn, + template + void multiply_target_and_add_to(const Entry_range_or_column_index& sourceColumn, const Field_element& coefficient, Index targetColumnIndex); /** * @brief Multiplies the source column with the coefficient before adding it to the target column. * That is: `targetColumn += (coefficient * sourceColumn)`. The source column will **not** be modified. * - * @tparam Cell_range_or_column_index Either a range of @ref Cell with a begin() and end() method, + * @tparam Entry_range_or_column_index Either a range of @ref Entry with a begin() and end() method, * or any integer type. * @param coefficient Value to multiply. - * @param sourceColumn Either a cell range or the @ref MatIdx index of the column to add. + * @param sourceColumn Either an entry range or the @ref MatIdx index of the column to add. * @param targetColumnIndex @ref MatIdx index of the target column. */ - template + template void multiply_source_and_add_to(const Field_element& coefficient, - const Cell_range_or_column_index& sourceColumn, + const Entry_range_or_column_index& sourceColumn, Index targetColumnIndex); /** - * @brief Zeroes the cell at the given coordinates. + * @brief Zeroes the entry at the given coordinates. * - * @param columnIndex @ref MatIdx index of the column of the cell. - * @param rowIndex @ref rowindex "Row index" of the row of the cell. + * @param columnIndex @ref MatIdx index of the column of the entry. + * @param rowIndex @ref rowindex "Row index" of the row of the entry. */ - void zero_cell(Index columnIndex, Index rowIndex); + void zero_entry(Index columnIndex, Index rowIndex); /** * @brief Zeroes the column at the given index. * @@ -265,14 +267,14 @@ class Base_matrix : public Master_matrix::template Base_swap_option >; using RA_opt = typename Master_matrix::Matrix_row_access_option; using Column_container = typename Master_matrix::Column_container; - using Cell_representative = + using Entry_representative = typename std::conditional @@ -330,7 +332,7 @@ class Base_matrix : public Master_matrix::template Base_swap_option void _insert(const Container& column, Index columnIndex, Dimension dim); @@ -513,11 +515,11 @@ inline typename Base_matrix::Index Base_matrix::ge } template -template -inline void Base_matrix::add_to(const Cell_range_or_column_index& sourceColumn, +template +inline void Base_matrix::add_to(const Entry_range_or_column_index& sourceColumn, Index targetColumnIndex) { - if constexpr (std::is_integral_v) { + if constexpr (std::is_integral_v) { _get_column(targetColumnIndex) += _get_column(sourceColumn); } else { _get_column(targetColumnIndex) += sourceColumn; @@ -525,12 +527,12 @@ inline void Base_matrix::add_to(const Cell_range_or_column_index& } template -template -inline void Base_matrix::multiply_target_and_add_to(const Cell_range_or_column_index& sourceColumn, +template +inline void Base_matrix::multiply_target_and_add_to(const Entry_range_or_column_index& sourceColumn, const Field_element& coefficient, Index targetColumnIndex) { - if constexpr (std::is_integral_v) { + if constexpr (std::is_integral_v) { _get_column(targetColumnIndex).multiply_target_and_add(coefficient, _get_column(sourceColumn)); } else { _get_column(targetColumnIndex).multiply_target_and_add(coefficient, sourceColumn); @@ -538,12 +540,12 @@ inline void Base_matrix::multiply_target_and_add_to(const Cell_ra } template -template +template inline void Base_matrix::multiply_source_and_add_to(const Field_element& coefficient, - const Cell_range_or_column_index& sourceColumn, + const Entry_range_or_column_index& sourceColumn, Index targetColumnIndex) { - if constexpr (std::is_integral_v) { + if constexpr (std::is_integral_v) { _get_column(targetColumnIndex).multiply_source_and_add(_get_column(sourceColumn), coefficient); } else { _get_column(targetColumnIndex).multiply_source_and_add(sourceColumn, coefficient); @@ -551,7 +553,7 @@ inline void Base_matrix::multiply_source_and_add_to(const Field_e } template -inline void Base_matrix::zero_cell(Index columnIndex, Index rowIndex) +inline void Base_matrix::zero_entry(Index columnIndex, Index rowIndex) { _get_column(columnIndex).clear(_get_real_row_index(rowIndex)); } @@ -562,7 +564,7 @@ inline void Base_matrix::zero_column(Index columnIndex) { } template -inline bool Base_matrix::is_zero_cell(Index columnIndex, Index rowIndex) const +inline bool Base_matrix::is_zero_entry(Index columnIndex, Index rowIndex) const { return !(_get_column(columnIndex).is_non_zero(_get_real_row_index(rowIndex))); } @@ -614,8 +616,8 @@ inline void Base_matrix::print() std::cout << "Row Matrix:\n"; for (Index i = 0; i < nextInsertIndex_; ++i) { const auto& row = RA_opt::rows_[i]; - for (const auto& cell : row) { - std::cout << cell.get_column_index() << " "; + for (const auto& entry : row) { + std::cout << entry.get_column_index() << " "; } std::cout << "(" << i << ")\n"; } diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Base_matrix_with_column_compression.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Base_matrix_with_column_compression.h index 009e016517..cdb3efb6e8 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Base_matrix_with_column_compression.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Base_matrix_with_column_compression.h @@ -45,18 +45,18 @@ template class Base_matrix_with_column_compression : protected Master_matrix::Matrix_row_access_option { public: - using Index = typename Master_matrix::Index; /**< Container index type. */ - using Dimension = typename Master_matrix::Dimension; /**< Dimension value type. */ + using Index = typename Master_matrix::Index; /**< Container index type. */ + using Dimension = typename Master_matrix::Dimension; /**< Dimension value type. */ /** * @brief Field operators class. Necessary only if @ref PersistenceMatrixOptions::is_z2 is false. */ using Field_operators = typename Master_matrix::Field_operators; - using Field_element = typename Master_matrix::Element; /**< Field element value type. */ - using Row = typename Master_matrix::Row; /**< Row type, - only necessary with row access option. */ - using Cell_constructor = typename Master_matrix::Cell_constructor; /**< Factory of @ref Cell classes. */ - using Column_settings = typename Master_matrix::Column_settings; /**< Structure giving access to the columns to - necessary external classes. */ + using Field_element = typename Master_matrix::Element; /**< Field element value type. */ + using Row = typename Master_matrix::Row; /**< Row type, + only necessary with row access option. */ + using Entry_constructor = typename Master_matrix::Entry_constructor; /**< Factory of @ref Entry classes. */ + using Column_settings = typename Master_matrix::Column_settings; /**< Structure giving access to the columns to + necessary external classes. */ /** * @brief Type for columns. Only one for each "column class" is explicitly constructed. @@ -119,9 +119,9 @@ class Base_matrix_with_column_compression : protected Master_matrix::Matrix_row_ * If no identical column already existed, a copy of the column is stored. If an identical one existed, no new * column is constructed and the relationship between the two is registered in an union-find structure. * - * @tparam Container Range type for @ref Matrix::Cell_representative ranges. + * @tparam Container Range type for @ref Matrix::Entry_representative ranges. * Assumed to have a begin(), end() and size() method. - * @param columns A vector of @ref Matrix::Cell_representative ranges to construct the columns from. + * @param columns A vector of @ref Matrix::Entry_representative ranges to construct the columns from. * The content of the ranges are assumed to be sorted by increasing ID value. * @param colSettings Pointer to an existing setting structure for the columns. The structure should contain all * the necessary external classes specifically necessary for the choosen column type, such as custom allocators. @@ -162,10 +162,10 @@ class Base_matrix_with_column_compression : protected Master_matrix::Matrix_row_ /** * @brief Inserts a new ordered column at the end of the matrix by copying the given range of - * @ref Matrix::Cell_representative. The content of the range is assumed to be sorted by increasing ID value. + * @ref Matrix::Entry_representative. The content of the range is assumed to be sorted by increasing ID value. * - * @tparam Container Range of @ref Matrix::Cell_representative. Assumed to have a begin(), end() and size() method. - * @param column Range of @ref Matrix::Cell_representative from which the column has to be constructed. Assumed to be + * @tparam Container Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() method. + * @param column Range of @ref Matrix::Entry_representative from which the column has to be constructed. Assumed to be * ordered by increasing ID value. */ template @@ -173,9 +173,10 @@ class Base_matrix_with_column_compression : protected Master_matrix::Matrix_row_ /** * @brief Same as @ref insert_column, only for interface purposes. The given dimension is ignored and not stored. * - * @tparam Boundary_range Range of @ref Matrix::Cell_representative. Assumed to have a begin(), end() and size() method. - * @param boundary Range of @ref Matrix::Cell_representative from which the column has to be constructed. Assumed to be - * ordered by increasing ID value. + * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() + * method. + * @param boundary Range of @ref Matrix::Entry_representative from which the column has to be constructed. Assumed to + * be ordered by increasing ID value. * @param dim Ignored. */ template @@ -205,11 +206,11 @@ class Base_matrix_with_column_compression : protected Master_matrix::Matrix_row_ * @brief If @ref PersistenceMatrixOptions::has_row_access and @ref PersistenceMatrixOptions::has_removable_rows * are true: assumes that the row is empty and removes it. Otherwise, does nothing. * - * @warning The removed rows are always assumed to be empty. If it is not the case, the deleted row cells are not + * @warning The removed rows are always assumed to be empty. If it is not the case, the deleted row entries are not * removed from their columns. And in the case of intrusive rows, this will generate a segmentation fault when - * the column cells are destroyed later. The row access is just meant as a "read only" access to the rows and the + * the column entries are destroyed later. The row access is just meant as a "read only" access to the rows and the * @ref erase_empty_row method just as a way to specify that a row is empty and can therefore be removed from - * dictionaries. This allows to avoid testing the emptiness of a row at each column cell removal, what can be + * dictionaries. This allows to avoid testing the emptiness of a row at each column entry removal, what can be * quite frequent. * * @param rowIndex @ref rowindex "Row index" of the empty row. @@ -229,13 +230,13 @@ class Base_matrix_with_column_compression : protected Master_matrix::Matrix_row_ * The representatives of redundant columns are summed together, which means that * all column compressed together with the target column are affected by the change, not only the target. * - * @tparam Cell_range_or_column_index Either a range of @ref Cell with a begin() and end() method, + * @tparam Entry_range_or_column_index Either a range of @ref Entry with a begin() and end() method, * or any integer type. - * @param sourceColumn Either a cell range or the @ref MatIdx index of the column to add. + * @param sourceColumn Either an entry range or the @ref MatIdx index of the column to add. * @param targetColumnIndex @ref MatIdx index of the target column. */ - template - void add_to(const Cell_range_or_column_index& sourceColumn, Index targetColumnIndex); + template + void add_to(const Entry_range_or_column_index& sourceColumn, Index targetColumnIndex); /** * @brief Multiplies the target column with the coefficient and then adds the source column to it. * That is: `targetColumn = (targetColumn * coefficient) + sourceColumn`. @@ -243,14 +244,14 @@ class Base_matrix_with_column_compression : protected Master_matrix::Matrix_row_ * The representatives of redundant columns are summed together, which means that * all column compressed together with the target column are affected by the change, not only the target. * - * @tparam Cell_range_or_column_index Either a range of @ref Cell with a begin() and end() method, + * @tparam Entry_range_or_column_index Either a range of @ref Entry with a begin() and end() method, * or any integer type. - * @param sourceColumn Either a @ref Cell range or the @ref MatIdx index of the column to add. + * @param sourceColumn Either a @ref Entry range or the @ref MatIdx index of the column to add. * @param coefficient Value to multiply. * @param targetColumnIndex @ref MatIdx index of the target column. */ - template - void multiply_target_and_add_to(const Cell_range_or_column_index& sourceColumn, + template + void multiply_target_and_add_to(const Entry_range_or_column_index& sourceColumn, const Field_element& coefficient, Index targetColumnIndex); /** @@ -260,26 +261,26 @@ class Base_matrix_with_column_compression : protected Master_matrix::Matrix_row_ * The representatives of redundant columns are summed together, which means that * all column compressed together with the target column are affected by the change, not only the target. * - * @tparam Cell_range_or_column_index Either a range of @ref Cell with a begin() and end() method, + * @tparam Entry_range_or_column_index Either a range of @ref Entry with a begin() and end() method, * or any integer type. * @param coefficient Value to multiply. - * @param sourceColumn Either a @ref Cell range or the @ref MatIdx index of the column to add. + * @param sourceColumn Either a @ref Entry range or the @ref MatIdx index of the column to add. * @param targetColumnIndex @ref MatIdx index of the target column. */ - template + template void multiply_source_and_add_to(const Field_element& coefficient, - const Cell_range_or_column_index& sourceColumn, + const Entry_range_or_column_index& sourceColumn, Index targetColumnIndex); /** - * @brief Indicates if the cell at given coordinates has value zero. + * @brief Indicates if the entry at given coordinates has value zero. * - * @param columnIndex @ref MatIdx index of the column of the cell. - * @param rowIndex @ref rowindex "Row index" of the row of the cell. - * @return true If the cell has value zero. + * @param columnIndex @ref MatIdx index of the column of the entry. + * @param rowIndex @ref rowindex "Row index" of the row of the entry. + * @return true If the entry has value zero. * @return false Otherwise. */ - bool is_zero_cell(Index columnIndex, Index rowIndex); + bool is_zero_entry(Index columnIndex, Index rowIndex); /** * @brief Indicates if the column at given index has value zero. * @@ -292,7 +293,7 @@ class Base_matrix_with_column_compression : protected Master_matrix::Matrix_row_ /** * @brief Resets the matrix to an empty matrix. * - * @param colSettings Pointer to the cell factory. + * @param colSettings Pointer to the entry factory. */ void reset(Column_settings* colSettings) { columnToRep_.clear_and_dispose(Delete_disposer(this)); @@ -346,7 +347,7 @@ class Base_matrix_with_column_compression : protected Master_matrix::Matrix_row_ std::vector repToColumn_; /**< Map from the representative index to the representative Column. */ Index nextColumnIndex_; /**< Next unused column index. */ - Column_settings* colSettings_; /**< Cell factory. */ + Column_settings* colSettings_; /**< Entry factory. */ /** * @brief Column factory. Has to be a pointer as Simple_object_pool is not swappable, so their addresses have to be * exchanged instead. @@ -519,15 +520,15 @@ Base_matrix_with_column_compression::get_number_of_columns() cons } template -template -inline void Base_matrix_with_column_compression::add_to(const Cell_range_or_column_index& sourceColumn, +template +inline void Base_matrix_with_column_compression::add_to(const Entry_range_or_column_index& sourceColumn, Index targetColumnIndex) { // handle case where targetRep == sourceRep? Index targetRep = columnClasses_.find_set(targetColumnIndex); Column& target = *repToColumn_[targetRep]; columnToRep_.erase(target); - if constexpr (std::is_integral_v) { + if constexpr (std::is_integral_v) { target += get_column(sourceColumn); } else { target += sourceColumn; @@ -536,15 +537,15 @@ inline void Base_matrix_with_column_compression::add_to(const Cel } template -template +template inline void Base_matrix_with_column_compression::multiply_target_and_add_to( - const Cell_range_or_column_index& sourceColumn, const Field_element& coefficient, Index targetColumnIndex) + const Entry_range_or_column_index& sourceColumn, const Field_element& coefficient, Index targetColumnIndex) { // handle case where targetRep == sourceRep? Index targetRep = columnClasses_.find_set(targetColumnIndex); Column& target = *repToColumn_[targetRep]; columnToRep_.erase(target); - if constexpr (std::is_integral_v) { + if constexpr (std::is_integral_v) { target.multiply_target_and_add(coefficient, get_column(sourceColumn)); } else { target.multiply_target_and_add(coefficient, sourceColumn); @@ -553,15 +554,15 @@ inline void Base_matrix_with_column_compression::multiply_target_ } template -template +template inline void Base_matrix_with_column_compression::multiply_source_and_add_to( - const Field_element& coefficient, const Cell_range_or_column_index& sourceColumn, Index targetColumnIndex) + const Field_element& coefficient, const Entry_range_or_column_index& sourceColumn, Index targetColumnIndex) { // handle case where targetRep == sourceRep? Index targetRep = columnClasses_.find_set(targetColumnIndex); Column& target = *repToColumn_[targetRep]; columnToRep_.erase(target); - if constexpr (std::is_integral_v) { + if constexpr (std::is_integral_v) { target.multiply_source_and_add(get_column(sourceColumn), coefficient); } else { target.multiply_source_and_add(sourceColumn, coefficient); @@ -570,7 +571,7 @@ inline void Base_matrix_with_column_compression::multiply_source_ } template -inline bool Base_matrix_with_column_compression::is_zero_cell(Index columnIndex, Index rowIndex) +inline bool Base_matrix_with_column_compression::is_zero_entry(Index columnIndex, Index rowIndex) { auto col = repToColumn_[columnClasses_.find_set(columnIndex)]; if (col == nullptr) return true; @@ -636,8 +637,8 @@ inline void Base_matrix_with_column_compression::print() std::cout << "Row Matrix:\n"; for (Index i = 0; i < RA_opt::rows_->size(); ++i) { const Row& row = RA_opt::rows_[i]; - for (const auto& cell : row) { - std::cout << cell.get_column_index() << " "; + for (const auto& entry : row) { + std::cout << entry.get_column_index() << " "; } std::cout << "(" << i << ")\n"; } diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Boundary_matrix.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Boundary_matrix.h index e9f6b07756..29c6f87d93 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Boundary_matrix.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Boundary_matrix.h @@ -50,14 +50,14 @@ class Boundary_matrix : public Master_matrix::Matrix_dimension_option, * @brief Field operators class. Necessary only if @ref PersistenceMatrixOptions::is_z2 is false. */ using Field_operators = typename Master_matrix::Field_operators; - using Field_element = typename Master_matrix::Element; /**< Type of an field element. */ - using Column = typename Master_matrix::Column; /**< Column type. */ - using Boundary = typename Master_matrix::Boundary; /**< Type of an input column. */ - using Row = typename Master_matrix::Row; /**< Row type, - only necessary with row access option. */ - using Cell_constructor = typename Master_matrix::Cell_constructor; /**< Factory of @ref Cell classes. */ - using Column_settings = typename Master_matrix::Column_settings; /**< Structure giving access to the columns to - necessary external classes. */ + using Field_element = typename Master_matrix::Element; /**< Type of an field element. */ + using Column = typename Master_matrix::Column; /**< Column type. */ + using Boundary = typename Master_matrix::Boundary; /**< Type of an input column. */ + using Row = typename Master_matrix::Row; /**< Row type, + only necessary with row access option. */ + using Entry_constructor = typename Master_matrix::Entry_constructor; /**< Factory of @ref Entry classes. */ + using Column_settings = typename Master_matrix::Column_settings; /**< Structure giving access to the columns to + necessary external classes. */ /** * @brief Constructs an empty matrix. @@ -67,11 +67,12 @@ class Boundary_matrix : public Master_matrix::Matrix_dimension_option, */ Boundary_matrix(Column_settings* colSettings); /** - * @brief Constructs a new matrix from the given ranges of @ref Matrix::Cell_representative. Each range corresponds to - * a column (the order of the ranges are preserved). The content of the ranges is assumed to be sorted by increasing - * IDs. The IDs of the simplices are also assumed to be consecutive, ordered by filtration value, starting with 0. + * @brief Constructs a new matrix from the given ranges of @ref Matrix::Entry_representative. Each range corresponds + * to a column (the order of the ranges are preserved). The content of the ranges is assumed to be sorted by + * increasing IDs. The IDs of the simplices are also assumed to be consecutive, ordered by filtration value, starting + * with 0. * - * @tparam Boundary_range Range type for @ref Matrix::Cell_representative ranges. + * @tparam Boundary_range Range type for @ref Matrix::Entry_representative ranges. * Assumed to have a begin(), end() and size() method. * @param orderedBoundaries Range of boundaries: @p orderedBoundaries is interpreted as a boundary matrix of a * filtered **simplicial** complex, whose boundaries are ordered by filtration order. @@ -125,14 +126,15 @@ class Boundary_matrix : public Master_matrix::Matrix_dimension_option, * instead by indicating the face ID used in the boundaries when the face is inserted. * * Different to the constructor, the boundaries do not have to come from a simplicial complex, but also from - * a more general cell complex. This includes cubical complexes or Morse complexes for example. + * a more general entry complex. This includes cubical complexes or Morse complexes for example. * * At the insertion, the boundary will be copied as is. The column will only be reduced later when the barcode * is requested in order to apply some optimizations with the additional knowledge. Hence, the barcode will also * not be updated, so call @ref Base_pairing::get_current_barcode "get_current_barcode" only when the matrix is * complete. * - * @tparam Boundary_range Range of @ref Matrix::Cell_representative. Assumed to have a begin(), end() and size() method. + * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() + * method. * @param boundary Boundary generating the new column. The content should be ordered by ID. * @param dim Dimension of the face whose boundary is given. If the complex is simplicial, * this parameter can be omitted as it can be deduced from the size of the boundary. @@ -148,7 +150,8 @@ class Boundary_matrix : public Master_matrix::Matrix_dimension_option, * As a face has to be inserted before one of its cofaces in a valid filtration (recall that it is assumed that * the faces are inserted by order of filtration), it is sufficient to indicate the ID of the face being inserted. * - * @tparam Boundary_range Range of @ref Matrix::Cell_representative. Assumed to have a begin(), end() and size() method. + * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() + * method. * @param faceIndex @ref IDIdx index to use to identify the new face. * @param boundary Boundary generating the new column. The indices of the boundary have to correspond to the * @p faceIndex values of precedent calls of the method for the corresponding faces and should be ordered in @@ -163,7 +166,7 @@ class Boundary_matrix : public Master_matrix::Matrix_dimension_option, * @brief Returns the column at the given @ref MatIdx index. * The type of the column depends on the choosen options, see @ref PersistenceMatrixOptions::column_type. * - * Note that before returning the column, all column cells can eventually be reordered, if lazy swaps occurred. + * Note that before returning the column, all column entries can eventually be reordered, if lazy swaps occurred. * It is therefore recommended to avoid calling @ref get_column between column or row swaps, otherwise the benefits * of the the laziness is lost. * @@ -176,7 +179,7 @@ class Boundary_matrix : public Master_matrix::Matrix_dimension_option, * Returns the row at the given @ref rowindex "row index" of the matrix. * The type of the row depends on the choosen options, see @ref PersistenceMatrixOptions::has_intrusive_rows. * - * Note that before returning the row, all column cells can eventually be reordered, if lazy swaps occurred. + * Note that before returning the row, all column entries can eventually be reordered, if lazy swaps occurred. * It is therefore recommended to avoid calling @ref get_row between column or row swaps, otherwise the benefits * of the the laziness is lost. * @@ -197,11 +200,11 @@ class Boundary_matrix : public Master_matrix::Matrix_dimension_option, * and @ref PersistenceMatrixOptions::has_column_and_row_swaps are true: cleans up maps used for the lazy row swaps. * Otherwise, does nothing. * - * @warning The removed rows are always assumed to be empty. If it is not the case, the deleted row cells are not + * @warning The removed rows are always assumed to be empty. If it is not the case, the deleted row entries are not * removed from their columns. And in the case of intrusive rows, this will generate a segmentation fault when - * the column cells are destroyed later. The row access is just meant as a "read only" access to the rows and the + * the column entries are destroyed later. The row access is just meant as a "read only" access to the rows and the * @ref erase_empty_row method just as a way to specify that a row is empty and can therefore be removed from - * dictionaries. This allows to avoid testing the emptiness of a row at each column cell removal, what can be + * dictionaries. This allows to avoid testing the emptiness of a row at each column entry removal, what can be * quite frequent. * * @param rowIndex @ref rowindex "Row index" of the empty row. @@ -266,15 +269,15 @@ class Boundary_matrix : public Master_matrix::Matrix_dimension_option, Index targetColumnIndex); /** - * @brief Zeroes the cell at the given coordinates. + * @brief Zeroes the entry at the given coordinates. * * @warning They will be no verification to ensure that the zeroing makes sense for the validity of a * boundary matrix of a filtered complex. So should be used while knowing what one is doing. * - * @param columnIndex @ref MatIdx index of the column of the cell. - * @param rowIndex @ref rowindex "Row index" of the row of the cell. + * @param columnIndex @ref MatIdx index of the column of the entry. + * @param rowIndex @ref rowindex "Row index" of the row of the entry. */ - void zero_cell(Index columnIndex, Index rowIndex); + void zero_entry(Index columnIndex, Index rowIndex); /** * @brief Zeroes the column at the given index. * @@ -285,14 +288,14 @@ class Boundary_matrix : public Master_matrix::Matrix_dimension_option, */ void zero_column(Index columnIndex); /** - * @brief Indicates if the cell at given coordinates has value zero. + * @brief Indicates if the entry at given coordinates has value zero. * - * @param columnIndex @ref MatIdx index of the column of the cell. - * @param rowIndex @ref rowindex "Row index" of the row of the cell. - * @return true If the cell has value zero. + * @param columnIndex @ref MatIdx index of the column of the entry. + * @param rowIndex @ref rowindex "Row index" of the row of the entry. + * @return true If the entry has value zero. * @return false Otherwise. */ - bool is_zero_cell(Index columnIndex, Index rowIndex) const; + bool is_zero_entry(Index columnIndex, Index rowIndex) const; /** * @brief Indicates if the column at given index has value zero. * @@ -358,9 +361,9 @@ class Boundary_matrix : public Master_matrix::Matrix_dimension_option, friend Swap_opt; friend Pair_opt; - Column_container matrix_; /**< Column container. */ - Index nextInsertIndex_; /**< Next unused column index. */ - Column_settings* colSettings_; /**< Cell factory. */ + Column_container matrix_; /**< Column container. */ + Index nextInsertIndex_; /**< Next unused column index. */ + Column_settings* colSettings_; /**< Entry factory. */ static constexpr bool activeDimOption = Master_matrix::Option_list::has_matrix_maximal_dimension_access || Master_matrix::maxDimensionIsNeeded; @@ -650,7 +653,7 @@ inline void Boundary_matrix::multiply_source_and_add_to(const Fie } template -inline void Boundary_matrix::zero_cell(Index columnIndex, Index rowIndex) +inline void Boundary_matrix::zero_entry(Index columnIndex, Index rowIndex) { _get_column(columnIndex).clear(_get_real_row_index(rowIndex)); } @@ -662,7 +665,7 @@ inline void Boundary_matrix::zero_column(Index columnIndex) } template -inline bool Boundary_matrix::is_zero_cell(Index columnIndex, Index rowIndex) const +inline bool Boundary_matrix::is_zero_entry(Index columnIndex, Index rowIndex) const { return !(_get_column(columnIndex).is_non_zero(_get_real_row_index(rowIndex))); } @@ -727,8 +730,8 @@ inline void Boundary_matrix::print() std::cout << "Row Matrix:\n"; for (ID_index i = 0; i < nextInsertIndex_; ++i) { const auto& row = RA_opt::rows_[i]; - for (const auto& cell : row) { - std::cout << cell.get_column_index() << " "; + for (const auto& entry : row) { + std::cout << entry.get_column_index() << " "; } std::cout << "(" << i << ")\n"; } diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Chain_matrix.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Chain_matrix.h index c1f0af1cf6..e113fb61b5 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Chain_matrix.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Chain_matrix.h @@ -57,12 +57,12 @@ class Chain_matrix : public Master_matrix::Matrix_dimension_option, using Column = typename Master_matrix::Column; /**< Column type. */ using Row = typename Master_matrix::Row; /**< Row type, only necessary with row access option. */ - using Cell = typename Master_matrix::Matrix_cell; /**< @ref Cell "Matrix cell" type. */ - using Cell_constructor = typename Master_matrix::Cell_constructor; /**< Factory of @ref Cell classes. */ + using Entry = typename Master_matrix::Matrix_entry; /**< @ref Entry "Matrix entry" type. */ + using Entry_constructor = typename Master_matrix::Entry_constructor; /**< Factory of @ref Entry classes. */ using Column_settings = typename Master_matrix::Column_settings; /**< Structure giving access to the columns to necessary external classes. */ using Boundary = typename Master_matrix::Boundary; /**< Type of an input column. */ - using Cell_representative = typename Master_matrix::Cell_representative; /**< %Cell content representative. */ + using Entry_representative = typename Master_matrix::Entry_representative; /**< %Entry content representative. */ using Index = typename Master_matrix::Index; /**< @ref MatIdx index type. */ using ID_index = typename Master_matrix::ID_index; /**< @ref IDIdx index type. */ using Pos_index = typename Master_matrix::Pos_index; /**< @ref PosIdx index type. */ @@ -78,14 +78,14 @@ class Chain_matrix : public Master_matrix::Matrix_dimension_option, */ Chain_matrix(Column_settings* colSettings); /** - * @brief Constructs a new matrix from the given ranges of @ref Matrix::Cell_representative. Each range corresponds to a - * column (the order of the ranges are preserved). The content of the ranges is assumed to be sorted by increasing - * IDs. The IDs of the simplices are also assumed to be consecutive, ordered by filtration value, starting with 0. - * Only available if @ref PersistenceMatrixOptions::has_column_pairings is true or + * @brief Constructs a new matrix from the given ranges of @ref Matrix::Entry_representative. Each range corresponds + * to a column (the order of the ranges are preserved). The content of the ranges is assumed to be sorted by + * increasing IDs. The IDs of the simplices are also assumed to be consecutive, ordered by filtration value, starting + * with 0. Only available if @ref PersistenceMatrixOptions::has_column_pairings is true or * @ref PersistenceMatrixOptions::has_vine_update is false. Otherwise, birth and death * comparators have to be provided. * - * @tparam Boundary_range Range type for @ref Matrix::Cell_representative ranges. + * @tparam Boundary_range Range type for @ref Matrix::Entry_representative ranges. * Assumed to have a begin(), end() and size() method. * @param orderedBoundaries Range of boundaries: @p orderedBoundaries is interpreted as a boundary matrix of a * filtered **simplicial** complex, whose boundaries are ordered by filtration order. @@ -140,9 +140,10 @@ class Chain_matrix : public Master_matrix::Matrix_dimension_option, const BirthComparatorFunction& birthComparator, const DeathComparatorFunction& deathComparator); /** - * @brief Constructs a new matrix from the given ranges of @ref Matrix::Cell_representative. Each range corresponds to a - * column (the order of the ranges are preserved). The content of the ranges is assumed to be sorted by increasing - * IDs. The IDs of the simplices are also assumed to be consecutive, ordered by filtration value, starting with 0. + * @brief Constructs a new matrix from the given ranges of @ref Matrix::Entry_representative. Each range corresponds + * to a column (the order of the ranges are preserved). The content of the ranges is assumed to be sorted by + * increasing IDs. The IDs of the simplices are also assumed to be consecutive, ordered by filtration value, starting + * with 0. * * @warning If @ref PersistenceMatrixOptions::has_vine_update is false, the comparators are not used. * And if @ref PersistenceMatrixOptions::has_vine_update is true, but @@ -151,7 +152,7 @@ class Chain_matrix : public Master_matrix::Matrix_dimension_option, * * @tparam BirthComparatorFunction Type of the birth comparator: (@ref Pos_index, @ref Pos_index) -> bool * @tparam DeathComparatorFunction Type of the death comparator: (@ref Pos_index, @ref Pos_index) -> bool - * @tparam Boundary_range Range type for @ref Matrix::Cell_representative ranges. + * @tparam Boundary_range Range type for @ref Matrix::Entry_representative ranges. * Assumed to have a begin(), end() and size() method. * @param orderedBoundaries Range of boundaries: @p orderedBoundaries is interpreted as a boundary matrix of a * filtered **simplicial** complex, whose boundaries are ordered by filtration order. @@ -233,19 +234,20 @@ class Chain_matrix : public Master_matrix::Matrix_dimension_option, * instead by indicating the face ID used in the boundaries when the face is inserted. * * Different to the constructor, the boundaries do not have to come from a simplicial complex, but also from - * a more general cell complex. This includes cubical complexes or Morse complexes for example. + * a more general entry complex. This includes cubical complexes or Morse complexes for example. * * When inserted, the given boundary is reduced and from the reduction process, the column is deduced in the form of: * `IDIdx + linear combination of older column IDIdxs`. If the barcode is stored, it will be updated. * - * @tparam Boundary_range Range of @ref Matrix::Cell_representative. Assumed to have a begin(), end() and size() method. + * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() + * method. * @param boundary Boundary generating the new column. The content should be ordered by ID. * @param dim Dimension of the face whose boundary is given. If the complex is simplicial, * this parameter can be omitted as it can be deduced from the size of the boundary. * @return The @ref MatIdx indices of the unpaired chains used to reduce the boundary. */ template - std::vector insert_boundary(const Boundary_range& boundary, Dimension dim = -1); + std::vector insert_boundary(const Boundary_range& boundary, Dimension dim = -1); /** * @brief It does the same as the other version, but allows the boundary faces to be identified without restrictions * except that all IDs have to be strictly increasing in the order of filtration. Note that you should avoid then @@ -254,7 +256,8 @@ class Chain_matrix : public Master_matrix::Matrix_dimension_option, * As a face has to be inserted before one of its cofaces in a valid filtration (recall that it is assumed that * the faces are inserted by order of filtration), it is sufficient to indicate the ID of the face being inserted. * - * @tparam Boundary_range Range of @ref Matrix::Cell_representative. Assumed to have a begin(), end() and size() method. + * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() + * method. * @param faceID @ref IDIdx index to use to identify the new face. * @param boundary Boundary generating the new column. The indices of the boundary have to correspond to the * @p faceID values of precedent calls of the method for the corresponding faces and should be ordered in @@ -264,7 +267,9 @@ class Chain_matrix : public Master_matrix::Matrix_dimension_option, * @return The @ref MatIdx index of the inserted boundary. */ template - std::vector insert_boundary(ID_index faceID, const Boundary_range& boundary, Dimension dim = -1); + std::vector insert_boundary(ID_index faceID, + const Boundary_range& boundary, + Dimension dim = -1); /** * @brief Returns the column at the given @ref MatIdx index. * The type of the column depends on the choosen options, see @ref PersistenceMatrixOptions::column_type. @@ -396,14 +401,14 @@ class Chain_matrix : public Master_matrix::Matrix_dimension_option, Index targetColumnIndex); /** - * @brief Indicates if the cell at given coordinates has value zero. + * @brief Indicates if the entry at given coordinates has value zero. * - * @param columnIndex @ref MatIdx index of the column of the cell. - * @param rowIndex @ref rowindex "Row index" of the row of the cell. - * @return true If the cell has value zero. + * @param columnIndex @ref MatIdx index of the column of the entry. + * @param rowIndex @ref rowindex "Row index" of the row of the entry. + * @return true If the entry has value zero. * @return false Otherwise. */ - bool is_zero_cell(Index columnIndex, ID_index rowIndex) const; + bool is_zero_entry(Index columnIndex, ID_index rowIndex) const; /** * @brief Indicates if the column at given index has value zero. Note that if the matrix is valid, this method * should always return false. @@ -491,14 +496,14 @@ class Chain_matrix : public Master_matrix::Matrix_dimension_option, Column_container matrix_; /**< Column container. */ Dictionary pivotToColumnIndex_; /**< Map from @ref IDIdx to @ref MatIdx index. */ Index nextIndex_; /**< Next unused column index. */ - Column_settings* colSettings_; /**< Cell factory. */ + Column_settings* colSettings_; /**< Entry factory. */ template - std::vector _reduce_boundary(ID_index faceID, const Boundary_range& boundary, Dimension dim); - void _reduce_by_G(Tmp_column& column, std::vector& chainsInH, Index currentPivot); - void _reduce_by_F(Tmp_column& column, std::vector& chainsInF, Index currentPivot); - void _build_from_H(ID_index faceID, Tmp_column& column, std::vector& chainsInH); - void _update_largest_death_in_F(const std::vector& chainsInF); + std::vector _reduce_boundary(ID_index faceID, const Boundary_range& boundary, Dimension dim); + void _reduce_by_G(Tmp_column& column, std::vector& chainsInH, Index currentPivot); + void _reduce_by_F(Tmp_column& column, std::vector& chainsInF, Index currentPivot); + void _build_from_H(ID_index faceID, Tmp_column& column, std::vector& chainsInH); + void _update_largest_death_in_F(const std::vector& chainsInF); void _insert_chain(const Tmp_column& column, Dimension dimension); void _insert_chain(const Tmp_column& column, Dimension dimension, Index pair); void _add_to(const Column& column, Tmp_column& set, unsigned int coef); @@ -667,7 +672,7 @@ inline Chain_matrix::Chain_matrix(Chain_matrix&& other) noexcept template template -inline std::vector Chain_matrix::insert_boundary( +inline std::vector Chain_matrix::insert_boundary( const Boundary_range& boundary, Dimension dim) { return insert_boundary(nextIndex_, boundary, dim); @@ -675,7 +680,7 @@ inline std::vector Chain_matrix template -inline std::vector Chain_matrix::insert_boundary( +inline std::vector Chain_matrix::insert_boundary( ID_index faceID, const Boundary_range& boundary, Dimension dim) { if constexpr (!Master_matrix::Option_list::has_map_column_container) { @@ -851,7 +856,7 @@ inline void Chain_matrix::multiply_source_and_add_to(const Field_ } template -inline bool Chain_matrix::is_zero_cell(Index columnIndex, ID_index rowIndex) const +inline bool Chain_matrix::is_zero_entry(Index columnIndex, ID_index rowIndex) const { return !get_column(columnIndex).is_non_zero(rowIndex); } @@ -911,8 +916,8 @@ inline void Chain_matrix::print() const for (ID_index i = 0; i < pivotToColumnIndex_.size() && pivotToColumnIndex_[i] != static_cast(-1); ++i) { Index pos = pivotToColumnIndex_[i]; const Column& col = matrix_[pos]; - for (const auto& cell : col) { - std::cout << cell.get_row_index() << " "; + for (const auto& entry : col) { + std::cout << entry.get_row_index() << " "; } std::cout << "(" << i << ", " << pos << ")\n"; } @@ -922,8 +927,8 @@ inline void Chain_matrix::print() const for (ID_index i = 0; i < pivotToColumnIndex_.size() && pivotToColumnIndex_[i] != static_cast(-1); ++i) { Index pos = pivotToColumnIndex_[i]; const Row& row = RA_opt::get_row(pos); - for (const auto& cell : row) { - std::cout << cell.get_column_index() << " "; + for (const auto& entry : row) { + std::cout << entry.get_column_index() << " "; } std::cout << "(" << i << ", " << pos << ")\n"; } @@ -931,8 +936,8 @@ inline void Chain_matrix::print() const } else { for (const auto& p : pivotToColumnIndex_) { const Column& col = matrix_.at(p.second); - for (const auto& cell : col) { - std::cout << cell.get_row_index() << " "; + for (const auto& entry : col) { + std::cout << entry.get_row_index() << " "; } std::cout << "(" << p.first << ", " << p.second << ")\n"; } @@ -941,8 +946,8 @@ inline void Chain_matrix::print() const std::cout << "Row Matrix:\n"; for (const auto& p : pivotToColumnIndex_) { const Row& row = RA_opt::get_row(p.first); - for (const auto& cell : row) { - std::cout << cell.get_column_index() << " "; + for (const auto& entry : row) { + std::cout << entry.get_column_index() << " "; } std::cout << "(" << p.first << ", " << p.second << ")\n"; } @@ -953,13 +958,13 @@ inline void Chain_matrix::print() const template template -inline std::vector Chain_matrix::_reduce_boundary( +inline std::vector Chain_matrix::_reduce_boundary( ID_index faceID, const Boundary_range& boundary, Dimension dim) { Tmp_column column(boundary.begin(), boundary.end()); if (dim == static_cast(-1)) dim = boundary.begin() == boundary.end() ? 0 : boundary.size() - 1; - std::vector chainsInH; // for corresponding indices in H (paired columns) - std::vector chainsInF; // for corresponding indices in F (unpaired, essential columns) + std::vector chainsInH; // for corresponding indices in H (paired columns) + std::vector chainsInF; // for corresponding indices in F (unpaired, essential columns) auto get_last = [&column]() { if constexpr (Master_matrix::Option_list::is_z2) @@ -1020,7 +1025,7 @@ inline std::vector Chain_matrix inline void Chain_matrix::_reduce_by_G(Tmp_column& column, - std::vector& chainsInH, + std::vector& chainsInH, Index currentIndex) { Column& col = get_column(currentIndex); @@ -1040,7 +1045,7 @@ inline void Chain_matrix::_reduce_by_G(Tmp_column& column, template inline void Chain_matrix::_reduce_by_F(Tmp_column& column, - std::vector& chainsInF, + std::vector& chainsInF, Index currentIndex) { Column& col = get_column(currentIndex); @@ -1061,7 +1066,7 @@ inline void Chain_matrix::_reduce_by_F(Tmp_column& column, template inline void Chain_matrix::_build_from_H(ID_index faceID, Tmp_column& column, - std::vector& chainsInH) + std::vector& chainsInH) { if constexpr (Master_matrix::Option_list::is_z2) { column.insert(faceID); @@ -1077,7 +1082,7 @@ inline void Chain_matrix::_build_from_H(ID_index faceID, } template -inline void Chain_matrix::_update_largest_death_in_F(const std::vector& chainsInF) +inline void Chain_matrix::_update_largest_death_in_F(const std::vector& chainsInF) { if constexpr (Master_matrix::Option_list::is_z2) { Index toUpdate = chainsInF[0]; @@ -1131,20 +1136,20 @@ inline void Chain_matrix::_add_to(const Column& column, { if constexpr (Master_matrix::Option_list::is_z2) { std::pair::iterator, bool> res_insert; - for (const Cell& cell : column) { - res_insert = set.insert(cell.get_row_index()); + for (const Entry& entry : column) { + res_insert = set.insert(entry.get_row_index()); if (!res_insert.second) { set.erase(res_insert.first); } } } else { auto& operators = colSettings_->operators; - for (const Cell& cell : column) { - auto res = set.emplace(cell.get_row_index(), cell.get_element()); + for (const Entry& entry : column) { + auto res = set.emplace(entry.get_row_index(), entry.get_element()); if (res.second){ operators.multiply_inplace(res.first->second, coef); } else { - operators.multiply_and_add_inplace_back(cell.get_element(), coef, res.first->second); + operators.multiply_and_add_inplace_back(entry.get_element(), coef, res.first->second); if (res.first->second == Field_operators::get_additive_identity()) { set.erase(res.first); } diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Id_to_index_overlay.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Id_to_index_overlay.h index b5393083af..91b09f2659 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Id_to_index_overlay.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Id_to_index_overlay.h @@ -41,25 +41,25 @@ template class Id_to_index_overlay { public: - using Index = typename Master_matrix::Index; /**< @ref MatIdx index type. */ - using ID_index = typename Master_matrix::ID_index; /**< @ref IDIdx index type. */ - using Pos_index = typename Master_matrix::Pos_index; /**< @ref PosIdx index type. */ - using Dimension = typename Master_matrix::Dimension; /**< Dimension value type. */ + using Index = typename Master_matrix::Index; /**< @ref MatIdx index type. */ + using ID_index = typename Master_matrix::ID_index; /**< @ref IDIdx index type. */ + using Pos_index = typename Master_matrix::Pos_index; /**< @ref PosIdx index type. */ + using Dimension = typename Master_matrix::Dimension; /**< Dimension value type. */ /** * @brief Field operators class. Necessary only if @ref PersistenceMatrixOptions::is_z2 is false. */ using Field_operators = typename Master_matrix::Field_operators; - using Field_element = typename Master_matrix::Element; /**< Type of an field element. */ - using Boundary = typename Master_matrix::Boundary; /**< Type of an input column. */ - using Column = typename Master_matrix::Column; /**< Column type. */ - using Row = typename Master_matrix::Row; /**< Row type, - only necessary with row access option. */ - using Bar = typename Master_matrix::Bar; /**< Bar type. */ - using Barcode = typename Master_matrix::Barcode; /**< Barcode type. */ - using Cycle = typename Master_matrix::Cycle; /**< Cycle type. */ - using Cell_constructor = typename Master_matrix::Cell_constructor; /**< Factory of @ref Cell classes. */ - using Column_settings = typename Master_matrix::Column_settings; /**< Structure giving access to the columns to - necessary external classes. */ + using Field_element = typename Master_matrix::Element; /**< Type of an field element. */ + using Boundary = typename Master_matrix::Boundary; /**< Type of an input column. */ + using Column = typename Master_matrix::Column; /**< Column type. */ + using Row = typename Master_matrix::Row; /**< Row type, + only necessary with row access option. */ + using Bar = typename Master_matrix::Bar; /**< Bar type. */ + using Barcode = typename Master_matrix::Barcode; /**< Barcode type. */ + using Cycle = typename Master_matrix::Cycle; /**< Cycle type. */ + using Entry_constructor = typename Master_matrix::Entry_constructor; /**< Factory of @ref Entry classes. */ + using Column_settings = typename Master_matrix::Column_settings; /**< Structure giving access to the columns to + necessary external classes. */ /** * @brief Constructs an empty matrix. @@ -69,11 +69,12 @@ class Id_to_index_overlay */ Id_to_index_overlay(Column_settings* colSettings); /** - * @brief Constructs a new matrix from the given ranges of @ref Matrix::Cell_representative. Each range corresponds to a - * column (the order of the ranges are preserved). The content of the ranges is assumed to be sorted by increasing - * IDs. The IDs of the simplices are also assumed to be consecutive, ordered by filtration value, starting with 0. + * @brief Constructs a new matrix from the given ranges of @ref Matrix::Entry_representative. Each range corresponds + * to a column (the order of the ranges are preserved). The content of the ranges is assumed to be sorted by + * increasing IDs. The IDs of the simplices are also assumed to be consecutive, ordered by filtration value, starting + * with 0. * - * @tparam Boundary_range Range type for @ref Matrix::Cell_representative ranges. + * @tparam Boundary_range Range type for @ref Matrix::Entry_representative ranges. * Assumed to have a begin(), end() and size() method. * @param orderedBoundaries Range of boundaries: @p orderedBoundaries is interpreted as a boundary matrix of a * filtered **simplicial** complex, whose boundaries are ordered by filtration order. @@ -127,9 +128,9 @@ class Id_to_index_overlay const DeathComparatorFunction& deathComparator); /** * @brief Only available for @ref chainmatrix "chain matrices". - * Constructs a new matrix from the given ranges of @ref Matrix::Cell_representative. Each range corresponds to a column - * (the order of the ranges are preserved). The content of the ranges is assumed to be sorted by increasing IDs. - * The IDs of the simplices are also assumed to be consecutive, ordered by filtration value, starting with 0. + * Constructs a new matrix from the given ranges of @ref Matrix::Entry_representative. Each range corresponds to a + * column (the order of the ranges are preserved). The content of the ranges is assumed to be sorted by increasing + * IDs. The IDs of the simplices are also assumed to be consecutive, ordered by filtration value, starting with 0. * * @warning If @ref PersistenceMatrixOptions::has_vine_update is false, the comparators are not used. * And if @ref PersistenceMatrixOptions::has_vine_update is true, but @@ -138,7 +139,7 @@ class Id_to_index_overlay * * @tparam BirthComparatorFunction Type of the birth comparator: (@ref Pos_index, @ref Pos_index) -> bool * @tparam DeathComparatorFunction Type of the death comparator: (@ref Pos_index, @ref Pos_index) -> bool - * @tparam Boundary_range Range type for @ref Matrix::Cell_representative ranges. + * @tparam Boundary_range Range type for @ref Matrix::Entry_representative ranges. * Assumed to have a begin(), end() and size() method. * @param orderedBoundaries Range of boundaries: @p orderedBoundaries is interpreted as a boundary matrix of a * filtered **simplicial** complex, whose boundaries are ordered by filtration order. @@ -195,7 +196,7 @@ class Id_to_index_overlay const BirthComparatorFunction& birthComparator, const DeathComparatorFunction& deathComparator); /** - * @brief Copy constructor. If @p operators or @p cellConstructor is not a null pointer, its value is kept + * @brief Copy constructor. If @p operators or @p entryConstructor is not a null pointer, its value is kept * instead of the one in the copied matrix. * * @param matrixToCopy Matrix to copy. @@ -225,7 +226,7 @@ class Id_to_index_overlay * face ID used in the boundaries when the face is inserted. * * Different to the constructor, the boundaries do not have to come from a simplicial complex, but also from - * a more general cell complex. This includes cubical complexes or Morse complexes for example. + * a more general entry complex. This includes cubical complexes or Morse complexes for example. * * The content of the new column will vary depending on the underlying @ref mp_matrices "type of the matrix": * - If it is a boundary type matrix and only \f$ R \f$ is stored, the boundary is just copied. The column will only @@ -237,7 +238,8 @@ class Id_to_index_overlay * `IDIdx + linear combination of older column IDIdxs`, where the combination is deduced while reducing the * given boundary. If the barcode is stored, it will also be updated. * - * @tparam Boundary_range Range of @ref Matrix::Cell_representative. Assumed to have a begin(), end() and size() method. + * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() + * method. * @param boundary Boundary generating the new column. The content should be ordered by ID. * @param dim Dimension of the face whose boundary is given. If the complex is simplicial, * this parameter can be omitted as it can be deduced from the size of the boundary. @@ -252,7 +254,8 @@ class Id_to_index_overlay * As a face has to be inserted before one of its cofaces in a valid filtration (recall that it is assumed that * the faces are inserted by order of filtration), it is sufficient to indicate the ID of the face being inserted. * - * @tparam Boundary_range Range of @ref Matrix::Cell_representative. Assumed to have a begin(), end() and size() method. + * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() + * method. * @param faceIndex @ref IDIdx index to use to identify the new face. * @param boundary Boundary generating the new column. The indices of the boundary have to correspond to the * @p faceIndex values of precedent calls of the method for the corresponding faces and should be ordered in @@ -277,7 +280,7 @@ class Id_to_index_overlay * For @ref boundarymatrix "RU matrices", the returned row is from \f$ R \f$. * The type of the row depends on the choosen options, see @ref PersistenceMatrixOptions::has_intrusive_rows. * - * @warning The @ref Cell_column_index::get_column_index "get_column_index" method of the row cells returns the + * @warning The @ref Entry_column_index::get_column_index "get_column_index" method of the row entries returns the * original @ref PosIdx indices (before any swaps) for @ref boundarymatrix "boundary matrices" and * @ref MatIdx indices for @ref chainmatrix "chain matrices". * @@ -301,11 +304,11 @@ class Id_to_index_overlay * @ref PersistenceMatrixOptions::has_removable_rows are true. * Assumes that the row is empty and removes it. * - * @warning The removed rows are always assumed to be empty. If it is not the case, the deleted row cells are not + * @warning The removed rows are always assumed to be empty. If it is not the case, the deleted row entries are not * removed from their columns. And in the case of intrusive rows, this will generate a segmentation fault when - * the column cells are destroyed later. The row access is just meant as a "read only" access to the rows and the + * the column entries are destroyed later. The row access is just meant as a "read only" access to the rows and the * @ref erase_empty_row method just as a way to specify that a row is empty and can therefore be removed from - * dictionaries. This allows to avoid testing the emptiness of a row at each column cell removal, what can be + * dictionaries. This allows to avoid testing the emptiness of a row at each column entry removal, what can be * quite frequent. * * @param rowIndex @ref rowindex "Row index" of the empty row to remove. @@ -431,16 +434,16 @@ class Id_to_index_overlay void multiply_source_and_add_to(const Field_element& coefficient, ID_index sourceFaceID, ID_index targetFaceID); /** - * @brief Zeroes the cell at the given coordinates. Not available for @ref chainmatrix "chain matrices". + * @brief Zeroes the entry at the given coordinates. Not available for @ref chainmatrix "chain matrices". * In general, should be used with care to not destroy the validity * of the persistence related properties of the matrix. * - * For @ref boundarymatrix "RU matrices", zeros only the cell in \f$ R \f$. + * For @ref boundarymatrix "RU matrices", zeros only the entry in \f$ R \f$. * - * @param faceID @ref IDIdx index of the face corresponding to the column of the cell. - * @param rowIndex @ref rowindex "Row index" of the row of the cell. + * @param faceID @ref IDIdx index of the face corresponding to the column of the entry. + * @param rowIndex @ref rowindex "Row index" of the row of the entry. */ - void zero_cell(ID_index faceID, ID_index rowIndex); + void zero_entry(ID_index faceID, ID_index rowIndex); /** * @brief Zeroes the column at the given index. Not available for @ref chainmatrix "chain matrices". * In general, should be used with care to not destroy the validity @@ -452,16 +455,16 @@ class Id_to_index_overlay */ void zero_column(ID_index faceID); /** - * @brief Indicates if the cell at given coordinates has value zero. + * @brief Indicates if the entry at given coordinates has value zero. * * For @ref boundarymatrix "RU matrices", looks into \f$ R \f$. * - * @param faceID @ref IDIdx index of the face corresponding to the column of the cell. - * @param rowIndex @ref rowindex "Row index" of the row of the cell. - * @return true If the cell has value zero. + * @param faceID @ref IDIdx index of the face corresponding to the column of the entry. + * @param rowIndex @ref rowindex "Row index" of the row of the entry. + * @return true If the entry has value zero. * @return false Otherwise. */ - bool is_zero_cell(ID_index faceID, ID_index rowIndex) const; + bool is_zero_entry(ID_index faceID, ID_index rowIndex) const; /** * @brief Indicates if the column at given index has value zero. * @@ -904,9 +907,9 @@ inline void Id_to_index_overlay::multiply_sour } template -inline void Id_to_index_overlay::zero_cell(ID_index faceID, ID_index rowIndex) +inline void Id_to_index_overlay::zero_entry(ID_index faceID, ID_index rowIndex) { - return matrix_.zero_cell(_id_to_index(faceID), rowIndex); + return matrix_.zero_entry(_id_to_index(faceID), rowIndex); } template @@ -916,10 +919,10 @@ inline void Id_to_index_overlay::zero_column(I } template -inline bool Id_to_index_overlay::is_zero_cell(ID_index faceID, +inline bool Id_to_index_overlay::is_zero_entry(ID_index faceID, ID_index rowIndex) const { - return matrix_.is_zero_cell(_id_to_index(faceID), rowIndex); + return matrix_.is_zero_entry(_id_to_index(faceID), rowIndex); } template diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Position_to_index_overlay.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Position_to_index_overlay.h index d908675a54..56cd2c2d27 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Position_to_index_overlay.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Position_to_index_overlay.h @@ -55,8 +55,8 @@ class Position_to_index_overlay using Bar = typename Master_matrix::Bar; /**< Bar type. */ using Barcode = typename Master_matrix::Barcode; /**< Barcode type. */ using Cycle = typename Master_matrix::Cycle; /**< Cycle type. */ - using Cell_representative = typename Master_matrix::Cell_representative; /**< %Cell content representative. */ - using Cell_constructor = typename Master_matrix::Cell_constructor; /**< Factory of @ref Cell classes. */ + using Entry_representative = typename Master_matrix::Entry_representative; /**< %Entry content representative. */ + using Entry_constructor = typename Master_matrix::Entry_constructor; /**< Factory of @ref Entry classes. */ using Column_settings = typename Master_matrix::Column_settings; /**< Structure giving access to the columns to necessary external classes. */ @@ -68,11 +68,12 @@ class Position_to_index_overlay */ Position_to_index_overlay(Column_settings* colSettings); /** - * @brief Constructs a new matrix from the given ranges of @ref Matrix::Cell_representative. Each range corresponds to a - * column (the order of the ranges are preserved). The content of the ranges is assumed to be sorted by increasing - * IDs. The IDs of the simplices are also assumed to be consecutive, ordered by filtration value, starting with 0. + * @brief Constructs a new matrix from the given ranges of @ref Matrix::Entry_representative. Each range corresponds + * to a column (the order of the ranges are preserved). The content of the ranges is assumed to be sorted by + * increasing IDs. The IDs of the simplices are also assumed to be consecutive, ordered by filtration value, starting + * with 0. * - * @tparam Boundary_range Range type for @ref Matrix::Cell_representative ranges. + * @tparam Boundary_range Range type for @ref Matrix::Entry_representative ranges. * Assumed to have a begin(), end() and size() method. * @param orderedBoundaries Range of boundaries: @p orderedBoundaries is interpreted as a boundary matrix of a * filtered **simplicial** complex, whose boundaries are ordered by filtration order. @@ -127,9 +128,9 @@ class Position_to_index_overlay const DeathComparatorFunction& deathComparator); /** * @brief Only available for @ref chainmatrix "chain matrices". - * Constructs a new matrix from the given ranges of @ref Matrix::Cell_representative. Each range corresponds to a column - * (the order of the ranges are preserved). The content of the ranges is assumed to be sorted by increasing IDs. - * The IDs of the simplices are also assumed to be consecutive, ordered by filtration value, starting with 0. + * Constructs a new matrix from the given ranges of @ref Matrix::Entry_representative. Each range corresponds to a + * column (the order of the ranges are preserved). The content of the ranges is assumed to be sorted by increasing + * IDs. The IDs of the simplices are also assumed to be consecutive, ordered by filtration value, starting with 0. * * @warning If @ref PersistenceMatrixOptions::has_vine_update is false, the comparators are not used. * And if @ref PersistenceMatrixOptions::has_vine_update is true, but @@ -138,7 +139,7 @@ class Position_to_index_overlay * * @tparam BirthComparatorFunction Type of the birth comparator: (@ref Pos_index, @ref Pos_index) -> bool * @tparam DeathComparatorFunction Type of the death comparator: (@ref Pos_index, @ref Pos_index) -> bool - * @tparam Boundary_range Range type for @ref Matrix::Cell_representative ranges. + * @tparam Boundary_range Range type for @ref Matrix::Entry_representative ranges. * Assumed to have a begin(), end() and size() method. * @param orderedBoundaries Range of boundaries: @p orderedBoundaries is interpreted as a boundary matrix of a * filtered **simplicial** complex, whose boundaries are ordered by filtration order. @@ -221,12 +222,13 @@ class Position_to_index_overlay * face ID used in the boundaries when the face is inserted. * * Different to the constructor, the boundaries do not have to come from a simplicial complex, but also from - * a more general cell complex. This includes cubical complexes or Morse complexes for example. + * a more general entry complex. This includes cubical complexes or Morse complexes for example. * * When inserted, the given boundary is reduced and from the reduction process, the column is deduced in the form of: * `IDIdx + linear combination of older column IDIdxs`. If the barcode is stored, it will be updated. * - * @tparam Boundary_range Range of @ref Matrix::Cell_representative. Assumed to have a begin(), end() and size() method. + * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() + * method. * @param boundary Boundary generating the new column. The content should be ordered by ID. * @param dim Dimension of the face whose boundary is given. If the complex is simplicial, * this parameter can be omitted as it can be deduced from the size of the boundary. @@ -241,7 +243,8 @@ class Position_to_index_overlay * As a face has to be inserted before one of its cofaces in a valid filtration (recall that it is assumed that * the faces are inserted by order of filtration), it is sufficient to indicate the ID of the face being inserted. * - * @tparam Boundary_range Range of @ref Matrix::Cell_representative. Assumed to have a begin(), end() and size() method. + * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() + * method. * @param faceIndex @ref IDIdx index to use to identify the new face. * @param boundary Boundary generating the new column. The indices of the boundary have to correspond to the * @p faceID values of precedent calls of the method for the corresponding faces and should be ordered in @@ -290,11 +293,11 @@ class Position_to_index_overlay * @ref PersistenceMatrixOptions::has_removable_rows are true. * Assumes that the row is empty and removes it. * - * @warning The removed rows are always assumed to be empty. If it is not the case, the deleted row cells are not + * @warning The removed rows are always assumed to be empty. If it is not the case, the deleted row entries are not * removed from their columns. And in the case of intrusive rows, this will generate a segmentation fault when - * the column cells are destroyed later. The row access is just meant as a "read only" access to the rows and the + * the column entries are destroyed later. The row access is just meant as a "read only" access to the rows and the * @ref erase_empty_row method just as a way to specify that a row is empty and can therefore be removed from - * dictionaries. This allows to avoid testing the emptiness of a row at each column cell removal, what can be + * dictionaries. This allows to avoid testing the emptiness of a row at each column entry removal, what can be * quite frequent. * * @param rowIndex @ref rowindex "Row index" of the empty row to remove. @@ -388,14 +391,14 @@ class Position_to_index_overlay Pos_index targetPosition); /** - * @brief Indicates if the cell at given coordinates has value zero. + * @brief Indicates if the entry at given coordinates has value zero. * - * @param position @ref PosIdx index of the face corresponding to the column of the cell. - * @param rowIndex @ref rowindex "Row index" of the row of the cell. - * @return true If the cell has value zero. + * @param position @ref PosIdx index of the face corresponding to the column of the entry. + * @param rowIndex @ref rowindex "Row index" of the row of the entry. + * @return true If the entry has value zero. * @return false Otherwise. */ - bool is_zero_cell(Pos_index position, ID_index rowIndex) const; + bool is_zero_entry(Pos_index position, ID_index rowIndex) const; /** * @brief Indicates if the column at given index has value zero. * @@ -752,10 +755,10 @@ inline void Position_to_index_overlay::multipl } template -inline bool Position_to_index_overlay::is_zero_cell(Pos_index position, +inline bool Position_to_index_overlay::is_zero_entry(Pos_index position, ID_index rowIndex) const { - return matrix_.is_zero_cell(positionToIndex_[position], rowIndex); + return matrix_.is_zero_entry(positionToIndex_[position], rowIndex); } template diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/RU_matrix.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/RU_matrix.h index 28b7a1412a..f738404e42 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/RU_matrix.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/RU_matrix.h @@ -45,18 +45,18 @@ class RU_matrix : public Master_matrix::RU_pairing_option, * @brief Field operators class. Necessary only if @ref PersistenceMatrixOptions::is_z2 is false. */ using Field_operators = typename Master_matrix::Field_operators; - using Field_element = typename Master_matrix::Element; /**< Type of an field element. */ - using Column = typename Master_matrix::Column; /**< Column type. */ - using Row = typename Master_matrix::Row; /**< Row type, - only necessary with row access option. */ - using Cell_constructor = typename Master_matrix::Cell_constructor; /**< Factory of @ref Cell classes. */ - using Column_settings = typename Master_matrix::Column_settings; /**< Structure giving access to the columns to - necessary external classes. */ - using Boundary = typename Master_matrix::Boundary; /**< Type of an input column. */ - using Index = typename Master_matrix::Index; /**< @ref MatIdx index type. */ - using ID_index = typename Master_matrix::ID_index; /**< @ref IDIdx index type. */ - using Pos_index = typename Master_matrix::Pos_index; /**< @ref PosIdx index type. */ - using Dimension = typename Master_matrix::Dimension; /**< Dimension value type. */ + using Field_element = typename Master_matrix::Element; /**< Type of an field element. */ + using Column = typename Master_matrix::Column; /**< Column type. */ + using Row = typename Master_matrix::Row; /**< Row type, + only necessary with row access option. */ + using Entry_constructor = typename Master_matrix::Entry_constructor; /**< Factory of @ref Entry classes. */ + using Column_settings = typename Master_matrix::Column_settings; /**< Structure giving access to the columns to + necessary external classes. */ + using Boundary = typename Master_matrix::Boundary; /**< Type of an input column. */ + using Index = typename Master_matrix::Index; /**< @ref MatIdx index type. */ + using ID_index = typename Master_matrix::ID_index; /**< @ref IDIdx index type. */ + using Pos_index = typename Master_matrix::Pos_index; /**< @ref PosIdx index type. */ + using Dimension = typename Master_matrix::Dimension; /**< Dimension value type. */ /** * @brief Constructs an empty matrix. @@ -66,11 +66,12 @@ class RU_matrix : public Master_matrix::RU_pairing_option, */ RU_matrix(Column_settings* colSettings); /** - * @brief Constructs a new matrix from the given ranges of @ref Matrix::Cell_representative. Each range corresponds to - * a column (the order of the ranges are preserved). The content of the ranges is assumed to be sorted by increasing - * IDs. The IDs of the simplices are also assumed to be consecutive, ordered by filtration value, starting with 0. + * @brief Constructs a new matrix from the given ranges of @ref Matrix::Entry_representative. Each range corresponds + * to a column (the order of the ranges are preserved). The content of the ranges is assumed to be sorted by + * increasing IDs. The IDs of the simplices are also assumed to be consecutive, ordered by filtration value, starting + * with 0. * - * @tparam Boundary_range Range type for @ref Matrix::Cell_representative ranges. + * @tparam Boundary_range Range type for @ref Matrix::Entry_representative ranges. * Assumed to have a begin(), end() and size() method. * @param orderedBoundaries Range of boundaries: @p orderedBoundaries is interpreted as a boundary matrix of a * filtered **simplicial** complex, whose boundaries are ordered by filtration order. @@ -120,11 +121,11 @@ class RU_matrix : public Master_matrix::RU_pairing_option, * face ID used in the boundaries when the face is inserted. * * Different to the constructor, the boundaries do not have to come from a simplicial complex, but also from - * a more general cell complex. This includes cubical complexes or Morse complexes for example. + * a more general entry complex. This includes cubical complexes or Morse complexes for example. * * At the insertion, the boundary is stored in its reduced form and the barcode, if enabled, is updated. * - * @tparam Boundary_range Range of @ref Matrix::Cell_representative. Assumed to have a begin(), end() and size() + * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() * method. * @param boundary Boundary generating the new column. The content should be ordered by ID. * @param dim Dimension of the face whose boundary is given. If the complex is simplicial, @@ -140,7 +141,7 @@ class RU_matrix : public Master_matrix::RU_pairing_option, * As a face has to be inserted before one of its cofaces in a valid filtration (recall that it is assumed that * the faces are inserted by order of filtration), it is sufficient to indicate the ID of the face being inserted. * - * @tparam Boundary_range Range of @ref Matrix::Cell_representative. Assumed to have a begin(), end() and size() + * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() * method. * @param faceIndex @ref IDIdx index to use to identify the new face. * @param boundary Boundary generating the new column. The indices of the boundary have to correspond to the @@ -156,7 +157,7 @@ class RU_matrix : public Master_matrix::RU_pairing_option, * in \f$ U \f$ if @p inR is false. * The type of the column depends on the choosen options, see @ref PersistenceMatrixOptions::column_type. * - * Note that before returning the column, all column cells can eventually be reordered, if lazy swaps occurred. + * Note that before returning the column, all column entries can eventually be reordered, if lazy swaps occurred. * It is therefore recommended to avoid calling @ref get_column between vine swaps, otherwise the benefits * of the the laziness is lost. * @@ -171,7 +172,7 @@ class RU_matrix : public Master_matrix::RU_pairing_option, * in \f$ U \f$ if @p inR is false. * The type of the row depends on the choosen options, see @ref PersistenceMatrixOptions::has_intrusive_rows. * - * Note that before returning the row, all column cells can eventually be reordered, if lazy swaps occurred. + * Note that before returning the row, all column entries can eventually be reordered, if lazy swaps occurred. * It is therefore recommended to avoid calling @ref get_row between vine swaps, otherwise the benefits * of the the laziness is lost. * @@ -190,10 +191,10 @@ class RU_matrix : public Master_matrix::RU_pairing_option, * Otherwise, does nothing. * * @warning The removed rows are always assumed to be empty in \f$ R \f$. If it is not the case, the deleted row - * cells are not removed from their columns. And in the case of intrusive rows, this will generate a segmentation - * fault when the column cells are destroyed later. The row access is just meant as a "read only" access to the + * entries are not removed from their columns. And in the case of intrusive rows, this will generate a segmentation + * fault when the column entries are destroyed later. The row access is just meant as a "read only" access to the * rows and the @ref erase_empty_row method just as a way to specify that a row is empty and can therefore be removed - * from dictionaries. This allows to avoid testing the emptiness of a row at each column cell removal, what can + * from dictionaries. This allows to avoid testing the emptiness of a row at each column entry removal, what can * be quite frequent. * * @param rowIndex @ref rowindex "Row index" of the empty row. @@ -280,16 +281,16 @@ class RU_matrix : public Master_matrix::RU_pairing_option, void multiply_source_and_add_to(const Field_element& coefficient, Index sourceColumnIndex, Index targetColumnIndex); /** - * @brief Zeroes the cell at the given coordinates in \f$ R \f$ if @p inR is true or in + * @brief Zeroes the entry at the given coordinates in \f$ R \f$ if @p inR is true or in * \f$ U \f$ if @p inR is false. Should be used with care to not destroy the validity of the persistence * related properties of the matrix. * - * @param columnIndex @ref MatIdx index of the column of the cell. - * @param rowIndex @ref rowindex "Row index" of the row of the cell. + * @param columnIndex @ref MatIdx index of the column of the entry. + * @param rowIndex @ref rowindex "Row index" of the row of the entry. * @param inR Boolean indicating in which matrix to zero: if true in \f$ R \f$ and if false in \f$ U \f$. * Default value: true. */ - void zero_cell(Index columnIndex, Index rowIndex, bool inR = true); + void zero_entry(Index columnIndex, Index rowIndex, bool inR = true); /** * @brief Zeroes the column at the given index in \f$ R \f$ if @p inR is true or in * \f$ U \f$ if @p inR is false. Should be used with care to not destroy the validity of the persistence @@ -301,17 +302,17 @@ class RU_matrix : public Master_matrix::RU_pairing_option, */ void zero_column(Index columnIndex, bool inR = true); /** - * @brief Indicates if the cell at given coordinates has value zero in \f$ R \f$ + * @brief Indicates if the entry at given coordinates has value zero in \f$ R \f$ * if @p inR is true or in \f$ U \f$ if @p inR is false. * - * @param columnIndex @ref MatIdx index of the column of the cell. - * @param rowIndex @ref rowindex "Row index" of the row of the cell. + * @param columnIndex @ref MatIdx index of the column of the entry. + * @param rowIndex @ref rowindex "Row index" of the row of the entry. * @param inR Boolean indicating in which matrix to look: if true in \f$ R \f$ and if false in \f$ U \f$. * Default value: true. - * @return true If the cell has value zero. + * @return true If the entry has value zero. * @return false Otherwise. */ - bool is_zero_cell(Index columnIndex, Index rowIndex, bool inR = true) const; + bool is_zero_entry(Index columnIndex, Index rowIndex, bool inR = true) const; /** * @brief Indicates if the column at given index has value zero in \f$ R \f$ * if @p inR is true or in \f$ U \f$ if @p inR is false. @@ -662,12 +663,12 @@ inline void RU_matrix::multiply_source_and_add_to(const Field_ele } template -inline void RU_matrix::zero_cell(Index columnIndex, Index rowIndex, bool inR) +inline void RU_matrix::zero_entry(Index columnIndex, Index rowIndex, bool inR) { if (inR) { - return reducedMatrixR_.zero_cell(columnIndex, rowIndex); + return reducedMatrixR_.zero_entry(columnIndex, rowIndex); } - return mirrorMatrixU_.zero_cell(columnIndex, rowIndex); + return mirrorMatrixU_.zero_entry(columnIndex, rowIndex); } template @@ -680,12 +681,12 @@ inline void RU_matrix::zero_column(Index columnIndex, bool inR) } template -inline bool RU_matrix::is_zero_cell(Index columnIndex, Index rowIndex, bool inR) const +inline bool RU_matrix::is_zero_entry(Index columnIndex, Index rowIndex, bool inR) const { if (inR) { - return reducedMatrixR_.is_zero_cell(columnIndex, rowIndex); + return reducedMatrixR_.is_zero_entry(columnIndex, rowIndex); } - return mirrorMatrixU_.is_zero_cell(columnIndex, rowIndex); + return mirrorMatrixU_.is_zero_entry(columnIndex, rowIndex); } template diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/allocators/cell_constructors.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/allocators/cell_constructors.h deleted file mode 100644 index f13d92256f..0000000000 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/allocators/cell_constructors.h +++ /dev/null @@ -1,139 +0,0 @@ -/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. - * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. - * Author(s): Hannah Schreiber - * - * Copyright (C) 2024 Inria - * - * Modification(s): - * - YYYY/MM Author: Description of the modification - */ - -/** - * @file cell_constructors.h - * @author Hannah Schreiber - * @brief Contains different versions of @ref Gudhi::persistence_matrix::Cell factories. - */ - -#ifndef PM_COLUMN_CELL_CONSTRUCTORS_H -#define PM_COLUMN_CELL_CONSTRUCTORS_H - -#include //std::swap - -#include - -namespace Gudhi { -namespace persistence_matrix { - -/** - * @private - * @ingroup persistence_matrix - * - * @brief @ref Cell factory. Constructs and destroys cell pointers with new and delete. - * - * @tparam Cell @ref Cell with the right templates. - */ -template -struct New_cell_constructor -{ - /** - * @brief Default constructor. - */ - New_cell_constructor() {} - - /** - * @brief Constructs a cell with the given cell arguments. - * - * @param u Arguments forwarded to the @ref Cell constructor. - * @return @ref Cell pointer. - */ - template - Cell* construct(U&&... u) const { - return new Cell(std::forward(u)...); - } - - /** - * @brief Destroys the given cell. - * - * @param cell @ref Cell pointer. - */ - void destroy(Cell* cell) const { delete cell; } - - /** - * @brief Swap operator. - */ - friend void swap(New_cell_constructor& col1, New_cell_constructor& col2) {} -}; - -/** - * @private - * @ingroup persistence_matrix - * - * @brief @ref Cell factory. Uses @ref Gudhi::Simple_object_pool, which is based on boost::object_pool, - * to construct and destroy cell pointer. - * - * @tparam Cell @ref Cell with the right templates. - */ -template -struct Pool_cell_constructor -{ - public: - /** - * @brief Default constructor. - * - */ - Pool_cell_constructor() : cellPool_() {} - //TODO: what does happen when the pool is copied? - /** - * @brief Copy constructor. - * - * @param col Factory to copy. - */ - Pool_cell_constructor(const Pool_cell_constructor& col) : cellPool_(col.cellPool_) {} - /** - * @brief Move constructor. - * - * @param col Factory to move. - */ - Pool_cell_constructor(Pool_cell_constructor&& col) : cellPool_(std::move(col.cellPool_)) {} - - /** - * @brief Constructs a cell with the given cell arguments. - * - * @param u Arguments forwarded to the @ref Cell constructor. - * @return @ref Cell pointer. - */ - template - Cell* construct(U&&... u) { - return cellPool_.construct(std::forward(u)...); - } - - /** - * @brief Destroys the given cell. - * - * @param cell @ref Cell pointer. - */ - void destroy(Cell* cell) { cellPool_.destroy(cell); } - - //TODO: Again, what does it mean to copy the pool? - /** - * @brief Assign operator. - */ - Pool_cell_constructor& operator=(const Pool_cell_constructor& other) { - cellPool_ = other.cellPool_; - return *this; - } - /** - * @brief Swap operator. - */ - friend void swap(Pool_cell_constructor& col1, Pool_cell_constructor& col2) { - std::swap(col1.cellPool_, col2.cellPool_); - } - - private: - Simple_object_pool cellPool_; /**< Cell pool. */ -}; - -} // namespace persistence_matrix -} // namespace Gudhi - -#endif // PM_COLUMN_CELL_CONSTRUCTORS_H diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/allocators/entry_constructors.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/allocators/entry_constructors.h new file mode 100644 index 0000000000..5062a985ec --- /dev/null +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/allocators/entry_constructors.h @@ -0,0 +1,139 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Hannah Schreiber + * + * Copyright (C) 2024 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +/** + * @file entry_constructors.h + * @author Hannah Schreiber + * @brief Contains different versions of @ref Gudhi::persistence_matrix::Entry factories. + */ + +#ifndef PM_COLUMN_CELL_CONSTRUCTORS_H +#define PM_COLUMN_CELL_CONSTRUCTORS_H + +#include //std::swap + +#include + +namespace Gudhi { +namespace persistence_matrix { + +/** + * @private + * @ingroup persistence_matrix + * + * @brief @ref Entry factory. Constructs and destroys entry pointers with new and delete. + * + * @tparam Entry @ref Entry with the right templates. + */ +template +struct New_entry_constructor +{ + /** + * @brief Default constructor. + */ + New_entry_constructor() {} + + /** + * @brief Constructs an entry with the given entry arguments. + * + * @param u Arguments forwarded to the @ref Entry constructor. + * @return @ref Entry pointer. + */ + template + Entry* construct(U&&... u) const { + return new Entry(std::forward(u)...); + } + + /** + * @brief Destroys the given entry. + * + * @param entry @ref Entry pointer. + */ + void destroy(Entry* entry) const { delete entry; } + + /** + * @brief Swap operator. + */ + friend void swap(New_entry_constructor& col1, New_entry_constructor& col2) {} +}; + +/** + * @private + * @ingroup persistence_matrix + * + * @brief @ref Entry factory. Uses @ref Gudhi::Simple_object_pool, which is based on boost::object_pool, + * to construct and destroy entry pointer. + * + * @tparam Entry @ref Entry with the right templates. + */ +template +struct Pool_entry_constructor +{ + public: + /** + * @brief Default constructor. + * + */ + Pool_entry_constructor() : entryPool_() {} + //TODO: what does happen when the pool is copied? + /** + * @brief Copy constructor. + * + * @param col Factory to copy. + */ + Pool_entry_constructor(const Pool_entry_constructor& col) : entryPool_(col.entryPool_) {} + /** + * @brief Move constructor. + * + * @param col Factory to move. + */ + Pool_entry_constructor(Pool_entry_constructor&& col) : entryPool_(std::move(col.entryPool_)) {} + + /** + * @brief Constructs an entry with the given entry arguments. + * + * @param u Arguments forwarded to the @ref Entry constructor. + * @return @ref Entry pointer. + */ + template + Entry* construct(U&&... u) { + return entryPool_.construct(std::forward(u)...); + } + + /** + * @brief Destroys the given entry. + * + * @param entry @ref Entry pointer. + */ + void destroy(Entry* entry) { entryPool_.destroy(entry); } + + //TODO: Again, what does it mean to copy the pool? + /** + * @brief Assign operator. + */ + Pool_entry_constructor& operator=(const Pool_entry_constructor& other) { + entryPool_ = other.entryPool_; + return *this; + } + /** + * @brief Swap operator. + */ + friend void swap(Pool_entry_constructor& col1, Pool_entry_constructor& col2) { + std::swap(col1.entryPool_, col2.entryPool_); + } + + private: + Simple_object_pool entryPool_; /**< Entry pool. */ +}; + +} // namespace persistence_matrix +} // namespace Gudhi + +#endif // PM_COLUMN_CELL_CONSTRUCTORS_H diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/base_swap.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/base_swap.h index e8f9bf412f..db6af1cc70 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/base_swap.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/base_swap.h @@ -77,7 +77,7 @@ class Base_swap { /** * @brief Swaps the two columns at given indices in the column container. Does not updates the column index value, - * potentially stored in the cells. This will be done when calling `_orderRows()`. + * potentially stored in the entries. This will be done when calling `_orderRows()`. * * @param columnIndex1 First @ref MatIdx column index. * @param columnIndex2 Second @ref MatIdx column index. @@ -145,7 +145,7 @@ template inline void Base_swap::swap_columns(Index columnIndex1, Index columnIndex2) { swap(_matrix()->matrix_.at(columnIndex1), _matrix()->matrix_.at(columnIndex2)); - if constexpr (Master_matrix::Option_list::has_row_access) rowSwapped_ = true; //to update column index in cells. + if constexpr (Master_matrix::Option_list::has_row_access) rowSwapped_ = true; //to update column index in entries. } template diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/chain_vine_swap.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/chain_vine_swap.h index 2956ba0e2e..887f89cb2c 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/chain_vine_swap.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/chain_vine_swap.h @@ -401,7 +401,7 @@ inline typename Chain_vine_swap::Index Chain_vine_swapis_zero_cell(columnIndex2, _matrix()->get_pivot(columnIndex1))) { + if (_matrix()->is_zero_entry(columnIndex2, _matrix()->get_pivot(columnIndex1))) { if constexpr (Master_matrix::Option_list::has_column_pairings) { ID_index pivot1 = _matrix()->get_pivot(columnIndex1); ID_index pivot2 = _matrix()->get_pivot(columnIndex2); @@ -415,7 +415,7 @@ inline typename Chain_vine_swap::Index Chain_vine_swapis_zero_cell(columnIndex2, _matrix()->get_pivot(columnIndex1))) { + if (_matrix()->is_zero_entry(columnIndex2, _matrix()->get_pivot(columnIndex1))) { if constexpr (Master_matrix::Option_list::has_column_pairings) { ID_index pivot1 = _matrix()->get_pivot(columnIndex1); ID_index pivot2 = _matrix()->get_pivot(columnIndex2); @@ -429,7 +429,7 @@ inline typename Chain_vine_swap::Index Chain_vine_swapis_zero_cell(columnIndex2, _matrix()->get_pivot(columnIndex1))) { + if (_matrix()->is_zero_entry(columnIndex2, _matrix()->get_pivot(columnIndex1))) { if constexpr (Master_matrix::Option_list::has_column_pairings) { ID_index pivot1 = _matrix()->get_pivot(columnIndex1); ID_index pivot2 = _matrix()->get_pivot(columnIndex2); @@ -442,7 +442,7 @@ inline typename Chain_vine_swap::Index Chain_vine_swapis_zero_cell(columnIndex2, _matrix()->get_pivot(columnIndex1))) { + if (_matrix()->is_zero_entry(columnIndex2, _matrix()->get_pivot(columnIndex1))) { if constexpr (Master_matrix::Option_list::has_column_pairings) { ID_index pivot1 = _matrix()->get_pivot(columnIndex1); ID_index pivot2 = _matrix()->get_pivot(columnIndex2); diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/cell_types.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/cell_types.h deleted file mode 100644 index 0bf59de134..0000000000 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/cell_types.h +++ /dev/null @@ -1,327 +0,0 @@ -/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. - * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. - * Author(s): Hannah Schreiber - * - * Copyright (C) 2022-24 Inria - * - * Modification(s): - * - YYYY/MM Author: Description of the modification - */ - -/** - * @file cell_types.h - * @author Hannah Schreiber - * @brief Contains the @ref Gudhi::persistence_matrix::Cell, @ref Gudhi::persistence_matrix::Cell_column_index and - * @ref Gudhi::persistence_matrix::Cell_field_element classes, as well as the - * @ref Gudhi::persistence_matrix::Dummy_cell_column_index_mixin and - * @ref Gudhi::persistence_matrix::Dummy_cell_field_element_mixin structures. - * Also defines the std::hash method for @ref Gudhi::persistence_matrix::Cell. - */ - -#ifndef PM_MATRIX_CELL_H -#define PM_MATRIX_CELL_H - -#include //std::swap, std::exchange & std::move -#include //std::hash - -namespace Gudhi { -namespace persistence_matrix { - -/** - * @ingroup persistence_matrix - * - * @brief Empty structure. - * Inherited instead of @ref Cell_column_index, when the row access is disabled. - */ -struct Dummy_cell_column_index_mixin -{ - Dummy_cell_column_index_mixin() {} - template - Dummy_cell_column_index_mixin([[maybe_unused]] Index columnIndex) {} -}; - -/** - * @ingroup persistence_matrix - * - * @brief Empty structure. - * Inherited instead of @ref Cell_field_element, when @ref PersistenceMatrixOptions::is_z2 is true. - */ -struct Dummy_cell_field_element_mixin -{ - Dummy_cell_field_element_mixin() {} - template - Dummy_cell_field_element_mixin([[maybe_unused]] Field_element t) {} -}; - -/** - * @ingroup persistence_matrix - * - * @brief Class managing the column index access of a cell. - * - * @tparam Index @ref MatIdx index type. - */ -template -class Cell_column_index -{ - public: - /** - * @brief Default constructor. Sets to the column index to -1. - */ - Cell_column_index() : columnIndex_(-1){}; - /** - * @brief Stores the given column index. - * - * @param columnIndex Column index of the cell. - */ - Cell_column_index(Index columnIndex) : columnIndex_(columnIndex){}; - /** - * @brief Copy constructor. - * - * @param cell Cell to copy. - */ - Cell_column_index(const Cell_column_index& cell) : columnIndex_(cell.columnIndex_){}; - /** - * @brief Move constructor. - * - * @param cell Cell to move. - */ - Cell_column_index(Cell_column_index&& cell) noexcept : columnIndex_(std::exchange(cell.columnIndex_, 0)){}; - - /** - * @brief Returns the @ref MatIdx column index stored in the cell. - * - * @return Column index of the cell. - */ - Index get_column_index() const { return columnIndex_; }; - /** - * @brief Sets the column index to the given value. - * - * @param columnIndex Column index of the cell. - */ - void set_column_index(Index columnIndex) { columnIndex_ = columnIndex; } - - /** - * @brief Assign operator. - */ - Cell_column_index& operator=(Cell_column_index other) { - std::swap(columnIndex_, other.columnIndex_); - return *this; - }; - - private: - Index columnIndex_; /**< Column index. */ -}; - -/** - * @ingroup persistence_matrix - * - * @brief Class managing the value access of a cell. - * - * @tparam Field_element Type of a cell value. - */ -template -class Cell_field_element -{ - public: - /** - * @brief Default constructor. Sets to the element to 0. - */ - Cell_field_element() : element_(0){}; - /** - * @brief Stores the given element. - * - * @param element Value to store. - */ - Cell_field_element(Field_element element) : element_(element){}; - /** - * @brief Copy constructor. - * - * @param cell Cell to copy. - */ - Cell_field_element(const Cell_field_element& cell) : element_(cell.element_){}; - /** - * @brief Move constructor. - * - * @param cell Cell to move. - */ - Cell_field_element(Cell_field_element&& cell) noexcept : element_(std::move(cell.element_)){}; - - /** - * @brief Returns the value stored in the cell. - * - * @return Reference to the value of the cell. - */ - Field_element& get_element() { return element_; }; - /** - * @brief Returns the value stored in the cell. - * - * @return Const reference to the value of the cell. - */ - const Field_element& get_element() const { return element_; }; - /** - * @brief Sets the value. - * - * @param element Value to store. - */ - void set_element(const Field_element& element) { element_ = element; } - - /** - * @brief Assign operator. - */ - Cell_field_element& operator=(Cell_field_element other) { - std::swap(element_, other.element_); - return *this; - }; - - private: - Field_element element_; /**< Value of the cell. */ -}; - -/** - * @class Cell cell_types.h gudhi/Persistence_matrix/columns/cell_types.h - * @ingroup persistence_matrix - * - * @brief %Matrix cell class. Stores by default only the row index it belongs to, but can also store its - * column index when the row access is enabled, as well as its value when they are different from only 0 and 1. - * Zero-valued cells are never made explicit in the matrix. - * - * @tparam Master_matrix An instantiation of @ref Matrix from which all types and options are deduced. - */ -template -class Cell : public Master_matrix::Cell_column_index_option, - public Master_matrix::Cell_field_element_option, - public Master_matrix::Row_hook, - public Master_matrix::Column_hook -{ - private: - using col_opt = typename Master_matrix::Cell_column_index_option; - using field_opt = typename Master_matrix::Cell_field_element_option; - - public: - using Master = Master_matrix; /**< Access to options from outside. */ - using Index = typename Master_matrix::Index; /**< Column index type. */ - using ID_index = typename Master_matrix::ID_index; /**< Row index type. */ - using Field_element = typename Master_matrix::Element; /**< Value type. */ - - /** - * @brief Constructs an cell with all attributes at default values. - */ - Cell(){}; - /** - * @brief Constructs a cell with given row index. Other possible attributes are set at default values. - * - * @param rowIndex @ref rowindex "Row index" of the cell. - */ - Cell(ID_index rowIndex) : col_opt(), field_opt(), rowIndex_(rowIndex){}; - /** - * @brief Constructs a cell with given row and column index. Other possible attributes are set at default values. - * - * @param columnIndex Column index of the cell. - * @param rowIndex @ref rowindex "Row index" of the cell. - */ - Cell(Index columnIndex, ID_index rowIndex) : col_opt(columnIndex), field_opt(), rowIndex_(rowIndex){}; - /** - * @brief Copy constructor. - * - * @param cell Cell to copy. - */ - Cell(const Cell& cell) - : col_opt(static_cast(cell)), - field_opt(static_cast(cell)), - rowIndex_(cell.rowIndex_){}; - /** - * @brief Move constructor. - * - * @param cell Cell to move. - */ - Cell(Cell&& cell) noexcept - : col_opt(std::move(static_cast(cell))), - field_opt(std::move(static_cast(cell))), - rowIndex_(std::exchange(cell.rowIndex_, 0)){}; - - /** - * @brief Returns the row index stored in the cell. - * - * @return @ref rowindex "Row index" of the cell. - */ - ID_index get_row_index() const { return rowIndex_; }; - /** - * @brief Sets the row index stored in the cell. - * - * @param rowIndex @ref rowindex "Row index" of the cell. - */ - void set_row_index(ID_index rowIndex) { rowIndex_ = rowIndex; }; - - /** - * @brief Assign operator. - */ - Cell& operator=(Cell other) { - col_opt::operator=(other); - field_opt::operator=(other); - std::swap(rowIndex_, other.rowIndex_); - return *this; - }; - - /** - * @brief Strictly smaller than comparator. - * - * @param c1 First cell to compare. - * @param c2 Second cell to compare. - * @return true If the row index of the first cell is strictly smaller than the row index of the second cell. - * @return false Otherwise. - */ - friend bool operator<(const Cell& c1, const Cell& c2) { return c1.get_row_index() < c2.get_row_index(); } - /** - * @brief Equality comparator. - * - * @param c1 First cell to compare. - * @param c2 Second cell to compare. - * @return true If the row index of the first cell is equal to the row index of the second cell. - * @return false Otherwise. - */ - friend bool operator==(const Cell& c1, const Cell& c2) { return c1.get_row_index() == c2.get_row_index(); } - - /** - * @brief Converts the cell into a row index. - * - * @return The row index of the cell. - */ - operator ID_index() const { return rowIndex_; } - /** - * @brief Converts the cell into a pair of row index and cell value. - * - * @return A std::pair with first element the row index and second element the value. - */ - operator std::pair() const { - if constexpr (Master_matrix::Option_list::is_z2) { - return {rowIndex_, 1}; - } else { - return {rowIndex_, field_opt::element_}; - } - } - - private: - ID_index rowIndex_; /**< Row index of the cell. */ -}; - -} // namespace persistence_matrix -} // namespace Gudhi - -/** - * @ingroup persistence_matrix - * - * @brief Hash method for @ref Gudhi::persistence_matrix::Cell. - * - * The cells are differentiated by their row indices only. For example, two cells with the same row index - * but different column indices have the same hash value. - * - * @tparam Master_matrix Template parameter of @ref Gudhi::persistence_matrix::Cell. - */ -template -struct std::hash > { - std::size_t operator()(const Gudhi::persistence_matrix::Cell& cell) const { - return std::hash()(cell.get_row_index()); - } -}; - -#endif // PM_MATRIX_CELL_H diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/column_utilities.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/column_utilities.h index 360ac37ec1..bb7670cf2e 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/column_utilities.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/column_utilities.h @@ -25,11 +25,11 @@ namespace Gudhi { namespace persistence_matrix { -template -Cell* _get_cell(const Cell_iterator& itTarget) +template +Entry* _get_entry(const Entry_iterator& itTarget) { - if constexpr (Cell::Master::Option_list::column_type == Column_types::INTRUSIVE_LIST || - Cell::Master::Option_list::column_type == Column_types::INTRUSIVE_SET) { + if constexpr (Entry::Master::Option_list::column_type == Column_types::INTRUSIVE_LIST || + Entry::Master::Option_list::column_type == Column_types::INTRUSIVE_SET) { return &*itTarget; } else { return *itTarget; @@ -37,41 +37,41 @@ Cell* _get_cell(const Cell_iterator& itTarget) } // works only for ordered columns -template -void _generic_merge_cell_to_column(Column& targetColumn, - Cell_iterator& itSource, - typename Column::Column_support::iterator& itTarget, - F1&& process_target, - F2&& process_source, - F3&& update_target1, - F4&& update_target2, - bool& pivotIsZeroed) +template +void _generic_merge_entry_to_column(Column& targetColumn, + Entry_iterator& itSource, + typename Column::Column_support::iterator& itTarget, + F1&& process_target, + F2&& process_source, + F3&& update_target1, + F4&& update_target2, + bool& pivotIsZeroed) { - typename Column::Cell* targetCell = _get_cell(itTarget); + typename Column::Entry* targetEntry = _get_entry(itTarget); - if (targetCell->get_row_index() < itSource->get_row_index()) { - process_target(targetCell); + if (targetEntry->get_row_index() < itSource->get_row_index()) { + process_target(targetEntry); ++itTarget; - } else if (targetCell->get_row_index() > itSource->get_row_index()) { + } else if (targetEntry->get_row_index() > itSource->get_row_index()) { process_source(itSource, itTarget); ++itSource; } else { if constexpr (Column::Master::Option_list::is_z2) { //_multiply_*_and_add never enters here so not treated if constexpr (Column::Master::isNonBasic && !Column::Master::Option_list::is_of_boundary_type) { - if (targetCell->get_row_index() == targetColumn.get_pivot()) pivotIsZeroed = true; + if (targetEntry->get_row_index() == targetColumn.get_pivot()) pivotIsZeroed = true; } - targetColumn._delete_cell(itTarget); + targetColumn._delete_entry(itTarget); } else { - update_target1(targetCell->get_element(), itSource); - if (targetCell->get_element() == Column::Field_operators::get_additive_identity()) { + update_target1(targetEntry->get_element(), itSource); + if (targetEntry->get_element() == Column::Field_operators::get_additive_identity()) { if constexpr (Column::Master::isNonBasic && !Column::Master::Option_list::is_of_boundary_type) { - if (targetCell->get_row_index() == targetColumn.get_pivot()) pivotIsZeroed = true; + if (targetEntry->get_row_index() == targetColumn.get_pivot()) pivotIsZeroed = true; } - targetColumn._delete_cell(itTarget); + targetColumn._delete_entry(itTarget); } else { - update_target2(targetCell); - if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_cell(*targetCell); + update_target2(targetEntry); + if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_entry(*targetEntry); ++itTarget; } } @@ -80,8 +80,8 @@ void _generic_merge_cell_to_column(Column& targetColumn, } // works only for ordered columns -template -bool _generic_add_to_column(const Cell_range& source, +template +bool _generic_add_to_column(const Entry_range& source, Column& targetColumn, F1&& process_target, F2&& process_source, @@ -95,9 +95,9 @@ bool _generic_add_to_column(const Cell_range& source, auto itTarget = target.begin(); auto itSource = source.begin(); while (itTarget != target.end() && itSource != source.end()) { - _generic_merge_cell_to_column(targetColumn, itSource, itTarget, - process_target, process_source, update_target1, update_target2, - pivotIsZeroed); + _generic_merge_entry_to_column(targetColumn, itSource, itTarget, + process_target, process_source, update_target1, update_target2, + pivotIsZeroed); } finish_target(itTarget); @@ -110,32 +110,32 @@ bool _generic_add_to_column(const Cell_range& source, return pivotIsZeroed; } -template -bool _add_to_column(const Cell_range& source, Column& targetColumn) +template +bool _add_to_column(const Entry_range& source, Column& targetColumn) { return _generic_add_to_column( source, targetColumn, - [&]([[maybe_unused]] typename Column::Cell* cellTarget) {}, - [&](typename Cell_range::const_iterator& itSource, const typename Column::Column_support::iterator& itTarget) { + [&]([[maybe_unused]] typename Column::Entry* entryTarget) {}, + [&](typename Entry_range::const_iterator& itSource, const typename Column::Column_support::iterator& itTarget) { if constexpr (Column::Master::Option_list::is_z2) { - targetColumn._insert_cell(itSource->get_row_index(), itTarget); + targetColumn._insert_entry(itSource->get_row_index(), itTarget); } else { - targetColumn._insert_cell(itSource->get_element(), itSource->get_row_index(), itTarget); + targetColumn._insert_entry(itSource->get_element(), itSource->get_row_index(), itTarget); } }, - [&](typename Column::Field_element& targetElement, typename Cell_range::const_iterator& itSource) { + [&](typename Column::Field_element& targetElement, typename Entry_range::const_iterator& itSource) { if constexpr (!Column::Master::Option_list::is_z2) targetColumn.operators_->add_inplace(targetElement, itSource->get_element()); }, - [&]([[maybe_unused]] typename Column::Cell* cellTarget) {}, + [&]([[maybe_unused]] typename Column::Entry* entryTarget) {}, [&]([[maybe_unused]] typename Column::Column_support::iterator& itTarget) {} ); } -template +template bool _multiply_target_and_add_to_column(const typename Column::Field_element& val, - const Cell_range& source, + const Entry_range& source, Column& targetColumn) { if (val == 0u) { @@ -150,33 +150,33 @@ bool _multiply_target_and_add_to_column(const typename Column::Field_element& va return _generic_add_to_column( source, targetColumn, - [&](typename Column::Cell* cellTarget) { - targetColumn.operators_->multiply_inplace(cellTarget->get_element(), val); - // targetColumn.RA_opt::update_cell(*itTarget) produces an internal compiler error + [&](typename Column::Entry* entryTarget) { + targetColumn.operators_->multiply_inplace(entryTarget->get_element(), val); + // targetColumn.RA_opt::update_entry(*itTarget) produces an internal compiler error // even though it works in _generic_add_to_column... Probably because of the lambda. - if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_cell(*cellTarget); + if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_entry(*entryTarget); }, - [&](typename Cell_range::const_iterator& itSource, const typename Column::Column_support::iterator& itTarget) { - targetColumn._insert_cell(itSource->get_element(), itSource->get_row_index(), itTarget); + [&](typename Entry_range::const_iterator& itSource, const typename Column::Column_support::iterator& itTarget) { + targetColumn._insert_entry(itSource->get_element(), itSource->get_row_index(), itTarget); }, - [&](typename Column::Field_element& targetElement, typename Cell_range::const_iterator& itSource) { + [&](typename Column::Field_element& targetElement, typename Entry_range::const_iterator& itSource) { targetColumn.operators_->multiply_and_add_inplace_front(targetElement, val, itSource->get_element()); }, - [&]([[maybe_unused]] typename Column::Cell* cellTarget) {}, + [&]([[maybe_unused]] typename Column::Entry* entryTarget) {}, [&](typename Column::Column_support::iterator& itTarget) { while (itTarget != targetColumn.column_.end()) { - typename Column::Cell* targetCell = _get_cell(itTarget); - targetColumn.operators_->multiply_inplace(targetCell->get_element(), val); - if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_cell(*targetCell); + typename Column::Entry* targetEntry = _get_entry(itTarget); + targetColumn.operators_->multiply_inplace(targetEntry->get_element(), val); + if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_entry(*targetEntry); itTarget++; } } ); } -template +template bool _multiply_source_and_add_to_column(const typename Column::Field_element& val, - const Cell_range& source, + const Entry_range& source, Column& targetColumn) { if (val == 0u) { @@ -186,17 +186,17 @@ bool _multiply_source_and_add_to_column(const typename Column::Field_element& va return _generic_add_to_column( source, targetColumn, - []([[maybe_unused]] typename Column::Cell* cellTarget) {}, - [&](typename Cell_range::const_iterator& itSource, const typename Column::Column_support::iterator& itTarget) { - typename Column::Cell* cell = - targetColumn._insert_cell(itSource->get_element(), itSource->get_row_index(), itTarget); - targetColumn.operators_->multiply_inplace(cell->get_element(), val); - if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_cell(*cell); + []([[maybe_unused]] typename Column::Entry* entryTarget) {}, + [&](typename Entry_range::const_iterator& itSource, const typename Column::Column_support::iterator& itTarget) { + typename Column::Entry* entry = + targetColumn._insert_entry(itSource->get_element(), itSource->get_row_index(), itTarget); + targetColumn.operators_->multiply_inplace(entry->get_element(), val); + if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_entry(*entry); }, - [&](typename Column::Field_element& targetElement, typename Cell_range::const_iterator& itSource) { + [&](typename Column::Field_element& targetElement, typename Entry_range::const_iterator& itSource) { targetColumn.operators_->multiply_and_add_inplace_back(itSource->get_element(), val, targetElement); }, - [&]([[maybe_unused]] typename Column::Cell* cellTarget) {}, + [&]([[maybe_unused]] typename Column::Entry* entryTarget) {}, []([[maybe_unused]] typename Column::Column_support::iterator& itTarget) {}); } @@ -206,8 +206,8 @@ template std::size_t hash_column(const Column& column) { std::size_t seed = 0; - for (auto& cell : column) { - seed ^= std::hash()(cell.get_row_index() * static_cast(cell.get_element())) + + for (auto& entry : column) { + seed ^= std::hash()(entry.get_row_index() * static_cast(entry.get_element())) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } return seed; diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/entry_types.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/entry_types.h new file mode 100644 index 0000000000..ca9ad3389f --- /dev/null +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/entry_types.h @@ -0,0 +1,327 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Hannah Schreiber + * + * Copyright (C) 2022-24 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +/** + * @file entry_types.h + * @author Hannah Schreiber + * @brief Contains the @ref Gudhi::persistence_matrix::Entry, @ref Gudhi::persistence_matrix::Entry_column_index and + * @ref Gudhi::persistence_matrix::Entry_field_element classes, as well as the + * @ref Gudhi::persistence_matrix::Dummy_entry_column_index_mixin and + * @ref Gudhi::persistence_matrix::Dummy_entry_field_element_mixin structures. + * Also defines the std::hash method for @ref Gudhi::persistence_matrix::Entry. + */ + +#ifndef PM_MATRIX_CELL_H +#define PM_MATRIX_CELL_H + +#include //std::swap, std::exchange & std::move +#include //std::hash + +namespace Gudhi { +namespace persistence_matrix { + +/** + * @ingroup persistence_matrix + * + * @brief Empty structure. + * Inherited instead of @ref Entry_column_index, when the row access is disabled. + */ +struct Dummy_entry_column_index_mixin +{ + Dummy_entry_column_index_mixin() {} + template + Dummy_entry_column_index_mixin([[maybe_unused]] Index columnIndex) {} +}; + +/** + * @ingroup persistence_matrix + * + * @brief Empty structure. + * Inherited instead of @ref Entry_field_element, when @ref PersistenceMatrixOptions::is_z2 is true. + */ +struct Dummy_entry_field_element_mixin +{ + Dummy_entry_field_element_mixin() {} + template + Dummy_entry_field_element_mixin([[maybe_unused]] Field_element t) {} +}; + +/** + * @ingroup persistence_matrix + * + * @brief Class managing the column index access of an entry. + * + * @tparam Index @ref MatIdx index type. + */ +template +class Entry_column_index +{ + public: + /** + * @brief Default constructor. Sets to the column index to -1. + */ + Entry_column_index() : columnIndex_(-1){}; + /** + * @brief Stores the given column index. + * + * @param columnIndex Column index of the entry. + */ + Entry_column_index(Index columnIndex) : columnIndex_(columnIndex){}; + /** + * @brief Copy constructor. + * + * @param entry Entry to copy. + */ + Entry_column_index(const Entry_column_index& entry) : columnIndex_(entry.columnIndex_){}; + /** + * @brief Move constructor. + * + * @param entry Entry to move. + */ + Entry_column_index(Entry_column_index&& entry) noexcept : columnIndex_(std::exchange(entry.columnIndex_, 0)){}; + + /** + * @brief Returns the @ref MatIdx column index stored in the entry. + * + * @return Column index of the entry. + */ + Index get_column_index() const { return columnIndex_; }; + /** + * @brief Sets the column index to the given value. + * + * @param columnIndex Column index of the entry. + */ + void set_column_index(Index columnIndex) { columnIndex_ = columnIndex; } + + /** + * @brief Assign operator. + */ + Entry_column_index& operator=(Entry_column_index other) { + std::swap(columnIndex_, other.columnIndex_); + return *this; + }; + + private: + Index columnIndex_; /**< Column index. */ +}; + +/** + * @ingroup persistence_matrix + * + * @brief Class managing the value access of an entry. + * + * @tparam Field_element Type of an entry value. + */ +template +class Entry_field_element +{ + public: + /** + * @brief Default constructor. Sets to the element to 0. + */ + Entry_field_element() : element_(0){}; + /** + * @brief Stores the given element. + * + * @param element Value to store. + */ + Entry_field_element(Field_element element) : element_(element){}; + /** + * @brief Copy constructor. + * + * @param entry Entry to copy. + */ + Entry_field_element(const Entry_field_element& entry) : element_(entry.element_){}; + /** + * @brief Move constructor. + * + * @param entry Entry to move. + */ + Entry_field_element(Entry_field_element&& entry) noexcept : element_(std::move(entry.element_)){}; + + /** + * @brief Returns the value stored in the entry. + * + * @return Reference to the value of the entry. + */ + Field_element& get_element() { return element_; }; + /** + * @brief Returns the value stored in the entry. + * + * @return Const reference to the value of the entry. + */ + const Field_element& get_element() const { return element_; }; + /** + * @brief Sets the value. + * + * @param element Value to store. + */ + void set_element(const Field_element& element) { element_ = element; } + + /** + * @brief Assign operator. + */ + Entry_field_element& operator=(Entry_field_element other) { + std::swap(element_, other.element_); + return *this; + }; + + private: + Field_element element_; /**< Value of the entry. */ +}; + +/** + * @class Entry entry_types.h gudhi/Persistence_matrix/columns/entry_types.h + * @ingroup persistence_matrix + * + * @brief %Matrix entry class. Stores by default only the row index it belongs to, but can also store its + * column index when the row access is enabled, as well as its value when they are different from only 0 and 1. + * Zero-valued entries are never made explicit in the matrix. + * + * @tparam Master_matrix An instantiation of @ref Matrix from which all types and options are deduced. + */ +template +class Entry : public Master_matrix::Entry_column_index_option, + public Master_matrix::Entry_field_element_option, + public Master_matrix::Row_hook, + public Master_matrix::Column_hook +{ + private: + using col_opt = typename Master_matrix::Entry_column_index_option; + using field_opt = typename Master_matrix::Entry_field_element_option; + + public: + using Master = Master_matrix; /**< Access to options from outside. */ + using Index = typename Master_matrix::Index; /**< Column index type. */ + using ID_index = typename Master_matrix::ID_index; /**< Row index type. */ + using Field_element = typename Master_matrix::Element; /**< Value type. */ + + /** + * @brief Constructs an entry with all attributes at default values. + */ + Entry(){}; + /** + * @brief Constructs an entry with given row index. Other possible attributes are set at default values. + * + * @param rowIndex @ref rowindex "Row index" of the entry. + */ + Entry(ID_index rowIndex) : col_opt(), field_opt(), rowIndex_(rowIndex){}; + /** + * @brief Constructs an entry with given row and column index. Other possible attributes are set at default values. + * + * @param columnIndex Column index of the entry. + * @param rowIndex @ref rowindex "Row index" of the entry. + */ + Entry(Index columnIndex, ID_index rowIndex) : col_opt(columnIndex), field_opt(), rowIndex_(rowIndex){}; + /** + * @brief Copy constructor. + * + * @param entry Entry to copy. + */ + Entry(const Entry& entry) + : col_opt(static_cast(entry)), + field_opt(static_cast(entry)), + rowIndex_(entry.rowIndex_){}; + /** + * @brief Move constructor. + * + * @param entry Entry to move. + */ + Entry(Entry&& entry) noexcept + : col_opt(std::move(static_cast(entry))), + field_opt(std::move(static_cast(entry))), + rowIndex_(std::exchange(entry.rowIndex_, 0)){}; + + /** + * @brief Returns the row index stored in the entry. + * + * @return @ref rowindex "Row index" of the entry. + */ + ID_index get_row_index() const { return rowIndex_; }; + /** + * @brief Sets the row index stored in the entry. + * + * @param rowIndex @ref rowindex "Row index" of the entry. + */ + void set_row_index(ID_index rowIndex) { rowIndex_ = rowIndex; }; + + /** + * @brief Assign operator. + */ + Entry& operator=(Entry other) { + col_opt::operator=(other); + field_opt::operator=(other); + std::swap(rowIndex_, other.rowIndex_); + return *this; + }; + + /** + * @brief Strictly smaller than comparator. + * + * @param c1 First entry to compare. + * @param c2 Second entry to compare. + * @return true If the row index of the first entry is strictly smaller than the row index of the second entry. + * @return false Otherwise. + */ + friend bool operator<(const Entry& c1, const Entry& c2) { return c1.get_row_index() < c2.get_row_index(); } + /** + * @brief Equality comparator. + * + * @param c1 First entry to compare. + * @param c2 Second entry to compare. + * @return true If the row index of the first entry is equal to the row index of the second entry. + * @return false Otherwise. + */ + friend bool operator==(const Entry& c1, const Entry& c2) { return c1.get_row_index() == c2.get_row_index(); } + + /** + * @brief Converts the entry into a row index. + * + * @return The row index of the entry. + */ + operator ID_index() const { return rowIndex_; } + /** + * @brief Converts the entry into a pair of row index and entry value. + * + * @return A std::pair with first element the row index and second element the value. + */ + operator std::pair() const { + if constexpr (Master_matrix::Option_list::is_z2) { + return {rowIndex_, 1}; + } else { + return {rowIndex_, field_opt::element_}; + } + } + + private: + ID_index rowIndex_; /**< Row index of the entry. */ +}; + +} // namespace persistence_matrix +} // namespace Gudhi + +/** + * @ingroup persistence_matrix + * + * @brief Hash method for @ref Gudhi::persistence_matrix::Entry. + * + * The entries are differentiated by their row indices only. For example, two entries with the same row index + * but different column indices have the same hash value. + * + * @tparam Master_matrix Template parameter of @ref Gudhi::persistence_matrix::Entry. + */ +template +struct std::hash > { + std::size_t operator()(const Gudhi::persistence_matrix::Entry& entry) const { + return std::hash()(entry.get_row_index()); + } +}; + +#endif // PM_MATRIX_CELL_H diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/heap_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/heap_column.h index 33e8558088..5a0e4dc5c2 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/heap_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/heap_column.h @@ -26,7 +26,7 @@ #include -#include +#include namespace Gudhi { namespace persistence_matrix { @@ -38,13 +38,13 @@ namespace persistence_matrix { * @brief Column class following the @ref PersistenceMatrixColumn concept. Not compatible with row access. * * Column based on a heap structure. The heap is represented as a vector sorted as a heap. The top of the heap is - * the cell with the biggest row index. The sum of two columns is lazy: the content of the source is simply inserted - * into the heap of the target. Therefore the underlying vector can contain several cells with the same row index. - * The real value of a cell at a row index corresponds to the sum in the coefficient field of all values with same - * row index. Additionally, the given cell range added into the heap does not need to be somehow ordered. + * the entry with the biggest row index. The sum of two columns is lazy: the content of the source is simply inserted + * into the heap of the target. Therefore the underlying vector can contain several entries with the same row index. + * The real value of an entry at a row index corresponds to the sum in the coefficient field of all values with same + * row index. Additionally, the given entry range added into the heap does not need to be somehow ordered. * * @tparam Master_matrix An instantiation of @ref Matrix from which all types and options are deduced. - * @tparam Cell_constructor Factory of @ref Cell classes. + * @tparam Entry_constructor Factory of @ref Entry classes. */ template class Heap_column : public Master_matrix::Column_dimension_option, public Master_matrix::Chain_column_option @@ -55,13 +55,13 @@ class Heap_column : public Master_matrix::Column_dimension_option, public Master using ID_index = typename Master_matrix::ID_index; using Dimension = typename Master_matrix::Dimension; using Field_element = typename Master_matrix::Element; - using Cell = typename Master_matrix::Matrix_cell; + using Entry = typename Master_matrix::Matrix_entry; using Column_settings = typename Master_matrix::Column_settings; private: using Field_operators = typename Master_matrix::Field_operators; - using Column_support = std::vector; - using Cell_constructor = typename Master_matrix::Cell_constructor; + using Column_support = std::vector; + using Entry_constructor = typename Master_matrix::Entry_constructor; public: using iterator = boost::indirect_iterator; @@ -119,19 +119,19 @@ class Heap_column : public Master_matrix::Column_dimension_option, public Master reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; - template - Heap_column& operator+=(const Cell_range& column); + template + Heap_column& operator+=(const Entry_range& column); Heap_column& operator+=(Heap_column& column); Heap_column& operator*=(unsigned int v); // this = v * this + column - template - Heap_column& multiply_target_and_add(const Field_element& val, const Cell_range& column); + template + Heap_column& multiply_target_and_add(const Field_element& val, const Entry_range& column); Heap_column& multiply_target_and_add(const Field_element& val, Heap_column& column); // this = this + column * v - template - Heap_column& multiply_source_and_add(const Cell_range& column, const Field_element& val); + template + Heap_column& multiply_source_and_add(const Entry_range& column, const Field_element& val); Heap_column& multiply_source_and_add(Heap_column& column, const Field_element& val); std::size_t compute_hash_value(); @@ -140,33 +140,33 @@ class Heap_column : public Master_matrix::Column_dimension_option, public Master if (&c1 == &c2) return true; Heap_column cc1(c1), cc2(c2); - Cell* p1 = cc1._pop_pivot(); - Cell* p2 = cc2._pop_pivot(); + Entry* p1 = cc1._pop_pivot(); + Entry* p2 = cc2._pop_pivot(); while (p1 != nullptr && p2 != nullptr) { if (p1->get_row_index() != p2->get_row_index()) { - c1.cellPool_->destroy(p1); - c2.cellPool_->destroy(p2); + c1.entryPool_->destroy(p1); + c2.entryPool_->destroy(p2); return false; } if constexpr (!Master_matrix::Option_list::is_z2) { if (p1->get_element() != p2->get_element()) { - c1.cellPool_->destroy(p1); - c2.cellPool_->destroy(p2); + c1.entryPool_->destroy(p1); + c2.entryPool_->destroy(p2); return false; } } - c1.cellPool_->destroy(p1); - c2.cellPool_->destroy(p2); + c1.entryPool_->destroy(p1); + c2.entryPool_->destroy(p2); p1 = cc1._pop_pivot(); p2 = cc2._pop_pivot(); } if (p1 == nullptr && p2 == nullptr) return true; if (p1 != nullptr) { - c1.cellPool_->destroy(p1); + c1.entryPool_->destroy(p1); return false; } - c2.cellPool_->destroy(p2); + c2.entryPool_->destroy(p2); return false; } friend bool operator<(const Heap_column& c1, const Heap_column& c2) { @@ -174,42 +174,42 @@ class Heap_column : public Master_matrix::Column_dimension_option, public Master // lexicographical order but starting from last value and not first Heap_column cc1(c1), cc2(c2); - Cell* p1 = cc1._pop_pivot(); - Cell* p2 = cc2._pop_pivot(); + Entry* p1 = cc1._pop_pivot(); + Entry* p2 = cc2._pop_pivot(); while (p1 != nullptr && p2 != nullptr) { if (p1->get_row_index() > p2->get_row_index()) { - c1.cellPool_->destroy(p1); - c2.cellPool_->destroy(p2); + c1.entryPool_->destroy(p1); + c2.entryPool_->destroy(p2); return false; } if (p1->get_row_index() < p2->get_row_index()) { - c1.cellPool_->destroy(p1); - c2.cellPool_->destroy(p2); + c1.entryPool_->destroy(p1); + c2.entryPool_->destroy(p2); return true; } if constexpr (!Master_matrix::Option_list::is_z2) { if (p1->get_element() > p2->get_element()) { - c1.cellPool_->destroy(p1); - c2.cellPool_->destroy(p2); + c1.entryPool_->destroy(p1); + c2.entryPool_->destroy(p2); return false; } if (p1->get_element() < p2->get_element()) { - c1.cellPool_->destroy(p1); - c2.cellPool_->destroy(p2); + c1.entryPool_->destroy(p1); + c2.entryPool_->destroy(p2); return true; } } - c1.cellPool_->destroy(p1); - c2.cellPool_->destroy(p2); + c1.entryPool_->destroy(p1); + c2.entryPool_->destroy(p2); p1 = cc1._pop_pivot(); p2 = cc2._pop_pivot(); } if (p2 == nullptr) { - c1.cellPool_->destroy(p1); + c1.entryPool_->destroy(p1); return false; } - c2.cellPool_->destroy(p2); + c2.entryPool_->destroy(p2); return true; } @@ -224,30 +224,30 @@ class Heap_column : public Master_matrix::Column_dimension_option, public Master col1.column_.swap(col2.column_); std::swap(col1.insertsSinceLastPrune_, col2.insertsSinceLastPrune_); std::swap(col1.operators_, col2.operators_); - std::swap(col1.cellPool_, col2.cellPool_); + std::swap(col1.entryPool_, col2.entryPool_); } private: using Dim_opt = typename Master_matrix::Column_dimension_option; using Chain_opt = typename Master_matrix::Chain_column_option; - struct CellPointerComp { - bool operator()(const Cell* c1, const Cell* c2) const { return *c1 < *c2; } - } cellPointerComp_; + struct EntryPointerComp { + bool operator()(const Entry* c1, const Entry* c2) const { return *c1 < *c2; } + } entryPointerComp_; Column_support column_; unsigned int insertsSinceLastPrune_; Field_operators* operators_; - Cell_constructor* cellPool_; + Entry_constructor* entryPool_; void _prune(); - Cell* _pop_pivot(); - template - bool _add(const Cell_range& column); - template - bool _multiply_target_and_add(const Field_element& val, const Cell_range& column); - template - bool _multiply_source_and_add(const Cell_range& column, const Field_element& val); + Entry* _pop_pivot(); + template + bool _add(const Entry_range& column); + template + bool _multiply_target_and_add(const Field_element& val, const Entry_range& column); + template + bool _multiply_source_and_add(const Entry_range& column, const Field_element& val); }; template @@ -256,7 +256,7 @@ inline Heap_column::Heap_column(Column_settings* colSettings) Chain_opt(), insertsSinceLastPrune_(0), operators_(nullptr), - cellPool_(colSettings == nullptr ? nullptr : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor)) { if (colSettings == nullptr) return; // to allow default constructor which gives a dummy column @@ -273,7 +273,7 @@ inline Heap_column::Heap_column(const Container& nonZeroRowIndice column_(nonZeroRowIndices.size(), nullptr), insertsSinceLastPrune_(0), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); @@ -285,15 +285,15 @@ inline Heap_column::Heap_column(const Container& nonZeroRowIndice Index i = 0; if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - column_[i++] = cellPool_->construct(id); + column_[i++] = entryPool_->construct(id); } } else { for (const auto& p : nonZeroRowIndices) { - column_[i] = cellPool_->construct(p.first); + column_[i] = entryPool_->construct(p.first); column_[i++]->set_element(operators_->get_value(p.second)); } } - std::make_heap(column_.begin(), column_.end(), cellPointerComp_); + std::make_heap(column_.begin(), column_.end(), entryPointerComp_); } template @@ -312,21 +312,21 @@ inline Heap_column::Heap_column(const Container& nonZeroRowIndice column_(nonZeroRowIndices.size(), nullptr), insertsSinceLastPrune_(0), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { Index i = 0; if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - column_[i++] = cellPool_->construct(id); + column_[i++] = entryPool_->construct(id); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - column_[i] = cellPool_->construct(p.first); + column_[i] = entryPool_->construct(p.first); column_[i++]->set_element(operators_->get_value(p.second)); } } - std::make_heap(column_.begin(), column_.end(), cellPointerComp_); + std::make_heap(column_.begin(), column_.end(), entryPointerComp_); } template @@ -336,7 +336,7 @@ inline Heap_column::Heap_column(const Heap_column& column, Column column_(column.column_.size(), nullptr), insertsSinceLastPrune_(0), operators_(colSettings == nullptr ? column.operators_ : nullptr), - cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { static_assert(!Master_matrix::Option_list::has_row_access, "Simple copy constructor not available when row access option enabled. Please specify the new column " @@ -347,12 +347,12 @@ inline Heap_column::Heap_column(const Heap_column& column, Column } Index i = 0; - for (const Cell* cell : column.column_) { + for (const Entry* entry : column.column_) { if constexpr (Master_matrix::Option_list::is_z2) { - column_[i++] = cellPool_->construct(cell->get_row_index()); + column_[i++] = entryPool_->construct(entry->get_row_index()); } else { - column_[i] = cellPool_->construct(cell->get_row_index()); - column_[i++]->set_element(cell->get_element()); + column_[i] = entryPool_->construct(entry->get_row_index()); + column_[i++]->set_element(entry->get_element()); } } // column.column_ already ordered as a heap, so no need of make_heap. @@ -365,7 +365,7 @@ inline Heap_column::Heap_column(Heap_column&& column) noexcept column_(std::move(column.column_)), insertsSinceLastPrune_(std::exchange(column.insertsSinceLastPrune_, 0)), operators_(std::exchange(column.operators_, nullptr)), - cellPool_(std::exchange(column.cellPool_, nullptr)) + entryPool_(std::exchange(column.entryPool_, nullptr)) {} template @@ -385,7 +385,7 @@ inline Heap_column::Heap_column(Index columnIndex, column_(nonZeroRowIndices.size(), nullptr), insertsSinceLastPrune_(0), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); @@ -393,16 +393,16 @@ inline Heap_column::Heap_column(Index columnIndex, Index i = 0; if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - column_[i++] = cellPool_->construct(id); + column_[i++] = entryPool_->construct(id); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - column_[i] = cellPool_->construct(p.first); + column_[i] = entryPool_->construct(p.first); column_[i++]->set_element(operators_->get_value(p.second)); } } - std::make_heap(column_.begin(), column_.end(), cellPointerComp_); + std::make_heap(column_.begin(), column_.end(), entryPointerComp_); } template @@ -423,21 +423,21 @@ inline Heap_column::Heap_column(Index columnIndex, column_(nonZeroRowIndices.size(), nullptr), insertsSinceLastPrune_(0), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { Index i = 0; if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - column_[i++] = cellPool_->construct(id); + column_[i++] = entryPool_->construct(id); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - column_[i] = cellPool_->construct(p.first); + column_[i] = entryPool_->construct(p.first); column_[i++]->set_element(operators_->get_value(p.second)); } } - std::make_heap(column_.begin(), column_.end(), cellPointerComp_); + std::make_heap(column_.begin(), column_.end(), entryPointerComp_); } template @@ -451,19 +451,19 @@ inline Heap_column::Heap_column(const Heap_column& column, column_(column.column_.size(), nullptr), insertsSinceLastPrune_(0), operators_(colSettings == nullptr ? column.operators_ : nullptr), - cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { if constexpr (!Master_matrix::Option_list::is_z2) { if (colSettings != nullptr) operators_ = &(colSettings->operators); } Index i = 0; - for (const Cell* cell : column.column_) { + for (const Entry* entry : column.column_) { if constexpr (Master_matrix::Option_list::is_z2) { - column_[i++] = cellPool_->construct(cell->get_row_index()); + column_[i++] = entryPool_->construct(entry->get_row_index()); } else { - column_[i] = cellPool_->construct(cell->get_row_index()); - column_[i++]->set_element(cell->get_element()); + column_[i] = entryPool_->construct(entry->get_row_index()); + column_[i++]->set_element(entry->get_element()); } } // column.column_ already ordered as a heap, so no need of make_heap. @@ -472,8 +472,8 @@ inline Heap_column::Heap_column(const Heap_column& column, template inline Heap_column::~Heap_column() { - for (auto* cell : column_) { - cellPool_->destroy(cell); + for (auto* entry : column_) { + entryPool_->destroy(entry); } } @@ -509,12 +509,12 @@ template inline bool Heap_column::is_non_zero(ID_index rowIndex) const { Field_element c(0); - for (const Cell* cell : column_) { - if (cell->get_row_index() == rowIndex) { + for (const Entry* entry : column_) { + if (entry->get_row_index() == rowIndex) { if constexpr (Master_matrix::Option_list::is_z2) c = !c; else - operators_->add_inplace(c, cell->get_element()); + operators_->add_inplace(c, entry->get_element()); } } return c != Field_operators::get_additive_identity(); @@ -523,10 +523,10 @@ inline bool Heap_column::is_non_zero(ID_index rowIndex) const template inline bool Heap_column::is_empty() { - Cell* pivot = _pop_pivot(); + Entry* pivot = _pop_pivot(); if (pivot != nullptr) { column_.push_back(pivot); - std::push_heap(column_.begin(), column_.end(), cellPointerComp_); + std::push_heap(column_.begin(), column_.end(), entryPointerComp_); return false; } return true; @@ -546,14 +546,14 @@ inline void Heap_column::reorder(const Row_index_map& valueMap, [ "Method not available for chain columns."); Column_support tempCol; - Cell* pivot = _pop_pivot(); + Entry* pivot = _pop_pivot(); while (pivot != nullptr) { pivot->set_row_index(valueMap.at(pivot->get_row_index())); tempCol.push_back(pivot); pivot = _pop_pivot(); } column_.swap(tempCol); - std::make_heap(column_.begin(), column_.end(), cellPointerComp_); + std::make_heap(column_.begin(), column_.end(), entryPointerComp_); insertsSinceLastPrune_ = 0; } @@ -564,8 +564,8 @@ inline void Heap_column::clear() static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Method not available for chain columns as a base element should not be empty."); - for (auto* cell : column_) { - cellPool_->destroy(cell); + for (auto* entry : column_) { + entryPool_->destroy(entry); } column_.clear(); @@ -579,12 +579,12 @@ inline void Heap_column::clear(ID_index rowIndex) "Method not available for chain columns."); Column_support tempCol; - Cell* pivot = _pop_pivot(); + Entry* pivot = _pop_pivot(); while (pivot != nullptr) { if (pivot->get_row_index() != rowIndex) { tempCol.push_back(pivot); } else { - cellPool_->destroy(pivot); + entryPool_->destroy(pivot); } pivot = _pop_pivot(); } @@ -600,10 +600,10 @@ inline typename Heap_column::ID_index Heap_column: "Method not available for base columns."); // could technically be, but is the notion useful then? if constexpr (Master_matrix::Option_list::is_of_boundary_type) { - Cell* pivot = _pop_pivot(); + Entry* pivot = _pop_pivot(); if (pivot != nullptr) { column_.push_back(pivot); - std::push_heap(column_.begin(), column_.end(), cellPointerComp_); + std::push_heap(column_.begin(), column_.end(), entryPointerComp_); return pivot->get_row_index(); } return -1; @@ -622,18 +622,18 @@ inline typename Heap_column::Field_element Heap_columnget_element(); } return 0; } else { Field_element sum(0); if (Chain_opt::get_pivot() == static_cast(-1)) return sum; - for (const Cell* cell : column_) { - if (cell->get_row_index() == Chain_opt::get_pivot()) operators_->add_inplace(sum, cell->get_element()); + for (const Entry* entry : column_) { + if (entry->get_row_index() == Chain_opt::get_pivot()) operators_->add_inplace(sum, entry->get_element()); } return sum; // should not be 0 if properly used. } @@ -689,10 +689,10 @@ inline typename Heap_column::const_reverse_iterator Heap_column -template -inline Heap_column& Heap_column::operator+=(const Cell_range& column) +template +inline Heap_column& Heap_column::operator+=(const Entry_range& column) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -744,8 +744,8 @@ inline Heap_column& Heap_column::operator*=(unsign if (val == Field_operators::get_multiplicative_identity()) return *this; - for (Cell* cell : column_) { - operators_->multiply_inplace(cell->get_element(), val); + for (Entry* entry : column_) { + operators_->multiply_inplace(entry->get_element(), val); } } @@ -753,11 +753,11 @@ inline Heap_column& Heap_column::operator*=(unsign } template -template +template inline Heap_column& Heap_column::multiply_target_and_add(const Field_element& val, - const Cell_range& column) + const Entry_range& column) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -815,11 +815,11 @@ inline Heap_column& Heap_column::multiply_target_a } template -template -inline Heap_column& Heap_column::multiply_source_and_add(const Cell_range& column, +template +inline Heap_column& Heap_column::multiply_source_and_add(const Entry_range& column, const Field_element& val) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -877,25 +877,25 @@ inline Heap_column& Heap_column::operator=(const H Chain_opt::operator=(other); while (column_.size() > other.column_.size()) { - if (column_.back() != nullptr) cellPool_->destroy(column_.back()); + if (column_.back() != nullptr) entryPool_->destroy(column_.back()); column_.pop_back(); } column_.resize(other.column_.size(), nullptr); Index i = 0; - for (const Cell* cell : other.column_) { + for (const Entry* entry : other.column_) { if (column_[i] != nullptr) { - cellPool_->destroy(column_[i]); + entryPool_->destroy(column_[i]); } - column_[i] = other.cellPool_->construct(cell->get_row_index()); + column_[i] = other.entryPool_->construct(entry->get_row_index()); if constexpr (!Master_matrix::Option_list::is_z2) { - column_[i]->set_element(cell->get_element()); + column_[i]->set_element(entry->get_element()); } ++i; } insertsSinceLastPrune_ = other.insertsSinceLastPrune_; operators_ = other.operators_; - cellPool_ = other.cellPool_; + entryPool_ = other.entryPool_; return *this; } @@ -913,7 +913,7 @@ inline void Heap_column::_prune() if (insertsSinceLastPrune_ == 0) return; Column_support tempCol; - Cell* pivot = _pop_pivot(); + Entry* pivot = _pop_pivot(); while (pivot != nullptr) { tempCol.push_back(pivot); pivot = _pop_pivot(); @@ -924,39 +924,39 @@ inline void Heap_column::_prune() } template -inline typename Heap_column::Cell* Heap_column::_pop_pivot() +inline typename Heap_column::Entry* Heap_column::_pop_pivot() { if (column_.empty()) { return nullptr; } - Cell* pivot = column_.front(); - std::pop_heap(column_.begin(), column_.end(), cellPointerComp_); + Entry* pivot = column_.front(); + std::pop_heap(column_.begin(), column_.end(), entryPointerComp_); column_.pop_back(); if constexpr (Master_matrix::Option_list::is_z2) { while (!column_.empty() && column_.front()->get_row_index() == pivot->get_row_index()) { - std::pop_heap(column_.begin(), column_.end(), cellPointerComp_); - cellPool_->destroy(column_.back()); + std::pop_heap(column_.begin(), column_.end(), entryPointerComp_); + entryPool_->destroy(column_.back()); column_.pop_back(); - cellPool_->destroy(pivot); + entryPool_->destroy(pivot); if (column_.empty()) { return nullptr; } pivot = column_.front(); - std::pop_heap(column_.begin(), column_.end(), cellPointerComp_); + std::pop_heap(column_.begin(), column_.end(), entryPointerComp_); column_.pop_back(); } } else { while (!column_.empty() && column_.front()->get_row_index() == pivot->get_row_index()) { operators_->add_inplace(pivot->get_element(), column_.front()->get_element()); - std::pop_heap(column_.begin(), column_.end(), cellPointerComp_); - cellPool_->destroy(column_.back()); + std::pop_heap(column_.begin(), column_.end(), entryPointerComp_); + entryPool_->destroy(column_.back()); column_.pop_back(); } if (pivot->get_element() == Field_operators::get_additive_identity()) { - cellPool_->destroy(pivot); + entryPool_->destroy(pivot); return _pop_pivot(); } } @@ -965,17 +965,17 @@ inline typename Heap_column::Cell* Heap_column::_p } template -template -inline bool Heap_column::_add(const Cell_range& column) +template +inline bool Heap_column::_add(const Entry_range& column) { if (column.begin() == column.end()) return false; if (column_.empty()) { // chain should never enter here. column_.resize(column.size()); Index i = 0; - for (const Cell& cell : column) { - column_[i] = cellPool_->construct(cell.get_row_index()); + for (const Entry& entry : column) { + column_[i] = entryPool_->construct(entry.get_row_index()); if constexpr (!Master_matrix::Option_list::is_z2) { - column_[i]->set_element(cell.get_element()); + column_[i]->set_element(entry.get_element()); } ++i; } @@ -988,21 +988,21 @@ inline bool Heap_column::_add(const Cell_range& column) if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) pivotVal = get_pivot_value(); - for (const Cell& cell : column) { + for (const Entry& entry : column) { ++insertsSinceLastPrune_; if constexpr (Master_matrix::Option_list::is_z2) { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - if (cell.get_row_index() == Chain_opt::get_pivot()) pivotVal = !pivotVal; + if (entry.get_row_index() == Chain_opt::get_pivot()) pivotVal = !pivotVal; } - column_.push_back(cellPool_->construct(cell.get_row_index())); + column_.push_back(entryPool_->construct(entry.get_row_index())); } else { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - if (cell.get_row_index() == Chain_opt::get_pivot()) operators_->add_inplace(pivotVal, cell.get_element()); + if (entry.get_row_index() == Chain_opt::get_pivot()) operators_->add_inplace(pivotVal, entry.get_element()); } - column_.push_back(cellPool_->construct(cell.get_row_index())); - column_.back()->set_element(cell.get_element()); + column_.push_back(entryPool_->construct(entry.get_row_index())); + column_.back()->set_element(entry.get_element()); } - std::push_heap(column_.begin(), column_.end(), cellPointerComp_); + std::push_heap(column_.begin(), column_.end(), entryPointerComp_); } if (2 * insertsSinceLastPrune_ > column_.size()) _prune(); @@ -1014,8 +1014,8 @@ inline bool Heap_column::_add(const Cell_range& column) } template -template -inline bool Heap_column::_multiply_target_and_add(const Field_element& val, const Cell_range& column) +template +inline bool Heap_column::_multiply_target_and_add(const Field_element& val, const Entry_range& column) { if (val == 0u) { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { @@ -1028,9 +1028,9 @@ inline bool Heap_column::_multiply_target_and_add(const Field_ele if (column_.empty()) { // chain should never enter here. column_.resize(column.size()); Index i = 0; - for (const Cell& cell : column) { - column_[i] = cellPool_->construct(cell.get_row_index()); - column_[i++]->set_element(cell.get_element()); + for (const Entry& entry : column) { + column_[i] = entryPool_->construct(entry.get_row_index()); + column_[i++]->set_element(entry.get_element()); } insertsSinceLastPrune_ = column_.size(); return true; @@ -1038,21 +1038,21 @@ inline bool Heap_column::_multiply_target_and_add(const Field_ele Field_element pivotVal(0); - for (Cell* cell : column_) { - operators_->multiply_inplace(cell->get_element(), val); + for (Entry* entry : column_) { + operators_->multiply_inplace(entry->get_element(), val); if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - if (cell->get_row_index() == Chain_opt::get_pivot()) operators_->add_inplace(pivotVal, cell->get_element()); + if (entry->get_row_index() == Chain_opt::get_pivot()) operators_->add_inplace(pivotVal, entry->get_element()); } } - for (const Cell& cell : column) { + for (const Entry& entry : column) { ++insertsSinceLastPrune_; if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - if (cell.get_row_index() == Chain_opt::get_pivot()) operators_->add_inplace(pivotVal, cell.get_element()); + if (entry.get_row_index() == Chain_opt::get_pivot()) operators_->add_inplace(pivotVal, entry.get_element()); } - column_.push_back(cellPool_->construct(cell.get_row_index())); - column_.back()->set_element(cell.get_element()); - std::push_heap(column_.begin(), column_.end(), cellPointerComp_); + column_.push_back(entryPool_->construct(entry.get_row_index())); + column_.back()->set_element(entry.get_element()); + std::push_heap(column_.begin(), column_.end(), entryPointerComp_); } if (2 * insertsSinceLastPrune_ > column_.size()) _prune(); @@ -1064,8 +1064,8 @@ inline bool Heap_column::_multiply_target_and_add(const Field_ele } template -template -inline bool Heap_column::_multiply_source_and_add(const Cell_range& column, const Field_element& val) +template +inline bool Heap_column::_multiply_source_and_add(const Entry_range& column, const Field_element& val) { if (val == 0u || column.begin() == column.end()) { return false; @@ -1073,9 +1073,9 @@ inline bool Heap_column::_multiply_source_and_add(const Cell_rang if (column_.empty()) { // chain should never enter here. column_.resize(column.size()); Index i = 0; - for (const Cell& cell : column) { - column_[i] = cellPool_->construct(cell.get_row_index()); - column_[i++]->set_element(cell.get_element()); + for (const Entry& entry : column) { + column_[i] = entryPool_->construct(entry.get_row_index()); + column_[i++]->set_element(entry.get_element()); } insertsSinceLastPrune_ = column_.size(); return true; @@ -1086,17 +1086,17 @@ inline bool Heap_column::_multiply_source_and_add(const Cell_rang if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) pivotVal = get_pivot_value(); - for (const Cell& cell : column) { + for (const Entry& entry : column) { ++insertsSinceLastPrune_; - column_.push_back(cellPool_->construct(cell.get_row_index())); - column_.back()->set_element(cell.get_element()); + column_.push_back(entryPool_->construct(entry.get_row_index())); + column_.back()->set_element(entry.get_element()); operators_->multiply_inplace(column_.back()->get_element(), val); if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - if (cell.get_row_index() == Chain_opt::get_pivot()) { + if (entry.get_row_index() == Chain_opt::get_pivot()) { operators_->add_inplace(pivotVal, column_.back()->get_element()); } } - std::push_heap(column_.begin(), column_.end(), cellPointerComp_); + std::push_heap(column_.begin(), column_.end(), entryPointerComp_); } if (2 * insertsSinceLastPrune_ > column_.size()) _prune(); @@ -1113,7 +1113,7 @@ inline bool Heap_column::_multiply_source_and_add(const Cell_rang * @brief Hash method for @ref Gudhi::persistence_matrix::Heap_column. * * @tparam Master_matrix Template parameter of @ref Gudhi::persistence_matrix::Heap_column. - * @tparam Cell_constructor Template parameter of @ref Gudhi::persistence_matrix::Heap_column. + * @tparam Entry_constructor Template parameter of @ref Gudhi::persistence_matrix::Heap_column. */ template struct std::hash > { diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_list_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_list_column.h index 01c6791de6..d041852a83 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_list_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_list_column.h @@ -25,7 +25,7 @@ #include -#include +#include #include namespace Gudhi { @@ -37,11 +37,11 @@ namespace persistence_matrix { * * @brief Column class following the @ref PersistenceMatrixColumn concept. * - * Column based on a intrusive list structure. The cells are always ordered by row index and only non-zero values + * Column based on a intrusive list structure. The entries are always ordered by row index and only non-zero values * are stored uniquely in the underlying container. * * @tparam Master_matrix An instantiation of @ref Matrix from which all types and options are deduced. - * @tparam Cell_constructor Factory of @ref Cell classes. + * @tparam Entry_constructor Factory of @ref Entry classes. */ template class Intrusive_list_column : public Master_matrix::Row_access_option, @@ -54,15 +54,15 @@ class Intrusive_list_column : public Master_matrix::Row_access_option, using ID_index = typename Master_matrix::ID_index; using Dimension = typename Master_matrix::Dimension; using Field_element = typename Master_matrix::Element; - using Cell = typename Master_matrix::Matrix_cell; + using Entry = typename Master_matrix::Matrix_entry; using Column_settings = typename Master_matrix::Column_settings; private: using Field_operators = typename Master_matrix::Field_operators; using Column_support = - boost::intrusive::list, + boost::intrusive::list, boost::intrusive::base_hook >; - using Cell_constructor = typename Master_matrix::Cell_constructor; + using Entry_constructor = typename Master_matrix::Entry_constructor; public: using iterator = typename Column_support::iterator; @@ -117,19 +117,19 @@ class Intrusive_list_column : public Master_matrix::Row_access_option, reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; - template - Intrusive_list_column& operator+=(const Cell_range& column); + template + Intrusive_list_column& operator+=(const Entry_range& column); Intrusive_list_column& operator+=(Intrusive_list_column& column); Intrusive_list_column& operator*=(const Field_element& val); // this = v * this + column - template - Intrusive_list_column& multiply_target_and_add(const Field_element& val, const Cell_range& column); + template + Intrusive_list_column& multiply_target_and_add(const Field_element& val, const Entry_range& column); Intrusive_list_column& multiply_target_and_add(const Field_element& val, Intrusive_list_column& column); // this = this + column * v - template - Intrusive_list_column& multiply_source_and_add(const Cell_range& column, const Field_element& val); + template + Intrusive_list_column& multiply_source_and_add(const Entry_range& column, const Field_element& val); Intrusive_list_column& multiply_source_and_add(Intrusive_list_column& column, const Field_element& val); friend bool operator==(const Intrusive_list_column& c1, const Intrusive_list_column& c2) { @@ -179,7 +179,7 @@ class Intrusive_list_column : public Master_matrix::Row_access_option, static_cast(col2)); col1.column_.swap(col2.column_); std::swap(col1.operators_, col2.operators_); - std::swap(col1.cellPool_, col2.cellPool_); + std::swap(col1.entryPool_, col2.entryPool_); } private: @@ -189,11 +189,11 @@ class Intrusive_list_column : public Master_matrix::Row_access_option, // Cloner object function for boost intrusive container struct New_cloner { - New_cloner(Cell_constructor* cellPool) : cellPool_(cellPool) {}; + New_cloner(Entry_constructor* entryPool) : entryPool_(entryPool) {}; - Cell* operator()(const Cell& clone_this) { return cellPool_->construct(clone_this); } + Entry* operator()(const Entry& clone_this) { return entryPool_->construct(clone_this); } - Cell_constructor* cellPool_; + Entry_constructor* entryPool_; }; // The disposer object function for boost intrusive container @@ -201,55 +201,55 @@ class Intrusive_list_column : public Master_matrix::Row_access_option, Delete_disposer() {}; Delete_disposer(Intrusive_list_column* col) : col_(col) {}; - void operator()(Cell* delete_this) { + void operator()(Entry* delete_this) { if constexpr (Master_matrix::Option_list::has_row_access) col_->unlink(delete_this); - col_->cellPool_->destroy(delete_this); + col_->entryPool_->destroy(delete_this); } Intrusive_list_column* col_; }; Field_operators* operators_; - Cell_constructor* cellPool_; + Entry_constructor* entryPool_; Column_support column_; - template - friend void _generic_merge_cell_to_column(Column& targetColumn, - Cell_iterator& itSource, + template + friend void _generic_merge_entry_to_column(Column& targetColumn, + Entry_iterator& itSource, typename Column::Column_support::iterator& itTarget, F1&& process_target, F2&& process_source, F3&& update_target1, F4&& update_target2, bool& pivotIsZeroed); - template - friend bool _generic_add_to_column(const Cell_range& source, + template + friend bool _generic_add_to_column(const Entry_range& source, Column& targetColumn, F1&& process_target, F2&& process_source, F3&& update_target1, F4&& update_target2, F5&& finish_target); - template - friend bool _add_to_column(const Cell_range& source, Column& targetColumn); - template + template + friend bool _add_to_column(const Entry_range& source, Column& targetColumn); + template friend bool _multiply_target_and_add_to_column(const typename Column::Field_element& val, - const Cell_range& source, + const Entry_range& source, Column& targetColumn); - template + template friend bool _multiply_source_and_add_to_column(const typename Column::Field_element& val, - const Cell_range& source, + const Entry_range& source, Column& targetColumn); - void _delete_cell(iterator& it); - Cell* _insert_cell(const Field_element& value, ID_index rowIndex, const iterator& position); - void _insert_cell(ID_index rowIndex, const iterator& position); - template - bool _add(const Cell_range& column); - template - bool _multiply_target_and_add(const Field_element& val, const Cell_range& column); - template - bool _multiply_source_and_add(const Cell_range& column, const Field_element& val); + void _delete_entry(iterator& it); + Entry* _insert_entry(const Field_element& value, ID_index rowIndex, const iterator& position); + void _insert_entry(ID_index rowIndex, const iterator& position); + template + bool _add(const Entry_range& column); + template + bool _multiply_target_and_add(const Field_element& val, const Entry_range& column); + template + bool _multiply_source_and_add(const Entry_range& column, const Field_element& val); }; template @@ -258,7 +258,7 @@ inline Intrusive_list_column::Intrusive_list_column(Column_settin Dim_opt(), Chain_opt(), operators_(nullptr), - cellPool_(colSettings == nullptr ? nullptr : &(colSettings->cellConstructor)), + entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor)), column_() { if (colSettings == nullptr) return; // to allow default constructor which gives a dummy column @@ -275,7 +275,7 @@ inline Intrusive_list_column::Intrusive_list_column(const Contain Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), Chain_opt(), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)), + entryPool_(&(colSettings->entryConstructor)), column_() { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, @@ -283,12 +283,12 @@ inline Intrusive_list_column::Intrusive_list_column(const Contain if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _insert_cell(id, column_.end()); + _insert_entry(id, column_.end()); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _insert_cell(operators_->get_value(p.second), p.first, column_.end()); + _insert_entry(operators_->get_value(p.second), p.first, column_.end()); } } } @@ -309,7 +309,7 @@ inline Intrusive_list_column::Intrusive_list_column(Index columnI } }()), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)), + entryPool_(&(colSettings->entryConstructor)), column_() { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, @@ -317,12 +317,12 @@ inline Intrusive_list_column::Intrusive_list_column(Index columnI if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _insert_cell(id, column_.end()); + _insert_entry(id, column_.end()); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _insert_cell(operators_->get_value(p.second), p.first, column_.end()); + _insert_entry(operators_->get_value(p.second), p.first, column_.end()); } } } @@ -342,17 +342,17 @@ inline Intrusive_list_column::Intrusive_list_column(const Contain } }()), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)), + entryPool_(&(colSettings->entryConstructor)), column_() { if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _insert_cell(id, column_.end()); + _insert_entry(id, column_.end()); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _insert_cell(operators_->get_value(p.second), p.first, column_.end()); + _insert_entry(operators_->get_value(p.second), p.first, column_.end()); } } } @@ -374,17 +374,17 @@ inline Intrusive_list_column::Intrusive_list_column(Index columnI } }()), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)), + entryPool_(&(colSettings->entryConstructor)), column_() { if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _insert_cell(id, column_.end()); + _insert_entry(id, column_.end()); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _insert_cell(operators_->get_value(p.second), p.first, column_.end()); + _insert_entry(operators_->get_value(p.second), p.first, column_.end()); } } } @@ -396,7 +396,7 @@ inline Intrusive_list_column::Intrusive_list_column(const Intrusi Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), operators_(colSettings == nullptr ? column.operators_ : nullptr), - cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor)), + entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)), column_() { static_assert(!Master_matrix::Option_list::has_row_access, @@ -406,7 +406,7 @@ inline Intrusive_list_column::Intrusive_list_column(const Intrusi if (colSettings != nullptr) operators_ = &(colSettings->operators); } - column_.clone_from(column.column_, New_cloner(cellPool_), Delete_disposer(this)); + column_.clone_from(column.column_, New_cloner(entryPool_), Delete_disposer(this)); } template @@ -419,18 +419,18 @@ inline Intrusive_list_column::Intrusive_list_column(const Intrusi Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), operators_(colSettings == nullptr ? column.operators_ : nullptr), - cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor)), + entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)), column_() { if constexpr (!Master_matrix::Option_list::is_z2) { if (colSettings != nullptr) operators_ = &(colSettings->operators); } - for (const Cell& cell : column.column_) { + for (const Entry& entry : column.column_) { if constexpr (Master_matrix::Option_list::is_z2) { - _insert_cell(cell.get_row_index(), column_.end()); + _insert_entry(entry.get_row_index(), column_.end()); } else { - _insert_cell(cell.get_element(), cell.get_row_index(), column_.end()); + _insert_entry(entry.get_element(), entry.get_row_index(), column_.end()); } } } @@ -441,7 +441,7 @@ inline Intrusive_list_column::Intrusive_list_column(Intrusive_lis Dim_opt(std::move(static_cast(column))), Chain_opt(std::move(static_cast(column))), operators_(std::exchange(column.operators_, nullptr)), - cellPool_(std::exchange(column.cellPool_, nullptr)), + entryPool_(std::exchange(column.entryPool_, nullptr)), column_(std::move(column.column_)) {} @@ -478,8 +478,8 @@ inline bool Intrusive_list_column::is_non_zero(ID_index rowIndex) // could be changed to dichotomic search as column is ordered by row index, // but I am not sure if it is really worth it as there is no random access // and the columns should not be that long anyway. - for (const Cell& cell : column_) - if (cell.get_row_index() == rowIndex) return true; + for (const Entry& entry : column_) + if (entry.get_row_index() == rowIndex) return true; return false; } @@ -505,21 +505,21 @@ inline void Intrusive_list_column::reorder(const Row_index_map& v "Method not available for chain columns."); for (auto it = column_.begin(); it != column_.end(); ++it) { - Cell* cell = &(*it); + Entry* entry = &(*it); if constexpr (Master_matrix::Option_list::has_row_access) { - RA_opt::unlink(cell); - if (columnIndex != static_cast(-1)) cell->set_column_index(columnIndex); + RA_opt::unlink(entry); + if (columnIndex != static_cast(-1)) entry->set_column_index(columnIndex); } - cell->set_row_index(valueMap.at(cell->get_row_index())); + entry->set_row_index(valueMap.at(entry->get_row_index())); if constexpr (Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access) - RA_opt::insert_cell(cell->get_row_index(), cell); + RA_opt::insert_entry(entry->get_row_index(), entry); } - // all cells have to be deleted first, to avoid problem with insertion when row is a set + // all entries have to be deleted first, to avoid problem with insertion when row is a set if constexpr (!Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access) { for (auto it = column_.begin(); it != column_.end(); ++it) { - Cell* cell = &(*it); - RA_opt::insert_cell(cell->get_row_index(), cell); + Entry* entry = &(*it); + RA_opt::insert_entry(entry->get_row_index(), entry); } } @@ -543,7 +543,7 @@ inline void Intrusive_list_column::clear(ID_index rowIndex) auto it = column_.begin(); while (it != column_.end() && it->get_row_index() != rowIndex) it++; - if (it != column_.end()) _delete_cell(it); + if (it != column_.end()) _delete_entry(it); } template @@ -575,8 +575,8 @@ Intrusive_list_column::get_pivot_value() const return column_.back().get_element(); } else { if (Chain_opt::get_pivot() == static_cast(-1)) return Field_element(); - for (const Cell& cell : column_) { - if (cell.get_row_index() == Chain_opt::get_pivot()) return cell.get_element(); + for (const Entry& entry : column_) { + if (entry.get_row_index() == Chain_opt::get_pivot()) return entry.get_element(); } return Field_element(); // should never happen if chain column is used properly } @@ -638,11 +638,11 @@ Intrusive_list_column::rend() const noexcept } template -template +template inline Intrusive_list_column& Intrusive_list_column::operator+=( - const Cell_range& column) + const Entry_range& column) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -696,9 +696,9 @@ inline Intrusive_list_column& Intrusive_list_columnmultiply_inplace(cell.get_element(), realVal); - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_cell(cell); + for (Entry& entry : column_) { + operators_->multiply_inplace(entry.get_element(), realVal); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(entry); } } @@ -706,11 +706,11 @@ inline Intrusive_list_column& Intrusive_list_column -template +template inline Intrusive_list_column& Intrusive_list_column::multiply_target_and_add( - const Field_element& val, const Cell_range& column) + const Field_element& val, const Entry_range& column) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -768,11 +768,11 @@ inline Intrusive_list_column& Intrusive_list_column -template +template inline Intrusive_list_column& Intrusive_list_column::multiply_source_and_add( - const Cell_range& column, const Field_element& val) + const Entry_range& column, const Field_element& val) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -833,67 +833,67 @@ inline Intrusive_list_column& Intrusive_list_column -inline void Intrusive_list_column::_delete_cell(iterator& it) +inline void Intrusive_list_column::_delete_entry(iterator& it) { it = column_.erase_and_dispose(it, Delete_disposer(this)); } template -inline typename Intrusive_list_column::Cell* Intrusive_list_column::_insert_cell( +inline typename Intrusive_list_column::Entry* Intrusive_list_column::_insert_entry( const Field_element& value, ID_index rowIndex, const iterator& position) { if constexpr (Master_matrix::Option_list::has_row_access) { - Cell* newCell = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - newCell->set_element(value); - column_.insert(position, *newCell); - RA_opt::insert_cell(rowIndex, newCell); - return newCell; + Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + newEntry->set_element(value); + column_.insert(position, *newEntry); + RA_opt::insert_entry(rowIndex, newEntry); + return newEntry; } else { - Cell* newCell = cellPool_->construct(rowIndex); - newCell->set_element(value); - column_.insert(position, *newCell); - return newCell; + Entry* newEntry = entryPool_->construct(rowIndex); + newEntry->set_element(value); + column_.insert(position, *newEntry); + return newEntry; } } template -inline void Intrusive_list_column::_insert_cell(ID_index rowIndex, const iterator& position) +inline void Intrusive_list_column::_insert_entry(ID_index rowIndex, const iterator& position) { if constexpr (Master_matrix::Option_list::has_row_access) { - Cell* newCell = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - column_.insert(position, *newCell); - RA_opt::insert_cell(rowIndex, newCell); + Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + column_.insert(position, *newEntry); + RA_opt::insert_entry(rowIndex, newEntry); } else { - Cell* newCell = cellPool_->construct(rowIndex); - column_.insert(position, *newCell); + Entry* newEntry = entryPool_->construct(rowIndex); + column_.insert(position, *newEntry); } } template -template -inline bool Intrusive_list_column::_add(const Cell_range& column) +template +inline bool Intrusive_list_column::_add(const Entry_range& column) { return _add_to_column(column, *this); } template -template +template inline bool Intrusive_list_column::_multiply_target_and_add(const Field_element& val, - const Cell_range& column) + const Entry_range& column) { return _multiply_target_and_add_to_column(val, column, *this); } template -template -inline bool Intrusive_list_column::_multiply_source_and_add(const Cell_range& column, +template +inline bool Intrusive_list_column::_multiply_source_and_add(const Entry_range& column, const Field_element& val) { return _multiply_source_and_add_to_column(val, column, *this); @@ -908,7 +908,7 @@ inline bool Intrusive_list_column::_multiply_source_and_add(const * @brief Hash method for @ref Gudhi::persistence_matrix::Intrusive_list_column. * * @tparam Master_matrix Template parameter of @ref Gudhi::persistence_matrix::Intrusive_list_column. - * @tparam Cell_constructor Template parameter of @ref Gudhi::persistence_matrix::Intrusive_list_column. + * @tparam Entry_constructor Template parameter of @ref Gudhi::persistence_matrix::Intrusive_list_column. */ template struct std::hash > { diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_set_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_set_column.h index 983e4259ad..3d1d00d613 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_set_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_set_column.h @@ -26,7 +26,7 @@ #include #include -#include +#include #include namespace Gudhi { @@ -38,11 +38,11 @@ namespace persistence_matrix { * * @brief Column class following the @ref PersistenceMatrixColumn concept. * - * Column based on a intrusive set structure. The cells are ordered by row index and only non-zero values + * Column based on a intrusive set structure. The entries are ordered by row index and only non-zero values * are stored uniquely in the underlying container. * * @tparam Master_matrix An instantiation of @ref Matrix from which all types and options are deduced. - * @tparam Cell_constructor Factory of @ref Cell classes. + * @tparam Entry_constructor Factory of @ref Entry classes. */ template class Intrusive_set_column : public Master_matrix::Row_access_option, @@ -55,15 +55,15 @@ class Intrusive_set_column : public Master_matrix::Row_access_option, using ID_index = typename Master_matrix::ID_index; using Dimension = typename Master_matrix::Dimension; using Field_element = typename Master_matrix::Element; - using Cell = typename Master_matrix::Matrix_cell; + using Entry = typename Master_matrix::Matrix_entry; using Column_settings = typename Master_matrix::Column_settings; private: using Field_operators = typename Master_matrix::Field_operators; using Column_support = - boost::intrusive::set, + boost::intrusive::set, boost::intrusive::base_hook >; - using Cell_constructor = typename Master_matrix::Cell_constructor; + using Entry_constructor = typename Master_matrix::Entry_constructor; public: using iterator = typename Column_support::iterator; @@ -118,19 +118,19 @@ class Intrusive_set_column : public Master_matrix::Row_access_option, reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; - template - Intrusive_set_column& operator+=(const Cell_range& column); + template + Intrusive_set_column& operator+=(const Entry_range& column); Intrusive_set_column& operator+=(Intrusive_set_column& column); Intrusive_set_column& operator*=(unsigned int v); // this = v * this + column - template - Intrusive_set_column& multiply_target_and_add(const Field_element& val, const Cell_range& column); + template + Intrusive_set_column& multiply_target_and_add(const Field_element& val, const Entry_range& column); Intrusive_set_column& multiply_target_and_add(const Field_element& val, Intrusive_set_column& column); // this = this + column * v - template - Intrusive_set_column& multiply_source_and_add(const Cell_range& column, const Field_element& val); + template + Intrusive_set_column& multiply_source_and_add(const Entry_range& column, const Field_element& val); Intrusive_set_column& multiply_source_and_add(Intrusive_set_column& column, const Field_element& val); friend bool operator==(const Intrusive_set_column& c1, const Intrusive_set_column& c2) { @@ -180,7 +180,7 @@ class Intrusive_set_column : public Master_matrix::Row_access_option, static_cast(col2)); col1.column_.swap(col2.column_); std::swap(col1.operators_, col2.operators_); - std::swap(col1.cellPool_, col2.cellPool_); + std::swap(col1.entryPool_, col2.entryPool_); } private: @@ -190,11 +190,11 @@ class Intrusive_set_column : public Master_matrix::Row_access_option, // Cloner object function for boost intrusive container struct New_cloner { - New_cloner(Cell_constructor* cellPool) : cellPool_(cellPool) {}; + New_cloner(Entry_constructor* entryPool) : entryPool_(entryPool) {}; - Cell* operator()(const Cell& clone_this) { return cellPool_->construct(clone_this); } + Entry* operator()(const Entry& clone_this) { return entryPool_->construct(clone_this); } - Cell_constructor* cellPool_; + Entry_constructor* entryPool_; }; // The disposer object function for boost intrusive container @@ -202,9 +202,9 @@ class Intrusive_set_column : public Master_matrix::Row_access_option, Delete_disposer() {}; Delete_disposer(Intrusive_set_column* col) : col_(col) {}; - void operator()(Cell* delete_this) { + void operator()(Entry* delete_this) { if constexpr (Master_matrix::Option_list::has_row_access) col_->unlink(delete_this); - col_->cellPool_->destroy(delete_this); + col_->entryPool_->destroy(delete_this); } Intrusive_set_column* col_; @@ -212,45 +212,45 @@ class Intrusive_set_column : public Master_matrix::Row_access_option, Column_support column_; Field_operators* operators_; - Cell_constructor* cellPool_; - - template - friend void _generic_merge_cell_to_column(Column& targetColumn, - Cell_iterator& itSource, - typename Column::Column_support::iterator& itTarget, - F1&& process_target, - F2&& process_source, - F3&& update_target1, - F4&& update_target2, - bool& pivotIsZeroed); - template - friend bool _generic_add_to_column(const Cell_range& source, + Entry_constructor* entryPool_; + + template + friend void _generic_merge_entry_to_column(Column& targetColumn, + Entry_iterator& itSource, + typename Column::Column_support::iterator& itTarget, + F1&& process_target, + F2&& process_source, + F3&& update_target1, + F4&& update_target2, + bool& pivotIsZeroed); + template + friend bool _generic_add_to_column(const Entry_range& source, Column& targetColumn, F1&& process_target, F2&& process_source, F3&& update_target1, F4&& update_target2, F5&& finish_target); - template - friend bool _add_to_column(const Cell_range& source, Column& targetColumn); - template + template + friend bool _add_to_column(const Entry_range& source, Column& targetColumn); + template friend bool _multiply_target_and_add_to_column(const typename Column::Field_element& val, - const Cell_range& source, + const Entry_range& source, Column& targetColumn); - template + template friend bool _multiply_source_and_add_to_column(const typename Column::Field_element& val, - const Cell_range& source, + const Entry_range& source, Column& targetColumn); - void _delete_cell(iterator& it); - Cell* _insert_cell(const Field_element& value, ID_index rowIndex, const iterator& position); - void _insert_cell(ID_index rowIndex, const iterator& position); - template - bool _add(const Cell_range& column); - template - bool _multiply_target_and_add(const Field_element& val, const Cell_range& column); - template - bool _multiply_source_and_add(const Cell_range& column, const Field_element& val); + void _delete_entry(iterator& it); + Entry* _insert_entry(const Field_element& value, ID_index rowIndex, const iterator& position); + void _insert_entry(ID_index rowIndex, const iterator& position); + template + bool _add(const Entry_range& column); + template + bool _multiply_target_and_add(const Field_element& val, const Entry_range& column); + template + bool _multiply_source_and_add(const Entry_range& column, const Field_element& val); }; template @@ -259,9 +259,9 @@ inline Intrusive_set_column::Intrusive_set_column(Column_settings Dim_opt(), Chain_opt(), operators_(nullptr), - cellPool_(colSettings == nullptr ? nullptr : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor)) { - if (operators_ == nullptr && cellPool_ == nullptr) return; // to allow default constructor which gives a dummy column + if (operators_ == nullptr && entryPool_ == nullptr) return; // to allow default constructor which gives a dummy column if constexpr (!Master_matrix::Option_list::is_z2) { operators_ = &(colSettings->operators); } @@ -275,19 +275,19 @@ inline Intrusive_set_column::Intrusive_set_column(const Container Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), Chain_opt(), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _insert_cell(id, column_.end()); + _insert_entry(id, column_.end()); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _insert_cell(operators_->get_value(p.second), p.first, column_.end()); + _insert_entry(operators_->get_value(p.second), p.first, column_.end()); } } } @@ -308,19 +308,19 @@ inline Intrusive_set_column::Intrusive_set_column(Index columnInd } }()), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _insert_cell(id, column_.end()); + _insert_entry(id, column_.end()); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _insert_cell(operators_->get_value(p.second), p.first, column_.end()); + _insert_entry(operators_->get_value(p.second), p.first, column_.end()); } } } @@ -340,16 +340,16 @@ inline Intrusive_set_column::Intrusive_set_column(const Container } }()), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _insert_cell(id, column_.end()); + _insert_entry(id, column_.end()); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _insert_cell(operators_->get_value(p.second), p.first, column_.end()); + _insert_entry(operators_->get_value(p.second), p.first, column_.end()); } } } @@ -371,16 +371,16 @@ inline Intrusive_set_column::Intrusive_set_column(Index columnInd } }()), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _insert_cell(id, column_.end()); + _insert_entry(id, column_.end()); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _insert_cell(operators_->get_value(p.second), p.first, column_.end()); + _insert_entry(operators_->get_value(p.second), p.first, column_.end()); } } } @@ -392,7 +392,7 @@ inline Intrusive_set_column::Intrusive_set_column(const Intrusive Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), operators_(colSettings == nullptr ? column.operators_ : nullptr), - cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { static_assert(!Master_matrix::Option_list::has_row_access, "Simple copy constructor not available when row access option enabled. Please specify the new column " @@ -402,7 +402,7 @@ inline Intrusive_set_column::Intrusive_set_column(const Intrusive if (colSettings != nullptr) operators_ = &(colSettings->operators); } - column_.clone_from(column.column_, New_cloner(cellPool_), Delete_disposer(this)); + column_.clone_from(column.column_, New_cloner(entryPool_), Delete_disposer(this)); } template @@ -415,17 +415,17 @@ inline Intrusive_set_column::Intrusive_set_column(const Intrusive Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), operators_(colSettings == nullptr ? column.operators_ : nullptr), - cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { if constexpr (!Master_matrix::Option_list::is_z2) { if (colSettings != nullptr) operators_ = &(colSettings->operators); } - for (const Cell& cell : column.column_) { + for (const Entry& entry : column.column_) { if constexpr (Master_matrix::Option_list::is_z2) { - _insert_cell(cell.get_row_index(), column_.end()); + _insert_entry(entry.get_row_index(), column_.end()); } else { - _insert_cell(cell.get_element(), cell.get_row_index(), column_.end()); + _insert_entry(entry.get_element(), entry.get_row_index(), column_.end()); } } } @@ -437,7 +437,7 @@ inline Intrusive_set_column::Intrusive_set_column(Intrusive_set_c Chain_opt(std::move(static_cast(column))), column_(std::move(column.column_)), operators_(std::exchange(column.operators_, nullptr)), - cellPool_(std::exchange(column.cellPool_, nullptr)) + entryPool_(std::exchange(column.entryPool_, nullptr)) {} template @@ -470,7 +470,7 @@ Intrusive_set_column::get_content(int columnLength) const template inline bool Intrusive_set_column::is_non_zero(ID_index rowIndex) const { - return column_.find(Cell(rowIndex)) != column_.end(); + return column_.find(Entry(rowIndex)) != column_.end(); } template @@ -496,31 +496,31 @@ inline void Intrusive_set_column::reorder(const Row_index_map& va if constexpr (Master_matrix::Option_list::has_row_access) { for (auto it = column_.begin(); it != column_.end();) { - Cell* newCell = cellPool_->construct(columnIndex == static_cast(-1) ? RA_opt::columnIndex_ : columnIndex, - valueMap.at(it->get_row_index())); + Entry* newEntry = entryPool_->construct( + columnIndex == static_cast(-1) ? RA_opt::columnIndex_ : columnIndex, valueMap.at(it->get_row_index())); if constexpr (!Master_matrix::Option_list::is_z2) { - newCell->set_element(it->get_element()); + newEntry->set_element(it->get_element()); } - newSet.insert(newSet.end(), *newCell); - _delete_cell(it); // increases it + newSet.insert(newSet.end(), *newEntry); + _delete_entry(it); // increases it if constexpr (Master_matrix::Option_list::has_intrusive_rows) // intrusive list - RA_opt::insert_cell(newCell->get_row_index(), newCell); + RA_opt::insert_entry(newEntry->get_row_index(), newEntry); } - // when row is a set, all cells have to be deleted first, to avoid colliding when inserting + // when row is a set, all entries have to be deleted first, to avoid colliding when inserting if constexpr (!Master_matrix::Option_list::has_intrusive_rows) { // set - for (Cell& cell : newSet) { - RA_opt::insert_cell(cell.get_row_index(), &cell); + for (Entry& entry : newSet) { + RA_opt::insert_entry(entry.get_row_index(), &entry); } } } else { for (auto it = column_.begin(); it != column_.end();) { - Cell* newCell = cellPool_->construct(valueMap.at(it->get_row_index())); + Entry* newEntry = entryPool_->construct(valueMap.at(it->get_row_index())); if constexpr (!Master_matrix::Option_list::is_z2) { - newCell->set_element(it->get_element()); + newEntry->set_element(it->get_element()); } - newSet.insert(newSet.end(), *newCell); - _delete_cell(it); // increases it + newSet.insert(newSet.end(), *newEntry); + _delete_entry(it); // increases it } } @@ -542,9 +542,9 @@ inline void Intrusive_set_column::clear(ID_index rowIndex) static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Method not available for chain columns."); - auto it = column_.find(Cell(rowIndex)); + auto it = column_.find(Entry(rowIndex)); if (it != column_.end()) { - _delete_cell(it); + _delete_entry(it); } } @@ -577,7 +577,7 @@ Intrusive_set_column::get_pivot_value() const return column_.rbegin()->get_element(); } else { if (Chain_opt::get_pivot() == static_cast(-1)) return 0; - auto it = column_.find(Cell(Chain_opt::get_pivot())); + auto it = column_.find(Entry(Chain_opt::get_pivot())); GUDHI_CHECK(it != column_.end(), "Intrusive_set_column::get_pivot_value - Pivot not found only if the column was misused."); return it->get_element(); @@ -640,10 +640,10 @@ inline typename Intrusive_set_column::const_reverse_iterator Intr } template -template -inline Intrusive_set_column& Intrusive_set_column::operator+=(const Cell_range& column) +template +inline Intrusive_set_column& Intrusive_set_column::operator+=(const Entry_range& column) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -696,9 +696,9 @@ inline Intrusive_set_column& Intrusive_set_column: if (val == Field_operators::get_multiplicative_identity()) return *this; - for (Cell& cell : column_) { - operators_->multiply_inplace(cell.get_element(), val); - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_cell(cell); + for (Entry& entry : column_) { + operators_->multiply_inplace(entry.get_element(), val); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(entry); } } @@ -706,11 +706,11 @@ inline Intrusive_set_column& Intrusive_set_column: } template -template +template inline Intrusive_set_column& Intrusive_set_column::multiply_target_and_add( - const Field_element& val, const Cell_range& column) + const Field_element& val, const Entry_range& column) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -768,11 +768,11 @@ inline Intrusive_set_column& Intrusive_set_column: } template -template +template inline Intrusive_set_column& Intrusive_set_column::multiply_source_and_add( - const Cell_range& column, const Field_element& val) + const Entry_range& column, const Field_element& val) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -833,67 +833,67 @@ inline Intrusive_set_column& Intrusive_set_column: // order is important column_.clear_and_dispose(Delete_disposer(this)); operators_ = other.operators_; - cellPool_ = other.cellPool_; - column_.clone_from(other.column_, New_cloner(cellPool_), Delete_disposer(this)); + entryPool_ = other.entryPool_; + column_.clone_from(other.column_, New_cloner(entryPool_), Delete_disposer(this)); return *this; } template -inline void Intrusive_set_column::_delete_cell(iterator& it) +inline void Intrusive_set_column::_delete_entry(iterator& it) { it = column_.erase_and_dispose(it, Delete_disposer(this)); } template -inline typename Intrusive_set_column::Cell* Intrusive_set_column::_insert_cell( +inline typename Intrusive_set_column::Entry* Intrusive_set_column::_insert_entry( const Field_element& value, ID_index rowIndex, const iterator& position) { if constexpr (Master_matrix::Option_list::has_row_access) { - Cell* newCell = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - newCell->set_element(value); - column_.insert(position, *newCell); - RA_opt::insert_cell(rowIndex, newCell); - return newCell; + Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + newEntry->set_element(value); + column_.insert(position, *newEntry); + RA_opt::insert_entry(rowIndex, newEntry); + return newEntry; } else { - Cell* newCell = cellPool_->construct(rowIndex); - newCell->set_element(value); - column_.insert(position, *newCell); - return newCell; + Entry* newEntry = entryPool_->construct(rowIndex); + newEntry->set_element(value); + column_.insert(position, *newEntry); + return newEntry; } } template -inline void Intrusive_set_column::_insert_cell(ID_index rowIndex, const iterator& position) +inline void Intrusive_set_column::_insert_entry(ID_index rowIndex, const iterator& position) { if constexpr (Master_matrix::Option_list::has_row_access) { - Cell* newCell = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - column_.insert(position, *newCell); - RA_opt::insert_cell(rowIndex, newCell); + Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + column_.insert(position, *newEntry); + RA_opt::insert_entry(rowIndex, newEntry); } else { - Cell* newCell = cellPool_->construct(rowIndex); - column_.insert(position, *newCell); + Entry* newEntry = entryPool_->construct(rowIndex); + column_.insert(position, *newEntry); } } template -template -inline bool Intrusive_set_column::_add(const Cell_range& column) +template +inline bool Intrusive_set_column::_add(const Entry_range& column) { return _add_to_column(column, *this); } template -template +template inline bool Intrusive_set_column::_multiply_target_and_add(const Field_element& val, - const Cell_range& column) + const Entry_range& column) { return _multiply_target_and_add_to_column(val, column, *this); } template -template -inline bool Intrusive_set_column::_multiply_source_and_add(const Cell_range& column, +template +inline bool Intrusive_set_column::_multiply_source_and_add(const Entry_range& column, const Field_element& val) { return _multiply_source_and_add_to_column(val, column, *this); @@ -908,7 +908,7 @@ inline bool Intrusive_set_column::_multiply_source_and_add(const * @brief Hash method for @ref Gudhi::persistence_matrix::Intrusive_set_column. * * @tparam Master_matrix Template parameter of @ref Gudhi::persistence_matrix::Intrusive_set_column. - * @tparam Cell_constructor Template parameter of @ref Gudhi::persistence_matrix::Intrusive_set_column. + * @tparam Entry_constructor Template parameter of @ref Gudhi::persistence_matrix::Intrusive_set_column. */ template struct std::hash > { diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/list_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/list_column.h index f795d87a83..f21827a725 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/list_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/list_column.h @@ -26,7 +26,7 @@ #include -#include +#include #include namespace Gudhi { @@ -38,11 +38,11 @@ namespace persistence_matrix { * * @brief Column class following the @ref PersistenceMatrixColumn concept. * - * Column based on a list structure. The cells are always ordered by row index and only non-zero values + * Column based on a list structure. The entries are always ordered by row index and only non-zero values * are stored uniquely in the underlying container. * * @tparam Master_matrix An instantiation of @ref Matrix from which all types and options are deduced. - * @tparam Cell_constructor Factory of @ref Cell classes. + * @tparam Entry_constructor Factory of @ref Entry classes. */ template class List_column : public Master_matrix::Row_access_option, @@ -55,13 +55,13 @@ class List_column : public Master_matrix::Row_access_option, using ID_index = typename Master_matrix::ID_index; using Dimension = typename Master_matrix::Dimension; using Field_element = typename Master_matrix::Element; - using Cell = typename Master_matrix::Matrix_cell; + using Entry = typename Master_matrix::Matrix_entry; using Column_settings = typename Master_matrix::Column_settings; private: using Field_operators = typename Master_matrix::Field_operators; - using Column_support = std::list; - using Cell_constructor = typename Master_matrix::Cell_constructor; + using Column_support = std::list; + using Entry_constructor = typename Master_matrix::Entry_constructor; public: using iterator = boost::indirect_iterator; @@ -116,19 +116,19 @@ class List_column : public Master_matrix::Row_access_option, reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; - template - List_column& operator+=(const Cell_range& column); + template + List_column& operator+=(const Entry_range& column); List_column& operator+=(List_column& column); List_column& operator*=(unsigned int v); // this = v * this + column - template - List_column& multiply_target_and_add(const Field_element& val, const Cell_range& column); + template + List_column& multiply_target_and_add(const Field_element& val, const Entry_range& column); List_column& multiply_target_and_add(const Field_element& val, List_column& column); // this = this + column * v - template - List_column& multiply_source_and_add(const Cell_range& column, const Field_element& val); + template + List_column& multiply_source_and_add(const Entry_range& column, const Field_element& val); List_column& multiply_source_and_add(List_column& column, const Field_element& val); friend bool operator==(const List_column& c1, const List_column& c2) { @@ -177,7 +177,7 @@ class List_column : public Master_matrix::Row_access_option, static_cast(col2)); col1.column_.swap(col2.column_); std::swap(col1.operators_, col2.operators_); - std::swap(col1.cellPool_, col2.cellPool_); + std::swap(col1.entryPool_, col2.entryPool_); } private: @@ -187,47 +187,47 @@ class List_column : public Master_matrix::Row_access_option, Column_support column_; Field_operators* operators_; - Cell_constructor* cellPool_; - - template - friend void _generic_merge_cell_to_column(Column& targetColumn, - Cell_iterator& itSource, - typename Column::Column_support::iterator& itTarget, - F1&& process_target, - F2&& process_source, - F3&& update_target1, - F4&& update_target2, - bool& pivotIsZeroed); - template - friend bool _generic_add_to_column(const Cell_range& source, + Entry_constructor* entryPool_; + + template + friend void _generic_merge_entry_to_column(Column& targetColumn, + Entry_iterator& itSource, + typename Column::Column_support::iterator& itTarget, + F1&& process_target, + F2&& process_source, + F3&& update_target1, + F4&& update_target2, + bool& pivotIsZeroed); + template + friend bool _generic_add_to_column(const Entry_range& source, Column& targetColumn, F1&& process_target, F2&& process_source, F3&& update_target1, F4&& update_target2, F5&& finish_target); - template - friend bool _add_to_column(const Cell_range& source, Column& targetColumn); - template + template + friend bool _add_to_column(const Entry_range& source, Column& targetColumn); + template friend bool _multiply_target_and_add_to_column(const typename Column::Field_element& val, - const Cell_range& source, + const Entry_range& source, Column& targetColumn); - template + template friend bool _multiply_source_and_add_to_column(const typename Column::Field_element& val, - const Cell_range& source, + const Entry_range& source, Column& targetColumn); - void _delete_cell(typename Column_support::iterator& it); - Cell* _insert_cell(const Field_element& value, ID_index rowIndex, const typename Column_support::iterator& position); - void _insert_cell(ID_index rowIndex, const typename Column_support::iterator& position); - void _update_cell(const Field_element& value, ID_index rowIndex, const typename Column_support::iterator& position); - void _update_cell(ID_index rowIndex, const typename Column_support::iterator& position); - template - bool _add(const Cell_range& column); - template - bool _multiply_target_and_add(const Field_element& val, const Cell_range& column); - template - bool _multiply_source_and_add(const Cell_range& column, const Field_element& val); + void _delete_entry(typename Column_support::iterator& it); + Entry* _insert_entry(const Field_element& value, ID_index rowIndex, const typename Column_support::iterator& position); + void _insert_entry(ID_index rowIndex, const typename Column_support::iterator& position); + void _update_entry(const Field_element& value, ID_index rowIndex, const typename Column_support::iterator& position); + void _update_entry(ID_index rowIndex, const typename Column_support::iterator& position); + template + bool _add(const Entry_range& column); + template + bool _multiply_target_and_add(const Field_element& val, const Entry_range& column); + template + bool _multiply_source_and_add(const Entry_range& column, const Field_element& val); }; template @@ -236,9 +236,9 @@ inline List_column::List_column(Column_settings* colSettings) Dim_opt(), Chain_opt(), operators_(nullptr), - cellPool_(colSettings == nullptr ? nullptr : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor)) { - if (operators_ == nullptr && cellPool_ == nullptr) return; // to allow default constructor which gives a dummy column + if (operators_ == nullptr && entryPool_ == nullptr) return; // to allow default constructor which gives a dummy column if constexpr (!Master_matrix::Option_list::is_z2) { operators_ = &(colSettings->operators); } @@ -252,7 +252,7 @@ inline List_column::List_column(const Container& nonZeroRowIndice Chain_opt(), column_(nonZeroRowIndices.size()), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); @@ -260,12 +260,12 @@ inline List_column::List_column(const Container& nonZeroRowIndice auto it = column_.begin(); if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _update_cell(id, it++); + _update_entry(id, it++); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _update_cell(operators_->get_value(p.second), p.first, it++); + _update_entry(operators_->get_value(p.second), p.first, it++); } } } @@ -287,7 +287,7 @@ inline List_column::List_column(Index columnIndex, }()), column_(nonZeroRowIndices.size()), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); @@ -295,12 +295,12 @@ inline List_column::List_column(Index columnIndex, auto it = column_.begin(); if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _update_cell(id, it++); + _update_entry(id, it++); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _update_cell(operators_->get_value(p.second), p.first, it++); + _update_entry(operators_->get_value(p.second), p.first, it++); } } } @@ -321,17 +321,17 @@ inline List_column::List_column(const Container& nonZeroRowIndice }()), column_(nonZeroRowIndices.size()), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { auto it = column_.begin(); if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _update_cell(id, it++); + _update_entry(id, it++); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _update_cell(operators_->get_value(p.second), p.first, it++); + _update_entry(operators_->get_value(p.second), p.first, it++); } } } @@ -354,17 +354,17 @@ inline List_column::List_column(Index columnIndex, }()), column_(nonZeroRowIndices.size()), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { auto it = column_.begin(); if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _update_cell(id, it++); + _update_entry(id, it++); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _update_cell(operators_->get_value(p.second), p.first, it++); + _update_entry(operators_->get_value(p.second), p.first, it++); } } } @@ -376,7 +376,7 @@ inline List_column::List_column(const List_column& column, Column Chain_opt(static_cast(column)), column_(column.column_.size()), operators_(colSettings == nullptr ? column.operators_ : nullptr), - cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { static_assert(!Master_matrix::Option_list::has_row_access, "Simple copy constructor not available when row access option enabled. Please specify the new column " @@ -387,11 +387,11 @@ inline List_column::List_column(const List_column& column, Column } auto it = column_.begin(); - for (const Cell* cell : column.column_) { + for (const Entry* entry : column.column_) { if constexpr (Master_matrix::Option_list::is_z2) { - _update_cell(cell->get_row_index(), it++); + _update_entry(entry->get_row_index(), it++); } else { - _update_cell(cell->get_element(), cell->get_row_index(), it++); + _update_entry(entry->get_element(), entry->get_row_index(), it++); } } } @@ -407,18 +407,18 @@ inline List_column::List_column(const List_column& column, Chain_opt(static_cast(column)), column_(column.column_.size()), operators_(colSettings == nullptr ? column.operators_ : nullptr), - cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { if constexpr (!Master_matrix::Option_list::is_z2) { if (colSettings != nullptr) operators_ = &(colSettings->operators); } auto it = column_.begin(); - for (const Cell* cell : column.column_) { + for (const Entry* entry : column.column_) { if constexpr (Master_matrix::Option_list::is_z2) { - _update_cell(cell->get_row_index(), it++); + _update_entry(entry->get_row_index(), it++); } else { - _update_cell(cell->get_element(), cell->get_row_index(), it++); + _update_entry(entry->get_element(), entry->get_row_index(), it++); } } } @@ -430,14 +430,14 @@ inline List_column::List_column(List_column&& column) noexcept Chain_opt(std::move(static_cast(column))), column_(std::move(column.column_)), operators_(std::exchange(column.operators_, nullptr)), - cellPool_(std::exchange(column.cellPool_, nullptr)) + entryPool_(std::exchange(column.entryPool_, nullptr)) {} template inline List_column::~List_column() { - for (auto* cell : column_) { - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(cell); - cellPool_->destroy(cell); + for (auto* entry : column_) { + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(entry); + entryPool_->destroy(entry); } } @@ -468,8 +468,8 @@ inline bool List_column::is_non_zero(ID_index rowIndex) const // could be changed to dichotomic search as column is ordered by row index, // but I am not sure if it is really worth it as there is no random access // and the columns should not be that long anyway. - for (const Cell* cell : column_) - if (cell->get_row_index() == rowIndex) return true; + for (const Entry* entry : column_) + if (entry->get_row_index() == rowIndex) return true; return false; } @@ -494,25 +494,25 @@ inline void List_column::reorder(const Row_index_map& valueMap, [ "Method not available for chain columns."); for (auto it = column_.begin(); it != column_.end(); ++it) { - Cell* cell = *it; + Entry* entry = *it; if constexpr (Master_matrix::Option_list::has_row_access) { - RA_opt::unlink(cell); - if (columnIndex != static_cast(-1)) cell->set_column_index(columnIndex); + RA_opt::unlink(entry); + if (columnIndex != static_cast(-1)) entry->set_column_index(columnIndex); } - cell->set_row_index(valueMap.at(cell->get_row_index())); + entry->set_row_index(valueMap.at(entry->get_row_index())); if constexpr (Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access) - RA_opt::insert_cell(cell->get_row_index(), cell); + RA_opt::insert_entry(entry->get_row_index(), entry); } - // all cells have to be deleted first, to avoid problem with insertion when row is a set + // all entries have to be deleted first, to avoid problem with insertion when row is a set if constexpr (!Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access) { for (auto it = column_.begin(); it != column_.end(); ++it) { - Cell* cell = *it; - RA_opt::insert_cell(cell->get_row_index(), cell); + Entry* entry = *it; + RA_opt::insert_entry(entry->get_row_index(), entry); } } - column_.sort([](const Cell* c1, const Cell* c2) { return *c1 < *c2; }); + column_.sort([](const Entry* c1, const Entry* c2) { return *c1 < *c2; }); } template @@ -521,9 +521,9 @@ inline void List_column::clear() static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Method not available for chain columns as a base element should not be empty."); - for (auto* cell : column_) { - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(cell); - cellPool_->destroy(cell); + for (auto* entry : column_) { + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(entry); + entryPool_->destroy(entry); } column_.clear(); @@ -537,7 +537,7 @@ inline void List_column::clear(ID_index rowIndex) auto it = column_.begin(); while (it != column_.end() && (*it)->get_row_index() != rowIndex) it++; - if (it != column_.end()) _delete_cell(it); + if (it != column_.end()) _delete_entry(it); } template @@ -568,8 +568,8 @@ inline typename List_column::Field_element List_columnget_element(); } else { if (Chain_opt::get_pivot() == static_cast(-1)) return Field_element(); - for (const Cell* cell : column_) { - if (cell->get_row_index() == Chain_opt::get_pivot()) return cell->get_element(); + for (const Entry* entry : column_) { + if (entry->get_row_index() == Chain_opt::get_pivot()) return entry->get_element(); } return Field_element(); // should never happen if chain column is used properly } @@ -625,10 +625,10 @@ inline typename List_column::const_reverse_iterator List_column -template -inline List_column& List_column::operator+=(const Cell_range& column) +template +inline List_column& List_column::operator+=(const Entry_range& column) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -680,9 +680,9 @@ inline List_column& List_column::operator*=(unsign if (val == 1u) return *this; - for (Cell* cell : column_) { - operators_->multiply_inplace(cell->get_element(), val); - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_cell(*cell); + for (Entry* entry : column_) { + operators_->multiply_inplace(entry->get_element(), val); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entry); } } @@ -690,11 +690,11 @@ inline List_column& List_column::operator*=(unsign } template -template +template inline List_column& List_column::multiply_target_and_add(const Field_element& val, - const Cell_range& column) + const Entry_range& column) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -752,11 +752,11 @@ inline List_column& List_column::multiply_target_a } template -template -inline List_column& List_column::multiply_source_and_add(const Cell_range& column, +template +inline List_column& List_column::multiply_source_and_add(const Entry_range& column, const Field_element& val) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -813,8 +813,8 @@ inline List_column& List_column::operator=(const L Dim_opt::operator=(other); Chain_opt::operator=(other); - auto tmpPool = cellPool_; - cellPool_ = other.cellPool_; + auto tmpPool = entryPool_; + entryPool_ = other.entryPool_; while (column_.size() > other.column_.size()) { if (column_.back() != nullptr) { @@ -826,15 +826,15 @@ inline List_column& List_column::operator=(const L column_.resize(other.column_.size(), nullptr); auto it = column_.begin(); - for (const Cell* cell : other.column_) { + for (const Entry* entry : other.column_) { if (*it != nullptr) { if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(*it); tmpPool->destroy(*it); } if constexpr (Master_matrix::Option_list::is_z2) { - _update_cell(cell->get_row_index(), it++); + _update_entry(entry->get_row_index(), it++); } else { - _update_cell(cell->get_element(), cell->get_row_index(), it++); + _update_entry(entry->get_element(), entry->get_row_index(), it++); } } @@ -844,85 +844,85 @@ inline List_column& List_column::operator=(const L } template -inline void List_column::_delete_cell(typename Column_support::iterator& it) +inline void List_column::_delete_entry(typename Column_support::iterator& it) { if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(*it); - cellPool_->destroy(*it); + entryPool_->destroy(*it); it = column_.erase(it); } template -inline typename List_column::Cell* List_column::_insert_cell( +inline typename List_column::Entry* List_column::_insert_entry( const Field_element& value, ID_index rowIndex, const typename Column_support::iterator& position) { if constexpr (Master_matrix::Option_list::has_row_access) { - Cell* newCell = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - newCell->set_element(value); - column_.insert(position, newCell); - RA_opt::insert_cell(rowIndex, newCell); - return newCell; + Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + newEntry->set_element(value); + column_.insert(position, newEntry); + RA_opt::insert_entry(rowIndex, newEntry); + return newEntry; } else { - Cell* newCell = cellPool_->construct(rowIndex); - newCell->set_element(value); - column_.insert(position, newCell); - return newCell; + Entry* newEntry = entryPool_->construct(rowIndex); + newEntry->set_element(value); + column_.insert(position, newEntry); + return newEntry; } } template -inline void List_column::_insert_cell(ID_index rowIndex, - const typename Column_support::iterator& position) +inline void List_column::_insert_entry(ID_index rowIndex, + const typename Column_support::iterator& position) { if constexpr (Master_matrix::Option_list::has_row_access) { - Cell* newCell = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - column_.insert(position, newCell); - RA_opt::insert_cell(rowIndex, newCell); + Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + column_.insert(position, newEntry); + RA_opt::insert_entry(rowIndex, newEntry); } else { - Cell* newCell = cellPool_->construct(rowIndex); - column_.insert(position, newCell); + Entry* newEntry = entryPool_->construct(rowIndex); + column_.insert(position, newEntry); } } template -inline void List_column::_update_cell(const Field_element& value, - ID_index rowIndex, - const typename Column_support::iterator& position) +inline void List_column::_update_entry(const Field_element& value, + ID_index rowIndex, + const typename Column_support::iterator& position) { if constexpr (Master_matrix::Option_list::has_row_access) { - *position = cellPool_->construct(RA_opt::columnIndex_, rowIndex); + *position = entryPool_->construct(RA_opt::columnIndex_, rowIndex); (*position)->set_element(value); - RA_opt::insert_cell(rowIndex, *position); + RA_opt::insert_entry(rowIndex, *position); } else { - *position = cellPool_->construct(rowIndex); + *position = entryPool_->construct(rowIndex); (*position)->set_element(value); } } template -inline void List_column::_update_cell(ID_index rowIndex, - const typename Column_support::iterator& position) +inline void List_column::_update_entry(ID_index rowIndex, + const typename Column_support::iterator& position) { if constexpr (Master_matrix::Option_list::has_row_access) { - *position = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - RA_opt::insert_cell(rowIndex, *position); + *position = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + RA_opt::insert_entry(rowIndex, *position); } else { - *position = cellPool_->construct(rowIndex); + *position = entryPool_->construct(rowIndex); } } template -template -inline bool List_column::_add(const Cell_range& column) +template +inline bool List_column::_add(const Entry_range& column) { if (column.begin() == column.end()) return false; if (column_.empty()) { // chain should never enter here. column_.resize(column.size()); auto it = column_.begin(); - for (const Cell& cell : column) { + for (const Entry& entry : column) { if constexpr (Master_matrix::Option_list::is_z2) { - _update_cell(cell.get_row_index(), it++); + _update_entry(entry.get_row_index(), it++); } else { - _update_cell(cell.get_element(), cell.get_row_index(), it++); + _update_entry(entry.get_element(), entry.get_row_index(), it++); } } return true; @@ -932,15 +932,15 @@ inline bool List_column::_add(const Cell_range& column) } template -template -inline bool List_column::_multiply_target_and_add(const Field_element& val, const Cell_range& column) +template +inline bool List_column::_multiply_target_and_add(const Field_element& val, const Entry_range& column) { return _multiply_target_and_add_to_column(val, column, *this); } template -template -inline bool List_column::_multiply_source_and_add(const Cell_range& column, const Field_element& val) +template +inline bool List_column::_multiply_source_and_add(const Entry_range& column, const Field_element& val) { return _multiply_source_and_add_to_column(val, column, *this); } @@ -954,7 +954,7 @@ inline bool List_column::_multiply_source_and_add(const Cell_rang * @brief Hash method for @ref Gudhi::persistence_matrix::List_column. * * @tparam Master_matrix Template parameter of @ref Gudhi::persistence_matrix::List_column. - * @tparam Cell_constructor Template parameter of @ref Gudhi::persistence_matrix::List_column. + * @tparam Entry_constructor Template parameter of @ref Gudhi::persistence_matrix::List_column. */ template struct std::hash > { diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/naive_vector_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/naive_vector_column.h index 9a7bb6bbc8..e91484b31f 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/naive_vector_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/naive_vector_column.h @@ -26,7 +26,7 @@ #include -#include +#include #include namespace Gudhi { @@ -38,11 +38,11 @@ namespace persistence_matrix { * * @brief Column class following the @ref PersistenceMatrixColumn concept. * - * Column based on a vector structure. The cells are always ordered by row index and only non-zero values + * Column based on a vector structure. The entries are always ordered by row index and only non-zero values * are stored uniquely in the underlying container. * * @tparam Master_matrix An instantiation of @ref Matrix from which all types and options are deduced. - * @tparam Cell_constructor Factory of @ref Cell classes. + * @tparam Entry_constructor Factory of @ref Entry classes. */ template class Naive_vector_column : public Master_matrix::Row_access_option, @@ -55,13 +55,13 @@ class Naive_vector_column : public Master_matrix::Row_access_option, using ID_index = typename Master_matrix::ID_index; using Dimension = typename Master_matrix::Dimension; using Field_element = typename Master_matrix::Element; - using Cell = typename Master_matrix::Matrix_cell; + using Entry = typename Master_matrix::Matrix_entry; using Column_settings = typename Master_matrix::Column_settings; private: using Field_operators = typename Master_matrix::Field_operators; - using Column_support = std::vector; - using Cell_constructor = typename Master_matrix::Cell_constructor; + using Column_support = std::vector; + using Entry_constructor = typename Master_matrix::Entry_constructor; public: using iterator = boost::indirect_iterator; @@ -116,19 +116,19 @@ class Naive_vector_column : public Master_matrix::Row_access_option, reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; - template - Naive_vector_column& operator+=(const Cell_range& column); + template + Naive_vector_column& operator+=(const Entry_range& column); Naive_vector_column& operator+=(Naive_vector_column& column); Naive_vector_column& operator*=(unsigned int v); // this = v * this + column - template - Naive_vector_column& multiply_target_and_add(const Field_element& val, const Cell_range& column); + template + Naive_vector_column& multiply_target_and_add(const Field_element& val, const Entry_range& column); Naive_vector_column& multiply_target_and_add(const Field_element& val, Naive_vector_column& column); // this = this + column * v - template - Naive_vector_column& multiply_source_and_add(const Cell_range& column, const Field_element& val); + template + Naive_vector_column& multiply_source_and_add(const Entry_range& column, const Field_element& val); Naive_vector_column& multiply_source_and_add(Naive_vector_column& column, const Field_element& val); friend bool operator==(const Naive_vector_column& c1, const Naive_vector_column& c2) { @@ -177,7 +177,7 @@ class Naive_vector_column : public Master_matrix::Row_access_option, static_cast(col2)); col1.column_.swap(col2.column_); std::swap(col1.operators_, col2.operators_); - std::swap(col1.cellPool_, col2.cellPool_); + std::swap(col1.entryPool_, col2.entryPool_); } private: @@ -187,19 +187,19 @@ class Naive_vector_column : public Master_matrix::Row_access_option, Column_support column_; Field_operators* operators_; - Cell_constructor* cellPool_; - - template - friend void _generic_merge_cell_to_column(Column& targetColumn, - Cell_iterator& itSource, - typename Column::Column_support::iterator& itTarget, - F1&& process_target, - F2&& process_source, - F3&& update_target1, - F4&& update_target2, - bool& pivotIsZeroed); - template - friend bool _generic_add_to_column(const Cell_range& source, + Entry_constructor* entryPool_; + + template + friend void _generic_merge_entry_to_column(Column& targetColumn, + Entry_iterator& itSource, + typename Column::Column_support::iterator& itTarget, + F1&& process_target, + F2&& process_source, + F3&& update_target1, + F4&& update_target2, + bool& pivotIsZeroed); + template + friend bool _generic_add_to_column(const Entry_range& source, Column& targetColumn, F1&& process_target, F2&& process_source, @@ -207,18 +207,18 @@ class Naive_vector_column : public Master_matrix::Row_access_option, F4&& update_target2, F5&& finish_target); - void _delete_cell(Cell* cell); - void _delete_cell(typename Column_support::iterator& it); - Cell* _insert_cell(const Field_element& value, ID_index rowIndex, Column_support& column); - void _insert_cell(ID_index rowIndex, Column_support& column); - void _update_cell(const Field_element& value, ID_index rowIndex, Index position); - void _update_cell(ID_index rowIndex, Index position); - template - bool _add(const Cell_range& column); - template - bool _multiply_target_and_add(const Field_element& val, const Cell_range& column); - template - bool _multiply_source_and_add(const Cell_range& column, const Field_element& val); + void _delete_entry(Entry* entry); + void _delete_entry(typename Column_support::iterator& it); + Entry* _insert_entry(const Field_element& value, ID_index rowIndex, Column_support& column); + void _insert_entry(ID_index rowIndex, Column_support& column); + void _update_entry(const Field_element& value, ID_index rowIndex, Index position); + void _update_entry(ID_index rowIndex, Index position); + template + bool _add(const Entry_range& column); + template + bool _multiply_target_and_add(const Field_element& val, const Entry_range& column); + template + bool _multiply_source_and_add(const Entry_range& column, const Field_element& val); }; template @@ -227,9 +227,9 @@ inline Naive_vector_column::Naive_vector_column(Column_settings* Dim_opt(), Chain_opt(), operators_(nullptr), - cellPool_(colSettings == nullptr ? nullptr : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor)) { - if (operators_ == nullptr && cellPool_ == nullptr) return; // to allow default constructor which gives a dummy column + if (operators_ == nullptr && entryPool_ == nullptr) return; // to allow default constructor which gives a dummy column if constexpr (!Master_matrix::Option_list::is_z2) { operators_ = &(colSettings->operators); } @@ -244,7 +244,7 @@ inline Naive_vector_column::Naive_vector_column(const Container& Chain_opt(), column_(nonZeroRowIndices.size(), nullptr), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); @@ -252,12 +252,12 @@ inline Naive_vector_column::Naive_vector_column(const Container& Index i = 0; if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _update_cell(id, i++); + _update_entry(id, i++); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _update_cell(operators_->get_value(p.second), p.first, i++); + _update_entry(operators_->get_value(p.second), p.first, i++); } } } @@ -279,7 +279,7 @@ inline Naive_vector_column::Naive_vector_column(Index columnIndex }()), column_(nonZeroRowIndices.size(), nullptr), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); @@ -287,12 +287,12 @@ inline Naive_vector_column::Naive_vector_column(Index columnIndex Index i = 0; if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _update_cell(id, i++); + _update_entry(id, i++); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _update_cell(operators_->get_value(p.second), p.first, i++); + _update_entry(operators_->get_value(p.second), p.first, i++); } } } @@ -313,17 +313,17 @@ inline Naive_vector_column::Naive_vector_column(const Container& }()), column_(nonZeroRowIndices.size(), nullptr), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { Index i = 0; if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _update_cell(id, i++); + _update_entry(id, i++); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _update_cell(operators_->get_value(p.second), p.first, i++); + _update_entry(operators_->get_value(p.second), p.first, i++); } } } @@ -346,17 +346,17 @@ inline Naive_vector_column::Naive_vector_column(Index columnIndex }()), column_(nonZeroRowIndices.size(), nullptr), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { Index i = 0; if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _update_cell(id, i++); + _update_entry(id, i++); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _update_cell(operators_->get_value(p.second), p.first, i++); + _update_entry(operators_->get_value(p.second), p.first, i++); } } } @@ -369,7 +369,7 @@ inline Naive_vector_column::Naive_vector_column(const Naive_vecto Chain_opt(static_cast(column)), column_(column.column_.size(), nullptr), operators_(colSettings == nullptr ? column.operators_ : nullptr), - cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { static_assert(!Master_matrix::Option_list::has_row_access, "Simple copy constructor not available when row access option enabled. Please specify the new column " @@ -380,11 +380,11 @@ inline Naive_vector_column::Naive_vector_column(const Naive_vecto } Index i = 0; - for (const Cell* cell : column.column_) { + for (const Entry* entry : column.column_) { if constexpr (Master_matrix::Option_list::is_z2) { - _update_cell(cell->get_row_index(), i++); + _update_entry(entry->get_row_index(), i++); } else { - _update_cell(cell->get_element(), cell->get_row_index(), i++); + _update_entry(entry->get_element(), entry->get_row_index(), i++); } } } @@ -400,18 +400,18 @@ inline Naive_vector_column::Naive_vector_column(const Naive_vecto Chain_opt(static_cast(column)), column_(column.column_.size(), nullptr), operators_(colSettings == nullptr ? column.operators_ : nullptr), - cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { if constexpr (!Master_matrix::Option_list::is_z2) { if (colSettings != nullptr) operators_ = &(colSettings->operators); } Index i = 0; - for (const Cell* cell : column.column_) { + for (const Entry* entry : column.column_) { if constexpr (Master_matrix::Option_list::is_z2) { - _update_cell(cell->get_row_index(), i++); + _update_entry(entry->get_row_index(), i++); } else { - _update_cell(cell->get_element(), cell->get_row_index(), i++); + _update_entry(entry->get_element(), entry->get_row_index(), i++); } } } @@ -423,14 +423,14 @@ inline Naive_vector_column::Naive_vector_column(Naive_vector_colu Chain_opt(std::move(static_cast(column))), column_(std::move(column.column_)), operators_(std::exchange(column.operators_, nullptr)), - cellPool_(std::exchange(column.cellPool_, nullptr)) + entryPool_(std::exchange(column.entryPool_, nullptr)) {} template inline Naive_vector_column::~Naive_vector_column() { - for (auto* cell : column_) { - _delete_cell(cell); + for (auto* entry : column_) { + _delete_entry(entry); } } @@ -458,9 +458,9 @@ Naive_vector_column::get_content(int columnLength) const template inline bool Naive_vector_column::is_non_zero(ID_index rowIndex) const { - Cell cell(rowIndex); - return std::binary_search(column_.begin(), column_.end(), &cell, - [](const Cell* a, const Cell* b) { return a->get_row_index() < b->get_row_index(); }); + Entry entry(rowIndex); + return std::binary_search(column_.begin(), column_.end(), &entry, + [](const Entry* a, const Entry* b) { return a->get_row_index() < b->get_row_index(); }); } template @@ -483,24 +483,24 @@ inline void Naive_vector_column::reorder(const Row_index_map& val static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Method not available for chain columns."); - for (Cell* cell : column_) { + for (Entry* entry : column_) { if constexpr (Master_matrix::Option_list::has_row_access) { - RA_opt::unlink(cell); - if (columnIndex != static_cast(-1)) cell->set_column_index(columnIndex); + RA_opt::unlink(entry); + if (columnIndex != static_cast(-1)) entry->set_column_index(columnIndex); } - cell->set_row_index(valueMap.at(cell->get_row_index())); + entry->set_row_index(valueMap.at(entry->get_row_index())); if constexpr (Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access) - RA_opt::insert_cell(cell->get_row_index(), cell); + RA_opt::insert_entry(entry->get_row_index(), entry); } - // all cells have to be deleted first, to avoid problem with insertion when row is a set + // all entries have to be deleted first, to avoid problem with insertion when row is a set if constexpr (!Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access) { - for (Cell* cell : column_) { - RA_opt::insert_cell(cell->get_row_index(), cell); + for (Entry* entry : column_) { + RA_opt::insert_entry(entry->get_row_index(), entry); } } - std::sort(column_.begin(), column_.end(), [](const Cell* c1, const Cell* c2) { return *c1 < *c2; }); + std::sort(column_.begin(), column_.end(), [](const Entry* c1, const Entry* c2) { return *c1 < *c2; }); } template @@ -509,9 +509,9 @@ inline void Naive_vector_column::clear() static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Method not available for chain columns as a base element should not be empty."); - for (auto* cell : column_) { - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(cell); - cellPool_->destroy(cell); + for (auto* entry : column_) { + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(entry); + entryPool_->destroy(entry); } column_.clear(); @@ -526,7 +526,7 @@ inline void Naive_vector_column::clear(ID_index rowIndex) auto it = column_.begin(); while (it != column_.end() && (*it)->get_row_index() != rowIndex) ++it; if (it != column_.end()) { - _delete_cell(*it); + _delete_entry(*it); column_.erase(it); } } @@ -558,8 +558,8 @@ inline typename Naive_vector_column::Field_element Naive_vector_c return column_.empty() ? Field_element() : column_.back()->get_element(); } else { if (Chain_opt::get_pivot() == static_cast(-1)) return Field_element(); - for (const Cell* cell : column_) { - if (cell->get_row_index() == Chain_opt::get_pivot()) return cell->get_element(); + for (const Entry* entry : column_) { + if (entry->get_row_index() == Chain_opt::get_pivot()) return entry->get_element(); } return Field_element(); // should never happen if chain column is used properly } @@ -621,10 +621,10 @@ inline typename Naive_vector_column::const_reverse_iterator Naive } template -template -inline Naive_vector_column& Naive_vector_column::operator+=(const Cell_range& column) +template +inline Naive_vector_column& Naive_vector_column::operator+=(const Entry_range& column) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -676,9 +676,9 @@ inline Naive_vector_column& Naive_vector_column::o if (val == Field_operators::get_multiplicative_identity()) return *this; - for (Cell* cell : column_) { - operators_->multiply_inplace(cell->get_element(), val); - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_cell(*cell); + for (Entry* entry : column_) { + operators_->multiply_inplace(entry->get_element(), val); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entry); } } @@ -686,11 +686,11 @@ inline Naive_vector_column& Naive_vector_column::o } template -template +template inline Naive_vector_column& Naive_vector_column::multiply_target_and_add( - const Field_element& val, const Cell_range& column) + const Field_element& val, const Entry_range& column) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -748,11 +748,11 @@ inline Naive_vector_column& Naive_vector_column::m } template -template +template inline Naive_vector_column& Naive_vector_column::multiply_source_and_add( - const Cell_range& column, const Field_element& val) + const Entry_range& column, const Field_element& val) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -810,8 +810,8 @@ inline Naive_vector_column& Naive_vector_column::o Dim_opt::operator=(other); Chain_opt::operator=(other); - auto tmpPool = cellPool_; - cellPool_ = other.cellPool_; + auto tmpPool = entryPool_; + entryPool_ = other.entryPool_; while (column_.size() > other.column_.size()) { if (column_.back() == nullptr) { @@ -823,15 +823,15 @@ inline Naive_vector_column& Naive_vector_column::o column_.resize(other.column_.size(), nullptr); Index i = 0; - for (const Cell* cell : other.column_) { + for (const Entry* entry : other.column_) { if (column_[i] != nullptr) { if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(column_[i]); tmpPool->destroy(column_[i]); } if constexpr (Master_matrix::Option_list::is_z2) { - _update_cell(cell->get_row_index(), i++); + _update_entry(entry->get_row_index(), i++); } else { - _update_cell(cell->get_element(), cell->get_row_index(), i++); + _update_entry(entry->get_element(), entry->get_row_index(), i++); } } @@ -841,90 +841,90 @@ inline Naive_vector_column& Naive_vector_column::o } template -inline void Naive_vector_column::_delete_cell(Cell* cell) +inline void Naive_vector_column::_delete_entry(Entry* entry) { - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(cell); - cellPool_->destroy(cell); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(entry); + entryPool_->destroy(entry); } template -inline void Naive_vector_column::_delete_cell(typename Column_support::iterator& it) +inline void Naive_vector_column::_delete_entry(typename Column_support::iterator& it) { - _delete_cell(*it); + _delete_entry(*it); ++it; } template -inline typename Naive_vector_column::Cell* Naive_vector_column::_insert_cell( +inline typename Naive_vector_column::Entry* Naive_vector_column::_insert_entry( const Field_element& value, ID_index rowIndex, Column_support& column) { if constexpr (Master_matrix::Option_list::has_row_access) { - Cell* newCell = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - newCell->set_element(value); - column.push_back(newCell); - RA_opt::insert_cell(rowIndex, newCell); - return newCell; + Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + newEntry->set_element(value); + column.push_back(newEntry); + RA_opt::insert_entry(rowIndex, newEntry); + return newEntry; } else { - Cell* newCell = cellPool_->construct(rowIndex); - column.push_back(newCell); - newCell->set_element(value); - return newCell; + Entry* newEntry = entryPool_->construct(rowIndex); + column.push_back(newEntry); + newEntry->set_element(value); + return newEntry; } } template -inline void Naive_vector_column::_insert_cell(ID_index rowIndex, Column_support& column) +inline void Naive_vector_column::_insert_entry(ID_index rowIndex, Column_support& column) { if constexpr (Master_matrix::Option_list::has_row_access) { - Cell* newCell = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - column.push_back(newCell); - RA_opt::insert_cell(rowIndex, newCell); + Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + column.push_back(newEntry); + RA_opt::insert_entry(rowIndex, newEntry); } else { - column.push_back(cellPool_->construct(rowIndex)); + column.push_back(entryPool_->construct(rowIndex)); } } template -inline void Naive_vector_column::_update_cell(const Field_element& value, +inline void Naive_vector_column::_update_entry(const Field_element& value, ID_index rowIndex, Index position) { if constexpr (Master_matrix::Option_list::has_row_access) { - Cell* newCell = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - newCell->set_element(value); - column_[position] = newCell; - RA_opt::insert_cell(rowIndex, newCell); + Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + newEntry->set_element(value); + column_[position] = newEntry; + RA_opt::insert_entry(rowIndex, newEntry); } else { - column_[position] = cellPool_->construct(rowIndex); + column_[position] = entryPool_->construct(rowIndex); column_[position]->set_element(value); } } template -inline void Naive_vector_column::_update_cell(ID_index rowIndex, Index position) +inline void Naive_vector_column::_update_entry(ID_index rowIndex, Index position) { if constexpr (Master_matrix::Option_list::has_row_access) { - Cell* newCell = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - column_[position] = newCell; - RA_opt::insert_cell(rowIndex, newCell); + Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + column_[position] = newEntry; + RA_opt::insert_entry(rowIndex, newEntry); } else { - column_[position] = cellPool_->construct(rowIndex); + column_[position] = entryPool_->construct(rowIndex); } } template -template -inline bool Naive_vector_column::_add(const Cell_range& column) +template +inline bool Naive_vector_column::_add(const Entry_range& column) { if (column.begin() == column.end()) return false; if (column_.empty()) { // chain should never enter here. column_.resize(column.size()); Index i = 0; - for (const Cell& cell : column) { + for (const Entry& entry : column) { if constexpr (Master_matrix::Option_list::is_z2) { - _update_cell(cell.get_row_index(), i++); + _update_entry(entry.get_row_index(), i++); } else { - _update_cell(cell.get_element(), cell.get_row_index(), i++); + _update_entry(entry.get_element(), entry.get_row_index(), i++); } } return true; @@ -936,20 +936,20 @@ inline bool Naive_vector_column::_add(const Cell_range& column) auto pivotIsZeroed = _generic_add_to_column( column, *this, - [&](Cell* cellTarget) { newColumn.push_back(cellTarget); }, - [&](typename Cell_range::const_iterator& itSource, + [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }, + [&](typename Entry_range::const_iterator& itSource, [[maybe_unused]] const typename Column_support::iterator& itTarget) { if constexpr (Master_matrix::Option_list::is_z2) { - _insert_cell(itSource->get_row_index(), newColumn); + _insert_entry(itSource->get_row_index(), newColumn); } else { - _insert_cell(itSource->get_element(), itSource->get_row_index(), newColumn); + _insert_entry(itSource->get_element(), itSource->get_row_index(), newColumn); } }, - [&](Field_element& targetElement, typename Cell_range::const_iterator& itSource) { + [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) { if constexpr (!Master_matrix::Option_list::is_z2) operators_->add_inplace(targetElement, itSource->get_element()); }, - [&](Cell* cellTarget) { newColumn.push_back(cellTarget); }, + [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }, [&](typename Column_support::iterator& itTarget) { while (itTarget != column_.end()) { newColumn.push_back(*itTarget); @@ -963,9 +963,9 @@ inline bool Naive_vector_column::_add(const Cell_range& column) } template -template +template inline bool Naive_vector_column::_multiply_target_and_add(const Field_element& val, - const Cell_range& column) + const Entry_range& column) { if (val == 0u) { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { @@ -978,11 +978,11 @@ inline bool Naive_vector_column::_multiply_target_and_add(const F if (column_.empty()) { // chain should never enter here. column_.resize(column.size()); Index i = 0; - for (const Cell& cell : column) { + for (const Entry& entry : column) { if constexpr (Master_matrix::Option_list::is_z2) { - _update_cell(cell.get_row_index(), i++); + _update_entry(entry.get_row_index(), i++); } else { - _update_cell(cell.get_element(), cell.get_row_index(), i++); + _update_entry(entry.get_element(), entry.get_row_index(), i++); } } return true; @@ -994,22 +994,22 @@ inline bool Naive_vector_column::_multiply_target_and_add(const F auto pivotIsZeroed = _generic_add_to_column( column, *this, - [&](Cell* cellTarget) { - operators_->multiply_inplace(cellTarget->get_element(), val); - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_cell(*cellTarget); - newColumn.push_back(cellTarget); + [&](Entry* entryTarget) { + operators_->multiply_inplace(entryTarget->get_element(), val); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entryTarget); + newColumn.push_back(entryTarget); }, - [&](typename Cell_range::const_iterator& itSource, const typename Column_support::iterator& itTarget) { - _insert_cell(itSource->get_element(), itSource->get_row_index(), newColumn); + [&](typename Entry_range::const_iterator& itSource, const typename Column_support::iterator& itTarget) { + _insert_entry(itSource->get_element(), itSource->get_row_index(), newColumn); }, - [&](Field_element& targetElement, typename Cell_range::const_iterator& itSource) { + [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) { operators_->multiply_and_add_inplace_front(targetElement, val, itSource->get_element()); }, - [&](Cell* cellTarget) { newColumn.push_back(cellTarget); }, + [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }, [&](typename Column_support::iterator& itTarget) { while (itTarget != column_.end()) { operators_->multiply_inplace((*itTarget)->get_element(), val); - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_cell(**itTarget); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(**itTarget); newColumn.push_back(*itTarget); itTarget++; } @@ -1021,8 +1021,8 @@ inline bool Naive_vector_column::_multiply_target_and_add(const F } template -template -inline bool Naive_vector_column::_multiply_source_and_add(const Cell_range& column, +template +inline bool Naive_vector_column::_multiply_source_and_add(const Entry_range& column, const Field_element& val) { if (val == 0u || column.begin() == column.end()) { @@ -1035,16 +1035,16 @@ inline bool Naive_vector_column::_multiply_source_and_add(const C auto pivotIsZeroed = _generic_add_to_column( column, *this, - [&](Cell* cellTarget) { newColumn.push_back(cellTarget); }, - [&](typename Cell_range::const_iterator& itSource, const typename Column_support::iterator& itTarget) { - Cell* newCell = _insert_cell(itSource->get_element(), itSource->get_row_index(), newColumn); - operators_->multiply_inplace(newCell->get_element(), val); - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_cell(*newCell); + [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }, + [&](typename Entry_range::const_iterator& itSource, const typename Column_support::iterator& itTarget) { + Entry* newEntry = _insert_entry(itSource->get_element(), itSource->get_row_index(), newColumn); + operators_->multiply_inplace(newEntry->get_element(), val); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*newEntry); }, - [&](Field_element& targetElement, typename Cell_range::const_iterator& itSource) { + [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) { operators_->multiply_and_add_inplace_back(itSource->get_element(), val, targetElement); }, - [&](Cell* cellTarget) { newColumn.push_back(cellTarget); }, + [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }, [&](typename Column_support::iterator& itTarget) { while (itTarget != column_.end()) { newColumn.push_back(*itTarget); @@ -1066,7 +1066,7 @@ inline bool Naive_vector_column::_multiply_source_and_add(const C * @brief Hash method for @ref Gudhi::persistence_matrix::Naive_vector_column. * * @tparam Master_matrix Template parameter of @ref Gudhi::persistence_matrix::Naive_vector_column. - * @tparam Cell_constructor Template parameter of @ref Gudhi::persistence_matrix::Naive_vector_column. + * @tparam Entry_constructor Template parameter of @ref Gudhi::persistence_matrix::Naive_vector_column. */ template struct std::hash > { diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/row_access.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/row_access.h index d170c49d1f..035ad0e12f 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/row_access.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/row_access.h @@ -52,7 +52,7 @@ class Row_access public: using Index = typename Master_matrix::Index; /**< @ref MatIdx index type. */ using ID_index = typename Master_matrix::ID_index; /**< @ref IDIdx index type. */ - using Matrix_cell = typename Master_matrix::Matrix_cell; /**< @ref Cell. */ + using Matrix_entry = typename Master_matrix::Matrix_entry; /**< @ref Entry. */ using Row_container = typename Master_matrix::Row_container; /**< Type of the row container. */ /** @@ -75,28 +75,28 @@ class Row_access Row_access(Row_access&& other) noexcept; /** - * @brief Inserts the given cell at the given row index. + * @brief Inserts the given entry at the given row index. * - * @param rowIndex @ref rowindex "Row index" of the cell. - * @param cell Pointer to the cell to insert. + * @param rowIndex @ref rowindex "Row index" of the entry. + * @param entry Pointer to the entry to insert. */ - void insert_cell(ID_index rowIndex, Matrix_cell* cell); + void insert_entry(ID_index rowIndex, Matrix_entry* entry); /** - * @brief Removes the given cell from its row. + * @brief Removes the given entry from its row. * - * @param cell Pointer to the cell to remove. + * @param entry Pointer to the entry to remove. */ - void unlink(Matrix_cell* cell); + void unlink(Matrix_entry* entry); /** - * @brief If @ref PersistenceMatrixOptions::has_intrusive_rows is false, updates the copy of the cell in its row. + * @brief If @ref PersistenceMatrixOptions::has_intrusive_rows is false, updates the copy of the entry in its row. * Otherwise does nothing. * - * If the rows are intrusive, only a pointer of the cell is stored and therefore any update on the cell (value + * If the rows are intrusive, only a pointer of the entry is stored and therefore any update on the entry (value * or column index) is automatically forwarded. But for non intrusive rows, any update has to be pushed explicitly. * - * @param cell Cell to update. + * @param entry Entry to update. */ - void update_cell(const Matrix_cell& cell); + void update_entry(const Matrix_entry& entry); /** * @brief Returns the @ref MatIdx column index. * @@ -135,7 +135,7 @@ inline Row_access::Row_access(Row_access&& other) noexcept {} template -inline void Row_access::insert_cell(ID_index rowIndex, Matrix_cell* cell) +inline void Row_access::insert_entry(ID_index rowIndex, Matrix_entry* entry) { if (rows_ == nullptr) return; @@ -145,38 +145,38 @@ inline void Row_access::insert_cell(ID_index rowIndex, Matrix_cel // if has_removable_rows should op[] create non existing entry? If not, use try_emplace() if constexpr (Master_matrix::Option_list::has_intrusive_rows) { - rows_->operator[](rowIndex).push_back(*cell); + rows_->operator[](rowIndex).push_back(*entry); } else { - rows_->operator[](rowIndex).insert(*cell); + rows_->operator[](rowIndex).insert(*entry); } } template -inline void Row_access::unlink(Matrix_cell* cell) +inline void Row_access::unlink(Matrix_entry* entry) { if (rows_ == nullptr) return; if constexpr (Master_matrix::Option_list::has_intrusive_rows) { - cell->Base_hook_matrix_row::unlink(); + entry->Base_hook_matrix_row::unlink(); } else { if constexpr (Master_matrix::Option_list::has_removable_rows) { - auto it = rows_->find(cell->get_row_index()); - it->second.erase(*cell); + auto it = rows_->find(entry->get_row_index()); + it->second.erase(*entry); } else { - rows_->operator[](cell->get_row_index()).erase(*cell); + rows_->operator[](entry->get_row_index()).erase(*entry); } } } template -inline void Row_access::update_cell(const Matrix_cell& cell) +inline void Row_access::update_entry(const Matrix_entry& entry) { if constexpr (!Master_matrix::Option_list::has_intrusive_rows) { if (rows_ == nullptr) return; - auto& row = rows_->at(cell.get_row_index()); - auto it = row.find(cell); + auto& row = rows_->at(entry.get_row_index()); + auto it = row.find(entry); it = row.erase(it); - row.insert(it, cell); + row.insert(it, entry); } } diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/set_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/set_column.h index d7c84e1277..de7151a75f 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/set_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/set_column.h @@ -26,7 +26,7 @@ #include -#include +#include #include namespace Gudhi { @@ -38,11 +38,11 @@ namespace persistence_matrix { * * @brief Column class following the @ref PersistenceMatrixColumn concept. * - * Column based on a set structure. The cells are always ordered by row index and only non-zero values + * Column based on a set structure. The entries are always ordered by row index and only non-zero values * are stored uniquely in the underlying container. * * @tparam Master_matrix An instantiation of @ref Matrix from which all types and options are deduced. - * @tparam Cell_constructor Factory of @ref Cell classes. + * @tparam Entry_constructor Factory of @ref Entry classes. */ template class Set_column : public Master_matrix::Row_access_option, @@ -55,18 +55,18 @@ class Set_column : public Master_matrix::Row_access_option, using ID_index = typename Master_matrix::ID_index; using Dimension = typename Master_matrix::Dimension; using Field_element = typename Master_matrix::Element; - using Cell = typename Master_matrix::Matrix_cell; + using Entry = typename Master_matrix::Matrix_entry; using Column_settings = typename Master_matrix::Column_settings; private: using Field_operators = typename Master_matrix::Field_operators; - struct CellPointerComp { - bool operator()(const Cell* c1, const Cell* c2) const { return *c1 < *c2; } + struct EntryPointerComp { + bool operator()(const Entry* c1, const Entry* c2) const { return *c1 < *c2; } }; - using Column_support = std::set; - using Cell_constructor = typename Master_matrix::Cell_constructor; + using Column_support = std::set; + using Entry_constructor = typename Master_matrix::Entry_constructor; public: using iterator = boost::indirect_iterator; @@ -121,19 +121,19 @@ class Set_column : public Master_matrix::Row_access_option, reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; - template - Set_column& operator+=(const Cell_range& column); + template + Set_column& operator+=(const Entry_range& column); Set_column& operator+=(Set_column& column); Set_column& operator*=(unsigned int v); // this = v * this + column - template - Set_column& multiply_target_and_add(const Field_element& val, const Cell_range& column); + template + Set_column& multiply_target_and_add(const Field_element& val, const Entry_range& column); Set_column& multiply_target_and_add(const Field_element& val, Set_column& column); // this = this + column * v - template - Set_column& multiply_source_and_add(const Cell_range& column, const Field_element& val); + template + Set_column& multiply_source_and_add(const Entry_range& column, const Field_element& val); Set_column& multiply_source_and_add(Set_column& column, const Field_element& val); friend bool operator==(const Set_column& c1, const Set_column& c2) { @@ -182,7 +182,7 @@ class Set_column : public Master_matrix::Row_access_option, static_cast(col2)); col1.column_.swap(col2.column_); std::swap(col1.operators_, col2.operators_); - std::swap(col1.cellPool_, col2.cellPool_); + std::swap(col1.entryPool_, col2.entryPool_); } private: @@ -192,45 +192,45 @@ class Set_column : public Master_matrix::Row_access_option, Column_support column_; Field_operators* operators_; - Cell_constructor* cellPool_; - - template - friend void _generic_merge_cell_to_column(Column& targetColumn, - Cell_iterator& itSource, - typename Column::Column_support::iterator& itTarget, - F1&& process_target, - F2&& process_source, - F3&& update_target1, - F4&& update_target2, - bool& pivotIsZeroed); - template - friend bool _generic_add_to_column(const Cell_range& source, + Entry_constructor* entryPool_; + + template + friend void _generic_merge_entry_to_column(Column& targetColumn, + Entry_iterator& itSource, + typename Column::Column_support::iterator& itTarget, + F1&& process_target, + F2&& process_source, + F3&& update_target1, + F4&& update_target2, + bool& pivotIsZeroed); + template + friend bool _generic_add_to_column(const Entry_range& source, Column& targetColumn, F1&& process_target, F2&& process_source, F3&& update_target1, F4&& update_target2, F5&& finish_target); - template - friend bool _add_to_column(const Cell_range& source, Column& targetColumn); - template + template + friend bool _add_to_column(const Entry_range& source, Column& targetColumn); + template friend bool _multiply_target_and_add_to_column(const typename Column::Field_element& val, - const Cell_range& source, + const Entry_range& source, Column& targetColumn); - template + template friend bool _multiply_source_and_add_to_column(const typename Column::Field_element& val, - const Cell_range& source, + const Entry_range& source, Column& targetColumn); - void _delete_cell(typename Column_support::iterator& it); - Cell* _insert_cell(const Field_element& value, ID_index rowIndex, const typename Column_support::iterator& position); - void _insert_cell(ID_index rowIndex, const typename Column_support::iterator& position); - template - bool _add(const Cell_range& column); - template - bool _multiply_target_and_add(const Field_element& val, const Cell_range& column); - template - bool _multiply_source_and_add(const Cell_range& column, const Field_element& val); + void _delete_entry(typename Column_support::iterator& it); + Entry* _insert_entry(const Field_element& value, ID_index rowIndex, const typename Column_support::iterator& position); + void _insert_entry(ID_index rowIndex, const typename Column_support::iterator& position); + template + bool _add(const Entry_range& column); + template + bool _multiply_target_and_add(const Field_element& val, const Entry_range& column); + template + bool _multiply_source_and_add(const Entry_range& column, const Field_element& val); }; template @@ -239,9 +239,9 @@ inline Set_column::Set_column(Column_settings* colSettings) Dim_opt(), Chain_opt(), operators_(nullptr), - cellPool_(colSettings == nullptr ? nullptr : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor)) { - if (operators_ == nullptr && cellPool_ == nullptr) return; // to allow default constructor which gives a dummy column + if (operators_ == nullptr && entryPool_ == nullptr) return; // to allow default constructor which gives a dummy column if constexpr (!Master_matrix::Option_list::is_z2) { operators_ = &(colSettings->operators); } @@ -254,19 +254,19 @@ inline Set_column::Set_column(const Container& nonZeroRowIndices, Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), Chain_opt(), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _insert_cell(id, column_.end()); + _insert_entry(id, column_.end()); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _insert_cell(operators_->get_value(p.second), p.first, column_.end()); + _insert_entry(operators_->get_value(p.second), p.first, column_.end()); } } } @@ -287,19 +287,19 @@ inline Set_column::Set_column(Index columnIndex, } }()), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _insert_cell(id, column_.end()); + _insert_entry(id, column_.end()); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _insert_cell(operators_->get_value(p.second), p.first, column_.end()); + _insert_entry(operators_->get_value(p.second), p.first, column_.end()); } } } @@ -319,16 +319,16 @@ inline Set_column::Set_column(const Container& nonZeroRowIndices, } }()), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _insert_cell(id, column_.end()); + _insert_entry(id, column_.end()); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _insert_cell(operators_->get_value(p.second), p.first, column_.end()); + _insert_entry(operators_->get_value(p.second), p.first, column_.end()); } } } @@ -350,16 +350,16 @@ inline Set_column::Set_column(Index columnIndex, } }()), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _insert_cell(id, column_.end()); + _insert_entry(id, column_.end()); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _insert_cell(operators_->get_value(p.second), p.first, column_.end()); + _insert_entry(operators_->get_value(p.second), p.first, column_.end()); } } } @@ -370,7 +370,7 @@ inline Set_column::Set_column(const Set_column& column, Column_se Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), operators_(colSettings == nullptr ? column.operators_ : nullptr), - cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { static_assert(!Master_matrix::Option_list::has_row_access, "Simple copy constructor not available when row access option enabled. Please specify the new column " @@ -380,11 +380,11 @@ inline Set_column::Set_column(const Set_column& column, Column_se if (colSettings != nullptr) operators_ = &(colSettings->operators); } - for (const Cell* cell : column.column_) { + for (const Entry* entry : column.column_) { if constexpr (Master_matrix::Option_list::is_z2) { - _insert_cell(cell->get_row_index(), column_.end()); + _insert_entry(entry->get_row_index(), column_.end()); } else { - _insert_cell(cell->get_element(), cell->get_row_index(), column_.end()); + _insert_entry(entry->get_element(), entry->get_row_index(), column_.end()); } } } @@ -399,17 +399,17 @@ inline Set_column::Set_column(const Set_column& column, Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), operators_(colSettings == nullptr ? column.operators_ : nullptr), - cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { if constexpr (!Master_matrix::Option_list::is_z2) { if (colSettings != nullptr) operators_ = &(colSettings->operators); } - for (const Cell* cell : column.column_) { + for (const Entry* entry : column.column_) { if constexpr (Master_matrix::Option_list::is_z2) { - _insert_cell(cell->get_row_index(), column_.end()); + _insert_entry(entry->get_row_index(), column_.end()); } else { - _insert_cell(cell->get_element(), cell->get_row_index(), column_.end()); + _insert_entry(entry->get_element(), entry->get_row_index(), column_.end()); } } } @@ -421,15 +421,15 @@ inline Set_column::Set_column(Set_column&& column) noexcept Chain_opt(std::move(static_cast(column))), column_(std::move(column.column_)), operators_(std::exchange(column.operators_, nullptr)), - cellPool_(std::exchange(column.cellPool_, nullptr)) + entryPool_(std::exchange(column.entryPool_, nullptr)) {} template inline Set_column::~Set_column() { - for (auto* cell : column_) { - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(cell); - cellPool_->destroy(cell); + for (auto* entry : column_) { + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(entry); + entryPool_->destroy(entry); } } @@ -457,8 +457,8 @@ inline std::vector::Field_element> Set_column template inline bool Set_column::is_non_zero(ID_index rowIndex) const { - Cell cell(rowIndex); - return column_.find(&cell) != column_.end(); + Entry entry(rowIndex); + return column_.find(&entry) != column_.end(); } template @@ -482,22 +482,22 @@ inline void Set_column::reorder(const Row_index_map& valueMap, [[ Column_support newSet; - for (Cell* cell : column_) { + for (Entry* entry : column_) { if constexpr (Master_matrix::Option_list::has_row_access) { - RA_opt::unlink(cell); - if (columnIndex != static_cast(-1)) cell->set_column_index(columnIndex); + RA_opt::unlink(entry); + if (columnIndex != static_cast(-1)) entry->set_column_index(columnIndex); } - cell->set_row_index(valueMap.at(cell->get_row_index())); - newSet.insert(cell); + entry->set_row_index(valueMap.at(entry->get_row_index())); + newSet.insert(entry); if constexpr (Master_matrix::Option_list::has_row_access && Master_matrix::Option_list::has_intrusive_rows) // intrusive list - RA_opt::insert_cell(cell->get_row_index(), cell); + RA_opt::insert_entry(entry->get_row_index(), entry); } - // when row is a set, all cells have to be deleted first, to avoid colliding when inserting + // when row is a set, all entries have to be deleted first, to avoid colliding when inserting if constexpr (Master_matrix::Option_list::has_row_access && !Master_matrix::Option_list::has_intrusive_rows) { // set - for (Cell* cell : newSet) { - RA_opt::insert_cell(cell->get_row_index(), cell); + for (Entry* entry : newSet) { + RA_opt::insert_entry(entry->get_row_index(), entry); } } @@ -510,9 +510,9 @@ inline void Set_column::clear() static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Method not available for chain columns as a base element should not be empty."); - for (auto* cell : column_) { - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(cell); - cellPool_->destroy(cell); + for (auto* entry : column_) { + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(entry); + entryPool_->destroy(entry); } column_.clear(); @@ -524,12 +524,12 @@ inline void Set_column::clear(ID_index rowIndex) static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Method not available for chain columns."); - auto cell = cellPool_->construct(rowIndex); - auto it = column_.find(cell); + auto entry = entryPool_->construct(rowIndex); + auto it = column_.find(entry); if (it != column_.end()) { - _delete_cell(it); + _delete_entry(it); } - cellPool_->destroy(cell); + entryPool_->destroy(entry); } template @@ -560,8 +560,8 @@ inline typename Set_column::Field_element Set_columnget_element(); } else { if (Chain_opt::get_pivot() == static_cast(-1)) return Field_element(); - for (const Cell* cell : column_) { - if (cell->get_row_index() == Chain_opt::get_pivot()) return cell->get_element(); + for (const Entry* entry : column_) { + if (entry->get_row_index() == Chain_opt::get_pivot()) return entry->get_element(); } return Field_element(); // should never happen if chain column is used properly } @@ -617,10 +617,10 @@ inline typename Set_column::const_reverse_iterator Set_column -template -inline Set_column& Set_column::operator+=(const Cell_range& column) +template +inline Set_column& Set_column::operator+=(const Entry_range& column) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -672,9 +672,9 @@ inline Set_column& Set_column::operator*=(unsigned if (val == Field_operators::get_multiplicative_identity()) return *this; - for (Cell* cell : column_) { - operators_->multiply_inplace(cell->get_element(), val); - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_cell(*cell); + for (Entry* entry : column_) { + operators_->multiply_inplace(entry->get_element(), val); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entry); } } @@ -682,11 +682,11 @@ inline Set_column& Set_column::operator*=(unsigned } template -template +template inline Set_column& Set_column::multiply_target_and_add(const Field_element& val, - const Cell_range& column) + const Entry_range& column) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -744,11 +744,11 @@ inline Set_column& Set_column::multiply_target_and } template -template -inline Set_column& Set_column::multiply_source_and_add(const Cell_range& column, +template +inline Set_column& Set_column::multiply_source_and_add(const Entry_range& column, const Field_element& val) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -805,20 +805,20 @@ inline Set_column& Set_column::operator=(const Set Dim_opt::operator=(other); Chain_opt::operator=(other); - for (auto* cell : column_) { - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(cell); - cellPool_->destroy(cell); + for (auto* entry : column_) { + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(entry); + entryPool_->destroy(entry); } column_.clear(); - cellPool_ = other.cellPool_; + entryPool_ = other.entryPool_; operators_ = other.operators_; - for (const Cell* cell : other.column_) { + for (const Entry* entry : other.column_) { if constexpr (Master_matrix::Option_list::is_z2) { - _insert_cell(cell->get_row_index(), column_.end()); + _insert_entry(entry->get_row_index(), column_.end()); } else { - _insert_cell(cell->get_element(), cell->get_row_index(), column_.end()); + _insert_entry(entry->get_element(), entry->get_row_index(), column_.end()); } } @@ -826,62 +826,62 @@ inline Set_column& Set_column::operator=(const Set } template -inline void Set_column::_delete_cell(typename Column_support::iterator& it) +inline void Set_column::_delete_entry(typename Column_support::iterator& it) { if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(*it); - cellPool_->destroy(*it); + entryPool_->destroy(*it); it = column_.erase(it); } template -inline typename Set_column::Cell* Set_column::_insert_cell( +inline typename Set_column::Entry* Set_column::_insert_entry( const Field_element& value, ID_index rowIndex, const typename Column_support::iterator& position) { if constexpr (Master_matrix::Option_list::has_row_access) { - Cell* newCell = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - newCell->set_element(value); - column_.insert(position, newCell); - RA_opt::insert_cell(rowIndex, newCell); - return newCell; + Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + newEntry->set_element(value); + column_.insert(position, newEntry); + RA_opt::insert_entry(rowIndex, newEntry); + return newEntry; } else { - Cell* newCell = cellPool_->construct(rowIndex); - newCell->set_element(value); - column_.insert(position, newCell); - return newCell; + Entry* newEntry = entryPool_->construct(rowIndex); + newEntry->set_element(value); + column_.insert(position, newEntry); + return newEntry; } } template -inline void Set_column::_insert_cell(ID_index rowIndex, +inline void Set_column::_insert_entry(ID_index rowIndex, const typename Column_support::iterator& position) { if constexpr (Master_matrix::Option_list::has_row_access) { - Cell* newCell = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - column_.insert(position, newCell); - RA_opt::insert_cell(rowIndex, newCell); + Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + column_.insert(position, newEntry); + RA_opt::insert_entry(rowIndex, newEntry); } else { - Cell* newCell = cellPool_->construct(rowIndex); - column_.insert(position, newCell); + Entry* newEntry = entryPool_->construct(rowIndex); + column_.insert(position, newEntry); } } template -template -inline bool Set_column::_add(const Cell_range& column) +template +inline bool Set_column::_add(const Entry_range& column) { return _add_to_column(column, *this); } template -template -inline bool Set_column::_multiply_target_and_add(const Field_element& val, const Cell_range& column) +template +inline bool Set_column::_multiply_target_and_add(const Field_element& val, const Entry_range& column) { return _multiply_target_and_add_to_column(val, column, *this); } template -template -inline bool Set_column::_multiply_source_and_add(const Cell_range& column, const Field_element& val) +template +inline bool Set_column::_multiply_source_and_add(const Entry_range& column, const Field_element& val) { return _multiply_source_and_add_to_column(val, column, *this); } @@ -895,7 +895,7 @@ inline bool Set_column::_multiply_source_and_add(const Cell_range * @brief Hash method for @ref Gudhi::persistence_matrix::Set_column. * * @tparam Master_matrix Template parameter of @ref Gudhi::persistence_matrix::Set_column. - * @tparam Cell_constructor Template parameter of @ref Gudhi::persistence_matrix::Set_column. + * @tparam Entry_constructor Template parameter of @ref Gudhi::persistence_matrix::Set_column. */ template struct std::hash > { diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/unordered_set_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/unordered_set_column.h index 0e4dc12462..4729b004dd 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/unordered_set_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/unordered_set_column.h @@ -31,22 +31,22 @@ #include #endif -#include +#include namespace Gudhi { namespace persistence_matrix { // For unordered_set container. Outside of Unordered_set_column because of a msvc bug who can't compile properly // unordered_flat_set if the hash method is nested. -template -struct CellPointerHash +template +struct EntryPointerHash { - size_t operator()(const Cell* c) const { return std::hash()(*c); } + size_t operator()(const Entry* c) const { return std::hash()(*c); } }; -template -struct CellPointerEq +template +struct EntryPointerEq { - bool operator()(const Cell* c1, const Cell* c2) const { return *c1 == *c2; } + bool operator()(const Entry* c1, const Entry* c2) const { return *c1 == *c2; } }; /** @@ -55,12 +55,12 @@ struct CellPointerEq * * @brief Column class following the @ref PersistenceMatrixColumn concept. * - * Column based on an unordered set structure. The cells are not ordered, but only non-zero values - * are stored uniquely in the underlying container. When adding a cell range into it, the given cell range + * Column based on an unordered set structure. The entries are not ordered, but only non-zero values + * are stored uniquely in the underlying container. When adding an entry range into it, the given entry range * also does not need to be ordered (contrary to most other column types). * * @tparam Master_matrix An instantiation of @ref Matrix from which all types and options are deduced. - * @tparam Cell_constructor Factory of @ref Cell classes. + * @tparam Entry_constructor Factory of @ref Entry classes. */ template class Unordered_set_column : public Master_matrix::Row_access_option, @@ -73,21 +73,21 @@ class Unordered_set_column : public Master_matrix::Row_access_option, using ID_index = typename Master_matrix::ID_index; using Dimension = typename Master_matrix::Dimension; using Field_element = typename Master_matrix::Element; - using Cell = typename Master_matrix::Matrix_cell; + using Entry = typename Master_matrix::Matrix_entry; using Column_settings = typename Master_matrix::Column_settings; private: using Field_operators = typename Master_matrix::Field_operators; - using Cell_constructor = typename Master_matrix::Cell_constructor; + using Entry_constructor = typename Master_matrix::Entry_constructor; - struct CellPointerComp { - bool operator()(const Cell* c1, const Cell* c2) const { return *c1 < *c2; } + struct EntryPointerComp { + bool operator()(const Entry* c1, const Entry* c2) const { return *c1 < *c2; } }; #if BOOST_VERSION >= 108100 - using Column_support = boost::unordered_flat_set, CellPointerEq>; + using Column_support = boost::unordered_flat_set, EntryPointerEq>; #else - using Column_support = std::unordered_set, CellPointerEq>; + using Column_support = std::unordered_set, EntryPointerEq>; #endif public: @@ -137,30 +137,30 @@ class Unordered_set_column : public Master_matrix::Row_access_option, iterator end() noexcept; const_iterator end() const noexcept; - template - Unordered_set_column& operator+=(const Cell_range& column); + template + Unordered_set_column& operator+=(const Entry_range& column); Unordered_set_column& operator+=(Unordered_set_column& column); Unordered_set_column& operator*=(unsigned int v); // this = v * this + column - template - Unordered_set_column& multiply_target_and_add(const Field_element& val, const Cell_range& column); + template + Unordered_set_column& multiply_target_and_add(const Field_element& val, const Entry_range& column); Unordered_set_column& multiply_target_and_add(const Field_element& val, Unordered_set_column& column); // this = this + column * v - template - Unordered_set_column& multiply_source_and_add(const Cell_range& column, const Field_element& val); + template + Unordered_set_column& multiply_source_and_add(const Entry_range& column, const Field_element& val); Unordered_set_column& multiply_source_and_add(Unordered_set_column& column, const Field_element& val); friend bool operator==(const Unordered_set_column& c1, const Unordered_set_column& c2) { if (&c1 == &c2) return true; if (c1.column_.size() != c2.column_.size()) return false; - for (Cell* cell : c1.column_) { - auto it = c2.column_.find(cell); + for (Entry* entry : c1.column_) { + auto it = c2.column_.find(entry); if (it == c2.column_.end()) return false; if constexpr (!Master_matrix::Option_list::is_z2) - if ((*it)->get_element() != cell->get_element()) return false; + if ((*it)->get_element() != entry->get_element()) return false; } return true; } @@ -168,7 +168,7 @@ class Unordered_set_column : public Master_matrix::Row_access_option, if (&c1 == &c2) return false; using ID_index = Unordered_set_column::ID_index; - using Cell_rep = + using Entry_rep = typename std::conditional @@ -176,35 +176,35 @@ class Unordered_set_column : public Master_matrix::Row_access_option, auto it1 = c1.column_.begin(); auto it2 = c2.column_.begin(); - std::set cells1, cells2; + std::set entries1, entries2; while (it1 != c1.column_.end() && it2 != c2.column_.end()) { if constexpr (Master_matrix::Option_list::is_z2) { - cells1.insert((*it1)->get_row_index()); - cells2.insert((*it2)->get_row_index()); + entries1.insert((*it1)->get_row_index()); + entries2.insert((*it2)->get_row_index()); } else { - cells1.emplace((*it1)->get_row_index(), (*it1)->get_element()); - cells2.emplace((*it2)->get_row_index(), (*it2)->get_element()); + entries1.emplace((*it1)->get_row_index(), (*it1)->get_element()); + entries2.emplace((*it2)->get_row_index(), (*it2)->get_element()); } ++it1; ++it2; } while (it1 != c1.column_.end()) { if constexpr (Master_matrix::Option_list::is_z2) { - cells1.insert((*it1)->get_row_index()); + entries1.insert((*it1)->get_row_index()); } else { - cells1.emplace((*it1)->get_row_index(), (*it1)->get_element()); + entries1.emplace((*it1)->get_row_index(), (*it1)->get_element()); } ++it1; } while (it2 != c2.column_.end()) { if constexpr (Master_matrix::Option_list::is_z2) { - cells2.insert((*it2)->get_row_index()); + entries2.insert((*it2)->get_row_index()); } else { - cells2.emplace((*it2)->get_row_index(), (*it2)->get_element()); + entries2.emplace((*it2)->get_row_index(), (*it2)->get_element()); } ++it2; } - return cells1 < cells2; + return entries1 < entries2; } // Disabled with row access. @@ -219,7 +219,7 @@ class Unordered_set_column : public Master_matrix::Row_access_option, static_cast(col2)); col1.column_.swap(col2.column_); std::swap(col1.operators_, col2.operators_); - std::swap(col1.cellPool_, col2.cellPool_); + std::swap(col1.entryPool_, col2.entryPool_); } private: @@ -229,19 +229,19 @@ class Unordered_set_column : public Master_matrix::Row_access_option, Column_support column_; Field_operators* operators_; - Cell_constructor* cellPool_; - - void _delete_cell(typename Column_support::iterator& it); - Cell* _insert_cell(const Field_element& value, ID_index rowIndex); - void _insert_cell(ID_index rowIndex); - template - bool _add(const Cell_range& column); - template - bool _multiply_target_and_add(const Field_element& val, const Cell_range& column); - template - bool _multiply_source_and_add(const Cell_range& column, const Field_element& val); - template - bool _generic_add(const Cell_range& source, F1&& process_source, F2&& update_target); + Entry_constructor* entryPool_; + + void _delete_entry(typename Column_support::iterator& it); + Entry* _insert_entry(const Field_element& value, ID_index rowIndex); + void _insert_entry(ID_index rowIndex); + template + bool _add(const Entry_range& column); + template + bool _multiply_target_and_add(const Field_element& val, const Entry_range& column); + template + bool _multiply_source_and_add(const Entry_range& column, const Field_element& val); + template + bool _generic_add(const Entry_range& source, F1&& process_source, F2&& update_target); }; template @@ -250,9 +250,9 @@ inline Unordered_set_column::Unordered_set_column(Column_settings Dim_opt(), Chain_opt(), operators_(nullptr), - cellPool_(colSettings == nullptr ? nullptr : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor)) { - if (operators_ == nullptr && cellPool_ == nullptr) return; // to allow default constructor which gives a dummy column + if (operators_ == nullptr && entryPool_ == nullptr) return; // to allow default constructor which gives a dummy column if constexpr (!Master_matrix::Option_list::is_z2) { operators_ = &(colSettings->operators); } @@ -267,19 +267,19 @@ inline Unordered_set_column::Unordered_set_column(const Container Chain_opt(), column_(nonZeroRowIndices.size()), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _insert_cell(id); + _insert_entry(id); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _insert_cell(operators_->get_value(p.second), p.first); + _insert_entry(operators_->get_value(p.second), p.first); } } } @@ -301,19 +301,19 @@ inline Unordered_set_column::Unordered_set_column(Index columnInd }()), column_(nonZeroRowIndices.size()), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _insert_cell(id); + _insert_entry(id); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _insert_cell(operators_->get_value(p.second), p.first); + _insert_entry(operators_->get_value(p.second), p.first); } } } @@ -334,16 +334,16 @@ inline Unordered_set_column::Unordered_set_column(const Container }()), column_(nonZeroRowIndices.size()), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _insert_cell(id); + _insert_entry(id); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _insert_cell(operators_->get_value(p.second), p.first); + _insert_entry(operators_->get_value(p.second), p.first); } } } @@ -366,16 +366,16 @@ inline Unordered_set_column::Unordered_set_column(Index columnInd }()), column_(nonZeroRowIndices.size()), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _insert_cell(id); + _insert_entry(id); } } else { operators_ = &(colSettings->operators); for (const auto& p : nonZeroRowIndices) { - _insert_cell(operators_->get_value(p.second), p.first); + _insert_entry(operators_->get_value(p.second), p.first); } } } @@ -388,7 +388,7 @@ inline Unordered_set_column::Unordered_set_column(const Unordered Chain_opt(static_cast(column)), column_(column.column_.bucket_count()), operators_(colSettings == nullptr ? column.operators_ : nullptr), - cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { static_assert(!Master_matrix::Option_list::has_row_access, "Simple copy constructor not available when row access option enabled. Please specify the new column " @@ -398,11 +398,11 @@ inline Unordered_set_column::Unordered_set_column(const Unordered if (colSettings != nullptr) operators_ = &(colSettings->operators); } - for (const Cell* cell : column.column_) { + for (const Entry* entry : column.column_) { if constexpr (Master_matrix::Option_list::is_z2) { - _insert_cell(cell->get_row_index()); + _insert_entry(entry->get_row_index()); } else { - _insert_cell(cell->get_element(), cell->get_row_index()); + _insert_entry(entry->get_element(), entry->get_row_index()); } } } @@ -418,17 +418,17 @@ inline Unordered_set_column::Unordered_set_column(const Unordered Chain_opt(static_cast(column)), column_(column.column_.bucket_count()), operators_(colSettings == nullptr ? column.operators_ : nullptr), - cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { if constexpr (!Master_matrix::Option_list::is_z2) { if (colSettings != nullptr) operators_ = &(colSettings->operators); } - for (const Cell* cell : column.column_) { + for (const Entry* entry : column.column_) { if constexpr (Master_matrix::Option_list::is_z2) { - _insert_cell(cell->get_row_index()); + _insert_entry(entry->get_row_index()); } else { - _insert_cell(cell->get_element(), cell->get_row_index()); + _insert_entry(entry->get_element(), entry->get_row_index()); } } } @@ -440,15 +440,15 @@ inline Unordered_set_column::Unordered_set_column(Unordered_set_c Chain_opt(std::move(static_cast(column))), column_(std::move(column.column_)), operators_(std::exchange(column.operators_, nullptr)), - cellPool_(std::exchange(column.cellPool_, nullptr)) + entryPool_(std::exchange(column.entryPool_, nullptr)) {} template inline Unordered_set_column::~Unordered_set_column() { - for (auto* cell : column_) { - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(cell); - cellPool_->destroy(cell); + for (auto* entry : column_) { + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(entry); + entryPool_->destroy(entry); } } @@ -457,7 +457,7 @@ inline std::vector::Field_element> Unordered_set_column::get_content(int columnLength) const { if (columnLength < 0 && column_.size() > 0) - columnLength = (*std::max_element(column_.begin(), column_.end(), CellPointerComp()))->get_row_index() + 1; + columnLength = (*std::max_element(column_.begin(), column_.end(), EntryPointerComp()))->get_row_index() + 1; else if (columnLength < 0) return std::vector(); @@ -477,8 +477,8 @@ Unordered_set_column::get_content(int columnLength) const template inline bool Unordered_set_column::is_non_zero(ID_index rowIndex) const { - Cell cell(rowIndex); - return column_.find(&cell) != column_.end(); + Entry entry(rowIndex); + return column_.find(&entry) != column_.end(); } template @@ -503,22 +503,22 @@ inline void Unordered_set_column::reorder(const Row_index_map& va Column_support newSet; - for (Cell* cell : column_) { + for (Entry* entry : column_) { if constexpr (Master_matrix::Option_list::has_row_access) { - RA_opt::unlink(cell); - if (columnIndex != static_cast(-1)) cell->set_column_index(columnIndex); + RA_opt::unlink(entry); + if (columnIndex != static_cast(-1)) entry->set_column_index(columnIndex); } - cell->set_row_index(valueMap.at(cell->get_row_index())); - newSet.insert(cell); + entry->set_row_index(valueMap.at(entry->get_row_index())); + newSet.insert(entry); if constexpr (Master_matrix::Option_list::has_row_access && Master_matrix::Option_list::has_intrusive_rows) // intrusive list - RA_opt::insert_cell(cell->get_row_index(), cell); + RA_opt::insert_entry(entry->get_row_index(), entry); } - // when row is a set, all cells have to be deleted first, to avoid colliding when inserting + // when row is a set, all entries have to be deleted first, to avoid colliding when inserting if constexpr (Master_matrix::Option_list::has_row_access && !Master_matrix::Option_list::has_intrusive_rows) { // set - for (Cell* cell : newSet) { - RA_opt::insert_cell(cell->get_row_index(), cell); + for (Entry* entry : newSet) { + RA_opt::insert_entry(entry->get_row_index(), entry); } } @@ -531,9 +531,9 @@ inline void Unordered_set_column::clear() static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Method not available for chain columns as a base element should not be empty."); - for (auto* cell : column_) { - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(cell); - cellPool_->destroy(cell); + for (auto* entry : column_) { + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(entry); + entryPool_->destroy(entry); } column_.clear(); @@ -545,12 +545,12 @@ inline void Unordered_set_column::clear(ID_index rowIndex) static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Method not available for chain columns."); - auto cell = cellPool_->construct(rowIndex); - auto it = column_.find(cell); + auto entry = entryPool_->construct(rowIndex); + auto it = column_.find(entry); if (it != column_.end()) { - _delete_cell(it); + _delete_entry(it); } - cellPool_->destroy(cell); + entryPool_->destroy(entry); } template @@ -563,7 +563,7 @@ inline typename Unordered_set_column::ID_index Unordered_set_colu if (column_.empty()) return -1; // linear search could be avoided with storing the pivot. But even then, some modifications of the column requires // the max, so not clear how much it is worth it. - return (*std::max_element(column_.begin(), column_.end(), CellPointerComp()))->get_row_index(); + return (*std::max_element(column_.begin(), column_.end(), EntryPointerComp()))->get_row_index(); } else { return Chain_opt::get_pivot(); } @@ -581,11 +581,11 @@ Unordered_set_column::get_pivot_value() const } else { if constexpr (Master_matrix::Option_list::is_of_boundary_type) { if (column_.empty()) return 0; - return (*std::max_element(column_.begin(), column_.end(), CellPointerComp()))->get_element(); + return (*std::max_element(column_.begin(), column_.end(), EntryPointerComp()))->get_element(); } else { if (Chain_opt::get_pivot() == static_cast(-1)) return Field_element(); - for (const Cell* cell : column_) { - if (cell->get_row_index() == Chain_opt::get_pivot()) return cell->get_element(); + for (const Entry* entry : column_) { + if (entry->get_row_index() == Chain_opt::get_pivot()) return entry->get_element(); } return Field_element(); // should never happen if chain column is used properly } @@ -619,10 +619,10 @@ inline typename Unordered_set_column::const_iterator Unordered_se } template -template -inline Unordered_set_column& Unordered_set_column::operator+=(const Cell_range& column) +template +inline Unordered_set_column& Unordered_set_column::operator+=(const Entry_range& column) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -675,9 +675,9 @@ inline Unordered_set_column& Unordered_set_column: if (val == Field_operators::get_multiplicative_identity()) return *this; - for (Cell* cell : column_) { - operators_->multiply_inplace(cell->get_element(), val); - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_cell(*cell); + for (Entry* entry : column_) { + operators_->multiply_inplace(entry->get_element(), val); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entry); } } @@ -685,11 +685,11 @@ inline Unordered_set_column& Unordered_set_column: } template -template +template inline Unordered_set_column& Unordered_set_column::multiply_target_and_add( - const Field_element& val, const Cell_range& column) + const Field_element& val, const Entry_range& column) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -747,11 +747,11 @@ inline Unordered_set_column& Unordered_set_column: } template -template +template inline Unordered_set_column& Unordered_set_column::multiply_source_and_add( - const Cell_range& column, const Field_element& val) + const Entry_range& column, const Field_element& val) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -809,20 +809,20 @@ inline Unordered_set_column& Unordered_set_column: Dim_opt::operator=(other); Chain_opt::operator=(other); - for (auto* cell : column_) { - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(cell); - cellPool_->destroy(cell); + for (auto* entry : column_) { + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(entry); + entryPool_->destroy(entry); } column_.clear(); operators_ = other.operators_; - cellPool_ = other.cellPool_; + entryPool_ = other.entryPool_; - for (const Cell* cell : other.column_) { + for (const Entry* entry : other.column_) { if constexpr (Master_matrix::Option_list::is_z2) { - _insert_cell(cell->get_row_index()); + _insert_entry(entry->get_row_index()); } else { - _insert_cell(cell->get_element(), cell->get_row_index()); + _insert_entry(entry->get_element(), entry->get_row_index()); } } @@ -830,65 +830,65 @@ inline Unordered_set_column& Unordered_set_column: } template -inline void Unordered_set_column::_delete_cell(typename Column_support::iterator& it) +inline void Unordered_set_column::_delete_entry(typename Column_support::iterator& it) { if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(*it); - cellPool_->destroy(*it); + entryPool_->destroy(*it); auto tmp = it++; // it = column_.erase(it); column_.erase(tmp); } template -inline typename Unordered_set_column::Cell* Unordered_set_column::_insert_cell( +inline typename Unordered_set_column::Entry* Unordered_set_column::_insert_entry( const Field_element& value, ID_index rowIndex) { if constexpr (Master_matrix::Option_list::has_row_access) { - Cell* newCell = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - newCell->set_element(value); - column_.insert(newCell); - RA_opt::insert_cell(rowIndex, newCell); - return newCell; + Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + newEntry->set_element(value); + column_.insert(newEntry); + RA_opt::insert_entry(rowIndex, newEntry); + return newEntry; } else { - Cell* newCell = cellPool_->construct(rowIndex); - newCell->set_element(value); - column_.insert(newCell); - return newCell; + Entry* newEntry = entryPool_->construct(rowIndex); + newEntry->set_element(value); + column_.insert(newEntry); + return newEntry; } } template -inline void Unordered_set_column::_insert_cell(ID_index rowIndex) +inline void Unordered_set_column::_insert_entry(ID_index rowIndex) { if constexpr (Master_matrix::Option_list::has_row_access) { - Cell* newCell = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - column_.insert(newCell); - RA_opt::insert_cell(rowIndex, newCell); + Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + column_.insert(newEntry); + RA_opt::insert_entry(rowIndex, newEntry); } else { - Cell* newCell = cellPool_->construct(rowIndex); - column_.insert(newCell); + Entry* newEntry = entryPool_->construct(rowIndex); + column_.insert(newEntry); } } template -template -inline bool Unordered_set_column::_add(const Cell_range& column) +template +inline bool Unordered_set_column::_add(const Entry_range& column) { return _generic_add( column, - [&](const Cell& oldCell, Cell* newCell) { - if constexpr (!Master_matrix::Option_list::is_z2) newCell->set_element(oldCell.get_element()); + [&](const Entry& oldEntry, Entry* newEntry) { + if constexpr (!Master_matrix::Option_list::is_z2) newEntry->set_element(oldEntry.get_element()); }, - [&](Cell* targetCell, const Cell& sourceCell) { + [&](Entry* targetEntry, const Entry& sourceEntry) { if constexpr (!Master_matrix::Option_list::is_z2) - operators_->add_inplace(targetCell->get_element(), sourceCell.get_element()); + operators_->add_inplace(targetEntry->get_element(), sourceEntry.get_element()); }); } template -template +template inline bool Unordered_set_column::_multiply_target_and_add(const Field_element& val, - const Cell_range& column) + const Entry_range& column) { if (val == 0u) { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { @@ -896,22 +896,22 @@ inline bool Unordered_set_column::_multiply_target_and_add(const // this would not only mess up the base, but also the pivots stored. } else { clear(); - for (const Cell& v : column) { - _insert_cell(v.get_element(), v.get_row_index()); + for (const Entry& v : column) { + _insert_entry(v.get_element(), v.get_row_index()); } return true; } } // because the column is unordered, I don't see a way to do both operations in one go - // without guarantees on the cell range... + // without guarantees on the entry range... operator*=(val); return _add(column); } template -template -inline bool Unordered_set_column::_multiply_source_and_add(const Cell_range& column, +template +inline bool Unordered_set_column::_multiply_source_and_add(const Entry_range& column, const Field_element& val) { if (val == 0u) { @@ -920,50 +920,50 @@ inline bool Unordered_set_column::_multiply_source_and_add(const return _generic_add( column, - [&](const Cell& oldCell, Cell* newCell) { - newCell->set_element(oldCell.get_element()); - operators_->multiply_inplace(newCell->get_element(), val); + [&](const Entry& oldEntry, Entry* newEntry) { + newEntry->set_element(oldEntry.get_element()); + operators_->multiply_inplace(newEntry->get_element(), val); }, - [&](Cell* targetCell, const Cell& sourceCell) { - operators_->multiply_and_add_inplace_back(sourceCell.get_element(), val, targetCell->get_element()); + [&](Entry* targetEntry, const Entry& sourceEntry) { + operators_->multiply_and_add_inplace_back(sourceEntry.get_element(), val, targetEntry->get_element()); }); } template -template -inline bool Unordered_set_column::_generic_add(const Cell_range& source, +template +inline bool Unordered_set_column::_generic_add(const Entry_range& source, F1&& process_source, F2&& update_target) { bool pivotIsZeroed = false; - for (const Cell& cell : source) { - Cell* newCell; + for (const Entry& entry : source) { + Entry* newEntry; if constexpr (Master_matrix::Option_list::has_row_access) { - newCell = cellPool_->construct(RA_opt::columnIndex_, cell.get_row_index()); + newEntry = entryPool_->construct(RA_opt::columnIndex_, entry.get_row_index()); } else { - newCell = cellPool_->construct(cell.get_row_index()); + newEntry = entryPool_->construct(entry.get_row_index()); } - auto res = column_.insert(newCell); + auto res = column_.insert(newEntry); if (res.second) { - process_source(cell, newCell); - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::insert_cell(cell.get_row_index(), newCell); + process_source(entry, newEntry); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::insert_entry(entry.get_row_index(), newEntry); } else { - cellPool_->destroy(newCell); + entryPool_->destroy(newEntry); if constexpr (Master_matrix::Option_list::is_z2) { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - if (cell.get_row_index() == Chain_opt::get_pivot()) pivotIsZeroed = true; + if (entry.get_row_index() == Chain_opt::get_pivot()) pivotIsZeroed = true; } - _delete_cell(res.first); + _delete_entry(res.first); } else { - update_target(*res.first, cell); + update_target(*res.first, entry); if ((*res.first)->get_element() == Field_operators::get_additive_identity()) { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { if ((*res.first)->get_row_index() == Chain_opt::get_pivot()) pivotIsZeroed = true; } - _delete_cell(res.first); + _delete_entry(res.first); } else { - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_cell(**res.first); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(**res.first); } } } @@ -981,15 +981,15 @@ inline bool Unordered_set_column::_generic_add(const Cell_range& * @brief Hash method for @ref Gudhi::persistence_matrix::Unordered_set_column. * * @tparam Master_matrix Template parameter of @ref Gudhi::persistence_matrix::Unordered_set_column. - * @tparam Cell_constructor Template parameter of @ref Gudhi::persistence_matrix::Unordered_set_column. + * @tparam Entry_constructor Template parameter of @ref Gudhi::persistence_matrix::Unordered_set_column. */ template struct std::hash> { std::size_t operator()(const Gudhi::persistence_matrix::Unordered_set_column& column) const { // can't use Gudhi::persistence_matrix::hash_column because unordered std::size_t seed = 0; - for (const auto& cell : column) { - seed ^= std::hash()(cell.get_row_index() * static_cast(cell.get_element())); + for (const auto& entry : column) { + seed ^= std::hash()(entry.get_row_index() * static_cast(entry.get_element())); } return seed; } diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/vector_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/vector_column.h index 135d610bee..8f7d4237bd 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/vector_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/vector_column.h @@ -38,13 +38,13 @@ namespace persistence_matrix { * * @brief Column class following the @ref PersistenceMatrixColumn concept. * - * Column based on a vector structure. The cells are always ordered by row index, but cells are removed by + * Column based on a vector structure. The entries are always ordered by row index, but entries are removed by * @ref PersistenceMatrixColumn::clear(PersistenceMatrixOptions::Index rowIndex) "clear(Index)" in a lazy way, * so erased values can still be in the underlying container. - * On the other hand, two cells will never have the same row index. + * On the other hand, two entries will never have the same row index. * * @tparam Master_matrix An instantiation of @ref Matrix from which all types and options are deduced. - * @tparam Cell_constructor Factory of @ref Cell classes. + * @tparam Entry_constructor Factory of @ref Entry classes. */ template class Vector_column : public Master_matrix::Row_access_option, @@ -57,13 +57,13 @@ class Vector_column : public Master_matrix::Row_access_option, using ID_index = typename Master_matrix::ID_index; using Dimension = typename Master_matrix::Dimension; using Field_element = typename Master_matrix::Element; - using Cell = typename Master_matrix::Matrix_cell; + using Entry = typename Master_matrix::Matrix_entry; using Column_settings = typename Master_matrix::Column_settings; private: using Field_operators = typename Master_matrix::Field_operators; - using Column_support = std::vector; - using Cell_constructor = typename Master_matrix::Cell_constructor; + using Column_support = std::vector; + using Entry_constructor = typename Master_matrix::Entry_constructor; public: using iterator = boost::indirect_iterator; @@ -104,7 +104,7 @@ class Vector_column : public Master_matrix::Row_access_option, template void reorder(const Row_index_map& valueMap, [[maybe_unused]] Index columnIndex = -1); void clear(); - // do not clear a cell to 0 if the cell was already 0, otherwise size/is_empty will be wrong. + // do not clear an entry to 0 if the entry was already 0, otherwise size/is_empty will be wrong. void clear(ID_index rowIndex); ID_index get_pivot(); @@ -119,19 +119,19 @@ class Vector_column : public Master_matrix::Row_access_option, reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; - template - Vector_column& operator+=(const Cell_range& column); + template + Vector_column& operator+=(const Entry_range& column); Vector_column& operator+=(Vector_column& column); Vector_column& operator*=(unsigned int v); // this = v * this + column - template - Vector_column& multiply_target_and_add(const Field_element& val, const Cell_range& column); + template + Vector_column& multiply_target_and_add(const Field_element& val, const Entry_range& column); Vector_column& multiply_target_and_add(const Field_element& val, Vector_column& column); // this = this + column * v - template - Vector_column& multiply_source_and_add(const Cell_range& column, const Field_element& val); + template + Vector_column& multiply_source_and_add(const Entry_range& column, const Field_element& val); Vector_column& multiply_source_and_add(Vector_column& column, const Field_element& val); std::size_t compute_hash_value(); @@ -209,7 +209,7 @@ class Vector_column : public Master_matrix::Row_access_option, col1.column_.swap(col2.column_); col1.erasedValues_.swap(col2.erasedValues_); std::swap(col1.operators_, col2.operators_); - std::swap(col1.cellPool_, col2.cellPool_); + std::swap(col1.entryPool_, col2.entryPool_); } private: @@ -221,11 +221,11 @@ class Vector_column : public Master_matrix::Row_access_option, std::unordered_set erasedValues_; // TODO: test other containers? Useless when clear(Index) is never // called, how much is it worth it? Field_operators* operators_; - Cell_constructor* cellPool_; + Entry_constructor* entryPool_; - template - friend void _generic_merge_cell_to_column(Column& targetColumn, - Cell_iterator& itSource, + template + friend void _generic_merge_entry_to_column(Column& targetColumn, + Entry_iterator& itSource, typename Column::Column_support::iterator& itTarget, F1&& process_target, F2&& process_source, @@ -233,20 +233,20 @@ class Vector_column : public Master_matrix::Row_access_option, F4&& update_target2, bool& pivotIsZeroed); - void _delete_cell(Cell* cell); - void _delete_cell(typename Column_support::iterator& it); - Cell* _insert_cell(const Field_element& value, ID_index rowIndex, Column_support& column); - void _insert_cell(ID_index rowIndex, Column_support& column); - void _update_cell(const Field_element& value, ID_index rowIndex, Index position); - void _update_cell(ID_index rowIndex, Index position); - template - bool _add(const Cell_range& column); - template - bool _multiply_target_and_add(const Field_element& val, const Cell_range& column); - template - bool _multiply_source_and_add(const Cell_range& column, const Field_element& val); - template - bool _generic_add(const Cell_range& source, + void _delete_entry(Entry* entry); + void _delete_entry(typename Column_support::iterator& it); + Entry* _insert_entry(const Field_element& value, ID_index rowIndex, Column_support& column); + void _insert_entry(ID_index rowIndex, Column_support& column); + void _update_entry(const Field_element& value, ID_index rowIndex, Index position); + void _update_entry(ID_index rowIndex, Index position); + template + bool _add(const Entry_range& column); + template + bool _multiply_target_and_add(const Field_element& val, const Entry_range& column); + template + bool _multiply_source_and_add(const Entry_range& column, const Field_element& val); + template + bool _generic_add(const Entry_range& source, F1&& process_target, F2&& process_source, F3&& update_target1, @@ -259,9 +259,9 @@ inline Vector_column::Vector_column(Column_settings* colSettings) Dim_opt(), Chain_opt(), operators_(nullptr), - cellPool_(colSettings == nullptr ? nullptr : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor)) { - if (operators_ == nullptr && cellPool_ == nullptr) return; // to allow default constructor which gives a dummy column + if (operators_ == nullptr && entryPool_ == nullptr) return; // to allow default constructor which gives a dummy column if constexpr (!Master_matrix::Option_list::is_z2) { operators_ = &(colSettings->operators); } @@ -275,7 +275,7 @@ inline Vector_column::Vector_column(const Container& nonZeroRowIn Chain_opt(), column_(nonZeroRowIndices.size(), nullptr), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); @@ -287,11 +287,11 @@ inline Vector_column::Vector_column(const Container& nonZeroRowIn Index i = 0; if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _update_cell(id, i++); + _update_entry(id, i++); } } else { for (const auto& p : nonZeroRowIndices) { - _update_cell(operators_->get_value(p.second), p.first, i++); + _update_entry(operators_->get_value(p.second), p.first, i++); } } } @@ -313,7 +313,7 @@ inline Vector_column::Vector_column(Index columnIndex, }()), column_(nonZeroRowIndices.size(), nullptr), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); @@ -325,11 +325,11 @@ inline Vector_column::Vector_column(Index columnIndex, Index i = 0; if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _update_cell(id, i++); + _update_entry(id, i++); } } else { for (const auto& p : nonZeroRowIndices) { - _update_cell(operators_->get_value(p.second), p.first, i++); + _update_entry(operators_->get_value(p.second), p.first, i++); } } } @@ -350,7 +350,7 @@ inline Vector_column::Vector_column(const Container& nonZeroRowIn }()), column_(nonZeroRowIndices.size(), nullptr), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { if constexpr (!Master_matrix::Option_list::is_z2) { operators_ = &(colSettings->operators); @@ -359,11 +359,11 @@ inline Vector_column::Vector_column(const Container& nonZeroRowIn Index i = 0; if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _update_cell(id, i++); + _update_entry(id, i++); } } else { for (const auto& p : nonZeroRowIndices) { - _update_cell(operators_->get_value(p.second), p.first, i++); + _update_entry(operators_->get_value(p.second), p.first, i++); } } } @@ -386,7 +386,7 @@ inline Vector_column::Vector_column(Index columnIndex, }()), column_(nonZeroRowIndices.size(), nullptr), operators_(nullptr), - cellPool_(&(colSettings->cellConstructor)) + entryPool_(&(colSettings->entryConstructor)) { if constexpr (!Master_matrix::Option_list::is_z2) { operators_ = &(colSettings->operators); @@ -395,11 +395,11 @@ inline Vector_column::Vector_column(Index columnIndex, Index i = 0; if constexpr (Master_matrix::Option_list::is_z2) { for (ID_index id : nonZeroRowIndices) { - _update_cell(id, i++); + _update_entry(id, i++); } } else { for (const auto& p : nonZeroRowIndices) { - _update_cell(operators_->get_value(p.second), p.first, i++); + _update_entry(operators_->get_value(p.second), p.first, i++); } } } @@ -412,7 +412,7 @@ inline Vector_column::Vector_column(const Vector_column& column, column_(column.column_.size(), nullptr), erasedValues_(column.erasedValues_), operators_(colSettings == nullptr ? column.operators_ : nullptr), - cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { static_assert(!Master_matrix::Option_list::has_row_access, "Simple copy constructor not available when row access option enabled. Please specify the new column " @@ -423,11 +423,11 @@ inline Vector_column::Vector_column(const Vector_column& column, } Index i = 0; - for (const Cell* cell : column.column_) { + for (const Entry* entry : column.column_) { if constexpr (Master_matrix::Option_list::is_z2) { - _update_cell(cell->get_row_index(), i++); + _update_entry(entry->get_row_index(), i++); } else { - _update_cell(cell->get_element(), cell->get_row_index(), i++); + _update_entry(entry->get_element(), entry->get_row_index(), i++); } } } @@ -444,18 +444,18 @@ inline Vector_column::Vector_column(const Vector_column& column, column_(column.column_.size(), nullptr), erasedValues_(column.erasedValues_), operators_(colSettings == nullptr ? column.operators_ : nullptr), - cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor)) + entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { if constexpr (!Master_matrix::Option_list::is_z2) { if (colSettings != nullptr) operators_ = &(colSettings->operators); } Index i = 0; - for (const Cell* cell : column.column_) { + for (const Entry* entry : column.column_) { if constexpr (Master_matrix::Option_list::is_z2) { - _update_cell(cell->get_row_index(), i++); + _update_entry(entry->get_row_index(), i++); } else { - _update_cell(cell->get_element(), cell->get_row_index(), i++); + _update_entry(entry->get_element(), entry->get_row_index(), i++); } } } @@ -468,14 +468,14 @@ inline Vector_column::Vector_column(Vector_column&& column) noexc column_(std::move(column.column_)), erasedValues_(std::move(column.erasedValues_)), operators_(std::exchange(column.operators_, nullptr)), - cellPool_(std::exchange(column.cellPool_, nullptr)) + entryPool_(std::exchange(column.entryPool_, nullptr)) {} template inline Vector_column::~Vector_column() { - for (auto* cell : column_) { - _delete_cell(cell); + for (auto* entry : column_) { + _delete_entry(entry); } } @@ -509,9 +509,9 @@ inline bool Vector_column::is_non_zero(ID_index rowIndex) const if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) if (erasedValues_.find(rowIndex) != erasedValues_.end()) return false; - Cell cell(rowIndex); - return std::binary_search(column_.begin(), column_.end(), &cell, - [](const Cell* a, const Cell* b) { return a->get_row_index() < b->get_row_index(); }); + Entry entry(rowIndex); + return std::binary_search(column_.begin(), column_.end(), &entry, + [](const Entry* a, const Entry* b) { return a->get_row_index() < b->get_row_index(); }); } template @@ -544,47 +544,47 @@ inline void Vector_column::reorder(const Row_index_map& valueMap, "Method not available for chain columns."); if (erasedValues_.empty()) { // to avoid useless push_backs. - for (Cell* cell : column_) { + for (Entry* entry : column_) { if constexpr (Master_matrix::Option_list::has_row_access) { - RA_opt::unlink(cell); - if (columnIndex != static_cast(-1)) cell->set_column_index(columnIndex); + RA_opt::unlink(entry); + if (columnIndex != static_cast(-1)) entry->set_column_index(columnIndex); } - cell->set_row_index(valueMap.at(cell->get_row_index())); + entry->set_row_index(valueMap.at(entry->get_row_index())); if constexpr (Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access) - RA_opt::insert_cell(cell->get_row_index(), cell); + RA_opt::insert_entry(entry->get_row_index(), entry); } - // all cells have to be deleted first, to avoid problem with insertion when row is a set + // all entries have to be deleted first, to avoid problem with insertion when row is a set if constexpr (!Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access) { - for (Cell* cell : column_) { - RA_opt::insert_cell(cell->get_row_index(), cell); + for (Entry* entry : column_) { + RA_opt::insert_entry(entry->get_row_index(), entry); } } - std::sort(column_.begin(), column_.end(), [](const Cell* c1, const Cell* c2) { return *c1 < *c2; }); + std::sort(column_.begin(), column_.end(), [](const Entry* c1, const Entry* c2) { return *c1 < *c2; }); } else { Column_support newColumn; - for (Cell* cell : column_) { - if (erasedValues_.find(cell->get_row_index()) == erasedValues_.end()) { + for (Entry* entry : column_) { + if (erasedValues_.find(entry->get_row_index()) == erasedValues_.end()) { if constexpr (Master_matrix::Option_list::has_row_access) { - RA_opt::unlink(cell); - if (columnIndex != static_cast(-1)) cell->set_column_index(columnIndex); + RA_opt::unlink(entry); + if (columnIndex != static_cast(-1)) entry->set_column_index(columnIndex); } - cell->set_row_index(valueMap.at(cell->get_row_index())); - newColumn.push_back(cell); + entry->set_row_index(valueMap.at(entry->get_row_index())); + newColumn.push_back(entry); if constexpr (Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access) - RA_opt::insert_cell(cell->get_row_index(), cell); + RA_opt::insert_entry(entry->get_row_index(), entry); } else { - _delete_cell(cell); + _delete_entry(entry); } } - // all cells have to be deleted first, to avoid problem with insertion when row is a set + // all entries have to be deleted first, to avoid problem with insertion when row is a set if constexpr (!Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access) { - for (Cell* cell : column_) { - RA_opt::insert_cell(cell->get_row_index(), cell); + for (Entry* entry : column_) { + RA_opt::insert_entry(entry->get_row_index(), entry); } } - std::sort(newColumn.begin(), newColumn.end(), [](const Cell* c1, const Cell* c2) { return *c1 < *c2; }); + std::sort(newColumn.begin(), newColumn.end(), [](const Entry* c1, const Entry* c2) { return *c1 < *c2; }); erasedValues_.clear(); column_.swap(newColumn); } @@ -596,9 +596,9 @@ inline void Vector_column::clear() static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Method not available for chain columns as a base element should not be empty."); - for (auto* cell : column_) { - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(cell); - cellPool_->destroy(cell); + for (auto* entry : column_) { + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(entry); + entryPool_->destroy(entry); } column_.clear(); @@ -627,7 +627,7 @@ inline typename Vector_column::ID_index Vector_columnget_row_index()); while (!column_.empty() && it != erasedValues_.end()) { erasedValues_.erase(it); - _delete_cell(column_.back()); + _delete_entry(column_.back()); column_.pop_back(); if (!column_.empty()) it = erasedValues_.find(column_.back()->get_row_index()); } @@ -655,7 +655,7 @@ inline typename Vector_column::Field_element Vector_columnget_row_index()); while (!column_.empty() && it != erasedValues_.end()) { erasedValues_.erase(it); - _delete_cell(column_.back()); + _delete_entry(column_.back()); column_.pop_back(); if (!column_.empty()) it = erasedValues_.find(column_.back()->get_row_index()); } @@ -664,8 +664,8 @@ inline typename Vector_column::Field_element Vector_columnget_element(); } else { if (Chain_opt::get_pivot() == static_cast(-1)) return Field_element(); - for (const Cell* cell : column_) { - if (cell->get_row_index() == Chain_opt::get_pivot()) return cell->get_element(); + for (const Entry* entry : column_) { + if (entry->get_row_index() == Chain_opt::get_pivot()) return entry->get_element(); } return Field_element(); // should never happen if chain column is used properly } @@ -723,10 +723,10 @@ inline typename Vector_column::const_reverse_iterator Vector_colu } template -template -inline Vector_column& Vector_column::operator+=(const Cell_range& column) +template +inline Vector_column& Vector_column::operator+=(const Entry_range& column) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -778,9 +778,9 @@ inline Vector_column& Vector_column::operator*=(un if (val == Field_operators::get_multiplicative_identity()) return *this; - for (Cell* cell : column_) { - operators_->multiply_inplace(cell->get_element(), val); - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_cell(*cell); + for (Entry* entry : column_) { + operators_->multiply_inplace(entry->get_element(), val); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entry); } } @@ -788,11 +788,11 @@ inline Vector_column& Vector_column::operator*=(un } template -template +template inline Vector_column& Vector_column::multiply_target_and_add(const Field_element& val, - const Cell_range& column) + const Entry_range& column) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -850,11 +850,11 @@ inline Vector_column& Vector_column::multiply_targ } template -template -inline Vector_column& Vector_column::multiply_source_and_add(const Cell_range& column, +template +inline Vector_column& Vector_column::multiply_source_and_add(const Entry_range& column, const Field_element& val) { - static_assert((!Master_matrix::isNonBasic || std::is_same_v), + static_assert((!Master_matrix::isNonBasic || std::is_same_v), "For boundary columns, the range has to be a column of same type to help ensure the validity of the " "base element."); // could be removed, if we give the responsibility to the user. static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), @@ -911,8 +911,8 @@ inline Vector_column& Vector_column::operator=(con Dim_opt::operator=(other); Chain_opt::operator=(other); - auto tmpPool = cellPool_; - cellPool_ = other.cellPool_; + auto tmpPool = entryPool_; + entryPool_ = other.entryPool_; while (column_.size() > other.column_.size()) { if (column_.back() != nullptr) { @@ -924,15 +924,15 @@ inline Vector_column& Vector_column::operator=(con column_.resize(other.column_.size(), nullptr); Index i = 0; - for (const Cell* cell : other.column_) { + for (const Entry* entry : other.column_) { if (column_[i] != nullptr) { if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(column_[i]); tmpPool->destroy(column_[i]); } if constexpr (Master_matrix::Option_list::is_z2) { - _update_cell(cell->get_row_index(), i++); + _update_entry(entry->get_row_index(), i++); } else { - _update_cell(cell->get_element(), cell->get_row_index(), i++); + _update_entry(entry->get_element(), entry->get_row_index(), i++); } } erasedValues_ = other.erasedValues_; @@ -945,9 +945,9 @@ template inline std::size_t Vector_column::compute_hash_value() { std::size_t seed = 0; - for (Cell* cell : column_) { - if (erasedValues_.find(cell->get_row_index()) == erasedValues_.end()) { - seed ^= std::hash()(cell->get_row_index() * static_cast(cell->get_element())) + + for (Entry* entry : column_) { + if (erasedValues_.find(entry->get_row_index()) == erasedValues_.end()) { + seed ^= std::hash()(entry->get_row_index() * static_cast(entry->get_element())) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } } @@ -955,89 +955,89 @@ inline std::size_t Vector_column::compute_hash_value() } template -inline void Vector_column::_delete_cell(Cell* cell) +inline void Vector_column::_delete_entry(Entry* entry) { - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(cell); - cellPool_->destroy(cell); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(entry); + entryPool_->destroy(entry); } template -inline void Vector_column::_delete_cell(typename Column_support::iterator& it) +inline void Vector_column::_delete_entry(typename Column_support::iterator& it) { - _delete_cell(*it); + _delete_entry(*it); ++it; } template -inline typename Vector_column::Cell* Vector_column::_insert_cell( +inline typename Vector_column::Entry* Vector_column::_insert_entry( const Field_element& value, ID_index rowIndex, Column_support& column) { if constexpr (Master_matrix::Option_list::has_row_access) { - Cell* newCell = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - newCell->set_element(value); - column.push_back(newCell); - RA_opt::insert_cell(rowIndex, newCell); - return newCell; + Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + newEntry->set_element(value); + column.push_back(newEntry); + RA_opt::insert_entry(rowIndex, newEntry); + return newEntry; } else { - Cell* newCell = cellPool_->construct(rowIndex); - newCell->set_element(value); - column.push_back(newCell); - return newCell; + Entry* newEntry = entryPool_->construct(rowIndex); + newEntry->set_element(value); + column.push_back(newEntry); + return newEntry; } } template -inline void Vector_column::_insert_cell(ID_index rowIndex, Column_support& column) +inline void Vector_column::_insert_entry(ID_index rowIndex, Column_support& column) { if constexpr (Master_matrix::Option_list::has_row_access) { - Cell* newCell = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - column.push_back(newCell); - RA_opt::insert_cell(rowIndex, newCell); + Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + column.push_back(newEntry); + RA_opt::insert_entry(rowIndex, newEntry); } else { - Cell* newCell = cellPool_->construct(rowIndex); - column.push_back(newCell); + Entry* newEntry = entryPool_->construct(rowIndex); + column.push_back(newEntry); } } template -inline void Vector_column::_update_cell(const Field_element& value, ID_index rowIndex, Index position) +inline void Vector_column::_update_entry(const Field_element& value, ID_index rowIndex, Index position) { if constexpr (Master_matrix::Option_list::has_row_access) { - Cell* newCell = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - newCell->set_element(value); - column_[position] = newCell; - RA_opt::insert_cell(rowIndex, newCell); + Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + newEntry->set_element(value); + column_[position] = newEntry; + RA_opt::insert_entry(rowIndex, newEntry); } else { - column_[position] = cellPool_->construct(rowIndex); + column_[position] = entryPool_->construct(rowIndex); column_[position]->set_element(value); } } template -inline void Vector_column::_update_cell(ID_index rowIndex, Index position) +inline void Vector_column::_update_entry(ID_index rowIndex, Index position) { if constexpr (Master_matrix::Option_list::has_row_access) { - Cell* newCell = cellPool_->construct(RA_opt::columnIndex_, rowIndex); - column_[position] = newCell; - RA_opt::insert_cell(rowIndex, newCell); + Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex); + column_[position] = newEntry; + RA_opt::insert_entry(rowIndex, newEntry); } else { - column_[position] = cellPool_->construct(rowIndex); + column_[position] = entryPool_->construct(rowIndex); } } template -template -inline bool Vector_column::_add(const Cell_range& column) +template +inline bool Vector_column::_add(const Entry_range& column) { if (column.begin() == column.end()) return false; if (column_.empty()) { // chain should never enter here. column_.resize(column.size()); Index i = 0; - for (const Cell& cell : column) { + for (const Entry& entry : column) { if constexpr (Master_matrix::Option_list::is_z2) { - _update_cell(cell.get_row_index(), i++); + _update_entry(entry.get_row_index(), i++); } else { - _update_cell(cell.get_element(), cell.get_row_index(), i++); + _update_entry(entry.get_element(), entry.get_row_index(), i++); } } return true; @@ -1048,20 +1048,20 @@ inline bool Vector_column::_add(const Cell_range& column) auto pivotIsZeroed = _generic_add( column, - [&](Cell* cellTarget) { newColumn.push_back(cellTarget); }, - [&](typename Cell_range::const_iterator& itSource, + [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }, + [&](typename Entry_range::const_iterator& itSource, [[maybe_unused]] const typename Column_support::iterator& itTarget) { if constexpr (Master_matrix::Option_list::is_z2) { - _insert_cell(itSource->get_row_index(), newColumn); + _insert_entry(itSource->get_row_index(), newColumn); } else { - _insert_cell(itSource->get_element(), itSource->get_row_index(), newColumn); + _insert_entry(itSource->get_element(), itSource->get_row_index(), newColumn); } }, - [&](Field_element& targetElement, typename Cell_range::const_iterator& itSource) { + [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) { if constexpr (!Master_matrix::Option_list::is_z2) operators_->add_inplace(targetElement, itSource->get_element()); }, - [&](Cell* cellTarget) { newColumn.push_back(cellTarget); } + [&](Entry* entryTarget) { newColumn.push_back(entryTarget); } ); column_.swap(newColumn); @@ -1070,8 +1070,8 @@ inline bool Vector_column::_add(const Cell_range& column) } template -template -inline bool Vector_column::_multiply_target_and_add(const Field_element& val, const Cell_range& column) +template +inline bool Vector_column::_multiply_target_and_add(const Field_element& val, const Entry_range& column) { if (val == 0u) { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { @@ -1084,14 +1084,14 @@ inline bool Vector_column::_multiply_target_and_add(const Field_e if (column_.empty()) { // chain should never enter here. column_.resize(column.size()); Index i = 0; - for (const Cell& cell : column) { + for (const Entry& entry : column) { if constexpr (Master_matrix::Option_list::is_z2) { - _update_cell(cell.get_row_index(), i++); + _update_entry(entry.get_row_index(), i++); } else { - _update_cell(cell.get_element(), cell.get_row_index(), i++); + _update_entry(entry.get_element(), entry.get_row_index(), i++); } } - if constexpr (std::is_same_v >) erasedValues_ = column.erasedValues_; + if constexpr (std::is_same_v >) erasedValues_ = column.erasedValues_; return true; } @@ -1100,18 +1100,18 @@ inline bool Vector_column::_multiply_target_and_add(const Field_e auto pivotIsZeroed = _generic_add( column, - [&](Cell* cellTarget) { - operators_->multiply_inplace(cellTarget->get_element(), val); - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_cell(*cellTarget); - newColumn.push_back(cellTarget); + [&](Entry* entryTarget) { + operators_->multiply_inplace(entryTarget->get_element(), val); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entryTarget); + newColumn.push_back(entryTarget); }, - [&](typename Cell_range::const_iterator& itSource, const typename Column_support::iterator& itTarget) { - _insert_cell(itSource->get_element(), itSource->get_row_index(), newColumn); + [&](typename Entry_range::const_iterator& itSource, const typename Column_support::iterator& itTarget) { + _insert_entry(itSource->get_element(), itSource->get_row_index(), newColumn); }, - [&](Field_element& targetElement, typename Cell_range::const_iterator& itSource) { + [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) { operators_->multiply_and_add_inplace_front(targetElement, val, itSource->get_element()); }, - [&](Cell* cellTarget) { newColumn.push_back(cellTarget); } + [&](Entry* entryTarget) { newColumn.push_back(entryTarget); } ); column_.swap(newColumn); @@ -1120,8 +1120,8 @@ inline bool Vector_column::_multiply_target_and_add(const Field_e } template -template -inline bool Vector_column::_multiply_source_and_add(const Cell_range& column, const Field_element& val) +template +inline bool Vector_column::_multiply_source_and_add(const Entry_range& column, const Field_element& val) { if (val == 0u || column.begin() == column.end()) { return false; @@ -1132,16 +1132,16 @@ inline bool Vector_column::_multiply_source_and_add(const Cell_ra auto pivotIsZeroed = _generic_add( column, - [&](Cell* cellTarget) { newColumn.push_back(cellTarget); }, - [&](typename Cell_range::const_iterator& itSource, const typename Column_support::iterator& itTarget) { - Cell* newCell = _insert_cell(itSource->get_element(), itSource->get_row_index(), newColumn); - operators_->multiply_inplace(newCell->get_element(), val); - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_cell(*newCell); + [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }, + [&](typename Entry_range::const_iterator& itSource, const typename Column_support::iterator& itTarget) { + Entry* newEntry = _insert_entry(itSource->get_element(), itSource->get_row_index(), newColumn); + operators_->multiply_inplace(newEntry->get_element(), val); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*newEntry); }, - [&](Field_element& targetElement, typename Cell_range::const_iterator& itSource) { + [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) { operators_->multiply_and_add_inplace_back(itSource->get_element(), val, targetElement); }, - [&](Cell* cellTarget) { newColumn.push_back(cellTarget); } + [&](Entry* entryTarget) { newColumn.push_back(entryTarget); } ); column_.swap(newColumn); @@ -1150,8 +1150,8 @@ inline bool Vector_column::_multiply_source_and_add(const Cell_ra } template -template -inline bool Vector_column::_generic_add(const Cell_range& column, +template +inline bool Vector_column::_generic_add(const Entry_range& column, F1&& process_target, F2&& process_source, F3&& update_target1, @@ -1160,13 +1160,13 @@ inline bool Vector_column::_generic_add(const Cell_range& column, auto updateTargetIterator = [&](typename Column_support::iterator& itTarget) { if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) { while (itTarget != column_.end() && erasedValues_.find((*itTarget)->get_row_index()) != erasedValues_.end()) { - _delete_cell(*itTarget); + _delete_entry(*itTarget); ++itTarget; } } }; - auto updateSourceIterator = [&](typename Cell_range::const_iterator& itSource) { - if constexpr (std::is_same_v > && + auto updateSourceIterator = [&](typename Entry_range::const_iterator& itSource) { + if constexpr (std::is_same_v > && (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type)) { while (itSource != column.end() && column.erasedValues_.find(itSource->get_row_index()) != column.erasedValues_.end()) @@ -1183,9 +1183,9 @@ inline bool Vector_column::_generic_add(const Cell_range& column, updateSourceIterator(itSource); if (itTarget == column_.end() || itSource == column.end()) break; - _generic_merge_cell_to_column(*this, itSource, itTarget, - process_target, process_source, update_target1, update_target2, - pivotIsZeroed); + _generic_merge_entry_to_column(*this, itSource, itTarget, + process_target, process_source, update_target1, update_target2, + pivotIsZeroed); } while (itSource != column.end()) { @@ -1218,7 +1218,7 @@ inline bool Vector_column::_generic_add(const Cell_range& column, * @brief Hash method for @ref Gudhi::persistence_matrix::Vector_column. * * @tparam Master_matrix Template parameter of @ref Gudhi::persistence_matrix::Vector_column. - * @tparam Cell_constructor Template parameter of @ref Gudhi::persistence_matrix::Vector_column. + * @tparam Entry_constructor Template parameter of @ref Gudhi::persistence_matrix::Vector_column. */ template struct std::hash > { diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/matrix_row_access.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/matrix_row_access.h index cb1f92ba65..925f573f7b 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/matrix_row_access.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/matrix_row_access.h @@ -42,8 +42,8 @@ struct Dummy_matrix_row_access * * @brief Class managing the row access for the inheriting matrix. * - * @tparam Row Either boost::intrusive::list if @ref PersistenceMatrixOptions::has_intrusive_rows - * is true, or std::set otherwise. + * @tparam Row Either boost::intrusive::list if @ref PersistenceMatrixOptions::has_intrusive_rows + * is true, or std::set otherwise. * @tparam Row_container Either std::map if @ref PersistenceMatrixOptions::has_removable_rows is * true, or std::vector otherwise. * @tparam has_removable_rows Value of @ref PersistenceMatrixOptions::has_removable_rows. diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_rep_cycles.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_rep_cycles.h index 330eec4d65..ea77ccb9e8 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_rep_cycles.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_rep_cycles.h @@ -148,8 +148,8 @@ inline void RU_representative_cycles::update_representative_cycle representativeCycles_.clear(); representativeCycles_.resize(c); for (Index i = 0; i < _matrix()->mirrorMatrixU_.get_number_of_columns(); i++) { - for (const auto& cell : _matrix()->mirrorMatrixU_.get_column(i)) { - auto idx = birthToCycle_[cell.get_row_index()]; + for (const auto& entry : _matrix()->mirrorMatrixU_.get_column(i)) { + auto idx = birthToCycle_[entry.get_row_index()]; if (idx != static_cast(-1)) { representativeCycles_[idx].push_back(i); } @@ -161,8 +161,8 @@ inline void RU_representative_cycles::update_representative_cycle for (Index i = 0; i < _matrix()->reducedMatrixR_.get_number_of_columns(); i++) { if (_matrix()->reducedMatrixR_.is_zero_column(i)) { representativeCycles_.push_back(Cycle()); - for (const auto& cell : _matrix()->mirrorMatrixU_.get_column(i)) { - representativeCycles_.back().push_back(cell.get_row_index()); + for (const auto& entry : _matrix()->mirrorMatrixU_.get_column(i)) { + representativeCycles_.back().push_back(entry.get_row_index()); } if constexpr (std::is_same_v || std::is_same_v::vine_swap_with_z_eq_1_case(Pos_index in bool iiIsPositive = _matrix()->reducedMatrixR_.is_zero_column(index + 1); if (iIsPositive && iiIsPositive) { - _matrix()->mirrorMatrixU_.zero_cell(index, _get_row_id_from_position(index + 1)); + _matrix()->mirrorMatrixU_.zero_entry(index, _get_row_id_from_position(index + 1)); return _positive_vine_swap(index); } else if (!iIsPositive && !iiIsPositive) { return _negative_vine_swap(index); @@ -228,14 +228,14 @@ inline bool RU_vine_swap::vine_swap(Pos_index index) _swap_at_index(index); return true; } - if (!_matrix()->mirrorMatrixU_.is_zero_cell(index, _get_row_id_from_position(index + 1))) { - _matrix()->mirrorMatrixU_.zero_cell(index, _get_row_id_from_position(index + 1)); + if (!_matrix()->mirrorMatrixU_.is_zero_entry(index, _get_row_id_from_position(index + 1))) { + _matrix()->mirrorMatrixU_.zero_entry(index, _get_row_id_from_position(index + 1)); } return _positive_vine_swap(index); } else if (!iIsPositive && !iiIsPositive) { if (_matrix()->reducedMatrixR_.get_column_dimension(index) != _matrix()->reducedMatrixR_.get_column_dimension(index + 1) || - _matrix()->mirrorMatrixU_.is_zero_cell(index, _get_row_id_from_position(index + 1))) { + _matrix()->mirrorMatrixU_.is_zero_entry(index, _get_row_id_from_position(index + 1))) { _negative_transpose(index); _swap_at_index(index); return true; @@ -244,7 +244,7 @@ inline bool RU_vine_swap::vine_swap(Pos_index index) } else if (iIsPositive && !iiIsPositive) { if (_matrix()->reducedMatrixR_.get_column_dimension(index) != _matrix()->reducedMatrixR_.get_column_dimension(index + 1) || - _matrix()->mirrorMatrixU_.is_zero_cell(index, _get_row_id_from_position(index + 1))) { + _matrix()->mirrorMatrixU_.is_zero_entry(index, _get_row_id_from_position(index + 1))) { _positive_negative_transpose(index); _swap_at_index(index); return true; @@ -253,7 +253,7 @@ inline bool RU_vine_swap::vine_swap(Pos_index index) } else { if (_matrix()->reducedMatrixR_.get_column_dimension(index) != _matrix()->reducedMatrixR_.get_column_dimension(index + 1) || - _matrix()->mirrorMatrixU_.is_zero_cell(index, _get_row_id_from_position(index + 1))) { + _matrix()->mirrorMatrixU_.is_zero_entry(index, _get_row_id_from_position(index + 1))) { _negative_positive_transpose(index); _swap_at_index(index); return true; @@ -392,7 +392,7 @@ inline bool RU_vine_swap::_positive_vine_swap(Index columnIndex) const Pos_index iiDeath = _get_death(columnIndex + 1); if (iDeath != static_cast(-1) && iiDeath != static_cast(-1) && - !(_matrix()->reducedMatrixR_.is_zero_cell(iiDeath, _get_row_id_from_position(columnIndex)))) { + !(_matrix()->reducedMatrixR_.is_zero_entry(iiDeath, _get_row_id_from_position(columnIndex)))) { if (iDeath < iiDeath) { _swap_at_index(columnIndex); _add_to(iDeath, iiDeath); @@ -408,7 +408,7 @@ inline bool RU_vine_swap::_positive_vine_swap(Index columnIndex) _swap_at_index(columnIndex); if (iDeath != static_cast(-1) || iiDeath == static_cast(-1) || - _matrix()->reducedMatrixR_.is_zero_cell(iiDeath, _get_row_id_from_position(columnIndex + 1))) { + _matrix()->reducedMatrixR_.is_zero_entry(iiDeath, _get_row_id_from_position(columnIndex + 1))) { _positive_transpose(columnIndex); return true; } @@ -437,7 +437,7 @@ inline bool RU_vine_swap::_negative_vine_swap(Index columnIndex) template inline bool RU_vine_swap::_positive_negative_vine_swap(Index columnIndex) { - _matrix()->mirrorMatrixU_.zero_cell(columnIndex, _get_row_id_from_position(columnIndex + 1)); + _matrix()->mirrorMatrixU_.zero_entry(columnIndex, _get_row_id_from_position(columnIndex + 1)); _swap_at_index(columnIndex); _positive_negative_transpose(columnIndex); diff --git a/src/Persistence_matrix/include/gudhi/persistence_matrix_options.h b/src/Persistence_matrix/include/gudhi/persistence_matrix_options.h index 276dad72fa..58f7bc117c 100644 --- a/src/Persistence_matrix/include/gudhi/persistence_matrix_options.h +++ b/src/Persistence_matrix/include/gudhi/persistence_matrix_options.h @@ -28,16 +28,16 @@ namespace persistence_matrix { * @brief List of column types. */ enum class Column_types { - LIST, /**< @ref List_column "": Underlying container is a std::list<@ref Cell*>. */ - SET, /**< @ref Set_column "": Underlying container is a std::set<@ref Cell*>. */ - HEAP, /**< @ref Heap_column "": Underlying container is a std::vector<@ref Cell*> ordered as a heap. + LIST, /**< @ref List_column "": Underlying container is a std::list<@ref Entry*>. */ + SET, /**< @ref Set_column "": Underlying container is a std::set<@ref Entry*>. */ + HEAP, /**< @ref Heap_column "": Underlying container is a std::vector<@ref Entry*> ordered as a heap. Is not compatible with row access and column compression. */ - VECTOR, /**< @ref Vector_column "": Underlying container is a std::vector<@ref Cell*> + VECTOR, /**< @ref Vector_column "": Underlying container is a std::vector<@ref Entry*> with a lazy removal method. */ - NAIVE_VECTOR, /**< @ref Naive_vector_column "": Underlying container is a std::vector<@ref Cell*>. */ - UNORDERED_SET, /**< @ref Unordered_set_column "": Underlying container is a std::unordered_set<@ref Cell*>. */ - INTRUSIVE_LIST, /**< @ref Intrusive_list_column "": Underlying container is a boost::intrusive::list<@ref Cell>. */ - INTRUSIVE_SET /**< @ref Intrusive_set_column "": Underlying container is a boost::intrusive::set<@ref Cell>. */ + NAIVE_VECTOR, /**< @ref Naive_vector_column "": Underlying container is a std::vector<@ref Entry*>. */ + UNORDERED_SET, /**< @ref Unordered_set_column "": Underlying container is a std::unordered_set<@ref Entry*>. */ + INTRUSIVE_LIST, /**< @ref Intrusive_list_column "": Underlying container is a boost::intrusive::list<@ref Entry>. */ + INTRUSIVE_SET /**< @ref Intrusive_set_column "": Underlying container is a boost::intrusive::set<@ref Entry>. */ }; /** diff --git a/src/Persistence_matrix/test/pm_column_tests.h b/src/Persistence_matrix/test/pm_column_tests.h index 29b4bea883..01d8759743 100644 --- a/src/Persistence_matrix/test/pm_column_tests.h +++ b/src/Persistence_matrix/test/pm_column_tests.h @@ -28,11 +28,11 @@ std::vector > get_ordered_column_contents(std::vector::type> > ordCol(matrix.size()); for (unsigned int i = 0; i < matrix.size(); ++i) { Column& col = matrix[i]; - for (auto& cell : col) { + for (auto& entry : col) { if constexpr (is_z2()) { - ordCol[i].insert(cell.get_row_index()); + ordCol[i].insert(entry.get_row_index()); } else { - ordCol[i].insert({cell.get_row_index(), cell.get_element()}); + ordCol[i].insert({entry.get_row_index(), entry.get_element()}); } } } @@ -47,12 +47,12 @@ std::vector > get_ordered_rows(std::vector& matri std::pair >::type> > rows; for (Column& col : matrix) { - for (auto& cell : col) { - if (cell.get_row_index() >= rows.size()) rows.resize(cell.get_row_index() + 1); + for (auto& entry : col) { + if (entry.get_row_index() >= rows.size()) rows.resize(entry.get_row_index() + 1); if constexpr (is_z2()) { - rows[cell.get_row_index()].insert(cell.get_column_index()); + rows[entry.get_row_index()].insert(entry.get_column_index()); } else { - rows[cell.get_row_index()].insert({cell.get_column_index(), cell.get_element()}); + rows[entry.get_row_index()].insert({entry.get_column_index(), entry.get_element()}); } } } @@ -166,11 +166,11 @@ std::vector >::type> > build_rows() { - using cell_type = typename std::conditional(), - unsigned int, - std::pair - >::type; - using Container = std::vector; + using entry_type = typename std::conditional(), + unsigned int, + std::pair + >::type; + using Container = std::vector; std::vector rows(7); if constexpr (is_z2()) { @@ -200,11 +200,11 @@ std::vector >::type> > build_column_values() { - using cell_type = typename std::conditional(), - unsigned int, - std::pair - >::type; - using Container = std::vector; + using entry_type = typename std::conditional(), + unsigned int, + std::pair + >::type; + using Container = std::vector; std::vector columns(6); if constexpr (is_z2()) { @@ -228,11 +228,11 @@ std::vector void column_test_common_constructors() { - using cell_type = typename std::conditional(), - unsigned int, - std::pair - >::type; - using Container = std::vector; + using entry_type = typename std::conditional(), + unsigned int, + std::pair + >::type; + using Container = std::vector; Container cont1, cont2; typename Column::Column_settings settings(5); @@ -278,9 +278,9 @@ void column_test_common_constructors() { BOOST_CHECK_EQUAL(rows.size(), 0); } -template +template void column_test_common_content_access(Column& col, - const std::set& setcont, + const std::set& setcont, const std::vector& veccont) { BOOST_CHECK(get_column_content_via_iterators(col) == setcont); BOOST_CHECK(col.get_content(veccont.size()) == veccont); @@ -519,18 +519,18 @@ void column_test_row_access_constructors(std::vector& matrix, Row_contai for (auto& r : rows) { if constexpr (Column::Master::Option_list::has_removable_rows) { if (!r.second.empty()) { - auto& cell = *r.second.rbegin(); - if (cell.get_row_index() == 0 || cell.get_row_index() == 1 || cell.get_row_index() == 3 || - cell.get_row_index() == 5) { - BOOST_CHECK_EQUAL(cell.get_column_index(), 6); + auto& entry = *r.second.rbegin(); + if (entry.get_row_index() == 0 || entry.get_row_index() == 1 || entry.get_row_index() == 3 || + entry.get_row_index() == 5) { + BOOST_CHECK_EQUAL(entry.get_column_index(), 6); } } } else { if (!r.empty()) { - auto& cell = *r.rbegin(); - if (cell.get_row_index() == 0 || cell.get_row_index() == 1 || cell.get_row_index() == 3 || - cell.get_row_index() == 5) { - BOOST_CHECK_EQUAL(cell.get_column_index(), 6); + auto& entry = *r.rbegin(); + if (entry.get_row_index() == 0 || entry.get_row_index() == 1 || entry.get_row_index() == 3 || + entry.get_row_index() == 5) { + BOOST_CHECK_EQUAL(entry.get_column_index(), 6); } } } @@ -543,18 +543,18 @@ void column_test_row_access_constructors(std::vector& matrix, Row_contai for (auto& r : rows) { if constexpr (Column::Master::Option_list::has_removable_rows) { if (!r.second.empty()) { - auto& cell = *r.second.rbegin(); - if (cell.get_row_index() == 0 || cell.get_row_index() == 1 || cell.get_row_index() == 3 || - cell.get_row_index() == 5) { - BOOST_CHECK_EQUAL(cell.get_column_index(), 6); + auto& entry = *r.second.rbegin(); + if (entry.get_row_index() == 0 || entry.get_row_index() == 1 || entry.get_row_index() == 3 || + entry.get_row_index() == 5) { + BOOST_CHECK_EQUAL(entry.get_column_index(), 6); } } } else { if (!r.empty()) { - auto& cell = *r.rbegin(); - if (cell.get_row_index() == 0 || cell.get_row_index() == 1 || cell.get_row_index() == 3 || - cell.get_row_index() == 5) { - BOOST_CHECK_EQUAL(cell.get_column_index(), 6); + auto& entry = *r.rbegin(); + if (entry.get_row_index() == 0 || entry.get_row_index() == 1 || entry.get_row_index() == 3 || + entry.get_row_index() == 5) { + BOOST_CHECK_EQUAL(entry.get_column_index(), 6); } } } @@ -567,18 +567,18 @@ void column_test_row_access_constructors(std::vector& matrix, Row_contai for (auto& r : rows) { if constexpr (Column::Master::Option_list::has_removable_rows) { if (!r.second.empty()) { - auto& cell = *r.second.rbegin(); - if (cell.get_row_index() == 0 || cell.get_row_index() == 1 || cell.get_row_index() == 3 || - cell.get_row_index() == 5) { - BOOST_CHECK_EQUAL(cell.get_column_index(), 6); + auto& entry = *r.second.rbegin(); + if (entry.get_row_index() == 0 || entry.get_row_index() == 1 || entry.get_row_index() == 3 || + entry.get_row_index() == 5) { + BOOST_CHECK_EQUAL(entry.get_column_index(), 6); } } } else { if (!r.empty()) { - auto& cell = *r.rbegin(); - if (cell.get_row_index() == 0 || cell.get_row_index() == 1 || cell.get_row_index() == 3 || - cell.get_row_index() == 5) { - BOOST_CHECK_EQUAL(cell.get_column_index(), 6); + auto& entry = *r.rbegin(); + if (entry.get_row_index() == 0 || entry.get_row_index() == 1 || entry.get_row_index() == 3 || + entry.get_row_index() == 5) { + BOOST_CHECK_EQUAL(entry.get_column_index(), 6); } } } @@ -587,11 +587,11 @@ void column_test_row_access_constructors(std::vector& matrix, Row_contai template void column_test_base_boundary_constructors() { - using cell_type = typename std::conditional(), - unsigned int, - std::pair - >::type; - using Container = std::vector; + using entry_type = typename std::conditional(), + unsigned int, + std::pair + >::type; + using Container = std::vector; typename Column::Column_settings settings(5); @@ -677,25 +677,25 @@ void column_test_base_boundary_z2_methods() { // assumes that matrix was build with build_column_matrix and was not modified since. template void column_test_base_z5_operators(std::vector& matrix) { - using Cell = typename Column::Cell; - std::set setcont; + using Entry = typename Column::Entry; + std::set setcont; std::vector veccont; - Cell cell(0); - cell.set_element(4); - setcont.insert(cell); - cell = Cell(1); - cell.set_element(2); - setcont.insert(cell); - cell = Cell(2); - cell.set_element(1); - setcont.insert(cell); - cell = Cell(5); - cell.set_element(1); - setcont.insert(cell); - cell = Cell(6); - cell.set_element(1); - setcont.insert(cell); + Entry entry(0); + entry.set_element(4); + setcont.insert(entry); + entry = Entry(1); + entry.set_element(2); + setcont.insert(entry); + entry = Entry(2); + entry.set_element(1); + setcont.insert(entry); + entry = Entry(5); + entry.set_element(1); + setcont.insert(entry); + entry = Entry(6); + entry.set_element(1); + setcont.insert(entry); matrix[0] += setcont; veccont = {0, 4, 1, 3, 0, 0, 1}; @@ -705,21 +705,21 @@ void column_test_base_z5_operators(std::vector& matrix) { } setcont.clear(); - cell = Cell(0); - cell.set_element(1); - setcont.insert(cell); - cell = Cell(1); - cell.set_element(3); - setcont.insert(cell); - cell = Cell(2); - cell.set_element(4); - setcont.insert(cell); - cell = Cell(5); - cell.set_element(4); - setcont.insert(cell); - cell = Cell(6); - cell.set_element(4); - setcont.insert(cell); + entry = Entry(0); + entry.set_element(1); + setcont.insert(entry); + entry = Entry(1); + entry.set_element(3); + setcont.insert(entry); + entry = Entry(2); + entry.set_element(4); + setcont.insert(entry); + entry = Entry(5); + entry.set_element(4); + setcont.insert(entry); + entry = Entry(6); + entry.set_element(4); + setcont.insert(entry); matrix[1] += setcont; veccont = {}; @@ -745,21 +745,21 @@ void column_test_base_z5_operators(std::vector& matrix) { } // this = this + column * v setcont.clear(); - cell = Cell(0); - cell.set_element(3); - setcont.insert(cell); - cell = Cell(2); - cell.set_element(1); - setcont.insert(cell); - cell = Cell(3); - cell.set_element(2); - setcont.insert(cell); - cell = Cell(5); - cell.set_element(2); - setcont.insert(cell); - cell = Cell(6); - cell.set_element(1); - setcont.insert(cell); + entry = Entry(0); + entry.set_element(3); + setcont.insert(entry); + entry = Entry(2); + entry.set_element(1); + setcont.insert(entry); + entry = Entry(3); + entry.set_element(2); + setcont.insert(entry); + entry = Entry(5); + entry.set_element(2); + setcont.insert(entry); + entry = Entry(6); + entry.set_element(1); + setcont.insert(entry); matrix[5].multiply_source_and_add(setcont, 3); veccont = {3, 2, 4, 1, 0, 2, 4}; BOOST_CHECK(matrix[5].get_content(veccont.size()) == veccont); @@ -768,24 +768,24 @@ void column_test_base_z5_operators(std::vector& matrix) { } // this = v * this + column setcont.clear(); - cell = Cell(0); - cell.set_element(3); - setcont.insert(cell); - cell = Cell(1); - cell.set_element(2); - setcont.insert(cell); - cell = Cell(2); - cell.set_element(4); - setcont.insert(cell); - cell = Cell(3); - cell.set_element(1); - setcont.insert(cell); - cell = Cell(5); - cell.set_element(2); - setcont.insert(cell); - cell = Cell(6); - cell.set_element(4); - setcont.insert(cell); + entry = Entry(0); + entry.set_element(3); + setcont.insert(entry); + entry = Entry(1); + entry.set_element(2); + setcont.insert(entry); + entry = Entry(2); + entry.set_element(4); + setcont.insert(entry); + entry = Entry(3); + entry.set_element(1); + setcont.insert(entry); + entry = Entry(5); + entry.set_element(2); + setcont.insert(entry); + entry = Entry(6); + entry.set_element(4); + setcont.insert(entry); matrix[3].multiply_target_and_add(4, setcont); veccont = {3, 2, 4, 1, 0, 2, 4}; BOOST_CHECK(matrix[3].get_content(veccont.size()) == veccont); @@ -797,7 +797,7 @@ void column_test_base_z5_operators(std::vector& matrix) { // assumes that matrix was build with build_column_matrix and was not modified since. template void column_test_base_z2_operators(std::vector& matrix) { - std::set setcont; + std::set setcont; std::vector veccont; setcont = {0, 1, 2, 5, 6}; diff --git a/src/Persistence_matrix/test/pm_column_tests_mastermatrix.h b/src/Persistence_matrix/test/pm_column_tests_mastermatrix.h index 689cbf0420..7a6c711a57 100644 --- a/src/Persistence_matrix/test/pm_column_tests_mastermatrix.h +++ b/src/Persistence_matrix/test/pm_column_tests_mastermatrix.h @@ -21,25 +21,25 @@ #include #include #include -#include +#include #include -#include +#include #include #include -using Gudhi::persistence_matrix::Cell; -using Gudhi::persistence_matrix::Cell_column_index; -using Gudhi::persistence_matrix::Cell_field_element; +using Gudhi::persistence_matrix::Entry; +using Gudhi::persistence_matrix::Entry_column_index; +using Gudhi::persistence_matrix::Entry_field_element; using Gudhi::persistence_matrix::Chain_column_extra_properties; using Gudhi::persistence_matrix::Column_dimension_holder; using Gudhi::persistence_matrix::Column_types; -using Gudhi::persistence_matrix::Dummy_cell_column_index_mixin; -using Gudhi::persistence_matrix::Dummy_cell_field_element_mixin; +using Gudhi::persistence_matrix::Dummy_entry_column_index_mixin; +using Gudhi::persistence_matrix::Dummy_entry_field_element_mixin; using Gudhi::persistence_matrix::Dummy_chain_properties; using Gudhi::persistence_matrix::Dummy_dimension_holder; using Gudhi::persistence_matrix::Dummy_row_access; -using Gudhi::persistence_matrix::New_cell_constructor; -using Gudhi::persistence_matrix::Pool_cell_constructor; +using Gudhi::persistence_matrix::New_entry_constructor; +using Gudhi::persistence_matrix::Pool_entry_constructor; using Gudhi::persistence_matrix::Row_access; using Zp = Gudhi::persistence_fields::Zp_field_operators<>; @@ -85,47 +85,48 @@ struct Column_mini_matrix { >::type >::type; - using Cell_column_index_option = - typename std::conditional, Dummy_cell_column_index_mixin>::type; - using Cell_field_element_option = typename std::conditional - >::type; - using Matrix_cell = Cell >; + using Entry_column_index_option = typename std::conditional, + Dummy_entry_column_index_mixin>::type; + using Entry_field_element_option = typename std::conditional + >::type; + using Matrix_entry = Entry >; - inline static New_cell_constructor defaultCellConstructor; - using Cell_constructor = New_cell_constructor; + inline static New_entry_constructor defaultEntryConstructor; + using Entry_constructor = New_entry_constructor; struct Column_z2_settings { - Column_z2_settings() : cellConstructor() {} - Column_z2_settings([[maybe_unused]] Characteristic characteristic) : cellConstructor() {} + Column_z2_settings() : entryConstructor() {} + Column_z2_settings([[maybe_unused]] Characteristic characteristic) : entryConstructor() {} - Cell_constructor cellConstructor; + Entry_constructor entryConstructor; }; struct Column_zp_settings { - Column_zp_settings() : operators(), cellConstructor() {} - Column_zp_settings(Characteristic characteristic) : operators(characteristic), cellConstructor() {} + Column_zp_settings() : operators(), entryConstructor() {} + Column_zp_settings(Characteristic characteristic) : operators(characteristic), entryConstructor() {} Field_operators operators; - Cell_constructor cellConstructor; + Entry_constructor entryConstructor; }; using Column_settings = typename std::conditional::type; - template - struct RowCellComp { - bool operator()(const Matrix_cell& c1, const Matrix_cell& c2) const { + template + struct RowEntryComp { + bool operator()(const Matrix_entry& c1, const Matrix_entry& c2) const { return c1.get_column_index() < c2.get_column_index(); } }; using Row = typename std::conditional, boost::intrusive::base_hook >, - std::set > + std::set > >::type; using Row_container = typename std::conditional void test_chain_boundary_insertion(Matrix& m1, Matrix& m2) { auto test = [](Matrix& m) { - BOOST_CHECK(m.is_zero_cell(1, 2)); - BOOST_CHECK(!m.is_zero_cell(1, 1)); - BOOST_CHECK(!m.is_zero_cell(3, 3)); + BOOST_CHECK(m.is_zero_entry(1, 2)); + BOOST_CHECK(!m.is_zero_entry(1, 1)); + BOOST_CHECK(!m.is_zero_entry(3, 3)); BOOST_CHECK(!m.is_zero_column(0)); BOOST_CHECK(!m.is_zero_column(1)); BOOST_CHECK(!m.is_zero_column(2)); @@ -549,9 +549,9 @@ void test_chain_boundary_insertion(Matrix& m1, Matrix& m2) { auto boundary1 = orderedBoundaries.back(); orderedBoundaries.pop_back(); - BOOST_CHECK(m2.is_zero_cell(1, 2)); - BOOST_CHECK(!m2.is_zero_cell(1, 1)); - BOOST_CHECK(!m2.is_zero_cell(3, 3)); + BOOST_CHECK(m2.is_zero_entry(1, 2)); + BOOST_CHECK(!m2.is_zero_entry(1, 1)); + BOOST_CHECK(!m2.is_zero_entry(3, 3)); BOOST_CHECK(!m2.is_zero_column(0)); BOOST_CHECK(!m2.is_zero_column(1)); BOOST_CHECK(!m2.is_zero_column(2)); @@ -618,13 +618,13 @@ void test_zeroing() { Matrix m(orderedBoundaries, 5); - BOOST_CHECK(!m.is_zero_cell(3, 1)); + BOOST_CHECK(!m.is_zero_entry(3, 1)); BOOST_CHECK(!m.is_zero_column(3)); - m.zero_cell(3, 1); - BOOST_CHECK(m.is_zero_cell(3, 1)); + m.zero_entry(3, 1); + BOOST_CHECK(m.is_zero_entry(3, 1)); BOOST_CHECK(!m.is_zero_column(3)); m.zero_column(3); - BOOST_CHECK(m.is_zero_cell(3, 1)); + BOOST_CHECK(m.is_zero_entry(3, 1)); BOOST_CHECK(m.is_zero_column(3)); } @@ -669,22 +669,22 @@ void test_ru_u_access() { } if constexpr (Matrix::Option_list::has_vine_update) { - BOOST_CHECK(!m.is_zero_cell(3, 5, false)); + BOOST_CHECK(!m.is_zero_entry(3, 5, false)); BOOST_CHECK(!m.is_zero_column(4, false)); - m.zero_cell(3, 5, false); - BOOST_CHECK(m.is_zero_cell(3, 5, false)); + m.zero_entry(3, 5, false); + BOOST_CHECK(m.is_zero_entry(3, 5, false)); BOOST_CHECK(!m.is_zero_column(4, false)); m.zero_column(4, false); - BOOST_CHECK(m.is_zero_cell(3, 5, false)); + BOOST_CHECK(m.is_zero_entry(3, 5, false)); BOOST_CHECK(m.is_zero_column(4, false)); } else { - BOOST_CHECK(!m.is_zero_cell(5, 3, false)); + BOOST_CHECK(!m.is_zero_entry(5, 3, false)); BOOST_CHECK(!m.is_zero_column(4, false)); - m.zero_cell(5, 3, false); - BOOST_CHECK(m.is_zero_cell(5, 3, false)); + m.zero_entry(5, 3, false); + BOOST_CHECK(m.is_zero_entry(5, 3, false)); BOOST_CHECK(!m.is_zero_column(4, false)); m.zero_column(4, false); - BOOST_CHECK(m.is_zero_cell(5, 3, false)); + BOOST_CHECK(m.is_zero_entry(5, 3, false)); BOOST_CHECK(m.is_zero_column(4, false)); } } @@ -696,8 +696,8 @@ void test_base_z2_row_access() { std::vector > rows; if constexpr (Matrix::Option_list::has_column_compression) { - // if the union find structure changes, the column_index values of de cells could also change. Change the test with - // all possibilities? + // if the union find structure changes, the column_index values of the entries could also change. Change the test + // with all possibilities? rows.push_back({3, 6}); rows.push_back({3, 5}); rows.push_back({5}); @@ -726,8 +726,8 @@ void test_base_z5_row_access() { std::vector > > rows; if constexpr (Matrix::Option_list::has_column_compression) { - // if the union find structure changes, the column_index values of de cells could also change. Change the test with - // all possibilities? + // if the union find structure changes, the column_index values of the entries could also change. Change the test + // with all possibilities? rows.push_back({{3, 1}, {6, 1}}); rows.push_back({{3, 4}, {5, 1}}); rows.push_back({{5, 4}}); @@ -806,11 +806,11 @@ void test_ru_u_row_access() { unsigned int i = 0; for (auto& r : rows) { orderedRows.clear(); - for (const auto& cell : m.get_row(i++, false)) { + for (const auto& entry : m.get_row(i++, false)) { if constexpr (Matrix::Option_list::is_z2) { - orderedRows.insert(cell.get_column_index()); + orderedRows.insert(entry.get_column_index()); } else { - orderedRows.insert({cell.get_column_index(), cell.get_element()}); + orderedRows.insert({entry.get_column_index(), entry.get_element()}); } } test_column_equality(r, orderedRows); @@ -1209,14 +1209,14 @@ void test_chain_operation(Matrix& m) { } template -void test_base_cell_range_operation() { - using Cell = typename Matrix::Matrix_cell; +void test_base_entry_range_operation() { + using Entry = typename Matrix::Matrix_entry; auto columns = build_general_matrix(); Matrix m(columns, 5); - std::vector range; - range = {Cell(0), Cell(1), Cell(4)}; + std::vector range; + range = {Entry(0), Entry(1), Entry(4)}; if constexpr (!Matrix::Option_list::is_z2) { range[0].set_element(1); range[1].set_element(4); @@ -1251,14 +1251,14 @@ void test_base_cell_range_operation() { } template -void test_base_col_comp_cell_range_operation() { - using Cell = typename Matrix::Matrix_cell; +void test_base_col_comp_entry_range_operation() { + using Entry = typename Matrix::Matrix_entry; auto columns = build_general_matrix(); Matrix m(columns, 5); - std::vector range; - range = {Cell(0), Cell(1), Cell(4)}; + std::vector range; + range = {Entry(0), Entry(1), Entry(4)}; if constexpr (!Matrix::Option_list::is_z2) { range[0].set_element(1); range[1].set_element(4); diff --git a/src/Persistence_matrix/test/pm_test_utilities.h b/src/Persistence_matrix/test/pm_test_utilities.h index 8dbb10fa51..dc20ad4bde 100644 --- a/src/Persistence_matrix/test/pm_test_utilities.h +++ b/src/Persistence_matrix/test/pm_test_utilities.h @@ -59,42 +59,44 @@ constexpr bool is_indexed_by_position() { } template -using Cell_representative = typename std::conditional(), unsigned int, - std::pair >::type; +using Entry_representative = typename std::conditional(), + unsigned int, + std::pair + >::type; template -using column_content = std::set >; +using column_content = std::set >; template -using witness_content = std::vector >; +using witness_content = std::vector >; -// for vector, assumes no cell was removed via clear(Index) +// for vector, assumes no entry was removed via clear(Index) template column_content get_column_content_via_iterators(const Column& col) { - column_content cells; + column_content entries; for (const auto& c : col) { if constexpr (is_z2()) { - cells.insert(c.get_row_index()); + entries.insert(c.get_row_index()); } else { - cells.insert({c.get_row_index(), c.get_element()}); + entries.insert({c.get_row_index(), c.get_element()}); } } - return cells; + return entries; } -// assumes no cell was removed via clear(Index) +// assumes no entry was removed via clear(Index) template column_content > get_column_content_via_iterators(const Heap_column& col) { - column_content > cells; + column_content > entries; std::vector::Field_element> cont; Zp operators(5); for (const auto& c : col) { if constexpr (is_z2 >()) { - auto p = cells.insert(c.get_row_index()); + auto p = entries.insert(c.get_row_index()); if (!p.second) { // possible in heap - cells.erase(p.first); + entries.erase(p.first); } } else { if (cont.size() <= c.get_row_index()) cont.resize(c.get_row_index() + 1, 0u); @@ -103,23 +105,23 @@ column_content > get_column_content_via_iterators(const Heap } if constexpr (!is_z2 >()) { for (unsigned int i = 0; i < cont.size(); ++i) { - if (cont[i] != 0u) cells.insert({i, cont[i]}); + if (cont[i] != 0u) entries.insert({i, cont[i]}); } } - return cells; + return entries; } -// for vector, assumes no cell was removed via clear(Index) +// for vector, assumes no entry was removed via clear(Index) // base and base comp cannot call get_row as const so m cannot be const... template column_content get_ordered_row(Matrix& m, unsigned int rowIndex) { column_content orderedRows; - for (const auto& cell : m.get_row(rowIndex)) { + for (const auto& entry : m.get_row(rowIndex)) { if constexpr (is_z2()) { - orderedRows.insert(cell.get_column_index()); + orderedRows.insert(entry.get_column_index()); } else { - orderedRows.insert({cell.get_column_index(), cell.get_element()}); + orderedRows.insert({entry.get_column_index(), entry.get_element()}); } } return orderedRows; diff --git a/src/Persistence_matrix/test/test_persistence_matrix_matrix_z2_base.cpp b/src/Persistence_matrix/test/test_persistence_matrix_matrix_z2_base.cpp index 8d179d204e..a01fbd64b5 100644 --- a/src/Persistence_matrix/test/test_persistence_matrix_matrix_z2_base.cpp +++ b/src/Persistence_matrix/test/test_persistence_matrix_matrix_z2_base.cpp @@ -42,7 +42,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(Base_matrix_z2_column_removal, Matrix, removable_c BOOST_AUTO_TEST_CASE_TEMPLATE(Base_matrix_z2_operation, Matrix, full_matrices) { test_base_operation(); - test_base_cell_range_operation(); + test_base_entry_range_operation(); test_const_operation(); } diff --git a/src/Persistence_matrix/test/test_persistence_matrix_matrix_z2_compression.cpp b/src/Persistence_matrix/test/test_persistence_matrix_matrix_z2_compression.cpp index b5f1c31e64..856ef08cf1 100644 --- a/src/Persistence_matrix/test/test_persistence_matrix_matrix_z2_compression.cpp +++ b/src/Persistence_matrix/test/test_persistence_matrix_matrix_z2_compression.cpp @@ -40,6 +40,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(Base_column_compression_matrix_z2_row_removal, Mat BOOST_AUTO_TEST_CASE_TEMPLATE(Base_column_compression_matrix_z2_operation, Matrix, full_matrices) { test_base_col_comp_operation(); - test_base_col_comp_cell_range_operation(); + test_base_col_comp_entry_range_operation(); test_base_col_comp_const_operation(); } diff --git a/src/Persistence_matrix/test/test_persistence_matrix_matrix_zp_base.cpp b/src/Persistence_matrix/test/test_persistence_matrix_matrix_zp_base.cpp index 2a5a996d37..d4ded9cff7 100644 --- a/src/Persistence_matrix/test/test_persistence_matrix_matrix_zp_base.cpp +++ b/src/Persistence_matrix/test/test_persistence_matrix_matrix_zp_base.cpp @@ -42,7 +42,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(Base_matrix_zp_column_removal, Matrix, removable_c BOOST_AUTO_TEST_CASE_TEMPLATE(Base_matrix_zp_operation, Matrix, full_matrices) { test_base_operation(); - test_base_cell_range_operation(); + test_base_entry_range_operation(); test_const_operation(); } diff --git a/src/Persistence_matrix/test/test_persistence_matrix_matrix_zp_compression.cpp b/src/Persistence_matrix/test/test_persistence_matrix_matrix_zp_compression.cpp index e5c92d0ead..4aa836a00e 100644 --- a/src/Persistence_matrix/test/test_persistence_matrix_matrix_zp_compression.cpp +++ b/src/Persistence_matrix/test/test_persistence_matrix_matrix_zp_compression.cpp @@ -40,6 +40,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(Base_column_compression_matrix_zp_row_removal, Mat BOOST_AUTO_TEST_CASE_TEMPLATE(Base_column_compression_matrix_zp_operation, Matrix, full_matrices) { test_base_col_comp_operation(); - test_base_col_comp_cell_range_operation(); + test_base_col_comp_entry_range_operation(); test_base_col_comp_const_operation(); } From 8d4fe2bb1a7c678cdc2ae09bf16fc17f16a27ae4 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Tue, 24 Sep 2024 10:00:15 +0200 Subject: [PATCH 72/96] feature requires python 3.8 --- .github/next_release.md | 3 ++- src/python/doc/installation.rst | 42 ++++++++++++++++----------------- src/python/setup.py.in | 2 +- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/.github/next_release.md b/.github/next_release.md index abd2ebd1bd..573d8ef940 100644 --- a/.github/next_release.md +++ b/.github/next_release.md @@ -20,6 +20,7 @@ Below is a list of changes: - Installation - CMake ≥ 3.15 is now required (was ≥ 3.8). + - Python ≥ 3.8 is now required (was ≥ 3.5), because of `importlib.metadata`. - Miscellaneous - The [list of bugs that were solved](https://github.com/GUDHI/gudhi-devel/issues?q=label%3A3.11.0+is%3Aclosed) is available on GitHub. @@ -29,7 +30,7 @@ However, there are still GPL dependencies for many modules. We invite you to che We kindly ask users to cite the GUDHI library as appropriately as possible in their papers, and to mention the use of the GUDHI library on the web pages of their projects using GUDHI and provide us with links to these web pages. -We provide [bibtex entries](https://gudhi.inria.fr/doc/latest/_citation.html) for the modules of the User and Reference Manual, as well as for publications directly related to the GUDHI library. +We provide [bibtex entries](https://gudhi.inria.fr/doc/latest/_citation.html) for the modules of the User and Reference Manual, as well as for publications directly related to the GUDHI library. Feel free to [contact us](https://gudhi.inria.fr/contact/) in case you have any questions or remarks. diff --git a/src/python/doc/installation.rst b/src/python/doc/installation.rst index 639a89d652..c1f7bd2c44 100644 --- a/src/python/doc/installation.rst +++ b/src/python/doc/installation.rst @@ -41,7 +41,7 @@ there. The library uses c++17 and requires `Boost `_ :math:`\geq` 1.71.0, `CMake `_ :math:`\geq` 3.15, -Python :math:`\geq` 3.5, `NumPy `_ :math:`\geq` 1.15.0, `Cython `_ +Python :math:`\geq` 3.8, `NumPy `_ :math:`\geq` 1.15.0, `Cython `_ :math:`\geq` 0.27 and `pybind11 `_ to compile the GUDHI Python module. It is a multi-platform library and compiles on Linux, Mac OSX and Visual Studio 2017 or later. @@ -145,10 +145,10 @@ You shall have something like: .. code-block:: none - Pybind11 version 2.8.1 + Pybind11 version 2.8.1 Python version 3.7.12 - Cython version 0.29.25 - Numpy version 1.21.4 + Cython version 0.29.25 + Numpy version 1.21.4 Boost version 1.77.0 + Installed modules are: off_utils;simplex_tree;rips_complex;cubical_complex;periodic_cubical_complex; persistence_graphical_tools;reader_utils;witness_complex;strong_witness_complex; @@ -156,7 +156,7 @@ You shall have something like: euclidean_strong_witness_complex; Here, you can see that the modules that need CGAL are missing, because CGAL is not installed. -:code:`persistence_graphical_tools` is installed, but +:code:`persistence_graphical_tools` is installed, but `its functions `_ will produce an error as matplotlib is not available. Unitary tests cannot be run as pytest is missing. @@ -165,23 +165,23 @@ A complete configuration would be : .. code-block:: none - Pybind11 version 2.8.1 + Pybind11 version 2.8.1 Python version 3.9.7 - Cython version 0.29.24 - Pytest version 6.2.5 - Matplotlib version 3.5.0 - Numpy version 1.21.4 - Scipy version 1.7.3 - Scikit-learn version 1.0.1 - POT version 0.8.0 + Cython version 0.29.24 + Pytest version 6.2.5 + Matplotlib version 3.5.0 + Numpy version 1.21.4 + Scipy version 1.7.3 + Scikit-learn version 1.0.1 + POT version 0.8.0 HNSWlib found PyKeOps version [pyKeOps]: 2.1 - EagerPy version 0.30.0 - TensorFlow version 2.7.0 - Sphinx version 4.3.0 - Sphinx-paramlinks version 0.5.2 - pydata_sphinx_theme version 0.13.1 - NetworkX version 3.0 + EagerPy version 0.30.0 + TensorFlow version 2.7.0 + Sphinx version 4.3.0 + Sphinx-paramlinks version 0.5.2 + pydata_sphinx_theme version 0.13.1 + NetworkX version 3.0 Eigen3 version 3.4.0 Boost version 1.74.0 CGAL version 5.3 @@ -194,7 +194,7 @@ A complete configuration would be : + Installed modules are: bottleneck;off_utils;simplex_tree;rips_complex;cubical_complex;periodic_cubical_complex; persistence_graphical_tools;reader_utils;witness_complex;strong_witness_complex;nerve_gic;subsampling; tangential_complex;alpha_complex;euclidean_witness_complex;euclidean_strong_witness_complex; - + Missing modules are: + + Missing modules are: Documentation @@ -422,7 +422,7 @@ TensorFlow requires `TensorFlow `_. The :doc:`cubical complex `, :doc:`simplex tree ` and :doc:`Rips complex ` modules require `TensorFlow`_ -for incorporating them in neural nets. +for incorporating them in neural nets. `TensorFlow`_ is also used in some automatic differentiation tests. diff --git a/src/python/setup.py.in b/src/python/setup.py.in index 3bc8d0805e..715ecdef77 100644 --- a/src/python/setup.py.in +++ b/src/python/setup.py.in @@ -73,7 +73,7 @@ setup( long_description_content_type='text/x-rst', long_description='@GUDHI_LONG_DESCRIPTION@', ext_modules = ext_modules, - python_requires='>=3.5.0', + python_requires='>=3.8.0', install_requires = ['numpy >= 1.15.0',], package_data={"": ["*.dll"], }, ) From 7b6d033c934ef927bac92e2753d7e904dbdbfa5f Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Tue, 24 Sep 2024 11:53:59 +0200 Subject: [PATCH 73/96] Use importlib.metadata to guess version numbers of dependencies --- .../modules/GUDHI_third_party_libraries.cmake | 30 +++------------ src/python/CMakeLists.txt | 34 ++++++++--------- src/python/doc/installation.rst | 38 ++++++++++--------- 3 files changed, 43 insertions(+), 59 deletions(-) diff --git a/src/cmake/modules/GUDHI_third_party_libraries.cmake b/src/cmake/modules/GUDHI_third_party_libraries.cmake index 7c03103cba..18149ebcc2 100644 --- a/src/cmake/modules/GUDHI_third_party_libraries.cmake +++ b/src/cmake/modules/GUDHI_third_party_libraries.cmake @@ -145,8 +145,9 @@ if (WITH_GUDHI_PYTHON) # returns ${PYTHON_MODULE_NAME_UP}_VERSION and ${PYTHON_MODULE_NAME_UP}_FOUND function( find_python_module PYTHON_MODULE_NAME ) string(TOUPPER ${PYTHON_MODULE_NAME} PYTHON_MODULE_NAME_UP) + # Modify tracebacklimit as the exception is quite verbose when module is not found execute_process( - COMMAND ${Python_EXECUTABLE} -c "import ${PYTHON_MODULE_NAME}; print(${PYTHON_MODULE_NAME}.__version__)" + COMMAND ${Python_EXECUTABLE} -c "import sys; sys.tracebacklimit = 0; from importlib.metadata import version; print(version('${PYTHON_MODULE_NAME}'))" RESULT_VARIABLE PYTHON_MODULE_RESULT OUTPUT_VARIABLE PYTHON_MODULE_VERSION ERROR_VARIABLE PYTHON_MODULE_ERROR) @@ -167,25 +168,6 @@ if (WITH_GUDHI_PYTHON) endif() endfunction( find_python_module ) - # For modules that do not define module.__version__ - function( find_python_module_no_version PYTHON_MODULE_NAME ) - string(TOUPPER ${PYTHON_MODULE_NAME} PYTHON_MODULE_NAME_UP) - execute_process( - COMMAND ${Python_EXECUTABLE} -c "import ${PYTHON_MODULE_NAME}" - RESULT_VARIABLE PYTHON_MODULE_RESULT - ERROR_VARIABLE PYTHON_MODULE_ERROR) - if(PYTHON_MODULE_RESULT EQUAL 0) - # Remove carriage return - message ("++ Python module ${PYTHON_MODULE_NAME} found") - set(${PYTHON_MODULE_NAME_UP}_FOUND TRUE PARENT_SCOPE) - else() - message ("PYTHON_MODULE_NAME = ${PYTHON_MODULE_NAME} - - PYTHON_MODULE_RESULT = ${PYTHON_MODULE_RESULT} - - PYTHON_MODULE_ERROR = ${PYTHON_MODULE_ERROR}") - set(${PYTHON_MODULE_NAME_UP}_FOUND FALSE PARENT_SCOPE) - endif() - endfunction( find_python_module_no_version ) - if( TARGET Python::Interpreter ) find_python_module("cython") find_python_module("pytest") @@ -193,17 +175,17 @@ if (WITH_GUDHI_PYTHON) find_python_module("numpy") find_python_module("scipy") find_python_module("sphinx") - find_python_module("sklearn") - find_python_module("ot") + find_python_module("scikit-learn") + find_python_module("POT") find_python_module("pybind11") find_python_module("torch") find_python_module("pykeops") find_python_module("eagerpy") - find_python_module_no_version("hnswlib") + find_python_module("hnswlib") find_python_module("tensorflow") find_python_module("sphinx_paramlinks") find_python_module("pydata_sphinx_theme") - find_python_module_no_version("sphinxcontrib.bibtex") + find_python_module("sphinxcontrib.bibtex") find_python_module("networkx") endif() diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index 5b2fad86aa..e68e8f2c64 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -131,19 +131,19 @@ if(SCIPY_FOUND) else() disable_python_documentation("scipy") endif() -if(SKLEARN_FOUND) - add_gudhi_debug_info("Scikit-learn version ${SKLEARN_VERSION}") +if(SCIKIT-LEARN_FOUND) + add_gudhi_debug_info("Scikit-learn version ${SCIKIT-LEARN_VERSION}") else() - disable_python_documentation("sklearn") + disable_python_documentation("scikit-learn") endif() -if(OT_FOUND) - add_gudhi_debug_info("POT version ${OT_VERSION}") +if(POT_FOUND) + add_gudhi_debug_info("POT version ${POT_VERSION}") else() disable_python_documentation("ot") endif() if(HNSWLIB_FOUND) # Does not have a version number... - add_gudhi_debug_info("HNSWlib found") + add_gudhi_debug_info("HNSWlib version ${HNSWLIB_VERSION}") endif() if(TORCH_FOUND) add_gudhi_debug_info("PyTorch version ${TORCH_VERSION}") @@ -176,7 +176,7 @@ else() endif() if(SPHINXCONTRIB.BIBTEX_FOUND) # Does not have a version number... - add_gudhi_debug_info("sphinxcontrib-bibtex found") + add_gudhi_debug_info("sphinxcontrib-bibtex version ${SPHINXCONTRIB.BIBTEX_VERSION}") else() disable_python_documentation("sphinxcontrib-bibtex") endif() @@ -461,7 +461,7 @@ add_test(NAME random_cubical_complex_persistence_example_py_test add_gudhi_py_test(test_cubical_complex) # Datasets are fetched for these tests -if(SKLEARN_FOUND AND WITH_GUDHI_REMOTE_TEST) +if(SCIKIT-LEARN_FOUND AND WITH_GUDHI_REMOTE_TEST) add_gudhi_py_test(test_sklearn_cubical_persistence) add_test(NAME cubical_complex_sklearn_itf_py_test @@ -590,7 +590,7 @@ add_test(NAME rips_complex_from_points_example_py_test add_gudhi_py_test(test_rips_complex) -if(SKLEARN_FOUND) +if(SCIKIT-LEARN_FOUND) # test_sklearn_rips_persistence is using gudhi.datasets.generators if (TARGET CGAL::CGAL AND TARGET Eigen3::Eigen) add_gudhi_py_test(test_sklearn_rips_persistence) @@ -636,7 +636,7 @@ add_gudhi_py_test(test_reader_utils) add_gudhi_py_test(test_off) # Wasserstein -if(OT_FOUND) +if(POT_FOUND) # EagerPy dependency because of enable_autodiff=True if(EAGERPY_FOUND) add_gudhi_py_test(test_wasserstein_distance) @@ -648,7 +648,7 @@ if(OT_FOUND) endif() # Representations -if(SKLEARN_FOUND AND MATPLOTLIB_FOUND AND OT_FOUND AND TARGET CGAL::CGAL) +if(SCIKIT-LEARN_FOUND AND MATPLOTLIB_FOUND AND POT_FOUND AND TARGET CGAL::CGAL) add_gudhi_py_test(test_representations) endif() @@ -658,17 +658,17 @@ if(TENSORFLOW_FOUND) endif() # Perslay -if(TENSORFLOW_FOUND AND SKLEARN_FOUND) +if(TENSORFLOW_FOUND AND SCIKIT-LEARN_FOUND) add_gudhi_py_test(test_perslay) endif() # Betti curves -if(SKLEARN_FOUND AND SCIPY_FOUND) +if(SCIKIT-LEARN_FOUND AND SCIPY_FOUND) add_gudhi_py_test(test_betti_curve_representations) endif() # Representations preprocessing -if(SKLEARN_FOUND) +if(SCIKIT-LEARN_FOUND) add_gudhi_py_test(test_representations_preprocessing) endif() @@ -676,13 +676,13 @@ endif() add_gudhi_py_test(test_time_delay) # DTM -if(SCIPY_FOUND AND SKLEARN_FOUND AND TORCH_FOUND AND HNSWLIB_FOUND AND PYKEOPS_FOUND AND EAGERPY_FOUND) +if(SCIPY_FOUND AND SCIKIT-LEARN_FOUND AND TORCH_FOUND AND HNSWLIB_FOUND AND PYKEOPS_FOUND AND EAGERPY_FOUND) add_gudhi_py_test(test_knn) add_gudhi_py_test(test_dtm) endif() # Tomato -if(SCIPY_FOUND AND SKLEARN_FOUND) +if(SCIPY_FOUND AND SCIKIT-LEARN_FOUND) add_gudhi_py_test(test_tomato) endif() @@ -697,7 +697,7 @@ if(SCIPY_FOUND) endif() # Cover complex -if(SKLEARN_FOUND) +if(SCIKIT-LEARN_FOUND) add_gudhi_py_test(test_cover_complex) endif() diff --git a/src/python/doc/installation.rst b/src/python/doc/installation.rst index c1f7bd2c44..067b733efb 100644 --- a/src/python/doc/installation.rst +++ b/src/python/doc/installation.rst @@ -165,26 +165,28 @@ A complete configuration would be : .. code-block:: none - Pybind11 version 2.8.1 - Python version 3.9.7 - Cython version 0.29.24 - Pytest version 6.2.5 - Matplotlib version 3.5.0 - Numpy version 1.21.4 - Scipy version 1.7.3 - Scikit-learn version 1.0.1 - POT version 0.8.0 - HNSWlib found - PyKeOps version [pyKeOps]: 2.1 + Python version 3.11.9 + Pybind11 version 2.12.0 + Cython version 3.0.10 + Numpy version 1.24.3 + Pytest version 8.2.1 + Matplotlib version 3.9.0 + Scipy version 1.13.1 + Scikit-learn version 1.3.2 + POT version 0.9.4 + HNSWlib version 0.8.0 + PyTorch version 2.3.0 + PyKeOps version 2.2.3 EagerPy version 0.30.0 - TensorFlow version 2.7.0 - Sphinx version 4.3.0 - Sphinx-paramlinks version 0.5.2 - pydata_sphinx_theme version 0.13.1 - NetworkX version 3.0 + TensorFlow version 2.13.1 + Sphinx version 7.3.7 + Sphinx-paramlinks version 0.6.0 + pydata_sphinx_theme version 0.15.2 + sphinxcontrib-bibtex version 2.6.2 + NetworkX version 3.3 Eigen3 version 3.4.0 - Boost version 1.74.0 - CGAL version 5.3 + Boost version 1.84.0 + CGAL header only version 5.6.1 GMP_LIBRARIES = /usr/lib/x86_64-linux-gnu/libgmp.so GMPXX_LIBRARIES = /usr/lib/x86_64-linux-gnu/libgmpxx.so MPFR_LIBRARIES = /usr/lib/x86_64-linux-gnu/libmpfr.so From 02cb463db14c5966739d862a5dde1bb7d054ab9e Mon Sep 17 00:00:00 2001 From: hschreiber Date: Tue, 24 Sep 2024 14:04:48 +0200 Subject: [PATCH 74/96] small fixes --- .../include/gudhi/Multi_critical_filtration.h | 53 ++++++++++++++++--- ...ultifiltration_multicritical_unit_test.cpp | 5 ++ .../include/gudhi/Multi_persistence/Line.h | 20 ++++--- .../test/multipersistence_line_unit_test.cpp | 12 +++-- 4 files changed, 71 insertions(+), 19 deletions(-) diff --git a/src/Multi_filtration/include/gudhi/Multi_critical_filtration.h b/src/Multi_filtration/include/gudhi/Multi_critical_filtration.h index 3ca198a185..5946690962 100644 --- a/src/Multi_filtration/include/gudhi/Multi_critical_filtration.h +++ b/src/Multi_filtration/include/gudhi/Multi_critical_filtration.h @@ -247,6 +247,17 @@ class Multi_critical_filtration { return multi_filtration_[0]; } + /** + * @brief Casts the object into the type of a generator. + * @pre The filtration value is 1-critical. If there are more than one generator, only the first will be preserved + * and if there is no generator, the method will segfault. + */ + operator const Generator() const { + GUDHI_CHECK(num_generators() == 1, "Casting a " + std::to_string(num_generators()) + + "-critical filtration value into an 1-critical filtration value."); + return multi_filtration_[0]; + } + // like numpy /** * @brief Returns a copy with entries casted into the type given as template parameter. @@ -847,14 +858,42 @@ class Multi_critical_filtration { // no nan values and if there is an inf/-inf, then 'end - curr == 1' // modifies multi_filtration_ only if true is returned. bool _generator_can_be_added(const Generator &x, std::size_t curr, std::size_t &end) { - if (x.empty() || x.is_nan() || (x.is_plus_inf() && end - curr != 0)) return false; + if (x.empty() || x.is_nan()) return false; - if (x.is_minus_inf()) { - if (end - curr == 1 && multi_filtration_[curr].is_minus_inf()) return false; - // assumes that everything between curr and end is already simplified - // so, if end - curr != 1, there can be no minus_inf anymore. - end = curr; - return true; + // assumes that everything between curr and end is simplified + // so, only multi_filtration_[curr] can be at inf or -inf. + if constexpr (co) { + if (multi_filtration_[curr].is_plus_inf() || (x.is_minus_inf() && end - curr != 0)) { + return false; + } + if (multi_filtration_[curr].is_minus_inf()) { + if (x.is_minus_inf()) { + return false; + } + end = curr; + return true; + } + if (x.is_plus_inf()) { + if (multi_filtration_[curr].is_plus_inf()) return false; + end = curr; + return true; + } + } else { + if (multi_filtration_[curr].is_minus_inf() || (x.is_plus_inf() && end - curr != 0)) { + return false; + } + if (multi_filtration_[curr].is_plus_inf()) { + if (x.is_plus_inf()) { + return false; + } + end = curr; + return true; + } + if (x.is_minus_inf()) { + if (multi_filtration_[curr].is_minus_inf()) return false; + end = curr; + return true; + } } while (curr != end) { diff --git a/src/Multi_filtration/test/multifiltration_multicritical_unit_test.cpp b/src/Multi_filtration/test/multifiltration_multicritical_unit_test.cpp index 8fd28d4f44..5c18498161 100644 --- a/src/Multi_filtration/test/multifiltration_multicritical_unit_test.cpp +++ b/src/Multi_filtration/test/multifiltration_multicritical_unit_test.cpp @@ -421,6 +421,11 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(multi_critical_filtration_add, T, list_of_tested_v BOOST_CHECK_EQUAL(f5[0][0], 0); BOOST_CHECK_EQUAL(f5[0][1], 1); BOOST_CHECK_EQUAL(f5[0][2], 2); + + Multi_critical_filtration f6 = Multi_critical_filtration::minus_inf(); + bool change = f6.add_generator(Multi_critical_filtration::inf()); + BOOST_CHECK(change); + BOOST_CHECK(f6.is_plus_inf()); } BOOST_AUTO_TEST_CASE_TEMPLATE(multi_critical_filtration_friends, T, list_of_tested_variants) diff --git a/src/Multi_persistence/include/gudhi/Multi_persistence/Line.h b/src/Multi_persistence/include/gudhi/Multi_persistence/Line.h index 2afdabbbbf..378e968366 100644 --- a/src/Multi_persistence/include/gudhi/Multi_persistence/Line.h +++ b/src/Multi_persistence/include/gudhi/Multi_persistence/Line.h @@ -18,6 +18,7 @@ #ifndef LINE_FILTRATION_TRANSLATION_H_INCLUDED #define LINE_FILTRATION_TRANSLATION_H_INCLUDED +#include #include #include #include @@ -85,6 +86,12 @@ class Line { GUDHI_CHECK(direction_.empty() || direction_.size() == basePoint_.size(), "Direction and base point do not have the same dimension."); + if constexpr (std::numeric_limits::has_quiet_NaN){ //to avoid windows error + if (std::isnan(t)) return Point::nan(); + } + if (t == Point::T_inf) return Point::inf(); + if (t == -Point::T_inf) return Point::minus_inf(); + Point x(basePoint_.size()); if (direction_.size() > 0) { @@ -225,22 +232,21 @@ class Line { } /** - * @brief Given a box, returns the intersection of this box and the line. + * @brief Given a box, returns "time" parameter of the intersection of this box and the line. * * @param box Box to intersect. * @return A pair representing the two bounding points of the intersection, such that the first element is the - * smallest of the two. If the box and the line do not intersect, returns the pair {inf, inf}. - * If the box is trivial, returns {NaN, NaN}. + * smallest of the two. If the box and the line do not intersect or the box is trivial, returns the pair {inf, -inf}. */ - std::pair get_bounds(const Box &box) const { - if (box.is_trivial()) return {Point::nan(), Point::nan()}; + std::pair get_bounds(const Box &box) const { + if (box.is_trivial()) return {Point::T_inf, -Point::T_inf}; T bottom = compute_forward_intersection(box.get_lower_corner()); T top = compute_backward_intersection(box.get_upper_corner()); - if (bottom > top) return {Point::inf(), Point::inf()}; // no intersection + if (bottom > top) return {Point::T_inf, -Point::T_inf}; // no intersection - return {(*this)[bottom], (*this)[top]}; + return {bottom, top}; } private: diff --git a/src/Multi_persistence/test/multipersistence_line_unit_test.cpp b/src/Multi_persistence/test/multipersistence_line_unit_test.cpp index 6450fb3854..d86db82d1d 100644 --- a/src/Multi_persistence/test/multipersistence_line_unit_test.cpp +++ b/src/Multi_persistence/test/multipersistence_line_unit_test.cpp @@ -87,9 +87,9 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(line_intersections, T, list_of_tested_variants) t = l.template compute_backward_intersection(KP({P{2,1,3}, P{2,3,3}})); BOOST_CHECK_EQUAL(t, 0); - std::pair bounds = l.get_bounds({{-10, 0, 10}, {10, 4, 10}}); - auto& bottom = bounds.first; - auto& top = bounds.second; + std::pair bounds = l.get_bounds({{-10, 0, 10}, {10, 4, 10}}); + auto bottom = l[bounds.first]; + auto top = l[bounds.second]; BOOST_CHECK_EQUAL(bottom.size(), 3); BOOST_CHECK_EQUAL(bottom[0], T(5. + 2. / 3.)); BOOST_CHECK_EQUAL(bottom[1], 2); @@ -100,8 +100,10 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(line_intersections, T, list_of_tested_variants) BOOST_CHECK_EQUAL(top[2], T(3. + T(7. / 6.) * 6.)); bounds = l.get_bounds({{-10, 0, 10}, {10, 1, 10}}); - BOOST_CHECK(bounds.first.is_plus_inf()); - BOOST_CHECK(bounds.second.is_plus_inf()); + BOOST_CHECK_EQUAL(bounds.first, P::T_inf); + BOOST_CHECK_EQUAL(bounds.second, -P::T_inf); + BOOST_CHECK(l[bounds.first].is_plus_inf()); + BOOST_CHECK(l[bounds.second].is_minus_inf()); } BOOST_AUTO_TEST_CASE_TEMPLATE(line_other, T, list_of_tested_variants) From fdaeb013cdfde476cf9f5bdc391c55062fe818f3 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Tue, 24 Sep 2024 15:27:47 +0200 Subject: [PATCH 75/96] renaming matrix cell as matrix entry --- .../Persistence_matrix/allocators/entry_constructors.h | 6 +++--- .../include/gudhi/Persistence_matrix/columns/entry_types.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/allocators/entry_constructors.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/allocators/entry_constructors.h index 5062a985ec..8485477450 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/allocators/entry_constructors.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/allocators/entry_constructors.h @@ -14,8 +14,8 @@ * @brief Contains different versions of @ref Gudhi::persistence_matrix::Entry factories. */ -#ifndef PM_COLUMN_CELL_CONSTRUCTORS_H -#define PM_COLUMN_CELL_CONSTRUCTORS_H +#ifndef PM_COLUMN_ENTRY_CONSTRUCTORS_H +#define PM_COLUMN_ENTRY_CONSTRUCTORS_H #include //std::swap @@ -136,4 +136,4 @@ struct Pool_entry_constructor } // namespace persistence_matrix } // namespace Gudhi -#endif // PM_COLUMN_CELL_CONSTRUCTORS_H +#endif // PM_COLUMN_ENTRY_CONSTRUCTORS_H diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/entry_types.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/entry_types.h index ca9ad3389f..81083d3d70 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/entry_types.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/entry_types.h @@ -18,8 +18,8 @@ * Also defines the std::hash method for @ref Gudhi::persistence_matrix::Entry. */ -#ifndef PM_MATRIX_CELL_H -#define PM_MATRIX_CELL_H +#ifndef PM_MATRIX_ENTRY_H +#define PM_MATRIX_ENTRY_H #include //std::swap, std::exchange & std::move #include //std::hash @@ -324,4 +324,4 @@ struct std::hash > { } }; -#endif // PM_MATRIX_CELL_H +#endif // PM_MATRIX_ENTRY_H From 848d853159083041511b070b85389ebb8cb217a6 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Wed, 25 Sep 2024 10:03:02 +0200 Subject: [PATCH 76/96] Specific case for PyKeops on Windows --- src/cmake/modules/GUDHI_third_party_libraries.cmake | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/cmake/modules/GUDHI_third_party_libraries.cmake b/src/cmake/modules/GUDHI_third_party_libraries.cmake index 18149ebcc2..ffed360461 100644 --- a/src/cmake/modules/GUDHI_third_party_libraries.cmake +++ b/src/cmake/modules/GUDHI_third_party_libraries.cmake @@ -179,7 +179,6 @@ if (WITH_GUDHI_PYTHON) find_python_module("POT") find_python_module("pybind11") find_python_module("torch") - find_python_module("pykeops") find_python_module("eagerpy") find_python_module("hnswlib") find_python_module("tensorflow") @@ -189,6 +188,17 @@ if (WITH_GUDHI_PYTHON) find_python_module("networkx") endif() + # Specific case for PyKeops that can be imported on Windows, but fails because it uses fcntl (not available on Windows) + # Also fcntl has no metadata, so find_python_module does not work + # "import fcntl" is about 1 sec. faster than "import pykeops" + execute_process( + COMMAND ${Python_EXECUTABLE} -c "import fcntl" + RESULT_VARIABLE FCNTL_IMPORT_MODULE_RESULT + OUTPUT_VARIABLE FCNTL_IMPORT_MODULE_OUPUT) + if(FCNTL_IMPORT_MODULE_RESULT EQUAL 0) + find_python_module("pykeops") + endif() + if(NOT GUDHI_PYTHON_PATH) message(FATAL_ERROR "ERROR: GUDHI_PYTHON_PATH is not valid.") endif(NOT GUDHI_PYTHON_PATH) From dee13f902aacb50fcf024653600af1cf143a38f5 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Wed, 25 Sep 2024 11:49:41 +0200 Subject: [PATCH 77/96] rename face as cell in persistence matrix --- .../concept/PersistenceMatrixColumn.h | 4 +- .../concept/PersistenceMatrixOptions.h | 8 +- .../doc/Intro_persistence_matrix.h | 4 +- src/Persistence_matrix/include/gudhi/Matrix.h | 148 +++++------ .../Persistence_matrix/Boundary_matrix.h | 46 ++-- .../gudhi/Persistence_matrix/Chain_matrix.h | 140 +++++----- .../Persistence_matrix/Id_to_index_overlay.h | 250 +++++++++--------- .../Position_to_index_overlay.h | 76 +++--- .../gudhi/Persistence_matrix/RU_matrix.h | 70 ++--- .../gudhi/Persistence_matrix/base_pairing.h | 12 +- ... => boundary_cell_position_to_id_mapper.h} | 14 +- .../Persistence_matrix/chain_vine_swap.h | 14 +- .../columns/chain_column_extra_properties.h | 4 +- .../matrix_dimension_holders.h | 16 +- .../gudhi/Persistence_matrix/ru_pairing.h | 12 +- .../gudhi/Persistence_matrix/ru_vine_swap.h | 18 +- src/Persistence_matrix/test/pm_matrix_tests.h | 6 +- 17 files changed, 421 insertions(+), 421 deletions(-) rename src/Persistence_matrix/include/gudhi/Persistence_matrix/{boundary_face_position_to_id_mapper.h => boundary_cell_position_to_id_mapper.h} (74%) diff --git a/src/Persistence_matrix/concept/PersistenceMatrixColumn.h b/src/Persistence_matrix/concept/PersistenceMatrixColumn.h index 6eaf75f7c9..8ae47e2924 100644 --- a/src/Persistence_matrix/concept/PersistenceMatrixColumn.h +++ b/src/Persistence_matrix/concept/PersistenceMatrixColumn.h @@ -86,7 +86,7 @@ class PersistenceMatrixColumn : PersistenceMatrixColumn(Column_settings* colSettings = nullptr); /** * @brief Constructs a column from the given range of @ref Matrix::Entry_representative. If the dimension is stored, - * the face is assumed to be simplicial and its dimension to be `nonZeroRowIndices length - 1` or `0`. + * the cell is assumed to be simplicial and its dimension to be `nonZeroRowIndices length - 1` or `0`. * Otherwise, the dimension should be specified with another constructor. * * @tparam Container Range of @ref Matrix::Entry_representative. Assumed to have a %begin(), %end() and %size() @@ -102,7 +102,7 @@ class PersistenceMatrixColumn : /** * @brief Constructs a column from the given range of @ref Matrix::Entry_representative such that the rows can be * accessed. Each new entry in the column is also inserted in a row using @ref Row_access::insert_entry. - * If the dimension is stored, the face is assumed to be simplicial and its dimension to be + * If the dimension is stored, the cell is assumed to be simplicial and its dimension to be * `nonZeroRowIndices length - 1` or `0`. Otherwise, the dimension should be specified with another constructor. * * @tparam Container Range of @ref Matrix::Entry_representative. Assumed to have a %begin(), %end() and %size() diff --git a/src/Persistence_matrix/concept/PersistenceMatrixOptions.h b/src/Persistence_matrix/concept/PersistenceMatrixOptions.h index b4d72dc82b..9d5cc83540 100644 --- a/src/Persistence_matrix/concept/PersistenceMatrixOptions.h +++ b/src/Persistence_matrix/concept/PersistenceMatrixOptions.h @@ -93,14 +93,14 @@ struct PersistenceMatrixOptions * If set to false, the container is a std::vector. By default, it is recommended to set it to false, but some * methods require it to be true to be enabled: * - @ref Matrix::remove_column(Index) "remove_column(Index)" for @ref basematrix "base matrices", - * - @ref Matrix::remove_maximal_face(Index) "remove_maximal_face(Index)" for @ref chainmatrix "chain matrices", - * - @ref Matrix::remove_maximal_face(Index, const std::vector&) - * "remove_maximal_face(ID_index, const std::vector&)" for @ref chainmatrix "chain matrices", + * - @ref Matrix::remove_maximal_cell(Index) "remove_maximal_cell(Index)" for @ref chainmatrix "chain matrices", + * - @ref Matrix::remove_maximal_cell(Index, const std::vector&) + * "remove_maximal_cell(ID_index, const std::vector&)" for @ref chainmatrix "chain matrices", * - @ref Matrix::remove_last "remove_last()" for @ref chainmatrix "chain matrices" if @ref has_vine_update is true. */ static const bool has_map_column_container; /** - * @brief If set to true, enables the methods @ref Matrix::remove_maximal_face and @ref Matrix::remove_last, + * @brief If set to true, enables the methods @ref Matrix::remove_maximal_cell and @ref Matrix::remove_last, * except for @ref basematrix "base matrices" when @ref has_column_compression is true. */ static const bool has_removable_columns; diff --git a/src/Persistence_matrix/doc/Intro_persistence_matrix.h b/src/Persistence_matrix/doc/Intro_persistence_matrix.h index 77b2657414..1185655b26 100644 --- a/src/Persistence_matrix/doc/Intro_persistence_matrix.h +++ b/src/Persistence_matrix/doc/Intro_persistence_matrix.h @@ -30,12 +30,12 @@ namespace persistence_matrix { * The main functionalities are: * @li column and row access, * @li column addition and scalar multiplication, - * @li removal of maximal faces while maintaining a valid reduced boundary matrix or compatible chain complex base + * @li removal of maximal cells while maintaining a valid reduced boundary matrix or compatible chain complex base * and a valid barcode with respect to the new filtration, * @li computation of persistent homology (but note that if the barcode is your only necessity, using the * @ref persistent_cohomology module is often more performant), * @li computation of representative cycles for the cycle classes, - * @li swapping of two consecutive faces in a filtration (cf. vineyards @cite vineyards) while maintaining a valid + * @li swapping of two consecutive cells in a filtration (cf. vineyards @cite vineyards) while maintaining a valid * reduced boundary matrix or compatible chain complex base and a valid barcode with respect to the new filtration, * * \note Matrix API is in a beta version and may change in incompatible ways in the near future. diff --git a/src/Persistence_matrix/include/gudhi/Matrix.h b/src/Persistence_matrix/include/gudhi/Matrix.h index a403ccaa81..d917bddc80 100644 --- a/src/Persistence_matrix/include/gudhi/Matrix.h +++ b/src/Persistence_matrix/include/gudhi/Matrix.h @@ -109,7 +109,7 @@ namespace persistence_matrix { * always take the same type of index as input (for optimization purposes). So, to avoid confusion, we will name and * define here the different possibilities, such that we can directly refer to it in the descriptions of the methods. * Note that every column and row in a @ref boundarymatrix "boundary" or @ref chainmatrix "chain matrix" is always - * associated to a single simplex/face, so in order to avoid repeating formulations like "of the simplex associated to + * associated to a single simplex/cell, so in order to avoid repeating formulations like "of the simplex associated to * the column" all the time, we will amalgamate both notions together. * * Let @f$ c @f$ be a column. @@ -134,7 +134,7 @@ namespace persistence_matrix { * indexed by its ID, so it correspond to the @ref IDIdx indexing scheme. If the matrix is not a * @ref chainmatrix "chain matrix", @f$ r @f$ will originally also be indexed by the ID, but when a swap occurs, * the rows also swap IDs and the new ID has to be used to access @f$ r @f$. This means that when the default - * @ref IDIdx scheme is used (the faces are numerated in order of appearance in the filtration starting at 0), + * @ref IDIdx scheme is used (the cells are numerated in order of appearance in the filtration starting at 0), * the indexation of the rows correspond to @ref PosIdx. * * @tparam PersistenceMatrixOptions Structure encoding all the options of the matrix. @@ -609,9 +609,9 @@ class Matrix { * (as in the implementation of the Zigzag algorithm @cite zigzag for example.) * * @param birthComparator Method taking two @ref PosIdx indices as parameter and returns true if and only if the first - * face is associated to a bar with strictly smaller birth than the bar associated to the second one. + * cell is associated to a bar with strictly smaller birth than the bar associated to the second one. * @param deathComparator Method taking two @ref PosIdx indices as parameter and returns true if and only if the first - * face is associated to a bar with strictly smaller death than the bar associated to the second one. + * cell is associated to a bar with strictly smaller death than the bar associated to the second one. */ Matrix(const std::function& birthComparator, const std::function& deathComparator); @@ -633,9 +633,9 @@ class Matrix { * method. * @param orderedBoundaries Vector of ordered boundaries in filtration order. Indexed continuously starting at 0. * @param birthComparator Method taking two @ref PosIdx indices as parameter and returns true if and only if the first - * face is associated to a bar with strictly smaller birth than the bar associated to the second one. + * cell is associated to a bar with strictly smaller birth than the bar associated to the second one. * @param deathComparator Method taking two @ref PosIdx indices as parameter and returns true if and only if the first - * face is associated to a bar with strictly smaller death than the bar associated to the second one. + * cell is associated to a bar with strictly smaller death than the bar associated to the second one. * @param characteristic Characteristic of the coefficient field. Has to be specified if * @ref PersistenceMatrixOptions::is_z2 is false. Default value is 11. * Ignored if @ref PersistenceMatrixOptions::is_z2 is true. @@ -660,9 +660,9 @@ class Matrix { * * @param numberOfColumns Number of columns to reserve space for. * @param birthComparator Method taking two @ref PosIdx indices as parameter and returns true if and only if the first - * face is associated to a bar with strictly smaller birth than the bar associated to the second one. + * cell is associated to a bar with strictly smaller birth than the bar associated to the second one. * @param deathComparator Method taking two @ref PosIdx indices as parameter and returns true if and only if the first - * face is associated to a bar with strictly smaller death than the bar associated to the second one. + * cell is associated to a bar with strictly smaller death than the bar associated to the second one. * @param characteristic Characteristic of the coefficient field. If not specified and * @ref PersistenceMatrixOptions::is_z2 is false, the characteristic has to be set later with the use of * @ref set_characteristic before calling for the first time a method needing it. @@ -736,10 +736,10 @@ class Matrix { /** * @brief Inserts at the end of the matrix a new ordered column corresponding to the given boundary. * This means that it is assumed that this method is called on boundaries in the order of the filtration. - * It also assumes that the faces in the given boundary are identified by their relative position in the filtration, + * It also assumes that the cells in the given boundary are identified by their relative position in the filtration, * starting at 0. If it is not the case, use the other - * @ref insert_boundary(ID_index faceIndex, const Boundary_range& boundary, Dimension dim) "insert_boundary" - * instead by indicating the face ID used in the boundaries when the face is inserted. + * @ref insert_boundary(ID_index cellIndex, const Boundary_range& boundary, Dimension dim) "insert_boundary" + * instead by indicating the cell ID used in the boundaries when the cell is inserted. * * Different to the constructor, the boundaries do not have to come from a simplicial complex, but also from * a more general entry complex. This includes cubical complexes or Morse complexes for example. @@ -759,7 +759,7 @@ class Matrix { * * @tparam Boundary_range Range of @ref Entry_representative. Assumed to have a begin(), end() and size() method. * @param boundary Boundary generating the new column. The content should be ordered by ID. - * @param dim Dimension of the face whose boundary is given. If the complex is simplicial, + * @param dim Dimension of the cell whose boundary is given. If the complex is simplicial, * this parameter can be omitted as it can be deduced from the size of the boundary. * @return If it is a @ref chainmatrix "chain matrix", the method returns the @ref MatIdx indices of the unpaired * chains used to reduce the boundary. Otherwise, nothing. @@ -768,26 +768,26 @@ class Matrix { Insertion_return insert_boundary(const Boundary_range& boundary, Dimension dim = -1); /** * @brief Only available for @ref mp_matrices "non-basic matrices". - * It does the same as the other version, but allows the boundary faces to be identified without restrictions + * It does the same as the other version, but allows the boundary cells to be identified without restrictions * except that all IDs have to be strictly increasing in the order of filtration. Note that you should avoid then * to use the other insertion method to avoid overwriting IDs. * - * As a face has to be inserted before one of its cofaces in a valid filtration (recall that it is assumed that - * for @ref mp_matrices "non-basic matrices", the faces are inserted by order of filtration), it is sufficient to - * indicate the ID of the face being inserted. + * As a cell has to be inserted before one of its cofaces in a valid filtration (recall that it is assumed that + * for @ref mp_matrices "non-basic matrices", the cells are inserted by order of filtration), it is sufficient to + * indicate the ID of the cell being inserted. * * @tparam Boundary_range Range of @ref Entry_representative. Assumed to have a begin(), end() and size() method. - * @param faceIndex @ref IDIdx index to use to identify the new face. + * @param cellIndex @ref IDIdx index to use to identify the new cell. * @param boundary Boundary generating the new column. The indices of the boundary have to correspond to the - * @p faceIndex values of precedent calls of the method for the corresponding faces and should be ordered in + * @p cellIndex values of precedent calls of the method for the corresponding cells and should be ordered in * increasing order. - * @param dim Dimension of the face whose boundary is given. If the complex is simplicial, + * @param dim Dimension of the cell whose boundary is given. If the complex is simplicial, * this parameter can be omitted as it can be deduced from the size of the boundary. * @return If it is a @ref chainmatrix "chain matrix", the method returns the @ref MatIdx indices of the unpaired * chains used to reduce the boundary. Otherwise, nothing. */ template - Insertion_return insert_boundary(ID_index faceIndex, const Boundary_range& boundary, Dimension dim = -1); + Insertion_return insert_boundary(ID_index cellIndex, const Boundary_range& boundary, Dimension dim = -1); /** * @brief Returns the column at the given @ref MatIdx index. @@ -895,10 +895,10 @@ class Matrix { * @brief Only available for @ref boundarymatrix "RU" and @ref chainmatrix "chain matrices" and if * @ref PersistenceMatrixOptions::has_removable_columns and @ref PersistenceMatrixOptions::has_vine_update are true. * For @ref chainmatrix "chain matrices", @ref PersistenceMatrixOptions::has_map_column_container and - * @ref PersistenceMatrixOptions::has_column_pairings also need to be true. Assumes that the face is maximal in the + * @ref PersistenceMatrixOptions::has_column_pairings also need to be true. Assumes that the cell is maximal in the * current complex and removes it such that the matrix remains consistent (i.e., RU is still an upper triangular * decomposition of the boundary matrix and chain is still a compatible bases of the chain complex in the sense - * of @cite zigzag). The maximality of the face is not verified. Also updates the barcode if it was computed. + * of @cite zigzag). The maximality of the cell is not verified. Also updates the barcode if it was computed. * * For @ref chainmatrix "chain matrices", using the other version of the method could perform better depending on how * the data is maintained on the side of the user. Then, @ref PersistenceMatrixOptions::has_column_pairings also do @@ -906,56 +906,56 @@ class Matrix { * * See also @ref remove_last and @ref remove_column. * - * @param columnIndex If @ref boundarymatrix "boundary matrix", @ref MatIdx index of the face to remove, otherwise the + * @param columnIndex If @ref boundarymatrix "boundary matrix", @ref MatIdx index of the cell to remove, otherwise the * @ref IDIdx index. */ - void remove_maximal_face(Index columnIndex); + void remove_maximal_cell(Index columnIndex); //TODO: See if it would be better to use something more general than a vector for columnsToSwap, such that // the user do not have to construct the vector from scratch. Like passing iterators instead. But it would be nice, - // to still be able to do (face, {})... + // to still be able to do (cell, {})... /** * @brief Only available for @ref chainmatrix "chain matrices" and if * @ref PersistenceMatrixOptions::has_removable_columns, @ref PersistenceMatrixOptions::has_vine_update and - * @ref PersistenceMatrixOptions::has_map_column_container are true. Assumes that the face is maximal in the current + * @ref PersistenceMatrixOptions::has_map_column_container are true. Assumes that the cell is maximal in the current * complex and removes it such that the matrix remains consistent (i.e., it is still a compatible bases of the chain - * complex in the sense of @cite zigzag). The maximality of the face is not verified. Also updates the barcode if it + * complex in the sense of @cite zigzag). The maximality of the cell is not verified. Also updates the barcode if it * was computed. * - * To maintain the compatibility, vine swaps are done to move the face up to the end of the filtration. Once at the + * To maintain the compatibility, vine swaps are done to move the cell up to the end of the filtration. Once at the * end, the removal is trivial. But for @ref chainmatrix "chain matrices", swaps do not actually swap the position of - * the column every time, so the faces appearing after @p faceIndex in the filtration have to be searched first within - * the matrix. If the user has an easy access to the @ref IDIdx of the faces in the order of filtration, passing them + * the column every time, so the cells appearing after @p cellIndex in the filtration have to be searched first within + * the matrix. If the user has an easy access to the @ref IDIdx of the cells in the order of filtration, passing them * by argument with @p columnsToSwap allows to skip a linear search process. Typically, if the user knows that the - * face he wants to remove is already the last face of the filtration, calling - * @ref remove_maximal_face(ID_index faceIndex, const std::vector& columnsToSwap) - * "remove_maximal_face(faceID, {})" will be faster than @ref remove_last(). + * cell he wants to remove is already the last cell of the filtration, calling + * @ref remove_maximal_cell(ID_index cellIndex, const std::vector& columnsToSwap) + * "remove_maximal_cell(cellID, {})" will be faster than @ref remove_last(). * * See also @ref remove_last. * - * @param faceIndex @ref IDIdx index of the face to remove - * @param columnsToSwap Vector of @ref IDIdx indices of the faces coming after @p faceIndex in the filtration. + * @param cellIndex @ref IDIdx index of the cell to remove + * @param columnsToSwap Vector of @ref IDIdx indices of the cells coming after @p cellIndex in the filtration. */ - void remove_maximal_face(ID_index faceIndex, const std::vector& columnsToSwap); + void remove_maximal_cell(ID_index cellIndex, const std::vector& columnsToSwap); /** - * @brief Removes the last inserted column/face from the matrix. + * @brief Removes the last inserted column/cell from the matrix. * If the matrix is @ref mp_matrices "non basic", @ref PersistenceMatrixOptions::has_removable_columns has to be true * for the method to be available. Additionally, if the matrix is a @ref chainmatrix "chain matrix", either * @ref PersistenceMatrixOptions::has_map_column_container has to be true or * @ref PersistenceMatrixOptions::has_vine_update has to be false. And if the matrix is a * @ref basematrix "base matrix" it should be without column compression. * - * See also @ref remove_maximal_face and @ref remove_column. + * See also @ref remove_maximal_cell and @ref remove_column. * - * For @ref chainmatrix "chain matrices", if @ref PersistenceMatrixOptions::has_vine_update is true, the last face + * For @ref chainmatrix "chain matrices", if @ref PersistenceMatrixOptions::has_vine_update is true, the last cell * does not have to be at the end of the matrix and therefore has to be searched first. In this case, if the user - * already knows the @ref IDIdx of the last face, calling - * @ref remove_maximal_face(ID_index faceIndex, const std::vector& columnsToSwap) - * "remove_maximal_face(faceID, {})" instead allows to skip the search. + * already knows the @ref IDIdx of the last cell, calling + * @ref remove_maximal_cell(ID_index cellIndex, const std::vector& columnsToSwap) + * "remove_maximal_cell(cellID, {})" instead allows to skip the search. */ void remove_last(); /** - * @brief Returns the maximal dimension of a face stored in the matrix. Only available for + * @brief Returns the maximal dimension of a cell stored in the matrix. Only available for * @ref mp_matrices "non-basic matrices" and if @ref PersistenceMatrixOptions::has_matrix_maximal_dimension_access * is true. * @@ -969,10 +969,10 @@ class Matrix { */ Index get_number_of_columns() const; /** - * @brief Returns the dimension of the given face. Only available for @ref mp_matrices "non-basic matrices". + * @brief Returns the dimension of the given cell. Only available for @ref mp_matrices "non-basic matrices". * - * @param columnIndex @ref MatIdx index of the column representing the face. - * @return Dimension of the face. + * @param columnIndex @ref MatIdx index of the column representing the cell. + * @return Dimension of the cell. */ Dimension get_column_dimension(Index columnIndex) const; @@ -1189,10 +1189,10 @@ class Matrix { * indices and that the @ref rowindex "row indices" for a @ref boundarymatrix "RU matrix" correspond to the updated * @ref IDIdx indices which got potentially swapped by a vine swap. * - * @param faceIndex @ref rowindex "Row index" of the pivot. + * @param cellIndex @ref rowindex "Row index" of the pivot. * @return @ref MatIdx index of the column with the given pivot. */ - Index get_column_with_pivot(ID_index faceIndex) const; + Index get_column_with_pivot(ID_index cellIndex) const; /** * @brief Returns the @ref rowindex "row index" of the pivot of the given column. Only available for * @ref mp_matrices "non-basic matrices". @@ -1280,7 +1280,7 @@ class Matrix { * Does the same than @ref vine_swap, but assumes that the swap is non trivial and therefore skips a part of the case * study. * - * @param index @ref PosIdx index of the first face to swap. The second one has to be at `index + 1`. Recall that for + * @param index @ref PosIdx index of the first cell to swap. The second one has to be at `index + 1`. Recall that for * @ref boundarymatrix "boundary matrices", @ref PosIdx == @ref MatIdx. * @return true If the barcode changed from the swap. * @return false Otherwise. @@ -1292,8 +1292,8 @@ class Matrix { * @ref Column_indexation_types::IDENTIFIER. Does the same than @ref vine_swap, but assumes that the swap is * non-trivial and therefore skips a part of the case study. * - * @param columnIndex1 @ref MatIdx index of the first face. - * @param columnIndex2 @ref MatIdx index of the second face. It is assumed that the @ref PosIdx of both only differs + * @param columnIndex1 @ref MatIdx index of the first cell. + * @param columnIndex2 @ref MatIdx index of the second cell. It is assumed that the @ref PosIdx of both only differs * by one. * @return Let \f$ pos1 \f$ be the @ref PosIdx index of @p columnIndex1 and \f$ pos2 \f$ be the @ref PosIdx index of * @p columnIndex2. The method returns the @ref MatIdx of the column which has now, after the swap, the @ref PosIdx @@ -1303,14 +1303,14 @@ class Matrix { /** * @brief Only available if @ref PersistenceMatrixOptions::has_vine_update is true and if it is either a * @ref boundarymatrix "boundary matrix" or @ref PersistenceMatrixOptions::column_indexation_type is set to - * @ref Column_indexation_types::POSITION. Does a vine swap between two faces which are consecutive in the + * @ref Column_indexation_types::POSITION. Does a vine swap between two cells which are consecutive in the * filtration. Roughly, if \f$ F \f$ is the current filtration represented by the matrix, the method modifies the * matrix such that the new state corresponds to a valid state for the filtration \f$ F' \f$ equal to \f$ F \f$ but - * with the two faces at position `index` and `index + 1` swapped. Of course, the two faces should not have a + * with the two cells at position `index` and `index + 1` swapped. Of course, the two cells should not have a * face/coface relation which each other ; \f$ F' \f$ has to be a valid filtration. * See @cite vineyards for more information about vine and vineyards. * - * @param index @ref PosIdx index of the first face to swap. The second one has to be at `index + 1`. Recall that for + * @param index @ref PosIdx index of the first cell to swap. The second one has to be at `index + 1`. Recall that for * @ref boundarymatrix "boundary matrices", @ref PosIdx == @ref MatIdx. * @return true If the barcode changed from the swap. * @return false Otherwise. @@ -1319,15 +1319,15 @@ class Matrix { /** * @brief Only available if @ref PersistenceMatrixOptions::has_vine_update is true and if it is either a * @ref chainmatrix "chain matrix" or @ref PersistenceMatrixOptions::column_indexation_type is set to - * @ref Column_indexation_types::IDENTIFIER. Does a vine swap between two faces which are consecutive in the + * @ref Column_indexation_types::IDENTIFIER. Does a vine swap between two cells which are consecutive in the * filtration. Roughly, if \f$ F \f$ is the current filtration represented by the matrix, the method modifies the * matrix such that the new state corresponds to a valid state for the filtration \f$ F' \f$ equal to \f$ F \f$ but - * with the two given faces at swapped positions. Of course, the two faces should not have a face/coface relation + * with the two given cells at swapped positions. Of course, the two cells should not have a face/coface relation * which each other ; \f$ F' \f$ has to be a valid filtration. * See @cite vineyards for more information about vine and vineyards. * - * @param columnIndex1 @ref MatIdx index of the first face. - * @param columnIndex2 @ref MatIdx index of the second face. It is assumed that the @ref PosIdx of both only differs + * @param columnIndex1 @ref MatIdx index of the first cell. + * @param columnIndex2 @ref MatIdx index of the second cell. It is assumed that the @ref PosIdx of both only differs * by one. * @return Let \f$ pos1 \f$ be the @ref PosIdx index of @p columnIndex1 and \f$ pos2 \f$ be the @ref PosIdx index of * @p columnIndex2. The method returns the @ref MatIdx of the column which has now, after the swap, the @ref PosIdx @@ -1531,7 +1531,7 @@ inline void Matrix::insert_column(const Container& col static_assert( !isNonBasic, - "'insert_column' not available for the chosen options. The input has to be in the form of a face boundary."); + "'insert_column' not available for the chosen options. The input has to be in the form of a cell boundary."); matrix_.insert_column(column); } @@ -1573,7 +1573,7 @@ Matrix::insert_boundary(const Boundary_range& boundary template template inline typename Matrix::Insertion_return -Matrix::insert_boundary(ID_index faceIndex, +Matrix::insert_boundary(ID_index cellIndex, const Boundary_range& boundary, Dimension dim) { @@ -1586,9 +1586,9 @@ Matrix::insert_boundary(ID_index faceIndex, static_assert(isNonBasic, "Only enabled for non-basic matrices."); if constexpr (!PersistenceMatrixOptions::is_of_boundary_type && PersistenceMatrixOptions::column_indexation_type == Column_indexation_types::CONTAINER) - return matrix_.insert_boundary(faceIndex, boundary, dim); + return matrix_.insert_boundary(cellIndex, boundary, dim); else - matrix_.insert_boundary(faceIndex, boundary, dim); + matrix_.insert_boundary(cellIndex, boundary, dim); } template @@ -1673,31 +1673,31 @@ inline void Matrix::erase_empty_row(ID_index rowIndex) } template -inline void Matrix::remove_maximal_face(Index columnIndex) +inline void Matrix::remove_maximal_cell(Index columnIndex) { static_assert(PersistenceMatrixOptions::has_removable_columns, - "'remove_maximal_face(ID_index)' is not available for the chosen options."); + "'remove_maximal_cell(ID_index)' is not available for the chosen options."); static_assert(isNonBasic && PersistenceMatrixOptions::has_vine_update, - "'remove_maximal_face(ID_index)' is not available for the chosen options."); + "'remove_maximal_cell(ID_index)' is not available for the chosen options."); static_assert(PersistenceMatrixOptions::is_of_boundary_type || (PersistenceMatrixOptions::has_map_column_container && PersistenceMatrixOptions::has_column_pairings), - "'remove_maximal_face(ID_index)' is not available for the chosen options."); + "'remove_maximal_cell(ID_index)' is not available for the chosen options."); - matrix_.remove_maximal_face(columnIndex); + matrix_.remove_maximal_cell(columnIndex); } template -inline void Matrix::remove_maximal_face(ID_index faceIndex, +inline void Matrix::remove_maximal_cell(ID_index cellIndex, const std::vector& columnsToSwap) { static_assert(PersistenceMatrixOptions::has_removable_columns, - "'remove_maximal_face(ID_index,const std::vector&)' is not available for the chosen options."); + "'remove_maximal_cell(ID_index,const std::vector&)' is not available for the chosen options."); static_assert(isNonBasic && !PersistenceMatrixOptions::is_of_boundary_type, - "'remove_maximal_face(ID_index,const std::vector&)' is not available for the chosen options."); + "'remove_maximal_cell(ID_index,const std::vector&)' is not available for the chosen options."); static_assert(PersistenceMatrixOptions::has_map_column_container && PersistenceMatrixOptions::has_vine_update, - "'remove_maximal_face(ID_index,const std::vector&)' is not available for the chosen options."); + "'remove_maximal_cell(ID_index,const std::vector&)' is not available for the chosen options."); - matrix_.remove_maximal_face(faceIndex, columnsToSwap); + matrix_.remove_maximal_cell(cellIndex, columnsToSwap); } template @@ -1902,14 +1902,14 @@ inline bool Matrix::is_zero_column(Index columnIndex, template inline typename Matrix::Index Matrix::get_column_with_pivot( - ID_index faceIndex) const + ID_index cellIndex) const { static_assert(isNonBasic && (!PersistenceMatrixOptions::is_of_boundary_type || (PersistenceMatrixOptions::has_vine_update || PersistenceMatrixOptions::can_retrieve_representative_cycles)), "'get_column_with_pivot' is not available for the chosen options."); - return matrix_.get_column_with_pivot(faceIndex); + return matrix_.get_column_with_pivot(cellIndex); } template diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Boundary_matrix.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Boundary_matrix.h index 29c6f87d93..93de613c03 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Boundary_matrix.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Boundary_matrix.h @@ -32,7 +32,7 @@ namespace persistence_matrix { * * @brief %Matrix structure to store the ordered @ref boundarymatrix "boundary matrix" \f$ R \f$ of a filtered complex * in order to compute its persistent homology. Provides an access to its columns and rows as well as the possibility - * to remove the last faces of the filtration while maintaining a valid barcode. + * to remove the last cells of the filtration while maintaining a valid barcode. * * @tparam Master_matrix An instantiation of @ref Matrix from which all types and options are deduced. */ @@ -120,10 +120,10 @@ class Boundary_matrix : public Master_matrix::Matrix_dimension_option, /** * @brief Inserts at the end of the matrix a new ordered column corresponding to the given boundary. * This means that it is assumed that this method is called on boundaries in the order of the filtration. - * It also assumes that the faces in the given boundary are identified by their relative position in the filtration, + * It also assumes that the cells in the given boundary are identified by their relative position in the filtration, * starting at 0. If it is not the case, use the other - * @ref insert_boundary(ID_index faceIndex, const Boundary_range& boundary, Dimension dim) "insert_boundary" - * instead by indicating the face ID used in the boundaries when the face is inserted. + * @ref insert_boundary(ID_index cellIndex, const Boundary_range& boundary, Dimension dim) "insert_boundary" + * instead by indicating the cell ID used in the boundaries when the cell is inserted. * * Different to the constructor, the boundaries do not have to come from a simplicial complex, but also from * a more general entry complex. This includes cubical complexes or Morse complexes for example. @@ -136,32 +136,32 @@ class Boundary_matrix : public Master_matrix::Matrix_dimension_option, * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() * method. * @param boundary Boundary generating the new column. The content should be ordered by ID. - * @param dim Dimension of the face whose boundary is given. If the complex is simplicial, + * @param dim Dimension of the cell whose boundary is given. If the complex is simplicial, * this parameter can be omitted as it can be deduced from the size of the boundary. * @return The @ref MatIdx index of the inserted boundary. */ template Index insert_boundary(const Boundary_range& boundary, Dimension dim = -1); /** - * @brief It does the same as the other version, but allows the boundary faces to be identified without restrictions + * @brief It does the same as the other version, but allows the boundary cells to be identified without restrictions * except that all IDs have to be strictly increasing in the order of filtration. Note that you should avoid then * to use the other insertion method to avoid overwriting IDs. * - * As a face has to be inserted before one of its cofaces in a valid filtration (recall that it is assumed that - * the faces are inserted by order of filtration), it is sufficient to indicate the ID of the face being inserted. + * As a cell has to be inserted before one of its cofaces in a valid filtration (recall that it is assumed that + * the cells are inserted by order of filtration), it is sufficient to indicate the ID of the cell being inserted. * * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() * method. - * @param faceIndex @ref IDIdx index to use to identify the new face. + * @param cellIndex @ref IDIdx index to use to identify the new cell. * @param boundary Boundary generating the new column. The indices of the boundary have to correspond to the - * @p faceIndex values of precedent calls of the method for the corresponding faces and should be ordered in + * @p cellIndex values of precedent calls of the method for the corresponding cells and should be ordered in * increasing order. - * @param dim Dimension of the face whose boundary is given. If the complex is simplicial, + * @param dim Dimension of the cell whose boundary is given. If the complex is simplicial, * this parameter can be omitted as it can be deduced from the size of the boundary. * @return The @ref MatIdx index of the inserted boundary. */ template - Index insert_boundary(ID_index faceIndex, const Boundary_range& boundary, Dimension dim = -1); + Index insert_boundary(ID_index cellIndex, const Boundary_range& boundary, Dimension dim = -1); /** * @brief Returns the column at the given @ref MatIdx index. * The type of the column depends on the choosen options, see @ref PersistenceMatrixOptions::column_type. @@ -189,9 +189,9 @@ class Boundary_matrix : public Master_matrix::Matrix_dimension_option, Row& get_row(Index rowIndex); /** * @brief Only available if @ref PersistenceMatrixOptions::has_removable_columns is true. - * Removes the last face in the filtration from the matrix and updates the barcode if this one was already computed. + * Removes the last cell in the filtration from the matrix and updates the barcode if this one was already computed. * - * @return The pivot of the removed face. + * @return The pivot of the removed cell. */ Index remove_last(); /** @@ -221,8 +221,8 @@ class Boundary_matrix : public Master_matrix::Matrix_dimension_option, /** * @brief Returns the dimension of the given column. * - * @param columnIndex @ref MatIdx index of the column representing the face. - * @return Dimension of the face. + * @param columnIndex @ref MatIdx index of the column representing the cell. + * @return Dimension of the cell. */ Dimension get_column_dimension(Index columnIndex) const; @@ -469,7 +469,7 @@ inline typename Boundary_matrix::Index Boundary_matrix template inline typename Boundary_matrix::Index Boundary_matrix::insert_boundary( - ID_index faceIndex, const Boundary_range& boundary, Dimension dim) + ID_index cellIndex, const Boundary_range& boundary, Dimension dim) { if (dim == -1) dim = boundary.size() == 0 ? 0 : boundary.size() - 1; @@ -492,12 +492,12 @@ inline typename Boundary_matrix::Index Boundary_matrix::Index Boundary_matrix std::vector insert_boundary(const Boundary_range& boundary, Dimension dim = -1); /** - * @brief It does the same as the other version, but allows the boundary faces to be identified without restrictions + * @brief It does the same as the other version, but allows the boundary cells to be identified without restrictions * except that all IDs have to be strictly increasing in the order of filtration. Note that you should avoid then * to use the other insertion method to avoid overwriting IDs. * - * As a face has to be inserted before one of its cofaces in a valid filtration (recall that it is assumed that - * the faces are inserted by order of filtration), it is sufficient to indicate the ID of the face being inserted. + * As a cell has to be inserted before one of its cofaces in a valid filtration (recall that it is assumed that + * the cells are inserted by order of filtration), it is sufficient to indicate the ID of the cell being inserted. * * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() * method. - * @param faceID @ref IDIdx index to use to identify the new face. + * @param cellID @ref IDIdx index to use to identify the new cell. * @param boundary Boundary generating the new column. The indices of the boundary have to correspond to the - * @p faceID values of precedent calls of the method for the corresponding faces and should be ordered in + * @p cellID values of precedent calls of the method for the corresponding cells and should be ordered in * increasing order. - * @param dim Dimension of the face whose boundary is given. If the complex is simplicial, + * @param dim Dimension of the cell whose boundary is given. If the complex is simplicial, * this parameter can be omitted as it can be deduced from the size of the boundary. * @return The @ref MatIdx index of the inserted boundary. */ template - std::vector insert_boundary(ID_index faceID, + std::vector insert_boundary(ID_index cellID, const Boundary_range& boundary, Dimension dim = -1); /** @@ -290,9 +290,9 @@ class Chain_matrix : public Master_matrix::Matrix_dimension_option, * @brief Only available if @ref PersistenceMatrixOptions::has_removable_columns and * @ref PersistenceMatrixOptions::has_vine_update are true, as well as, * @ref PersistenceMatrixOptions::has_map_column_container and @ref PersistenceMatrixOptions::has_column_pairings. - * Assumes that the face is maximal in the current complex and removes it such that the matrix remains consistent + * Assumes that the cell is maximal in the current complex and removes it such that the matrix remains consistent * (i.e., the matrix is still a compatible bases of the chain complex in the sense of @cite zigzag). - * The maximality of the face is not verified. + * The maximality of the cell is not verified. * Also updates the barcode if it is stored. * * Note that using the other version of the method could perform better depending on how the data is @@ -300,46 +300,46 @@ class Chain_matrix : public Master_matrix::Matrix_dimension_option, * * See also @ref remove_last. * - * @param faceID @ref IDIdx index of the face to remove + * @param cellID @ref IDIdx index of the cell to remove */ - void remove_maximal_face(ID_index faceID); + void remove_maximal_cell(ID_index cellID); /** * @brief Only available if @ref PersistenceMatrixOptions::has_removable_columns, * @ref PersistenceMatrixOptions::has_vine_update and @ref PersistenceMatrixOptions::has_map_column_container * are true. - * Assumes that the face is maximal in the current complex and removes it such that the matrix remains consistent + * Assumes that the cell is maximal in the current complex and removes it such that the matrix remains consistent * (i.e., it is still a compatible bases of the chain complex in the sense of @cite zigzag). - * The maximality of the face is not verified. + * The maximality of the cell is not verified. * Also updates the barcode if it is stored. * - * To maintain the compatibility, vine swaps are done to move the face up to the end of the filtration. Once at + * To maintain the compatibility, vine swaps are done to move the cell up to the end of the filtration. Once at * the end, the removal is trivial. But for @ref chainmatrix "chain matrices", swaps do not actually swap the position - * of the column every time, so the faces appearing after @p faceID in the filtration have to be searched first within - * the matrix. If the user has an easy access to the @ref IDIdx of the faces in the order of filtration, passing them + * of the column every time, so the cells appearing after @p cellID in the filtration have to be searched first within + * the matrix. If the user has an easy access to the @ref IDIdx of the cells in the order of filtration, passing them * by argument with @p columnsToSwap allows to skip a linear search process. Typically, if the user knows that the - * face he wants to remove is already the last face of the filtration, calling - * @ref remove_maximal_face(ID_index faceIndex, const std::vector& columnsToSwap) - * "remove_maximal_face(faceID, {})" will be faster than @ref remove_last(). + * cell he wants to remove is already the last cell of the filtration, calling + * @ref remove_maximal_cell(ID_index cellIndex, const std::vector& columnsToSwap) + * "remove_maximal_cell(cellID, {})" will be faster than @ref remove_last(). * * See also @ref remove_last. * - * @param faceID @ref IDIdx index of the face to remove - * @param columnsToSwap Vector of @ref IDIdx indices of the faces coming after @p faceID in the filtration. + * @param cellID @ref IDIdx index of the cell to remove + * @param columnsToSwap Vector of @ref IDIdx indices of the cells coming after @p cellID in the filtration. */ - void remove_maximal_face(ID_index faceID, const std::vector& columnsToSwap); + void remove_maximal_cell(ID_index cellID, const std::vector& columnsToSwap); /** * @brief Only available if @ref PersistenceMatrixOptions::has_removable_columns is true and, * if @ref PersistenceMatrixOptions::has_map_column_container is true or * @ref PersistenceMatrixOptions::has_vine_update is false. - * Removes the last face in the filtration from the matrix and updates the barcode if it is stored. + * Removes the last cell in the filtration from the matrix and updates the barcode if it is stored. * - * See also @ref remove_maximal_face. + * See also @ref remove_maximal_cell. * - * @warning If @ref PersistenceMatrixOptions::has_vine_update is true, the last face does not have to + * @warning If @ref PersistenceMatrixOptions::has_vine_update is true, the last cell does not have to * be at the end of the matrix container and therefore has to be searched first. In this case, if the user - * already knows the @ref IDIdx of the last face, calling - * @ref remove_maximal_face(ID_index faceIndex, const std::vector& columnsToSwap) - * "remove_maximal_face(faceID, {})" instead allows to skip the search. + * already knows the @ref IDIdx of the last cell, calling + * @ref remove_maximal_cell(ID_index cellIndex, const std::vector& columnsToSwap) + * "remove_maximal_cell(cellID, {})" instead allows to skip the search. */ void remove_last(); @@ -353,8 +353,8 @@ class Chain_matrix : public Master_matrix::Matrix_dimension_option, /** * @brief Returns the dimension of the given column. * - * @param columnIndex @ref MatIdx index of the column representing the face. - * @return Dimension of the face. + * @param columnIndex @ref MatIdx index of the column representing the cell. + * @return Dimension of the cell. */ Dimension get_column_dimension(Index columnIndex) const; @@ -422,10 +422,10 @@ class Chain_matrix : public Master_matrix::Matrix_dimension_option, /** * @brief Returns the column with given @ref rowindex "row index" as pivot. Assumes that the pivot exists. * - * @param faceID @ref rowindex "Row index" of the pivot. + * @param cellID @ref rowindex "Row index" of the pivot. * @return @ref MatIdx index of the column with the given pivot. */ - Index get_column_with_pivot(ID_index faceID) const; + Index get_column_with_pivot(ID_index cellID) const; /** * @brief Returns the @ref rowindex "row index" of the pivot of the given column. * @@ -499,10 +499,10 @@ class Chain_matrix : public Master_matrix::Matrix_dimension_option, Column_settings* colSettings_; /**< Entry factory. */ template - std::vector _reduce_boundary(ID_index faceID, const Boundary_range& boundary, Dimension dim); + std::vector _reduce_boundary(ID_index cellID, const Boundary_range& boundary, Dimension dim); void _reduce_by_G(Tmp_column& column, std::vector& chainsInH, Index currentPivot); void _reduce_by_F(Tmp_column& column, std::vector& chainsInF, Index currentPivot); - void _build_from_H(ID_index faceID, Tmp_column& column, std::vector& chainsInH); + void _build_from_H(ID_index cellID, Tmp_column& column, std::vector& chainsInH); void _update_largest_death_in_F(const std::vector& chainsInF); void _insert_chain(const Tmp_column& column, Dimension dimension); void _insert_chain(const Tmp_column& column, Dimension dimension, Index pair); @@ -681,21 +681,21 @@ inline std::vector Chain_matrix template inline std::vector Chain_matrix::insert_boundary( - ID_index faceID, const Boundary_range& boundary, Dimension dim) + ID_index cellID, const Boundary_range& boundary, Dimension dim) { if constexpr (!Master_matrix::Option_list::has_map_column_container) { - if (pivotToColumnIndex_.size() <= faceID) { - pivotToColumnIndex_.resize(faceID * 2 + 1, -1); + if (pivotToColumnIndex_.size() <= cellID) { + pivotToColumnIndex_.resize(cellID * 2 + 1, -1); } } if constexpr (Master_matrix::Option_list::has_vine_update && Master_matrix::Option_list::has_column_pairings) { if constexpr (Master_matrix::Option_list::has_map_column_container) { - Swap_opt::CP::pivotToPosition_.try_emplace(faceID, _nextPosition()); + Swap_opt::CP::pivotToPosition_.try_emplace(cellID, _nextPosition()); } else { - if (Swap_opt::CP::pivotToPosition_.size() <= faceID) + if (Swap_opt::CP::pivotToPosition_.size() <= cellID) Swap_opt::CP::pivotToPosition_.resize(pivotToColumnIndex_.size(), -1); - Swap_opt::CP::pivotToPosition_[faceID] = _nextPosition(); + Swap_opt::CP::pivotToPosition_[cellID] = _nextPosition(); } } @@ -703,7 +703,7 @@ inline std::vector Chain_matrix(-1) ? (boundary.size() == 0 ? 0 : boundary.size() - 1) : dim); } - return _reduce_boundary(faceID, boundary, dim); + return _reduce_boundary(cellID, boundary, dim); } template @@ -728,22 +728,22 @@ inline const typename Chain_matrix::Column& Chain_matrix -inline void Chain_matrix::remove_maximal_face(ID_index faceID) +inline void Chain_matrix::remove_maximal_cell(ID_index cellID) { static_assert(Master_matrix::Option_list::has_removable_columns, - "'remove_maximal_face' is not implemented for the chosen options."); + "'remove_maximal_cell' is not implemented for the chosen options."); static_assert(Master_matrix::Option_list::has_map_column_container && Master_matrix::Option_list::has_vine_update && Master_matrix::Option_list::has_column_pairings, - "'remove_maximal_face' is not implemented for the chosen options."); + "'remove_maximal_cell' is not implemented for the chosen options."); // TODO: find simple test to verify that col at columnIndex is maximal even without row access. const auto& pivotToPosition = Swap_opt::CP::pivotToPosition_; - auto it = pivotToPosition.find(faceID); - if (it == pivotToPosition.end()) return; // face does not exists. TODO: put an assert instead? + auto it = pivotToPosition.find(cellID); + if (it == pivotToPosition.end()) return; // cell does not exists. TODO: put an assert instead? Pos_index startPos = it->second; - Index startIndex = pivotToColumnIndex_.at(faceID); + Index startIndex = pivotToColumnIndex_.at(cellID); if (startPos != _nextPosition() - 1) { std::vector colToSwap; @@ -765,17 +765,17 @@ inline void Chain_matrix::remove_maximal_face(ID_index faceID) } template -inline void Chain_matrix::remove_maximal_face(ID_index faceID, +inline void Chain_matrix::remove_maximal_cell(ID_index cellID, const std::vector& columnsToSwap) { static_assert(Master_matrix::Option_list::has_removable_columns, - "'remove_maximal_face' is not implemented for the chosen options."); + "'remove_maximal_cell' is not implemented for the chosen options."); static_assert(Master_matrix::Option_list::has_map_column_container && Master_matrix::Option_list::has_vine_update, - "'remove_maximal_face' is not implemented for the chosen options."); + "'remove_maximal_cell' is not implemented for the chosen options."); // TODO: find simple test to verify that col at columnIndex is maximal even without row access. - Index startIndex = pivotToColumnIndex_.at(faceID); + Index startIndex = pivotToColumnIndex_.at(cellID); for (ID_index i : columnsToSwap) { startIndex = Swap_opt::vine_swap(startIndex, pivotToColumnIndex_.at(i)); @@ -797,7 +797,7 @@ inline void Chain_matrix::remove_last() if constexpr (Master_matrix::Option_list::has_vine_update) { // careful: linear because of the search of the last index. It is better to keep track of the @ref IDIdx index // of the last column while performing swaps (or the @ref MatIdx with the return values of `vine_swap` + get_pivot) - // and then call `remove_maximal_face` with it and an empty `columnsToSwap`. + // and then call `remove_maximal_cell` with it and an empty `columnsToSwap`. ID_index pivot = 0; Index colIndex = 0; @@ -869,12 +869,12 @@ inline bool Chain_matrix::is_zero_column(Index columnIndex) template inline typename Chain_matrix::Index Chain_matrix::get_column_with_pivot( - ID_index faceID) const + ID_index cellID) const { if constexpr (Master_matrix::Option_list::has_map_column_container) { - return pivotToColumnIndex_.at(faceID); + return pivotToColumnIndex_.at(cellID); } else { - return pivotToColumnIndex_[faceID]; + return pivotToColumnIndex_[cellID]; } } @@ -959,7 +959,7 @@ inline void Chain_matrix::print() const template template inline std::vector Chain_matrix::_reduce_boundary( - ID_index faceID, const Boundary_range& boundary, Dimension dim) + ID_index cellID, const Boundary_range& boundary, Dimension dim) { Tmp_column column(boundary.begin(), boundary.end()); if (dim == static_cast(-1)) dim = boundary.begin() == boundary.end() ? 0 : boundary.size() - 1; @@ -975,9 +975,9 @@ inline std::vector Chain_matrix Chain_matrix Chain_matrix::_reduce_by_F(Tmp_column& column, } template -inline void Chain_matrix::_build_from_H(ID_index faceID, +inline void Chain_matrix::_build_from_H(ID_index cellID, Tmp_column& column, std::vector& chainsInH) { if constexpr (Master_matrix::Option_list::is_z2) { - column.insert(faceID); + column.insert(cellID); for (Index idx_h : chainsInH) { _add_to(get_column(idx_h), column, 1u); } } else { - column.emplace(faceID, 1); + column.emplace(cellID, 1); for (std::pair& idx_h : chainsInH) { _add_to(get_column(idx_h.first), column, idx_h.second); } diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Id_to_index_overlay.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Id_to_index_overlay.h index 91b09f2659..be885d182a 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Id_to_index_overlay.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Id_to_index_overlay.h @@ -220,10 +220,10 @@ class Id_to_index_overlay /** * @brief Inserts at the end of the matrix a new ordered column corresponding to the given boundary. * This means that it is assumed that this method is called on boundaries in the order of the filtration. - * It also assumes that the faces in the given boundary are identified by their relative position in the filtration, + * It also assumes that the cells in the given boundary are identified by their relative position in the filtration, * starting at 0. If it is not the case, use the other * @ref insert_boundary(ID_index, const Boundary_range&, Dimension) "insert_boundary" instead by indicating the - * face ID used in the boundaries when the face is inserted. + * cell ID used in the boundaries when the cell is inserted. * * Different to the constructor, the boundaries do not have to come from a simplicial complex, but also from * a more general entry complex. This includes cubical complexes or Morse complexes for example. @@ -241,39 +241,39 @@ class Id_to_index_overlay * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() * method. * @param boundary Boundary generating the new column. The content should be ordered by ID. - * @param dim Dimension of the face whose boundary is given. If the complex is simplicial, + * @param dim Dimension of the cell whose boundary is given. If the complex is simplicial, * this parameter can be omitted as it can be deduced from the size of the boundary. */ template void insert_boundary(const Boundary_range& boundary, Dimension dim = -1); /** - * @brief It does the same as the other version, but allows the boundary faces to be identified without restrictions + * @brief It does the same as the other version, but allows the boundary cells to be identified without restrictions * except that all IDs have to be strictly increasing in the order of filtration. Note that you should avoid then * to use the other insertion method to avoid overwriting IDs. * - * As a face has to be inserted before one of its cofaces in a valid filtration (recall that it is assumed that - * the faces are inserted by order of filtration), it is sufficient to indicate the ID of the face being inserted. + * As a cell has to be inserted before one of its cofaces in a valid filtration (recall that it is assumed that + * the cells are inserted by order of filtration), it is sufficient to indicate the ID of the cell being inserted. * * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() * method. - * @param faceIndex @ref IDIdx index to use to identify the new face. + * @param cellIndex @ref IDIdx index to use to identify the new cell. * @param boundary Boundary generating the new column. The indices of the boundary have to correspond to the - * @p faceIndex values of precedent calls of the method for the corresponding faces and should be ordered in + * @p cellIndex values of precedent calls of the method for the corresponding cells and should be ordered in * increasing order. - * @param dim Dimension of the face whose boundary is given. If the complex is simplicial, + * @param dim Dimension of the cell whose boundary is given. If the complex is simplicial, * this parameter can be omitted as it can be deduced from the size of the boundary. */ template - void insert_boundary(ID_index faceIndex, const Boundary_range& boundary, Dimension dim = -1); + void insert_boundary(ID_index cellIndex, const Boundary_range& boundary, Dimension dim = -1); /** * @brief Returns the column at the given @ref IDIdx index. * For @ref boundarymatrix "RU matrices", the returned column is from \f$ R \f$. * The type of the column depends on the choosen options, see @ref PersistenceMatrixOptions::column_type. * - * @param faceID @ref IDIdx index of the column to return. + * @param cellID @ref IDIdx index of the column to return. * @return Reference to the column. */ - Column& get_column(ID_index faceID); + Column& get_column(ID_index cellID); /** * @brief Only available if @ref PersistenceMatrixOptions::has_row_access is true. * Returns the row at the given @ref rowindex "row index". @@ -319,10 +319,10 @@ class Id_to_index_overlay * @ref PersistenceMatrixOptions::has_removable_columns and @ref PersistenceMatrixOptions::has_vine_update are true. * For @ref chainmatrix "chain matrices", @ref PersistenceMatrixOptions::has_map_column_container and * @ref PersistenceMatrixOptions::has_column_pairings also need to be true. - * Assumes that the face is maximal in the current complex and removes it such that the matrix remains consistent + * Assumes that the cell is maximal in the current complex and removes it such that the matrix remains consistent * (i.e., RU is still an upper triangular decomposition of the @ref boundarymatrix "boundary matrix" and chain is * still a compatible bases of the chain complex in the sense of @cite zigzag). - * The maximality of the face is not verified. + * The maximality of the cell is not verified. * Also updates the barcode if it was computed. * * For @ref chainmatrix "chain matrices", using the other version of the method could perform better depending on @@ -331,51 +331,51 @@ class Id_to_index_overlay * * See also @ref remove_last. * - * @param faceID @ref IDIdx index of the face to remove. + * @param cellID @ref IDIdx index of the cell to remove. */ - void remove_maximal_face(ID_index faceID); + void remove_maximal_cell(ID_index cellID); /** * @brief Only available for @ref chainmatrix "chain matrices" and if * @ref PersistenceMatrixOptions::has_removable_columns, @ref PersistenceMatrixOptions::has_vine_update * and @ref PersistenceMatrixOptions::has_map_column_container are true. - * Assumes that the face is maximal in the current complex and removes it such that the matrix remains consistent + * Assumes that the cell is maximal in the current complex and removes it such that the matrix remains consistent * (i.e., it is still a compatible bases of the chain complex in the sense of @cite zigzag). - * The maximality of the face is not verified. + * The maximality of the cell is not verified. * Also updates the barcode if it was computed. * - * To maintain the compatibility, vine swaps are done to move the face up to the end of the filtration. Once at + * To maintain the compatibility, vine swaps are done to move the cell up to the end of the filtration. Once at * the end, the removal is trivial. But for @ref chainmatrix "chain matrices", swaps do not actually swap the position - * of the column every time, so the faces appearing after @p faceIndex in the filtration have to be searched first - * within the matrix. If the user has an easy access to the @ref IDIdx of the faces in the order of filtration, + * of the column every time, so the cells appearing after @p cellIndex in the filtration have to be searched first + * within the matrix. If the user has an easy access to the @ref IDIdx of the cells in the order of filtration, * passing them by argument with @p columnsToSwap allows to skip a linear search process. Typically, if the user knows - * that the face he wants to remove is already the last face of the filtration, calling - * @ref remove_maximal_face(ID_index, const std::vector&) "remove_maximal_face(faceID, {})" + * that the cell he wants to remove is already the last cell of the filtration, calling + * @ref remove_maximal_cell(ID_index, const std::vector&) "remove_maximal_cell(cellID, {})" * will be faster than @ref remove_last(). * * See also @ref remove_last. * - * @param faceID @ref IDIdx index of the face to remove. - * @param columnsToSwap Vector of @ref IDIdx indices of the faces coming after @p faceID in the filtration. + * @param cellID @ref IDIdx index of the cell to remove. + * @param columnsToSwap Vector of @ref IDIdx indices of the cells coming after @p cellID in the filtration. */ - void remove_maximal_face(ID_index faceID, const std::vector& columnsToSwap); + void remove_maximal_cell(ID_index cellID, const std::vector& columnsToSwap); /** * @brief Only available if @ref PersistenceMatrixOptions::has_removable_columns is true. Additionally, if the * matrix is a @ref chainmatrix "chain matrix", either @ref PersistenceMatrixOptions::has_map_column_container has to * be true or @ref PersistenceMatrixOptions::has_vine_update has to be false. - * Removes the last face in the filtration from the matrix and updates the barcode if it is stored. + * Removes the last cell in the filtration from the matrix and updates the barcode if it is stored. * - * See also @ref remove_maximal_face. + * See also @ref remove_maximal_cell. * - * For @ref chainmatrix "chain matrices", if @ref PersistenceMatrixOptions::has_vine_update is true, the last face + * For @ref chainmatrix "chain matrices", if @ref PersistenceMatrixOptions::has_vine_update is true, the last cell * does not have to be at the end of the matrix and therefore has to be searched first. In this case, if the user - * already knows the @ref IDIdx of the last face, calling - * @ref remove_maximal_face(ID_index, const std::vector&) "remove_maximal_face(faceID, {})" + * already knows the @ref IDIdx of the last cell, calling + * @ref remove_maximal_cell(ID_index, const std::vector&) "remove_maximal_cell(cellID, {})" * instead allows to skip the search. */ void remove_last(); /** - * @brief Returns the maximal dimension of a face stored in the matrix. Only available + * @brief Returns the maximal dimension of a cell stored in the matrix. Only available * if @ref PersistenceMatrixOptions::has_matrix_maximal_dimension_access is true. * * @return The maximal dimension. @@ -388,24 +388,24 @@ class Id_to_index_overlay */ Index get_number_of_columns() const; /** - * @brief Returns the dimension of the given face. Only available for @ref mp_matrices "non-basic matrices". + * @brief Returns the dimension of the given cell. Only available for @ref mp_matrices "non-basic matrices". * - * @param faceID @ref IDIdx index of the face. - * @return Dimension of the face. + * @param cellID @ref IDIdx index of the cell. + * @return Dimension of the cell. */ - Dimension get_column_dimension(ID_index faceID) const; + Dimension get_column_dimension(ID_index cellID) const; /** - * @brief Adds column corresponding to @p sourceFaceID onto the column corresponding to @p targetFaceID. + * @brief Adds column corresponding to @p sourceCellID onto the column corresponding to @p targetCellID. * * @warning They will be no verification to ensure that the addition makes sense for the validity of the matrix. * For example, a right-to-left addition could corrupt the computation of the barcode if done blindly. * So should be used with care. * - * @param sourceFaceID @ref IDIdx index of the source column. - * @param targetFaceID @ref IDIdx index of the target column. + * @param sourceCellID @ref IDIdx index of the source column. + * @param targetCellID @ref IDIdx index of the target column. */ - void add_to(ID_index sourceFaceID, ID_index targetFaceID); + void add_to(ID_index sourceCellID, ID_index targetCellID); /** * @brief Multiplies the target column with the coefficient and then adds the source column to it. * That is: `targetColumn = (targetColumn * coefficient) + sourceColumn`. @@ -414,11 +414,11 @@ class Id_to_index_overlay * For example, a right-to-left addition could corrupt the computation of the barcode if done blindly. * So should be used with care. * - * @param sourceFaceID @ref IDIdx index of the source column. + * @param sourceCellID @ref IDIdx index of the source column. * @param coefficient Value to multiply. - * @param targetFaceID @ref IDIdx index of the target column. + * @param targetCellID @ref IDIdx index of the target column. */ - void multiply_target_and_add_to(ID_index sourceFaceID, const Field_element& coefficient, ID_index targetFaceID); + void multiply_target_and_add_to(ID_index sourceCellID, const Field_element& coefficient, ID_index targetCellID); /** * @brief Multiplies the source column with the coefficient before adding it to the target column. * That is: `targetColumn += (coefficient * sourceColumn)`. The source column will **not** be modified. @@ -428,10 +428,10 @@ class Id_to_index_overlay * So should be used with care. * * @param coefficient Value to multiply. - * @param sourceFaceID @ref IDIdx index of the source column. - * @param targetFaceID @ref IDIdx index of the target column. + * @param sourceCellID @ref IDIdx index of the source column. + * @param targetCellID @ref IDIdx index of the target column. */ - void multiply_source_and_add_to(const Field_element& coefficient, ID_index sourceFaceID, ID_index targetFaceID); + void multiply_source_and_add_to(const Field_element& coefficient, ID_index sourceCellID, ID_index targetCellID); /** * @brief Zeroes the entry at the given coordinates. Not available for @ref chainmatrix "chain matrices". @@ -440,10 +440,10 @@ class Id_to_index_overlay * * For @ref boundarymatrix "RU matrices", zeros only the entry in \f$ R \f$. * - * @param faceID @ref IDIdx index of the face corresponding to the column of the entry. + * @param cellID @ref IDIdx index of the cell corresponding to the column of the entry. * @param rowIndex @ref rowindex "Row index" of the row of the entry. */ - void zero_entry(ID_index faceID, ID_index rowIndex); + void zero_entry(ID_index cellID, ID_index rowIndex); /** * @brief Zeroes the column at the given index. Not available for @ref chainmatrix "chain matrices". * In general, should be used with care to not destroy the validity @@ -451,20 +451,20 @@ class Id_to_index_overlay * * For @ref boundarymatrix "RU matrices", zeros only the column in \f$ R \f$. * - * @param faceID @ref IDIdx index of the face corresponding to the column. + * @param cellID @ref IDIdx index of the cell corresponding to the column. */ - void zero_column(ID_index faceID); + void zero_column(ID_index cellID); /** * @brief Indicates if the entry at given coordinates has value zero. * * For @ref boundarymatrix "RU matrices", looks into \f$ R \f$. * - * @param faceID @ref IDIdx index of the face corresponding to the column of the entry. + * @param cellID @ref IDIdx index of the cell corresponding to the column of the entry. * @param rowIndex @ref rowindex "Row index" of the row of the entry. * @return true If the entry has value zero. * @return false Otherwise. */ - bool is_zero_entry(ID_index faceID, ID_index rowIndex) const; + bool is_zero_entry(ID_index cellID, ID_index rowIndex) const; /** * @brief Indicates if the column at given index has value zero. * @@ -473,11 +473,11 @@ class Id_to_index_overlay * Note that for @ref chainmatrix "chain matrices", this method should always return false, as a valid * @ref chainmatrix "chain matrix" never has empty columns. * - * @param faceID @ref IDIdx index of the face corresponding to the column. + * @param cellID @ref IDIdx index of the cell corresponding to the column. * @return true If the column has value zero. * @return false Otherwise. */ - bool is_zero_column(ID_index faceID); + bool is_zero_column(ID_index cellID); /** * @brief Returns the @ref IDIdx index of the column which has the given @ref rowindex "row index" as pivot. @@ -487,17 +487,17 @@ class Id_to_index_overlay * the row indices for a @ref boundarymatrix "RU matrix" correspond to the updated @ref IDIdx indices which got * potentially swapped by a vine swap. * - * @param faceIndex @ref rowindex "Row index" of the pivot. + * @param cellIndex @ref rowindex "Row index" of the pivot. * @return @ref IDIdx index of the column with the given pivot. */ - ID_index get_column_with_pivot(ID_index faceIndex) const; + ID_index get_column_with_pivot(ID_index cellIndex) const; /** * @brief Returns the @ref rowindex "row index" of the pivot of the given column. * - * @param faceID @ref IDIdx index of the face corresponding to the column. + * @param cellID @ref IDIdx index of the cell corresponding to the column. * @return The @ref rowindex "row index" of the pivot. */ - ID_index get_pivot(ID_index faceID); + ID_index get_pivot(ID_index cellID); /** * @brief Resets the matrix to an empty matrix. @@ -549,10 +549,10 @@ class Id_to_index_overlay * Swaps the two given columns. Note that it really just swaps two columns and do not updates * anything else, nor performs additions to maintain some properties on the matrix. * - * @param faceID1 First column @ref IDIdx index to swap. - * @param faceID2 Second column @ref IDIdx index to swap. + * @param cellID1 First column @ref IDIdx index to swap. + * @param cellID2 Second column @ref IDIdx index to swap. */ - void swap_columns(ID_index faceID1, ID_index faceID2); + void swap_columns(ID_index cellID1, ID_index cellID2); /** * @brief Only available for simple @ref boundarymatrix "boundary matrices" (only storing R) * and if @ref PersistenceMatrixOptions::has_column_and_row_swaps is true. @@ -568,29 +568,29 @@ class Id_to_index_overlay * Does the same than @ref vine_swap, but assumes that the swap is non trivial and * therefore skips a part of the case study. * - * @param faceID1 @ref IDIdx index of the first face. - * @param faceID2 @ref IDIdx index of the second face. It is assumed that the @ref PosIdx of both only differs by one. + * @param cellID1 @ref IDIdx index of the first cell. + * @param cellID2 @ref IDIdx index of the second cell. It is assumed that the @ref PosIdx of both only differs by one. * @return Let \f$ pos1 \f$ be the @ref PosIdx index of @p columnIndex1 and \f$ pos2 \f$ be the @ref PosIdx index of * @p columnIndex2. The method returns the @ref MatIdx of the column which has now, after the swap, the @ref PosIdx * \f$ max(pos1, pos2) \f$. */ - ID_index vine_swap_with_z_eq_1_case(ID_index faceID1, ID_index faceID2); + ID_index vine_swap_with_z_eq_1_case(ID_index cellID1, ID_index cellID2); /** * @brief Only available if @ref PersistenceMatrixOptions::has_vine_update is true. - * Does a vine swap between two faces which are consecutive in the filtration. Roughly, if \f$ F \f$ is + * Does a vine swap between two cells which are consecutive in the filtration. Roughly, if \f$ F \f$ is * the current filtration represented by the matrix, the method modifies the matrix such that the new state - * corresponds to a valid state for the filtration \f$ F' \f$ equal to \f$ F \f$ but with the two given faces - * at swapped positions. Of course, the two faces should not have a face/coface relation which each other ; + * corresponds to a valid state for the filtration \f$ F' \f$ equal to \f$ F \f$ but with the two given cells + * at swapped positions. Of course, the two cells should not have a face/coface relation which each other ; * \f$ F' \f$ has to be a valid filtration. * See @cite vineyards for more information about vine and vineyards. * - * @param faceID1 @ref IDIdx index of the first face. - * @param faceID2 @ref IDIdx index of the second face. It is assumed that the @ref PosIdx of both only differs by one. + * @param cellID1 @ref IDIdx index of the first cell. + * @param cellID2 @ref IDIdx index of the second cell. It is assumed that the @ref PosIdx of both only differs by one. * @return Let \f$ pos1 \f$ be the @ref PosIdx index of @p columnIndex1 and \f$ pos2 \f$ be the @ref PosIdx index of * @p columnIndex2. The method returns the @ref MatIdx of the column which has now, after the swap, the @ref PosIdx * \f$ max(pos1, pos2) \f$. */ - ID_index vine_swap(ID_index faceID1, ID_index faceID2); + ID_index vine_swap(ID_index cellID1, ID_index cellID2); /** * @brief Only available if @ref PersistenceMatrixOptions::can_retrieve_representative_cycles is true. Pre-computes @@ -752,26 +752,26 @@ inline void Id_to_index_overlay::insert_bounda template template -inline void Id_to_index_overlay::insert_boundary(ID_index faceIndex, +inline void Id_to_index_overlay::insert_boundary(ID_index cellIndex, const Boundary_range& boundary, Dimension dim) { if constexpr (Master_matrix::Option_list::has_map_column_container) { - GUDHI_CHECK(idToIndex_->find(faceIndex) == idToIndex_->end(), + GUDHI_CHECK(idToIndex_->find(cellIndex) == idToIndex_->end(), std::invalid_argument("Id_to_index_overlay::insert_boundary - Index for simplex already chosen!")); } else { - GUDHI_CHECK((idToIndex_->size() <= faceIndex || _id_to_index(faceIndex) == static_cast(-1)), + GUDHI_CHECK((idToIndex_->size() <= cellIndex || _id_to_index(cellIndex) == static_cast(-1)), std::invalid_argument("Id_to_index_overlay::insert_boundary - Index for simplex already chosen!")); } - matrix_.insert_boundary(faceIndex, boundary, dim); + matrix_.insert_boundary(cellIndex, boundary, dim); if constexpr (Master_matrix::Option_list::is_of_boundary_type) { if constexpr (Master_matrix::Option_list::has_map_column_container) { - idToIndex_->emplace(faceIndex, nextIndex_); + idToIndex_->emplace(cellIndex, nextIndex_); } else { - if (idToIndex_->size() <= faceIndex) { - idToIndex_->resize(faceIndex + 1, -1); + if (idToIndex_->size() <= cellIndex) { + idToIndex_->resize(cellIndex + 1, -1); } - _id_to_index(faceIndex) = nextIndex_; + _id_to_index(cellIndex) = nextIndex_; } ++nextIndex_; } @@ -779,9 +779,9 @@ inline void Id_to_index_overlay::insert_bounda template inline typename Id_to_index_overlay::Column& -Id_to_index_overlay::get_column(ID_index faceID) +Id_to_index_overlay::get_column(ID_index cellID) { - return matrix_.get_column(_id_to_index(faceID)); + return matrix_.get_column(_id_to_index(cellID)); } template @@ -798,7 +798,7 @@ inline void Id_to_index_overlay::erase_empty_r } template -inline void Id_to_index_overlay::remove_maximal_face(ID_index faceID) +inline void Id_to_index_overlay::remove_maximal_cell(ID_index cellID) { if constexpr (Master_matrix::Option_list::is_of_boundary_type) { std::vector indexToID(nextIndex_); @@ -812,34 +812,34 @@ inline void Id_to_index_overlay::remove_maxima } } --nextIndex_; - for (Index curr = _id_to_index(faceID); curr < nextIndex_; ++curr) { + for (Index curr = _id_to_index(cellID); curr < nextIndex_; ++curr) { matrix_.vine_swap(curr); std::swap(idToIndex_->at(indexToID[curr]), idToIndex_->at(indexToID[curr + 1])); } matrix_.remove_last(); - GUDHI_CHECK(_id_to_index(faceID) == nextIndex_, - std::logic_error("Id_to_index_overlay::remove_maximal_face - Indexation problem.")); + GUDHI_CHECK(_id_to_index(cellID) == nextIndex_, + std::logic_error("Id_to_index_overlay::remove_maximal_cell - Indexation problem.")); if constexpr (Master_matrix::Option_list::has_map_column_container) { - idToIndex_->erase(faceID); + idToIndex_->erase(cellID); } else { - _id_to_index(faceID) = -1; + _id_to_index(cellID) = -1; } } else { - matrix_.remove_maximal_face(faceID); + matrix_.remove_maximal_cell(cellID); } } template -inline void Id_to_index_overlay::remove_maximal_face( - ID_index faceID, const std::vector& columnsToSwap) +inline void Id_to_index_overlay::remove_maximal_cell( + ID_index cellID, const std::vector& columnsToSwap) { static_assert(!Master_matrix::Option_list::is_of_boundary_type, - "'remove_maximal_face(ID_index,const std::vector&)' is not available for the chosen options."); + "'remove_maximal_cell(ID_index,const std::vector&)' is not available for the chosen options."); std::vector translatedIndices; std::transform(columnsToSwap.cbegin(), columnsToSwap.cend(), std::back_inserter(translatedIndices), [&](ID_index id) { return _id_to_index(id); }); - matrix_.remove_maximal_face(faceID, translatedIndices); + matrix_.remove_maximal_cell(cellID, translatedIndices); } template @@ -881,54 +881,54 @@ Id_to_index_overlay::get_number_of_columns() c template inline typename Id_to_index_overlay::Dimension -Id_to_index_overlay::get_column_dimension(ID_index faceID) const +Id_to_index_overlay::get_column_dimension(ID_index cellID) const { - return matrix_.get_column_dimension(_id_to_index(faceID)); + return matrix_.get_column_dimension(_id_to_index(cellID)); } template -inline void Id_to_index_overlay::add_to(ID_index sourceFaceID, ID_index targetFaceID) +inline void Id_to_index_overlay::add_to(ID_index sourceCellID, ID_index targetCellID) { - return matrix_.add_to(_id_to_index(sourceFaceID), _id_to_index(targetFaceID)); + return matrix_.add_to(_id_to_index(sourceCellID), _id_to_index(targetCellID)); } template inline void Id_to_index_overlay::multiply_target_and_add_to( - ID_index sourceFaceID, const Field_element& coefficient, ID_index targetFaceID) + ID_index sourceCellID, const Field_element& coefficient, ID_index targetCellID) { - return matrix_.multiply_target_and_add_to(_id_to_index(sourceFaceID), coefficient, _id_to_index(targetFaceID)); + return matrix_.multiply_target_and_add_to(_id_to_index(sourceCellID), coefficient, _id_to_index(targetCellID)); } template inline void Id_to_index_overlay::multiply_source_and_add_to( - const Field_element& coefficient, ID_index sourceFaceID, ID_index targetFaceID) + const Field_element& coefficient, ID_index sourceCellID, ID_index targetCellID) { - return matrix_.multiply_source_and_add_to(coefficient, _id_to_index(sourceFaceID), _id_to_index(targetFaceID)); + return matrix_.multiply_source_and_add_to(coefficient, _id_to_index(sourceCellID), _id_to_index(targetCellID)); } template -inline void Id_to_index_overlay::zero_entry(ID_index faceID, ID_index rowIndex) +inline void Id_to_index_overlay::zero_entry(ID_index cellID, ID_index rowIndex) { - return matrix_.zero_entry(_id_to_index(faceID), rowIndex); + return matrix_.zero_entry(_id_to_index(cellID), rowIndex); } template -inline void Id_to_index_overlay::zero_column(ID_index faceID) +inline void Id_to_index_overlay::zero_column(ID_index cellID) { - return matrix_.zero_column(_id_to_index(faceID)); + return matrix_.zero_column(_id_to_index(cellID)); } template -inline bool Id_to_index_overlay::is_zero_entry(ID_index faceID, +inline bool Id_to_index_overlay::is_zero_entry(ID_index cellID, ID_index rowIndex) const { - return matrix_.is_zero_entry(_id_to_index(faceID), rowIndex); + return matrix_.is_zero_entry(_id_to_index(cellID), rowIndex); } template -inline bool Id_to_index_overlay::is_zero_column(ID_index faceID) +inline bool Id_to_index_overlay::is_zero_column(ID_index cellID) { - return matrix_.is_zero_column(_id_to_index(faceID)); + return matrix_.is_zero_column(_id_to_index(cellID)); } template @@ -947,12 +947,12 @@ Id_to_index_overlay::get_column_with_pivot(ID_ template inline typename Id_to_index_overlay::ID_index -Id_to_index_overlay::get_pivot(ID_index faceID) +Id_to_index_overlay::get_pivot(ID_index cellID) { if constexpr (Master_matrix::Option_list::is_of_boundary_type) { - return matrix_.get_pivot(_id_to_index(faceID)); + return matrix_.get_pivot(_id_to_index(cellID)); } else { - return faceID; + return cellID; } } @@ -1004,10 +1004,10 @@ Id_to_index_overlay::get_representative_cycle( } template -inline void Id_to_index_overlay::swap_columns(ID_index faceID1, ID_index faceID2) +inline void Id_to_index_overlay::swap_columns(ID_index cellID1, ID_index cellID2) { - matrix_.swap_columns(_id_to_index(faceID1), _id_to_index(faceID2)); - std::swap(idToIndex_->at(faceID1), idToIndex_->at(faceID2)); + matrix_.swap_columns(_id_to_index(cellID1), _id_to_index(cellID2)); + std::swap(idToIndex_->at(cellID1), idToIndex_->at(cellID2)); } template @@ -1018,10 +1018,10 @@ inline void Id_to_index_overlay::swap_rows(Ind template inline typename Id_to_index_overlay::ID_index -Id_to_index_overlay::vine_swap_with_z_eq_1_case(ID_index faceID1, ID_index faceID2) +Id_to_index_overlay::vine_swap_with_z_eq_1_case(ID_index cellID1, ID_index cellID2) { - Index first = _id_to_index(faceID1); - Index second = _id_to_index(faceID2); + Index first = _id_to_index(cellID1); + Index second = _id_to_index(cellID2); if (first > second) std::swap(first, second); if constexpr (Master_matrix::Option_list::is_of_boundary_type) { @@ -1031,12 +1031,12 @@ Id_to_index_overlay::vine_swap_with_z_eq_1_cas bool change = matrix_.vine_swap_with_z_eq_1_case(first); - std::swap(idToIndex_->at(faceID1), idToIndex_->at(faceID2)); + std::swap(idToIndex_->at(cellID1), idToIndex_->at(cellID2)); if (change) { - return faceID1; + return cellID1; } - return faceID2; + return cellID2; } else { return matrix_.vine_swap_with_z_eq_1_case(first, second); } @@ -1044,10 +1044,10 @@ Id_to_index_overlay::vine_swap_with_z_eq_1_cas template inline typename Id_to_index_overlay::ID_index -Id_to_index_overlay::vine_swap(ID_index faceID1, ID_index faceID2) +Id_to_index_overlay::vine_swap(ID_index cellID1, ID_index cellID2) { - Index first = _id_to_index(faceID1); - Index second = _id_to_index(faceID2); + Index first = _id_to_index(cellID1); + Index second = _id_to_index(cellID2); if (first > second) std::swap(first, second); if constexpr (Master_matrix::Option_list::is_of_boundary_type) { @@ -1056,12 +1056,12 @@ Id_to_index_overlay::vine_swap(ID_index faceID bool change = matrix_.vine_swap(first); - std::swap(idToIndex_->at(faceID1), idToIndex_->at(faceID2)); + std::swap(idToIndex_->at(cellID1), idToIndex_->at(cellID2)); if (change) { - return faceID1; + return cellID1; } - return faceID2; + return cellID2; } else { return matrix_.vine_swap(first, second); } diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Position_to_index_overlay.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Position_to_index_overlay.h index 56cd2c2d27..4a19488230 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Position_to_index_overlay.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Position_to_index_overlay.h @@ -216,10 +216,10 @@ class Position_to_index_overlay /** * @brief Inserts at the end of the matrix a new ordered column corresponding to the given boundary. * This means that it is assumed that this method is called on boundaries in the order of the filtration. - * It also assumes that the faces in the given boundary are identified by their relative position in the filtration, + * It also assumes that the cells in the given boundary are identified by their relative position in the filtration, * starting at 0. If it is not the case, use the other * @ref insert_boundary(ID_index, const Boundary_range&, Dimension) "insert_boundary" instead by indicating the - * face ID used in the boundaries when the face is inserted. + * cell ID used in the boundaries when the cell is inserted. * * Different to the constructor, the boundaries do not have to come from a simplicial complex, but also from * a more general entry complex. This includes cubical complexes or Morse complexes for example. @@ -230,30 +230,30 @@ class Position_to_index_overlay * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() * method. * @param boundary Boundary generating the new column. The content should be ordered by ID. - * @param dim Dimension of the face whose boundary is given. If the complex is simplicial, + * @param dim Dimension of the cell whose boundary is given. If the complex is simplicial, * this parameter can be omitted as it can be deduced from the size of the boundary. */ template void insert_boundary(const Boundary_range& boundary, Dimension dim = -1); /** - * @brief It does the same as the other version, but allows the boundary faces to be identified without restrictions + * @brief It does the same as the other version, but allows the boundary cells to be identified without restrictions * except that all IDs have to be strictly increasing in the order of filtration. Note that you should avoid then * to use the other insertion method to avoid overwriting IDs. * - * As a face has to be inserted before one of its cofaces in a valid filtration (recall that it is assumed that - * the faces are inserted by order of filtration), it is sufficient to indicate the ID of the face being inserted. + * As a cell has to be inserted before one of its cofaces in a valid filtration (recall that it is assumed that + * the cells are inserted by order of filtration), it is sufficient to indicate the ID of the cell being inserted. * * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() * method. - * @param faceIndex @ref IDIdx index to use to identify the new face. + * @param cellIndex @ref IDIdx index to use to identify the new cell. * @param boundary Boundary generating the new column. The indices of the boundary have to correspond to the - * @p faceID values of precedent calls of the method for the corresponding faces and should be ordered in + * @p cellID values of precedent calls of the method for the corresponding cells and should be ordered in * increasing order. - * @param dim Dimension of the face whose boundary is given. If the complex is simplicial, + * @param dim Dimension of the cell whose boundary is given. If the complex is simplicial, * this parameter can be omitted as it can be deduced from the size of the boundary. */ template - void insert_boundary(ID_index faceIndex, const Boundary_range& boundary, Dimension dim = -1); + void insert_boundary(ID_index cellIndex, const Boundary_range& boundary, Dimension dim = -1); /** * @brief Returns the column at the given @ref PosIdx index. * The type of the column depends on the choosen options, see @ref PersistenceMatrixOptions::column_type. @@ -307,28 +307,28 @@ class Position_to_index_overlay * @brief Only available if @ref PersistenceMatrixOptions::has_removable_columns, * @ref PersistenceMatrixOptions::has_vine_update and @ref PersistenceMatrixOptions::has_map_column_container * are true. - * Assumes that the face is maximal in the current complex and removes it such that the matrix remains consistent + * Assumes that the cell is maximal in the current complex and removes it such that the matrix remains consistent * (i.e., the matrix is still a compatible bases of the chain complex in the sense of @cite zigzag). - * The maximality of the face is not verified. + * The maximality of the cell is not verified. * Also updates the barcode if it was computed. * * See also @ref remove_last. * - * @param position @ref PosIdx index of the face to remove. + * @param position @ref PosIdx index of the cell to remove. */ - void remove_maximal_face(Pos_index position); + void remove_maximal_cell(Pos_index position); /** * @brief Only available if @ref PersistenceMatrixOptions::has_removable_columns is true and, * if @ref PersistenceMatrixOptions::has_map_column_container is true or * @ref PersistenceMatrixOptions::has_vine_update is false. - * Removes the last face in the filtration from the matrix and updates the barcode if it is stored. + * Removes the last cell in the filtration from the matrix and updates the barcode if it is stored. * - * See also @ref remove_maximal_face. + * See also @ref remove_maximal_cell. */ void remove_last(); /** - * @brief Returns the maximal dimension of a face stored in the matrix. Only available + * @brief Returns the maximal dimension of a cell stored in the matrix. Only available * if @ref PersistenceMatrixOptions::has_matrix_maximal_dimension_access is true. * * @return The maximal dimension. @@ -341,10 +341,10 @@ class Position_to_index_overlay */ Index get_number_of_columns() const; /** - * @brief Returns the dimension of the given face. + * @brief Returns the dimension of the given cell. * - * @param position @ref PosIdx index of the face. - * @return Dimension of the face. + * @param position @ref PosIdx index of the cell. + * @return Dimension of the cell. */ Dimension get_column_dimension(Pos_index position) const; @@ -393,7 +393,7 @@ class Position_to_index_overlay /** * @brief Indicates if the entry at given coordinates has value zero. * - * @param position @ref PosIdx index of the face corresponding to the column of the entry. + * @param position @ref PosIdx index of the cell corresponding to the column of the entry. * @param rowIndex @ref rowindex "Row index" of the row of the entry. * @return true If the entry has value zero. * @return false Otherwise. @@ -405,7 +405,7 @@ class Position_to_index_overlay * Note that this method should always return false, as a valid @ref chainmatrix "chain matrix" never has * empty columns. * - * @param position @ref PosIdx index of the face corresponding to the column. + * @param position @ref PosIdx index of the cell corresponding to the column. * @return true If the column has value zero. * @return false Otherwise. */ @@ -415,14 +415,14 @@ class Position_to_index_overlay * @brief Returns the @ref PosIdx index of the column which has the given @ref rowindex "row index" as pivot. * Assumes that the pivot exists. * - * @param faceIndex @ref rowindex "Row index" of the pivot. + * @param cellIndex @ref rowindex "Row index" of the pivot. * @return @ref PosIdx index of the column with the given pivot. */ - Pos_index get_column_with_pivot(ID_index faceIndex) const; // assumes that pivot exists + Pos_index get_column_with_pivot(ID_index cellIndex) const; // assumes that pivot exists /** * @brief Returns the @ref rowindex "row index" of the pivot of the given column. * - * @param position @ref PosIdx index of the face corresponding to the column. + * @param position @ref PosIdx index of the cell corresponding to the column. * @return The @ref rowindex "row index" of the pivot. */ ID_index get_pivot(Pos_index position); @@ -500,21 +500,21 @@ class Position_to_index_overlay * Does the same than @ref vine_swap, but assumes that the swap is non trivial and * therefore skips a part of the case study. * - * @param position @ref PosIdx index of the first face to swap. The second one has to be at `position + 1`. + * @param position @ref PosIdx index of the first cell to swap. The second one has to be at `position + 1`. * @return true If the barcode changed from the swap. * @return false Otherwise. */ bool vine_swap_with_z_eq_1_case(Pos_index position); /** * @brief Only available if @ref PersistenceMatrixOptions::has_vine_update is true. - * Does a vine swap between two faces which are consecutive in the filtration. Roughly, if \f$ F \f$ is the current + * Does a vine swap between two cells which are consecutive in the filtration. Roughly, if \f$ F \f$ is the current * filtration represented by the matrix, the method modifies the matrix such that the new state corresponds to - * a valid state for the filtration \f$ F' \f$ equal to \f$ F \f$ but with the two faces at position `position` - * and `position + 1` swapped. Of course, the two faces should not have a face/coface relation which each other ; + * a valid state for the filtration \f$ F' \f$ equal to \f$ F \f$ but with the two cells at position `position` + * and `position + 1` swapped. Of course, the two cells should not have a face/coface relation which each other ; * \f$ F' \f$ has to be a valid filtration. * See @cite vineyards for more information about vine and vineyards. * - * @param position @ref PosIdx index of the first face to swap. The second one has to be at `position + 1`. + * @param position @ref PosIdx index of the first cell to swap. The second one has to be at `position + 1`. * @return true If the barcode changed from the swap. * @return false Otherwise. */ @@ -629,7 +629,7 @@ inline void Position_to_index_overlay::insert_ template template -inline void Position_to_index_overlay::insert_boundary(ID_index faceIndex, +inline void Position_to_index_overlay::insert_boundary(ID_index cellIndex, const Boundary_range& boundary, Dimension dim) { @@ -639,7 +639,7 @@ inline void Position_to_index_overlay::insert_ positionToIndex_[nextPosition_++] = nextIndex_++; - matrix_.insert_boundary(faceIndex, boundary, dim); + matrix_.insert_boundary(cellIndex, boundary, dim); } template @@ -677,7 +677,7 @@ inline void Position_to_index_overlay::erase_e } template -inline void Position_to_index_overlay::remove_maximal_face(Pos_index position) +inline void Position_to_index_overlay::remove_maximal_cell(Pos_index position) { --nextPosition_; @@ -693,7 +693,7 @@ inline void Position_to_index_overlay::remove_ columnsToSwap.back() = positionToIndex_[nextPosition_]; } - matrix_.remove_maximal_face(pivot, columnsToSwap); + matrix_.remove_maximal_cell(pivot, columnsToSwap); } template @@ -702,9 +702,9 @@ inline void Position_to_index_overlay::remove_ --nextPosition_; if constexpr (Master_matrix::Option_list::has_vine_update) { std::vector columnsToSwap; - matrix_.remove_maximal_face(matrix_.get_pivot(positionToIndex_[nextPosition_]), columnsToSwap); + matrix_.remove_maximal_cell(matrix_.get_pivot(positionToIndex_[nextPosition_]), columnsToSwap); } else { - matrix_.remove_last(); // linear with vine updates, so it is better to use remove_maximal_face + matrix_.remove_last(); // linear with vine updates, so it is better to use remove_maximal_cell } } @@ -769,9 +769,9 @@ inline bool Position_to_index_overlay::is_zero template inline typename Position_to_index_overlay::Pos_index -Position_to_index_overlay::get_column_with_pivot(ID_index faceIndex) const +Position_to_index_overlay::get_column_with_pivot(ID_index cellIndex) const { - Index id = matrix_.get_column_with_pivot(faceIndex); + Index id = matrix_.get_column_with_pivot(cellIndex); Pos_index i = 0; while (positionToIndex_[i] != id) ++i; return i; diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/RU_matrix.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/RU_matrix.h index f738404e42..7c3661a8a9 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/RU_matrix.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/RU_matrix.h @@ -30,7 +30,7 @@ namespace persistence_matrix { * * @brief %Matrix structure to store the ordered @ref boundarymatrix "boundary matrix" \f$ R \cdot U \f$ of a filtered * complex in order to compute its persistent homology, as well as representative cycles. - * Supports vineyards (see @cite vineyards) and the removal of maximal faces while maintaining + * Supports vineyards (see @cite vineyards) and the removal of maximal cells while maintaining * a valid barcode. Provides an access to its columns and rows. * * @tparam Master_matrix An instantiation of @ref Matrix from which all types and options are deduced. @@ -115,10 +115,10 @@ class RU_matrix : public Master_matrix::RU_pairing_option, /** * @brief Inserts at the end of the matrix a new ordered column corresponding to the given boundary. * This means that it is assumed that this method is called on boundaries in the order of the filtration. - * It also assumes that the faces in the given boundary are identified by their relative position in the filtration, + * It also assumes that the cells in the given boundary are identified by their relative position in the filtration, * starting at 0. If it is not the case, use the other * @ref insert_boundary(ID_index, const Boundary_range&, Dimension) "insert_boundary" instead by indicating the - * face ID used in the boundaries when the face is inserted. + * cell ID used in the boundaries when the cell is inserted. * * Different to the constructor, the boundaries do not have to come from a simplicial complex, but also from * a more general entry complex. This includes cubical complexes or Morse complexes for example. @@ -128,30 +128,30 @@ class RU_matrix : public Master_matrix::RU_pairing_option, * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() * method. * @param boundary Boundary generating the new column. The content should be ordered by ID. - * @param dim Dimension of the face whose boundary is given. If the complex is simplicial, + * @param dim Dimension of the cell whose boundary is given. If the complex is simplicial, * this parameter can be omitted as it can be deduced from the size of the boundary. */ template void insert_boundary(const Boundary_range& boundary, Dimension dim = -1); /** - * @brief It does the same as the other version, but allows the boundary faces to be identified without restrictions + * @brief It does the same as the other version, but allows the boundary cells to be identified without restrictions * except that all IDs have to be strictly increasing in the order of filtration. Note that you should avoid then * to use the other insertion method to avoid overwriting IDs. * - * As a face has to be inserted before one of its cofaces in a valid filtration (recall that it is assumed that - * the faces are inserted by order of filtration), it is sufficient to indicate the ID of the face being inserted. + * As a cell has to be inserted before one of its cofaces in a valid filtration (recall that it is assumed that + * the cells are inserted by order of filtration), it is sufficient to indicate the ID of the cell being inserted. * * @tparam Boundary_range Range of @ref Matrix::Entry_representative. Assumed to have a begin(), end() and size() * method. - * @param faceIndex @ref IDIdx index to use to identify the new face. + * @param cellIndex @ref IDIdx index to use to identify the new cell. * @param boundary Boundary generating the new column. The indices of the boundary have to correspond to the - * @p faceIndex values of precedent calls of the method for the corresponding faces and should be ordered in + * @p cellIndex values of precedent calls of the method for the corresponding cells and should be ordered in * increasing order. - * @param dim Dimension of the face whose boundary is given. If the complex is simplicial, + * @param dim Dimension of the cell whose boundary is given. If the complex is simplicial, * this parameter can be omitted as it can be deduced from the size of the boundary. */ template - void insert_boundary(ID_index faceIndex, const Boundary_range& boundary, Dimension dim = -1); + void insert_boundary(ID_index cellIndex, const Boundary_range& boundary, Dimension dim = -1); /** * @brief Returns the column at the given @ref MatIdx index in \f$ R \f$ if @p inR is true and * in \f$ U \f$ if @p inR is false. @@ -203,26 +203,26 @@ class RU_matrix : public Master_matrix::RU_pairing_option, /** * @brief Only available if @ref PersistenceMatrixOptions::has_removable_columns and * @ref PersistenceMatrixOptions::has_vine_update are true. - * Assumes that the face is maximal in the current complex and removes it such that the matrix remains consistent + * Assumes that the cell is maximal in the current complex and removes it such that the matrix remains consistent * (i.e., RU is still an upper triangular decomposition of the @ref boundarymatrix "boundary matrix"). - * The maximality of the face is not verified. + * The maximality of the cell is not verified. * Also updates the barcode if it is stored. * * See also @ref remove_last. * - * @param columnIndex @ref MatIdx index of the face to remove. + * @param columnIndex @ref MatIdx index of the cell to remove. */ - void remove_maximal_face(Index columnIndex); + void remove_maximal_cell(Index columnIndex); /** * @brief Only available if @ref PersistenceMatrixOptions::has_removable_columns is true. - * Removes the last face in the filtration from the matrix and updates the barcode if it is stored. + * Removes the last cell in the filtration from the matrix and updates the barcode if it is stored. * - * See also @ref remove_maximal_face. + * See also @ref remove_maximal_cell. */ void remove_last(); /** - * @brief Returns the maximal dimension of a face stored in the matrix. + * @brief Returns the maximal dimension of a cell stored in the matrix. * Only available if @ref PersistenceMatrixOptions::has_matrix_maximal_dimension_access is true. * * @return The maximal dimension. @@ -237,8 +237,8 @@ class RU_matrix : public Master_matrix::RU_pairing_option, /** * @brief Returns the dimension of the given column. * - * @param columnIndex @ref MatIdx index of the column representing the face. - * @return Dimension of the face. + * @param columnIndex @ref MatIdx index of the column representing the cell. + * @return Dimension of the cell. */ Dimension get_column_dimension(Index columnIndex) const; @@ -331,10 +331,10 @@ class RU_matrix : public Master_matrix::RU_pairing_option, * @brief Returns the @ref MatIdx index of the column which has the given @ref rowindex "row index" as pivot in * \f$ R \f$. Assumes that the pivot exists. * - * @param faceIndex @ref rowindex "Row index" of the pivot. + * @param cellIndex @ref rowindex "Row index" of the pivot. * @return @ref MatIdx index of the column in \f$ R \f$ with the given pivot. */ - Index get_column_with_pivot(Index faceIndex) const; + Index get_column_with_pivot(Index cellIndex) const; /** * @brief Returns the @ref rowindex "row index" of the pivot of the given column in \f$ R \f$. * @@ -522,28 +522,28 @@ inline void RU_matrix::insert_boundary(const Boundary_range& boun template template -inline void RU_matrix::insert_boundary(ID_index faceIndex, +inline void RU_matrix::insert_boundary(ID_index cellIndex, const Boundary_range& boundary, Dimension dim) { // maps for possible shifting between column content and position indices used for birth events if constexpr (Master_matrix::Option_list::has_column_pairings && !Master_matrix::Option_list::has_vine_update) { - if (faceIndex != nextEventIndex_) { - Pair_opt::idToPosition_.emplace(faceIndex, nextEventIndex_); + if (cellIndex != nextEventIndex_) { + Pair_opt::idToPosition_.emplace(cellIndex, nextEventIndex_); if constexpr (Master_matrix::Option_list::has_removable_columns) { - Pair_opt::PIDM::map_.emplace(nextEventIndex_, faceIndex); + Pair_opt::PIDM::map_.emplace(nextEventIndex_, cellIndex); } } } if constexpr (Master_matrix::Option_list::has_vine_update) { - if (faceIndex != nextEventIndex_) { - Swap_opt::_positionToRowIdx().emplace(nextEventIndex_, faceIndex); + if (cellIndex != nextEventIndex_) { + Swap_opt::_positionToRowIdx().emplace(nextEventIndex_, cellIndex); if (Master_matrix::Option_list::has_column_pairings) { - Swap_opt::template RU_pairing::idToPosition_.emplace(faceIndex, nextEventIndex_); + Swap_opt::template RU_pairing::idToPosition_.emplace(cellIndex, nextEventIndex_); } } } - _insert_boundary(reducedMatrixR_.insert_boundary(faceIndex, boundary, dim)); + _insert_boundary(reducedMatrixR_.insert_boundary(cellIndex, boundary, dim)); } template @@ -573,10 +573,10 @@ inline void RU_matrix::erase_empty_row(Index rowIndex) } template -inline void RU_matrix::remove_maximal_face(Index columnIndex) +inline void RU_matrix::remove_maximal_cell(Index columnIndex) { static_assert(Master_matrix::Option_list::has_removable_columns && Master_matrix::Option_list::has_vine_update, - "'remove_maximal_face' is not implemented for the chosen options."); + "'remove_maximal_cell' is not implemented for the chosen options."); // TODO: is there an easy test to verify maximality even without row access? @@ -699,12 +699,12 @@ inline bool RU_matrix::is_zero_column(Index columnIndex, bool inR } template -inline typename RU_matrix::Index RU_matrix::get_column_with_pivot(Index faceIndex) const +inline typename RU_matrix::Index RU_matrix::get_column_with_pivot(Index cellIndex) const { if constexpr (Master_matrix::Option_list::has_map_column_container) { - return pivotToColumnIndex_.at(faceIndex); + return pivotToColumnIndex_.at(cellIndex); } else { - return pivotToColumnIndex_[faceIndex]; + return pivotToColumnIndex_[cellIndex]; } } diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/base_pairing.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/base_pairing.h index ac883fff38..8ce95ce743 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/base_pairing.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/base_pairing.h @@ -23,7 +23,7 @@ #include #include -#include "boundary_face_position_to_id_mapper.h" +#include "boundary_cell_position_to_id_mapper.h" namespace Gudhi { namespace persistence_matrix { @@ -50,7 +50,7 @@ struct Dummy_base_pairing { template class Base_pairing : public std::conditional< Master_matrix::Option_list::has_removable_columns, - Face_position_to_ID_mapper, + Cell_position_to_ID_mapper, Dummy_pos_mapper >::type { @@ -82,8 +82,8 @@ class Base_pairing : public std::conditional< */ friend void swap(Base_pairing& pairing1, Base_pairing& pairing2) { if constexpr (Master_matrix::Option_list::has_removable_columns) { - swap(static_cast&>(pairing1), - static_cast&>(pairing2)); + swap(static_cast&>(pairing1), + static_cast&>(pairing2)); } pairing1.barcode_.swap(pairing2.barcode_); pairing1.deathToBar_.swap(pairing2.deathToBar_); @@ -98,14 +98,14 @@ class Base_pairing : public std::conditional< using Base_matrix = typename Master_matrix::Master_boundary_matrix; //PIDM = Position to ID Map using PIDM = typename std::conditional, + Cell_position_to_ID_mapper, Dummy_pos_mapper >::type; Barcode barcode_; /**< Bar container. */ Dictionary deathToBar_; /**< Map from death index to bar index. */ /** - * @brief Map from face ID to face position. Only stores a pair if ID != position. + * @brief Map from cell ID to cell position. Only stores a pair if ID != position. */ std::unordered_map idToPosition_; //TODO: test other map types bool isReduced_; /**< True if `_reduce()` was called. */ diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/boundary_face_position_to_id_mapper.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/boundary_cell_position_to_id_mapper.h similarity index 74% rename from src/Persistence_matrix/include/gudhi/Persistence_matrix/boundary_face_position_to_id_mapper.h rename to src/Persistence_matrix/include/gudhi/Persistence_matrix/boundary_cell_position_to_id_mapper.h index 5464804196..1b85b07c82 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/boundary_face_position_to_id_mapper.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/boundary_cell_position_to_id_mapper.h @@ -9,10 +9,10 @@ */ /** - * @file base_pairing.h + * @file boundary_cell_position_to_id_mapper.h * @author Hannah Schreiber - * @brief Contains the @ref Gudhi::persistence_matrix::Base_pairing class and - * @ref Gudhi::persistence_matrix::Dummy_base_pairing structure. + * @brief Contains the @ref Gudhi::persistence_matrix::Cell_position_to_ID_mapper class and + * @ref Gudhi::persistence_matrix::Dummy_pos_mapper structure. */ #ifndef PM_ID_POS_MAPPER_H @@ -28,7 +28,7 @@ namespace persistence_matrix { * @ingroup persistence_matrix * * @brief Empty structure. - * Inherited instead of @ref Face_position_to_ID_mapper. + * Inherited instead of @ref Cell_position_to_ID_mapper. */ struct Dummy_pos_mapper { friend void swap([[maybe_unused]] Dummy_pos_mapper& d1, [[maybe_unused]] Dummy_pos_mapper& d2) {} @@ -38,18 +38,18 @@ struct Dummy_pos_mapper { * @private * @ingroup persistence_matrix * - * @brief Map from face position to face ID. Only stores a pair if ID != position and has_removable_column is true. + * @brief Map from cell position to cell ID. Only stores a pair if ID != position and has_removable_column is true. * * @tparam ID_index @ref IDIdx index type * @tparam Pos_index @ref PosIdx index type */ template -struct Face_position_to_ID_mapper { +struct Cell_position_to_ID_mapper { using Index_map = std::unordered_map; //TODO: test other map types Index_map map_; - friend void swap(Face_position_to_ID_mapper& mapper1, Face_position_to_ID_mapper& mapper2) { + friend void swap(Cell_position_to_ID_mapper& mapper1, Cell_position_to_ID_mapper& mapper2) { mapper1.map_.swap(mapper2.map_); } }; diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/chain_vine_swap.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/chain_vine_swap.h index 887f89cb2c..3168b54031 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/chain_vine_swap.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/chain_vine_swap.h @@ -281,23 +281,23 @@ class Chain_vine_swap : public std::conditional dimensions_; /**< Number of faces by dimension. */ - Dimension maxDim_; /**< Current maximal dimension. */ + std::vector dimensions_; /**< Number of cells by dimension. */ + Dimension maxDim_; /**< Current maximal dimension. */ void update_up(unsigned int dimension) { if (dimensions_.size() <= dimension) dimensions_.resize(dimension + 1, 0); diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_pairing.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_pairing.h index f44e518e78..e6afe9fc89 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_pairing.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_pairing.h @@ -20,7 +20,7 @@ #include -#include "boundary_face_position_to_id_mapper.h" +#include "boundary_cell_position_to_id_mapper.h" namespace Gudhi { namespace persistence_matrix { @@ -48,7 +48,7 @@ struct Dummy_ru_pairing template class RU_pairing : public std::conditional< Master_matrix::Option_list::has_removable_columns, - Face_position_to_ID_mapper, + Cell_position_to_ID_mapper, Dummy_pos_mapper >::type { @@ -57,9 +57,9 @@ class RU_pairing : public std::conditional< using ID_index = typename Master_matrix::ID_index; //PIDM = Position to ID Map using PIDM = typename std::conditional, - Dummy_pos_mapper - >::type; + Cell_position_to_ID_mapper, + Dummy_pos_mapper + >::type; public: using Barcode = typename Master_matrix::Barcode; /**< Barcode type. */ @@ -93,7 +93,7 @@ class RU_pairing : public std::conditional< Barcode barcode_; /**< Bar container. */ Dictionary indexToBar_; /**< Map from @ref MatIdx index to bar index. */ /** - * @brief Map from face ID to face position. Only stores a pair if ID != position. + * @brief Map from cell ID to cell position. Only stores a pair if ID != position. */ std::unordered_map idToPosition_; //TODO: test other map types diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_vine_swap.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_vine_swap.h index 64561c8683..00c76749f7 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_vine_swap.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_vine_swap.h @@ -25,7 +25,7 @@ #include //std::invalid_argument #include "ru_pairing.h" -#include "boundary_face_position_to_id_mapper.h" +#include "boundary_cell_position_to_id_mapper.h" namespace Gudhi { namespace persistence_matrix { @@ -68,7 +68,7 @@ class RU_vine_swap : public std::conditional >::type { @@ -98,20 +98,20 @@ class RU_vine_swap : public std::conditional&>(swap1), static_cast&>(swap2)); } if (!Master_matrix::Option_list::has_column_pairings || !Master_matrix::Option_list::has_removable_columns) { - swap(static_cast&>(swap1), - static_cast&>(swap2)); + swap(static_cast&>(swap1), + static_cast&>(swap2)); } } @@ -144,7 +144,7 @@ class RU_vine_swap : public std::conditional + Cell_position_to_ID_mapper >::type; constexpr auto& _positionToRowIdx(); diff --git a/src/Persistence_matrix/test/pm_matrix_tests.h b/src/Persistence_matrix/test/pm_matrix_tests.h index c6785b9b92..dd20612656 100644 --- a/src/Persistence_matrix/test/pm_matrix_tests.h +++ b/src/Persistence_matrix/test/pm_matrix_tests.h @@ -902,7 +902,7 @@ void test_ru_maximal_simplex_removal() { } if constexpr (Matrix::Option_list::has_vine_update) { - m.remove_maximal_face(6); + m.remove_maximal_cell(6); } else { m.remove_last(); } @@ -927,7 +927,7 @@ void test_chain_maximal_simplex_removal(Matrix& m) { if constexpr (Matrix::Option_list::has_vine_update && Matrix::Option_list::has_map_column_container && Matrix::Option_list::has_column_pairings) { - m.remove_maximal_face(6); + m.remove_maximal_cell(6); } else { m.remove_last(); } @@ -957,7 +957,7 @@ void test_maximal_dimension(Matrix& m) { if constexpr (Matrix::Option_list::has_vine_update && (Matrix::Option_list::is_of_boundary_type || (Matrix::Option_list::has_map_column_container && Matrix::Option_list::has_column_pairings))) { - m.remove_maximal_face(7); + m.remove_maximal_cell(7); BOOST_CHECK_EQUAL(m.get_max_dimension(), 3); } } From b4694d930d810c26c5aa5234dc059ce2f771595f Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Thu, 26 Sep 2024 15:59:43 +0200 Subject: [PATCH 78/96] code review: just test if windows for pykeops --- .../modules/GUDHI_third_party_libraries.cmake | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/cmake/modules/GUDHI_third_party_libraries.cmake b/src/cmake/modules/GUDHI_third_party_libraries.cmake index ffed360461..a72d106bb2 100644 --- a/src/cmake/modules/GUDHI_third_party_libraries.cmake +++ b/src/cmake/modules/GUDHI_third_party_libraries.cmake @@ -186,18 +186,12 @@ if (WITH_GUDHI_PYTHON) find_python_module("pydata_sphinx_theme") find_python_module("sphinxcontrib.bibtex") find_python_module("networkx") + # Specific case for PyKeops that can be imported on Windows, but fails because it uses fcntl (not available on Windows) + if (NOT WIN32) + find_python_module("pykeops") + endif() endif() - # Specific case for PyKeops that can be imported on Windows, but fails because it uses fcntl (not available on Windows) - # Also fcntl has no metadata, so find_python_module does not work - # "import fcntl" is about 1 sec. faster than "import pykeops" - execute_process( - COMMAND ${Python_EXECUTABLE} -c "import fcntl" - RESULT_VARIABLE FCNTL_IMPORT_MODULE_RESULT - OUTPUT_VARIABLE FCNTL_IMPORT_MODULE_OUPUT) - if(FCNTL_IMPORT_MODULE_RESULT EQUAL 0) - find_python_module("pykeops") - endif() if(NOT GUDHI_PYTHON_PATH) message(FATAL_ERROR "ERROR: GUDHI_PYTHON_PATH is not valid.") From 9df2c0460d5ca9b646fa228fb3b228aeed8d967a Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Thu, 26 Sep 2024 16:47:29 +0200 Subject: [PATCH 79/96] try sphinx_autodoc_typehints --- src/python/doc/conf.py | 5 ++- src/python/gudhi/sklearn/rips_persistence.py | 42 ++++++++++---------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/python/doc/conf.py b/src/python/doc/conf.py index 76c8e15ece..6adf827328 100755 --- a/src/python/doc/conf.py +++ b/src/python/doc/conf.py @@ -8,18 +8,21 @@ sys.path.insert(0, os.path.abspath(".")) extensions = [ + "sphinx.ext.napoleon", + # let napoleon be the first extension, cf. https://github.com/tox-dev/sphinx-autodoc-typehints/issues/15 "matplotlib.sphinxext.plot_directive", "sphinx.ext.autodoc", + "sphinx_autodoc_typehints", "sphinx.ext.doctest", "sphinx.ext.mathjax", "sphinx.ext.ifconfig", "sphinx.ext.viewcode", - "sphinx.ext.napoleon", "sphinxcontrib.bibtex", "sphinx_paramlinks", ] autodoc_class_signature = "separated" +autodoc_typehints = "description" bibtex_bibfiles = ["../../biblio/bibliography.bib"] diff --git a/src/python/gudhi/sklearn/rips_persistence.py b/src/python/gudhi/sklearn/rips_persistence.py index 68f0646e14..b5c643fb1f 100644 --- a/src/python/gudhi/sklearn/rips_persistence.py +++ b/src/python/gudhi/sklearn/rips_persistence.py @@ -52,25 +52,25 @@ def __init__( homology_coeff_field: int = 11, n_jobs: Optional[int] = None, ): - """ - Constructor for the RipsPersistence class. - - Parameters: - homology_dimensions (int or list of int): The returned persistence diagrams dimension(s). - Short circuit the use of :class:`~gudhi.representations.preprocessing.DimensionSelector` when only one - dimension matters (in other words, when `homology_dimensions` is an int). - threshold (float): Rips maximal edge length value. Default is +Inf. Ignored if input_type is 'distance coo_matrix'. - input_type (str): Can be 'point cloud' when inputs are point clouds, 'full distance matrix', - 'lower distance matrix' when inputs are lower triangular distance matrix (can be full square, - but the upper part will not be considered), or 'distance coo_matrix' for a distance matrix in SciPy's - sparse format, which should contain each edge at most once (avoid the symmetric) and no diagonal entry. - Default is 'point cloud'. - num_collapses (int|str): Specify the number of iterations of :func:`~gudhi.flag_filtration.edge_collapse.reduce_graph` - (edge collapse) to perform on the graph. Default value is 'auto'. - homology_coeff_field (int): The homology coefficient field. Must be a prime number. Default value is 11. - n_jobs (Optional[int]): Number of jobs to run in parallel. `None` (default value) means `n_jobs = 1` unless in a - joblib.parallel_backend context. `-1` means using all processors. cf. - https://joblib.readthedocs.io/en/latest/generated/joblib.Parallel.html for more details. + """Constructor for the RipsPersistence class. + + :param homology_dimensions: The returned persistence diagrams dimension(s). + Short circuit the use of :class:`~gudhi.representations.preprocessing.DimensionSelector` when only one + dimension matters (in other words, when `homology_dimensions` is an int). + :param threshold: Rips maximal edge length value. Default is +Inf. Ignored if input_type is + 'distance coo_matrix'. + :param input_type: Can be 'point cloud' when inputs are point clouds, 'full distance matrix', + 'lower distance matrix' when inputs are lower triangular distance matrix (can be full square, + but the upper part will not be considered), or 'distance coo_matrix' for a distance matrix in SciPy's + sparse format, which should contain each edge at most once (avoid the symmetric) and no diagonal entry. + Default is 'point cloud'. + :param num_collapses: Specify the number of iterations of + :func:`~gudhi.flag_filtration.edge_collapse.reduce_graph` (edge collapse) to perform on the graph. + Default value is 'auto'. + :param homology_coeff_field: The homology coefficient field. Must be a prime number. Default value is 11. + :param n_jobs: Number of jobs to run in parallel. `None` (default value) means `n_jobs = 1` unless in a + joblib.parallel_backend context. `-1` means using all processors. cf. + https://joblib.readthedocs.io/en/latest/generated/joblib.Parallel.html for more details. """ self.homology_dimensions = homology_dimensions self.threshold = threshold @@ -165,7 +165,7 @@ def __transform(self, inp): dgm = _sparse(inp.row, inp.col, inp.data, inp.shape[0], max_dimension=max_dimension, max_edge_length=threshold, homology_coeff_field=self.homology_coeff_field) else: raise ValueError("Only 'point cloud', 'lower distance matrix', 'full distance matrix' and 'distance coo_matrix' are valid input_type") # move to __init__? - + # dgm stops at n-2 return [dgm[dim] if dim < len(dgm) else np.empty((0,2)) for dim in self.dim_list_] @@ -177,7 +177,7 @@ def transform(self, X, Y=None): :return: Persistence diagrams in the format: - - If `homology_dimensions` was set to `n`: `[array( Hn(X[0]) ), array( Hn(X[1]) ), ...]` + - If `homology_dimensions` was set to `n`: `[array( Hn(X[0]) ), array( Hn(X[1]) ), ...]` - If `homology_dimensions` was set to `[i, j]`: `[[array( Hi(X[0]) ), array( Hj(X[0]) )], [array( Hi(X[1]) ), array( Hj(X[1]) )], ...]` :rtype: list of numpy ndarray of shape (,2) or list of list of numpy ndarray of shape (,2) From 9fbea63b0db06a40a80d5be379bbfda24677985a Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Thu, 26 Sep 2024 16:51:05 +0200 Subject: [PATCH 80/96] [skip ci] code review: Rework comment. Remove comments that were no more relevant. --- src/cmake/modules/GUDHI_third_party_libraries.cmake | 2 +- src/python/CMakeLists.txt | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/cmake/modules/GUDHI_third_party_libraries.cmake b/src/cmake/modules/GUDHI_third_party_libraries.cmake index a72d106bb2..6527d0be3c 100644 --- a/src/cmake/modules/GUDHI_third_party_libraries.cmake +++ b/src/cmake/modules/GUDHI_third_party_libraries.cmake @@ -186,7 +186,7 @@ if (WITH_GUDHI_PYTHON) find_python_module("pydata_sphinx_theme") find_python_module("sphinxcontrib.bibtex") find_python_module("networkx") - # Specific case for PyKeops that can be imported on Windows, but fails because it uses fcntl (not available on Windows) + # Specific case for PyKeops on Windows where import fails because it uses fcntl (not available on Windows) if (NOT WIN32) find_python_module("pykeops") endif() diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index e68e8f2c64..3198461820 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -142,7 +142,6 @@ else() disable_python_documentation("ot") endif() if(HNSWLIB_FOUND) - # Does not have a version number... add_gudhi_debug_info("HNSWlib version ${HNSWLIB_VERSION}") endif() if(TORCH_FOUND) @@ -175,7 +174,6 @@ else() disable_python_documentation("pydata_sphinx_theme") endif() if(SPHINXCONTRIB.BIBTEX_FOUND) - # Does not have a version number... add_gudhi_debug_info("sphinxcontrib-bibtex version ${SPHINXCONTRIB.BIBTEX_VERSION}") else() disable_python_documentation("sphinxcontrib-bibtex") From f8ecddfac18aa7e6ab3bde0e72cec29a269c3876 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Thu, 26 Sep 2024 22:35:52 +0200 Subject: [PATCH 81/96] make sphinx-autodoc-typehints work as required (cmake, ci, doc) --- .circleci/config.yml | 20 ++++++++----------- .../modules/GUDHI_third_party_libraries.cmake | 1 + src/python/CMakeLists.txt | 5 +++++ src/python/doc/conf.py | 2 +- src/python/doc/installation.rst | 2 ++ 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6559558c32..1dbd459a57 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,12 +1,11 @@ version: 2.0 jobs: - -### With all third parties + ### With all third parties examples: docker: # cf. https://github.com/GUDHI/gudhi-deploy/blob/main/Dockerfile_for_circleci_image - - image: gudhi/ci_for_gudhi:2024.06.02 + - image: gudhi/ci_for_gudhi:2024.09.01 steps: - checkout - run: @@ -25,7 +24,7 @@ jobs: tests: docker: - - image: gudhi/ci_for_gudhi:2024.06.02 + - image: gudhi/ci_for_gudhi:2024.09.01 steps: - checkout - run: @@ -44,7 +43,7 @@ jobs: debug_tests: docker: - - image: gudhi/ci_for_gudhi:2024.06.02 + - image: gudhi/ci_for_gudhi:2024.09.01 steps: - checkout - run: @@ -63,7 +62,7 @@ jobs: utils: docker: - - image: gudhi/ci_for_gudhi:2024.06.02 + - image: gudhi/ci_for_gudhi:2024.09.01 steps: - checkout - run: @@ -82,7 +81,7 @@ jobs: python: docker: - - image: gudhi/ci_for_gudhi:2024.06.02 + - image: gudhi/ci_for_gudhi:2024.09.01 resource_class: large # Delaunay complex requires about 5 Gb of RAM to compile steps: - checkout @@ -94,7 +93,6 @@ jobs: - run: name: Build and test python module. Generates and tests the python documentation command: | - pip3 install pydata-sphinx-theme mkdir build cd build cmake -DWITH_GUDHI_THIRD_PARTY=OFF -DUSER_VERSION_DIR=version .. @@ -167,8 +165,7 @@ jobs: latexmk -pdf -interaction=nonstopmode test_biblio.tex latexmk -pdf -interaction=nonstopmode test_gudhi_citation.tex - -### With all third parties, except CGAL and Eigen + ### With all third parties, except CGAL and Eigen examples_without_cgal_eigen: docker: @@ -248,8 +245,7 @@ jobs: python3 setup.py build_ext --inplace ctest --output-on-failure - -### With all third parties, except CGAL + ### With all third parties, except CGAL examples_without_cgal: docker: diff --git a/src/cmake/modules/GUDHI_third_party_libraries.cmake b/src/cmake/modules/GUDHI_third_party_libraries.cmake index 6527d0be3c..250401ff3a 100644 --- a/src/cmake/modules/GUDHI_third_party_libraries.cmake +++ b/src/cmake/modules/GUDHI_third_party_libraries.cmake @@ -185,6 +185,7 @@ if (WITH_GUDHI_PYTHON) find_python_module("sphinx_paramlinks") find_python_module("pydata_sphinx_theme") find_python_module("sphinxcontrib.bibtex") + find_python_module("sphinx-autodoc-typehints") find_python_module("networkx") # Specific case for PyKeops on Windows where import fails because it uses fcntl (not available on Windows) if (NOT WIN32) diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index 3198461820..4be5ce9602 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -178,6 +178,11 @@ if(SPHINXCONTRIB.BIBTEX_FOUND) else() disable_python_documentation("sphinxcontrib-bibtex") endif() +if(SPHINX-AUTODOC-TYPEHINTS_FOUND) + add_gudhi_debug_info("sphinx-autodoc-typehints version ${SPHINX-AUTODOC-TYPEHINTS_VERSION}") +else() + disable_python_documentation("sphinx-autodoc-typehints") +endif() if(NETWORKX_FOUND) add_gudhi_debug_info("NetworkX version ${NETWORKX_VERSION}") endif() diff --git a/src/python/doc/conf.py b/src/python/doc/conf.py index 6adf827328..a974c7aee4 100755 --- a/src/python/doc/conf.py +++ b/src/python/doc/conf.py @@ -22,7 +22,7 @@ ] autodoc_class_signature = "separated" -autodoc_typehints = "description" +autodoc_typehints = "none" bibtex_bibfiles = ["../../biblio/bibliography.bib"] diff --git a/src/python/doc/installation.rst b/src/python/doc/installation.rst index 067b733efb..d3aff7e706 100644 --- a/src/python/doc/installation.rst +++ b/src/python/doc/installation.rst @@ -183,6 +183,7 @@ A complete configuration would be : Sphinx-paramlinks version 0.6.0 pydata_sphinx_theme version 0.15.2 sphinxcontrib-bibtex version 2.6.2 + sphinx-autodoc-typehints version 2.4.4 NetworkX version 3.3 Eigen3 version 3.4.0 Boost version 1.84.0 @@ -204,6 +205,7 @@ Documentation To build the documentation, `sphinx-doc `_, `sphinxcontrib-bibtex `_, +`sphinx-autodoc-typehints `_, `sphinxcontrib-paramlinks `_ and `pydata-sphinx-theme `_ :math:`\geq` 0.8.0 are required. As the documentation is auto-tested, `CGAL`_, `Eigen`_, From 52aa6022583a68c781ce925a904d7870c5206c62 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Fri, 27 Sep 2024 12:33:06 +0200 Subject: [PATCH 82/96] code review: switch to google style --- src/python/gudhi/sklearn/rips_persistence.py | 35 ++++++++++---------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/python/gudhi/sklearn/rips_persistence.py b/src/python/gudhi/sklearn/rips_persistence.py index b5c643fb1f..ff6bbecba6 100644 --- a/src/python/gudhi/sklearn/rips_persistence.py +++ b/src/python/gudhi/sklearn/rips_persistence.py @@ -54,23 +54,24 @@ def __init__( ): """Constructor for the RipsPersistence class. - :param homology_dimensions: The returned persistence diagrams dimension(s). - Short circuit the use of :class:`~gudhi.representations.preprocessing.DimensionSelector` when only one - dimension matters (in other words, when `homology_dimensions` is an int). - :param threshold: Rips maximal edge length value. Default is +Inf. Ignored if input_type is - 'distance coo_matrix'. - :param input_type: Can be 'point cloud' when inputs are point clouds, 'full distance matrix', - 'lower distance matrix' when inputs are lower triangular distance matrix (can be full square, - but the upper part will not be considered), or 'distance coo_matrix' for a distance matrix in SciPy's - sparse format, which should contain each edge at most once (avoid the symmetric) and no diagonal entry. - Default is 'point cloud'. - :param num_collapses: Specify the number of iterations of - :func:`~gudhi.flag_filtration.edge_collapse.reduce_graph` (edge collapse) to perform on the graph. - Default value is 'auto'. - :param homology_coeff_field: The homology coefficient field. Must be a prime number. Default value is 11. - :param n_jobs: Number of jobs to run in parallel. `None` (default value) means `n_jobs = 1` unless in a - joblib.parallel_backend context. `-1` means using all processors. cf. - https://joblib.readthedocs.io/en/latest/generated/joblib.Parallel.html for more details. + Parameters: + homology_dimensions: The returned persistence diagrams dimension(s). + Short circuit the use of :class:`~gudhi.representations.preprocessing.DimensionSelector` when only one + dimension matters (in other words, when `homology_dimensions` is an int). + threshold: Rips maximal edge length value. Default is +Inf. Ignored if input_type is + 'distance coo_matrix'. + input_type: Can be 'point cloud' when inputs are point clouds, 'full distance matrix', + 'lower distance matrix' when inputs are lower triangular distance matrix (can be full square, + but the upper part will not be considered), or 'distance coo_matrix' for a distance matrix in SciPy's + sparse format, which should contain each edge at most once (avoid the symmetric) and no diagonal entry. + Default is 'point cloud'. + num_collapses: Specify the number of iterations of + :func:`~gudhi.flag_filtration.edge_collapse.reduce_graph` (edge collapse) to perform on the graph. + Default value is 'auto'. + homology_coeff_field: The homology coefficient field. Must be a prime number. Default value is 11. + n_jobs: Number of jobs to run in parallel. `None` (default value) means `n_jobs = 1` unless in a + joblib.parallel_backend context. `-1` means using all processors. cf. + https://joblib.readthedocs.io/en/latest/generated/joblib.Parallel.html for more details. """ self.homology_dimensions = homology_dimensions self.threshold = threshold From 20c7761a60a3e5ddf48f8aaaad898d773223f415 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Mon, 30 Sep 2024 09:42:15 +0200 Subject: [PATCH 83/96] code review: optimize some options --- src/python/doc/conf.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/python/doc/conf.py b/src/python/doc/conf.py index a974c7aee4..5738d04eab 100755 --- a/src/python/doc/conf.py +++ b/src/python/doc/conf.py @@ -22,7 +22,10 @@ ] autodoc_class_signature = "separated" +# cf. https://github.com/tox-dev/sphinx-autodoc-typehints#options autodoc_typehints = "none" +napoleon_use_rtype = True +always_use_bars_union = True bibtex_bibfiles = ["../../biblio/bibliography.bib"] From 418247a2dcac31243624bf54758da286f54b1336 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Wed, 2 Oct 2024 09:12:40 +0200 Subject: [PATCH 84/96] include mpl list that is used in this test --- src/Alpha_complex/test/Incremental_delaunay_test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Alpha_complex/test/Incremental_delaunay_test.cpp b/src/Alpha_complex/test/Incremental_delaunay_test.cpp index 8609fb3f34..4c697ea2f0 100644 --- a/src/Alpha_complex/test/Incremental_delaunay_test.cpp +++ b/src/Alpha_complex/test/Incremental_delaunay_test.cpp @@ -12,6 +12,7 @@ #define BOOST_TEST_MODULE "incremental_delaunay" #include #include +#include #include #include From 00b82d18113bf58bb1fccec18270a97273e260d9 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Fri, 4 Oct 2024 13:40:56 +0200 Subject: [PATCH 85/96] Fix strange bug on windows, where '#define far' is performed in windows.h and makes the compilation fails sometimes --- .../include/gudhi/choose_n_farthest_points.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Subsampling/include/gudhi/choose_n_farthest_points.h b/src/Subsampling/include/gudhi/choose_n_farthest_points.h index eaf91e676d..f270e2049e 100644 --- a/src/Subsampling/include/gudhi/choose_n_farthest_points.h +++ b/src/Subsampling/include/gudhi/choose_n_farthest_points.h @@ -168,7 +168,7 @@ using radius_priority_ds = boost::heap::mutable_, boost::heap::constant_time_size>; template struct Landmark_info { - std::size_t far; FT radius; + std::size_t far_idx; FT radius; // The points that are closer to this landmark than to other landmarks std::vector> voronoi; // For a landmark A, the list of landmarks B such that picking a Voronoi @@ -251,7 +251,7 @@ void choose_n_farthest_points_metric(Distance dist_, } } landmarks[i].radius = r; - landmarks[i].far = jmax; + landmarks[i].far_idx = jmax; }; auto update_radius = [&](std::size_t i) { @@ -280,7 +280,7 @@ void choose_n_farthest_points_metric(Distance dist_, for (std::size_t current_number_of_landmarks = 1; current_number_of_landmarks != final_size; current_number_of_landmarks++) { std::size_t l_parent = radius_priority.top(); auto& parent_info = landmarks[l_parent]; - std::size_t l = parent_info.far; + std::size_t l = parent_info.far_idx; FT radius = parent_info.radius; auto& info = landmarks[l]; *output_it++ = input_pts[l]; @@ -309,8 +309,8 @@ void choose_n_farthest_points_metric(Distance dist_, if (it != ngb_info.voronoi.end()) { // modified, always true for ngb==l_parent ngb_info.voronoi.erase(it, ngb_info.voronoi.end()); modified_neighbors.push_back(ngb); - // We only need to recompute the radius if far was removed, which we can test here with - // if (dist(l, ngb_info.far) < ngb_info.radius) + // We only need to recompute the radius if far_idx was removed, which we can test here with + // if (dist(l, ngb_info.far_idx) < ngb_info.radius) // to avoid a costly test for each w in the loop above, but it does not seem to help. update_radius(ngb); // if (ngb_info.voronoi.empty()) radius_priority.erase(ngb_info.position_in_queue); From 7fb35b8a511e27407188399a075262d70ffb0fe8 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Fri, 4 Oct 2024 15:02:48 +0200 Subject: [PATCH 86/96] code review: Rename as farthest --- .../include/gudhi/choose_n_farthest_points.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Subsampling/include/gudhi/choose_n_farthest_points.h b/src/Subsampling/include/gudhi/choose_n_farthest_points.h index f270e2049e..8925c4669c 100644 --- a/src/Subsampling/include/gudhi/choose_n_farthest_points.h +++ b/src/Subsampling/include/gudhi/choose_n_farthest_points.h @@ -168,7 +168,7 @@ using radius_priority_ds = boost::heap::mutable_, boost::heap::constant_time_size>; template struct Landmark_info { - std::size_t far_idx; FT radius; + std::size_t farthest; FT radius; // The points that are closer to this landmark than to other landmarks std::vector> voronoi; // For a landmark A, the list of landmarks B such that picking a Voronoi @@ -251,7 +251,7 @@ void choose_n_farthest_points_metric(Distance dist_, } } landmarks[i].radius = r; - landmarks[i].far_idx = jmax; + landmarks[i].farthest = jmax; }; auto update_radius = [&](std::size_t i) { @@ -280,7 +280,7 @@ void choose_n_farthest_points_metric(Distance dist_, for (std::size_t current_number_of_landmarks = 1; current_number_of_landmarks != final_size; current_number_of_landmarks++) { std::size_t l_parent = radius_priority.top(); auto& parent_info = landmarks[l_parent]; - std::size_t l = parent_info.far_idx; + std::size_t l = parent_info.farthest; FT radius = parent_info.radius; auto& info = landmarks[l]; *output_it++ = input_pts[l]; @@ -309,8 +309,8 @@ void choose_n_farthest_points_metric(Distance dist_, if (it != ngb_info.voronoi.end()) { // modified, always true for ngb==l_parent ngb_info.voronoi.erase(it, ngb_info.voronoi.end()); modified_neighbors.push_back(ngb); - // We only need to recompute the radius if far_idx was removed, which we can test here with - // if (dist(l, ngb_info.far_idx) < ngb_info.radius) + // We only need to recompute the radius if farthest was removed, which we can test here with + // if (dist(l, ngb_info.farthest) < ngb_info.radius) // to avoid a costly test for each w in the loop above, but it does not seem to help. update_radius(ngb); // if (ngb_info.voronoi.empty()) radius_priority.erase(ngb_info.position_in_queue); From 0c5a3c03ec7d13447faa5b8f4731246b949ee361 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 4 Oct 2024 17:31:31 +0200 Subject: [PATCH 87/96] optimization for column reduction at construction for RU --- .../concept/PersistenceMatrixColumn.h | 9 ++ .../gudhi/Persistence_matrix/Base_matrix.h | 2 +- .../Persistence_matrix/Boundary_matrix.h | 4 +- .../gudhi/Persistence_matrix/RU_matrix.h | 14 +-- .../Persistence_matrix/columns/heap_column.h | 15 ++++ .../columns/intrusive_list_column.h | 14 +++ .../columns/intrusive_set_column.h | 14 +++ .../Persistence_matrix/columns/list_column.h | 14 +++ .../columns/naive_vector_column.h | 14 +++ .../Persistence_matrix/columns/set_column.h | 14 +++ .../columns/unordered_set_column.h | 14 +++ .../columns/vector_column.h | 14 +++ .../gudhi/Persistence_matrix/ru_rep_cycles.h | 2 +- src/Persistence_matrix/test/pm_matrix_tests.h | 88 ++++++------------- 14 files changed, 160 insertions(+), 72 deletions(-) diff --git a/src/Persistence_matrix/concept/PersistenceMatrixColumn.h b/src/Persistence_matrix/concept/PersistenceMatrixColumn.h index 8ae47e2924..0be4d79f5c 100644 --- a/src/Persistence_matrix/concept/PersistenceMatrixColumn.h +++ b/src/Persistence_matrix/concept/PersistenceMatrixColumn.h @@ -426,6 +426,15 @@ class PersistenceMatrixColumn : template PersistenceMatrixColumn& multiply_source_and_add(const Entry_range& column, const Field_element& val); + /** + * @brief Adds a copy of the given entry at the end of the column. It is therefore assumed that the row index + * of the entry is higher than the current pivot of the column. Not available for @ref chainmatrix "chain matrices" + * and is only needed for @ref rumatrix "RU matrices". + * + * @param entry Entry to push back. + */ + void push_back(const Entry& entry); + /** * @brief Equality comparator. Equal in the sense that what is "supposed" to be contained in the columns is equal, * not what is actually stored in the underlying container. For example, the underlying container of diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Base_matrix.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Base_matrix.h index c78cf41107..0630aabc02 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Base_matrix.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Base_matrix.h @@ -615,7 +615,7 @@ inline void Base_matrix::print() if constexpr (Master_matrix::Option_list::has_row_access) { std::cout << "Row Matrix:\n"; for (Index i = 0; i < nextInsertIndex_; ++i) { - const auto& row = RA_opt::rows_[i]; + const auto& row = (*RA_opt::rows_)[i]; for (const auto& entry : row) { std::cout << entry.get_column_index() << " "; } diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Boundary_matrix.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Boundary_matrix.h index 93de613c03..4ffb3fbe6d 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Boundary_matrix.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Boundary_matrix.h @@ -729,8 +729,8 @@ inline void Boundary_matrix::print() if constexpr (Master_matrix::Option_list::has_row_access) { std::cout << "Row Matrix:\n"; for (ID_index i = 0; i < nextInsertIndex_; ++i) { - const auto& row = RA_opt::rows_[i]; - for (const auto& entry : row) { + const auto& row = (*RA_opt::rows_)[i]; + for (const typename Column::Entry& entry : row) { std::cout << entry.get_column_index() << " "; } std::cout << "(" << i << ")\n"; diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/RU_matrix.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/RU_matrix.h index 7c3661a8a9..38ceae6a2a 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/RU_matrix.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/RU_matrix.h @@ -638,7 +638,7 @@ inline void RU_matrix::add_to(Index sourceColumnIndex, Index targ { reducedMatrixR_.add_to(sourceColumnIndex, targetColumnIndex); // U transposed to avoid row operations - if constexpr (Master_matrix::Option_list::has_vine_update) + if constexpr (Master_matrix::Option_list::is_z2) mirrorMatrixU_.add_to(targetColumnIndex, sourceColumnIndex); else mirrorMatrixU_.add_to(sourceColumnIndex, targetColumnIndex); @@ -649,6 +649,8 @@ inline void RU_matrix::multiply_target_and_add_to(Index sourceCol const Field_element& coefficient, Index targetColumnIndex) { + static_assert(!Master_matrix::Option_list::is_z2, + "Multiplication with something else than the identity is not allowed with Z2 coefficients."); reducedMatrixR_.multiply_target_and_add_to(sourceColumnIndex, coefficient, targetColumnIndex); mirrorMatrixU_.multiply_target_and_add_to(sourceColumnIndex, coefficient, targetColumnIndex); } @@ -658,6 +660,8 @@ inline void RU_matrix::multiply_source_and_add_to(const Field_ele Index sourceColumnIndex, Index targetColumnIndex) { + static_assert(!Master_matrix::Option_list::is_z2, + "Multiplication with something else than the identity is not allowed with Z2 coefficients."); reducedMatrixR_.multiply_source_and_add_to(coefficient, sourceColumnIndex, targetColumnIndex); mirrorMatrixU_.multiply_source_and_add_to(coefficient, sourceColumnIndex, targetColumnIndex); } @@ -844,10 +848,7 @@ inline void RU_matrix::_reduce_column_by(Index target, Index sour curr += reducedMatrixR_.get_column(source); // to avoid having to do line operations during vineyards, U is transposed // TODO: explain this somewhere in the documentation... - if constexpr (Master_matrix::Option_list::has_vine_update) - mirrorMatrixU_.get_column(source) += mirrorMatrixU_.get_column(target); - else - mirrorMatrixU_.get_column(target) += mirrorMatrixU_.get_column(source); + mirrorMatrixU_.get_column(source).push_back(*mirrorMatrixU_.get_column(target).begin()); } else { Column& toadd = reducedMatrixR_.get_column(source); Field_element coef = toadd.get_pivot_value(); @@ -855,8 +856,9 @@ inline void RU_matrix::_reduce_column_by(Index target, Index sour operators_->multiply_inplace(coef, operators_->get_characteristic() - curr.get_pivot_value()); curr.multiply_source_and_add(toadd, coef); + // but no transposition for Zp, careful if there will be vineyard or rep cycles in Zp one day + // TODO: explain this somewhere in the documentation... mirrorMatrixU_.multiply_source_and_add_to(coef, source, target); - // mirrorMatrixU_.get_column(target).multiply_source_and_add(mirrorMatrixU_.get_column(source), coef); } } diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/heap_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/heap_column.h index 5a0e4dc5c2..c7b0fa8e07 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/heap_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/heap_column.h @@ -134,6 +134,8 @@ class Heap_column : public Master_matrix::Column_dimension_option, public Master Heap_column& multiply_source_and_add(const Entry_range& column, const Field_element& val); Heap_column& multiply_source_and_add(Heap_column& column, const Field_element& val); + void push_back(const Entry& entry); + std::size_t compute_hash_value(); friend bool operator==(const Heap_column& c1, const Heap_column& c2) { @@ -868,6 +870,19 @@ inline Heap_column& Heap_column::multiply_source_a return *this; } +template +inline void Heap_column::push_back(const Entry& entry) +{ + static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices."); + + Entry* newEntry = entryPool_->construct(entry.get_row_index()); + if constexpr (!Master_matrix::Option_list::is_z2) { + newEntry->set_element(operators_->get_value(entry.get_element())); + } + column_.push_back(newEntry); + std::push_heap(column_.begin(), column_.end(), entryPointerComp_); +} + template inline Heap_column& Heap_column::operator=(const Heap_column& other) { diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_list_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_list_column.h index d041852a83..773058019c 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_list_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_list_column.h @@ -132,6 +132,8 @@ class Intrusive_list_column : public Master_matrix::Row_access_option, Intrusive_list_column& multiply_source_and_add(const Entry_range& column, const Field_element& val); Intrusive_list_column& multiply_source_and_add(Intrusive_list_column& column, const Field_element& val); + void push_back(const Entry& entry); + friend bool operator==(const Intrusive_list_column& c1, const Intrusive_list_column& c2) { if (&c1 == &c2) return true; @@ -821,6 +823,18 @@ inline Intrusive_list_column& Intrusive_list_column +inline void Intrusive_list_column::push_back(const Entry& entry) +{ + static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices."); + + if constexpr (Master_matrix::Option_list::is_z2) { + _insert_entry(entry.get_row_index(), column_.end()); + } else { + _insert_entry(entry.get_element(), entry.get_row_index(), column_.end()); + } +} + template inline Intrusive_list_column& Intrusive_list_column::operator=( const Intrusive_list_column& other) diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_set_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_set_column.h index 3d1d00d613..17cb7d86b2 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_set_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_set_column.h @@ -133,6 +133,8 @@ class Intrusive_set_column : public Master_matrix::Row_access_option, Intrusive_set_column& multiply_source_and_add(const Entry_range& column, const Field_element& val); Intrusive_set_column& multiply_source_and_add(Intrusive_set_column& column, const Field_element& val); + void push_back(const Entry& entry); + friend bool operator==(const Intrusive_set_column& c1, const Intrusive_set_column& c2) { if (&c1 == &c2) return true; @@ -821,6 +823,18 @@ inline Intrusive_set_column& Intrusive_set_column: return *this; } +template +inline void Intrusive_set_column::push_back(const Entry& entry) +{ + static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices."); + + if constexpr (Master_matrix::Option_list::is_z2) { + _insert_entry(entry.get_row_index(), column_.end()); + } else { + _insert_entry(entry.get_element(), entry.get_row_index(), column_.end()); + } +} + template inline Intrusive_set_column& Intrusive_set_column::operator=( const Intrusive_set_column& other) diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/list_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/list_column.h index f21827a725..5793d5239d 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/list_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/list_column.h @@ -131,6 +131,8 @@ class List_column : public Master_matrix::Row_access_option, List_column& multiply_source_and_add(const Entry_range& column, const Field_element& val); List_column& multiply_source_and_add(List_column& column, const Field_element& val); + void push_back(const Entry& entry); + friend bool operator==(const List_column& c1, const List_column& c2) { if (&c1 == &c2) return true; @@ -805,6 +807,18 @@ inline List_column& List_column::multiply_source_a return *this; } +template +inline void List_column::push_back(const Entry& entry) +{ + static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices."); + + if constexpr (Master_matrix::Option_list::is_z2) { + _insert_entry(entry.get_row_index(), column_.end()); + } else { + _insert_entry(entry.get_element(), entry.get_row_index(), column_.end()); + } +} + template inline List_column& List_column::operator=(const List_column& other) { diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/naive_vector_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/naive_vector_column.h index e91484b31f..21809f121d 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/naive_vector_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/naive_vector_column.h @@ -131,6 +131,8 @@ class Naive_vector_column : public Master_matrix::Row_access_option, Naive_vector_column& multiply_source_and_add(const Entry_range& column, const Field_element& val); Naive_vector_column& multiply_source_and_add(Naive_vector_column& column, const Field_element& val); + void push_back(const Entry& entry); + friend bool operator==(const Naive_vector_column& c1, const Naive_vector_column& c2) { if (&c1 == &c2) return true; if (c1.column_.size() != c2.column_.size()) return false; @@ -801,6 +803,18 @@ inline Naive_vector_column& Naive_vector_column::m return *this; } +template +inline void Naive_vector_column::push_back(const Entry& entry) +{ + static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices."); + + if constexpr (Master_matrix::Option_list::is_z2) { + _insert_entry(entry.get_row_index(), column_); + } else { + _insert_entry(entry.get_element(), entry.get_row_index(), column_); + } +} + template inline Naive_vector_column& Naive_vector_column::operator=( const Naive_vector_column& other) diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/set_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/set_column.h index de7151a75f..c2efb18b2f 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/set_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/set_column.h @@ -136,6 +136,8 @@ class Set_column : public Master_matrix::Row_access_option, Set_column& multiply_source_and_add(const Entry_range& column, const Field_element& val); Set_column& multiply_source_and_add(Set_column& column, const Field_element& val); + void push_back(const Entry& entry); + friend bool operator==(const Set_column& c1, const Set_column& c2) { if (&c1 == &c2) return true; @@ -797,6 +799,18 @@ inline Set_column& Set_column::multiply_source_and return *this; } +template +inline void Set_column::push_back(const Entry& entry) +{ + static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices."); + + if constexpr (Master_matrix::Option_list::is_z2) { + _insert_entry(entry.get_row_index(), column_.end()); + } else { + _insert_entry(entry.get_element(), entry.get_row_index(), column_.end()); + } +} + template inline Set_column& Set_column::operator=(const Set_column& other) { diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/unordered_set_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/unordered_set_column.h index 4729b004dd..9513a2022b 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/unordered_set_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/unordered_set_column.h @@ -152,6 +152,8 @@ class Unordered_set_column : public Master_matrix::Row_access_option, Unordered_set_column& multiply_source_and_add(const Entry_range& column, const Field_element& val); Unordered_set_column& multiply_source_and_add(Unordered_set_column& column, const Field_element& val); + void push_back(const Entry& entry); + friend bool operator==(const Unordered_set_column& c1, const Unordered_set_column& c2) { if (&c1 == &c2) return true; if (c1.column_.size() != c2.column_.size()) return false; @@ -800,6 +802,18 @@ inline Unordered_set_column& Unordered_set_column: return *this; } +template +inline void Unordered_set_column::push_back(const Entry& entry) +{ + static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices."); + + if constexpr (Master_matrix::Option_list::is_z2) { + _insert_entry(entry.get_row_index()); + } else { + _insert_entry(entry.get_element(), entry.get_row_index()); + } +} + template inline Unordered_set_column& Unordered_set_column::operator=( const Unordered_set_column& other) diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/vector_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/vector_column.h index 8f7d4237bd..0721d86edc 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/vector_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/vector_column.h @@ -134,6 +134,8 @@ class Vector_column : public Master_matrix::Row_access_option, Vector_column& multiply_source_and_add(const Entry_range& column, const Field_element& val); Vector_column& multiply_source_and_add(Vector_column& column, const Field_element& val); + void push_back(const Entry& entry); + std::size_t compute_hash_value(); friend bool operator==(const Vector_column& c1, const Vector_column& c2) { @@ -903,6 +905,18 @@ inline Vector_column& Vector_column::multiply_sour return *this; } +template +inline void Vector_column::push_back(const Entry& entry) +{ + static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices."); + + if constexpr (Master_matrix::Option_list::is_z2) { + _insert_entry(entry.get_row_index(), column_); + } else { + _insert_entry(entry.get_element(), entry.get_row_index(), column_); + } +} + template inline Vector_column& Vector_column::operator=(const Vector_column& other) { diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_rep_cycles.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_rep_cycles.h index ea77ccb9e8..fb2e0c0884 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_rep_cycles.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_rep_cycles.h @@ -135,7 +135,7 @@ inline RU_representative_cycles::RU_representative_cycles( template inline void RU_representative_cycles::update_representative_cycles() { - if constexpr (Master_matrix::Option_list::has_vine_update) { + if constexpr (Master_matrix::Option_list::is_z2) { birthToCycle_.clear(); birthToCycle_.resize(_matrix()->reducedMatrixR_.get_number_of_columns(), -1); Index c = 0; diff --git a/src/Persistence_matrix/test/pm_matrix_tests.h b/src/Persistence_matrix/test/pm_matrix_tests.h index dd20612656..3d0aac966e 100644 --- a/src/Persistence_matrix/test/pm_matrix_tests.h +++ b/src/Persistence_matrix/test/pm_matrix_tests.h @@ -635,23 +635,13 @@ void test_ru_u_access() { std::vector > uColumns(7); if constexpr (Matrix::Option_list::is_z2) { - if constexpr (Matrix::Option_list::has_vine_update) { - uColumns[0] = {0}; - uColumns[1] = {1}; - uColumns[2] = {2}; - uColumns[3] = {3, 5}; - uColumns[4] = {4, 5}; - uColumns[5] = {5}; - uColumns[6] = {6}; - } else { - uColumns[0] = {0}; - uColumns[1] = {1}; - uColumns[2] = {2}; - uColumns[3] = {3}; - uColumns[4] = {4}; - uColumns[5] = {3, 4, 5}; - uColumns[6] = {6}; - } + uColumns[0] = {0}; + uColumns[1] = {1}; + uColumns[2] = {2}; + uColumns[3] = {3, 5}; + uColumns[4] = {4, 5}; + uColumns[5] = {5}; + uColumns[6] = {6}; } else { uColumns[0] = {{0, 1}}; uColumns[1] = {{1, 1}}; @@ -668,7 +658,7 @@ void test_ru_u_access() { test_column_equality(c, get_column_content_via_iterators(col)); } - if constexpr (Matrix::Option_list::has_vine_update) { + if constexpr (Matrix::Option_list::is_z2) { BOOST_CHECK(!m.is_zero_entry(3, 5, false)); BOOST_CHECK(!m.is_zero_column(4, false)); m.zero_entry(3, 5, false); @@ -775,23 +765,13 @@ void test_ru_u_row_access() { std::vector > rows; if constexpr (Matrix::Option_list::is_z2) { - if constexpr (Matrix::Option_list::has_vine_update) { - rows.push_back({0}); - rows.push_back({1}); - rows.push_back({2}); - rows.push_back({3}); - rows.push_back({4}); - rows.push_back({3, 4, 5}); - rows.push_back({6}); - } else { - rows.push_back({0}); - rows.push_back({1}); - rows.push_back({2}); - rows.push_back({3, 5}); - rows.push_back({4, 5}); - rows.push_back({5}); - rows.push_back({6}); - } + rows.push_back({0}); + rows.push_back({1}); + rows.push_back({2}); + rows.push_back({3}); + rows.push_back({4}); + rows.push_back({3, 4, 5}); + rows.push_back({6}); } else { rows.push_back({{0, 1}}); rows.push_back({{1, 1}}); @@ -1059,23 +1039,13 @@ void test_ru_operation() { std::vector > uColumns(7); if constexpr (Matrix::Option_list::is_z2) { - if constexpr (Matrix::Option_list::has_vine_update) { - uColumns[0] = {0}; - uColumns[1] = {1}; - uColumns[2] = {2}; - uColumns[3] = {3, 5}; - uColumns[4] = {4, 5}; - uColumns[5] = {5}; - uColumns[6] = {6}; - } else { - uColumns[0] = {0}; - uColumns[1] = {1}; - uColumns[2] = {2}; - uColumns[3] = {3}; - uColumns[4] = {4}; - uColumns[5] = {3, 4, 5}; - uColumns[6] = {6}; - } + uColumns[0] = {0}; + uColumns[1] = {1}; + uColumns[2] = {2}; + uColumns[3] = {3, 5}; + uColumns[4] = {4, 5}; + uColumns[5] = {5}; + uColumns[6] = {6}; } else { uColumns[0] = {{0, 1}}; uColumns[1] = {{1, 1}}; @@ -1097,10 +1067,7 @@ void test_ru_operation() { m.add_to(3, 5); if constexpr (Matrix::Option_list::is_z2) { columns[5] = {0, 1}; - if constexpr (Matrix::Option_list::has_vine_update) - uColumns[3] = {3}; - else - uColumns[5] = {4, 5}; + uColumns[3] = {3}; } else { columns[5] = {{0, 1}, {1, 4}}; uColumns[5] = {{4, 4}, {5, 1}}; @@ -1116,10 +1083,7 @@ void test_ru_operation() { m.add_to(4, 5); if constexpr (Matrix::Option_list::is_z2) { columns[5] = {0, 2}; - if constexpr (Matrix::Option_list::has_vine_update) - uColumns[4] = {4}; - else - uColumns[5] = {5}; + uColumns[4] = {4}; } else { columns[5] = {{0, 1}, {2, 4}}; uColumns[5] = {{5, 1}}; @@ -1132,11 +1096,11 @@ void test_ru_operation() { } } - if constexpr (!Matrix::Option_list::has_vine_update) { + if constexpr (!Matrix::Option_list::is_z2 || !is_RU()) { m.multiply_target_and_add_to(5, 3, 3); if constexpr (Matrix::Option_list::is_z2) { columns[3] = {1, 2}; - uColumns[3] = {3, 5}; + uColumns[5] = {3, 5}; } else { columns[3] = {{0, 4}, {1, 2}, {2, 4}}; uColumns[3] = {{3, 3}, {5, 1}}; From 26c7fb8aefc489e2f6bb925534b00f4be7ebb14a Mon Sep 17 00:00:00 2001 From: hschreiber Date: Mon, 14 Oct 2024 11:25:40 +0200 Subject: [PATCH 88/96] forgotten constexpr --- .../include/gudhi/Persistence_matrix/RU_matrix.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/RU_matrix.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/RU_matrix.h index 38ceae6a2a..2020e0d11f 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/RU_matrix.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/RU_matrix.h @@ -538,7 +538,7 @@ inline void RU_matrix::insert_boundary(ID_index cellIndex, if constexpr (Master_matrix::Option_list::has_vine_update) { if (cellIndex != nextEventIndex_) { Swap_opt::_positionToRowIdx().emplace(nextEventIndex_, cellIndex); - if (Master_matrix::Option_list::has_column_pairings) { + if constexpr (Master_matrix::Option_list::has_column_pairings) { Swap_opt::template RU_pairing::idToPosition_.emplace(cellIndex, nextEventIndex_); } } From 5db9b3ad510fe143abb28ab5a2ff4e47fe60e262 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Mon, 21 Oct 2024 15:37:30 +0200 Subject: [PATCH 89/96] name change from 'face' to 'cell' --- .../concept/ZigzagOptions.h | 8 +- .../doc/Intro_zigzag_persistence.h | 4 +- ...mple_usage_filtered_zigzag_persistence.cpp | 18 +-- ...ltered_zigzag_persistence_with_storage.cpp | 18 +-- .../example_usage_zigzag_persistence.cpp | 18 +-- ...xample_zigzag_filtration_as_input_loop.cpp | 10 +- .../example_zzfiltration_from_file.cpp | 14 +- .../gudhi/filtered_zigzag_persistence.h | 152 +++++++++--------- .../include/gudhi/zigzag_persistence.h | 80 ++++----- .../test/test_filtered_zigzag_persistence.cpp | 64 ++++---- .../test/test_zigzag_persistence.cpp | 24 +-- 11 files changed, 205 insertions(+), 205 deletions(-) diff --git a/src/Zigzag_persistence/concept/ZigzagOptions.h b/src/Zigzag_persistence/concept/ZigzagOptions.h index 79ee25995a..35f421ac11 100644 --- a/src/Zigzag_persistence/concept/ZigzagOptions.h +++ b/src/Zigzag_persistence/concept/ZigzagOptions.h @@ -26,15 +26,15 @@ namespace zigzag_persistence { */ struct FilteredZigzagOptions { /** - * @brief Numerical type for the face IDs used internally and other indexations. It must be signed. + * @brief Numerical type for the cell IDs used internally and other indexations. It must be signed. */ using Internal_key = unspecified; /** - * @brief Type for the face IDs used at insertion and in the boundaries given as argument. + * @brief Type for the cell IDs used at insertion and in the boundaries given as argument. * Has to be usable as key in a hashtable, so "hashable" and comparable. */ - using Face_key = unspecified; + using Cell_key = unspecified; /** * @brief Type for filtration values. @@ -59,7 +59,7 @@ struct FilteredZigzagOptions { */ struct ZigzagOptions { /** - * @brief Numerical type for the face IDs used internally and other indexations. It must be signed. + * @brief Numerical type for the cell IDs used internally and other indexations. It must be signed. */ using Internal_key = unspecified; diff --git a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h index 0e7ddac996..282825e7ba 100644 --- a/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h +++ b/src/Zigzag_persistence/doc/Intro_zigzag_persistence.h @@ -24,12 +24,12 @@ namespace zigzag_persistence { * We refer to the introduction page \ref persistent_cohomology for persistent (co)homology for an introduction * to the topic. * Zigzag persistence is a generalization of the latter. While standard persistence only allows to grow the filtered - * complex by adding faces, zigzag persistence also allows removals. Hence the name "zigzag", as the module + * complex by adding cells, zigzag persistence also allows removals. Hence the name "zigzag", as the module * diagram will have arrows alternating between forward and backward. * * The module consists of the @ref Zigzag_persistence class and two wrappers @ref Filtered_zigzag_persistence and * @ref Filtered_zigzag_persistence_with_storage "": - * - @ref Zigzag_persistence computes the persistence of a sequence of insertions and removals. A face can be inserted + * - @ref Zigzag_persistence computes the persistence of a sequence of insertions and removals. A cell can be inserted * or removed one at a time and the returned persistence pairs / bars are indexed on the operation numbers. * For example, if a cycle is born at operation number 6 and dies at operation number 7, it will output a bar starting * at 6 and ending at 7. diff --git a/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp b/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp index 0419dd79f9..1ceb362015 100644 --- a/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp +++ b/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence.cpp @@ -26,25 +26,25 @@ int main() { // It is important that the operations of insertions and removals are made **in the same order** as in the zigzag // filtration ones wants to compute the barcode from. - // A face can be identified in the boundaries by any given numerical label, it is just important that the given + // A cell can be identified in the boundaries by any given numerical label, it is just important that the given // filtration values are monotonous (ie., either only increasing or only decreasing). // inserts vertex 2 at filtration value 0.1 -> birth at 0.1 of 0-cycle - zp.insert_face(2, {}, 0, 0.1); + zp.insert_cell(2, {}, 0, 0.1); // inserts vertex 4 at filtration value 0.1 -> birth at 0.1 of 0-cycle - zp.insert_face(4, {}, 0, 0.1); + zp.insert_cell(4, {}, 0, 0.1); // inserts edge 5 = (2,4) at filtration value 0.3 -> death at 0.3 -> outputs (0, 0.1, 0.3) - zp.insert_face(5, {2, 4}, 1, 0.3); + zp.insert_cell(5, {2, 4}, 1, 0.3); // inserts vertex 3 at filtration value 0.4 -> birth at 0.4 of 0-cycle - zp.insert_face(3, {}, 0, 0.4); + zp.insert_cell(3, {}, 0, 0.4); // inserts edge 6 = (2,3) at filtration value 0.4 -> death at 0.4 of the cycle born at 0.4 -> outputs nothing - zp.insert_face(6, {2, 3}, 1, 0.4); + zp.insert_cell(6, {2, 3}, 1, 0.4); // inserts edge 9 = (3,4) at filtration value 1.2 -> birth at 1.2 of 1-cycle - zp.insert_face(9, {4, 3}, 1, 1.2); + zp.insert_cell(9, {4, 3}, 1, 1.2); // removes edge 6 at filtration value 1.5 -> death at 1.5 -> outputs (1, 1.2, 1.5) - zp.remove_face(6, 1.5); + zp.remove_cell(6, 1.5); // removes edge 5 at filtration value 2.0 -> birth at 2.0 of 0-cycle - zp.remove_face(5, 2.0); + zp.remove_cell(5, 2.0); // Only the closed bars where output so far, so the open/infinite bars still need to be retrieved. diff --git a/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence_with_storage.cpp b/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence_with_storage.cpp index 7cc0c866e9..cd14b60fe0 100644 --- a/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence_with_storage.cpp +++ b/src/Zigzag_persistence/example/example_usage_filtered_zigzag_persistence_with_storage.cpp @@ -21,25 +21,25 @@ int main() { // It is important that the operations of insertions and removals are made **in the same order** as in the zigzag // filtration ones wants to compute the barcode from. - // A face can be identified in the boundaries by any given numerical label, it is just important that the given + // A cell can be identified in the boundaries by any given numerical label, it is just important that the given // filtration values are monotonous (ie., either only increasing or only decreasing). // inserts vertex 2 at filtration value 0.1 -> birth at 0.1 of 0-cycle - zp.insert_face(2, {}, 0, 0.1); + zp.insert_cell(2, {}, 0, 0.1); // inserts vertex 4 at filtration value 0.1 -> birth at 0.1 of 0-cycle - zp.insert_face(4, {}, 0, 0.1); + zp.insert_cell(4, {}, 0, 0.1); // inserts edge 5 = (2,4) at filtration value 0.3 -> death at 0.3 -> stores (0, 0.1, 0.3) - zp.insert_face(5, {2, 4}, 1, 0.3); + zp.insert_cell(5, {2, 4}, 1, 0.3); // inserts vertex 3 at filtration value 0.4 -> birth at 0.4 of 0-cycle - zp.insert_face(3, {}, 0, 0.4); + zp.insert_cell(3, {}, 0, 0.4); // inserts edge 6 = (2,3) at filtration value 0.4 -> death at 0.4 of the cycle born at 0.4 -> stores nothing - zp.insert_face(6, {2, 3}, 1, 0.4); + zp.insert_cell(6, {2, 3}, 1, 0.4); // inserts edge 9 = (3,4) at filtration value 1.2 -> birth at 1.2 of 1-cycle - zp.insert_face(9, {4, 3}, 1, 1.2); + zp.insert_cell(9, {4, 3}, 1, 1.2); // removes edge 6 at filtration value 1.5 -> death at 1.5 -> stores (1, 1.2, 1.5) - zp.remove_face(6, 1.5); + zp.remove_cell(6, 1.5); // removes edge 5 at filtration value 2.0 -> birth at 2.0 of 0-cycle - zp.remove_face(5, 2.0); + zp.remove_cell(5, 2.0); // The bars are stored within the class and where not output at all for now. diff --git a/src/Zigzag_persistence/example/example_usage_zigzag_persistence.cpp b/src/Zigzag_persistence/example/example_usage_zigzag_persistence.cpp index e987b90ef4..e50f94cfc0 100644 --- a/src/Zigzag_persistence/example/example_usage_zigzag_persistence.cpp +++ b/src/Zigzag_persistence/example/example_usage_zigzag_persistence.cpp @@ -26,24 +26,24 @@ int main() { // It is important that the operations of insertions and removals are made **in the same order** as in the zigzag // filtration ones wants to compute the barcode from. - // A face has to be identified in the boundaries by the operation number the face was inserted with in the sequence. + // A cell has to be identified in the boundaries by the operation number the cell was inserted with in the sequence. // inserts vertex 0 -> birth at 0 of 0-cycle - zp.insert_face({}, 0); + zp.insert_cell({}, 0); // inserts vertex 1 -> birth at 1 of 0-cycle - zp.insert_face({}, 0); + zp.insert_cell({}, 0); // inserts edge 2 = (0,1) -> death at 2 -> outputs (0, 1, 2) - zp.insert_face({0, 1}, 1); + zp.insert_cell({0, 1}, 1); // inserts vertex 3 -> birth at 3 of 0-cycle - zp.insert_face({}, 0); + zp.insert_cell({}, 0); // inserts edge 4 = (0,3) -> death at 4 -> outputs (0, 3, 4) - zp.insert_face({0, 3}, 1); + zp.insert_cell({0, 3}, 1); // inserts edge 5 = (1,3) -> birth at 5 of 1-cycle - zp.insert_face({1, 3}, 1); + zp.insert_cell({1, 3}, 1); // removes edge 4 -> death at 6 -> outputs (1, 5, 6) - zp.remove_face(4); + zp.remove_cell(4); // removes edge 2 -> birth at 7 of 0-cycle - zp.remove_face(2); + zp.remove_cell(2); // Only the closed bars were output so far, so the open/infinite bars still need to be retrieved. diff --git a/src/Zigzag_persistence/example/example_zigzag_filtration_as_input_loop.cpp b/src/Zigzag_persistence/example/example_zigzag_filtration_as_input_loop.cpp index 046e599b88..e98dae969e 100644 --- a/src/Zigzag_persistence/example/example_zigzag_filtration_as_input_loop.cpp +++ b/src/Zigzag_persistence/example/example_zigzag_filtration_as_input_loop.cpp @@ -14,7 +14,7 @@ #include using ZP = Gudhi::zigzag_persistence::Filtered_zigzag_persistence_with_storage<>; -using Face_handle = ZP::Face_key; +using Cell_handle = ZP::Cell_key; using Filtration_value = ZP::Filtration_value; using Interval_filtration = ZP::Filtration_value_interval; @@ -50,7 +50,7 @@ void print_indices(ZP& zp) { } } -std::vector > get_boundaries() { +std::vector > get_boundaries() { return {{}, {}, {}, @@ -114,7 +114,7 @@ int main(int argc, char* const argv[]) { ZP zp; - std::vector > simplices = get_boundaries(); + std::vector > simplices = get_boundaries(); std::vector fils = get_filtration_values(); std::vector dirs = get_directions(); @@ -125,10 +125,10 @@ int main(int argc, char* const argv[]) { } if (dirs[i]) { int dim = simplices[i].size() == 0 ? 0 : simplices[i].size() - 1; - zp.insert_face(i, simplices[i], dim, fils[i]); + zp.insert_cell(i, simplices[i], dim, fils[i]); } else { auto id = simplices[i][0]; - zp.remove_face(id, fils[i]); + zp.remove_cell(id, fils[i]); } } diff --git a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp index 333194be6f..a3aff58d68 100644 --- a/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp +++ b/src/Zigzag_persistence/example/example_zzfiltration_from_file.cpp @@ -16,15 +16,15 @@ #include using ZP = Gudhi::zigzag_persistence::Filtered_zigzag_persistence<>; -using ID_handle = ZP::Face_key; +using ID_handle = ZP::Cell_key; using Filtration_value = ZP::Filtration_value; using Dimension = ZP::Dimension; enum lineType : int { INCLUSION, REMOVAL, COMMENT }; -lineType read_operation(std::string& line, std::vector& faces, double& timestamp) { +lineType read_operation(std::string& line, std::vector& cells, double& timestamp) { lineType type; - faces.clear(); + cells.clear(); ID_handle num; size_t current = line.find_first_not_of(' ', 0); @@ -53,7 +53,7 @@ lineType read_operation(std::string& line, std::vector& faces, double while (current != std::string::npos) { next = line.find_first_of(' ', current); num = std::stoi(line.substr(current, next - current)); - faces.push_back(num); + cells.push_back(num); current = line.find_first_not_of(' ', next); } @@ -89,7 +89,7 @@ int main(int argc, char* const argv[]) { while (getline(file, line, '\n') && read_operation(line, data, timestamp) == COMMENT); double lastTimestamp = timestamp; // first operation has to be an insertion. - zp.insert_face(id, data, 0, timestamp); + zp.insert_cell(id, data, 0, timestamp); while (getline(file, line, '\n')) { type = read_operation(line, data, timestamp); @@ -100,10 +100,10 @@ int main(int argc, char* const argv[]) { if (type == INCLUSION) { ++id; int dim = data.size() == 0 ? 0 : data.size() - 1; - zp.insert_face(id, data, dim, timestamp); + zp.insert_cell(id, data, dim, timestamp); } else if (type == REMOVAL) { ++id; - zp.remove_face(data[0], timestamp); + zp.remove_cell(data[0], timestamp); } } diff --git a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h index dabaf31cf5..21f1e1cb48 100644 --- a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h @@ -42,8 +42,8 @@ namespace zigzag_persistence { * @brief Default options for @ref Filtered_zigzag_persistence_with_storage and @ref Filtered_zigzag_persistence. */ struct Default_filtered_zigzag_options { - using Internal_key = int; /**< Face ID used internally, must be signed. */ - using Face_key = int; /**< Face ID used in the given boundaries. */ + using Internal_key = int; /**< Cell ID used internally, must be signed. */ + using Cell_key = int; /**< Cell ID used in the given boundaries. */ using Filtration_value = double; /**< Filtration value type. */ using Dimension = int; /**< Dimension value type. */ /** @@ -61,7 +61,7 @@ struct Default_filtered_zigzag_options { * stored during the whole process and not removed. It is therefore suited for smaller filtrations where the clean * ups produce a higher overhead than the memory consumption. * @details After construction of the class, the zigzag filtration should be given in a streaming like way, i.e., - * call @ref insert_face, @ref remove_face or @ref apply_identity for each step of the filtration in order of + * call @ref insert_cell, @ref remove_cell or @ref apply_identity for each step of the filtration in order of * the filtration. To retrieve the current persistence diagram at any moment of the filtration, * use @ref get_persistence_diagram or @ref get_index_persistence_diagram. * @@ -87,25 +87,25 @@ struct Default_filtered_zigzag_options { * // In all cases, it is important that the operations of insertions and removals are made **in the same order** * // as in the zigzag filtration ones wants to compute the barcode from. * - * // A face can be identified in the boundaries by any given numerical label, it is just important that the given + * // A cell can be identified in the boundaries by any given numerical label, it is just important that the given * // filtration values are monotonous (ie., either only increasing or only decreasing). * * //inserts vertex 2 at filtration value 0.1 -> birth at 0.1 of 0-cycle - * zp.insert_face(2, {}, 0, 0.1); + * zp.insert_cell(2, {}, 0, 0.1); * //inserts vertex 4 at filtration value 0.1 -> birth at 0.1 of 0-cycle - * zp.insert_face(4, {}, 0, 0.1); + * zp.insert_cell(4, {}, 0, 0.1); * //inserts edge 5 = (2,4) at filtration value 0.3 -> death at 0.3 -> outputs/stores (0, 0.1, 0.3) - * zp.insert_face(5, {2, 4}, 1, 0.3); + * zp.insert_cell(5, {2, 4}, 1, 0.3); * //inserts vertex 3 at filtration value 0.4 -> birth at 0.4 of 0-cycle - * zp.insert_face(3, {}, 0, 0.4); + * zp.insert_cell(3, {}, 0, 0.4); * //inserts edge 6 = (2,3) at filtration value 0.4 -> death at 0.4 of the cycle born at 0.4 -> outputs/stores nothing - * zp.insert_face(6, {2, 3}, 1, 0.4); + * zp.insert_cell(6, {2, 3}, 1, 0.4); * //inserts edge 9 = (3,4) at filtration value 1.2 -> birth at 1.2 of 1-cycle - * zp.insert_face(9, {4, 3}, 1, 1.2); + * zp.insert_cell(9, {4, 3}, 1, 1.2); * //removes edge 6 at filtration value 1.5 -> death at 1.5 -> outputs/stores (1, 1.2, 1.5) - * zp.remove_face(6, 1.5); + * zp.remove_cell(6, 1.5); * //removes edge 5 at filtration value 2.0 -> birth at 2.0 of 0-cycle - * zp.remove_face(5, 2.0); + * zp.remove_cell(5, 2.0); * ``` * * #### Finalizations @@ -130,7 +130,7 @@ class Filtered_zigzag_persistence_with_storage public: using Options = FilteredZigzagOptions; /**< Zigzag options. */ using Internal_key = typename Options::Internal_key; /**< Key and index type, has to be signed. */ - using Face_key = typename Options::Face_key; /**< Face ID type from external inputs. */ + using Cell_key = typename Options::Cell_key; /**< Cell ID type from external inputs. */ using Filtration_value = typename Options::Filtration_value; /**< Type for filtration values. */ using Dimension = typename Options::Dimension; /**< Type for dimension values. */ @@ -146,13 +146,13 @@ class Filtered_zigzag_persistence_with_storage /** * @brief Constructor. * @details After construction of the class, the zigzag filtration should be given in a streaming like way, i.e., - * call @ref insert_face, @ref remove_face or @ref apply_identity for each step of the filtration in order of + * call @ref insert_cell, @ref remove_cell or @ref apply_identity for each step of the filtration in order of * the filtration. To retrieve the current persistence diagram at any moment of the filtration, * use @ref get_persistence_diagram or @ref get_index_persistence_diagram. * - * @param preallocationSize Reserves space for @p preallocationSize faces in the internal data structure. + * @param preallocationSize Reserves space for @p preallocationSize cells in the internal data structure. * This is optional and just helps skip a few reallocations. The optimal value (no reallocation, no wasted space) is - * the number of faces in the biggest complex of the filtration. + * the number of cells in the biggest complex of the filtration. * Default value: 0. * @param ignoreCyclesAboveDim Ignores cycles in dimension larger or equal in the final diagram. * If -1, no cycles are ignored. Default value: -1. @@ -171,21 +171,21 @@ class Filtered_zigzag_persistence_with_storage preallocationSize) {} /** - * @brief Updates the zigzag persistence diagram after the insertion of the given face. + * @brief Updates the zigzag persistence diagram after the insertion of the given cell. * * @tparam BoundaryRange Range type needing size, begin and end members. - * @param faceID ID representing the inserted face. - * @param boundary Boundary of the inserted face. The range should be composed of the IDs of all faces contained in - * the boundary (i.e. with non-zero coefficients), using the ID specified as `faceID` when the corresponding face - * was previously inserted (recall that the faces should be inserted in order of filtration). - * @param dimension Dimension of the inserted face. - * @param filtrationValue Filtration value associated to the face. + * @param cellID ID representing the inserted cell. + * @param boundary Boundary of the inserted cell. The range should be composed of the IDs of all cells contained in + * the boundary (i.e. with non-zero coefficients), using the ID specified as `cellID` when the corresponding cell + * was previously inserted (recall that the cells should be inserted in order of filtration). + * @param dimension Dimension of the inserted cell. + * @param filtrationValue Filtration value associated to the cell. * Assumed to be always larger or equal to previously used filtration values or always smaller or equal than previous * values, ie. the changes are monotonous. * @return Number of the operation. */ - template > - Internal_key insert_face(Face_key faceID, + template > + Internal_key insert_cell(Cell_key cellID, const BoundaryRange& boundary, Dimension dimension, Filtration_value filtrationValue) @@ -198,34 +198,34 @@ class Filtered_zigzag_persistence_with_storage _store_filtration_value(filtrationValue); - [[maybe_unused]] auto res = handleToKey_.try_emplace(faceID, numArrow_); + [[maybe_unused]] auto res = handleToKey_.try_emplace(cellID, numArrow_); - GUDHI_CHECK(res.second, "Zigzag_persistence::insert_face - face already in the complex"); + GUDHI_CHECK(res.second, "Zigzag_persistence::insert_cell - cell already in the complex"); - // Compute the keys of the faces of the boundary. + // Compute the keys of the cells of the boundary. std::set translatedBoundary; // set maintains the natural order on indices for (auto b : boundary) { translatedBoundary.insert(handleToKey_.at(b)); // TODO: add possibilities of coefficients } - pers_.insert_face(translatedBoundary, dimension); + pers_.insert_cell(translatedBoundary, dimension); return numArrow_; } /** - * @brief Updates the zigzag persistence diagram after the removal of the given face if the face was contained - * in the current complex (note that it will not contain faces of dimension > ignoreCyclesAboveDim if the latter was + * @brief Updates the zigzag persistence diagram after the removal of the given cell if the cell was contained + * in the current complex (note that it will not contain cells of dimension > ignoreCyclesAboveDim if the latter was * non negative at construction of the class). Otherwise, just increases the operation count by one. * - * @param faceID ID representing the face to remove. Should be the same than the one used to insert it. + * @param cellID ID representing the cell to remove. Should be the same than the one used to insert it. * @param filtrationValue Filtration value associated to the removal. * Assumed to be always larger or equal to previously used filtration values or always smaller or equal than previous * values, ie. the changes are monotonous. * @return Number of the operation. */ - Internal_key remove_face(Face_key faceID, Filtration_value filtrationValue) { - auto it = handleToKey_.find(faceID); + Internal_key remove_cell(Cell_key cellID, Filtration_value filtrationValue) { + auto it = handleToKey_.find(cellID); if (it == handleToKey_.end()) { return apply_identity(); @@ -235,14 +235,14 @@ class Filtered_zigzag_persistence_with_storage _store_filtration_value(filtrationValue); - pers_.remove_face(it->second); + pers_.remove_cell(it->second); handleToKey_.erase(it); return numArrow_; } /** - * @brief To use when a face is neither inserted nor removed, but the filtration moves along the identity operator + * @brief To use when a cell is neither inserted nor removed, but the filtration moves along the identity operator * on homology level. Useful to keep the birth/death indices aligned when insertions/removals are purposely skipped * to avoid useless computation. * @return Number of the operation. @@ -301,15 +301,15 @@ class Filtered_zigzag_persistence_with_storage } private: - std::unordered_map handleToKey_; /**< Map from input keys to internal keys. */ + std::unordered_map handleToKey_; /**< Map from input keys to internal keys. */ Dimension dimMax_; /**< Maximal dimension of a bar to record. */ std::vector persistenceDiagram_; /**< Stores current closed persistence intervals. */ Internal_key numArrow_; /**< Current arrow number. */ Filtration_value previousFiltrationValue_; /**< Filtration value of the previous arrow. */ /** * @brief filtrationValues_ stores consecutive pairs (i,f) , (j,f') with f != f', - * meaning that all inserted faces with key in [i;j-1] have filtration value f, - * i is the smallest face index whose face has filtration value f. + * meaning that all inserted cells with key in [i;j-1] have filtration value f, + * i is the smallest cell index whose cell has filtration value f. */ std::vector > filtrationValues_; Zigzag_persistence pers_; /**< Class computing the pairs. */ @@ -323,7 +323,7 @@ class Filtered_zigzag_persistence_with_storage void _store_filtration_value(Filtration_value filtrationValue) { if (filtrationValue != previousFiltrationValue_) // check whether the filt value has changed { - // consecutive pairs (i,f), (j,f') mean faces of index k in [i,j-1] have filtration value f + // consecutive pairs (i,f), (j,f') mean cells of index k in [i,j-1] have filtration value f previousFiltrationValue_ = filtrationValue; filtrationValues_.emplace_back(numArrow_, previousFiltrationValue_); } @@ -379,7 +379,7 @@ class Filtered_zigzag_persistence_with_storage * * @brief Class computing the zigzag persistent homology of a zigzag filtration. Algorithm based on \cite zigzag. * @details After construction of the class, the zigzag filtration should be given in a streaming like way, i.e., - * call @ref insert_face, @ref remove_face or @ref apply_identity for each step of the filtration in order of + * call @ref insert_cell, @ref remove_cell or @ref apply_identity for each step of the filtration in order of * the filtration. The bars of the diagram are retrieved via the given callback method every time * a pair with non-zero length is closed. To retrieve the open/infinite bars, use @ref get_current_infinite_intervals. * @@ -410,25 +410,25 @@ class Filtered_zigzag_persistence_with_storage * // In all cases, it is important that the operations of insertions and removals are made **in the same order** * // as in the zigzag filtration ones wants to compute the barcode from. * - * // A face can be identified in the boundaries by any given numerical label, it is just important that the given + * // A cell can be identified in the boundaries by any given numerical label, it is just important that the given * // filtration values are monotonous (ie., either only increasing or only decreasing). * * //inserts vertex 2 at filtration value 0.1 -> birth at 0.1 of 0-cycle - * zp.insert_face(2, {}, 0, 0.1); + * zp.insert_cell(2, {}, 0, 0.1); * //inserts vertex 4 at filtration value 0.1 -> birth at 0.1 of 0-cycle - * zp.insert_face(4, {}, 0, 0.1); + * zp.insert_cell(4, {}, 0, 0.1); * //inserts edge 5 = (2,4) at filtration value 0.3 -> death at 0.3 -> outputs/stores (0, 0.1, 0.3) - * zp.insert_face(5, {2, 4}, 1, 0.3); + * zp.insert_cell(5, {2, 4}, 1, 0.3); * //inserts vertex 3 at filtration value 0.4 -> birth at 0.4 of 0-cycle - * zp.insert_face(3, {}, 0, 0.4); + * zp.insert_cell(3, {}, 0, 0.4); * //inserts edge 6 = (2,3) at filtration value 0.4 -> death at 0.4 of the cycle born at 0.4 -> outputs/stores nothing - * zp.insert_face(6, {2, 3}, 1, 0.4); + * zp.insert_cell(6, {2, 3}, 1, 0.4); * //inserts edge 9 = (3,4) at filtration value 1.2 -> birth at 1.2 of 1-cycle - * zp.insert_face(9, {4, 3}, 1, 1.2); + * zp.insert_cell(9, {4, 3}, 1, 1.2); * //removes edge 6 at filtration value 1.5 -> death at 1.5 -> outputs/stores (1, 1.2, 1.5) - * zp.remove_face(6, 1.5); + * zp.remove_cell(6, 1.5); * //removes edge 5 at filtration value 2.0 -> birth at 2.0 of 0-cycle - * zp.remove_face(5, 2.0); + * zp.remove_cell(5, 2.0); * ``` * * #### Finalizations @@ -449,14 +449,14 @@ class Filtered_zigzag_persistence { public: using Options = FilteredZigzagOptions; /**< Zigzag options. */ using Internal_key = typename Options::Internal_key; /**< Key and index type, has to be signed. */ - using Face_key = typename Options::Face_key; /**< Face ID type from external inputs. */ + using Cell_key = typename Options::Cell_key; /**< Cell ID type from external inputs. */ using Filtration_value = typename Options::Filtration_value; /**< Type for filtration values. */ using Dimension = typename Options::Dimension; /**< Type for dimension values. */ /** * @brief Constructor. * @details After construction of the class, the zigzag filtration should be given in a streaming like way, i.e., - * call @ref insert_face, @ref remove_face or @ref apply_identity for each step of the filtration in order of + * call @ref insert_cell, @ref remove_cell or @ref apply_identity for each step of the filtration in order of * the filtration. The bars of the diagram are retrieved via the given callback method every time * a pair with non-zero length is closed. To retrieve the open/infinite bars, use @ref get_current_infinite_intervals. * @@ -464,9 +464,9 @@ class Filtered_zigzag_persistence { * Has to take three arguments as input: first the dimension of the cycle, then the birth value of the cycle * and third the death value of the cycle. The values corresponds to the filtration values which were given at * insertions or removals. Note that bars of length 0 will not be token into account. - * @param preallocationSize Reserves space for @p preallocationSize faces in the internal data structure. + * @param preallocationSize Reserves space for @p preallocationSize cells in the internal data structure. * This is optional and just helps skip a few reallocations. The optimal value (no reallocation, no wasted space) is - * the number of faces in the biggest complex of the filtration. + * the number of cells in the biggest complex of the filtration. * Default value: 0. * @tparam F Type of callback method. */ @@ -488,67 +488,67 @@ class Filtered_zigzag_persistence { preallocationSize) {} /** - * @brief Updates the zigzag persistence diagram after the insertion of the given face. + * @brief Updates the zigzag persistence diagram after the insertion of the given cell. * * @tparam BoundaryRange Range type needing size, begin and end members. - * @param faceID ID representing the inserted face. - * @param boundary Boundary of the inserted face. The range should be composed of the IDs of all faces contained in - * the boundary (i.e. with non-zero coefficients), using the ID specified as `faceID` when the corresponding face - * was previously inserted (recall that the faces should be inserted in order of filtration). - * @param dimension Dimension of the inserted face. - * @param filtrationValue Filtration value associated to the face. + * @param cellID ID representing the inserted cell. + * @param boundary Boundary of the inserted cell. The range should be composed of the IDs of all cells contained in + * the boundary (i.e. with non-zero coefficients), using the ID specified as `cellID` when the corresponding cell + * was previously inserted (recall that the cells should be inserted in order of filtration). + * @param dimension Dimension of the inserted cell. + * @param filtrationValue Filtration value associated to the cell. * Assumed to be always larger or equal to previously used filtration values or always smaller or equal than previous * values, ie. the changes are monotonous. */ - template > - Internal_key insert_face(Face_key faceID, + template > + Internal_key insert_cell(Cell_key cellID, const BoundaryRange& boundary, Dimension dimension, Filtration_value filtrationValue) { ++numArrow_; - [[maybe_unused]] auto res = handleToKey_.try_emplace(faceID, numArrow_); + [[maybe_unused]] auto res = handleToKey_.try_emplace(cellID, numArrow_); - GUDHI_CHECK(res.second, "Zigzag_persistence::insert_face - face already in the complex"); + GUDHI_CHECK(res.second, "Zigzag_persistence::insert_cell - cell already in the complex"); keyToFiltrationValue_.try_emplace(numArrow_, filtrationValue); - // Compute the keys of the faces of the boundary. + // Compute the keys of the cells of the boundary. std::set translatedBoundary; // set maintains the natural order on indices for (auto b : boundary) { translatedBoundary.insert(handleToKey_.at(b)); // TODO: add possibilities of coefficients } - pers_.insert_face(translatedBoundary, dimension); + pers_.insert_cell(translatedBoundary, dimension); return numArrow_; } /** - * @brief Updates the zigzag persistence diagram after the removal of the given face. + * @brief Updates the zigzag persistence diagram after the removal of the given cell. *preallocationSize - * @param faceID ID representing the face to remove. Should be the same than the one used to insert it. + * @param cellID ID representing the cell to remove. Should be the same than the one used to insert it. * @param filtrationValue Filtration value associated to the removal. * Assumed to be always larger or equal to previously used filtration values or always smaller or equal than previous * values, ie. the changes are monotonous. */ - Internal_key remove_face(Face_key faceID, Filtration_value filtrationValue) { + Internal_key remove_cell(Cell_key cellID, Filtration_value filtrationValue) { ++numArrow_; - auto it = handleToKey_.find(faceID); - GUDHI_CHECK(it != handleToKey_.end(), "Zigzag_persistence::remove_face - face not in the complex"); + auto it = handleToKey_.find(cellID); + GUDHI_CHECK(it != handleToKey_.end(), "Zigzag_persistence::remove_cell - cell not in the complex"); keyToFiltrationValue_.try_emplace(numArrow_, filtrationValue); - pers_.remove_face(it->second); + pers_.remove_cell(it->second); handleToKey_.erase(it); return numArrow_; } /** - * @brief To use when a face is neither inserted nor removed, but the filtration moves along the identity operator + * @brief To use when a cell is neither inserted nor removed, but the filtration moves along the identity operator * on homology level. Useful to keep the birth/death indices aligned when insertions/removals are purposely skipped * to avoid useless computation. */ @@ -575,9 +575,9 @@ class Filtered_zigzag_persistence { template using Dictionary = std::unordered_map; // TODO: benchmark with other map types - Dictionary handleToKey_; /**< Map from input keys to internal keys. */ + Dictionary handleToKey_; /**< Map from input keys to internal keys. */ Internal_key numArrow_; /**< Current arrow number. */ - Dictionary keyToFiltrationValue_; /**< Face Key to filtration value map. */ + Dictionary keyToFiltrationValue_; /**< Cell Key to filtration value map. */ Zigzag_persistence pers_; /**< Class computing the pairs. */ }; // end class Filtered_zigzag_persistence diff --git a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h index cdb32a6fe1..08639137f4 100644 --- a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h @@ -62,7 +62,7 @@ struct Zigzag_matrix_options : Gudhi::persistence_matrix::Default_options birth at 0 of 0-cycle - * zp.insert_face({}, 0); + * zp.insert_cell({}, 0); * //inserts vertex 1 -> birth at 1 of 0-cycle - * zp.insert_face({}, 0); + * zp.insert_cell({}, 0); * //inserts edge 2 = (0,1) -> death at 2 -> outputs (0, 1, 2) - * zp.insert_face({0, 1}, 1); + * zp.insert_cell({0, 1}, 1); * //inserts vertex 3 -> birth at 3 of 0-cycle - * zp.insert_face({}, 0); + * zp.insert_cell({}, 0); * //inserts edge 4 = (0,3) -> death at 4 -> outputs (0, 3, 4) - * zp.insert_face({0, 3}, 1); + * zp.insert_cell({0, 3}, 1); * //inserts edge 5 = (1,3) -> birth at 5 of 1-cycle - * zp.insert_face({1, 3}, 1); + * zp.insert_cell({1, 3}, 1); * //removes edge 4 -> death at 6 -> outputs (1, 5, 6) - * zp.remove_face(4); + * zp.remove_cell(4); * //removes edge 2 -> birth at 7 of 0-cycle - * zp.remove_face(2); + * zp.remove_cell(2); * ``` * * #### Finalizations @@ -248,18 +248,18 @@ class Zigzag_persistence /** * @brief Constructor of the Zigzag_persistence class. * @details After construction of the class, the zigzag filtration should be given in a streaming like way, i.e., - * call @ref insert_face, @ref remove_face or @ref apply_identity for each step of the filtration in order of + * call @ref insert_cell, @ref remove_cell or @ref apply_identity for each step of the filtration in order of * the filtration. The pairs of birth and death indices are retrieved via the given callback method every time * a pair is closed. To retrieve the open pairs (corresponding to infinite bars), * use @ref get_current_infinite_intervals. * * @param stream_interval Callback method to process the birth and death index pairs. Has to take three arguments * as input: first the dimension of the cycle, then the birth index of the cycle and third the death index of the - * cycle. An index always corresponds to the arrow number the event occurred (one call to @ref insert_face, - * @ref remove_face or @ref apply_identity is equal to one arrow and increases the arrow count by one). - * @param preallocationSize Reserves space for @p preallocationSize faces in the internal data structure. + * cycle. An index always corresponds to the arrow number the event occurred (one call to @ref insert_cell, + * @ref remove_cell or @ref apply_identity is equal to one arrow and increases the arrow count by one). + * @param preallocationSize Reserves space for @p preallocationSize cells in the internal data structure. * This is optional and just helps skip a few reallocations. The optimal value (no reallocation, no wasted space) is - * the number of faces in the biggest complex of the filtration. + * the number of cells in the biggest complex of the filtration. * Default value: 0. */ Zigzag_persistence(std::function stream_interval, @@ -276,37 +276,37 @@ class Zigzag_persistence numArrow_(-1), stream_interval_(std::move(stream_interval)) {} /** - * @brief Updates the zigzag persistence diagram after the insertion of the given face. + * @brief Updates the zigzag persistence diagram after the insertion of the given cell. * * @tparam BoundaryRange Range type needing size, begin and end members. - * @param boundary Boundary of the inserted face. The boundary should be represented by all the faces with - * non-zero coefficients generating it. A face should be represented by the arrow number when the face appeared for - * the first time in the filtration (if a face was inserted and then removed and reinserted etc., only the last - * insertion counts). The face range should be ordered by increasing arrow numbers. - * @param dimension Dimension of the inserted face. + * @param boundary Boundary of the inserted cell. The boundary should be represented by all the cells with + * non-zero coefficients generating it. A cell should be represented by the arrow number when the cell appeared for + * the first time in the filtration (if a cell was inserted and then removed and reinserted etc., only the last + * insertion counts). The cell range should be ordered by increasing arrow numbers. + * @param dimension Dimension of the inserted cell. * @return Number of the operation. */ template > - Index insert_face(const BoundaryRange& boundary, Dimension dimension) { + Index insert_cell(const BoundaryRange& boundary, Dimension dimension) { ++numArrow_; _process_forward_arrow(boundary, dimension); return numArrow_; } /** - * @brief Updates the zigzag persistence diagram after the removal of the given face. + * @brief Updates the zigzag persistence diagram after the removal of the given cell. * - * @param arrowNumber Arrow number of when the face to remove was inserted for the last time. + * @param arrowNumber Arrow number of when the cell to remove was inserted for the last time. * @return Number of the operation. */ - Index remove_face(Index arrowNumber) { + Index remove_cell(Index arrowNumber) { ++numArrow_; _process_backward_arrow(arrowNumber); return numArrow_; } /** - * @brief To use when a face is neither inserted nor removed, but the filtration moves along the identity operator + * @brief To use when a cell is neither inserted nor removed, but the filtration moves along the identity operator * on homology level. Useful to keep the birth/death indices aligned when insertions/removals are purposely skipped * to avoid useless computation. Increases the arrow number by one. * @return Number of the operation. @@ -342,12 +342,12 @@ class Zigzag_persistence private: /** - * @brief Express the boundary cycle of the new face as a sum of cycles in a matrix. + * @brief Express the boundary cycle of the new cell as a sum of cycles in a matrix. * If some cycles are not boundary cycles, i.e., columns with F-index * in the matrix, it applies a surjective diamond to the zigzag module. * - * @param boundary Boundary of the inserted face. - * @param dim Dimension of the inserted face. + * @param boundary Boundary of the inserted cell. + * @param dim Dimension of the inserted cell. */ template void _process_forward_arrow(const BoundaryRange& boundary, Dimension dim) { @@ -369,7 +369,7 @@ class Zigzag_persistence * the boundary in _process_forward_arrow(...). It is equivalent to decreasing death index * order w.r.t. the & chainsInF) { @@ -448,17 +448,17 @@ class Zigzag_persistence } /** - * @brief Removes the given face by pushing up the matrix the corresponding column and erasing it. + * @brief Removes the given cell by pushing up the matrix the corresponding column and erasing it. * - * @param faceID Internal ID of the face to remove. + * @param cellID Internal ID of the cell to remove. */ - void _process_backward_arrow(Index faceID) { - // column whose key is the one of the removed face - Matrix_index currCol = matrix_.get_column_with_pivot(faceID); + void _process_backward_arrow(Index cellID) { + // column whose key is the one of the removed cell + Matrix_index currCol = matrix_.get_column_with_pivot(cellID); // Record all columns that get affected by the transpositions, i.e., have a coeff std::vector modifiedColumns; - const auto& row = matrix_.get_row(faceID); + const auto& row = matrix_.get_row(cellID); modifiedColumns.reserve(row.size()); std::transform(row.begin(), row.end(), std::back_inserter(modifiedColumns), [](const auto& cell) { return cell.get_column_index(); }); @@ -487,13 +487,13 @@ class Zigzag_persistence births_[col.get_paired_chain_index()] = numArrow_; } - // cannot be in G as the removed face is maximal - matrix_.remove_maximal_face(faceID, {}); // also un-pairs c_g if in H + // cannot be in G as the removed cell is maximal + matrix_.remove_maximal_cell(cellID, {}); // also un-pairs c_g if in H } private: Matrix matrix_; /**< Matrix storing a base of the current chain complex. */ - Birth_dictionary births_; /**< Map face index in F to corresponding birth. */ + Birth_dictionary births_; /**< Map cell index in F to corresponding birth. */ Birth_ordering birthOrdering_; /**< Maintains stream_interval_; /**< Callback method for closed pairs. */ diff --git a/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp b/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp index 4e20047a51..6d03c0cc9e 100644 --- a/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp +++ b/src/Zigzag_persistence/test/test_filtered_zigzag_persistence.cpp @@ -128,7 +128,7 @@ std::vector get_filtration_values() { template void test_filtered_zigzag_with_storage() { - using face_handle = typename ZP::Face_key; + using cell_handle = typename ZP::Cell_key; using Filtration_value = typename ZP::Filtration_value; using Interval_index = typename ZP::Index_interval; using Interval_filtration = typename ZP::Filtration_value_interval; @@ -139,11 +139,11 @@ void test_filtered_zigzag_with_storage() { realIndices.reserve(13); realBarcode.reserve(9); - std::vector > simplices = get_boundaries(); + std::vector > simplices = get_boundaries(); std::vector filValues = get_filtration_values(); for (unsigned int i = 0; i < 14; ++i) { - zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); + zp.insert_cell(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); } realIndices.emplace_back(1, 3, 0); @@ -160,11 +160,11 @@ void test_filtered_zigzag_with_storage() { for (unsigned int i = 14; i < 16; ++i) { auto id = simplices[i][0]; - zp.remove_face(id, filValues[i]); + zp.remove_cell(id, filValues[i]); } for (unsigned int i = 16; i < 24; ++i) { - zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); + zp.insert_cell(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); } realIndices.emplace_back(5, 16, 0); @@ -179,19 +179,19 @@ void test_filtered_zigzag_with_storage() { for (unsigned int i = 24; i < 27; ++i) { auto id = simplices[i][0]; - zp.remove_face(id, filValues[i]); + zp.remove_cell(id, filValues[i]); } realIndices.emplace_back(24, 25, 1); realBarcode.emplace_back(8, 9, 1); - zp.insert_face(27, simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1, filValues[27]); + zp.insert_cell(27, simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1, filValues[27]); realIndices.emplace_back(23, 27, 2); realBarcode.emplace_back(7, 9, 2); auto id = simplices[28][0]; - zp.remove_face(id, filValues[28]); + zp.remove_cell(id, filValues[28]); realBarcode.emplace_back(0, Interval_filtration::inf, 0); realBarcode.emplace_back(9, Interval_filtration::inf, 0); @@ -203,7 +203,7 @@ void test_filtered_zigzag_with_storage() { template void test_filtered_zigzag_with_storage_max1() { - using face_handle = typename ZP::Face_key; + using cell_handle = typename ZP::Cell_key; using Filtration_value = typename ZP::Filtration_value; using Interval_index = typename ZP::Index_interval; using Interval_filtration = typename ZP::Filtration_value_interval; @@ -214,11 +214,11 @@ void test_filtered_zigzag_with_storage_max1() { realIndices.reserve(5); realBarcode.reserve(3); - std::vector > simplices = get_boundaries(); + std::vector > simplices = get_boundaries(); std::vector filValues = get_filtration_values(); for (unsigned int i = 0; i < 14; ++i) { - zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); + zp.insert_cell(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); } realIndices.emplace_back(1, 3, 0); @@ -231,11 +231,11 @@ void test_filtered_zigzag_with_storage_max1() { for (unsigned int i = 14; i < 16; ++i) { auto id = simplices[i][0]; - zp.remove_face(id, filValues[i]); + zp.remove_cell(id, filValues[i]); } for (unsigned int i = 16; i < 24; ++i) { - zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); + zp.insert_cell(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); } realIndices.emplace_back(5, 16, 0); @@ -243,12 +243,12 @@ void test_filtered_zigzag_with_storage_max1() { for (unsigned int i = 24; i < 27; ++i) { auto id = simplices[i][0]; - zp.remove_face(id, filValues[i]); + zp.remove_cell(id, filValues[i]); } - zp.insert_face(27, simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1, filValues[27]); + zp.insert_cell(27, simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1, filValues[27]); auto id = simplices[28][0]; - zp.remove_face(id, filValues[28]); + zp.remove_cell(id, filValues[28]); realBarcode.emplace_back(0, Interval_filtration::inf, 0); realBarcode.emplace_back(9, Interval_filtration::inf, 0); @@ -264,7 +264,7 @@ BOOST_AUTO_TEST_CASE(filtered_zigzag_persistence_with_storage) { template void test_filtered_zigzag() { - using face_handle = typename ZP::Face_key; + using cell_handle = typename ZP::Cell_key; using Filtration_value = typename ZP::Filtration_value; using Dimension = typename ZP::Dimension; using Interval = std::tuple; @@ -308,37 +308,37 @@ void test_filtered_zigzag() { realBarcode.emplace_back(2, 7, 9); //23-27 realBarcode.emplace_back(3, 0, 28); //dummy - std::vector > simplices = get_boundaries(); + std::vector > simplices = get_boundaries(); std::vector filValues = get_filtration_values(); for (unsigned int i = 0; i < 14; ++i) { interval = realBarcode[i]; - zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); + zp.insert_cell(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); } for (unsigned int i = 14; i < 16; ++i) { interval = realBarcode[i]; auto id = simplices[i][0]; - zp.remove_face(id, filValues[i]); + zp.remove_cell(id, filValues[i]); } for (unsigned int i = 16; i < 24; ++i) { interval = realBarcode[i]; - zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); + zp.insert_cell(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); } for (unsigned int i = 24; i < 27; ++i) { interval = realBarcode[i]; auto id = simplices[i][0]; - zp.remove_face(id, filValues[i]); + zp.remove_cell(id, filValues[i]); } interval = realBarcode[27]; - zp.insert_face(27, simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1, filValues[27]); + zp.insert_cell(27, simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1, filValues[27]); interval = realBarcode[28]; auto id = simplices[28][0]; - zp.remove_face(id, filValues[28]); + zp.remove_cell(id, filValues[28]); //there is no real guarantee on the order of the infinite bars std::vector infiniteBars; @@ -364,7 +364,7 @@ void test_filtered_zigzag() { template void test_filtered_zigzag_max1() { - using face_handle = typename ZP::Face_key; + using cell_handle = typename ZP::Cell_key; using Filtration_value = typename ZP::Filtration_value; using Dimension = typename ZP::Dimension; using Interval = std::tuple; @@ -412,37 +412,37 @@ void test_filtered_zigzag_max1() { realBarcode.emplace_back(2, 7, 9); //23-27 realBarcode.emplace_back(1, 0, 28); //dummy - std::vector > simplices = get_boundaries(); + std::vector > simplices = get_boundaries(); std::vector filValues = get_filtration_values(); for (unsigned int i = 0; i < 14; ++i) { interval = realBarcode[i]; - zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); + zp.insert_cell(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); } for (unsigned int i = 14; i < 16; ++i) { interval = realBarcode[i]; auto id = simplices[i][0]; - zp.remove_face(id, filValues[i]); + zp.remove_cell(id, filValues[i]); } for (unsigned int i = 16; i < 24; ++i) { interval = realBarcode[i]; - zp.insert_face(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); + zp.insert_cell(i, simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1, filValues[i]); } for (unsigned int i = 24; i < 27; ++i) { interval = realBarcode[i]; auto id = simplices[i][0]; - zp.remove_face(id, filValues[i]); + zp.remove_cell(id, filValues[i]); } interval = realBarcode[27]; - zp.insert_face(27, simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1, filValues[27]); + zp.insert_cell(27, simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1, filValues[27]); interval = realBarcode[28]; auto id = simplices[28][0]; - zp.remove_face(id, filValues[28]); + zp.remove_cell(id, filValues[28]); //there is no real guarantee on the order of the infinite bars std::vector infiniteBars; diff --git a/src/Zigzag_persistence/test/test_zigzag_persistence.cpp b/src/Zigzag_persistence/test/test_zigzag_persistence.cpp index c589fa57b6..cb2ed8d6ed 100644 --- a/src/Zigzag_persistence/test/test_zigzag_persistence.cpp +++ b/src/Zigzag_persistence/test/test_zigzag_persistence.cpp @@ -97,7 +97,7 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single) { std::vector > simplices = get_boundaries(); for (unsigned int i = 0; i < 14; ++i) { - zp.insert_face(simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1); + zp.insert_cell(simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1); } realIndices.emplace_back(0, 1, 3); @@ -109,11 +109,11 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single) { for (unsigned int i = 14; i < 16; ++i) { auto id = simplices[i][0]; - zp.remove_face(id); + zp.remove_cell(id); } for (unsigned int i = 16; i < 24; ++i) { - zp.insert_face(simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1); + zp.insert_cell(simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1); } realIndices.emplace_back(0, 5, 16); @@ -124,17 +124,17 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single) { for (unsigned int i = 24; i < 27; ++i) { auto id = simplices[i][0]; - zp.remove_face(id); + zp.remove_cell(id); } realIndices.emplace_back(1, 24, 25); - zp.insert_face(simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1); + zp.insert_cell(simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1); realIndices.emplace_back(2, 23, 27); auto id = simplices[28][0]; - zp.remove_face(id); + zp.remove_cell(id); realIndices.emplace_back(0, 0, -1); realIndices.emplace_back(0, 26, -1); @@ -165,7 +165,7 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single_max1) { std::vector > simplices = get_boundaries(); for (unsigned int i = 0; i < 14; ++i) { - zp.insert_face(simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1); + zp.insert_cell(simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1); } realIndices.emplace_back(0, 1, 3); @@ -175,23 +175,23 @@ BOOST_AUTO_TEST_CASE(zigzag_persistence_single_max1) { for (unsigned int i = 14; i < 16; ++i) { auto id = simplices[i][0]; - zp.remove_face(id); + zp.remove_cell(id); } for (unsigned int i = 16; i < 24; ++i) { - zp.insert_face(simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1); + zp.insert_cell(simplices[i], simplices[i].size() == 0 ? 0 : simplices[i].size() - 1); } realIndices.emplace_back(0, 5, 16); for (unsigned int i = 24; i < 27; ++i) { auto id = simplices[i][0]; - zp.remove_face(id); + zp.remove_cell(id); } - zp.insert_face(simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1); + zp.insert_cell(simplices[27], simplices[27].size() == 0 ? 0 : simplices[27].size() - 1); auto id = simplices[28][0]; - zp.remove_face(id); + zp.remove_cell(id); realIndices.emplace_back(0, 0, -1); realIndices.emplace_back(0, 26, -1); From 915b5ea8f62c564b3052cee1cc36dab6b1ca2724 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Mon, 21 Oct 2024 18:11:38 +0200 Subject: [PATCH 90/96] removal of 'erase_birth_history' --- .../gudhi/filtered_zigzag_persistence.h | 15 +++------ .../include/gudhi/zigzag_persistence.h | 33 +++++-------------- .../test/test_zigzag_persistence.cpp | 1 - 3 files changed, 12 insertions(+), 37 deletions(-) diff --git a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h index 21f1e1cb48..36bfe89e8a 100644 --- a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h @@ -41,16 +41,9 @@ namespace zigzag_persistence { * * @brief Default options for @ref Filtered_zigzag_persistence_with_storage and @ref Filtered_zigzag_persistence. */ -struct Default_filtered_zigzag_options { - using Internal_key = int; /**< Cell ID used internally, must be signed. */ +struct Default_filtered_zigzag_options : Default_zigzag_options { using Cell_key = int; /**< Cell ID used in the given boundaries. */ using Filtration_value = double; /**< Filtration value type. */ - using Dimension = int; /**< Dimension value type. */ - /** - * @brief Column type use by the internal matrix. - */ - static const Gudhi::persistence_matrix::Column_types column_type = - Gudhi::persistence_matrix::Column_types::NAIVE_VECTOR; }; /** @@ -302,7 +295,7 @@ class Filtered_zigzag_persistence_with_storage private: std::unordered_map handleToKey_; /**< Map from input keys to internal keys. */ - Dimension dimMax_; /**< Maximal dimension of a bar to record. */ + Dimension dimMax_; /**< Maximal dimension of a bar to record. */ std::vector persistenceDiagram_; /**< Stores current closed persistence intervals. */ Internal_key numArrow_; /**< Current arrow number. */ Filtration_value previousFiltrationValue_; /**< Filtration value of the previous arrow. */ @@ -312,7 +305,7 @@ class Filtered_zigzag_persistence_with_storage * i is the smallest cell index whose cell has filtration value f. */ std::vector > filtrationValues_; - Zigzag_persistence pers_; /**< Class computing the pairs. */ + Zigzag_persistence pers_; /**< Class computing the pairs. */ /** * @brief Stores the filtration value if the value is new. Assumes that the given value is either greater (or equal) @@ -578,7 +571,7 @@ class Filtered_zigzag_persistence { Dictionary handleToKey_; /**< Map from input keys to internal keys. */ Internal_key numArrow_; /**< Current arrow number. */ Dictionary keyToFiltrationValue_; /**< Cell Key to filtration value map. */ - Zigzag_persistence pers_; /**< Class computing the pairs. */ + Zigzag_persistence pers_; /**< Class computing the pairs. */ }; // end class Filtered_zigzag_persistence } // namespace zigzag_persistence diff --git a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h index 08639137f4..e704587dee 100644 --- a/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/zigzag_persistence.h @@ -68,13 +68,11 @@ struct Default_zigzag_options { * @brief Column type use by the internal matrix. */ static const Gudhi::persistence_matrix::Column_types column_type = - Gudhi::persistence_matrix::Column_types::NAIVE_VECTOR; //TODO: redo benchmark with oscillating rips + Gudhi::persistence_matrix::Column_types::NAIVE_VECTOR; }; // TODO: add the possibility of something else than Z2. Which means that the possibility of vineyards without Z2 // also needs to be implemented. The theory needs to be done first. -// TODO: erase_birth_history will be moved to the options if it is proven to be useful. In the meantime -// it stays here undocumented to ease benchmarks. /** * @class Zigzag_persistence zigzag_persistence.h gudhi/zigzag_persistence.h * @brief Class computing the zigzag persistent homology of a zigzag sequence. Algorithm based on \cite zigzag. @@ -146,7 +144,7 @@ struct Default_zigzag_options { * * @tparam ZigzagOptions Structure following the @ref ZigzagOptions concept. Default value: @ref Default_zigzag_options. */ -template +template class Zigzag_persistence { public: @@ -324,19 +322,8 @@ class Zigzag_persistence template void get_current_infinite_intervals(F&& stream_infinite_interval) { for (auto& p : births_) { - if constexpr (erase_birth_history) { - auto& col = matrix_.get_column(p.first); - stream_infinite_interval(col.get_dimension(), p.second); - } else { - try { - auto& col = matrix_.get_column(p.first); - if (!col.is_paired()) { - stream_infinite_interval(col.get_dimension(), p.second); - } - } catch (const std::out_of_range&) { - continue; - } - } + auto& col = matrix_.get_column(p.first); + stream_infinite_interval(col.get_dimension(), p.second); } } @@ -438,10 +425,8 @@ class Zigzag_persistence } // birth not available anymore, do not } // modify *chain_f_it. - if constexpr (erase_birth_history) { - birthOrdering_.remove_birth(maxb); - births_.erase(chainFp); - } + birthOrdering_.remove_birth(maxb); + births_.erase(chainFp); // Update persistence diagram with left interval [fil(b_max) ; fil(m)) stream_interval_(dim - 1, maxb, numArrow_); @@ -477,10 +462,8 @@ class Zigzag_persistence if (!col.is_paired()) { // in F auto it = births_.find(currCol); stream_interval_(col.get_dimension(), it->second, numArrow_); - if constexpr (erase_birth_history) { - birthOrdering_.remove_birth(it->second); - births_.erase(it); - } + birthOrdering_.remove_birth(it->second); + births_.erase(it); } else { // in H -> paired with c_g, that now belongs to F now // maintain the <=b order birthOrdering_.add_birth_backward(numArrow_); diff --git a/src/Zigzag_persistence/test/test_zigzag_persistence.cpp b/src/Zigzag_persistence/test/test_zigzag_persistence.cpp index cb2ed8d6ed..0f1edb9a2b 100644 --- a/src/Zigzag_persistence/test/test_zigzag_persistence.cpp +++ b/src/Zigzag_persistence/test/test_zigzag_persistence.cpp @@ -17,7 +17,6 @@ #include using ZP = Gudhi::zigzag_persistence::Zigzag_persistence<>; -// using ZP = Gudhi::zigzag_persistence::Zigzag_persistence; struct Interval { Interval() {} From b3158e3e25fc22da8426610b998044e66b22ef3c Mon Sep 17 00:00:00 2001 From: hschreiber Date: Tue, 22 Oct 2024 14:59:05 +0200 Subject: [PATCH 91/96] replacing set with vector for boundary translation --- .../include/gudhi/filtered_zigzag_persistence.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h index 36bfe89e8a..c026da8534 100644 --- a/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h +++ b/src/Zigzag_persistence/include/gudhi/filtered_zigzag_persistence.h @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -196,10 +195,12 @@ class Filtered_zigzag_persistence_with_storage GUDHI_CHECK(res.second, "Zigzag_persistence::insert_cell - cell already in the complex"); // Compute the keys of the cells of the boundary. - std::set translatedBoundary; // set maintains the natural order on indices + std::vector translatedBoundary; + translatedBoundary.reserve(dimension * 2); // boundary does not have to have `size()` for (auto b : boundary) { - translatedBoundary.insert(handleToKey_.at(b)); // TODO: add possibilities of coefficients + translatedBoundary.push_back(handleToKey_.at(b)); // TODO: add possibilities of coefficients } + std::sort(translatedBoundary.begin(), translatedBoundary.end()); pers_.insert_cell(translatedBoundary, dimension); @@ -508,10 +509,12 @@ class Filtered_zigzag_persistence { keyToFiltrationValue_.try_emplace(numArrow_, filtrationValue); // Compute the keys of the cells of the boundary. - std::set translatedBoundary; // set maintains the natural order on indices + std::vector translatedBoundary; + translatedBoundary.reserve(dimension * 2); // boundary does not have to have `size()` for (auto b : boundary) { - translatedBoundary.insert(handleToKey_.at(b)); // TODO: add possibilities of coefficients + translatedBoundary.push_back(handleToKey_.at(b)); // TODO: add possibilities of coefficients } + std::sort(translatedBoundary.begin(), translatedBoundary.end()); pers_.insert_cell(translatedBoundary, dimension); From e1b4634010a06b8595a6eb2721ca9dc491789044 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Wed, 23 Oct 2024 11:15:47 +0200 Subject: [PATCH 92/96] add gudhi_check for column push_back --- .../include/gudhi/Persistence_matrix/columns/heap_column.h | 3 +++ .../gudhi/Persistence_matrix/columns/intrusive_list_column.h | 2 ++ .../gudhi/Persistence_matrix/columns/intrusive_set_column.h | 2 ++ .../include/gudhi/Persistence_matrix/columns/list_column.h | 2 ++ .../gudhi/Persistence_matrix/columns/naive_vector_column.h | 2 ++ .../include/gudhi/Persistence_matrix/columns/set_column.h | 2 ++ .../gudhi/Persistence_matrix/columns/unordered_set_column.h | 2 ++ .../include/gudhi/Persistence_matrix/columns/vector_column.h | 2 ++ 8 files changed, 17 insertions(+) diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/heap_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/heap_column.h index c7b0fa8e07..e195dfea4e 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/heap_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/heap_column.h @@ -25,6 +25,7 @@ #include //std::swap, std::move & std::exchange #include +#include "gudhi/Debug_utils.h" #include @@ -875,6 +876,8 @@ inline void Heap_column::push_back(const Entry& entry) { static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices."); + GUDHI_CHECK(entry.get_row_index() > get_pivot(), "The new row index has to be higher than the current pivot."); + Entry* newEntry = entryPool_->construct(entry.get_row_index()); if constexpr (!Master_matrix::Option_list::is_z2) { newEntry->set_element(operators_->get_value(entry.get_element())); diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_list_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_list_column.h index 773058019c..0f5aaa8325 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_list_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_list_column.h @@ -828,6 +828,8 @@ inline void Intrusive_list_column::push_back(const Entry& entry) { static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices."); + GUDHI_CHECK(entry.get_row_index() > get_pivot(), "The new row index has to be higher than the current pivot."); + if constexpr (Master_matrix::Option_list::is_z2) { _insert_entry(entry.get_row_index(), column_.end()); } else { diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_set_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_set_column.h index 17cb7d86b2..994a5014d1 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_set_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/intrusive_set_column.h @@ -828,6 +828,8 @@ inline void Intrusive_set_column::push_back(const Entry& entry) { static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices."); + GUDHI_CHECK(entry.get_row_index() > get_pivot(), "The new row index has to be higher than the current pivot."); + if constexpr (Master_matrix::Option_list::is_z2) { _insert_entry(entry.get_row_index(), column_.end()); } else { diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/list_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/list_column.h index 5793d5239d..658541f973 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/list_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/list_column.h @@ -812,6 +812,8 @@ inline void List_column::push_back(const Entry& entry) { static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices."); + GUDHI_CHECK(entry.get_row_index() > get_pivot(), "The new row index has to be higher than the current pivot."); + if constexpr (Master_matrix::Option_list::is_z2) { _insert_entry(entry.get_row_index(), column_.end()); } else { diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/naive_vector_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/naive_vector_column.h index 21809f121d..e99d37b7e2 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/naive_vector_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/naive_vector_column.h @@ -808,6 +808,8 @@ inline void Naive_vector_column::push_back(const Entry& entry) { static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices."); + GUDHI_CHECK(entry.get_row_index() > get_pivot(), "The new row index has to be higher than the current pivot."); + if constexpr (Master_matrix::Option_list::is_z2) { _insert_entry(entry.get_row_index(), column_); } else { diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/set_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/set_column.h index c2efb18b2f..6f69c53c96 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/set_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/set_column.h @@ -804,6 +804,8 @@ inline void Set_column::push_back(const Entry& entry) { static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices."); + GUDHI_CHECK(entry.get_row_index() > get_pivot(), "The new row index has to be higher than the current pivot."); + if constexpr (Master_matrix::Option_list::is_z2) { _insert_entry(entry.get_row_index(), column_.end()); } else { diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/unordered_set_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/unordered_set_column.h index 9513a2022b..b63adcbac4 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/unordered_set_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/unordered_set_column.h @@ -807,6 +807,8 @@ inline void Unordered_set_column::push_back(const Entry& entry) { static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices."); + GUDHI_CHECK(entry.get_row_index() > get_pivot(), "The new row index has to be higher than the current pivot."); + if constexpr (Master_matrix::Option_list::is_z2) { _insert_entry(entry.get_row_index()); } else { diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/vector_column.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/vector_column.h index 0721d86edc..f6a7da8e84 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/vector_column.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/columns/vector_column.h @@ -910,6 +910,8 @@ inline void Vector_column::push_back(const Entry& entry) { static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices."); + GUDHI_CHECK(entry.get_row_index() > get_pivot(), "The new row index has to be higher than the current pivot."); + if constexpr (Master_matrix::Option_list::is_z2) { _insert_entry(entry.get_row_index(), column_); } else { From 5213928ff90438a12022c218f52e2da19c00731d Mon Sep 17 00:00:00 2001 From: hschreiber <48448038+hschreiber@users.noreply.github.com> Date: Thu, 24 Oct 2024 11:09:48 +0200 Subject: [PATCH 93/96] Update src/common/doc/main_page.md Co-authored-by: Vincent Rouvreau <10407034+VincentRouvreau@users.noreply.github.com> --- src/common/doc/main_page.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/doc/main_page.md b/src/common/doc/main_page.md index b9369ab17b..334746b319 100644 --- a/src/common/doc/main_page.md +++ b/src/common/doc/main_page.md @@ -423,7 +423,7 @@ Author: Clément Maria, Hannah Schreiber
- Introduced in: GUDHI 3.9.0
+ Introduced in: GUDHI 3.11.0
Copyright: MIT
From f4c5345404e2c4341317af954932966f534c8825 Mon Sep 17 00:00:00 2001 From: hschreiber <48448038+hschreiber@users.noreply.github.com> Date: Thu, 24 Oct 2024 11:10:01 +0200 Subject: [PATCH 94/96] Update src/Zigzag_persistence/doc/COPYRIGHT Co-authored-by: Vincent Rouvreau <10407034+VincentRouvreau@users.noreply.github.com> --- src/Zigzag_persistence/doc/COPYRIGHT | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Zigzag_persistence/doc/COPYRIGHT b/src/Zigzag_persistence/doc/COPYRIGHT index 61f17f6da1..f9ac497dac 100644 --- a/src/Zigzag_persistence/doc/COPYRIGHT +++ b/src/Zigzag_persistence/doc/COPYRIGHT @@ -1,9 +1,9 @@ The files of this directory are part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. -Author(s): Vincent Rouvreau +Author(s): Hannah Schreiber -Copyright (C) 2015 Inria +Copyright (C) 2024 Inria This gives everyone the freedoms to use openFrameworks in any context: commercial or non-commercial, public or private, open or closed source. From 795c23515aff418750fd6156315cce68fff295b5 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Wed, 6 Nov 2024 14:44:57 +0100 Subject: [PATCH 95/96] bug fix in R reduction + print fix --- .../gudhi/Persistence_matrix/Chain_matrix.h | 24 +- .../gudhi/Persistence_matrix/base_pairing.h | 23 +- src/Persistence_matrix/test/pm_matrix_tests.h | 225 +++++++++++++++++- 3 files changed, 249 insertions(+), 23 deletions(-) diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Chain_matrix.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Chain_matrix.h index 7611990b82..dce0a1d504 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/Chain_matrix.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/Chain_matrix.h @@ -913,24 +913,28 @@ inline void Chain_matrix::print() const { std::cout << "Column Matrix:\n"; if constexpr (!Master_matrix::Option_list::has_map_column_container) { - for (ID_index i = 0; i < pivotToColumnIndex_.size() && pivotToColumnIndex_[i] != static_cast(-1); ++i) { + for (ID_index i = 0; i < pivotToColumnIndex_.size(); ++i) { Index pos = pivotToColumnIndex_[i]; - const Column& col = matrix_[pos]; - for (const auto& entry : col) { - std::cout << entry.get_row_index() << " "; + if (pos != static_cast(-1)){ + const Column& col = matrix_[pos]; + for (const auto& entry : col) { + std::cout << entry.get_row_index() << " "; + } + std::cout << "(" << i << ", " << pos << ")\n"; } - std::cout << "(" << i << ", " << pos << ")\n"; } if constexpr (Master_matrix::Option_list::has_row_access) { std::cout << "\n"; std::cout << "Row Matrix:\n"; - for (ID_index i = 0; i < pivotToColumnIndex_.size() && pivotToColumnIndex_[i] != static_cast(-1); ++i) { + for (ID_index i = 0; i < pivotToColumnIndex_.size(); ++i) { Index pos = pivotToColumnIndex_[i]; - const Row& row = RA_opt::get_row(pos); - for (const auto& entry : row) { - std::cout << entry.get_column_index() << " "; + if (pos != static_cast(-1)){ + const Row& row = RA_opt::get_row(pos); + for (const auto& entry : row) { + std::cout << entry.get_column_index() << " "; + } + std::cout << "(" << i << ", " << pos << ")\n"; } - std::cout << "(" << i << ", " << pos << ")\n"; } } } else { diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/base_pairing.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/base_pairing.h index 8ce95ce743..780040f011 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/base_pairing.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/base_pairing.h @@ -132,10 +132,11 @@ inline const typename Base_pairing::Barcode& Base_pairing inline void Base_pairing::_reduce() { - std::unordered_map pivotsToColumn(_matrix()->get_number_of_columns()); + std::unordered_map negativeColumns(_matrix()->get_number_of_columns()); auto dim = _matrix()->get_max_dimension(); std::vector > columnsByDim(dim + 1); + for (auto& v : columnsByDim) v.reserve(_matrix()->get_number_of_columns()); for (unsigned int i = 0; i < _matrix()->get_number_of_columns(); i++) { columnsByDim[dim - _matrix()->get_column_dimension(i)].push_back(i); } @@ -144,17 +145,21 @@ inline void Base_pairing::_reduce() for (Index i : cols) { auto& curr = _matrix()->get_column(i); if (curr.is_empty()) { - if (pivotsToColumn.find(i) == pivotsToColumn.end()) { + if (negativeColumns.find(i) == negativeColumns.end()) { barcode_.emplace_back(i, -1, dim); } } else { ID_index pivot = curr.get_pivot(); + auto it = idToPosition_.find(pivot); + Index pivotColumnNumber = it == idToPosition_.end() ? pivot : it->second; + auto itNeg = negativeColumns.find(pivotColumnNumber); + Index pivotKiller = itNeg == negativeColumns.end() ? -1 : itNeg->second; - while (pivot != static_cast(-1) && pivotsToColumn.find(pivot) != pivotsToColumn.end()) { + while (pivot != static_cast(-1) && pivotKiller != static_cast(-1)) { if constexpr (Master_matrix::Option_list::is_z2) { - curr += _matrix()->get_column(pivotsToColumn.at(pivot)); + curr += _matrix()->get_column(pivotKiller); } else { - auto& toadd = _matrix()->get_column(pivotsToColumn.at(pivot)); + auto& toadd = _matrix()->get_column(pivotKiller); typename Master_matrix::Element coef = toadd.get_pivot_value(); auto& operators = _matrix()->colSettings_->operators; coef = operators.get_inverse(coef); @@ -163,12 +168,14 @@ inline void Base_pairing::_reduce() } pivot = curr.get_pivot(); + it = idToPosition_.find(pivot); + pivotColumnNumber = it == idToPosition_.end() ? pivot : it->second; + itNeg = negativeColumns.find(pivotColumnNumber); + pivotKiller = itNeg == negativeColumns.end() ? -1 : itNeg->second; } if (pivot != static_cast(-1)) { - pivotsToColumn.emplace(pivot, i); - auto it = idToPosition_.find(pivot); - auto pivotColumnNumber = it == idToPosition_.end() ? pivot : it->second; + negativeColumns.emplace(pivotColumnNumber, i); _matrix()->get_column(pivotColumnNumber).clear(); barcode_.emplace_back(pivotColumnNumber, i, dim - 1); } else { diff --git a/src/Persistence_matrix/test/pm_matrix_tests.h b/src/Persistence_matrix/test/pm_matrix_tests.h index 3d0aac966e..0028079c57 100644 --- a/src/Persistence_matrix/test/pm_matrix_tests.h +++ b/src/Persistence_matrix/test/pm_matrix_tests.h @@ -1348,8 +1348,9 @@ template void test_barcode() { struct BarComp { bool operator()(const std::tuple& c1, const std::tuple& c2) const { - if (std::get<0>(c1) == std::get<0>(c2)) return std::get<1>(c1) < std::get<1>(c2); - return std::get<0>(c1) < std::get<0>(c2); + if (std::get<0>(c1) != std::get<0>(c2)) return std::get<0>(c1) < std::get<0>(c2); + if (std::get<1>(c1) != std::get<1>(c2)) return std::get<1>(c1) < std::get<1>(c2); + return std::get<2>(c1) < std::get<2>(c2); } }; @@ -1420,12 +1421,220 @@ void test_barcode() { } template -void test_shifted_barcode() { +void test_shifted_barcode1() { + using C = typename Matrix::Column; + struct BarComp { + bool operator()(const std::tuple& c1, const std::tuple& c2) const { + if (std::get<0>(c1) != std::get<0>(c2)) return std::get<0>(c1) < std::get<0>(c2); + if (std::get<1>(c1) != std::get<1>(c2)) return std::get<1>(c1) < std::get<1>(c2); + return std::get<2>(c1) < std::get<2>(c2); + } + }; + + Matrix m(17, 2); + if constexpr (is_z2()) { + m.insert_boundary(0, {}, 0); + m.insert_boundary(1, {}, 0); + m.insert_boundary(2, {}, 0); + m.insert_boundary(3, {}, 0); + m.insert_boundary(4, {}, 0); + m.insert_boundary(5, {}, 0); + m.insert_boundary(6, {}, 0); + m.insert_boundary(10, {0, 1}, 1); + m.insert_boundary(11, {1, 3}, 1); + m.insert_boundary(12, {2, 3}, 1); + m.insert_boundary(13, {2, 4}, 1); + m.insert_boundary(14, {3, 4}, 1); + m.insert_boundary(15, {2, 6}, 1); + m.insert_boundary(16, {4, 6}, 1); + m.insert_boundary(17, {5, 6}, 1); + m.insert_boundary(30, {12, 13, 14}, 2); + m.insert_boundary(31, {13, 15, 16}, 2); + } else { + m.insert_boundary(0, {}, 0); + m.insert_boundary(1, {}, 0); + m.insert_boundary(2, {}, 0); + m.insert_boundary(3, {}, 0); + m.insert_boundary(4, {}, 0); + m.insert_boundary(5, {}, 0); + m.insert_boundary(6, {}, 0); + m.insert_boundary(10, {{0, 1}, {1, 1}}, 1); + m.insert_boundary(11, {{1, 1}, {3, 1}}, 1); + m.insert_boundary(12, {{2, 1}, {3, 1}}, 1); + m.insert_boundary(13, {{2, 1}, {4, 1}}, 1); + m.insert_boundary(14, {{3, 1}, {4, 1}}, 1); + m.insert_boundary(15, {{2, 1}, {6, 1}}, 1); + m.insert_boundary(16, {{4, 1}, {6, 1}}, 1); + m.insert_boundary(17, {{5, 1}, {6, 1}}, 1); + m.insert_boundary(30, {{12, 1}, {13, 1}, {14, 1}}, 2); + m.insert_boundary(31, {{13, 1}, {15, 1}, {16, 1}}, 2); + } + + const auto& barcode = m.get_current_barcode(); + + std::vector > reducedMatrix; + if constexpr (is_z2()) { + if constexpr (Matrix::Option_list::is_of_boundary_type) { + reducedMatrix.emplace_back(); + reducedMatrix.emplace_back(); + reducedMatrix.emplace_back(); + reducedMatrix.emplace_back(); + reducedMatrix.emplace_back(); + reducedMatrix.emplace_back(); + reducedMatrix.emplace_back(); + reducedMatrix.push_back({0, 1}); + reducedMatrix.push_back({1, 3}); + reducedMatrix.push_back({1, 2}); + reducedMatrix.push_back({2, 4}); + reducedMatrix.emplace_back(); + reducedMatrix.push_back({2, 6}); + reducedMatrix.emplace_back(); + reducedMatrix.push_back({2, 5}); + reducedMatrix.push_back({12, 13, 14}); + reducedMatrix.push_back({13, 15, 16}); + } else { + reducedMatrix.push_back({0}); + reducedMatrix.push_back({0, 1}); + reducedMatrix.push_back({0, 2}); + reducedMatrix.push_back({0, 3}); + reducedMatrix.push_back({0, 4}); + reducedMatrix.push_back({0, 5}); + reducedMatrix.push_back({0, 6}); + reducedMatrix.push_back({10}); + reducedMatrix.push_back({10, 11}); + reducedMatrix.push_back({10, 11, 12}); + reducedMatrix.push_back({10, 11, 12, 13}); + reducedMatrix.push_back({12, 13, 14}); + reducedMatrix.push_back({10, 11, 12, 15}); + reducedMatrix.push_back({13, 15, 16}); + reducedMatrix.push_back({10, 11, 12, 15, 17}); + reducedMatrix.push_back({30}); + reducedMatrix.push_back({31}); + } + } else { + if constexpr (Matrix::Option_list::is_of_boundary_type) { + reducedMatrix.emplace_back(); + reducedMatrix.emplace_back(); + reducedMatrix.emplace_back(); + reducedMatrix.emplace_back(); + reducedMatrix.emplace_back(); + reducedMatrix.emplace_back(); + reducedMatrix.emplace_back(); + reducedMatrix.push_back({{0, 1}, {1, 1}}); + reducedMatrix.push_back({{1, 1}, {3, 1}}); + reducedMatrix.push_back({{1, 1}, {2, 1}}); + reducedMatrix.push_back({{2, 1}, {4, 1}}); + reducedMatrix.emplace_back(); + reducedMatrix.push_back({{2, 1}, {6, 1}}); + reducedMatrix.emplace_back(); + reducedMatrix.push_back({{2, 1}, {5, 1}}); + reducedMatrix.push_back({{12, 1}, {13, 1}, {14, 1}}); + reducedMatrix.push_back({{13, 1}, {15, 1}, {16, 1}}); + } else { + reducedMatrix.push_back({{0, 1}}); + reducedMatrix.push_back({{0, 1}, {1, 1}}); + reducedMatrix.push_back({{0, 1}, {2, 1}}); + reducedMatrix.push_back({{0, 1}, {3, 1}}); + reducedMatrix.push_back({{0, 1}, {4, 1}}); + reducedMatrix.push_back({{0, 1}, {5, 1}}); + reducedMatrix.push_back({{0, 1}, {6, 1}}); + reducedMatrix.push_back({{10, 1}}); + reducedMatrix.push_back({{10, 1}, {11, 1}}); + reducedMatrix.push_back({{10, 1}, {11, 1}, {12, 1}}); + reducedMatrix.push_back({{10, 1}, {11, 1}, {12, 1}, {13, 1}}); + reducedMatrix.push_back({{12, 1}, {13, 1}, {14, 1}}); + reducedMatrix.push_back({{10, 1}, {11, 1}, {12, 1}, {15, 1}}); + reducedMatrix.push_back({{13, 1}, {15, 1}, {16, 1}}); + reducedMatrix.push_back({{10, 1}, {11, 1}, {12, 1}, {15, 1}, {17, 1}}); + reducedMatrix.push_back({{30, 1}}); + reducedMatrix.push_back({{31, 1}}); + } + } + + if constexpr (Matrix::Option_list::column_indexation_type == Column_indexation_types::IDENTIFIER){ + test_column_equality(reducedMatrix[0], get_column_content_via_iterators(m.get_column(0))); + test_column_equality(reducedMatrix[1], get_column_content_via_iterators(m.get_column(1))); + test_column_equality(reducedMatrix[2], get_column_content_via_iterators(m.get_column(2))); + test_column_equality(reducedMatrix[3], get_column_content_via_iterators(m.get_column(3))); + test_column_equality(reducedMatrix[4], get_column_content_via_iterators(m.get_column(4))); + test_column_equality(reducedMatrix[5], get_column_content_via_iterators(m.get_column(5))); + test_column_equality(reducedMatrix[6], get_column_content_via_iterators(m.get_column(6))); + test_column_equality(reducedMatrix[7], get_column_content_via_iterators(m.get_column(10))); + test_column_equality(reducedMatrix[8], get_column_content_via_iterators(m.get_column(11))); + test_column_equality(reducedMatrix[9], get_column_content_via_iterators(m.get_column(12))); + test_column_equality(reducedMatrix[10], get_column_content_via_iterators(m.get_column(13))); + test_column_equality(reducedMatrix[11], get_column_content_via_iterators(m.get_column(14))); + test_column_equality(reducedMatrix[12], get_column_content_via_iterators(m.get_column(15))); + test_column_equality(reducedMatrix[13], get_column_content_via_iterators(m.get_column(16))); + test_column_equality(reducedMatrix[14], get_column_content_via_iterators(m.get_column(17))); + test_column_equality(reducedMatrix[15], get_column_content_via_iterators(m.get_column(30))); + test_column_equality(reducedMatrix[16], get_column_content_via_iterators(m.get_column(31))); + } else { + test_content_equality(reducedMatrix, m); + } + + std::set, BarComp> bars1; + std::set, BarComp> bars2; + std::set, BarComp> bars3; + // bars are not ordered the same for all matrices + for (auto it = barcode.begin(); it != barcode.end(); ++it) { + //three access possibilities + bars1.emplace(it->dim, it->birth, it->death); + bars2.emplace(std::get<2>(*it), std::get<0>(*it), std::get<1>(*it)); + auto [ x, y, z ] = *it; + bars3.emplace(z, x, y); + } + auto it = bars1.begin(); + BOOST_CHECK_EQUAL(std::get<0>(*it), 0); + BOOST_CHECK_EQUAL(std::get<1>(*it), 0); + BOOST_CHECK_EQUAL(std::get<2>(*it), -1); + ++it; + BOOST_CHECK_EQUAL(std::get<0>(*it), 0); + BOOST_CHECK_EQUAL(std::get<1>(*it), 1); + BOOST_CHECK_EQUAL(std::get<2>(*it), 7); + ++it; + BOOST_CHECK_EQUAL(std::get<0>(*it), 0); + BOOST_CHECK_EQUAL(std::get<1>(*it), 2); + BOOST_CHECK_EQUAL(std::get<2>(*it), 9); + ++it; + BOOST_CHECK_EQUAL(std::get<0>(*it), 0); + BOOST_CHECK_EQUAL(std::get<1>(*it), 3); + BOOST_CHECK_EQUAL(std::get<2>(*it), 8); + ++it; + BOOST_CHECK_EQUAL(std::get<0>(*it), 0); + BOOST_CHECK_EQUAL(std::get<1>(*it), 4); + BOOST_CHECK_EQUAL(std::get<2>(*it), 10); + ++it; + BOOST_CHECK_EQUAL(std::get<0>(*it), 0); + BOOST_CHECK_EQUAL(std::get<1>(*it), 5); + BOOST_CHECK_EQUAL(std::get<2>(*it), 14); + ++it; + BOOST_CHECK_EQUAL(std::get<0>(*it), 0); + BOOST_CHECK_EQUAL(std::get<1>(*it), 6); + BOOST_CHECK_EQUAL(std::get<2>(*it), 12); + ++it; + BOOST_CHECK_EQUAL(std::get<0>(*it), 1); + BOOST_CHECK_EQUAL(std::get<1>(*it), 11); + BOOST_CHECK_EQUAL(std::get<2>(*it), 15); + ++it; + BOOST_CHECK_EQUAL(std::get<0>(*it), 1); + BOOST_CHECK_EQUAL(std::get<1>(*it), 13); + BOOST_CHECK_EQUAL(std::get<2>(*it), 16); + ++it; + BOOST_CHECK(it == bars1.end()); + + BOOST_CHECK(bars1 == bars2); + BOOST_CHECK(bars1 == bars3); +} + +template +void test_shifted_barcode2() { using C = typename Matrix::Column; struct BarComp { bool operator()(const std::tuple& c1, const std::tuple& c2) const { - if (std::get<0>(c1) == std::get<0>(c2)) return std::get<1>(c1) < std::get<1>(c2); - return std::get<0>(c1) < std::get<0>(c2); + if (std::get<0>(c1) != std::get<0>(c2)) return std::get<0>(c1) < std::get<0>(c2); + if (std::get<1>(c1) != std::get<1>(c2)) return std::get<1>(c1) < std::get<1>(c2); + return std::get<2>(c1) < std::get<2>(c2); } }; @@ -1553,6 +1762,12 @@ void test_shifted_barcode() { BOOST_CHECK(bars1 == bars3); } +template +void test_shifted_barcode() { + test_shifted_barcode1(); + test_shifted_barcode2(); +} + template void test_base_swaps() { auto columns = build_simple_boundary_matrix(); From b752394140a931d8cc2da7f79f7f56bb2660beb7 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 15 Nov 2024 14:34:11 +0100 Subject: [PATCH 96/96] merge fix --- src/cmake/modules/GUDHI_third_party_libraries.cmake | 3 ++- src/python/CMakeLists.txt | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cmake/modules/GUDHI_third_party_libraries.cmake b/src/cmake/modules/GUDHI_third_party_libraries.cmake index 43ec964976..088ab1b8e5 100644 --- a/src/cmake/modules/GUDHI_third_party_libraries.cmake +++ b/src/cmake/modules/GUDHI_third_party_libraries.cmake @@ -193,10 +193,11 @@ if (WITH_GUDHI_PYTHON) endif() endif() + if(NOT GUDHI_PYTHON_PATH) message(FATAL_ERROR "ERROR: GUDHI_PYTHON_PATH is not valid.") endif(NOT GUDHI_PYTHON_PATH) option(WITH_GUDHI_PYTHON_RUNTIME_LIBRARY_DIRS "Build with setting runtime_library_dirs. Useful when setting rpath is not allowed" ON) -endif (WITH_GUDHI_PYTHON) +endif (WITH_GUDHI_PYTHON) \ No newline at end of file diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index 8a3b6bdd9e..8314661f04 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -131,6 +131,7 @@ if(SCIPY_FOUND) else() disable_python_documentation("scipy") endif() +if(SCIKIT-LEARN_FOUND) add_gudhi_debug_info("Scikit-learn version ${SCIKIT-LEARN_VERSION}") else() disable_python_documentation("scikit-learn") @@ -714,4 +715,4 @@ if(MATPLOTLIB_FOUND) endif() # Set missing or not modules -set(GUDHI_MODULES ${GUDHI_MODULES} "python" CACHE INTERNAL "GUDHI_MODULES") +set(GUDHI_MODULES ${GUDHI_MODULES} "python" CACHE INTERNAL "GUDHI_MODULES") \ No newline at end of file