#!/usr/bin/env bash
# One-command check of every ancillary program that a proof in the paper depends on
# (first table of the section "Computer certificates").
#
#   ./verify_all.sh          quick mode: every check except the two RSC certificate verifiers
#   ./verify_all.sh --full   also the two RSC certificate verifiers (Proposition rsc-cert)
#   PROCS=8 ./verify_all.sh --full   number of processes for the RSC verifiers (default 4)
#   PYTHON=/path/to/python3 ./verify_all.sh   interpreter to use (default python3)
#   LOGDIR=/some/folder ./verify_all.sh       where the logs go (default verify-logs/ in this folder)
#
# Needs Python 3 with python-flint, NumPy and SciPy; requirements.txt pins the tested versions
# (python3 -m venv .venv && .venv/bin/pip install -r requirements.txt && PYTHON=.venv/bin/python ./verify_all.sh). Each program writes to standard
# output; this script saves it as $LOGDIR/<program>.log (default LOGDIR: verify-logs/ in this folder) and
# compares it with the recorded output <program>.out of the authors' run, ignoring lines that contain
# "time" (timings). For the two RSC verifiers, whose recorded outputs carry run headers, it requires the
# line VERIFIED instead. The script stops at the first program that exits with an error or whose output
# differs.
set -euo pipefail
# A relative LOGDIR or PYTHON path is taken relative to the current folder (plain shell, so that it
# also works with the BSD tools of macOS, whose realpath has no -m).
case "${LOGDIR:-}" in
  "" | /*) ;;
  *) LOGDIR=$PWD/$LOGDIR ;;
esac
PY=${PYTHON:-python3}
case "$PY" in
  /*) ;;
  */*) PY=$PWD/$PY ;;
esac
cd "$(dirname "$0")"
PROCS=${PROCS:-4}
FULL=0
LOGDIR=${LOGDIR:-$PWD/verify-logs}
mkdir -p "$LOGDIR"
[ "${1:-}" = "--full" ] && FULL=1

run() {  # run <folder> <log name> <command...>
  local dir=$1 log=$2; shift 2
  local start=$SECONDS
  printf '%-48s' "$log"
  (cd "$dir" && "$@" > "$LOGDIR/$log.log" 2>&1) || { echo "FAILED (see $LOGDIR/$log.log)"; exit 1; }
  if [ "$log" = rsc-verify ] || [ "$log" = rsc-verify-independent ]; then
    # the recorded outputs carry run headers and timings; the verdict line is what counts
    grep -q "VERIFIED" "$LOGDIR/$log.log" || { echo "FAILED (no VERIFIED line in $LOGDIR/$log.log)"; exit 1; }
    echo "VERIFIED ($((SECONDS - start)) s)"
  elif diff -q <(grep -vi time "$LOGDIR/$log.log") <(grep -vi time "$dir/$log.out") > /dev/null; then
    echo "ok, same as $log.out ($((SECONDS - start)) s)"
  else
    echo "FAILED (output differs from $dir/$log.out; see $LOGDIR/$log.log)"; exit 1
  fi
}

echo "== checksums"
# The arXiv copy of these files leaves out the RSC certificate (45 MB; arXiv would store it unpacked,
# 152 MB); it is in the archived copy and on the companion site. Without it, the other checksums are
# checked and --full stops.
SUMS=SHA256SUMS
CERT=rsc/rsc-certificate.json.gz
if [ ! -f "$CERT" ]; then
  [ "$FULL" = 1 ] && { echo "$CERT is missing; download it from the archived copy (see README.md)."; exit 1; }
  SUMS=$(mktemp); grep -v "  $CERT\$" SHA256SUMS > "$SUMS"
  echo "($CERT not present: checking the other files)"
fi
if command -v sha256sum > /dev/null; then
  sha256sum -c --quiet "$SUMS"
else  # older macOS
  shasum -a 256 -c --quiet "$SUMS"
fi
echo "SHA256SUMS ok"

echo "== RS, RS-theta, lobsters, deterministic, component count, DST, Paired Domination"
run . rs_closed_form_interval      "$PY" rs_closed_form_interval.py
run . verify_cert                  "$PY" verify_cert.py cert_final_0.json cert_final_1.json
run . verify_cert_indep            "$PY" verify_cert_indep.py cert_final_0.json cert_final_1.json
run . v_cert_primal                "$PY" v_cert_primal.py cert_final_0.json cert_final_1.json
run . cz_bounds                    "$PY" cz_bounds.py
run . rst_rate_interval            "$PY" rst_rate_interval.py
run . lobster_rate_certificate     "$PY" lobster_rate_certificate.py
run . rates                        "$PY" rates.py
run . v_rates                      "$PY" v_rates.py
run . component_count_rate_interval "$PY" component_count_rate_interval.py
run . dst_certificate_verify       "$PY" dst_certificate_verify.py dst_certificates.json
run . paired_rate_certificate      "$PY" paired_rate_certificate.py

echo "== RSC"
run rsc rsc-credits                "$PY" rsc-credits.py
if [ "$FULL" = 1 ]; then
  run rsc rsc-verify               "$PY" rsc-verify.py rsc-certificate.json.gz "$PROCS"
  run rsc rsc-verify-independent   "$PY" rsc-verify-independent.py rsc-certificate.json.gz "$PROCS"
else
  echo "(skipped the two RSC certificate verifiers; run with --full, about 46 and 16 minutes with 4 processes)"
fi
echo "All checks passed."
