Skip to content

Simple API

ropt.simple

The high-level convenience API for running optimizations.

This module builds on the low-level ropt primitives. Import its names directly, for example from ropt.simple import optimize, session. See Running Optimizations for a walkthrough.

Enumerations used in the configuration and results (for example ExitCode and VariableType) are not re-exported here; import them from ropt.enums.

Nothing about a run depends on where it is called from. Where its evaluations happen is decided by the pool it is given with pool=, and which handlers see its results by the handlers= it is given. A session hands out both; a run given no pool evaluates in-process. This holds wherever the run is started from, including a thread you spawn yourself.

Running optimizations

ropt.simple.optimize

optimize(
    config: dict[str, Any],
    x0: ArrayLike,
    function: EvaluationFunction,
    *,
    pool: WorkerPool | None = None,
    handlers: Sequence[EventHandler | SharedHandlers]
    | None = None,
    report: ReportCallback | None = None,
    constraint_tolerance: float = 1e-10,
    metadata: dict[str, Any] | None = None,
) -> OptimizationResult

Run a single optimization.

See Running Optimizations for a walkthrough.

A pool or group that is closed — because it was closed directly, or because its session ended — is refused here with a WorkflowError, as is one carried into a worker process, where it cannot work at all.

Without a pool the evaluations run in-process, on the calling thread. A run started from inside an evaluation needs a different pool: the pool it is already running on refuses the work.

handlers mixes two kinds. An EventHandler is local: it is claimed for the duration of this run, and may be reused by a later run to accumulate results, but not shared with a concurrent one, and never afterwards with a SharedHandlers group. A group is shared: this run feeds it alongside every other run that lists it.

Returning True from report stops the optimization early with USER_ABORT. Reporting stops there, so results after it in the same batch are not passed on.

Parameters:

Name Type Description Default
config dict[str, Any]

The optimization configuration.

required
x0 ArrayLike

The initial variable vector.

required
function EvaluationFunction

The per-realization evaluation function.

required
pool WorkerPool | None

The pool to evaluate on, from a session factory.

None
handlers Sequence[EventHandler | SharedHandlers] | None

Optional local handlers and shared groups.

None
report ReportCallback | None

Optional callback invoked per function evaluation.

None
constraint_tolerance float

The tolerance within which a constraint is satisfied.

1e-10
metadata dict[str, Any] | None

Optional dictionary attached to every emitted result.

None

Returns:

Type Description
OptimizationResult

An OptimizationResult describing the outcome.

ropt.simple.optimize_many

optimize_many(
    config: dict[str, Any] | Sequence[dict[str, Any]],
    x0: ArrayLike,
    function: EvaluationFunction
    | Sequence[EvaluationFunction],
    *,
    pool: WorkerPool | None = None,
    handlers: Sequence[SharedHandlers] | None = None,
    report: ReportCallback
    | Sequence[ReportCallback]
    | None = None,
    limit: int | None = None,
    constraint_tolerance: float = 1e-10,
    metadata: dict[str, Any]
    | Sequence[dict[str, Any]]
    | None = None,
) -> tuple[OptimizationResult, ...]

Run several optimizations concurrently, sharing one pool.

Each of config, x0, and function may be a single value (used for every run) or a sequence (one per run). Sequences set the number of runs and must agree in length; single values are broadcast. A single x0 is a 1-D vector; a per-run sequence of x0s is a 2-D matrix with one vector per row. A sequence that is empty gives no runs, and returns no results.

The runs execute concurrently on driver threads and all evaluate on the same pool, so its workers are shared between them; limit bounds how many run simultaneously. Without a pool the runs still overlap, but each evaluation runs in-process on its own driver thread, so function is then called by several threads at once and must tolerate that. See Parallel Execution and Many Runs for a walkthrough, and Failure in one run for what happens when one raises.

Unlike optimize, this takes no local handlers: a local handler belongs to one run at a time and these runs overlap, so handlers= accepts only SharedHandlers groups, which every run feeds together. report=, being local by nature, is the opposite: it is given per run, or broadcast to all of them.

