#!/bin/sh # Rebuilds the tractable experiments of the study and re-checks the certificates. # # sh code/reproduce.sh default : bounded reproduction, about 25 min on 16 cores (our run: steps 0-7 in 26 min # before trimming; now bounded well inside the platform's 60 min limit) # QUICK=1 sh code/reproduce.sh checks only, about 10 min # FULL=1 sh code/reproduce.sh everything (adds roughly 5-6 h; see step 11) # # Where it writes. Nothing in the shipped archive is modified: the script makes a working copy # of code/ and of the small result files under results/reproduction/work/ (symlinking the # shipped certificate directory and .pydeps), runs every step there, writes regenerated # certificates to results/reproduction/work/certificates/, and finally compares the working # copy with the shipped files (code/tools/compare_reproduction.py) into # results/reproduction/summary.json. Its execution log is results/reproduction/experiment-log.jsonl. # INPLACE=1 runs in the archive itself instead (appends to the shipped record files; not # recommended), REPRO_WORK=DIR chooses another working directory. # # What each mode does (manuscript Appendix C): # QUICK : steps 0-3, 9, 10. Builds the tools, re-runs the graph-invariant, order-independence and # lemma checks, replays every stored witness, and re-verifies with drat-trim the shipped # fort-cover proofs for n = 11..21 and a fixed sample of the boundary proofs # (n = 24, 26..40, 60) if they are present on disk; rebuilds tables and metrics # in the working copy; re-runs the Stage 5 robustness checks that need no enumeration. # Proofs not present on disk are reported as "skipped", never as verified. # default : adds steps 4-8: exhaustive oracle n = 11..22 (rows 11..22 of Table 2), the boundary # table for p = 16..20, the certified window for 26 <= n <= 40 regenerated with fresh # DRAT proofs (checked, and their CNF digests compared with the shipped records), the # fort-cover certificates n = 11..21 (column F of Table 1 for n <= 21; the round-based # encoding only for n <= 17 with a 60 s limit), then a re-check of the regenerated # certificates. # FULL=1 : adds step 11: exhaustive oracle n = 23..27 (rows 23..27 of Table 2, about 70 min), # the complete boundary table p = 12..24, the complete certified window 26 <= n <= 154 # (about 35 min on 12 cores), the fort-cover certificate n = 22 (about 11 min), a re-check of # every shipped proof present on disk including the 4.0 GB (n = 23) fort-cover proof (about # 2 h), a drat-trim check of the stored 7.7 GB n = 25 proof file (status unknown; 1-2 h), # proof-logging re-solves of the stored fort-cover CNFs for n = 23 and 25 (about 2-3 h # including drat-trim), the round encoding n = 18..22 with the original 600 s limit, # the second enumerator E' through n = 40 (about 1 h) and the exhaustive boundary-encoding # checks of Section 8(c). # Any interrupted step leaves the result rows of that step unchanged; a timed-out or killed solver is # never recorded as UNSAT. set -e ROOT=$(cd "$(dirname "$0")/.." && pwd) cd "$ROOT" MODE=default; [ -n "$QUICK" ] && MODE=quick; [ "${FULL:-0}" = "1" ] && MODE=full T0=$(date -u +%FT%TZ) if [ "${INPLACE:-0}" = "1" ]; then WORK="$ROOT" export AUTOSCHOLAR_CERTS_DIR="$ROOT/results/reproduction/certificates" else WORK=${REPRO_WORK:-$ROOT/results/reproduction/work} rm -rf "$WORK"; mkdir -p "$WORK/code/proofs" "$WORK/results" rsync -a --exclude proofs/certificates --exclude brute_force --exclude robustness/ff_brute --exclude robustness/beta_brute \ --exclude tools/drat-trim/drat-trim "$ROOT/code/" "$WORK/code/" ln -s "$ROOT/code/proofs/certificates" "$WORK/code/proofs/certificates" [ -d "$ROOT/.pydeps" ] && ln -s "$ROOT/.pydeps" "$WORK/.pydeps" cp "$ROOT"/results/*.json "$ROOT"/results/*.jsonl "$ROOT"/results/*.csv "$ROOT"/results/*.md "$WORK/results/" 2>/dev/null || true for d in tables robustness; do [ -d "$ROOT/results/$d" ] && cp -R "$ROOT/results/$d" "$WORK/results/$d"; done export AUTOSCHOLAR_CERTS_DIR="$WORK/certificates" fi mkdir -p "$ROOT/results/reproduction" "$WORK/results/logs" "$AUTOSCHOLAR_CERTS_DIR" export AUTOSCHOLAR_EXPLOG="$WORK/results/experiment-log.jsonl" [ "$WORK" = "$ROOT" ] || : > "$AUTOSCHOLAR_EXPLOG" cd "$WORK" export PYTHONPATH=.pydeps:code run() { name=$1; shift; echo "== $name: $*"; python3 code/tools/logrun.py "$name" --log "results/logs/$name.log" -- "$@"; } echo "[0] dependencies and tools (mode: $MODE, work: $WORK)" [ -d .pydeps/pysat ] || python3 -m pip install --no-index --target "$ROOT/.pydeps" "$ROOT"/code/wheels/*.whl run build_drat_trim gcc -O2 -o code/tools/drat-trim/drat-trim code/tools/drat-trim/drat-trim.c run build_brute_force gcc -O2 -o code/brute_force code/brute_force.c run build_ff_brute gcc -O2 -o code/robustness/ff_brute code/robustness/ff_brute.c -lpthread run build_beta_brute gcc -O2 -o code/robustness/beta_brute code/robustness/beta_brute.c -lpthread echo "[1] graph invariants (T1) and order independence (T2)" run T1_graph_invariants python3 code/graph_constructor.py 5 48 run T2_order_independence python3 code/closure_oracle.py echo "[2] lemma checks (CS6, T8, sympy)" run lemma_checks python3 code/verify_lemmas.py echo "[3] independent certificate checks: witness replay; drat-trim on shipped proofs present on disk" run verify_upper_bounds python3 code/verify_upper_bounds.py 60 if [ "$MODE" = "full" ]; then run verify_lower_bounds_all_shipped python3 code/verify_lower_bounds.py 8 else VERIFY_BOUNDARY_N="24,26-40,60" VERIFY_FORTCOVER_N="11-21" VERIFY_MAX_PROOF_BYTES=1500000000 \ run verify_lower_bounds_sample python3 code/verify_lower_bounds.py 8 fi if [ "$MODE" != "quick" ]; then echo "[4] exhaustive oracle n = 11..22 (C program, 16 threads, ~2 min)" BF_TIME_LIMIT=3600 run brute_force_11_22 python3 code/brute_force.py 11 12 13 14 15 16 17 18 19 20 21 22 echo "[5] boundary table p = 16..20, n = 13..30 (~2 min)" run boundary_table_p16_20 python3 code/run_boundary_table.py 16 20 13 30 12 echo "[6] certified boundary window p = 18, n = 26..40, fresh DRAT proofs (~2 min)" run boundary_window_26_40 python3 code/run_boundary_window.py 18 26 40 12 echo "[7] fort-cover certificates n = 11..21 (round encoding only n <= 17, 60 s limit; ~8 min; n = 22 is in FULL mode)" FORT_LIMIT=300 ROUND_LIMIT=60 run exact_fortcover_11_17 python3 code/run_exact.py 11 12 13 14 15 16 17 FORT_LIMIT=600 SKIP_ROUND=1 run exact_fortcover_18_21 python3 code/run_exact.py 18 19 20 21 echo "[8] re-check of the regenerated certificates with the independent checker" run verify_upper_bounds_again python3 code/verify_upper_bounds.py 60 VERIFY_BOUNDARY_N="26-40" VERIFY_FORTCOVER_N="11-21" VERIFY_MAX_PROOF_BYTES=1500000000 \ VERIFY_OUT=results/lower_bound_verification_regenerated.json run verify_lower_bounds_regenerated python3 code/verify_lower_bounds.py 8 fi echo "[9] tables and metrics (working copy)" run build_tables python3 code/build_tables.py echo "[10] Stage 5 robustness checks that need no enumeration (see code/robustness/README.md)" run robustness_check_counts python3 code/robustness/check_counts.py run robustness_witness_replay python3 code/robustness/check_witness_replay.py run robustness_deletion_lemma python3 code/robustness/check_deletion_lemma.py run robustness_drat_negative_controls python3 code/robustness/check_drat_negative_controls.py run robustness_margin python3 code/robustness/check_margin.py run robustness_local_search python3 code/robustness/attack_local_search.py if [ "$MODE" = "full" ]; then echo "[11] FULL: exhaustive oracle n = 23..27, complete boundary table and window, big proof re-solves, E' enumerations" BF_TIME_LIMIT=3600 run brute_force_23_27 python3 code/brute_force.py 23 24 25 26 27 run boundary_table_full python3 code/run_boundary_table.py 12 24 13 30 12 run boundary_window_41_154 python3 code/run_boundary_window.py 18 41 154 12 FORT_LIMIT=600 SKIP_ROUND=1 run exact_fortcover_22 python3 code/run_exact.py 22 FORT_LIMIT=600 ROUND_LIMIT=600 run exact_round_18_22 python3 code/run_exact.py 18 19 20 21 22 run regen_fortcover_proof_23 python3 code/regen_fortcover_proof.py 23 11 run regen_fortcover_proof_25 python3 code/regen_fortcover_proof.py 25 11 # drat-trim on the stored n = 25 proof file (exit 1 and no record if it does not verify) run check_fortcover_proof_25 python3 code/check_fortcover_proof.py 25 11 18000 || true VERIFY_OUT=results/lower_bound_verification_regenerated.json run verify_lower_bounds_regenerated_full python3 code/verify_lower_bounds.py 8 run build_tables_full python3 code/build_tables.py run robustness_beta_brute sh code/robustness/run_beta_brute.sh run robustness_boundary_encoding python3 code/robustness/check_boundary_encoding.py run robustness_ff_brute sh code/robustness/run_ff_brute.sh for n in 31 32 33 34 35 36 37 38 39 40; do code/robustness/ff_brute $n 5 11 16; done >> results/robustness/ff_brute_stdout_31_40.txt fi run robustness_collect python3 code/robustness/collect_robustness_metrics.py echo "[12] comparison with the shipped artifacts" cd "$ROOT" set +e python3 code/tools/compare_reproduction.py "$WORK" "$ROOT" "$MODE" "$ROOT/results/reproduction/summary.json" CMP=$? set -e [ "$WORK" = "$ROOT" ] || cp "$AUTOSCHOLAR_EXPLOG" "$ROOT/results/reproduction/experiment-log.jsonl" # remove compiled binaries (rebuilt by step 0) and regenerated DRAT proofs (their digests are in the records) rm -f "$WORK/code/brute_force" "$WORK/code/robustness/ff_brute" "$WORK/code/robustness/beta_brute" "$WORK/code/tools/drat-trim/drat-trim" find "$AUTOSCHOLAR_CERTS_DIR" -name '*.drat' -delete 2>/dev/null || true echo "reproduce.sh finished: mode=$MODE started=$T0 ended=$(date -u +%FT%TZ) comparison_exit=$CMP (results/reproduction/summary.json)" exit $CMP