Skip to content

Optimization Plans

ropt.plan

Code for executing optimization plans.

The Plan class orchestrates optimization workflows by managing steps and event handlers.

A plan consists of PlanStep objects, which define individual actions, and EventHandler objects, which process and store data generated during execution. Both steps and event handlers are implemented using a plugin mechanism, making it easy to extend the range of supported actions and data processing. The ropt library provides default implementations through the default plan handler and default plan step plugins. These provide basic steps and event handlers to support a wide range of optimization workflows.

Setting up and executing a Plan object for simple optimization cases can be complex. The BasicOptimizer class simplifies this process by providing a convenient way to build and execute straightforward plans involving a single optimization.

ropt.plan.Plan

Plan class for executing optimization workflows.

The Plan object is the core component for executing optimization workflows. It orchestrates the execution of individual steps, manages evaluators for function computations, and processes data and results through event handlers.

Building a Plan:

A Plan is constructed by adding three main types of components, typically instantiated via the PluginManager:

  1. Steps (PlanStep): These define individual actions or operations within the optimization workflow. Steps are added using the add_step method.
  2. Event Handlers (EventHandler): These components process data, track results, or react to events emitted during plan execution. Event handlers are added using the add_event_handler method.
  3. Evaluators (Evaluator): These are responsible for performing function evaluations (e.g., objective functions, constraints). Evaluators are added using the add_evaluator method and can be passed to steps that need them.

Tags:

Steps, event handlers, and evaluators can be assigned one or more tags. These tags can be used to identify the components instead of their unique IDs. Unlike ID's, tags do not need to be unique. This is useful when the components are created dynamically or if multiple components are to be identified as a group. For example, when specifying the source of events that a handler should process, its sources argument may contain both component objects, which identifies by their ID, or tags, which could refer to multiple components that have that tag.

Executing a Plan:

Once a plan is assembled, the run method can be invoked for each step individually. This approach allows for the integration of complex logic and custom functions, leveraging the full capabilities of Python.

PluginManager:

A PluginManager object can be provided that is used by the plan object to find and instantiate step, event handler, and evaluator objects. This manager can also be used by these components to implement further plugin-based functionality.

Events:

Steps can communicate events by retrieving a list of handlers using the get_event_handlers method. Event handlers can respond to these events, enabling actions such as processing optimization results. Event handlers are added to the plan using the add_event_handler method. To connect the event handlers to steps, they generally accept a set of steps via the sources argument. The steps must be part of the same plan, or a child plan (if existent).

Evaluators:

Evaluators (Evaluator) are key components responsible for performing function evaluations, such as computing objective functions or constraint values. They are added to the plan using the add_evaluator method. They connect to the steps in the plan, or in child plans, via the clients argument.

Nested Plans:

Multiple plans can be defined. A step within one plan can trigger the execution of another plan, enabling nested workflows. In nested plans, the set_parent method establishes a parent-child relationship. This allows events to propagate up the hierarchy to the parent plan.

Aborting a Plan:

A plan's execution can be terminated, either programmatically from within a step or event handler, or externally by directly calling the abort method. The aborted property can be used to check if a plan has been aborted.

Handler Data:

Individual event handlers may store values that they accumulate or calculate from the events that they handle. Code outside of the event handlers, such as the optimization workflow code that runs the steps, can set and retrieve these values using the [] operator.

aborted property

aborted: bool

Check if the plan was aborted.

Determines whether the plan's execution has been aborted.

Returns:

Name Type Description
bool bool

True if the plan was aborted; otherwise, False.

plugin_manager property

plugin_manager: PluginManager

Return the plugin manager.

Retrieves the PluginManager object associated with this plan.

Returns:

Type Description
PluginManager

The plugin manager stored by the plan.

__init__

__init__(
    plugin_manager: PluginManager,
    parent: Plan | None = None,
) -> None

Initialize a plan object.

Constructs a new plan, associating it with an evaluator, and optionally with a plugin manager and/or a parent plan.

The plugin_manager is used by the plan, and possibly by steps and event handlers to add plugin functionality.

If a parent plan is specified, this plan becomes a child, enabling communication up the plan hierarchy.

Parameters:

Name Type Description Default
plugin_manager PluginManager

A plugin manager.

required
parent Plan | None

An optional parent plan.

None

add_event_handler

add_event_handler(
    name: str,
    tags: set[str] | None = None,
    sources: set[PlanComponent | str] | None = None,
    **kwargs: Any,
) -> EventHandler

Add an event handler to the plan.

Constructs and registers an event handler with the plan. The handler's type is determined by the provided name, which the plugin system uses to locate the corresponding handler class. Any additional keyword arguments are passed to the handler's constructor.

The sources parameter acts as a filter, determining which plan steps this event handler should listen to. It should be a set containing the PlanStep instances whose event you want to receive. When an event is received, this event handler checks if the step that emitted the event (event.source) is present in the sources set. If sources is None, events from all sources will be processed.

