Monitor¶
The monitor subsystem provides 30+ dynamical observers plus STL runtime monitoring for different aspects of oscillator network behavior. Most oscillator simulators provide only the global order parameter R. SPO's monitors detect chimera states, cross-frequency coupling, causal information flow, topological invariants, and thermodynamic irreversibility — phenomena that R alone cannot capture.
Detailed module references:
Hybrid Classical-Quantum Order Parameter¶
compute_hybrid_entanglement_order_parameter() evaluates local quantum
co-simulation evidence only. It combines Kuramoto R/Psi with bipartition
Von Neumann entropy, normalised entropy, participation ratio, deterministic
record hashing, and the
quantum_cosimulation_monitor_not_qpu_execution claim boundary.
The monitor now accepts an explicit simulator_backend contract:
numpy_statevector_density_matrix: default compatibility path accepting either statevectors or density matrices.numpy_statevector: requires a one-dimensional statevector payload.numpy_density_matrix: requires a square Hermitian positive-semidefinite density matrix payload representing a pure state. Mixed-state reduced entropy is not promoted as entanglement evidence.
All backends are local NumPy simulators. They do not execute QPU workloads, apply controls, or promote simulator evidence to hardware evidence.
Phase and quantum arrays are validated without text, boolean, or complex-to-real coercion, and malformed array protocols fail at the monitor boundary. Published results independently replay scalar domains, bipartition coverage, entropy normalisation, participation bounds, simulator/no-QPU flags, and the canonical record hash, so direct construction cannot fabricate contradictory audit evidence.
hybrid_order ¶
Classical+quantum co-simulation order monitor.
Computes Kuramoto synchrony and qubit-partition entanglement entropy from either statevectors or density matrices using NumPy only.
Classes¶
HybridOrderParameterResult
dataclass
¶
HybridOrderParameterResult(
R: float,
Psi: float,
entanglement_entropy: float,
normalised_entanglement_entropy: float,
participation_ratio: float,
qubit_count: int,
bipartition: tuple[tuple[int, ...], tuple[int, ...]],
backend: str,
claim_boundary: str,
non_actuating: bool,
execution_disabled: bool,
record_hash: str,
)
Result of a hybrid classical-quantum order-parameter evaluation.
Methods:¶
__post_init__ ¶
Validate and normalize immutable published evidence.
Source code in src/scpn_phase_orchestrator/monitor/hybrid_order.py
to_audit_record ¶
Return a JSON-safe audit record.
Returns¶
dict[str, object] Return a JSON-safe audit record.
Source code in src/scpn_phase_orchestrator/monitor/hybrid_order.py
Functions:¶
compute_hybrid_entanglement_order_parameter ¶
compute_hybrid_entanglement_order_parameter(
phases: FloatArray,
quantum_state: object,
*,
qubit_count: int | None = None,
bipartition: tuple[tuple[int, ...], tuple[int, ...]]
| None = None,
simulator_backend: str = BACKEND,
) -> HybridOrderParameterResult
Compute classical R/Psi and the entanglement-aware hybrid order metric.
Parameters¶
phases : FloatArray
Classical phase data.
quantum_state : object
Vector of length 2**n or density matrix shape (2**n, 2**n).
qubit_count : int | None
Optional explicit qubit-count override; must match the state.
bipartition : tuple[tuple[int, ...], tuple[int, ...]] | None
Optional pair of qubit index groups for reduced entropy.
simulator_backend : str
Explicit local simulator contract. The default accepts either statevector or
density-matrix NumPy inputs; "numpy_statevector" and
"numpy_density_matrix" require the corresponding payload shape and record
that backend explicitly.
Returns¶
HybridOrderParameterResult HybridOrderParameterResult with a deterministic audit record hash.
Raises¶
ValueError If the quantum state or bipartition is invalid.
Source code in src/scpn_phase_orchestrator/monitor/hybrid_order.py
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | |
Hybrid Order Scenario Fixtures¶
build_hybrid_order_parameter_scenarios() emits deterministic review fixtures
for quantum-simulation, power-grid, and cardiac-rhythm examples. Scenario and
candidate records are JSON-safe, non-actuating, execution-disabled, and carry
the same no-QPU claim boundary for Studio and audit use.
Fixture entropy is computed from the declared bipartition's Schmidt spectrum, not from computational-basis probabilities. Validation replays each candidate's unit-normalised amplitudes, entropy, phase-derived order metrics, unique identity, and scenario hash; coercive phase aliases cannot enter review evidence.
hybrid_order_examples ¶
Deterministic scenario fixtures for quantum co-simulation audit evidence.
The fixtures model hybrid order-parameter audits (entanglement entropy plus classical synchrony metrics) for non-actuating review workflows.
Classes¶
HybridStateCandidate
dataclass
¶
HybridStateCandidate(
state_id: str,
candidate_type: str,
amplitudes: ComplexArray,
entanglement_entropy: float,
order_metric_r: float,
order_metric_psi: float,
objective_labels: tuple[str, ...],
non_actuating: bool = True,
execution_disabled: bool = True,
claim_boundary: str = HybridBoundary,
)
Deterministic candidate state description for a scenario.
HybridOrderScenario
dataclass
¶
HybridOrderScenario(
domain: str,
scenario_id: str,
phases: FloatArray,
qubit_count: int,
bipartition: tuple[tuple[int, ...], tuple[int, ...]],
state_candidates: tuple[HybridStateCandidate, ...],
objective_labels: tuple[str, ...],
non_actuating: bool = True,
execution_disabled: bool = True,
claim_boundary: str = HybridBoundary,
scenario_hash: str = "",
)
One deterministic scenario with review-safe outputs.
Functions:¶
build_hybrid_order_parameter_scenarios ¶
Return deterministic, JSON-safe hybrid order-parameter scenarios.
Returns¶
tuple[dict[str, object], ...] Return deterministic, JSON-safe hybrid order-parameter scenarios.
Source code in src/scpn_phase_orchestrator/monitor/hybrid_order_examples.py
Boundary Observer¶
Detects when oscillator dynamics violate configured safety/performance
boundaries. Fires alerts when R drops below R_good threshold or
exceeds R_bad threshold. Used by the supervisor to trigger regime
transitions.
boundaries ¶
Boundary observer utilities for compartment and event-bus safety checks.
The observer evaluates declared soft and hard partitions against runtime state without mutating the monitored values. Missing state variables are ignored so partially observed deployments can still emit useful diagnostics, while unknown severity policy is treated as a fail-hard configuration error before monitoring starts. Events are emitted through the supplied bus only after checks are classified, preserving a clear separation between detection and actuation.
Classes¶
BoundaryState
dataclass
¶
BoundaryState(
violations: list[str] = list(),
soft_violations: list[str] = list(),
hard_violations: list[str] = list(),
)
Snapshot of boundary violations partitioned by severity.
BoundaryObserver ¶
Check measured values against boundary definitions.
Source code in src/scpn_phase_orchestrator/monitor/boundaries.py
Methods:¶
set_event_bus ¶
Attach an event bus for posting boundary_breach events.
Parameters¶
event_bus : EventBus
Event bus for posting boundary_breach events.
Raises¶
TypeError
If event_bus is not an EventBus.
Source code in src/scpn_phase_orchestrator/monitor/boundaries.py
observe ¶
Evaluate scalar measurements against configured boundaries.
Parameters¶
values
Mapping from monitored variable name to the current scalar
measurement.
step
Optional supervisor step attached to any posted
boundary_breach event. When omitted, the observer reuses
its previous step counter.
Returns¶
BoundaryState Partitioned violation snapshot containing all violations plus soft and hard subsets.
Notes¶
Missing variables are ignored. Unknown severities are logged and treated as hard violations so safety-critical callers fail closed.
Raises¶
TypeError
If values is not a metric mapping.
ValueError
If a measurement is non-finite.
Source code in src/scpn_phase_orchestrator/monitor/boundaries.py
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | |
Coherence Monitor¶
Tracks the Kuramoto order parameter R over time with configurable
thresholds for phase-lock detection. Provides R_good (target coherence)
and R_bad (harmful mode-locking) as dual objectives.
coherence ¶
Coherence partition monitoring utilities for layer-bound phase states.
This module computes in-group and out-group Kuramoto-style locking metrics, including R_good/R_bad summaries and PLV-based lock detection. Configuration objects validate layer indices, threshold intervals, CLA terms, and denominator semantics before analysis; invalid layer references fail early instead of being silently clipped into a different biological partition.
Classes¶
CoherenceMonitor ¶
Track coherence partitioned into good vs bad layer subsets.
Source code in src/scpn_phase_orchestrator/monitor/coherence.py
Methods:¶
compute_r_good ¶
Mean order parameter R across good (synchronise) layers.
Parameters¶
upde_state : UPDEState The UPDE state to evaluate.
Returns¶
float
The mean order parameter R over the maintain (good) layers.
Source code in src/scpn_phase_orchestrator/monitor/coherence.py
compute_r_bad ¶
Mean order parameter R across bad (desynchronise) layers.
Parameters¶
upde_state : UPDEState The UPDE state to evaluate.
Returns¶
float
The mean order parameter R over the suppress (bad) layers.
Source code in src/scpn_phase_orchestrator/monitor/coherence.py
detect_phase_lock ¶
Return pairs of layer indices whose PLV exceeds threshold.
Uses cross_layer_alignment matrix as the primary PLV source (matches Rust implementation). Falls back to lock_signatures if CLA entry is below threshold but a signature overrides it.
Parameters¶
upde_state : UPDEState The UPDE state to evaluate. threshold : float Decision threshold.
Returns¶
list[tuple[int, int]] The layer-index pairs whose PLV exceeds the threshold.
Raises¶
TypeError
If upde_state is not a diagnostic state.
ValueError
If state structure, alignment evidence, threshold, or a consulted
fallback lock signature violates its public contract.
Source code in src/scpn_phase_orchestrator/monitor/coherence.py
Session Start Gate¶
Verifies that the oscillator network reaches a minimum coherence threshold before the main control loop engages. Prevents the supervisor from acting on transient startup dynamics.
The gate is fail-closed on malformed evidence: phase and imprint vectors
must be one-dimensional real numeric arrays with finite entries and the
expected oscillator count, and extractor quality values must be finite
floats in [0, 1]. Any violation is recorded as a report error and fails
the gate; an invalid n_osc raises instead of reporting.
session_start ¶
Session-start validation gate for extractor, imprint, and coherence inputs.
The validator checks startup preconditions across extractor quality signals, imprint availability, and initial coherence metrics before a session is allowed to proceed. It returns explicit warnings and errors without mutating source state or triggering actuation, keeping the gate suitable for dry-run previews, operator review, and fail-closed orchestration handoffs.
The gate is fail-closed on malformed evidence: phase and imprint vectors must
be one-dimensional real numeric arrays with finite entries and the expected
oscillator count, and extractor quality values must be finite floats in
[0, 1]. Any violation is recorded as an error and fails the gate rather
than being silently skipped; quality scoring and coherence metrics are only
computed from evidence that passed validation. n_osc is a caller-supplied
structural parameter, so an invalid n_osc raises instead of reporting.
Classes¶
SessionCoherenceReport
dataclass
¶
SessionCoherenceReport(
quality_scores: dict[str, float] = dict(),
initial_r: float = 0.0,
imprint_level: float = 0.0,
warnings: list[str] = list(),
errors: list[str] = list(),
passed: bool = True,
)
Results of the session-start coherence gate check.
Functions:¶
check_session_start ¶
check_session_start(
phase_states: list[PhaseState],
initial_phases: FloatArray,
imprint_state: ImprintState,
n_osc: int,
) -> SessionCoherenceReport
Validate extraction quality, imprint consistency, and initial coherence.
Parameters¶
phase_states : list[PhaseState] extracted states from all configured channels. initial_phases : FloatArray phase array that will seed the UPDE engine. imprint_state : ImprintState loaded (or fresh) imprint state. n_osc : int expected oscillator count; must be a positive int.
Returns¶
SessionCoherenceReport SessionCoherenceReport with pass/fail, quality scores, and diagnostics.
Raises¶
TypeError
If n_osc is not an int (bool excluded).
ValueError
If n_osc is not positive.
Source code in src/scpn_phase_orchestrator/monitor/session_start.py
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | |
Merge Window Monitor¶
MergeWindowMonitor is the PHA-C.4 gate for moving-frame runs where phase lock
and axial position lock must both hold before a merge is accepted. It computes
wrapped phase dispersion around theta_ref, axial spatial dispersion around
z_ref, and a consecutive joint-lock counter. The monitor reports
lock_achieved=True only after the configured number of consecutive samples
passes both predicates.
See the Merge Window reference for the contract, use cases, and benchmark command.
merge_window ¶
Phase-and-space merge-window lock monitor.
The PHA-C moving-frame lane tracks phase theta and axial position z for
candidate merger/coalescence events. A merge is accepted only when both the
wrapped phase dispersion and the axial spatial dispersion remain inside their
reviewed tolerances for a configured number of consecutive samples.
Classes¶
MergeWindowToleranceProfile
dataclass
¶
MergeWindowToleranceProfile(
name: str,
phase_tol_rad: float,
spatial_tol_m: float,
multiplier: float,
baseline_phase_tol_rad: float,
baseline_spatial_tol_m: float,
)
Resolved phase and spatial tolerances for a PHA-C merge window.
Methods:¶
__post_init__ ¶
Validate and normalise the resolved named-profile evidence.
Source code in src/scpn_phase_orchestrator/monitor/merge_window.py
MergeReport
dataclass
¶
MergeReport(
t: float,
phase_dispersion_rad: float,
spatial_dispersion_m: float,
phase_margin_rad: float,
spatial_margin_m: float,
phase_locked: bool,
spatial_locked: bool,
lock_achieved: bool,
consecutive_lock_samples: int,
)
Audit-ready merge-window state for one sampled instant.
Attributes¶
t: Sample timestamp in the caller's runtime units.
phase_dispersion_rad: Maximum wrapped distance to the reference phase.
spatial_dispersion_m: Maximum axial distance to the reference point.
phase_margin_rad: Signed distance from phase tolerance to dispersion.
spatial_margin_m: Signed distance from spatial tolerance to dispersion.
phase_locked: True when phase margin is non-negative.
spatial_locked: True when spatial margin is non-negative.
lock_achieved: True after the required consecutive joint-lock count.
consecutive_lock_samples: Current consecutive joint-lock count.
Methods:¶
__post_init__ ¶
Validate and normalise directly constructed merge evidence.
Source code in src/scpn_phase_orchestrator/monitor/merge_window.py
MergeWindowMonitor ¶
MergeWindowMonitor(
*,
phase_tol_rad: object = DEFAULT_PHASE_TOL_RAD,
spatial_tol_m: object = DEFAULT_SPATIAL_TOL_M,
required_consecutive_samples: object = 3,
tolerance_profile: object | None = None,
)
Stateful consecutive-sample gate for PHA-C merge events.
Initialise the stateful merge gate.
Parameters¶
phase_tol_rad : object
Baseline phase tolerance in radians.
spatial_tol_m : object
Baseline spatial tolerance in metres.
required_consecutive_samples : object
Positive joint-lock sample count required for acceptance.
tolerance_profile : object | None
Reviewed named tolerance profile, or None for explicit values.
Raises¶
ValueError If a tolerance, count, or named-profile contract is invalid.
Source code in src/scpn_phase_orchestrator/monitor/merge_window.py
Attributes¶
consecutive_lock_samples
property
¶
Methods:¶
reset ¶
evaluate ¶
evaluate(
phases: ArrayLike,
positions: ArrayLike,
*,
t: object = 0.0,
reference_phase: object = 0.0,
reference_point: object = 0.0,
) -> MergeReport
Evaluate one sample and update the consecutive joint-lock counter.
Parameters¶
phases : ArrayLike
Oscillator phases in radians, shape (N,).
positions : ArrayLike
Absolute axial coordinates per oscillator, shape (N,).
t : object
Absolute time of the sample in seconds.
reference_phase : object
Reference phase for the lock criterion, in radians.
reference_point : object
Reference axial coordinate for the spatial-margin criterion.
Returns¶
MergeReport The merge-window report with the updated lock counter.
Source code in src/scpn_phase_orchestrator/monitor/merge_window.py
__call__ ¶
__call__(
phases: ArrayLike,
positions: ArrayLike,
*,
t: object = 0.0,
reference_phase: object = 0.0,
reference_point: object = 0.0,
) -> MergeReport
Alias for :meth:evaluate for monitor-pipeline call sites.
Source code in src/scpn_phase_orchestrator/monitor/merge_window.py
Functions:¶
resolve_merge_window_tolerance_profile ¶
resolve_merge_window_tolerance_profile(
tolerance_profile: object,
*,
phase_baseline_rad: object = DEFAULT_PHASE_TOL_RAD,
spatial_baseline_m: object = DEFAULT_SPATIAL_TOL_M,
) -> MergeWindowToleranceProfile
Resolve a named PHA-C tolerance profile into numeric tolerances.
Parameters¶
tolerance_profile : object
Named tolerance profile, or None for the baseline.
phase_baseline_rad : object
Baseline phase tolerance in radians.
spatial_baseline_m : object
Baseline spatial tolerance in metres.
Returns¶
MergeWindowToleranceProfile The resolved numeric tolerance profile.
Source code in src/scpn_phase_orchestrator/monitor/merge_window.py
evaluate_merge_window ¶
evaluate_merge_window(
phases: ArrayLike,
positions: ArrayLike,
*,
t: object = 0.0,
reference_phase: object = 0.0,
reference_point: object = 0.0,
phase_tol_rad: object = DEFAULT_PHASE_TOL_RAD,
spatial_tol_m: object = DEFAULT_SPATIAL_TOL_M,
required_consecutive_samples: object = 3,
prior_consecutive_lock_samples: object = 0,
tolerance_profile: object | None = None,
) -> MergeReport
Evaluate one PHA-C merge-window sample.
Phase lock is max_i |wrap(theta_i - theta_ref)| <= phase_tol_rad.
Spatial lock is max_i |z_i - z_ref| <= spatial_tol_m. The combined lock
counter increments only when both predicates pass; otherwise it resets to
zero. lock_achieved becomes true once the counter reaches
required_consecutive_samples.
Parameters¶
phases : ArrayLike
Oscillator phases in radians, shape (N,).
positions : ArrayLike
Absolute axial coordinates per oscillator, shape (N,).
t : object
Absolute time of the sample in seconds.
reference_phase : object
Reference phase for the lock criterion, in radians.
reference_point : object
Reference axial coordinate for the spatial-margin criterion.
phase_tol_rad : object
Phase lock tolerance in radians.
spatial_tol_m : object
Spatial lock tolerance in metres.
required_consecutive_samples : object
Consecutive in-tolerance samples required to declare lock.
prior_consecutive_lock_samples : object
Consecutive lock-sample count carried in from a prior window.
tolerance_profile : object | None
Named tolerance profile, or None for the baseline.
Returns¶
MergeReport The merge-window evaluation report for the sample.
Raises¶
ValueError If any input is invalid.
Source code in src/scpn_phase_orchestrator/monitor/merge_window.py
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 | |
merge_window_report_to_dict ¶
Convert a :class:MergeReport into a JSON-safe dictionary.
Parameters¶
report : MergeReport The merge-window report to serialise.
Returns¶
dict[str, float | int | bool] The JSON-safe merge-window report dictionary.
Source code in src/scpn_phase_orchestrator/monitor/merge_window.py
merge_window_tolerance_profile_to_dict ¶
merge_window_tolerance_profile_to_dict(
profile: MergeWindowToleranceProfile,
) -> dict[str, float | str]
Convert a resolved tolerance profile into a JSON-safe dictionary.
Parameters¶
profile : MergeWindowToleranceProfile The resolved tolerance profile to serialise.
Returns¶
dict[str, float | str] The JSON-safe tolerance-profile dictionary.
Source code in src/scpn_phase_orchestrator/monitor/merge_window.py
Signal Temporal Logic Runtime Verification¶
STLMonitor evaluates runtime safety formulas over scalar monitor traces.
It uses rtamt when available for full STL syntax and includes a builtin
robustness evaluator for common safety forms:
always (R >= 0.3)eventually (R >= 0.8)always (R >= 0.85 and amplitude_spread < 0.2)always[0,20] (R >= 0.3)— bounded, holds over the next 20 stepseventually[0,50] (R >= 0.8)— bounded, holds within the next 50 steps
The bounded operators always[a,b] / eventually[a,b] take an integer
discrete step window (0 <= a <= b) and reduce the pointwise robustness over
that window at the initial time, clamped to the trace end — the value matches
what rtamt reports at time zero, so the result is identical whether or not
rtamt is installed. A window that starts past the trace end is a vacuous
quantifier: always yields +inf and eventually yields -inf. until,
nested temporal operators, and other syntax still require the optional rtamt
backend and raise a clear ImportError when it is absent.
Positive robustness means the formula is satisfied; negative robustness
means violated. evaluate_result() returns an audit-ready result with
the formula, robustness, satisfaction boolean, and backend name.
Trace signals are validated at the public boundary before builtin evaluation,
rtamt handoff, automaton synthesis, controller synthesis, or closed-loop
planning. Each signal must be a one-dimensional, finite, real-valued numeric
sequence with no boolean aliases; complex/object-complex payloads and NaN/Inf
samples are rejected because they do not define ordered STL predicate
robustness.
from scpn_phase_orchestrator.monitor.stl import STLMonitor
monitor = STLMonitor("always (R >= 0.3)")
result = monitor.evaluate_result({"R": [0.9, 0.8, 0.6]})
assert result.satisfied
synthesise_stl_monitoring_automaton() converts supported builtin formulas
into an audit-ready runtime automaton. The automaton records the state
sequence, trace-indexed transitions, first violation or satisfaction index,
pointwise robustness margins, and final satisfaction result.
from scpn_phase_orchestrator.monitor.stl import (
synthesise_stl_monitoring_automaton,
)
automaton = synthesise_stl_monitoring_automaton(
"always (R >= 0.3)",
{"R": [0.9, 0.2, 0.6]},
)
audit_payload = automaton.to_audit_record()
assert audit_payload["states"][1]["first_hit_index"] == 1
Policy YAML integration is available through load_policy_stl_specs(),
evaluate_policy_stl_specs(), and synthesise_policy_stl_automata() in
scpn_phase_orchestrator.supervisor.policy_rules. This keeps STL
specification loading in the policy DSL while preserving STLMonitor and the
automata synthesizer as runtime evaluators.
synthesise_stl_controller_candidates() adds the first controller-synthesis
linkage. It consumes a builtin STL automaton plus the same trace and emits
non-actuating signal-level candidates for the weakest violated predicate.
The result is an audit/review artefact only: actuating is always False, and
callers must still pass any candidate through policy, projection, safety, and
actuation gates.
from scpn_phase_orchestrator.monitor.stl import (
synthesise_stl_controller_candidates,
)
synthesis = synthesise_stl_controller_candidates(
automaton,
{"R": [0.9, 0.2, 0.6]},
action_map={"R": "raise_coupling"},
)
audit_payload = synthesis.to_audit_record()
assert audit_payload["actuating"] is False
project_stl_controller_candidates() then maps those candidates through
explicit policy-approved projection templates and the standard
ActionProjector. It still returns a review plan only: actuating remains
False, unmapped candidates are rejected with reasons, and the approved
entries are bounded ControlAction proposals rather than applied commands.
from scpn_phase_orchestrator.monitor.stl import (
STLActionProjectionTemplate,
project_stl_controller_candidates,
)
plan = project_stl_controller_candidates(
synthesis,
(
STLActionProjectionTemplate(
action="raise_coupling",
knob="K",
scope="global",
base_value=0.9,
step=10.0,
ttl_s=0.5,
previous_value=0.9,
value_bounds=(0.0, 1.0),
rate_limit=0.05,
),
),
)
assert plan.to_audit_record()["actuating"] is False
synthesise_stl_closed_loop_plan() now also records a
runtime_actuation_gate audit section. The gate routes projected
ControlAction proposals through ActuationMapper using the same explicit
projection templates, records deterministic actuator-command evidence, and
keeps non_actuating plus execution_disabled true. This is the intended use
case for STL closed-loop planning: prove that a violated safety formula can be
translated into bounded, mapper-valid runtime actions for operator review
without enabling live actuation.
from scpn_phase_orchestrator.monitor.stl import (
synthesise_stl_closed_loop_plan,
)
closed_loop_plan = synthesise_stl_closed_loop_plan(
automaton,
{"R": [0.1, 0.2, 0.75]},
(projection_template,),
horizon_steps=4,
action_map={"R": "raise_coupling"},
)
gate = closed_loop_plan.to_audit_record()["runtime_actuation_gate"]
assert gate["execution_disabled"] is True
Curated phase-field specification catalogue¶
PHASE_FIELD_SPECIFICATIONS is a small, curated catalogue of named
single-signal safety properties for Kuramoto-type phase fields — an
order-parameter floor, a coupling-gain ceiling, a chimera-index ceiling, a
Sakaguchi phase-lag bound, and a winding-stability bound. Each
PhaseFieldSpecification renders a builtin-compatible STL formula, so it
evaluates without rtamt, and carries a physical rationale plus a soft/hard
severity tier. The thresholds are documented engineering defaults, not
empirically fitted constants: robustness measures runtime signal margin, it is
not a formal proof of correctness. Look one up by name with
phase_field_specification() and enumerate the keys with
phase_field_specification_names().
from scpn_phase_orchestrator.monitor.stl import phase_field_specification
spec = phase_field_specification("order_parameter_floor")
assert spec.spec == "always (R >= 0.3)"
result = spec.evaluate({"R": [0.9, 0.8, 0.6]})
assert result.satisfied and result.backend == "builtin"
stl ¶
Signal Temporal Logic monitor, synthesis, and runtime actuation gating.
rtamt is an optional dependency: pip install rtamt. The implementation is
split into responsibility modules (monitor, automaton synthesis, controller
synthesis, action projection, runtime actuation gate, and closed-loop plan)
behind a stable re-export surface; HAS_RTAMT reports rtamt availability.
Classes¶
STLRuntimeActuationGate
dataclass
¶
STLRuntimeActuationGate(
spec: str,
non_actuating: bool,
execution_disabled: bool,
accepted: bool,
action_count: int,
mapper_valid_action_count: int,
mapped_command_count: int,
commands: tuple[dict[str, object], ...],
blocked_reasons: tuple[str, ...],
)
Non-actuating runtime-stack validation of projected STL actions.
The gate verifies projected proposals against the same actuator mapping boundary used by runtime actuation, but it never enables execution. This makes the closed-loop STL plan auditable through the safety/actuation stack without converting a review artefact into a live controller command.
Methods:¶
to_audit_record ¶
Return a JSON-serialisable runtime gate record.
Returns¶
dict[str, object] Return a JSON-serialisable runtime gate record.
Source code in src/scpn_phase_orchestrator/monitor/stl/actuation_gate.py
STLAutomatonState
dataclass
¶
STLAutomatonState(
name: str,
accepting: bool,
violation: bool,
first_hit_index: int | None = None,
)
State in a synthesized STL monitoring automaton.
Methods:¶
to_audit_record ¶
Return a JSON-serialisable automaton-state payload.
Returns¶
dict[str, object] Return a JSON-serialisable automaton-state payload.
Source code in src/scpn_phase_orchestrator/monitor/stl/automaton.py
STLAutomatonTransition
dataclass
¶
Trace-indexed transition taken by a runtime STL automaton.
Methods:¶
to_audit_record ¶
Return a JSON-serialisable automaton-transition payload.
Returns¶
dict[str, object] Return a JSON-serialisable automaton-transition payload.
Source code in src/scpn_phase_orchestrator/monitor/stl/automaton.py
STLMonitoringAutomaton
dataclass
¶
STLMonitoringAutomaton(
spec: str,
temporal_op: str,
signals: tuple[str, ...],
states: tuple[STLAutomatonState, ...],
transitions: tuple[STLAutomatonTransition, ...],
robustness: float,
satisfied: bool,
backend: str = "builtin",
)
Audit-ready runtime automaton synthesized from a simple STL monitor.
Methods:¶
to_audit_record ¶
Return a JSON-serialisable STL automaton audit payload.
Returns¶
dict[str, object] Return a JSON-serialisable STL automaton audit payload.
Source code in src/scpn_phase_orchestrator/monitor/stl/automaton.py
STLClosedLoopSynthesisPlan
dataclass
¶
STLClosedLoopSynthesisPlan(
spec: str,
trace_length: int,
horizon_steps: int,
next_review_start_index: int,
next_review_end_index: int,
feedback_signals: tuple[str, ...],
satisfied: bool,
actuating: bool,
synthesis: STLControllerSynthesis,
projected_plan: STLProjectedActionPlan,
runtime_gate: STLRuntimeActuationGate,
blocked_reasons: tuple[str, ...],
)
Offline closed-loop STL controller plan for operator review.
The plan binds the current monitor state, signal feedback surface, projected action proposals, and next review horizon. It is intentionally non-actuating: callers must still pass approved actions through runtime policy, safety, and actuation gates before any live controller can use them.
Methods:¶
to_audit_record ¶
Return a JSON-serialisable closed-loop synthesis plan.
Returns¶
dict[str, object] Return a JSON-serialisable closed-loop synthesis plan.
Source code in src/scpn_phase_orchestrator/monitor/stl/closed_loop.py
STLControllerCandidate
dataclass
¶
STLControllerCandidate(
signal: str,
action: str,
direction: str,
time_index: int,
robustness: float,
rationale: str,
)
Non-actuating controller candidate derived from an STL automaton.
Methods:¶
to_audit_record ¶
Return a JSON-serialisable controller-candidate payload.
Returns¶
dict[str, object] Return a JSON-serialisable controller-candidate payload.
Source code in src/scpn_phase_orchestrator/monitor/stl/controller.py
STLControllerSynthesis
dataclass
¶
STLControllerSynthesis(
spec: str,
satisfied: bool,
actuating: bool,
source_backend: str,
candidates: tuple[STLControllerCandidate, ...],
)
Audit-ready, non-actuating controller synthesis proposal.
Methods:¶
to_audit_record ¶
Return a JSON-serialisable controller-synthesis payload.
Returns¶
dict[str, object] Return a JSON-serialisable controller-synthesis payload.
Source code in src/scpn_phase_orchestrator/monitor/stl/controller.py
STLMonitor ¶
Evaluate STL specifications against numeric traces.
Parameters¶
spec : str
An STL specification string, e.g. "always (sync_error <= 0.3)".
The builtin backend evaluates the unbounded operators
always/eventually and their bounded forms
always[a,b]/eventually[a,b] (integer discrete step window,
0 <= a <= b) over a conjunction of atomic predicates; until,
nesting, and other syntax require the optional rtamt backend.
Source code in src/scpn_phase_orchestrator/monitor/stl/monitor.py
Methods:¶
evaluate ¶
Return the robustness value of spec over trace.
A positive value means the specification is satisfied; negative means violated. The magnitude indicates how far from the boundary.
Parameters¶
trace : dict[str, list[float]] Signal trace keyed by variable name, each a list of floats.
Returns¶
float The robustness value of the specification over the trace.
Raises¶
ImportError If the rtamt STL backend is not installed.
Source code in src/scpn_phase_orchestrator/monitor/stl/monitor.py
evaluate_result ¶
Evaluate and return robustness plus audit metadata.
Parameters¶
trace : dict[str, list[float]] Signal trace keyed by variable name, each a list of floats.
Returns¶
STLTraceResult The robustness value plus audit metadata.
Source code in src/scpn_phase_orchestrator/monitor/stl/monitor.py
STLTraceResult
dataclass
¶
STLActionProjectionTemplate
dataclass
¶
STLActionProjectionTemplate(
action: str,
knob: str,
scope: str,
base_value: float,
step: float,
ttl_s: float,
previous_value: float,
value_bounds: tuple[float, float],
rate_limit: float | None = None,
)
Policy-approved projection template for one STL candidate action.
STLProjectedActionPlan
dataclass
¶
STLProjectedActionPlan(
spec: str,
actuating: bool,
approved_actions: tuple[ControlAction, ...],
rejected_candidates: tuple[dict[str, object], ...],
)
Policy-gated, non-actuating projection of STL candidates.
Methods:¶
to_audit_record ¶
Return a JSON-serialisable projected-action plan.
Returns¶
dict[str, object] Return a JSON-serialisable projected-action plan.
Source code in src/scpn_phase_orchestrator/monitor/stl/projection.py
PhaseFieldSpecification
dataclass
¶
PhaseFieldSpecification(
name: str,
signal: str,
temporal_op: str,
comparison: str,
threshold: float,
rationale: str,
severity: str = "soft",
)
A named single-signal STL property of a Kuramoto-type phase field.
Parameters¶
name : str
Stable catalogue key, e.g. "order_parameter_floor".
signal : str
Trace key the property constrains, e.g. "R".
temporal_op : str
Temporal operator, "always" or "eventually".
comparison : str
Predicate comparison operator: one of >=, >, <=, <,
==.
threshold : float
Finite predicate threshold.
rationale : str
Physical or engineering justification for the property and threshold.
severity : str
Escalation tier, "soft" (default) or "hard".
Raises¶
ValueError If any field is empty or outside its permitted set, or if the threshold is not finite.
Attributes¶
spec
property
¶
Return the builtin-compatible STL formula for this property.
Returns¶
str
An STL string such as "always (R >= 0.3)" that both the builtin
and the rtamt backends of :class:~.monitor.STLMonitor accept.
Methods:¶
monitor ¶
Return a fresh :class:~.monitor.STLMonitor for this property.
Returns¶
STLMonitor
A monitor bound to :attr:spec.
Source code in src/scpn_phase_orchestrator/monitor/stl/specifications.py
evaluate ¶
Evaluate this property over trace and return its robustness record.
Parameters¶
trace : dict[str, list[float]]
Signal trace keyed by variable name; must include :attr:signal.
Returns¶
STLTraceResult Robustness value plus audit metadata (spec, satisfied, backend).
Raises¶
ValueError If the trace is empty, ragged, or numerically invalid.
Source code in src/scpn_phase_orchestrator/monitor/stl/specifications.py
Functions:¶
validate_stl_runtime_actuation_gate ¶
validate_stl_runtime_actuation_gate(
projected_plan: STLProjectedActionPlan,
templates: Sequence[STLActionProjectionTemplate],
) -> STLRuntimeActuationGate
Validate projected STL actions through runtime actuation mapping.
This is an audit gate only: returned commands are deterministic evidence
that proposals can be represented by the configured actuation stack, while
execution_disabled and non_actuating remain true for every outcome.
Invalid runtime knobs, missing mappings, and empty projected plans fail
closed with explicit blocker reasons.
Parameters¶
projected_plan : STLProjectedActionPlan The projected STL action plan to validate. templates : Sequence[STLActionProjectionTemplate] STL action-projection templates.
Returns¶
STLRuntimeActuationGate The runtime actuation-gate validation result.
Source code in src/scpn_phase_orchestrator/monitor/stl/actuation_gate.py
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | |
synthesise_stl_monitoring_automaton ¶
synthesise_stl_monitoring_automaton(
spec: str, trace: dict[str, list[float]]
) -> STLMonitoringAutomaton
Synthesize a trace automaton for builtin simple STL safety formulas.
The synthesized automaton is intentionally conservative and audit-oriented:
it records the state sequence taken by the monitor over the supplied trace
for supported always (...) and eventually (...) conjunctions. More
expressive STL remains delegated to rtamt for robustness evaluation.
Parameters¶
spec : str STL specification string. trace : dict[str, list[float]] Signal trace keyed by variable name, each a list of floats.
Returns¶
STLMonitoringAutomaton The trace automaton for the STL safety formula.
Raises¶
ValueError If the spec is not a supported builtin STL formula.
Source code in src/scpn_phase_orchestrator/monitor/stl/automaton.py
synthesise_stl_closed_loop_plan ¶
synthesise_stl_closed_loop_plan(
automaton: STLMonitoringAutomaton,
trace: dict[str, list[float]],
templates: Sequence[STLActionProjectionTemplate],
*,
horizon_steps: int = 1,
action_map: dict[str, str] | None = None,
) -> STLClosedLoopSynthesisPlan
Build an offline closed-loop STL controller plan.
The function synthesizes candidates from the current STL automaton, projects them through explicit policy templates, and records the future feedback review window. It does not mutate runtime state or permit actuation.
Parameters¶
automaton : STLMonitoringAutomaton
The STL monitoring automaton.
trace : dict[str, list[float]]
Signal trace keyed by variable name, each a list of floats.
templates : Sequence[STLActionProjectionTemplate]
STL action-projection templates.
horizon_steps : int
Closed-loop planning horizon in steps.
action_map : dict[str, str] | None
Mapping of automaton state to action name, or None.
Returns¶
STLClosedLoopSynthesisPlan The offline closed-loop STL controller plan.
Source code in src/scpn_phase_orchestrator/monitor/stl/closed_loop.py
synthesise_stl_controller_candidates ¶
synthesise_stl_controller_candidates(
automaton: STLMonitoringAutomaton,
trace: dict[str, list[float]],
*,
action_map: dict[str, str] | None = None,
) -> STLControllerSynthesis
Synthesize non-actuating controller candidates from an STL automaton.
The result is a review artefact, not a controller. It identifies the
weakest predicate margin and proposes signal-level adjustment directions for
supported builtin always and eventually monitors. Callers must still
map candidates through policy, projection, safety, and actuation gates.
Parameters¶
automaton : STLMonitoringAutomaton
The STL monitoring automaton.
trace : dict[str, list[float]]
Signal trace keyed by variable name, each a list of floats.
action_map : dict[str, str] | None
Mapping of automaton state to action name, or None.
Returns¶
STLControllerSynthesis The non-actuating controller-candidate synthesis.
Raises¶
ValueError If the automaton or trace is invalid.
Source code in src/scpn_phase_orchestrator/monitor/stl/controller.py
project_stl_controller_candidates ¶
project_stl_controller_candidates(
synthesis: STLControllerSynthesis,
templates: Sequence[STLActionProjectionTemplate],
) -> STLProjectedActionPlan
Project STL candidates into bounded, non-actuating action proposals.
Only candidates with an explicit policy-approved projection template are
converted. Projection uses the standard :class:ActionProjector; the
returned plan remains a review artefact with actuating=False.
Parameters¶
synthesis : STLControllerSynthesis The STL controller synthesis result. templates : Sequence[STLActionProjectionTemplate] STL action-projection templates.
Returns¶
STLProjectedActionPlan The bounded, non-actuating projected action plan.
Source code in src/scpn_phase_orchestrator/monitor/stl/projection.py
phase_field_specification ¶
Return the curated specification registered under name.
Parameters¶
name : str
A catalogue key from :func:phase_field_specification_names.
Returns¶
PhaseFieldSpecification The matching specification.
Raises¶
KeyError If name is not a registered catalogue key.
Source code in src/scpn_phase_orchestrator/monitor/stl/specifications.py
Chimera State Detection¶
Detects chimera states: the coexistence of coherent (phase-locked) and incoherent (desynchronised) clusters within the same network. This is a fundamentally different phenomenon from uniform synchronization or uniform incoherence — it requires spatially resolved analysis.
Theory: Kuramoto & Battogtokh 2002 discovered that identical oscillators with identical coupling can spontaneously split into synchronised and desynchronised subpopulations. This was later confirmed experimentally in chemical oscillators and electronic circuits.
Algorithm:
- Compute local order parameter R_i for each oscillator based on its coupled neighbors (oscillators j where K_ij > 0)
- Classify: R_i > 0.7 → coherent, R_i < 0.3 → incoherent
- Chimera index = fraction of oscillators in the boundary region
Usage:
from scpn_phase_orchestrator.monitor.chimera import detect_chimera
state = detect_chimera(phases, knm)
# state.coherent_indices: list of phase-locked oscillators
# state.incoherent_indices: list of desynchronised oscillators
# state.chimera_index: 0.0 = pure state, >0 = chimera
chimera ¶
Chimera state detection with a 5-backend fallback chain.
Kuramoto & Battogtokh 2002, Nonlinear Phenomena in Complex Systems
5:380–385. An oscillator i is coherent when its local order
parameter R_i = |⟨exp(i(θ_j − θ_i))⟩_{j ∈ N(i)}| exceeds the
coherence threshold, incoherent when it falls below the incoherence
threshold. The chimera index is the fraction of oscillators that sit
in the boundary band in between.
Compute surface:
- :func:
local_order_parameter—(N,)per-oscillatorR_ivector; the coupling diagonal must be zero so self-coupling is never counted as a neighbour. - :func:
detect_chimera— classification wrapper returning :class:ChimeraState.
Classes¶
ChimeraState
dataclass
¶
ChimeraState(
coherent_indices: list[int] = list(),
incoherent_indices: list[int] = list(),
chimera_index: float = 0.0,
)
Chimera detection result: coherent/incoherent oscillator partitions and index.
Methods:¶
__post_init__ ¶
Validate and normalise immutable Chimera result fields.
Source code in src/scpn_phase_orchestrator/monitor/chimera.py
Functions:¶
local_order_parameter ¶
Per-oscillator local order parameter.
R_i = |⟨exp(i(θ_j − θ_i))⟩_{j ∈ N(i)}| with N(i) =
{j : K_ij > 0} and a required zero self-coupling diagonal. Zero
when oscillator i has no neighbours.
Parameters¶
phases : FloatArray
Oscillator phases in radians, shape (N,).
knm : FloatArray
Coupling matrix K_nm, shape (N, N).
Returns¶
FloatArray
The per-oscillator local order parameter, shape (N,).
Source code in src/scpn_phase_orchestrator/monitor/chimera.py
detect_chimera ¶
Detect chimera states in a Kuramoto network.
Parameters¶
phases : FloatArray
(N,) oscillator phases.
knm : FloatArray
(N, N) coupling matrix. K_ij > 0 defines neighbours; diagonal
self-coupling must be zero.
Returns¶
ChimeraState
:class:ChimeraState with coherent / incoherent index lists and the
boundary-fraction chimera index.
Source code in src/scpn_phase_orchestrator/monitor/chimera.py
Entrainment Verification Score (EVS)¶
Detailed documentation: EVS (Entrainment) — detailed reference
Three-criterion battery that distinguishes genuine entrainment
(phase-locking to a stimulus) from broadband artifacts. All three
criteria must pass for is_entrained=True:
- ITPC persistence: Mean inter-trial phase coherence across time points must exceed threshold (default 0.6)
- Survival during pause: ITPC must remain elevated after the stimulus stops, proving the oscillator was entrained (not just responding reactively; default threshold 0.4)
- Frequency specificity: ITPC at the target frequency divided by ITPC at a control frequency must exceed threshold (default 1.5), proving the locking is frequency-specific
Usage:
from scpn_phase_orchestrator.monitor.evs import EVSMonitor
monitor = EVSMonitor(
itpc_threshold=0.5,
persistence_threshold=0.3,
specificity_threshold=2.0,
)
result = monitor.evaluate(
phases_trials, # (n_trials, T) phase matrix
pause_indices=list(range(500, 600)),
target_freq=10.0, # stimulus frequency in Hz
control_freq=7.0, # comparison frequency in Hz
)
# result.is_entrained: bool
# result.itpc_value, result.persistence_score, result.specificity_ratio
evs ¶
EVS and phase-locking metrics for finite two-dimensional phase recordings.
The module implements ITPC, persistence across pauses, and
frequency-specificity checks for Entrainment Verification Signals. A Rust
extension is used when available while the Python fallback remains the
reference-compatible path. Inputs are normalized to finite trials x time
phase arrays, pause indices are bounds-checked, and candidate frequency vectors
must match the trial axis before evidence is reported.
Classes¶
EVSMonitor ¶
EVSMonitor(
itpc_threshold: float = 0.6,
persistence_threshold: float = 0.4,
specificity_threshold: float = 1.5,
)
Combine ITPC, persistence, and frequency specificity into one score.
Three criteria must all pass for is_entrained=True:
- Mean ITPC across all time points >=
itpc_threshold - ITPC during/after stimulus pause >=
persistence_threshold - ITPC at the target frequency / ITPC at a control frequency
=
specificity_threshold
The specificity test distinguishes frequency-specific entrainment from broadband phase-locking artefacts.
Source code in src/scpn_phase_orchestrator/monitor/evs.py
Methods:¶
evaluate ¶
evaluate(
phases_trials: FloatArray,
pause_indices: list[int] | IntArray,
target_freq: float,
control_freq: float,
) -> EVSResult
Run the full EVS battery.
Parameters¶
phases_trials : FloatArray shape (n_trials, n_timepoints), phases in radians at the target frequency. pause_indices : list[int] | IntArray time-point indices within/after a stimulus pause window. target_freq : float stimulus frequency (Hz). control_freq : float non-stimulus control frequency (Hz).
Returns¶
EVSResult EVSResult with all three sub-scores and the overall verdict.
Source code in src/scpn_phase_orchestrator/monitor/evs.py
EVS rejects coercive phase aliases before ITPC, normalises pause indices to a unique in-range set, and verifies every native specificity score against the canonical NumPy calculation before it can affect the entrainment verdict.
Partial Information Decomposition (PID)¶
Decomposes the information that two oscillator groups carry about the global synchronisation state into redundancy (information both groups share) and synergy (information available only from the joint observation), with a 5-backend fallback chain (Rust → Mojo → Julia → Go → Python).
Theory: Williams & Beer 2010 (arXiv:1004.2515). Mutual information is a
property of a distribution, so the input is a phase history (T, N)
(T timesteps, N oscillators). Each timestep is reduced to three circular
observables — the global order-parameter phase (target Y) and the two group
order-parameter phases (sources A, B) — binned into n_bins phase bins
(default 32). With the specific information
I_spec(Y=y; S) = Σ_s p(s|y)·log[p(y|s)/p(y)]:
redundancy I_red = Σ_y p(y)·min( I_spec(Y=y; A), I_spec(Y=y; B) ) # I_min
synergy I_syn = MI(A,B; Y) − MI(A; Y) − MI(B; Y) + I_red
Each source's unique information is MI(S; Y) − I_red; all components are
non-negative and MI(A; Y) = I_red + U_A holds by construction. A single
snapshot (T = 1) carries no distributional information, so every component is
0; meaningful decomposition needs T ≥ 2. Histories, group indices, bin
counts, and backend scalar outputs are validated as finite real quantities;
boolean aliases, numeric-string aliases, complex dtypes, and out-of-range
indices are rejected before estimation or backend acceptance.
Usage:
from scpn_phase_orchestrator.monitor.pid import redundancy, synergy
# history: (T, N) phase history; groups are oscillator index sets into N
R = redundancy(history, group_a=[0, 1, 2], group_b=[3, 4, 5])
S = synergy(history, group_a=[0, 1, 2], group_b=[3, 4, 5])
High synergy means the groups carry complementary information — neither alone
predicts the target, but together they do. This detects higher-order functional
relationships invisible to pairwise PLV. The polyglot parity gate
benchmark_pid_polyglot_parity_gate (benchmarks/pid_benchmark.py, wired into
benchmarks/reference_suite.py as pid_polyglot) verifies cross-backend parity
of the redundancy/synergy estimates and the decomposition contracts (a
co-varying source pair has positive synergy; a fully redundant configuration has
vanishing synergy).
pid ¶
Partial information decomposition (PID) about global synchronisation.
Decomposes two oscillator groups with a 5-backend fallback chain.
Model¶
Williams & Beer 2010 (Nonnegative Decomposition of Multivariate Information,
arXiv:1004.2515) decompose the information two sources carry about a target into
redundant, unique, and synergistic parts. Estimating it needs a distribution,
so the input is a phase history (T, N) (T timesteps, N
oscillators). Each timestep is reduced to three circular observables:
- target
Y_t— the global order-parameter phase∠⟨e^{iθ}⟩over all oscillators, - source
A_t— the group-A order-parameter phase, - source
B_t— the group-B order-parameter phase.
The three series are binned into n_bins equal-width phase bins and the joint
distribution is estimated over the T samples.
Decomposition¶
With the specific information I_spec(Y=y; S) = Σ_s p(s|y)·log[p(y|s)/p(y)]:
redundancy I_red = Σ_y p(y)·min( I_spec(Y=y; A), I_spec(Y=y; B) )
synergy I_syn = MI(A,B; Y) − MI(A; Y) − MI(B; Y) + I_red
I_red is the Williams & Beer I_min redundancy; the unique information of
each source is MI(S; Y) − I_red and MI(A; Y) = I_red + U_A holds by
construction. All terms are non-negative.
A single snapshot (T = 1) carries no distributional information, so every
component is 0; meaningful decomposition needs T ≥ 2.
Functions:¶
redundancy ¶
redundancy(
phases: FloatArray,
group_a: list[int] | IntArray,
group_b: list[int] | IntArray,
n_bins: int = _DEFAULT_BINS,
) -> float
Redundant information both groups share about the global phase.
I_red = Σ_y p(y)·min(I_spec(Y=y; A), I_spec(Y=y; B)) (Williams & Beer
2010 I_min). phases is a (T, N) phase history.
Parameters¶
phases : FloatArray
Oscillator phases in radians, shape (N,).
group_a : list[int] | IntArray
Indices of the first oscillator group.
group_b : list[int] | IntArray
Indices of the second oscillator group.
n_bins : int
Number of histogram bins.
Returns¶
float The redundant information the groups share about the global phase.
Source code in src/scpn_phase_orchestrator/monitor/pid.py
synergy ¶
synergy(
phases: FloatArray,
group_a: list[int] | IntArray,
group_b: list[int] | IntArray,
n_bins: int = _DEFAULT_BINS,
) -> float
Synergistic information present only in the joint (A, B).
I_syn = MI(A,B; Y) − MI(A; Y) − MI(B; Y) + I_red. Positive synergy means
the combined group carries information about the global state that neither
subgroup carries alone. phases is a (T, N) phase history.
Parameters¶
phases : FloatArray
Oscillator phases in radians, shape (N,).
group_a : list[int] | IntArray
Indices of the first oscillator group.
group_b : list[int] | IntArray
Indices of the second oscillator group.
n_bins : int
Number of histogram bins.
Returns¶
float
The synergistic information present only in the joint (A, B).
Source code in src/scpn_phase_orchestrator/monitor/pid.py
Integrated-Information Monitor¶
Estimates an approximate Phi-style global integration metric from
phase trajectories. The monitor builds a pairwise circular
mutual-information matrix, evaluates unique bipartitions, and reports
the minimum cross-partition information as phi.
This is an engineering proxy for comparing regime traces and writing
audit records. It is not an exact IIT quantity and is not a
consciousness claim.
Phase-series inputs, bin/sample counts, audit scalars, partitions, and
pairwise mutual-information matrices are validated as finite real-valued
contracts. Boolean aliases, complex dtypes, and object arrays carrying Python
or NumPy complex scalar aliases are rejected before circular histogram
estimation or audit-record acceptance; numeric text and broken array protocols
also fail at the monitor boundary. A directly constructed result independently
recomputes total integration, the canonical minimum bipartition, and phi from
its pairwise-MI matrix before it can become audit evidence.
Usage:
from scpn_phase_orchestrator.monitor import (
benchmark_integrated_information_approximations,
integrated_information,
)
# phase_series: (n_oscillators, n_samples)
result = integrated_information(phase_series, n_bins=16)
record = result.to_audit_record()
benchmark = benchmark_integrated_information_approximations()
benchmark_record = benchmark.to_audit_record()
benchmark_integrated_information_approximations() runs deterministic
synthetic calibration cases for independent, modular, phase-lagged chain, noisy
locked, and globally locked phase regimes. It is a numerical approximation
benchmark, not a hardware performance benchmark; the audit record documents
ordering margins and preserves the same engineering-proxy claim boundary.
Studio renders those audit records through the public
scpn_phase_orchestrator.studio.build_integrated_information_panel() facade,
which keeps the monitor passive,
requires the explicit engineering-proxy claim boundary, and exposes Phi,
normalised Phi, total-integration ranges, and minimum partitions for operator
review without enabling actuation or consciousness claims.
information_integration ¶
Approximate integrated-information monitor for phase trajectories.
The monitor reports a bounded engineering proxy over binned circular mutual information. It is intended for regime comparison and audit traces, not for theoretical integrated-information claims.
Classes¶
IntegratedInformationResult
dataclass
¶
IntegratedInformationResult(
phi: float,
normalised_phi: float,
total_integration: float,
minimum_partition: Partition,
pairwise_mi: FloatArray,
n_bins: int,
)
Audit-ready result from the integrated-information monitor.
Attributes¶
phi: Minimum cross-partition information in nats. This is an
approximate Phi-style proxy, not an exact IIT quantity.
normalised_phi: ``phi`` divided by ``log(n_bins)`` and clipped
to ``[0, 1]`` for dashboards.
total_integration: Mean off-diagonal pairwise mutual information
across all oscillator trajectories.
minimum_partition: Bipartition that minimises cross-partition
information.
pairwise_mi: Symmetric pairwise mutual-information matrix.
n_bins: Number of circular histogram bins used by the estimator.
Methods:¶
to_audit_record ¶
Return a JSON-serialisable audit record.
Returns¶
dict[str, Any] Return a JSON-serialisable audit record.
Source code in src/scpn_phase_orchestrator/monitor/information_integration.py
IntegratedInformationBenchmarkCase
dataclass
¶
IntegratedInformationBenchmarkCase(
name: str,
description: str,
result: IntegratedInformationResult,
)
IntegratedInformationBenchmarkReport
dataclass
¶
IntegratedInformationBenchmarkReport(
cases: tuple[IntegratedInformationBenchmarkCase, ...],
expected_ordering_passed: bool,
locked_phi_margin: float,
modular_total_margin: float,
noisy_lock_phi_margin: float,
phase_lag_total_margin: float,
n_samples: int,
n_bins: int,
)
Audit report for deterministic integrated-information approximations.
Methods:¶
to_audit_record ¶
Return a JSON-serialisable benchmark report.
Returns¶
dict[str, Any] Return a JSON-serialisable benchmark report.
Source code in src/scpn_phase_orchestrator/monitor/information_integration.py
Functions:¶
integrated_information ¶
integrated_information(
phase_series: FloatArray, n_bins: int = _DEFAULT_BINS
) -> IntegratedInformationResult
Estimate an approximate integrated-information metric.
Parameters¶
phase_series : FloatArray
Phase trajectory array with shape (n_oscillators, n_samples). Values are
wrapped onto the circular interval before histogramming.
n_bins : int
Number of circular bins for mutual-information estimation. Must be at least two.
Returns¶
IntegratedInformationResult
IntegratedInformationResult containing the minimum information bipartition
and audit fields.
Raises¶
ValueError If the trajectory is not a finite two-dimensional array with at least two oscillators and two samples.
Source code in src/scpn_phase_orchestrator/monitor/information_integration.py
benchmark_integrated_information_approximations ¶
benchmark_integrated_information_approximations(
*, n_samples: int = 256, n_bins: int = 8
) -> IntegratedInformationBenchmarkReport
Run deterministic approximation checks for the Phi proxy.
This is a numerical calibration, not a hardware performance benchmark. It checks five synthetic regimes: independent streams, modular streams with high within-module information but weak cross-module Phi, phase-lagged chains, noisy globally locked streams, and globally locked streams with high cross-partition Phi.
Parameters¶
n_samples : int Number of samples. n_bins : int Number of histogram bins.
Returns¶
IntegratedInformationBenchmarkReport The Phi-proxy approximation benchmark report.
Source code in src/scpn_phase_orchestrator/monitor/information_integration.py
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 | |
Lyapunov Exponent¶
Real-time estimation of the maximal Lyapunov exponent from phase trajectories. The Lyapunov exponent characterizes the system's sensitivity to initial conditions:
- λ > 0: chaotic (exponential divergence of nearby trajectories)
- λ ≈ 0: edge of chaos (critical regime, maximal computational capacity)
- λ < 0: stable attractor (perturbations decay exponentially)
The "edge of chaos" (λ ≈ 0) is where flexible, high-capacity dynamics operate (PNAS 2022) and where reservoir computing achieves optimal performance (arXiv:2407.16172).
The spectrum surface validates phase/frequency vectors, coupling/lag matrices, and optional backend spectra before float coercion. Boolean aliases, complex aliases, numeric-string aliases, non-finite values, unsorted spectra, and wrong cardinality fail closed before publication.
lyapunov ¶
Lyapunov stability monitor with a 5-backend fallback chain.
Two public surfaces:
- :class:
LyapunovGuard— stateful observer that tracks the Lyapunov functionV(θ) = -(K/2N) Σ_ij A_ij cos(θ_i − θ_j), its numerical time derivative, and basin-of-attraction membership (van Hemmen & Wreszinski 1993). Single-backend NumPy; inexpensive per call. - :func:
lyapunov_spectrum— full Lyapunov spectrum via periodic QR reorthogonalisation (Benettin 1980 / Shimada-Nagashima 1979). Multi- backend; the heavy kernel is dispatched to Rust → Mojo → Julia → Go → Python in order of availability.
Classes¶
LyapunovState
dataclass
¶
Lyapunov function V, dV/dt, basin membership, and max phase diff.
Methods:¶
__post_init__ ¶
Normalize scalar aliases and reject invalid state fields.
Source code in src/scpn_phase_orchestrator/monitor/lyapunov.py
LyapunovGuard ¶
Lyapunov stability monitor for Kuramoto networks.
V(θ) = -(K/2N) Σ_{i,j} A_ij cos(θ_i - θ_j)
dV/dt ≤ 0 for gradient flow (Kuramoto is gradient on V). Basin of attraction: max|θ_i - θ_j| < π/2 for connected pairs.
van Hemmen & Wreszinski 1993, J. Stat. Phys. 72:145-166.
Create a guard with a validated geodesic basin threshold.
Source code in src/scpn_phase_orchestrator/monitor/lyapunov.py
Methods:¶
evaluate ¶
Compute Lyapunov function, its time derivative, and basin check.
Parameters¶
phases : object
Oscillator phases in radians, shape (N,).
knm : object
Coupling matrix K_nm, shape (N, N).
Returns¶
LyapunovState The Lyapunov value, its derivative, and the basin-check result.
Source code in src/scpn_phase_orchestrator/monitor/lyapunov.py
Functions:¶
lyapunov_spectrum ¶
lyapunov_spectrum(
phases_init: object,
omegas: object,
knm: object,
alpha: object,
dt: object = 0.01,
n_steps: object = 1000,
qr_interval: object = 10,
zeta: object = 0.0,
psi: object = 0.0,
) -> FloatArray
Full Lyapunov spectrum (all N exponents) via QR decomposition.
Evolves N perturbation vectors alongside the Kuramoto ODE. Every
qr_interval steps, QR-reorthogonalises and accumulates growth
rates from the diagonal of R.
Benettin et al. 1980, Meccanica 15:9-20. Shimada & Nagashima 1979, Prog. Theor. Phys. 61:1605-1616.
Dispatches to the first available backend per the SPO fallback chain (Rust → Mojo → Julia → Go → Python). All five produce the same exponents up to floating-point rounding; the dispatcher's choice only affects wall-clock cost.
Parameters¶
phases_init : object (N,) initial phases. omegas : object (N,) natural frequencies. knm : object (N, N) coupling matrix. alpha : object (N, N) phase-lag matrix. dt : object integration timestep. n_steps : object total integration steps. qr_interval : object steps between QR reorthogonalisations. zeta : object driver strength. psi : object target driver phase.
Returns¶
FloatArray (N,) array of Lyapunov exponents, sorted descending.
Raises¶
ValueError If the integration parameters are invalid.
Source code in src/scpn_phase_orchestrator/monitor/lyapunov.py
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 | |
Digital-Twin Confidence¶
Scores how well a running orchestrator tracks its physical or simulated twin
from a phase-histogram Jensen–Shannon divergence and an order-parameter
Wasserstein-1 distance, calibrated against a nominal baseline into a confidence
in [0, 1] plus an operator status. See the dedicated
Twin Confidence page for the formalism, the
polyglot backend chain, and benchmarks.
The public and direct backend boundaries reject boolean aliases, complex aliases, numeric-string aliases, non-finite payloads, shape mismatches, invalid order-parameter ranges, and backend-output range violations before divergence evidence can feed the operator summary, Prometheus export, Studio panel, or conformal twin-confidence gate.
twin_confidence ¶
Online digital-twin confidence scoring from model–observation divergence.
A running orchestrator and its physical (or simulated) twin both emit a phase
state and an order-parameter trajectory at every control tick. This module
turns the disagreement between the two streams into a single calibrated
confidence score in [0, 1] plus an operator status, using two complementary
divergences computed by the multi-language acceleration chain:
- Phase distribution Jensen–Shannon divergence — model and observed phase
vectors are wrapped to
[0, 2π)and binned inton_binshistograms; the symmetric Jensen–Shannon divergence (natural log, range[0, ln 2]) measures how differently the two populations are distributed around the ring. - Order-parameter Wasserstein-1 distance — the model and observed
order-parameter windows
R ∈ [0, 1]are compared with the closed-form one-dimensional Wasserstein-1 distance (mean absolute difference of the order-sorted samples, range[0, 1]).
The raw (js, w1) pair is the compute hot path and is produced by the
Rust → Mojo → Julia → Go → NumPy fallback chain (fastest available first). The
calibration, confidence mapping, operating bands, and audit records are
deterministic NumPy/Python on top.
Calibration follows the standard online-monitoring pattern: a baseline of
nominal-operation (js, w1) samples fixes per-divergence operating means and
standard deviations together with a normal-quantile operating band. At runtime,
each new divergence is converted to a one-sided z-score against its baseline,
the two z-scores are combined into a composite deviation, and the confidence is
exp(-z_composite / sensitivity) — exactly 1.0 while the twin tracks
inside its calibrated band, decaying smoothly as it drifts away.
The scorer is review-only: it never proposes or applies actuation. It is a health observable consumed by the digital-twin operator evidence summary and the observability exporters.
Classes¶
TwinDivergence
dataclass
¶
Raw divergence pair between a model tick and its observed twin tick.
Attributes¶
phase_js_divergence : float
Jensen–Shannon divergence (natural log) between the model and observed
phase histograms, in [0, ln 2].
order_wasserstein : float
One-dimensional Wasserstein-1 distance between the model and observed
order-parameter windows, in [0, 1].
n_bins : int
Number of phase histogram bins used.
backend : str
Name of the acceleration backend that produced the pair.
Methods:¶
to_audit_record ¶
Return a JSON-safe audit mapping of the divergence pair.
Returns¶
dict[str, object] Deterministic, JSON-safe mapping of the divergence fields.
Source code in src/scpn_phase_orchestrator/monitor/twin_confidence.py
TwinConfidenceBaseline
dataclass
¶
TwinConfidenceBaseline(
phase_js_mean: float,
phase_js_std: float,
order_w1_mean: float,
order_w1_std: float,
sample_count: int,
band_z: float,
)
Calibrated nominal-operation baseline for twin divergences.
Attributes¶
phase_js_mean, phase_js_std : float
Mean and (population) standard deviation of the nominal phase
Jensen–Shannon divergence samples.
order_w1_mean, order_w1_std : float
Mean and (population) standard deviation of the nominal Wasserstein-1
samples.
sample_count : int
Number of nominal samples the baseline was fitted on.
band_z : float
Normal-quantile multiplier defining the upper operating band
mean + band_z * std for each divergence.
Attributes¶
phase_js_upper_band
property
¶
Return the upper nominal operating band for the phase divergence.
Returns¶
float
phase_js_mean + band_z * phase_js_std.
order_w1_upper_band
property
¶
Return the upper nominal operating band for the Wasserstein distance.
Returns¶
float
order_w1_mean + band_z * order_w1_std.
Methods:¶
to_audit_record ¶
Return a JSON-safe audit mapping of the baseline.
Returns¶
dict[str, object] Deterministic, JSON-safe mapping of the baseline fields and bands.
Source code in src/scpn_phase_orchestrator/monitor/twin_confidence.py
TwinConfidenceScore
dataclass
¶
TwinConfidenceScore(
confidence: float,
status: str,
phase_js_divergence: float,
order_wasserstein: float,
phase_js_z: float,
order_w1_z: float,
composite_z: float,
phase_js_within_band: bool,
order_w1_within_band: bool,
backend: str,
score_hash: str,
)
Online confidence score for one twin tick against a baseline.
Attributes¶
confidence : float
Calibrated confidence in [0, 1]; 1.0 while the twin tracks
inside its nominal band, decaying as it diverges.
status : str
Operator status: "healthy", "warning", or "critical".
phase_js_divergence, order_wasserstein : float
The raw divergences scored.
phase_js_z, order_w1_z : float
One-sided z-scores of each divergence against its baseline.
composite_z : float
Euclidean combination of the two one-sided z-scores.
phase_js_within_band, order_w1_within_band : bool
Whether each divergence is inside its calibrated upper operating band.
backend : str
Acceleration backend that produced the divergences.
score_hash : str
Deterministic SHA-256 over the audit record (excluding the hash).
Methods:¶
to_audit_record ¶
Return a JSON-safe audit mapping of the confidence score.
Returns¶
dict[str, object]
Deterministic, JSON-safe mapping of every score field including the
score_hash.
Source code in src/scpn_phase_orchestrator/monitor/twin_confidence.py
TwinConfidenceCalibrator
dataclass
¶
TwinConfidenceCalibrator(
band_z: float = _DEFAULT_BAND_Z,
_phase_js: list[float] = cast("list[float]", None),
_order_w1: list[float] = cast("list[float]", None),
)
Accumulate nominal twin divergences into a calibrated baseline.
The calibrator ingests divergence pairs gathered while the twin is known to
track its model (commissioning, healthy replay, or a trusted window) and
fits per-divergence means, population standard deviations, and a
normal-quantile operating band. The resulting :class:TwinConfidenceBaseline
feeds :func:score_twin_confidence.
Attributes¶
band_z : float
Normal-quantile multiplier for the upper operating band (default 3).
Attributes¶
sample_count
property
¶
Methods:¶
__post_init__ ¶
Validate configuration and initialise sample buffers.
observe ¶
Add one nominal divergence pair to the calibration set.
Parameters¶
divergence : TwinDivergence A divergence pair measured during trusted nominal operation.
Source code in src/scpn_phase_orchestrator/monitor/twin_confidence.py
observe_many ¶
Add several nominal divergence pairs to the calibration set.
Parameters¶
divergences : Sequence[TwinDivergence] Divergence pairs measured during trusted nominal operation.
Source code in src/scpn_phase_orchestrator/monitor/twin_confidence.py
baseline ¶
Fit and return the calibrated baseline.
Returns¶
TwinConfidenceBaseline Per-divergence means, population standard deviations, sample count, and operating band multiplier.
Raises¶
ValueError If no nominal samples have been observed.
Source code in src/scpn_phase_orchestrator/monitor/twin_confidence.py
TwinConfidenceSummary
dataclass
¶
TwinConfidenceSummary(
tick_count: int,
healthy_count: int,
warning_count: int,
critical_count: int,
min_confidence: float,
mean_confidence: float,
latest_confidence: float,
worst_status: str,
latest_status: str,
summary_hash: str,
)
Operator-facing aggregate over a sequence of twin-confidence scores.
Attributes¶
tick_count : int
Number of scored ticks.
healthy_count, warning_count, critical_count : int
Per-status tick counts.
min_confidence, mean_confidence : float
Minimum and arithmetic-mean confidence across the scored ticks.
latest_confidence : float
Confidence of the most recently scored tick.
worst_status : str
"critical" if any tick was critical, else "warning" if any was
warning, else "healthy".
latest_status : str
Status of the most recently scored tick.
summary_hash : str
Deterministic SHA-256 over the audit record (excluding the hash).
Methods:¶
to_audit_record ¶
Return a JSON-safe audit mapping of the summary.
Returns¶
dict[str, object]
Deterministic, JSON-safe mapping of every summary field including
the summary_hash.
Source code in src/scpn_phase_orchestrator/monitor/twin_confidence.py
Functions:¶
phase_order_divergence ¶
phase_order_divergence(
model_phases: FloatArray,
observed_phases: FloatArray,
model_order: FloatArray,
observed_order: FloatArray,
*,
n_bins: int = _DEFAULT_N_BINS,
) -> TwinDivergence
Compute the phase/order divergence pair for one twin tick.
Parameters¶
model_phases, observed_phases : FloatArray
Model and observed phase vectors (radians). Must share length N >= 1.
model_order, observed_order : FloatArray
Model and observed order-parameter windows with values in [0, 1].
Must share length W >= 1.
n_bins : int, optional
Number of phase histogram bins (default 36, i.e. 10° per bin).
Returns¶
TwinDivergence The Jensen–Shannon phase divergence and Wasserstein-1 order distance, produced by the fastest available backend.
Raises¶
ValueError
If shapes mismatch, lengths are empty, order values fall outside
[0, 1], n_bins is not a positive integer, or a backend returns a
non-physical pair.
Source code in src/scpn_phase_orchestrator/monitor/twin_confidence.py
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 | |
score_twin_confidence ¶
score_twin_confidence(
divergence: TwinDivergence,
baseline: TwinConfidenceBaseline,
*,
sensitivity: float = _DEFAULT_SENSITIVITY,
warning_confidence: float = _DEFAULT_WARNING_CONFIDENCE,
critical_confidence: float = _DEFAULT_CRITICAL_CONFIDENCE,
) -> TwinConfidenceScore
Score one twin divergence against a calibrated baseline.
Each divergence is converted to a one-sided z-score against its baseline
mean and standard deviation; the two z-scores are combined into a composite
Euclidean deviation, and the confidence is exp(-composite_z /
sensitivity) — 1.0 while both divergences sit at or below their
nominal means, decaying smoothly as the twin drifts.
Parameters¶
divergence : TwinDivergence
The divergence pair to score.
baseline : TwinConfidenceBaseline
The calibrated nominal baseline.
sensitivity : float, optional
Composite-deviation scale of the confidence decay (default 3):
larger values decay more slowly. Must be > 0.
warning_confidence : float, optional
Confidence at or above which the status is "healthy" rather than
"warning" (default 0.6). In [0, 1].
critical_confidence : float, optional
Confidence below which the status is "critical" (default 0.3).
In [0, 1] and <= warning_confidence.
Returns¶
TwinConfidenceScore The calibrated confidence, status, z-scores, band membership, and a deterministic audit hash.
Raises¶
ValueError
If sensitivity <= 0 or the confidence thresholds are inconsistent.
Source code in src/scpn_phase_orchestrator/monitor/twin_confidence.py
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 | |
summarise_twin_confidence ¶
Aggregate a sequence of twin-confidence scores into operator evidence.
Parameters¶
scores : Sequence[TwinConfidenceScore] The per-tick scores in chronological order.
Returns¶
TwinConfidenceSummary The deterministic operator-facing aggregate.
Raises¶
ValueError
If scores is empty.
Source code in src/scpn_phase_orchestrator/monitor/twin_confidence.py
twin_confidence_prometheus_text ¶
Render a twin-confidence summary as Prometheus exposition text.
Parameters¶
summary : TwinConfidenceSummary
The operator-facing aggregate to export.
prefix : str, optional
Metric-name prefix (default "spo").
Returns¶
str Prometheus exposition text with confidence gauges, per-status counters, and a numeric worst-status level gauge.
Raises¶
ValueError
If prefix is not a non-empty string.
Source code in src/scpn_phase_orchestrator/monitor/twin_confidence.py
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 | |
Conformal Twin-Confidence Gate¶
Wraps the twin-confidence stream in a distribution-free admission gate. From a
trusted nominal calibration window it learns a threshold on the composite
z-deviation such that nominal ticks stay inside the band with probability
1 − target_miscoverage, then admits a tick only when its score is inside the
band. The threshold adapts online by Adaptive Conformal Inference (Gibbs &
Candès, 2021) so the long-run empirical miscoverage tracks the target under
non-stationarity, and it can be regime-conditioned (a separate band per detected
sync / chimera / chaotic regime). Review-only: a flagged tick signals the twin
has drifted beyond its calibrated band and autonomy should narrow. In the
generic simulation loop, callers can supply a calibrated gate and
deployment-specific twin-confidence source; rejected conformal ticks suppress
the current policy action set and are recorded in result/audit surfaces. The
default CLI run has no observed-twin feed, so this admission gate is opt-in.
twin_conformal_gate ¶
Coverage-valid admission gate over the twin-confidence stream.
The twin-confidence score (:mod:scpn_phase_orchestrator.monitor.twin_confidence)
quantifies model–observation disagreement, but a raw score gives no statistical
guarantee. This module wraps the stream in a distribution-free conformal gate:
it learns, from a trusted nominal calibration window, a threshold on a
nonconformity score (the composite z-deviation) such that nominal ticks fall
inside the band with probability 1 − target_miscoverage, then admits a tick
only when its score stays inside the band.
Because the twin's behaviour is non-stationary, the threshold adapts online by
Adaptive Conformal Inference (Gibbs & Candès, 2021): the effective miscoverage
alpha_t is nudged up when a tick is covered and down when it is missed, so
the long-run empirical miscoverage tracks the target. The gate is optionally
regime conditioned — it keeps a separate calibration set and alpha_t per
detected regime (sync / chimera / chaotic), which SPO already classifies — so the
band is appropriate to the current dynamical regime rather than a global average.
This is a review-only safety observable: a flagged tick signals the twin has drifted beyond its calibrated nominal band and that autonomy should narrow; it never actuates. The computation is lightweight online statistics (one sorted calibration array per regime, O(1) per update), so it has no compute hot path and no multi-language backend.
References¶
Gibbs, I. & Candès, E. (2021). Adaptive conformal inference under distribution shift. NeurIPS. Regime conditioning follows the change-point/transition-conformal direction (e.g. arXiv:2509.02844); only the established ACI core is implemented here, with regime conditioning as the SPO-specific adaptation.
Classes¶
ConformalGateConfig
dataclass
¶
ConformalGateConfig(
target_miscoverage: float = 0.1,
adaptation_rate: float = 0.02,
regime_conditioned: bool = True,
)
Configuration for the conformal admission gate.
Attributes¶
target_miscoverage : float
Desired long-run fraction of nominal ticks falling outside the band
(alpha); in (0, 1), default 0.1 (90% coverage).
adaptation_rate : float
Adaptive Conformal Inference step size (gamma); in (0, 1],
default 0.02.
regime_conditioned : bool
Whether to keep a separate calibration set and adaptive miscoverage per
regime (default True).
Methods:¶
to_audit_record ¶
Return a JSON-safe audit mapping of the configuration.
Returns¶
dict[str, object] Deterministic, JSON-safe mapping of the configuration fields.
Source code in src/scpn_phase_orchestrator/monitor/twin_conformal_gate.py
ConformalDecision
dataclass
¶
ConformalDecision(
admitted: bool,
nonconformity_score: float,
threshold: float,
effective_miscoverage: float,
empirical_coverage: float,
regime: str,
tick: int,
decision_hash: str,
)
One conformal admission decision for a twin-confidence tick.
Attributes¶
admitted : bool
True when the nonconformity score is within the conformal band.
nonconformity_score : float
The scored tick's nonconformity value.
threshold : float
The conformal band upper bound used for this decision (may be infinite
when the calibration set is too small to bound at the current level).
effective_miscoverage : float
The adaptive miscoverage alpha_t in force for this decision.
empirical_coverage : float
Running fraction of admitted ticks for this regime, including this tick.
regime : str
The regime key the decision was scored against.
tick : int
Per-regime decision index (1-based).
decision_hash : str
Deterministic SHA-256 over the audit record (excluding the hash).
Methods:¶
to_audit_record ¶
Return a JSON-safe audit mapping of the decision.
Returns¶
dict[str, object]
Deterministic, JSON-safe mapping of every decision field. An infinite
threshold is serialised as None to stay JSON-safe.
Source code in src/scpn_phase_orchestrator/monitor/twin_conformal_gate.py
TwinConformalGate
dataclass
¶
Adaptive conformal admission gate over twin nonconformity scores.
Attributes¶
config : ConformalGateConfig The gate configuration.
Methods:¶
calibrate ¶
Fit the conformal band for a regime from nominal nonconformity scores.
Parameters¶
nominal_scores : Sequence[float]
Nonconformity scores gathered during trusted nominal operation.
regime : str, optional
Regime key to calibrate (default "default").
Raises¶
ValueError
If nominal_scores is empty, a score is non-finite, or regime
is not a non-empty string.
Source code in src/scpn_phase_orchestrator/monitor/twin_conformal_gate.py
update ¶
Score one tick against the conformal band and adapt the threshold.
Parameters¶
nonconformity_score : float
The tick's nonconformity value (higher = more anomalous).
regime : str or None, optional
Detected regime; used when the gate is regime conditioned and the
regime is calibrated, otherwise the "default" regime is used.
Returns¶
ConformalDecision The admission decision and the post-update running coverage.
Raises¶
ValueError If the score is non-finite or no applicable regime has been calibrated.
Source code in src/scpn_phase_orchestrator/monitor/twin_conformal_gate.py
empirical_coverage ¶
Return the running admitted fraction for a regime.
Parameters¶
regime : str or None, optional
Regime key (default-resolved when None).
Returns¶
float
Admitted ticks over total ticks for the regime, or 0.0 before any
tick has been scored.
Raises¶
ValueError If no applicable regime has been calibrated.
Source code in src/scpn_phase_orchestrator/monitor/twin_conformal_gate.py
to_audit_record ¶
Return a JSON-safe audit mapping of the gate state.
Returns¶
dict[str, object] Configuration, total ticks scored, and per-regime calibration size, adaptive miscoverage, and coverage.
Source code in src/scpn_phase_orchestrator/monitor/twin_conformal_gate.py
Functions:¶
confidence_nonconformity ¶
Return the nonconformity score used by the gate for a confidence score.
The composite one-sided z-deviation is already a non-negative "how far from nominal" quantity, which is exactly the nonconformity scale the conformal gate expects.
Parameters¶
score : TwinConfidenceScore A scored twin-confidence tick.
Returns¶
float The composite z-deviation as a nonconformity score.
Source code in src/scpn_phase_orchestrator/monitor/twin_conformal_gate.py
Conformal Alarm Streams¶
Extends the same finite-sample split-conformal calibration to early-warning
alarm streams. ConformalAlarmStream learns an alarm threshold from a window
of trusted nominal (transition-free) detector scores so that, on exchangeable
nominal operation, the probability of a false alarm is bounded by the configured
target_false_alarm (the conformal alpha); the guarantee is the marginal
split-conformal one and nothing more. It flags an alarm whenever a live score
exceeds the threshold, reports the running empirical false-alarm rate over the
ticks it is told are nominal, and can adapt the threshold online by Adaptive
Conformal Inference (Gibbs & Candès, 2021) when the nominal distribution drifts —
consuming only nominal ticks, because an alarm on an event tick is a detection,
not a false alarm. It makes no claim about detection power. Review-only: an alarm
signals the nominal false-alarm budget was exceeded at a calibrated rate.
Configuration and decision records normalise valid Python/NumPy real scalars to
JSON-safe floats and reject boolean or non-finite numeric aliases. Nominal labels
must be exact booleans (or None for an unlabelled tick), regime keys must be
non-empty text, and direct decision records enforce unit-interval rates,
non-negative tick counts, and finite scores before audit serialisation.
from scpn_phase_orchestrator.monitor.conformal_alarm import (
ConformalAlarmConfig,
ConformalAlarmStream,
)
stream = ConformalAlarmStream(ConformalAlarmConfig(target_false_alarm=0.1))
stream.calibrate(nominal_scores) # trusted transition-free window
decision = stream.update(live_score, is_nominal=False)
assert isinstance(decision.alarm, bool)
conformal_alarm ¶
Split-conformal false-alarm control for early-warning detector streams.
An early-warning detector emits a stream of scores, higher meaning more evidence of an approaching transition. Turning that stream into alarms needs a threshold whose false-alarm rate on nominal operation is controlled, not guessed. This module calibrates that threshold with the same finite-sample split-conformal quantile the twin-confidence gate uses (Vovk et al.; Gibbs & Candès 2021), so on exchangeable nominal scores the probability of an alarm is bounded by the target false-alarm rate. It fires alarms on a live stream, reports the empirical false-alarm rate over the nominal ticks it is told about, and can adapt the threshold online with Adaptive Conformal Inference when the nominal distribution drifts.
The coverage statement is exactly the split-conformal one — a bound on the nominal false-alarm rate under exchangeability — and nothing more: an alarm on an event tick is a detection, not a miscoverage, so online adaptation only ever consumes ticks that are declared nominal. It makes no claim about detection power.
Classes¶
ConformalAlarmConfig
dataclass
¶
ConformalAlarmConfig(
target_false_alarm: float = 0.1,
adaptation_rate: float = 0.0,
regime_conditioned: bool = False,
)
Configuration of a split-conformal alarm stream.
Parameters¶
target_false_alarm : float
Allowed long-run fraction of nominal ticks that raise an alarm (the
conformal alpha); in (0, 1), default 0.1.
adaptation_rate : float
Adaptive Conformal Inference step size; 0.0 (default) keeps the fixed
split-conformal threshold, a positive value lets the threshold track a
drifting nominal distribution over the ticks declared nominal.
regime_conditioned : bool
Whether to keep a separate calibration and adaptive rate per regime.
Raises¶
ValueError
If target_false_alarm is not in (0, 1) or adaptation_rate is
negative.
Methods:¶
to_audit_record ¶
Return a JSON-safe mapping of the configuration.
Returns¶
dict[str, object] The target false alarm, adaptation rate, and regime-conditioning flag.
Source code in src/scpn_phase_orchestrator/monitor/conformal_alarm.py
ConformalAlarmDecision
dataclass
¶
ConformalAlarmDecision(
alarm: bool,
score: float,
threshold: float,
effective_false_alarm: float,
empirical_false_alarm: float,
regime: str,
nominal_ticks: int,
)
The alarm decision for one tick and the running nominal coverage.
Parameters¶
alarm : bool
True when the score exceeds the conformal threshold.
score : float
The tick's detector score.
threshold : float
The conformal threshold used (may be +inf when the calibration is too
small to place a finite bound at the target rate).
effective_false_alarm : float
The adaptive false-alarm target alpha_t in force for this decision.
empirical_false_alarm : float
Running fraction of nominal ticks that alarmed, this tick included when it
is nominal.
regime : str
The regime the decision was scored under.
nominal_ticks : int
Number of nominal ticks scored in this regime so far.
Methods:¶
to_audit_record ¶
Return a JSON-safe mapping of the decision.
The threshold is serialised as the string "inf" when unbounded so the
record stays strict JSON.
Returns¶
dict[str, object] The alarm flag, score, threshold, effective and empirical false-alarm rates, regime, and nominal tick count.
Source code in src/scpn_phase_orchestrator/monitor/conformal_alarm.py
ConformalAlarmStream
dataclass
¶
Adaptive split-conformal alarm stream over detector scores.
Attributes¶
config : ConformalAlarmConfig The alarm-stream configuration.
Methods:¶
calibrate ¶
Fit the conformal threshold for a regime from nominal detector scores.
Parameters¶
nominal_scores : Sequence[float]
Detector scores gathered during trusted transition-free operation.
regime : str, optional
Regime key to calibrate (default "default").
Raises¶
ValueError
If nominal_scores is empty, a score is non-finite, or regime
is not a non-empty string.
Source code in src/scpn_phase_orchestrator/monitor/conformal_alarm.py
update ¶
update(
score: float,
*,
is_nominal: bool | None = None,
regime: str | None = None,
) -> ConformalAlarmDecision
Score one tick against the conformal threshold and report coverage.
Parameters¶
score : float
The tick's detector score (higher = more anomalous).
is_nominal : bool or None, optional
Whether the tick is known to be transition-free. Only nominal ticks
update the empirical false-alarm rate and the adaptive threshold; an
alarm on an event tick is a detection, not a false alarm, and an
unlabelled tick (None) is scored without touching the calibration.
regime : str or None, optional
Detected regime; used when the stream is regime conditioned and the
regime is calibrated, otherwise the "default" regime is used.
Returns¶
ConformalAlarmDecision The alarm decision and the running nominal false-alarm rate.
Raises¶
ValueError If the score is non-finite or no applicable regime has been calibrated.
Source code in src/scpn_phase_orchestrator/monitor/conformal_alarm.py
empirical_false_alarm ¶
Return the running nominal false-alarm rate for a regime.
Parameters¶
regime : str or None, optional
Regime key (default-resolved when None).
Returns¶
float
Alarmed nominal ticks over total nominal ticks, or 0.0 before any
nominal tick has been scored.
Raises¶
ValueError If no applicable regime has been calibrated.
Source code in src/scpn_phase_orchestrator/monitor/conformal_alarm.py
to_audit_record ¶
Return a JSON-safe audit mapping of the stream state.
Returns¶
dict[str, object] Configuration and, per regime, the calibration size, adaptive false alarm, nominal tick count, and empirical false-alarm rate.
Source code in src/scpn_phase_orchestrator/monitor/conformal_alarm.py
Entropy Production Rate¶
Measures the thermodynamic irreversibility of the phase dynamics. Higher entropy production means the system is further from equilibrium — it is actively dissipating energy to maintain its current synchronization state.
Theory: For Kuramoto dynamics, entropy production rate is proportional to the mean squared coupling torque. A system at thermal equilibrium (detailed balance) has zero entropy production; a synchronised Kuramoto network actively maintained by coupling has positive entropy production.
The public dispatcher and backend adapters reject boolean aliases, numeric-string aliases, complex/object-complex payloads, non-finite values, shape mismatches, negative timesteps, and negative backend entropy-rate outputs before publishing a dissipation value.
entropy_prod ¶
Overdamped-Kuramoto thermodynamic dissipation rate with a 5-backend chain.
Σ = Σ_i (dθ_i/dt)² · dt
dθ_i/dt = ω_i + (α / N) · Σ_j K_ij · sin(θ_j − θ_i)
Zero at frequency-locked fixed points; positive otherwise. Reference: Acebrón et al. 2005, Rev. Mod. Phys. 77:137–185.
Functions:¶
entropy_production_rate ¶
entropy_production_rate(
phases: object,
omegas: object,
knm: object,
alpha: object,
dt: object,
) -> float
Thermodynamic dissipation rate Σ (dθ/dt)² · dt.
dθ_i/dt = ω_i + (α / N) Σ_j K_ij sin(θ_j − θ_i). Zero at
frequency-locked fixed points; positive otherwise.
Acebrón et al. 2005, Rev. Mod. Phys. 77:137–185.
Parameters¶
phases : object
(N,) instantaneous phases in radians.
omegas : object
(N,) natural frequencies.
knm : object
(N, N) coupling matrix.
alpha : object
global coupling strength.
dt : object
integration timestep for the · dt factor.
Returns¶
float Non-negative dissipation scalar.
Raises¶
ValueError If the inputs are non-finite or mismatched.
Source code in src/scpn_phase_orchestrator/monitor/entropy_prod.py
Winding Number¶
Topological invariant counting how many times the phase wraps around the circle [0, 2π) over a time window. The winding number is an integer-valued quantity that is robust to noise and small perturbations.
Usage:
from scpn_phase_orchestrator.monitor.winding import winding_numbers
# phases_history: (T, N) phase trajectory
w = winding_numbers(phases_history) # (N,) integer winding numbers
Different winding numbers for different oscillators indicate frequency differences; a sudden change in winding number signals a phase slip (loss of synchronization with a specific partner).
Public and direct accelerator contracts reject boolean aliases, numeric-string aliases, complex/object-complex payloads, non-finite phase histories, malformed cardinality, non-integer winding outputs, out-of-bound winding counts, and exact-reference divergence before integer winding evidence reaches reports or benchmark gates.
winding ¶
Cumulative winding-number tracker with a 5-backend fallback chain.
w_i = floor(Σ_t wrap(Δθ_{i,t}) / 2π) where wrap(x) ∈ (−π, π].
Counts how many full 2π rotations each oscillator completes
across a phase history; positive = counterclockwise, negative =
clockwise.
Functions:¶
winding_numbers ¶
Cumulative winding number of each oscillator over a trajectory.
w_i = floor(Σ_t wrap(Δθ_{i,t}) / 2π) with
wrap(x) ∈ (−π, π].
Parameters¶
phases_history : FloatArray
(T, N) phases in radians.
Returns¶
IntArray
(N,) int64 array of winding numbers.
Source code in src/scpn_phase_orchestrator/monitor/winding.py
winding_vector ¶
N-dimensional integer classification vector from winding numbers.
Alias for :func:winding_numbers; topologically distinct
trajectories map to distinct integer-lattice points.
Parameters¶
phases_history : FloatArray
Phase history, shape (T, N).
Returns¶
IntArray The integer winding classification vector.
Source code in src/scpn_phase_orchestrator/monitor/winding.py
Inter-Trial Phase Coherence (ITPC)¶
Standard neuroscience measure of phase consistency across repeated trials or time windows. ITPC = |mean(exp(i*theta))| computed across trials at each time point.
ITPC = 1: perfect phase alignment across trials (stimulus-locked). ITPC ≈ 0: random phase relationship (no consistent response).
Used by the EVS monitor as one of three entrainment criteria.
itpc ¶
Lachaux 1999 inter-trial phase coherence with a 5-backend fallback chain.
Two kernels:
- :func:
compute_itpc— ITPC across trials at each time point. - :func:
itpc_persistence— mean ITPC at stimulus-pause indices.
Functions:¶
compute_itpc ¶
Inter-Trial Phase Coherence at each time point.
ITPC = |mean(exp(i·θ))| across trials (Lachaux et al. 1999).
Parameters¶
phases_trials : object
shape (n_trials, n_timepoints) — phases in radians. A 1-D input is treated
as a single trial.
Returns¶
FloatArray
(n_timepoints,) array of ITPC values in [0, 1].
Source code in src/scpn_phase_orchestrator/monitor/itpc.py
itpc_persistence ¶
Mean ITPC at stimulus-pause indices.
Distinguishes true neural entrainment from evoked response: if ITPC remains high after the driving stimulus stops, oscillators have genuinely phase-locked. If it drops immediately, the response was merely evoked.
Parameters¶
phases_trials : object
(n_trials, n_timepoints) phases in radians.
pause_indices : object
time-point indices falling within / after a pause.
Returns¶
float
Mean ITPC across pause_indices. 0.0 if empty.
Source code in src/scpn_phase_orchestrator/monitor/itpc.py
Phase Transfer Entropy¶
Directed information-theoretic measure of causal influence between oscillators. Transfer entropy TE(i→j) quantifies how much the past of oscillator i reduces uncertainty about the future of oscillator j, beyond what j's own past provides.
Key property: Unlike PLV (symmetric), transfer entropy is directional — TE(i→j) ≠ TE(j→i) in general. This detects causal coupling direction, not just correlation.
Used by the te_adaptive coupling module to adapt K_ij based on
measured causal information flow (Lizier 2012).
transfer_entropy ¶
Phase transfer entropy via binned histograms with a 5-backend chain.
Two compute kernels:
phase_transfer_entropy— scalarTE(X → Y)on a pair of equal-length phase series.transfer_entropy_matrix—(N, N)pairwise TE matrix overNoscillator trajectories.
Estimator: 1-step Markov-order conditional entropy difference
TE(X → Y) = H(Y_{t+1} | Y_t) − H(Y_{t+1} | Y_t, X_t)
with phases wrapped to [0, 2π) and binned into n_bins
equal-width intervals. Higher TE indicates stronger directional
coupling from source to target.
Functions:¶
phase_transfer_entropy ¶
Transfer entropy TE(X → Y) on binned phase series.
Parameters¶
source : FloatArray
Source phase series, shape (T,).
target : FloatArray
Target phase series, shape (T,).
n_bins : int
Number of histogram bins.
Returns¶
float
The transfer entropy TE(X → Y).
Raises¶
ValueError If the source or target series contain boolean aliases, numeric-string aliases, complex values, non-finite values, or non-vector shapes.
Source code in src/scpn_phase_orchestrator/monitor/transfer_entropy.py
transfer_entropy_matrix ¶
Return the pairwise TE matrix [i, j] = TE(i → j) with zero diagonal.
Parameters¶
phase_series : FloatArray
Phase time series, shape (T, N).
n_bins : int
Number of histogram bins.
Returns¶
FloatArray The pairwise TE matrix with zero diagonal.
Raises¶
ValueError
If phase_series contains boolean aliases, numeric-string aliases,
complex values, non-finite values, or a non-matrix shape.
Source code in src/scpn_phase_orchestrator/monitor/transfer_entropy.py
Recurrence Quantification Analysis (RQA)¶
Extracts dynamical invariants from phase trajectories via recurrence plots. RQA is powerful because it works on short, non-stationary time series where spectral methods fail.
Eight measures:
| Measure | Symbol | Meaning |
|---|---|---|
| Recurrence rate | RR | Density of recurrence points |
| Determinism | DET | Fraction forming diagonal lines → deterministic dynamics |
| Average diagonal | L | Mean diagonal line length → prediction horizon |
| Max diagonal | L_max | Inversely related to max Lyapunov exponent |
| Diagonal entropy | ENTR | Complexity of deterministic structure |
| Laminarity | LAM | Fraction forming vertical lines → laminar states |
| Trapping time | TT | Mean time in laminar state |
| Max vertical | V_max | Longest laminar episode |
Cross-RQA extends this to detect synchronization between two oscillator groups by computing the cross-recurrence matrix.
Usage:
from scpn_phase_orchestrator.monitor.recurrence import rqa, cross_rqa
# Auto-RQA on a single trajectory
result = rqa(trajectory, epsilon=0.3, metric="angular")
print(f"DET={result.determinism:.3f}, LAM={result.laminarity:.3f}")
# Cross-RQA between two oscillator groups
cr = cross_rqa(traj_a, traj_b, epsilon=0.3)
print(f"Cross-DET={cr.determinism:.3f}")
References: Eckmann, Kamphorst & Ruelle 1987; Zbilut & Webber 1992; Marwan et al. 2007, Phys. Reports 438:237-329.
recurrence ¶
Recurrence analysis with a 5-backend fallback chain.
Compute surface:
- :func:
recurrence_matrix—R_ij = Θ(ε − ‖x_i − x_j‖). - :func:
cross_recurrence_matrix— cross-recurrence of two trajectories. - :func:
rqa— full Recurrence Quantification Analysis using the dispatched matrix; line-length histograms + RQA statistics stay Python-side for uniformity. - :func:
cross_rqa— cross-RQA; same pattern.
References: Eckmann, Kamphorst & Ruelle 1987, Europhys. Lett. 4:973–977; Zbilut & Webber 1992, Phys. Lett. A 171:199–203; Marwan et al. 2007, Phys. Reports 438:237–329.
Classes¶
RQAResult
dataclass
¶
RQAResult(
recurrence_rate: float,
determinism: float,
avg_diagonal: float,
max_diagonal: int,
entropy_diagonal: float,
laminarity: float,
trapping_time: float,
max_vertical: int,
)
Standard RQA measures from Marwan et al. 2007.
Functions:¶
recurrence_matrix ¶
recurrence_matrix(
trajectory: FloatArray,
epsilon: float,
metric: str = "euclidean",
) -> BoolArray
Binary recurrence matrix R_ij = ‖x_i − x_j‖ ≤ ε.
Parameters¶
trajectory : FloatArray
(T, d) or (T,) state-space trajectory.
epsilon : float
recurrence threshold.
metric : str
"euclidean" or "angular" (chord distance on S¹).
Returns¶
BoolArray
(T, T) boolean array.
Source code in src/scpn_phase_orchestrator/monitor/recurrence.py
cross_recurrence_matrix ¶
cross_recurrence_matrix(
traj_a: FloatArray,
traj_b: FloatArray,
epsilon: float,
metric: str = "euclidean",
) -> BoolArray
Cross-recurrence matrix CR_ij = ‖x_i − y_j‖ ≤ ε.
traj_a and traj_b must have the same length and
dimensionality.
Parameters¶
traj_a : FloatArray
First trajectory, shape (T, d).
traj_b : FloatArray
Second trajectory, shape (T, d).
epsilon : float
Recurrence threshold.
metric : str
Distance metric name.
Returns¶
BoolArray The binary cross-recurrence matrix.
Raises¶
ValueError If the two trajectories are incompatible.
Source code in src/scpn_phase_orchestrator/monitor/recurrence.py
rqa ¶
rqa(
trajectory: FloatArray,
epsilon: float,
l_min: int = 2,
v_min: int = 2,
metric: str = "euclidean",
) -> RQAResult
Full Recurrence Quantification Analysis.
The recurrence matrix is computed via the 5-backend dispatcher; line-length histograms and RQA statistics are computed in Python for uniformity across backends.
Parameters¶
trajectory : FloatArray
Phase-space trajectory, shape (T, d).
epsilon : float
Recurrence threshold.
l_min : int
Minimum diagonal-line length counted by RQA.
v_min : int
Minimum vertical-line length counted by RQA.
metric : str
Distance metric name.
Returns¶
RQAResult The recurrence quantification analysis result.
Source code in src/scpn_phase_orchestrator/monitor/recurrence.py
cross_rqa ¶
cross_rqa(
traj_a: FloatArray,
traj_b: FloatArray,
epsilon: float,
l_min: int = 2,
metric: str = "euclidean",
) -> RQAResult
Cross-Recurrence Quantification Analysis between two trajectories.
Parameters¶
traj_a : FloatArray
First trajectory, shape (T, d).
traj_b : FloatArray
Second trajectory, shape (T, d).
epsilon : float
Recurrence threshold.
l_min : int
Minimum diagonal-line length counted by RQA.
metric : str
Distance metric name.
Returns¶
RQAResult The cross-recurrence quantification analysis result.
Source code in src/scpn_phase_orchestrator/monitor/recurrence.py
Delay Embedding (Attractor Reconstruction)¶
Reconstructs the full state-space attractor from a scalar observable using Takens' embedding theorem. This is the prerequisite for computing correlation dimension, Lyapunov exponents from scalar data, and recurrence analysis on scalar measurements.
Three-step procedure:
- Optimal delay τ via first minimum of average mutual information (Fraser & Swinney 1986)
- Optimal dimension m via False Nearest Neighbors (Kennel, Brown & Abarbanel 1992)
- Embedding constructs vectors v(t) = [x(t), x(t-τ), ..., x(t-(m-1)τ)]
Inputs and backend outputs are validated as finite real-valued arrays. Boolean aliases and complex samples are rejected before the Rust/Mojo/Julia/Go backend chain because Takens delay coordinates, Fraser-Swinney mutual information, and false-nearest-neighbour distances are defined over real scalar observations. The Mojo subprocess adapter also validates raw stdout cardinality for delay-coordinate rows, mutual-information scalars, and nearest-neighbour distance/index pairs before numeric parsing, so blank-line insertion or missing rows cannot be normalised into a plausible embedding payload.
Usage:
from scpn_phase_orchestrator.monitor.embedding import auto_embed
# Automatic: determines τ and m, then embeds
result = auto_embed(signal)
print(f"τ={result.delay}, m={result.dimension}")
trajectory = result.trajectory # (T', m) array
# Manual control
from scpn_phase_orchestrator.monitor.embedding import (
optimal_delay, optimal_dimension, delay_embed,
)
tau = optimal_delay(signal, max_lag=100)
m = optimal_dimension(signal, delay=tau, max_dim=10)
embedded = delay_embed(signal, delay=tau, dimension=m)
References: Takens 1981, Lecture Notes in Mathematics 898:366-381.
embedding ¶
Delay-embedding analysis with a 5-backend fallback chain.
Three compute primitives on the multi-language chain:
- :func:
delay_embed— time-delay embedding matrix. - :func:
mutual_information— Fraser-Swinney 1986 average mutual information. - :func:
nearest_neighbor_distances— brute-forcek=1kNN in the embedded space (consumed by FNN).
Two wrappers stay Python-side (they are control flow over the primitives):
- :func:
optimal_delay— first local minimum of MI (Fraser-Swinney). - :func:
optimal_dimension— Kennel-Brown-Abarbanel 1992 FNN. - :func:
auto_embed— convenience that chainsoptimal_delay,optimal_dimension, and :func:delay_embed.
The Rust backend exposes native optimal_delay_rust and
optimal_dimension_rust entry points; when Rust is active those
wrappers use the native path for maximum throughput. The Python
fallback composes the primitives through the dispatcher.
MI and NN are exposed by Julia / Go / Mojo / Python only — Rust does not expose standalone MI or kNN FFI; those slots dispatch to the next available backend in the chain.
Classes¶
EmbeddingResult
dataclass
¶
Delay-embedding output.
Methods:¶
__post_init__ ¶
Validate and normalise the embedded trajectory record.
Source code in src/scpn_phase_orchestrator/monitor/embedding.py
Functions:¶
delay_embed ¶
Time-delay embedding: v(t) = [x(t), x(t+τ), x(t+2τ), …].
Parameters¶
signal : object
Real-valued time series, shape (T,).
delay : object
Embedding delay τ in samples.
dimension : object
Embedding dimension.
Returns¶
FloatArray
The time-delay embedding, shape (M, dimension).
Raises¶
ValueError
If delay or dimension is non-positive or too large for the signal.
Source code in src/scpn_phase_orchestrator/monitor/embedding.py
mutual_information ¶
Fraser-Swinney 1986 average mutual information at lag.
Parameters¶
signal : object
Real-valued time series, shape (T,).
lag : object
Lag in samples.
n_bins : object
Number of histogram bins.
Returns¶
float The average mutual information at the given lag.
Source code in src/scpn_phase_orchestrator/monitor/embedding.py
nearest_neighbor_distances ¶
Brute-force k = 1 kNN on the rows of embedded.
Parameters¶
embedded : object
Delay-embedded trajectory, shape (M, dimension).
Returns¶
tuple[FloatArray, IntArray] The nearest-neighbour distances and their indices.
Source code in src/scpn_phase_orchestrator/monitor/embedding.py
optimal_delay ¶
First local minimum of :func:mutual_information vs lag.
Parameters¶
signal : object
Real-valued time series, shape (T,).
max_lag : object
Largest lag to search.
n_bins : object
Number of histogram bins.
Returns¶
int The first mutual-information minimum, as a lag in samples.
Source code in src/scpn_phase_orchestrator/monitor/embedding.py
optimal_dimension ¶
optimal_dimension(
signal: object,
delay: object,
max_dim: object = 10,
rtol: object = 15.0,
atol: object = 2.0,
) -> int
Kennel-Brown-Abarbanel 1992 FNN to select embedding dimension.
Parameters¶
signal : object
Real-valued time series, shape (T,).
delay : object
Embedding delay τ in samples.
max_dim : object
Largest embedding dimension to test.
rtol : object
Relative tolerance for the false-nearest-neighbour test.
atol : object
Absolute tolerance for the false-nearest-neighbour test.
Returns¶
int The selected embedding dimension.
Source code in src/scpn_phase_orchestrator/monitor/embedding.py
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 | |
auto_embed ¶
optimal_delay ∘ optimal_dimension ∘ delay_embed.
Parameters¶
signal : object
Real-valued time series, shape (T,).
max_lag : object
Largest lag to search.
max_dim : object
Largest embedding dimension to test.
Returns¶
EmbeddingResult The auto-selected delay/dimension embedding result.
Source code in src/scpn_phase_orchestrator/monitor/embedding.py
Psychedelic State Metrics¶
The psychedelic monitor is a research diagnostic for phase-dispersion simulation inspired by entropic-brain hypotheses. Public Python calls and Go/Julia/Mojo entropy adapters reject boolean aliases, numeric-string aliases, complex phases, object arrays carrying Python or NumPy complex scalar aliases, non-finite phases, invalid bin counts, numeric-string entropy payloads, complex entropy payloads, and invalid coupling-reduction backend matrices before results are accepted. This preserves the circular Shannon entropy and Kuramoto coupling semantics over real-valued phase observations; it is not a clinical, dosage, or actuation interface.
Direct accelerator boundary contract: Go, Julia, and Mojo entropy adapters use
one shared float64 validation path before loading shared-library, Julia, or
subprocess runtimes. Empty phase samples return zero entropy without requiring
optional runtimes, matching the public Python fallback and preserving the
Shannon special case for an empty empirical distribution.
Direct backend entropy outputs are also revalidated as finite real scalars in
the physical interval [0, log(n_bins)] and must not arrive as numeric strings;
malformed Mojo raw stdout line counts, blank-line insertion, and non-scalar
tokens are rejected before the value reaches downstream monitor logic.
psychedelic ¶
Psychedelic phase-dispersion simulation utilities for research diagnostics.
The helpers model coupling reduction, phase entropy, and trajectory evolution through an optional backend chain while keeping a deterministic Python fallback. Inputs are constrained to finite phase vectors, finite square coupling matrices, and unit-interval coupling factors before simulation begins. The module is a research simulation surface only; it does not provide clinical guidance, actuation, dosage advice, or patient-state decisions.
Classes¶
Functions:¶
reduce_coupling ¶
Scale coupling matrix by (1 − reduction_factor).
Parameters¶
knm : FloatArray
(n, n) coupling matrix.
reduction_factor : float
fraction to reduce, in [0, 1].
Returns¶
FloatArray
Scaled copy. Zero when reduction_factor == 1.
Source code in src/scpn_phase_orchestrator/monitor/psychedelic.py
entropy_from_phases ¶
Circular Shannon entropy of a phase distribution.
Wraps phases to [0, 2π), bins into n_bins equal-width
intervals (default 36 = 10° resolution), returns entropy in
nats.
Carhart-Harris et al. 2014, Front. Hum. Neurosci. 8:20 ("The entropic brain").
Parameters¶
phases : FloatArray
Oscillator phases in radians, shape (N,).
n_bins : int
Number of histogram bins.
Returns¶
float The circular Shannon entropy of the phase distribution.
Source code in src/scpn_phase_orchestrator/monitor/psychedelic.py
simulate_psychedelic_trajectory ¶
simulate_psychedelic_trajectory(
engine: UPDEEngine,
phases: FloatArray,
omegas: FloatArray,
knm: FloatArray,
alpha: FloatArray,
reduction_schedule: list[float],
n_steps_per_level: int = 100,
) -> list[dict[str, Any]]
Progressively reduce coupling, recording observables at each level.
Models the entropic brain hypothesis: reduced serotonergic gating (coupling reduction) increases neural entropy and breaks coherent states into chimera-like patterns.
Parameters¶
engine : UPDEEngine UPDE integrator instance. phases : FloatArray initial oscillator phases, shape (n,). omegas : FloatArray natural frequencies, shape (n,). knm : FloatArray baseline coupling matrix, shape (n, n). alpha : FloatArray phase-lag matrix, shape (n, n). reduction_schedule : list[float] list of reduction_factor values (0 to 1). n_steps_per_level : int integration steps at each coupling level.
Returns¶
list[dict[str, Any]] List of dicts, one per level, with keys: reduction_factor, R, entropy, chimera_index, phases.
Raises¶
ValueError If the reduction schedule or state arrays are invalid.
Source code in src/scpn_phase_orchestrator/monitor/psychedelic.py
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 | |
Fractal Dimension¶
Estimates the fractal dimension of attractors from embedded trajectories. Two complementary measures:
Correlation dimension D₂ (Grassberger & Procaccia 1983): Counts the fraction of point pairs within distance ε, then extracts the power-law exponent C(ε) ~ ε^D₂. The scaling region is automatically identified as the range with most stable local slopes.
Kaplan-Yorke dimension D_KY (Kaplan & Yorke 1979): Computed from the Lyapunov spectrum as D_KY = j + (Σᵢ₌₁ʲ λᵢ)/|λⱼ₊₁| where j is the largest index with non-negative cumulative sum. The Kaplan-Yorke conjecture equates D_KY to the information dimension.
Usage:
from scpn_phase_orchestrator.monitor.dimension import (
correlation_dimension, kaplan_yorke_dimension,
)
# From embedded trajectory
result = correlation_dimension(trajectory, n_epsilons=30)
print(f"D2={result.D2:.2f}, scaling={result.scaling_range}")
# From Lyapunov spectrum
from scpn_phase_orchestrator.monitor.lyapunov import lyapunov_spectrum
spec = lyapunov_spectrum(phases, omegas, knm, alpha)
D_KY = kaplan_yorke_dimension(spec)
print(f"D_KY={D_KY:.2f}")
References: Grassberger & Procaccia 1983, Phys. Rev. Lett. 50:346-349; Kaplan & Yorke 1979, Lecture Notes in Mathematics 730:228-237.
dimension ¶
Fractal dimension estimation with a 5-backend fallback chain.
Implements:
- :func:
correlation_integral— Grassberger-Procaccia 1983C(ε). - :func:
correlation_dimension—D2via log-log slope onC(ε). - :func:
kaplan_yorke_dimension—D_KYfrom a Lyapunov spectrum (Kaplan & Yorke 1979).
For parity across backends the RNG that picks subsampled pairs is owned by the Python dispatcher and its seeded indices are passed to every non-Rust backend. The Rust path keeps its own internal RNG for backward compatibility; full-pairs mode is bit-exact across all five.
Classes¶
CorrelationDimensionResult
dataclass
¶
CorrelationDimensionResult(
D2: float,
epsilons: FloatArray,
C_eps: FloatArray,
slope: FloatArray,
scaling_range: tuple[float, float],
)
Result of correlation dimension estimation.
Attributes¶
D2: Estimated correlation dimension.
epsilons: (K,) array of distance thresholds used.
C_eps: (K,) correlation integral values C(ε).
slope: (K-1,) local log-log slopes.
scaling_range: (ε_lo, ε_hi) range where power law holds.
Functions:¶
correlation_integral ¶
correlation_integral(
trajectory: object,
epsilons: object,
max_pairs: object = 50000,
seed: object = 42,
) -> FloatArray
Correlation integral C(ε) = fraction of pairs within ε.
Grassberger-Procaccia 1983: C(ε) ∝ ε^{D₂} in the scaling
region.
Dispatches to the active backend. For T · (T−1)/2 ≤ max_pairs
all pairs are evaluated and every backend returns bit-exact
agreement; when subsampling is needed the Python dispatcher owns
the RNG and passes deterministic indices to every non-Rust
backend, while the Rust path keeps its in-kernel RNG for API
stability.
Parameters¶
trajectory : object
(T, d) embedded trajectory.
epsilons : object
(K,) distance thresholds.
max_pairs : object
maximum number of pairs to evaluate.
seed : object
RNG seed for pair subsampling.
Returns¶
FloatArray
(K,) array of C(ε) values.
Source code in src/scpn_phase_orchestrator/monitor/dimension.py
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 | |
correlation_dimension ¶
correlation_dimension(
trajectory: object,
n_epsilons: object = 30,
max_pairs: object = 50000,
seed: object = 42,
) -> CorrelationDimensionResult
Estimate D₂ via a log-log plateau over C(ε).
Parameters¶
trajectory : object
Phase-space trajectory, shape (T, d).
n_epsilons : object
Number of radii sampled across the log-log range.
max_pairs : object
Maximum number of point pairs sampled, or None for all.
seed : object
Seed for the deterministic RNG.
Returns¶
CorrelationDimensionResult
The estimated correlation dimension D₂ result.
Source code in src/scpn_phase_orchestrator/monitor/dimension.py
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 | |
kaplan_yorke_dimension ¶
Kaplan-Yorke / information dimension from a Lyapunov spectrum.
D_KY = j + (Σ_{i=1}^{j} λ_i) / |λ_{j+1}| where j is the
largest index such that the cumulative sum of the first j
exponents is non-negative.
Kaplan & Yorke 1979. The Kaplan-Yorke conjecture equates this to
the information dimension D₁.
Parameters¶
lyapunov_exponents : FloatArray
(N,) Lyapunov exponents.
Returns¶
float
D_KY. Returns 0.0 if the largest exponent is negative (stable fixed
point, zero-dimensional attractor).
Source code in src/scpn_phase_orchestrator/monitor/dimension.py
Poincare Sections¶
Detects when a trajectory crosses a hyperplane, extracts the crossing points (Poincare map), and computes return time statistics. Return time regularity distinguishes periodic orbits (constant return time) from chaotic ones (fluctuating return times).
Public and direct accelerator contracts reject boolean aliases, numeric-string aliases, complex values, non-finite values, malformed cardinality, and out-of-range crossing counts before section evidence reaches reports. Mojo text output keeps an explicit crossing-count header plus exact raw-line cardinality because stdout is a text transport.
Detailed documentation: Poincare section monitor
Two interfaces:
poincare_section(): general hyperplane crossing for any state-space trajectoryphase_poincare(): specialized for phase oscillators — detects when one oscillator crosses a reference phase value
Usage:
from scpn_phase_orchestrator.monitor.poincare import (
poincare_section, phase_poincare,
)
# General hyperplane section
result = poincare_section(trajectory, normal=[1, 0, 0])
print(f"Mean return time: {result.mean_return_time:.1f}")
print(f"Return time std: {result.std_return_time:.3f}")
# Phase-specific section
result = phase_poincare(phases, oscillator_idx=0, section_phase=0.0)
poincare ¶
Poincaré-section crossings with a 5-backend fallback chain.
Detects when a trajectory crosses a hyperplane, extracts the crossing points (Poincaré map), and computes return-time statistics.
For phase oscillators the natural section is the plane where one
oscillator's phase crosses a reference value. The module exposes
:func:poincare_section for generic hyperplanes and
:func:phase_poincare for the phase-specific case.
References¶
Poincaré 1899, "Les méthodes nouvelles de la mécanique céleste".
Strogatz 2015, "Nonlinear Dynamics and Chaos", Ch. 8.
Classes¶
PoincareResult
dataclass
¶
PoincareResult(
crossings: FloatArray,
crossing_times: FloatArray,
return_times: FloatArray,
mean_return_time: float,
std_return_time: float,
)
Poincaré-section output.
Methods:¶
__post_init__ ¶
Validate crossing arrays and derived return-time statistics.
Source code in src/scpn_phase_orchestrator/monitor/poincare.py
Functions:¶
poincare_section ¶
poincare_section(
trajectory: object,
normal: object,
offset: object = 0.0,
direction: str = "positive",
) -> PoincareResult
Hyperplane-crossing Poincaré section.
Parameters¶
trajectory : object
Phase-space trajectory, shape (T, d).
normal : object
Normal vector defining the Poincaré hyperplane.
offset : object
Scalar offset of the Poincaré hyperplane.
direction : str
Crossing direction to record (e.g. positive).
Returns¶
PoincareResult The Poincaré-section crossing result.
Raises¶
ValueError If the normal vector or direction is invalid.
Source code in src/scpn_phase_orchestrator/monitor/poincare.py
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 | |
return_times ¶
Shortcut: return only the return-time sequence.
Parameters¶
trajectory : object
Phase-space trajectory, shape (T, d).
normal : object
Normal vector defining the Poincaré hyperplane.
offset : object
Scalar offset of the Poincaré hyperplane.
Returns¶
FloatArray The sequence of return times between crossings.
Source code in src/scpn_phase_orchestrator/monitor/poincare.py
phase_poincare ¶
phase_poincare(
phases: object,
oscillator_idx: object = 0,
section_phase: object = 0.0,
) -> PoincareResult
Poincaré section for phase-oscillator trajectories.
Detects when phases[:, oscillator_idx] crosses
section_phase (mod 2π).
Parameters¶
phases : object
Oscillator phases in radians, shape (N,).
oscillator_idx : object
Index of the oscillator whose phase defines the section.
section_phase : object
Phase value at which to record a crossing.
Returns¶
PoincareResult The Poincaré-section result for the phase oscillator.
Source code in src/scpn_phase_orchestrator/monitor/poincare.py
Sleep Stage Classifier¶
AASM sleep staging mapped to the Kuramoto order parameter R. Classifies phases into Wake/N1/N2/N3/REM based on R thresholds and a functional desynchronisation flag. Includes ultradian (~90 min) cycle phase estimation. Detailed documentation: Sleep Staging — detailed reference
sleep_staging ¶
Sleep staging helpers derived from validated phase-synchrony time series.
The staging path maps Kuramoto R summaries and ultradian phase estimates into an AASM-like heuristic stage timeline for diagnostics and simulation review. R values, timestamps, and stage labels are validated before use, and the Rust accelerator mirrors the deterministic Python fallback rather than changing classification semantics.
Functions:¶
classify_sleep_stage ¶
Classify sleep stage from Kuramoto order parameter R.
Parameters¶
R : float order parameter in [0, 1]. functional_desync : bool True when EEG shows desynchronisation pattern characteristic of REM (low-voltage mixed-frequency), as opposed to wakeful desynchronisation.
Returns¶
str
One of "N3", "N2", "N1", "REM", "Wake".
Source code in src/scpn_phase_orchestrator/monitor/sleep_staging.py
ultradian_phase ¶
Estimate position within the ~90-minute ultradian sleep cycle.
Finds the most recent N3 epoch (cycle trough = deepest sleep) and returns the elapsed fraction of a 90-minute period since that point.
Parameters¶
timestamps : FloatArray monotonic epoch times in seconds, shape (n_epochs,). stage_history : list[str] sleep stage label per epoch, same length as timestamps.
Returns¶
float Phase in [0, 1) where 0 = cycle start (N3 onset), 0.5 ≈ mid-cycle (REM), wrapping back toward 0. Returns 0.0 if no N3 epoch is found.
Source code in src/scpn_phase_orchestrator/monitor/sleep_staging.py
Hybrid Order Monitoring¶
Hybrid classical/quantum order-parameter monitors and deterministic example fixtures for review-only cosimulation evidence.
hybrid_order ¶
Classical+quantum co-simulation order monitor.
Computes Kuramoto synchrony and qubit-partition entanglement entropy from either statevectors or density matrices using NumPy only.
Classes¶
HybridOrderParameterResult
dataclass
¶
HybridOrderParameterResult(
R: float,
Psi: float,
entanglement_entropy: float,
normalised_entanglement_entropy: float,
participation_ratio: float,
qubit_count: int,
bipartition: tuple[tuple[int, ...], tuple[int, ...]],
backend: str,
claim_boundary: str,
non_actuating: bool,
execution_disabled: bool,
record_hash: str,
)
Result of a hybrid classical-quantum order-parameter evaluation.
Methods:¶
__post_init__ ¶
Validate and normalize immutable published evidence.
Source code in src/scpn_phase_orchestrator/monitor/hybrid_order.py
to_audit_record ¶
Return a JSON-safe audit record.
Returns¶
dict[str, object] Return a JSON-safe audit record.
Source code in src/scpn_phase_orchestrator/monitor/hybrid_order.py
Functions:¶
compute_hybrid_entanglement_order_parameter ¶
compute_hybrid_entanglement_order_parameter(
phases: FloatArray,
quantum_state: object,
*,
qubit_count: int | None = None,
bipartition: tuple[tuple[int, ...], tuple[int, ...]]
| None = None,
simulator_backend: str = BACKEND,
) -> HybridOrderParameterResult
Compute classical R/Psi and the entanglement-aware hybrid order metric.
Parameters¶
phases : FloatArray
Classical phase data.
quantum_state : object
Vector of length 2**n or density matrix shape (2**n, 2**n).
qubit_count : int | None
Optional explicit qubit-count override; must match the state.
bipartition : tuple[tuple[int, ...], tuple[int, ...]] | None
Optional pair of qubit index groups for reduced entropy.
simulator_backend : str
Explicit local simulator contract. The default accepts either statevector or
density-matrix NumPy inputs; "numpy_statevector" and
"numpy_density_matrix" require the corresponding payload shape and record
that backend explicitly.
Returns¶
HybridOrderParameterResult HybridOrderParameterResult with a deterministic audit record hash.
Raises¶
ValueError If the quantum state or bipartition is invalid.
Source code in src/scpn_phase_orchestrator/monitor/hybrid_order.py
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | |
hybrid_order_examples ¶
Deterministic scenario fixtures for quantum co-simulation audit evidence.
The fixtures model hybrid order-parameter audits (entanglement entropy plus classical synchrony metrics) for non-actuating review workflows.
Classes¶
HybridStateCandidate
dataclass
¶
HybridStateCandidate(
state_id: str,
candidate_type: str,
amplitudes: ComplexArray,
entanglement_entropy: float,
order_metric_r: float,
order_metric_psi: float,
objective_labels: tuple[str, ...],
non_actuating: bool = True,
execution_disabled: bool = True,
claim_boundary: str = HybridBoundary,
)
Deterministic candidate state description for a scenario.
HybridOrderScenario
dataclass
¶
HybridOrderScenario(
domain: str,
scenario_id: str,
phases: FloatArray,
qubit_count: int,
bipartition: tuple[tuple[int, ...], tuple[int, ...]],
state_candidates: tuple[HybridStateCandidate, ...],
objective_labels: tuple[str, ...],
non_actuating: bool = True,
execution_disabled: bool = True,
claim_boundary: str = HybridBoundary,
scenario_hash: str = "",
)
One deterministic scenario with review-safe outputs.
Functions:¶
build_hybrid_order_parameter_scenarios ¶
Return deterministic, JSON-safe hybrid order-parameter scenarios.
Returns¶
tuple[dict[str, object], ...] Return deterministic, JSON-safe hybrid order-parameter scenarios.
Source code in src/scpn_phase_orchestrator/monitor/hybrid_order_examples.py
Information Replay Examples¶
Domain-specific information replay fixtures for cyber-industrial,
infrastructure, and physiology validation paths.
Physiology replay records enforce non-actuating audit boundaries, integer
sample/bin/oscillator counts, finite non-negative metrics, unit-interval
normalised Phi, and minimum partitions free of boolean aliases and
object-complex integer aliases before replay corpus relationships are accepted.
The corpus is exactly four uniquely named canonical cases with consistent
sample/bin geometry; each expected-relationship string is bound to its case and
normalised Phi is replayed from Phi and n_bins.
Infrastructure replay records apply the same engineering-proxy boundary to
power-grid and traffic-corridor replay corpora: sample/bin/oscillator counts are
integer-only, metrics are finite real non-negative values, normalised Phi is
bounded to the unit interval, and minimum partitions reject boolean aliases plus
object-complex integer aliases before the re-synchronisation/recovery ordering
contracts are accepted. The corpus is exactly four uniquely named canonical
cases with consistent sample/bin geometry; each expected-relationship string is
bound to its case and normalised Phi is replayed from Phi and n_bins.
Cyber-industrial replay records apply the same boundary to lateral-movement and
manufacturing SPC corpora so containment/recovery ordering claims are accepted
only after integer-only record counts, finite real metrics, bounded normalised
Phi, and minimum partitions free of boolean aliases and object-complex integer
aliases pass validation. The corpus is exactly four uniquely named canonical
cases with consistent sample/bin geometry; each expected-relationship string is
bound to its case and normalised Phi is replayed from Phi and n_bins.
information_replay_cyber_industrial ¶
Deterministic cyber-industrial replay benchmark records (engineering proxy).
These are proxy-only monitors for empirical replay corpora and are not theoretical IIT claims.
Functions:¶
build_cyber_industrial_integrated_information_replays ¶
build_cyber_industrial_integrated_information_replays(
*, n_samples: int = 256, n_bins: int = 8
) -> tuple[dict[str, Any], ...]
Build deterministic cyber-industrial replay audit records.
Parameters¶
n_samples : int
Number of time samples in each phase trajectory. Must be at least 32.
n_bins : int
Bin count passed to integrated_information. Must be an int > 1.
Returns¶
tuple[dict[str, Any], ...] JSON-safe replay records (one per case).
Raises¶
ValueError
If n_samples or n_bins are invalid.
Source code in src/scpn_phase_orchestrator/monitor/information_replay_cyber_industrial.py
information_replay_infrastructure ¶
Deterministic infrastructure replay records for the integrated-information proxy.
These records are empirical benchmark proxies over circular phase trajectories and are explicitly not theoretical IIT claims.
Functions:¶
build_infrastructure_integrated_information_replays ¶
build_infrastructure_integrated_information_replays(
*, n_samples: int = 256, n_bins: int = 8
) -> tuple[dict[str, Any], ...]
Build deterministic infrastructure replay records.
Parameters¶
n_samples : int
Number of trajectory samples per case. Must be an int >= 32.
n_bins : int
Histogram bins for integrated_information. Must be an int >= 2.
Returns¶
tuple[dict[str, Any], ...] JSON-safe infrastructure replay records.
Raises¶
ValueError If parameters are invalid or the corpus does not satisfy ordering and schema validation.
Source code in src/scpn_phase_orchestrator/monitor/information_replay_infrastructure.py
information_replay_physiology ¶
Deterministic physiology replay benchmark records (engineering proxy).
These records are explicit empirical replay cases used as audit-level indicators, not as theoretical IIT claims.
Functions:¶
build_physiology_integrated_information_replays ¶
build_physiology_integrated_information_replays(
*, n_samples: int = 256, n_bins: int = 8
) -> tuple[dict[str, Any], ...]
Build deterministic physiology replay audit records.
Parameters¶
n_samples : int
Number of time samples in each trajectory. Must be at least 32.
n_bins : int
Number of phase bins used by integrated_information. Must be an integer > 1.
Returns¶
tuple[dict[str, Any], ...] JSON-safe replay records (one per physiology case).
Raises¶
ValueError If inputs are invalid or the benchmark ordering cannot be established.
Source code in src/scpn_phase_orchestrator/monitor/information_replay_physiology.py
Self-Model Reconfiguration¶
Self-model error records and review-only reconfiguration examples. Phase, order-signal, and channel-weight evidence must be finite, real, and non-coercive: boolean, complex, numeric-text, arbitrary conversion objects, and broken array protocols fail before discrepancy arithmetic. Channel labels and domain/scenario identifiers are canonical non-empty strings; labels are also unique. Optional order-specific RMSE and max-absolute thresholds are applied independently and retained in the audit record, falling back to the phase thresholds only when omitted.
Frozen SelfModelErrorResult construction is itself an evidence boundary. It
replays channel lengths, aggregate and weighted metric equations, threshold
decisions, optional order evidence, non-actuation flags, backend/claim identity,
and the canonical record hash. A directly constructed contradictory result
therefore cannot be serialised as monitor evidence.
Replay-backed reconfiguration proposals preserve the same custody boundary. Direct construction canonicalises phase vectors to read-only finite real arrays and rejects boolean, complex, numeric-text, arbitrary conversion, and broken array-protocol inputs before circular-error arithmetic. Domain, scenario, proposed-action, blocked-field, boolean safety-gate, positive-threshold, and lowercase SHA-256 identities fail closed. Nested proposal evidence must be strict JSON with string keys and finite values.
Replayed scenario records admit exactly the documented schema. Validation recomputes the canonical scenario hash and independently verifies the derived threshold-safety decision and phase-error summary, so an extra unsigned field or tampering with either derived record cannot survive as review evidence. The records remain operator-review-only and execution-disabled.
self_model ¶
Deterministic self-model discrepancy monitor with auditable evidence.
Computes channel-wise and aggregate errors between observed and predicted phase trajectories, optional order-parameter errors, deterministic breach flags, and a stable evidence hash suitable for non-actuating industrial reporting.
Classes¶
SelfModelErrorThresholdConfig
dataclass
¶
SelfModelErrorThresholdConfig(
tolerance: float,
max_abs_tolerance: float,
order_tolerance: float | None = None,
order_max_abs_tolerance: float | None = None,
)
Thresholds and optional order-specific thresholds for monitor evaluation.
Methods:¶
__post_init__ ¶
Validate and canonicalise the frozen threshold configuration.
Source code in src/scpn_phase_orchestrator/monitor/self_model.py
SelfModelErrorResult
dataclass
¶
SelfModelErrorResult(
domain: str,
scenario_id: str | None,
channel_labels: tuple[str, ...],
channel_count: int,
sample_count: int,
overall_rmse: float,
overall_mae: float,
overall_max_abs_error: float,
channel_rmse: tuple[float, ...],
channel_mae: tuple[float, ...],
channel_max_abs_error: tuple[float, ...],
channel_breaches: tuple[bool, ...],
weighted_rmse: float | None,
weighted_mae: float | None,
weighted_max_abs_error: float | None,
channel_weights: tuple[float, ...] | None,
tolerance: float,
max_abs_tolerance: float,
order_tolerance: float,
order_max_abs_tolerance: float,
breached: bool,
order_rmse: float | None,
order_mae: float | None,
order_max_abs_error: float | None,
order_breached: bool | None,
claim_boundary: str,
non_actuating: bool,
execution_disabled: bool,
backend: str,
record_hash: str,
)
Deterministic result of one self-model error monitor invocation.
Methods:¶
__post_init__ ¶
to_audit_record ¶
Return a JSON-safe audit record for the computed monitor output.
Returns¶
dict[str, object] Return a JSON-safe audit record for the computed monitor output.
Source code in src/scpn_phase_orchestrator/monitor/self_model.py
Functions:¶
compute_self_model_error ¶
compute_self_model_error(
observed_phases: object,
predicted_phases: object,
*,
observed_order: object | None = None,
predicted_order: object | None = None,
channel_labels: object | None = None,
channel_weights: object | None = None,
tolerance: float = 0.0,
max_abs_tolerance: float = 0.0,
order_tolerance: float | None = None,
order_max_abs_tolerance: float | None = None,
domain: str = "self_model",
scenario_id: str | None = None,
) -> SelfModelErrorResult
Compute deterministic channel-wise discrepancy metrics for a self-model pair.
Parameters¶
observed_phases : object
Observed phase trajectories shaped (C, T) or (T,).
predicted_phases : object
Predicted phase trajectories with matching shape.
observed_order : object | None
Optional observed order signal, shape (C,).
predicted_order : object | None
Optional predicted order signal, shape (C,).
channel_labels : object | None
Optional channel names for audit output.
channel_weights : object | None
Optional positive weights for channels.
tolerance : float
Global RMSE threshold used for pass/fail decisions.
max_abs_tolerance : float
Global max-abs threshold used for pass/fail decisions.
order_tolerance : float | None
Optional order-signal RMSE threshold; defaults to tolerance.
order_max_abs_tolerance : float | None
Optional order-signal max-abs threshold; defaults to
max_abs_tolerance.
domain : str
Logical monitor domain identifier.
scenario_id : str | None
Optional scenario identifier for evidence context.
Returns¶
SelfModelErrorResult SelfModelErrorResult with deterministic hash and audit payload.
Raises¶
ValueError If the observed or predicted inputs are invalid.
Source code in src/scpn_phase_orchestrator/monitor/self_model.py
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | |
self_model_examples ¶
Deterministic replay-backed self-model reconfiguration examples.
These fixtures remain review-only and serialisable evidence for industrial control reconfiguration proposals. They intentionally disable execution and require operator review.
Classes¶
SelfModelErrorResult
dataclass
¶
SelfModelErrorResult(
domain: str,
scenario_id: str | None,
channel_labels: tuple[str, ...],
channel_count: int,
sample_count: int,
overall_rmse: float,
overall_mae: float,
overall_max_abs_error: float,
channel_rmse: tuple[float, ...],
channel_mae: tuple[float, ...],
channel_max_abs_error: tuple[float, ...],
channel_breaches: tuple[bool, ...],
weighted_rmse: float | None,
weighted_mae: float | None,
weighted_max_abs_error: float | None,
channel_weights: tuple[float, ...] | None,
tolerance: float,
max_abs_tolerance: float,
order_tolerance: float,
order_max_abs_tolerance: float,
breached: bool,
order_rmse: float | None,
order_mae: float | None,
order_max_abs_error: float | None,
order_breached: bool | None,
claim_boundary: str,
non_actuating: bool,
execution_disabled: bool,
backend: str,
record_hash: str,
)
Deterministic result of one self-model error monitor invocation.
Methods:¶
__post_init__ ¶
to_audit_record ¶
Return a JSON-safe audit record for the computed monitor output.
Returns¶
dict[str, object] Return a JSON-safe audit record for the computed monitor output.
Source code in src/scpn_phase_orchestrator/monitor/self_model.py
SelfModelReconfigurationProposal
dataclass
¶
SelfModelReconfigurationProposal(
domain: str,
scenario_id: str,
predicted_phase: FloatArray,
observed_phase: FloatArray,
error_threshold: float,
self_model_error: SelfModelErrorResult
| dict[str, object],
proposed_reconfiguration_action: str,
serialisable_evidence: dict[str, Any],
blocked_live_execution_fields: tuple[str, ...],
operator_review_required: bool = True,
execution_disabled: bool = True,
claim_boundary: str = SelfModelBoundary,
scenario_hash: str = "",
)
Single replay-backed, review-only self-model reconfiguration scenario.
Methods:¶
__post_init__ ¶
Validate and canonicalise directly constructed proposal evidence.
Source code in src/scpn_phase_orchestrator/monitor/self_model_examples.py
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 | |
to_audit_record ¶
Return a deterministic JSON-safe audit record.
Returns¶
dict[str, Any] Return a deterministic JSON-safe audit record.
Raises¶
ValueError If the proposal fields are inconsistent.
Source code in src/scpn_phase_orchestrator/monitor/self_model_examples.py
Functions:¶
build_self_model_reconfiguration_examples ¶
Build deterministic review-only self-model reconfiguration evidence records.
Returns¶
tuple[dict[str, Any], ...] Build deterministic review-only self-model reconfiguration evidence records.
Source code in src/scpn_phase_orchestrator/monitor/self_model_examples.py
Early-Warning Detector Suite¶
Three complementary passive detectors share one alarm contract — a robust
(median / MAD) z-score against a leading baseline, a relative-change gate, and a
persistence run — so they can be compared, and fused, at a matched false-alarm
rate. Each reads a different moment of an approaching synchronisation transition
(a seizure onset, a grid coherence collapse): critical slowing down reads the
second-moment variance / autocorrelation rise, rising synchronisation reads the
first-moment Kuramoto order-parameter rise, and the
ordinal-transition-entropy detector reads a
regularisation drop. All are passive — they read observables and emit a warning
record; they never actuate. A fair head-to-head
(bench/early_warning_leadtime.py) established that the detection is a
commodity, so the value is the auditable, sealed
early-warning evidence around
the alarm, not a claim that any one detector warns earlier.
Explosive-sync signals are non-empty, finite, real, and non-coercive. Its published warning record owns read-only array copies and replays the entropy mean, baseline median/MAD, derived scores, window grid, and sustained-breach decision before summary or metric export.
Critical Slowing Down¶
Rising variance and lag-one autocorrelation of an observable ahead of a critical transition (Scheffer et al. 2009; Dakos et al. 2012) — the classical early-warning baseline, implemented as a passive windowed monitor. Either a rising variance or a lengthening autocorrelation is a valid warning; requiring both understates the classical method.
critical_slowing_down ¶
Critical-slowing-down early warning from rising variance and autocorrelation.
The established generic early-warning framework for an approaching critical
transition is critical slowing down: as a system nears a bifurcation its
recovery from perturbations lengthens, which shows up as a rising variance and a
rising lag-one autocorrelation of the observable ahead of the transition. This
module implements that classical indicator as a passive monitor, so it can serve
as the literature baseline against the ordinal-transition-entropy detector in
monitor/explosive_sync.py.
critical_slowing_down_warning slides a window across a multi-node signal
array, computes each window's mean-detrended variance and lag-one autocorrelation
per node, aggregates them across nodes, and raises a fail-early alarm when either
indicator rises a robust (median / MAD) margin above its leading baseline (a
rising variance or a lengthening autocorrelation is each a valid slowing-down
warning; requiring both understates the classical method). The
alarm logic — robust z-score against a leading baseline, a relative-change gate,
and a persistence run — mirrors explosive_sync_warning exactly (sign
reversed, since slowing-down is a rise and entropy regularisation is a drop),
so a lead-time comparison between the two is a same-alarm, different-indicator
test rather than an artefact of differing detector machinery. The monitor is
passive: it reads observables and emits a warning record; it never actuates.
References¶
- Scheffer et al. 2009, Nature 461, 53 — early-warning signals for critical transitions.
- Dakos, Carpenter, Brock, Ellison, Guttal, Ives, Kéfi, Livina, Seekell, van Nes & Scheffer 2012, PLoS ONE 7, e41010 — methods for detecting early warning signals of critical transitions in time series.
Classes¶
CriticalSlowingDownWarning
dataclass
¶
CriticalSlowingDownWarning(
window_starts: IntArray,
variance_index: FloatArray,
autocorrelation_index: FloatArray,
combined_z: FloatArray,
robust_z_variance: FloatArray,
robust_z_autocorrelation: FloatArray,
relative_rise: FloatArray,
baseline_variance: float,
baseline_autocorrelation: float,
baseline_scale_variance: float,
baseline_scale_autocorrelation: float,
n_baseline_windows: int,
warning_triggered: bool,
warning_window: int | None,
warning_sample: int | None,
window: int,
step: int,
z_threshold: float,
rise_threshold: float,
persistence: int,
)
Result of a critical-slowing-down early-warning sweep.
Attributes¶
window_starts : IntArray
First sample index of each analysis window, shape (W,).
variance_index : FloatArray
Mean per-node window variance per window, shape (W,).
autocorrelation_index : FloatArray
Mean per-node lag-one autocorrelation per window, shape (W,).
combined_z : FloatArray
Per-window rising indicator: the larger of the variance and
autocorrelation robust z-scores, shape (W,). Large positive means
at least one indicator rose — the sensitive critical-slowing-down
signature (either a rising variance or a lengthening autocorrelation is
a valid early warning; requiring both agrees less often and understates
the classical method).
robust_z_variance, robust_z_autocorrelation : FloatArray
Median / MAD robust z-scores of each indicator against its baseline,
shape (W,).
relative_rise : FloatArray
Larger of the two indicators' fractional rise above baseline, shape
(W,).
baseline_variance, baseline_autocorrelation : float
Median of each indicator over the leading baseline windows.
baseline_scale_variance, baseline_scale_autocorrelation : float
Robust scale (1.4826 × MAD) of each baseline.
n_baseline_windows : int
Number of leading windows used to fit the baseline.
warning_triggered : bool
Whether a sustained rise crossed both the z and relative gates.
warning_window : int | None
Index of the first window of the triggering run, or None.
warning_sample : int | None
Sample index window_starts[warning_window], or None.
window, step : int
Echoed analysis parameters.
z_threshold, rise_threshold : float
Echoed alarm gates.
persistence : int
Echoed number of consecutive breaching windows required to alarm.
Methods:¶
summary ¶
Return a flat scalar summary for logging or metric export.
Returns¶
dict[str, float | int | bool | None] Window/baseline counts, the peak rising z-score, the maximum relative rise, and the alarm verdict.
Source code in src/scpn_phase_orchestrator/monitor/critical_slowing_down.py
Functions:¶
critical_slowing_down_warning ¶
critical_slowing_down_warning(
signals: FloatArray,
*,
window: int = 128,
step: int = 16,
baseline_fraction: float = 0.25,
min_baseline_windows: int = 3,
z_threshold: float = 3.0,
rise_threshold: float = 0.1,
persistence: int = 2,
) -> CriticalSlowingDownWarning
Sweep a multi-node signal for a critical-slowing-down warning.
Parameters¶
signals : FloatArray
Per-node scalar observables, shape (N, T); a one-dimensional array
is treated as a single node.
window : int
Analysis window length in samples; must be at least three to admit a
lag-one autocorrelation estimate.
step : int
Hop between consecutive window starts in samples.
baseline_fraction : float
Leading fraction of windows used to fit the baseline, in (0, 1).
min_baseline_windows : int
Lower bound on the number of baseline windows.
z_threshold : float
Robust z-score magnitude above which a window breaches the rise gate.
rise_threshold : float
Minimum fractional rise above the baseline median to breach the gate.
persistence : int
Number of consecutive breaching windows required to raise the alarm.
Returns¶
CriticalSlowingDownWarning The per-window variance and autocorrelation fields, baseline fit, and the alarm decision.
Raises¶
ValueError If the inputs are malformed or the window does not fit the series.
Source code in src/scpn_phase_orchestrator/monitor/critical_slowing_down.py
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | |
critical_slowing_down_multiscale_warning ¶
critical_slowing_down_multiscale_warning(
signals: FloatArray,
*,
windows: Sequence[int] | None = None,
step: int = 16,
baseline_fraction: float = 0.25,
min_baseline_windows: int = 3,
z_threshold: float = 3.0,
rise_threshold: float = 0.1,
persistence: int = 2,
aggregation: str = "max",
) -> CriticalSlowingDownWarning
Multi-scale critical-slowing-down warning.
Variance and lag-one autocorrelation are computed at every window start for each of the supplied window lengths. The per-scale indices are then aggregated across scales on the shared window grid before the robust-rise alarm rule is applied. This lets the detector respond to precursors that emerge at horizons shorter or longer than a single fixed window.
Parameters¶
signals : FloatArray
Per-node scalar observables, shape (N, T); a one-dimensional array
is treated as a single node.
windows : sequence of int or None
Window lengths to combine. Defaults to (64, 128, 256).
step : int
Hop between consecutive window starts in samples; shared by all scales.
baseline_fraction : float
Leading fraction of windows used to fit the baseline.
min_baseline_windows : int
Lower bound on the number of baseline windows.
z_threshold : float
Robust z-score gate applied to the aggregated combined score.
rise_threshold : float
Minimum fractional rise above the baseline median.
persistence : int
Number of consecutive breaching windows required to raise the alarm.
aggregation : str
How to aggregate scales: "max" (recommended) takes the strongest
scale per window; "mean" averages scales.
Returns¶
CriticalSlowingDownWarning The aggregated per-window fields, baseline fit, and alarm decision.
Raises¶
ValueError
If windows contains duplicate lengths, if aggregation is neither
"max" nor "mean", if any window is smaller than three samples,
or if the largest window exceeds the series length. Parameter validation
also raises ValueError for non-positive integers or fractions
outside the unit interval.
Source code in src/scpn_phase_orchestrator/monitor/critical_slowing_down.py
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | |
surrogate_score_threshold ¶
surrogate_score_threshold(
signals: FloatArray,
*,
n_surrogates: int = 200,
percentile: float = 95.0,
block_length: int | None = None,
window: int = 128,
step: int = 16,
baseline_fraction: float = 0.25,
min_baseline_windows: int = 3,
persistence: int = 2,
rng: int | Generator | None = None,
) -> float
Return a false-alarm threshold from a block-bootstrap null distribution.
The order-parameter series is resampled by circular block bootstrap. For each
surrogate, the critical-slowing-down combined score is computed with a zero
z-threshold and the maximum post-baseline score is recorded. The returned
threshold is the requested percentile of those maxima and can be passed as
z_threshold to :func:critical_slowing_down_warning to control the
empirical false-alarm probability.
Parameters¶
signals : FloatArray
Per-node scalar observables, shape (N, T) or one-dimensional.
n_surrogates : int
Number of bootstrap surrogates to draw.
percentile : float
Percentile of the surrogate max-score distribution to return as the
threshold; e.g. 95.0 targets roughly a 5% false-alarm rate.
block_length : int or None
Bootstrap block length in samples; defaults to max(1, T // 20).
window, step : int
Analysis window length and hop passed to the underlying warning sweep.
baseline_fraction : float
Baseline fraction passed to the underlying warning sweep.
min_baseline_windows : int
Minimum baseline windows passed to the underlying warning sweep.
persistence : int
Persistence passed to the underlying warning sweep.
rng : int or np.random.Generator or None
Seed or generator for reproducible bootstrapping.
Returns¶
float A positive threshold on the combined score.
Raises¶
ValueError
If percentile exceeds 100, or if any count or length parameter is
not a positive integer.
Source code in src/scpn_phase_orchestrator/monitor/critical_slowing_down.py
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | |
Critical-slowing-down signal ingress requires a non-empty finite real one- or
two-dimensional array and rejects boolean, complex, and text-coercible aliases.
Multiscale windows are a non-empty integer sequence. Surrogate RNG custody accepts
only a non-negative Python/NumPy integer seed, an explicit NumPy Generator, or
None; boolean seeds are rejected before bootstrap.
Rising Synchronisation¶
A sustained rise in the windowed Kuramoto order parameter
R(t) = |⟨e^{iθ}⟩|, the first-moment coherence precursor complementary to the
slowing-down and entropy indicators.
synchronisation ¶
Rising-synchronisation early warning from the Kuramoto order parameter.
A synchronisation transition — the abrupt collective phase-locking behind a
seizure onset or a grid coherence collapse — is preceded by the population's
phase coherence climbing toward the locked state. The Kuramoto order parameter
R(t) = |⟨e^{iθ}⟩| measures that coherence directly, so a sustained rise in
its windowed level is a first-moment early-warning signal complementary to the
second-moment critical-slowing-down indicators (monitor/critical_slowing_down.py,
which read a variance/autocorrelation rise) and to the ordinal-transition-
entropy detector (monitor/explosive_sync.py, which reads a regularisation
drop). On a real scalp-EEG seizure the order parameter is the signal that
carries the leading precursor, which is why it is a first-class member of the
early-warning detector suite.
synchronisation_warning computes the instantaneous order parameter across the
per-node phases, averages it within each sliding window, and raises a fail-early
alarm when the windowed coherence rises a robust (median / MAD) margin above its
leading baseline. The alarm logic — robust z-score against a leading baseline, a
relative-change gate, and a persistence run — is the suite's shared contract, so
this detector is directly comparable with the others at a matched false-alarm
rate. The monitor is passive: it reads phases and emits a warning record; it
never actuates.
References¶
- Kuramoto 1984, Chemical Oscillations, Waves, and Turbulence — the order parameter of coupled phase oscillators.
- Scheffer et al. 2009, Nature 461, 53 — early-warning signals for critical transitions (the framework this contributes a synchrony indicator to).
Classes¶
SynchronisationWarning
dataclass
¶
SynchronisationWarning(
window_starts: IntArray,
synchrony_index: FloatArray,
robust_z: FloatArray,
relative_rise: FloatArray,
baseline_median: float,
baseline_scale: float,
n_baseline_windows: int,
warning_triggered: bool,
warning_window: int | None,
warning_sample: int | None,
window: int,
step: int,
z_threshold: float,
rise_threshold: float,
persistence: int,
)
Result of a rising-synchronisation early-warning sweep.
Attributes¶
window_starts : IntArray
First sample index of each analysis window, shape (W,).
synchrony_index : FloatArray
Mean Kuramoto order parameter within each window, shape (W,); the
headline coherence level in [0, 1].
robust_z : FloatArray
Median / MAD robust z-score of synchrony_index against the baseline,
shape (W,). Strongly positive means a sharp coherence rise.
relative_rise : FloatArray
Fractional rise of synchrony_index above the baseline median, shape
(W,).
baseline_median : float
Median synchrony index over the leading baseline windows.
baseline_scale : float
Robust scale (1.4826 × MAD) of the baseline windows.
n_baseline_windows : int
Number of leading windows used to fit the baseline.
warning_triggered : bool
Whether a sustained rise crossed both the z and relative-rise gates.
warning_window : int | None
Index of the first window of the triggering run, or None.
warning_sample : int | None
Sample index window_starts[warning_window], or None.
window, step : int
Echoed analysis parameters.
z_threshold, rise_threshold : float
Echoed alarm gates.
persistence : int
Echoed number of consecutive breaching windows required to alarm.
Methods:¶
summary ¶
Return a flat scalar summary for logging or metric export.
Returns¶
dict[str, float | int | bool | None] Window/baseline counts, the baseline coherence, the peak rising z-score, the maximum relative rise, and the alarm verdict.
Source code in src/scpn_phase_orchestrator/monitor/synchronisation.py
Functions:¶
synchronisation_warning ¶
synchronisation_warning(
phases: FloatArray,
*,
window: int = 128,
step: int = 16,
baseline_fraction: float = 0.25,
min_baseline_windows: int = 3,
z_threshold: float = 3.0,
rise_threshold: float = 0.1,
persistence: int = 2,
) -> SynchronisationWarning
Sweep per-node phases for a rising-synchronisation warning.
Parameters¶
phases : FloatArray
Per-node instantaneous phases in radians, shape (N, T) with at least
two nodes (synchrony is undefined for a single oscillator).
window : int
Analysis window length in samples; must be at least one.
step : int
Hop between consecutive window starts in samples.
baseline_fraction : float
Leading fraction of windows used to fit the baseline, in (0, 1).
min_baseline_windows : int
Lower bound on the number of baseline windows.
z_threshold : float
Robust z-score magnitude above which a window breaches the rise gate.
rise_threshold : float
Minimum fractional rise above the baseline median to breach the gate.
persistence : int
Number of consecutive breaching windows required to raise the alarm.
Returns¶
SynchronisationWarning The per-window coherence field, baseline fit, and the alarm decision.
Raises¶
ValueError If the inputs are malformed or the window does not fit the series.
Source code in src/scpn_phase_orchestrator/monitor/synchronisation.py
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 | |
Ensemble Fusion¶
Fuses the suite over one window grid: a weighted rule (weighted mean of the
members' oriented z-scores against a scalar threshold, calibratable to a matched
false-alarm rate) and a vote rule (at least min_votes members breach their
own gate). The gain from fusion must be reported as an improvement in
matched-false-alarm lead time, never as a raw detection rate — an OR of the
members trivially raises the rate by spending the false-alarm budget.
ensemble_warning ¶
Ensemble early warning that fuses the detector suite into one decision.
The early-warning suite carries three complementary passive indicators of an
approaching synchronisation transition, each on its own observable: critical
slowing down (:mod:~scpn_phase_orchestrator.monitor.critical_slowing_down,
rising variance / autocorrelation), rising synchronisation
(:mod:~scpn_phase_orchestrator.monitor.synchronisation, the Kuramoto order
parameter) and ordinal-transition entropy
(:mod:~scpn_phase_orchestrator.monitor.explosive_sync, a regularisation drop).
A fair head-to-head (bench/early_warning_leadtime.py) showed no single
indicator dominates, so the integration question is how to combine them without
cheating the false-alarm budget.
ensemble_warning fuses the members' per-window oriented evidence — each
member's robust z-score re-signed so that larger always means more anomalous —
that share a common window grid. Two rules are offered:
weighted— a weighted mean of the oriented z-scores crossed against a single scalarfused_threshold. The threshold is continuous, so it can be calibrated to a matched false-alarm rate on a no-transition null exactly like a single detector; this is the rule to use for a fair lead-time comparison.vote— an alarm when at leastmin_votesmembers individually breach their own gate. Interpretable and conservative, but its knob is discrete (one operating point per vote count), so it calibrates coarsely.
Both rules require a sustained persistence run over the post-baseline windows
(the fused baseline is the widest of the members', so no member alarms while still
inside its baseline). The gain from fusion must be shown as an improvement in
matched-false-alarm lead time, never as a raw detection rate: an OR of the
members (min_votes = 1) trivially raises the detection rate by spending the
false-alarm budget, which is not an advantage. The monitor is passive: it reads
the members' warnings and emits a fused record; it never actuates.
References¶
- Scheffer et al. 2009, Nature 461, 53 — generic early-warning signals for critical transitions (the framework the fused indicators contribute to).
- Kittler, Hatef, Duin & Matas 1998, IEEE TPAMI 20, 226 — combining classifiers (the sum / vote fusion rules this monitor specialises to z-score evidence).
Classes¶
MemberEvidence
dataclass
¶
MemberEvidence(
name: str,
native_direction: str,
window_starts: IntArray,
oriented_z: FloatArray,
native_robust_z: FloatArray,
breaches: BoolArray,
baseline_median: float,
z_threshold: float,
n_baseline_windows: int,
)
One suite member's per-window evidence, aligned on the shared grid.
Attributes¶
name : str
Member label, e.g. critical_slowing_down.
native_direction : str
:data:RISE or :data:DROP — the member's own alarm direction, kept so
the fused record can report each contribution with its native sign.
window_starts : IntArray
First sample index of each window; must match across members.
oriented_z : FloatArray
The member's robust z-score re-signed so larger means more anomalous
(native_robust_z for a rise, its negation for a drop).
native_robust_z : FloatArray
The member's own signed robust z-score.
breaches : BoolArray
The member's own per-window gate decision (its z and relative gates and
the post-baseline mask), used by the vote rule.
baseline_median : float
Median of the member's raw indicator over its baseline windows (for the
multi-indicator critical-slowing-down member this is the variance
indicator's baseline).
z_threshold : float
The member's robust z-score gate.
n_baseline_windows : int
Number of leading windows the member fitted its baseline on.
MemberContribution
dataclass
¶
MemberContribution(
name: str,
direction: str,
robust_z: float,
baseline_median: float,
z_threshold: float,
breached: bool,
)
A member's snapshot at the reported window of a fused alarm.
Attributes¶
name : str Member label. direction : str The member's native alarm direction. robust_z : float The member's signed robust z-score at the reported window. baseline_median : float Median of the member's raw indicator over its baseline windows. z_threshold : float The member's robust z-score gate. breached : bool Whether the member's own gate held at the reported window.
EnsembleWarning
dataclass
¶
EnsembleWarning(
window_starts: IntArray,
fused_score: FloatArray,
vote_count: IntArray,
rule: str,
fused_threshold: float,
min_votes: int,
persistence: int,
n_baseline_windows: int,
member_names: tuple[str, ...],
contributions: tuple[MemberContribution, ...],
warning_triggered: bool,
warning_window: int | None,
warning_sample: int | None,
)
Result of a fused ensemble early-warning sweep.
Attributes¶
window_starts : IntArray
First sample index of each analysis window, shape (W,).
fused_score : FloatArray
Weighted mean of the members' oriented z-scores per window, shape
(W,); the headline combined evidence (always computed, both rules).
vote_count : IntArray
Number of members breaching their own gate per window, shape (W,).
rule : str
:data:WEIGHTED_RULE or :data:VOTE_RULE.
fused_threshold : float
Scalar gate on fused_score used by the weighted rule.
min_votes : int
Vote count required by the vote rule.
persistence : int
Consecutive breaching windows required to alarm.
n_baseline_windows : int
Fused baseline boundary (the widest member baseline); no window before it
may alarm.
member_names : tuple[str, ...]
Fused member labels, in order.
contributions : tuple[MemberContribution, ...]
Each member's snapshot at the reported window (the alarm window when
triggered, else the closest fused approach).
warning_triggered : bool
Whether a sustained fused breach was found.
warning_window : int | None
Index of the first window of the triggering run, or None.
warning_sample : int | None
Sample index window_starts[warning_window], or None.
Methods:¶
summary ¶
Return a flat scalar summary for logging or metric export.
Returns¶
dict[str, float | int | bool | str | None] The fusion rule, window count, the peak fused score, the peak vote count, and the alarm verdict.
Source code in src/scpn_phase_orchestrator/monitor/ensemble_warning.py
Functions:¶
ensemble_warning ¶
ensemble_warning(
members: list[MemberEvidence]
| tuple[MemberEvidence, ...],
*,
rule: str = WEIGHTED_RULE,
weights: list[float] | tuple[float, ...] | None = None,
fused_threshold: float = 3.0,
min_votes: int = 2,
persistence: int = 2,
) -> EnsembleWarning
Fuse aligned suite-member evidence into one early-warning decision.
Parameters¶
members : sequence of MemberEvidence
At least one member, all sharing an identical window_starts grid.
rule : str
:data:WEIGHTED_RULE (weighted-mean oriented z against fused_threshold)
or :data:VOTE_RULE (at least min_votes members breach).
weights : sequence of float or None
Per-member weights for the weighted rule; defaults to equal weights. Each
must be a positive finite real and the length must match members.
fused_threshold : float
Scalar gate on the weighted-mean oriented z-score; must be non-negative.
min_votes : int
Members that must breach for the vote rule; 1 ≤ min_votes ≤ len(members).
persistence : int
Consecutive breaching windows required to alarm.
Returns¶
EnsembleWarning The fused score, vote count, per-member contributions, and the alarm decision.
Raises¶
ValueError If the members are empty or misaligned, the rule is unknown, the weights are malformed, or a control is out of range.
Source code in src/scpn_phase_orchestrator/monitor/ensemble_warning.py
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 | |
member_from_critical_slowing_down ¶
Adapt a critical-slowing-down warning into fused member evidence.
The member's oriented z-score is the detector's combined_z (already a
rise), and its gate reconstructs the detector's own per-window breach mask.
Parameters¶
warning : object
A
:class:~scpn_phase_orchestrator.monitor.critical_slowing_down.CriticalSlowingDownWarning
to align onto the shared fusion grid.
Returns¶
MemberEvidence
The oriented per-window evidence, with combined_z as the oriented
z-score and the detector's own per-window breach mask reconstructed.
Raises¶
ValueError
If warning is not a
:class:~scpn_phase_orchestrator.monitor.critical_slowing_down.CriticalSlowingDownWarning.
Source code in src/scpn_phase_orchestrator/monitor/ensemble_warning.py
member_from_synchronisation ¶
Adapt a rising-synchronisation warning into fused member evidence.
Parameters¶
warning : object
A
:class:~scpn_phase_orchestrator.monitor.synchronisation.SynchronisationWarning
to align onto the shared fusion grid.
Returns¶
MemberEvidence The oriented per-window evidence, with the order-parameter robust z-score as the oriented score and the detector's own breach mask.
Raises¶
ValueError
If warning is not a
:class:~scpn_phase_orchestrator.monitor.synchronisation.SynchronisationWarning.
Source code in src/scpn_phase_orchestrator/monitor/ensemble_warning.py
member_from_transition_entropy ¶
Adapt an ordinal-transition-entropy warning into fused member evidence.
The member warns on a drop, so its oriented z-score is the negation of the
detector's signed robust_z.
Parameters¶
warning : object
An
:class:~scpn_phase_orchestrator.monitor.explosive_sync.ExplosiveSyncWarning
to align onto the shared fusion grid.
Returns¶
MemberEvidence
The oriented per-window evidence; because the member warns on a drop,
the oriented z-score is the negation of the detector's signed
robust_z.
Raises¶
ValueError
If warning is not an
:class:~scpn_phase_orchestrator.monitor.explosive_sync.ExplosiveSyncWarning.
Source code in src/scpn_phase_orchestrator/monitor/ensemble_warning.py
Each MemberEvidence record owns immutable copies of one non-empty, strictly
increasing window grid and aligned finite-real/boolean vectors. Member names are
unique, native direction is canonical, and oriented z-scores must equal the
native score for rising alarms or its negation for dropping alarms. Weighted
fusion does not apply the vote-only quorum upper bound; vote fusion still
requires min_votes <= member_count.
Domain-Adaptable Suite¶
Runs the three members and the weighted fusion over one neutral observable
bundle (SuiteObservables: per-node phases, their sin(phase) projection, and
the cross-node order parameter), so a scalp-EEG seizure, a grid coherence
collapse, and a cardiac arrhythmia are screened by the same suite. Each is a
synchronisation transition in a population of coupled oscillators; the only
per-domain work is a DomainObservableAdapter that turns that domain's raw
signals into the bundle. The suite itself is domain-neutral — it never learns
where the observables came from.
early_warning_suite ¶
Domain-adaptable early-warning suite over a neutral phase-observable contract.
The early-warning detectors — critical slowing down
(:mod:~scpn_phase_orchestrator.monitor.critical_slowing_down), rising
synchronisation (:mod:~scpn_phase_orchestrator.monitor.synchronisation), and
ordinal-transition entropy (:mod:~scpn_phase_orchestrator.monitor.explosive_sync)
— read generic arrays, not any one domain. The reason a scalp-EEG seizure, a grid
coherence collapse, and a cardiac arrhythmia can all be screened by the same
suite is that each is a synchronisation transition in a population of coupled
oscillators; the only per-domain work is turning that domain's raw signals into
three phase observables. This module makes that the explicit contract.
:class:SuiteObservables is the neutral bundle every detector reads: the
per-node instantaneous phases (rising synchronisation), their projection
sin(phase) (ordinal-transition entropy), and the cross-node Kuramoto order
parameter R(t) = |⟨e^{iφ}⟩| (critical slowing down). A
:class:DomainObservableAdapter is anything that turns a domain's raw signal
block into that bundle — the scalp-EEG band-pass/Hilbert/decimation pipeline is
one adapter; a cardiac ECG or grid PMU pipeline is another. Given the bundle,
:func:run_early_warning_suite runs all three members and the weighted fusion
under one alarm contract, returning a :class:SuiteWarnings, with no knowledge of
where the observables came from.
The suite is passive: it reads observables and emits warning records; it never
actuates. Sealing an alarm into auditable evidence is
:mod:~scpn_phase_orchestrator.assurance.early_warning_evidence; calibrating a
matched false-alarm threshold and measuring lead time on a labelled corpus is a
validation harness, not this module.
References¶
- Scheffer et al. 2009, Nature 461, 53 — generic early-warning signals for critical transitions.
- Kuramoto 1984, Chemical Oscillations, Waves, and Turbulence — the order parameter of coupled phase oscillators.
Classes¶
SuiteObservables
dataclass
¶
SuiteObservables(
phases: FloatArray,
phase_field: FloatArray,
order_parameter: FloatArray,
sampling_rate_hz: float,
)
The neutral phase observables every early-warning detector reads.
Attributes¶
phases : FloatArray
Per-node instantaneous phase in radians, shape (N, T) with at least
two nodes; the rising-synchronisation input.
phase_field : FloatArray
Per-node projection sin(phase), shape (N, T); the
ordinal-transition-entropy input.
order_parameter : FloatArray
Cross-node Kuramoto order parameter R(t) = |⟨e^{iφ}⟩| in [0, 1],
shape (T,); the critical-slowing-down input.
sampling_rate_hz : float
Sampling rate of the observables, in hertz; converts a sample lead into
seconds when an alarm is sealed.
Attributes¶
Methods:¶
__post_init__ ¶
Validate the observable shapes and ranges are mutually consistent.
Source code in src/scpn_phase_orchestrator/monitor/early_warning_suite.py
SuiteWarnings
dataclass
¶
SuiteWarnings(
critical_slowing_down: CriticalSlowingDownWarning,
synchronisation: SynchronisationWarning,
transition_entropy: ExplosiveSyncWarning,
ensemble: EnsembleWarning,
)
The four early-warning records the suite emits over one observable bundle.
Attributes¶
critical_slowing_down : CriticalSlowingDownWarning
The variance / autocorrelation rise on the order parameter.
synchronisation : SynchronisationWarning
The order-parameter rise on the per-node phases.
transition_entropy : ExplosiveSyncWarning
The ordinal-transition-entropy drop on the sin(phase) field.
ensemble : EnsembleWarning
The weighted fusion of the three members.
Methods:¶
triggered ¶
Return each detector's alarm verdict keyed by :data:SUITE_DETECTORS.
Returns¶
dict[str, bool]
One label -> warning_triggered entry per detector, in
:data:SUITE_DETECTORS order — the three members then the fusion.
Source code in src/scpn_phase_orchestrator/monitor/early_warning_suite.py
DomainObservableAdapter ¶
Bases: Protocol
A domain's bridge from raw signals to :class:SuiteObservables.
An adapter names its domain and turns a raw per-channel signal block into the neutral observable bundle the suite reads. The scalp-EEG band-pass / Hilbert / decimation pipeline is one adapter; a cardiac ECG or grid PMU pipeline is another. Adapters carry their own domain configuration, so the suite stays ignorant of the domain.
Attributes¶
Methods:¶
observables ¶
Return the neutral observable bundle for one raw recording.
Parameters¶
raw : FloatArray One raw per-channel recording block in the adapter's native domain units, e.g. band-passed scalp-EEG samples or PMU frequency traces.
Returns¶
SuiteObservables The neutral phase-observable bundle the suite reads.
Source code in src/scpn_phase_orchestrator/monitor/early_warning_suite.py
Functions:¶
observables_from_phases ¶
Build the neutral observable bundle from a per-node phase field.
Most adapters end at a reconstructed per-node phase; this derives the
remaining two observables — the sin(phase) projection and the cross-node
order parameter — so an adapter need only supply phases and a rate.
Parameters¶
phases : FloatArray
Per-node phase in radians, shape (N, T) with at least two nodes.
sampling_rate_hz : float
Sampling rate of the phases, in hertz.
Returns¶
SuiteObservables
The phases, their sin projection, and the order parameter.
Raises¶
ValueError If the phase field is malformed or has fewer than two nodes.
Source code in src/scpn_phase_orchestrator/monitor/early_warning_suite.py
run_early_warning_suite ¶
run_early_warning_suite(
observables: SuiteObservables,
*,
thresholds: Mapping[str, float],
relative_gate: float = 0.05,
window: int = 128,
step: int = 16,
baseline_fraction: float = 0.25,
persistence: int = 2,
) -> SuiteWarnings
Run the three members and the weighted fusion over one observable bundle.
Each detector reads the observable it is designed for at the supplied
threshold: critical slowing down the order parameter, rising synchronisation
the per-node phases, ordinal-transition entropy the sin(phase) field. The
fusion is a weighted mean of the members' oriented z-scores. This is the
domain-neutral core — it does not know which domain produced observables.
Parameters¶
observables : SuiteObservables
The neutral observable bundle.
thresholds : Mapping[str, float]
Robust z-score (fused-score for the ensemble) gate per label in
:data:SUITE_DETECTORS.
relative_gate : float
Minimum fractional change gate shared by the three members.
window, step : int
Analysis window length and hop, in samples.
baseline_fraction : float
Leading fraction of windows used to fit each detector's baseline.
persistence : int
Consecutive breaching windows required to raise an alarm.
Returns¶
SuiteWarnings The four warning records, aligned on one window grid.
Raises¶
KeyError
If thresholds is missing a detector label.
ValueError
If an analysis control is out of range for a detector.
Source code in src/scpn_phase_orchestrator/monitor/early_warning_suite.py
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | |
SuiteObservables is a coherent evidence bundle, not three independent arrays:
phase_field must equal sin(phases) and order_parameter must equal the
cross-node Kuramoto magnitude derived from those same phases. Arrays must be
finite real and non-coercive; valid numeric-object inputs normalise to contiguous
float64. Suite thresholds are prevalidated as a complete mapping of
non-negative finite real values before any detector executes.