Drop7 Research
approaches/lifetime-objective/fast-engine/corpus.hppC++129 lines · 4.6 KB
#pragma once
// Shared helpers for the fast-engine gates, profile and benchmark: seed-lease
// bookkeeping, real-state harvesting and process memory readout.
//
// Seed lease SEEDLEASE-A52-FAST covers 0xa5270000-0xa5277fff.  Nothing in this
// approach touches a seed outside it.  Every program here is a CHECK-tier
// mechanical or timing operation and makes no strength claim, so no cohort role
// is consumed beyond marking the lease block as read.

#include "fast-engine.hpp"

#include <cstdint>
#include <cstdio>
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>

namespace drop7::fast {

inline constexpr std::uint32_t kLeaseFirst = 0xa527'0000u;
inline constexpr std::uint32_t kLeaseLast = 0xa527'7fffu;

// Sub-blocks, fixed here so two programs never overlap.
inline constexpr std::uint32_t kTrajectoryDeterministicSeeds = 0xa527'0000u;
inline constexpr std::uint32_t kTrajectorySearchSeeds = 0xa527'1000u;
inline constexpr std::uint32_t kSearchParitySeeds = 0xa527'2000u;
inline constexpr std::uint32_t kLeafCorpusSeeds = 0xa527'3000u;
inline constexpr std::uint32_t kProfileCorpusSeeds = 0xa527'4000u;
inline constexpr std::uint32_t kBenchmarkSeeds = 0xa527'5000u;

inline void requireLease(std::uint32_t seed) {
  if (seed < kLeaseFirst || seed > kLeaseLast) {
    std::ostringstream message;
    message << "seed 0x" << std::hex << seed
            << " is outside SEEDLEASE-A52-FAST [0xa5270000, 0xa5277fff]";
    throw std::runtime_error(message.str());
  }
}

// Peak resident set of the whole process, in bytes.
inline std::uint64_t peakResidentBytes() {
  std::ifstream status("/proc/self/status");
  std::string line;
  while (std::getline(status, line)) {
    if (line.rfind("VmHWM:", 0) == 0) {
      std::uint64_t kilobytes = 0;
      std::sscanf(line.c_str(), "VmHWM: %lu kB", &kilobytes);
      return kilobytes * 1024u;
    }
  }
  return 0;
}

inline std::uint64_t currentResidentBytes() {
  std::ifstream status("/proc/self/status");
  std::string line;
  while (std::getline(status, line)) {
    if (line.rfind("VmRSS:", 0) == 0) {
      std::uint64_t kilobytes = 0;
      std::sscanf(line.c_str(), "VmRSS: %lu kB", &kilobytes);
      return kilobytes * 1024u;
    }
  }
  return 0;
}

inline double loadAverage() {
  std::ifstream loadavg("/proc/loadavg");
  double one = -1.0;
  loadavg >> one;
  return one;
}

// Collects the states a real game actually visits at the root, using the
// supplied decider to advance play through the unmodified frozen engine.
template <typename Decider>
inline void harvestRootStates(std::uint32_t seed, int maximum_moves,
                              Decider& decide, std::vector<State>& out) {
  requireLease(seed);
  State state = initialHeadlessState(seed);
  while (!state.game_over && state.moves_played < maximum_moves) {
    out.push_back(state);
    int column = decide(state);
    if (column < 0 || !isLegal(state.board, column)) {
      column = centerFirstMove(state.board);
      if (column < 0) break;
    }
    MoveResult move;
    if (!playHeadlessMove(state, seed, column, move)) break;
  }
}

// Expands a root exactly the way the search does -- same column order, same
// stratified chance samples, same canonicalisation -- and records every state
// the search would evaluate at the requested remaining depth.  With
// `record_depth == 0` this is precisely the distribution of leaf states.
inline void harvestSearchStates(const State& state, int depth, int strata,
                                int record_depth, std::uint32_t policy_seed,
                                std::vector<State>& out, std::size_t limit) {
  if (out.size() >= limit) return;
  if (depth == record_depth) {
    out.push_back(state);
    return;
  }
  if (depth == 0 || state.game_over) return;
  const std::uint32_t state_seed =
      cfpi::detail::scenarioSeedForState(state, policy_seed, depth);
  for (const int column : cfpi::detail::kColumnOrder) {
    if (!isLegal(state.board, column)) continue;
    for (int sample = 0; sample < strata; ++sample) {
      if (out.size() >= limit) return;
      cfpi::detail::StratifiedRandom random{state_seed, sample, strata, 0};
      MoveResult move;
      if (!cfpi::detail::playMoveSampled(state, column, random, move)) continue;
      if (move.state.game_over) continue;
      move.state.score = 0;
      move.state.next_disc =
          cfpi::detail::sampledNextDisc(state_seed, sample, strata);
      bool ignored = false;
      const State next = cfpi::detail::canonicalState(move.state, ignored);
      harvestSearchStates(next, depth - 1, strata, record_depth, policy_seed,
                          out, limit);
    }
  }
}

}  // namespace drop7::fast