Skip to content

Hybrid Systems

This page covers the public API of flowcean.hybrid and its subpackages:

  • Modeling and simulation: system definitions, automaton diagrams, trajectories, explicit sampling, and plotting.
  • Benchmarks: reusable system factories.
  • HyDRA identification: HyDRALearner returns fully assigned LearnedFlows or raises HyDRAIdentificationError with the failing segment. Use to_labeled_frames for selector training or to_flow_ids for NumPy assignments. Progress observers use HyDRACallback or PlotCallback; selector helpers are also available from flowcean.hybrid.hydra.selector.

See the hybrid systems guide for modeling concepts and examples.

Modeling and simulation

Hybrid-system modeling, automaton diagrams, simulation, and traces.

Attributes

Input module-attribute

Input = np.ndarray

InputStream module-attribute

InputStream = Callable[[float], Input]

Parameters module-attribute

Parameters = Mapping[str, float]

Classes

CrossingDirection

Bases: IntEnum

Direction in which an event surface must cross zero.

Attributes
FALLING class-attribute instance-attribute
FALLING = -1
EITHER class-attribute instance-attribute
EITHER = 0
RISING class-attribute instance-attribute
RISING = 1

DelayFunction

Bases: Protocol

Transition delay sampled at each accepted detection, not at execution.

The transition's scheduling policy determines which detections are accepted and which sampled occurrence can execute. Each sample freezes that occurrence's deadline at detection time plus the returned duration. Return a finite, nonnegative scalar duration in model time units. The source location's state, effective parameters, and residence time are supplied at detection. See FlowFunction for shared inputs, supported signatures, and purity requirements.

EventSurface dataclass

EventSurface(fn: Callable[..., float], direction: CrossingDirection = EITHER, label: str | None = None)

Scalar event surface defining a simulated transition event.

Supply a continuous scalar function whose zero crossings identify the switching boundary. RISING accepts negative-to-positive crossings, FALLING positive-to-negative crossings, and EITHER both. Exact zero on entry follows the transition's SurfaceEntryPolicy. NaN values raise InvalidEventSurfaceValueError; nonzero values, including infinities, retain their sign in entry checks. Continuous crossing detection brackets roots using integration-step endpoint signs. Multiple crossings within a step can be missed; tangency detection depends on the step endpoints.

Parameters:

Name Type Description Default
fn Callable[..., float]

Root function. See FlowFunction for callback inputs.

required
direction CrossingDirection

Crossing direction. Defaults to either direction.

EITHER
label str | None

Optional display label.

None
Attributes
fn instance-attribute
fn: Callable[..., float]
direction class-attribute instance-attribute
label class-attribute instance-attribute
label: str | None = None

EventSurfaceFunction

Bases: Protocol

Scalar event-surface callback.

See FlowFunction for shared inputs and supported callback signatures.

Flow dataclass

Flow(fn: Callable[..., Derivative], label: str | None = None)

Reusable continuous-state derivative law.

Parameters:

Name Type Description Default
fn Callable[..., Derivative]

Function returning the state derivative. See FlowFunction for callback inputs. Scalar derivative returns are accepted only for single-state systems, both during solver evaluation and when derivatives are explicitly sampled from a trajectory.

required
label str | None

Optional display label.

None
Attributes
fn instance-attribute
fn: Callable[..., Derivative]
label class-attribute instance-attribute
label: str | None = None

FlowFunction

Bases: Protocol

Continuous-state derivative callback.

Flow, event-surface, reset, and delay callbacks share these inputs: physical time (t), the continuous state vector, effective parameters, an input_stream returning a vector for a requested time, and the current visit's elapsed location_time.

Model callbacks may declare any subset using these names, including keyword-only arguments. Named callbacks with **kwargs receive all five inputs. Four-positional callbacks receive (t, state, parameters, input_stream); positional-only arguments, *args, and noncanonical required names select that form.

Callbacks and input streams must be pure and deterministic: integration and derivative sampling can evaluate the same inputs repeatedly.

HybridSystem dataclass

HybridSystem(locations: Sequence[Location], transitions: Sequence[Transition], initial_location: Location, initial_state: State, parameters: Parameters = dict())

Hybrid system with locations and transitions.

Parameters:

Name Type Description Default
locations Sequence[Location]

Location objects in this system.

required
transitions Sequence[Transition]

Transition list defining event surfaces and resets.

required
initial_location Location

Starting location object.

required
initial_state State

Initial state vector.

required
parameters Parameters

Global parameter map passed to callbacks.

dict()
Attributes
locations instance-attribute
locations: Sequence[Location]
transitions instance-attribute
transitions: Sequence[Transition]
initial_location instance-attribute
initial_location: Location
initial_state instance-attribute
initial_state: State
parameters class-attribute instance-attribute
parameters: Parameters = field(default_factory=dict)
Methods:
transitions_from
transitions_from(location: Location) -> list[Transition]

Return transitions leaving the given location.

Location dataclass

Location(flow: Flow, *, label: str | None = None, parameters: Parameters | None = None)
Location(flow: Callable[..., Derivative], *, label: str | None = None, parameters: Parameters | None = None)
Location(flow: Flow | Callable[..., Derivative], *, label: str | None = None, parameters: Parameters | None = None)

Discrete hybrid-automaton location.

Parameters:

Name Type Description Default
flow Flow | Callable[..., Derivative]

Flow definition or bare derivative callback active here.

required
label str | None

Optional display label.

None
parameters Parameters | None

Location-local parameters overriding system parameters with the same names. Effective maps are snapshotted for each run.

None
Attributes
flow instance-attribute
flow: Flow
label instance-attribute
label: str | None
parameters instance-attribute
parameters: Parameters

Reset dataclass

Reset(fn: Callable[..., State], label: str | None = None)

State reset applied on a transition.

The callback receives the source location's effective parameters and residence time. Its result must match the continuous-state dimension; a scalar is accepted for a single-state system.

Parameters:

Name Type Description Default
fn Callable[..., State]

Reset function applied at the event time. See FlowFunction for callback inputs.

required
label str | None

Optional display label.

None
Attributes
fn instance-attribute
fn: Callable[..., State]
label class-attribute instance-attribute
label: str | None = None

ResetFunction

Bases: Protocol

State reset callback.

See FlowFunction for shared inputs and supported callback signatures.

SurfaceEntryPolicy

Bases: StrEnum

Behavior when a transition surface is exactly zero on location entry.

Entry includes initialization and arrival after a transition. ERROR raises SurfaceEntryError; TRIGGER detects the transition immediately (starting its delay); CONTINUE begins continuous integration with the surface at zero. For CONTINUE, choose a flow that departs in the direction opposite to the accepted crossing so integration can advance.

All outgoing surfaces are evaluated before resolving entry. NaN values are rejected first, then zero ERROR surfaces. Exactly one zero-delay TRIGGER surface at zero performs a jump; multiple such surfaces raise AmbiguousTransitionError. Positive-delay TRIGGER surfaces schedule execution without a jump. Entry handling repeats at the target after an immediate transition.

Attributes
ERROR class-attribute instance-attribute
ERROR = 'error'
TRIGGER class-attribute instance-attribute
TRIGGER = 'trigger'
CONTINUE class-attribute instance-attribute
CONTINUE = 'continue'

Transition dataclass