A pool or group that is closed — because it was closed directly, or because its session ended — is refused here with a WorkflowError, as is one carried into a worker process, where it cannot work at all.

A run started from inside an evaluation needs a different pool: the pool it is already running on refuses the work. Returning True from a report callback stops that run early with USER_ABORT. metadata also reaches each run's function as context.metadata, which makes it a way to tag a run, for example with {"run_id": i}.

Parameters:

Name Type Description Default
config dict[str, Any] | Sequence[dict[str, Any]]

The configuration, or one per run.

required
x0 ArrayLike

The initial variable vector, or one per row.

required
function EvaluationFunction | Sequence[EvaluationFunction]

The evaluation function, or one per run.

required
pool WorkerPool | None

The pool every run evaluates on.

None
handlers Sequence[SharedHandlers] | None

Optional shared groups, fed by every run.

None
report ReportCallback | Sequence[ReportCallback] | None

Optional callback per evaluation, shared or one per run.

None
limit int | None

The maximum number of runs to execute at once.

None
constraint_tolerance float

The tolerance within which a constraint is satisfied.

1e-10
metadata dict[str, Any] | Sequence[dict[str, Any]] | None

Optional dictionary attached to every emitted result.

None

Returns:

Type Description
tuple[OptimizationResult, ...]

One OptimizationResult per run, in order.

Raises:

Type Description
WorkflowError

If handlers holds a handler that is not in a group.

Evaluating without optimizing

ropt.simple.evaluate

evaluate(
    config: dict[str, Any],
    variables: ArrayLike,
    function: EvaluationFunction,
    *,
    pool: WorkerPool | None = None,
    handlers: Sequence[EventHandler | SharedHandlers]
    | None = None,
    report: ReportCallback | None = None,
    metadata: dict[str, Any] | None = None,
) -> FunctionResults

Evaluate a single variable vector without optimizing.

Use evaluate_many to evaluate several vectors at once. See Running Optimizations for a walkthrough.

A pool or group that is closed — because it was closed directly, or because its session ended — is refused here with a WorkflowError, as is one carried into a worker process, where it cannot work at all.

Without a pool the evaluations run in-process, on the calling thread. A run started from inside an evaluation needs a different pool: the pool it is already running on refuses the work. handlers mixes local EventHandler objects with shared SharedHandlers groups, as optimize takes them.

An evaluation is a single batch that has already run by the time report sees it, and there is no optimizer loop to interrupt, so unlike on optimize returning True cannot stop anything: it only ends the reporting, and every result is still returned. metadata also reaches function as context.metadata.

Parameters:

Name Type Description Default
config dict[str, Any]

The optimization configuration.

required
variables ArrayLike

The variable vector to evaluate.

required
function EvaluationFunction

The per-realization evaluation function.

required
pool WorkerPool | None

The pool to evaluate on, from a session factory.

None
handlers Sequence[EventHandler | SharedHandlers] | None

Optional local handlers and shared groups.

None
report ReportCallback | None

Optional callback invoked with each evaluation's results.

None
metadata dict[str, Any] | None

Optional dictionary attached to the emitted results.

None

Returns:

Type Description
FunctionResults

The FunctionResults for the vector.

Raises:

Type Description
ValueError

If variables is not a single vector.

ropt.simple.evaluate_many

evaluate_many(
    config: dict[str, Any],
    variables: ArrayLike,
    function: EvaluationFunction,
    *,
    pool: WorkerPool | None = None,
    handlers: Sequence[EventHandler | SharedHandlers]
    | None = None,
    report: ReportCallback | None = None,
    metadata: dict[str, Any] | None = None,
) -> tuple[FunctionResults, ...]

Evaluate a batch of variable vectors without optimizing.

Each row of variables is one variable vector; the results are returned in the same order. See Running Optimizations for a walkthrough.

A pool or group that is closed — because it was closed directly, or because its session ended — is refused here with a WorkflowError, as is one carried into a worker process, where it cannot work at all.

