Skip to content

acgetchell/CDT-plusplus

Repository files navigation

CDT-plusplus

Quantize spacetime on your laptop.

License CI Documentation codecov

Small foliated Delaunay triangulation

Maintenance status

CDT++ is being prepared for one final C++23 release, v1.0.0, after which this repository will be archived. It is maintained as an independent scientific reference and regression oracle for causal-triangulations, the supported Rust successor. New C++ work is limited to correctness, reproducibility, cross-implementation validation, the complete supported 2+1D move set, and the final release contract tracked by issue #90.

Table of contents

Introduction

For an introduction to Causal Dynamical Triangulations, including the foundations and recent results, please see the wiki.

Causal Dynamical Triangulations in C++ uses the Computational Geometry Algorithms Library, Boost, and TBB. Arbitrary-precision numbers and functions are by MPFR and GMP. Melissa E. O'Neill's Permuted Congruential Generators library provides high-quality RNGs that pass L'Ecuyer's TestU01 statistical tests. doctest provides BDD/TDD. vcpkg provides library management and building. Doxygen provides automated document generation. {fmt} provides a safe and fast alternative to iostream. spdlog provides fast, multithreaded logging. CometML provides experiment tracking for the optional Python workflows.

Regression-oracle scope

The principal reason to preserve this implementation is its causality-filtering Delaunay construction path in include/Foliated_triangulation.hpp. check_timevalues classifies cells from stored vertex time labels, find_bad_vertex selects a vertex responsible for an acausal local configuration, and fix_timevalues removes offending vertices through CGAL so the cavity is retriangulated until the foliation contract is satisfied.

The deterministic doctest scenario "Detecting and fixing problems with vertices and cells" in tests/Foliated_triangulation_test.cpp exercises this path with fixed points and time labels. Its inputs, detected bad vertex, final initialization state, cell counts, and causal classification are the first comparison fixture for causal-triangulations; exact Monte Carlo trajectories are not required to match.

After building, run that fixture directly with:

./out/build/reference/tests/CDT_unit_tests \
  --test-case='*Detecting and fixing problems with vertices and cells*'