Transition(source: Location, target: Location, event_surface: EventSurface | Callable[..., float], reset: Reset | Callable[..., State] | None = None, *, entry_policy: SurfaceEntryPolicy = ERROR, delay: float | Callable[..., float] = 0.0, scheduling_policy: TransitionSchedulingPolicy = FIRST_DETECTION)

Discrete event-triggered transition between locations.

event_surface is a scalar zero-crossing surface.

Parameters:

Name Type Description Default
source Location

Source location.

required
target Location

Target location.

required
event_surface EventSurface | Callable[..., float]

Event surface that triggers the transition.

required
reset Reset | Callable[..., State] | None

Optional reset applied upon transition.

None
entry_policy SurfaceEntryPolicy

Behavior when the event surface is exactly zero upon entry to the source location.

ERROR
delay float | Callable[..., float]

Fixed finite, nonnegative scalar duration, or a pure, deterministic callback returning one in the model's time units. See DelayFunction for inputs. The callback is evaluated at detection, including entry triggers, and validated then; fixed values are validated on construction. Each accepted detection freezes an occurrence's deadline at detection time plus delay. The source flow and residence clock continue until execution; the reset receives that execution context. Zero (the default) requests immediate execution.

0.0
scheduling_policy TransitionSchedulingPolicy

How repeated detections affect this transition's pending occurrence. FIRST_DETECTION (the default) accepts only the first detection for the entire visit, even if it loses to another candidate. LATEST_DETECTION replaces the occurrence on every crossing, advancing or postponing its deadline. EACH_DETECTION samples every crossing and keeps the earliest deadline; equal own deadlines retain the earliest detection time. Every exit, including a self-transition, cancels all occurrences. The earliest outgoing deadline executes. At an exactly equal numerical time, direction-qualified detections are processed before execution; equal earliest deadlines of distinct transitions are ambiguous. No tolerance groups nearby times.

FIRST_DETECTION
Attributes
source instance-attribute
source: Location
target instance-attribute
target: Location
event_surface instance-attribute
event_surface: EventSurface
reset class-attribute instance-attribute
reset: Reset | None = None
entry_policy class-attribute instance-attribute
delay class-attribute instance-attribute
delay: float | Callable[..., float] = 0.0
scheduling_policy class-attribute instance-attribute

TransitionSchedulingPolicy

Bases: StrEnum

How detections schedule a transition during one source-location visit.

FIRST_DETECTION accepts only the first detection, even when another transition currently has an earlier deadline. LATEST_DETECTION accepts every direction-qualified crossing and replaces this transition's pending occurrence. EACH_DETECTION samples an independent occurrence at each crossing; the earliest deadline wins, with equal deadlines retaining the earliest detection time. Leaving the visit cancels all occurrences.

Attributes
FIRST_DETECTION class-attribute instance-attribute
FIRST_DETECTION = 'first_detection'
LATEST_DETECTION class-attribute instance-attribute
LATEST_DETECTION = 'latest_detection'
EACH_DETECTION class-attribute instance-attribute
EACH_DETECTION = 'each_detection'

AmbiguousTransitionError

Bases: HybridSimulationError

Raised for competing entry-time jumps or equal scheduled deadlines.

HybridSimulationError

Bases: RuntimeError

Base class for hybrid simulation runtime failures.

InvalidEventSurfaceValueError

InvalidEventSurfaceValueError(transitions: Sequence[Transition], time: float, *, context: str)

Bases: HybridSimulationError

Raised when an event surface returns NaN.

SimulationProgressError

Bases: HybridSimulationError

Raised when a solver event does not advance physical time.

SurfaceEntryError

Bases: HybridSimulationError

Raised when an ERROR surface is zero on location entry.

ContinuousSegment dataclass

ContinuousSegment(location: Location, t_span: tuple[float, float], _solution: Callable[[ndarray], ndarray], _clock: _ResidenceClock, _knots: ndarray)

Continuous evolution in one location over a time interval.

The solver's dense solution and plotting knots are private. The residence clock stays anchored throughout this visit, independent of sampling grids.

Attributes
location instance-attribute
location: Location
t_span instance-attribute
t_span: tuple[float, float]
Methods:
evaluate
evaluate(time: float) -> TrajectoryPoint

Evaluate within the inclusive interval without invoking callbacks.

The start is after any preceding jump chain; the end is before any following jump. Times must be finite; extrapolation is not allowed.

location_time
location_time(time: float) -> float

Return residence age without evaluating the continuous state.

Event dataclass

Event(time: float, transition: Transition, state_before: State, state_after: State, microstep: int, location_time_before: float, detection_time: float)

A recorded transition with states immediately before and after it.

Pre- and post-reset state snapshots are detached and read-only. transition references the model's transition, including its source, target, event surface, and reset. time is physical simulation time; microstep orders events at that time, starting at zero. location_time_before is the age of the source visit before the jump. detection_time identifies the detection that scheduled the executed occurrence, possibly on location entry: the first for FIRST_DETECTION, the latest for LATEST_DETECTION, or the earliest-deadline occurrence for EACH_DETECTION (earliest detection when its own deadlines tie). time is when the transition executed after its sampled delay. They are equal for zero-delay transitions. Unexecuted detections are not recorded as events.

Attributes
time instance-attribute
time: float
transition instance-attribute
transition: Transition
state_before instance-attribute
state_before: State
state_after instance-attribute
state_after: State
microstep instance-attribute
microstep: int
location_time_before instance-attribute
location_time_before: float
detection_time instance-attribute
detection_time: float

HybridTrajectory dataclass

HybridTrajectory(system: HybridSystem, t_span: tuple[float, float], initial_state: State, initial_location: Location, initial_location_time: float, execution: tuple[ContinuousSegment | Event, ...], _bindings: _RunBindings)

A run's ordered execution, associated model, and parameter snapshots.

Numerical snapshots are read-only. Model identity is retained, but later model parameter edits do not affect this run. Callbacks and input streams must remain deterministic and pure when explicitly resampled.

Attributes
system instance-attribute
system: HybridSystem
t_span instance-attribute
t_span: tuple[float, float]
initial_state instance-attribute
initial_state: State
initial_location instance-attribute
initial_location: Location
initial_location_time instance-attribute
initial_location_time: float
execution instance-attribute
execution: tuple[ContinuousSegment | Event, ...]
segments property
segments: tuple[ContinuousSegment, ...]

Continuous pieces in execution order.

events property
events: tuple[Event, ...]

Individual transitions, including every same-time microstep.

parameters property
parameters: Mapping[Location, Parameters]

Read-only effective parameter snapshots for all declared locations.

Methods:
evaluate
evaluate(time: float) -> TrajectoryPoint

Evaluate a finite time in the inclusive run interval, without callbacks.

At an exact event time, return the final state and location after the entire jump chain, with zero residence age. This includes initial and final events.

sample
sample(times: Iterable[float] | None = None, *, dt: float | None = None, include_state: bool = True, include_location_id: bool = True, include_location_label: bool = False, include_location_time: bool = True, include_inputs: bool = False, include_derivatives: bool = False) -> DataFrame

Build a frame at requested times, using post-transition event values.

At an event time, the row describes the state after the entire same-time chain, as returned by evaluate. Default sampling invokes no callbacks. Inputs and flow derivatives are evaluated at the requested times when included; these callbacks and input streams must remain pure and deterministic.

Parameters:

Name Type Description Default
times Iterable[float] | None