Without a pool the evaluations run in-process, on the calling thread. A run started from inside an evaluation needs a different pool: the pool it is already running on refuses the work. handlers mixes local EventHandler objects with shared SharedHandlers groups, as optimize takes them.

An evaluation is a single batch that has already run by the time report sees it, and there is no optimizer loop to interrupt, so unlike on optimize returning True cannot stop anything: it only ends the reporting, and every result is still returned. metadata also reaches function as context.metadata.

Parameters:

Name Type Description Default
config dict[str, Any]

The optimization configuration.

required
variables ArrayLike

The variable vectors to evaluate, one per row.

required
function EvaluationFunction

The per-realization evaluation function.

required
pool WorkerPool | None

The pool to evaluate on, from a session factory.

None
handlers Sequence[EventHandler | SharedHandlers] | None

Optional local handlers and shared groups.

None
report ReportCallback | None

Optional callback invoked with each evaluation's results.

None
metadata dict[str, Any] | None

Optional dictionary attached to every emitted result.

None

Returns:

Type Description
tuple[FunctionResults, ...]

One FunctionResults per input vector.

Raises:

Type Description
ValueError

If variables is not a 2-D matrix.

Evaluation functions

ropt.simple.EvaluationFunctionContext dataclass

Context for a single function evaluation.

Attributes:

Name Type Description
realization int

The realization index.

perturbation int

The perturbation index (-1 when unperturbed).

batch_id int

Integer identifying the current evaluation batch.

eval_idx int

Row index within the batch.

metadata dict[str, Any] | None

The metadata the run was started with, if any.

ropt.simple.EvaluationFunctionResult dataclass

Result of a single function evaluation.

Attributes:

Name Type Description
objectives NDArray[float64] | float

The objective values as an array.

constraints NDArray[float64] | float | None

Optional constraint values as an array.

metadata dict[str, Any] | None

Optional dictionary with extra information.

Sessions and pools

ropt.simple.session

session() -> Session

Open a background session that pools and shared handlers run on.

The session owns one event loop, on a daemon thread, for as long as the block is open. Build pools on it with its factories, and pass them to the runs that should use them. Closing the session releases every pool it created, so most code needs no further cleanup. See Running Optimizations for a walkthrough.

Returns:

Type Description
Session

A context manager binding the Session.

ropt.simple.Session

An open session, and the factories that build on it.

A session owns one background event loop, on its own daemon thread. Pools need that loop to run on, which is why they are built here rather than constructed on their own. Everything a session creates is returned to the caller and passed on explicitly; nothing is discovered from the surroundings.

Bind the session with as and call its factories inside the block. See Running Optimizations.

A session may be opened inside another: each gets its own loop, and pools from different sessions never interact. A session is single use — once closed it cannot be reopened.

__init__

__init__() -> None

Initialize the session.

__enter__

__enter__() -> Self

Open the session's event loop.

Returns:

Type Description
Self

The session itself.

Raises:

Type Description
WorkflowError

If the session was already opened.

__exit__

__exit__(*_exc: object) -> None

Close the session, releasing every pool it created.

thread_pool

thread_pool(
    *, workers: int = 1, bundle_size: int = 1
) -> WorkerPool

Create a pool that runs evaluations in worker threads.

See Running Optimizations for a walkthrough.

bundle_size matters more on a process_pool, where a task is transferred between processes.

Parameters:

Name Type Description Default
workers int

The number of worker threads.

1
bundle_size int

Evaluations per task, 0 for the whole batch.

1

Returns:

Type Description
WorkerPool

A pool backed by a thread pool.

process_pool

process_pool(
    *, workers: int = 1, bundle_size: int = 1
) -> WorkerPool

Create a pool that runs evaluations in worker processes.

The evaluation function must be picklable. See Running Optimizations for a walkthrough.

Closing the pool terminates its worker processes and nothing else. A program an evaluation started itself keeps running, without an error being raised; use local_pool where an evaluation launches external programs.

