├── cmake ├── .clang-tidy ├── PreventInSourceBuilds.cmake ├── Cache.cmake ├── StaticAnalyzers.cmake ├── StandardProjectSettings.cmake ├── Sanitizers.cmake └── CompilerWarnings.cmake ├── docs └── images │ ├── 26.png │ ├── 44.png │ ├── t8-v68-s298.png │ └── S3-7-27528-I1-R1.png ├── .github ├── CODEOWNERS ├── dependabot.yml ├── workflows │ ├── whitespace.yml │ ├── doxygen.yml │ ├── clang-format-check.yml │ ├── cpp-linter.yml │ ├── windows-pkgx.yml │ ├── windows-msvc.yml │ ├── cppcheck.yml │ ├── linux-gcc.yml │ ├── linux-clang.yml │ ├── macos.yml │ ├── lsan.yml │ ├── asan.yml │ ├── msan.yml │ ├── tsan.yml │ ├── valgrind.yml │ ├── codecov-upload.yml │ ├── sonarcloud.yml │ └── codeql.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── CODE_OF_CONDUCT.md └── CONTRIBUTING.md ├── .gitpod.yml ├── Dockerfile ├── scripts ├── cppcheck.sh ├── build.sh ├── debug.sh ├── fast-build.sh ├── scan.sh ├── lsan.sh ├── msan.sh ├── tsan.sh ├── clang-tidy.sh ├── asan.sh ├── iwyu.sh ├── gcov.sh ├── slurm.sh ├── codecov.sh ├── fast-build.bat ├── build.bat └── pvs-studio.sh ├── vcpkg.json ├── .cmake-format.yaml ├── tests ├── main.cpp ├── CMakeLists.txt ├── Torus_test.cpp ├── Settings_test.cpp ├── S3Action_test.cpp ├── Function_ref_test.cpp ├── Move_always_test.cpp ├── Apply_move_test.cpp ├── Move_tracker_test.cpp ├── Geometry_test.cpp ├── Metropolis_test.cpp └── Vertex_test.cpp ├── .codecov.yml ├── sonar-project.properties ├── .gitignore ├── include ├── Move_strategy.hpp ├── Formatters.hpp ├── Torus_d.hpp ├── Apply_move.hpp ├── Periodic_3_complex.hpp ├── Settings.hpp ├── Triangulation_traits.hpp ├── Periodic_3_triangulations.hpp ├── Geometry.hpp ├── Move_always.hpp └── Move_tracker.hpp ├── src ├── test.py ├── cdt-opt.cpp ├── CMakeLists.txt ├── optimize-initialize.py ├── bistellar-flip.cpp ├── cdt-viewer.cpp └── initialize.cpp ├── LICENSE.md ├── .appveyor.yml ├── .coderabbit.yaml ├── CMakeLists.txt ├── .travis.yml └── .clang-format /cmake/.clang-tidy: -------------------------------------------------------------------------------- 1 | # Disable all checks in folder 2 | Checks: '-*' -------------------------------------------------------------------------------- /docs/images/26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acgetchell/CDT-plusplus/HEAD/docs/images/26.png -------------------------------------------------------------------------------- /docs/images/44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acgetchell/CDT-plusplus/HEAD/docs/images/44.png -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in the repo. 2 | * @acgetchell -------------------------------------------------------------------------------- /docs/images/t8-v68-s298.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acgetchell/CDT-plusplus/HEAD/docs/images/t8-v68-s298.png -------------------------------------------------------------------------------- /docs/images/S3-7-27528-I1-R1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acgetchell/CDT-plusplus/HEAD/docs/images/S3-7-27528-I1-R1.png -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | image: acgetchell/vcpkg-image 2 | 3 | tasks: 4 | - init: > 5 | vcpkg install 6 | && cd scripts 7 | && ./fast-build.sh 8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM acgetchell/vcpkg-image 2 | 3 | LABEL description="CDT++ run container" 4 | 5 | RUN git clone https://github.com/acgetchell/CDT-plusplus.git \ 6 | && cd /CDT-plusplus/scripts \ 7 | && ./fast-build.sh 8 | 9 | CMD ["/bin/bash"] -------------------------------------------------------------------------------- /scripts/cppcheck.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Before running this script, make sure $VCPKG_ROOT is set, e.g. 4 | # VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT 5 | 6 | cd .. 7 | rm -rf build 8 | cmake -S . -B build -G Ninja -D ENABLE_CPPCHECK=ON 9 | cmake --build build 10 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Before running this script, make sure $VCPKG_ROOT is set, e.g. 4 | # VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT 5 | 6 | cd .. 7 | rm -rf build/ 8 | cmake --preset build 9 | cmake --build build 10 | cd build || exit 11 | ctest --output-on-failure -j2 -------------------------------------------------------------------------------- /scripts/debug.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Before running this script, make sure $VCPKG_ROOT is set, e.g. 4 | # VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT 5 | 6 | cd .. 7 | rm -rf build/ 8 | cmake --preset debug 9 | cmake --build build 10 | cd build || exit 11 | ctest --output-on-failure -j2 12 | -------------------------------------------------------------------------------- /scripts/fast-build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Before running this script, make sure $VCPKG_ROOT is set, e.g. 4 | # VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT 5 | 6 | cd .. 7 | rm -rf build/ 8 | cmake --preset fast-build 9 | cmake --build build 10 | cd build || exit 11 | ctest --output-on-failure -j2 -------------------------------------------------------------------------------- /vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cdt-plusplus", 3 | "version": "0.1.8", 4 | "dependencies": [ 5 | "boost-program-options", 6 | "doctest", 7 | "date", 8 | "fmt", 9 | "ms-gsl", 10 | "eigen3", 11 | "pcg", 12 | "spdlog", 13 | "tbb", 14 | "tl-function-ref", 15 | { 16 | "name": "yasm-tool", 17 | "platform": "windows" 18 | }, 19 | "cgal" 20 | ] 21 | } -------------------------------------------------------------------------------- /.github/workflows/whitespace.yml: -------------------------------------------------------------------------------- 1 | name: Whitespace 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - develop 8 | pull_request: 9 | branches: 10 | - develop 11 | workflow_dispatch: 12 | 13 | jobs: 14 | whitespace: 15 | name: Find Trailing Whitespace 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v4 19 | - uses: erictleung/find-file-whitespace@main -------------------------------------------------------------------------------- /scripts/scan.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # MacOS and homebrew specific 3 | 4 | # Before running this script, make sure $VCPKG_ROOT is set, e.g. 5 | # VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT 6 | 7 | cd .. 8 | rm -rf build/ 9 | mkdir build 10 | cd build || exit 11 | cmake -D CMAKE_BUILD_TYPE=Debug -G Ninja -D CMAKE_CXX_COMPILER=clang++ .. 12 | # M1 Mac location 13 | /opt/homebrew/opt/llvm/bin/scan-build -o "$(pwd)"/scanresults -v ninja 14 | -------------------------------------------------------------------------------- /.cmake-format.yaml: -------------------------------------------------------------------------------- 1 | additional_commands: 2 | foo: 3 | flags: 4 | - BAR 5 | - BAZ 6 | kwargs: 7 | DEPENDS: '*' 8 | HEADERS: '*' 9 | SOURCES: '*' 10 | bullet_char: '*' 11 | dangle_parens: false 12 | enum_char: . 13 | line_ending: unix 14 | line_width: 120 15 | max_pargs_hwrap: 3 16 | separate_ctrl_name_with_space: false 17 | separate_fn_name_with_space: false 18 | tab_size: 2 19 | 20 | markup: 21 | enable_markup: false -------------------------------------------------------------------------------- /scripts/lsan.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Before running this script, make sure $VCPKG_ROOT is set, e.g. 4 | # VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT 5 | 6 | cd .. 7 | rm -rf build 8 | cmake -S . -B build -G Ninja -D CMAKE_BUILD_TYPE=RelWithDebInfo -D ENABLE_SANITIZER_LEAK:BOOL=TRUE 9 | cmake --build build 10 | pwd 11 | cd build/src || exit 12 | ./initialize --s -n32000 -t11 -o 13 | cd .. || exit 14 | ctest --rerun-failed --output-on-failure -j2 -------------------------------------------------------------------------------- /scripts/msan.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Before running this script, make sure $VCPKG_ROOT is set, e.g. 4 | # VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT 5 | 6 | cd .. 7 | rm -rf build 8 | cmake -S . -B build -G Ninja -D CMAKE_BUILD_TYPE=RelWithDebInfo -D ENABLE_SANITIZER_MEMORY:BOOL=TRUE 9 | cmake --build build 10 | pwd 11 | cd build/src || exit 12 | ./initialize --s -n32000 -t11 -o 13 | cd .. || exit 14 | ctest --rerun-failed --output-on-failure -j2 -------------------------------------------------------------------------------- /scripts/tsan.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Before running this script, make sure $VCPKG_ROOT is set, e.g. 4 | # VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT 5 | 6 | cd .. 7 | rm -rf build 8 | cmake -S . -B build -G Ninja -D CMAKE_BUILD_TYPE=RelWithDebInfo -D ENABLE_SANITIZER_THREAD:BOOL=TRUE 9 | cmake --build build 10 | pwd 11 | cd build/src || exit 12 | ./initialize --s -n32000 -t11 -o 13 | cd .. || exit 14 | ctest --rerun-failed --output-on-failure -j2 -------------------------------------------------------------------------------- /scripts/clang-tidy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Before running this script, make sure $VCPKG_ROOT is set, e.g. 4 | # VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT 5 | 6 | cd .. 7 | rm -rf build/ 8 | cmake -S . -B build -G Ninja -D ENABLE_CLANG_TIDY=ON 9 | # Make blank .clang-tidy into build directory to tell clang-tidy to ignore the Qt files which cause a lot of warnings 10 | touch build/.clang-tidy 11 | #echo "Checks: '-*'" >> build/.clang-tidy 12 | cmake --build build 13 | -------------------------------------------------------------------------------- /.github/workflows/doxygen.yml: -------------------------------------------------------------------------------- 1 | name: Doxygen GitHub Pages Deploy Action 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - develop 8 | workflow_dispatch: 9 | 10 | jobs: 11 | deploy: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: DenverCoder1/doxygen-github-pages-action@v2.0.0 15 | with: 16 | github_token: ${{ secrets.GITHUB_TOKEN }} 17 | branch: gh-pages 18 | folder: docs/html 19 | config_file: docs/Doxyfile -------------------------------------------------------------------------------- /scripts/asan.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Before running this script, make sure $VCPKG_ROOT is set, e.g. 4 | # VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT 5 | 6 | cd .. 7 | rm -rf build 8 | cmake -S . -B build -G Ninja -D CMAKE_BUILD_TYPE=RelWithDebInfo -D ENABLE_SANITIZER_ADDRESS:BOOL=TRUE -D ENABLE_SANITIZER_UNDEFINED_BEHAVIOR:BOOL=TRUE 9 | cmake --build build 10 | pwd 11 | cd build/src || exit 12 | ./initialize --s -n32000 -t11 -o 13 | cd .. || exit 14 | ctest --rerun-failed --output-on-failure -j2 -------------------------------------------------------------------------------- /scripts/iwyu.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This script runs include-what-you-use 4 | # It assumes that you have it installed in a standard location, e.g. brew install include-what-you-use 5 | 6 | # Before running this script, make sure $VCPKG_ROOT is set, e.g. 7 | # VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT 8 | 9 | 10 | cd .. 11 | rm -rf build/ 12 | cmake -G Ninja -D CMAKE_BUILD_TYPE=RelWithDebInfo -D ENABLE_TESTING:BOOL=TRUE -D ENABLE_INCLUDE_WHAT_YOU_USE:BOOL=TRUE -S . -B build 13 | cmake --build build -------------------------------------------------------------------------------- /tests/main.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2017 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file main.cpp 8 | /// @brief doctest driver 9 | /// @author https://github.com/doctest/doctest 10 | /// @details Main doctest driver 11 | 12 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 13 | #define DOCTEST_CONFIG_SUPER_FAST_ASSERTS 14 | #include 15 | -------------------------------------------------------------------------------- /scripts/gcov.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Before running this script, make sure $VCPKG_ROOT is set, e.g. 4 | # VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT 5 | 6 | cd .. 7 | rm -rf build/ 8 | cmake -G Ninja -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE=Debug -D ENABLE_TESTING:BOOL=TRUE -S . -B build 9 | cmake --build build 10 | cd build || exit 11 | ctest --output-on-failure -j2 12 | mkdir gcov-reports 13 | pushd gcov-reports 14 | for f in `find ../tests/CMakeFiles/CDT_test.dir -name '*.o'`; do 15 | echo "Processing $f file..." 16 | gcov -o ${f} x 17 | done 18 | ls | wc -l 19 | popd -------------------------------------------------------------------------------- /scripts/slurm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -l 2 | # For use on Slurm 3 | # sbatch -p high -t 60 slurm.sh 4 | # Or, interactively, 5 | # srun -p med2 -t 1-00 --mem=100G --ntasks 12 --pty /bin/bash -il 6 | module load cmake/3.28.1 7 | module load gcc/13.2.0 8 | module load autoconf-archive/2022.02.11 9 | cd .. 10 | rm -rf build/ 11 | cmake -D CMAKE_BUILD_TYPE=RelWithDebInfo -D ENABLE_TESTING:BOOL=TRUE -S . -B build 12 | cmake --build build 13 | cd build || exit 14 | ctest --output-on-failure -j2 15 | #mkdir "$HOME"/data/"$(date +%Y-%m-%d.%R%Z)" 16 | #cp cdt-opt "$HOME"/data/"$(date +%Y-%m-%d.%R%Z)"/ 17 | #cd "$HOME"/data/"$(date +%Y-%m-%d.%R%Z)" || exit 18 | #./cdt-opt 2>>errors 1>>output -------------------------------------------------------------------------------- /scripts/codecov.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Before running this script, make sure $VCPKG_ROOT is set, e.g. 4 | # VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT 5 | 6 | cd .. 7 | rm -rf build 8 | mkdir build 9 | cd build || exit 10 | cmake -D ENABLE_COVERAGE:BOOL=TRUE --trace-source=CMakeLists.txt --trace-source=Sanitizers.cmake .. 11 | cmake --build . --config Debug 12 | pwd 13 | ctest --schedule-random -V -j2 14 | lcov --directory . --capture --output-file coverage.info 15 | lcov --remove coverage.info '/usr/*' '*/usr/include/*' '*/vcpkg/*' --output-file coverage.info 16 | lcov --list coverage.info 17 | bash <(curl -s https://codecov.io/bash) -f coverage.info || echo "Codecov did not collect coverage reports" -------------------------------------------------------------------------------- /scripts/fast-build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | SETLOCAL ENABLEEXTENSIONS 4 | SET me=%~n0 5 | SET parent=%~dp0 6 | 7 | cd .. 8 | IF EXIST "build" rmdir /S /Q build || EXIT /B 1 9 | :: Assumes you have cloned vcpkg into %HOMEPATH%\Projects 10 | set VCPKG_PATH=%HOMEPATH%\Projects\vcpkg 11 | 12 | :: In case you want to build from the command line 13 | set PATH=%PATH%;%VCPKG_PATH% 14 | 15 | 16 | :: Change to your version of Visual Studio 17 | cmake -G "Visual Studio 16 2019" -A x64 -D CMAKE_BUILD_TYPE=Release ENABLE_TESTING:BOOL=FALSE -D ENABLE_CACHE:BOOL=FALSE -D CMAKE_TOOLCHAIN_FILE=%VCPKG_PATH%/scripts/buildsystems/vcpkg.cmake -S . -B build 18 | cmake --build build 19 | 20 | :: Executables are in \build\src\Release -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /scripts/build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | SETLOCAL ENABLEEXTENSIONS 4 | SET me=%~n0 5 | SET parent=%~dp0 6 | 7 | cd .. 8 | IF EXIST "build" rmdir /S /Q build || EXIT /B 1 9 | :: Assumes you have cloned vcpkg into %HOMEPATH%\Projects 10 | set VCPKG_PATH=%HOMEPATH%\Projects\vcpkg 11 | 12 | :: In case you want to build from the command line with Ninja from vcpkg 13 | set PATH=%PATH%;%VCPKG_PATH% 14 | 15 | :: Change to your version of Visual Studio 16 | cmake -G "Visual Studio 16 2019" -A x64 -D CMAKE_BUILD_TYPE=RelWithDebInfo -D ENABLE_TESTING:BOOL=TRUE -D ENABLE_CACHE:BOOL=FALSE -D CMAKE_TOOLCHAIN_FILE=%VCPKG_PATH%/scripts/buildsystems/vcpkg.cmake -S . -B build 17 | cmake --build build 18 | 19 | :: Executables are in \build\src\Debug 20 | :: Tests are in \build\tests\Debug -------------------------------------------------------------------------------- /.github/workflows/clang-format-check.yml: -------------------------------------------------------------------------------- 1 | name: clang-format Check 2 | on: 3 | push: 4 | branches: 5 | - main 6 | - develop 7 | pull_request: 8 | branches: 9 | - develop 10 | workflow_dispatch: 11 | 12 | jobs: 13 | formatting-check: 14 | name: Formatting Check 15 | runs-on: ubuntu-latest 16 | strategy: 17 | matrix: 18 | path: 19 | - 'src' 20 | - 'include' 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Run clang-format style check for C/C++/Protobuf programs. 24 | uses: jidicula/clang-format-action@v4.15.0 25 | with: 26 | clang-format-version: '18' 27 | check-path: ${{ matrix.path }} 28 | fallback-style: 'Google' # optional -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | token: 2a599f2d-815e-4c14-9c66-054407863d2b 3 | notify: 4 | require_ci_to_pass: no 5 | 6 | coverage: 7 | precision: 2 8 | round: down 9 | range: "30...100" 10 | 11 | status: 12 | project: 13 | default: 14 | threshold: 3% 15 | patch: off 16 | changes: false 17 | 18 | notify: 19 | gitter: 20 | default: 21 | url: https://webhooks.gitter.im/e/c70e4d2749931f601747 22 | threshold: 1% 23 | 24 | parsers: 25 | gcov: 26 | branch_detection: 27 | conditional: yes 28 | loop: yes 29 | method: no 30 | macro: no 31 | 32 | comment: 33 | layout: "reach, diff, flags, files, footer" 34 | behavior: default 35 | require_changes: false 36 | 37 | ignore: 38 | - "tests/" 39 | -------------------------------------------------------------------------------- /.github/workflows/cpp-linter.yml: -------------------------------------------------------------------------------- 1 | name: cpp-linter 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - develop 8 | pull_request: 9 | branches: 10 | - develop 11 | workflow_dispatch: 12 | 13 | jobs: 14 | cpp-linter: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | - uses: cpp-linter/cpp-linter-action@v2 19 | id: linter 20 | env: 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | with: 23 | style: file 24 | tidy-checks: '' 25 | version: 19 26 | 27 | - name: Fail fast?! 28 | if: steps.linter.outputs.checks-failed > 0 29 | run: echo "Some files failed the linting checks!" 30 | # for actual deployment 31 | # run: exit 1 -------------------------------------------------------------------------------- /scripts/pvs-studio.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This script runs PVS-Studio Analyzer 4 | # It assumes that you have it installed in a standard location with the proper license 5 | # CMake must output compile_commands.json in order for pvs-studio-analyzer to work 6 | 7 | # Before running this script, make sure $VCPKG_ROOT is set, e.g. 8 | # VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT 9 | 10 | cd .. 11 | rm -rf build/ 12 | cmake --preset debug 13 | cmake --build build 14 | cd build || exit 15 | pvs-studio-analyzer analyze -o pvsreport.log -e ../vcpkg_installed -j8 16 | # Filter warning 521 17 | pvs-studio-analyzer suppress -v521 pvsreport.log 18 | pvs-studio-analyzer filter-suppressed pvsreport.log 19 | plog-converter -t fullhtml -o pvs-html pvsreport.log 20 | cd pvs-html || exit 21 | open index.html 22 | -------------------------------------------------------------------------------- /cmake/PreventInSourceBuilds.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # This function will prevent in-source builds 3 | function(AssureOutOfSourceBuilds) 4 | # make sure the user doesn't play dirty with symlinks 5 | get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH) 6 | get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH) 7 | 8 | # disallow in-source builds 9 | if("${srcdir}" STREQUAL "${bindir}") 10 | message("######################################################") 11 | message("Warning: in-source builds are disabled") 12 | message("Please create a separate build directory and run cmake from there") 13 | message("######################################################") 14 | message(FATAL_ERROR "Quitting configuration") 15 | endif() 16 | endfunction() 17 | 18 | assureoutofsourcebuilds() 19 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Causal Dynamical Triangulations in C++ using CGAL 3 | # 4 | # Copyright © 2021 Adam Getchell 5 | # 6 | 7 | sonar.projectKey=acgetchell_CDT-plusplus 8 | sonar.organization=acgetchell-github 9 | 10 | # This is the name and version displayed in the SonarCloud UI. 11 | #sonar.projectName=CDT-plusplus 12 | #sonar.projectVersion=1.0 13 | 14 | # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. 15 | sonar.sources=src,include 16 | sonar.tests=tests 17 | sonar.cfamily.build-wrapper-output=build_wrapper_output_directory 18 | #sonar.cfamily.cache.enabled=true 19 | #sonar.cfamily.cache.path=.sonar 20 | sonar.cfamily.threads=2 21 | sonar.cfamily.gcov.reportsPath=build/gcov-reports 22 | sonar.python.version=2.7, 3.9 23 | 24 | # Encoding of the source code. Default is default system encoding 25 | #sonar.sourceEncoding=UTF-8 -------------------------------------------------------------------------------- /cmake/Cache.cmake: -------------------------------------------------------------------------------- 1 | option(ENABLE_CACHE "Enable cache if available" ON) 2 | if(NOT ENABLE_CACHE) 3 | return() 4 | endif() 5 | 6 | set(CACHE_OPTION 7 | "ccache" 8 | CACHE STRING "Compiler cache to be used") 9 | set(CACHE_OPTION_VALUES "ccache" "sccache") 10 | set_property(CACHE CACHE_OPTION PROPERTY STRINGS ${CACHE_OPTION_VALUES}) 11 | list( 12 | FIND 13 | CACHE_OPTION_VALUES 14 | ${CACHE_OPTION} 15 | CACHE_OPTION_INDEX) 16 | 17 | if(${CACHE_OPTION_INDEX} EQUAL -1) 18 | message( 19 | STATUS 20 | "Using custom compiler cache system: '${CACHE_OPTION}', explicitly supported entries are ${CACHE_OPTION_VALUES}") 21 | endif() 22 | 23 | find_program(CACHE_BINARY ${CACHE_OPTION}) 24 | if(CACHE_BINARY) 25 | message(STATUS "${CACHE_OPTION} found and enabled") 26 | set(CMAKE_CXX_COMPILER_LAUNCHER ${CACHE_BINARY}) 27 | else() 28 | message(WARNING "${CACHE_OPTION} is enabled but was not found. Not using it") 29 | endif() 30 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable( 2 | CDT_unit_tests 3 | ${PROJECT_SOURCE_DIR}/tests/main.cpp 4 | Apply_move_test.cpp 5 | Bistellar_flip_test.cpp 6 | Ergodic_moves_3_test.cpp 7 | Foliated_triangulation_test.cpp 8 | Function_ref_test.cpp 9 | Geometry_test.cpp 10 | Manifold_test.cpp 11 | Metropolis_test.cpp 12 | Move_always_test.cpp 13 | Move_command_test.cpp 14 | Move_tracker_test.cpp 15 | S3Action_test.cpp 16 | Settings_test.cpp 17 | Tetrahedron_test.cpp 18 | Torus_test.cpp 19 | Utilities_test.cpp 20 | Vertex_test.cpp) 21 | # Activate C++23 features 22 | target_compile_features(CDT_unit_tests PRIVATE cxx_std_23) 23 | target_link_libraries( 24 | CDT_unit_tests 25 | PRIVATE project_options 26 | project_warnings 27 | date::date-tz 28 | fmt::fmt-header-only 29 | TBB::tbb 30 | CGAL::CGAL) 31 | 32 | # Run unit tests 33 | add_test(NAME cdt-unit-tests COMMAND $) 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/workflows/windows-pkgx.yml: -------------------------------------------------------------------------------- 1 | name: Windows pkgx 2 | 3 | on: [workflow_dispatch] 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.ref }} 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | build: 11 | runs-on: windows-latest 12 | 13 | env: 14 | VCPKG_DEFAULT_TRIPLET: x64-windows 15 | VCPKG_ROOT: C:\vcpkg 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | with: 20 | fetch-depth: 0 21 | submodules: true 22 | 23 | - name: Setup Clang 24 | uses: pkgxdev/setup@v4 25 | with: 26 | +: clang@19 27 | 28 | - name: Restore artifacts, or setup vcpkg 29 | uses: lukka/run-vcpkg@v11 30 | with: 31 | vcpkgGitCommitId: ${{ vars.VCPKG_GIT_COMMIT_ID }} 32 | 33 | - name: Install vcpkg packages and configure CMake 34 | run: | 35 | vcpkg install 36 | cmake -D CMAKE_BUILD_TYPE=RelWithDebInfo -D ENABLE_TESTING:BOOL=TRUE -D ENABLE_CACHE:BOOL=FALSE -S . -B build 37 | 38 | - name: Build 39 | run: cmake --build build -------------------------------------------------------------------------------- /.github/workflows/windows-msvc.yml: -------------------------------------------------------------------------------- 1 | name: Windows 2 | 3 | on: [workflow_dispatch] 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.ref }} 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | build: 11 | runs-on: windows-latest 12 | 13 | env: 14 | VCPKG_DEFAULT_TRIPLET: x64-windows 15 | VCPKG_ROOT: C:\vcpkg 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | with: 20 | fetch-depth: 0 21 | submodules: true 22 | 23 | - name: Setup Clang 24 | uses: egor-tensin/setup-clang@v1 25 | with: 26 | platform: x64 27 | 28 | - name: Restore artifacts, or setup vcpkg 29 | uses: lukka/run-vcpkg@v11 30 | with: 31 | vcpkgGitCommitId: ${{ vars.VCPKG_GIT_COMMIT_ID }} 32 | 33 | - name: Install vcpkg packages and configure CMake 34 | run: | 35 | vcpkg install 36 | cmake -D CMAKE_BUILD_TYPE=RelWithDebInfo -D ENABLE_TESTING:BOOL=TRUE -D ENABLE_CACHE:BOOL=FALSE -S . -B build 37 | 38 | - name: Build 39 | run: cmake --build build -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # C++.gitignore 2 | 3 | # Compiled Object files 4 | *.slo 5 | *.lo 6 | 7 | # Compiled Dynamic libraries 8 | *.so 9 | *.dylib 10 | 11 | # Compiled Static libraries 12 | *.lai 13 | *.la 14 | 15 | # Precompiled headers 16 | *.pch 17 | 18 | # OS X temporary files that should never be committed 19 | .DS_Store 20 | *.swp 21 | *.lock 22 | profile 23 | 24 | # Build, Doc, and Testing dirs 25 | /build* 26 | html/ 27 | /cmake-build* 28 | cov-int 29 | /out/* 30 | /Testing 31 | 32 | # Editor files 33 | .clang_complete 34 | .idea 35 | .vs* 36 | xcode/ 37 | CMakeSEttings.json 38 | 39 | # Program/script executables 40 | cdt_tests 41 | grid_d 42 | 43 | # Output files 44 | output* 45 | errors 46 | *.off 47 | *.dat 48 | slurm-*.out 49 | *PVS-Studio* 50 | 51 | # Instrumentation 52 | *.trace 53 | build-wrapper-macosx-x86 54 | *.scannerwork 55 | bw-output/* 56 | coverage.info 57 | 58 | # Cruft 59 | *.old.* 60 | *.bak 61 | 62 | # SourceTrail 63 | *.srctrlbm 64 | *.srctrldb* 65 | *.srctrlprj 66 | 67 | # Pipenv 68 | Pipfile 69 | scanresults/ 70 | venv 71 | 72 | # vcpkg 73 | vcpkg_installed 74 | -------------------------------------------------------------------------------- /include/Move_strategy.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2017 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file Move_strategy.hpp 8 | /// @brief Template class for move algorithms (strategies) on manifolds 9 | /// @author Adam Getchell 10 | /// @details Template class for all move algorithms, e.g. Metropolis, 11 | /// MoveAlways. 12 | 13 | #ifndef INCLUDE_MOVE_ALGORITHM_HPP_ 14 | #define INCLUDE_MOVE_ALGORITHM_HPP_ 15 | 16 | /** 17 | * \brief The algorithms available to make ergodic moves on triangulations 18 | */ 19 | enum class Strategies 20 | { 21 | MOVE_ALWAYS, 22 | METROPOLIS 23 | }; 24 | 25 | /** 26 | * \brief Select a move algorithm 27 | * \tparam strategies The move algorithm to use 28 | * \tparam ManifoldType The manifold to perform moves on 29 | */ 30 | template 31 | class MoveStrategy 32 | {}; 33 | 34 | #endif // INCLUDE_MOVE_ALGORITHM_HPP_ 35 | -------------------------------------------------------------------------------- /.github/workflows/cppcheck.yml: -------------------------------------------------------------------------------- 1 | name: Cppcheck 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - develop 8 | pull_request: 9 | branches: 10 | - develop 11 | workflow_dispatch: 12 | 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.ref }} 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | submodules: true 26 | 27 | - name: Setup 28 | run: | 29 | sudo apt update 30 | sudo apt-get install build-essential automake autoconf autoconf-archive texinfo libtool-bin yasm ninja-build ccache cppcheck 31 | 32 | - name: Setup GCC 33 | uses: pkgxdev/setup@v4 34 | with: 35 | +: gcc@15 36 | 37 | - run: gcc --version 38 | 39 | - name: Restore artifacts or setup vcpkg 40 | uses: lukka/run-vcpkg@v11 41 | with: 42 | vcpkgGitCommitId: ${{ vars.VCPKG_GIT_COMMIT_ID }} 43 | 44 | - name: Configure 45 | run: cmake --preset=cppcheck 46 | 47 | - name: Build 48 | run: cmake --build build -j 2 -------------------------------------------------------------------------------- /src/test.py: -------------------------------------------------------------------------------- 1 | # Causal Dynamical Triangulations in C++ using CGAL 2 | # 3 | # Copyright © 2021 Adam Getchell 4 | # 5 | # First pass at ML for CDT++ 6 | 7 | # @file test.py 8 | # @brief ML using TensorFlow 9 | # @author Adam Getchell 10 | 11 | # Usage: python test.py 12 | # 13 | 14 | import tensorflow as tf 15 | 16 | mnist = tf.keras.datasets.mnist 17 | 18 | (x_train, y_train), (x_test, y_test) = mnist.load_data() 19 | x_train, x_test = x_train / 255.0, x_test / 255.0 20 | 21 | model = tf.keras.models.Sequential([ 22 | tf.keras.layers.Flatten(input_shape=(28, 28)), 23 | tf.keras.layers.Dense(128, activation='relu'), 24 | tf.keras.layers.Dropout(0.2), 25 | tf.keras.layers.Dense(10) 26 | ]) 27 | 28 | predictions = model(x_train[:1]).numpy() 29 | 30 | tf.nn.softmax(predictions).numpy() 31 | 32 | loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True) 33 | 34 | loss_fn(y_train[:1], predictions).numpy() 35 | 36 | model.compile(optimizer='adam', 37 | loss=loss_fn, 38 | metrics=['accuracy']) 39 | 40 | model.fit(x_train, y_train, epochs=5) 41 | 42 | model.evaluate(x_test, y_train, verbose=2) 43 | 44 | probability_model = tf.keras.Sequential([ 45 | model, 46 | tf.keras.layers.Softmax() 47 | ]) 48 | 49 | probability_model(x_test[:5]) -------------------------------------------------------------------------------- /.github/workflows/linux-gcc.yml: -------------------------------------------------------------------------------- 1 | name: Linux GCC 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - develop 8 | pull_request: 9 | branches: 10 | - develop 11 | workflow_dispatch: 12 | 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.ref }} 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | submodules: true 26 | 27 | - name: Setup 28 | run: | 29 | sudo apt update 30 | sudo apt-get install build-essential automake autoconf autoconf-archive texinfo libtool-bin yasm ninja-build ccache 31 | 32 | - name: Setup GCC 33 | uses: pkgxdev/setup@v4 34 | with: 35 | +: gcc@15 36 | 37 | - run: gcc --version 38 | 39 | - name: Restore artifacts or setup vcpkg 40 | uses: lukka/run-vcpkg@v11 41 | with: 42 | vcpkgGitCommitId: ${{ vars.VCPKG_GIT_COMMIT_ID }} 43 | 44 | - name: Configure 45 | run: cmake --preset=build 46 | 47 | - name: Build 48 | run: cmake --build build -j 2 49 | 50 | - name: Test 51 | working-directory: build 52 | continue-on-error: true 53 | run: ctest --rerun-failed --output-on-failure -j 2 -------------------------------------------------------------------------------- /.github/workflows/linux-clang.yml: -------------------------------------------------------------------------------- 1 | name: Linux Clang 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - develop 8 | pull_request: 9 | branches: 10 | - develop 11 | workflow_dispatch: 12 | 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.ref }} 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | submodules: true 26 | 27 | - name: Setup 28 | run: | 29 | sudo apt update 30 | sudo apt-get install build-essential automake autoconf autoconf-archive texinfo libtool-bin yasm ninja-build ccache 31 | 32 | - name: Setup Clang 33 | uses: pkgxdev/setup@v4 34 | with: 35 | +: clang@20 36 | 37 | - run: clang --version 38 | 39 | - name: Restore artifacts or setup vcpkg 40 | uses: lukka/run-vcpkg@v11 41 | with: 42 | vcpkgGitCommitId: ${{ vars.VCPKG_GIT_COMMIT_ID }} 43 | 44 | - name: Configure 45 | run: cmake --preset=build 46 | 47 | - name: Build 48 | run: cmake --build build -j 2 49 | 50 | - name: Test 51 | working-directory: build 52 | continue-on-error: true 53 | run: ctest --rerun-failed --output-on-failure -j 2 -------------------------------------------------------------------------------- /cmake/StaticAnalyzers.cmake: -------------------------------------------------------------------------------- 1 | option(ENABLE_CPPCHECK "Enable static analysis with cppcheck" OFF) 2 | option(ENABLE_CLANG_TIDY "Enable static analysis with clang-tidy" OFF) 3 | option(ENABLE_INCLUDE_WHAT_YOU_USE "Enable static analysis with include-what-you-use" OFF) 4 | 5 | if(ENABLE_CPPCHECK) 6 | find_program(CPPCHECK cppcheck) 7 | if(CPPCHECK) 8 | set(CMAKE_CXX_CPPCHECK 9 | ${CPPCHECK} 10 | --suppress=missingInclude 11 | --enable=all 12 | --inconclusive 13 | --force 14 | --verbose) 15 | message(STATUS "CppCheck enabled.") 16 | else() 17 | message(SEND_ERROR "cppcheck requested but executable not found") 18 | endif() 19 | endif() 20 | 21 | if(ENABLE_CLANG_TIDY) 22 | find_program(CLANGTIDY clang-tidy) 23 | if(CLANGTIDY) 24 | set(CMAKE_CXX_CLANG_TIDY ${CLANGTIDY} -extra-arg=-Wno-unknown-warning-option) 25 | message(STATUS "Clang-tidy enabled.") 26 | else() 27 | message(SEND_ERROR "clang-tidy requested but executable not found") 28 | endif() 29 | endif() 30 | 31 | if(ENABLE_INCLUDE_WHAT_YOU_USE) 32 | find_program(INCLUDE_WHAT_YOU_USE include-what-you-use) 33 | if(INCLUDE_WHAT_YOU_USE) 34 | set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${INCLUDE_WHAT_YOU_USE}) 35 | message(STATUS "Include-what-you-use enabled.") 36 | else() 37 | message(SEND_ERROR "include-what-you-use requested but executable not found") 38 | endif() 39 | endif() 40 | -------------------------------------------------------------------------------- /include/Formatters.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2025 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file Formatters.hpp 8 | /// @brief Formatter specializations for various types 9 | /// @author Adam Getchell 10 | /// @details Formatter specializations for types used in the project 11 | 12 | #ifndef CDT_PLUSPLUS_FORMATTERS_HPP 13 | #define CDT_PLUSPLUS_FORMATTERS_HPP 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | #include "Triangulation_traits.hpp" 21 | 22 | // Formatter specialization for CGAL::Point_3 23 | template 24 | struct fmt::formatter> 25 | { 26 | // Format specification handling - keeping it simple for now 27 | auto constexpr parse(format_parse_context& ctx) -> decltype(ctx.begin()) 28 | { 29 | return ctx.begin(); 30 | } 31 | 32 | // Format the point as a string with coordinates 33 | template 34 | auto format(const CGAL::Point_3& point, FormatContext& ctx) const 35 | -> decltype(ctx.out()) 36 | { 37 | std::stringstream ss; 38 | ss << point; 39 | return fmt::format_to(ctx.out(), "{}", ss.str()); 40 | } 41 | }; 42 | 43 | #endif // CDT_PLUSPLUS_FORMATTERS_HPP 44 | -------------------------------------------------------------------------------- /tests/Torus_test.cpp: -------------------------------------------------------------------------------- 1 | /// Causal Dynamical Triangulations in C++ using CGAL 2 | /// 3 | /// Copyright © 2017 Adam Getchell 4 | /// 5 | /// Tests that 2-tori and 3-tori are correctly constructed in 3D and 4D. 6 | /// 7 | /// @file Torus_test.cpp 8 | /// @brief Tests for wraparound grids 9 | /// @author Adam Getchell 10 | 11 | #include 12 | 13 | #include "Torus_d.hpp" 14 | 15 | SCENARIO("Torus construction" * doctest::test_suite("torus")) 16 | { 17 | std::size_t constexpr NUMBER_OF_POINTS = 250; 18 | std::vector points; 19 | points.reserve(NUMBER_OF_POINTS); 20 | GIVEN("A 2-torus") 21 | { 22 | WHEN("A 2-torus is constructed.") 23 | { 24 | THEN("It should not throw.") 25 | { 26 | int constexpr dim = 3; 27 | REQUIRE_NOTHROW(make_d_cube(points, NUMBER_OF_POINTS, dim)); 28 | } 29 | } 30 | } 31 | GIVEN("A constructed 2-torus") 32 | { 33 | int constexpr dim = 3; 34 | make_d_cube(points, NUMBER_OF_POINTS, dim); 35 | WHEN("The type is queried") 36 | { 37 | THEN("A result should be returned.") 38 | { 39 | fmt::print("Torus = {}", 40 | boost::typeindex::type_id_with_cvr() 41 | .pretty_name()); 42 | } 43 | } 44 | } 45 | GIVEN("A 3-torus") 46 | { 47 | WHEN("A 3-torus is constructed.") 48 | { 49 | THEN("It should not throw.") 50 | { 51 | int constexpr dim = 4; 52 | REQUIRE_NOTHROW(make_d_cube(points, NUMBER_OF_POINTS, dim)); 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2022, Adam Getchell 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /.github/workflows/macos.yml: -------------------------------------------------------------------------------- 1 | name: macOS 2 | 3 | on: [workflow_dispatch] 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.ref }} 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | build: 11 | runs-on: macos-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | with: 16 | fetch-depth: 0 17 | submodules: true 18 | 19 | - name: Setup Xcode 15.3 (Apple Clang 17) 20 | uses: maxim-lobanov/setup-xcode@v1 21 | with: 22 | xcode-version: '15.3' 23 | 24 | - name: Verify Clang version 25 | run: clang --version 26 | 27 | - name: Setup 28 | run: | 29 | declare -a python_files=("2to3", "idle3", "pydoc3", "python3", "python3-config") 30 | declare -a python_versions=("3.11" "3.12") 31 | echo "Checking and removing Python symlinks..." 32 | for base in "${python_files[@]}"; do 33 | for version in "${python_versions[@]}"; do 34 | file="/usr/local/bin/${base}${version}" 35 | [ -L "$file" ] && sudo rm "$file" || true 36 | done 37 | done 38 | echo "Python symlink cleanup completed." 39 | brew install automake autoconf autoconf-archive libtool texinfo yasm ninja python ccache pkg-config 40 | 41 | - name: Restore artifacts or setup vcpkg 42 | uses: lukka/run-vcpkg@v11 43 | with: 44 | vcpkgGitCommitId: ${{ vars.VCPKG_GIT_COMMIT_ID }} 45 | 46 | - name: Configure 47 | run: cmake --preset=build 48 | 49 | - name: Build 50 | run: cmake --build build -j 2 51 | 52 | - name: Test 53 | working-directory: build 54 | continue-on-error: true 55 | run: ctest --rerun-failed --output-on-failure -j 2 -------------------------------------------------------------------------------- /include/Torus_d.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2017 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file Torus_d.hpp 8 | /// @brief Functions on d-dimensional torus 9 | /// @author Adam Getchell 10 | /// @details Inserts a given number of points into a d-dimensional grid (cube) 11 | /// @todo Make the vector compatible with the triangulation data structure 12 | 13 | #ifndef INCLUDE_TORUS_D_HPP_ 14 | #define INCLUDE_TORUS_D_HPP_ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | using Kd = CGAL::Cartesian_d; 24 | using Point = Kd::Point_d; 25 | using Creator_d = CGAL::Creator_uniform_d::iterator, Point>; 26 | 27 | /** 28 | * \brief Make a d-dimensional torus 29 | * \param t_points The container of points 30 | * \param t_number_of_points The number of points to insert 31 | * \param t_dimension The dimensionality of the torus 32 | * \return A d-dimensional torus 33 | */ 34 | inline auto make_d_cube(std::vector t_points, 35 | std::size_t t_number_of_points, int t_dimension) 36 | { 37 | double constexpr size = 1.0; 38 | 39 | fmt::print("Generating {} grid points in {}D\n", t_number_of_points, 40 | t_dimension); 41 | 42 | t_points.reserve(t_number_of_points); 43 | return points_on_cube_grid_d(t_dimension, size, t_number_of_points, 44 | std::back_inserter(t_points), 45 | Creator_d(t_dimension)); 46 | } 47 | 48 | #endif // INCLUDE_TORUS_D_HPP_ 49 | -------------------------------------------------------------------------------- /.github/workflows/lsan.yml: -------------------------------------------------------------------------------- 1 | name: Leak Sanitizer 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - develop 8 | pull_request: 9 | branches: 10 | - develop 11 | workflow_dispatch: 12 | 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.ref }} 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | submodules: true 26 | 27 | - name: Setup 28 | run: | 29 | sudo apt update 30 | sudo apt-get install build-essential automake autoconf autoconf-archive texinfo libtool-bin yasm ninja-build ccache 31 | 32 | - name: Setup Clang 33 | uses: pkgxdev/setup@v4 34 | with: 35 | +: clang@20 36 | 37 | - run: clang --version 38 | 39 | - name: Restore artifacts or setup vcpkg 40 | uses: lukka/run-vcpkg@v11 41 | with: 42 | vcpkgGitCommitId: ${{ vars.VCPKG_GIT_COMMIT_ID }} 43 | 44 | - name: Configure 45 | run: cmake --preset=lsan 46 | 47 | - name: Build 48 | run: cmake --build build -j 2 49 | 50 | - name: Run tests 51 | working-directory: build 52 | continue-on-error: true 53 | run: ctest -VV 54 | 55 | - name: Run LSAN on initialize 56 | working-directory: build/src 57 | continue-on-error: true 58 | run: ./initialize --s -n32000 -t11 -o 59 | 60 | - name: Run LSAN on cdt-opt 61 | working-directory: build/src 62 | continue-on-error: true 63 | run: ./cdt-opt 64 | 65 | - name: Run LSAN on cdt 66 | working-directory: build/src 67 | continue-on-error: true 68 | run: ./cdt --s -n64 -t3 -a.6 -k1.1 -l.1 -p10 -------------------------------------------------------------------------------- /.github/workflows/asan.yml: -------------------------------------------------------------------------------- 1 | name: Address Sanitizer 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - develop 8 | pull_request: 9 | branches: 10 | - develop 11 | workflow_dispatch: 12 | 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.ref }} 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | submodules: true 26 | 27 | - name: Setup 28 | run: | 29 | sudo apt update 30 | sudo apt-get install build-essential automake autoconf autoconf-archive texinfo libtool-bin yasm ninja-build ccache 31 | 32 | - name: Setup Clang 33 | uses: pkgxdev/setup@v4 34 | with: 35 | +: clang@20 36 | 37 | - run: clang --version 38 | 39 | - name: Restore artifacts or setup vcpkg 40 | uses: lukka/run-vcpkg@v11 41 | with: 42 | vcpkgGitCommitId: ${{ vars.VCPKG_GIT_COMMIT_ID }} 43 | 44 | - name: Configure 45 | run: cmake --preset=asan 46 | 47 | - name: Build 48 | run: cmake --build build -j 2 49 | 50 | - name: Run tests 51 | working-directory: build 52 | continue-on-error: true 53 | run: ctest -VV 54 | 55 | - name: Run ASAN on initialize 56 | working-directory: build/src 57 | continue-on-error: true 58 | run: ./initialize --s -n32000 -t11 -o 59 | 60 | - name: Run ASAN on cdt-opt 61 | working-directory: build/src 62 | continue-on-error: true 63 | run: ./cdt-opt 64 | 65 | - name: Run ASAN on cdt 66 | working-directory: build/src 67 | continue-on-error: true 68 | run: ./cdt --s -n64 -t3 -a.6 -k1.1 -l.1 -p10 -------------------------------------------------------------------------------- /.github/workflows/msan.yml: -------------------------------------------------------------------------------- 1 | name: Memory Sanitizer 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - develop 8 | pull_request: 9 | branches: 10 | - develop 11 | workflow_dispatch: 12 | 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.ref }} 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | submodules: true 26 | 27 | - name: Setup 28 | run: | 29 | sudo apt update 30 | sudo apt-get install build-essential automake autoconf autoconf-archive texinfo libtool-bin yasm ninja-build ccache 31 | 32 | - name: Setup Clang 33 | uses: pkgxdev/setup@v4 34 | with: 35 | +: clang@20 36 | 37 | - run: clang --version 38 | 39 | - name: Restore artifacts or setup vcpkg 40 | uses: lukka/run-vcpkg@v11 41 | with: 42 | vcpkgGitCommitId: ${{ vars.VCPKG_GIT_COMMIT_ID }} 43 | 44 | - name: Configure 45 | run: cmake --preset=msan 46 | 47 | - name: Build 48 | run: cmake --build build -j 2 49 | 50 | - name: Run tests 51 | working-directory: build 52 | continue-on-error: true 53 | run: ctest -VV 54 | 55 | - name: Run MSAN on initialize 56 | working-directory: build/src 57 | continue-on-error: true 58 | run: ./initialize --s -n32000 -t11 -o 59 | 60 | - name: Run MSAN on cdt-opt 61 | working-directory: build/src 62 | continue-on-error: true 63 | run: ./cdt-opt 64 | 65 | - name: Run MSAN on cdt 66 | working-directory: build/src 67 | continue-on-error: true 68 | run: ./cdt --s -n64 -t3 -a.6 -k1.1 -l.1 -p10 -------------------------------------------------------------------------------- /.github/workflows/tsan.yml: -------------------------------------------------------------------------------- 1 | name: Thread Sanitizer 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - develop 8 | pull_request: 9 | branches: 10 | - develop 11 | workflow_dispatch: 12 | 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.ref }} 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | submodules: true 26 | 27 | - name: Setup 28 | run: | 29 | sudo apt update 30 | sudo apt-get install build-essential automake autoconf autoconf-archive texinfo libtool-bin yasm ninja-build ccache 31 | 32 | - name: Setup Clang 33 | uses: pkgxdev/setup@v4 34 | with: 35 | +: clang@20 36 | 37 | - run: clang --version 38 | 39 | - name: Restore artifacts or setup vcpkg 40 | uses: lukka/run-vcpkg@v11 41 | with: 42 | vcpkgGitCommitId: ${{ vars.VCPKG_GIT_COMMIT_ID }} 43 | 44 | - name: Configure 45 | run: cmake --preset=tsan 46 | 47 | - name: Build 48 | run: cmake --build build -j 2 49 | 50 | - name: Run tests 51 | working-directory: build 52 | continue-on-error: true 53 | run: ctest -VV 54 | 55 | - name: Run TSAN on initialize 56 | working-directory: build/src 57 | continue-on-error: true 58 | run: ./initialize --s -n32000 -t11 -o 59 | 60 | - name: Run TSAN on cdt-opt 61 | working-directory: build/src 62 | continue-on-error: true 63 | run: ./cdt-opt 64 | 65 | - name: Run TSAN on cdt 66 | working-directory: build/src 67 | continue-on-error: true 68 | run: ./cdt --s -n64 -t3 -a.6 -k1.1 -l.1 -p10 -------------------------------------------------------------------------------- /include/Apply_move.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2019 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file Apply_move.hpp 8 | /// @brief Apply Pachner moves to foliated Delaunay triangulations 9 | /// @author Adam Getchell 10 | 11 | #ifndef CDT_PLUSPLUS_APPLY_MOVE_HPP 12 | #define CDT_PLUSPLUS_APPLY_MOVE_HPP 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | /** 21 | * \brief An applicative function similar to std::apply on a manifold 22 | * \tparam ManifoldType The type (topology, dimensionality) of manifold 23 | * \tparam ExpectedType The result type of the move on the manifold 24 | * \tparam FunctionType The type of move applied to the manifold 25 | * \param t_manifold The manifold on which to make the Pachner move 26 | * \param t_move The Pachner move 27 | * \return The expected or unexpected result in a std::expected 28 | */ 29 | template , 31 | typename FunctionType = tl::function_ref> 32 | auto constexpr apply_move(ManifoldType&& t_manifold, 33 | FunctionType t_move) noexcept -> decltype(auto) 34 | { 35 | if (auto result = std::invoke(t_move, std::forward(t_manifold)); 36 | result.has_value()) 37 | { 38 | return result; 39 | } 40 | else // NOLINT 41 | { 42 | // Log errors 43 | spdlog::debug("apply_move called.\n"); 44 | spdlog::debug("{}", result.error()); 45 | return result; 46 | } 47 | } 48 | 49 | #endif // CDT_PLUSPLUS_APPLY_MOVE_HPP 50 | -------------------------------------------------------------------------------- /tests/Settings_test.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2020 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file Settings_test.cpp 8 | /// @brief Global settings on integer types and MPFR precision 9 | /// @author Adam Getchell 10 | /// @details Tests number types and precision settings for the project 11 | 12 | #include "Settings.hpp" 13 | 14 | #include 15 | #include 16 | 17 | using namespace std; 18 | 19 | SCENARIO("Check settings" * doctest::test_suite("settings")) 20 | { 21 | GIVEN("Settings are retrieved.") 22 | { 23 | WHEN("The integer type is queried.") 24 | { 25 | auto const& int_precision = typeid(Int_precision).name(); 26 | THEN("The value is std::int_fast32_t.") 27 | { 28 | fmt::print("TypeID of Int_precision is {}.\n", int_precision); 29 | CHECK_EQ(int_precision, typeid(std::int_fast32_t).name()); 30 | } 31 | } 32 | WHEN("MPFR precision is queried.") 33 | { 34 | auto precision = PRECISION; 35 | THEN("The value is 256 bits.") 36 | { 37 | fmt::print("MPFR precision set to {}.\n", precision); 38 | REQUIRE_EQ(precision, 256); 39 | } 40 | } 41 | WHEN("Memory alignment is queried.") 42 | { 43 | auto constexpr align_64 = ALIGNMENT_64_BIT; 44 | THEN("The value is 64 bits.") 45 | { 46 | fmt::print("Memory alignment is set to {}.\n", align_64); 47 | REQUIRE_EQ(align_64, 64); 48 | } 49 | auto constexpr align_32 = ALIGNMENT_32_BIT; 50 | THEN("The value is 32 bits.") 51 | { 52 | fmt::print("Memory alignment is set to {}.\n", align_32); 53 | REQUIRE_EQ(align_32, 32); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /include/Periodic_3_complex.hpp: -------------------------------------------------------------------------------- 1 | /// Causal Dynamical Triangulations in C++ using CGAL 2 | /// 3 | /// Copyright © 2013 Adam Getchell 4 | /// 5 | /// Periodic (toroidal) simplicial complexes 6 | 7 | /// @file Periodic_3_complex.hpp 8 | /// @brief Toroidal simplicial complexes 9 | /// @author Adam Getchell 10 | 11 | #ifndef INCLUDE_PERIODIC_3_COMPLEX_HPP_ 12 | #define INCLUDE_PERIODIC_3_COMPLEX_HPP_ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | using K = CGAL::Exact_predicates_inexact_constructions_kernel; 25 | using GT = CGAL::Periodic_3_triangulation_traits_3; 26 | using PDT = CGAL::Periodic_3_Delaunay_triangulation_3; 27 | 28 | /// Make 3D toroidal (periodic in 3D) simplicial complexes 29 | void make_random_T3_simplicial_complex(PDT* T3, 30 | int number_of_simplices) noexcept 31 | { 32 | typedef CGAL::Creator_uniform_3 Creator; 33 | CGAL::Random random(7); 34 | CGAL::Random_points_in_cube_3 in_cube(.5, random); 35 | 36 | /// We can't directly pick number of simplices as we can in S3 37 | /// but heuristically a point has <6 simplices 38 | int n = number_of_simplices / 6; 39 | std::vector pts; 40 | 41 | // Generate random points 42 | for (int i = 0; i < n; i++) 43 | { 44 | PDT::Point p = *in_cube; 45 | in_cube++; 46 | pts.emplace_back(PDT::Point(p.x() + .5, p.y() + .5, p.z() + .5)); 47 | } 48 | 49 | // Iterator range insertion using spatial sorting and dummy point heuristic 50 | T3->insert(pts.begin(), pts.end(), true); 51 | 52 | assert(T3->dimension() == 3); 53 | assert(T3->is_valid()); 54 | } 55 | #endif // INCLUDE_PERIODIC_3_COMPLEX_HPP_ 56 | -------------------------------------------------------------------------------- /.github/workflows/valgrind.yml: -------------------------------------------------------------------------------- 1 | name: Valgrind 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - develop 8 | pull_request: 9 | branches: 10 | - develop 11 | workflow_dispatch: 12 | 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.ref }} 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | submodules: true 26 | 27 | - name: Setup 28 | run: | 29 | sudo apt update 30 | sudo apt-get install build-essential automake autoconf autoconf-archive texinfo libtool-bin yasm ninja-build ccache valgrind 31 | 32 | - name: Setup GCC 33 | uses: pkgxdev/setup@v4 34 | with: 35 | +: gcc@15 36 | 37 | - run: gcc --version 38 | 39 | - name: Restore artifacts or setup vcpkg 40 | uses: lukka/run-vcpkg@v11 41 | with: 42 | vcpkgGitCommitId: ${{ vars.VCPKG_GIT_COMMIT_ID }} 43 | 44 | - name: Configure 45 | run: cmake --preset=valgrind 46 | 47 | - name: Build 48 | run: cmake --build build -j 2 49 | 50 | - name: Run memcheck 51 | working-directory: build 52 | continue-on-error: true 53 | run: | 54 | ctest -VV -T memcheck --verbose 55 | 56 | - name: Run Valgrind on initialize 57 | working-directory: build/src 58 | continue-on-error: true 59 | run: valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose ./initialize --s -n32000 -t11 -o 60 | 61 | - name: Run Valgrind on cdt-opt 62 | working-directory: build/src 63 | continue-on-error: true 64 | run: valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose ./cdt-opt 65 | 66 | - name: Run Valgrind on cdt 67 | working-directory: build/src 68 | continue-on-error: true 69 | run: valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose ./cdt --s -n64 -t3 -a.6 -k1.1 -l.1 -p10 -------------------------------------------------------------------------------- /.appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 0.1.8.{build} 2 | 3 | skip_tags: true 4 | 5 | skip_branch_with_pr: true 6 | 7 | image: 8 | - Visual Studio 2022 9 | 10 | clone_folder: c:\projects\cdt-plusplus 11 | 12 | shallow_clone: true 13 | 14 | clone_script: 15 | - cmd: >- 16 | git clone -q --recursive --branch=%APPVEYOR_REPO_BRANCH% https://github.com/%APPVEYOR_REPO_NAME%.git %APPVEYOR_BUILD_FOLDER% 17 | && cd %APPVEYOR_BUILD_FOLDER% 18 | && git checkout -qf %APPVEYOR_REPO_COMMIT% 19 | && git submodule update --init --recursive 20 | 21 | environment: 22 | APPVEYOR_SAVE_CACHE_ON_ERROR: false 23 | APPVEYOR_CACHE_SKIP_RESTORE: true 24 | VCPKG_DEFAULT_TRIPLET: x64-windows 25 | VCPKG_ROOT: c:\tools\vcpkg 26 | 27 | cache: 28 | - c:\Users\appveyor\AppData\Local\vcpkg\archives\ 29 | - c:\tools\vcpkg\packages\ 30 | 31 | install: 32 | # Setup vcpkg 33 | - cd c:\tools\vcpkg 34 | - git pull 35 | - .\bootstrap-vcpkg.bat 36 | - set PATH=%PATH%;%VCPKG_ROOT% 37 | - vcpkg integrate install 38 | - cmake --version 39 | # Setup Clang-cl 40 | - set PATH=%PATH%;"C:\Program Files\LLVM\bin" 41 | - clang-cl -v 42 | - set CC=clang-cl -mrtm 43 | - set CXX=clang-cl -mrtm 44 | # Visual Studio 2022 45 | - call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" 46 | - set CMAKE_CXX_COMPILER="C:\Program Files\LLVM\bin\clang-cl" 47 | 48 | platform: 49 | - x64 50 | 51 | configuration: Release 52 | 53 | build: 54 | verbosity: detailed 55 | 56 | build_script: 57 | - cd %APPVEYOR_BUILD_FOLDER% 58 | - cmake --preset=appveyor 59 | - cmake --build build 60 | 61 | #test_script: 62 | # - cd build 63 | # - ctest --output-on-failure -j2 --output-junit test-results.xml 64 | # 65 | #after_test: 66 | # - find "$APPVEYOR_BUILD_FOLDER" -type f -name 'test-results.xml' -print0 | xargs -0 -I '{}' curl -F 'file=@{}' "https://ci.appveyor.com/api/testresults/junit/$APPVEYOR_JOB_ID" 67 | 68 | notifications: 69 | - provider: Email 70 | to: 71 | - acgetchell@ucdavis.edu 72 | on_build_status_changed: true 73 | 74 | #on_failure: 75 | # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) 76 | -------------------------------------------------------------------------------- /.github/workflows/codecov-upload.yml: -------------------------------------------------------------------------------- 1 | name: CodeCov 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - develop 8 | workflow_dispatch: 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.ref }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | codecov: 16 | name: CodeCov 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | with: 22 | fetch-depth: 0 23 | 24 | - name: Setup 25 | run: | 26 | sudo apt update 27 | sudo apt upgrade 28 | sudo apt-get install build-essential automake autoconf autoconf-archive texinfo libtool-bin yasm ninja-build ccache 29 | 30 | - name: Setup GCC 31 | uses: pkgxdev/setup@v4 32 | with: 33 | +: gcc@15 34 | 35 | - run: gcc --version 36 | 37 | - name: Restore artifacts or setup vcpkg 38 | uses: lukka/run-vcpkg@v11 39 | with: 40 | vcpkgGitCommitId: ${{ vars.VCPKG_GIT_COMMIT_ID }} 41 | 42 | - name: Configure 43 | run: cmake -G Ninja -D CMAKE_BUILD_TYPE=RelWithDebInfo -D ENABLE_TESTING:BOOL=TRUE -D ENABLE_COVERAGE:BOOL=TRUE -S . -B build 44 | 45 | - name: Build 46 | run: cmake --build build -j 2 47 | 48 | - name: Test 49 | working-directory: build 50 | continue-on-error: true 51 | run: ctest --rerun-failed --output-on-failure -j 2 52 | 53 | # - name: collect code coverage 54 | # run: bash <(curl -s https://codecov.io/bash) || echo "Codecov did not collect coverage reports" 55 | 56 | - name: Generate coverage info 57 | working-directory: build 58 | continue-on-error: true 59 | run: | 60 | mkdir gcov-reports 61 | pushd gcov-reports 62 | for f in `find ../tests/CMakeFiles/CDT_test.dir -name '*.o'`; do 63 | echo "Processing $f file..." 64 | gcov -o ${f} x 65 | done 66 | ls | wc -l 67 | popd 68 | 69 | - name: Submit to codecov.io 70 | uses: codecov/codecov-action@v5 71 | with: 72 | # directory: build/gcov-reports 73 | fail_ci_if_error: false 74 | verbose: true 75 | gcov: true -------------------------------------------------------------------------------- /include/Settings.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2020 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file Settings.hpp 8 | /// @brief Global integer and precision settings 9 | /// @author Adam Getchell 10 | /// @details Global project settings on integer types and MPFR precision 11 | 12 | #ifndef INCLUDE_SETTINGS_HPP_ 13 | #define INCLUDE_SETTINGS_HPP_ 14 | 15 | #include 16 | 17 | #include 18 | 19 | /// Results are converted to a CGAL multi-precision floating point number. 20 | /// Gmpzf itself is based on GMP (https://gmplib.org), as is MPFR. 21 | using Gmpzf = CGAL::Gmpzf; 22 | 23 | /// Sets the type of integer to use throughout the project. 24 | /// These are the base values read into the program or used in calculations. 25 | /// Casts to unsigned types are still necessary for certain library functions 26 | /// to work. 27 | 28 | #if __linux 29 | using Int_precision = int; 30 | #else 31 | using Int_precision = std::int_fast32_t; 32 | #endif 33 | 34 | #ifdef _WIN32 35 | #define __PRETTY_FUNCTION__ __FUNCSIG__ 36 | #endif 37 | 38 | // #define CGAL_LINKED_WITH_TBB 39 | 40 | /// Correctly declare global constants 41 | /// See Jonathan Boccara's C++ Pitfalls, January 2021 42 | 43 | /// Sets the precision for MPFR. 44 | static inline Int_precision constexpr PRECISION = 256; 45 | 46 | /// Default foliated triangulation spacings 47 | static inline double constexpr INITIAL_RADIUS = 1.0; 48 | static inline double constexpr FOLIATION_SPACING = 1.0; 49 | 50 | /// Sets epsilon values for floating point comparisons 51 | static inline double constexpr TOLERANCE = 0.01; 52 | 53 | /// Depends on INITIAL_RADIUS and RADIAL_FACTOR 54 | [[maybe_unused]] static inline Int_precision constexpr GV_BOUNDING_BOX_SIZE = 55 | 100; 56 | 57 | /// Aligns data for ease of access on 64-bit CPUs at the expense of padding 58 | static inline int constexpr ALIGNMENT_64_BIT = 64; 59 | 60 | /// Except when we only need 32 bits 61 | static inline int constexpr ALIGNMENT_32_BIT = 32; 62 | 63 | #endif // INCLUDE_SETTINGS_HPP_ 64 | -------------------------------------------------------------------------------- /cmake/StandardProjectSettings.cmake: -------------------------------------------------------------------------------- 1 | # Disable CLion generation of MinSizeRel to avoid conflicts with CGAL_SetupFlags.cmake 2 | set(CMAKE_CONFIGURATION_TYPES 3 | "Release" "Debug" "RelWithDebInfo" 4 | CACHE STRING "" FORCE) 5 | 6 | # Set a default build type if none was specified 7 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 8 | message(STATUS "Setting build type to 'RelWithDebInfo' as none was specified.") 9 | set(CMAKE_BUILD_TYPE 10 | RelWithDebInfo 11 | CACHE STRING "Choose the type of build." FORCE) 12 | # Set the possible values of build type for cmake-gui, ccmake 13 | set_property( 14 | CACHE CMAKE_BUILD_TYPE 15 | PROPERTY STRINGS 16 | "Debug" 17 | "Release" 18 | "RelWithDebInfo") 19 | endif() 20 | 21 | # Compile commands for ClangTidy et. al 22 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 23 | 24 | # Link time optimization 25 | # Turning this on disables debugging 26 | option(ENABLE_IPO "Enable Interprocedural Optimization, aka Link Time Optimization (LTO)" OFF) 27 | if(ENABLE_IPO) 28 | include(CheckIPOSupported) 29 | check_ipo_supported(RESULT result OUTPUT output) 30 | if(result) 31 | set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) 32 | message(STATUS "IPO enabled.") 33 | else() 34 | message(WARNING "IPO is not supported: ${output}") 35 | endif() 36 | endif() 37 | 38 | # Set minimum Boost version 39 | set(BOOST_MIN_VERSION "1.75.0") 40 | 41 | # Use C++23 42 | set(CMAKE_CXX_STANDARD 23) 43 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 44 | set(CMAKE_CXX_EXTENSIONS OFF) 45 | 46 | # Turn on / off TBB 47 | set(TBB_ON ON) 48 | 49 | # Threads 50 | set(CMAKE_THREAD_PREFER_PTHREAD TRUE) 51 | 52 | # Turn off CGAL Triangulation Assertions and Postconditions, fix https://gitlab.com/libeigen/eigen/-/issues/1894 53 | add_definitions(-DCGAL_TRIANGULATION_NO_ASSERTIONS -DCGAL_TRIANGULATION_NO_POSTCONDITIONS -D_HAS_DEPRECATED_RESULT_OF=1 -DEIGEN_HAS_STD_RESULT_OF=0 -DCGAL_USE_GMP=ON -DCGAL_USE_MPFR=ON -DCGAL_DO_NOT_USE_BOOST_MP=ON) 54 | 55 | # Easier navigation in an IDE when projects are organized in folders. 56 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 57 | 58 | # Deal with UTF-8 encoding 59 | if (MSVC) 60 | add_compile_options(/utf-8) 61 | else() 62 | add_compile_options(-finput-charset=UTF-8) 63 | endif() 64 | -------------------------------------------------------------------------------- /.coderabbit.yaml: -------------------------------------------------------------------------------- 1 | language: en-US 2 | tone_instructions: 'Be constructive and professional. Focus on technical accuracy while maintaining a friendly tone.' 3 | early_access: true 4 | enable_free_tier: true 5 | reviews: 6 | profile: assertive 7 | request_changes_workflow: true 8 | high_level_summary: true 9 | high_level_summary_placeholder: '@coderabbitai summary' 10 | auto_title_placeholder: '@coderabbitai' 11 | review_status: true 12 | commit_status: true 13 | poem: true 14 | collapse_walkthrough: false 15 | sequence_diagrams: true 16 | changed_files_summary: true 17 | labeling_instructions: [] 18 | path_filters: [] 19 | path_instructions: 20 | - path: 'src/**/*.cpp' 21 | instructions: 'Focus on performance, memory management, and RAII principles' 22 | - path: 'include/**/*.hpp' 23 | instructions: 'Focus on design patterns, interfaces, and encapsulation' 24 | - path: 'test/**/*.cpp' 25 | instructions: | 26 | Review the following unit test code written using doctest. Ensure the following: 27 | - Comprehensive test coverage and proper test organization. 28 | - The code adheres to best practices using doctest. 29 | - Descriptive test names are used to clearly convey the intent of each test. 30 | abort_on_close: true 31 | auto_review: 32 | enabled: true 33 | auto_incremental_review: true 34 | ignore_title_keywords: [] 35 | labels: [] 36 | drafts: true 37 | base_branches: [] 38 | tools: 39 | shellcheck: 40 | enabled: true 41 | markdownlint: 42 | enabled: true 43 | github-checks: 44 | enabled: true 45 | timeout_ms: 90000 46 | gitleaks: 47 | enabled: true 48 | cppcheck: 49 | enabled: true 50 | languagetool: 51 | enabled: true 52 | enabled_only: false 53 | level: default 54 | hadolint: 55 | enabled: true 56 | yamllint: 57 | enabled: true 58 | actionlint: 59 | enabled: true 60 | pmd: 61 | enabled: true 62 | semgrep: 63 | enabled: true 64 | chat: 65 | auto_reply: true 66 | knowledge_base: 67 | opt_out: false 68 | learnings: 69 | scope: auto 70 | issues: 71 | scope: auto 72 | jira: 73 | project_keys: [] 74 | linear: 75 | team_keys: [] 76 | pull_requests: 77 | scope: auto 78 | -------------------------------------------------------------------------------- /.github/workflows/sonarcloud.yml: -------------------------------------------------------------------------------- 1 | name: SonarCloud 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - develop 8 | pull_request: 9 | types: [opened, synchronize, reopened] 10 | workflow_dispatch: 11 | 12 | concurrency: 13 | group: ${{ github.workflow }}-${{ github.ref }} 14 | cancel-in-progress: true 15 | 16 | jobs: 17 | sonarcloud: 18 | name: SonarCloud 19 | runs-on: ubuntu-latest 20 | env: 21 | BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed 22 | steps: 23 | - uses: actions/checkout@v4 24 | with: 25 | fetch-depth: 0 26 | 27 | - name: Setup 28 | run: | 29 | sudo apt update 30 | sudo apt-get install build-essential automake autoconf autoconf-archive texinfo libtool-bin yasm ninja-build ccache lcov 31 | 32 | - name: Setup GCC 33 | uses: pkgxdev/setup@v4 34 | with: 35 | +: gcc@15 36 | 37 | - run: gcc --version 38 | 39 | - name: Install sonar-scanner and build-wrapper 40 | uses: sonarsource/sonarcloud-github-c-cpp@v3 41 | 42 | - name: Restore artifacts or setup vcpkg 43 | uses: lukka/run-vcpkg@v11 44 | with: 45 | vcpkgGitCommitId: ${{ vars.VCPKG_GIT_COMMIT_ID }} 46 | 47 | - name: Configure 48 | run: cmake -G Ninja -D CMAKE_BUILD_TYPE=RelWithDebInfo -D ENABLE_TESTING:BOOL=TRUE -D ENABLE_COVERAGE:BOOL=TRUE -S . -B build 49 | 50 | - name: Build 51 | run: build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build 52 | 53 | - name: Test 54 | working-directory: build 55 | continue-on-error: true 56 | run: ctest --rerun-failed --output-on-failure -j 2 57 | 58 | - name: Generate coverage info 59 | working-directory: build 60 | continue-on-error: true 61 | run: | 62 | mkdir gcov-reports 63 | pushd gcov-reports 64 | for f in `find ../tests/CMakeFiles/CDT_test.dir -name '*.o'`; do 65 | echo "Processing $f file..." 66 | gcov -o ${f} x 67 | done 68 | ls | wc -l 69 | popd 70 | 71 | - name: Run sonar-scanner 72 | env: 73 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR info, if any 74 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 75 | run: sonar-scanner --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" -------------------------------------------------------------------------------- /include/Triangulation_traits.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2021 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file Triangulation_traits.hpp 8 | /// @brief Traits class for particular uses of CGAL 9 | /// @author Adam Getchell 10 | 11 | #ifndef CDT_PLUSPLUS_TRIANGULATION_TRAITS_HPP 12 | #define CDT_PLUSPLUS_TRIANGULATION_TRAITS_HPP 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "Settings.hpp" 21 | 22 | template 23 | struct TriangulationTraits; 24 | 25 | template <> 26 | struct TriangulationTraits<3> 27 | { 28 | using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; 29 | using Vertex_base = 30 | CGAL::Triangulation_vertex_base_with_info_3; 31 | using Cell_base = 32 | CGAL::Triangulation_cell_base_with_info_3; 33 | #ifdef CGAL_LINKED_WITH_TBB 34 | using Tds = CGAL::Triangulation_data_structure_3; 36 | #else 37 | using Tds = CGAL::Triangulation_data_structure_3; 38 | #endif 39 | using Delaunay = CGAL::Delaunay_triangulation_3; 40 | 41 | using Cell_handle = Delaunay::Cell_handle; 42 | using Face_handle = std::pair; 43 | using Facet = Delaunay::Facet; 44 | using Edge_handle = CGAL::Triple; 45 | using Vertex_handle = Delaunay::Vertex_handle; 46 | using Point = Delaunay::Point; 47 | using Causal_vertices = std::vector>; 48 | 49 | /// @brief CGAL::squared_distance 50 | /// See 51 | /// https://doc.cgal.org/latest/Kernel_23/group__squared__distance__grp.html#ga1ff73525660a052564d33fbdd61a4f71 52 | /// @returns Square of Euclidean distance between two geometric objects 53 | using squared_distance = Kernel::Compute_squared_distance_3; 54 | 55 | using Spherical_points_generator = CGAL::Random_points_on_sphere_3; 56 | 57 | static inline Point const ORIGIN_POINT = Point{0, 0, 0}; 58 | }; // TriangulationTraits<3> 59 | 60 | #endif // CDT_PLUSPLUS_TRIANGULATION_TRAITS_HPP 61 | -------------------------------------------------------------------------------- /src/cdt-opt.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2016 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file cdt-opt.cpp 8 | /// @brief Outputs values to determine optimizations 9 | /// @author Adam Getchell 10 | /// @details Full run-through with default options used to calculate 11 | /// optimal values for thermalization, etc. A simpler version 12 | /// that encompasses the entire lifecycle. Also suitable for 13 | /// scripting parallel runs, e.g. 14 | /// 15 | /// ./cdt-opt 2>>errors 1>>output & 16 | /// @todo Print out graph of time-value vs. volume vs. pass number 17 | 18 | #include 19 | #include 20 | 21 | using namespace std; 22 | 23 | auto main() -> int 24 | try 25 | { 26 | fmt::print("cdt-opt started at {}\n", utilities::current_date_time()); 27 | Int_precision constexpr simplices = 256; 28 | Int_precision constexpr timeslices = 4; 29 | /// @brief Constants in units of \f$c=G=\hbar=1 \alpha\approx 0.0397887\f$ 30 | auto constexpr alpha = static_cast(0.6); 31 | auto constexpr k = static_cast(1.1); // NOLINT 32 | /// @brief \f$\Lambda=2.036\times 10^{-35} s^{-2}\approx 0\f$ 33 | auto constexpr lambda = static_cast(0.1); 34 | Int_precision constexpr passes = 10; 35 | Int_precision constexpr checkpoint = 10; 36 | 37 | // Create logs 38 | utilities::create_logger(); 39 | 40 | // Initialize the Metropolis algorithm 41 | Metropolis_3 run(alpha, k, lambda, passes, checkpoint); 42 | 43 | // Make a triangulation 44 | manifolds::Manifold_3 const universe(simplices, timeslices); 45 | 46 | // Look at triangulation 47 | universe.print(); 48 | universe.print_details(); 49 | universe.print_volume_per_timeslice(); 50 | 51 | // Run algorithm on triangulation 52 | auto const result = run(universe); 53 | 54 | if (auto max_timevalue = result.max_time(); max_timevalue < timeslices) 55 | { 56 | spdlog::info("You wanted {} timeslices but only got {}.\n", timeslices, 57 | max_timevalue); 58 | } 59 | 60 | if (!result.is_valid()) { throw runtime_error("Result is invalid!\n"); } 61 | 62 | // Print results 63 | fmt::print("=== Run Results ===\n"); 64 | result.print(); 65 | result.print_details(); 66 | result.print_volume_per_timeslice(); 67 | 68 | return EXIT_SUCCESS; 69 | } 70 | catch (runtime_error const& RuntimeError) 71 | { 72 | spdlog::critical("{}\n", RuntimeError.what()); 73 | return EXIT_FAILURE; 74 | } 75 | catch (...) 76 | { 77 | spdlog::critical("Something went wrong ... Exiting.\n"); 78 | return EXIT_FAILURE; 79 | } 80 | -------------------------------------------------------------------------------- /include/Periodic_3_triangulations.hpp: -------------------------------------------------------------------------------- 1 | /// Causal Dynamical Triangulations in C++ using CGAL 2 | /// 3 | /// Copyright © 2014 Adam Getchell 4 | /// 5 | /// Periodic (toroidal) 3D triangulations 6 | 7 | /// @file Periodic_3_triangulations.hpp 8 | /// @brief Toroidal 3D triangulations 9 | /// @author Adam Getchell 10 | 11 | #ifndef INCLUDE_PERIODIC_3_TRIANGULATIONS_HPP_ 12 | #define INCLUDE_PERIODIC_3_TRIANGULATIONS_HPP_ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | using K = CGAL::Exact_predicates_inexact_constructions_kernel; 26 | using GT = CGAL::Periodic_3_triangulation_filtered_traits_3; 27 | 28 | using VbDS = CGAL::Periodic_3_triangulation_ds_vertex_base_3<>; 29 | using T3Vb = CGAL::Triangulation_vertex_base_3; 30 | 31 | using CbDS = CGAL::Periodic_3_triangulation_ds_cell_base_3<>; 32 | using Cb = CGAL::Triangulation_cell_base_3; 33 | 34 | /// Allows each vertex to contain an integer denoting its timeslice 35 | using VbInfo = CGAL::Triangulation_vertex_base_with_info_3; 36 | using TDS = CGAL::Triangulation_data_structure_3; 37 | using PDT = CGAL::Periodic_3_Delaunay_triangulation_3; 38 | using T3Point = PDT::Point; 39 | 40 | /// Random point generators for d-dimensional points in a d-cube per timeslice 41 | using Kd = CGAL::Cartesian_d; 42 | using Point = Kd::Point_d; 43 | 44 | /// Make 3D toroidal (periodic) triangulations 45 | template 46 | void make_random_T3_triangulation(T* T3, int simplices, int timeslices) noexcept 47 | { 48 | std::cout << "make_random_T3_triangulation() called" << std::endl; 49 | 50 | int simplices_per_timeslice = simplices / timeslices; 51 | /// We can't directly pick number of simplices as we can in S3 52 | /// but a point has <6 simplices in 3D 53 | int points = simplices / 6; 54 | int points_per_timeslice = simplices_per_timeslice / 6; 55 | /// We're working on 2 dimensional random points with the z component 56 | /// fixed by the timeslice 57 | int const dim = 2; 58 | 59 | std::vector v; 60 | v.reserve(points); 61 | 62 | /// In d-dimensions the range of points in a d-cube is the d-th root 63 | double size = sqrt(points_per_timeslice); 64 | 65 | CGAL::Random_points_in_cube_d gen(dim, size); 66 | 67 | /// Setup random point creation in a square (2-cube) 68 | for (size_t i = 0; i < timeslices; i++) 69 | { 70 | /// Debugging 71 | std::cout << "Timeslice " << i << std::endl; 72 | for (size_t i = 0; i < points_per_timeslice; i++) { v.push_back(*gen++); } 73 | for (size_t i = 0; i < points_per_timeslice; i++) 74 | { 75 | std::cout << " " << v[i] << std::endl; 76 | } 77 | } 78 | } 79 | #endif // INCLUDE_PERIODIC_3_TRIANGULATIONS_HPP_ 80 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at adam@adamgetchell.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /tests/S3Action_test.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2017 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file S3Action_test.cpp 8 | /// @brief Tests for the S3 action functions 9 | /// @author Adam Getchell 10 | /// @details Ensures that the S3 bulk action calculations are correct, and give 11 | /// similar results for similar values. 12 | 13 | #include "S3Action.hpp" 14 | 15 | #include 16 | 17 | #include "Manifold.hpp" 18 | 19 | using namespace std; 20 | using namespace manifolds; 21 | 22 | SCENARIO("Calculate the bulk action on S3 triangulations" * 23 | doctest::test_suite("s3action")) 24 | { 25 | spdlog::debug("Calculate the bulk action on S3 triangulations.\n"); 26 | GIVEN("A 3D 2-sphere foliated triangulation.") 27 | { 28 | auto constexpr simplices = 6400; 29 | auto constexpr timeslices = 7; 30 | auto constexpr K = 1.1L; // NOLINT 31 | auto constexpr Lambda = 0.1L; 32 | Manifold_3 const universe(simplices, timeslices); 33 | // Verify triangulation 34 | CHECK_EQ(universe.N3(), universe.simplices()); 35 | CHECK_EQ(universe.N1(), universe.edges()); 36 | CHECK_EQ(universe.N0(), universe.vertices()); 37 | CHECK_EQ(universe.dimensionality(), 3); 38 | CHECK(universe.is_correct()); 39 | 40 | universe.print_volume_per_timeslice(); 41 | 42 | CHECK_EQ(universe.max_time(), timeslices); 43 | CHECK_EQ(universe.min_time(), 1); 44 | WHEN("The alpha=-1 Bulk Action is calculated.") 45 | { 46 | auto Bulk_action = S3_bulk_action_alpha_minus_one( 47 | universe.N1_TL(), universe.N3_31_13(), universe.N3_22(), K, Lambda); 48 | THEN("The action falls within accepted values.") 49 | { 50 | spdlog::debug("S3_bulk_action_alpha_minus_one() = {}\n", 51 | Bulk_action.to_double()); 52 | REQUIRE_LE(3500, Bulk_action); 53 | REQUIRE_LE(Bulk_action, 4500); 54 | } 55 | } 56 | WHEN("The alpha=1 Bulk Action is calculated.") 57 | { 58 | auto Bulk_action = S3_bulk_action_alpha_one( 59 | universe.N1_TL(), universe.N3_31_13(), universe.N3_22(), K, Lambda); 60 | THEN("The action falls within accepted values.") 61 | { 62 | spdlog::debug("S3_bulk_action_alpha_one() = {}\n", 63 | Bulk_action.to_double()); 64 | REQUIRE_LE(2000, Bulk_action); 65 | REQUIRE_LE(Bulk_action, 3000); 66 | } 67 | } 68 | WHEN("The generalized Bulk Action is calculated.") 69 | { 70 | auto constexpr Alpha = 0.6L; 71 | spdlog::debug("(Long double) Alpha = {}\n", Alpha); 72 | auto Bulk_action = S3_bulk_action(universe.N1_TL(), universe.N3_31_13(), 73 | universe.N3_22(), Alpha, K, Lambda); 74 | THEN("The action falls within accepted values.") 75 | { 76 | spdlog::debug("S3_bulk_action() = {}\n", Bulk_action.to_double()); 77 | REQUIRE_LE(2700, Bulk_action); 78 | REQUIRE_LE(Bulk_action, 3700); 79 | } 80 | } 81 | WHEN( 82 | "S3_bulk_action(alpha=1) and S3_bulk_action_alpha_one() are " 83 | "calculated.") 84 | { 85 | auto constexpr Alpha = 1.0L; 86 | auto Bulk_action = S3_bulk_action(universe.N1_TL(), universe.N3_31_13(), 87 | universe.N3_22(), Alpha, K, Lambda); 88 | auto Bulk_action_one = S3_bulk_action_alpha_one( 89 | universe.N1_TL(), universe.N3_31_13(), universe.N3_22(), K, Lambda); 90 | THEN( 91 | "S3_bulk_action(alpha=1) == S3_bulk_action_alpha_one() within " 92 | "tolerances.") 93 | { 94 | spdlog::debug("S3_bulk_action() = {}\n", Bulk_action.to_double()); 95 | spdlog::debug("S3_bulk_action_alpha_one() = {}\n", 96 | Bulk_action_one.to_double()); 97 | REQUIRE(utilities::Gmpzf_to_double(Bulk_action_one) == 98 | doctest::Approx(utilities::Gmpzf_to_double(Bulk_action)) 99 | .epsilon(TOLERANCE)); 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /include/Geometry.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2018 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file Geometry.hpp 8 | /// @brief Geometric scalars of the Manifold used to calculate the Regge action 9 | /// @details This is a data structure to hold the geometric information of the 10 | /// Manifold for quick access in calculation of the Regge action. There are 11 | /// no class invariants, so it is a simple struct. 12 | /// @author Adam Getchell 13 | 14 | #ifndef CDT_PLUSPLUS_GEOMETRY_HPP 15 | #define CDT_PLUSPLUS_GEOMETRY_HPP 16 | 17 | #include "Foliated_triangulation.hpp" 18 | 19 | /// Geometry class template 20 | /// @tparam dimension Dimensionality of geometry 21 | template 22 | struct Geometry; 23 | 24 | /// 3D Geometry 25 | template <> 26 | struct [[nodiscard("This contains data!")]] Geometry<3> 27 | { 28 | /// @brief Number of 3D simplices 29 | Int_precision N3{0}; // NOLINT 30 | 31 | /// @brief Number of (3,1) simplices 32 | Int_precision N3_31{0}; // NOLINT 33 | 34 | /// @brief Number of (1,3) simplices 35 | Int_precision N3_13{0}; // NOLINT 36 | 37 | /// @brief Number of (3,1) + (1,3) simplices 38 | Int_precision N3_31_13{0}; // NOLINT 39 | 40 | /// @brief Number of (2,2) simplices 41 | Int_precision N3_22{0}; // NOLINT 42 | 43 | /// @brief Number of 2D faces 44 | Int_precision N2{0}; // NOLINT 45 | 46 | /// @brief Number of 1D edges 47 | Int_precision N1{0}; // NOLINT 48 | 49 | /// @brief Number of timelike edges 50 | Int_precision N1_TL{0}; // NOLINT 51 | 52 | /// @brief Number of spacelike edges 53 | Int_precision N1_SL{0}; // NOLINT 54 | 55 | /// @brief Number of vertices 56 | Int_precision N0{0}; // NOLINT 57 | 58 | /// @brief Default ctor 59 | Geometry() = default; 60 | 61 | /// @brief Constructor with triangulation 62 | /// @param triangulation Triangulation for which Geometry is being 63 | /// calculated 64 | explicit Geometry( 65 | foliated_triangulations::FoliatedTriangulation_3 const& triangulation) 66 | 67 | : N3{static_cast(triangulation.number_of_finite_cells())} 68 | , N3_31{static_cast(triangulation.get_three_one().size())} 69 | , N3_13{static_cast(triangulation.get_one_three().size())} 70 | , N3_31_13{N3_31 + N3_13} 71 | , N3_22{static_cast(triangulation.get_two_two().size())} 72 | , N2{static_cast(triangulation.number_of_finite_facets())} 73 | , N1{static_cast(triangulation.number_of_finite_edges())} 74 | , N1_TL{triangulation.N1_TL()} 75 | , N1_SL{triangulation.N1_SL()} 76 | , N0{static_cast(triangulation.number_of_vertices())} 77 | 78 | {} 79 | 80 | /// @brief Non-member swap function for Geometry 81 | /// @details Used for no-except updates of geometry data structures. 82 | /// Usually called from a Manifold swap. 83 | /// @param swap_from The value to be swapped from. Assumed to be discarded. 84 | /// @param swap_into The value to be swapped into. 85 | friend void swap(Geometry& swap_from, Geometry& swap_into) noexcept 86 | { 87 | #ifndef NDEBUG 88 | spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); 89 | #endif 90 | using std::swap; 91 | swap(swap_from.N3, swap_into.N3); 92 | swap(swap_from.N3_31, swap_into.N3_31); 93 | swap(swap_from.N3_13, swap_into.N3_13); 94 | swap(swap_from.N3_31_13, swap_into.N3_31_13); 95 | swap(swap_from.N3_22, swap_into.N3_22); 96 | swap(swap_from.N2, swap_into.N2); 97 | swap(swap_from.N1, swap_into.N1); 98 | swap(swap_from.N1_TL, swap_into.N1_TL); 99 | swap(swap_from.N1_SL, swap_into.N1_SL); 100 | swap(swap_from.N0, swap_into.N0); 101 | } // swap 102 | }; // struct Geometry<3> 103 | 104 | using Geometry_3 = Geometry<3>; 105 | 106 | template <> 107 | struct [[nodiscard("This contains data!")]] Geometry<4> 108 | { 109 | Int_precision N4{0}; 110 | Int_precision N3{0}; 111 | Int_precision N2{0}; 112 | Int_precision N1{0}; 113 | Int_precision N0{0}; 114 | }; // struct Geometry<4> 115 | 116 | using Geometry_4 = Geometry<4>; 117 | 118 | #endif // CDT_PLUSPLUS_GEOMETRY_HPP 119 | -------------------------------------------------------------------------------- /cmake/Sanitizers.cmake: -------------------------------------------------------------------------------- 1 | # Derived from: 2 | # 3 | # https://github.com/lefticus/cpp_starter_project/blob/master/cmake/Sanitizers.cmake 4 | # 5 | 6 | function(enable_sanitizers project_name) 7 | 8 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") 9 | option(ENABLE_COVERAGE "Enable coverage reporting for gcc/clang" OFF) 10 | 11 | if(ENABLE_COVERAGE) 12 | target_compile_options(${project_name} INTERFACE --coverage -O0 -g) 13 | target_link_libraries(${project_name} INTERFACE --coverage) 14 | message(STATUS "Coverage enabled.") 15 | endif() 16 | 17 | option(ENABLE_VALGRIND "Enable Valgrind" OFF) 18 | if(ENABLE_VALGRIND) 19 | target_compile_options(project_options INTERFACE -g -O0) 20 | target_link_libraries(project_options INTERFACE -fsanitize=address -static-libasan) 21 | message(STATUS "Valgrind enabled.") 22 | set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --leak-check=full") 23 | set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --track-fds=yes") 24 | set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --trace-children=yes") 25 | set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --error-exitcode=1") 26 | endif() 27 | 28 | set(SANITIZERS "") 29 | 30 | option(ENABLE_SANITIZER_ADDRESS "Enable address sanitizer" OFF) 31 | if(ENABLE_SANITIZER_ADDRESS) 32 | list(APPEND SANITIZERS "address") 33 | message(STATUS "AddressSanitizer enabled.") 34 | set(ENV{ASAN_OPTIONS} "fast_unwind_on_malloc=0") 35 | set(ENV{ASAN_OPTIONS} "$ENV{ASAN_OPTIONS}:help=1") 36 | set(ENV{ASAN_OPTIONS} "$ENV{ASAN_OPTIONS}:symbolize=1") 37 | set(ENV{ASAN_OPTIONS} "$ENV{ASAN_OPTIONS}:verbosity=2") 38 | message(STATUS "ASAN_OPTIONS=$ENV{ASAN_OPTIONS}") 39 | endif() 40 | 41 | option(ENABLE_SANITIZER_LEAK "Enable leak sanitizer" OFF) 42 | if(ENABLE_SANITIZER_LEAK) 43 | if(${APPLE}) 44 | message(FATAL_ERROR "Leak sanitizer not supported on x86_64-apple-darwin") 45 | else() 46 | list(APPEND SANITIZERS "leak") 47 | message(STATUS "LeakSanitizer enabled.") 48 | endif() 49 | endif() 50 | 51 | option(ENABLE_SANITIZER_UNDEFINED_BEHAVIOR "Enable undefined behavior sanitizer" OFF) 52 | if(ENABLE_SANITIZER_UNDEFINED_BEHAVIOR) 53 | list(APPEND SANITIZERS "undefined") 54 | message(STATUS "UndefinedBehaviorSanitizer enabled.") 55 | set(ENV{UBSAN_OPTIONS} "print_stacktrace=1") 56 | message(STATUS "UBSAN_OPTIONS=$ENV{UBSAN_OPTIONS}") 57 | endif() 58 | 59 | option(ENABLE_SANITIZER_THREAD "Enable thread sanitizer" OFF) 60 | if(ENABLE_SANITIZER_THREAD) 61 | if("address" IN_LIST SANITIZERS OR "leak" IN_LIST SANITIZERS) 62 | message(WARNING "Thread sanitizer does not work with Address and Leak sanitizer enabled.") 63 | else() 64 | list(APPEND SANITIZERS "thread") 65 | message(STATUS "ThreadSanitizer enabled.") 66 | endif() 67 | endif() 68 | 69 | option(ENABLE_SANITIZER_MEMORY "Enable memory sanitizer" OFF) 70 | if(ENABLE_SANITIZER_MEMORY AND CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") 71 | if(${APPLE}) 72 | message(FATAL_ERROR "Memory sanitizer not supported on x86_64-apple-darwin") 73 | else() 74 | if("address" IN_LIST SANITIZERS 75 | OR "thread" IN_LIST SANITIZERS 76 | OR "leak" IN_LIST SANITIZERS) 77 | message(WARNING "Memory sanitizer does not work with Address, Thread, and Leak sanitizer enabled.") 78 | else() 79 | list(APPEND SANITIZERS "memory") 80 | message(STATUS "Memory sanitizer enabled.") 81 | endif() 82 | endif() 83 | endif() 84 | 85 | list( 86 | JOIN 87 | SANITIZERS 88 | "," 89 | LIST_OF_SANITIZERS) 90 | 91 | endif() 92 | 93 | if(LIST_OF_SANITIZERS) 94 | if(NOT 95 | "${LIST_OF_SANITIZERS}" 96 | STREQUAL 97 | "") 98 | target_compile_options( 99 | ${project_name} 100 | INTERFACE -g 101 | -O1 102 | -fsanitize=${LIST_OF_SANITIZERS} 103 | -fno-omit-frame-pointer) 104 | target_link_libraries(${project_name} INTERFACE -fsanitize=${LIST_OF_SANITIZERS}) 105 | endif() 106 | endif() 107 | 108 | endfunction() 109 | -------------------------------------------------------------------------------- /cmake/CompilerWarnings.cmake: -------------------------------------------------------------------------------- 1 | # Derived from: 2 | # 3 | # https://github.com/lefticus/cpp_starter_project/blob/master/cmake/CompilerWarnings.cmake 4 | 5 | function(set_project_warnings project_name) 6 | option(WARNINGS_AS_ERRORS "Treat compiler warnings as errors" FALSE) 7 | 8 | set(MSVC_WARNINGS 9 | /W4 # Baseline reasonable warnings 10 | /w14242 # 'identifier': conversion from 'type1' to 'type1', possible loss of data 11 | /w14254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data 12 | /w14263 # 'function': member function does not override any base class virtual member function 13 | /w14265 # 'classname': class has virtual functions, but destructor is not virtual instances of this class may not 14 | # be destructed correctly 15 | /w14287 # 'operator': unsigned/negative constant mismatch 16 | /we4289 # nonstandard extension used: 'variable': loop control variable declared in the for-loop is used outside 17 | # the for-loop scope 18 | /w14296 # 'operator': expression is always 'boolean_value' 19 | /w14311 # 'variable': pointer truncation from 'type1' to 'type2' 20 | /w14545 # expression before comma evaluates to a function which is missing an argument list 21 | /w14546 # function call before comma missing argument list 22 | /w14547 # 'operator': operator before comma has no effect; expected operator with side-effect 23 | /w14549 # 'operator': operator before comma has no effect; did you intend 'operator'? 24 | /w14555 # expression has no effect; expected expression with side- effect 25 | /w14619 # pragma warning: there is no warning number 'number' 26 | /w14640 # Enable warning on thread un-safe static member initialization 27 | /w14826 # Conversion from 'type1' to 'type_2' is sign-extended. This may cause unexpected runtime behavior. 28 | /w14905 # wide string literal cast to 'LPSTR' 29 | /w14906 # string literal cast to 'LPWSTR' 30 | /w14928 # illegal copy-initialization; more than one user-defined conversion has been implicitly applied 31 | /permissive- # standards conformance mode for MSVC compiler. 32 | ) 33 | 34 | set(CLANG_WARNINGS 35 | -Wall 36 | -Wextra # reasonable and standard 37 | -Wshadow # warn the user if a variable declaration shadows one from a parent context 38 | -Wnon-virtual-dtor # warn the user if a class with virtual functions has a non-virtual destructor. This helps 39 | # catch hard to track down memory errors 40 | -Wold-style-cast # warn for c-style casts 41 | -Wcast-align # warn for potential performance problem casts 42 | -Wunused # warn on anything being unused 43 | -Woverloaded-virtual # warn if you overload (not override) a virtual function 44 | -Wpedantic # warn if non-standard C++ is used 45 | -Wconversion # warn on type conversions that may lose data 46 | -Wsign-conversion # warn on sign conversions 47 | -Wnull-dereference # warn if a null dereference is detected 48 | -Wdouble-promotion # warn if float is implicit promoted to double 49 | -Wformat=2 # warn on security issues around functions that format output (ie printf) 50 | -Wsign-conversion # warn on sign conversions 51 | -Wcast-qual # warn on casts which remove qualifiers 52 | -Wimplicit-fallthrough # warn on implicit fallthrough in unreachable code 53 | -Wextra-semi # warn on extra semicolons 54 | ) 55 | 56 | if(WARNINGS_AS_ERRORS) 57 | set(CLANG_WARNINGS ${CLANG_WARNINGS} -Werror) 58 | set(MSVC_WARNINGS ${MSVC_WARNINGS} /WX) 59 | endif() 60 | 61 | set(GCC_WARNINGS 62 | ${CLANG_WARNINGS} 63 | -Wmisleading-indentation # warn if indentation implies blocks where blocks do not exist 64 | -Wduplicated-cond # warn if if / else chain has duplicated conditions 65 | -Wduplicated-branches # warn if if / else branches have duplicated code 66 | -Wlogical-op # warn about logical operations being used where bitwise were probably wanted 67 | #-Wuseless-cast # warn if you perform a cast to the same type 68 | ) 69 | 70 | if(MSVC) 71 | set(PROJECT_WARNINGS ${MSVC_WARNINGS}) 72 | elseif(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") 73 | set(PROJECT_WARNINGS ${CLANG_WARNINGS}) 74 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 75 | set(PROJECT_WARNINGS ${GCC_WARNINGS}) 76 | else() 77 | message(AUTHOR_WARNING "No compiler warnings set for '${CMAKE_CXX_COMPILER_ID}' compiler.") 78 | endif() 79 | 80 | target_compile_options(${project_name} INTERFACE ${PROJECT_WARNINGS}) 81 | 82 | endfunction() 83 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(initialize ${PROJECT_SOURCE_DIR}/src/initialize.cpp) 2 | target_link_libraries( 3 | initialize 4 | PRIVATE project_options 5 | project_warnings 6 | date::date-tz 7 | Boost::program_options 8 | fmt::fmt-header-only 9 | Eigen3::Eigen 10 | spdlog::spdlog_header_only 11 | TBB::tbb 12 | CGAL::CGAL) 13 | target_compile_features(initialize PRIVATE cxx_std_23) 14 | 15 | add_executable(cdt-opt ${PROJECT_SOURCE_DIR}/src/cdt-opt.cpp) 16 | target_link_libraries( 17 | cdt-opt 18 | PRIVATE project_options 19 | project_warnings 20 | date::date-tz 21 | fmt::fmt-header-only 22 | Eigen3::Eigen 23 | spdlog::spdlog_header_only 24 | TBB::tbb 25 | CGAL::CGAL) 26 | target_compile_features(cdt-opt PRIVATE cxx_std_23) 27 | 28 | add_executable(cdt ${PROJECT_SOURCE_DIR}/src/cdt.cpp) 29 | target_link_libraries( 30 | cdt 31 | PRIVATE project_options 32 | project_warnings 33 | date::date-tz 34 | Boost::program_options 35 | fmt::fmt-header-only 36 | Eigen3::Eigen 37 | spdlog::spdlog_header_only 38 | TBB::tbb 39 | CGAL::CGAL) 40 | target_compile_features(cdt PRIVATE cxx_std_23) 41 | 42 | # Build cdt-viewer locally, but not in CI since QT takes more than an hour to build there 43 | #if(APPLE AND NOT ($ENV{CI})) 44 | # add_executable(cdt-viewer ${PROJECT_SOURCE_DIR}/src/cdt-viewer.cpp) 45 | # target_link_libraries( 46 | # cdt-viewer 47 | # PRIVATE project_options 48 | # project_warnings 49 | # date::date-tz 50 | # Boost::program_options 51 | # fmt::fmt-header-only 52 | # Eigen3::Eigen 53 | # spdlog::spdlog_header_only 54 | # TBB::tbb 55 | # CGAL::CGAL_Basic_viewer) 56 | # target_compile_features(cdt-viewer PRIVATE cxx_std_23) 57 | #endif() 58 | 59 | # Build bistellar-flip locally, but not in CI since QT takes more than an hour to build there 60 | #if(APPLE AND NOT ($ENV{CI})) 61 | # add_executable(bistellar-flip ${PROJECT_SOURCE_DIR}/src/bistellar-flip.cpp) 62 | # target_link_libraries( 63 | # bistellar-flip 64 | # PRIVATE project_options 65 | # project_warnings 66 | # date::date-tz 67 | # fmt::fmt-header-only 68 | # Eigen3::Eigen 69 | # spdlog::spdlog_header_only 70 | # TBB::tbb) 71 | # CGAL::CGAL_Basic_viewer) 72 | # target_compile_features(bistellar-flip PRIVATE cxx_std_23) 73 | #endif() 74 | 75 | # 76 | # Tests ## 77 | # 78 | 79 | add_test(NAME cdt COMMAND $ -s -n127 -t4 -a0.6 -k1.1 -l0.1 -p10) 80 | set_tests_properties(cdt PROPERTIES PASS_REGULAR_EXPRESSION "Writing to file S3-4-") 81 | 82 | add_test(NAME cdt-triangle-inequalities COMMAND $ -s -n64 -t3 -a0.4 -k1.1 -l0.1) 83 | set_tests_properties(cdt-triangle-inequalities PROPERTIES PASS_REGULAR_EXPRESSION "Triangle inequalities violated") 84 | 85 | add_test(NAME cdt-dimensionality COMMAND $ -s -n64 -t3 -d4 -a0.4 -k1.1 -l0.1) 86 | set_tests_properties(cdt-dimensionality PROPERTIES PASS_REGULAR_EXPRESSION "Currently, dimensions cannot be >3.") 87 | 88 | add_test(NAME cdt-toroidal COMMAND $ -e -n64 -t3 -a0.6 -k1.1 -l0.1) 89 | set_tests_properties(cdt-toroidal PROPERTIES PASS_REGULAR_EXPRESSION "Toroidal triangulations not yet supported.") 90 | 91 | add_test(NAME initialize COMMAND $ -s -n640 -t4 -o) 92 | set_tests_properties(initialize PROPERTIES PASS_REGULAR_EXPRESSION "Writing to file S3-4") 93 | 94 | add_test(NAME initialize-minimum-simplices COMMAND $ -s -n1 -t1 -o) 95 | set_tests_properties(initialize-minimum-simplices 96 | PROPERTIES PASS_REGULAR_EXPRESSION "Simplices and timeslices should be greater or equal to 2.") 97 | 98 | add_test(NAME initialize-dimensionality COMMAND $ -s -n64 -t3 -d4 -o) 99 | set_tests_properties(initialize-dimensionality PROPERTIES PASS_REGULAR_EXPRESSION "Currently, dimensions cannot be >3.") 100 | 101 | add_test(NAME initialize-toroidal COMMAND $ -e -n64 -t3 -o) 102 | set_tests_properties(initialize-toroidal PROPERTIES PASS_REGULAR_EXPRESSION 103 | "Toroidal triangulations not yet supported.") 104 | 105 | add_test(NAME cdt-opt COMMAND $) 106 | set_tests_properties(cdt-opt PROPERTIES PASS_REGULAR_EXPRESSION "cdt-opt started at") 107 | 108 | #if(APPLE AND NOT ($ENV{CI})) 109 | # add_test(NAME cdt-viewer COMMAND $ --dry-run test.off) 110 | # set_tests_properties(cdt-viewer PROPERTIES PASS_REGULAR_EXPRESSION "Dry run. Exiting.") 111 | #endif() 112 | -------------------------------------------------------------------------------- /src/optimize-initialize.py: -------------------------------------------------------------------------------- 1 | # Causal Dynamical Triangulations in C++ using CGAL 2 | # 3 | # Copyright © 2018 Adam Getchell 4 | # 5 | # A program that optimizes spacetime generation parameters 6 | 7 | # @file optimize-initialize.py 8 | # @brief Optimize spacetime generation 9 | # @author Adam Getchell 10 | 11 | # Usage: python optimize-initialize.py 12 | # 13 | from __future__ import absolute_import, division, print_function 14 | 15 | import os 16 | import traceback 17 | 18 | # Import Comet.ml 19 | from comet_ml import Experiment 20 | # from comet_ml import Optimizer 21 | import comet_ml as cm 22 | 23 | # Import TensorFlow 24 | # import tensorflow as tf 25 | # import tensorflow.contrib.eager as tfe 26 | import matplotlib.pyplot as plt 27 | import numpy as np 28 | 29 | # Run command line programs 30 | import shlex 31 | from subprocess import check_output as qx 32 | import re 33 | 34 | # Create an optimizer for dynamic parameters 35 | # optimizer = Optimizer(api_key=os.environ['COMET_API_KEY']) 36 | # params = """ 37 | # initial_radius integer [1, 2] [1] 38 | # foliation_spacing integer [1, 2] [1] 39 | # """ 40 | # 41 | # optimizer.set_params(params) 42 | 43 | # tf.enable_eager_execution() 44 | 45 | # Create parameters to vary 46 | parameters = [(initial_radius, spacing) for initial_radius in range(1, 4) for spacing in np.arange(1, 2.5, 0.5)] 47 | 48 | try: 49 | # while True: 50 | # Get a suggestion 51 | # suggestion = optimizer.get_suggestion() 52 | for parameter_pair in parameters: 53 | 54 | # Create an experiment with api key 55 | experiment = Experiment(api_key=os.environ['COMET_API_KEY'], project_name="cdt-plusplus", team_name="ucdavis") 56 | 57 | # print('TensorFlow version: {}'.format(tf.VERSION)) 58 | 59 | hyper_params = {'simplices': 12000, 'foliations': 12} 60 | experiment.log_multiple_params(hyper_params) 61 | # init_radius = suggestion["initial_radius"] 62 | init_radius = parameter_pair[0] 63 | # radial_factor = suggestion["foliation_spacing"] 64 | radial_factor = parameter_pair[1] 65 | 66 | command_line = "../build/src/initialize --s -n" + str(experiment.get_parameter("simplices")) \ 67 | + " -t" + str(experiment.get_parameter("foliations")) + " -i" + str(init_radius) \ 68 | + " -f" + str(radial_factor) 69 | args = shlex.split(command_line) 70 | 71 | print(args) 72 | 73 | output = qx(args) 74 | 75 | # Parse output into a list of [simplices, min timeslice, max timeslice] 76 | result = [0, 0, 0] 77 | graph = [] 78 | for line in output.splitlines(): 79 | if line.startswith("Minimum timevalue"): 80 | s = re.findall('\d+', line) 81 | result[1] = float(s[0]) 82 | elif line.startswith("Maximum timevalue"): 83 | s = re.findall('\d+', line) 84 | result[2] = float(s[0]) 85 | elif line.startswith("Final number"): 86 | # print(line) 87 | s = re.findall('\d+', line) 88 | # print(s) 89 | result[0] = float(s[0]) 90 | elif line.startswith("Timeslice"): 91 | t = re.findall('\d+', line) 92 | graph.append(t) 93 | 94 | print(result) 95 | print('Initial radius is: {}'.format(init_radius)) 96 | print('Radial factor is: {}'.format(radial_factor)) 97 | for element in graph: 98 | print("Timeslice {} has {} spacelike faces.".format(element[0], element[1])) 99 | print("") 100 | 101 | # Score model 102 | score = ((result[0] - experiment.get_parameter("simplices"))/(experiment.get_parameter("simplices")))*100 103 | 104 | # Report results 105 | experiment.log_metric("Error %", score) 106 | experiment.log_other("Min Timeslice", result[1]) 107 | experiment.log_other("Max Timeslice", result[2]) 108 | 109 | # Graph volume profile 110 | timeslice = [] 111 | volume = [] 112 | for element in graph: 113 | timeslice.append(int(element[0])) 114 | volume.append(int(element[1])) 115 | plt.plot(timeslice, volume) 116 | plt.xlabel('Timeslice') 117 | plt.ylabel('Volume (spacelike faces)') 118 | plt.title('Volume Profile') 119 | plt.grid(True) 120 | experiment.log_figure(figure_name="Volume per Timeslice", figure=plt) 121 | plt.clf() 122 | 123 | 124 | except cm.exceptions.NoMoreSuggestionsAvailable as NoMore: 125 | print("No more suggestions.") 126 | 127 | except (TypeError, KeyError): 128 | pass 129 | 130 | finally: 131 | traceback.print_exc() 132 | 133 | print("All done with parameter optimization, look at Comet.ml for results.") 134 | -------------------------------------------------------------------------------- /tests/Function_ref_test.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2017 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file Function_ref_test.cpp 8 | /// @brief Tests on function pointers, lambdas, and function_refs 9 | /// @author Adam Getchell 10 | /// @details Tests for lambdas and function_refs to store function objects for 11 | /// delayed calls 12 | 13 | #include 14 | 15 | #include 16 | 17 | #include "Ergodic_moves_3.hpp" 18 | 19 | using namespace std; 20 | using namespace manifolds; 21 | 22 | SCENARIO("Simple Lambda operations" * doctest::test_suite("function_ref")) 23 | { 24 | auto constexpr increment_lambda = [](int a) { return ++a; }; // NOLINT 25 | GIVEN("A simple lambda.") 26 | { 27 | WHEN("Lambda is called with 0.") 28 | { 29 | THEN("We should get 1.") { REQUIRE_EQ(increment_lambda(0), 1); } 30 | } 31 | 32 | WHEN("Lambda is called with 1.") 33 | { 34 | THEN("We should get 2.") { REQUIRE_EQ(increment_lambda(1), 2); } 35 | } 36 | 37 | WHEN("Lambda is called with 5.") 38 | { 39 | THEN("We should get 6.") { REQUIRE_EQ(increment_lambda(5), 6); } 40 | } 41 | } 42 | } 43 | 44 | SCENARIO("Complex lambda operations" * doctest::test_suite("function_ref")) 45 | { 46 | GIVEN("A lambda storing a move.") 47 | { 48 | auto constexpr desired_simplices = 640; 49 | auto constexpr desired_timeslices = 4; 50 | Manifold_3 manifold(desired_simplices, desired_timeslices); 51 | REQUIRE(manifold.is_correct()); 52 | WHEN("A lambda is constructed for a move.") 53 | { 54 | auto const move23 = [](Manifold_3& m) { // NOLINT 55 | return ergodic_moves::do_23_move(m).value(); 56 | }; 57 | THEN("Running the lambda makes the move.") 58 | { 59 | auto result = move23(manifold); 60 | result.update(); 61 | CHECK(ergodic_moves::check_move(manifold, result, 62 | move_tracker::move_type::TWO_THREE)); 63 | // Human verification 64 | fmt::print("Manifold properties:\n"); 65 | manifold.print_details(); 66 | fmt::print("Moved manifold properties:\n"); 67 | result.print_details(); 68 | } 69 | } 70 | } 71 | } 72 | 73 | SCENARIO("Function_ref operations" * doctest::test_suite("function_ref")) 74 | { 75 | GIVEN("A simple lambda stored in a function_ref.") 76 | { 77 | auto const increment = [](int incr) { return ++incr; }; 78 | tl::function_ref const lambda_ref(increment); 79 | WHEN("Function_ref is called with 0.") 80 | { 81 | THEN("We should get 1.") { REQUIRE_EQ(lambda_ref(1), 2); } 82 | } 83 | } 84 | GIVEN("A function pointer to a move stored in a function_ref.") 85 | { 86 | auto constexpr desired_simplices = 640; 87 | auto constexpr desired_timeslices = 4; 88 | Manifold_3 manifold(desired_simplices, desired_timeslices); 89 | REQUIRE(manifold.is_correct()); 90 | tl::function_ref const complex_ref(ergodic_moves::do_23_move); 91 | WHEN("The function_ref is invoked.") 92 | { 93 | auto result = complex_ref(manifold); 94 | result->update(); 95 | THEN("The move from the function_ref is correct.") 96 | { 97 | CHECK(ergodic_moves::check_move(manifold, result.value(), 98 | move_tracker::move_type::TWO_THREE)); 99 | // Human verification 100 | fmt::print("Manifold properties:\n"); 101 | manifold.print_details(); 102 | fmt::print("Moved manifold properties:\n"); 103 | result->print_details(); 104 | } 105 | } 106 | } 107 | GIVEN("A lambda invoking a move stored in a function_ref.") 108 | { 109 | auto constexpr desired_simplices = 640; 110 | auto constexpr desired_timeslices = 4; 111 | Manifold_3 manifold(desired_simplices, desired_timeslices); 112 | REQUIRE(manifold.is_correct()); 113 | auto const move23 = [](Manifold_3& t_manifold) { 114 | return ergodic_moves::do_23_move(t_manifold).value(); 115 | }; 116 | tl::function_ref const complex_ref(move23); 117 | WHEN("The function_ref is invoked.") 118 | { 119 | auto result = complex_ref(manifold); 120 | result.update(); 121 | THEN( 122 | "The move stored in the lambda invoked by the function_ref is " 123 | "correct.") 124 | { 125 | CHECK(ergodic_moves::check_move(manifold, result, 126 | move_tracker::move_type::TWO_THREE)); 127 | // Human verification 128 | fmt::print("Manifold properties:\n"); 129 | manifold.print_details(); 130 | fmt::print("Moved manifold properties:\n"); 131 | result.print_details(); 132 | } 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/bistellar-flip.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | Copyright © 2023 Adam Getchell 4 | ******************************************************************************/ 5 | 6 | /// @file bistellar-flip.cpp 7 | /// @brief Tests and views bistellar flips 8 | /// @details This is a unit test of the bistellar flip algorithm. 9 | /// The reason it is not in /tests is because it uses CGAL::draw() to 10 | /// display the results, which requires Qt5. Qt5 is extremely heavy 11 | /// and not needed for the other unit tests, so I don't want to require/link 12 | /// it to the test binary. 13 | /// @author Adam Getchell 14 | 15 | #ifdef NDEBUG 16 | #define DOCTEST_CONFIG_DISABLE 17 | #include 18 | #endif 19 | 20 | #define DOCTEST_CONFIG_IMPLEMENT 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #include "Ergodic_moves_3.hpp" 28 | 29 | static inline std::floating_point auto constexpr SQRT_2 = 30 | std::numbers::sqrt2_v; 31 | static inline std::floating_point auto constexpr INV_SQRT_2 = 1 / SQRT_2; 32 | 33 | auto bistellar_triangulation_vertices() -> std::vector> 34 | { 35 | std::vector vertices{ 36 | Point_t<3>{ 0, 0, 0}, 37 | Point_t<3>{ INV_SQRT_2, 0, INV_SQRT_2}, 38 | Point_t<3>{ 0, INV_SQRT_2, INV_SQRT_2}, 39 | Point_t<3>{-INV_SQRT_2, 0, INV_SQRT_2}, 40 | Point_t<3>{ 0, -INV_SQRT_2, INV_SQRT_2}, 41 | Point_t<3>{ 0, 0, 2} 42 | }; 43 | return vertices; 44 | } 45 | 46 | auto main(int const argc, char* argv[]) -> int 47 | try 48 | { 49 | // Doctest integration into code 50 | doctest::Context context; 51 | context.setOption("no-breaks", 52 | true); // don't break in debugger when assertions fail 53 | context.applyCommandLine(argc, argv); 54 | 55 | int const res = context.run(); // run tests unless --no-run is specified 56 | if (context.shouldExit()) 57 | { // important - query flags (and --exit) rely on the user doing this 58 | return res; // propagate the result of the tests 59 | } 60 | 61 | context.clearFilters(); // important - otherwise the context filters will be 62 | // used during the next evaluation of RUN_ALL_TESTS, 63 | // which will lead to wrong results 64 | 65 | #ifdef NDEBUG 66 | fmt::print("Before bistellar flip.\n"); 67 | auto vertices = bistellar_triangulation_vertices(); 68 | ergodic_moves::Delaunay const dt{vertices.begin(), vertices.end()}; 69 | manifolds::Manifold_3 const manifold{ 70 | foliated_triangulations::FoliatedTriangulation_3{dt, 0, 1} 71 | }; 72 | #ifdef ENABLE_VISUALIZATION 73 | CGAL::draw(manifold.get_delaunay()); 74 | #endif 75 | fmt::print("After bistellar flip.\n"); 76 | manifold.print_cells(); 77 | utilities::print_delaunay(dt); 78 | #endif 79 | } 80 | catch (std::exception const& e) 81 | { 82 | spdlog::critical("Error: {}\n", e.what()); 83 | return EXIT_FAILURE; 84 | } 85 | 86 | catch (...) 87 | { 88 | spdlog::critical("Something went wrong ... Exiting.\n"); 89 | return EXIT_FAILURE; 90 | } 91 | 92 | SCENARIO("Perform bistellar flip on Delaunay triangulation" * 93 | doctest::test_suite("bistellar")) 94 | { 95 | GIVEN("A triangulation setup for a bistellar flip") 96 | { 97 | auto vertices = bistellar_triangulation_vertices(); 98 | ergodic_moves::Delaunay triangulation(vertices.begin(), vertices.end()); 99 | WHEN("We have a valid triangulation") 100 | { 101 | CHECK(triangulation.is_valid()); 102 | THEN("We can perform a bistellar flip") 103 | { 104 | // Obtain top and bottom vertices by re-inserting, which returns the 105 | // Vertex_handle 106 | auto top = triangulation.insert(Point_t<3>{0, 0, 2}); 107 | auto bottom = triangulation.insert(Point_t<3>{0, 0, 0}); 108 | auto edges = foliated_triangulations::collect_edges<3>(triangulation); 109 | auto pivot_edge = ergodic_moves::find_pivot_edge(triangulation, edges); 110 | REQUIRE_MESSAGE(pivot_edge, "No pivot edge found."); 111 | 112 | // Check this didn't actually change vertices in the triangulation 113 | REQUIRE_EQ(vertices.size(), 6); 114 | 115 | if (pivot_edge) 116 | { 117 | auto flipped_triangulation = ergodic_moves::bistellar_flip( 118 | triangulation, pivot_edge.value(), top, bottom); 119 | 120 | REQUIRE_MESSAGE(flipped_triangulation, "Bistellar flip failed."); 121 | if (flipped_triangulation) 122 | { 123 | /// FIXME: This fails because the triangulation is not valid after 124 | /// the flip neighbor of c has not c as neighbor 125 | WARN(flipped_triangulation->is_valid()); 126 | } 127 | } 128 | } 129 | } 130 | } 131 | } -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL Advanced" 13 | 14 | on: 15 | push: 16 | branches: [ "develop", "gh-pages" ] 17 | pull_request: 18 | branches: [ "develop", "gh-pages" ] 19 | schedule: 20 | - cron: '29 0 * * 2' 21 | 22 | jobs: 23 | analyze: 24 | name: Analyze (${{ matrix.language }}) 25 | # Runner size impacts CodeQL analysis time. To learn more, please see: 26 | # - https://gh.io/recommended-hardware-resources-for-running-codeql 27 | # - https://gh.io/supported-runners-and-hardware-resources 28 | # - https://gh.io/using-larger-runners (GitHub.com only) 29 | # Consider using larger runners or machines with greater resources for possible analysis time improvements. 30 | runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} 31 | permissions: 32 | # required for all workflows 33 | security-events: write 34 | 35 | # required to fetch internal or private CodeQL packs 36 | packages: read 37 | 38 | # only required for workflows in private repositories 39 | actions: read 40 | contents: read 41 | 42 | strategy: 43 | fail-fast: false 44 | matrix: 45 | include: 46 | - language: actions 47 | build-mode: none 48 | - language: c-cpp 49 | build-mode: autobuild 50 | - language: python 51 | build-mode: none 52 | # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' 53 | # Use `c-cpp` to analyze code written in C, C++ or both 54 | # Use 'java-kotlin' to analyze code written in Java, Kotlin or both 55 | # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both 56 | # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, 57 | # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. 58 | # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how 59 | # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages 60 | steps: 61 | - name: Checkout repository 62 | uses: actions/checkout@v4 63 | 64 | # Add any setup steps before running the `github/codeql-action/init` action. 65 | # This includes steps like installing compilers or runtimes (`actions/setup-node` 66 | # or others). This is typically only required for manual builds. 67 | # - name: Setup runtime (example) 68 | # uses: actions/setup-example@v1 69 | 70 | # Initializes the CodeQL tools for scanning. 71 | - name: Initialize CodeQL 72 | uses: github/codeql-action/init@v3 73 | with: 74 | languages: ${{ matrix.language }} 75 | build-mode: ${{ matrix.build-mode }} 76 | # If you wish to specify custom queries, you can do so here or in a config file. 77 | # By default, queries listed here will override any specified in a config file. 78 | # Prefix the list here with "+" to use these queries and those in the config file. 79 | 80 | # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 81 | # queries: security-extended,security-and-quality 82 | 83 | # If the analyze step fails for one of the languages you are analyzing with 84 | # "We were unable to automatically build your code", modify the matrix above 85 | # to set the build mode to "manual" for that language. Then modify this step 86 | # to build your code. 87 | # ℹ️ Command-line programs to run using the OS shell. 88 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 89 | - if: matrix.build-mode == 'manual' 90 | shell: bash 91 | run: | 92 | echo 'If you are using a "manual" build mode for one or more of the' \ 93 | 'languages you are analyzing, replace this with the commands to build' \ 94 | 'your code, for example:' 95 | echo ' make bootstrap' 96 | echo ' make release' 97 | exit 1 98 | 99 | - name: Perform CodeQL Analysis 100 | uses: github/codeql-action/analyze@v3 101 | with: 102 | category: "/language:${{matrix.language}}" 103 | -------------------------------------------------------------------------------- /src/cdt-viewer.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | Copyright © 2022 Adam Getchell 4 | ******************************************************************************/ 5 | 6 | /// @file cdt-viewer.cpp 7 | /// @brief Views 3D spacetimes 8 | /// @author Adam Getchell 9 | 10 | #ifdef NDEBUG 11 | #define DOCTEST_CONFIG_DISABLE 12 | #endif 13 | 14 | #include 15 | 16 | #define DOCTEST_CONFIG_IMPLEMENT 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | #include "Manifold.hpp" 24 | #include "Utilities.hpp" 25 | 26 | namespace po = boost::program_options; 27 | 28 | static auto constexpr USAGE = 29 | R"(Causal Dynamical Triangulations in C++ using CGAL. 30 | 31 | Copyright (c) 2022 Adam Getchell 32 | 33 | A program that views 3D triangulated spacetimes with a defined causal 34 | structure. Specify the filename of the triangulation to view. 35 | 36 | Usage: 37 | cdt-viewer -f FILENAME 38 | 39 | Options)"; 40 | 41 | auto main(int const argc, char* const argv[]) -> int 42 | try 43 | { 44 | // Doctest integration into code 45 | doctest::Context context; 46 | context.setOption("no-breaks", 47 | true); // don't break in debugger when assertions fail 48 | context.applyCommandLine(argc, argv); 49 | 50 | int const res = context.run(); // run tests unless --no-run is specified 51 | if (context.shouldExit()) 52 | { // important - query flags (and --exit) rely on the user doing this 53 | return res; // propagate the result of the tests 54 | } 55 | 56 | context.clearFilters(); // important - otherwise the context filters will be 57 | // used during the next evaluation of RUN_ALL_TESTS, 58 | // which will lead to wrong results 59 | 60 | std::string const intro{USAGE}; 61 | // Parsed arguments 62 | std::string filename; 63 | 64 | po::options_description description(intro); 65 | description.add_options()("help,h", "Show this message")( 66 | "version,v", "Show program version")("dry-run", 67 | "Don't actually do anything")( 68 | "filename,f", po::value(&filename), 69 | "Filename of triangulation to view"); 70 | 71 | po::variables_map args; 72 | po::store(po::parse_command_line(argc, argv, description), args); 73 | po::notify(args); 74 | 75 | if (args.count("help")) 76 | { 77 | std::cout << description << "\n"; 78 | return res + EXIT_SUCCESS; 79 | } 80 | 81 | if (args.count("version")) 82 | { 83 | fmt::print("cdt-viewer 1.0\n"); 84 | return res + EXIT_SUCCESS; 85 | } 86 | 87 | if (args.count("dry-run")) 88 | { 89 | fmt::print("Dry run. Exiting.\n"); 90 | return res + EXIT_SUCCESS; 91 | } 92 | 93 | fmt::print("cdt-viewer started at {}\n", utilities::current_date_time()); 94 | fmt::print("Reading triangulation from file {}\n", 95 | std::string_view(filename)); 96 | 97 | // Read from file 98 | auto const dt_in = utilities::read_file>(filename); 99 | 100 | // Draw triangulation 101 | fmt::print("Drawing {}\n", filename); 102 | draw(dt_in); 103 | 104 | return res + EXIT_SUCCESS; 105 | } 106 | 107 | catch (std::exception const& e) 108 | { 109 | spdlog::critical("Error: {}\n", e.what()); 110 | return EXIT_FAILURE; 111 | } 112 | 113 | catch (...) 114 | { 115 | spdlog::critical("Something went wrong ... Exiting.\n"); 116 | return EXIT_FAILURE; 117 | } 118 | 119 | SCENARIO("Given a 3D Manifold, it can be written to file and read back in." * 120 | doctest::test_suite("cdt-viewer")) 121 | { 122 | GIVEN("A 3D Manifold.") 123 | { 124 | auto constexpr simplices = 640; 125 | auto constexpr timeslices = 4; 126 | manifolds::Manifold_3 const manifold(simplices, timeslices); 127 | 128 | WHEN("It is written to file.") 129 | { 130 | auto const filename = utilities::make_filename(manifold); 131 | utilities::write_file(manifold); 132 | 133 | THEN("It can be read back in.") 134 | { 135 | auto dt_in = utilities::read_file>(filename); 136 | REQUIRE(dt_in.is_valid(true)); 137 | REQUIRE_EQ(dt_in.dimension(), manifold.dimensionality()); 138 | REQUIRE_EQ(dt_in.number_of_finite_cells(), manifold.N3()); 139 | REQUIRE_EQ(dt_in.number_of_finite_facets(), manifold.N2()); 140 | REQUIRE_EQ(dt_in.number_of_finite_edges(), manifold.N1()); 141 | REQUIRE_EQ(dt_in.number_of_vertices(), manifold.N0()); 142 | } 143 | THEN("It can be drawn.") 144 | { 145 | auto const dt_in = utilities::read_file>(filename); 146 | CGAL::draw(dt_in); 147 | // Cleanup test file 148 | REQUIRE_NOTHROW(std::filesystem::remove(filename)); 149 | } 150 | } 151 | } 152 | GIVEN("A non-existent filename.") 153 | { 154 | WHEN("It is read back in.") 155 | { 156 | THEN("An exception is thrown.") 157 | { 158 | REQUIRE_THROWS_AS(utilities::read_file>("unused.off"), 159 | std::filesystem::filesystem_error); 160 | } 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | # vcpkg settings must be set before project() 4 | if(DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE) 5 | set(CMAKE_TOOLCHAIN_FILE 6 | "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" 7 | CACHE STRING "") 8 | endif() 9 | 10 | if(POLICY CMP0167) 11 | cmake_policy(SET CMP0167 NEW) 12 | endif () 13 | 14 | # In Manifest mode CMake invokes vcpkg automatically This makes setup easier, however, in CI or Docker we may want to 15 | # turn this off 16 | option(VCPKG_MANIFEST_MODE "Build vcpkg ports from manifest" ON) 17 | 18 | # Ensure we install vcpkg ports in the same place so they can be reused between builds 19 | set(_VCPKG_INSTALLED_DIR 20 | "${CMAKE_CURRENT_LIST_DIR}/vcpkg_installed" 21 | CACHE STRING "") 22 | 23 | project( 24 | CDT-plusplus 25 | VERSION 0.1.8 26 | DESCRIPTION "Fast Causal Dynamical Triangulations in C++" 27 | LANGUAGES CXX) 28 | 29 | # Project settings 30 | include(cmake/StandardProjectSettings.cmake) 31 | 32 | # Prevent in source builds 33 | include(cmake/PreventInSourceBuilds.cmake) 34 | 35 | # Link this 'library' to set the c++ standard / compile-time options requested 36 | add_library(project_options INTERFACE) 37 | target_compile_features(project_options INTERFACE cxx_std_23) 38 | 39 | if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") 40 | option(ENABLE_BUILD_WITH_TIME_TRACE "Enable -ftime-trace to generate time tracing .json files on clang" OFF) 41 | if(ENABLE_BUILD_WITH_TIME_TRACE) 42 | add_compile_definitions(project_options INTERFACE -ftime-trace) 43 | endif() 44 | endif() 45 | 46 | # Link this 'library' to use the warnings specified in CompilerWarnings.cmake 47 | add_library(project_warnings INTERFACE) 48 | 49 | # enable cache system 50 | include(cmake/Cache.cmake) 51 | 52 | # standard compiler warnings 53 | include(cmake/CompilerWarnings.cmake) 54 | set_project_warnings(project_warnings) 55 | 56 | # sanitizer options if supported by compiler 57 | include(cmake/Sanitizers.cmake) 58 | enable_sanitizers(project_options) 59 | 60 | # allow for static analysis options 61 | include(cmake/StaticAnalyzers.cmake) 62 | 63 | # Options ## 64 | option(BUILD_SHARED_LIBS "Enable compilation of shared libraries" OFF) 65 | option(ENABLE_TESTING "Enable building of tests" ON) 66 | 67 | # Modules and scripts ## 68 | include(CTest) 69 | include(CMakeDependentOption) 70 | 71 | # Set CGAL_DATA_DIR to the location of the CGAL data files 72 | set(ENV{CGAL_DATA_DIR} CMAKE_BINARY_DIR/Data) 73 | 74 | # Minimum compiler versions required for C++23 support: 75 | # - MSVC 19.34 (Visual Studio 2022 version 17.4) 76 | # - GCC 12.2 77 | # - AppleClang 14.0 78 | # - Clang 16.0 79 | if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.34") 80 | message(FATAL_ERROR "MSVC 19.34 or higher required for C++23 support") 81 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "12.2") 82 | message(FATAL_ERROR "GCC 12.2 or higher required for C++23 support") 83 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "14.0") 84 | message(FATAL_ERROR "AppleClang 14.0 or higher required for C++23 support") 85 | elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "16.0") 86 | message(FATAL_ERROR "Clang 16.0 or higher required for C++23 support") 87 | endif() 88 | 89 | # Set NOMINMAX to avoid min/max macro errors on Windows in date.h 90 | #if(WIN32) 91 | # # Workaround for https://github.com/CGAL/cgal/issues/4665 and https://github.com/microsoft/vcpkg/issues/23572 92 | # add_compile_options(/DNOMINMAX) 93 | #endif() 94 | 95 | # Project vcpkg dependencies 96 | 97 | # https://github.com/CGAL/cgal 98 | find_package(CGAL CONFIG REQUIRED) 99 | # Don't let CGAL override flags 100 | set(CGAL_DONT_OVERRIDE_CMAKE_FLAGS 101 | TRUE 102 | CACHE BOOL "Force CGAL to maintain CMAKE flags") 103 | set(CGAL_DO_NOT_WARN_ABOUT_CMAKE_BUILD_TYPE TRUE) 104 | 105 | # https://howardhinnant.github.io/date/date.html 106 | find_package(date CONFIG REQUIRED) 107 | 108 | # https://github.com/doctest/doctest 109 | find_package(doctest CONFIG REQUIRED) 110 | 111 | # https://eigen.tuxfamily.org/index.php?title=Main_Page 112 | find_package(Eigen3 CONFIG REQUIRED) 113 | 114 | # https://github.com/fmtlib/fmt 115 | find_package(fmt CONFIG REQUIRED) 116 | 117 | # https://github.com/microsoft/GSL 118 | find_package(Microsoft.GSL CONFIG REQUIRED) 119 | 120 | # https://www.pcg-random.org 121 | find_path(PCG_INCLUDE_DIRS "pcg_extras.hpp") 122 | 123 | find_package(Boost CONFIG REQUIRED COMPONENTS program_options) 124 | 125 | # https://github.com/gabime/spdlog 126 | find_package(spdlog CONFIG REQUIRED) 127 | 128 | # https://github.com/intel/tbb 129 | find_package(TBB CONFIG REQUIRED) 130 | 131 | # https://github.com/TartanLlama/function_ref 132 | find_package(tl-function-ref CONFIG REQUIRED) 133 | 134 | # Header files 135 | include_directories(BEFORE ${PROJECT_SOURCE_DIR}/include) 136 | 137 | # doctest 138 | if(ENABLE_TESTING) 139 | enable_testing() 140 | message(STATUS "Building tests. Look at /tests for unit tests.") 141 | message(STATUS "Look at /tests/logs for spdlog results from unit tests.") 142 | message(NOTICE "These logs can get quite big in DEBUG mode if you run all tests.") 143 | add_subdirectory(tests) 144 | endif() 145 | 146 | add_subdirectory(src) 147 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | version: ~> 1.0 2 | language: cpp 3 | dist: jammy 4 | 5 | cache: 6 | - ccache 7 | - directories: 8 | - $TRAVIS_BUILD_DIR/vcpkg 9 | - $HOME/.cache/vcpkg/archives 10 | 11 | # Don't double build branch PRs 12 | branches: 13 | except: 14 | - /^pr\..*/ 15 | 16 | addons: 17 | apt: 18 | update: true 19 | packages: 20 | - build-essential 21 | - automake 22 | - autoconf 23 | - autoconf-archive 24 | - libtool-bin 25 | - texinfo 26 | - yasm 27 | - gcc-12 28 | - g++-12 29 | - ninja-build 30 | - cppcheck 31 | - doxygen 32 | - graphviz 33 | - lcov 34 | - valgrind 35 | - ccache 36 | - wget 37 | 38 | os: 39 | - linux 40 | 41 | compiler: 42 | - g++-12 43 | - clang-19 44 | 45 | jobs: 46 | fast_finish: true 47 | # include: 48 | # # CppCheck 49 | # - os: linux 50 | # compiler: g++12 51 | # env: CPPCHECK=true 52 | # before_script: 53 | # - export CMAKE_ARGS="-D ENABLE_CPPCHECK:BOOL=TRUE" 54 | # after_success: skip 55 | # # Valgrind 56 | # - os: linux 57 | # compiler: g++12 58 | # env: VALGRIND=true 59 | # before_script: 60 | # - export CMAKE_ARGS="-D ENABLE_IPO:BOOL=FALSE -D ENABLE_VALGRIND:BOOL=TRUE" 61 | # after_success: 62 | # - cd $TRAVIS_BUILD_DIR/build/ 63 | # - travis_wait 60 ctest -VV -T memcheck --verbose 64 | # - cd src 65 | # - travis_wait 30 valgrind --leak-check=full --show-leak-kinds=all --verbose ./initialize --s -n32000 -t11 -o 66 | # - travis_wait 30 valgrind --leak-check=full --show-leak-kinds=all --verbose ./cdt-opt 67 | # - travis_wait 30 valgrind --leak-check=full --show-leak-kinds=all --verbose ./cdt --s -n64 -t3 -a0.6 -k1.1 -l0.1 -p10 68 | # # AddressSanitizer and UndefinedBehaviorSanitizer 69 | # - os: linux 70 | # compiler: clang-15 71 | # env: ASAN=true 72 | # before_script: 73 | # - export CMAKE_ARGS="-D ENABLE_SANITIZER_ADDRESS:BOOL=TRUE -D ENABLE_SANITIZER_UNDEFINED_BEHAVIOR:BOOL=TRUE" 74 | # after_success: 75 | # - cd $TRAVIS_BUILD_DIR/build/ 76 | # - ctest -VV 77 | # - cd src 78 | # - ./initialize --s -n32000 -t11 -o 79 | # # LeakSanitizer 80 | # - os: linux 81 | # compiler: clang-15 82 | # env: LSAN=true 83 | # before_script: 84 | # - export CMAKE_ARGS="-D ENABLE_SANITIZER_LEAK:BOOL=TRUE" 85 | # after_success: 86 | # - cd $TRAVIS_BUILD_DIR/build/ 87 | # - ctest -VV 88 | # - cd src 89 | # - ./initialize --s -n32000 -t11 -o 90 | # # MemorySanitizer 91 | # - os: linux 92 | # compiler: clang-15 93 | # env: MSAN=true 94 | # before_script: 95 | # - export CMAKE_ARGS="-D ENABLE_SANITIZER_MEMORY:BOOL=TRUE" 96 | # after_success: 97 | # - cd $TRAVIS_BUILD_DIR/build/ 98 | # - ctest -VV 99 | # - cd src 100 | # - ./initialize --s -n32000 -t11 -o 101 | # # ThreadSanitizer 102 | # - os: linux 103 | # compiler: clang-15 104 | # env: TSAN=true 105 | # before_script: 106 | # - export CMAKE_ARGS="-D ENABLE_SANITIZER_THREAD:BOOL=TRUE" 107 | # after_success: 108 | # - cd $TRAVIS_BUILD_DIR/build/ 109 | # - travis_wait 90 ctest -VV 110 | # - cd src 111 | # - ./initialize --s -n32000 -t11 -o 112 | # # Doxygen 113 | # - os: linux 114 | # compiler: g++12 115 | # env: DOXYGEN=true 116 | # install: skip 117 | # script: 118 | # - cd $TRAVIS_BUILD_DIR 119 | # - doxygen docs/Doxyfile 120 | # - touch docs/html/.nojekyll 121 | # after_success: 122 | # # Overwrite usual after_success step without canceling it (which would cause deploy to not run) 123 | # - pwd 124 | # deploy: 125 | # provider: pages 126 | # skip_cleanup: true 127 | # local_dir: docs/html 128 | # github_token: $GITHUB_TOKEN 129 | # keep_history: true 130 | # verbose: true 131 | # edge: true 132 | # on: 133 | # all_branches: true 134 | # condition: $TRAVIS_BRANCH =~ ^(master|develop)$ 135 | # allow_failures: 136 | # - os: linux 137 | # compiler: g++12 138 | # env: DOXYGEN=true 139 | 140 | before_install: 141 | - | 142 | if [[ "$CXX" == "g++" ]]; then 143 | sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 90 144 | sudo update-alternatives --config gcc 145 | export CXX="g++-12" CC="gcc-12" 146 | fi 147 | - | 148 | if [[ "$CXX" == "clang++" ]]; then 149 | wget https://apt.llvm.org/llvm.sh 150 | chmod +x llvm.sh 151 | sudo ./llvm.sh 19 152 | sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-19 100 153 | sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-19 100 154 | export CXX="clang++-19" CC="clang-19" 155 | clang --version 156 | clang++ --version 157 | fi 158 | 159 | install: 160 | # vcpkg should be cached, but clone it if not 161 | - | 162 | if [[ ! -f vcpkg/vcpkg ]]; then 163 | git clone https://github.com/Microsoft/vcpkg.git 164 | fi 165 | - export VCPKG_ROOT="$TRAVIS_BUILD_DIR/vcpkg" 166 | - export PATH="$VCPKG_ROOT:$PATH" 167 | - cd $VCPKG_ROOT 168 | - git pull origin master --no-rebase 169 | - ./bootstrap-vcpkg.sh 170 | - rm -rf downloads buildtrees packages 171 | - cmake --version 172 | - cd .. 173 | - pwd 174 | # Install required libraries (these are often cached, so you must remove old dependencies first, as above) 175 | - travis_wait 120 vcpkg install 176 | - vcpkg list 177 | 178 | script: 179 | - cmake $CMAKE_ARGS -G Ninja -D CMAKE_BUILD_TYPE=RelWithDebInfo -D ENABLE_TESTING:BOOL=TRUE -S . -B build 180 | - travis_wait 60 cmake --build build 181 | 182 | after_success: 183 | - cd build 184 | - travis_wait 90 ctest --output-on-failure -j2 -------------------------------------------------------------------------------- /src/initialize.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2018 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file initialize.cpp 8 | /// @brief Generates initial spacetimes 9 | /// @author Adam Getchell 10 | 11 | #include 12 | 13 | #include "Manifold.hpp" 14 | 15 | using namespace std; 16 | namespace po = boost::program_options; 17 | 18 | static string_view constexpr USAGE{ 19 | R"(Causal Dynamical Triangulations in C++ using CGAL. 20 | 21 | Copyright (c) 2014 Adam Getchell 22 | 23 | A program that generates d-dimensional triangulated spacetimes 24 | with a defined causal structure. Specify the topology of the triangulation 25 | (spherical or toroidal), the desired number of simplices, and the 26 | desired number of timeslices. 27 | 28 | Usage:./initialize (--spherical | --toroidal) -n SIMPLICES -t TIMESLICES 29 | [-d DIM] 30 | [--init INITIAL RADIUS] 31 | [--foliate FOLIATION SPACING] 32 | [--output] 33 | 34 | Optional arguments are in square brackets. 35 | 36 | Examples: 37 | ./initialize --spherical --simplices 32000 --timeslices 11 --init 1.0 --foliate 1.0 --output 38 | ./initialize -s -n32000 -t11 -i1.0 -f1.0 -o 39 | 40 | Options)"}; 41 | 42 | auto main(int const argc, char* const argv[]) -> int 43 | try 44 | { 45 | std::string const intro{USAGE}; 46 | // Parsed arguments 47 | topology_type topology; 48 | long long simplices; 49 | long long timeslices; 50 | long long dimensions; 51 | double initial_radius; 52 | double foliation_spacing; 53 | bool save_file; 54 | 55 | po::options_description description(intro); 56 | description.add_options()("help,h", "Show this message")( 57 | "version,v", "Show program version")("spherical,s", "Spherical topology")( 58 | "toroidal,e", "Toroidal topology")("simplices,n", 59 | po::value(&simplices), 60 | "Approximate number of simplices")( 61 | "timeslices,t", po::value(×lices), 62 | "Number of timeslices")( 63 | "dimensions,d", po::value(&dimensions)->default_value(3), 64 | "Dimensionality")("init,i", 65 | po::value(&initial_radius)->default_value(1.0), 66 | "Initial radius")( 67 | "foliate,f", po::value(&foliation_spacing)->default_value(1.0), 68 | "Foliation spacing")("output,o", "Save triangulation into OFF file"); 69 | 70 | po::variables_map args; 71 | po::store(po::parse_command_line(argc, argv, description), args); 72 | po::notify(args); 73 | 74 | if (args.count("help")) 75 | { 76 | cout << description << "\n"; 77 | return EXIT_SUCCESS; 78 | } 79 | 80 | if (args.count("version")) 81 | { 82 | fmt::print("CDT initializer version 1.0\n"); 83 | return EXIT_SUCCESS; 84 | } 85 | 86 | if (args.count("spherical")) { topology = topology_type::SPHERICAL; } 87 | else if (args.count("toroidal")) { topology = topology_type::TOROIDAL; } 88 | else 89 | { 90 | fmt::print("Topology not specified.\n"); 91 | return EXIT_FAILURE; 92 | } 93 | 94 | if (args.count("simplices")) 95 | { 96 | simplices = args["simplices"].as(); 97 | } 98 | else 99 | { 100 | fmt::print("Number of simplices not specified.\n"); 101 | return EXIT_FAILURE; 102 | } 103 | 104 | if (args.count("timeslices")) 105 | { 106 | timeslices = args["timeslices"].as(); 107 | } 108 | else 109 | { 110 | fmt::print("Number of timeslices not specified.\n"); 111 | return EXIT_FAILURE; 112 | } 113 | 114 | if (args.count("output")) { save_file = true; } 115 | else { save_file = false; } 116 | 117 | // Initialize triangulation 118 | manifolds::Manifold_3 universe; 119 | 120 | // Display job parameters 121 | fmt::print("Topology is {}\n", utilities::topology_to_str(topology)); 122 | fmt::print("Number of dimensions = {}\n", dimensions); 123 | fmt::print("Number of desired simplices = {}\n", simplices); 124 | fmt::print("Number of desired timeslices = {}\n", timeslices); 125 | fmt::print("Initial radius = {}\n", initial_radius); 126 | fmt::print("Foliation spacing = {}\n", foliation_spacing); 127 | 128 | if (save_file) { fmt::print("Output will be saved.\n"); } 129 | 130 | if (simplices < 2 || timeslices < 2) 131 | { 132 | throw invalid_argument( 133 | "Simplices and timeslices should be greater or equal to 2."); 134 | } 135 | 136 | switch (topology) 137 | { 138 | case topology_type::SPHERICAL: 139 | if (dimensions == 3) 140 | { 141 | // Start your run 142 | manifolds::Manifold_3 populated_universe( 143 | static_cast(simplices), 144 | static_cast(timeslices), initial_radius, 145 | foliation_spacing); 146 | swap(populated_universe, universe); 147 | } 148 | else { throw invalid_argument("Currently, dimensions cannot be >3."); } 149 | break; 150 | case topology_type::TOROIDAL: 151 | throw invalid_argument("Toroidal triangulations not yet supported."); 152 | } 153 | universe.print(); 154 | universe.print_volume_per_timeslice(); 155 | fmt::print("Final number of simplices: {}\n", universe.N3()); 156 | if (save_file) { utilities::write_file(universe); } 157 | return EXIT_SUCCESS; 158 | } 159 | catch (invalid_argument const& InvalidArgument) 160 | { 161 | spdlog::critical("{}\n", InvalidArgument.what()); 162 | spdlog::critical("Invalid parameter ... Exiting.\n"); 163 | return EXIT_FAILURE; 164 | } 165 | catch (...) 166 | { 167 | spdlog::critical("Something went wrong ... Exiting.\n"); 168 | return EXIT_FAILURE; 169 | } 170 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## How to Contribute 2 | 3 | First, thank you! 4 | 5 | Writing esoteric scientific software can be its own reward, but it's not for the faint of heart. 6 | 7 | If you want a general overview as to why this software package exists, please look at the [Wiki] or my talk 8 | [Causal Dynamical Triangulations with CGAL][slides]. 9 | 10 | Second, here are some simple guidelines that will make it easier on me to process and accept your contributions. 11 | 12 | 1. Fork the repository. 13 | 14 | 2. This project uses [GitFlow]. That is, new [features] are branched from/merged into [develop]. 15 | New [releases] are periodically made from [develop], then merged back into [master], 16 | which is the stable work history. [Tagged] versions are [releases] at a point in time, citable via [ORCID]. 17 | for reproducibility. 18 | 19 | 3. Familiarize yourself with [doctest] and the [Gherkin] syntax. 20 | 21 | 4. Write a unit test for your proposed contribution. Unit tests go in the `tests` directory and are named 22 | \{YourContribution\}_test.cpp, don't forget to add to `/tests/CMakeLists.txt`. 23 | All proposed features of your contribution should have a corresponding test in \{YourContribution\}_test.cpp. 24 | Consult the [doctest test cases] if you are unsure, or consult existing tests for examples. 25 | 26 | 5. I highly recommend writing your tests first, before your contribution, as this helps to think about how the 27 | rest of the program will use your functions and/or classes. 28 | [Test-Driven Development] (and [BDD]) has saved me quite a bit from various mistakes. 29 | 30 | 6. Project source files go into the `src` directory; header files go into `include`. 31 | This makes integration into various tests and the main program easy and modular, and follows convention. 32 | 33 | 7. Don't forget documentation! It's helpful if you state explicitly what your functions and classes do. 34 | I use [Doxygen] to automatically build documentation, so using `/// @brief` and `/// @param` is helpful and easy. 35 | Consult existing code for examples. 36 | 37 | 8. Commit your changes with a clear, [well-written commit message]. 38 | 39 | 9. Check your whitespace with `git diff --check HEAD^`. 40 | 41 | 10. Run `clang-format` using the project's [.clang-format]. 42 | 43 | 11. Run `clang-tidy` using the project's [clang-tidy.sh]. 44 | 45 | 12. Open a pull request against the develop branch of the main repository (which is the default). 46 | [Travis-CI] will test it against combinations of Linux (Ubuntu 22.04) with clang and gcc. [GitHub Actions] will test 47 | against macOS and run various other checks. 48 | [AppVeyor] will test it against Visual Studio 2019 with `clang-cl` (version 14.0.6). Ensure that 49 | your code compiles on Windows, macOS, and Linux with `msvc`, `gcc`, and `clang`. 50 | 51 | 13. All pull requests must pass [Travis-CI] and [AppVeyor] to be accepted. 52 | In particular, look at results from [Cppcheck], [Valgrind], [ASAN], [LSAN], [MSAN], and [TSAN], because simulations may 53 | run for a long time so memory leaks will be eventually fatal. 54 | [GitHub Actions] also has a lot of useful checks that will help fix your code. 55 | 56 | 14. I will get to your change as soon as I can. 57 | Feel free to ping me on [Gitter] with any questions. 58 | You will receive proper credit for your contributions both in the code and any resulting scientific papers 59 | using the output of `git log --format='%aN | sort -u`. 60 | 61 | ## Style Guide 62 | 63 | This project generally follows [Stroustrup formatting with Allman brackets][1], enforced by [ClangFormat]. 64 | The [C++ Core Guidelines][cpp-core] are checked using [ClangTidy]. 65 | Running [clang-tidy.sh] changes the code (using `-fix`), so compare results and run unit tests before you commit. 66 | Especially since some of ClangTidy's fixes break the codebase (the script runs just the tests that don't). 67 | 68 | Most editors/IDEs have plugins for `clang-format` and `clang-tidy`. 69 | 70 | [Wiki]: https://github.com/acgetchell/CDT-plusplus/wiki 71 | [Test-Driven Development]: http://alexott.net/en/cpp/CppTestingIntro.html 72 | [Doxygen]: http://doxygen.org 73 | [well-written commit message]: https://chris.beams.io/posts/git-commit/ 74 | [Travis-CI]: https://travis-ci.org/acgetchell/CDT-plusplus 75 | [1]: https://isocpp.org/wiki/faq/coding-standards 76 | [2]: http://llvm.org/releases/4.0.0/tools/clang/docs/ClangFormatStyleOptions.html 77 | [ClangFormat]: https://releases.llvm.org/6.0.1/tools/clang/docs/ClangFormat.html 78 | [slides]: http://slides.com/acgetchell/causal-dynamical-triangulations-3 79 | [Valgrind]: http://valgrind.org/docs/manual/quick-start.html#quick-start.mcrun 80 | [cpp-core]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md 81 | [clang-tidy.sh]: https://github.com/acgetchell/CDT-plusplus/blob/develop/clang-tidy.sh 82 | [AppVeyor]: https://ci.appveyor.com/project/acgetchell/cdt-plusplus 83 | [doctest]: https://github.com/doctest/doctest 84 | [Gherkin]: https://www.tutorialspoint.com/behavior_driven_development/behavior_driven_development_gherkin.htm 85 | [BDD]: https://en.wikipedia.org/wiki/Behavior-driven_development 86 | [doctest test cases]: https://github.com/doctest/doctest/blob/master/doc/markdown/testcases.md 87 | [Gitter]: https://gitter.im/acgetchell/CDT-plusplus 88 | [ClangTidy]: https://releases.llvm.org/6.0.1/tools/clang/tools/extra/docs/clang-tidy/index.html 89 | [LGTM]: https://lgtm.com/projects/g/acgetchell/CDT-plusplus/ 90 | [GitFlow]: https://leanpub.com/git-flow/read 91 | [features]: https://leanpub.com/git-flow/read#leanpub-auto-feature-branches 92 | [develop]: https://github.com/acgetchell/CDT-plusplus 93 | [releases]: https://github.com/acgetchell/CDT-plusplus/releases 94 | [master]: https://github.com/acgetchell/CDT-plusplus/tree/master 95 | [.clang-format]: https://github.com/acgetchell/CDT-plusplus/blob/develop/.clang-format 96 | [Tagged]: https://github.com/acgetchell/CDT-plusplus/tags 97 | [ORCID]: https://orcid.org/ 98 | [Cppcheck]: http://cppcheck.sourceforge.net 99 | [ASAN]: https://github.com/google/sanitizers/wiki/AddressSanitizer 100 | [MSAN]: https://github.com/google/sanitizers/wiki/MemorySanitizer 101 | [GitHub Actions]: https://github.com/acgetchell/CDT-plusplus/actions 102 | [LSAN]: https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer 103 | [TSAN]: https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual -------------------------------------------------------------------------------- /include/Move_always.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2017 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file Move_always.hpp 8 | /// @brief Randomly selects moves to always perform on triangulations 9 | /// @author Adam Getchell 10 | /// @details Picks a random move on the FoliatedTriangulation. 11 | /// For testing purposes. 12 | /// @bug Fix initialization 13 | 14 | #ifndef INCLUDE_MOVE_ALWAYS_HPP_ 15 | #define INCLUDE_MOVE_ALWAYS_HPP_ 16 | 17 | #include "Move_command.hpp" 18 | #include "Move_strategy.hpp" 19 | 20 | /// @brief The Move Always algorithm 21 | template 22 | class MoveStrategy // NOLINT 23 | { 24 | using Counter = move_tracker::MoveTracker; 25 | 26 | /// @brief The number of move passes executed by the algorithm 27 | /// @details Each move pass makes a number of attempts equal to the number 28 | /// of simplices in the triangulation. 29 | Int_precision m_passes{1}; 30 | 31 | /// @brief The number of passes before a checkpoint 32 | /// @details Each checkpoint writes a file containing the current 33 | /// triangulation. 34 | Int_precision m_checkpoint{1}; 35 | 36 | /// @brief The number of moves that were attempted by a MoveCommand 37 | Counter m_attempted_moves; 38 | 39 | /// @brief The number of moves that succeeded in the MoveCommand 40 | Counter m_successful_moves; 41 | 42 | /// @brief The number of moves that a MoveCommand failed to make due to an 43 | /// error. 44 | Counter m_failed_moves; 45 | 46 | public: 47 | /// @brief Default ctor 48 | MoveStrategy() = default; 49 | 50 | /// @brief Constructor for MoveAlways 51 | /// @param t_number_of_passes Number of passes to run 52 | /// @param t_checkpoint Number of passes per checkpoint 53 | [[maybe_unused]] MoveStrategy(Int_precision const t_number_of_passes, 54 | Int_precision const t_checkpoint) 55 | : m_passes{t_number_of_passes}, m_checkpoint{t_checkpoint} 56 | {} 57 | 58 | /// @returns The number of passes made on a triangulation 59 | [[nodiscard]] auto passes() const { return m_passes; } 60 | 61 | /// @returns The number of passes per checkpoint 62 | [[nodiscard]] auto checkpoint() const { return m_checkpoint; } 63 | 64 | /// @returns The MoveTracker of attempted moves 65 | auto get_attempted() const { return m_attempted_moves; } 66 | 67 | /// @returns The MoveTracker of successful moves 68 | auto get_succeeded() const { return m_successful_moves; } 69 | 70 | /// @returns The array of failed moves 71 | auto get_failed() const { return m_failed_moves; } 72 | 73 | /// @brief Call operator 74 | auto operator()(ManifoldType const& t_manifold) -> ManifoldType 75 | { 76 | #ifndef NDEBUG 77 | spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); 78 | #endif 79 | fmt::print("Starting Move Always algorithm in {}+1 dimensions ...\n", 80 | ManifoldType::dimension - 1); 81 | 82 | // Start the move command 83 | MoveCommand command(t_manifold); 84 | 85 | fmt::print("Making random moves ...\n"); 86 | 87 | // Loop through passes 88 | for (auto pass_number = 1; pass_number <= m_passes; ++pass_number) 89 | { 90 | fmt::print("=== Pass {} ===\n", pass_number); 91 | auto total_simplices_this_pass = command.get_const_results().N3(); 92 | // Make a random move per simplex 93 | for (auto move_attempt = 0; move_attempt < total_simplices_this_pass; 94 | ++move_attempt) 95 | { 96 | // Pick a move to attempt 97 | auto move_choice = utilities::generate_random_int( 98 | 0, move_tracker::moves_per_dimension(ManifoldType::dimension) - 1); 99 | #ifndef NDEBUG 100 | fmt::print("Move choice = {}\n", move_choice); 101 | #endif 102 | if (move_choice == 0 && ManifoldType::dimension == 3) 103 | { 104 | command.enqueue(move_tracker::move_type::TWO_THREE); 105 | } 106 | 107 | if (move_choice == 1 && ManifoldType::dimension == 3) 108 | { 109 | command.enqueue(move_tracker::move_type::THREE_TWO); 110 | } 111 | 112 | if (move_choice == 2 && ManifoldType::dimension == 3) 113 | { 114 | command.enqueue(move_tracker::move_type::TWO_SIX); 115 | } 116 | 117 | if (move_choice == 3 && ManifoldType::dimension == 3) 118 | { 119 | command.enqueue(move_tracker::move_type::SIX_TWO); 120 | } 121 | 122 | if (move_choice == 4 && ManifoldType::dimension == 3) 123 | { 124 | command.enqueue(move_tracker::move_type::FOUR_FOUR); 125 | } 126 | } 127 | command.execute(); 128 | // Update attempted, successful, and failed moves 129 | m_attempted_moves += command.get_attempted(); 130 | m_successful_moves += command.get_succeeded(); 131 | m_failed_moves += command.get_failed(); 132 | } 133 | return command.get_results(); 134 | } 135 | 136 | /// @brief Display results of run 137 | void print_results() 138 | { 139 | if (ManifoldType::dimension == 3) 140 | { 141 | fmt::print("=== Move Results ===\n"); 142 | fmt::print("(2,3) moves: {} attempted = {} successful and {} failed.\n", 143 | m_attempted_moves.two_three_moves(), 144 | m_successful_moves.two_three_moves(), 145 | m_failed_moves.two_three_moves()); 146 | fmt::print("(3,2) moves: {} attempted = {} successful and {} failed.\n", 147 | m_attempted_moves.three_two_moves(), 148 | m_successful_moves.three_two_moves(), 149 | m_failed_moves.three_two_moves()); 150 | fmt::print("(2,6) moves: {} attempted = {} successful and {} failed.\n", 151 | m_attempted_moves.two_six_moves(), 152 | m_successful_moves.two_six_moves(), 153 | m_failed_moves.two_six_moves()); 154 | fmt::print("(6,2) moves: {} attempted = {} successful and {} failed.\n", 155 | m_attempted_moves.six_two_moves(), 156 | m_successful_moves.six_two_moves(), 157 | m_failed_moves.six_two_moves()); 158 | fmt::print("(4,4) moves: {} attempted = {} successful and {} failed.\n", 159 | m_attempted_moves.four_four_moves(), 160 | m_successful_moves.four_four_moves(), 161 | m_failed_moves.four_four_moves()); 162 | } 163 | } 164 | }; 165 | 166 | using MoveAlways_3 = 167 | MoveStrategy; 168 | using MoveAlways_4 = 169 | MoveStrategy; 170 | 171 | #endif // INCLUDE_MOVE_ALWAYS_HPP_ 172 | -------------------------------------------------------------------------------- /tests/Move_always_test.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2021 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file Move_always_test.cpp 8 | /// @brief Tests for the Move Always algorithm 9 | /// @author Adam Getchell 10 | 11 | #include "Move_always.hpp" 12 | 13 | #include 14 | 15 | using namespace std; 16 | using namespace manifolds; 17 | 18 | SCENARIO("MoveStrategy special member and swap properties" * 19 | doctest::test_suite("move_always")) 20 | { 21 | spdlog::debug( 22 | "MoveStrategy special member and swap properties.\n"); 23 | GIVEN("A Move always move strategy.") 24 | { 25 | WHEN("Special members are examined.") 26 | { 27 | THEN("It is no-throw destructible.") 28 | { 29 | REQUIRE(is_nothrow_destructible_v); 30 | REQUIRE(is_nothrow_destructible_v); 31 | spdlog::debug("It is no-throw destructible.\n"); 32 | } 33 | THEN("It is no-throw default constructible.") 34 | { 35 | REQUIRE(is_nothrow_default_constructible_v); 36 | REQUIRE(is_nothrow_default_constructible_v); 37 | spdlog::debug("It is no-throw default constructible.\n"); 38 | } 39 | THEN("It is no-throw copy constructible.") 40 | { 41 | REQUIRE(is_nothrow_copy_constructible_v); 42 | REQUIRE(is_nothrow_copy_constructible_v); 43 | spdlog::debug("It is no-throw copy constructible.\n"); 44 | } 45 | THEN("It is no-throw copy assignable.") 46 | { 47 | REQUIRE(is_nothrow_copy_assignable_v); 48 | REQUIRE(is_nothrow_copy_assignable_v); 49 | spdlog::debug("It is no-throw copy assignable.\n"); 50 | } 51 | THEN("It is no-throw move constructible.") 52 | { 53 | REQUIRE(is_nothrow_move_constructible_v); 54 | REQUIRE(is_nothrow_move_constructible_v); 55 | spdlog::debug("It is no-throw move constructible.\n"); 56 | } 57 | THEN("It is no-throw move assignable.") 58 | { 59 | REQUIRE(is_nothrow_move_assignable_v); 60 | REQUIRE(is_nothrow_move_assignable_v); 61 | spdlog::debug("It is no-throw move assignable.\n"); 62 | } 63 | THEN("It is no-throw swappable.") 64 | { 65 | REQUIRE(is_nothrow_swappable_v); 66 | REQUIRE(is_nothrow_swappable_v); 67 | spdlog::debug("It is no-throw swappable.\n"); 68 | } 69 | THEN("It is constructible from 2 parameters.") 70 | { 71 | REQUIRE(is_constructible_v); 72 | REQUIRE(is_constructible_v); 73 | spdlog::debug("It is constructible from 2 parameters.\n"); 74 | } 75 | } 76 | } 77 | } 78 | 79 | SCENARIO("MoveAlways member functions" * doctest::test_suite("move_always")) 80 | { 81 | spdlog::debug("MoveAlways member functions.\n"); 82 | GIVEN("A correctly-constructed Manifold_3.") 83 | { 84 | auto constexpr simplices = 640; 85 | auto constexpr timeslices = 4; 86 | Manifold_3 const manifold(simplices, timeslices); 87 | REQUIRE(manifold.is_correct()); 88 | WHEN("A MoveAlways_3 is constructed.") 89 | { 90 | auto constexpr passes = 10; 91 | auto constexpr checkpoint = 5; 92 | MoveAlways_3 const mover(passes, checkpoint); 93 | THEN("The correct passes and checkpoints are instantiated.") 94 | { 95 | CHECK_EQ(mover.passes(), passes); 96 | CHECK_EQ(mover.checkpoint(), checkpoint); 97 | } 98 | THEN("Attempted, successful, and failed moves are zero-initialized.") 99 | { 100 | CHECK_EQ(mover.get_attempted().total(), 0); 101 | CHECK_EQ(mover.get_succeeded().total(), 0); 102 | CHECK_EQ(mover.get_failed().total(), 0); 103 | } 104 | } 105 | WHEN("A MoveAlways_3 algorithm is instantiated.") 106 | { 107 | auto constexpr passes = 1; 108 | auto constexpr checkpoint = 1; 109 | MoveAlways_3 const mover(passes, checkpoint); 110 | THEN("The correct passes and checkpoints are instantiated.") 111 | { 112 | CHECK_EQ(mover.passes(), passes); 113 | CHECK_EQ(mover.checkpoint(), checkpoint); 114 | } 115 | THEN("Attempted moves and successful moves are zero-initialized.") 116 | { 117 | CHECK_EQ(mover.get_attempted().total(), 0); 118 | CHECK_EQ(mover.get_succeeded().total(), 0); 119 | CHECK_EQ(mover.get_failed().total(), 0); 120 | } 121 | } 122 | } 123 | } 124 | 125 | // This may take a while, so the scenario decorated with doctest::skip() 126 | // to disable by default 127 | SCENARIO("Using the MoveAlways algorithm" * doctest::test_suite("move_always") * 128 | doctest::skip()) 129 | { 130 | spdlog::debug("Using the MoveAlways algorithm.\n"); 131 | GIVEN("A correctly-constructed Manifold_3.") 132 | { 133 | auto constexpr simplices = 64; 134 | auto constexpr timeslices = 3; 135 | Manifold_3 const manifold(simplices, timeslices); 136 | REQUIRE(manifold.is_correct()); 137 | WHEN("A MoveAlways_3 algorithm is used.") 138 | { 139 | auto constexpr passes = 1; 140 | auto constexpr checkpoint = 1; 141 | MoveAlways_3 mover(passes, checkpoint); 142 | THEN("A lot of moves are made.") 143 | { 144 | auto result = mover(manifold); 145 | // Output 146 | CHECK(result.is_valid()); 147 | AND_THEN( 148 | "The correct number of attempted, successful, and failed moves are " 149 | "made.") 150 | { 151 | CHECK_EQ(mover.get_attempted().total(), 152 | mover.get_succeeded().total() + mover.get_failed().total()); 153 | // Human verification 154 | mover.print_results(); 155 | } 156 | } 157 | } 158 | } 159 | GIVEN("A 4D manifold.") 160 | { 161 | WHEN("A MoveStrategy4 is constructed.") 162 | { 163 | auto constexpr passes = 1; 164 | auto constexpr checkpoint = 1; 165 | MoveAlways_4 const mover(passes, checkpoint); 166 | THEN("The correct passes and checkpoints are instantiated.") 167 | { 168 | CHECK_EQ(mover.passes(), passes); 169 | CHECK_EQ(mover.checkpoint(), checkpoint); 170 | } 171 | THEN("Attempted moves and successful moves are zero-initialized.") 172 | { 173 | CHECK_EQ(mover.get_attempted().two_four_moves(), 0); 174 | CHECK_EQ(mover.get_failed().two_four_moves(), 0); 175 | } 176 | } 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: Google 4 | AccessModifierOffset: -1 5 | AlignAfterOpenBracket: Align 6 | AlignArrayOfStructures: Right 7 | AlignConsecutiveMacros: AcrossEmptyLinesAndComments 8 | AlignConsecutiveAssignments: AcrossEmptyLinesAndComments 9 | AlignConsecutiveBitFields: None 10 | AlignConsecutiveDeclarations: AcrossEmptyLines 11 | AlignEscapedNewlines: Left 12 | AlignOperands: AlignAfterOperator 13 | AlignTrailingComments: true 14 | AllowAllArgumentsOnNextLine: true 15 | AllowAllConstructorInitializersOnNextLine: true 16 | AllowAllParametersOfDeclarationOnNextLine: true 17 | AllowShortEnumsOnASingleLine: true 18 | AllowShortBlocksOnASingleLine: Always 19 | AllowShortCaseLabelsOnASingleLine: true 20 | AllowShortFunctionsOnASingleLine: All 21 | AllowShortLambdasOnASingleLine: All 22 | AllowShortIfStatementsOnASingleLine: AllIfsAndElse 23 | AllowShortLoopsOnASingleLine: true 24 | AlwaysBreakAfterDefinitionReturnType: None 25 | AlwaysBreakAfterReturnType: None 26 | AlwaysBreakBeforeMultilineStrings: true 27 | AlwaysBreakTemplateDeclarations: Yes 28 | AttributeMacros: 29 | - __capability 30 | BinPackArguments: true 31 | BinPackParameters: true 32 | BraceWrapping: 33 | AfterCaseLabel: true 34 | AfterClass: true 35 | AfterControlStatement: Always 36 | AfterEnum: true 37 | AfterFunction: true 38 | AfterNamespace: true 39 | AfterObjCDeclaration: false 40 | AfterStruct: true 41 | AfterUnion: true 42 | AfterExternBlock: false 43 | BeforeCatch: true 44 | BeforeElse: true 45 | BeforeLambdaBody: false 46 | BeforeWhile: true 47 | IndentBraces: false 48 | SplitEmptyFunction: false 49 | SplitEmptyRecord: false 50 | SplitEmptyNamespace: false 51 | BreakBeforeBinaryOperators: None 52 | BreakBeforeConceptDeclarations: true 53 | BreakBeforeBraces: Custom 54 | BreakBeforeInheritanceComma: false 55 | BreakInheritanceList: BeforeComma 56 | BreakBeforeTernaryOperators: true 57 | BreakConstructorInitializersBeforeComma: true 58 | BreakConstructorInitializers: BeforeComma 59 | BreakAfterJavaFieldAnnotations: false 60 | BreakStringLiterals: false 61 | ColumnLimit: 80 62 | CommentPragmas: '^ IWYU pragma:' 63 | CompactNamespaces: true 64 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 65 | ConstructorInitializerIndentWidth: 4 66 | ContinuationIndentWidth: 4 67 | Cpp11BracedListStyle: true 68 | DeriveLineEnding: true 69 | DerivePointerAlignment: true 70 | DisableFormat: false 71 | EmptyLineAfterAccessModifier: Never 72 | EmptyLineBeforeAccessModifier: LogicalBlock 73 | ExperimentalAutoDetectBinPacking: false 74 | FixNamespaceComments: true 75 | ForEachMacros: 76 | - foreach 77 | - Q_FOREACH 78 | - BOOST_FOREACH 79 | IfMacros: 80 | - KJ_IF_MAYBE 81 | IncludeBlocks: Regroup 82 | IncludeCategories: 83 | - Regex: '^' 84 | Priority: 2 85 | SortPriority: 0 86 | CaseSensitive: false 87 | - Regex: '^<.*\.h>' 88 | Priority: 1 89 | SortPriority: 0 90 | CaseSensitive: false 91 | - Regex: '^<.*' 92 | Priority: 2 93 | SortPriority: 0 94 | CaseSensitive: false 95 | - Regex: '.*' 96 | Priority: 3 97 | SortPriority: 0 98 | CaseSensitive: false 99 | IncludeIsMainRegex: '([-_](test|unittest))?$' 100 | IncludeIsMainSourceRegex: '' 101 | IndentAccessModifiers: false 102 | IndentCaseLabels: true 103 | IndentCaseBlocks: false 104 | IndentGotoLabels: true 105 | IndentPPDirectives: None 106 | IndentExternBlock: AfterExternBlock 107 | IndentRequiresClause: true 108 | IndentWidth: 2 109 | IndentWrappedFunctionNames: false 110 | InsertBraces: true 111 | InsertTrailingCommas: None 112 | JavaScriptQuotes: Leave 113 | JavaScriptWrapImports: true 114 | KeepEmptyLinesAtTheStartOfBlocks: false 115 | LambdaBodyIndentation: Signature 116 | MacroBlockBegin: '' 117 | MacroBlockEnd: '' 118 | MaxEmptyLinesToKeep: 1 119 | NamespaceIndentation: All 120 | ObjCBinPackProtocolList: Never 121 | ObjCBlockIndentWidth: 2 122 | ObjCBreakBeforeNestedBlockParam: true 123 | ObjCSpaceAfterProperty: false 124 | ObjCSpaceBeforeProtocolList: true 125 | PenaltyBreakAssignment: 2 126 | PenaltyBreakBeforeFirstCallParameter: 1 127 | PenaltyBreakComment: 300 128 | PenaltyBreakFirstLessLess: 120 129 | PenaltyBreakString: 1000 130 | PenaltyBreakTemplateDeclaration: 10 131 | PenaltyExcessCharacter: 1000000 132 | PenaltyReturnTypeOnItsOwnLine: 200 133 | PenaltyIndentedWhitespace: 0 134 | PointerAlignment: Left 135 | PPIndentWidth: -1 136 | QualifierAlignment: Custom 137 | QualifierOrder: 138 | - static 139 | - inline 140 | - type 141 | - const 142 | - constexpr 143 | - volatile 144 | - restrict 145 | RawStringFormats: 146 | - Language: Cpp 147 | Delimiters: 148 | - cc 149 | - CC 150 | - cpp 151 | - Cpp 152 | - CPP 153 | - 'c++' 154 | - 'C++' 155 | CanonicalDelimiter: '' 156 | BasedOnStyle: google 157 | - Language: TextProto 158 | Delimiters: 159 | - pb 160 | - PB 161 | - proto 162 | - PROTO 163 | EnclosingFunctions: 164 | - EqualsProto 165 | - EquivToProto 166 | - PARSE_PARTIAL_TEXT_PROTO 167 | - PARSE_TEST_PROTO 168 | - PARSE_TEXT_PROTO 169 | - ParseTextOrDie 170 | - ParseTextProtoOrDie 171 | - ParseTestProto 172 | - ParsePartialTestProto 173 | CanonicalDelimiter: pb 174 | BasedOnStyle: google 175 | ReferenceAlignment: Pointer 176 | ReflowComments: true 177 | ShortNamespaceLines: 1 178 | SortIncludes: CaseInsensitive 179 | SortJavaStaticImport: Before 180 | SortUsingDeclarations: true 181 | SpaceAfterCStyleCast: false 182 | SpaceAfterLogicalNot: false 183 | SpaceAfterTemplateKeyword: true 184 | SpaceBeforeAssignmentOperators: true 185 | SpaceBeforeCaseColon: false 186 | SpaceBeforeCpp11BracedList: false 187 | SpaceBeforeCtorInitializerColon: true 188 | SpaceBeforeInheritanceColon: true 189 | SpaceBeforeParens: ControlStatements 190 | SpaceAroundPointerQualifiers: Default 191 | SpaceBeforeRangeBasedForLoopColon: true 192 | SpaceInEmptyBlock: false 193 | SpaceInEmptyParentheses: false 194 | SpacesBeforeTrailingComments: 2 195 | SpacesInAngles: Never 196 | SpacesInConditionalStatement: false 197 | SpacesInContainerLiterals: true 198 | SpacesInCStyleCastParentheses: false 199 | SpacesInLineCommentPrefix: 200 | Minimum: 1 201 | Maximum: -1 202 | SpacesInParentheses: false 203 | SpacesInSquareBrackets: false 204 | SpaceBeforeSquareBrackets: false 205 | BitFieldColonSpacing: Both 206 | Standard: c++20 207 | StatementAttributeLikeMacros: 208 | - Q_EMIT 209 | StatementMacros: 210 | - Q_UNUSED 211 | - QT_REQUIRE_VERSION 212 | TabWidth: 8 213 | UseCRLF: false 214 | UseTab: Never 215 | WhitespaceSensitiveMacros: 216 | - STRINGIZE 217 | - PP_STRINGIZE 218 | - BOOST_PP_STRINGIZE 219 | - NS_SWIFT_NAME 220 | - CF_SWIFT_NAME 221 | ... 222 | -------------------------------------------------------------------------------- /tests/Apply_move_test.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2019 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file Apply_move_test.cpp 8 | /// @brief Applying ergodic moves to manifolds 9 | /// @author Adam Getchell 10 | /// @details Tests applying ergodic moves singly and in groups 11 | 12 | #include "Apply_move.hpp" 13 | 14 | #include 15 | 16 | #include "Ergodic_moves_3.hpp" 17 | 18 | using namespace std; 19 | 20 | SCENARIO("Apply an ergodic move to 2+1 manifolds" * 21 | doctest::test_suite("apply")) 22 | { 23 | GIVEN("A 2+1 dimensional spherical manifold.") 24 | { 25 | auto constexpr desired_simplices = 9600; 26 | auto constexpr desired_timeslices = 7; 27 | manifolds::Manifold_3 manifold(desired_simplices, desired_timeslices); 28 | REQUIRE(manifold.is_correct()); 29 | // Copy of manifold 30 | auto manifold_before = manifold; 31 | WHEN("A null move is applied to the manifold.") 32 | { 33 | spdlog::debug("Applying null move to manifold.\n"); 34 | if (auto result = apply_move(manifold, ergodic_moves::null_move); result) 35 | { 36 | manifold = result.value(); 37 | // Update Geometry and Foliated_triangulation with new info 38 | manifold.update(); 39 | } 40 | else 41 | { 42 | spdlog::debug("{}", result.error()); 43 | REQUIRE(result.has_value()); 44 | } 45 | THEN("The resulting manifold is valid and unchanged.") 46 | { 47 | CHECK(manifold.is_valid()); 48 | CHECK_EQ(manifold_before.simplices(), manifold.simplices()); 49 | CHECK_EQ(manifold_before.faces(), manifold.faces()); 50 | CHECK_EQ(manifold_before.edges(), manifold.edges()); 51 | CHECK_EQ(manifold_before.vertices(), manifold.vertices()); 52 | // Human verification 53 | fmt::print("Old manifold.\n"); 54 | manifold_before.print_details(); 55 | fmt::print("New manifold after null move:\n"); 56 | manifold.print_details(); 57 | } 58 | } 59 | WHEN("A (2,3) move is applied to the manifold.") 60 | { 61 | spdlog::debug("Applying (2,3) move to manifold.\n"); 62 | if (auto result = apply_move(manifold, ergodic_moves::do_23_move); result) 63 | { 64 | manifold = result.value(); 65 | // Update Geometry and Foliated_triangulation with new info 66 | manifold.update(); 67 | } 68 | else 69 | { 70 | spdlog::debug("{}", result.error()); 71 | REQUIRE(result.has_value()); 72 | } 73 | THEN("The resulting manifold has the applied move.") 74 | { 75 | CHECK(ergodic_moves::check_move(manifold_before, manifold, 76 | move_tracker::move_type::TWO_THREE)); 77 | // Human verification 78 | fmt::print("Old manifold.\n"); 79 | manifold_before.print_details(); 80 | fmt::print("New manifold after (2,3) move:\n"); 81 | manifold.print_details(); 82 | } 83 | } 84 | WHEN("A (3,2) move is applied to the manifold.") 85 | { 86 | spdlog::debug("Applying (3,2) move to manifold.\n"); 87 | if (auto result = apply_move(manifold, ergodic_moves::do_32_move); result) 88 | { 89 | manifold = result.value(); 90 | // Update Geometry and Foliated_triangulation with new info 91 | manifold.update(); 92 | } 93 | else 94 | { 95 | spdlog::debug("{}", result.error()); 96 | // Stop further tests 97 | REQUIRE(result.has_value()); 98 | } 99 | THEN("The resulting manifold has the applied move.") 100 | { 101 | CHECK(ergodic_moves::check_move(manifold_before, manifold, 102 | move_tracker::move_type::THREE_TWO)); 103 | // Human verification 104 | fmt::print("Old manifold.\n"); 105 | manifold_before.print_details(); 106 | fmt::print("New manifold after (3,2) move:\n"); 107 | manifold.print_details(); 108 | } 109 | } 110 | WHEN("A (2,6) move is applied to the manifold.") 111 | { 112 | spdlog::debug("Applying (2,6) move to manifold.\n"); 113 | if (auto result = apply_move(manifold, ergodic_moves::do_26_move); result) 114 | { 115 | manifold = result.value(); 116 | // Update Geometry and Foliated_triangulation with new info 117 | manifold.update(); 118 | } 119 | else 120 | { 121 | spdlog::debug("{}", result.error()); 122 | // Stop further tests 123 | REQUIRE(result.has_value()); 124 | } 125 | THEN("The resulting manifold has the applied move.") 126 | { 127 | CHECK(ergodic_moves::check_move(manifold_before, manifold, 128 | move_tracker::move_type::TWO_SIX)); 129 | // Human verification 130 | fmt::print("Old manifold.\n"); 131 | manifold_before.print_details(); 132 | fmt::print("New manifold after (2,6) move:\n"); 133 | manifold.print_details(); 134 | } 135 | } 136 | WHEN("A (6,2) move is applied to the manifold.") 137 | { 138 | spdlog::debug("Applying (6,2) move to manifold.\n"); 139 | auto result = apply_move(manifold, ergodic_moves::do_62_move); 140 | if (result) 141 | { 142 | manifold = result.value(); 143 | // Update Geometry and Foliated_triangulation with new info 144 | manifold.update(); 145 | THEN("The resulting manifold has the applied move.") 146 | { 147 | CHECK(ergodic_moves::check_move(manifold_before, manifold, 148 | move_tracker::move_type::SIX_TWO)); 149 | // Human verification 150 | fmt::print("Old manifold.\n"); 151 | manifold_before.print_details(); 152 | fmt::print("New manifold after (6,2) move:\n"); 153 | manifold.print_details(); 154 | } 155 | } 156 | else 157 | { 158 | spdlog::warn("Cannot apply (6,2) move: {}", result.error()); 159 | doctest::skip("No valid (6,2) move exists in this manifold configuration."); 160 | } 161 | } 162 | WHEN("A (4,4) move is applied to the manifold.") 163 | { 164 | spdlog::debug("Applying (4,4) move to manifold.\n"); 165 | if (auto result = apply_move(manifold, ergodic_moves::do_44_move); result) 166 | { 167 | manifold = result.value(); 168 | // Update Geometry and Foliated_triangulation with new info 169 | manifold.update(); 170 | } 171 | else 172 | { 173 | spdlog::debug("{}", result.error()); 174 | // Stop further tests 175 | REQUIRE(result.has_value()); 176 | } 177 | THEN("The resulting manifold has the applied move.") 178 | { 179 | CHECK(ergodic_moves::check_move(manifold_before, manifold, 180 | move_tracker::move_type::FOUR_FOUR)); 181 | // Human verification 182 | fmt::print("Old manifold.\n"); 183 | manifold_before.print_details(); 184 | fmt::print("New manifold after (4,4) move:\n"); 185 | manifold.print_details(); 186 | } 187 | } 188 | } 189 | } -------------------------------------------------------------------------------- /tests/Move_tracker_test.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2021 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file Move_tracker_test.cpp 8 | /// @brief Tests of MoveTracker, that is, that moves are tracked properly 9 | /// @author Adam Getchell 10 | 11 | #include "Move_tracker.hpp" 12 | 13 | #include 14 | 15 | #include "Manifold.hpp" 16 | 17 | using namespace std; 18 | using namespace manifolds; 19 | using namespace move_tracker; 20 | 21 | SCENARIO("MoveTracker special members" * doctest::test_suite("move_tracker")) 22 | { 23 | spdlog::debug("MoveTracker special members.\n"); 24 | GIVEN("A MoveTracker.") 25 | { 26 | WHEN("It's properties are examined.") 27 | { 28 | THEN("It is no-throw destructible.") 29 | { 30 | REQUIRE(is_nothrow_destructible_v>); 31 | spdlog::debug("It is no-throw destructible.\n"); 32 | } 33 | THEN("It is no-throw default constructible.") 34 | { 35 | REQUIRE(is_nothrow_default_constructible_v>); 36 | spdlog::debug("It is no-throw default constructible.\n"); 37 | } 38 | THEN("It is copy constructible.") 39 | { 40 | REQUIRE(is_copy_constructible_v>); 41 | spdlog::debug("It is copy constructible.\n"); 42 | } 43 | THEN("It is copy assignable.") 44 | { 45 | REQUIRE(is_copy_assignable_v>); 46 | spdlog::debug("It is copy assignable.\n"); 47 | } 48 | THEN("It is no-throw move constructible.") 49 | { 50 | REQUIRE(is_nothrow_move_constructible_v>); 51 | spdlog::debug("Small function optimization supported."); 52 | spdlog::debug("It is no-throw move constructible.\n"); 53 | } 54 | THEN("It is no-throw move assignable.") 55 | { 56 | REQUIRE(is_nothrow_move_assignable_v>); 57 | spdlog::debug("It is no-throw move assignable.\n"); 58 | } 59 | THEN("It is no-throw swappable") 60 | { 61 | REQUIRE(is_nothrow_swappable_v>); 62 | spdlog::debug("It is no-throw swappable.\n"); 63 | } 64 | } 65 | } 66 | } 67 | 68 | SCENARIO("Move type to integer conversion" * 69 | doctest::test_suite("move_tracker")) 70 | { 71 | spdlog::debug("Move type to integer conversion.\n"); 72 | GIVEN("A move type.") 73 | { 74 | auto move23 = move_type::TWO_THREE; 75 | REQUIRE_EQ(as_integer(move23), 0); 76 | auto move32 = move_type::THREE_TWO; 77 | REQUIRE_EQ(as_integer(move32), 1); 78 | auto move26 = move_type::TWO_SIX; 79 | REQUIRE_EQ(as_integer(move26), 2); 80 | auto move62 = move_type::SIX_TWO; 81 | REQUIRE_EQ(as_integer(move62), 3); 82 | auto move44 = move_type::FOUR_FOUR; 83 | REQUIRE_EQ(as_integer(move44), 4); 84 | } 85 | } 86 | 87 | SCENARIO("Integer to move type conversion" * 88 | doctest::test_suite("move_tracker")) 89 | { 90 | spdlog::debug("Integer to move type conversion.\n"); 91 | GIVEN("An integer.") 92 | { 93 | auto move_choice = 0; 94 | REQUIRE_EQ(as_move(move_choice), move_type::TWO_THREE); 95 | move_choice = 1; 96 | REQUIRE_EQ(as_move(move_choice), move_type::THREE_TWO); 97 | move_choice = 2; 98 | REQUIRE_EQ(as_move(move_choice), move_type::TWO_SIX); 99 | move_choice = 3; 100 | REQUIRE_EQ(as_move(move_choice), move_type::SIX_TWO); 101 | move_choice = 4; 102 | REQUIRE_EQ(as_move(move_choice), move_type::FOUR_FOUR); 103 | } 104 | } 105 | 106 | SCENARIO("MoveTracker functionality" * doctest::test_suite("move_tracker")) 107 | { 108 | spdlog::debug("MoveTracker functionality.\n"); 109 | GIVEN("A 3D Move_tracker.") 110 | { 111 | MoveTracker tracked_moves; 112 | THEN("There are the correct number of elements.") 113 | { 114 | REQUIRE_EQ(tracked_moves.size(), NUMBER_OF_3D_MOVES); 115 | } 116 | THEN("Each element is zero-initialized.") 117 | { 118 | REQUIRE_EQ(tracked_moves.total(), 0); 119 | } 120 | THEN("Moves can be added.") 121 | { 122 | // Add +1 to each move 123 | tracked_moves.two_three_moves()++; 124 | tracked_moves.three_two_moves()++; 125 | tracked_moves.two_six_moves()++; 126 | tracked_moves.six_two_moves()++; 127 | tracked_moves.four_four_moves()++; 128 | // Now check that it's added 129 | for (auto move : tracked_moves.moves_view()) { REQUIRE_EQ(move, 1); } 130 | } 131 | THEN("Two move trackers can be added.") 132 | { 133 | // Add +1 move to left-hand side 134 | tracked_moves.two_three_moves() += 1; 135 | tracked_moves.three_two_moves() += 1; 136 | tracked_moves.two_six_moves() += 1; 137 | tracked_moves.six_two_moves() += 1; 138 | tracked_moves.four_four_moves() += 1; 139 | MoveTracker added_moves; 140 | added_moves.two_three_moves() += 2; 141 | added_moves.three_two_moves() += 2; 142 | added_moves.two_six_moves() += 2; 143 | added_moves.six_two_moves() += 2; 144 | added_moves.four_four_moves() += 2; 145 | // Add the MoveTrackers 146 | tracked_moves += added_moves; 147 | 148 | // Now check 149 | for (auto move : tracked_moves.moves_view()) { REQUIRE_EQ(move, 3); } 150 | } 151 | } 152 | GIVEN("A 4D Move_tracker.") 153 | { 154 | MoveTracker tracked_moves; 155 | THEN("There are the correct number of elements.") 156 | { 157 | REQUIRE_EQ(tracked_moves.size(), NUMBER_OF_4D_MOVES); 158 | } 159 | THEN("Each element is zero-initialized.") 160 | { 161 | REQUIRE_EQ(tracked_moves.total(), 0); 162 | } 163 | THEN("Moves can be added.") 164 | { 165 | // Add +1 to each move 166 | tracked_moves.two_four_moves()++; 167 | tracked_moves.four_two_moves()++; 168 | tracked_moves.three_three_moves()++; 169 | tracked_moves.four_six_moves()++; 170 | tracked_moves.six_four_moves()++; 171 | tracked_moves.two_eight_moves()++; 172 | tracked_moves.eight_two_moves()++; 173 | for (auto move : tracked_moves.moves_view()) { REQUIRE_EQ(move, 1); } 174 | } 175 | THEN("Two move trackers can be added.") 176 | { 177 | // Add +1 move to left-hand side 178 | tracked_moves.two_four_moves() += 1; 179 | tracked_moves.four_two_moves() += 1; 180 | tracked_moves.three_three_moves() += 1; 181 | tracked_moves.four_six_moves() += 1; 182 | tracked_moves.six_four_moves() += 1; 183 | tracked_moves.two_eight_moves() += 1; 184 | tracked_moves.eight_two_moves() += 1; 185 | MoveTracker added_moves; 186 | added_moves.two_four_moves() += 2; 187 | added_moves.four_two_moves() += 2; 188 | added_moves.three_three_moves() += 2; 189 | added_moves.four_six_moves() += 2; 190 | added_moves.six_four_moves() += 2; 191 | added_moves.two_eight_moves() += 2; 192 | added_moves.eight_two_moves() += 2; 193 | // Add the Move_trackers 194 | tracked_moves += added_moves; 195 | 196 | // Now check 197 | for (auto move : tracked_moves.moves_view()) { REQUIRE_EQ(move, 3); } 198 | } 199 | } 200 | } -------------------------------------------------------------------------------- /tests/Geometry_test.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2018 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file Geometry_test.cpp 8 | /// @brief Tests of new geometry data structure 9 | /// @author Adam Getchell 10 | 11 | #include "Geometry.hpp" 12 | 13 | #include 14 | 15 | using namespace std; 16 | using namespace foliated_triangulations; 17 | 18 | SCENARIO("Geometry special member and swap properties" * 19 | doctest::test_suite("geometry")) 20 | { 21 | spdlog::debug("Geometry special member and swap properties.\n"); 22 | GIVEN("A 3-dimensional geometry.") 23 | { 24 | WHEN("Special members are examined.") 25 | { 26 | THEN("It is trivially destructible.") 27 | { 28 | REQUIRE(is_trivially_destructible_v); 29 | spdlog::debug("It is trivially destructible.\n"); 30 | } 31 | THEN("It is no-throw default constructible.") 32 | { 33 | REQUIRE(is_nothrow_default_constructible_v); 34 | spdlog::debug("It is no-throw default constructible.\n"); 35 | } 36 | THEN("It is no-throw copy constructible.") 37 | { 38 | REQUIRE(is_nothrow_copy_constructible_v); 39 | spdlog::debug("It is no-throw copy constructible.\n"); 40 | } 41 | THEN("It is no-throw copy assignable.") 42 | { 43 | REQUIRE(is_nothrow_copy_assignable_v); 44 | spdlog::debug("It is no-throw copy assignable.\n"); 45 | } 46 | THEN("It is no-throw move constructible.") 47 | { 48 | REQUIRE(is_nothrow_move_constructible_v); 49 | spdlog::debug("It is no-throw move constructible.\n"); 50 | } 51 | THEN("It is no-throw move assignable.") 52 | { 53 | REQUIRE(is_nothrow_move_assignable_v); 54 | spdlog::debug("It is no-throw move assignable.\n"); 55 | } 56 | THEN("It is no-throw swappable.") 57 | { 58 | REQUIRE(is_nothrow_swappable_v); 59 | spdlog::debug("It is no-throw swappable.\n"); 60 | } 61 | } 62 | } 63 | } 64 | 65 | SCENARIO("3-Geometry classification" * doctest::test_suite("geometry")) 66 | { 67 | spdlog::debug("3-Geometry classification.\n"); 68 | GIVEN("A small 3-dimensional geometry.") 69 | { 70 | WHEN("It is constructed with a Delaunay triangulation.") 71 | { 72 | auto constexpr desired_simplices = 72; 73 | auto constexpr desired_timeslices = 3; 74 | FoliatedTriangulation_3 const triangulation(desired_simplices, 75 | desired_timeslices); 76 | Geometry_3 geometry(triangulation); 77 | THEN("The Delaunay triangulation is described by the geometry.") 78 | { 79 | fmt::print("There are {} simplices ...\n", geometry.N3); 80 | fmt::print( 81 | "There are {} (3,1) simplices and {} (2,2) simplices and {} (1,3) " 82 | "simplices.\n", 83 | geometry.N3_31, geometry.N3_22, geometry.N3_13); 84 | CHECK_GT(geometry.N3, 2); 85 | CHECK_EQ(geometry.N3, static_cast( 86 | triangulation.number_of_finite_cells())); 87 | CHECK_EQ(geometry.N3_31, static_cast( 88 | triangulation.get_three_one().size())); 89 | CHECK_EQ(geometry.N3_13, static_cast( 90 | triangulation.get_one_three().size())); 91 | CHECK_EQ(geometry.N3_31 + geometry.N3_22 + geometry.N3_13, geometry.N3); 92 | CHECK_EQ(geometry.N3_22, static_cast( 93 | triangulation.get_two_two().size())); 94 | CHECK_EQ(geometry.N2, static_cast( 95 | triangulation.number_of_finite_facets())); 96 | CHECK_EQ(geometry.N1, static_cast( 97 | triangulation.number_of_finite_edges())); 98 | CHECK_NE(geometry.N1_TL, 0); 99 | CHECK_NE(geometry.N1_SL, 0); 100 | CHECK_EQ(geometry.N1, geometry.N1_TL + geometry.N1_SL); 101 | CHECK_EQ(geometry.N0, static_cast( 102 | triangulation.number_of_vertices())); 103 | 104 | // Human verification 105 | fmt::print("There are {} edges.\n", geometry.N1); 106 | fmt::print("There are {} timelike edges and {} spacelike edges.\n", 107 | geometry.N1_TL, geometry.N1_SL); 108 | #ifndef NDEBUG 109 | triangulation.print_cells(); 110 | triangulation.print_edges(); 111 | #endif 112 | fmt::print( 113 | "There are {} vertices with a max timevalue of {} and a min " 114 | "timevalue of {}.\n", 115 | geometry.N0, triangulation.max_time(), triangulation.min_time()); 116 | triangulation.print_volume_per_timeslice(); 117 | } 118 | } 119 | } 120 | } 121 | 122 | SCENARIO("3-Geometry initialization" * doctest::test_suite("geometry")) 123 | { 124 | spdlog::debug("3-Geometry initialization.\n"); 125 | GIVEN("A 3-dimensional geometry.") 126 | { 127 | WHEN("It is default constructed.") 128 | { 129 | THEN("All data members are zero-initialized.") 130 | { 131 | Geometry_3 constexpr geometry; 132 | REQUIRE_EQ(geometry.N3, 0); 133 | REQUIRE_EQ(geometry.N3_31, 0); 134 | REQUIRE_EQ(geometry.N3_13, 0); 135 | REQUIRE_EQ(geometry.N3_22, 0); 136 | REQUIRE_EQ(geometry.N2, 0); 137 | REQUIRE_EQ(geometry.N1, 0); 138 | REQUIRE_EQ(geometry.N1_TL, 0); 139 | REQUIRE_EQ(geometry.N1_SL, 0); 140 | REQUIRE_EQ(geometry.N0, 0); 141 | } 142 | } 143 | WHEN("It is constructed with a triangulation.") 144 | { 145 | auto constexpr desired_simplices = 640; 146 | auto constexpr desired_timeslices = 4; 147 | FoliatedTriangulation_3 const triangulation(desired_simplices, 148 | desired_timeslices); 149 | Geometry_3 const geometry(triangulation); 150 | THEN( 151 | "The properties of the Delaunay triangulation are saved in geometry " 152 | "info.") 153 | { 154 | CHECK_EQ(geometry.N3, static_cast( 155 | triangulation.number_of_finite_cells())); 156 | CHECK_EQ(geometry.N3_31, static_cast( 157 | triangulation.get_three_one().size())); 158 | CHECK_EQ(geometry.N3_13, static_cast( 159 | triangulation.get_one_three().size())); 160 | CHECK_EQ(geometry.N3_31 + geometry.N3_22 + geometry.N3_13, geometry.N3); 161 | CHECK_EQ(geometry.N3_22, static_cast( 162 | triangulation.get_two_two().size())); 163 | CHECK_EQ(geometry.N2, static_cast( 164 | triangulation.number_of_finite_facets())); 165 | CHECK_EQ(geometry.N1, static_cast( 166 | triangulation.number_of_finite_edges())); 167 | CHECK_NE(geometry.N1_TL, 0); 168 | CHECK_NE(geometry.N1_SL, 0); 169 | CHECK_EQ(geometry.N1_TL + geometry.N1_SL, geometry.N1); 170 | CHECK_EQ(geometry.N0, static_cast( 171 | triangulation.number_of_vertices())); 172 | triangulation.print(); 173 | triangulation.print_volume_per_timeslice(); 174 | } 175 | } 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /tests/Metropolis_test.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2021 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file Metropolis_test.cpp 8 | /// @brief Tests for the Metropolis-Hastings algorithm 9 | /// @author Adam Getchell 10 | 11 | #include "Metropolis.hpp" 12 | 13 | #include 14 | 15 | using namespace std; 16 | using namespace manifolds; 17 | 18 | SCENARIO("MoveStrategy special member and swap properties" * 19 | doctest::test_suite("metropolis")) 20 | { 21 | spdlog::debug( 22 | "MoveStrategy special member and swap properties.\n"); 23 | GIVEN("A Metropolis move strategy.") 24 | { 25 | WHEN("Special members are examined.") 26 | { 27 | THEN("It is no-throw destructible.") 28 | { 29 | REQUIRE(is_nothrow_destructible_v); 30 | REQUIRE(is_nothrow_destructible_v); 31 | spdlog::debug("It is no-throw destructible.\n"); 32 | } 33 | THEN("It is no-throw default constructible.") 34 | { 35 | REQUIRE(is_nothrow_default_constructible_v); 36 | REQUIRE(is_nothrow_default_constructible_v); 37 | spdlog::debug("It is no-throw default constructible.\n"); 38 | } 39 | THEN("It is no-throw copy constructible.") 40 | { 41 | REQUIRE(is_nothrow_copy_constructible_v); 42 | REQUIRE(is_nothrow_copy_constructible_v); 43 | spdlog::debug("It is no-throw copy constructible.\n"); 44 | } 45 | THEN("It is no-throw copy assignable.") 46 | { 47 | REQUIRE(is_nothrow_copy_assignable_v); 48 | REQUIRE(is_nothrow_copy_assignable_v); 49 | spdlog::debug("It is no-throw copy assignable.\n"); 50 | } 51 | THEN("It is no-throw move constructible.") 52 | { 53 | REQUIRE(is_nothrow_move_constructible_v); 54 | REQUIRE(is_nothrow_move_constructible_v); 55 | spdlog::debug("It is no-throw move constructible.\n"); 56 | } 57 | THEN("It is no-throw move assignable.") 58 | { 59 | REQUIRE(is_nothrow_move_assignable_v); 60 | REQUIRE(is_nothrow_move_assignable_v); 61 | spdlog::debug("It is no-throw move assignable.\n"); 62 | } 63 | THEN("It is no-throw swappable.") 64 | { 65 | REQUIRE(is_nothrow_swappable_v); 66 | REQUIRE(is_nothrow_swappable_v); 67 | spdlog::debug("It is no-throw swappable.\n"); 68 | } 69 | THEN("It is constructible from 5 parameters.") 70 | { 71 | REQUIRE(is_constructible_v); 73 | REQUIRE(is_constructible_v); 75 | spdlog::debug("It is constructible from 5 parameters.\n"); 76 | } 77 | } 78 | } 79 | } 80 | 81 | SCENARIO("Metropolis member functions" * doctest::test_suite("metropolis")) 82 | { 83 | auto constexpr Alpha = static_cast(0.6); 84 | auto constexpr K = static_cast(1.1); // NOLINT 85 | auto constexpr Lambda = static_cast(0.1); 86 | GIVEN("A correctly-constructed Manifold_3.") 87 | { 88 | auto constexpr simplices = 640; 89 | auto constexpr timeslices = 4; 90 | Manifold_3 const universe(simplices, timeslices); 91 | // It is correctly constructed 92 | REQUIRE(universe.is_correct()); 93 | WHEN("A Metropolis function object is constructed.") 94 | { 95 | auto constexpr output_every_n_passes = 1; 96 | auto constexpr passes = 10; 97 | Metropolis_3 testrun(Alpha, K, Lambda, passes, output_every_n_passes); 98 | THEN("The Metropolis function object is initialized correctly.") 99 | { 100 | CHECK_EQ(testrun.Alpha(), Alpha); 101 | CHECK_EQ(testrun.K(), K); 102 | CHECK_EQ(testrun.Lambda(), Lambda); 103 | CHECK_EQ(testrun.passes(), passes); 104 | CHECK_EQ(testrun.checkpoint(), output_every_n_passes); 105 | CHECK_EQ(testrun.get_proposed().total(), 0); 106 | CHECK_EQ(testrun.get_accepted().total(), 0); 107 | CHECK_EQ(testrun.get_rejected().total(), 0); 108 | CHECK_EQ(testrun.get_attempted().total(), 0); 109 | CHECK_EQ(testrun.get_succeeded().total(), 0); 110 | CHECK_EQ(testrun.get_failed().total(), 0); 111 | } 112 | THEN("The initial moves are made correctly.") 113 | { 114 | auto result = testrun.initialize(universe); 115 | auto total_rejected = testrun.get_rejected().total(); 116 | auto total_attempted = testrun.get_attempted().total(); 117 | auto total_successful = testrun.get_succeeded().total(); 118 | auto total_failed = testrun.get_failed().total(); 119 | // Initialization proposes one move of each type 120 | for (auto i = 0; i < move_tracker::NUMBER_OF_3D_MOVES; ++i) 121 | { 122 | CHECK_EQ(testrun.get_proposed()[i], 1); 123 | } 124 | // Initialization accepts one move of each type 125 | for (auto i = 0; i < move_tracker::NUMBER_OF_3D_MOVES; ++i) 126 | { 127 | CHECK_EQ(testrun.get_accepted()[i], 1); 128 | } 129 | // Initialization does not reject any moves 130 | CHECK_EQ(total_rejected, 0); 131 | // Initialization attempts one move of each type 132 | for (auto i = 0; i < move_tracker::NUMBER_OF_3D_MOVES; ++i) 133 | { 134 | CHECK_EQ(testrun.get_attempted()[i], 1); 135 | } 136 | CHECK_EQ(total_attempted, total_successful + total_failed); 137 | 138 | // Human verification 139 | REQUIRE_MESSAGE(result, 140 | "The Metropolis function object failed to " 141 | "initialize the universe."); 142 | if (result) 143 | { 144 | result->print_attempts(); 145 | result->print_successful(); 146 | result->print_errors(); 147 | } 148 | } 149 | } 150 | } 151 | } 152 | 153 | SCENARIO("Using the Metropolis algorithm" * doctest::test_suite("metropolis")) 154 | { 155 | auto constexpr Alpha = static_cast(0.6); 156 | auto constexpr K = static_cast(1.1); // NOLINT 157 | auto constexpr Lambda = static_cast(0.1); 158 | GIVEN("A correctly-constructed Manifold_3.") 159 | { 160 | auto constexpr simplices = 640; 161 | auto constexpr timeslices = 4; 162 | Manifold_3 const universe(simplices, timeslices); 163 | // It is correctly constructed 164 | REQUIRE(universe.is_correct()); 165 | WHEN("A Metropolis function object is constructed.") 166 | { 167 | auto constexpr output_every_n_passes = 1; 168 | auto constexpr passes = 1; 169 | Metropolis_3 testrun(Alpha, K, Lambda, passes, output_every_n_passes); 170 | THEN("A lot of moves are done.") 171 | { 172 | auto result = testrun(universe); 173 | // Output 174 | CHECK(result.is_valid()); 175 | AND_THEN("The correct number of moves are attempted.") 176 | { 177 | auto total_proposed = testrun.get_proposed().total(); 178 | auto total_accepted = testrun.get_accepted().total(); 179 | auto total_rejected = testrun.get_rejected().total(); 180 | auto total_attempted = testrun.get_attempted().total(); 181 | auto total_successful = testrun.get_succeeded().total(); 182 | auto total_failed = testrun.get_failed().total(); 183 | // We should have at least a trial move per simplex on average 184 | // per pass, times the number of passes 185 | CHECK_GT(total_proposed, universe.N3() * passes); 186 | CHECK_EQ(total_proposed, total_accepted + total_rejected); 187 | // We should attempt a move for each accepted move 188 | CHECK_EQ(total_attempted, total_accepted); 189 | CHECK_GT(total_successful, 0); 190 | CHECK_GE(total_failed, 0); 191 | CHECK_EQ(total_attempted, total_successful + total_failed); 192 | // Human verification 193 | testrun.print_results(); 194 | } 195 | } 196 | } 197 | } 198 | } -------------------------------------------------------------------------------- /tests/Vertex_test.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2017 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file Vertex_test.cpp 8 | /// @brief Tests on points and vertices in foliated Delaunay triangulations 9 | /// @author Adam Getchell 10 | /// @details Tests for inserting and deleting vertices. 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #include "Manifold.hpp" 18 | 19 | using namespace manifolds; 20 | 21 | static inline auto constexpr RADIUS_2 = 2.0 * std::numbers::inv_sqrt3_v; 22 | 23 | SCENARIO("Point operations" * doctest::test_suite("vertex")) 24 | { 25 | using Point = Point_t<3>; 26 | GIVEN("Some points.") 27 | { 28 | auto const point_1 = Point(0, 0, 0); 29 | auto const point_2 = Point(0, 0.0, 0.0); 30 | auto const point_3 = Point(1, 1, 1); 31 | WHEN("They are compared.") 32 | { 33 | THEN("Similar points are equal.") { REQUIRE_EQ(point_1, point_2); } 34 | THEN("Dissimilar points are not equal.") { REQUIRE_NE(point_1, point_3); } 35 | } 36 | } 37 | } 38 | 39 | SCENARIO("Vertex operations" * doctest::test_suite("vertex")) 40 | { 41 | using Causal_vertices = Causal_vertices_t<3>; 42 | using Manifold = Manifold_3; 43 | using Point = Point_t<3>; 44 | GIVEN("A foliated Delaunay triangulation.") 45 | { 46 | Causal_vertices causal_vertices; 47 | WHEN("A vertex is inserted.") 48 | { 49 | causal_vertices.emplace_back(Point(0, 0, 0), 1); 50 | Manifold const manifold(causal_vertices, 0, 1); 51 | THEN("The vertex is in the manifold.") 52 | { 53 | // auto vertex = manifold.get_vertices(); 54 | auto vertex = manifold.get_vertices_span(); 55 | REQUIRE(manifold.is_vertex(vertex.front())); 56 | } 57 | 58 | THEN("The Delaunay triangulation is valid.") 59 | { 60 | REQUIRE(manifold.is_valid()); 61 | } 62 | 63 | THEN("There is 1 vertex.") { REQUIRE_EQ(manifold.N0(), 1); } 64 | 65 | THEN("There are no edges.") { REQUIRE_EQ(manifold.N1(), 0); } 66 | 67 | THEN("A 1 vertex manifold has dimension 0.") 68 | { 69 | REQUIRE_EQ(manifold.dimensionality(), 0); 70 | } 71 | 72 | THEN("The vertex is valid.") 73 | { 74 | fmt::print("When a causal vertex is inserted, the vertices are:\n"); 75 | manifold.print_vertices(); 76 | CHECK(manifold.get_triangulation().check_all_vertices()); 77 | } 78 | } 79 | 80 | AND_WHEN("Two vertices are inserted.") 81 | { 82 | causal_vertices.emplace_back(Point(0, 0, 0), 1); 83 | causal_vertices.emplace_back(Point(1, 0, 0), 2); 84 | Manifold const manifold(causal_vertices, 0, 1); 85 | 86 | THEN("The vertices are in the manifold.") 87 | { 88 | auto vertex = manifold.get_vertices_span(); 89 | REQUIRE(manifold.is_vertex(vertex.front())); 90 | REQUIRE(manifold.is_vertex(vertex.back())); 91 | } 92 | 93 | THEN("The Delaunay triangulation is valid.") 94 | { 95 | REQUIRE(manifold.is_valid()); 96 | } 97 | 98 | THEN("There are 2 vertices.") { REQUIRE_EQ(manifold.N0(), 2); } 99 | 100 | THEN("There is 1 edge.") { REQUIRE_EQ(manifold.N1(), 1); } 101 | 102 | THEN("There are no faces.") { REQUIRE_EQ(manifold.N2(), 0); } 103 | 104 | THEN("A 2 vertex manifold has dimension 1.") 105 | { 106 | REQUIRE_EQ(manifold.dimensionality(), 1); 107 | } 108 | 109 | THEN("The vertices are valid.") 110 | { 111 | fmt::print("When 2 causal vertices are inserted, the vertices are:\n"); 112 | manifold.print_vertices(); 113 | CHECK(manifold.get_triangulation().check_all_vertices()); 114 | } 115 | } 116 | 117 | AND_WHEN("Three vertices are inserted.") 118 | { 119 | causal_vertices.emplace_back(Point(0, 0, 0), 1); 120 | causal_vertices.emplace_back(Point(1, 0, 0), 2); 121 | causal_vertices.emplace_back(Point(0, 1, 0), 2); 122 | Manifold manifold(causal_vertices, 0, 1); 123 | 124 | THEN("The vertices are in the manifold.") 125 | { 126 | auto vertices = manifold.get_vertices_span(); 127 | auto require = [&manifold](auto& vertex) { 128 | REQUIRE(manifold.is_vertex(vertex)); 129 | }; 130 | std::ranges::for_each(vertices, require); 131 | } 132 | 133 | THEN("The Delaunay triangulation is valid.") 134 | { 135 | REQUIRE(manifold.is_valid()); 136 | } 137 | 138 | THEN("There are 3 vertices.") { REQUIRE_EQ(manifold.N0(), 3); } 139 | 140 | THEN("There are 3 edges.") { REQUIRE_EQ(manifold.N1(), 3); } 141 | 142 | THEN("There is 1 face.") { REQUIRE_EQ(manifold.N2(), 1); } 143 | 144 | THEN("There are no simplices.") { REQUIRE_EQ(manifold.N3(), 0); } 145 | 146 | THEN("A 3 vertex manifold has dimension 2.") 147 | { 148 | REQUIRE_EQ(manifold.dimensionality(), 2); 149 | } 150 | 151 | THEN("The vertices are valid.") 152 | { 153 | fmt::print("When 3 causal vertices are inserted, the vertices are:\n"); 154 | manifold.print_vertices(); 155 | CHECK(manifold.get_triangulation().check_all_vertices()); 156 | } 157 | } 158 | 159 | AND_WHEN("Four vertices are inserted.") 160 | { 161 | causal_vertices.emplace_back(Point(0, 0, 0), 1); 162 | causal_vertices.emplace_back(Point(1, 0, 0), 2); 163 | causal_vertices.emplace_back(Point(0, 1, 0), 2); 164 | causal_vertices.emplace_back(Point(0, 0, 1), 2); 165 | Manifold manifold(causal_vertices, 0, 1); 166 | 167 | THEN("The vertices are in the manifold.") 168 | { 169 | auto vertices = manifold.get_vertices_span(); 170 | auto require = [&manifold](auto& vertex) { 171 | REQUIRE(manifold.is_vertex(vertex)); 172 | }; 173 | std::ranges::for_each(vertices, require); 174 | } 175 | 176 | THEN("The Delaunay triangulation is valid.") 177 | { 178 | REQUIRE(manifold.is_valid()); 179 | } 180 | 181 | THEN("There are 4 vertices.") { REQUIRE_EQ(manifold.N0(), 4); } 182 | 183 | THEN("There are 6 edges.") { REQUIRE_EQ(manifold.N1(), 6); } 184 | 185 | THEN("There are 4 faces.") { REQUIRE_EQ(manifold.N2(), 4); } 186 | 187 | THEN("There is a simplex.") { REQUIRE_EQ(manifold.N3(), 1); } 188 | 189 | THEN("A 4 vertex manifold has dimension 3.") 190 | { 191 | REQUIRE_EQ(manifold.dimensionality(), 3); 192 | } 193 | 194 | THEN("The vertices are valid.") 195 | { 196 | fmt::print( 197 | "When 4 causal vertices are inserted, there is a simplex:\n"); 198 | manifold.print_cells(); 199 | CHECK(manifold.get_triangulation().check_all_vertices()); 200 | } 201 | } 202 | 203 | AND_WHEN("Five vertices are inserted.") 204 | { 205 | causal_vertices.emplace_back(Point(0, 0, 0), 1); 206 | causal_vertices.emplace_back(Point(1, 0, 0), 2); 207 | causal_vertices.emplace_back(Point(0, 1, 0), 2); 208 | causal_vertices.emplace_back(Point(0, 0, 1), 2); 209 | causal_vertices.emplace_back(Point(RADIUS_2, RADIUS_2, RADIUS_2), 3); 210 | Manifold manifold(causal_vertices, 0, 1); 211 | 212 | THEN("The vertices are in the manifold.") 213 | { 214 | auto vertices = manifold.get_vertices_span(); 215 | auto require = [&manifold](auto& vertex_candidate) { 216 | REQUIRE(manifold.is_vertex(vertex_candidate)); 217 | }; 218 | std::ranges::for_each(vertices, require); 219 | } 220 | 221 | THEN("The Delaunay triangulation is valid.") 222 | { 223 | REQUIRE(manifold.is_valid()); 224 | } 225 | 226 | THEN("There are 5 vertices.") { REQUIRE_EQ(manifold.N0(), 5); } 227 | 228 | THEN("There are 9 edges.") { REQUIRE_EQ(manifold.N1(), 9); } 229 | 230 | THEN("There are 7 faces.") { REQUIRE_EQ(manifold.N2(), 7); } 231 | 232 | THEN("There are 2 simplexes.") { REQUIRE_EQ(manifold.N3(), 2); } 233 | 234 | THEN("A 5 vertex manifold still has dimension 3.") 235 | { 236 | REQUIRE_EQ(manifold.dimensionality(), 3); 237 | } 238 | 239 | THEN("The vertices are valid.") 240 | { 241 | fmt::print( 242 | "When 5 causal vertices are inserted, there are 2 simplices:\n"); 243 | manifold.print_cells(); 244 | CHECK(manifold.get_triangulation().check_all_vertices()); 245 | } 246 | } 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /include/Move_tracker.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Causal Dynamical Triangulations in C++ using CGAL 3 | 4 | Copyright © 2021 Adam Getchell 5 | ******************************************************************************/ 6 | 7 | /// @file Move_tracker.hpp 8 | /// @brief Track ergodic moves 9 | /// @author Adam Getchell 10 | 11 | #ifndef CDT_PLUSPLUS_MOVE_TRACKER_HPP 12 | #define CDT_PLUSPLUS_MOVE_TRACKER_HPP 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "Settings.hpp" 20 | #include "Utilities.hpp" 21 | 22 | namespace move_tracker 23 | { 24 | static inline Int_precision constexpr NUMBER_OF_3D_MOVES = 5; 25 | static inline Int_precision constexpr NUMBER_OF_4D_MOVES = 7; 26 | 27 | /** 28 | * \brief The types of 3D ergodic moves 29 | */ 30 | enum class [[nodiscard("This contains data!")]] move_type{ 31 | TWO_THREE = 0, THREE_TWO = 1, TWO_SIX = 2, SIX_TWO = 3, FOUR_FOUR = 4}; 32 | 33 | /** 34 | * \brief Convert enum to integer 35 | * \tparam Enumeration The enum type 36 | * \param value The enum 37 | * \return The integer value of the enum 38 | */ 39 | template 40 | auto as_integer(Enumeration value) -> std::underlying_type_t 41 | { 42 | return static_cast>(value); 43 | } // as_integer 44 | 45 | /** 46 | * \brief Convert integer to move_type 47 | * \param move_choice The move choice integer 48 | * \return The move_type 49 | */ 50 | inline auto as_move(int const move_choice) -> move_type 51 | { 52 | if (move_choice == 0) { return move_type::TWO_THREE; } 53 | if (move_choice == 1) { return move_type::THREE_TWO; } 54 | if (move_choice == 2) { return move_type::TWO_SIX; } 55 | if (move_choice == 3) { return move_type::SIX_TWO; } 56 | return move_type::FOUR_FOUR; 57 | } // as_move 58 | 59 | /** 60 | * \brief Generate random 3D ergodic move 61 | * \return The move_type to be performed 62 | */ 63 | [[nodiscard]] inline auto generate_random_move_3() -> move_type 64 | { 65 | auto move_choice = utilities::generate_random_int(0, 4); 66 | #ifndef NDEBUG 67 | fmt::print("Move choice = {}\n", move_choice); 68 | #endif 69 | return as_move(move_choice); 70 | } // generate_random_move_3 71 | 72 | /** 73 | * \brief Determine the ergodic moves for a given dimensionality 74 | * \param dim Dimensionality of the manifold 75 | * \return The number of ergodic moves for that dimensionality 76 | */ 77 | auto constexpr moves_per_dimension(Int_precision const dim) -> Int_precision 78 | { 79 | if (dim == 3) { return NUMBER_OF_3D_MOVES; } 80 | if (dim == 4) { return NUMBER_OF_4D_MOVES; } 81 | return 0; // Error condition 82 | } // moves_per_dimension 83 | 84 | /** 85 | * \brief The data and methods to track ergodic moves 86 | * \tparam ManifoldType The type of manifold on which moves are made 87 | */ 88 | template 89 | class MoveTracker 90 | { 91 | using Container = 92 | std::array; 93 | 94 | Container moves = {0}; // NOLINT 95 | 96 | public: 97 | /** 98 | * \brief Get a view of the moves 99 | * \return Read-only container of moves 100 | */ 101 | auto moves_view() const { return std::span(moves); } 102 | 103 | /** 104 | * \brief The [] operator for MoveTracker 105 | * \param index The index of the element to be accessed 106 | * \return The number of moves at the index 107 | */ 108 | auto operator[](gsl::index index) -> auto& 109 | { 110 | return gsl::at(moves, index); 111 | } // operator[] 112 | 113 | /** 114 | * \brief The [] operator for MoveTracker 115 | * \param move The move type to be accessed 116 | * \return The number of moves of that type 117 | */ 118 | auto operator[](move_type const move) const -> auto& 119 | { 120 | return gsl::at(moves, as_integer(move)); 121 | } // operator[] 122 | 123 | /** 124 | * \brief The += operator for MoveTracker 125 | * \param rhs The MoveTracker to be added 126 | * \return The sum of the individual elements of the MoveTrackers 127 | */ 128 | auto operator+=(MoveTracker const& rhs) 129 | { 130 | for (std::size_t i = 0; i < moves.size(); ++i) 131 | { 132 | moves[i] += rhs.moves[i]; 133 | } 134 | return *this; 135 | } // operator+= 136 | 137 | /** 138 | * \brief Total moves 139 | * \return The total number of moves in the MoveTracker 140 | */ 141 | auto total() const noexcept 142 | { 143 | return std::accumulate(moves.begin(), moves.end(), 0); 144 | } // total 145 | 146 | /** 147 | * \brief Container size 148 | * \return The size of the container of moves 149 | */ 150 | auto size() const noexcept { return moves.size(); } 151 | 152 | // 3D 153 | 154 | /** 155 | * \brief Write access to (2,3) moves 156 | * \return Reference to number of (2,3) moves 157 | */ 158 | auto two_three_moves() -> auto& { return gsl::at(moves, 0); } 159 | 160 | /** 161 | * \brief Read access to (2,3) moves 162 | * \return Value of number of (2,3) moves 163 | */ 164 | auto two_three_moves() const { return gsl::at(moves, 0); } 165 | 166 | /** 167 | * \brief Write access to (3,2) moves 168 | * \return Reference to number of (3,2) moves 169 | */ 170 | auto three_two_moves() -> auto& { return gsl::at(moves, 1); } 171 | 172 | /** 173 | * \brief Read access to (3,2) moves 174 | * \return Value of number of (3,2) moves 175 | */ 176 | auto three_two_moves() const { return gsl::at(moves, 1); } 177 | 178 | /** 179 | * \brief Write access to (2,6) moves 180 | * \return Reference to number of (2,6) moves 181 | */ 182 | auto two_six_moves() -> auto& { return gsl::at(moves, 2); } 183 | 184 | /** 185 | * \brief Read access to (2,6) moves 186 | * \return Value of number of (2,6) moves 187 | */ 188 | auto two_six_moves() const { return gsl::at(moves, 2); } 189 | 190 | /** 191 | * \brief Write access to (6,2) moves 192 | * \return Reference to number of (6,2) moves 193 | */ 194 | auto six_two_moves() -> auto& { return gsl::at(moves, 3); } 195 | 196 | /** 197 | * \brief Read access to (6,2) moves 198 | * \return Value of number of (6,2) moves 199 | */ 200 | auto six_two_moves() const { return gsl::at(moves, 3); } 201 | 202 | /** 203 | * \brief Write access to (4,4) moves 204 | * \return Reference to number of (4,4) moves 205 | */ 206 | auto four_four_moves() -> auto& { return gsl::at(moves, 4); } 207 | 208 | /** 209 | * \brief Read access to (4,4) moves 210 | * \return Value of number of (4,4) moves 211 | */ 212 | auto four_four_moves() const { return gsl::at(moves, 4); } 213 | 214 | // 4D 215 | /// @brief Write access to (2,4) moves 216 | auto two_four_moves() -> auto& { return gsl::at(moves, 0); } 217 | 218 | /// @brief Read access to (2,4) moves 219 | auto two_four_moves() const { return gsl::at(moves, 0); } 220 | 221 | /// @brief Write access to (4,2) moves 222 | auto four_two_moves() -> auto& { return gsl::at(moves, 1); } 223 | 224 | /// @brief Read access to (4,2) moves 225 | auto four_two_moves() const { return gsl::at(moves, 1); } 226 | 227 | /// @brief Write access to (3,3) moves 228 | auto three_three_moves() -> auto& { return gsl::at(moves, 2); } 229 | 230 | /// @brief Read access to (3,3) moves 231 | auto three_three_moves() const { return gsl::at(moves, 2); } 232 | 233 | /// @brief Write access to (4,6) moves 234 | auto four_six_moves() -> auto& { return gsl::at(moves, 3); } 235 | 236 | /// @brief Read access to (4,6) moves 237 | auto four_six_moves() const { return gsl::at(moves, 3); } 238 | 239 | /// @brief Write access to (6,4) moves 240 | auto six_four_moves() -> auto& { return gsl::at(moves, 4); } 241 | 242 | /// @brief Read access to (6,4) moves 243 | auto six_four_moves() const { return gsl::at(moves, 4); } 244 | 245 | /// @brief Write access to (2,8) moves 246 | auto two_eight_moves() -> auto& { return gsl::at(moves, 5); } // NOLINT 247 | 248 | /// @brief Read access to (2,8) moves 249 | auto two_eight_moves() const { return gsl::at(moves, 5); } // NOLINT 250 | 251 | /// @brief Write access to (8,2) moves 252 | auto eight_two_moves() -> auto& { return gsl::at(moves, 6); } // NOLINT 253 | 254 | /// @brief Read access to (8,2) moves 255 | auto eight_two_moves() const { return gsl::at(moves, 6); } // NOLINT 256 | 257 | /// @brief Reset all moves counts to zero 258 | void reset() { moves.fill(0); } 259 | }; 260 | 261 | } // namespace move_tracker 262 | 263 | #endif // CDT_PLUSPLUS_MOVE_TRACKER_HPP 264 | --------------------------------------------------------------------------------