Skip to content

Formulas: from the equation in the source to the function in the code

Every operation in the package that appears in a paper or a textbook gets one named function, even when it is called once, so a reader can go from an equation to the code and back. This catalogue is the index: one row per formula, the function that implements it, the equation in plain text, the source with a key from REFERENCES.md, and where it is used.

A formula is a pure function in formulas/, cited here once, and the rest of the package calls it rather than repeating the expression. A new formula function gets its row here in the same change.

How a formula function is written

def swing_zscore(nx: np.ndarray, prev: np.ndarray, scale_t: np.ndarray, metered: np.ndarray) -> np.ndarray:
    """The one-step injection change as a z-score of the bus's typical recent change [FED26]:
    spikes (Aq, Al) read large, the slow ramp and benign scans stay near 1.

        swing[b] = ([P_inj, Q_inj](t) - [P_inj, Q_inj](t-1)) / scale_t[b]

    nx, prev : [N, 4] current and previous scan; scale_t : [N, 2] from recent_change_scale
    metered  : [N] bool, buses with an injection meter
    returns  : [N, 2] float32, dimensionless
    """
    sw = np.zeros((nx.shape[0], 2), np.float32)
    sw[metered, 0] = (nx[metered, 1] - prev[metered, 1]) / scale_t[metered, 0]
    sw[metered, 1] = (nx[metered, 2] - prev[metered, 2]) / scale_t[metered, 1]
    return sw

The rules: the name is the operation, not the caller; the first line of the docstring names the quantity and cites the key with its equation number; the equation follows in plain text; every argument has its shape and unit; the function is pure (numpy in, numpy out, no I/O, no dataset objects); one test checks it on a case small enough to verify by hand.

Catalogue