Every task is transferred to a worker separately, and the evaluations within one run after another, so bundle_size is a trade between spreading a batch and the cost of moving it. The default of 1 gives every evaluation its own task, spreading a batch as widely as the workers allow; a larger value groups that many per task; and 0 sends the whole batch as a single task, which suits a pool whose parallelism comes from the runs above it rather than from within a batch.

Parameters:

Name Type Description Default
workers int

The number of worker processes.

1
bundle_size int

Evaluations per task, 0 for the whole batch.

1

Returns:

Type Description
WorkerPool

A pool backed by a process pool.

local_pool

local_pool(
    *,
    workers: int = 1,
    workdir: Path | str | None = None,
    retries: int = 0,
    bundle_size: int = 1,
) -> WorkerPool

Create a pool that runs each evaluation as a separate local process.

Between a process pool and a cluster: every evaluation gets an interpreter of its own, which can be stopped outright and whose output is captured to a file, but there is no queueing system and nothing to install. This is the local stand-in for hpc_pool: the same job shape, so an evaluation function that works here works there.

Each job is a fresh command rather than a re-import of your script, so the evaluation function must live in a module the job can import, or the ropt[cloudpickle] extra must be installed.

POSIX only. See Running Optimizations for a walkthrough.

The default workdir is a temporary directory that is removed when the pool closes, unless an evaluation failed, in which case it is kept, with that evaluation's output in it, and its path logged. The retries default of 0 is enough here: a local job writes its result before it exits.

Parameters:

Name Type Description Default
workers int

The maximum number of concurrent local jobs.

1
workdir Path | str | None

The directory holding each evaluation's files.

None
retries int

Extra polls to wait for a result.

0
bundle_size int

Evaluations per task, 0 for the whole batch.

1

Returns:

Type Description
WorkerPool

A pool backed by local processes.

hpc_pool

hpc_pool(
    *,
    workers: int = 1,
    cores: int = 1,
    cluster: str | None = None,
    queue: str | None = None,
    workdir: Path | str | None = None,
    config_path: Path | str | None = None,
    template: str | None = None,
    scheduler: str | None = None,
    memory_max: int | str | None = None,
    run_time_max: int | None = None,
    submit_options: dict[str, Any] | None = None,
    retries: int = 30,
    bundle_size: int = 1,
) -> WorkerPool

Create a pool that runs evaluations on an HPC cluster.

Interfaces with a cluster queue (for example Slurm) through pysqa; requires the ropt[hpc] extra. Each evaluation is a job started as its own command, so the evaluation function must live in a module the compute nodes can import, or the ropt[cloudpickle] extra must be installed. Develop against local_pool first: it has the same shape and the same rule, without a cluster. The cluster is selected from cluster/queue: give a queue to search for its cluster, a cluster to use its default queue, or both to be explicit.

A template is the alternative to all of that: it submits without a configuration, so it cannot be combined with config_path, cluster or queue. See Running on an HPC cluster for the configuration layout and Slurm examples.

Parameters:

Name Type Description Default
workers int

The maximum number of concurrent cluster jobs.

1
cores int

The number of CPUs per job.

1
cluster str | None

The cluster name.

None
queue str | None

The queue name.

None
workdir Path | str | None

The shared-filesystem working directory.

None
config_path Path | str | None

The pysqa configuration directory.

None
template str | None

A submission-script template.

None
scheduler str | None

The queueing system a template is written for.

None
memory_max int | str | None

The memory per job.

None
run_time_max int | None

The run time per job.

None
submit_options dict[str, Any] | None

Extra variables for the submission script.

None
retries int

Number of retries for polling the cluster for results.

30
bundle_size int

Evaluations per task, 0 for the whole batch.

1

Returns:

Type Description
WorkerPool

A pool backed by an HPC cluster.

serial_pool

serial_pool() -> WorkerPool

Create a pool that evaluates in-process, on the calling thread.

Identical to the free serial_pool function, except that this pool is closed when the session closes, so runs cannot keep using it afterwards. The free function returns a pool that is tied to no session.

