From 244b522d8e9695567ec0b09c7fe14a58dcb75ce5 Mon Sep 17 00:00:00 2001 From: Hydrodynamical Date: Tue, 20 Oct 2026 20:13:37 -0400 Subject: [PATCH] Polish benchmark README and repair offline reproducibility --- .github/workflows/offline-checks.yml | 27 +++ .python-version | 1 + README.md | 351 +++++++++++---------------- generate_transcripts.py | 54 ++++- main_loop.py | 44 ++-- paper.pdf | Bin 278735 -> 265182 bytes paper.tex | 110 ++++++--- requirements-api.txt | 35 +++ requirements.txt | 12 + test_cli.py | 55 +++++ test_parser.py | 241 +++++++++--------- test_sweep.py | 172 +++++++++++++ 12 files changed, 710 insertions(+), 392 deletions(-) create mode 100644 .github/workflows/offline-checks.yml create mode 100644 .python-version create mode 100644 requirements-api.txt create mode 100644 requirements.txt create mode 100644 test_cli.py create mode 100644 test_sweep.py diff --git a/.github/workflows/offline-checks.yml b/.github/workflows/offline-checks.yml new file mode 100644 index 0000000..fe3cd59 --- /dev/null +++ b/.github/workflows/offline-checks.yml @@ -0,0 +1,27 @@ +name: Offline reproducibility + +on: + push: + pull_request: + +permissions: + contents: read + +jobs: + offline: + runs-on: ubuntu-latest + env: + MPLBACKEND: Agg + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 + with: + python-version: '3.12' + cache: pip + cache-dependency-path: requirements.txt + - name: Install numerical environment + run: python -m pip install -r requirements.txt + - name: Test numerical core, parser, and CLI workflows + run: python -m unittest discover -s . -p 'test_*.py' -v + - name: Generate an offline example with its dashboard + run: python main_loop.py --mock --difficulty easy --seed 42 --output-dir runs/ci-smoke diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..e4fba21 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/README.md b/README.md index 05a3638..6fd357d 100644 --- a/README.md +++ b/README.md @@ -1,237 +1,180 @@ # Can Language Models Learn a PDE? -A benchmark testing whether LLMs can identify an unknown elliptic PDE by probing -it with test functions through the weak formulation. The model receives solution -data, a budget of queries, and diagnostic tools — but must design its own -experimental strategy. +**A benchmark for experimental design in scientific AI.** ---- +Can a language model choose informative measurements to identify an unknown +elliptic PDE? The model selects test functions, queries weak-form integrals, +inspects numerical diagnostics, and decides when to submit its estimate. +Numerical tools perform coefficient recovery; the model directs the experiment. -## Quick Start +[Manuscript](paper.pdf) · [Source](paper.tex) · [Kaggle notebooks](#repository-guide) · [MIT License](LICENSE) -```bash -# Install dependencies -pip install numpy scipy matplotlib anthropic openai google-genai - -# Set your API keys -export ANTHROPIC_API_KEY=your_key_here -export OPENAI_API_KEY=your_key_here -export GOOGLE_API_KEY=your_key_here - -# Full paper benchmark (6 models × 3 difficulties × 10 seeds) -python generate_transcripts.py \ - --models gpt-5.4-mini gpt-5.4 gemini-3.1-pro-preview gemini-3-flash-preview claude-opus-4-6 claude-sonnet-4-20250514 \ - --difficulties easy medium hard \ - --seeds "1-10" \ - --output-dir runs \ - --no-plot - -# Single run (one model, one seed) -python main_loop.py --provider google --model gemini-3-flash-preview --difficulty hard --seed 42 - -# Test with mock LLM (no API key needed) -python main_loop.py --mock --difficulty easy -``` - -Budget and turn limits are auto-scaled from difficulty — no manual tuning needed. -All output files are saved to the current directory (override with `--output-dir`). +## How it works ---- - -## The PDE - -The model must identify the coefficient functions in: +The hidden equation is ```text --(a(x) u'(x))' + b(x) u'(x) + c(x) u(x) = f(x) on [0, 1] -u(0) = 0, u(1) = 0 +-(a(x) u'(x))' + b(x) u'(x) + c(x) u(x) = f(x), x in [0, 1] +u(0) = u(1) = 0. ``` -Each coefficient is a linear combination of shifted Legendre polynomials. -The number of basis functions (and thus unknowns) scales with difficulty. - ---- - -## Tools Available to the Model - -| Command | Returns | Cost | -| --- | --- | --- | -| `QUERY: ` | ∫f·φ dx | 1 query | -| `COMPUTE: eval_solution x1 x2 ...` | u(x) and u'(x) at given points | free | -| `COMPUTE: term_integrals ` | All three term weights at once: ∫u'φ' dx (diffusion), ∫u'φ dx (advection), ∫uφ dx (reaction) | free | -| `COMPUTE: solve` | Least-squares coefficient recovery + delta from previous solve | free | -| `COMPUTE: check ` | Predicted LHS vs actual ∫fφ dx for a new test function | free | -| `PREDICT:` | End session and submit last `COMPUTE: solve` coefficients as answer | — | +The four coefficient functions are represented in a shifted Legendre basis. +Models can inspect the solution through tools and choose test functions that +vanish at the endpoints. Integration by parts converts each query into a +measurement for a linear inverse problem. + +```mermaid +flowchart LR + A[Choose a test function] --> B[Query a weak-form integral] + B --> C[Recover coefficients with least squares] + C --> D[Inspect conditioning and consistency] + D --> A + D --> E[Submit and score against hidden coefficients] +``` -`COMPUTE: solve` shows per-coefficient change from the previous solve, so the -model can tell when its estimates have converged. +The benchmark records coefficient error, query efficiency, test-function +diversity, and confidence reports. It supports comparisons of query-selection +strategies and prompt conditions on the same seeded PDE instances. -`COMPUTE: term_integrals` returns all three weights in a single call, making it -easy to screen candidate test functions for reaction-term informativeness before -spending a query. +## Reproduce an offline example -`COMPUTE: check` is a free consistency diagnostic. It compares the predicted -LHS (from current â, b̂, ĉ estimates) against the actual ∫fφ dx for a new test -function. Zero discrepancy does NOT confirm correctness — it only means this test -function is consistent with the current fit. Unlike QUERY, check is read-only: it -does not add the test function to the solver's equation system. +Use **Python 3.12** (tested locally with 3.12.12). The pinned numerical environment +includes plotting and analysis dependencies; provider SDKs are optional. ---- +```bash +git clone https://github.com/Hydrodynamical/PDE_Learning.git +cd PDE_Learning +python3.12 -m venv .venv +source .venv/bin/activate +python -m pip install -r requirements.txt -## Difficulty Levels +# Run the numerical and protocol regression tests. +python -m unittest discover -s . -p 'test_*.py' -v -Budget and turn limits are derived automatically. Override with `--max-queries` and `--max-turns`. +# Complete a scripted session: query, solve, submit, and save a dashboard. +python main_loop.py --mock --difficulty easy --seed 42 --output-dir runs/mock +``` -| Difficulty | Basis size | Unknowns | Auto budget | Auto turns | -| --- | --- | --- | --- | --- | -| `easy` | 2 | 8 | 12 | 36 | -| `medium` | 3 | 12 | 18 | 54 | -| `hard` | 4 | 16 | 24 | 72 | -| `extreme` | 8 | 32 | 48 | 144 | +On Windows, activate with `.venv\Scripts\activate` instead. The mock uses no API +keys or provider SDKs. It checks the workflow and produces a scored prediction; +it is **not an LLM performance result**. Add `--no-plot` for JSON only. ---- +The [offline workflow](.github/workflows/offline-checks.yml) runs the tests and +example on GitHub Actions without model credentials. -## Output Files +## Run a model experiment -Each run produces three co-indexed files sharing a common stem: +Install the pinned provider environment and set the key for your chosen provider: -``` -run__s__.json -run__s___dashboard.png -run__s___auc.png +```bash +python -m pip install -r requirements-api.txt +export OPENAI_API_KEY="your-key" +python main_loop.py --provider openai --model gpt-4o \ + --difficulty easy --seed 42 --temperature 0 \ + --output-dir runs/standard --no-plot ``` -The JSON log contains: full turn transcript, per-query records, per-solve -coefficient estimates and errors vs ground truth, verifications, term integrals, -efficiency error curves, final scores, ground truth, behavioral metrics, and -metacognitive metrics. +`--provider` also accepts `anthropic` and `google`, using `ANTHROPIC_API_KEY` and +`GOOGLE_API_KEY`, respectively. Pass the desired model ID explicitly; availability +and behavior depend on the provider. The seed fixes the PDE instance, not the +provider's responses. Temperature zero does not guarantee identical API output; +the OpenAI backend omits temperature when a reasoning-effort override is used. -**Behavioral metrics** (in `behavioral_metrics`): +The **standard** condition adds an initial hint about unequal coefficient +identifiability. `--baseline` omits that hint. Both conditions retain the same +PDE, tool instructions, and protocol. -| Field | Description | -| --- | --- | -| `learning_rate` | Slope of log₁₀(error) vs query count across solves (negative = improving) | -| `improvement_ratio` | First-solve error / last-solve error (> 1 means within-session learning) | -| `wasted_turns` / `wasted_turn_fraction` | Turns with no recognized action (malformed commands or pure reasoning) | -| `max_unproductive_streak` | Longest consecutive run of wasted turns | -| `tail_after_last_solve` | Turns between final solve and session end | -| `max_gap_without_progress` | Longest stretch without a QUERY or COMPUTE: solve after the first solve | -| `duplicate_queries` | Count of repeated test functions (working memory failures) | -| `family_entropy` / `family_entropy_normalized` | Shannon entropy of test function family distribution (0 = all one family) | -| `family_counts` | Per-family query counts (polynomial, trigonometric, exponential, localized, other) | -| `query_space_blocks` | Per-block SVD analysis: effective rank, log-volume, condition number for diffusion/advection/reaction blocks | -| `mean_monitoring_accuracy` | Mean Spearman correlation between stated and true uncertainty rankings ($\bar{M}$) | -| `mean_control_efficiency` | Mean fraction of information gain on the most uncertain coefficient ($\bar{C}$) | -| `n_confidence_reports` | Number of times the model reported per-coefficient confidence | +### Compare multiple seeds -Use `--output-dir runs/` to collect logs from multiple runs in one place. +For example, run one registered model on three difficulties and two seeds: ---- +```bash +python generate_transcripts.py --models gpt-4o \ + --difficulties easy medium hard --seeds "42 137" \ + --output-dir runs/standard --no-plot + +# Repeat the same selection with the baseline prompt. +python generate_transcripts.py --models gpt-4o \ + --difficulties easy medium hard --seeds "42 137" --baseline \ + --output-dir runs/baseline --no-plot +``` -## CLI Reference +Each invocation above attempts six runs. The runner's defaults attempt +**18 standard-condition runs**: three models, three difficulties, and two seeds. +They do not automatically include a baseline ablation. See `MODELS` in +[generate_transcripts.py](generate_transcripts.py) for the registered model IDs. -### `generate_transcripts.py` — batch sweep +To resume a sweep, repeat its arguments with `--retry-failed`. Matching includes +model, difficulty, seed, prompt condition, temperature, and reasoning effort. +Legacy summaries missing these settings are preserved and rerun. Use separate +output directories for different conditions/settings so downstream plots and +aggregate tables compare like with like. -``` -python generate_transcripts.py [options] - - --models MODEL [MODEL ...] Models to run (must be in MODELS registry) - --difficulties {easy,medium,hard,extreme} [...] - --seeds SEEDS Space-separated or range: "42 137" or "1-10" - --output-dir DIR Output directory (default: runs/) - --no-plot Skip PNG generation (JSON only) - --retry-failed Re-run only seeds missing from sweep_results.json - --temperature FLOAT Sampling temperature (default: 0.0) - --reasoning-effort LEVEL Override reasoning effort for OpenAI models -``` +## Protocol and outputs -### `main_loop.py` — single run +| Difficulty | Basis size per coefficient | Total coefficients | Query budget | Turn limit | +| --- | ---: | ---: | ---: | ---: | +| Easy | 2 | 8 | 12 | 36 | +| Medium | 3 | 12 | 18 | 54 | +| Hard | 4 | 16 | 24 | 72 | +| Extreme | 8 | 32 | 48 | 144 | -```text -python main_loop.py [options] - -Core options: - --difficulty {easy,medium,hard,extreme} Problem difficulty (default: medium) - --seed INT Random seed (default: 42) - --provider {anthropic,openai,google} LLM provider (default: anthropic) - --model MODEL Model name - --temperature FLOAT Sampling temperature (default: 0.0) - -Budget overrides (auto-scaled by default): - --max-queries INT Query budget - --max-turns INT Max conversation turns (default: 3× budget) - --min-queries INT Min queries before PREDICT is allowed - -Output: - --output-dir DIR Directory for JSON and PNG output (default: .) - --save-transcript FILE Also save full transcript as plain text - --no-plot Skip PNG generation - -Testing: - --mock Use scripted mock LLM (no API key needed) - --baseline Minimal prompt (no mathematical context) -``` +Single-run limits can be overridden with `--max-queries` and `--max-turns`. ---- - -## Results (Seed 42, Hard Difficulty) - -| Metric | Baseline | Standard | -| --- | --- | --- | -| Total coefficient error | 2.2742 | **0.0085** | -| a(x) error | 0.0659 | 0.0001 | -| b(x) error | 1.2281 | 0.0012 | -| c(x) error | 0.9803 | 0.0072 | -| f(x) error | 0.0000 | 0.0000 | -| Queries used | 28 | 28 | -| Test function diversity | 25 polynomial | 6 poly, 19 trig | - -The baseline used all polynomials — x^k(1-x)^m — which are nearly collinear in -the weak-form integral space. The standard prompt model used a mix of sines and -polynomials, giving a well-conditioned overdetermined system. - ---- - -## File Structure - -### Main entry points - -| File | Description | -|---|---| -| `main_loop.py` | **Primary entry point.** Probe-only benchmark with Anthropic/OpenAI/Google support, auto-scaled budget, convergence delta tracking, and full JSON logging. | -| `kaggle.py` | Kaggle Benchmarks notebook adapter. Uses `dispatch_turn()` from main_loop.py with kbench's `llm.prompt()` interface. | -| `probe_loop.py` | Earlier version of main_loop.py (without convergence deltas). | -| `llm_loop.py` | Legacy variant supporting DECOMPOSE commands and auto-progress feedback. Uses `interactive.py`. | - -### Core library (imported by main entry points) - -| File | Description | -|---|---| -| `pde.py` | PDE generation and numerical solving | -| `basis.py` | Shifted Legendre polynomial basis | -| `weak_form.py` | Weak-form integral computation | -| `expression_parser.py` | Symbolic test function parsing | -| `benchmark.py` | Scoring and evaluation | -| `diagnostics.py` | Result plotting | -| `interactive.py` | Session manager (used only by `llm_loop.py`) | - -### Standalone scripts (not imported by main entry points) - -| File | Description | -|---|---| -| `generate_transcripts.py` | Batch runner for multi-seed experiments | -| `analyze_adaptation.py` | Post-hoc analysis of LLM reasoning patterns | -| `oracle_decompose.py` | Reference oracle implementation | -| `demo.py` / `demo_benchmark.py` / `demo_full.py` | Example scripts | -| `test_basis.py` / `test_functions.py` / `test_interactive.py` / `test_parser.py` / `test_weak_form.py` | Unit tests | - ---- - -## Requirements - -- Python 3.10+ -- `numpy`, `scipy`, `matplotlib` -- `anthropic` (for Anthropic models) — `pip install anthropic` -- `openai` (for OpenAI models) — `pip install openai` -- `google-genai` (for Google models) — `pip install google-genai` -- `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, and/or `GOOGLE_API_KEY` environment variables +| Command | Role | +| --- | --- | +| `QUERY: ` | Measure the source integral; costs one query. | +| `COMPUTE: eval_solution ` | Inspect the solution and its derivative. | +| `COMPUTE: term_integrals ` | Inspect diffusion, advection, and reaction weights. | +| `COMPUTE: solve` | Recover coefficients from accumulated queries using least squares. | +| `COMPUTE: check ` | Check consistency against a new test function without adding a query. | +| `PREDICT:` | Submit the latest solve coefficients. | + +A small consistency residual alone does not establish coefficient recovery: +ill-conditioned measurements can fit well while identifying coefficients poorly. + +Every completed invocation writes a timestamped `run_*.json` with configuration, +transcripts, queries, solves, ground truth, and available scores/diagnostics. +Single runs also attempt a dashboard after a prediction; batch runs attempt a +dashboard and AUC plot. `--no-plot` disables plot generation. Batch summaries are +saved to `sweep_results.json`. `--save-transcript` and `--save-plot` take explicit +paths, independently of `--output-dir`. + +For a reproducible experiment record, retain the JSON logs, exact command, +`git rev-parse HEAD`, and `python -m pip freeze` alongside your analysis. + +## Results and evidence status + +This repository contains several historical experiment artifacts with different +scopes: + +- The manuscript's preliminary comparison lists **18 attempts / 15 scored runs** + across three OpenAI models, three difficulties, and seeds 42 and 137. +- Checked-in success-rate figures are labeled **180 scored runs across six + models**, with ten runs per model/difficulty combination. This is a different + design from the manuscript's proposed five-seed, two-prompt study. +- Saved Kaggle notebook outputs contain additional exploratory runs under their + own settings. + +The complete per-run JSON archive behind those tables and figures is **not +bundled**, so their aggregates cannot currently be regenerated from a fresh +checkout. The manuscript's six-model, five-seed, two-prompt protocol is a proposed +expansion, not a completed result established here. Historical numerical tables +are preserved; no new provider benchmark was run for this reproducibility update. +The previous README's single-seed, 28-query example is omitted because its source +logs and exact settings are unavailable and it exceeds the current default hard +budget of 24 queries. + +## Repository guide + +| Path | Contents | +| --- | --- | +| [main_loop.py](main_loop.py) | Active single-session CLI, tools, prompts, and backends | +| [generate_transcripts.py](generate_transcripts.py) | Batch experiments, summaries, and resumption | +| `basis.py`, `pde.py`, `weak_form.py` | Numerical problem generation and weak-form operations | +| `expression_parser.py`, `sanitize_expression.py` | Test-function parsing and normalization | +| `benchmark.py`, `diagnostics.py` | Scoring and dashboards | +| `replot.py`, `plot_*.py`, `verify_metacognition.py` | Analysis of saved run logs | +| [kaggle-benchmark.ipynb](kaggle-benchmark.ipynb), [kaggle.ipynb](kaggle.ipynb) | Kaggle-specific exploratory notebooks; require their own Kaggle environment | +| `test_basis.py`, `test_weak_form.py`, `test_parser.py`, `test_cli.py`, `test_sweep.py` | Offline numerical, protocol, and workflow tests | +| [archive/](archive/) | Historical demos and earlier interfaces; outside the supported quick start | diff --git a/generate_transcripts.py b/generate_transcripts.py index 32aabda..0df8739 100644 --- a/generate_transcripts.py +++ b/generate_transcripts.py @@ -14,6 +14,7 @@ import time import json import os +from uuid import uuid4 import numpy as np from main_loop import ( @@ -41,9 +42,21 @@ DEFAULT_DIFFICULTIES = ["easy", "medium", "hard"] DEFAULT_SEEDS = [42, 137] +# Legacy summaries did not record every setting. Keep them distinguishable from +# explicitly configured runs rather than guessing which experiment they belong to. +_UNSPECIFIED = object() +_RUN_KEY_FIELDS = ( + "model", "difficulty", "seed", "prompt_condition", "temperature", "reasoning_effort", +) + # ── Helpers ────────────────────────────────────────────────────────────────── +def run_key(record: dict) -> tuple: + """Identify an experiment without conflating prompt or sampling settings.""" + return tuple(record.get(field, _UNSPECIFIED) for field in _RUN_KEY_FIELDS) + + def parse_seeds(seed_str: str) -> list[int]: """Parse '42-46' or '42 43 44' into a list of ints.""" if "-" in seed_str and seed_str.count("-") == 1: @@ -91,6 +104,7 @@ def run_single(model: str, provider: str, difficulty: str, seed: int, "budget_source": "auto", "prompt_condition": "baseline" if baseline else "standard", "reasoning_effort": reasoning_effort, + "temperature": temperature, "timestamp": time.strftime("%Y-%m-%dT%H:%M:%S"), }, "turns": [], @@ -209,7 +223,10 @@ def run_single(model: str, provider: str, difficulty: str, seed: int, # ── Save files ── model_slug = model.replace("/", "_").replace(".", "_") - stem = f"run_{difficulty}_s{seed}_{model_slug}_{time.strftime('%Y%m%d_%H%M%S')}" + # Prompt/settings can differ even when model, PDE seed and wall-clock second + # match. Never let one run replace another run's raw log or plots. + stem = (f"run_{difficulty}_s{seed}_{model_slug}_" + f"{time.strftime('%Y%m%d_%H%M%S')}_{uuid4().hex}") log_path = os.path.join(output_dir, stem + ".json") with open(log_path, "w") as f: @@ -248,6 +265,8 @@ def run_single(model: str, provider: str, difficulty: str, seed: int, "difficulty": difficulty, "seed": seed, "reasoning_effort": reasoning_effort, + "prompt_condition": "baseline" if baseline else "standard", + "temperature": temperature, "queries_used": result["queries_used"], "max_queries": max_queries, "turns": result["turns"], @@ -346,7 +365,7 @@ def main(): parser.add_argument("--output-dir", type=str, default="runs", help="Output directory (default: runs/)") parser.add_argument("--baseline", action="store_true", - help="Use baseline prompt (no mathematical context)") + help="Omit the initial identifiability hint (shared PDE/tool instructions remain)") parser.add_argument("--reasoning-effort", type=str, default=None, choices=["none", "low", "medium", "high", "xhigh"], help="Override reasoning effort for all OpenAI models") @@ -355,7 +374,7 @@ def main(): parser.add_argument("--retry-failed", action="store_true", help="Read sweep_results.json from output-dir, re-run only failed/missing seeds") parser.add_argument("--temperature", type=float, default=0.0, - help="LLM sampling temperature (0 = deterministic)") + help="Requested LLM sampling temperature (default: 0; API outputs can vary)") args = parser.parse_args() seeds = parse_seeds(args.seeds) @@ -371,6 +390,8 @@ def main(): } elif "claude" in m or "anthropic" in m.lower(): model_configs[m] = {"provider": "anthropic", "reasoning_effort": None} + elif "gemini" in m.lower(): + model_configs[m] = {"provider": "google", "reasoning_effort": None} else: model_configs[m] = {"provider": "openai", "reasoning_effort": args.reasoning_effort} @@ -381,6 +402,16 @@ def main(): for seed in seeds ] + def requested_key(model, difficulty, seed): + return run_key({ + "model": model, + "difficulty": difficulty, + "seed": seed, + "prompt_condition": "baseline" if args.baseline else "standard", + "temperature": args.temperature, + "reasoning_effort": model_configs[model]["reasoning_effort"], + }) + if args.retry_failed: sweep_path = os.path.join(args.output_dir, "sweep_results.json") if os.path.exists(sweep_path): @@ -389,9 +420,12 @@ def main(): done = set() for r in existing: if "error" not in r and r.get("total_coeff_error") is not None: - done.add((r["model"], r["difficulty"], r["seed"])) - all_combos = [(m, d, s) for m, d, s in all_combos if (m, d, s) not in done] - print(f"Retrying {len(all_combos)} failed/missing seeds ({len(done)} already succeeded)") + done.add(run_key(r)) + requested_count = len(all_combos) + all_combos = [(m, d, s) for m, d, s in all_combos + if requested_key(m, d, s) not in done] + print(f"Retrying {len(all_combos)} failed/missing runs " + f"({requested_count - len(all_combos)} matching runs already succeeded)") else: print(f"No sweep_results.json found in {args.output_dir}, running all") @@ -445,6 +479,8 @@ def main(): "model": model, "provider": provider, "difficulty": difficulty, "seed": seed, "reasoning_effort": reasoning_effort, + "prompt_condition": "baseline" if args.baseline else "standard", + "temperature": args.temperature, "error": str(e), }) @@ -453,9 +489,9 @@ def main(): if os.path.exists(sweep_path): with open(sweep_path) as f: existing = json.load(f) - existing_map = {(r["model"], r["difficulty"], r["seed"]): r for r in existing} + existing_map = {run_key(r): r for r in existing} for r in new_results: - existing_map[(r["model"], r["difficulty"], r["seed"])] = r + existing_map[run_key(r)] = r all_results = sorted(existing_map.values(), key=lambda r: r["seed"]) else: all_results = new_results @@ -468,4 +504,4 @@ def main(): if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/main_loop.py b/main_loop.py index 661ef78..3a8e91e 100644 --- a/main_loop.py +++ b/main_loop.py @@ -698,21 +698,22 @@ def chat(self, system: str, messages: list[dict]) -> str: class MockBackend: - """Simple mock that queries a few test functions then predicts zeros.""" - def __init__(self): + """Scripted offline workflow check, not a model-performance baseline.""" + def __init__(self, n_queries: int = 8): self.model = "mock" self.call_count = 0 self.script = [ "COMPUTE: eval_solution 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9", - "QUERY: sin(pi*x)", - "QUERY: sin(2*pi*x)", - "QUERY: sin(3*pi*x)", - "QUERY: x*(1-x)", - "QUERY: x*(1-x)*(2*x-1)", - "QUERY: x**2*(1-x)**2", - "QUERY: x*(1-x)*sin(pi*x)", - "PREDICT:\na_coeffs = [1.0, 0.0, 0.0]\nb_coeffs = [0.0, 0.0, 0.0]\nc_coeffs = [0.0, 0.0, 0.0]\nf_coeffs = [0.0, 0.0, 0.0]", ] + for index in range(n_queries): + mode = index // 2 + 1 + expression = (f"sin({mode}*pi*x)" if index % 2 == 0 + else f"x*(1-x)*exp(-{mode}*x)") + self.script.append(f"QUERY: {expression}") + self.script.extend([ + "COMPUTE: solve", + "PREDICT:\nConfidence: a=0%, b=0%, c=0%, f=0%", + ]) def chat(self, system, messages): idx = min(self.call_count, len(self.script) - 1) @@ -1525,12 +1526,12 @@ def main(): parser.add_argument("--model", default=None, help="Model name (default: claude-haiku-4-5-20251001 for anthropic, gpt-4o for openai)") parser.add_argument("--max-turns", type=int, default=None, - help="Override auto-scaled turn limit (default: 2x budget)") + help="Override auto-scaled turn limit (default: 3x budget)") parser.add_argument("--save-transcript", type=str, default=None) parser.add_argument("--save-plot", type=str, default=None, - help="Save results plot to file (default: probe__.png)") + help="Save dashboard to this path (default: alongside the timestamped JSON)") parser.add_argument("--baseline", action="store_true", - help="Use minimal prompt without mathematical context (for ablation)") + help="Omit the initial identifiability hint (shared PDE/tool instructions remain)") parser.add_argument("--reasoning-effort", type=str, default=None, choices=["none", "low", "medium", "high", "xhigh"], help="Reasoning effort for OpenAI GPT-5+ models " @@ -1542,7 +1543,7 @@ def main(): parser.add_argument("--no-plot", action="store_true", help="Skip generating dashboard PNG (JSON only)") parser.add_argument("--temperature", type=float, default=0.0, - help="LLM sampling temperature (0 = deterministic)") + help="Requested LLM sampling temperature; API responses may vary") args = parser.parse_args() if args.model is None: @@ -1553,12 +1554,19 @@ def main(): config = DIFFICULTY_CONFIG[args.difficulty] max_queries = args.max_queries if args.max_queries is not None else config["budget"] max_turns = args.max_turns if args.max_turns is not None else 3 * max_queries + if max_queries <= 0 or max_turns <= 0: + parser.error("--max-queries and --max-turns must be positive") + mock_queries = max(config["unknowns"], args.min_queries or 0) + if args.mock and (max_queries < mock_queries or max_turns < mock_queries + 3): + parser.error(f"--mock needs at least {mock_queries} queries and {mock_queries + 3} turns") os.makedirs(args.output_dir, exist_ok=True) session = ProbeSession.from_difficulty(args.difficulty, args.seed, max_queries) if args.mock: - backend = MockBackend() + backend = MockBackend(n_queries=mock_queries) + args.model = "mock" + args.provider = "mock" elif args.provider == "openai": backend = OpenAIBackend(model=args.model, reasoning_effort=args.reasoning_effort, temperature=args.temperature) @@ -1580,6 +1588,8 @@ def main(): "budget_source": "override" if args.max_queries is not None else "auto", "prompt_condition": "baseline" if args.baseline else "standard", "reasoning_effort": args.reasoning_effort, + "temperature": args.temperature, + "min_queries": args.min_queries, "timestamp": datetime.now().isoformat(), }, "turns": [], @@ -1699,7 +1709,7 @@ def main(): re_tag = f"_re{args.reasoning_effort}" if args.reasoning_effort else "" run_stem = ( f"run_{args.difficulty}_s{args.seed}_{model_slug}{re_tag}" - f"_{datetime.now().strftime('%Y%m%d_%H%M%S')}" + f"_{datetime.now().strftime('%Y%m%d_%H%M%S_%f')}" ) log_path = os.path.join(args.output_dir, run_stem + ".json") with open(log_path, "w") as f: @@ -1744,4 +1754,4 @@ def main(): if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/paper.pdf b/paper.pdf index e403ddc8706297d3164d15e7c6dd7efc899b04b9..9f44cfc182d35e5af83b121b1cc12647437c9ca0 100644 GIT binary patch delta 55399 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

