Skip to main content

CADAQUES

DOI PyPI

Cost-Aware Dual Architecture for QUery-Efficient diScovery

An open-source framework for autonomous discovery campaigns: any oracle, any driver, one budget.

CADAQUES decouples autonomous discovery into two symmetric protocols. A metered Oracle abstracts anything that answers queries at a price — a simulator, a laboratory instrument, an analytic function. A Driver abstracts anything that decides what to ask next — random search, Bayesian optimization, gradient methods, LLM agents. Between them sits the framework's one structural commitment: cost is a first-class primitive. Every oracle query and every driver decision is priced in heterogeneous currencies (wall time, CPU hours, euros, tokens) and charged against a single campaign budget. Campaigns end when the budget is exhausted, not when an iteration counter runs out, and all results are reported as performance per unit cost. Every query counts.

Installation

pip install cadaques          # core: NumPy only
pip install "cadaques[bo]"    # + the Gaussian-process driver (scikit-learn)

Or, for development, install the latest version from source:

git clone https://github.com/jorgebravoabad/cadaques.git
cd cadaques
pip install -e .

Quickstart: a discovery campaign with an exact answer

Locate the critical temperature of the 2D Ising model by maximizing the magnetic susceptibility under a fixed compute budget. Onsager's exact result, T_c = 2/ln(1+√2) ≈ 2.269, provides the ground truth against which any driver can be validated.

from cadaques import Budget, Campaign, Cost
from cadaques.drivers import AnnealedLocalDriver
from cadaques.oracles import Ising2DOracle, T_C_EXACT

oracle = Ising2DOracle(seed=0)
driver = AnnealedLocalDriver(
    space={"T": (1.5, 3.5)},
    fidelity={"L": 24, "sweeps": 400},
    seed=0,
)
campaign = Campaign(oracle, driver, Budget(total=Cost(seconds=30.0)))

outcome = campaign.run()
print(f"Best T = {outcome.best.query.params['T']:.3f}  (exact: {T_C_EXACT:.3f})")
print(f"Queries: {outcome.n_queries}, stop reason: {outcome.stop_reason}")
print(f"Spent: {outcome.budget.spent}")

The campaign is a durable object (since 0.2)

Since 0.2 a campaign is not a script you ran once — it is a declarative, inspectable, replayable object:

from cadaques import Budget, Campaign, Cost, Task, checkpoint, replay, resume
from cadaques.drivers import RandomDriver
from cadaques.oracles import Ising2DOracle

task = Task.from_bounds({"T": (1.5, 3.5)}, name="ising_tc")
campaign = Campaign(
    Ising2DOracle(), RandomDriver(space=task.space.bounds),
    Budget(total=Cost(seconds=30.0)),
    task=task,      # direction, bounds, constraints, success criterion
    seed=42,        # one campaign seed rules all randomness (ADR-0012)
)

spec = campaign.to_spec()            # the campaign as portable JSON
outcome = campaign.run()
outcome.events.to_jsonl("run.jsonl") # append-only event log: the source of truth

# audit later, with no re-execution — derived state equals the live state:
assert replay(spec, "run.jsonl") == outcome.state

# or kill it and continue exactly where it stopped:
checkpoint(campaign, "ckpt/")
revived = resume("ckpt/")

What this buys, concretely:

  • Event-sourced runtime. Every transition — start, proposal, rejection, result, failure, stop — is an immutable event (JSONL, schema-versioned). The accounting ledger is a derived view of the event log.
  • Failure is a result. An oracle exception becomes a FAILED Result that settles its declared cost and stays on the record; out-of-task proposals are recorded rejections, never crashes.
  • Replay and resume. Final state derives from (spec, events) alone; a checkpointed campaign continues query-for-query identically to an uninterrupted one (rng states included).
  • Specs refuse to lie. Participants holding callables are not spec-serializable and are refused loudly — a spec is a portable declaration, never a pickled blob.
  • Conformance suites. cadaques.testing ships the Oracle/Driver/ Resource contract checks; external adapters are encouraged to run them.

From a spreadsheet to the next experiments (0.3)

The first domain vertical. A chemist declares column roles once — composition descriptors, reaction conditions, an objective, a recorded cost per run — and the table compiles to kernel objects:

from cadaques.verticals import ReactionTable

table = ReactionTable.from_csv(
    "reactions.csv",
    objective="c2_yield",
    composition=("x_Mn", "x_Ce"),
    conditions=("T", "P"),
    cost_columns={"seconds": "run_s"},
)

# Recommendation mode: which experiments should the lab run next?
ranking = table.recommend_next(k=5, seed=42)     # requires: pip install "cadaques[bo]"
print(ranking.summary())
ranking.to_csv("next_experiments.csv")           # for the lab notebook

# Campaign mode: would Bayesian optimization have beaten random on this table?
from cadaques import Budget, Cost
from cadaques.drivers import BayesianDriver, RandomDriver
from cadaques.stats import paired_campaigns

result = paired_campaigns(
    lambda seed: table.campaign(BayesianDriver(space=table.oracle().bounds),
                                Budget(total=Cost(seconds=25000)), seed=seed),
    lambda seed: table.campaign(RandomDriver(space=table.oracle().bounds),
                                Budget(total=Cost(seconds=25000)), seed=seed),
    seeds=range(20), metric=lambda o: o.best.value, alternative="greater",
)
print(result.summary())   # paired bootstrap CI + Wilcoxon, quotable as-is