Returns:

Type Description
WorkerPool

A pool without an executor.

shared_handlers

shared_handlers(
    *handler: EventHandler,
    threaded: EventHandler | Sequence[EventHandler] = (),
    report: ReportCallback | None = None,
) -> SharedHandlers

Group result handlers that several runs share.

Pass the group to every run that should feed it, in handlers=. Each handler then sees the results of all those runs, serialized across them, which is what makes accumulating over concurrent runs safe. A run may feed several groups, and mix them with handlers of its own.

A handler joins one group at a time, and a handler that was ever passed to a run as a local handler cannot join a group at all; decide per handler whether it is local or shared. See Running Optimizations for a walkthrough.

Handlers run on the session's event-loop thread unless listed in threaded. Running one on a worker thread only helps if it spends real time in blocking, GIL-releasing I/O (files, databases, network); for in-memory work it gives no benefit under CPython's GIL. See Result Handlers.

Returning True from report stops the emitting run early with USER_ABORT if it is an optimization; an evaluation has no optimizer loop to interrupt, so there the return value is ignored.

Parameters:

Name Type Description Default
handler EventHandler

The result handlers to share.

()
threaded EventHandler | Sequence[EventHandler]

Handlers to run on a worker thread instead of the loop.

()
report ReportCallback | None

Optional callback invoked per evaluation across the group.

None

Returns:

Type Description
SharedHandlers

A SharedHandlers group.

ropt.simple.WorkerPool

The workers that run evaluations, and the batch IDs they share.

Created by a session factory such as thread_pool. Every run using the same pool draws its batch IDs from the same counter, so concurrent runs never produce the same batch ID.

A pool lives until its session closes, which releases it. Release it earlier with close, or by using it as a context manager. See Running Optimizations for a walkthrough.

A pool built by serial_pool has no executor and no workers to release; it exists to give runs one batch-ID sequence, whether or not they run in parallel.

__init__

__init__(
    executor: Executor | None = None,
    session: _Session | None = None,
    bundle_size: int = 1,
) -> None

Initialize the pool.

Parameters:

Name Type Description Default
executor Executor | None

The started executor, or None to evaluate in-process.

None
session _Session | None

The session that owns the pool, if it has one.

None
bundle_size int

Evaluations per worker task, 0 for the whole batch.

1

Raises:

Type Description
ValueError

If bundle_size is negative.

closed property

closed: bool

Whether the pool has been released.

Returns:

Type Description
bool

True once the pool, or the session that built it, was closed.

executor property

executor: Executor | None

The executor that runs this pool's evaluations.

Returns:

Type Description
Executor | None

The executor, or None for a serial pool.

batch_ids property

batch_ids: BatchIdCounter

The counter every run on this pool draws its batch IDs from.

Returns:

Type Description
BatchIdCounter

The batch ID counter.

bundle_size property

bundle_size: int

How many evaluations are sent to a worker as one task.

Returns:

Type Description
int

The number of evaluations per task, 0 meaning the whole batch.

close

close() -> None

Release the pool's workers without waiting for the session to close.

See Releasing a pool early for when this matters and the resulting lifecycle.

__enter__

__enter__() -> Self

Enter a block that closes the pool on exit.

Returns:

Type Description
Self

The pool itself.

__exit__

__exit__(*_exc: object) -> None

Close the pool.

ropt.simple.serial_pool

serial_pool() -> WorkerPool

Create a pool that evaluates in-process, on the calling thread.

A serial pool has no workers: it carries only the batch-ID counter that the runs sharing it draw from. Use it to give concurrent runs one batch-ID sequence without running their evaluations in parallel, or as an explicit way to say that a run should evaluate in-process.

It needs no session, and needs no releasing.

Returns:

Type Description
WorkerPool

A pool without an executor.

Offloading work to a pool

ropt.simple.offload