Finite, non-descending times within the trajectory's interval. Accepts generators, duplicates, and an empty grid. Supply exactly one of times or dt.

None
dt float | None

Positive finite grid spacing. Includes the final endpoint; a zero-duration run produces one row.

None
include_state bool

Include continuous-state columns x0, x1, ...

True
include_location_id bool

Include location_id, the index of the active location in the system's declaration order.

True
include_location_label bool

Include the display location_label.

False
include_location_time bool

Include elapsed visit time as location_time.

True
include_inputs bool

Evaluate the input stream and include u0, u1, ... . Requires a stream and a nonempty grid; the input width must be constant across requested times.

False
include_derivatives bool

Evaluate the active flow with the sampled state and run parameters, including dx0, dx1, ... .

False

Returns:

Type Description
DataFrame

A Polars frame with physical time t and the selected columns.

DataFrame

Empty grids retain the known state, derivative, and location

DataFrame

schemas. Use Polars to select or rename columns and add row indices.

Raises:

Type Description
ValueError

Grid arguments, input capture, or callback outputs are invalid.

TrajectoryPoint dataclass

TrajectoryPoint(state: State, location: Location, location_time: float)

State, location, and residence age at one point in an execution.

The state is a detached, read-only array; location is the active model object.

Attributes
state instance-attribute
state: State
location instance-attribute
location: Location
location_time instance-attribute
location_time: float

Functions:

build_hybrid_system_dot

build_hybrid_system_dot(system: HybridSystem, *, show_event_labels: bool = True, show_reset_labels: bool = True, show_direction: bool = False, show_entry_policy: bool = False) -> str

Export the complete declared automaton as deterministic DOT text.

Locations and transitions retain declaration order, including isolated locations, parallel transitions, and self-loops. A point and incoming arrow mark the initial location. Node IDs are positional, independent of display labels; reordering locations changes their IDs.

Labels follow the model's display-label precedence: explicit labels, then callback names, then positional fallbacks for unnamed objects. Labels are treated as literal text, not DOT markup or mathematical expressions. No simulation or callback evaluation is performed, and Graphviz need not be installed. Positive fixed delays are annotated in model time units; delay callbacks are annotated by name, without evaluation.

Parameters:

Name Type Description Default
system HybridSystem

Constructed hybrid system to visualize.

required
show_event_labels bool

Annotate transitions with event-surface labels.

True
show_reset_labels bool

Annotate transitions that have resets with labels.

True
show_direction bool

Include the event surface's zero-crossing direction.

False
show_entry_policy bool

Include each transition's surface-entry policy.

False

Returns:

Type Description
str

DOT source suitable for saving or passing to render_dot_svg.

render_dot_svg

render_dot_svg(dot_source: str) -> str

Render DOT text as SVG using Graphviz's external dot executable.

No files are written and no viewer is opened. SVG layout can vary between Graphviz versions even when the input DOT is identical.

Parameters:

Name Type Description Default
dot_source str

DOT source to render.

required

Returns:

Type Description
str

SVG text decoded as UTF-8.

Raises:

Type Description
RuntimeError

Graphviz is not installed or rejects the DOT source.

plot_locations

plot_locations(trajectory: HybridTrajectory, *, location_colors: Mapping[Location, str] | None = None, show_labels: bool = False, alpha: float = 0.08, ax: Axes | None = None) -> Axes

Shade actual positive-duration segments, using Location identity.

plot_state_space

plot_state_space(trajectory: HybridTrajectory, x_dim: int = 0, y_dim: int = 1, *, location_colors: Mapping[Location, str] | None = None, show_location_legend: bool = True, show_event_points: bool = False, show: bool = False, ax: Axes | None = None) -> Axes

Plot two selected continuous state coordinates, with time implicit.

Each continuous segment is drawn separately so reset jumps are not joined. show_event_points optionally marks states on both sides of transitions; switches without resets are unmarked by default.

plot_trajectory

plot_trajectory(trajectory: HybridTrajectory, dims: Sequence[int] | None = None, *, location_colors: Mapping[Location, str] | None = None, show_locations: bool = True, show_location_labels: bool = False, show_events: bool = True, show_event_labels: bool = True, show_event_points: bool = False, show: bool = False, ax: Axes | None = None) -> Axes

Plot state coordinates against time without lines across resets.

show_events controls vertical transition indicators and labels; show_event_points separately marks the states before and after each transition. Markers are off by default, including at continuous switches.

simulate

simulate(system: HybridSystem, t_span: tuple[float, float], x0: Iterable[float] | None = None, location0: Location | None = None, *, input_stream: InputStream | None = None, initial_location_time: float = 0.0, max_jumps: int = 256, rtol: float = 1e-07, atol: float = 1e-09, max_step: float | None = None) -> HybridTrajectory

Integrate a hybrid execution with dense continuous segments.

Sampling is a separate operation on the returned trajectory. Callbacks and input streams must be pure and deterministic under repeated evaluation. Equal endpoints resolve entry transitions without calling the ODE solver. Parameters are snapshotted for every location at the start of the run. Each transition's scheduling policy selects accepted detections and pending occurrences. Delay callbacks run once per accepted detection, freezing that occurrence's deadline. A positive delay keeps the source flow and residence clock active until execution. Leaving the source visit cancels all its occurrences. At exactly equal numerical times, all direction-qualified detections precede execution, even at the final endpoint; a latest detection can postpone execution beyond the run. Distinct transitions with equal earliest deadlines are ambiguous.

Root detection uses integration-step endpoint signs: multiple roots within a step can be missed, and tangencies are step-dependent. Equality means exact numerical equality, not mathematical simultaneity or a tolerance.

Parameters:

Name Type Description Default
system HybridSystem

Model to simulate.

required
t_span tuple[float, float]

Finite start and end times, with end at or after start.

required
x0 Iterable[float] | None

Initial continuous state, overriding the model's initial state.

None
location0 Location | None

Initial location, overriding the model's initial location.

None
input_stream InputStream | None

Function returning a one-dimensional input vector at a requested physical time.

None
initial_location_time float

Finite, nonnegative age of the initial visit. Each subsequent transition begins a new visit at age zero. Each run starts with no pending transition.

0.0
max_jumps int

Maximum number of transitions, including same-time chains.

256
rtol float

Relative tolerance for SciPy integration.

1e-07
atol float

Absolute tolerance for SciPy integration.

1e-09
max_step float | None

Maximum integration step; None uses SciPy's default.

None

Returns:

Type Description
HybridTrajectory

The trajectory, retaining its supplied initial condition and ordered

HybridTrajectory

continuous segments and events.

Raises:

Type Description
HybridSimulationError

The transition limit is exceeded or a subclass reports an invalid surface, ambiguous entry, or progress failure.

ValueError

Time bounds, initial conditions, or callback outputs are invalid.

Benchmarks

Reusable hybrid-system benchmark factories.

Functions:

wind_turbine_power

wind_turbine_power(rotor_speeds: Sequence[float] | ndarray, location_labels: Sequence[str], *, parameters: Parameters) -> ndarray

Return generator-shaft mechanical power (W) for each rotor speed.

rotor_speeds are positive angular speeds in rad/s; each corresponding location_labels entry selects the active torque law. The location matters in hysteresis bands, where speed alone does not select a law. parameters are those of the simulated turbine, including its gearbox ratio. The resulting one-dimensional array contains one power value per input speed, or no values for empty inputs. This is not electrical output; rated shaft power is not an instantaneous cap in other modes.