Behind this sit the 0.3 components: DatasetOracle (a measured table as a hidden oracle, with a declared miss policy — a dataset miss is a FAILED result that settles its declared cost — and deterministic economics that can replay recorded per-row costs); BayesianDriver (Matérn GP with Expected Improvement per predicted unit cost, learned from the driver's own settled history, exploration annealed with fraction_used); cadaques.stats (paired bootstrap and Wilcoxon on NumPy alone, exact null to n=25); and recommendation mode (recommend() → a ranked, seeded, bit-for-bit reproducible object whose provenance records the driver's declaration, a fingerprint of the history, and the measured thinking time — the price of intelligence, attached to the advice it produced). A frozen retrospective-benchmark protocol over four public datasets lives in studies/.

Design principles

  • Dual agnosticism. Oracles and Drivers are typing.Protocol classes with two methods each. Anything that speaks the protocol plugs in. Since 0.2 the dual architecture has an operational counterpart: Resource (submit/status/collect) with an OracleResource adapter.
  • Declared vs. settled cost. Oracles declare a price ex ante (oracle.price(query)); the actual cost is settled ex post inside each Result. Real oracles deviate from their estimates — the ledger records both, and the discrepancy is itself an observable.
  • Both sides are metered. Driver decisions cost wall time — and tokens, if the driver is an LLM agent. A campaign's economics include the price of intelligence, enabling the question: when does an expensive smart driver beat a cheap dumb one?
  • Failure is a result. A failed evaluation — an oracle exception, a dataset miss — settles its declared cost and stays on the record, exactly like a wasted experiment.
  • Budget-aware strategies. Drivers receive a read-only BudgetView and may adapt: the reference AnnealedLocalDriver explores while rich and exploits while poor; BayesianDriver anneals its exploration margin the same way.
  • The event log is the provenance. Every transition (declared, settled, timestamped, schema-versioned) exports to JSONL: a complete, replayable trace of the campaign, from which the accounting ledger is derived.

Status, stability and roadmap

Status: research software, pre-1.0. The claim of record is the latest tagged release — this README describes shipped capability only, and the roadmap below is a plan, not a feature list.

Stability policy (ADR-0010). Semantic versioning; nothing public breaks without a deprecation shim spanning at least two minor releases. The exact implementation accompanying v1 of the arXiv paper is permanently tagged (v0.1.0-paper), and its imports run against every release via compatibility shims (cadaques.core.protocols, cadaques.core.campaign, CampaignResult). Durable design decisions live in docs/adr/.

Kernel (shipped in 0.2). Task · Query/Result and the general Action/Observation envelopes · Driver · Oracle · Resource (with the OracleResource adapter) · Campaign · Budget · Event · Artifact · Outcome · CampaignSpec — the twelve objects of the campaign architecture, with event-sourced state, seed streams, replay, checkpoint/resume and public conformance suites (cadaques.testing).

Generality proof (shipped in 0.3). DatasetOracle for retrospective campaigns over measured tables; the cost-aware BayesianDriver (extra cadaques[bo]); the audited cadaques.stats module; recommendation mode (recommend(), RankedCandidates); the chemistry vertical (ReactionTable); and the frozen study protocol in studies/.

Roadmap (not yet shipped). Asynchronous executors and a Slurm-backed workflow resource behind the frozen Resource lifecycle (ADR-0007); a portfolio Driver allocating budget across strategies as a cost-aware bandit; native categorical and mixed search spaces; declarative constraint vocabulary for specs; plugin entry points for external drivers and oracles; an LLM-agent driver adapter with token metering. See ARCHITECTURE.md and docs/adr/ for boundaries and decision gates.

Citation

If you use CADAQUES in academic work, please cite it (see CITATION.cff). Concept DOI (always resolves to the latest version): 10.5281/zenodo.21293589. Version DOIs are listed per release in CHANGELOG.md. Paper: arXiv:2607.16127.

License

MIT.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cadaques-0.3.0.tar.gz (82.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cadaques-0.3.0-py3-none-any.whl (58.5 kB view details)

Uploaded Python 3

File details

Details for the file cadaques-0.3.0.tar.gz.

File metadata

  • Download URL: cadaques-0.3.0.tar.gz
  • Upload date:
  • Size: 82.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.8

File hashes

Hashes for cadaques-0.3.0.tar.gz
Algorithm Hash digest
SHA256 af79c8a272da169625d94983df8289af0001d091726adad87f90dba4126f3e8e
MD5 95f50192a9d77449e01b9ea3e81a06ba
BLAKE2b-256 b27d6a898a833b99ae1e0be2320c4c66d571dad33417e4a02ccdf8e9e9471a3c

See more details on using hashes here.

File details

Details for the file cadaques-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: cadaques-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 58.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.8

File hashes

Hashes for cadaques-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cc9daead5e9ffbe1a154afeb533089ea454adb954f77db3c260a4f33b02828f0
MD5 c36c430defa64a448b136e4e66e624df
BLAKE2b-256 da09d83cf95c843ada500c8670353b290bc47cf0c047a2740be5fc0301e6c8c2

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page