offload(
    work: Callable[[], _T], *, pool: WorkerPool | None = ...
) -> _T
offload(
    work: Sequence[Callable[[], _T]],
    *,
    pool: WorkerPool | None = ...,
) -> tuple[_T, ...]
offload(
    work: Callable[[], _T] | Sequence[Callable[[], _T]],
    *,
    pool: WorkerPool | None = None,
) -> _T | tuple[_T, ...]

Offload one or more callables to a pool.

Pass a single zero-argument callable to run one call and return its result, or a sequence of callables to run them concurrently (they may be entirely different functions) and return a tuple of results in the order of work. Bind arguments with functools.partial.

Without a pool, or with a serial_pool, the callables run inline on the calling thread, one after another. Code that may or may not have a pool to hand therefore needs no fallback: pass whatever it has, including None. The callables must be picklable for a process or HPC pool.

See Running Optimizations for a walkthrough.

A handler in a shared group runs on the session's own event loop and cannot wait on it; offloading from there raises a WorkflowError. So does a pool that is closed, or one carried into a worker process. A call that the machinery could not run, for instance because its worker process was killed, raises an ExecutionError. Work offloaded from inside an evaluation needs a different pool: the pool it is already running on refuses it.

Parameters:

Name Type Description Default
work Callable[[], _T] | Sequence[Callable[[], _T]]

A single zero-argument callable, or a sequence of them.

required
pool WorkerPool | None

The pool to dispatch to, or None to run inline.

None

Returns:

Type Description
_T | tuple[_T, ...]

The single result, or a tuple of results in the order of work.

Handlers

ropt.simple.EventHandler

Bases: ABC

Abstract base class for event handlers.

A concrete handler reacts to the events emitted by a ComputeStep it is attached to, by implementing handle_event. Handlers may store state using dictionary-like access ([]).

Note

A handler's handle_event is not re-entrant, and not safe to call from two threads at once: both raise WorkflowError. Register a handler shared across concurrently running steps with an EventDispatcher instead, which serializes the calls. See Optimization Workflows and Event dispatcher for usage and pitfalls.

__init__

__init__() -> None

Initialize the EventHandler.

claim

claim() -> None

Claim this handler for exclusive use by one run at a time.

Claiming marks the handler as dedicated to a single consumer, such as one optimization run, until it is released with release. While a claim is held, a second claim raises, so a handler can never be shared by two runs at once; releasing it at the end of a run lets the same handler be reused by a later, sequential run, for example to accumulate results. Handlers meant to aggregate across concurrent runs are not claimed; they are shared explicitly through an EventDispatcher.

This claim is independent of the attachment to a dispatcher or a compute step, and of the transient concurrency guard on handle_event.

Raises:

Type Description
WorkflowError

If the handler is currently claimed.

release

release() -> None

Release a claim taken with claim so the handler can be reused.

Clears the exclusive-use flag, letting a later run claim the handler again, for example to accumulate results across sequential runs. The attachment to a dispatcher or a compute step is left untouched. Releasing an unclaimed handler is a no-op.

event_types abstractmethod property

event_types: set[EnOptEventType]

The event types that are handled.

Returns:

Type Description
set[EnOptEventType]

A set of event types that are handled.

handle_event

handle_event(event: EnOptEvent) -> None

React to an emitted event.

Parameters:

Name Type Description Default
event EnOptEvent

The event object.

required

Raises:

Type Description
WorkflowError

If this handler is already running on another thread.

__getitem__

__getitem__(key: str) -> Any

Retrieve a stored value by key (handler[key]).

Parameters:

Name Type Description Default
key str

The string key identifying the value to retrieve.

required

Returns:

Type Description
Any

The value associated with the specified key.

Raises:

Type Description
AttributeError

If key does not exist in the stored values.

__setitem__

__setitem__(key: str, value: Any) -> None

Store or update a value in the internal state (handler[key] = value).

Parameters:

Name Type Description Default
key str

The string key identifying the value to store (must be an identifier).

required
value Any

The value to associate with the key.

required

Raises:

Type Description
AttributeError

If key is not a valid identifier.

ropt.simple.ResultsHandler

Bases: EventHandler