Parameters:

Name Type Description Default
name str

The name of the event handler to add.

required
tags set[str] | None

Optional tags

None
sources set[PlanComponent | str] | None

The steps whose events should be processed.

None
kwargs Any

Additional arguments for the handler's constructor.

{}

Returns:

Type Description
EventHandler

The newly added event handler.

add_step

add_step(
    name: str, tags: set[str] | None = None, **kwargs: Any
) -> PlanStep

Add a step to the plan.

Registers a step with the plan. The step's type is determined by the provided name, which the plugin system uses to locate the corresponding step class. Any additional keyword arguments are passed to the step's constructor.

Parameters:

Name Type Description Default
name str

The name of the step to add.

required
tags set[str] | None

Optional tags

None
kwargs Any

Additional arguments for the step's constructor.

{}

Returns:

Type Description
PlanStep

The newly added step.

add_evaluator

add_evaluator(
    name: str,
    tags: set[str] | None = None,
    clients: set[PlanComponent | str] | None = None,
    **kwargs: Any,
) -> Evaluator

Add an evaluator object to the plan.

Creates an evaluator of a type that is determined by the provided name, which the plugin system uses to locate the corresponding evaluator class. Any additional keyword arguments are passed to the evaluators's constructor.

The clients parameter acts as a filter, determining which plan steps this evaluator should serve. It should be a set containing the PlanStep instances that should be handled. When an evaluation is requested, this evaluator checks if the step is present in the client set.

Parameters:

Name Type Description Default
name str

The name of the evaluator to add.

required
tags set[str] | None

Optional tags

None
clients set[PlanComponent | str] | None

The clients that should be served by this evaluator.

None
kwargs Any

Additional arguments for the evaluators's constructor.

{}

Returns:

Type Description
Evaluator

The new evaluator object.

run_step

run_step(step: PlanStep, **kwargs: Any) -> Any

Run a step in the plan.

Executes a specific step within the plan. The step's run method is called with the provided keyword arguments. If the plan has been aborted, a PlanAborted exception is raised before the step is executed.

The step is executed only once. The value returned by the step's run method is returned by this method.

Parameters:

Name Type Description Default
step PlanStep

The step to run.

required
kwargs Any

Additional arguments to pass to the step's run method.

{}

Returns:

Name Type Description
Any Any

The value returned by the step's run method.

Raises:

Type Description
AttributeError

If the provided step ID is not valid.

PlanAborted

If the plan has been aborted.

get_event_handlers

get_event_handlers(
    source: PlanComponent, event_types: set[EventType]
) -> dict[EventType, list[Callable[[Event], None]]]

Get the event handlers for a given source and event types.

When this method is called, all event handlers associated with the plan are searched for those that handle the source. Then, if the plan has a parent, the parent plan's get_event_handlers method is also called, find handlers further up the hierarchy.

Parameters:

Name Type Description Default
source PlanComponent

The source of the event.

required
event_types set[EventType]

The event types that should be handled.

required

Returns:

Type Description
dict[EventType, list[Callable[[Event], None]]]

A mapping of event types to a list of suitable handlers.

get_evaluator

get_evaluator(client: PlanComponent) -> Evaluator

Retrieve the appropriate evaluator for a given client step.

This method searches for an Evaluator that is configured to serve the specified client (PlanStep). The search starts in the current plan and, if no suitable evaluator is found and a parent plan exists, continues recursively up the plan hierarchy.

An evaluator is considered suitable the id or tags of the client step is present in the clients set of the evaluator.

The method expects to find exactly one suitable evaluator.

Parameters:

Name Type Description Default
client PlanComponent

The step for which an evaluator is being requested.

required

Returns:

Type Description
Evaluator

The single evaluator instance configured to serve the client.

Raises:

Type Description
AttributeError

If no suitable evaluator is found, or if multiple suitable evaluators are found.

abort

abort() -> None

Abort the plan.

Prevents further steps in the plan from being executed. This method does not interrupt a currently running step but ensures that no subsequent steps will be initiated. It can be used to halt the plan's execution due to a step failure or external intervention.

The aborted property can be used to check if the plan has been aborted.

set_parent

set_parent(parent: Plan) -> None

Set the parent of the plan.

Establishes a parent-child relationship between this plan and another plan. This enables event propagation up the plan hierarchy. It also allows the get_evaluation method to inquire the parent for an evaluator object, if necessary.

Parameters:

Name Type Description Default
parent Plan

The parent plan.

required

ropt.plan.Event dataclass

Stores data related to an optimization event.

During the execution of an optimization plan, events are triggered to signal specific occurrences. Callbacks can be registered to react to these events and will receive an Event object containing relevant information.

The specific data within the Event object varies depending on the event type. See the EventType documentation for details.

Attributes:

Name Type Description
event_type EventType

The type of event that occurred.

data dict[str, Any]

A dictionary containing additional event-specific data.