Suggestions and observations#
Closed beta (nothing installed): the examples on this page use the Python client, which the beta does not distribute; the same open-suggestion bookkeeping over plain HTTP is parallel_workers_rest.py in the hosted examples.
Open and closed suggestions#
A suggestion is a point the engine handed you and has not heard back about.
It opens when suggest returns it and closes in one of three ways: an
observation reports against its id, you dismiss it, or, on the hosted plane
only, the next ask finds it older than the experiment’s suggestion_ttl_s
(24 hours by default) and closes it with expired_at set. suggestions(exp_id, state="open") lists the ones still holding a slot; the list is also the
state check after a lost response, since a request that died with a 5xx may
have committed on the server.
A suggestion’s states. (1) suggest returns it open, holding one parallel_bandwidth slot. It closes (2) when an observation reports against its id, (3) when you dismiss it with close_suggestion or close_all_suggestions, or (4) on the hosted plane, when the next ask finds it older than suggestion_ttl_s and sets expired_at. The dashed line is the edge of the dedup universe. Above it are the observed and open points, which every new suggestion must differ from (with dedup on and no duplicate intents); a dismissed or expired point drops below it, unless another observed or open record still holds it, and may be suggested again (sobol still advances past every point it issued).#
Open suggestions are the unit of parallelism, and the strategies treat them
as evidence of work in flight: the single-objective Gaussian-process (GP)
rungs condition on each open point at a pessimistic placeholder value (the worst value observed
so far; under gp_ei each outcome-constraint component sits at its threshold), and the multi-objective rung integrates over their posterior.
Either way, parallel workers spread out instead of crowding one optimum.
Bandwidth slots#
parallel_bandwidth caps how many suggestions may be open at once; the
default is 1. At the cap, suggest answers 429 bandwidth_full on both
drivers. Observing or dismissing a suggestion frees its slot. The hosted
transport retries a 429 with bounded backoff; past that budget, the error
exposes retry_after so your own loop can wait.
from tauopt import ApiError, Client
client = Client(driver="local")
exp = client.create_experiment(
name="slots",
parameters=[{"name": "x", "type": "integer", "bounds": [0, 100]}],
metric={"name": "score", "objective": "maximize"},
parallel_bandwidth=2,
)
a = client.suggest(exp.id)
b = client.suggest(exp.id)
try:
client.suggest(exp.id)
except ApiError as e:
print(e.status_code, e.error_type)
client.close_suggestion(exp.id, b.id)
c = client.suggest(exp.id)
print(b.assignments, c.assignments, [s.state for s in client.suggestions(exp.id)])
client.observe(exp.id, assignments={"x": 7}, value=1.0)
client.observe(exp.id, suggestion_id=a.id, value=2.0)
print([o.suggestion_id for o in client.observations(exp.id)])
print([s.id for s in client.suggestions(exp.id, state="open")])
p = a.provenance
print(p.strategy, p.policy, p.fallback_from, p.seed, p.config_hash, p.dedup["collision_count"])
429 bandwidth_full
{'x': 10} {'x': 28} ['open', 'closed', 'open']
[None, 'local-1-s1']
['local-1-s3']
sobol default@v1 None 7585348709055410755 blake2b_3f9b420b29870c18 0
Dismissal#
close_suggestion closes a suggestion without an observation;
close_all_suggestions does it in bulk and returns the count. A dismissal
changes the engine’s view in three ways:
It increments the state’s dismissal counter.
The Sobol rung skips past every point ever issued – observed, open, and dismissed – so the point you declined is not handed straight back, as
bandcabove show.The point leaves the deduplication universe, which covers observed and open points only, so a later ask may legitimately suggest it again.
If you later observe a dismissed suggestion, the observation itself advances history and the dismissal stops counting.
The dismissal carries no information about the point’s quality. If you know
the evaluation failed, report failed=True instead: a failed observation is
excluded from modeling but stays a tried point for dedup.
Reporting results, on or off a suggestion#
observe takes exactly one of suggestion_id or assignments, and exactly
one of a result (value, or values in metrics mode) or failed=True.
Reporting by assignments lets you feed in points the engine never
suggested – a warm start from earlier work, or a grid you ran elsewhere. The
assignments must validate against the space exactly: the active parameter
set, typed values in range, every linear constraint satisfied. Off-suggestion
observations carry suggestion_id of None, as the listing above shows.
Validation runs against a candidate state and commits only on success, so a
400 never closes the suggestion or frees its slot. Observing the same
suggestion twice answers 409 conflict, because a double-counted point would
poison the model.
What rides on each suggestion#
Every suggestion carries its provenance receipt: the engine identity triple
(version, sha, dependency fingerprint), the executed strategy, the policy
that routed it (None when the config pins a strategy other than auto),
the config_hash, the resolved seed, fallback_from when a ladder descent
answered, GP timings where a fit ran, the dedup record with its collision
counts and status, the center, selection, and acq_init_filters audit
records when their mechanisms ran, and the optional GP internals. An intent field appears only on authorized
duplicate grants. The receipt and the recorded state are enough to re-derive
the point; see provenance and determinism.
Do it: Report failures and noise and Archive experiments.