Track a single optimization result based on selection criteria.

Listens for FINISHED_EVALUATION events and retains either the best (lowest weighted objective) or most recent valid result. Optionally filters by constraint tolerance. The selected result is accessible via the result property or handler["results"].

See Result Handlers for full details on selection criteria and scaling.

__init__

__init__(
    *,
    what: Literal["best", "last"] = "best",
    constraint_tolerance: float | None = None,
    filter: Callable[[Results], bool] | None = None,
) -> None

Initialize the ResultsHandler.

Constraint violations are compared in the domain the optimizer works in, so a scale applies to them as well.

Parameters:

Name Type Description Default
what Literal['best', 'last']

Criterion for selecting results ('best' or 'last').

'best'
constraint_tolerance float | None

Optional threshold for constraint violations.

None
filter Callable[[Results], bool] | None

Optional callable to filter results based on custom logic.

None

result property

result: FunctionResults | None

The selected (best or last) result, or None if none is available.

event_types property

event_types: set[EnOptEventType]

The event types that are handled.

Returns:

Type Description
set[EnOptEventType]

A set of event types that are handled.

ropt.simple.HistoryHandler

Bases: EventHandler

Collect all optimization results into a tuple.

Listens for FINISHED_EVALUATION events and appends every Results object to a growing tuple accessible via the results property or handler["results"].

See Result Handlers for full details on scaling and accumulation behavior.

__init__

__init__() -> None

Initialize the HistoryHandler.

results property

results: tuple[Results, ...]

All results collected so far, in the order received.

event_types property

event_types: set[EnOptEventType]

The event types that are handled.

Returns:

Type Description
set[EnOptEventType]

A set of event types that are handled.

ropt.simple.DataFrameHandler

Bases: EventHandler

Build pandas or polars DataFrames from optimization results.

Collects FunctionResults and GradientResults into named tables. Tables are defined via add_table with a column specification, or registered in bulk with set_default_tables.

The frame library is chosen with the engine argument. The "polars" engine, the default, produces long-format tables in which batch and axis labels are ordinary leading columns; the "pandas" engine produces tables indexed by those instead.

Access tables via dictionary syntax: handler["functions"].

Warning

Tables are generated on the fly from internal data when accessing them in this way. When multiple accesses are needed, it is more efficient to first store them in a variable.

See Result Handlers for the column specification, default tables, and callback details.

__init__

__init__(
    *, engine: DataFrameEngine = "polars", sep: str = ","
) -> None

Initialize a default table event handler.

Parameters:

Name Type Description Default
engine DataFrameEngine

Frame library used to build the tables.

'polars'
sep str

Separator used in column names.

','

Raises:

Type Description
ValueError

If engine is not "pandas" or "polars".

UnsupportedError

If the selected frame library is not installed.

engine property

engine: DataFrameEngine

The frame library used to build the tables.

Returns:

Type Description
DataFrameEngine

Either "pandas" or "polars".

set_default_tables

set_default_tables() -> None

Register a standard set of result tables.

Adds the default functions, evaluations, and constraints tables for function results, and the default gradients and perturbations tables for gradient results.

set_callback

set_callback(
    callback: Callable[[Path | None], None],
) -> None

Set a function to call whenever the tables are updated.

The callback receives the output directory configured for the run (OptimizerConfig.output_dir, None if it is not set), and reads the tables from this handler. If it performs blocking operations (for example writing tables to disk), register this handler with run_in_thread=True on the EventDispatcher. See Optimization Workflows.

Parameters:

Name Type Description Default
callback Callable[[Path | None], None]

A function that is called when the tables are updated.

required

add_table

add_table(
    name: str,
    table_type: Literal["functions", "gradients"],
    columns: dict[str, str],
) -> None

Register a new table to be populated from incoming results.

Column keys are result-field attribute names, in dotted attribute syntax.

Parameters:

Name Type Description Default
name str

Key under which the table is stored and looked up.

required
table_type Literal['functions', 'gradients']

Fill from "functions" or from "gradients".