System factories

bouncing_ball

bouncing_ball(gravity: float = 9.81, restitution: float = 0.8, initial_state: ndarray | None = None) -> HybridSystem

Create a bouncing ball benchmark system.

Parameters:

Name Type Description Default
gravity float

Downward acceleration.

9.81
restitution float

Velocity multiplier on bounce.

0.8
initial_state ndarray | None

Optional initial [height, velocity].

None

Returns:

Type Description
HybridSystem

HybridSystem configured for a bouncing ball.

buck_converter

buck_converter(source_voltage: float = 24.0, inductance: float = 0.00265, capacitance: float = 0.0022, load_resistance: float = 10.0, *, inductor_resistance: float = 0.52, switch_resistance: float = 0.2, voltage_high: float = 12.1, voltage_low: float = 11.9, initial_state: Sequence[float] | ndarray | None = None) -> HybridSystem

Create a physical hysteretic nonsynchronous buck converter.

A buck converter is a step-down DC-DC power circuit. A controlled switch connects a constant-voltage supply to an inductor, which feeds a capacitor and resistive load in parallel. The inductor stores magnetic energy and prevents abrupt current changes; the capacitor stores electrical energy and smooths the output voltage. A freewheel diode provides a current path when the switch opens. Nonsynchronous means this diode, rather than a second controlled switch, carries the freewheeling current.

The state is [inductor_current, capacitor_voltage] in amperes and volts. The capacitor voltage is also the load voltage. Three locations describe the circuit's conduction states:

  • switch_on: The source supplies energy through the closed switch. Inductor current typically rises, feeding the load and capacitor.
  • switch_off: The source is disconnected, but inductor current continues through the diode. Stored magnetic energy feeds the output while current falls; the capacitor can still charge during this phase.
  • zero_current: Once inductor current reaches zero, the diode blocks reverse current. Only the capacitor supplies the load, so its voltage decays exponentially with time constant load_resistance * capacitance.

Hysteretic control opens the switch when voltage rises to voltage_high and closes it when voltage falls to voltage_low. Between thresholds, the switch retains its state. Switching is state-triggered, not driven by a fixed-frequency clock. The switch may close before current reaches zero, skipping zero_current. The thresholds are switching commands, not hard output-voltage bounds: stored inductor energy can produce overshoot.

The flows follow Kirchhoff's laws and the relations v_L = L * di/dt and i_C = C * dv/dt. With current i, output voltage v, supply V_s, inductance L, capacitance C, load resistance R, inductor resistance r_L, and closed-switch resistance r_S:

  • Switch on: di/dt = (V_s - (r_L + r_S) * i - v) / L.
  • Switch off: di/dt = (-r_L * i - v) / L.
  • In either conducting state: dv/dt = (i - v / R) / C.
  • Zero current: di/dt = 0 and dv/dt = -v / (R * C).

Each location has affine continuous dynamics; voltage and current events select the active circuit configuration. The diode is ideal, with no forward voltage drop or reverse current. Switching delays and diode recovery are not modeled; resistive losses are included in r_L, r_S, and the load.

On entry to zero_current, current is reset exactly to zero to remove numerical event-localization residuals, not to model a physical impulse. Lower-threshold voltage residuals within event-time localization precision are also snapped to the threshold, allowing coincident events to settle without an artificial integration step.

For a nonzero initial current, the latch starts on below voltage_high and off at or above it. At zero current, it starts in zero_current above voltage_low and otherwise starts on. A useful nominal simulation horizon is 0.02 seconds.

Parameters:

Name Type Description Default
source_voltage float

Constant input supply voltage in volts.

24.0
inductance float

Inductance in henries.

0.00265
capacitance float

Output capacitance in farads.

0.0022
load_resistance float

Resistive load in ohms.

10.0
inductor_resistance float

Inductor series resistance in ohms.

0.52
switch_resistance float

Closed-switch resistance in ohms.

0.2
voltage_high float

Rising output-voltage threshold that switches off.

12.1
voltage_low float

Falling output-voltage threshold that switches on.

11.9
initial_state Sequence[float] | ndarray | None

Initial [inductor_current, capacitor_voltage].

None

Returns:

Type Description
HybridSystem

HybridSystem configured for hysteretic buck conversion.

hybrid_oscillator

hybrid_oscillator(damping_left: float = 0.2, damping_right: float = 0.1, frequency: float = 2.0, initial_state: ndarray | None = None) -> HybridSystem

Create a piecewise damped oscillator benchmark.

Parameters:

Name Type Description Default
damping_left float

Damping for the left half-space.

0.2
damping_right float

Damping for the right half-space.

0.1
frequency float

Oscillation frequency.

2.0
initial_state ndarray | None

Optional initial [position, velocity].

None

Returns:

Type Description
HybridSystem

HybridSystem configured for a hybrid oscillator.

impact_oscillator

impact_oscillator(damping: float = 0.1, stiffness: float = 4.0, *, restitution: float = 0.7, initial_state: ndarray | None = None) -> HybridSystem

Create an impact oscillator driven by an external force.

Simulate with an explicit finite one-element input vector [force].

Parameters:

Name Type Description Default
damping float

Linear damping coefficient.

0.1
stiffness float

Spring stiffness.

4.0
restitution float

Velocity multiplier on impact.

0.7
initial_state ndarray | None

Optional initial [position, velocity].

None

Returns:

Type Description
HybridSystem

HybridSystem configured for an impact oscillator.

location_cycle

location_cycle(location_count: int = 4, dimension: int = 4, dwell_time: float = 0.5, initial_state: ndarray | None = None) -> HybridSystem

Create a scalable hybrid system that cycles through locations.

The system has location_count locations, each with linear dynamics active for dwell_time. Transitions leave the continuous state unchanged.

Parameters:

Name Type Description Default
location_count int

Number of locations in the cycle.

4
dimension int

Dimension of the continuous state.

4
dwell_time float

Time to stay in each location.

0.5
initial_state ndarray | None

Optional initial state (length dimension).

None

Returns:

Type Description
HybridSystem

HybridSystem cycling through multiple linear locations.

pid_controlled_plant

pid_controlled_plant(kp: float = 6.0, ki: float = 2.0, kd: float = 1.0, stiffness: float = 3.0, damping: float = 0.6, *, u_min: float = -1.0, u_max: float = 1.0, initial_state: ndarray | None = None) -> HybridSystem

Create a PID-controlled second-order plant with saturation.

The state is [position, velocity, integral_error]. Simulate with an explicit finite two-element input vector [reference, reference_rate]; the second component is the reference's time derivative. The controller tracks this reference and saturates the control input, yielding hybrid locations.

Parameters:

Name Type Description Default
kp float

Proportional gain.

6.0
ki float

Integral gain.

2.0
kd float

Derivative gain.

1.0
stiffness float

Plant stiffness.

3.0
damping float

Plant damping.

0.6
u_min float

Minimum control input.

-1.0
u_max float

Maximum control input.

1.0
initial_state ndarray | None

Optional initial state.

None

Returns:

Type Description
HybridSystem

HybridSystem configured for PID control with saturation.

piecewise_affine

