CDT++ 1.0.0
Causal Dynamical Triangulations in C++
Loading...
Searching...
No Matches
Metropolis.hpp
Go to the documentation of this file.
1/*******************************************************************************
2 Causal Dynamical Triangulations in C++ using CGAL
3
4 Copyright © 2015 Adam Getchell
5 ******************************************************************************/
6
16
17#ifndef INCLUDE_METROPOLIS_HPP_
18#define INCLUDE_METROPOLIS_HPP_
19
20#include <cmath>
21#include <cstdint>
22#include <expected>
23#include <optional>
24#include <stdexcept>
25#include <utility>
26
27// CDT headers
28#include "Ergodic_moves_3.hpp"
29#include "Move_run.hpp"
30#include "Move_strategy.hpp"
31#include "Random.hpp"
32#include "S3Action.hpp"
33#include "Utilities.hpp"
34
35namespace cdt
36{
50 template <typename ManifoldType>
51 requires(ManifoldType::dimension == 3)
52 class MoveStrategy<MoveStrategyKind::METROPOLIS, ManifoldType>
53 {
54 using Counter = move_tracker::MoveTracker;
55 using CommandResults = detail::MoveCommandResults<ManifoldType>;
56
57 struct RunStatistics
58 {
61
63 std::uint64_t transition_trace{14695981039346656037ULL};
64
66 std::uint64_t transition_count{};
67
69 Counter proposed;
70
72 Counter accepted;
73
75 Counter rejected;
76 };
77
78 using PassResult = detail::MovePassResult<ManifoldType, RunStatistics>;
79
82
84 MoveRunCadence m_cadence;
85
87 bool m_write_files{true};
88
90 cdt::Random m_generator{
92
95
97 CommandResults m_command_results;
98
100 RunStatistics m_run_statistics;
101
103 Int_precision m_checkpoint_events{};
104
106 Int_precision m_completed_passes{};
107
109 bool m_resume_pending{};
110
111 [[nodiscard]] static auto to_counts(Counter const& counter)
113 {
115 for (std::size_t index = 0; index < counts.size(); ++index)
116 {
117 counts[index] = counter[static_cast<gsl::index>(index)];
118 }
119 return counts;
120 }
121
122 [[nodiscard]] static auto from_counts(
123 utilities::Move_statistics::Counts const& counts) -> Counter
124 {
125 Counter counter;
126 for (std::size_t index = 0; index < counts.size(); ++index)
127 {
128 counter[static_cast<gsl::index>(index)] = counts[index];
129 }
130 return counter;
131 }
132
133 void restore_statistics(utilities::Reproducibility_metadata const& metadata)
134 {
135 if (!metadata.move_statistics || !metadata.transition_trace ||
136 !metadata.transition_count)
137 {
138 throw std::invalid_argument(
139 "Checkpoint resume requires cumulative transition statistics.");
140 }
141 auto const& saved = *metadata.move_statistics;
142 m_command_results.attempted = from_counts(saved.attempted);
143 m_command_results.succeeded = from_counts(saved.succeeded);
144 m_command_results.failed = from_counts(saved.failed);
145 m_run_statistics.proposed = from_counts(saved.proposed);
146 m_run_statistics.accepted = from_counts(saved.accepted);
147 m_run_statistics.rejected = from_counts(saved.rejected);
148 m_run_statistics.transition_trace = *metadata.transition_trace;
149 m_run_statistics.transition_count = *metadata.transition_count;
150 }
151
152 static void record_transition(
153 RunStatistics& statistics, move_tracker::MoveType const move,
154 ergodic_moves::MoveOutcome const outcome) noexcept
155 {
156 auto const append = [&statistics](std::uint8_t const value) {
157 statistics.transition_trace ^= value;
158 statistics.transition_trace *= 1099511628211ULL;
159 };
160 append(static_cast<std::uint8_t>(move));
161 append(static_cast<std::uint8_t>(outcome));
162 ++statistics.transition_count;
163 }
164
165 public:
166 MoveStrategy() = delete;
167
180 [[maybe_unused]] MoveStrategy(long double const alpha, long double const k,
181 long double const lambda,
182 Int_precision const passes,
184 bool const write_files = true)
185 : MoveStrategy{alpha,
186 k,
187 lambda,
188 passes,
190 write_files,
191 cdt::Random{}.split(cdt::random_streams::transitions)}
192 {}
193
213 [[maybe_unused]] MoveStrategy(
214 long double const alpha, long double const k, long double const lambda,
216 bool const write_files, cdt::Random random,
217 std::optional<utilities::Reproducibility_metadata> reproducibility =
218 std::nullopt,
219 Int_precision const completed_passes = 0)
220 : m_parameters{s3_action::make_physical_parameters(alpha, k, lambda)}
221 , m_cadence{detail::parse_move_run_cadence(passes, checkpoint,
222 "Metropolis")}
223 , m_write_files{write_files}
224 , m_generator{std::move(random)}
225 , m_reproducibility{reproducibility.value_or(
226 utilities::Reproducibility_metadata{
227 .seed = m_generator.seed(),
228 .alpha = alpha,
229 .k = k,
230 .lambda = lambda,
231 .configured_passes = passes,
232 .checkpoint_interval = checkpoint})}
233 , m_completed_passes{completed_passes}
234 {
235 if (m_completed_passes < 0)
236 {
237 throw std::invalid_argument("Completed passes cannot be negative.");
238 }
239 m_reproducibility.alpha = m_parameters.alpha();
240 m_reproducibility.k = m_parameters.k();
241 m_reproducibility.lambda = m_parameters.lambda();
242 auto const total_passes = static_cast<std::int64_t>(m_completed_passes) +
243 static_cast<std::int64_t>(m_cadence.passes());
244 if (!std::in_range<Int_precision>(total_passes))
245 {
246 throw std::out_of_range(
247 "Total pass count exceeds the supported range.");
248 }
249 if (m_completed_passes > 0 || m_reproducibility.transition_random_state)
250 {
251 if (!m_reproducibility.configured_passes ||
252 *m_reproducibility.configured_passes != total_passes ||
253 !m_reproducibility.transition_random_state)
254 {
255 throw std::invalid_argument(
256 "Checkpoint resume state does not match its pass range.");
257 }
258 if (m_reproducibility.seed != m_generator.seed() ||
259 m_reproducibility.transition_stream != m_generator.stream() ||
260 *m_reproducibility.transition_random_state !=
261 m_generator.serialized_state())
262 {
263 throw std::invalid_argument(
264 "Checkpoint resume generator does not match its recorded random state.");
265 }
266 restore_statistics(m_reproducibility);
267 m_resume_pending = true;
268 }
269 m_reproducibility.seed = m_generator.seed();
270 m_reproducibility.transition_stream = m_generator.stream();
271 m_reproducibility.configured_passes =
272 static_cast<Int_precision>(total_passes);
273 m_reproducibility.checkpoint_interval = m_cadence.checkpoint();
274 m_reproducibility.transition_random_state.reset();
275#ifndef NDEBUG
276 spdlog::debug("{} called.\n", CDT_PRETTY_FUNCTION);
277#endif
278 }
279
291 MoveStrategy(long double const alpha, long double const k,
292 long double const lambda, Int_precision const passes,
293 Int_precision const checkpoint, bool const write_files,
294 cdt::RandomSeed const seed)
295 : MoveStrategy{
296 alpha,
297 k,
298 lambda,
299 passes,
301 write_files,
302 cdt::Random{seed, cdt::random_streams::transitions}
303 }
304 {}
305
307 [[nodiscard]] auto alpha() const noexcept { return m_parameters.alpha(); }
308
310 [[nodiscard]] auto k() const noexcept { return m_parameters.k(); }
311
313 [[nodiscard]] auto lambda() const noexcept { return m_parameters.lambda(); }
314
316 [[nodiscard]] auto passes() const noexcept { return m_cadence.passes(); }
317
319 [[nodiscard]] auto checkpoint() const noexcept
320 { return m_cadence.checkpoint(); }
321
323 [[nodiscard]] auto checkpoint_events() const noexcept
324 { return m_checkpoint_events; }
325
327 [[nodiscard]] auto writes_files() const noexcept { return m_write_files; }
328
330 [[nodiscard]] auto seed() const noexcept { return m_generator.seed(); }
331
333 [[nodiscard]] auto stream() const noexcept { return m_generator.stream(); }
334
337 [[nodiscard]] auto transition_trace() const noexcept
338 { return m_run_statistics.transition_trace; }
339
341 [[nodiscard]] auto transition_count() const noexcept
342 { return m_run_statistics.transition_count; }
343
350 [[nodiscard]] auto reproducibility_metadata(
351 ManifoldType const& manifold, utilities::ArtifactKind const artifact,
352 Int_precision const completed_passes) const
354 {
355 return make_reproducibility_metadata(manifold, artifact, completed_passes,
356 m_command_results, m_run_statistics);
357 }
358
360 [[nodiscard]] auto proposed() const noexcept -> Counter const&
361 { return m_run_statistics.proposed; }
362
364 [[nodiscard]] auto accepted() const noexcept -> Counter const&
365 { return m_run_statistics.accepted; }
366
368 [[nodiscard]] auto rejected() const noexcept -> Counter const&
369 { return m_run_statistics.rejected; }
370
372 [[nodiscard]] auto attempted() const noexcept -> Counter const&
373 { return m_command_results.attempted; }
374
376 [[nodiscard]] auto succeeded() const noexcept -> Counter const&
377 { return m_command_results.succeeded; }
378
380 [[nodiscard]] auto failed() const noexcept -> Counter const&
381 { return m_command_results.failed; }
382
384 [[nodiscard]] auto geometry() const noexcept
385 -> Geometry<ManifoldType::dimension> const&
386 { return m_run_statistics.geometry; }
387
390 [[nodiscard]] static constexpr auto reverse_move(
391 move_tracker::MoveType const move) noexcept
392 -> std::optional<move_tracker::MoveType>
393 {
394 using enum move_tracker::MoveType;
395 switch (move)
396 {
397 case TWO_THREE: return THREE_TWO;
398 case THREE_TWO: return TWO_THREE;
399 case TWO_SIX: return SIX_TWO;
400 case SIX_TWO: return TWO_SIX;
401 case FOUR_FOUR: return FOUR_FOUR;
402 }
403 return std::nullopt;
404 }
405
409 [[nodiscard]] static constexpr auto proposal_site_count(
411 move_tracker::MoveType const move) noexcept -> Int_precision
412 {
413 using enum move_tracker::MoveType;
414 switch (move)
415 {
416 case TWO_THREE: return geometry.N3_22;
417 case THREE_TWO: return geometry.N1_TL;
418 case TWO_SIX: return geometry.N3_13;
419 case SIX_TWO: return geometry.N0;
420 case FOUR_FOUR: return geometry.N1_SL;
421 }
422 return 0;
423 }
424
433 [[nodiscard]] static auto proposal_probability(
436 {
437 auto const sites = proposal_site_count(geometry, move);
438 if (sites <= 0) { return mpfr_values::zero(); }
439 auto const move_count =
441 auto const site_count = mpfr_values::from_integer(sites);
442 auto const denominator = mpfr_values::multiply(move_count, site_count);
443 return mpfr_values::divide(mpfr_values::from_integer(1), denominator);
444 }
445
456 [[nodiscard]] static auto hastings_ratio(
460 {
461 auto const forward = proposal_probability(current, move);
462 auto const reverse_type = reverse_move(move);
463 if (!reverse_type)
464 {
465 throw std::invalid_argument{"Cannot reverse an unknown move type."};
466 }
467 auto const reverse = proposal_probability(proposed, *reverse_type);
468 if (mpfr_zero_p(forward.fr()) != 0 || mpfr_zero_p(reverse.fr()) != 0)
469 {
470 throw std::logic_error(
471 "A successful reversible proposal must have nonzero forward and reverse probabilities.");
472 }
473 return mpfr_values::divide(reverse, forward);
474 }
475
482 [[nodiscard]] auto action_ratio(
486 {
487 auto const current_action = s3_action::s3_bulk_action(
488 current.N1_TL, current.N3_31_13, current.N3_22, m_parameters);
489 auto const proposed_action = s3_action::s3_bulk_action(
490 proposed.N1_TL, proposed.N3_31_13, proposed.N3_22, m_parameters);
492 mpfr_values::subtract(current_action, proposed_action));
493 }
494
501 [[nodiscard]] auto acceptance_probability(
504 move_tracker::MoveType const move) const -> mpfr_values::Value
505 {
506 auto const ratio =
508 action_ratio(current, proposed));
509 auto const one = mpfr_values::from_integer(1);
510 return mpfr_cmp(ratio.fr(), one.fr()) < 0 ? ratio : one;
511 }
512
513 private:
514 [[nodiscard]] auto propose_candidate(ManifoldType const& current,
515 move_tracker::MoveType const move)
517 {
518 using enum move_tracker::MoveType;
519 switch (move)
520 {
521 case TWO_THREE:
522 return ergodic_moves::propose_23_move(current, m_generator);
523 case THREE_TWO:
524 return ergodic_moves::propose_32_move(current, m_generator);
525 case TWO_SIX:
526 return ergodic_moves::propose_26_move(current, m_generator);
527 case SIX_TWO:
528 return ergodic_moves::propose_62_move(current, m_generator);
529 case FOUR_FOUR:
530 return ergodic_moves::propose_44_move(current, m_generator);
531 }
532 return std::unexpected{
533 ergodic_moves::MoveError{
534 .category = ergodic_moves::MoveFailure::UNKNOWN_MOVE,
535 .requested_move = move}
536 };
537 }
538
539 [[nodiscard]] auto make_reproducibility_metadata(
540 ManifoldType const& manifold, utilities::ArtifactKind const artifact,
541 Int_precision const completed_passes,
542 CommandResults const& command_results,
543 RunStatistics const& statistics) const
545 {
546 auto metadata = m_reproducibility;
547 metadata.artifact = artifact;
548 metadata.completed_passes = completed_passes;
549 metadata.transition_trace = statistics.transition_trace;
550 metadata.transition_count = statistics.transition_count;
552 .proposed = to_counts(statistics.proposed),
553 .accepted = to_counts(statistics.accepted),
554 .rejected = to_counts(statistics.rejected),
555 .attempted = to_counts(command_results.attempted),
556 .succeeded = to_counts(command_results.succeeded),
557 .failed = to_counts(command_results.failed)};
558 if (artifact == utilities::ArtifactKind::CHECKPOINT &&
559 metadata.max_threads && *metadata.max_threads > 0)
560 {
561 metadata.transition_random_state =
562 std::make_shared<std::string const>(m_generator.serialized_state());
563 }
564 else
565 {
566 metadata.transition_random_state.reset();
567 }
568 utilities::update_reproducibility_state(metadata, manifold);
569 if (metadata.desired_simplices == 0)
570 {
571 metadata.desired_simplices = manifold.N3();
572 }
573 if (metadata.desired_timeslices == 0)
574 {
575 metadata.desired_timeslices = manifold.max_time();
576 }
577 return metadata;
578 }
579
580 auto resolve_transition(ManifoldType& current,
581 CommandResults& command_results,
582 RunStatistics& statistics,
583 move_tracker::MoveType const move,
584 long double const trial_value)
586 {
587 if (!std::isfinite(trial_value) || trial_value < 0.0L ||
588 trial_value > 1.0L)
589 {
590 throw std::invalid_argument("MH trial value must lie in [0, 1].");
591 }
592
593 if (!reverse_move(move))
594 {
597 .requested_move = move});
598 }
599
600 statistics.geometry = current.geometry();
601 ++statistics.proposed[move];
602 ++command_results.attempted[move];
603
604 auto candidate = propose_candidate(current, move);
605 if (!candidate)
606 {
607 ++command_results.failed[move];
608 ++statistics.rejected[move];
609 auto const outcome = ergodic_moves::outcome_from(candidate.error());
610 record_transition(statistics, move, outcome);
611 return outcome;
612 }
613 if (!ergodic_moves::detail::check_move(current, *candidate, move))
614 {
615 ++command_results.failed[move];
616 ++statistics.rejected[move];
617 record_transition(statistics, move,
620 }
621
622 ++command_results.succeeded[move];
623 auto const probability = acceptance_probability(
624 statistics.geometry, candidate->geometry(), move);
625 if (mpfr_cmp_ld(probability.fr(), trial_value) >= 0)
626 {
627 swap(*candidate, current);
628 statistics.geometry = current.geometry();
629 ++statistics.accepted[move];
630 record_transition(statistics, move,
633 }
634
635 ++statistics.rejected[move];
636 record_transition(statistics, move,
639 }
640
641 [[nodiscard]] auto sample_transition(ManifoldType& current,
642 CommandResults& command_results,
643 RunStatistics& statistics)
645 {
646 auto const move = move_tracker::generate_random_move_3(m_generator);
647 auto const trial_value = utilities::generate_probability(m_generator);
648 return {move, resolve_transition(current, command_results, statistics,
649 move, trial_value)};
650 }
651
652 [[nodiscard]] auto execute_pass(ManifoldType current,
653 RunStatistics statistics,
654 Int_precision const attempts) -> PassResult
655 {
656 auto command_results = CommandResults{};
657 for (auto move_attempt = Int_precision{0}; move_attempt < attempts;
658 ++move_attempt)
659 {
660 static_cast<void>(
661 sample_transition(current, command_results, statistics));
662 }
663 return {.manifold = std::move(current),
664 .command_results = std::move(command_results),
665 .strategy_state = std::move(statistics)};
666 }
667
668 static void print_results(CommandResults const& command_results,
669 RunStatistics const& statistics)
670 {
671 fmt::print("=== Move Results ===\n");
672 fmt::print(
673 "There were {} proposed moves with {} accepted moves and {} rejected "
674 "moves.\n",
675 statistics.proposed.total(), statistics.accepted.total(),
676 statistics.rejected.total());
677 fmt::print(
678 "There were {} candidate construction attempts with {} successful "
679 "candidates and {} failed candidates.\n",
680 command_results.attempted.total(), command_results.succeeded.total(),
681 command_results.failed.total());
682 fmt::print(
683 "(2,3) moves: {} proposed ({} accepted and {} rejected); candidate "
684 "construction: {} attempted ({} succeeded and {} failed).\n",
685 statistics.proposed.two_three_moves(),
686 statistics.accepted.two_three_moves(),
687 statistics.rejected.two_three_moves(),
688 command_results.attempted.two_three_moves(),
689 command_results.succeeded.two_three_moves(),
690 command_results.failed.two_three_moves());
691
692 fmt::print(
693 "(3,2) moves: {} proposed ({} accepted and {} rejected); candidate "
694 "construction: {} attempted ({} succeeded and {} failed).\n",
695 statistics.proposed.three_two_moves(),
696 statistics.accepted.three_two_moves(),
697 statistics.rejected.three_two_moves(),
698 command_results.attempted.three_two_moves(),
699 command_results.succeeded.three_two_moves(),
700 command_results.failed.three_two_moves());
701
702 fmt::print(
703 "(2,6) moves: {} proposed ({} accepted and {} rejected); candidate "
704 "construction: {} attempted ({} succeeded and {} failed).\n",
705 statistics.proposed.two_six_moves(),
706 statistics.accepted.two_six_moves(),
707 statistics.rejected.two_six_moves(),
708 command_results.attempted.two_six_moves(),
709 command_results.succeeded.two_six_moves(),
710 command_results.failed.two_six_moves());
711
712 fmt::print(
713 "(6,2) moves: {} proposed ({} accepted and {} rejected); candidate "
714 "construction: {} attempted ({} succeeded and {} failed).\n",
715 statistics.proposed.six_two_moves(),
716 statistics.accepted.six_two_moves(),
717 statistics.rejected.six_two_moves(),
718 command_results.attempted.six_two_moves(),
719 command_results.succeeded.six_two_moves(),
720 command_results.failed.six_two_moves());
721
722 fmt::print(
723 "(4,4) moves: {} proposed ({} accepted and {} rejected); candidate "
724 "construction: {} attempted ({} succeeded and {} failed).\n",
725 statistics.proposed.four_four_moves(),
726 statistics.accepted.four_four_moves(),
727 statistics.rejected.four_four_moves(),
728 command_results.attempted.four_four_moves(),
729 command_results.succeeded.four_four_moves(),
730 command_results.failed.four_four_moves());
731 }
732
733 public:
745 [[nodiscard]] auto attempt_transition(ManifoldType& current,
746 move_tracker::MoveType const move,
747 long double const trial_value)
749 {
750 return {move, resolve_transition(current, m_command_results,
751 m_run_statistics, move, trial_value)};
752 }
753
761 [[nodiscard]] auto attempt_transition(ManifoldType& current)
763 { return sample_transition(current, m_command_results, m_run_statistics); }
764
767 void initialize(ManifoldType const& manifold)
768 { m_run_statistics.geometry = manifold.geometry(); }
769
780 [[nodiscard]] auto operator()(ManifoldType const& t_manifold)
781 -> ManifoldType
782 {
783#ifndef NDEBUG
784 spdlog::debug("{} called.\n", CDT_PRETTY_FUNCTION);
785#endif
786
787 auto initial_statistics =
788 m_resume_pending ? m_run_statistics : RunStatistics{};
789 initial_statistics.geometry = t_manifold.geometry();
790 auto initial_command_results =
791 m_resume_pending ? m_command_results : CommandResults{};
792 auto const initial_completed_passes =
793 m_resume_pending ? m_completed_passes : Int_precision{};
794 auto result = detail::execute_move_run(
795 t_manifold, std::move(initial_command_results),
796 std::move(initial_statistics), initial_completed_passes, m_cadence,
797 detail::MoveRunIdentity{.algorithm = "Metropolis-Hastings",
798 .seed = seed(),
799 .stream = stream()},
800 m_write_files,
801 [this](ManifoldType current, RunStatistics statistics,
802 Int_precision const attempts) {
803 return execute_pass(std::move(current), std::move(statistics),
804 attempts);
805 },
806 [](ManifoldType const&, CommandResults const& command_results,
807 RunStatistics const& statistics) {
808 print_results(command_results, statistics);
809 },
810 [this](ManifoldType const& current,
811 CommandResults const& command_results,
812 RunStatistics const& statistics,
813 Int_precision const pass_number) {
815 current, make_reproducibility_metadata(
817 pass_number, command_results, statistics));
818 });
819
820 m_command_results = std::move(result.command_results);
821 m_run_statistics = std::move(result.strategy_state);
822 m_checkpoint_events = result.checkpoint_events;
823 m_completed_passes = initial_completed_passes + m_cadence.passes();
824 m_resume_pending = false;
825 return std::move(result.manifold);
826 }
827
829 void print_results() const
830 { print_results(m_command_results, m_run_statistics); }
831 }; // Metropolis
832
836} // namespace cdt
837
838#endif // INCLUDE_METROPOLIS_HPP_
Pachner moves on 2+1 dimensional foliated Delaunay triangulations.
auto propose_44_move(Manifold const &t_manifold, Generator &generator) -> Expected
Propose one spacelike edge as a (4,4) site.
auto propose_62_move(Manifold const &t_manifold, Generator &generator) -> Expected
Propose one vertex as a (6,2) site for Metropolis-Hastings.
auto propose_23_move(Manifold const &t_manifold, Generator &generator) -> Expected
Propose one (2,3) site for Metropolis-Hastings.
auto propose_32_move(Manifold const &t_manifold, Generator &generator) -> Expected
Propose one (3,2) site for Metropolis-Hastings.
auto check_move(Manifold const &before, Manifold const &after, move_tracker::MoveType const &move) -> bool
Check tracked move deltas and essential CDT manifold invariants.
auto propose_26_move(Manifold const &t_manifold, Generator &generator) -> Expected
Propose a uniformly selected (2,6) site.
constexpr auto outcome_from(MoveError const error) noexcept -> MoveOutcome
Classify a structured move error for counter accounting.
std::expected< ManifoldType, MoveError > MoveResult
Value returned by a fallible Pachner-move transformation.
MoveOutcome
Typed state used to route proposal and execution accounting.
@ METROPOLIS_ACCEPTED
Metropolis-Hastings accepted the proposal.
@ EXECUTION_FAILED
Mutation failed after proposal preparation.
@ METROPOLIS_REJECTED
Metropolis-Hastings rejected the proposal.
@ UNKNOWN_MOVE
The requested move kind is unsupported.
Shared value-oriented orchestration for ergodic-move strategies.
auto execute_move_run(ManifoldType initial, MoveCommandResults< ManifoldType > initial_command_results, StrategyState initial_strategy_state, Int_precision const completed_passes, MoveRunCadence const cadence, MoveRunIdentity const identity, bool const writes_files, ExecutePass execute_pass, Report report, Checkpoint checkpoint) -> MoveRunResult< ManifoldType, StrategyState >
Execute shared pass, accounting, checkpoint, and report cadence.
Definition Move_run.hpp:179
Template class for move algorithms (strategies) on manifolds.
MoveType
The types of 3D ergodic moves.
auto generate_random_move_3(Generator &generator) -> MoveType
Generate a uniformly distributed 3D move from caller-owned RNG.
constexpr std::size_t NUMBER_OF_3D_MOVES
Number of supported Pachner move kinds in three dimensions.
auto multiply(Value const &left, Value const &right) -> Value
auto from_integer(long const value) -> Value
auto subtract(Value const &left, Value const &right) -> Value
auto exponential(Value const &value) -> Value
auto divide(Value const &numerator, Value const &denominator) -> Value
auto zero() -> Value
CGAL::Gmpfr Value
Owning arbitrary-precision floating-point value used by CDT++.
Run-owned random-number generation and reproducible stream splitting.
constexpr RandomStream transitions
Stream reserved for stochastic state transitions.
Definition Random.hpp:122
Calculate S3 bulk actions on 3D Delaunay Triangulations.
auto s3_bulk_action(Int_precision const n1_tl_count, Int_precision const n3_31_13_count, Int_precision const n3_22_count, PhysicalParameters const &parameters) -> mpfr_values::Value
Calculates the generalized S3 bulk action in terms of , , , , , and .
Definition S3Action.hpp:253
#define CDT_PRETTY_FUNCTION
Cross-platform spelling of the current function signature for diagnostics.
Definition Settings.hpp:37
Utility functions.
void update_reproducibility_state(Reproducibility_metadata &metadata, ManifoldType const &manifold)
Refresh state-dependent provenance after a transition sequence.
ArtifactKind
Persistence artifact represented by a triangulation payload.
Definition Utilities.hpp:99
@ CHECKPOINT
Intermediate snapshot during a move run.
auto generate_probability(Generator &generator)
Generate a probability.
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.
Positive pass count and checkpoint interval for a move run.
Definition Move_run.hpp:38
constexpr auto checkpoint() const noexcept
Definition Move_run.hpp:81
MoveStrategy(long double const alpha, long double const k, long double const lambda, Int_precision const passes, Int_precision const checkpoint, bool const write_files, cdt::Random random, std::optional< utilities::Reproducibility_metadata > reproducibility=std::nullopt, Int_precision const completed_passes=0)
Construct a run from an already selected PCG stream.
auto reproducibility_metadata(ManifoldType const &manifold, utilities::ArtifactKind const artifact, Int_precision const completed_passes) const -> utilities::Reproducibility_metadata
Materialize output provenance for the supplied canonical state.
static constexpr auto proposal_site_count(Geometry< ManifoldType::dimension > const &geometry, move_tracker::MoveType const move) noexcept -> Int_precision
void initialize(ManifoldType const &manifold)
Initialize the cached action geometry from the canonical manifold.
static auto proposal_probability(Geometry< ManifoldType::dimension > const &geometry, move_tracker::MoveType const move) -> mpfr_values::Value
MoveStrategy(long double const alpha, long double const k, long double const lambda, Int_precision const passes, Int_precision const checkpoint, bool const write_files=true)
Metropolis function object constructor.
auto geometry() const noexcept -> Geometry< ManifoldType::dimension > const &
auto action_ratio(Geometry< ManifoldType::dimension > const &current, Geometry< ManifoldType::dimension > const &proposed) const -> mpfr_values::Value
Calculate the action factor .
static auto hastings_ratio(Geometry< ManifoldType::dimension > const &current, Geometry< ManifoldType::dimension > const &proposed, move_tracker::MoveType const move) -> mpfr_values::Value
Calculate the Hastings reverse-to-forward proposal ratio.
static constexpr auto reverse_move(move_tracker::MoveType const move) noexcept -> std::optional< move_tracker::MoveType >
auto acceptance_probability(Geometry< ManifoldType::dimension > const &current, Geometry< ManifoldType::dimension > const &proposed, move_tracker::MoveType const move) const -> mpfr_values::Value
auto attempt_transition(ManifoldType &current) -> ergodic_moves::MetropolisTransition
Sample and immediately resolve one Markov transition.
MoveStrategy(long double const alpha, long double const k, long double const lambda, Int_precision const passes, Int_precision const checkpoint, bool const write_files, cdt::RandomSeed const seed)
Construct a replayable run with an explicit RNG seed.
auto operator()(ManifoldType const &t_manifold) -> ManifoldType
Execute a fresh run while continuing the owned random stream.
void print_results() const
Display results of the latest completed invocation.
auto attempt_transition(ManifoldType &current, move_tracker::MoveType const move, long double const trial_value) -> ergodic_moves::MetropolisTransition
Resolve one caller-selected Markov transition.
Select a move algorithm.
A run-owned PCG engine with a recorded seed and stream identifier.
Definition Random.hpp:137
auto split(RandomStream const stream) const -> Random
Create a fresh reproducible stream from the same root seed.
Definition Random.hpp:194
auto serialized_state() const -> std::string
Serialize the complete mutable PCG state for exact continuation.
Definition Random.hpp:199
auto seed() const noexcept -> RandomSeed
Definition Random.hpp:185
auto stream() const noexcept -> RandomStream
Definition Random.hpp:188
Root entropy value used to reproduce a random run.
Definition Random.hpp:49
Result of one fully sampled Metropolis-Hastings transition.
The data and methods to track ergodic moves.
Finite physical couplings used to evaluate the Euclidean action.
Definition S3Action.hpp:37
clang-15 does not support std::format
std::int32_t Int_precision
Definition Settings.hpp:30
MoveStrategy< MoveStrategyKind::METROPOLIS, manifolds::Manifold_3 > Metropolis_3
Metropolis-Hastings move strategy for the supported 3D manifold.
Typed error returned by move preparation or private execution.
Cumulative counters needed to preserve observable run state.
std::array< Int_precision, move_tracker::NUMBER_OF_3D_MOVES > Counts
Per-move counts in stable MoveType index order.
Provenance recorded next to every stochastic triangulation.
Int_precision desired_timeslices
Requested timeslice count.
ArtifactKind artifact
Artifact role.
std::shared_ptr< std::string const > transition_random_state
Exact PCG state.
cdt::RandomStream transition_stream
Transition stream.
std::optional< Int_precision > configured_passes
Requested move passes.
std::optional< std::uint64_t > max_threads
Configured concurrency.
Int_precision desired_simplices
Requested simplex target.
std::optional< Int_precision > checkpoint_interval
Checkpoint cadence.
std::optional< std::uint64_t > transition_count
Hashed transitions.
std::optional< Int_precision > completed_passes
Passes before snapshot.
std::optional< std::uint64_t > transition_trace
Ordered trace hash.
std::optional< Move_statistics > move_statistics
Cumulative counters.
cdt::RandomSeed seed
Root seed for the recorded run.