required
columns dict[str, str]

Mapping from field paths to display titles.

required

get_tables

get_tables() -> dict[str, pd.DataFrame | pl.DataFrame]

Return the tables stored in the event handler.

Returns:

Type Description
dict[str, DataFrame | DataFrame]

A dictionary mapping table names to their corresponding tables.

Warning

Tables are generated on the fly from internal data. When multiple access is needed, it is more efficient to first store them in a variable.

event_types property

event_types: set[EnOptEventType]

The event types that are handled.

Returns:

Type Description
set[EnOptEventType]

A set of event types that are handled.

__getitem__

__getitem__(key: str) -> Any

Retrieve a of a table from the event handler.

Warning

The table is generated on the fly from internal data hen multiple access are needed, it is more efficient to first store them in a variable.

Parameters:

Name Type Description Default
key str

The string key identifying the table to retrieve.

required

Returns:

Type Description
Any

The table associated with the specified key.

Raises:

Type Description
AttributeError

If the requested table does not exist.

add_column

add_column(table: str, name: str, title: str) -> None

Add a column to a given table.

Parameters:

Name Type Description Default
table str

The name of the table to add the column to.

required
name str

The name of the field to add as a column, using attribute syntax.

required
title str

The title of the column to add.

required

Aggregating results across runs

ropt.simple.SharedHandlers

A group of result handlers that several runs share.

Created by shared_handlers and passed to the runs that should feed it. Each handler in the group sees the results of every one of those runs, sequential or concurrent, and the group's dispatcher serializes them, so a handler that accumulates across runs needs no locking of its own.

A group lives until its session closes, which releases it and its handlers. Release it earlier with close, or by using it as a context manager. See Running Optimizations for a walkthrough.

__init__

__init__(
    entries: Sequence[tuple[EventHandler, bool]],
    session: _Session,
) -> None

Initialize the group and start its dispatcher.

Parameters:

Name Type Description Default
entries Sequence[tuple[EventHandler, bool]]

The handlers, each with whether to run it in a thread.

required
session _Session

The session whose event loop the dispatcher runs on.

required

closed property

closed: bool

Whether the group has been released.

Returns:

Type Description
bool

True once the group, or the session that built it, was closed.

attach_to

attach_to(step: ComputeStep[Any]) -> None

Forward the events of a run's compute step to this group's handlers.

A fresh forwarding handler is added per step (one handler cannot serve several steps), carrying only the event types the group's handlers want.

Parameters:

Name Type Description Default
step ComputeStep[Any]

The compute step whose events feed the shared handlers.

required

close

close() -> None

Release the group's handlers without waiting for the session to close.

See Sharing a handler across concurrent runs for when this matters and the resulting lifecycle.

__enter__

__enter__() -> Self

Enter a block that closes the group on exit.

Returns:

Type Description
Self

The group itself.

__exit__

__exit__(*_exc: object) -> None

Close the group.

Result objects

ropt.simple.OptimizationResult dataclass

The outcome of a single optimization run.

A run ends at one evaluation, the best one it found, and that evaluation is carried unchanged on results. See Running Optimizations for a walkthrough.

Attributes:

Name Type Description
exit_code ExitCode

The exit code describing how the optimization terminated.

results FunctionResults | None

The best evaluation, or None if there was no valid result.

Callback types

ropt.simple.EvaluationFunction

Bases: Protocol

The call signature for a high-level evaluation function.

__call__

__call__(
    variables: NDArray[float64],
    context: EvaluationFunctionContext,
) -> FunctionValue

Evaluate the objectives and constraints for a single variable vector.

Parameters:

Name Type Description Default
variables NDArray[float64]

The 1-D variable vector for this evaluation.

required
context EvaluationFunctionContext

The context identifying the evaluation.

required

Returns:

Type Description
FunctionValue
FunctionValue

a scalar, or objectives followed by constraints.

ropt.simple.ReportCallback module-attribute

ReportCallback = Callable[[FunctionResults], bool | None]

Called with each function evaluation; returning True stops the run.