piecewise_affine(a_left: ndarray | None = None, a_right: ndarray | None = None, b_left: ndarray | None = None, b_right: ndarray | None = None, threshold: float = 0.0, initial_state: ndarray | None = None) -> HybridSystem

Create a piecewise affine system with oscillatory switching.

Parameters:

Name Type Description Default
a_left ndarray | None

Linear dynamics matrix for the left region.

None
a_right ndarray | None

Linear dynamics matrix for the right region.

None
b_left ndarray | None

Affine offset for the left region.

None
b_right ndarray | None

Affine offset for the right region.

None
threshold float

Event-surface threshold on x[0].

0.0
initial_state ndarray | None

Optional initial state.

None

Returns:

Type Description
HybridSystem

HybridSystem configured with piecewise affine dynamics.

relay_integrator

relay_integrator(rate: float = 1.0, lower: float = -1.0, upper: float = 1.0, initial_state: ndarray | None = None) -> HybridSystem

Create a relay integrator with hysteresis.

Parameters:

Name Type Description Default
rate float

Magnitude of the integrator rate.

1.0
lower float

Lower switching threshold.

-1.0
upper float

Upper switching threshold.

1.0
initial_state ndarray | None

Optional initial scalar state.

None

Returns:

Type Description
HybridSystem

HybridSystem configured with relay dynamics.

switched_linear

switched_linear(a_on: ndarray | None = None, a_off: ndarray | None = None, threshold: float = 0.0, initial_state: ndarray | None = None) -> HybridSystem

Create a switched linear system benchmark.

Parameters:

Name Type Description Default
a_on ndarray | None

Dynamics matrix for the "on" location.

None
a_off ndarray | None

Dynamics matrix for the "off" location.

None
threshold float

Switching threshold on x[0].

0.0
initial_state ndarray | None

Optional initial state.

None

Returns:

Type Description
HybridSystem

HybridSystem configured with switching linear dynamics.

tank_valves

tank_valves(area_1: float = 1.0, area_2: float = 1.2, inflow: float = 0.02, *, outlet_area_1: float = 0.002, outlet_area_2: float = 0.012, valve_gain: float = 0.01, high_level: float = 1.2, low_level: float = 0.4, gravity: float = 9.81, initial_state: Sequence[float] | ndarray | None = None) -> HybridSystem

Create a gravity-drained two-tank benchmark.

Both tanks have atmospheric free surfaces and share a bottom datum. An always-on pump feeds tank 1. A check valve permits gravity-driven transfer from tank 1 to tank 2 only while open; overflow is not modeled.

Parameters:

Name Type Description Default
area_1 float

Tank 1 cross-sectional area in square meters.

1.0
area_2 float

Tank 2 cross-sectional area in square meters.

1.2
inflow float

Constant pump inflow to tank 1 in cubic meters per second.

0.02
outlet_area_1 float

Tank 1 discharge coefficient times physical outlet area, in square meters.

0.002
outlet_area_2 float

Tank 2 discharge coefficient times physical outlet area, in square meters.

0.012
valve_gain float

Effective open-valve transfer area in square meters.

0.01
high_level float

Tank 1 level in meters at which the valve opens.

1.2
low_level float

Tank 1 level in meters at which the valve closes.

0.4
gravity float

Gravitational acceleration in meters per second squared.

9.81
initial_state Sequence[float] | ndarray | None

Initial [level_1, level_2] in meters.

None

Returns:

Type Description
HybridSystem

HybridSystem configured for valve-controlled gravity flow.

References

The gravity-orifice basis follows the standard square-root head model described in https://www.mdpi.com/2076-3417/13/9/5414, Section 2.1.2.

thermostat

thermostat(ambient: float = 20.0, heating_power: float = 5.0, cooling_rate: float = 0.3, hysteresis: float = 2.0, initial_state: ndarray | None = None) -> HybridSystem

Create a thermostat benchmark system.

Simulate with an explicit one-element finite input vector [target] giving the target temperature at each requested time. The target sets the high and low switching thresholds; flows depend only on state.

Parameters:

Name Type Description Default
ambient float

Ambient temperature.

20.0
heating_power float

Heating input strength.

5.0
cooling_rate float

Cooling coefficient.

0.3
hysteresis float

Temperature hysteresis band width.

2.0
initial_state ndarray | None

Optional initial temperature.

None

Returns:

Type Description
HybridSystem

HybridSystem configured for thermostat switching.

time_forced_switch

time_forced_switch(period: float = 1.0, initial_state: ndarray | None = None) -> HybridSystem

Create a system that alternates between fast and slow decay.

The two physical state coordinates are unchanged at switches. Each location is active for half the period.

Parameters:

Name Type Description Default
period float

Full period of the two-location cycle.

1.0
initial_state ndarray | None

Optional initial [x1, x2] state.

None

Returns:

Type Description
HybridSystem

HybridSystem with time-triggered switches.

time_varying_event_surface

time_varying_event_surface(*, hysteresis: float = 0.2, drift: float = 0.6, damping: float = 0.4, initial_state: ndarray | None = None) -> HybridSystem

Create a system with externally driven event-surface thresholds.

Simulate with an explicit finite one-element input vector [threshold]. Both switching surfaces use the supplied threshold at the queried time.

Parameters:

Name Type Description Default
hysteresis float

Event-surface hysteresis width.

0.2
drift float

Drift magnitude per location.

0.6
damping float

Damping on the second state.

0.4
initial_state ndarray | None

Optional initial state.

None

Returns:

Type Description
HybridSystem

HybridSystem with time-dependent event surfaces.

wind_turbine

wind_turbine(*, initial_state: Sequence[float] | ndarray | None = None, pitch_kp: float = 0.01882681, pitch_ki: float = 0.008068634, speed_hysteresis: float = 0.2) -> HybridSystem

Model an already-running 5 MW-class wind turbine.

Wind turns the rotor; the generator resists rotation to extract power. Wind thrust bends the tower, modeled as a damped mass-spring system. Turning the blades out of the wind (pitching) reduces their loading. Startup, shutdown, and emergency-braking control are not modeled.

The state vector is [omega, x, v, beta, beta_rate, integral]:

  • omega: rotor speed (rad/s).
  • x: tower displacement from its undeflected position (m).
  • v: tower velocity (m/s).
  • beta: blade pitch (rad).
  • beta_rate: pitch rate (rad/s).
  • integral: pitch controller's integral contribution (rad).

By default, the rotor turns at 0.65 rad/s and all other states are zero. The five locations set generator torque according to generator speed:

  • no_generation: zero torque; the rotor spins without generating.
  • gradual_generation: torque increases linearly with speed.
  • below_rated_power: torque is proportional to speed squared.
  • approaching_rated_power: a second linear torque ramp.
  • rated_power: constant power, with torque equal to power/speed.

Rated power is about 5.30 MW at the generator shaft; electrical output is not modeled. Locations form a two-way chain in the order above. Upward and downward speed thresholds differ by 2*speed_hysteresis; between them, the current mode is retained. Switching leaves physical states unchanged.

Pitch control runs in every mode, using speed error and its accumulated value (PI control). Blade motion lags the command, limited to 0..18 degrees. The controller corrects accumulated error at those limits; they are not mechanical stops. Hardware and controller constants are recorded in system.parameters.

