Refinements by abstraction functions and stacked potentials #
A Refinement D E is a Module D E whose representation is single-valued: an implementation
invariant on lower states together with an abstraction function abs : E.State → D.State. Each
method, run from a lower state satisfying the invariant, must realize the specified step at the
abstract state, ending in a state satisfying the invariant. On deterministic specifications
(Refinement.ofFn) the obligation reads D.stepFn (abs e) o = (abs e', a).
A single-valued representation is what makes amortized costs compose. Refinement.Amortized
asks that every method satisfy the physicist's inequality
lower cost + potential e' ≤ upper (abs e) o + potential e, with a potential on lower states.
Composing two refinements adds their potentials, the upper one read through the lower
abstraction (Refinement.Amortized.comp). A relational representation would leave the
intermediate state existential, and the composed potential would not be a function of the lower
state. For the same reason an amortized refinement over a native implementation whose
representation is functional yields an Amortized certificate of the realized module
(Refinement.Amortized.realize).
Products of refinements over one lower interface (Refinement.prod) need non-interference: the
methods of each side leave the other side's abstraction, invariant and potential unchanged. A
joint invariant, such as the disjointness of the memory the two sides use, may be part of the
product's invariant. Memory.Framed.prod discharges these obligations from footprints.
Glue. A realization charges, besides each lower call, the glue code that consumes its answer.
In a free-monad program every bind follows exactly one call, so glue charged per bind is a
further charge per lower call, and Refinement.Amortized.glue absorbs it at a constant rate when
it is at most proportional to the call's charge plus one. Work not attached to a lower call, such
as a loop iteration that makes no call, is charged per call one level up and added with
Refinement.Amortized.add.
Main definitions #
Refinement: a module given by methods, an implementation invariant and an abstraction function.Refinement.ofFn: the constructor for deterministic specifications.Refinement.toModule: the underlying relational module.Refinement.id,Refinement.comp,Refinement.prod: identity, composition, and products under non-interference.Methods.prod: the methods of both sides of a product.Refinement.Amortized: per-method amortized cost refinement with a potential on lower states.productCharge: componentwise charges of a product specification.
The transcript-cost lemmas StateTransitionSpec.totalCostTranscript_mono,
StateTransitionSpec.totalCostTranscript_mul_left and StateTransitionSpec.totalCostTranscript_add
sit here, beside their only clients, rather than in the widely imported StateTransition module.
Main results #
Refinement.simulates_demonic,Refinement.simulates_client: whole adaptive clients run through the abstraction function.Refinement.comp_rep_iff: composition agrees withModule.compof the underlying modules.Refinement.Amortized.demonic,Refinement.Amortized.client: potentials telescope along adaptive clients.Refinement.Amortized.comp: potentials stack across composition.Refinement.Amortized.prod: potentials add across non-interfering products.Refinement.Amortized.realize: an amortized certificate for the realized module.Refinement.Amortized.id: the identity refinement passes charges through.Refinement.Amortized.mono,Refinement.Amortized.mul_left,Refinement.Amortized.add: weaken charges, exchange both currencies at a constant rate, and add certificates.Refinement.Amortized.glue,Refinement.Amortized.glue_of_one_le: absorb glue charged per lower call.StateTransitionSpec.totalCost_glue_le: the same on a history.productCharge_const: equal constant charges on a product.StateTransitionSpec.totalCostTranscript_mono,StateTransitionSpec.totalCostTranscript_mul_left,StateTransitionSpec.totalCostTranscript_add: monotonicity, scaling and additivity of transcript costs.Refinement.Amortized.chargeBound,Refinement.Amortized.of_chargeBound: with zero potential, the existing worst-caseModule.ChargeBound.
References #
A module whose representation is an implementation invariant inv together with an
abstraction function abs. From a lower state satisfying inv, every run of a method on an
admissible operation realizes a permitted step of the abstract state and preserves inv.
- methods : Methods D E
Bodies implementing the upper interface using lower-interface calls.
The implementation invariant on lower states.
The abstraction function from lower states to upper states.
- valid {e : E.State} (o : D.Op) : self.inv e → D.valid (self.abs e) o → E.DemonicValid e (self.methods o)
Each method is demonically admissible from a state satisfying the invariant.
Instances For
The methods of both sides of a product, over one lower interface.
Instances For
Equal constant charges on both components are that constant charge on the product.
Smaller charges total less along any transcript.
Scaling every charge by K scales the total by K.
Charges add along a transcript.
Glue on a history. Glue charged with each operation at most K times its charge plus K
costs, together with the charges, at most 2 K + 1 times the charges, when every operation
costs at least one unit.
The constructor for deterministic specifications: each method's history is admissible, and
D.stepFn (abs e) o = (abs e', a) for its final state e' and result a.
Instances For
The underlying relational module: s is represented by e when e satisfies the invariant
and abstracts to s.
Instances For
Every run of a linked admissible client corresponds to a run of the client at the abstract state, ending at the abstraction of the final lower state.
On deterministic specifications, a linked client returns the specified result, and its final lower state satisfies the invariant and abstracts to the specified final state.
The identity refinement: each operation calls itself, with no invariant.
Instances For
Composition: the upper methods are linked through the lower ones, the invariants conjoin, and the abstraction functions compose.
Instances For
Composing refinements represents the same states as composing their modules.
Linking through a composition links through each refinement in turn.
Two refinements over one lower interface implement the product of their specifications,
provided the methods of each leave the other's abstraction and invariant unchanged. The joint
invariant J holds of the shared lower state and is preserved by both sides; it records what
keeps them apart, such as the disjointness of the memory each one uses.
Instances For
Amortized costs #
Amortized cost refinement: the lower charges of every method run, plus the potential after it, are at most the upper charge of the operation plus the potential before it. Potentials are natural numbers, hence nonnegative; a client bound subtracts nothing when the initial potential is zero.
- step {e : E.State} (o : D.Op) {a : D.Result o} {e' : E.State} {tr : E.Transcript} : M.inv e → D.valid (M.abs e) o → E.ClientRun e (M.methods o) a e' tr → E.totalCostTranscript lower e tr + potential e' ≤ upper (M.abs e) o + potential e
The physicist's inequality for one method run.
Instances For
The amortized inequality on a deterministic lower specification, along each method's history.
Weaker charges: cheaper lower charges and dearer upper charges on admissible operations.
Exchange at a constant rate. Scaling both currencies and the potential by K preserves
the amortized inequality.
Two certificates of one refinement add: their lower charges, upper charges and potentials.
Glue charges. A realization of the lower interface charges, besides each lower call, the
glue that consumes its answer: in a free-monad program every bind follows exactly one call. If
the glue charged with a call is at most K times the call's charge plus K, a certificate for
the charges and one for the number of calls give a certificate for the combined charge. Work that
is not attached to a lower call, such as the iterations of a loop that makes no call, is a
further per-call charge of the upper interface, added with Amortized.add one level up.
Glue charges, when every call costs at least one unit, as every memory operation does:
then the calls are paid for by their charges, and the combined charge is amortized at 2 K + 1
times the upper charge.
Potentials telescope along any run of a linked admissible client.
On deterministic specifications, the lower charges of a linked client plus the final potential are at most the upper charges of its history plus the initial potential.
Potentials stack across composition. If the upper refinement is amortized against the middle charges and the lower refinement is amortized from the middle charges, the composite is amortized with the sum of the upper potential, read through the lower abstraction, and the lower potential.
Potentials add across non-interfering products, provided the methods of each side leave the other side's potential unchanged.
Potentials stack through a realization. An amortized refinement over a native
implementation with an amortized certificate yields an amortized certificate of the realized
module, provided the native representation is functional: the represented lower state is
absR c.
The identity refinement passes each charge through unchanged.
With zero potential, an amortized refinement is a worst-case Module.ChargeBound of its
module.
A worst-case Module.ChargeBound of the module is an amortized refinement with zero
potential.