#!/usr/bin/env bash
# crates/mrs-bench/systems/mrs/starexec_run_default
#
# StarExec solver entry point (as opposed to invoke.sh, which is used by
# the local benchmark harness and takes an explicit time-limit argument).
#
# StarExec calls a solver's `starexec_run_<config>` script with a single
# argument (the problem file path) and enforces the configured wall-clock
# / CPU limits itself via SIGALRM/SIGXCPU; it does not pass the limit on
# the command line. It does, however, export STAREXEC_WALLCLOCK_LIMIT
# (seconds) into the environment for the running process, which we use
# (with a conservative fallback and safety margin) so mrs's own internal
# deadline fires and flushes a clean SZS status line before StarExec's
# external signal could kill the process mid-search with no output.
#
# Division/category detection uses `--auto-schedule` (content-based:
# presence of equality literals, function symbols, unit-equality-only
# clause sets) rather than parsing the problem's directory path, because
# StarExec sometimes executes solvers using absolute flat paths (e.g.
# /starexec/sandbox/problem_123.p) that carry no division information —
# see docs/FAQ.md for the full rationale. This also means this script
# does not need to be told which division it is running.
set -euo pipefail

PROBLEM="${1:?Usage: starexec_run_default <problem_path>}"

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BINARY="${SCRIPT_DIR}/mrs"
if [[ ! -x "${BINARY}" ]]; then
    echo "% SZS status Error (mrs binary not found next to starexec_run_default)"
    exit 1
fi

# %include resolution: prefer an already-set TPTP env var (StarExec sets
# this for jobs that need it); otherwise fall back to a bundled copy if
# one was shipped alongside the solver package.
if [[ -z "${TPTP:-}" && -d "${SCRIPT_DIR}/TPTP" ]]; then
    export TPTP="${SCRIPT_DIR}/TPTP"
fi

WALLCLOCK="${STAREXEC_WALLCLOCK_LIMIT:-240}"
SOFT_TIME=$(( WALLCLOCK > 5 ? WALLCLOCK - 5 : WALLCLOCK ))

# Raise the stack limit for the parsing/clausification phase (mrs_tptp's
# recursive-descent parser and mrs_cnf's NNF/Skolemization/CNF pipeline both
# run on the main thread, before run_schedule spawns worker threads -- see
# docs/STATUS.md). crates/mrs-tptp/doc/technical.md documents deeply nested
# formulas as a stack-overflow risk. Best-effort: some sandboxes cap the
# hard limit and refuse to raise the soft limit further, which prints a
# warning but does not abort under `set -e`.
ulimit -s unlimited 2>/dev/null || true

# `ulimit -s` above only covers the main thread. The strategy portfolio
# (std::thread::scope in strategy.rs, default 8 workers) spawns worker
# threads with Rust's own runtime default of 2 MiB (DEFAULT_MIN_STACK_SIZE,
# smaller than the typical 8 MiB main-thread default) unless RUST_MIN_STACK
# is set in the environment before the process starts. Those threads run
# genuinely recursive code from mrs-unify/mrs-core/mrs-index throughout the
# entire given-clause search -- a stack overflow there triggers Rust's
# abort() handler, killing the whole process with zero output, which is
# worse than a clean timeout. 64 MiB matches the precedent already set by
# crates/mrs-tptp/examples/parse_folder.rs's stack_size(64 * 1024 * 1024)
# and gives on the order of 300,000 levels of recursion headroom --
# comfortably more than any real TPTP problem's term nesting depth, at
# negligible cost (thread stacks are lazily-committed virtual memory, not
# counted against RSS until used).
export RUST_MIN_STACK=67108864

exec "${BINARY}" --time "${SOFT_TIME}" --workers "${MRS_WORKERS:-8}" --auto-schedule "${PROBLEM}"
