Drop7 Research
approaches/lifetime-objective/planner-distill/student-probe.cppC++55 lines · 1.8 KB
// student-probe - evaluates the exported student on states read from stdin.
//
//   student-probe model.d7pdst < states.txt
//
// One state per line: 49 cell values, then the visible next disc, then the
// moves until the next rise.  One float per line on stdout: the residual head.
//
// This exists so `parity_student.py` can compare the native path against the
// PyTorch checkpoint without linking anything from PyTorch into the search
// binary.  The native path is the one that plays.

#include "corpus.hpp"
#include "student.hpp"

#include <cstdio>
#include <iostream>
#include <string>
#include <vector>

int main(int argc, char** argv) {
  if (argc < 2) {
    std::cerr << "usage: student-probe model.d7pdst < states\n";
    return 2;
  }
  drop7::distill::Student model(argv[1]);
  std::vector<float> scratch(
      static_cast<std::size_t>(model.hidden() + model.mid() + 16));
  std::uint8_t board[drop7::distill::kCells];
  int next_disc = 0;
  int moves_remaining = 0;
  std::string line;
  while (std::getline(std::cin, line)) {
    if (line.empty()) continue;
    std::size_t cursor = 0;
    const auto number = [&]() {
      while (cursor < line.size() && line[cursor] == ' ') ++cursor;
      int value = 0;
      while (cursor < line.size() && line[cursor] >= '0' && line[cursor] <= '9') {
        value = value * 10 + (line[cursor++] - '0');
      }
      return value;
    };
    for (int index = 0; index < drop7::distill::kCells; ++index) {
      board[index] = static_cast<std::uint8_t>(number());
    }
    next_disc = number();
    moves_remaining = number();
    float residual = 0.0f;
    float lifetime = 0.0f;
    model.evaluate(board, next_disc, moves_remaining, scratch.data(), residual,
                   lifetime);
    std::printf("%.7g\n", static_cast<double>(residual));
  }
  return 0;
}