Journey 04 — Compare arms
Use compare() to get a four-objective corpus lookup table without running solvers locally. Understand corpus_match and source='corpus' rows.
Prerequisites: Journey 03 — you know recommend() objectives. Scenario: A corpus-backed work-precision table (no local solve)
Key APIs
solvscout.compare(rhs, y0, t_span)Comparison.sectionsComparison.corpus_matchRunResult.source
Concepts to internalize
- No local solve — compare() classifies, then looks up benchmark medians. nfev/wall_s are corpus statistics, not this call's cost.
- Four sections — one per objective (precision, balanced, survival, efficiency), each with a recommended arm.
- corpus_match — 'exact' or 'class proxy'; tells you how literally the table applies.
- Printed table — compare() also renders a human-readable table to stdout.
Important code
The guided tour script wraps this pattern. Copy the production shape into your pipeline:
import solvscout as scout
# Robertson stiff chemistry
rhs = lambda t, y: [
-0.04*y[0] + 1e4*y[1]*y[2],
0.04*y[0] - 1e4*y[1]*y[2] - 3e7*y[1]**2,
3e7*y[1]**2,
]
comparison = scout.compare(rhs, [1, 0, 0], (0, 100))
print(comparison.recommended, comparison.corpus_match)
for section in comparison.sections:
print(section.objective, section.recommended)
for row in section.results:
print(row.arm, row.survived, row.nfev, row.source) # source='corpus'Act-by-act walkthrough
Act 1 — What compare() does
compare(rhs, y0, t_span) classifies the problem, then looks up all four SolvTune objectives (precision, balanced, survival, efficiency) from the benchmark corpus. It does NOT run solvers here - it prints the table and returns a Comparison. There is no objective= argument.
| Field | Value | Notes |
|---|---|---|
problem | stiffness S2, relaxation, dim 3 | |
sigma | clean | |
evidence | corpus match: exact | |
accuracy | 'scaled err' = deterministic error vs a 1e-12 reference. | |
envelope | 3 arm(s) do not survive here: RK45, DOP853, RK23. |
precision
| Field | Value | Notes |
|---|---|---|
recommended | SolvSRK (confidence: high) | |
why | SolvSRK - precision pick: 12.6 sig-digits, 100% survival, 106,041 fevals. +2.1 digits over Radau. | |
paste | cfg = solvsrk.config(mode='acmode', rtol=1e-12, atol=1e-12, ek_dt=0.0001, ek_max_steps=0, timeout_s=60) | |
strongest | SolvSRK (0.288s) | |
fastest | LSODA (0.005s) | |
most efficient | Radau (eff=0.31, within tol) |
balanced
| Field | Value | Notes |
|---|---|---|
recommended | SolvSRK (confidence: high) | |
why | SolvSRK - balanced pick: 12.6 sig-digits, 100% survival, 106,041 fevals. | |
paste | cfg = solvsrk.config(mode='acmode', rtol=1e-12, atol=1e-12, ek_dt=0.0001, ek_max_steps=0, timeout_s=60) | |
strongest | SolvSRK (0.288s) | |
fastest | LSODA (0.005s) | |
most efficient | Radau (eff=0.31, within tol) |
survival
| Field | Value | Notes |
|---|---|---|
recommended | SolvSRK (confidence: high) | |
why | SolvSRK - survival pick: 12.6 sig-digits, 100% survival, 106,041 fevals. | |
paste | cfg = solvsrk.config(mode='acmode', rtol=1e-12, atol=1e-12, ek_dt=0.0001, ek_max_steps=0, timeout_s=60) | |
strongest | SolvSRK (0.288s) | |
fastest | LSODA (0.005s) | |
most efficient | Radau (eff=0.31, within tol) |
efficiency
| Field | Value | Notes |
|---|---|---|
recommended | LSODA (confidence: high) | |
why | LSODA - efficiency pick: 7.4 sig-digits, 100% survival, 1,022 fevals. ~1x fewer fevals than BDF. | |
paste | cfg = solvsrk.config(mode='acmode', rtol=1e-12, atol=1e-12, ek_dt=0.0001, ek_max_steps=0, timeout_s=60) | |
strongest | SolvSRK (0.288s) | |
fastest | LSODA (0.005s) | |
most efficient | Radau (eff=0.31, within tol) | |
source | benchmark corpus | |
note | table lookup only — not a live run on your problem |
Act 2 — The returned object
Comparison.sections has one payload per objective; each has a recommended field arm and a copy-paste solvsrk.config(...) line. corpus_match is 'exact' or 'class proxy' — never a benchmark slug.
| Field | Value | Notes |
|---|---|---|
recommended | solvsrk | |
recommended_confidence | high | |
corpus_match | exact | |
n_sections | 4 | |
n_rows | 7 |
Act 3 — Per-arm rows
Each RunResult carries status, survived, error (tol units), nfev and wall_s. source='corpus' confirms these are looked-up medians, not a live run.
precision-ranked corpus rows (7 steps)
| Field | Value | Notes |
|---|---|---|
status | corpus | |
survived | True | |
error | 0.0555 | |
nfev | 106041 | |
wall_s | 0.2876 | |
source | corpus | |
status | corpus | |
survived | True | |
error | 0.0892 | |
nfev | 2503 | |
wall_s | 0.0495 | |
source | corpus | |
status | corpus | |
survived | True | |
error | 0.1766 | |
nfev | 1382 | |
wall_s | 0.0394 | |
source | corpus | |
status | corpus | |
survived | True | |
error | 0.1817 | |
nfev | 1022 | |
wall_s | 0.0051 | |
source | corpus | |
status | corpus | |
survived | False | |
error | - | |
nfev | - | |
wall_s | - | |
source | corpus | |
status | corpus | |
survived | False | |
error | - | |
nfev | - | |
wall_s | - | |
source | corpus | |
status | corpus | |
survived | False | |
error | - | |
nfev | - | |
wall_s | - | |
source | corpus | compare() is corpus lookup only. For live integration use solvsrk.run_profile or solvsrk.run. |
problem | robertson |
Guided tour output
Verified console capture from 04_compare_arms.py:
A corpus-backed work-precision table (no local solve)
-- Act 1 - What compare() does --
-> compare(rhs, y0, t_span) classifies the problem, then looks up all four SolvTune objectives (precision, balanced, survival, efficiency) from the benchmark corpus. It does NOT run solvers here - it prints the table and returns a Comparison. There is no objective= argument.
problem: stiffness S2, relaxation, dim 3
sigma: clean
evidence: corpus match: exact
accuracy: 'scaled err' = deterministic error vs a 1e-12 reference.
envelope: 3 arm(s) do not survive here: RK45, DOP853, RK23.
_section: precision
recommended: SolvSRK (confidence: high)
why: SolvSRK - precision pick: 12.6 sig-digits, 100% survival, 106,041 fevals. +2.1 digits over Radau.
paste: cfg = solvsrk.config(mode='acmode', rtol=1e-12, atol=1e-12, ek_dt=0.0001, ek_max_steps=0, timeout_s=60)
strongest: SolvSRK (0.288s)
fastest: LSODA (0.005s)
most efficient: Radau (eff=0.31, within tol)
_section: balanced
recommended: SolvSRK (confidence: high)
why: SolvSRK - balanced pick: 12.6 sig-digits, 100% survival, 106,041 fevals.
paste: cfg = solvsrk.config(mode='acmode', rtol=1e-12, atol=1e-12, ek_dt=0.0001, ek_max_steps=0, timeout_s=60)
strongest: SolvSRK (0.288s)
fastest: LSODA (0.005s)
most efficient: Radau (eff=0.31, within tol)
_section: survival
recommended: SolvSRK (confidence: high)
why: SolvSRK - survival pick: 12.6 sig-digits, 100% survival, 106,041 fevals.
paste: cfg = solvsrk.config(mode='acmode', rtol=1e-12, atol=1e-12, ek_dt=0.0001, ek_max_steps=0, timeout_s=60)
strongest: SolvSRK (0.288s)
fastest: LSODA (0.005s)
most efficient: Radau (eff=0.31, within tol)
_section: efficiency
recommended: LSODA (confidence: high)
why: LSODA - efficiency pick: 7.4 sig-digits, 100% survival, 1,022 fevals. ~1x fewer fevals than BDF.
paste: cfg = solvsrk.config(mode='acmode', rtol=1e-12, atol=1e-12, ek_dt=0.0001, ek_max_steps=0, timeout_s=60)
strongest: SolvSRK (0.288s)
fastest: LSODA (0.005s)
most efficient: Radau (eff=0.31, within tol)
source: benchmark corpus
note: table lookup only — not a live run on your problem
-- Act 2 - The returned object --
-> Comparison.sections has one payload per objective; each has a recommended field arm and a copy-paste solvsrk.config(...) line. corpus_match is 'exact' or 'class proxy' — never a benchmark slug.
recommended: solvsrk
recommended_confidence: high
corpus_match: exact
n_sections: 4
n_rows: 7
-- Act 3 - Per-arm rows --
-> Each RunResult carries status, survived, error (tol units), nfev and wall_s. source='corpus' confirms these are looked-up medians, not a live run.
_section: precision-ranked corpus rows (7 steps)
status: corpus
survived: True
error: 0.0555
nfev: 106041
wall_s: 0.2876
source: corpus
status: corpus
survived: True
error: 0.0892
nfev: 2503
wall_s: 0.0495
source: corpus
status: corpus
survived: True
error: 0.1766
nfev: 1382
wall_s: 0.0394
source: corpus
status: corpus
survived: True
error: 0.1817
nfev: 1022
wall_s: 0.0051
source: corpus
status: corpus
survived: False
error: -
nfev: -
wall_s: -
source: corpus
status: corpus
survived: False
error: -
nfev: -
wall_s: -
source: corpus
status: corpus
survived: False
error: -
nfev: -
wall_s: -
source: corpus
-> compare() is corpus lookup only. For live integration use solvsrk.run_profile or solvsrk.run.
problem: robertson
-- Run complete --
next_journey: 05_product_profile.py
recommended: solvsrkRun it
cd python
# Guided tour — narrated scenario walkthrough (recommended first run):
python examples/journeys/04_compare_arms.py
# Production one-liner — same API call you ship:
python -c "import solvscout as s; rhs=lambda t,y:(lambda x,z,w:[-z-w,x+0.2*z,0.2+w*(x-5.7)])(*y); c=s.compare(rhs,[1,1,1],(0,100)); print(c.recommended, c.corpus_match)"What comes next
Journey 05 mints a portable SolvSRK profile token with recommend_product().
Navigation
← Journey 03 — Recommend a solver · Journey 05 — Product profile token →