Drop7 Research
approaches/fair-expectimax/selective-depth/fair-cycle-boundary-depth5.cppC++599 lines · 24.9 KB
#define DROP7_FAIR_SELECTIVE_DEPTH_NO_MAIN
#include "fair-selective-depth.cpp"
#undef DROP7_FAIR_SELECTIVE_DEPTH_NO_MAIN

#include <algorithm>
#include <array>
#include <atomic>
#include <chrono>
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <fstream>
#include <future>
#include <iomanip>
#include <iostream>
#include <optional>
#include <stdexcept>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

// Uses completed fair-D5/w2 only when the visible phase is exactly one full
// five-move rise cycle away.  All other
// decisions use the reference full-width fair-D4 policy.  A {4,5} ablation is
// eligible only when the primary policy fails its fitting gate.
namespace drop7::fair_cycle_boundary_depth5 {

namespace selective = drop7::fair_selective_depth;
namespace d4 = drop7::fair_only_depth4;
namespace frozen = drop7::fair_only_horizon;

constexpr std::uint32_t kFittingSeedStart = 0x3de7'0000u;
constexpr std::uint32_t kHeldoutSeedStart = 0x3de8'0000u;
constexpr std::uint32_t kScreenSeedStart = 0x3eb5'0000u;
constexpr std::uint32_t kConfirmationSeedStart = 0x3eb6'0000u;
constexpr int kFittingGames = 4;
constexpr int kHeldoutGames = 8;
constexpr int kScreenGames = 8;
constexpr int kConfirmationGames = 16;
constexpr int kMaximumMoves = 1'000;
constexpr int kParallelism = 4;
constexpr double kMaximumThroughputRegression = 0.01;
constexpr double kMaximumProjectedWallSeconds = 40.0 * 60.0;
// Worst case includes the optional fitting ablation and every later gate.
constexpr double kFirstPairProjectionMultiplier = 10.5;

enum class CycleKind { kD4, kPhase5, kPhase45 };

struct CycleSpec {
  const char* name = "";
  CycleKind kind = CycleKind::kD4;
};

constexpr CycleSpec kBaseline{"fair-d4", CycleKind::kD4};
constexpr CycleSpec kPrimary{"cycle-boundary-d5w2-phase5",
                             CycleKind::kPhase5};
constexpr CycleSpec kAblation{"cycle-boundary-d5w2-phases45",
                              CycleKind::kPhase45};

constexpr selective::PolicySpec artifactSpec(const CycleSpec& spec) {
  if (spec.kind == CycleKind::kD4) return selective::kBaseline;
  return {spec.name, selective::PolicyKind::kPhaseAligned, 5, 2};
}

static_assert(selective::kWorstD5W2Work == 2'760'835);
static_assert(selective::kWorstD5W2Cache == 38'885);
static_assert(selective::kWorstD5W2Work <
              selective::kMaximumSelectiveWork);
static_assert(selective::kWorstD5W2Cache <
              selective::kMaximumCacheEntries);
static_assert(frozen::kChanceSamples == 5);
static_assert(kLevelBonus == 7'000);
static_assert(kFittingSeedStart + kFittingGames < kHeldoutSeedStart);
static_assert(kHeldoutSeedStart + kHeldoutGames < kScreenSeedStart);
static_assert(kScreenSeedStart + kScreenGames < kConfirmationSeedStart);
static_assert((kFittingSeedStart >> 24) != 0x7du &&
              (kFittingSeedStart >> 24) != 0xd7u);
static_assert((kHeldoutSeedStart >> 24) != 0x7du &&
              (kHeldoutSeedStart >> 24) != 0xd7u);
static_assert((kScreenSeedStart >> 24) != 0x7du &&
              (kScreenSeedStart >> 24) != 0xd7u);
static_assert((kConfirmationSeedStart >> 24) != 0x7du &&
              (kConfirmationSeedStart >> 24) != 0xd7u);

bool usesDepth5(const CycleSpec& spec, int moves_remaining) {
  if (spec.kind == CycleKind::kPhase5) return moves_remaining == 5;
  if (spec.kind == CycleKind::kPhase45) return moves_remaining >= 4;
  return false;
}

selective::SearchDecision chooseCycleAction(const State& source,
                                            const CycleSpec& spec) {
  if (!usesDepth5(spec, source.moves_remaining)) {
    return selective::wrapDepth4(d4::chooseDepth4Action(source));
  }
  const selective::SearchDecision result = selective::chooseUniformSelective(
      source, selective::kUniformMenu[0]);
  if (!result.complete || !result.selective_complete || result.used_fallback ||
      !result.full_root || result.requested_depth != 5 ||
      result.internal_width != 2) {
    throw std::runtime_error("cycle-boundary D5/w2 failed to complete");
  }
  return result;
}

selective::GameResult runGame(const CycleSpec& spec, std::uint32_t seed,
                              std::string_view phase_name) {
  const auto started = std::chrono::steady_clock::now();
  State state = initialHeadlessState(seed);
  selective::GameResult result;
  result.seed = seed;
  while (!state.game_over && state.moves_played < kMaximumMoves) {
    const int phase_index = state.moves_remaining - 1;
    if (phase_index < 0 || phase_index >= kMovesPerLevel) {
      throw std::runtime_error("invalid cycle-boundary phase");
    }
    const selective::SearchDecision decision = chooseCycleAction(state, spec);
    if (!decision.complete || !decision.full_root ||
        !isLegal(state.board, decision.action)) {
      throw std::runtime_error("cycle-boundary policy chose invalid action");
    }
    selective::PhaseStats& phase = result.phase[phase_index];
    ++phase.decisions;
    phase.policy_work += decision.work;
    result.work += decision.work;
    result.selective_work += decision.selective_work;
    result.fallback_work += decision.fallback_work;
    result.nodes += decision.nodes;
    result.cache_hits += decision.cache_hits;
    result.ordering_work += decision.ordering_work;
    result.peak_cache_entries =
        std::max(result.peak_cache_entries, decision.peak_cache_entries);
    result.root_width_violations += !decision.full_root;
    if (usesDepth5(spec, state.moves_remaining)) {
      if (!decision.selective_complete || decision.used_fallback) {
        throw std::runtime_error("proved D5/w2 unexpectedly fell back");
      }
    }
    MoveResult move;
    if (!playHeadlessMove(state, seed, decision.action, move)) {
      throw std::runtime_error("cycle-boundary transition failed");
    }
    selective::observeMove(move, result, phase);
  }
  result.score = state.score;
  result.moves = state.moves_played;
  result.censored = !state.game_over;
  result.peak_rss_bytes = selective::peakRssBytes();
  result.elapsed_seconds = std::chrono::duration<double>(
                               std::chrono::steady_clock::now() - started)
                               .count();
  selective::reportGame(phase_name, artifactSpec(spec), result);
  return result;
}

selective::Cohort runCohort(const CycleSpec& spec,
                            std::uint32_t seed_start, int games,
                            std::string_view phase_name) {
  const auto started = std::chrono::steady_clock::now();
  selective::Cohort result;
  result.spec = artifactSpec(spec);
  result.maximum_moves = kMaximumMoves;
  result.games.resize(games);
  std::atomic<int> next_game{0};
  std::vector<std::future<void>> workers;
  for (int worker = 0; worker < std::min(kParallelism, games); ++worker) {
    workers.push_back(std::async(std::launch::async, [&] {
      for (;;) {
        const int game = next_game.fetch_add(1);
        if (game >= games) return;
        result.games[game] = runGame(
            spec, seed_start + static_cast<std::uint32_t>(game), phase_name);
      }
    }));
  }
  for (auto& worker : workers) worker.get();
  result.wall_seconds = std::chrono::duration<double>(
                            std::chrono::steady_clock::now() - started)
                            .count();
  return result;
}

void appendCohort(selective::Cohort& target,
                  selective::Cohort source) {
  target.games.insert(target.games.end(),
                      std::make_move_iterator(source.games.begin()),
                      std::make_move_iterator(source.games.end()));
  target.wall_seconds += source.wall_seconds;
}

struct Gate {
  selective::Comparison comparison{};
  int leave_one_out_positive_both = 0;
  bool means_positive = false;
  bool throughput_ok = false;
  bool fitting_passed = false;
  bool evaluation_passed = false;
};

int positiveLeaveOneOut(const selective::Cohort& baseline,
                        const selective::Cohort& candidate) {
  if (baseline.games.size() != candidate.games.size() ||
      baseline.games.size() < 2) {
    throw std::invalid_argument("invalid leave-one-out cohorts");
  }
  double score_total = 0.0;
  double move_total = 0.0;
  for (std::size_t index = 0; index < baseline.games.size(); ++index) {
    score_total += candidate.games[index].score - baseline.games[index].score;
    move_total += candidate.games[index].moves - baseline.games[index].moves;
  }
  int positive = 0;
  for (std::size_t index = 0; index < baseline.games.size(); ++index) {
    const double score =
        candidate.games[index].score - baseline.games[index].score;
    const double moves =
        candidate.games[index].moves - baseline.games[index].moves;
    positive += score_total - score > 0.0 && move_total - moves > 0.0;
  }
  return positive;
}

Gate gate(const selective::Cohort& baseline,
          const selective::Cohort& candidate, bool fitting) {
  const selective::Summary baseline_summary = selective::summarize(baseline);
  const selective::Summary candidate_summary = selective::summarize(candidate);
  Gate result;
  result.comparison = selective::compare(baseline, candidate);
  result.leave_one_out_positive_both =
      positiveLeaveOneOut(baseline, candidate);
  result.means_positive = result.comparison.both_means_positive;
  result.throughput_ok =
      candidate_summary.clears_per_move >=
          (1.0 - kMaximumThroughputRegression) *
              baseline_summary.clears_per_move &&
      candidate_summary.reveals_per_move >=
          (1.0 - kMaximumThroughputRegression) *
              baseline_summary.reveals_per_move;
  result.fitting_passed = result.means_positive && result.throughput_ok &&
                          result.leave_one_out_positive_both >= 3;
  result.evaluation_passed = result.means_positive && result.throughput_ok;
  if (!fitting) result.fitting_passed = false;
  return result;
}

struct Stage {
  selective::Cohort baseline;
  selective::Cohort candidate;
  selective::Summary baseline_summary;
  selective::Summary candidate_summary;
  Gate result;
};

Stage makeStage(selective::Cohort baseline,
                selective::Cohort candidate, bool fitting) {
  Stage result;
  result.baseline = std::move(baseline);
  result.candidate = std::move(candidate);
  result.baseline_summary = selective::summarize(result.baseline);
  result.candidate_summary = selective::summarize(result.candidate);
  result.result = gate(result.baseline, result.candidate, fitting);
  return result;
}

Stage runStage(const CycleSpec& candidate, std::uint32_t seed_start,
               int games, std::string_view phase_name) {
  return makeStage(
      runCohort(kBaseline, seed_start, games,
                std::string(phase_name) + "-baseline"),
      runCohort(candidate, seed_start, games,
                std::string(phase_name) + "-candidate"),
      false);
}

void writeGate(std::ostream& output, const Gate& result) {
  output << "{\"comparison\":";
  selective::writeComparison(output, result.comparison);
  output << ",\"leaveOneOutPositiveBoth\":"
         << result.leave_one_out_positive_both
         << ",\"meansPositive\":"
         << (result.means_positive ? "true" : "false")
         << ",\"throughputOk\":"
         << (result.throughput_ok ? "true" : "false")
         << ",\"fittingPassed\":"
         << (result.fitting_passed ? "true" : "false")
         << ",\"evaluationPassed\":"
         << (result.evaluation_passed ? "true" : "false") << '}';
}

void writeStage(std::ostream& output, const Stage& stage) {
  output << "{\"baseline\":";
  selective::writeCohort(output, stage.baseline, stage.baseline_summary);
  output << ",\"candidate\":";
  selective::writeCohort(output, stage.candidate, stage.candidate_summary);
  output << ",\"gate\":";
  writeGate(output, stage.result);
  output << '}';
}

struct Options {
  std::string output = "/tmp/drop7-fair-cycle-boundary-depth5.json";
};

Options parseOptions(int argc, char** argv, int begin) {
  Options result;
  for (int index = begin; index < argc; index += 2) {
    if (index + 1 >= argc) throw std::invalid_argument("missing option value");
    const std::string argument = argv[index];
    if (argument == "--output") {
      result.output = argv[index + 1];
    } else {
      throw std::invalid_argument("unknown option " + argument);
    }
  }
  return result;
}

void writePausedArtifact(const Options& options,
                         const selective::Cohort& baseline,
                         const selective::Cohort& candidate,
                         double first_pair_wall, double projected_wall) {
  std::ofstream output(options.output);
  if (!output) throw std::runtime_error("could not open paused artifact");
  const selective::Summary baseline_summary = selective::summarize(baseline);
  const selective::Summary candidate_summary = selective::summarize(candidate);
  output << std::setprecision(12)
         << "{\"experiment\":\"fair-cycle-boundary-depth5\""
         << ",\"pilotPairOnly\":true"
         << ",\"formalInference\":false"
         << ",\"conclusion\":\"rejected-paused-by-preregistered-runtime-gate\""
         << ",\"pausedForProjectedWall\":true"
         << ",\"readGameSeeds\":[\"0x3de70000\"]"
         << ",\"untouchedRanges\":[\"0x3de70001...003 fitting remainder\",\"0x3de70000...003 phase45 ablation\",\"0x3de80000...007 heldout\",\"0x3eb50000...007 screen\",\"0x3eb60000...00f confirmation\",\"0x7d... protected\",\"0xd7... protected\"]"
         << ",\"firstPairWallSeconds\":" << first_pair_wall
         << ",\"projectedMaximumWallSeconds\":" << projected_wall
         << ",\"firstPairBaseline\":";
  selective::writeCohort(output, baseline, baseline_summary);
  output << ",\"firstPairCandidate\":";
  selective::writeCohort(output, candidate, candidate_summary);
  output << "}\n";
}

bool selfTest(std::ostream& output) {
  const bool dependency_test = selective::selfTest(output);
  State source = frozen::fixtureState(frozen::kTypeScriptFixtures[1]);
  for (const int column : {0, 1, 5, 6}) {
    for (int row = 0; row < kBoardSize; ++row) {
      source.board[indexOf(row, column)] = kSolid;
    }
  }
  source.game_over = false;
  source.moves_remaining = 5;
  const selective::SearchDecision primary = chooseCycleAction(source, kPrimary);
  const selective::SearchDecision repeat = chooseCycleAction(source, kPrimary);
  State reflected = source;
  reflected.board = cfpi::detail::mirrorBoard(source.board);
  const selective::SearchDecision mirror = chooseCycleAction(reflected, kPrimary);
  State metadata = source;
  metadata.score = 7'777'777;
  metadata.level = 88;
  metadata.moves_played = 654;
  const selective::SearchDecision metadata_result =
      chooseCycleAction(metadata, kPrimary);

  State phase4 = source;
  phase4.moves_remaining = 4;
  const selective::SearchDecision primary_phase4 =
      chooseCycleAction(phase4, kPrimary);
  const d4::SearchDecision exact_phase4 = d4::chooseDepth4Action(phase4);
  const selective::SearchDecision ablation_phase4 =
      chooseCycleAction(phase4, kAblation);
  State phase3 = source;
  phase3.moves_remaining = 3;
  const selective::SearchDecision primary_phase3 =
      chooseCycleAction(phase3, kPrimary);

  const bool deterministic =
      primary.action == repeat.action && primary.work == repeat.work &&
      primary.cache_hits == repeat.cache_hits;
  const bool reflection_safe =
      mirror.action == kBoardSize - 1 - primary.action &&
      mirror.work == primary.work;
  const bool public_only = metadata_result.action == primary.action &&
                           metadata_result.work == primary.work;
  const bool exact_phase_routing =
      primary.selective_complete && !primary.used_fallback &&
      primary.requested_depth == 5 && primary.internal_width == 2 &&
      primary_phase4.action == exact_phase4.action &&
      primary_phase4.work == exact_phase4.work &&
      !primary_phase4.selective_complete &&
      ablation_phase4.selective_complete &&
      !ablation_phase4.used_fallback &&
      primary_phase3.requested_depth == 4 &&
      !primary_phase3.selective_complete;
  const bool legal = isLegal(source.board, primary.action) &&
                     isLegal(phase4.board, primary_phase4.action) &&
                     isLegal(phase4.board, ablation_phase4.action);
  const bool complete = primary.complete && primary.full_root &&
                        primary_phase4.complete && primary_phase4.full_root &&
                        ablation_phase4.complete && ablation_phase4.full_root;
  const bool bounded =
      primary.work <= selective::kMaximumSelectiveWork &&
      primary.peak_cache_entries <= selective::kMaximumCacheEntries &&
      ablation_phase4.work <= selective::kMaximumSelectiveWork &&
      ablation_phase4.peak_cache_entries <=
          selective::kMaximumCacheEntries;
  const bool protocol =
      kFittingSeedStart == 0x3de7'0000u &&
      kHeldoutSeedStart == 0x3de8'0000u &&
      kScreenSeedStart == 0x3eb5'0000u &&
      kConfirmationSeedStart == 0x3eb6'0000u && kFittingGames == 4 &&
      kHeldoutGames == 8 && kScreenGames == 8 &&
      kConfirmationGames == 16 && kMaximumMoves == 1'000;
  const bool passed = dependency_test && deterministic && reflection_safe &&
                      public_only && exact_phase_routing && legal && complete &&
                      bounded && protocol;
  output << std::setprecision(12)
         << "FAIR_CYCLE_BOUNDARY_DEPTH5_SELF_TEST {\"passed\":"
         << (passed ? "true" : "false")
         << ",\"dependencyTest\":"
         << (dependency_test ? "true" : "false")
         << ",\"deterministic\":" << (deterministic ? "true" : "false")
         << ",\"reflectionSafe\":"
         << (reflection_safe ? "true" : "false")
         << ",\"publicMetadataAndGameSeedBlind\":"
         << (public_only ? "true" : "false")
         << ",\"exactPhaseRouting\":"
         << (exact_phase_routing ? "true" : "false")
         << ",\"legal\":" << (legal ? "true" : "false")
         << ",\"completeFullRoot\":"
         << (complete ? "true" : "false")
         << ",\"bounded\":" << (bounded ? "true" : "false")
         << ",\"phase5Action\":" << primary.action
         << ",\"phase5Work\":" << primary.work
         << ",\"worstD5W2Work\":" << selective::kWorstD5W2Work
         << ",\"worstD5W2Cache\":" << selective::kWorstD5W2Cache
         << "}\n";
  return passed;
}

int run(const Options& options, std::ostream& report) {
  const auto all_started = std::chrono::steady_clock::now();
  selective::Cohort fitting_baseline =
      runCohort(kBaseline, kFittingSeedStart, 1, "fit-first-baseline");
  selective::Cohort fitting_primary =
      runCohort(kPrimary, kFittingSeedStart, 1, "fit-first-primary");
  const double first_pair_wall =
      fitting_baseline.wall_seconds + fitting_primary.wall_seconds;
  const double projected_wall =
      first_pair_wall * kFirstPairProjectionMultiplier;
  {
    const std::lock_guard<std::mutex> lock(selective::progress_mutex);
    std::cerr << "first-pair wall " << first_pair_wall
              << " seconds, projected gated maximum " << projected_wall
              << " seconds\n";
  }
  if (projected_wall > kMaximumProjectedWallSeconds) {
    writePausedArtifact(options, fitting_baseline, fitting_primary,
                        first_pair_wall, projected_wall);
    report << "FAIR_CYCLE_BOUNDARY_DEPTH5_PAUSED {\"firstPairWallSeconds\":"
           << first_pair_wall << ",\"projectedMaximumWallSeconds\":"
           << projected_wall << ",\"limitSeconds\":"
           << kMaximumProjectedWallSeconds << ",\"artifact\":\""
           << options.output << "\"}\n";
    return 3;
  }

  appendCohort(fitting_baseline,
               runCohort(kBaseline, kFittingSeedStart + 1,
                         kFittingGames - 1, "fit-baseline"));
  appendCohort(fitting_primary,
               runCohort(kPrimary, kFittingSeedStart + 1,
                         kFittingGames - 1, "fit-primary"));
  Stage primary_fit =
      makeStage(fitting_baseline, fitting_primary, true);
  std::optional<Stage> ablation_fit;
  const CycleSpec* selected = nullptr;
  if (primary_fit.result.fitting_passed) {
    selected = &kPrimary;
  } else {
    selective::Cohort ablation =
        runCohort(kAblation, kFittingSeedStart, kFittingGames,
                  "fit-ablation");
    ablation_fit = makeStage(primary_fit.baseline, std::move(ablation), true);
    if (ablation_fit->result.fitting_passed) selected = &kAblation;
  }

  std::optional<Stage> heldout;
  std::optional<Stage> screen;
  std::optional<Stage> confirmation;
  bool heldout_passed = false;
  bool screen_passed = false;
  bool confirmation_passed = false;
  if (selected != nullptr) {
    heldout = runStage(*selected, kHeldoutSeedStart, kHeldoutGames, "heldout");
    heldout_passed = heldout->result.evaluation_passed;
  }
  if (heldout_passed) {
    screen = runStage(*selected, kScreenSeedStart, kScreenGames, "screen");
    screen_passed = screen->result.means_positive;
  }
  if (screen_passed) {
    confirmation = runStage(*selected, kConfirmationSeedStart,
                            kConfirmationGames, "confirmation");
    confirmation_passed = confirmation->result.evaluation_passed;
  }
  const double total_wall = std::chrono::duration<double>(
                                std::chrono::steady_clock::now() - all_started)
                                .count();

  std::ofstream artifact(options.output);
  if (!artifact) throw std::runtime_error("could not open cycle artifact");
  artifact << std::setprecision(12)
           << "{\n  \"experiment\":\"fair-cycle-boundary-depth5\",\n"
           << "  \"preregistered\":true,\n"
           << "  \"hypothesis\":\"D5w2 only at movesRemaining 5 spans one covered-row rise cycle\",\n"
           << "  \"search\":{\"d4\":\"qualified-full-width\""
           << ",\"cycleSearch\":\"completed-selective-d5-w2-s5\""
           << ",\"worstD5W2Work\":" << selective::kWorstD5W2Work
           << ",\"worstD5W2Cache\":" << selective::kWorstD5W2Cache
           << ",\"maximumMoves\":" << kMaximumMoves
           << ",\"parallelism\":" << kParallelism << "},\n"
           << "  \"wallProjection\":{\"firstPairSeconds\":"
           << first_pair_wall << ",\"multiplier\":"
           << kFirstPairProjectionMultiplier << ",\"projectedSeconds\":"
           << projected_wall << ",\"limitSeconds\":"
           << kMaximumProjectedWallSeconds << ",\"paused\":false},\n"
           << "  \"fittingPrimary\":";
  writeStage(artifact, primary_fit);
  artifact << ",\n  \"fittingAblation\":";
  if (ablation_fit) writeStage(artifact, *ablation_fit);
  else artifact << "null";
  artifact << ",\n  \"selected\":";
  if (selected == nullptr) artifact << "null";
  else selective::writeSpec(artifact, artifactSpec(*selected));
  artifact << ",\n  \"heldout\":";
  if (heldout) writeStage(artifact, *heldout); else artifact << "null";
  artifact << ",\n  \"heldoutPassed\":"
           << (heldout_passed ? "true" : "false")
           << ",\n  \"screen\":";
  if (screen) writeStage(artifact, *screen); else artifact << "null";
  artifact << ",\n  \"screenPassed\":"
           << (screen_passed ? "true" : "false")
           << ",\n  \"confirmation\":";
  if (confirmation) writeStage(artifact, *confirmation);
  else artifact << "null";
  artifact << ",\n  \"confirmationPassed\":"
           << (confirmation_passed ? "true" : "false")
           << ",\n  \"qualified\":"
           << (heldout_passed && screen_passed && confirmation_passed
                   ? "true"
                   : "false")
           << ",\n  \"peakRssBytes\":" << selective::peakRssBytes()
           << ",\n  \"totalWallSeconds\":" << total_wall << "\n}\n";
  artifact.close();

  report << std::fixed << std::setprecision(6)
         << "FAIR_CYCLE_BOUNDARY_DEPTH5_RESULT {\"selected\":";
  if (selected == nullptr) report << "null";
  else report << '\"' << selected->name << '\"';
  report << ",\"primaryFitPassed\":"
         << (primary_fit.result.fitting_passed ? "true" : "false")
         << ",\"ablationRan\":" << (ablation_fit ? "true" : "false")
         << ",\"heldoutPassed\":" << (heldout_passed ? "true" : "false")
         << ",\"screenRan\":" << (screen ? "true" : "false")
         << ",\"screenPassed\":" << (screen_passed ? "true" : "false")
         << ",\"confirmationRan\":"
         << (confirmation ? "true" : "false")
         << ",\"confirmationPassed\":"
         << (confirmation_passed ? "true" : "false")
         << ",\"peakRssBytes\":" << selective::peakRssBytes()
         << ",\"totalWallSeconds\":" << total_wall
         << ",\"artifact\":\"" << options.output << "\"}\n";
  return 0;
}

}  // namespace drop7::fair_cycle_boundary_depth5

int main(int argc, char** argv) {
  try {
    if (argc >= 2 && std::string_view(argv[1]) == "--self-test") {
      return drop7::fair_cycle_boundary_depth5::selfTest(std::cout)
                 ? EXIT_SUCCESS
                 : EXIT_FAILURE;
    }
    if (argc >= 2 && std::string_view(argv[1]) == "--run") {
      const auto options =
          drop7::fair_cycle_boundary_depth5::parseOptions(argc, argv, 2);
      return drop7::fair_cycle_boundary_depth5::run(options, std::cout);
    }
    std::cerr << "usage: drop7_fair_cycle_boundary_depth5 --self-test | "
                 "--run [--output PATH]\n";
    return 2;
  } catch (const std::exception& error) {
    std::cerr << "error: " << error.what() << '\n';
    return 1;
  }
}