This is the canonical end-to-end example for the supported C++23 API. Its source is built as CDT_cpp_api_quickstart in every normal CMake build and run by CTest when ENABLE_TESTING is enabled, so the documentation cannot drift silently away from the public headers.
The example validates raw configuration values before constructing a manifold, splits a fixed root seed into named initialization and transition streams, asks the strategy to sample and resolve ten proposals through the public one-transition Metropolis API. Every proposal prints its move kind, whether candidate construction and validation succeeded, and whether the Metropolis-Hastings criterion accepted and committed it. The existing strategy summary then reports the aggregate proposal and candidate counters.
“Successful” and “accepted” describe different stages. A successful proposal produced a valid candidate; it may still be rejected by Metropolis-Hastings. An accepted proposal is necessarily successful and replaces the canonical state. The one-argument attempt_transition() overload returns both facts in a typed transition report, so callers do not need to infer an individual outcome from aggregate counters.
Finally, the example writes the resulting triangulation with a provenance sidecar. Reading the payload back verifies the sidecar checksum, recorded geometry, and topology fingerprints before the example compares the finite simplex counts. Because the one-transition API does not complete a configured move pass, the artifact records zero completed passes and a transition-trace count of ten. Its optional configured_attempts=10 field identifies the explicit one-step execution plan independently of the pass cadence retained by the strategy.
After Pachner evolution, the canonical state is required to preserve the CGAL triangulation data structure and CDT causal manifold invariants. A bistellar flip is not required to preserve CGAL's geometric Delaunay predicate, so the round-trip check deliberately tests tds().is_valid() rather than Delaunay_t<3>::is_valid().
The strategy owns the named transition stream and draws each move kind, acceptance trial, and candidate site in sequence. This preserves single ownership of the stream and makes the complete sequence replayable from the recorded root seed.
#include <fmt/base.h>
#include <cstddef>
#include <cstdint>
#include <exception>
#include <filesystem>
#include <string_view>
namespace
{
inline constexpr std::size_t QUICKSTART_TRANSITIONS = 10;
[[nodiscard]] constexpr auto yes_no(bool const value) noexcept
-> std::string_view
{ return value ? "yes" : "no"; }
[[nodiscard]] auto same_finite_counts(
{
return restored.number_of_vertices() ==
static_cast<std::size_t>(expected.N0()) &&
restored.number_of_finite_edges() ==
static_cast<std::size_t>(expected.N1()) &&
restored.number_of_finite_facets() ==
static_cast<std::size_t>(expected.N2()) &&
restored.number_of_finite_cells() ==
static_cast<std::size_t>(expected.N3());
}
}
auto main(int argc, char* argv[]) -> int
try
{
if (argc > 2)
{
fmt::print(stderr, "usage: {} [output.off]\n", argv[0]);
return 2;
}
auto const output = argc == 2 ? std::filesystem::path{argv[1]}
: std::filesystem::path{"cdt-quickstart.off"};
triangulation_config, 0.6L, 1.1L, 0.1L, 1, 1, false);
auto initialization_random =
auto const initialization_stream = initialization_random.stream();
triangulation_config.simplices(), triangulation_config.timeslices(),
initialization_random, triangulation_config.initial_radius(),
triangulation_config.foliation_spacing()};
{
fmt::print(stderr, "initial triangulation failed validation\n");
return 1;
}
initial, triangulation_config.seed(),
provenance.initialization_stream = initialization_stream;
provenance.desired_simplices = triangulation_config.simplices();
provenance.desired_timeslices = triangulation_config.timeslices();
provenance.configured_attempts =
provenance.max_threads =
static_cast<std::uint64_t>(triangulation_config.threads());
simulation_config.alpha(),
simulation_config.k(),
simulation_config.lambda(),
simulation_config.passes(),
simulation_config.checkpoint(),
simulation_config.write_files(),
provenance};
auto evolved = initial;
fmt::print("=== Ten explicit Metropolis proposals ===\n");
for (std::size_t index = 0; index < QUICKSTART_TRANSITIONS; ++index)
{
auto const transition = strategy.attempt_transition(evolved);
if (transition.accepted() && !transition.successful())
{
fmt::print(stderr, "accepted transition lacked a valid candidate\n");
return 1;
}
fmt::print("proposal {}: move {}, accepted={}, successful={}\n", index + 1,
transition.move(), yes_no(transition.accepted()),
yes_no(transition.successful()));
}
strategy.print_results();
!evolved.is_correct_with_diagnostics())
{
fmt::print(stderr, "Metropolis transitions failed manifold validation\n");
return 1;
}
if (strategy.proposed().total() !=
strategy.accepted().total() + strategy.rejected().total() !=
strategy.succeeded().total() + strategy.failed().total() !=
{
fmt::print(stderr, "Metropolis summary counters are inconsistent\n");
return 1;
}
auto const final_metadata = strategy.reproducibility_metadata(
final_metadata);
if (!restored.tds().is_valid() || !same_finite_counts(restored, evolved))
{
fmt::print(
stderr,
"persisted triangulation failed round-trip checks: tds_valid={}, "
"counts=({},{},{},{}) expected=({},{},{},{})\n",
restored.tds().is_valid(), restored.number_of_vertices(),
restored.number_of_finite_edges(), restored.number_of_finite_facets(),
restored.number_of_finite_cells(), evolved.N0(), evolved.N1(),
evolved.N2(), evolved.N3());
return 1;
}
fmt::print("wrote and verified {} with {} finite simplices\n",
output.string(), evolved.N3());
return 0;
}
catch (std::exception const& error)
{
fmt::print(stderr, "quickstart failed: {}\n", error.what());
return 1;
}
Data structures for manifolds.
Manifold< 3 > Manifold_3
Three-dimensional spherical CDT manifold.
Perform Metropolis-Hastings algorithm on Delaunay Triangulations.
Run-owned random-number generation and reproducible stream splitting.
constexpr RandomStream initialization
Stream reserved for initial triangulation generation.
constexpr RandomStream transitions
Stream reserved for stochastic state transitions.
Validated runtime configuration for CDT++ command-line programs.
auto make_simulation(Triangulation const &triangulation, long double const alpha, long double const k, long double const lambda, long long const passes, long long const checkpoint, bool const write_files) -> Simulation
Validate the complete simulation configuration.
auto make_triangulation(bool const spherical, bool const toroidal, long long const simplices, long long const timeslices, long long const dimensions, double const initial_radius, double const foliation_spacing, cdt::RandomSeed const seed=cdt::RandomSeed{}, long long const threads=1) -> Triangulation
Validate raw triangulation options and narrow them into project types.
@ FINAL_TRIANGULATION
Final state after the configured move run.
@ INITIAL_TRIANGULATION
Initial state before stochastic transitions.
void write_file(std::filesystem::path const &filename, TriangulationType const &triangulation)
Write triangulation to file.
auto make_reproducibility_metadata(ManifoldType const &manifold, cdt::RandomSeed const seed, ArtifactKind const artifact) -> Reproducibility_metadata
Build provenance from a canonical manifold state.
auto read_file(std::filesystem::path const &filename) -> TriangulationType
Read triangulation from file.
A run-owned PCG engine with a recorded seed and stream identifier.
auto split(RandomStream const stream) const -> Random
Create a fresh reproducible stream from the same root seed.
Root entropy value used to reproduce a random run.
auto is_correct_with_diagnostics() const -> bool
typename detail::TriangulationTraits< dimension >::Delaunay Delaunay_t
Delaunay triangulation type for dimension spatial dimensions.
std::int32_t Int_precision
MoveStrategy< MoveStrategyKind::METROPOLIS, manifolds::Manifold_3 > Metropolis_3
Metropolis-Hastings move strategy for the supported 3D manifold.
The program accepts zero or one argument. Without an argument it writes cdt-quickstart.off and cdt-quickstart.off.meta in the current directory. With an argument, the sidecar is written next to that payload by appending .meta to its name.
Configuration, construction, move execution, and persistence failures are reported on standard error and produce a nonzero exit status. A caller-owned random stream may already have advanced when a later operation throws; replay therefore starts from the recorded root seed and named stream, not from an engine object retained after failure.
CGAL handles and facet or edge descriptors borrow from the exact triangulation that produced them. Do not use them with a copied triangulation or after an invalidating topology mutation. delaunay_snapshot() instead returns an owning, detached triangulation suitable for persistence or transfer across an ownership boundary. See the multithreaded CGAL contract for the full lifetime and synchronization policy.