CJ|Z9yRa9f@FBF)No^4#eHE2 zw16+CI=%-VpvqND&RdhAQx|UZub>~{O7{fH+o*Gf4eA*sK zkVKzh!`SFf9HG^c+=8Psps_>dpRyuKkpW)6yHm6DV`&INHdJ&HP5r9T<3qz{-&n=~ zjSkB?BN(=iVWS zMY=`#dvlVGDdhwRmExif9Hoq5C zl+2c>Z=N{bl#9?JiTD`vW!pWnJ?7Y;%`~P`9F!SuW#%9rulu%A8o$>e92FZ&G+hkX zv~zX2tc0{RyN{BAUKOWsyk%`U*R(Uu{F$?d?Hz2pmKJ%=m;l`-k3B2ZnJSae=Z4Rz zw}bZ;Wn~wjtxKXL;qbKnx_F))u)xQ~P!wwRqGB+H4;P5(3$$J+i#r-99YHfB78c2r zT8!NilU5TP9-7^;?{A3qkJqqmRY$9N{)|eBW6O8U2DUOI38)k40jcQRsM}QE#-pfP zZPxeNr|yi!E>IeT6V8!wRB)%vno3YM8P7dq1xHyILb{E(IXLkAg3Vqd8NFr0&h(=Y z!5i27f|Jbl5xz3iVQdtI4Fj!_6y;F1%OSQFKwj@ye*XsATg497mlEHcu zABe@{QmyPX>`JefSD~)u>)%5ozkC#8ZaLVHB zGk>lC7MF(&eSN0>D@cX&rRE}q=~axp82_>^{zbQIay}OC2qqa-r`r8dtyeleoH;y< zj|Q5(QVfz#2{XWYcpvgi(!?YLyi$VS?JD>({#~48mDWg}h&~|rDarBecthNK@~o$l z@7bW^>8mne$Zqptb^{f>&+V#YCw$bBCd`!ubco|{&)Fm^4tF-E;o?*i$l5v0j>HB< za5x@tMzZb_N#@q3R_<6_xL=hS)+U1JK$8LhE)JJt{-<=SS=i#$X-h_oV}HYnH=WqS zj9=v0#{$phiYMtn@dt8#W#gT$$^9j4Mzy)h#$_Lu8vDZ#b-ut@3iP*M}Z2&K#c zsbP-^FFY#La*njB*#Jf16K3i0fZhp3p#=;H%t z_QIY7yjFksFsLd`qS&i92kwvbR=@}V7_p8!+yNkQh+B|x5GfJ?i?M%rlV3~!KngFg zR>p>m)F+N}<`&}~lC&`*dup^9EHy?Na^j;BzK8HlWdG&w(HLqEVztVFG*~R8CjvX4 zTQWPXXwuBJmWrRytB%{~T>+IAa0dp1TtoDrvvgZa9N#Y+j2T)>6mgKNmFeIHSRJA$ z@|>X$YoDu?lqsCRTeYy-QkekQ3-I}}PR}A9yeWNKH z%$&Ihj4WY&2-D3_K&n`UG}@gb)l0O&s6qt~zIw>?5OHln+oRp>=zL2$=ybMPoicgD z78}Rf=@>tCN}bBbYSFp!D=7>EP~Ys>9)qsQ(2{Hd+0lMV;!?qqSX(l~3pDXPbwPqZ zhhtC@@uBJN)Y*C>j8G`k$hr4eS;1C@qvUMe>O3UMFM!;%D?e~BT>ti1Z`7+q{vgec zZ+ECnY{E#iw=Ff)PC`e3yik}7WAF%~wbjEATZ48WMk-~p4 zC87QD$;?`^t5x}#@Zg4>-QJtTpXO0%hAh04!ex{HZf;M!fU+fYDLVAzY*KklBgL16 z*jc#%BnqO5!P2V?o=cnnB?QYfMq6AlIqF+aZo+H)8RAq$&@cj{1#*r0TgkCnNwWxM z`e_!RCf#l??*o5z9Brs@XxeV1*Y)ng?mNni^Lv)7B%}%xR*)>z$35iT+d-66sTjGL ziLR6fBKK(Fp<_*$?hK8LS@$SS^faKM*a^2;T34&wMlH9<_medNp!qy<-doJc4Zr51 z`a*l2GHn0o#*1H=f}{|)>>+>cDm6&79U=Mdb{SbE0oZXSG{CSrVH&F$ObeE*gnn%) z)Zx+zoQZfDH#Sf@UT7LNk5+eo_xtxJ69T1xr4Q*+sj(p@fg7&(_QioR@FDAfaFaKY zovBr7=sK>A*;^n1v8(bc1+hlFEI4P(Il^b+$Q}G|=lj>?k|zmkiPc7Gfhr}|H+!O0 zv0U&~@Q6682BeMW)fI4JEXW;zVloPD7Eev%* zy?xR(7iICf0D@fdyzmG)klr@1^GQ|iP{bjWKbl1~QJPZBL3w1Xt*LslKN%qmMzN5Ya8+h<(Kv6*68q9=T603b%a}L$z6R3b^&J z6^PuH;V?+RB(#s4j9YF;pKUqku`f^(P6>9{0MNwg*yX}8bR#~W`JGt~{)2Hd&@2>> zjgA52InCUs#)CFD^sFf$xJYg&P%w4GFu}Q_sAydAxe$FkxltrfJdJ9JdlC_0OBQ-U3UIj$-qq*)HnRU|x1#GoO;$#?Yb4%Ko?9 zWC1zAUvh`}rK^uKyQO;a?)~S*q@+G9bydH;k+H5$11|q(Avo{s^1s2Wg?_VaeYI-H z&dQ8|6J0mryAWu1DphRj&KM> zodGOq_mm!u0u4KH<{w6n68~npGuKKBG~^;+=;SW$TN$aoLEwbgf@c_Czh{apo|kCI zXi1c)!A9S=zre3Py=(Mz$X`{T68&a;|CQ9qR|kZu_q9QM;~n!kxbiVu2{61}MWZh4 zio9As)Wxji1a)Is_^q=k_}uK5C9z)1(@?6L0A`cvR z7ssj>ziZ=mYy!C>g@xbhx9yr!5gx3wRO$w#JsgvD0b6fW$xJ;?pc0V8xxeb9l04~L&Gc4A z%M$D&5{wSdBUO^{S-|Q5?n$o-W!GO2X$GO?klzU+#2$YMTEmX z0I~!7A?7^H=IS44P+!R}KycZ+xc{Q7Mt1yagArB%ebeXaC57b}5|69cgJem$pSXGt z`dwf!ej0>mX48z#k)+1YGJ|)TK6{ zdmx|8GEvMje@V+?B;}<8DU&)d@yGbFdeBe9E%dwU-@SgIWzbZk2N(e)j;3rWo#}eF zj3H8p#Or#hkb~@-O!qo%$q_tfQ0^lk>ehj~?jiv4Wczu$0`7D=u7+?uUK5>ZGUQ`W z=t{hMrr1fKm!2k@z{JG&#!`uCo3ouTZf9e9T$#qk3JZkKn=O>XgYc8<3tFY*g}x; zc2+Jj{``YSnO|@YjaojjfB94w@0NrlS*!lTPY&VR(DR9N=@$8cV{-UhKCqO6CI{~o zp_O4EvOU_h9ag1F9h@TmOkK^xM~eEN+oVnp=YaX_obU0)vTi(T<{y$!;&b#&v`043d(xGQ%AJ^ z<80jhUDX#n=?t%B`{Sb8 zM<)>R3(+`M2rK)3-L*Au6;ywOu3$)V1wxza~no_vW=1 z920tUO#tA;E2h=|=H88+I=d?7jiD!)yfUoYASG;3L(9hl2mw=JL86jn{4N%xZJJy!%6rN z2DLWX;R314O7XNk{xs%cK7SS^8}C&!eG?z9l&CrTY3Nm$AAsshSnJ*Xg`K2jfm99D z$nl0b0UB!bE21jfgTd8F13bIFB8dfji3DXVs+n!ILiRtJjW7QTgf%?*xCt_QrI5XVP;Udq!UaF4(Hw|&*2s;m zh{W`Izs3@r48wL42IosuP(T1(ZF)Zl4nA0x!wEr+g!YZB2INKm#nvd)gau10=Y*x= zznTdeT%9x3HJA+qz=1{H6hj!=?=>ec0+9}+|3_;U{0~?c#6!R=P9F3_d$K~T8EC0O ztxX9RL4|c*Qf3>`Vp4A}utSItK?XL=H>lZ2_CTYsb$~%IgeV(PRH}}y!kQ{+xbQnF zSKC(vUJX4=b3q%gXz*#4T&;i<(pX|6MKYZh2|EEbxMi6bK#`BR+61D{Lx;!OW-_Qc zok$-bRpuQ~rNu`JjE>@iq)B(qXY~iHIzg`H7<)MR-u{4S)vUO9DC`(S(o3y^kT8I} z;UXXg3>cmvix~V83Pmxn+SCjNT2>56@_Gxne&e{yQOQH&kPj_c8@Qm!vQ)%)Jv5kk zS%lxTeHBa?0NDUl(g;DM8;E#t(}5oV)r#_cxKcg(uyv3d8aH!y)bO>n_seW1DHOAB z+TqpF=imQ!Nn7aC+}BBH(2JAiK%@jqVLpNjsVBLD+o#@CQ{~n! zMa_|bEDG;DE0-eIE(wSH(wReq7VT-(R_$v(JB4!vE0_4OGp2(Q?LT~g>4#O zelYAJ*AFSiJ`K7Mf#elu^ed4D-{jF zUy^R;0^R^?S}NEWcF6LOM`;%*@G$R}%IKBM2+^hCm-^^@iwPzf3F|DzjbX*05@TWGr z2D(c6-T~*blg>Szo%DGlnlxUZ}%Z zr1ccd`xM!UJrb%PR1PC4j$JK#C>P3Y6!-E9`Hy6?bW#G8!puMxk$A-&>`KQTj5im;akyH>83FPk(M{-OXtsH4l!nQ`;G~J>BbHjG21Z-SJyPt=MHTC zIR?#Z6ift=2I<9>TtwZb>D<`Au$4}#cpN6iEQgwhANb?!?Y*ykYOn0br!8Nn6 z@*vmx{cn&V$@H99+Z?2%Sf2-%BxH+;3+p*wP6c;=ohVv`%Q=7~1nb6&Cwh2Hn+7)B z+aHmssxizvEpF15zW+DG=OfL*d)u$iD?Hf7xo;xFbeCbdH(I@qA~Uoh!Qy1c#|%0k z!hY6o@My?0J>kuw&j<%JF3m!$pgxe^R~9VKxV@n9VLI#^95VG9Bq6cjo#lAC5u9y8 zrw5;QOsAmwt`&fU&_Bo_+ug6jxg~qr;PD&J#sycl{6|M&73zj`uO`+_R*B!P zgYfXcw-eh2PhH}9g&4C2G=3UYUo2A`nRvwxn{*`yg#`eUCqu_hhL8QIp4>J~<{8^l zo4g%Nxb}B-7ely?&5RRh{IG1WPGF(0MNw(+XjOu*if2?svYu@aLfL4i zs_}{(C3*zMLIp`a?HS%$KQu#x1hL4sCiGE_0v`avaE>-SxfCxpj-f(1wZQDC?p6*= zU6xn!?gIwHDlX9(G7*+6@KyjQdQ{k*^xt-eFoaP{rtxZlxTPfk;3Zx~gEY36_Ys&= z!t)%4W@-mepq6njJtRq(k*%WNJPioH;5n&D@FGCMaEbw0L*=1Hz$#|G(d88}N*oIR z_k%rJmpAR8n2ZgXB^8#^doa>rV!z)7oaR*JHi$}R2A09Q1~ZK1h%id-JY7cU{2R$L zsrRd|I@#L*L6MmAaXm(({2dZlewqcQAJRXvN6SIg(q-TKlxXwiNDVoej!3Rv*5-@c zDe6fZKZT99&1(0beQnkD@rykFo8mWq4k-YCWLi9&v#&>!_2062d1-A>_9}AJbb(DO zaYE*}CLQ z`sj&8o%h8Nh9En6j?1G)2MLJf0*s3%J)vMO<;{X7b!xeEpJV0t7?v^HGG5zEqsnn1 z%@^mDMk-H)Bz0H%T1nU2wbK+98{7Q%VGB8$(fidI@9wlX&(~hbA!U{Ey>OTl=&wjb zCD{}eYP0G%X9x4~lDf2m)WDGpF;qaL0R`(~r3O|=Q;tew+*=lv`JxvJ;&=?&DzSgy z2=?T-)pcc5XQU~$6hD)cTs&$3KjlS=`9O_$I*O>m;UO73k7-cu1kN-SYxWAcwR|67w1>WaN1ADn1lb1rgIF=tZUkK ztO+KzZQHhO+jg$lb|#wGwr$(CZGBVU{k(s6Rj*y$)qmI7tB|Um zMf>#g6Bkf=r} zP-l=4Za>abG)*WYVOB*DD9(e?(jfU(@o-V8jk!C~Kd0*vhD|<2wtsAN123Dusa_GK z34S~sMGjV5JzVY3VhOe)n7(S_T?iTWsI+K$^~Fms(bn8MdVv#Qn%O|@T9qTFU2oF6 zHha9D^CrcxaINfe1wzTnr7waP%M>qgZs9Fa;m%yf9)D*GE?%Jq*Myp^G_J)dzmqul z@aS|^G=C$hUCKPS@vNQn(p-f&MJx36o1vC*b)TP$b>u z@=RA-fqr{#ANLA?@e0TeyA%fPQ73+p8;*?RYN>aYX`ifKR(=x0=>Q`0#r2kVwd;zy zV2(oDINfEDU$%`{U9@HODB}#O#`J8F=eW;{>`3rzlpStfV~s-%XnAY#EZ?BRX9xCe znfuZr2g#_E&u-kdl-DBXa_!)h$_=(JOX-)+zg%K26KV(OZ3*NCUop(p*CfYmf?P74 zQl$Q+7*>noqA`0B{{^>UBs)sJKpVCK%^$J0^id;$muT z(h~VNdW?WQ!9*ej)6b?Vy~onkSf;WGgyo zR(!E-t*mPfz`~j>6?GdEw5^Ju_IrhsnND#ZtJO`5TxpHHPY~Y##vrCt5yU{#QR2|A zSljZ+Ys{2U+U+##%A9MoqLe<~O4Q15wrOn-W?%sIjU_jfZj3t%r?1de@S5i=vYYqd ztry6sACQaq-t>Rs14`Pf1Tad&Svsn0T51w7Y6J2ylrRW8QySwdFmek6CGZG72s_Jv z5v(NeJqIWgJKKL@MG|ll4lu`mfl@6nJ01uJ!+%lEG;jhX2nSQkzbZ7QARPZI;G_#u z!VdhublMaU73}{@2blz^rUBvnU;5B1h$#^W=l_~;X9IP{{dbxF{~diRgVqWDR{{l* zk)7lJ?)FRsj4c0VyMmO!sNjrjjBG4Pbq3^sm=|ybob`Ed7~;MyT!_F9?!K)pQ~!S- zVF!1K_}%Khpbl>bclSWP>9$1Yo}U`8n$kectqNE7n<<5Osxl_1%ysM_lFKU{3=ND7 zPvHD}D=V5wATu*IF*7qY4;UC$X>{yaz~L)=4CE>1AKisJikTy{xZSrfHow__ z#5)b(11XiY0HWdH(Rl=9f(F|P%B7MCaQpMj4uP0_;LU+qfGRYx*MYTpe8>H=^81C3 z4yi{*=I-t;_P2_;peyN(9LvkUqX-ZME&zTA>*NHQ0rE|S`4^}W{HudS%mc>%Pe{>2 z4@&v78Qrx2`R`p_17k~&dS^d&$0lZQPT=hVP?e%1ph$Rv4nV@ux9DHU&kjx?G_lm5 z_K%h){aBi-Z#IZO>8l%DKvz7pSChbIscZ!P`N22^QDMJ$fh^45(Ge{UY<>WC2ri&n z>p(F((0~$nFbODXQ2!g$?+!k5WO8XpbaOFt>C7H0llO@!@64eq8PO|STR}Iv>07`N zx!D;Qljltb`9crE%KG&7*7OJe=;ZwL;$;n!j4p2a;uQ_9uHd}U&v9qe?$79?ARQ3A znVFd#n;Ot4BG5fUoxwY`{~tgJ=&3#Fg#P{umQNS%B`%QJjj6v6?UcX`V7Dtfz>dH_ zDv5e@N8Qq_8baNj5JMP7uar9FE_3Ja6h8L)P^5$R!#Nhklq$l@r zhkSBzdwTc*;p>LjOi5*Bb~dr(!+q>WH8OnF8>ka=6&SYC#s&zUjSc`rjzHe~0_dUu zrv1qt;-@LPn!E(&`H_0=lKzogz1l$*__}%e3;bC_5B~Ae1`b^M6WxZ#4B0UDL7)0F zGw|Iq_S1v;GcoaVk^Zw2O`>CK^S!M66LtGj0J*NU?(v;@$JbI#cf(C!|I-ca_LEi) z{l2n49wbAnYx`59whjP)?f%v8cFgu;TUgW(Tm(6)GB!UnxPPpMKskDFLkPjZxW3lWnF+LA@c^E_#@+YhT9~B+LJO1j5?#FIZl zFoI+#`x3+fB75RLl1WkKfy$^{9OV`1fBfLdSp)AHVrNgT~)lCg;EL zw>$w-88|<{I~A_)|C*S3i~H)3H^=_lFvJgaL#O)h8{CF|L|FEg z-u!p0z5fka-<@`Lhw!SGd$My2K${(0I_ok^>$w?yx%x!-{ul!d;1M9Zje2+{^C47g zA_UkXEcJt3!*(2iFr#$*v1EbWj*`2ojvHkdV^P%_cSwH{W^dCMT6{{Oiwm8;p}J9Z94F#QlLIh|REVE}qfIFtVga%TNQ2xA2?C2mdu|0X zy1Ft2XL3A<6Cz52UU(zSsBf3o3}W7RPnxuq`^F+__##RXr1DTf*N*p zbugOfYHwpQLJ@6z8{-De3xgh$)z#&&aKqMyEfd6@k~dqLVks3WAQ9=T)t5#CngPpu z7@ojs)011eLQL{?Wwk2?_P4(_ebbS%%R04bq614_wvYG2w66}d*A5oep>=BvbsK0o zUTG^+#1d5N(&%Hm)9+`4*}XTj`QFqrNDo=JdDW1~;hFKg@yf5hO!v*JM{gP4#?B~8 zG2SrwTPZ^K?X4MBpLWYVv|{>p9|7$aE@8K+B#UX7xb!c2Yx2(GuJf&?xt*I^(AYe- ziDWQEoY8aGl9e+1@~*Yxgz*c+r^s#f4<}(#rq&+#d@y4)nQAbyO;TC@abtkBo*O2b zDPJbh4+}Z<4-cAIkJ~ej{ejBq6?%c6;$aopey9-bNhnHq+u|ZyzwGtzPe9P;CcSUO z?kd>6F?c)iK{DsuJk-`Dr1Oirgd+DWB}FS5{IXe$Axt}}Cdw+&jPQWED$-WqG1XZ; zsq6cmvEyesvy`B0wmn7N5jaRok#>7QFmFWE`x5@wyqK$5yNjPEyf>_x=#pO{-Laf^{ba|lJ65d&F^_no$rgdxI7n) z4>>6sL6oW=e>t?=)SS?^!R8uPje=Dj#DPd1vNHnvflkkc)ay=t1~3ucy9ZW^j*?849x-Bu)-0#W|W_jicp;4eyDO-R1$7MGt_Fy=is4A*5fs_&3vh(%9Xl% zS4(XEIotT}k|C#@NPCq7GrJI~|CdhUz|r4Lys2p$5V{mT?h(Jea__*y>aFdh#5>y; zYU|AEiNnWPhw=HBQouWnU{vN~IN3qvl=`|T5!5}9$HF&A0hE*fy!qfv#$IPYsfi$G z8Yv4SDc`yB$rtH}q8Z0*&jiCD*1ayCg1M}6N0bxTICBHXaP`LL8I<2)uBM}_B91mp zSCNsuA#DEKZh(A9Oetf4ELZ4WMU9LU&hq96YXeDJxICCFJD~a)no#x#e7AP@$)_fT zK><<5@b%Bg)h9!EmRE6HioW4 z%m&J8@@hlM?jiMgetuP5aPRTujhZs4GzT(=0HKOQ&x3CtEYE%h1}PFd_M#495gUwT zCI0qS|}kSJeZ?R!|_Sg|OJgCiuLRB>TIzan;vFF;8jBuyV9C zf8UH+IHv@{Yvi}`u+RExwhJ|?W8+jCyMu-;7XZ3as1kXe!y;ULAwgwlr=EYMi*@ew zilFBZR0d_qu4OJX1lWZ=|BqIsOGdT|$EewfIG)yrM!)K$uY4@x`}x+Vn}JsERzH=0 zdHO1$4Q__ku5bpM^uxBUrbn#Th>9oULc~6CG8Rt=;t_P7I}~fR4L*IrX~a=Fjl5o1 z7(fLdG;|~N^?{}%j1bas)y`(xXu?@UjQ(q?g=m2m8=mR_@jzAl9i@z0%-_i93D|vy zEGsZ@t4prt5EUi5-~z+(KwzrV2WfC7lkTBpKvS7a0!j?yLz#bl`x)hNDm9m40GB`} zEGz-SBeg+G-#ZydvljV0+1cLkQ_}p+7C=NS2!yrY5{jtLqk{ifLF2;kXcTl-M08$4 znhM`yex31A68BAL<0Oj{(h-IVrIpE=3 zAGojzhj~j~Jp2Plc;J*s)?yE%=N3y$W&$?jzyobo30dLEl3xVaS^&2?t}54r!7b=l z5xc+m+))@^ru-v#7&7yrYlHAl%}R;>Cd0+pAIsoaBPZW0TgGkb60xTAh@j$YNie=& zgc6BN_IffgnvhB={H~+I{pfx30Kiz>iL>~L{ovs9#oyS_A^($sd*>=|^)b%Myr)g; zSp|c?_IMfyHMQVjS%npAC;UgfXEugOX*^f{VZ5VHt&WugnDOxMNPr2kd(~~eW2c?6N$(>%W5-EuUdt__paXA^JFy!mMeH98i(^3oi!xDJ=ts7=Kd(V zDc0%oA-&ib{8D0(-y+Wp6Df7`cj;oP7c@4=^#vZdKw~M3Ga?Ueo(_t6r+;CgrI?y92K1N27EXHs8Y8st}Eiy)vsJ)&Fr7_G$D)YwA!!S;Gr z>mNETe?9VaVi1HtGr@k|ky;`5gPpV3T)99Zy(d zH>k4%SpXor_dfq9f7$ACOaD6rr}_efY0yeN4mCo_P-Ayl6*hpv z79p;7M`yd(Hzh|tQOB$9KGKBeJh2TO!dwL^jUChRu`?`2M}5bot{+MQE7FbvK69N&pLPaBOg$S@HsQabTcrIZ(Qlq24UQiJ>2evmO z%at}dV_7IRpUhWSq~mVen>?;#Wvvry;&x-x#zI|q(& zPwxh$kq4D6U{pgUVhY-QP>d0CrA@vsejW*r_RF03cAc*z+Lqh+fY94_9vdHo24W&x zlNxLEd<)d--%hr%Zt)_780&#;%rm1F5&|Tw`eYNRiVm3{!3PD0$YnSoi45MzwF8p( zEoV1%UC%&g?j5erUo^=t%X(71&KlTge)U*jSFtYy`kh%Xh;na_j+`v8`8`<^o<3^* z+iib6ZeEs92d!8WR}Oo3ADt^q#@URY-A;3) zQy$8>@g5+I{gaT_`%2weo&u9)-#N{J!eBSpXmbBqFgs|O6ZT76jR$7lOTqFBXAaG| zf&$hn0iQ1M_7Ob9eB`dvGv+iB1G-ooqBNQeow$iRT*Xv}bVAdpaeeVxY8OSGcMb=GtN2P@ zI#ct7-@!q`jVL6rSsLot>j(-4f+Wnbpu&~O#L8rEBt2~<%uWtBWO~`DpaHn$U_MR$ zy8NpYwd?9!>=L)UX%$ko@QvxJ)<^9;$1HQy%QP7Wf7`u2&rshk*z?hU3YgyfRgzsn z5tGz8XEeUFNxP&R9Vhji?M8Npp2faY(QX zBg9Bv#Pv^D>K@l!B)42zApp=;eW6K%Pzl`lfk5PQH`URTOhfN|v3+U&Sx;%aQ5y=- zgmhd?90Kk?M`c#dvt~h5s1NpVrqf=IJR$R%O3!X=ih&)~I7a^W(24teX(sW$OhNXt zy83M%>eYjL6?j3><&Hr}MZd8_e`{?$PRXhv&PQANmfIJb!9(8%H6Jh@5&gw&bOVwM zSY8qwhrk1(&aX0y{qqd$1>HW3u1%{Bm(GTVhLWnw25cCb!fBnOyUO+9m8WVUagsQg zI3Y#M6L;D5k00D^i`1!*jjXSBStL@yqm)?Q{@z#;O1dKqKD>Qowa*WPn~B%58aHl>F5Nt(iv)gRWmOxs5YD_$`_;ez$L zmwphPq1A5B?-VizSsYH5ec!Al%|Tg2mL%eNY@7Yp$E!8VYOaP9pnU7smgwm9)z>4Y zYer`|yQQsvqJEU;0%iM~preT`Dr})C@2m7n(}pDBGLJF>M;S0%nGnU{N@=`>Ud1VB zZ8GvrV3T{r8D;fP1z{cyyI7{*I0z8mH}B_pbRZ(YTtM}Es(*z8aqKuFhdK~7Si&+yxOe9XRN`Ys?3DGVj z5O1%Bt=_yc2K>Z7l_mX}(O7+PHgMze3&>ioBs%#2R5V1Jt|f?(?1x!gca<8(UMZ#lp==p-@Q#Li{e1vK z6#PYd2j(`AWu1=QX=5B-zKhWS51>@sNa^fj_jU}QdV3%t@vCA`CXhfI>$Nv1VDyKN zMR_}c=mAujG-x-La5B%7Lm$qrPP(O;!3JTLf zXGv8wWx}<|ha7!DHxvwra(C84t|ljaH7^!8Y3R0Rt{nN9>ED7=*xV)ZE|+>3pr{!6 zL0=Pkp6^E)>uVkvFkE~szHtP$E`T;z8jfpz4~leDn3RK)eiH6EHL!=ei?`Bx$C(i zof{B5wC38kV8)pj@5gablDL&?mJ49Ti3^!CFE~yvvCY&*I1>(cHfDhlDmMLL0tuyL zz~mG_&%2DX$E~l|5<=r|kM31uK6{3-{kV-ls}4E?&E{x1X|ziaV#z!uTo)lG?(IdX zyXjAn?{A8Ue2FoE6)k5Ar;RkjrAJ_FMFdE`g<{l@K|pa?cyk{f-b_GFzc9yeC&C<= z-YEra4?ovu%zL{jpA$aIf?Ycwi>TW`>pIWz-BI!5Mu5%HjhEs{D?InA;-6dGsh^yXnhZ~4r^e=c*s^tt-%CMYV4sRVR@{Hh#tJ6 zD28o~zJAp~UIc@Cf^nJk03n+>KmxiL@$rwuwTS&T72n6N*4q4NA4g~n^rx3+aku^& zPcnbn_^8NSJE^0MI1RoIxLf!c6i=9(w~c$3MCbA^TpjuqS>k#xT7Mt^`XTPeST!Br zJ$zAR$WbIeW!(%FsHZs~NW(uHusqBOODcM3!y*UrokH2Xemh%}-%)SLAO!T}ZM`Q^ z97U0^Sj{7yg~LCYi&6M-E5X6~bDLFj!={4{?>BIBcs~KVrIE z)|j3`S2>h($)Lle*MDxc5VBadr6fLL5l=BsXg+F1vZOknyaB-i6-KW<7}*EJGlsf0 zcVz(gD-1E~TeR#dmOCDX-2{5HK~>mQ-P$rQ5FkoRVwb}3yBO57dK)|=-Cl43PrHrt zWrdvV;%*F8VHI+>zyj{funWh%Uv9(6pIMFM5QUFiR0g!Mf))ttMBv-QjZ{D3?;UuQF5`i@(R-w=+zxg zf{8b&EJyr<4j_8&jFWGLnGZ=O_68k!)aEPF;nNTrFUFCCoy&T$&vIsBClM%}*Tq@N zXS-(11EU4zSOCCDPa_@b0mRO#R^DfyW*cyPNEuLC9=){XjBv5ne`0!+*X*c?G4T_Z za6?)d$6L}M3|C-lh+ed;2b%n9KZK2kU!K_ph-0&moO4>mw9?a72prPmO3!9bisi4V z|9Qq>Au7IbD^d1Hr30;K^ejsWhc{o_Pd-GT-z#2{?f`)D>(C*G-^OL6-WJ3AAZY&9 z3Sojx4)tSOF3aV@?=M9$fc1|(nomfFld2f+Tb^Y_d#(#6iP$!2oNcHgBb@RP87}pm zL3SjW7h}%E<3BMuXJC(KPl?no9Xul(F&ED8Z0fIuLL&-!TZYG|WrgKA>yHVv*)K1t zj|ZpzqqMy>aPzvT+u}T%@rx}Zn77%%IeK|qLl#gL;1{5r_KDWs{YE3+z!0Mh=gVGE+I1n%|qCDx45`B z%LPzWEKT7i7GKmFQ~pL&?oV;?cjH)*JUg_e%=f#lUusL|?LZ@ZI=W$QRH2;LOyXf* zcGBhiuCOHJXO(9-aPTVshO*z2OBHY;kY-61XH@Um9>49r?n$CJg1E=$`IKFjSGxGu+SPDY{M0FRHi{~vDyNY>i z?wiE~N9q>mE<`66y19GS_<@k*OBOvKY)dIxo08p{8MsL}rcnYjqQG#@eV7glP3EeLZOwr0~H3jl!b(l2z%nn3FOKSgvzp!y%1bT8{@CJIcsC+Sqxc zEP`J0V~{L7FXWHf5=ac&25O+$PUkh-GaKl{-^80o>*~kSbEfmGPF9ehNxJX(VPz8|vKX(k~45g``DvtSdf*5HJ>8Nhlkn z!Ehnh24$D_Dainlb9^6bpRmQeLfvTljstccH|J|Th~@FLz-Whz7;XSto`<1kQK!`f zeF$qQ&Q!cgJLt>0Dh0E9w-n zpRjaczCy91$6>UDk~LTaam%_C1DaOBk$)(6Pj==&z^0-1J>eOGDt^9=z%{oMGc z-hv`hs36C{GN1o3dn4dI01;su=EKRtLb12uDZRn0px8>$)R`}iHo~6RXd$~eG@O#= z46aWklx5bo?r3TbE7G=pS4*W22Il2qxWE*4`FW~~U^gL3`~Wdu!Magx!F@=uu+VhX zj3tg5xkvi;E;M}cZFz>F(|I`QtD|h&JCRlelsfs@XhYLb;I{qBG?Hs`9ZP{)}C(w?U#C-$anfBU_zcc&c#DdLU55FhGK(N%X%^?^_^`7vn z?B8}(=%8-z5lDBduQ~IP71VCpehgT&Q5vPwky(K-gvX8)b`FWbwbdj^i>WN`aCukw zqE4*T>J!&$=d5~Pusp3YBv^uy@ujS?E+Hk~0{?yw>ckq0hY<$*w23#|atJvL6E`XUyX7NN zABEi?d11<^h2d)drK1PaQ#q9ugNB4InJf~_>n4l{IP{$CD9cU?L{9!qie)6WlUN?M z>Q@Xs?NJ~RA9(Et#^Aep{-|6C&ysGktUBfxs3gF#S9&`AbeQFiDm^jl%l`U9>?u*K zCah(bU%R%K{2AVALxjf8EfA}SKln(Hg)9vMxAa`qXZm$%Q^{D-_QCPNm>2xlNmbK+ zWoQBPk5p@ixtC>)4`t;D8?8BZNbF;FXdqrayWf;s6@4(_N81X^Y@|cCE+vRz zzIggOh_^Ec@MTO3W`htMbj+8S$qKf?DVvt)=72fSuBjZVar*b3o{*_|-al0@T=ADs zE3q6M2EVhK$!y;ul?{!4S3_MC^5S`ZB@R6TXMNatoFrKXBq6gUVNUz0Sz`_apsHWqa5d*WY=D;-vU~~2F zl}_TJ>n!{A#Yn=(WpuN~A|gcm0I9iaH5%x)18Ep`*VEq^uFBQ#>GO0#Scf~Z9Vwnhu<*BU;EAkPq>Vi{f{Z%vf0>aWxtS38 z1Bpd@N-~!BHhlzk@9FvmRh|pXP%s@WEPJbSuM41 zizW3@jjO}>bq<+uI7XP4mPJ-t)b1MrHC`>0IM&p`?)UKSG~c0>ctH#J)DF#`SbzpS zrF`^_PKGVD4>tD1I$FF>S5P-gS$Hh=(|;}~A97A34OB*7X#jUaM+_V;WW~Tn?jUJw zhPzEzFd%8yzgzTEZaX)D)Rvcv5_fL9{j#a+^(E7nT|ByWAD`%O$bvYdm}7xp zsU~o?jO0rP>hq(w3|9art;t^omDVAlFC-Qa&eIAy$n~_0dv5_C&;6un#L7feRGY$# zKqrZlej@JY=*sW z$a%+*S{U~E!R~?ew)b}#2JwsF8?|jyy;U$tAzL zd4^}0gRXj|+=v7mV{j+?kWICM^K1wrK+u5^Jm6TRPF(gTUa<<2a_`sJ;od9XUZexj zURPSSYYh-vi!8C$_o=?tq+Crf*`DF#0pqfl1f#Z>lcMt~G$^w{29yzQ)Bnt`Xz;%0 zcVC1Te;Ie3h1kC0+{G$Lj=?xMw#*IzivDh-vsM%3HSbN7Yx5;CP0pi!T)mT~Q;~~HmnLt4%0&xL@YelaKR zypWd8F!Jn>;*9lkk#0NyRx0UY76oD5h2+O*_)gcdo=ixqP1Zufg~f44Z3D;KbI*<= zPO$?_@8}u(l(CjN(CBY8%*pU^uMH_Wt{4M2c;3Qr|EGW<;e0ZfeEe==zPPt+ERE^eKWckQM^5L;`M!z;12DL2(;dajM&h z7%nj|>4RunOd44=}~0S4-1)VLhf!_62QC%mguFxqOnC+(&B$&hGY%$1ik?2 zvx&?1Fgc3Iey2Swi)x3ddLyGNSma!*i5(iCW*maLnnO0Tf5XnC;ORh?u3`(_y-@^= z?}?=N>03C7ZPcTHAu9SB=sc~v*vkvW{%V)TSVQx61&P1O<2iDn9LuHrgM#==Q}%Ay z7i(+F0pFVNGWALV?3@HC(dH5FyvOWx9u<46Q}V;t2{U&ly!@w***pW5VOu^nd^e+F zKq`~HF6y!>RN|=cNu!)I0L}drC@>K)!pDgo9W6K;DdJ24-=UQg+s?3{rY<+i7WKQ) zvUNB(Y+_}!QhgbfAq39(tZGRq^J1IIY^xWHWwj$`EU)YHxETh-)2U2aM<$)#(EL{k z(LY0L`Qd?QjlAD8?qpj&DlYKDc((djHXRd7uggzuj!QbFO&d|_#x2LSmGxziruD|s{pCL~52y%ijxdwea?z}6r?}B)_xkvn!yS zo_&}5s9Scv6BRlBcXawc0xs$bm)&b5xUeV z&_SgfNp1C`+7#7yx5`za^vPL(mdC5K;!hu-`G# za@Psb-M&AJ);t>^T2rd~T!Mr!h>>Q!*`* zpD$#WSiyv+ynrQs5aZ#h5Jq7b?gv?72(DMJ@BgM4pNP3#JfnO_tbSRMnxB?Y(r0`q zfK`6Xwb)i;@s4TPF3TnXx*Y`UV-+ac{(Ki5!PAf{<7uNHNc|K;<7$Bll`gG(e#C^$ zujd_Vm(0TSn%lzoE33(SLA~9TNSqs(FqI{IGvr2rgY#X^5i}m{?`k9p$DJ0+?xD|8 ze>3|O)K6h71*DaS&iR-K-vlSLhv4C46992lD=8ehcvY$6TBhX!a^hH8_hI9DF67orJ1HDnJdadv)*(Mcfy6otL zvHI{uJ!ziiUVxwl6t2i~D6lIwv(?}X;=>8U&=Q!aFFgk9tm`aGICFj3Vm*aGz_=Ybdz3A6jL;#ycM6TWE^z%9yZC$2M%U7?^8cc48&Pp&5=l<~~Vn6-^WrLTxJ@jtjR# zdhDr`$fm=@*!DK{Due`FYSuaq1?ac38&PDi(aEZfs#s@Oa8?iFfGUV4ABcCfr7)?z z(nD=)V;^OoA(P1R+W7OGVm~3GLHQ^+ff7- zTTMx<<=8t=coi%4tH<-xs?SSy{SjUh#lDP zZkpPQtvojln)#+Cy)n}jm2Z?$AK!KNRP{XoU~_jZ%I`d)n^SnnI3LaF=ppyf$D_HQAa}Mv1ULMSZ@G*fsE(_QP*a4A9pZY)z)y5#mz- zUg>Ui7TMNc#yi1Cq|Ogs74IDf`IePqFQ2o?-uX)XUmt2LE~FPn{&KpIsO<7A_oBe3 z46E*}7&HxaN@Xxa-h3@PY7WBWuQ;$MYSSn;L(Z)If%*5nu@$gqt$OUb&m-D!d^#sS z9=G`KSE=8EGPL=Y;9kTD^J8N86@zkszM*RdrXe36IY54|JSwb>?W+74k*EJQfYFiZ zKJfbK3Dc;g$9YR)dqc?@+Fa*Qy1!VNiH`56IJ#2h!D3FaD`#TZ%eWdAH3p*x9NVzUJma5cJ11md7uvn^iXH* zD#6bnB5$hgDGtzQg0d2OVtprAb)z;Y(i|IrNoZ6(s%any5io8yTD)G_@$@$dY&zL0 zKNQM0=F>6+HOF4=JWtGg)xVx?SOt*5jo_HPv9hu&oaj6z8G@O}P3O8)J(*;*2dfLA zQKoDwf?~HV4o_^P1u2R$x7`9FuP5la-*aa8mH-OB;#9lI)yhO!4*Nco&bT{3tD!?Lng_1vz_Ysh&Q-mAHv z6QeBQ={&H97ta~On}|PCo@3`mkYwgp^#XS=tjyaXZ2TeXUh5D5`1^jZjgQE~?e27S z4JYt{9fjh^=u-1V(t`5cgI(2CWdqJ(qbT2hJ>p|Cf>sN?we% zF9+WPXbvF3Eo}Lbp=3ZI3%AI6C5m92Z@JN^!q2^OSgWT17qIgMhl8Uwz43B03sL9V zhtJvFFtQF(^`ky%p;8eYrusNAGwOL4oP?cbK1KtS6~@1o(`YiZVr^5U?b|(E=j?Iq z`Mn*$swHozZ&wn5tCFvhxyjs>p;WfA^or83Pub`;sTyW~-MYf3PRh$89kgL78m*2u z9vlbh-d3gqY8XUVR9Nbpge=G>r$&2sWdu$bzJGfLlyZdfeO)qJ3`!C!Hv1h1_r>K8 z%E-F)ykOCTEb82esDBXPHnLWK3Vc3wfd3~P!$i_Rjcb0E;nTxs&pZX5(=OGp^XwP;ittAD zC0SZ&BXMWtOQpX)A2PQB#kUj>6``sp`EkWG z2I?XKKoP|)tDlkPDw{OT7z9k@0vhkI2p}7G(?iw3%D*dF66b!!2s#N1v%0!c)lGsU zBF2F2*VX;$(>7?#T`hz@Ug+cbw4bv%3f#8}OBm)Uu2&@?-IU>lk^3YZp_%VxQ*Pnz zoSoH9B3Fk*J>xO^&Fx$4ixmsieEO@l=`R{+K!i&-VoY3=wTSLf;`hnfR-%uQStA!N zae}$UuuNp$LLMQ~w-HQYT&-vAH!$x8JRjbq0u!0w@dl+YJevhCJAxMQpXub#Mx#kl z!lA@(ecuyn`iJ?5(1E0M?<`92Y0oySVZd^SYMz+K9g_KU%0r+R!VKO+jk3^VDU+NXa8diF$-+QB%59HIx9xhXL0R^NYWddYo z0;&=2$9n{I4_HjFVchW@E`Ag3BVof-H+J?(Xhx!C9OD z8{C5hmk=}%9KvFO;O-WJTd?2+5Bd4Ns{d4-t5b8+)6+9^H8nNeQ_pLXVlw5rM%zE4 zq9;5N6LoKAn6Fta_4kS*Hz|c)Apc_UPt|%VF8S64_B1iAch|*_4dluDw5_X`3=t8R zQb)EUb5v&EKC`xJ!n|py_vnn|iA5?3Yb`0S#CuksDp~Xs8WDKAfQCNB6+Mrp19~N; zm{bL5`ECJ0p{lsU5pp>qnbS#0+#-!4ZTb1gW|g&;=)lSK9Vcbg@O$G7q>Od_ zivS<->YLTvUpEYg<|G|LKZmKo`LTP~zq?7GUQR;y5!G(kR+cRU8z7Z;RH>T>!kEEX z0t(&`P{;{$1mgb8$6BjQ^Tnz%-E{dV>Hfj29*iw4n%nvqeOXhfc0waAmhOHRk5SXN zH`9=573E8l*HBL+(Z#P)N=TNrr?(&14*{4!0yO`HTxyQs-gsxALo`ZFH>c86=z^FL z%bcIpxXa^R*izt{gwq7TDVw_D!Cozj2|B3nRwt7ljKHIVlI<&}(7{sktw^|c2g7G0 z|5CiL!ZzVoXJoHQy5lR{`K=)P0hhpdQTcD2xly=jP5(Suwr-~qRy3xFV%;XMG5)8! zMa+e_zgTrjr1BPPyEyV{mJ7lNpo>AV#TRN6<)V{T8D#J851|u=rnPgJ;={lDWsbq$ z25Mqvs}UQC-Ns+M^NM*EuU0ri*jp>wuReDV%B z3Rb&FnG6dn#uc2hIasNc-yo<^y8bTlX;xc@iLT~ck*+ZMql;^JR+H#}P#<-fXX^E` z4t`4xgXyn>RJF0DOHDfX%(C3NyR{;yf6-j99dI6XKhUKGdDK*eAUHSARJnY z$%bIps6mW>C3+<(PyA98z2+#03=4P-vAkbnNokB&6f{A4nVpx zXb_3{1e6A3>HtA6zgmE<0GTG}paCQW2=wfy9ux}k&q05UUip1o{Xpy#DV@j*t& zGaS$|AoCv)hy=Ng526Dic}YPF7|1nx&ypdNJS|G!{U~I1NZU<3&I5dKeqtPEAY%y_#^;iMO2#@d94Wi7fEl^!S~CFy@XqAy!=4EpO+JiWuJTEY50t0Bdj z!8%8t?>!riziewyXu{_i9CYEL1w-=h5>9%3I4h*}5vUm0Gv6iU^LSbZ6W+HZND(r7 zs9CikN>gGyUyL$#!&VxgL`3$GFN{`G&*EgZEuVK%NS;3t@}+9`yzAz)o2N|&^MrMC z5-MRIX?`ze-HXA?n_@14n7xRity5G&BcfGM)=4HOWMkA)kfjtWwKUVA?}oxoLlBSb26A-awPOGH@Yf_I zQ6?=fbB8d|Hf#tfVo&-Ct1Q_GoJl-zjnOmWa2zR7nWd(+Zvlb&U&N{zsDN(?C{@se zTr9C}i)C$LXnr;=VVYqD8;UNruZGa}m16Qx#L%Qs19Q&B@B)8g#aP(l4pHnIB}7Uh zT)=4VmMAgbsVH?`03*i1Q1n`PxzBMYo^eFFNP{iJ+pe$NO zP!IyGsNopeD&a`#@R7WNo*^CTH`Jbp=9^3a=ItarSTh(ta;9?z#NFBQ-=D>dw~48m z+j=J*C{$5%!ieD?dX|1MA|Rqkh(27q|Mjo`mscx(gpMH6!)c+Ok9QoL=tFrJd9-I2 z#9ePKtW>D8Ml`Z;m!oolD{t=KS<#BPVhezn&;uP+adUzXHkP`K@L}p0n4Z26zjvlGAFm5ZN`=7%O^Ybr8 z`yKn%;bG2JMn4ICzk@K_9d{_BR|8n3!L-CyPG6~j%l<%ZQvn8`|H7xR;Xj_ClbXhF z9SVL#|@mbg7eFKNaMpyOnS2?CA_c=t{eL zDvK}u>Fvei@vs9zW9|D|R8$cYeojg`y~eQAML}9)nTQjapL$a5#3XmVNZWeu2n81I zzgZ!h{X$;xEkU(t-^y=;wOt*pL3`9t##h||Ah8qT-DZlbecYW(wA=JCeLpMl^$$z& ze;QTIJ{FAc@QJ+a<7P34{pr_0LK9VUCY3zXThvIz`(=zb*qg z@-;lyWv0C|-E(b8uSpnP`w^qPt_7-a2+qIJjhN-qVZ(6&=L^@j> z+&(2~+*12^^8c{^>A3EbeG5=t|P z*`O8)bxO=gCSv&)HFXn*R0mim9Iw^-N14wf+?gwB(L_Eph!|-!jQP>{u%l^ANIhsZ zQ}&uZ$zp8A)~G+>E^(Aiy;REx_&NEg9^Dfn|uIA??(?TcyX8B1s8z(5D50Y3+vWQL5R-e<6D&u+)2G#-ey)B)V;rt=V}l7`CcJfX*1B3YbcK4ByD4R?;G*8rcF_V=I46A zoPV2Lig=MGl8(wahJ%JP-m`8`&o5rR>E^#MZ3w?$| zI$nlf%i%H87bB0s1Akf`4mRDUnV3cgH&QfIaQ{KpU+x>mx^N{u>vL)84QC_%~I*3cj+d#Iy`9ZP@aK z6TeXuIHDI3V(70+PreoB=r*FbF*?VP)Bw0U4`N1I-8aa$I2ytXc}VB@49(wggxquB!8a>FN^Tc)W}S z7NZne)4kDWVvmOml6^t0Gn*t=G&_{E{I4-QeP{R&JVQ+r5gVzT8=dU~rS>=WQfIiC0 zxA!!JcQ~A02v;Du}5s990`6ogsWnIkfGf{N%pxf06F(*p=Ive3`HSck09qcuf_spjd!A*fQcrZ^6?5Ud>#865n~3AG<;&`g2)^h)|3oVRK+;A z9(iRKY`#DP8p@+_pTw0?vf~t+#~l>Yi0OqBX}nXLjR*Zf?`@h^59(1`Sm9Q)0^YUU zN18eWcU$YU^g;pjSDfVft79XqE${E{@pf%x$Ki!B z*TirCCEB3`czQ$YrWk)EO$I&bhv(*#F2TXL53Z$TF)% zL1Z`(Gc0bMH-UCwUOq_XlqiVAS@2m&SsRO6$<5v!%==$uwg2>F!6u^8P&q!R0E97(u%S|pK^ zoyb#*KT;+?X9BM__2x53OZDdU)16dIk^-A>V?(pZvr}(@eI>HwidnxQ^gKj71ky~j zv3-&ZJdk8XCLGp1lQeGU+P5dIdj;Q4TInOsxL?q}ApLm{tYkSHbNdhq`aO6gR|>|) z**=!G3#W#JErySv1y~}e-C5Y_NZzq^xap#kgi&;G%>gt)_UFEZaZ*YVjSFMGBieNY z+}O2ga6;DJ(Sc=oBRuvq_*t_y7rM$B)>*Trei(ZPjyZ-MzhRs~%%XZL&fG@&mTOrR z+UPmymTQqIs{R&dk8`mp+Tq#AnK9du6wv&YIkp|6VWL4KG6ez0HH2slnQ*Lx^W{EW6MncEWGU0k>*y&1u*ss11-L5@Nx zhWDpuNkn@jFX?`&B3kD zI(BBBRdo>Fa(ZQ7{%!B{zP6bP#d%{P!D>(0xv%XxNeHI4RK-hEqvD6ofu8=+w(t)v zfO5VRdV?s%_r%x+9GKy+ab&;8zVm|mw@1F_%!!k|g%pZ)(j}l8Z&C|}p!9W^(#+9# z|2$}&eN#THo|exnl6XOgjf7H)jvO87P+<^T5+!-{9u&?>m4~Zi1Y=DFOQ2$gfB7n&zoj;5SyuCGMAN(Dhu3NM8NL(SR zV&A2*YXbjUpd0!sNx2l75fs3p=lEu#ZVsSg@GXy zpE%0(JE=M{oX}v&F1)|5ukH@;KTRZrhHnr|xl3DQ2YUaQu~-bV+g-!_hx)IyMd^PI l_kT3eZQZS%u)Msj;NJdlJ9{js03QSf#d`HhPD38+{{hjH@MQo1 delta 68816 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 diff --git a/paper.tex b/paper.tex index db0fb44..7d6b1bc 100644 --- a/paper.tex +++ b/paper.tex @@ -33,14 +33,17 @@ metacognitive control, executive planning, cognitive flexibility, in-context learning, attention, and goal maintenance. Each faculty is measured by a dedicated, mathematically grounded metric with -computable ground truth. Across three OpenAI models (GPT-4o, GPT-5.4-mini, -GPT-5.4) and three difficulty levels, we find a clear capability hierarchy: -GPT-5.4 achieves near-perfect coefficient recovery at medium difficulty -(error $< 10^{-4}$) while GPT-4o fails at basic tool use on hard problems. +computable ground truth. A preliminary reported comparison covers three +OpenAI models (GPT-4o, GPT-5.4-mini, GPT-5.4), three difficulty levels, +and two seeds per configuration. In that comparison, GPT-5.4 achieves +total coefficient error below $0.002$ on both medium-difficulty instances, +while GPT-4o fails to produce a scored run on the two hard instances. The benchmark reveals distinct behavioral failure modes---test function homogeneity, premature termination, and over-reliance on consistency -checks---that map onto specific cognitive deficits. All code, logs, and -data are publicly available. +checks---that map onto specific cognitive deficits. These observations +are exploratory. The implementation and selected notebook outputs are +publicly available; the underlying run-log archive for the manuscript's +tables is not included in the repository. \end{abstract} %---------------------------------------------------------------------- @@ -130,10 +133,10 @@ \subsection{Difficulty Levels} \toprule \textbf{Difficulty} & $N$ & \textbf{Unknowns} & \textbf{Budget} & \textbf{Turn limit} \\ \midrule -Easy & 2 & 8 & 12 & 24 \\ -Medium & 3 & 12 & 18 & 36 \\ -Hard & 4 & 16 & 24 & 48 \\ -Extreme & 8 & 32 & 48 & 96 \\ +Easy & 2 & 8 & 12 & 36 \\ +Medium & 3 & 12 & 18 & 54 \\ +Hard & 4 & 16 & 24 & 72 \\ +Extreme & 8 & 32 & 48 & 144 \\ \bottomrule \end{tabular} \end{center} @@ -141,7 +144,9 @@ \subsection{Difficulty Levels} \noindent The budget is set to $1.5\times$ the number of unknowns, providing enough headroom for the model to solve the system, diagnose problems, and iterate---but not so much that brute-force data collection -suffices. The turn limit is $2\times$ the budget. +suffices. These are the current runner's defaults: its turn limit is +$3\times$ the budget. Historical results must be compared using their +recorded run settings, which are not recoverable from the tables alone. \subsection{Tools Available to the Model} @@ -455,7 +460,9 @@ \section{Experimental Design} \subsection{Models} -We evaluate six models spanning three providers and two capability tiers: +The preliminary comparison reported in Table~\ref{tab:sweep} covers +GPT-4o, GPT-5.4-mini, and GPT-5.4. An expanded comparison is proposed +across six models spanning three providers and two capability tiers: \begin{center} \small @@ -463,37 +470,49 @@ \subsection{Models} \toprule \textbf{Provider} & \textbf{Large} & \textbf{Small} \\ \midrule -Anthropic & Claude Opus 4.6 & Claude Sonnet 4.6 \\ +Anthropic & Claude Opus 4.6 & Claude Sonnet 4 (2025-05-14) \\ OpenAI & GPT-5.4 & GPT-5.4-mini \\ Google & Gemini 3.1 Pro & Gemini 3 Flash \\ \bottomrule \end{tabular} \end{center} -\noindent All models are accessed through the same benchmark infrastructure, -ensuring identical tool interfaces, system prompts, and parsing logic across -providers. OpenAI models use \texttt{reasoning\_effort: medium} (see -Limitations). All models use the standard prompt with mathematical context. +\noindent Provider backends share tool interfaces, prompt construction, +and parsing logic. The proposed model names reflect the +runner's model registry; this is distinct from the three-model table. The draft +reports \texttt{reasoning\_effort: medium} for GPT-5.4 and GPT-5.4-mini; +GPT-4o has no reasoning-effort override in the registry. The preliminary +comparison uses the standard prompt with mathematical context. \subsection{Protocol} -Each model is evaluated at three difficulty levels (easy, medium, hard) -across five random seeds, with and without the mathematical context prompt -(baseline ablation), for a total of $6 \times 3 \times 5 \times 2 = 180$ -runs. Budgets and turn limits are auto-scaled from difficulty. Each run +The preliminary table reports $3 \times 3 \times 2 = 18$ attempted runs: +three models at three difficulty levels (easy, medium, hard), using seeds +42 and 137. Fifteen attempts have reported scores and three have no +score. This matches the batch runner's default model, difficulty, and +seed selection; it is not evidence that the table has been regenerated +with the current code. + +The proposed expanded study would evaluate six models across five seeds, +with and without the mathematical context prompt (baseline ablation), for +a total of $6 \times 3 \times 5 \times 2 = 180$ runs. This expanded sweep +is not reported as completed here. The runner selects one prompt condition +per invocation via \texttt{--baseline}; both conditions require separate +invocations. Budgets and turn limits are auto-scaled from difficulty. Each run produces a JSON log containing: the full turn-by-turn transcript, every query and its result, every solve with coefficient errors against ground truth, every consistency check, every term integral call, the post-hoc efficiency curve (error at each query count), and the metacognitive metrics ($\sigma$-curves, monitoring reports, control efficiency). -The benchmark is available as a Kaggle Community Benchmark. The -\texttt{kaggle.py} adapter wraps the core benchmark loop using the -\texttt{kaggle-benchmarks} SDK, importing \texttt{dispatch\_turn()} from -the main benchmark code to ensure identical tool dispatch logic across the -command-line and notebook interfaces. The full sweep costs approximately -\$25 at standard API pricing (calibrated from Opus 4.6 runs at \$0.85/run), -making reproduction accessible. +Kaggle integration is provided in \texttt{kaggle-benchmark.ipynb} and +\texttt{kaggle.ipynb}, using the \texttt{kaggle-benchmarks} SDK and importing +\texttt{dispatch\_turn()} from the main benchmark code. Saved notebook +outputs document additional exploratory runs; they are separate from the +18-attempt table and do not establish completion of the proposed study. +The original draft estimated approximately \$25 for the expanded sweep +(calibrated from Opus 4.6 runs at \$0.85/run); this estimate has not been +revalidated and actual cost depends on the selected models and usage. %---------------------------------------------------------------------- \section{Results} @@ -502,14 +521,27 @@ \section{Results} \subsection{Cross-Model Comparison} -Table~\ref{tab:sweep} shows the primary results. The identifiability +\paragraph{Evidence status.} +The tables below retain the historical values reported in this draft. +The repository does not include their underlying per-run JSON logs or +sweep summaries, so these values and aggregates cannot be recomputed from +the checkout alone. The checked-in figures likewise do not include a +complete source-run archive. In particular, the checked-in success-rate +figures label 180 scored runs across six models, with ten runs per +model--difficulty combination. That aggregate has a different design +from the proposed five-seed, two-prompt study above. Saved Kaggle notebook +outputs provide additional exploratory evidence under their own recorded settings. +No numerical results have been regenerated for this revision. + +Table~\ref{tab:sweep} shows the preliminary reported results. The identifiability hierarchy $f \gg a > b > c$ holds across all models and difficulties: $f$ is recovered to machine precision, $a$ is consistently accurate, and $c$ is the limiting factor. \begin{table}[h] \centering -\caption{Coefficient error across models and difficulty levels (2 seeds each). +\caption{Historical reported coefficient error across three models and three +difficulty levels (2 seeds each; 18 attempts, 15 scored). ``---'' indicates the model failed to produce a scored run.}\label{tab:sweep} \small \begin{tabular}{llrrrrrrrr} @@ -745,15 +777,19 @@ \subsection{Limitations} mathematical inadequacy. Future versions could use structured tool calling to separate these concerns. -The current evaluation uses only two seeds per difficulty level. Hard +The manuscript's preliminary comparison uses only two seeds per difficulty +level and does not report the proposed cross-provider prompt ablation. Its +underlying run archive is not included, limiting independent verification +of the numerical tables and behavioral aggregates. Hard difficulty shows high variance (GPT-5.4 achieves 0.29 on one seed and 3.68 on the other), suggesting that some PDE instances are inherently easier to identify. A larger seed sweep would provide more robust estimates. GPT-5.2 and newer OpenAI models default to \texttt{reasoning\_effort: -none}, which disables chain-of-thought reasoning. All results reported -here use \texttt{reasoning\_effort: medium}, set explicitly via the API. +none}, which disables chain-of-thought reasoning. The draft reports +\texttt{reasoning\_effort: medium} for GPT-5.4 and GPT-5.4-mini; GPT-4o +has no reasoning-effort override in the runner. Runs without this override would likely perform significantly worse, particularly GPT-5.4-mini, and the results should not be compared to evaluations that use the default API setting. @@ -784,8 +820,10 @@ \section{Conclusion} This addresses a gap identified by Burnell et al.\ in the current landscape of cognitive evaluations for AI systems. -All code, run logs, and analysis tools are publicly available at -\texttt{[repository URL]}. +The code, analysis tools, and selected notebook outputs are available at +\url{https://github.com/Hydrodynamical/PDE_Learning}. The complete +source-run archive for the manuscript's tables and checked-in figures +remains to be published. \bibliographystyle{plainnat} @@ -848,4 +886,4 @@ \section{Conclusion} \end{thebibliography} -\end{document} \ No newline at end of file +\end{document} diff --git a/requirements-api.txt b/requirements-api.txt new file mode 100644 index 0000000..a89fafe --- /dev/null +++ b/requirements-api.txt @@ -0,0 +1,35 @@ +# Optional provider SDKs and their resolved dependencies (Python 3.12). +-r requirements.txt +annotated-types==0.8.0 +anthropic==1.17.0 +anyio==4.15.1 +certifi==2026.10.19 +cffi==2.1.1 +charset-normalizer==3.5.2 +cryptography==50.0.2 +distro==1.9.0 +docstring_parser==0.18.0 +google-auth==2.62.0 +google-genai==2.31.0 +h11==0.16.0 +httpcore2==2.15.1 +httpcore==1.0.9 +httpx2==2.15.1 +httpx==0.28.1 +idna==3.20 +jiter==0.17.0 +openai==3.35.1 +opentelemetry-api==1.45.1 +pyasn1==0.6.4 +pyasn1_modules==0.4.2 +pycparser==3.11 +pydantic==2.14.1 +pydantic_core==2.50.1 +requests==2.34.2 +sniffio==1.3.1 +tenacity==9.1.4 +truststore==0.10.5 +typing-inspection==0.4.4 +typing_extensions==4.16.0 +urllib3==2.8.0 +websockets==16.1.1 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e5b465c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,12 @@ +contourpy==1.4.0 +cycler==0.12.1 +fonttools==4.67.0 +kiwisolver==1.5.1 +matplotlib==3.11.2 +numpy==2.5.4 +packaging==26.3 +pillow==13.0.0 +pyparsing==3.3.3 +python-dateutil==2.9.0.post0 +scipy==1.18.1 +six==1.17.0 diff --git a/test_cli.py b/test_cli.py new file mode 100644 index 0000000..3912d9a --- /dev/null +++ b/test_cli.py @@ -0,0 +1,55 @@ +"""End-to-end checks of the documented offline command; never call a provider.""" + +import json +import math +import os +from pathlib import Path +import subprocess +import sys +import tempfile +import unittest + + +ROOT = Path(__file__).resolve().parent + + +class TestOfflineCLI(unittest.TestCase): + def test_mock_produces_a_scored_log_for_each_difficulty(self): + for difficulty, expected_queries in (("easy", 8), ("medium", 12), ("hard", 16), ("extreme", 32)): + with self.subTest(difficulty=difficulty), tempfile.TemporaryDirectory() as directory: + result = subprocess.run( + [sys.executable, str(ROOT / "main_loop.py"), "--mock", "--difficulty", difficulty, + "--seed", "42", "--no-plot", "--output-dir", directory], + cwd=ROOT, text=True, capture_output=True, timeout=60, + env={**os.environ, "MPLBACKEND": "Agg"}, + ) + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + logs = list(Path(directory).glob("*.json")) + self.assertEqual(len(logs), 1) + log = json.loads(logs[0].read_text()) + self.assertEqual(log["config"]["model"], "mock") + self.assertEqual(log["config"]["provider"], "mock") + self.assertEqual(log["config"]["seed"], 42) + self.assertIn("temperature", log["config"]) + self.assertIn("min_queries", log["config"]) + self.assertEqual(len(log["queries"]), expected_queries) + self.assertEqual(len(log["solves"]), 1) + self.assertFalse(log["behavioral_metrics"]["auto_submitted"]) + self.assertTrue(math.isfinite(log["results"]["coefficient_errors"]["total"])) + self.assertIn("predict", log["turns"][-1]["parsed_actions"]) + + def test_mock_rejects_limits_that_cannot_complete_the_protocol(self): + for limits in (("--max-queries", "7"), ("--max-turns", "10")): + with self.subTest(limits=limits), tempfile.TemporaryDirectory() as directory: + result = subprocess.run( + [sys.executable, str(ROOT / "main_loop.py"), "--mock", "--difficulty", "easy", + "--no-plot", "--output-dir", directory, *limits], + cwd=ROOT, text=True, capture_output=True, timeout=30, + ) + self.assertEqual(result.returncode, 2) + self.assertIn("--mock needs at least", result.stderr) + self.assertEqual(list(Path(directory).iterdir()), []) + + +if __name__ == "__main__": + unittest.main() diff --git a/test_parser.py b/test_parser.py index 7009634..1612861 100644 --- a/test_parser.py +++ b/test_parser.py @@ -1,139 +1,128 @@ -"""Tests for the LLM response parser.""" +"""Offline tests for the response protocol used by ``main_loop.py``. + +PREDICT submits the session's most recent COMPUTE: solve result. Coefficient +arrays and the legacy DECOMPOSE action belong to the archived protocol. +""" import unittest -from llm_loop import parse_llm_response, _parse_prediction +from main_loop import parse_probe_response -class TestParser(unittest.TestCase): +class TestProbeResponseParser(unittest.TestCase): def test_simple_query(self): - actions = parse_llm_response("QUERY: sin(pi*x)") - self.assertEqual(len(actions), 1) - self.assertEqual(actions[0]["action"], "query") - self.assertEqual(actions[0]["spec"], "sin(pi*x)") - - def test_query_with_quotes(self): - actions = parse_llm_response('QUERY: "x*(1-x)*sin(pi*x)"') - self.assertEqual(actions[0]["spec"], "x*(1-x)*sin(pi*x)") - - def test_query_with_backticks(self): - actions = parse_llm_response("QUERY: `sin(2*pi*x)`") - self.assertEqual(actions[0]["spec"], "sin(2*pi*x)") - - def test_query_case_insensitive(self): - actions = parse_llm_response("query: sin(pi*x)") - self.assertEqual(actions[0]["action"], "query") - - def test_multiple_queries(self): - text = "Let me try two.\n\nQUERY: sin(pi*x)\nQUERY: sin(2*pi*x)" - actions = parse_llm_response(text) - queries = [a for a in actions if a["action"] == "query"] - self.assertEqual(len(queries), 2) - self.assertEqual(queries[0]["spec"], "sin(pi*x)") - self.assertEqual(queries[1]["spec"], "sin(2*pi*x)") - - def test_reasoning_plus_query(self): - text = "I think sine modes will be informative.\n\nQUERY: sin(pi*x)" - actions = parse_llm_response(text) - reasoning = [a for a in actions if a["action"] == "reasoning"] - queries = [a for a in actions if a["action"] == "query"] - self.assertGreater(len(reasoning), 0) - self.assertEqual(len(queries), 1) - - def test_prediction(self): - text = ( - "PREDICT:\n" - "a_coeffs = [1.0, 0.5, -0.3]\n" - "b_coeffs = [0.0, 0.1, 0.2]\n" - "c_coeffs = [-0.5, 0.0, 0.3]\n" - "f_coeffs = [1.0, -0.5, 0.0]" + self.assertEqual( + parse_probe_response("QUERY: sin(pi*x)"), + [{"action": "query", "spec": "sin(pi*x)"}], + ) + + def test_quoted_queries(self): + for quote in ('"', "'", "`"): + with self.subTest(quote=quote): + actions = parse_probe_response(f"QUERY: {quote}x*(1-x){quote}") + self.assertEqual(actions, [{"action": "query", "spec": "x*(1-x)"}]) + + def test_commands_are_case_insensitive(self): + self.assertEqual( + parse_probe_response("query: sin(pi*x)\ncompute: solve\npredict:"), + [ + {"action": "query", "spec": "sin(pi*x)"}, + {"action": "compute", "command": "solve"}, + {"action": "predict"}, + ], + ) + + def test_query_sanitizes_latex_and_implicit_multiplication(self): + self.assertEqual( + parse_probe_response(r"QUERY: $\sin(2\pi x)$"), + [{"action": "query", "spec": "sin(2*pi*x)"}], + ) + + def test_multiple_queries_preserve_order(self): + self.assertEqual( + parse_probe_response("QUERY: sin(pi*x)\nQUERY: sin(2*pi*x)"), + [ + {"action": "query", "spec": "sin(pi*x)"}, + {"action": "query", "spec": "sin(2*pi*x)"}, + ], + ) + + def test_compute_commands_preserve_arguments(self): + commands = [ + "eval_solution 0.1 0.5 0.9", + "solve", + "check x*(1-x)", + "term_integrals sin(2*pi*x)", + ] + for command in commands: + with self.subTest(command=command): + self.assertEqual( + parse_probe_response(f"COMPUTE: {command}"), + [{"action": "compute", "command": command}], + ) + + def test_predict_does_not_require_coefficient_arrays(self): + self.assertEqual(parse_probe_response("PREDICT:"), [{"action": "predict"}]) + + def test_predict_preserves_confidence_report_as_reasoning(self): + confidence = "Confidence: a=90%, b=80%, c=70%, f=95%" + self.assertEqual( + parse_probe_response(f"PREDICT:\n{confidence}"), + [{"action": "predict"}, {"action": "reasoning", "text": confidence}], + ) + + def test_legacy_arrays_do_not_override_solved_coefficients(self): + actions = parse_probe_response("PREDICT:\na_coeffs = [99.0, 99.0]") + self.assertEqual( + actions, + [ + {"action": "predict"}, + {"action": "reasoning", "text": "a_coeffs = [99.0, 99.0]"}, + ], + ) + + def test_legacy_decompose_is_reasoning(self): + self.assertEqual( + parse_probe_response("DECOMPOSE: sin(pi*x)"), + [{"action": "reasoning", "text": "DECOMPOSE: sin(pi*x)"}], ) - actions = parse_llm_response(text) - preds = [a for a in actions if a["action"] == "predict"] - self.assertEqual(len(preds), 1) - self.assertEqual(preds[0]["a"], [1.0, 0.5, -0.3]) - self.assertEqual(preds[0]["f"], [1.0, -0.5, 0.0]) - - def test_prediction_short_form(self): - text = ( - "PREDICT:\n" - "a = [1.0, 0.5]\n" - "b = [0.0, 0.1]\n" - "c = [-0.5, 0.0]\n" - "f = [1.0, -0.5]" + + def test_mixed_actions_and_reasoning_preserve_order(self): + self.assertEqual( + parse_probe_response( + "First inspect the solution.\n\n" + "COMPUTE: eval_solution 0.25 0.75\n" + "QUERY: sin(pi*x)\n" + "I will examine the result next." + ), + [ + {"action": "reasoning", "text": "First inspect the solution."}, + {"action": "compute", "command": "eval_solution 0.25 0.75"}, + {"action": "query", "spec": "sin(pi*x)"}, + {"action": "reasoning", "text": "I will examine the result next."}, + ], ) - actions = parse_llm_response(text) - preds = [a for a in actions if a["action"] == "predict"] - self.assertEqual(len(preds), 1) - self.assertEqual(preds[0]["a"], [1.0, 0.5]) - - def test_reasoning_only(self): - text = "I need to think about this problem more carefully." - actions = parse_llm_response(text) - self.assertTrue(all(a["action"] == "reasoning" for a in actions)) - - def test_empty_string(self): - actions = parse_llm_response("") - self.assertEqual(len(actions), 0) - - def test_prediction_with_reasoning(self): - text = ( - "Based on my analysis, f is approximately constant and negative.\n" - "The diffusion coefficient is roughly 0.5.\n\n" - "PREDICT:\n" - "a_coeffs = [0.5, 0.0, 0.0]\n" - "b_coeffs = [0.0, 0.0, 0.0]\n" - "c_coeffs = [0.0, 0.0, 0.0]\n" - "f_coeffs = [-0.1, 0.0, 0.0]" + + def test_empty_and_whitespace_responses(self): + for text in ("", " \n\t\n "): + with self.subTest(text=text): + self.assertEqual(parse_probe_response(text), []) + + def test_empty_query_and_compute_are_not_dispatched(self): + self.assertEqual( + parse_probe_response("QUERY:\nCOMPUTE:"), + [ + {"action": "reasoning", "text": "QUERY:"}, + {"action": "reasoning", "text": "COMPUTE:"}, + ], ) - actions = parse_llm_response(text) - reasoning = [a for a in actions if a["action"] == "reasoning"] - preds = [a for a in actions if a["action"] == "predict"] - self.assertGreater(len(reasoning), 0) - self.assertEqual(len(preds), 1) - - def test_decompose(self): - actions = parse_llm_response("DECOMPOSE: sin(pi*x)") - self.assertEqual(len(actions), 1) - self.assertEqual(actions[0]["action"], "decompose") - self.assertEqual(actions[0]["spec"], "sin(pi*x)") - - def test_decompose_case_insensitive(self): - actions = parse_llm_response("decompose: x*(1-x)") - self.assertEqual(actions[0]["action"], "decompose") - - def test_compute(self): - actions = parse_llm_response("COMPUTE: basis_info") - self.assertEqual(len(actions), 1) - self.assertEqual(actions[0]["action"], "compute") - self.assertEqual(actions[0]["command"], "basis_info") - - def test_compute_with_args(self): - actions = parse_llm_response("COMPUTE: eval_basis 0.1 0.5 0.9") - self.assertEqual(actions[0]["action"], "compute") - self.assertEqual(actions[0]["command"], "eval_basis 0.1 0.5 0.9") - - def test_compute_solve(self): - actions = parse_llm_response("COMPUTE: solve") - self.assertEqual(len(actions), 1) - self.assertEqual(actions[0]["action"], "compute") - self.assertEqual(actions[0]["command"], "solve") - - def test_mixed_actions(self): - text = ( - "Let me get basis info and then decompose.\n\n" - "COMPUTE: basis_info\n" - "DECOMPOSE: sin(pi*x)\n" - "QUERY: sin(2*pi*x)" + + def test_commands_must_start_the_line(self): + text = "I considered QUERY: sin(pi*x), but have not selected a probe." + self.assertEqual( + parse_probe_response(text), [{"action": "reasoning", "text": text}] ) - actions = parse_llm_response(text) - computes = [a for a in actions if a["action"] == "compute"] - decomps = [a for a in actions if a["action"] == "decompose"] - queries = [a for a in actions if a["action"] == "query"] - self.assertEqual(len(computes), 1) - self.assertEqual(len(decomps), 1) - self.assertEqual(len(queries), 1) if __name__ == "__main__": - unittest.main(verbosity=2) \ No newline at end of file + unittest.main(verbosity=2) diff --git a/test_sweep.py b/test_sweep.py new file mode 100644 index 0000000..07813d0 --- /dev/null +++ b/test_sweep.py @@ -0,0 +1,172 @@ +"""Regression tests for sweep provenance and resumption; never call an API.""" + +import contextlib +import io +import json +from pathlib import Path +from types import SimpleNamespace +import tempfile +import unittest +from unittest.mock import patch + +import generate_transcripts as sweep + + +def successful_record(**overrides): + record = { + "model": "gpt-4o", "provider": "openai", "difficulty": "easy", "seed": 42, + "prompt_condition": "standard", "temperature": 0.0, "reasoning_effort": None, + "total_coeff_error": 1.0, "queries_used": 8, + } + record.update(overrides) + return record + + +class TestSweepResumption(unittest.TestCase): + def run_sweep(self, existing, *options, fail=False): + """Exercise the actual CLI's resume/merge logic with a fake single run.""" + with tempfile.TemporaryDirectory() as directory: + summary_path = Path(directory) / "sweep_results.json" + summary_path.write_text(json.dumps(existing)) + + def fake_run(**kwargs): + return successful_record( + model=kwargs["model"], provider=kwargs["provider"], + difficulty=kwargs["difficulty"], seed=kwargs["seed"], + prompt_condition="baseline" if kwargs["baseline"] else "standard", + temperature=kwargs["temperature"], + reasoning_effort=kwargs["reasoning_effort"], total_coeff_error=0.25, + ) + + argv = [ + "generate_transcripts.py", "--models", "gpt-4o", + "--difficulties", "easy", "--seeds", "42", "--no-plot", + "--output-dir", directory, *options, + ] + with patch("sys.argv", argv), patch.object( + sweep, "run_single", side_effect=RuntimeError("fake failure") if fail else fake_run + ) as runner, patch.object(sweep, "print_summary_table"), contextlib.redirect_stdout(io.StringIO()): + sweep.main() + + return json.loads(summary_path.read_text()), runner.call_args_list + + def test_retry_skips_exact_success_including_zero_error(self): + records, calls = self.run_sweep( + [successful_record(total_coeff_error=0.0)], "--retry-failed" + ) + self.assertEqual(calls, []) + self.assertEqual(records[0]["total_coeff_error"], 0.0) + + def test_retry_does_not_reuse_other_prompt_temperature_or_reasoning(self): + for options in (("--baseline",), ("--temperature", "0.5"), ("--reasoning-effort", "low")): + with self.subTest(options=options): + records, calls = self.run_sweep( + [successful_record()], "--retry-failed", *options + ) + self.assertEqual(len(calls), 1) + self.assertEqual(len(records), 2) + self.assertNotEqual(sweep.run_key(records[0]), sweep.run_key(records[1])) + + def test_legacy_summary_is_preserved_and_does_not_skip_current_run(self): + for missing in ("prompt_condition", "temperature", "reasoning_effort"): + with self.subTest(missing=missing): + legacy = successful_record() + del legacy[missing] + records, calls = self.run_sweep([legacy], "--retry-failed") + self.assertEqual(len(calls), 1) + self.assertEqual(len(records), 2) + self.assertIn(legacy, records) + + def test_retry_replaces_matching_failure(self): + failed = successful_record(total_coeff_error=None, error="previous failure") + records, calls = self.run_sweep([failed], "--retry-failed") + self.assertEqual(len(calls), 1) + self.assertEqual(len(records), 1) + self.assertEqual(records[0]["total_coeff_error"], 0.25) + self.assertNotIn("error", records[0]) + + def test_merge_replaces_only_matching_configuration(self): + old = [ + successful_record(), + successful_record(prompt_condition="baseline"), + successful_record(temperature=0.5), + successful_record(reasoning_effort="low"), + ] + records, calls = self.run_sweep(old) + self.assertEqual(len(calls), 1) + self.assertEqual(len(records), 4) + matching = [r for r in records if sweep.run_key(r) == sweep.run_key(old[0])] + self.assertEqual(matching[0]["total_coeff_error"], 0.25) + for unchanged in old[1:]: + self.assertIn(unchanged, records) + + def test_failed_run_keeps_configuration_metadata(self): + records, _ = self.run_sweep( + [], "--baseline", "--temperature", "0.5", "--reasoning-effort", "low", fail=True + ) + self.assertEqual(records[0]["prompt_condition"], "baseline") + self.assertEqual(records[0]["temperature"], 0.5) + self.assertEqual(records[0]["reasoning_effort"], "low") + self.assertEqual(records[0]["error"], "fake failure") + + def test_unregistered_gemini_model_uses_google_backend(self): + _, calls = self.run_sweep([], "--models", "gemini-example") + self.assertEqual(calls[0].kwargs["provider"], "google") + self.assertIsNone(calls[0].kwargs["reasoning_effort"]) + + +class TestSingleRunMetadata(unittest.TestCase): + def make_session(self): + coefficient = SimpleNamespace(coeffs=SimpleNamespace(tolist=lambda: [1.0])) + return SimpleNamespace(pde=SimpleNamespace( + a=coefficient, b=coefficient, c=coefficient, f=coefficient, + describe=lambda: "synthetic test PDE", + )) + + def test_json_and_summary_record_requested_configuration(self): + result = {"turns": 1, "queries_used": 0, "prediction_submitted": False} + with tempfile.TemporaryDirectory() as directory, patch.object( + sweep.ProbeSession, "from_difficulty", return_value=self.make_session() + ), patch.object(sweep, "make_backend"), patch.object( + sweep, "run_probe_session", return_value=result + ), patch.object(sweep, "compute_extended_metrics", return_value={}): + summary = sweep.run_single( + "example-model", "openai", "easy", 42, directory, + baseline=True, temperature=0.5, reasoning_effort="low", no_plot=True, + ) + log = json.loads(Path(summary["log_path"]).read_text()) + + for record in (summary, log["config"]): + self.assertEqual(record["prompt_condition"], "baseline") + self.assertEqual(record["temperature"], 0.5) + self.assertEqual(record["reasoning_effort"], "low") + + def test_runs_in_same_second_keep_both_raw_logs(self): + result = {"turns": 1, "queries_used": 0, "prediction_submitted": False} + with tempfile.TemporaryDirectory() as directory, patch.object( + sweep.ProbeSession, "from_difficulty", return_value=self.make_session() + ), patch.object(sweep, "make_backend"), patch.object( + sweep, "run_probe_session", return_value=result + ), patch.object(sweep, "compute_extended_metrics", return_value={}), patch.object( + sweep.time, "strftime", return_value="20261020_120000" + ): + standard = sweep.run_single( + "example-model", "openai", "easy", 42, directory, no_plot=True, + ) + baseline = sweep.run_single( + "example-model", "openai", "easy", 42, directory, baseline=True, + temperature=0.5, no_plot=True, + ) + self.assertNotEqual(standard["log_path"], baseline["log_path"]) + self.assertEqual(len(list(Path(directory).glob("run_*.json"))), 2) + standard_log = json.loads(Path(standard["log_path"]).read_text()) + baseline_log = json.loads(Path(baseline["log_path"]).read_text()) + + self.assertEqual(standard_log["config"]["prompt_condition"], "standard") + self.assertEqual(standard_log["config"]["temperature"], 0.0) + self.assertEqual(baseline_log["config"]["prompt_condition"], "baseline") + self.assertEqual(baseline_log["config"]["temperature"], 0.5) + + +if __name__ == "__main__": + unittest.main()