Supply simulate(..., input_stream=...) with a finite one-element vector [wind] containing a positive wind speed (m/s), such as lambda t: np.array([11.0]). Relative wind is u = wind - v; it and rotor speed must stay positive. With radius R=63 m, the tip-speed ratio omega*R/u must stay in 2.5..14.5 and pitch in -2..20 degrees. Leaving the polynomial fit's domain raises an error.

The fit gives torque coefficient Cq and thrust coefficient Ct. Rotor torque is rho*pi*R**3*u**2*Cq/2 and thrust rho*pi*R**2*u**2*Ct/2, where rho is air density. Negative torque brakes the rotor. The rigid, lossless gearbox makes generator speed 97*omega. Generator torque and inertia are referred to the rotor by factors of 97 and 97 squared. Generator torque has no delay or rate limit. Aerodynamics assume head-on wind and an instantaneous response to current conditions (a quasi-steady approximation); blades are rigid.

Parameters:

Name Type Description Default
initial_state Sequence[float] | ndarray | None

Optional six-element running state (copied).

None
pitch_kp float

Positive finite pitch proportional gain (rad per rad/s).

0.01882681
pitch_ki float

Positive finite integral gain (rad per rad/s per second).

0.008068634
speed_hysteresis float

Positive generator-speed threshold halfwidth (rad/s).

0.2

Returns:

Type Description
HybridSystem

HybridSystem with five torque-control locations.

valve_closure

valve_closure(delay: float = 1.0) -> HybridSystem

Fill a tank until its inlet valve closes after threshold detection.

Water height rises at a constant rate until it reaches the closing threshold, which schedules valve closure. Filling continues during the delay; after closure the height stays constant.

Parameters:

Name Type Description Default
delay float

Finite, nonnegative closing delay in model time units. Use zero for immediate closure at the threshold.

1.0

Returns:

Type Description
HybridSystem

A two-location system with water height as its single state coordinate.

HyDRA identification

Curated HyDRA hybrid-system identification API.

Classes

HyDRACallback

Observe discovery geometry and scalar fits; override any desired hooks.

Hooks run synchronously, and their exceptions propagate to the caller.

Methods:
start
start(*, trace_count: int, threshold: float, start_width: int, step_width: int) -> None

Begin discovery over trace_count independent traces.

threshold is the strict upper bound on absolute prediction error. start_width and step_width are the initial candidate window size and its growth step, measured in consecutive observations.

pending_segment_found
pending_segment_found(segment: TraceSegment) -> None

Report the unassigned segment where candidate fitting will begin.

candidate_window_evaluated
candidate_window_evaluated(*, segment: TraceSegment, fit: float) -> None

Report candidate accuracy on the observations in segment.

fit is the maximum absolute prediction error over that window.

candidate_selected
candidate_selected(*, segment: TraceSegment, fit: float) -> None

Report the last evaluated window whose candidate met the threshold.

fit is its maximum absolute prediction error. The selected candidate will next be used to group matching unassigned observations.

grouping_evaluated
grouping_evaluated(*, flow_id: int, accepted_segments: tuple[TraceSegment, ...], considered_count: int) -> None

Report candidate acceptance across all traces, before final refitting.

Parameters:

Name Type Description Default
flow_id int

ID reserved for this candidate if its final fit succeeds.

required
accepted_segments tuple[TraceSegment, ...]

Previously unassigned observations that match the candidate within the error threshold.

required
considered_count int

Total number of unassigned observations across all traces before grouping, including both accepted and rejected observations. Already assigned observations are excluded.

required
flow_finalized
flow_finalized(*, flow_id: int, flow: LearnedFlow) -> None

Report a flow successfully refitted on its accepted observations.

flow_id is its position in result.flows. flow contains the refitted model and the segments accepted before that refit.

finish
finish(result: LearnedFlows) -> None

Receive the successful result assigning every supplied observation.

result is the same object returned by learn. This hook is not called if identification, a backend, or an earlier callback fails.

HyDRAIdentificationError

HyDRAIdentificationError(segment: TraceSegment, message: str)

Bases: RuntimeError

Discovery could not assign the supplied observations in a segment.

Attributes:

Name Type Description
segment TraceSegment

The failing trace segment, with half-open row bounds.

Attributes
segment instance-attribute
segment: TraceSegment = segment

HyDRALearner

HyDRALearner(regressor_factory: Callable[[], SupervisedLearner], threshold: float, start_width: int = 10, step_width: int = 5, callback: HyDRACallback | None = None)

Discover shared flow models from ordered traces with one scalar target.

HyDRA fits candidates on growing windows of consecutive observations, groups matching observations across traces, and refits each discovered flow on its accepted group. Supply derivatives as targets to learn rates of change, or another regression target to learn its shared behaviors.

Parameters:

Name Type Description Default
regressor_factory Callable[[], SupervisedLearner]

Creates a fresh batch SupervisedLearner for every candidate window and final fit. Each instance receives one learn call with the observations for that fit. Fitting state must be independent: later fits must not mutate previously returned models or any prediction-affecting state. A fresh wrapper around a shared mutable estimator is insufficient; immutable sharing is fine.

required
threshold float

Finite, non-negative maximum absolute prediction error. Candidate acceptance uses the strict comparison error < threshold.

required
start_width int

Positive initial window size in consecutive observations.

10
step_width int

Positive number of observations added at each window step.

5
callback HyDRACallback | None

Observer for discovery progress; defaults to a no-op HyDRACallback.

None
Attributes
regressor_factory instance-attribute
regressor_factory: Callable[[], SupervisedLearner] = regressor_factory
threshold instance-attribute
threshold: float = threshold
start_width instance-attribute
start_width: int = start_width
step_width instance-attribute
step_width: int = step_width
callback instance-attribute
callback: HyDRACallback = callback if callback is not None else HyDRACallback()
Methods:
learn
learn(traces: Sequence[DataFrame], *, input_features: Sequence[str], output_features: Sequence[str]) -> LearnedFlows

Discover flows and return their models and observation membership.

Parameters:

Name Type Description Default
traces Sequence[DataFrame]

Nonempty collection of nonempty Polars frames in observation order. Each frame is an independent trace. Additional columns can be retained when projecting the result onto these frames.

required
input_features Sequence[str]

Nonempty, unique input column names.

required
output_features Sequence[str]

Exactly one target column, distinct from inputs.

required

Selected columns must contain finite numeric values with no nulls. flow_id is reserved for assignments and must be absent from frames and feature lists. Selected observations and backend predictions use Polars Float64 as their computational representation for fitting and residuals, not as a precision improvement. Decimal values and large integers can collapse to the same Float64 value. Original frames are unchanged.

Returns:

Type Description
LearnedFlows

Models and segments assigning every supplied observation to a flow.

Raises:

Type Description
ValueError

Data or feature roles violate the stated constraints.

TypeError

A supplied trace is not a Polars DataFrame.

HyDRAIdentificationError

A pending segment cannot be identified. Its segment identifies the failing trace and row bounds.

Backend and callback exceptions propagate to the caller.

LearnedFlow dataclass

LearnedFlow(model: Model, segments: tuple[TraceSegment, ...])

A fitted model and the observation segments accepted by its candidate.

Segments use half-open row bounds and are ordered by trace, then row. Membership is recorded before the final model refit.

Attributes
model instance-attribute
model: Model
segments instance-attribute
segments: tuple[TraceSegment, ...]

LearnedFlows dataclass

