Event Model Decomposition
Introduction
One of the most important feature of the Event-B approach is the ability to introduce new events during refinement steps, but a consequence is an increasing complexity of the refinement process when having to deal with many events and many state variables.
The main idea of the decomposition is to cut a model into sub-models , which can be refined separately and more comfortably than the whole.
The constraint that shall be satisfied by the decomposition is that these refined models might - the recomposition will never be performed in practice - be recomposed into a whole model in a way that guarantees that refines . An event-based decomposition of a model is detailed in Event Model Decomposition: the events of a model are partitioned to form the events of the sub-models. In parallel, the variables on which these events act are distributed among the sub-models.
The purpose is here to precisely describe what is required at the Rodin platform level to integrate this event model decomposition, and to explain why. The details of how it could be implemented are out of scope.
Other decomposition structures for Event-B are not considered here.
Terminology
- Event model decomposition: The decomposition of a model, as defined in the modelling language, in sub-models.
A model can contain contexts, machines, or both. The notion of model decomposition covers on the one hand the machine decomposition, and on the other hand the context decomposition, both being interdependent.
- Sub-machine: A machine built from a non-decomposed machine during the event model decomposition.
- Sub-context: A context built from a non-decomposed context during the event model decomposition.
- Shared variable: A variable of a given machine which is accessed by events distributed in distinct sub-machines (by opposition to private variable).
- Private variable: A variable of a given machine which is only accessed by events of the same sub-machine (by opposition to shared variable).
- External event: An event of a sub-machine which is built from an event of the non-decomposed machine, and which simulates the way the shared variables (between this sub-machine and another sub-machine) are handled in the non-decomposed machine (by opposition to internal event).
- Internal event: An event copied from the non-decomposed machine to a sub-machine, according to the end-user specified distribution (by opposition to external event).
Note that a variable is said to be accessed when it is read or written. More precisely, such an access may be performed by a predicate (invariant, guard, witness) or in an assignment (action).
Low-level Specification
The low-level specification details through several steps how the event model decomposition shall be performed, and in which order. It establishes a distinction between the steps performed on the end-user's initiative, and the computed ones. It links when possible to the already implemented features of the Rodin platform which can be used at some steps.
Decomposition of a machine in sub-machines
The purpose of this paragraph is to specify how to decompose a machine in sub-machines.
The hierarchy of machines (see the clauses) shall be first flatten (virtually or not), as illustrated below. The resulting machine is considered as being the non-decomposed machine from which the sub-machines shall be built.
Note that it may be necessary to rename same variables or invariants.
About the variables
Some variables are needed by several sub-machines of the decomposition. As a consequence, these variables shall be replicated in the sub-machines. Beyond that, since it is not possible to ensure that such a variable will be refined in the same way in each sub-machine, they shall be given a special status (shared variable), with the limitation that they cannot be refined.
We will specify in this section how to introduce the notion of shared variable in the Rodin platform, and how to check the associated rules.
The following DTD excerpt describes the structure of a variable in the Rodin database:
<!ENTITY % NameAttDecl "name CDATA #REQUIRED"> <!ENTITY % CommentAttDecl "org.eventb.core.comment CDATA #IMPLIED"> <!ENTITY % IdentAttDecl "org.eventb.core.identifier CDATA #REQUIRED"> <!ELEMENT %variable; EMPTY> <!ATTLIST %variable; %NameAttDecl; %CommentAttDecl; %IdentAttDecl; >
A first possibility to tag a variable as shared would be to add a shared specific attribute, which would be set to true if and only if the variable is shared:
<ENTITY % shared "org.eventb.core.shared CDATA #REQUIRED"> <!ELEMENT %variable; EMPTY> <!ATTLIST %variable; ... %shared; (false|true) #REQUIRED >
Another possibility would be to define a more generic attribute, which could take different values, according to the nature of the variable:
<ENTITY % nature "org.eventb.core.nature CDATA #REQUIRED"> <!ATTLIST %variable; ... %nature; (0|1) #REQUIRED >
The second option, which has the main advantage to be more scalable, is retained here.
A shared variable shall always be present in the state space of any refinement of the component. The verification shall be added to those already performed by the static checker. The static checker shall have a way to determine if a given variable is shared or not.
Partitioning the variables in the sub-machines of the decomposition
The first question raised by the partition of the variables is whether it shall be the first stage of the decomposition, or not. Let's first suppose that the answer is "yes". The case where is an event that accesses a variable associated to a sub-machine and a variable associated to a sub-machine cannot be successfully handled: should be associated to or to ? Moreover, contrary to the events, the variables are not essentially bearers of meanings, and they cannot by themselves guide the decomposition.
As a consequence, it is pertinent to assume that the events have been first partitioned. The following cases have then to be taken into consideration when dealing with the variable distribution:
- If is a variable that is only accessed by events of a given sub-machine , then is a private variable of , and it shall be moved to .
- If is a variable that is accessed by events of distinct sub-machines , then is a shared variable, and it shall be duplicated in all sub-machines.
If all the variables are shared at the conclusion of the partition, the end user shall be notified (it certainly means that the decomposition was not judicious!).
About the events
It shall be possible to simulate the way the shared variables are handled in the non-decomposed machine. This is precisely the purpose of the so-called external events.
We will examine in this section how to define such events in the Rodin platform, how to construct them, and how to enforce the rules that apply (in particular, these events cannot be refined).
Identifying an event as external
An attribute is already defined, which is introduced below, to precise the nature of an event. A first solution would be to add another masked value (eg. 4) to encode the external status.
<!ENTITY % convergence "org.eventb.core.convergence"> <!ATTLIST %event; ... %convergence; (0|1|2) #REQUIRED ... >
Another solution would be to add a distinct external attribute, which would be set to true if and only if the event is external:
<ENTITY % external "org.eventb.core.external CDATA #REQUIRED"> <!ATTLIST %event; ... %external; (false|true) #REQUIRED >
This solution is preferred because the notion of external event is totally orthogonal to the notion of convergence.
Constructing an external event
An external event shall be built for each event of the non-decomposed machine modifying shared variables.
As explained in the modelling language, a non-deterministic action expressed as a variable identifier, followed by , followed by a set expression, can always be translated to a non-deterministic action made of a list of distinct variable identifiers, followed by , followed by a before-after predicate.
In the same manner, a deterministic action can always be translated to a non-deterministic action, as shown in the following example. Let's consider a machine with variables , and . Here is an action:
is the same as |
As a consequence, we will first focus on the construction of an external event from an event of a sub-machine whose action relies on , and then derivate the construction from an event of whose action relies on or .
is an event of , are private variables of , are shared variables between and the destination sub-machine (i.e. the sub-machine where the external event will be dispatched), are before-after predicates of , and is a predicate of .
Generic construction for
e WHERE THEN
The first step of the construction is to replace the private variables by parameters. Note that this step is purely fictive, because assigning an event parameter is not allowed!
e ANY WHERE THEN
The second step consists of adding guards to define the types of the parameters, if necessary. More precisely, a theorem shall be added for each parameter for which typing is required. The .bcm file associated to the non-decomposed machine shall be parsed in order to retrieve the typing information. TODO: Some precisions and examples should be added here.
The third and last step of the construction is to introduce an existential quantifier to resolve the invalid assignment. is the newly built external event.
external_e ANY WHERE THEN
Derived construction for TO BE REVIEWED
e WHERE THEN ... ...
It may alternatively be represented with a single predicate, which is an intersection of the predicates:
e WHERE THEN
It is then possible to build the external event, by following the same steps of construction than for the generic case:
external_e ANY WHERE THEN
Or, after applying some simplification rules:
external_e ANY WHERE THEN ...
Construction for
Additional simplification rules apply:
If is equal to , then is always true and shall be deleted.
If is equal to , and if there is no private variable (i.e. there is no existential quantifier on the right-hand side of the assignments), then shall be rewritten as .
Proof obligations generated for deterministic actions are indeed more suitable than those generated for non-deterministic actions.
Construction for
Additional simplification rules apply:
If is equal to , and if there is no private variable (i.e. there is no existential quantifier on the right-hand side of the assignments), then shall be rewritten as .
For a given set , proving that (proof obligation generated from ) is indeed not as "simple" as proving that (proof obligation generated from ).
Partitioning the events in the sub-machines of the decomposition
The following sequence shall be followed:
- The events shall be first partitioned, as indicated by the end-user. More precisely, machines shall be created, according to this partition. At this step, the machines shall only contain the specified events. In particular, the and clauses shall be empty. Moreover, note that it may be necessary to rename some events when performing the partition.
- The Rodin platform shall then be able to distribute the variables, according to the event partition (see Variable partition).
- The Rodin platform shall be able to distribute the invariants, according to the variable partition (see Invariant partition).
- If is an event that modifies a shared variable (i.e. is listed among the free identifiers on the left-hand side of an assignment), then an external event that modifies shall be built from in each sub-machine where is accessed.
N.B. : Note that the construction of an external event depends on the source sub-machine (i.e. the sub-machine containing the internal event from which the external event is to be built) and on the destination sub-machine (i.e. the sub-machine where the external event is to be built).
Building an external event from a given event modifying a shared variable and duplicating it in each sub-machine where is accessed does not indeed entirely fit the requirements, as illustrated below: the sub-machine does not know the shared variable and the sub-machine does not know the shared variable .
Propagating the convergence status
A sub-machine can be seen as a new abstract machine. As a consequence, the convergence status of a given event shall be propagated in the sub-machines as described below:
- An event tagged as ordinary in the non-decomposed machine shall remain ordinary in the sub-machine.
- An event tagged as convergent in the non-decomposed machine shall become ordinary in the sub-machine.
- An event tagged as anticipated in the non-decomposed machine shall remain anticipated in the sub-machine.
- An external event shall always be declared as ordinary.
See the modelling language for precisions on the convergence status.
Propagating the extended status
An event (external or not) of a sub-machine shall always be declared as non-extended.
Ensuring that an external event cannot be refined
The verification shall be performed by the static checker. The static checker shall have a way to determine if a given event is external or not.
Decomposing the initialization event
An initialization event shall be built in each sub-machine from the initialization event of the non-decomposed machine, and according to the distribution of the variables among these sub-machines. The construction is detailed below. is the initial event and the built event, are variables (private or shared) of the sub-machine containing , are variables of other sub-machines, is a before-after predicate and is a predicate.
initialization THEN
Only the variables of the considered sub-machine shall appear in the built initialization event; other variables shall become bound:
e THEN
The derived cases and simplification rules introduced during the construction of the external events apply here as well.
About the invariants
We will see in this section how to distribute the invariants among the sub-machines, once the variables have been partitioned.
- Case 1: If is an invariant only involving private variables of a given sub-machine, then it shall be copied in this sub-machine.
- Case 2: If is an invariant involving private variables of distinct sub-machines, then it shall not be copied.
- Case 3: If is an invariant only involving shared variables, then it shall only be copied in the sub-machines containing all these variables.
- Case 4: If is an invariant involving private variables and shared variables, then it shall not be copied.
These different cases are illustrated in the opposite figure.
TO BE COMPLETED Beyond that, if an invariant is used for typing but is not copied, a theorem shall be added for each variable for which typing is required (otherwise a problem would be detected by the static checker).
Should this be recursively done through the refinement chain? Will this be really useful? If this is the case, what about the invariant between the concrete variables (either private or shared) and asome abstract variables?
About the variants
As mentioned before, there is no convergent event in sub-machines. As a consequence, there is no need to take the variants into consideration when performing the decomposition.
Decomposition of a context in sub-contexts
The purpose of this paragraph is to specify how to decompose the contexts, according to the decomposition of the machines, and to establish how to link the sub-contexts to the sub-machines.
The hierarchy of contexts (see the clauses) shall be first accumulated in a single context. More precisely, a new context shall be built (virtually or not), which contains all the carrier sets, constants and axioms of the hierarchy. This context is assumed to be the non-decomposed context from which the sub-contexts shall be built.
Note that it may be necessary to rename some axioms when flattening the hierarchy.
Then, an empty context shall be built for each sub-machine , which shall be linked to through its clause. Note that, at the conclusion of the context decomposition, the sub-contexts that may be empty shall not be kept, and a clause shall not be added to the associated sub-machines.
About the carrier sets
A carrier set shall be visible from any sub-machine that references it, through a predicate (invariant or guard) or an assignment (action). In other terms, a carrier set of a non-decomposed context shall be copied in a sub-context if and only if this set appears in a predicate or assignment of the associated sub-machine.
About the constants
Similarly, a constant of a non-decomposed context shall be copied in a sub-context if and only if it appears in a predicate or an assignment of the associated sub-machine.
About the axioms
We will see in this section how to distribute the axioms among the sub-contexts, once the carrier sets and constants have been copied.
TODO
High-level Specification
The high-level specification details how the event model decomposition shall be integrated into the Rodin platform as a new feature, by linking to the existing architecture.
Definition of the decomposition
It is necessary to first give a definition of the event model decomposition in the Rodin platform. Is it an Event-B project decomposition? Or, is it a decomposition performed from some well-identified machines and contexts of a given Event-B project?
The entry point for the decomposition is a machine , its visible contexts, and its whole parent hierarchy of machines.
The machine to be taken as input for the decomposition shall be pointed by the end-user. The clauses of contexts and the clauses of machines are used to build the associated hierarchy of contexts. In the same manner, the clauses allow to build the associated hierarchy of machines.
Configuration of the decomposition
The end-user shall be asked to parametrize the decomposition, and more precisely to:
- identify the machine to be taken as input for the decomposition.
- identify the sub-machines to be created.
- partition the events.
- indicate which invariants, axioms or theorems shall be ignored (because they are not required any longer).
It is more suitable for the end-user to visualize the configuration, and as a consequence it shall preferably be performed through the Graphical User Interface of the Rodin platform.
The following dialog box, which fills these requirements, is given as an example. The left-hand side displays the non-decomposed model and the right-hand side the decomposed model. The second one is built by the user, by first adding machines and then copying events from left to right. The unchecked invariants are those to be ignored, the checked events are those to be copied (the initialization events are not copied).
Execution of the decomposition
A Decompose action shall be added. It shall be enabled if and only if a machine is selected. It shall be available from the Project menu, from the toolbar, and in the contextual menu displayed when right-clicking on the selected project.
A new Event-B project shall be created for each sub-machine built during the configuration. The decomposition of the sub-machine shall first be completed, and then the non-decomposed context shall be partitioned, as specified before.
As far as possible, the developments shall not be performed in the Event-B core; the dedicated extension points shall be used instead (eg. those provided for the static checker. See the plugin.xml file of the org.eventb.core package).
Generation of the proof obligations
TODO
- Generating the useful proof obligations
- Not "propagating" useless proof obligations
Mathematical Approach
The purpose of this section is to mathematically formalize the Event-B decomposition previously specified, and by the way to remove the possible remaining ambiguity.
Let's define as the set of all machine handles, the set of all events, and the set of all variables.
- The distribution of the events of the non-decomposed machine among the different sub-machines (according to the end-user configuration) can be represented as with a partial function:
For a given sub-machine , is then the set of internal events of .
- The access of a variable by a given event (according to the static-checker) can be expressed as:
For a given sub-machine , is then the set of variables accessed by the events contained in .
- The association of a variable with the events modifying this variable (according to the static-checker) can be specified as:
For a given sub-machine and a variable , is then the set of the events modifying .
- The construction of the external events for a sub-machine can be represented with a relation:
It is computed as follows:
Thus, the external events of a given sub-machine are events modifying the variables accessed by the internal events of , but they are not internal events of .
Example
The following example is taken from the Event Model Decomposition.
A non-decomposed machine has been decomposed in two sub-machines and , as illustrated by the figure.
According to the terminology, and are internal events of , and and are internal events of . Concerning the variables, and are private variables of , and are private variables of , and , and are shared variables.
The variables accessed by the internal events of are , , , and . The events modifying these variables are , , which both are internal events of , and , which is an internal event of . Thus, according to the definition given before, is an external event for . In the same manner, is an external event for .
N.B.: Note that the expression "is an external event for" is an extrapolation, and shall be literally interpreted as "should lead to the construction of an external event in".
Bibliography
- J.R. Abrial, Mathematical Models for Refinement and Decomposition, in The Event-B Book, to be published in 2009 (lien externe).
- J.R. Abrial, Event Model Decomposition, Version 1.3, April 2009.
- M. Butler, Decomposition Structures for Event-B, in Integrated Formal Methods iFM2009, Springer, LNCS 5423, 2009 (lien externe).