formula function equation source used by
regional subspace prior formulas.federated.block_diagonal_basis, through federated.RegionalPrior V[cols_k, block k] = V_k from each client's own whitened_svd_basis, zero elsewhere; orthonormal for disjoint column sets [EST26], [FED26] the federated fit of the estimator's prior
federated average formulas.federated.fedavg θ = Σ_k (n_k / n) θ_k, in float64, cast back; one client returns its own tensor [MCM17] the federated localizers
the buses of each client formulas.federated.interior_boundary, cut_edge_count, attackable_affinity, hop_distance, halo_nodes, through federated.spectral_partition and compute_nodes interior: every neighbour in the same client; cut edges: ends in different clients; W = A ⊙ √(m mᵀ), m = heavy at attackable buses; halo: other clients' buses within h hops, own buses first [VLX07], [FED26] the federated partition
pooled channel moments formulas.federated.channel_moments, pool_moments, through localization.learned.standardization f_a = n_a / n, f_b = n_b / n, mean = mean_a + (mean_b − mean_a) f_b, var = f_a var_a + f_b var_b + (mean_b − mean_a)² f_a f_b; one part returns unchanged [CGL79] the learned localizers' standardization, pooled across federated clients
per-bus rates and average precision formulas.metrics.perbus_rates, average_precision, through LocalizerBase.score_perbus and LearnedLocalizer.score_grid F1 = 2TP / (2TP + FP + FN), DR = TP / (TP + FN), FR = FP / (FP + TN); AP = Σ (R_n − R_{n−1}) P_n over distinct thresholds, highest first [KEC25], [DG06] the federated paper's node-wise table and grid detection
per-bus confusion counts and the papers' threshold formulas.metrics.perbus_counts, perbus_f1_from_counts, tau_from_counts, through LearnedLocalizer.tune_threshold F1 = 2TP / (2TP + FP + FN); tau = argmax over the grid of the mean per-bus F1 on the active buses [KEC25], [FED26] the learned localizers' validation threshold, summable across clients
swing z-score and temporal delta formulas.temporal.temporal_delta, formulas.temporal.swing_zscore, through timeline.write_temporal_layers (each observed frame against the previous emitted frame, after the walk) delta_t = z_t − z_{t−1} at injection-metered buses; swing = delta_t / scale_t [FED26] the swing and temporal_delta features, SwingThreshold, DeltaThreshold
recent-change scale formulas.temporal.recent_change_scale (over the observed frames, through timeline.write_temporal_layers) scale_t = std over [t − W, t) of the one-step change, plus 1e-3 [FED26] the swing feature
bus voltage phasors formulas.network.complex_voltages V = |V| e^{jθ} [AE04, eq. 2.1] every AC evaluation
bus injections formulas.network.bus_injections (numpy); se.base.SEBase._h_t is its torch twin, kept for callers that differentiate through it and pinned by tests/test_formulas.py S = V ∘ conj(Y V) [AE04, eq. 2.6] the estimator's h(x)
AC measurement function formulas.network.ac_measurement, called by SEBase._h h = [|V|, −Re S, −Im S, θ, Re S_f, Im S_f] [AE04, eqs. 2.6, 2.8] every estimator, JacobianFeatures.delta_z
AC measurement Jacobian formulas.network.ac_jacobian (pandapower's dSbus_dV and dSbr_dV), called by SEBase._jacobian (the chord Jacobian in fit), pinned to the autograd Jacobian by tests/test_formulas.py ∂S/∂θ = j diag(V) conj(diag(I) − Y diag(V)); ∂S/∂|V| = diag(V) conj(Y diag(V/|V|)) + conj(diag(I)) diag(V/|V|); the same for S_f with C_f and Y_f [AE04, ch. 2], [MP19, dSbus_dV, dSbr_dV] every estimator
branch flows formulas.network.branch_flows; called by engine.measurement.emit_from_state, clean_flows_from_states and dataset._clean_flows_full S_f = V_from ∘ conj(Y_f V) [AE04, eq. 2.8] every emitted flow meter, the clean flow layers, the estimator's h(x)
branch admittances formulas.network.branch_admittances; called by dataset._admittances (ybus, yf, yt) y_tt = y_s + (g + jb)/2, y_ff = y_tt / (t conj t), y_ft = −y_s / conj t, y_tf = −y_s / t; shunts on the diagonal [MP19, makeYbus] the loader's admittance matrices
series admittance formulas.network.series_admittance, called by FdiaGenerator._branch_physics and branch_admittances y_s = 1 / (r + jx), zero when the branch has no impedance [MP19, branch model] the static edge physics
accuracy-class error split formulas.noise.bias_jitter_split, called by FdiaGenerator.__init__ bias² + jitter² = SD², jitter = 0.25 SD [ASP14], the jitter fraction set in this package every emitted measurement
ramp profile formulas.attacks.ramp_profile, through engine.attacks.episodes.ramp_dev dev(i) = rate_up·i for i < rise; peak on the hold; max(0, peak − rate_down·(i − rise − hold)) after [DAT26] the At family (the overload Am follows its own goal, overload.overload_goal)
attacker's subnetwork formulas.network.subnetwork, engine.attacks.area.AreaMixin.local_region the buses within hops branches of the seeds (never the slack, grown over zero-injection boundary buses) and their boundary [WU26] every stealthy family
local false state formulas.network.local_ac_solve, engine.attacks.false_state.FalseStateMixin.solve_local S_i(V) = V_i conj(Σ_j Y_ij V_j) = S_target_i on the interior, every other V held true; Newton on [θ_I, |V|_I], each step halved until the mismatch drops (the full step first, so a plain-Newton iteration is unchanged) [WU26], [AE04, ch. 2] Aq, At, Al, Am
a scan's load at a generator bus formulas.attacks.bus_load, through engine.physics.PhysicsMixin.true_load and scan_generation P_load = P_inj + s P_gen,base = s P_load,base with s = P_inj / (P_load,base − P_gen,base), the pools scaling a bus's load and generation by one factor [DAT26] Aq, At, Al, Am, contingency re-solves
a bus's scan load over its load elements formulas.attacks.element_loads, through true_load P_e = P_bus(e) · P0_e / Σ P0 over the bus's elements, the pools scaling every load at a bus by one factor [DAT26] Aq, At, Al, Am, contingency re-solves
operating limits of a false state formulas.attacks.operating_limits, generator_output, within_limits, checked by FalseStateMixin.stealthy_state per bus V_i^min, V_i^max and the generator limits from the case; every generator's implied output P_gen − (ΔP_inj − ΔP_load), Q_gen − ΔQ_inj within its limits, the true output recovered from the pool's common load and generation scale, ΔP_load the load change the attacker pretends; a true value already outside a limit is its own bound (the false state may not make it worse); a false state outside is rejected and its step halved [WU26, eqs. 21-23] Aq, At, Al, Am
attack vector engine.attacks.false_state.FalseStateMixin._attack_vector, called by _stealthy_frame a = h(x_false) - h(x_true), the noiseless reading of the local false state minus that of the true state, added to the true scan so every meter keeps its own noise draw [WU26] Aq, At, Al, Am
open attack subspace formulas.trust.attack_subspace, sparse_basis {H c : H_S c = 0} = H · null(H_S), its basis in reduced row echelon form [WU26], [AE04, ch. 5] the trusted-meter selectors
attack cost formulas.trust.attack_cost the fewest meters the cheapest open attack touches: the sparsest row of the echelon basis (an upper bound on the sparsest vector of the subspace, NP-hard) [WU26] TrustedMeters, the DQN reward
sparsest attack by row reduction formulas.trust.sparsest_rows, called by engine.attacks.rref.RrefMixin.rref_support reduce the transposed Jacobian to RREF, move the sparsest row's nonzero columns to the end, reduce again until the sparsest row stops getting sparser, map the rows back; eligible restricts the chased row (an attack that moves a target line) [WU26] Sec. IV-D1, [YAN17] Am with support_method="rref"
greedy trusted meters formulas.trust.greedy_trusted_meters, called by trust.TrustedMeters secure, on the cheapest open attack, the meter whose protection leaves the costliest cheapest attack; ties to the meter the most basis attacks pass through [WU26], the row-reduction selection TrustedMeters
tamper set of a stealthy frame engine.attacks.false_state.changed_meters, called by _stealthy_frame the metered channels the attack vector moves: the interior's and boundary's injections and voltages, the flows on branches touching the interior [WU26] Aq, At, Al, Am
per-scan jitter sigma formulas.noise.jitter_sigma, called by MeasurementMixin.emit_from_state σ_jit = jitter_v on |V|, degrees(jitter_va) on the angle, |P| jitter_pi + floor and |Q| jitter_qi + floor on injections, |P_f| jitter_pf + floor and |Q_f| jitter_qf + floor on flows [ASP14], the rule set in this package emission only: the per-scan noise every measurement draws
accuracy-class sigma of a scan formulas.noise.accuracy_sigma, through formulas.estimation.accuracy_class_sigma (the measured calibration's rule) σ_acc = class_v on |V|, degrees(class_va) on the angle, class_x |reading| + floor on every power channel [ASP14] what a change must exceed to count as tampered, and the most a channel may move between snapshots, in the fewest-tamper search
tampered channels formulas.attacks.tampered_channels, called by the fewest-tamper search tampered_m = metered_m and |a_m| > σ_acc,m [WU26, eq. 12] with sub-noise changes excluded At with min_tamper
tampered devices formulas.attacks.tampered_devices, called by the fewest-tamper search a channel counts toward its device: a bus's SCADA terminal (injections, the flows metered at the bus, a voltage meter without PMU) or its PMU (|V|, angle, and the branch currents read at the bus) [WU26], the device count of its results At with min_tamper
pool line rating OverloadMixin.use_line_ratings with rating_source="pool" (the default; generate_timeline(..., am_attack={"rating_margin": ...})) S_max_l = rating_margin × max over the pool of |S_f,l|, the noiseless from-end apparent flow of every branch (MeasurementMixin.all_flows_from_states), rating_margin = 1.25 the plan's D15 Am
branch rating formulas.attacks.branch_ratings, called by OverloadMixin.line_ratings (am_attack={"rating_source": "pglib"}) the PGLib-OPF rate_a of the row with the branch's two end buses, the smallest over parallel rows; the 9,900 MVA placeholder is no rating [WU26, eq. 25]; PGLib-OPF v23.07 Am
flow-goal false state formulas.network.local_flow_solve, called by FalseStateMixin.solve_flow_local S_i(V) = S_fixed_i at the held buses of the interior and |V_f conj(y_f · V)| = target_l on each goal branch l, the free injections (attackable loads and generators) free, least-norm Gauss-Newton steps halved until the residual drops; an active set pins a generator component at the limit (22)-(23) it would pass (in the support or on its edge), a load bus's active change at load_cap times its true load (|ΔD_i| ≤ τ D_i [YUA11]), and holds a bus voltage at its limit (21), then solves again [WU26, eqs. 13-14, 21-25], [YUA11] Am
branch currents formulas.network.branch_currents, called by MeasurementMixin._emit_currents and currents_from_states I_f = Y_f V, I_t = Y_t V; columns Re I_f, Im I_f, Re I_t, Im I_t [WU26, eqs. 19-20], [MP19] the hybrid meters' PMU current channels
PMU current sigma formulas.noise.current_sigma, PMU_CURRENT_CLASS; paper_current_sigma for Am σ_re = σ_im = rel |I_end| + 1e-5 pu, rel = 0.01/3 (the whole class) or its jitter part; Am: 0.01 pu [C37118]; [WU26, case studies] the emitter's jitter, the fewest-tamper search (D7, D8)
PMU pseudo voltage formulas.estimation.pmu_pseudo_links, pmu_pseudo_voltages, through SEBase(pmu_pseudo=True) V_f = (I_n − y_nn V_n) / y_nf, the mean over the links reaching f; dV_f = R(1/y_nf) dI_n − R(y_nn/y_nf) P_n (d|V_n|, dθ_n), var|V_f| = g_r C g_rᵀ, var θ_f = g_θ C g_θᵀ [WU26, eq. (3)] the estimators' pmu_pseudo option
paper noise formulas.noise.paper_sigma, WU26_NOISE, called by the fewest-tamper search for a flow goal σ = 0.03 pu × base MVA on P, Q injections and flows, 0.01 pu on a PMU bus's |V| (0.03 on a SCADA voltmeter), degrees(0.01) on the angle [WU26, case studies] Am (D8)
overload target sets OverloadMixin._target_sets, _partner, called by am_overload_design from one random order of the eligible lines, each line a with the first other eligible line b whose ends lie inside a's attack area (the buses within hops of a's ends), each pair once, at most AM_LINE_TRIES [WU26, case studies]; the plan's D17 Am
overload goal engine.attacks.overload.OverloadMixin.overload_goal S_{l,t} = S_true_{l,t} + (t − κ)/T (S_max − S_true_{l,κ+T}) on the noiseless reading, the rating at the last snapshot [WU26, eqs. 24-25]; the plan's D9 Am
fewest-tamper support engine.attacks.minimize.MinimizeMixin.min_tamper, called by EpisodeDesignMixin.ramp_design and OverloadMixin.am_overload_design minimize over supports S in the attacker's area the devices tampered at some snapshot of the window, S held for the window and feasible at every snapshot (local solve, the goal, the operating limits, for At's load goal no metered channel moving more than its σ from one snapshot to the next, the first from the frame before the episode; Am's flow goal has no such bound, D11) and moving at least one device beyond σ, where σ is σ_acc for At's load goal (D7) and [WU26]'s own noise paper_sigma for Am's flow goal (D8, the count's threshold only, D11); proven only among converged local solves, closed over zero-injection boundary buses; smallest first from the region, proven when exhausted or at the devices the goal forces above noise [WU26, eq. 12] At with min_tamper, Am with am_attack="overload"
WLS step formulas.estimation.wls_step (shared weights) and wls_step_batched (per-record weights), called by SEBase._solve_plain and _w_solve Δc = (BᵀWB)⁻¹BᵀW (z − h(x)) [SCH70, part II] every estimator
gain matrix formulas.estimation.normal_matrix; per record formulas.linalg.batched_normal_matrices G = HᵀWH [SCH70, part II] every estimator, the observability guard
weighted objective formulas.estimation.weighted_objective, the divergence guard of SEBase._w_solve J = Σ w_i (z_i − h_i(x))² [SCH70] the robust arms
residual covariance formulas.estimation.residual_covariance_diag, critical_measurements, floored_covariance, called by SEBase.fit Ω = R − H G⁻¹ Hᵀ; critical when Ω_ii < 1e-6 R_ii [HAN75] normalized residuals, ResidualRemoval
accuracy-class sigma formulas.estimation.accuracy_class_sigma, called by SEBase._class_sigma (fit(calibrate="measured")) σ_i = c_i |z̄_i| + floor (relative), σ_i = c_i (absolute) [ASP14] the measurement-only calibration of the detector paths
normalized residual formulas.estimation.normalized_residual, called by SEBase._nres r_N,i = |z_i − h_i(x̂)| / √Ω_ii [HAN75] Huber, residual removal, ResidualLocalizer
Huber weight formulas.estimation.huber_weights, called by AdaptiveWeighting, SubspacePrior._huber_passes, JacobianWeighting a_i = min(1, c / |r_N,i|) [HUB64] AdaptiveWeighting, SubspacePrior, JacobianWeighting
operating-point prior formulas.estimation.whitened_svd_basis, called by SubspacePrior._fit_states whiten X per coordinate, SVD, keep the leading rank_frac directions, un-whiten, QR [EST26] SubspacePrior, GatedPrior
localization gate formulas.estimation.gate_weights, called by GatedPrior.gated_weights w_i ← factor · w_i for every meter incident to a flagged bus [EST26] GatedPrior
guarded inverse, condition number formulas.linalg.guarded_inverse, condition_number (Cholesky, power and inverse iteration) inverse when PD and cond < 1/(100 eps), else pseudo-inverse; cond = λ_max / λ_min numerical guards, no source every estimator, the observability guard
weighted pseudo-inverse formulas.projection.weighted_pseudoinverse H_W⁺ = G⁻¹HᵀW [SCH70, part II] Jacobian features
explained / unexplained split formulas.projection.explained_unexplained, called by JacobianFeatures.transform dx̂ = H_W⁺ Δz, r∥ = H dx̂, r⊥ = Δz − r∥ [JAC26] Jacobian features, JacobianWeighting
leverage formulas.projection.leverage diag of P = Hw G⁻¹ Hwᵀ, Hw = W^{1/2} H [HAN75] the leverage-weighted change feature
weak directions formulas.projection.weak_directions, direction_coefficients, weak_move SVD of Hw; α = Uᵀ W^{1/2} Δz; V_weak V_weakᵀ dx̂ [JAC26] the α_weak and weak-move features
meter-to-bus aggregation formulas.projection.bus_incidence, meters_to_buses a bus's own V, P, Q, θ channels plus the flows of its incident branches; sum for energies, max for changes [JAC26] the per-bus features, GatedPrior, ResidualLocalizer
[WU26] states implemented in tested by
eq. 3 PMU pseudo-measurements of the neighbouring voltages, from the branch currents (KKT form) formulas.estimation.pmu_pseudo_links
formulas.estimation.pmu_pseudo_phasors
formulas.estimation.pmu_pseudo_voltages
models.config.SolveConfig
models.grid.PseudoLinks
models.grid.PseudoVoltages
se.base.SEBase.__init__
se.base.SEBase._build_pseudo
tests.test_pmu_channels.test_eq3_is_exact_without_noise
eq. 12 the attack: fewest tampered measurements over the window (l0) engine.attacks
engine.attacks.episodes.RampDesigner.design
engine.attacks.minimize
engine.attacks.minimize.MinimizeMixin
engine.attacks.minimize.SearchSupport
formulas.attacks.tampered_channels
models.choices.SupportMethod
models.config.SearchSettings
models.config.TimelineKnobs
models.frames.FrameKnobs
models.frames.MinimizerResult
timeline.generate_timeline
trust.wu26
trust.wu26.solve_window
tests.test_attack_area.test_every_attack_the_search_returns_is_valid
tests.test_minimize
tests.test_overload.test_the_search_on_a_flow_goal_equals_brute_force
tests.test_trusted_pmus.test_an_empty_schedule_costs_what_no_schedule_costs
eq. 13 SCADA active injection under attack engine.attacks.false_state.FalseStateMixin._attack_vector
engine.attacks.false_state.FalseStateMixin.generator_buses
engine.attacks.minimize.MinimizeMixin.goal_state
trust.wu26
tests.test_overload.test_a_generator_only_support_is_valid_and_its_output_stays_in_limits
tests.test_search_speed.test_the_support_attack_vector_equals_the_full_one
tests.test_timeline.test_stealthy_families_pass_the_residual_test
eq. 14 SCADA reactive injection under attack engine.attacks.false_state.FalseStateMixin._attack_vector
engine.attacks.false_state.FalseStateMixin.generator_buses
engine.attacks.minimize.MinimizeMixin.goal_state
trust.wu26
tests.test_overload.test_a_generator_only_support_is_valid_and_its_output_stays_in_limits
tests.test_search_speed.test_the_support_attack_vector_equals_the_full_one
tests.test_timeline.test_stealthy_families_pass_the_residual_test
eq. 15 SCADA active branch flow under attack engine.attacks.false_state.FalseStateMixin._attack_vector
engine.attacks.minimize.MinimizeMixin.goal_state
trust.wu26
tests.test_search_speed.test_the_support_attack_vector_equals_the_full_one
tests.test_timeline.test_stealthy_families_pass_the_residual_test
eq. 16 SCADA reactive branch flow under attack engine.attacks.false_state.FalseStateMixin._attack_vector
engine.attacks.minimize.MinimizeMixin.goal_state
trust.wu26
tests.test_search_speed.test_the_support_attack_vector_equals_the_full_one
tests.test_timeline.test_stealthy_families_pass_the_residual_test
eq. 17 PMU voltage magnitude under attack engine.attacks.false_state.FalseStateMixin._attack_vector
engine.attacks.minimize.MinimizeMixin.goal_state
engine.core.FdiaGenerator.__init__
models.choices.MeterModel
timeline.generate_timeline
trust.wu26
tests.test_timeline.test_stealthy_families_pass_the_residual_test
tests.test_trusted_pmus.test_a_trusted_pmu_keeps_its_bus_true_from_its_slot_on
eq. 18 PMU voltage angle under attack engine.attacks.false_state.FalseStateMixin._attack_vector
engine.attacks.minimize.MinimizeMixin.goal_state
engine.core.FdiaGenerator.__init__
models.choices.MeterModel
timeline.generate_timeline
trust.wu26
tests.test_timeline.test_stealthy_families_pass_the_residual_test
tests.test_trusted_pmus.test_a_trusted_pmu_keeps_its_bus_true_from_its_slot_on
eq. 19 PMU branch current, real part, under attack engine.attacks.false_state.FalseStateMixin._current_attack
engine.attacks.false_state.FalseStateMixin._currents_with_attack
engine.attacks.minimize.MinimizeMixin.goal_state
engine.attacks.minimize._Window.__init__
engine.core.FdiaGenerator.__init__
engine.measurement.MeasurementMixin.current_mask
formulas.attacks.tampered_devices
formulas.network.branch_currents
formulas.noise.jitter_sigma
models.choices.MeterModel
models.fields.PmuCurrentFields
models.grid.CurrentColumns
models.grid.MeterPlan
timeline.generate_timeline
trust.wu26
tests.test_pmu_channels
tests.test_pmu_channels.test_a_false_state_writes_its_currents
tests.test_timeline.test_stealthy_families_pass_the_residual_test
eq. 20 PMU branch current, imaginary part, under attack engine.attacks.false_state.FalseStateMixin._current_attack
engine.attacks.false_state.FalseStateMixin._currents_with_attack
engine.attacks.minimize.MinimizeMixin.goal_state
engine.attacks.minimize._Window.__init__
engine.core.FdiaGenerator.__init__
engine.measurement.MeasurementMixin.current_mask
formulas.attacks.tampered_devices
formulas.network.branch_currents
formulas.noise.jitter_sigma
models.choices.MeterModel
models.fields.PmuCurrentFields
models.grid.CurrentColumns
models.grid.MeterPlan
timeline.generate_timeline
trust.wu26
tests.test_pmu_channels
tests.test_pmu_channels.test_a_false_state_writes_its_currents
tests.test_timeline.test_stealthy_families_pass_the_residual_test
eq. 21 bus voltage limits engine.attacks.episodes.OverloadDesigner.design
engine.attacks.false_state.FalseStateMixin._within_limits
engine.attacks.false_state.FalseStateMixin.operating_limits
engine.attacks.false_state.FalseStateMixin.stealthy_state
engine.attacks.minimize.MinimizeMixin.goal_state
engine.core.FdiaGenerator._case_limits
formulas.attacks.operating_limits
formulas.attacks.within_limits
models.frames.OperatingLimits
timeline._knobs
timeline.generate_timeline
trust.wu26
tests.test_overload.test_a_voltage_is_held_at_its_limit_while_the_goal_is_met
eq. 22 generator active output limits engine.attacks.episodes.OverloadDesigner.design
engine.attacks.false_state.FalseStateMixin._within_limits
engine.attacks.false_state.FalseStateMixin.operating_limits
engine.attacks.false_state.FalseStateMixin.stealthy_state
engine.attacks.false_state._clip_generator
engine.attacks.minimize.MinimizeMixin.goal_state
engine.core.FdiaGenerator._case_limits
formulas.attacks.operating_limits
formulas.attacks.within_limits
models.frames.OperatingLimits
timeline._knobs
timeline.generate_timeline
tests.test_overload.test_a_generator_at_its_p_limit_keeps_its_q_free
tests.test_overload.test_a_generator_only_support_is_valid_and_its_output_stays_in_limits
eq. 23 generator reactive output limits engine.attacks.episodes.OverloadDesigner.design
engine.attacks.false_state.FalseStateMixin._within_limits
engine.attacks.false_state.FalseStateMixin.operating_limits
engine.attacks.false_state.FalseStateMixin.stealthy_state
engine.attacks.false_state._clip_generator
engine.attacks.minimize.MinimizeMixin.goal_state
engine.core.FdiaGenerator._case_limits
formulas.attacks.operating_limits
formulas.attacks.within_limits
models.frames.OperatingLimits
timeline._knobs
timeline.generate_timeline
tests.test_overload.test_a_generator_at_its_p_limit_keeps_its_q_free
tests.test_overload.test_a_generator_only_support_is_valid_and_its_output_stays_in_limits
eq. 24 the target flow grows snapshot by snapshot engine.attacks.episodes.OverloadDesigner.design
engine.attacks.false_state.FalseStateMixin.solve_flow_local
engine.attacks.minimize.MinimizeMixin.goal_state
engine.attacks.overload
formulas.network.local_flow_solve
models.errors.NoLineRatings
models.frames.FlowGoal
models.frames.LoadGoal
trust.wu26
tests.test_attack_area.test_delta_ratings_end_each_goal_at_its_flow_plus_the_step
tests.test_attack_area.test_every_attack_the_search_returns_is_valid
tests.test_overload.test_the_goal_rides_on_the_true_flow_and_ends_at_the_rating
eq. 25 the target flow reaches its rating S_max over the window engine.attacks.episodes.OverloadDesigner.design
engine.attacks.false_state.FalseStateMixin.solve_flow_local
engine.attacks.minimize.MinimizeMixin.goal_state
engine.attacks.overload
engine.attacks.overload._schedule
formulas.attacks.branch_ratings
formulas.network.local_flow_solve
models.errors.NoLineRatings
models.frames.FlowGoal
models.frames.LoadGoal
trust.wu26
tests.test_attack_area.test_delta_ratings_end_each_goal_at_its_flow_plus_the_step
tests.test_attack_area.test_every_attack_the_search_returns_is_valid
tests.test_overload.test_the_goal_rides_on_the_true_flow_and_ends_at_the_rating
tests.test_split_first.test_every_frame_labelled_attacked_carries_an_attack
tests.test_timeline.test_layers_and_tamper_masks_agree
eq. 26 the SE linearization with the secure and nonsecure PMU rows engine.attacks.minimize.MinimizeMixin.min_tamper tests.test_trusted_pmus_solution1.test_the_first_pmu_reads_the_sparsest_attack_on_a_target_line
eq. 27 the secure set h^S: a trusted PMU's own V and angle rows
eq. 28 the attack under defense: fewest nonsecure measurements engine.attacks.minimize
engine.attacks.minimize.MinimizeMixin.min_tamper
engine.attacks.minimize._Window.cost
engine.attacks.rref
tests.test_trusted_pmus.test_an_empty_schedule_costs_what_no_schedule_costs
eq. 29 the trusted rows' state deviation is zero engine.attacks.minimize
engine.attacks.minimize.MinimizeMixin.min_tamper
engine.attacks.minimize._Window.__init__
models.inputs.TrustablePmus
trust.wu26
trust.wu26.incremental_freeze
tests.test_attack_area.test_every_attack_the_search_returns_is_valid
tests.test_trusted_pmus.test_a_trusted_pmu_keeps_its_bus_true_from_its_slot_on
eq. 30 the nonsecure set at t engine.attacks.minimize.MinimizeMixin.min_tamper
engine.attacks.minimize._Window.__init__
trust.wu26
trust.wu26.incremental_freeze
tests.test_trusted_pmus.test_trust_accumulates_from_its_slot
eq. 31 trust accumulates: h^S_t = h^S_t-1 + dh^S_t engine.attacks.minimize.MinimizeMixin.min_tamper
engine.attacks.minimize._Window.__init__
tests.test_trusted_pmus.test_trust_accumulates_from_its_slot
eq. 32 the rows one trusted PMU adds engine.attacks.minimize.MinimizeMixin.min_tamper tests.test_trusted_pmus.test_a_trusted_pmu_keeps_its_bus_true_from_its_slot_on
eq. 33 the defense effect: the rise in the attack's cost trust.defense
trust.wu26_defense
tests.test_wu_defense_env.test_the_reward_is_the_rise_in_the_search_cost
eq. 34 the DQN's greedy action trust.wu_dqn.TrustedPMUsDQN._act tests.test_trusted_pmus_dqn.test_algorithm_1_learns_the_pmu_that_pays
eq. 35 the DQN's loss over a mini-batch trust.wu_dqn.TrustedPMUsDQN._learn tests.test_trusted_pmus_dqn.test_algorithm_1_learns_the_pmu_that_pays
eq. 36 the target Q value trust.wu_dqn.TrustedPMUsDQN._learn tests.test_trusted_pmus_dqn.test_algorithm_1_learns_the_pmu_that_pays
eq. 37 the gradient step trust.wu_dqn.TrustedPMUsDQN._learn tests.test_trusted_pmus_dqn.test_algorithm_1_learns_the_pmu_that_pays
Alg. 1 the DRL-based defense (training loop) trust.wu_dqn.TrustedPMUsDQN.fit tests.test_trusted_pmus_dqn.test_algorithm_1_learns_the_pmu_that_pays