LearnedFlows(flows: tuple[LearnedFlow, ...], trace_lengths: tuple[int, ...], input_features: tuple[str, ...], output_features: tuple[str, ...])

Discovered flows and their membership in the supplied observations.

Parameters:

Name Type Description Default
flows tuple[LearnedFlow, ...]

Fitted models with accepted segments. A flow's position is its shared flow ID across all traces.

required
trace_lengths tuple[int, ...]

Row counts in the original trace order.

required
input_features tuple[str, ...]

Ordered input column names used for fitting.

required
output_features tuple[str, ...]

Output column names used for fitting.

required

Accepted segments cover every supplied observation exactly once. Use to_labeled_frames(original_traces) to train a selector, or to_flow_ids() for row-aligned NumPy assignments.

Attributes
flows instance-attribute
flows: tuple[LearnedFlow, ...]
trace_lengths instance-attribute
trace_lengths: tuple[int, ...]
input_features instance-attribute
input_features: tuple[str, ...]
output_features instance-attribute
output_features: tuple[str, ...]
Methods:
to_flow_ids
to_flow_ids() -> list[ndarray]

Return fresh, fully populated int64 arrays of row assignments.

to_labeled_frames
to_labeled_frames(traces: Sequence[DataFrame]) -> list[DataFrame]

Add an Int64 flow_id column to each supplied frame.

Frames must match the original trace count, row counts, and positional order. All existing columns are preserved; every row has a flow ID.

TraceSegment dataclass

TraceSegment(trace_index: int, start: int, stop: int)

Consecutive observations within a trace: start inclusive, stop exclusive.

Parameters:

Name Type Description Default
trace_index int

Index in the supplied trace collection.

required
start int

Index of the first included observation.

required
stop int

Index just past the last observation.

required
Attributes
trace_index instance-attribute
trace_index: int
start instance-attribute
start: int
stop instance-attribute
stop: int

HyDRAModel

HyDRAModel(flow_models: list[Model], *, input_features: Sequence[str], output_features: Sequence[str], selector: HybridDecisionTreeModel | None = None, trace_schema: HyDRATraceSchema | None = None)

Bases: Model

Model composed of learned flow models and an optional selector.

A single-flow model predicts directly with that flow model. A multi-flow model needs a selector for batch prediction. Supply a trace schema for derivative rollout. Persistence uses pickle: load models only from trusted sources.

Attributes
flow_models instance-attribute
flow_models = flow_models
input_features instance-attribute
input_features = list(input_features)
output_features instance-attribute
output_features = list(output_features)
selector instance-attribute
selector = selector
trace_schema instance-attribute
trace_schema = trace_schema
Methods:
predict_with_diagnostics
predict_with_diagnostics(input_features: DataFrame | LazyFrame) -> HyDRABatchPrediction

Route observations to flow models and retain row alignment details.

Parameters:

Name Type Description Default
input_features DataFrame | LazyFrame

Frame containing all flow inputs and selector features. Flow inputs are converted to Float64 for prediction.

required

Returns:

Type Description
HyDRABatchPrediction

Predicted outputs, original row indices, and selector decisions.

HyDRABatchPrediction

History-based selectors begin after their required warmup rows.

HyDRABatchPrediction

Selectors using previous-flow features require the stateful

HyDRABatchPrediction

selector runtime.

simulate
simulate(t_span: tuple[float, float], x0: Iterable[float], *, input_stream: InputStream | None = None, include_inputs: bool = False, sample_times: Iterable[float] | None = None, sample_dt: float | None = None, rtol: float = 1e-07, atol: float = 1e-09, max_step: float | None = None) -> DataFrame

Integrate a learned derivative model on the requested time grid.

Requires a trace schema with matching state and derivative widths, and an input stream for any external inputs. Multi-flow models require a selector using current time, state, and external input features.

Select a flow at each grid point, including the final endpoint, and integrate it until the next point. The chosen grid therefore determines when flow changes can occur.

Returns:

Type Description
DataFrame

Sampled frame with t, state columns x0, x1, etc.,

DataFrame

flow_id for the selected model, and flow_time for the time

DataFrame

since it became active. With include_inputs=True, also includes

DataFrame

external input columns u0, u1, etc.

predict_next_state
predict_next_state(state: Iterable[float], *, t: float, dt: float, input_stream: InputStream | None = None, rtol: float = 1e-07, atol: float = 1e-09, max_step: float | None = None) -> ndarray

PlotCallback

PlotCallback(frame: DataFrame, *, columns: Sequence[str], time_column: str | None = None, trace_index: int = 0, ax: Axes | None = None, show: bool = True, pause: float = 0.001)

Bases: HyDRACallback

Plot selected trace columns and discovery segments live.

Attributes
columns instance-attribute
columns = list(columns)
frame instance-attribute
frame = frame
time_column instance-attribute
time_column = time_column
trace_index instance-attribute
trace_index = trace_index
ax instance-attribute
ax = ax
show instance-attribute
show = show
pause instance-attribute
pause = pause
Methods:
start
start(*, trace_count: int, threshold: float, start_width: int, step_width: int) -> None
pending_segment_found
pending_segment_found(segment: TraceSegment) -> None
candidate_window_evaluated
candidate_window_evaluated(*, segment: TraceSegment, fit: float) -> None
candidate_selected
candidate_selected(*, segment: TraceSegment, fit: float) -> None
grouping_evaluated
grouping_evaluated(*, flow_id: int, accepted_segments: tuple[TraceSegment, ...], considered_count: int) -> None
flow_finalized
flow_finalized(*, flow_id: int, flow: LearnedFlow) -> None
finish
finish(result: LearnedFlows) -> None

HyDRATraceSchema dataclass

HyDRATraceSchema(time: str, state: tuple[str, ...], derivative: tuple[str, ...], inputs: tuple[str, ...] = ())

Column roles for a learned derivative model and its rollout.

Parameters:

Name Type Description Default
time str

Time column name.

required
state tuple[str, ...]

State column names used as model inputs.

required
derivative tuple[str, ...]

Derivative column names used as model outputs, in the same order as their corresponding state columns.

required
inputs tuple[str, ...]

Optional external input column names.

()

All column names must be distinct. input_features collects the time, state, and external input columns. Rollout requires equal numbers of state and derivative columns.

Attributes
time instance-attribute
time: str
state instance-attribute
state: tuple[str, ...]
derivative instance-attribute
derivative: tuple[str, ...]
inputs class-attribute instance-attribute
inputs: tuple[str, ...] = ()
input_features property
input_features: tuple[str, ...]
Methods:
validate_input_features
validate_input_features(input_features: Sequence[str]) -> None
validate_output_features
validate_output_features(output_features: Sequence[str]) -> None
validate_state_derivative_width
validate_state_derivative_width() -> None

FlowPredictionResult dataclass

FlowPredictionResult(ready: bool, flow_id: int | None, probabilities: dict[int, float] = dict(), leaf_id: int | None = None, flow_model: Model | None = None)
Attributes
ready instance-attribute
ready: bool
flow_id instance-attribute
flow_id: int | None
probabilities class-attribute instance-attribute
probabilities: dict[int, float] = field(default_factory=dict)
leaf_id class-attribute instance-attribute
leaf_id: int | None = None
flow_model class-attribute instance-attribute
flow_model: Model | None = None

HybridDecisionTreeLearner

HybridDecisionTreeLearner(feature_config: SelectorFeatureConfig, **tree_kwargs: Any)

