Parallel Composition of SubSystemSpec / FDIRBundle / BehavioralSpec #
Binary composition operators for FDIRBundle, BehavioralSpec, and
SubSystemSpec over the product Kripke structure ProductKripke x y.
Each operator builds the composed value by composing the corresponding
component of the two operands.
Contents #
FDIRBundle.compose— parallel composition of twoFDIRBundles.BehavioralSpec.compose— parallel composition of twoBehavioralSpecs.SubSystemSpec.compose— parallel composition of twoSubSystemSpecs.
All three are parameterized over arbitrary [ToKripke α S D] instances
rather than specialized to StateMachine, so compositions of three or
more operands nest directly:
let s₁₂ := SubSystemSpec.compose s₁ s₂ pk₁₂ hne₁ hne₂ [] ...
let s₁₂₃ := SubSystemSpec.compose s₁₂ s₃ pk₁₂₃ s₁₂.behavioral.nonEmpty hne₃ [] ...
The intermediate pk₁₂ : ProductKripke x₁ x₂ carries its own
ToKripke instance, so the NonEmpty witness required at the next
level is simply s₁₂.behavioral.nonEmpty.
FDIR composition semantics #
isFault := f₁.isFault p.1 ∨ f₂.isFault p.2— either side faultisRecovery := f₁.isRecovery p.1 ∨ f₂.isRecovery p.2— either side recoveryisSafe := f₁.isSafe q.1 ∧ f₂.isSafe q.2— both sides safe
Why isRecovery uses ∨ #
A natural first instinct is to define
isRecovery := f₁.isRecovery p.1 ∧ f₂.isRecovery p.2
(both sides recovering simultaneously), but this condition is typically
unreachable: if only one side experiences a fault, the other remains
frozen at its nominal state, and a component-level FDIRBundle
guarantees nothing about whether the non-faulting side ever enters its
recovery predicate.
The ∨ semantics — "whichever side faulted must eventually recover" —
matches the practical requirement and admits a straightforward proof
via Leads_prod.of_left / .of_right. Use cases requiring stricter
recovery (e.g. synchronized both-side recovery) can bypass this
composition and construct FDIRBundle pk directly.
API granularity #
Only binary compose is provided at this level. For variadic
composition over a homogeneous list, see the anonymous-payload wrapper
SubSystemPayload.composeMany in VV/VariadicCompose.lean, which
threads compose through List.foldl.
Parallel composition of two FDIRBundles.
Because the type signature is parameterized over
{α β} [ToKripke α S₁ D₁] [ToKripke β S₂ D₂] {x : α} {y : β},
the same API supports nested compositions such as
FDIRBundle.compose f₁₂ f₃ pk₁₂₃ hne₁₂ hne₃.
The result is a unified FDIRBundle pk over the product Kripke
structure pk : ProductKripke x y.
Construction:
safety—Always_prod.of_andcombines both safety properties into a conjunction over the product.detection— lift the left-side detection withEventually_prod.of_leftand wrap withOr.inl.recovery— useLeads_prod.of_left/.of_righton the side that faulted, then map throughOr.inl/Or.inrinto the composedisRecovery.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Parallel composition of two BehavioralSpecs.
The result is a BehavioralSpec pk over the product Kripke
structure. Its nonEmpty field is built by ProductKripke.nonEmpty
from the component NonEmpty witnesses.
Equations
- ⋯ = ⋯
Instances For
Parallel composition of two SubSystemSpecs.
Each field of the result is the component-level composition of the
corresponding field of the operands. The result is a unified
SubSystemSpec pk over the product Kripke structure pk.
structural←StructuralSpec.compose(withbridgeconnectors)behavioral←BehavioralSpec.composefdir←FDIRBundle.compose
For N-ary composition, nest compose calls directly (see the module
docstring). At the third step and beyond, the NonEmpty witness is
available as s₁₂.behavioral.nonEmpty, since the intermediate
ProductKripke carries its own ToKripke instance.
Equations
- spec₁.compose spec₂ pk hne₁ hne₂ bridge hbridge = { structural := spec₁.structural.compose spec₂.structural bridge hbridge, behavioral := ⋯, fdir := spec₁.fdir.compose spec₂.fdir pk hne₁ hne₂ }