Roadmap

  • Cross-platform support on Linux, macOS (x64 & arm64), and Windows
  • Cross-compiler support on gcc, clang, and MSVC
  • Develop with literate programming using Doxygen
  • Efficient Pure Functional Programming in C++ Using Move Semantics
  • Test using CTest
  • Develop using Behavior-driven development (BDD) with doctest
  • Continuous integration by GitHub Actions on the leading edge
  • 3D Simplex
  • 3D Spherical triangulation
  • 2+1 foliation
  • S3 Bulk action
  • 3D Ergodic moves
  • High-quality Random Number Generation with M.E. O'Neill's PCG library
  • Restore optional parallel triangulation with TBB (#74)
  • Automated code analysis with CodeQL
  • Build/debug with Visual Studio 2022
  • Use {fmt} library (instead of iostream)
  • 3D Metropolis algorithm
  • Multithreaded logging with spdlog
  • Restore optional visualization with Qt (#98)
  • Initialize two masses
  • The shortest path algorithm
  • Einstein tensor
  • Complete test coverage
  • Complete documentation
  • Quantize Spacetime!

Quickstart

From a fresh checkout, the primary supported headless build, dependency bootstrap, and test path is:

just build

The build recipe uses the pkgx launcher on Unix when pkgx is available, then delegates to scripts/build.sh. Its first run creates an ignored .cache/vcpkg checkout at the exact builtin-baseline recorded in vcpkg.json, bootstraps vcpkg, installs the manifest dependencies, builds in out/build/reference, and runs the supported CTest smoke suite. The first dependency build can take several minutes; subsequent runs reuse both vcpkg dependencies and CMake/Ninja outputs, so an unchanged build is a no-op apart from configuration and tests.

The optional pkgx entry point supplies the complete Unix developer-tool environment ephemerally and invokes the same build contract directly, without requiring Just:

./scripts/pkgx-build.sh

pkgx does not install CGAL or any other project library; those remain owned by the pinned vcpkg manifest. The underlying ./scripts/build.sh and scripts\build.bat entry points remain available for troubleshooting and native Windows development.

Current reference-suite status

With the pinned baseline, the reference configuration and build succeed on macOS with AppleClang. build.sh runs eleven supported smoke tests on Unix: nine lightweight CLI integration tests and two focused doctest suites. The known failing initialize scenario is excluded from Windows smoke runs, while the other initialization cases remain enabled. The complete registered suite additionally runs the full unit-test executable and a focused utilities registration; the focused registrations remain available for quick iteration and are labeled as full-suite duplicates for sanitizer runs.

Setup

This project uses CMake+Ninja to build C++23 sources and vcpkg manifest mode to manage C++ libraries. macOS with AppleClang is the primary v1.0.0 restoration target; the remaining compiler and platform matrix will be recorded as it is verified.

Prerequisites

The smallest pkgx-assisted host setup is:

  • Xcode Command Line Tools on macOS, or a C++23 compiler and base build environment on Linux
  • pkgx
  • Just when invoking the recipes directly; scripts/pkgx-build.sh does not require it
  • Python 3.12 and uv when checking or running the Python support scripts

The pkgx launcher supplies Git, Bash, CMake, Ninja, Python, M4, Autoconf, Autoconf Archive, Automake, GNU Libtool, Texinfo, and pkg-config. If pkgx is not installed, provide these tools conventionally through a package manager such as Homebrew or apt:

  • Git
  • Bash
  • build-essential (Linux only)
  • m4
  • automake
  • autoconf
  • autoconf-archive
  • libtool (macOS) or libtool-bin (Linux)
  • pkg-config
  • texinfo
  • ninja (macOS) or ninja-build (Linux)

The build does not require a pre-existing personal vcpkg checkout, a fork, a submodule, Docker, or a hosted development environment.

Developer workflow

The repository-root Justfile provides the same small command vocabulary used by the related projects:

just check                 # Fast, non-mutating local checks
just fix                   # Format C++/Python source and the Justfile
just clang-tidy            # Analyze C++ with LLVM 22
just sanitize asan         # Build and exercise one Linux sanitizer preset
just build                 # Bootstrap, configure, build, and smoke-test
just run --help            # Build as needed and run cdt with forwarded arguments
just ci                    # Comprehensive pre-commit/pre-push validation
just update-actions        # Update and repin Actions with pinact, then validate
just python-sync           # Install the locked Ruff and ty development environment
just python-check          # Check Python formatting, lint, and types
just python-fix            # Apply safe Ruff fixes and formatting

check covers repository-wide C++ formatting, Python formatting/lint/type checks, YAML, GitHub Actions syntax and security, whitespace, and CMake preset parsing. ci adds the pinact policy check and the supported build/test contract. Install the developer tools with Homebrew, use equivalent system packages, or let pkgx supply them ephemerally; pkgx remains optional. For example:

pkgx +just.systems +git-scm.org +cmake.org +ninja-build.org +python.org +llvm.org@22 \
  +yamllint +actionlint +zizmor just check

pinact uses .pinact.yaml to retain immutable action SHAs, readable release comments, and a seven-day release cooldown. just update-actions uses an installed pinact or a pkgx-provided Go fallback, then requires yamllint, actionlint, and zizmor to pass.

vcpkg maintenance

vcpkg.json is the dependency source of truth. Its builtin-baseline pins the official microsoft/vcpkg registry commit used locally and in CI. The repository-local .cache/vcpkg checkout is disposable tool/cache infrastructure and must not be edited or committed.

To update dependencies intentionally, bootstrap the current checkout, run the vcpkg baseline updater, review the manifest diff, and then rerun the complete build:

./scripts/bootstrap-vcpkg.sh
export VCPKG_ROOT="$PWD/.cache/vcpkg"
"$VCPKG_ROOT/vcpkg" x-update-baseline
./scripts/build.sh

CI uses lukka/run-vcpkg, which derives the vcpkg checkout commit from the same manifest baseline and supplies a binary cache. No separately maintained repository variable is required.

Build

Run just build from the repository root. It delegates to ./scripts/build.sh, which can itself be run from any working directory for troubleshooting. If VCPKG_ROOT already names the clean official checkout at the manifest baseline, the script respects it; otherwise it uses the pinned disposable checkout described above. The script invokes the reference configure and build presets followed by the reference-smoke test preset; products and tests are isolated under out/build/reference. Windows uses the same presets through scripts\build.bat, while scripts\fast-build.bat configures the same reference tree and builds only the primary cdt target. All entry points preserve a compatible CMake cache and refresh it only when the selected vcpkg toolchain path changes.

Project Layout

The project is similar to PitchFork Layout, as follows:

  • .github - GitHub specific settings
  • out/build/reference - Ephemeral supported headless build directory
  • cmake - Cmake configurations
  • docs - Documentation
  • external - Includes submodules of external projects (none so far, all using vcpkg)
  • include - Header files
  • scripts - Build, test, and run scripts
  • src - Source files
  • tests - Unit tests

Run

The supported build produces cdt and initialize in out/build/reference/src. Run the primary cdt executable through Just and pass its arguments after the recipe name:

just run --help

For troubleshooting, the equivalent direct command is ./out/build/reference/src/cdt --help.

Use --no-output for batch, debugging, or scripted runs that should print results without writing checkpoint or final triangulation files:

just run -s -n256 -t4 -a0.6 -k1.1 -l0.1 -p10 -c10 --no-output

Usage

CDT-plusplus uses program_options to parse options from the help message, and so understands long or short argument formats, provided the short argument given is an unambiguous match to a longer one. The help message should be instructive:

./out/build/reference/src/cdt --help
Causal Dynamical Triangulations in C++ using CGAL.

Copyright (c) 2013-2026 Adam Getchell

A program that generates d-dimensional triangulated spacetimes
with a defined causal structure and evolves them according
to the Metropolis algorithm. Specify the number of passes to control
how much evolution is desired. Each pass attempts a number of ergodic
moves equal to the number of simplices in the simulation.

Usage:./cdt (--spherical | --toroidal) -n SIMPLICES -t TIMESLICES
            [-d DIM]
            [--init INITIAL RADIUS]
            [--foliate FOLIATION SPACING]
            [--no-output]
            -k K
            --alpha ALPHA
            --lambda LAMBDA
            [-p PASSES]
            [-c CHECKPOINT]

Optional arguments are in square brackets.

Examples:
./cdt --spherical -n 32000 -t 11 --alpha 0.6 -k 1.1 --lambda 0.1 --passes 1000
./cdt -s -n32000 -t11 -a.6 -k1.1 -l.1 -p1000

Options:
  -h [ --help ]                 Show this message
  -v [ --version ]              Show program version
  -s [ --spherical ]            Spherical topology
  -e [ --toroidal ]             Toroidal topology
  -n [ --simplices ] arg        Approximate number of simplices
  -t [ --timeslices ] arg       Number of timeslices
  -d [ --dimensions ] arg (=3)  Dimensionality
  -i [ --init ] arg (=1)        Initial radius
  -f [ --foliate ] arg (=1)     Foliation spacing
  --no-output                   Do not write checkpoint or final triangulation
                                files
  -a [ --alpha ] arg            Negative squared geodesic length of 1-d
                                timelike edges
  -k [ --k ] arg                K = 1/(8*pi*G_newton)
  -l [ --lambda ] arg           K * Cosmological constant
  -p [ --passes ] arg (=100)    Number of passes
  -c [ --checkpoint ] arg (=10) Checkpoint every n passes

The dimensionality of the spacetime is such that each slice of spacetime is d-1-dimensional, so setting d=3 generates two spacelike dimensions and one timelike dimension, with a defined global time foliation. A d-dimensional simplex will have some d-1 sub-simplices that are purely spacelike (all on the same timeslice) as well as some that are timelike (span two timeslices). In CDT we actually care more about the timelike links (in 2+1 spacetime), and the timelike faces (in 3+1 spacetime).

Documentation

Online documentation is at https://adamgetchell.org/CDT-plusplus/.

If you have Doxygen installed you can generate the same information locally using the configuration file in docs/Doxyfile by simply typing at the top level directory (Doxygen will recursively search):

doxygen ./docs/Doxyfile

This will generate a docs/html/ directory containing documentation generated from CDT++ source files. USE_MATHJAX has been enabled in Doxyfile so that the LaTeX formulae can be rendered in the HTML documentation using MathJax. HAVE_DOT is set to YES which allows various graphs to be autogenerated by Doxygen using GraphViz. If you do not have GraphViz installed, set this option to NO (along with UML_LOOK).

Testing

Run just build; it delegates to ./scripts/build.sh, builds the test target, and executes the 22 supported smoke tests. These include two focused doctest runs for the Boost.Compat function_ref migration and causal-foliation construction, plus 20 executable integration tests covering normal CLI use and invalid-boundary rejection. Run just ci for the complete local validation gate.

The doctest executable can also be run directly:

./out/build/reference/tests/CDT_unit_tests

To rerun the supported smoke suite without rebuilding:

ctest --preset reference-smoke

To run every currently registered test, including the full unit-test executable and focused duplicate registrations, bypass the smoke filter explicitly:

ctest --test-dir out/build/reference --output-on-failure

In addition to the command line output, you can see detailed results in the out/build/reference/Testing directory generated by CTest.

Static Analysis

Python 3.12 is selected by .python-version, uv locks the environment in uv.lock, Ruff owns Python formatting and linting, and ty owns static type checking. Run just python-sync once and then use just python-check or just python-fix; both commands are also part of the repository-wide validation recipes.

This project follows the CppCore Guidelines as enforced by ClangTidy. The repository pins LLVM 22; run Clang-Tidy through its Just recipe:

just clang-tidy

(Or use your favorite linter plugin for your editor/IDE.)

Sanitizers

AddressSanitizer + UndefinedBehaviorSanitizer, LeakSanitizer, MemorySanitizer, and ThreadSanitizer share the repository-owned Linux driver and CMake presets. Run one locally with just sanitize asan, just sanitize lsan, just sanitize msan, or just sanitize tsan; the GitHub Actions workflows invoke the same commands. MemorySanitizer remains experimental because third-party dependencies are not instrumented.

Optimizing Parameters

CometML is used to record Experiments conducted by src/optimize-initialize.py; src/test.py is the existing TensorFlow MNIST experiment. These optional, heavyweight dependencies are kept out of the normal lint environment. Synchronize them from the same uv lockfile when working on the experiment scripts:

just python-sync-experiments
uv run --locked --group experiments python src/optimize-initialize.py

Set COMET_API_KEY before starting an online experiment. The experiment results are then available in Comet. Migration of these legacy scripts to Python 3.14, PyTorch, and the current Comet API is tracked by #104.

Visualization

The Qt-based cdt-viewer target is currently disabled. Its opt-in dependency feature, deterministic smoke fixture, supported desktop matrix, and v1.0.0 restoration are tracked by #98; Qt and Eigen are intentionally absent from the default headless build until that work is complete.

Contributing

Please see CONTRIBUTING.md and our CODE_OF_CONDUCT.md.

Your code should pass Continuous Integration:

  • just fix for safe automatic formatting with the repository's .clang-format

  • just clang-tidy to analyze C++ with the pinned LLVM 22 toolchain

  • just check for fast, non-mutating source, YAML, workflow, and CMake validation

  • just ci for the supported build and smoke-test contract before pushing

The slower sanitizer workflows remain available through GitHub Actions and repository commands when relevant to a change:

Valgrind is intentionally unsupported: on x86/AMD64 its floating-point emulation does not honor the directed rounding required by CGAL's interval predicates. Disabling CGAL's rounding check would make geometric results untrustworthy, so memory diagnostics use the supported sanitizer workflows instead.

Optional:

Issues

About

Causal Dynamical Triangulations in C++ using CGAL

Topics

Resources

License

Code of conduct

Contributing

Stars

70 stars

Watchers

9 watching

Forks

Packages

 
 
 

Contributors