Design studies¶
Describe, sample, run, and measure design variations; see the guide.
Parameters¶
Span
dataclass
¶
Span(
name: str,
low: float,
high: float,
nominal: Optional[float] = None,
sigma: Optional[float] = None,
unit: Optional[str] = None,
integer: bool = False,
)
A numeric parameter on the closed interval [low, high].
nominal is the design value (default: the midpoint, rounded down for
an integer span); the corner sampler uses it and the random samplers
centre a sigma draw on it. sigma (float spans only) makes
monte_carlo and
latin_hypercube draw from a normal distribution
around nominal truncated to [low, high]; without it they draw
uniformly. unit is display metadata; when omitted it is inferred from
the name's suffix (width_um gives "um"). integer=True keeps
every value an int.
normalize
¶
value as this parameter stores it (float, or int for
an integer span), refused when it is outside [low, high].
from_unit
¶
Map u in [0, 1) to a value (the inverse CDF of this
parameter's sampling distribution): uniform on [low, high], a
normal around nominal truncated to [low, high] when sigma
is set, or uniform over the integers of an integer span.
Choices
dataclass
¶
Choices(
name: str,
values: Tuple[Value, ...],
nominal: Optional[Value] = None,
unit: Optional[str] = None,
)
A parameter that takes one of a finite list of values.
The values share one type family: all real numbers, all str or all
bool. nominal (default: the first value) is the design value the
corner sampler starts from. The random samplers pick every value with
equal probability. unit is display metadata, inferred from the name's
suffix when omitted.
normalize
¶
The stored value equal to value; refused when value is not
one of values. A number matches a number of equal value
(1 matches 1.0); a bool never matches a number.
from_unit
¶
Map u in [0, 1) to one of values, each with equal
probability.
from_dict
classmethod
¶
The Choices a to_dict description records.
Samples¶
Samples
dataclass
¶
Samples(
parameters: Tuple[Parameter, ...],
rows: Tuple[Tuple[Value, ...], ...],
method: str,
seed: Optional[int] = None,
options: Mapping[str, Any] = dict(),
)
A frozen set of sample points over parameters.
rows holds one tuple of values per sample, in parameter order, each
value normalized by its parameter. Iterating yields one {name: value}
dict per row, len() is the row count and samples[i] is row i
as a dict. method, seed and options record how the rows were
made. Rows may repeat. a + b concatenates two sample sets over the
same parameters.
options
class-attribute
instance-attribute
¶
sample_names
property
¶
One deterministic name per row, derived from its values (equal rows share a name).
to_dict
¶
JSON-safe description; from_dict reverses it.
rows=False leaves the rows out (a summary of how they were made).
from_dict
classmethod
¶
The Samples a to_dict description (with rows)
records; every row is checked against its parameters again.
grid
¶
grid(
parameters: Sequence[Parameter],
*,
num_points: Union[int, Mapping[str, int]] = 5,
) -> Samples
The full factorial grid. Each Span takes num_points
evenly spaced values from low to high inclusive (an int, or a
{name: int} mapping naming every span; at least 2 each; an integer
span keeps the distinct rounded values); each Choices takes all
its values. Rows are in row-major order: the last parameter varies
fastest.
points
¶
points(
parameters: Sequence[Parameter],
rows: Sequence[Mapping[str, Value]],
) -> Samples
An explicit list of sample points: rows is a sequence of
{name: value} mappings, each naming every parameter exactly once.
Values are checked against their parameter (inside a span, one of the
choices).
corners
¶
corners(
parameters: Sequence[Parameter], *, style: str = "all"
) -> Samples
Process corners. The first row is every parameter at its nominal.
style="all" then adds every combination of each parameter's extremes
(low and high of a span, every non-nominal value of a choice), in
row-major order; style="one_at_a_time" adds each parameter at each
extreme in turn with the others at nominal (span: low then high;
choice: each non-nominal value in order). A choice with a single value
stays at it in every row. Rows equal to the nominal row are not
repeated. options records {"style": style}.
monte_carlo
¶
monte_carlo(
parameters: Sequence[Parameter],
*,
num_samples: int,
seed: int,
) -> Samples
num_samples independent random draws, reproducible from seed.
Unit-cube points come from numpy.random.Generator(PCG64(seed))
.random((num_samples, num_parameters)); column j is mapped through
parameter j's from_unit.
latin_hypercube
¶
latin_hypercube(
parameters: Sequence[Parameter],
*,
num_samples: int,
seed: int,
) -> Samples
A Latin hypercube of num_samples points, reproducible from
seed: for every parameter, each of the num_samples equal-
probability strata of [0, 1) holds exactly one point before the
parameter's from_unit maps it. For each parameter in order the
generator draws a permutation of the strata, then the offsets inside
them; that order is part of the reproducibility contract.
Running¶
plan
¶
plan(
samples,
build,
*,
path=None,
retry_failed=False,
cloud=False,
device=None,
) -> StudyPlan
Preview the jobs a study would run without writing or executing.
samples supplies parameter rows and build(params) returns a
Simulation for each row. path optionally reads an existing study
directory for resume decisions. retry_failed includes failed jobs in
to_run. Build and runnability failures count as failed rows; if no row
is runnable, the first error is raised. The estimate is local, not a
cloud quote.
cloud and device apply the same per-row checks as run.
This toolkit makes no physics claim about the resulting samples.
run
¶
run(
samples,
build,
*,
path,
measure=None,
cloud=False,
retry_failed=False,
max_workers=1,
progress=None,
quiet=False,
solver_path=None,
device=None,
timeout=None,
solver=None,
max_usd=DEFAULT_MAX_USD,
max_usd_total=5.0,
wait_timeout_s=None,
)
Run or resume a study and return one results-table row per sample.
samples contains parameter rows; build(params) makes each row's
Simulation and optional measure(result) returns named finite scalars.
path stores samples, jobs, measurements and the latest table. Identical
solver inputs run once. Succeeded jobs and measurements are reused; failed
jobs and measurements are retried only with retry_failed=True. Submitted
or timed-out cloud jobs are collected on a call with cloud=True.
A local call leaves their submitted or timed-out status unchanged.
Without measure, succeeded rows have no stored measurement. A later
call with measure reads stored output without running the solver again.
cloud chooses cloud execution; otherwise solver_path selects the
local solver. solver selects the cloud build and is recorded with each
job and submission; resuming with a different cloud build is refused.
On a GPU, solver=None takes the build the directory recorded, so
collecting and adding jobs needs no local solver; a directory with none
recorded submits its first jobs with the commit of the locally installed
solver, as every cloud call does. device=None is the service's only
GPU.
max_workers, device, timeout (local) and
wait_timeout_s (cloud) control the runners. progress receives study
event dictionaries; quiet suppresses the one-line stderr job reports.
The cloud path quotes every new job before the first submission. Its
max_usd per-job ceiling defaults to $5, as for every cloud entry point;
max_usd_total defaults to $5 and counts all submitted jobs recorded in
this directory, including quotes from failed or locally retried jobs.
Submission history is append-only, including ambiguous submit outcomes
whose job id is unknown. Those failed jobs require retry_failed=True
to submit again; inspect ph.cloud.list_jobs() before retrying.
A definite service refusal leaves rows pending with its error. If all new
submissions are refused, the table is saved and a CloudError is raised.
Both ceilings must be finite and non-negative. If either quote ceiling is
exceeded during initial quoting, the new batch is refused before submission.
Stale quotes are refreshed before each submission and checked against the
remaining budget; a refresh refusal leaves that entry pending. A submitted
job is collected without another submission.
Cloud completion hooks record status before measurements run. An exclusive
directory lock prevents concurrent runs on the same path. This toolkit
makes no physics claim about the returned measurements.
StudyPlan
dataclass
¶
StudyPlan(
num_samples: int,
num_jobs: int,
num_build_failed: int,
reused: tuple[str, ...],
to_run: tuple[str, ...],
to_collect: tuple[str, ...],
skipped_failed: tuple[str, ...],
estimate_usd: float,
)
A read-only preview of a study run.
num_samples counts rows, num_jobs unique solver inputs and
num_build_failed rows whose builder failed or whose simulation was
not runnable. reused lists succeeded
jobs in the directory, to_run jobs that would run or submit,
to_collect already submitted cloud jobs awaiting collection and
skipped_failed failed jobs held unless retried. estimate_usd sums
local cost estimates for to_run and is not a service quote.
Results¶
save
¶
Write table (a build_table dataset) to file as
deterministic JSON and return the path. NaN is written as null; dtypes
and attrs are recorded so load gives an identical dataset. The
write is atomic (a sibling temporary file, then os.replace).
load
¶
Read a table written by save. A directory reads its
table.json (a study directory).
yield_fraction
¶
yield_fraction(
table: Dataset,
criteria: Mapping[
str, Tuple[Optional[float], Optional[float]]
],
*,
incomplete: str = "exclude",
) -> YieldEstimate
Count the rows of table whose measured values meet criteria,
{name: (low, high)} with inclusive bounds and None for an open
side. Rows whose status is not "succeeded" (or that lack a value
a criterion names) are incomplete: incomplete="exclude" leaves them
out of the denominator, "fail" counts them as failing.
The fraction is a count over the samples given; it is only as good as the sampling and the simulations behind it.
YieldEstimate
dataclass
¶
YieldEstimate(
fraction: float,
num_pass: int,
num_evaluated: int,
num_samples: int,
num_incomplete: int,
incomplete: str,
criteria: Mapping[
str, Tuple[Optional[float], Optional[float]]
],
interval_95: Tuple[float, float],
)
The share of samples meeting pass criteria, with the counts behind it.
fraction is num_pass / num_evaluated (NaN when nothing was
evaluated); num_samples is every row, num_incomplete the rows that
did not succeed, and incomplete says whether those were excluded or
counted as failing. interval_95 is the Wilson score interval at 95%
confidence.