Bases: SupervisedLearner

Attributes
classifier instance-attribute
classifier: DecisionTreeClassifier = DecisionTreeClassifier(**classifier_kwargs)
feature_config instance-attribute
feature_config = feature_config
Methods:
learn
learn(inputs: DataFrame | LazyFrame, outputs: DataFrame | LazyFrame) -> HybridDecisionTreeModel
learn_from_traces
learn_from_traces(traces: list[DataFrame], flow_models_by_id: dict[int, Model] | None = None) -> HybridDecisionTreeModel

HybridDecisionTreeModel

HybridDecisionTreeModel(classifier: DecisionTreeClassifier, feature_columns: tuple[str, ...], feature_config: SelectorFeatureConfig, flow_models_by_id: dict[int, Model] | None = None)

Bases: Model

Attributes
classifier instance-attribute
classifier = classifier
feature_columns instance-attribute
feature_columns = feature_columns
feature_config instance-attribute
feature_config = feature_config
flow_models_by_id instance-attribute
flow_models_by_id = flow_models_by_id or {}
Methods:
predict_details
predict_details(input_features: DataFrame | LazyFrame) -> list[FlowPredictionResult]
resolve_flow
resolve_flow(flow_id: int) -> Model | None
feature_importances
feature_importances() -> dict[str, float]
tree_text
tree_text() -> str
summary_text
summary_text() -> str
leaf_summary_text
leaf_summary_text() -> str
flow_summary_text
flow_summary_text() -> str
to_dot
to_dot() -> str
to_svg
to_svg() -> str
save_svg
save_svg(path: str | Path) -> None
debug_prediction_text
debug_prediction_text(input_features: DataFrame | LazyFrame) -> str
inspect
inspect() -> SelectorInspection

SelectorEvaluationReport dataclass

SelectorEvaluationReport(accuracy: float, samples: int, confusion_matrix: DataFrame)
Attributes
accuracy instance-attribute
accuracy: float
samples instance-attribute
samples: int
confusion_matrix instance-attribute
confusion_matrix: DataFrame

SelectorFeatureConfig dataclass

SelectorFeatureConfig(state_features: tuple[str, ...] = (), input_features: tuple[str, ...] = (), derivative_features: tuple[str, ...] = (), state_history: int = 0, input_history: int = 0, derivative_history: int = 0, flow_history: int = 0)

Configuration for selector feature construction.

Parameters:

Name Type Description Default
state_features tuple[str, ...]

State columns available to the selector.

()
input_features tuple[str, ...]

Raw input columns available to the selector.

()
derivative_features tuple[str, ...]

Derivative columns available to the selector.

()
state_history int

Number of previous state rows used for selector features.

0
input_history int

Number of previous input rows used for selector features.

0
derivative_history int

Number of previous derivative rows used for selector features.

0
flow_history int

Number of previous flow IDs used for selector features.

0
Attributes
state_features class-attribute instance-attribute
state_features: tuple[str, ...] = ()
input_features class-attribute instance-attribute
input_features: tuple[str, ...] = ()
derivative_features class-attribute instance-attribute
derivative_features: tuple[str, ...] = ()
state_history class-attribute instance-attribute
state_history: int = 0
input_history class-attribute instance-attribute
input_history: int = 0
derivative_history class-attribute instance-attribute
derivative_history: int = 0
flow_history class-attribute instance-attribute
flow_history: int = 0
max_history property
max_history: int
Methods:
required_columns
required_columns() -> tuple[str, ...]
validate
validate() -> None

SelectorFlowInspection dataclass

SelectorFlowInspection(flow_id: int, weighted_support: float, flow_summary: str)
Attributes
flow_id instance-attribute
flow_id: int
weighted_support instance-attribute
weighted_support: float
flow_summary instance-attribute
flow_summary: str

SelectorInspection dataclass

SelectorInspection(feature_columns: tuple[str, ...], classes: tuple[int, ...], max_depth: int, n_leaves: int, nodes: tuple[SelectorNodeInspection, ...], leaves: tuple[SelectorLeafInspection, ...], flows: tuple[SelectorFlowInspection, ...])
Attributes
feature_columns instance-attribute
feature_columns: tuple[str, ...]
classes instance-attribute
classes: tuple[int, ...]
max_depth instance-attribute
max_depth: int
n_leaves instance-attribute
n_leaves: int
nodes instance-attribute
nodes: tuple[SelectorNodeInspection, ...]
leaves instance-attribute
leaves: tuple[SelectorLeafInspection, ...]
flows instance-attribute
flows: tuple[SelectorFlowInspection, ...]

SelectorLeafInspection dataclass

SelectorLeafInspection(node_id: int, flow_id: int, sample_count: int, weighted_class_support: dict[int, float], flow_summary: str)
Attributes
node_id instance-attribute
node_id: int
flow_id instance-attribute
flow_id: int
sample_count instance-attribute
sample_count: int
weighted_class_support instance-attribute
weighted_class_support: dict[int, float]
flow_summary instance-attribute
flow_summary: str

SelectorNodeInspection dataclass

SelectorNodeInspection(node_id: int, sample_count: int, impurity: float, is_leaf: bool, predicted_flow_id: int, weighted_class_support: dict[int, float], feature_index: int | None = None, feature_name: str | None = None, threshold: float | None = None, left_child_id: int | None = None, right_child_id: int | None = None)
Attributes
node_id instance-attribute
node_id: int
sample_count instance-attribute
sample_count: int
impurity instance-attribute
impurity: float
is_leaf instance-attribute
is_leaf: bool
predicted_flow_id instance-attribute
predicted_flow_id: int
weighted_class_support instance-attribute
weighted_class_support: dict[int, float]
feature_index class-attribute instance-attribute
feature_index: int | None = None
feature_name class-attribute instance-attribute
feature_name: str | None = None
threshold class-attribute instance-attribute
threshold: float | None = None
left_child_id class-attribute instance-attribute
left_child_id: int | None = None
right_child_id class-attribute instance-attribute
right_child_id: int | None = None

StatefulHybridDecisionTreeSelector

StatefulHybridDecisionTreeSelector(model: HybridDecisionTreeModel, seed_flows: Sequence[int] = ())
Attributes
model instance-attribute
model = model
config instance-attribute
config = model.feature_config
Methods:
predict
predict(sample: Mapping[str, Any]) -> FlowPredictionResult

StateTraceComparison dataclass

StateTraceComparison(absolute_error: ndarray, mae: float, rmse: float, max_error: float)
Attributes
absolute_error instance-attribute
absolute_error: ndarray
mae instance-attribute
mae: float
rmse instance-attribute
rmse: float
max_error instance-attribute
max_error: float

Functions:

evaluate_selector_autoregressive

evaluate_selector_autoregressive(model: HybridDecisionTreeModel, traces: list[DataFrame], seed_flows: tuple[int, ...] | list[int] = ()) -> SelectorEvaluationReport

evaluate_selector_oracle

evaluate_selector_oracle(model: HybridDecisionTreeModel, traces: list[DataFrame]) -> SelectorEvaluationReport

compare_state_traces

compare_state_traces(reference_frame: DataFrame, predicted_frame: DataFrame, *, state_columns: Sequence[str] | None = None) -> StateTraceComparison

Compare matching grids and ordered states; select renamed states explicitly.