17#ifndef INCLUDE_METROPOLIS_HPP_
18#define INCLUDE_METROPOLIS_HPP_
25using Gmpzf = CGAL::Gmpzf;
36template <
typename ManifoldType>
42 long double m_Alpha{};
49 long double m_Lambda{};
97 [[maybe_unused]]
MoveStrategy(
long double const Alpha,
long double const K,
98 long double const Lambda,
105 , m_checkpoint{checkpoint}
108 spdlog::debug(
"{} called.\n", __PRETTY_FUNCTION__);
113 [[nodiscard]]
auto Alpha() const noexcept {
return m_Alpha; }
116 [[nodiscard]]
auto K() const noexcept {
return m_K; }
119 [[nodiscard]]
auto Lambda() const noexcept {
return m_Lambda; }
122 [[nodiscard]]
auto passes() const noexcept {
return m_passes; }
125 [[nodiscard]]
auto checkpoint() const noexcept {
return m_checkpoint; }
154 auto all_moves = m_proposed_moves.
total();
155 auto this_move = m_proposed_moves[move];
165 mpfr_init_set_si(r_1, this_move, MPFR_RNDD);
166 mpfr_init_set_si(r_2, all_moves, MPFR_RNDD);
169 mpfr_div(a_1, r_1, r_2, MPFR_RNDD);
172 auto result = mpfr_get_ld(a_1, MPFR_RNDD);
175 mpfr_clears(r_1, r_2, a_1,
nullptr);
178 spdlog::debug(
"{} called.\n", __PRETTY_FUNCTION__);
179 spdlog::trace(
"Total proposed moves = {}\n", all_moves);
180 spdlog::trace(
"A1 is {}\n", result);
191 template <
int dimension>
196 auto currentS3Action =
198 m_geometry.N3_22, m_Alpha, m_K, m_Lambda);
199 auto newS3Action =
static_cast<Gmpzf
>(0);
202 case move_tracker::move_type::TWO_THREE:
207 m_geometry.N3_22 + 1, m_Alpha, m_K, m_Lambda);
209 case move_tracker::move_type::THREE_TWO:
214 m_geometry.N3_22 - 1, m_Alpha, m_K, m_Lambda);
216 case move_tracker::move_type::TWO_SIX:
221 m_geometry.N3_22, m_Alpha, m_K, m_Lambda);
223 case move_tracker::move_type::SIX_TWO:
228 m_geometry.N3_22 - 4, m_Alpha, m_K, m_Lambda);
230 case move_tracker::move_type::FOUR_FOUR:
234 spdlog::trace(
"A2 is 1\n");
236 return static_cast<long double>(1);
240 auto exponent = currentS3Action - newS3Action;
241 auto exponent_double = utilities::Gmpzf_to_double(exponent);
245 if (exponent >= 0) {
return static_cast<long double>(1); }
256 mpfr_init_set_ld(r_1, exponent_double,
260 mpfr_exp(a_2, r_1, MPFR_RNDD);
263 auto result = mpfr_get_ld(a_2, MPFR_RNDD);
266 mpfr_clears(r_1, a_2,
nullptr);
269 spdlog::trace(
"A2 is {}\n", result);
285 ++m_proposed_moves[as_integer(move)];
288 auto a_1 = CalculateA1(move);
291 auto a_2 = CalculateA2<3>(move);
293 if (
auto const trial_value = utilities::generate_probability();
294 trial_value <= a_1 * a_2)
297 spdlog::debug(
"{} called.\n", __PRETTY_FUNCTION__);
298 spdlog::trace(
"Trying move.\n");
299 spdlog::trace(
"Move type = {}\n", as_integer(move));
300 spdlog::trace(
"Trial_value = {}\n", trial_value);
301 spdlog::trace(
"A1 = {}\n", a_1);
302 spdlog::trace(
"A2 = {}\n", a_2);
303 spdlog::trace(
"A1*A2 = {}\n", a_1 * a_2);
304 spdlog::trace(
"{}\n", trial_value <= a_1 * a_2 ?
"Move accepted."
308 ++m_accepted_moves[as_integer(move)];
313 ++m_rejected_moves[as_integer(move)];
325 -> std::optional<MoveCommand<ManifoldType>>
329 fmt::print(
"Making initial moves ...\n");
333 move < move_tracker::moves_per_dimension(ManifoldType::dimension);
337 spdlog::trace(
"Making move {} ...\n", move);
339 command.
enqueue(move_tracker::as_move(move));
340 ++m_proposed_moves[move];
341 ++m_accepted_moves[move];
359 initial_results.print();
360 initial_results.print_details();
364 catch (std::system_error
const& SystemError)
366 spdlog::debug(
"Metropolis initialization failed with {} ... exiting.\n",
368 spdlog::trace(
"{}\n", SystemError.code().message());
379 auto operator()(ManifoldType
const& t_manifold) -> ManifoldType
382 spdlog::debug(
"{} called.\n", __PRETTY_FUNCTION__);
386 "Starting Metropolis-Hastings algorithm in {}+1 dimensions ...\n",
387 ManifoldType::dimension - 1);
389 auto command = initialize(t_manifold).value_or(
MoveCommand(t_manifold));
391 fmt::print(
"Making random moves ...\n");
394 for (
auto pass_number = 1; pass_number <= m_passes; ++pass_number)
396 fmt::print(
"=== Pass {} ===\n", pass_number);
397 auto total_simplices_this_pass = command.get_const_results().N3();
399 for (
auto move_attempt = 0; move_attempt < total_simplices_this_pass;
404 if (
auto move = move_tracker::generate_random_move_3(); try_move(move))
406 command.enqueue(move);
414 this->m_attempted_moves += command.get_attempted();
415 this->m_succeeded_moves += command.get_succeeded();
416 this->m_failed_moves += command.get_failed();
419 if (pass_number % m_checkpoint == 0)
421 fmt::print(
"=== Pass {} ===\n", pass_number);
422 fmt::print(
"Writing to file.\n");
424 auto result = command.get_results();
425 utilities::write_file(result);
430 fmt::print(
"=== Run results ===\n");
432 return command.get_results();
438 if (ManifoldType::dimension == 3)
440 fmt::print(
"=== Move Results ===\n");
442 "There were {} proposed moves with {} accepted moves and {} rejected "
444 m_proposed_moves.
total(), m_accepted_moves.
total(),
445 m_rejected_moves.
total());
447 "There were {} attempted moves with {} successful moves and {} "
449 m_attempted_moves.
total(), m_succeeded_moves.
total(),
450 m_failed_moves.
total());
452 "(2,3) moves: {} proposed ({} accepted and {} rejected) with {} "
453 "attempted ({} successful and {} failed).\n",
462 "(3,2) moves: {} proposed ({} accepted and {} rejected) with {} "
463 "attempted ({} successful and {} failed).\n",
472 "(2,6) moves: {} proposed ({} accepted and {} rejected) with {} "
473 "attempted ({} successful and {} failed).\n",
479 "(6,2) moves: {} proposed ({} accepted and {} rejected) with {} "
480 "attempted ({} successful and {} failed).\n",
486 "(4,4) moves: {} proposed ({} accepted and {} rejected) with {} "
487 "attempted ({} successful and {} failed).\n",
Do ergodic moves using the Command pattern.
Template class for move algorithms (strategies) on manifolds.
Strategies
The algorithms available to make ergodic moves on triangulations.
move_type
The types of 3D ergodic moves.
Calculate S3 bulk actions on 3D Delaunay Triangulations.
auto S3_bulk_action(Int_precision const N1_TL, Int_precision const N3_31_13, Int_precision const N3_22, long double const Alpha, long double const K, long double const Lambda) noexcept -> Gmpzf
Calculates the generalized S3 bulk action in terms of , , , , , and .
std::int_fast32_t Int_precision
static Int_precision constexpr PRECISION
Sets the precision for MPFR.
void execute()
Execute all moves in the queue on the manifold.
void reset_counters()
Reset counters.
auto get_attempted() const -> Counter const &
Attempted moves by MoveCommand.
auto get_results() -> ManifoldType &
Results of the moves invoked by MoveCommand.
void print_errors() const
Print move errors.
auto get_failed() const -> Counter const &
Failed moves by MoveCommand.
auto get_succeeded() const
Successful moves by MoveCommand.
void print_successful() const
Print successful moves.
void enqueue(move_tracker::move_type const t_move)
Push a Pachner move onto the move queue.
void print_results()
Display results of run.
Counter m_attempted_moves
The number of moves that were attempted by a MoveCommand.
auto get_rejected() const
Counter m_failed_moves
The number of moves that a MoveCommand failed to make due to an error.
auto get_proposed() const
auto CalculateA2(move_tracker::move_type const move) const noexcept
Calculate A2.
Counter m_succeeded_moves
The number of moves that succeeded in the MoveCommand.
Geometry< ManifoldType::dimension > m_geometry
The current geometry of the manifold.
auto operator()(ManifoldType const &t_manifold) -> ManifoldType
Call operator.
auto get_succeeded() const
auto Alpha() const noexcept
Counter m_proposed_moves
The number of moves the algorithm tried.
auto checkpoint() const noexcept
MoveStrategy(long double const Alpha, long double const K, long double const Lambda, Int_precision const passes, Int_precision const checkpoint)
Metropolis function object constructor.
MoveStrategy()=default
Default ctor.
auto Lambda() const noexcept
auto passes() const noexcept
Counter m_accepted_moves
The number of moves accepted by the algorithm.
auto try_move(move_tracker::move_type const move) -> bool
Try a move of the selected type.
auto get_accepted() const
auto get_attempted() const
auto CalculateA1(move_tracker::move_type move) const noexcept
Calculate A1.
auto initialize(ManifoldType t_manifold) -> std::optional< MoveCommand< ManifoldType > > try
Initialize the Metropolis algorithm.
Counter m_rejected_moves
The number of moves rejected by the algorithm.
The data and methods to track ergodic moves.
auto two_six_moves() -> auto &
Write access to (2,6) moves.
auto total() const noexcept
Total moves.
auto four_four_moves() -> auto &
Write access to (4,4) moves.
auto six_two_moves() -> auto &
Write access to (6,2) moves.
auto three_two_moves() -> auto &
Write access to (3,2) moves.
auto two_three_moves() -> auto &
Write access to (2,3) moves.