AIMhe. ELSEVIER
Contents lists available at ScienceDirect
Science of Computer Programming
www.elsevier.com/locate/scico
cience of Computer rogramming
Translating essential OCL invariants to nested graph constraints for generating instances of meta-models ^
Hendrik Radkeb*, Thorsten Arendta, Jan Steffen Beckerb, Annegret Habelb, Gabriele Taentzerc
a GFFTInnovationsförderung GmbH, Bad Vibel, Germany b Universität Oldenburg, Germany c Philipps-Universität Marburg, Germany
A R T I C L E I N F 0 A B S T R A C T
Domain-specific modeling languages (DSMLs) are usually defined by meta-modeling using the Object Constraint Language (OCL) for specifying invariants. This approach is purely declarative in the sense that instance construction is not supported. In contrast, grammar-based language definition incorporates the stepwise construction of instances by applying production rules. Since the underlying structure of models are generally graphs, graph grammars are well suited to define modeling languages. Establishing a formal relation between meta-modeling and graph grammars opens up the possibility to integrate techniques of both fields. This integration can be advantageously used for optimizing DSML definition. We follow an approach where a meta-model is translated to a type graph with a set of nested graph constraints. While previous meta-model translations neglected OCL constraints, we focus on the translation of Essential OCL invariants to nested graph constraints in this paper. We show that a model satisfies an Essential OCL invariant iff its corresponding instance graph satisfies the corresponding nested graph constraint. In addition, nested graph constraints can be translated to application conditions of graph transformation rules. Composing both translations, an instance-generating graph grammar can be equipped with application conditions such that it generates instances of the original meta-model only.
© 2017 The Authors. Published by Elsevier B.V. This is an open access article under the CC BY-NC-ND license (http://creativecommons.org/licenses/by-nc-nd/4.0/).
CrossMark
Article history:
Received 11 November 2015 Received in revised form 16 March 2017 Accepted 14 August 2017
Keywords: Meta modeling Essential OCL Graph constraints Instance generation
1. Introduction
Model-based software development causes the need for new, often domain-specific modeling languages (DSMLs) to carry high-level knowledge about the software. Nowadays, DSMLs are typically defined by meta-models following the pure declarative approach. In that approach, language properties are specified by the Object Constraint Language (OCL) [1].
Given a meta-model, instance generation has been considered by several approaches in the literature. Most of them are logic-oriented as, e.g., [2,3]. They translate class models with OCL constraints into logical facts and formulas. Logic
* This work is partly supported by the German Research Foundation (DFG), Grants HA 2936/4-1 and TA 294/13-1 (Meta modeling and graph grammars: integration of two paradigms for the definition of visual modeling languages).
* Corresponding author.
E-mail addresses: radke@informatik.uni-oldenburg.de (H. Radke), thorsten.arendt@gfft-ev.de (T. Arendt), jan.steffen.becker@informatik.uni-oldenburg.de (J.S. Becker), habel@informatik.uni-oldenburg.de (A. Habel), taentzer@informatik.uni-marburg.de (G. Taentzer).
http://dx.doi.org/10.1016/j.scico.2017.08.006
0167-6423/© 2017 The Authors. Published by Elsevier B.V. This is an open access article under the CC BY-NC-ND license (http://creativecommons.org/licenses/by-nc-nd/4.0/).
conform to
Fig. 1. Overview of the approach taken.
approaches such as Alloy [4] can be used for instance generation, as done, e.g., in [3]: After translating a class diagram to Alloy, an instance can be generated or it can be shown that no instances exist. This generation relies on the use of SAT solvers and can also enumerate possible instances. All these approaches have in common that they translate class models with OCL constraints into logical facts and formulas, not exploring the graph properties of underlying model structures.
Alternatively, graph grammars have shown to be suitable and natural to specify (domain-specific) visual languages in a constructive way [5]. Similarly to string grammars, all language instances are generated from a start graph by applying rules consecutively. This instance generation process is optimized w.r.t. graph properties.
In this article, we translate OCL constraints to graph patterns or graph constraints and therefore bridge between both approaches. To formally treat models and meta-models (without OCL constraints) they are translated to instance and type graphs. Hence, we follow the graph-based approach keeping the graph structure of models as units of abstraction where graph axioms are satisfied by default. In [6], we started to formally translate OCL constraints to nested graph constraints [7]. In [8], this translation is extended to set operations such as select, collect, union and size. Meanwhile, Bergmann [9] has implemented a translator of OCL constraints to graph patterns. The focus of that work, however, is not a formal translation but an efficient implementation of constraint checking.
Our main intention for using such an OCL translation is to generate instances of meta-models. Following the ideas by Ehrig et al. in [10], a meta-model can be translated into a graph grammar defining an equivalent language. Taking such a graph grammar, graph constraints which result from the OCL translation can be further translated to application conditions of transformation rules [7]. We illustrate this approach on the generation of Petri nets.
Since graph-based approaches rely on (type and object) graphs, they support flat object sets as the only form of OCL collections to be translated to. This is sufficient for language definition where a specific order of objects as well as the distinction of duplicates are not crucial (see also [3]). Moreover, our OCL translation is formulated for a slightly simpler form of meta-models specified by EMOF [11], i.e., we focus on Essential OCL being closer to supporting technologies such as the Eclipse Modeling Framework. Furthermore, our considerations are restricted to a first-order, two-valued logic, as for graph constraints, i.e., the translation is straightened to the corresponding OCL features. Our translation comprises all language features of Essential OCL used in existing specifications, according to an empirical study conducted in [12] which identifies the set of OCL language constructs actually used in practice. Since the focus of OCL usage is DSML definition, our translation mainly concentrates on OCL invariants.
The main contribution of this paper is the following: the translation of Essential OCL invariants to nested graph constraints is shown to be correct, i.e., a model satisfies an Essential OCL invariant iff its corresponding instance graph satisfies the corresponding nested graph constraint. Moreover, we show that our translation is complete for the chosen set of OCL invariants. The overall aim of this work is to establish a formal relation between meta-modeling and the theory of graph transformation. It shall form a basis for integrating works in both fields in an advantageous way.
This paper is structured as follows: the next section gives an informal introduction to our approach. It introduces the running example and shows the translation of OCL to graph constraints and further to application conditions using this example. Moreover, it presents an instance-generating grammar for this example. Section 3 recalls Essential OCL. Section 4 recalls nested graph conditions. It also introduces a compact notion of graph conditions. Section 5 presents the translation of Essential OCL invariants to nested graph constraints, more precisely to compact conditions. The correctness and completeness of this translation is shown in Section 6. The translation of graph constraints to application conditions of rules is sketched in Section 7. Section 8 contains a comparison to related work and Section 9 concludes the paper. Note that this paper is accompanied by a long version [13] containing further information about this work, especially w.r.t. the correctness proof.
2. Informal introduction to the translation of OCL invariants
This section gives an informal overview of our approach: we show how a given meta-model is translated to an instance-generating graph grammar. While the meta-model structure (including types) is defined by the type graph and instance-generating grammar rules, multiplicities and OCL invariants are translated to graph constraints being further translated to application conditions (abbreviated by "ac" in Fig. 1) of grammar rules. This augmented graph grammar can be used to generate instance graphs which conform to the given meta-model. See also Fig. 1.
g * postArc
Fig. 2. Meta-model for Petri nets (adapted from [15]).
We illustrate our approach with Petri nets as modeling language. Note that the presentation in this section is completely informal. All formal definitions and theorems are presented later in Sections 3 to 7.
2.1. Running example
A Petri net (PetriNet) [14] is composed of several places (Place) and transitions (Transition). Petri nets, places and transitions are all NamedElements. Arcs between places and transitions are explicit. PTArc and TPArc are respectively representing place-to-transition arcs and transition-to-place ones. An arc is annotated with a weight. A place can have an arbitrary number of incoming (preArc) and outgoing (postArc) arcs. In order to model dynamic aspects, places need to be marked with tokens (Token). The corresponding meta-model is shown in Fig. 2.
Despite of multiplicities, this meta-model allows to build inappropriate instances, e.g., place and transition names may be empty or equal. Therefore, the meta-model has to be complemented with invariants being formulated in OCL. In the following, the main invariants are formulated.
1. Two different Petri nets have distinct names.
context PetriNet inv: PetriNet.allInstances() -> forall(p: PetriNet | p <> self implies p.name <> self.name)
2. The name of a place is not empty. context Place inv: self.name <> "
3. The name of a transition is not empty.1 context Transition inv: self.name <> "
4. Two different places of a Petri net have distinct names. context PetriNet inv:
self.place -> forall(p1,p2:Place | pi <> p2 implies pl.name <> p2.name))
5. Two different transitions of a Petri net have distinct names. context PetriNet inv:
self.transition -> forall(ti,t2:Transition | tl <> t2 implies tl.name <> t2.name))
6. The weight of an arc is strictly positive. context Arc inv: self.weight >= 1
7. There is at most one arc between a pair of place and transition. context PetriNet inv:
TPArc.allInstances() -> forall(ai,a2:TPArc | al <> a2 implies (al.src <> a2.src or al.dst <> a2.dst))) and PTArc.allInstances() -> forall(al,a2:PTArc | al <> a2 implies (al.src <> a2.src or al.dst <> a2.dst)))
8. There is at least one place in a Petri net having at least one token.
context PetriNet inv: self.place -> exists(p:Place | p.token -> notEmpty())
1 OCL constraints 2 and 3 can also be combined to one OCL constraint in the context of superclass NamedElement, i.e., the name of a named element is not empty.
buffer
readyP-j?roduca
nsum*-^f?^0
Fig. 3. An example Petri net showing a simple producer/consumer system with a 1-buffer.
pll:Pl
name='readyP'
postArc
¡Token
pl3:Pl
name= empty'
\ et-0 £ 0
: Token
Fig. 4. Snippet of the abstract syntax representation of the Petri net in Fig. 3.
An example Petri net is given in Fig. 3. It specifies a simple producer/consumer system with a 1-buffer. This means that the producer can produce exactly one piece to be stored in the buffer. Thereafter, the consumer has to become active before the producer creates the next piece. A transition can fire if all places connected to this transition by a PTArc each have a token. In the example Petri net, produce is the only transition that can fire. After firing, there is again a token on place readyP and a token on place buffer. Hence, transition consume can fire thereafter. Actually this Petri net can continuously fire, i.e, transitions produce and consume can fire alternately.
2.2. Type and instance graphs
When translating a meta-model, we focus on its structure first and neglect all kinds of constraints, even multiplicities. This structural part of a meta-model is translated to a type graph in a straightforward way: The meta-model structure is just considered as a graph. From now on, we abbreviate some of the type names due to space limitations in subsequent figures: A "PetriNet" is abbreviated to "PN", "Place" to "Pl", "Transition" to "Tr", and "Token" to "Tk". Furthermore, we use
bidirectional edges -^ to clearly indicate that edges without arrows (occurring in the meta-model in Fig. 2) are actually
bidirectional ones.
In Fig. 4, we show a snippet of the abstract syntax of the example Petri net in Fig. 3 as instance of the meta-model in Fig. 2.
2.3. Translating OCL invariants to nested graph constraints
In the next step, we translate multiplicities and all the OCL constraints of a meta-model to nested graph constraints [7] and hence, complete the translation of meta-models.
Simple graph constraints are concerned with the existence and non-existence of graph patterns. Graph patterns are drawn in a standard way: A node is depicted by a rectangle carrying its name followed by its type. An edge is drawn by an arrow pointing from the source to the target node and the edge label is placed next to the arrow. For instance, the upper bound of a multiplicity can be expressed by the non-existence of a pattern that shows a situation where the upper bound is exceeded by 1. If a PTArc must not have more than one source place ("Place" is abbreviated to "Pl"), a pattern consisting of a PTArc with two source edges must not exist:
A graph fulfills this graph constraint if none of its PTArcs has more than one source edge, i.e., there is no occurrence of this pattern in the graph.
Graph constraints may be nested, i.e., graph constraints may occur in graph constraints. Each graph in a graph constraint is equipped with a quantifier, namely the existential quantifier 3, the universal quantifier V or their negations. Each nesting increases the expressiveness of constraints. Inclusions are given by the names of the nodes: Two occurrences of v in different graphs of the graph constraint, e.g. 3(0, 3(0, c)) or 3(0, 3«), mean that they are in inclusion relation. A simple example of a nested graph constraint is used to formalize lower bounds of multiplicities. For example, a PTArc must have at least one source place:
V( 1:PTArc |. 3( ^PTArcF^flPll))
A graph fulfills this graph constraint if all its PTArcs have at least one source edge. Furthermore, nested graph constraints may be connected by propositional logic. As rules, graph constraints may contain variables for attribute values. They are implicitly declared.
The translation of OCL invariants to nested graph constraints is possible if they stick to flat object sets as the only form of OCL collections. Furthermore, their semantics is restricted to first-order, two-valued logic, as the one for nested graph constraints. These restrictions do not harm if OCL is used for language definition.
In the following, we show the graph constraints to which the OCL invariants in Section 2.1 are translated. The way in which OCL invariants are translated to graph constraints is presented in Section 5.
1. Two different Petri nets have distinct names.
1:PN 2:PN
name=n name=n
2. There is neither a place nor a transition with an empty name.
:Pl ) Vd( :Tr
name=' ' name=' '
3. Two different places or transitions of a Petri net have distinct names.
p1:Pl ^place
name=n
|l:PNp
1 place p2:Pl
1 ' nameon
t1:Tr trans 1
name=n
{TPN11^
nameon
4. The weight of an arc is positive. v(1:Arc1, 3("
weight > 1
5. Double arcs from a transition to a place, or vice versa, are forbidden.
V( 1:TPArc|[2:TPArc|. 3(1:TPArc12:TPArcptc|":Tr1) v 3(1 1:TPArch^^KTP^12:TPAr^hd^HTPTI))a
V( 1:PTArc|[27TPArc1, 3 (I1:PTAr^hsrHTPT12:PTArcv 3(1 1:PTArchds^|2:PTArc[dH7Tr1))
6. Every Petri net has at least one token.
v( 1:PN|. зdTTPN£tacefTP^I^k£»ПTk1))
2.4. Instance-creating transformation rules
Since the main motivation for the OCL translation is to get a rule-based approach for generating meta-model instances, we consider generation rules next. In the following, we first present the rules and then translate the graph constraints shown above to left application conditions (short ACs) of these transformation rules restricting their applicability such that consistency is preserved, also w.r.t. OCL constraints. We just show the resulting application conditions. The proper translation is illustrated in Section 7.
We consider a rule set for the generation of Petri nets. All rules conform to the meta-model in Fig. 2. Together with the empty instance as start graph, they form a graph grammar for the generation of Petri nets. A generated graph may represent more than one Petri net. The main idea of graph grammars and graph transformation is the rule-based modification of graphs where each application of a graph transformation rule leads to a graph change. In particular, graph grammars can be
used to define graph languages. A graph belongs to the graph grammar-defined language if it can be derived from its start graph by arbitrarily many rule applications.
The core of a graph transformation rule is a pair of typed graphs, called left-hand side (LHS) and right-hand side (RHS). Roughly spoken, a rule is applied by finding a match of the LHS in the source graph and by replacing its image by a copy of the RHS leading to the target graph of the graph transformation. This means in particular that attribute values occurring in the LHS are compared with those in the source graph while attributes are set to values occurring in the RHS. In rules, attribute values may also be variables that are instantiated during rule matching and used for attribute computations during rule application. Abstract types as presented in [16] may be used in rules to formulate them on an appropriate abstraction level. All elements that are newly created, however, need to have concrete types. For further controlling the application of a rule, left ACs can be formulated that have to be fulfilled before applying the rule. For the moment, we do not consider ACs and come back to them below.
1. Creating a new Petri net with at least one place and transition:
createPetriNet(tn:String, n:String, pn:String)
:Tr trans :PN place :Pl
name=tn name=n name=pn
:Token
2. Inserting a new place in a given Petri net: insertPlace(p:PN, n:String)
place :Pl
name=n
3. Inserting a transition in a given Petri net: insertTransition(p:PN, n:String)
4. Connecting a transition to a place: insertTPArc(t:Tr, w:int, p:Pl)
tTT^ IPipT
5. Connecting a place to a transition: insertPTArc(p:Pl, w:int, t:Tr)
6. Inserting a token in a given place: insertToken(p:Pl)
p:Pl ^ p:Pl ioke»nTokim
By consecutive rule applications from the start graph, a specific instance can be created. Let's start with the start graph which is empty: Creating a Petri net with name 'ProducerConsumer' together with place 'readyP' and transition 'produce', inserting two places with names 'buffer' and 'empty', connecting them by two TPArcs and two PTArcs (all with weight 1) and inserting a token in place 'readyP' and another one in place 'empty' by corresponding rule applications would yield the abstract syntax graph in Fig. 4.
2.5. Translating graph constraints to application conditions of grammar rules
After having translated OCL invariants to graph constraints, those constraints may be further translated to left application conditions (ACs) of transformation rules. The basic idea behind this additional step is the following: Given a graph grammar or graph transformation system, its rules may violate the graph constraints resulting from the OCL translation. In this case, corresponding rules are augmented by additional left ACs restricting their application. It has been shown in [7] that all possible applications of augmented rules ensure all constraints.
The set of left ACs for all rules being presented in Section 2.4 is discussed below. The corresponding translation process is presented in Section 7.
1. Creating a new Petri net: createPetriNet: This rule gets additional left ACs checking that all the names are not empty. Furthermore, the name of the new Petri net has to be compared with the names of existing nets in advance to ensure that all Petri nets have unique names. The resulting left AC is:
) a n = '' a tn = '' a pn = '
2. Rules insertPlace and insertTransition: These rules get additional left ACs checking that the names of the new nodes are not empty or already used by existing places/transitions. The resulting left ACs are:
) a n = ''
) A n = ''
3. Rules insertTPArc, insertPTArc: These rules get additional left ACs checking that the weight w of a new arc is at least 1 and that there are not already TPArc or PTArc between the same pairs of place and transition. A node may carry a set of names. In the case of name set {u. v}, we write u. v (or u = v) inside the node rectangle. The resulting left ACs are:
4. Rule insertToken: This rule does not get any further left AC. 2.6. Generating meta-model instances
To generate the snippet of the example Petri net shown in Fig. 4, we start with the empty start graph and apply the following rules:
createPetriNet('ProducerConsumer','readyP',produce'); insertPlace(pn,'buffer');
insertPlace(pn,'empty'); insertTPArc(tr1,1,pl2); insertPTArc(pl1,1,tr1); insertPTArc(pl3,1,tr1); insertToken(pl3)
These rules are applicable in this order at the given arguments such that all ACs are fulfilled: Applying rule createValid-PetriNet to the empty graph there is no other Petri net with the same name and all newly inserted elements have proper names. Hence, the left AC is satisfied. For the following two applications of insertPlace we have to check that the names 'buffer' and 'empty' have not been used which is fulfilled. Moreover, they are non-empty. For the applications of insertTPArc and insertPTArc, we have to check that the chosen weights are at least 1 which is the case and that there are not already arcs of corresponding types between the specified places and transitions which is also the case. Rule insertToken can be applied without checking any further AC. Hence, the left ACs of all rules applied are fulfilled. The result is a valid instance graph.
3. Essential OCL invariants
In this section, we recall the main concepts of OCL and its sub-language Essential OCL. Furthermore, we clarify which part of Essential OCL is translated by our approach and recall the formal syntax definition of OCL given in the OCL specification [1] which forms the basis our translation is building on.
3.1. OCL language description
The Object Constraint Language (OCL) [1] is a formal language used to describe expressions on object-oriented models being consistent to either the Meta Object Facility (MOF) [11] or the Unified Modeling Language (UML) [17]. These expressions typically specify invariant conditions that must hold for the system being modeled (e.g., see the running example in Section 2.1) or queries over objects described in a model. Further usages of OCL are the specification of initial and derived values as well as the specification of operation contracts, i.e., pre-, body-, and post-conditions of operations.
The OCL type system The type system in OCL mainly consists of three categories: custom types, predefined types, and template types. Custom types are either class types or enumeration types defined by the user in the corresponding meta-model. Predefined types are Integer, Real, String, and Boolean, called primitive data types. In meta-models, they are used as types of class attributes. Furthermore, OCL has two special predefined types representing the top (OclAny) and bottom (OclVoid) elements of the corresponding type hierarchy. Template types are Collection(T) and Tuple(T1, T2) whose parameters T, T1, and T2 are applied to other types. Collection is an abstract type: its concrete subtypes are Set, OrderedSet, Bag, and Sequence and differ with respect to frequency and ordering of the contained elements.
Navigation in OCL expressions In OCL expressions, object structures can be traversed using the so-called dot notation. Accessible elements are objects (i.e., class instances) and their features (i.e., attributes respectively opposite association ends). Depending on the feature's multiplicity, a navigation results either in a single-valued return type (for multiplicities with upper bound set to 1) or in a multi-valued type, more precisely in a set (for multiplicities with upper bound greater than 1). If, in a multi-valued reference, there does not exist any target object, the navigation results in an empty set. Whereas, in the case of multiplicity 0..1, the absence of an appropriate value yields null representing the only value of bottom type OclVoid.
Logic used in OCL We mentioned above that (1) OclVoid is a subtype of any custom and predefined type, i.e., it is also a subtype of the predefined type Boolean, and that (2) OclVoid consists of value null. Moreover, OclInvalid is used as an additional type to allow invalid outcomes of functions. As a consequence, OCL type Boolean comes along with a four-valued logic, i.e., Boolean={true,false,null,invalid} [1]. Besides and, or, not, xor, and implies, OCL provides a universal quantifier forAll and an existential quantifier exists, both in the sense of first-order logic. Consequently, both quantifiers range over finite collections only and cannot be used, for example, on all instances of the type Integer or String [18].
OCL collection type operations In the following, we give a rough overview of some selected but substantial predefined collection type operations being called by the arrow-notation (for example, someSet->foo()). Construction operations are either explicit type constructors like Set{...} and Bag{...} or one of the implicit constructors including(e) and excluding(e). An implicit constructor takes an element e as parameter and adds it to a given collection (including) respectively removes all occurrences of it from a given collection (excluding). Conversion operations like asSet() and asBag() allow to convert one collection kind into any of the other three collection kinds. Filter operations like se-lect(BExp), reject(BExp), and any(BExp) are used to filter collection elements according to the evaluation of the Boolean expression BExp. Extraction operations extract some information from the given collection except for Boolean values. Examples of this kind of operations are size(), collect(Exp), and union(Collection(T)). Operation size() returns the number of elements within the collection while collect(Exp) is used to construct new collections (with potentially other type elements) from existing ones according to the expression Exp. Finally, OCL provides a number of operations returning Boolean values. For checking the existence of elements within a collection, isEmpty() respectively notEmpty() can be used, for example. In order to test membership in collections, the operations includes(e) and excludes(e) testing on single elements e as well as includesAll(Collection(T)) and excludesAll(Col-lection(T)) for testing element collections are available.
Essential OCL According to the OCL specification of the OMG [1], Essential OCL is "...the minimal OCL required to work with EMOF". Essential MOF (EMOF) is a subset of MOF [1] that allows to define simple meta-models using simple concepts. In the following, we consider a slightly restricted form of Essential OCL neglecting OCL features that cannot be translated. W.r.t. our translation of EssentialOCL to nested graph constraints, we restrict our consideration to a two-valued logic. The exact limitations of our translation are presented in Section 5.4.
3.2. Formalizing the OCL syntax
We base our OCL translation on the OCL specification [1], Annex A which itself is based on the doctoral thesis by Richters [19]. We prefer this formalization, in contrast to the UML-based specification, since it is more suitable for proving the semantics preservation of our translation. In the following, we recall the main definitions from [19] formalizing the OCL syntax. As a first step, we define an object model representing the EMOF-based meta-model types as follows.
Assumption 1. Let DSIG = (S, OP) be a data signature with S = {Integer, Real, Boolean, String} and corresponding operation symbols O P.
Definition 1 (Object model). An object model over DSIG is a structure M = (CLASS, ABSCL, ENUM, ATT, OPS, ASSOC, assoc, rtgt, mult, <) where CLASS is a finite set of classes with a true subset of abstract classes ABSCL c CLASS, ENUM is a finite set of enumerations, ATT = {ATTc}ceCLASS is a family of attributes att: c ^ (S U ENUM) of class c, OPS is a family of user-defined operation signatures w: w ^ t where w e (S U ENUM U CLASS)* and t e (S U ENUM U CLASS) having no side-effects (queries), ASSOC is a set of associations, with assoc: ASSOC ^ (CLASS x CLASS) mapping each
association to a pair of participating classes and rtgt: ASSOC ^ String mapping each association to a non-empty role name, mult: ASSOC ^ P(N+) 2 is a function assigning each association a multiplicity interval and a is a partial order on CLASS reflecting its generalization hierarchy.
Example 1. Regard the Petri net meta-model shown in Fig. 2. The corresponding object model M consists of CLASS = {NE. PN. Pl. Tk. Arc. PTArc, TP Arc. Tr}, ABSCL = {NE. Arc}, ENUM = 0, ATT = {name : NE ^ String. weight: Arc ^ Integer}, OPS = 0, ASSOC = {PN_place. PN_transition. PN_arc. Pl_token. Pl_preArc. Pl_postArc. PT_src. PT_dst. Tr_preArc. Tr_postArc. TP_src. TP_dst},3 with, e.g. for association a = PT_src: assoc(a) =< PT. Pl >, rtgt(a) = src, and mult(a) ={1}, and r= {PN a NE. Pl a NE. Tr a NE. PT a Arc. TP a Arc}.
Since the evaluation of an OCL invariant requires knowledge about the complete context of an object model at a discrete point in time, we recall the definition of a system state of an object model M. Informally, a system state consists of a set of objects, functions assigning attribute values to each object attribute, and a finite set of links connecting objects within the model.
Definition 2 (System state). A system state of an object model M is a structure v(M) = (oClass. vAtt. o Assoc) where
• for each class c e CLASS, vClass(c) is a finite set of object identifiers (since abstract classes cannot be instantiated, aaass(c) = 0 for each c e ABSCL),
• for each attribute att: c ^ t e ATTa, aAtt(att): vClass(c) ^ I(t) is an operation from class objects to some interpretation of type t e (S U ENUM) where ATTcr := [Jcac, ATTci represents the set of all owned and inherited attribute symbols of a class c,
• for each association a e ASSOC with assoc(a) = (c1. c2), oAssoc(a) c valass(c1) xaciass(c2) is a finite set of links connecting objects where vaass(c) := Uc'<c aClass(c') is the set of all objects of type c or a (possibly indirect) subtype of c. Furthermore, OAssoc(a) must meet the multiplicity specification for a: Vo1 e vaiass(c\) : |{l = (o1. o2) 11 e ffAssoc(a)}\ e mult(a).
Example 2. The system state v(M) corresponding to the Petri net instance in Fig. 3 consists of aClass = {aClass(PN).
VClass(Pl). VClass(Tk). (Taass(PT). VClass(TP). VClass(Tr)} with, e.g., ffClass(Tr) = {tru tr2} and &Class(TP) = {tp1. tp2. tp3. tp4}, e.g., aAtt(name)(tr1) = produce and om(weight)(tp1) = 1, and, e.g., aAsSoC(Tr_postArc) = {< tr1. tp1 >. < tr1. tp2 >. < tr2. tp3 >. < tr2. tp4 >} and vAssoc(TP_src) = {< tp1. tr1 >. < tp2. tr1 >. < tp3. tr2 >. < tp4. tr2 >}.
Based on the definition of an object model, the underlying type system (signature) for expressions in Essential OCL is defined as follows:
Definition 3 (Signature). A signature over an object model M is a structure £M = (TM. <M. QM) where TM is a set of types consisting of all basic types (S in DSIG), all object types (for each c e CLASS there is an object type tc e TM), all enumeration types E e ENUM, and the collection type Set(tc) for an arbitrary object type tc e TM, <M is a partial order on TM representing a type hierarchy over TM, where Integer <M Real and tc <M tci if c r c', and QM is a set of operations on TM consisting of an exhaustive set of predefined operations on primitive data types such as comparison operations on Integer, implication on Boolean, etc., operations allInstancestc for obtaining all objects of type tc, operations a : tc ^ t to access type attributes, operations a : w ^ t to obtain the result of a query, operations role' : tc ^ tci with a e ASSOC, assoc(a) = (c. c'), rtgt(a) = role', mult(a) = Mc/, and Mc/ c {0. 1} to access single-valued associations of type tc, operations role': tc ^ Set(tci) with a e ASSOC, assoc(a) = (c. c'), rtgt(a) = role', mult(a) = Mc/, and Mc/ {0. 1} to access multi-valued associations of type tc, operations on sets, i.e., isEmpty, notEmpty, includes, includesAll, excludes, excludesAll, including, excluding, size, union, —, intersection, and symmetricDifference, the constructor mkSett for creating a set with elements of type t, and operations equality (=) and non-equality (=) for all types t e TM.
For specifying expressions in Essential OCL we use a signature over an object model M as defined above and a family of variable sets indexed by types t e TM.
Definition 4 (Essential OCL expressions). Let £M = (TM. <M. QM) be a signature over an object model M. Let Var = {Vart}teTM be a family of variable sets indexed by types t e TM. The family of Essential OCL expressions over £M is given by Expr = {Exprt }teTM representing sets of expressions. The syntax of an Essential OCL expression is defined recursively as follows:
2 P(N+) denotes the power set of the natural numbers (excluding {0} since an association with both lower bound and upper bound of 0 makes no sense). More specifically, we consider intervals with lower and upper bound. Moreover, the upper bound may be * which means infinite.
3 Since in the meta-model shown in Fig. 2 associations are unnamed, we use the convention A_b to label an association between classes A and B with
rtgt = b.
• VariableExpression: v e Exprt for each variable v e Vart, referring to a context, iterator or local variable.
• OperationExp: e := w(e1, ■■■ , en) e Exprt for each operation symbol w : ti x ••• x tn ^ t e QM and for all ei e Exprti (1 < i < n). This includes predefined operations on data types and user-defined non-recursive queries (OperationCallExp), class attribute operations, navigable association end operations (both PropertyCallExp), and constants (LiteralExp). Tables 1 and 2 in Section Appendix A give an overview of the syntax of selected concrete operation expressions in Essential OCL.
• IfExp: If e1, e2, e3 e ExprBoolean then e : = if e1 then e2 else e3 e ExprBoolean.
• TypeExp: If e e Exprt, t, t', t" e TM, and t" <M t then e.ocllsTypeOf(t'), e.ocllsKindOf(t') e ExprBoolean and e.oclAsType(t") e Exprt«.
• iteratorExp: If s e ExprSet(t), v e Vart, b e ExprBoolean, e1 e Exprti, and e2 e ExprSet(ti) then s->exists(v | b), e ExprBoolean, s->select(v | b) e ExprSet(t), s->collect(v | e1) e ExprSet(ti). This formal definition of collect results in sets of values instead of bags, possibly yielding duplicate values. The translation approach presented in this paper thus restricts the expressiveness of collect. However, in many circumstances, not the number of duplicate values is crucial, but the collection of distinct values [3].
• LetExp: If v e Vart, e e Exprt, e' e Exprti and t, t" e TM then let v = e in e' e Exprti.
As mentioned above, we concentrate on invariants being formulated in Essential OCL. Therefore, we consider invariants and OCL constraints as synonyms in the remainder of this paper.
Definition 5 (Essential OCL invariant). Given an object model M, an Essential OCL invariant is a Boolean OCL expression with a free variable v e VarC where C is a classifier type. The concrete syntax of an invariant is: context v:C inv : <expr>. The set InvariantM denotes the set of all Essential OCL invariants over M.
The semantics definition of Essential OCL expressions which is necessary to proof correctness, is recalled in Section 6.1. 4. Nested graph constraints
In this section, we recall the definition of typed attributed graphs with node type inheritance and introduce nested constraints over this type of graphs and compact constraints, compact representations of nested constraints, used in the translation of Essential OCL invariants.
4.1. Graphs
In this subsection, we recall the definitions of attributed graphs and typed attributed graphs with node type inheritance [20] extended by a set of variables and a set of formulas that constrain the possible values of these variables, closely related to symbolic graphs [21].
A directed graph consists of a set of nodes and a set of edges where each edge is equipped with a source and a target node. An A-graph is a directed graph together with a set of data nodes and a set of node attribute edges where each node attribute edge is equipped with a graph node and a data node.
An attributed graph is an A-graph combined with an algebra over a data signature DSIG, in the sense of algebraic signatures (see e.g. [22]). In the signature, we distinguish a set of attribute value sorts. The corresponding carrier sets in the algebra are used for the attribution. Our definition generalizes largely the one in [20] by allowing variables and a set of formulas that constrain the possible values of these variables and is closely related to symbolic graphs [21].
Definition 6 (Attributedgraphs). Let DSIG = (S, OP) be a data signature, X = {Xs}seS be a family of variables, and TDSIG(X) the term algebra w.r.t. DSIG and X. An attributed graph over DSIG and X is a tuple AG = (G, D, $) where G is an attributed graph, D is a DSIG-algebra over the attribute values of G, and $ is a finite set of DSIG-formulas over attributes with free variables in X. A set {F1, ..., Fn} of formulas can be regarded as a single formula F1 A ... A Fn. An attributed graph AG = (G, D, 0) with an empty set of formulas is basic and is compactly denoted by AG = (G, D). Given two attributed graphs AG1 and AG2, an attributed graph morphism f: AG1 ^ AG2 is a pair f = (fG, fD) of an attributed graph morphism fG: G1 ^ G2 and a DSIG-homomorphism fD: D1 ^ D2 such that $2 ^ fD(O1) where fD(O1) is the set of formulas obtained when replacing in O1 every variable x in G1 by fD (x).
We are interested in the case where D1 is a DSIG-term algebra with variables and Df is a DSIG-algebra (without variables). In this case the DSIG-homomorphism assigns values to variables and terms.
An attributed type graph with inheritance is an attributed graph with a distinguished set of abstract nodes and inheritance relations between the nodes. The inheritance clan of a node represents all its subnodes. The notion of typed graph morphism has to be extended to capture the inheritance clan. They are called clan morphisms.
Definition 7 (Typed attributed graphs). An attributed type graph with inheritance ATGI = (TG, Z, I) consists of an A-graph TG, the final algebra Z over attributes with an empty set of formulas, and a simple inheritance graph I (i.e. having neither multiple edges nor loops) with IV = TGV. For each node v e IV, the inheritance clan is the set clanI(v) = {v' e IV | 3 path v' — v in I} where v' v in I stands for a directed path in I from v' to v of length > 0. A typed attributed graph (AG, type) over ATGI, short ATGI-graph, consists of an attributed graph AG = (G, D, $) and a clan morphism, type : AG — ATGI.
Given two ATGI-graphs AG1 = (G1, type1) and AG2 = (G2, type2), an ATGI-morphism f: AG1 — AG2 is an attributed graph morphism such that type2 o f < type1. An ATGI-morphism is called (type-)strict if type2 o f = type1.
An example of a typed attributed graph is shown in Fig. 4.
In the following, we always use typed attributed graphs and ATGI-morphisms but simply call them graphs and (graph) morphisms.
4.2. Nested graph constraints
Graph conditions and graph constraints [23,7] are nested constructs, which can be represented as trees of morphisms equipped with quantifiers and Boolean connectives. Graph conditions are implemented in, e.g., the tool environments AGG [24], GROOVE [25], GrGen [26], and Henshin [27].
Definition 8 (Nested graph conditions). A nested graph condition on typed attributed graphs, short condition, over a graph P is of the form true or 3(a, c) where a : P ^ C is an injective morphism and c is a condition over C. Boolean formulas over conditions over P yield conditions over P, that is, for conditions c, ci (i e I with I being finite) over P, —c and f\iejci are conditions over P. Conditions over the empty graph 0 are also called constraints. In the context of rules, conditions are called application conditions.
Notation. Graph conditions may be written in a more compact form: 3a abbreviates 3(a, true), V(a, c) abbreviates —3(a, — c), false abbreviates —true, \/iei ci abbreviates — f\iei —ci, c ^ c' abbreviates —c v c', c ■ c' abbreviates (c ^ c') A (c' ^ c).
Examples for nested constraints and conditions can be found in Section 2 above. The satisfaction of a graph condition is established by the presence and absence of certain graph morphisms from the graphs within the condition to the tested graph. The presented injective satisfiability notion restricts these morphisms to be injective: no identification of nodes and edges is allowed. In this way, explicit counting such as the existence/non-existence of n nodes is easily expressible.
Definition 9 (Semantics). Satisfiability of a condition over P by an injective morphism p: P — G is inductively defined as follows: p satisfies true. p satisfies 3(P C, c) if there exists an injective morphism q: C — G such that p = q o a and q satisfies c.
3 p = > c <c
For Boolean formulas over conditions, the semantics is as usual: p satisfies —c if p does not satisfy c, and p satisfies ¡\ieici if p satisfies each ci (i e I). We write p == c if p: P — G satisfies the condition c over P. Satisfiability of a constraint, i.e. a condition over the empty graph 0, by a graph is defined as follows: A graph G satisfies a constraint c, short G = c, if the morphism p: 0 — G satisfies c. Two conditions c and c' over P are equivalent, denoted c = c', if, for all injective morphisms p with domain P, p = c iff p = c'.
For simplicity, we also consider so-called compact conditions, built from true and compact conditions of the form 3(C, c) where C is a graph and c is a compact condition. One may translate nested conditions to compact conditions as follows: By definition, nested conditions are based on injective morphisms. Without loss of generality, they also may be based on inclusions. For each inclusion in a condition, the domain is not represented when it can unambiguously inferred, e.g. ^(Ci, 3(C2, c)) :=V(0 ^ Ci, 3(Ci ^ C2, c)). Examples of compact conditions can be found in Section 2.3.
Definition 10 (Compact conditions). A compact (nested) condition on typed attributed graphs is of the form true or 3(C, c) where C is a graph and c is a compact condition. Boolean formulas over compact conditions yield compact conditions. 3(C) abbreviates 3(C, true).
The semantics of compact conditions is defined by the semantics of nested conditions. For this purpose, we transform compact conditions into nested conditions.
Construction (From compact conditions to conditions). For a graph P and a compact condition d, Cond(P, d) denotes the condition over P, inductively defined as follows:
0 .....> C <c Cond(P, true) = true.
\ \b Cond(P, 3(C, c)) = V(a.b),F 3(P -C', Cond(Cc))
v * where F = {(a, b) | (a, b) jointly surjective, a, b inclusions} and (a, b) is jointly surjective if,
P —» C' <] for each x e C', there is a preimage of x in P or in C.
a Cond(P, —c) = —Cond(P, c) and Cond(P, AieJci) = AieJCond(P, ci).
Example 3. The OCL constraint4
context Petrinet inv: self.transition->forAll(t:Transition | t.preArc->notEmpty() or t.postArc->notEmpty())
can be expressed as the compact condition
The completion over the empty graph leads to the nested condition
v(0 — self:PNPrTt?TF1, 3(|self:PN№T^- |self:PNpT[T?r^pr^vl:PTArc|, true)
v 3(1 self:PN№T?1 - |self:PNpT[I?T^postArHv2:TPArc, true)). The detailed translation is given in the long version [13].
Satisfiability of a compact condition is defined by the satisfiability of the corresponding nested condition.
Definition 11 (Semantics of compact conditions). An injective morphism p satisfies the compact condition c, denoted p = c, if p satisfies the nested condition Cond(P, c). Two compact conditions c and c' are equivalent wrt. a graph P, denoted c =P c', if Cond(P, c) = Cond(P, c'). We call them equivalent if they are equivalent wrt. any graph.
By definition, compact conditions and nested conditions have the same expressive power. Somewhat ambiguously, compact conditions are also called conditions.
5. Translation of essential OCL invariants
In this section, we present the translation of Essential OCL to nested graph constraints. The translation process consists of three main steps: In a pre-processing step, OCL expressions are refactored such that a few features do no longer occur and control variables of different collection operations have distinct names. The resulting OCL invariants are then translated to nested graph conditions. The translation is performed recursively along the syntax structure of OCL expressions. The resulting graph constraints may be simplified using proven equivalences on graph conditions. The translation is illustrated at several examples. Limitations that are imposed by our translation are summarized at the end of this section.
As a pre-requisite for the translation, we show in the next subsection how an object model corresponds to an attributed type graph and how system states of an object model correspond to typed attributed graphs.
5.1. Type and state correspondences
The correspondence of an object model M and an attributed typed graph with inheritance ATGI is given by bijective mappings relating every class in M to a node in the type graph, every attribute in M to an attribute node in the type graph, and every association in M to an edge in the type graph being named after the target role name.
Definition 12 (Type correspondence). An object model M over DSÎG corresponds to an attributed type graph with inheritance ATGI = (TG, Z, Inh) with type graph TG = (TGV, TGD, TGE, TGA, srcG, tgtG ,srcA, tgtA ), final DS/G'-Algebra Z for DSIG' = (S U ENUM, OP U {=ENUM, =enum}), and inheritance relation Inh, if there is a correspondence relation corrtype = (corrCLASS, corratt, corrassoc) with bijective mappings
4 Note that this constraint does not occur in Section 2 since definitions of Petri nets usually allow transitions without arcs.
ASSOC corrassoc >TGe pri,W2 srcG,tgtG
cll -ss COrrcLASS >tgv ¡rCA
GAssociai , pr2
b aci<
Fig. 5. Type and system state correspondences.
C-Assoc E
srcG,tgtG vv
CClass
corrCLASS : CLASS ^ TGV with corrCLASS(c)=c for c e CLASS such that Vci,c2 e CLASS: c1 - c2 ^^ (corrCLASS(c1), corrcLASS(C2)) e Inh,
corrATT : ATT ^ TGA with corrATT(att) = attc for att : c ^ s e ATTc such that srcA(corrATT(att)) = corrCLASS(c) and tgtA(corrATT(att)) = x if {x} = Zs with s e S U ENUM,
corrASSOC : ASSOC ^ TGE with corrASSOC(a) = rtgt(a) for a e ASSOC, assoc(a) = (c, c'), pr1(a) = c, pr2(a) = c' and c, c' e CLASS such that srcG(corrassoc(a)) = corrCLASs(pri(a)) and tgtG(corrassoc(a)) = corrCLASS (pr2(a)). See Fig. 5 (left) for an illustration.
To show the correctness of our translation, we also need to establish a correspondence relation between system states being meta-model instances and typed attributed graphs. The correspondence relation is a bijective mapping from objects to nodes, attributes to attribute nodes and associations to edges in the graph.
Definition 13 (State correspondence). Let M be an object model over DSIG and ATGI = (TG, Z, Inh) an attributed type graph with inheritance with corrtype(M) = ATGI. A system state a(M) = (ffCiass, aAtt, &ASS0C) corresponds to an attributed graph AG = (G, D) with G = (GV, GD, GE, GA, srcG, tgtG, srcA, tgtA) typed over ATGI by clan morphism type if there is a state correspondence relation corrstate = (cCiass, cAtt, cAssoc) from a system state to a typed attributed graph, defined by the bijective mappings
• cciass: Ociass ^ Gv with typeGv (cciass(o)) = corrcLASs(c) for o e aciass(c) and c e CLASS,
• cAtt: OAtt ^ Ga with srcA (cAtt (a)) = cciass (o), tgtA (cAtt (a)) = d for typeGh (cAtt (oAtt (att))) = corrATT (att) and a e a Att (att) if att: c ^ s e ATT*, OAtt (att): ociass(c) ^ Ds, o e ociass(c), c e cLASS and a Att (att)(o) = d,
• cAssoc : a Assoc ^ Ge with srcc o cAssoc = cciass ◦ pri and tgtc o cAssoc = cciass ◦ pr2 with i = (oi, o2) e OAssoc(a), pT\ (i) = oi, and pr2(i) = o2. Moreover, typeGE o cAssoc(aAssoc) = cottassoc(ASSOc). See Fig. 5 (right) for an illustration state correspondence.
5.2. Pre-processing of OcL expressions
In order to make the translation of Essential OCL invariants as simple as possible, we perform several pre-processing steps. All steps are semantics preserving and can be regarded as refactorings on OCL expressions [28,29].
• Removing "let" expressions and local variable calls.
Let expr := context self:C inv: let v = e in e' an Essential OCL invariant over an object model M with v e Vart, e e Exprt, e' e ExprBooiean and t e TM. Then expr is equivalent to the Essential OCL invariant expr' := context self:C inv: e" with e" := e'{v/e} meaning that each occurrence of variable v in e' is substituted by (a copy of) the initializing expression e of v.
• Inlining non-recursive query operation calls.
The call of a non-recursive query operation can be replaced by (a copy of) the body expression defining the operation and replacing the context variable seif by the source of the operation call.
• Replacing multiple iterators.
Multiple iterators within a forAll iterator expression can be replaced by inserting a new forAll iterator expression for each additional iterator on the same source expression and in a nested way.
• Ensuring variable names to be unique.
We give each variable a distinct name, e.g. self.a->collect(v | v.b)->exists(v | expr) becomes self.a->collect(v | v.b)->exists(v' | expr).
Example 4 (Pre-processing of OCL constraints).
• The Essential OCL invariant including a locally defined variable
context PetriNet inv: let allPlaces:Set(Place)=Place.allInstances() in (allPlaces-> forall(p1:Place | allPlaces -> forall(p2:Place | p1<>p2 implies p1.name<>p2.name))) is refactored to
context PetriNet inv: Place.allInstances()->forall(p1:Place| Place.allInstances()-> forall(p2:Place | pi <> p2 implies pl.name <> p2.name)).
• The call of the (non-recursive) query operation
context Place::noTok():Integer body: self.tokens -> size() within the OCL expression context PetriNet inv: places -> exist(p:Place | p.noTok() > 0) is refactored to context PetriNet inv: places -> exist(p:Place | p.tokens -> size() > 0).
• OCL invariant context PetriNet inv: self.place -> forAll(pi:Place, p2:Place | pi<>p2 implies pi.name<>p2.name) is refactored to
context PetriNet inv: self.place -> forAll(pi:Place | self.place -> forall(p2:Place | pi <> p2 implies pi.name<>p2.name)).
5.3. Translation of essential OCL invariants
In the following, we present the translation of Essential OCL invariants to nested constraints. It consists of several parts: Invariants are translated by the translation function tr1, OCL expressions yielding a Boolean value by trE, expressions yielding single objects by trN, and expressions yielding collections (i.e., sets) of objects by trS.
OCL expression translation function
OCL invariants tri
OCL expressions yielding a Boolean value trE
OCL expressions yielding single objects trN
OCL expressions yielding collections of objects trS
The latter two translations take a single node as their second parameter; this node represents the object (or the set of objects) yielded by the expression. For set expressions, this node can be matched by any object that is member of the set; so it represents the full set. On the other hand, the resulting condition restricts matchings to nodes inside the set. In general, our OCL translation implements the following design decisions:
• OCL expressions are translated along their abstract syntax structure. For example, given an expression a->union(b)->notEmpty(), we translate notEmpty, then union, and then its arguments a and b.
• The constraint header, declaring that the constraint shall hold for all instances of the context class, is translated to a V constraint just containing an object of the context class. The translated body is nested into this graph constraint.
• Set operations such as union are translated with the characteristic function of sets in mind: E.g. v e A U B if v e A or v e B. An expression expri -> select(v:T | expr2) is translated by yielding all elements in the translations of expri and expr2. We pass a single node v as an extra parameter to the translation function trS serving as representative of the set: trS(a->union(b), v) := trS(a, v) V trS(b, v).
• The operations 3 and V are translated to their counterparts in nested graph constraints.
• Navigation expressions, which yield a single object, are treated like single-element sets.
As an introduction to OCL translation, we present an example translation. To keep track of different constraint parts during the translation process, we mark them with different colors.
Example 5 (The name of a transition is not empty). The OCL invariant context Transition inv: self.name <> " states that transitions have non-empty names. This will be translated as follows: The overall expression is an invariant, so we use tr1:
tri(context Transition inv: self.name <> ")
Invariants have to hold for all objects of the specified type. The variable self represents one object of that type, so we have
V( self:Tr |, trE (self.name <> "))
Then the translation proceeds at inner expressions, in this case self.name <> ". We translate along the abstract syntax tree, look at the attribute name of transitions and introduce a new node |v:Tr| as a representative of the rest of the expression (in this case self).
V(lself:Tr|, v:Tr|, trN(self,|v:Tr) A 3(
In the next step, the variable expression self is translated. The node |v:Tr| introduced in the last step is equal to the node |self:Tr|, as expressed by the | self=v:Tr] node below.
v(self:TrI a(v?fr], 3(|self=v:Tr|) A 3(|name <> "))) This expression can be further simplified. The result is
V(self:Tr1, 3( n^" ))
Example 6 (Set expressions). As a more advanced example, let's have a look at OCL expressions of the form s-> exists(v:Tr | v.name='a') as part of an invariant. We start at the outermost part exists(v:Tr | name='a') and translate this to 3(1 v:Tr\, trE(name='a')). We next formalize that |v:T| is an element of the set described by s. This is done by giving a predicate trS (s, that describes the set precisely and passes wrn as a parameter to trS. The transla-
tion of the whole expression s->exists(v:T | v.name='a' has to fulfill both trE(name='a') and trS(Iv:Tr\, s).
becomes 3(1 v:Tr I,
arS(s,I v:Tr)), because |v:Tr|
Definition 14 (Constraint translation). Let M be an object model over DS1G with ATGI = corrtype(M). Let t : Expr ^ T be a typing function which returns the type of an OCL expression. Let InvariantM be the set of Essential OCL invariants over M and CompactConditionATGI be the set of all compact conditions as defined in Definition 10. The translation functions
invariant translation expression translation navigation translation set translation
tri : InvariantM
trE : ExprBoolean
trN : Exprc x GraphATGI -trS : ExprSet x GraphATGI -
CompactConditionATGI CompactConditionATGI CompactConditionATGI CompactConditionATGI
where C e CLASS, are defined as follows:
Let expr, expri and expr2 be OCL expressions, u, v, v' variables (also used as names of nodes), T = t(v) denote the type of v and likewise T' = t(v'), attri and attr2 be attribute names, op e {<, >, <, >, =, <>} a comparison operator, and role be a role of a class. Then
1. (a) tr1 (context C inv: expr) := V(lself:C|, trE(expr))
(b) tri(context var:C inv: expr) := V(lvar:C I, trE (expr))
2. Translation of Boolean operators is straightforward: trE(true) := true, trE(not expr) := — trE(expr), trE(expri and expr2) := trE(expri) A trE(expr2) and likewise for or and implies.
trE (if cond then expri else expr2) := (trE (cond) A trE (expri)) V (—trE (cond) A trE (expr2))
3. (a) trE(expri->exists(v:T | expr2)) := 3(1v:T|, trS(expri,I v:T|) a trE(expr2)) (b) trE(expri->forall(v:T | expr2)) := V(lv:T\, trS(expri, [v^) ^ trE(expr2))
4. trE(expri->includesAll(expr2)) := V(lv:T\, trS(expr2, I v:T) ^ trS(expri, I v:T)) where t(expri) = t(expr2) = Set(T). The translation of excludesAll is analogous.
5. trE(expr->notEmpty()) := 3(1 v:T|, trS(expr, [vTl))
6. (a) trE(expr->size() >= n) := 3(1 vi:T|•••! vn:T\, /\n=1 trS(expr,
where n>0 is an integer constant, t(expr) = Set(T) and vi, ..., vn are fresh variables of type T. (b) trE(expr->size() >= 0) := true
7. (a) trE(expri = expr2) := 3(iv7T1, trN(expri, [vTT]) a trN(expr2, E^)
if t(expri) = t(expr2) = T for some class T, (b) trE(expri = expr2) :=V(|v:Tl, trS(expri, [vTtI) ^ trS(expr2,[vTI)) if t(expri) = t(expr2) = Set(T) for some class T.
8. trE(expr.attri op con) := 3(1v:T|, trN(expr, I v:T|) a3(" where con is a constant and t(expr) = T for some class T.
attri op con
name <>
9. trE(expr1.attr1 op expr2.attr2) := 3([VT, trN (expr1,
attr1 op x
) A trN(expr2,
3(1 v:T||v':T' |, trN (expr1,
attrl op x
) A trN(expr2,
v':t(v')
where t(expr1) = T, t(expr2) = T', t(x) = t(attr1) = t(attr2) and x, v and v' are fresh variables.
10. (a) trE(expr.oclIsKindOf(T)) := 3(1 v:T'|[vÎTl, trN(expr, I v:T'|)) ___
(b) trE(expr.oclIsTypeOf(T) ) := 3(1 v:T'|[vTt], At"eç -3(iv?T|v:T") a trN(expr, I v:T'|))
where T' = t(expr), T e clan(T') and Ç = clan(T) — {T}. Note that in this step and the following, non-strict morphisms are used.
11. trN(expr.oclAsType(T),iv?T) := 3(|v:T'| [v?T, trN(expr, I v:T')) where T' = t(expr) and T e clan(T')
12. (a) trN(v, I v':T) := if v is a variable, _
(b) trN (expr.role, [v?T) := 3(1 v':T'hrolefv?T, trN (expr, I v':T' )) if T' £ clan(T) and 3(1 v'TFi^fv-TI, trN(expr,I v':T'I)) v 3(iv?^role, trN(expr, [v?T])) else.
13. trS (expr1->select(v:T | expr2) , I v':T' ) :=
3([v?T, trS(expr1, I v:T'I) a trE(expr2){v/v'} where expr2{v/v'} means replacing v in expr2 with v'.
14. trS(expr1->collect(v:T | expr2),I v':T') :=
trS (expr1, ivd ) A trS (expr2, I v :T )) if expr2 yields a set
15. trS(expr1->union(expr2) , ET) : = trS (expr1, ET ) V trS (expr2, ET) The translations of set operations intersect, - and symmetricDifference are analogous.
16. trS (T.allInstances() , I^T] ) := 3([vT)
17. trS(Set{expr1, ..., exprN},I v:T|) :=
trN (expr1,
ET) V ••• V trN(exprN, ET) where expr1, ..., exprN are OCL expressions of type T.
Further translations of Essential OCL constraints can be derived from equivalences of OCL expressions. Most of these equivalences follow from basic set theory and logic axioms, cf. Richters [19, Tables 4.4 and 4.5 and page 73]. Such equivalences include operations includes, excludes, including, excluding, <>, isEmpty, expr->size op n for op in >, = ,<=,<,<>, any and one.
In the following, we present two examples which illustrate the translation given above. For further examples, please refer to the OCL constraints in Section 2.1 and their translations to graph conditions in Section 2.3. These translations are shown in all details in [13].
Example 7. To illustrate our translation defined above, we translate the invariant There is at least one place in a Petri net having at least one token presented in Section 2:
context PetriNet inv: self.place->select(p:Place | p.token->notEmpty())-> notEmpty()
An index above the = sign refers to the translation rule used; the equivalences used to simplify the results are detailed in [13]. Colors are used to distinguish different parts of the constraints and show their correspondence during translation.
tri(context PetriNet inv:self.place->select(p:Place|p.token->notEmpty())->
notEmpty())=
v(self:PN|. trE(self.place->3elect(p:Place|p.token->notEmpty() ) ->notEmpty())) =
V(| self:PN |, 3(|p:Pl |, trS (self.place->select(p:Place|p.token->notEmpty() ), |p:Pl )) =
V(|self:PN|, 3(|p:P1 trS(self.place, |p:P1 |) a trE(p.token->notEmpty() ))) = V( self:PN |, g^P^, trS (self.place, [p^ ) A 3(1 t:Tk |. trS (p.token, (ETE)))) =
attr2 = x
attr2 = x
5 The part before v is omitted if clan(t(expr1)) n clan(t(expr2)) = 0, and the part after v is omitted if expr1 = expr2.
V(lself:PN|, g^pPI], 3(1self:PN^p?P^ a 3^?Tkl, =
V(lself:PN|, 3(1 self:PN^pla£e[p:P^Ioke»[t?Tk1 ))
Example 8 (Further invariant translations). Distinct places of a Petri net have distinct names. tr/(context PetriNet inv:
self.place->forAll(pi,p2:Place | p1<>p2 implies pi.name <> p2.name)) =
V(|self:PN|, 3(| self:PN
' Jiace
p1:Pl p2:Pl
nameox name=x
This is equivalent to the corresponding example constraint in Section 2.3.
Remark 1 (Translations of Core and Essential OCL). The translation of Core OCL constraints in [6] is closely related to the translation of Essential OCL constraints presented in this paper: Every Core OCL constraint translated as in [6] yields a nested graph constraint which is equivalent to the translation result in this paper. For the proof, see [13].
5.4. Limitations
Since we focus on the use of OCL within DSML definitions, we restrict our translation to invariants. Therefore, we do not consider expression oclIsNew that is mainly used within post-condition specifications of operations.
Graph-based approaches rely on graphs to represent type and object structures. Therefore, flat object sets are the only form of OCL collections to be translated. Consequently, we do not translate expressions related to further collection types (e.g., Sequence) such as sortedBy and isUnique as well as expressions related to hierarchical sets (e.g., flatten) and sets of primitive values (e.g., sum).
Since nested graph constraints are restricted to a first-order, two-valued logic, our OCL translation is straightened to corresponding OCL features, focusing on the equivalence of constraints to true in our proofs. Therefore, we do not consider types void and invalid as well as expressions like oclIsUndefined. As argued in [30], the use of three- or four-valued logic often leads to unexpected results; there are also techniques to avoid the use of null and invalid values in OCL by using guards [31].
The translation of If-expressions is restricted to those which consist of Boolean expressions only. The size operation may only be used in comparison with constants, since it is expressed structurally in graph constraints. Furthermore, we do not consider iterate, which is not first-order. Finally, OperationCall expressions are considered only if underlying operations are not user-defined.
6. Correctness and completeness of the translation
In this section, we show the correctness and completeness of the translation tr given in Definition 14. In order to do this, we need to recall the formal semantics for the Essential OCL invariants we translate, as given in the OCL specification [1].
6.1. Semantics of Essential OCL invariants
The essence of OCL semantics is recalled from the doctoral thesis by Richters [19]. We prefer this formalization, in contrast to the UML-based specification, since it is more suitable for proving the semantics preservation of our translation.
Definition 15 (Semantics of a signature). Let SM = (TM, <M, QM) be a signature over an object model M. The semantics of M is a structure 1(^M) = (1(TM), 1 (<M), 1 (QM)) where
• 1 (TM) assigns to each type t e TM an interpretation 1 (t), e.g., 1 (Real) = R, 1(tc) = o^lass(c) for class c, and 1 (Set(t)) is the set of all finite subsets of 1(t).
• 1 (<M) implies for all types t, t' e TM that 1 (t) c 1 (t) if t <M t',
• and 1 (QM) assigns each operation a: t1 x ••• x tn ^ t e QM a total function 1(a) = 1 (t1) x ••• x 1 (tn) ^ 1(t), e.g., 1 (42) = 42, 1 (+1nteger)(i, j) = i + j for integers i and j, 1 (att: tc ^ t) = OAtt(att)(c') with c' e oaaSs(c), and 1 (c': tc ^ Set(tc)) = c | (c, c') e oAssoc (a)}.
With the help of the signature semantics, we now recall the semantics of Essential OCL expressions, laying the basis for the correctness proof of our OCL translation.
Definition 16 (Semantics of essential OCL expressions). Let 'EM = (TM, <M, i2M) be a signature over an object model M. Let Var = {Vart}teTM be a family of variable sets indexed by types t e TM. Let Env = {t | t = (a, /3)} be a set of environments
with system states a and variable assignments 55: Vart ^ I(t) which map variable names to values. The semantics of an Essential OCL expression e e Exprt is a function I [e]: Env ^ I(t) and is defined recursively as given in Tables 1 and 2 for each t = (a. ¡5) e Env.
Remark 2. An invariant context v:C inv:expr can be expressed by C.allInstances->forAll(v|expr) [32, p. 213]. Therefore, the semantics of this invariant is equal to the semantics of the corresponding Essential OCL expression.
6.2. Main theorem and proof
To show that the translation of Essential OCL invariants is correct, we consider their semantics and the semantics of graph constraints. If an invariant holds for a system state, the corresponding graph constraint is fulfilled by the corresponding graph.
Theorem 1 (Correct translation of essential OCL invariants). Given an object model M and its corresponding attributed type graph corrtype(M), for all Essential OCL invariants inv e Dom(trl), all environments (a. ¡5) e Env and typed attributed graph
G = corrstate (a),
I\inv](a.fi) = true — G = trl(inv).
The proof proceeds by induction over the items of Definition 14. The semantics of the respective OCL expressions is taken from Definition 16 and then reformed until it fits the semantics of the graph condition according to Definition 9.
Proof. We prove three statements concerning the translation functions trN, trE, and trs, respectively: Given an object model M with attributed type graph corrtype(M), for all Essential OCL expressions expr in the domain of trN, trE, and trs, all environments (a. ¡5) e Env and morphism p from the empty graph to G = corrstate(a),
(i) i[expr] (a.¡) = true — p = trE(expr) — G = trE(expr)
(ii) I [[expr] (a .¡) = v — p e idv = trN (expr. [v^ 6
(iii) i[expr] (a.¡) = V — VveV .p e idvl= trs(expr. [v?f]).
By Remark 2 and the definition of tr, for invariants inv = context C inv: expr and morphisms p :0 ^ G,
I [inv] (a= true — C.allInstances->forAll(self|expr) — p =V( self:C I. trE (expr)) — p = tri (inv) — G = tri (inv).
Base case. I [context C inv: true] (a. ¡5) = true = Vv e aCiass(C ).true = true) = tri (context C inv: true).
Hypothesis. For all subexpressions expr, objects v. v 1..... vn and morphisms p: {[vT e caass(f(v)) |v e Dom(5)} ^ corrstate(a), let statements (i), (ii) and (iii) be true. Induction step.
(1) I [context var:T inv: expr](a. 5) — I [C.allInstances()->forAll(expr) ] (a. 5) Ind. hyp.
— p |= V(IvTTI. trE (expr)) Def. =
— p |= tri (context var:T inv: expr)
Case context C inv: expr follows as a special case of the above with var = self.
(2) Since Boolean operators in OCL have corresponding operators in conditions, proofs are straightforward.
(3) Let t(expr1) = T.
i[expr1->exists(v:T | expr2) ](a. /5)
— i [expr1] (a. 5) = {v 1..... vn} A V 1<i<n i [expr2] (a. 5{v/vi})
— i[expr1](a. 5) = {v 1. .... vn} A3vi e{v 1. .... vn}.i[expr2](a. 5{v/vi})
— 3v e aaass(T).i[expr1] (a. 5) A i[expr2] (a. 5)
— e cdass(aClass(T)).p e idv l= trs(expr1. EI]) A p e idv l= trE(expr2))
— p =3(ivTl. trs (expr1. ^^) A trE(expr2))
— p = trE (expr1->exists(v:T| expr2)) The proof of forall is analoguous.
(4) Let t(expr1) = t(expr2) = Set(T).
6 For morphisms p : P ^ G, let function composition p ® idv be the morphism p' : P ® |v:T ^ G, with p'(v) = p(v) if v e Dom(p) and p'(v) = v otherwise. Note that P = 0 for constraints.
(Definition 16) (set axioms) (set axioms) (Ind. hyp.) (Def. |=) (Definition 14.3)
1 [expri->includesAll(expr2)](o, ft) • 1 [expr2] (a, ft) C 1 [expri] (o, ft)
• Vv e o(T).v e 1[expr2](o, ft) implies v e 1 [expri](a, ft)
• V^1 e caass(o(T)).p 0 idv |= trS(expr2, [^ implies p 0 idv |= trS(expri, [v:T])
• p =V(EH, trS(expr2,[v-Th implies trS(expri,[vTtI))
• p = trE(expri->includesAll(expr2)) The proof of excludesall is analogous.
(5) 1 [expr->notEmpty() ] (o, ft) • 1 [expr](o, ft) = 0
• 3v e OClass(T).v e 1 [expr] (O, ft)
• 3^1 e caass(OClass(T)).p 0 idv = trS (expr, [v?f])
• p |= 3(v^T], trS (expr, a
• p |= trE(expr->notEmpty())
1 [expr->size() >= n](a, ft) •I {v |1 [expr] (o, ft)} | >= n
• 3v 1, ..., vn e o(T). mj=u=j(vi = vj) A An=1(vi e 1 [expr] (o, ft))
• ^[vTTT]. .^[vniT]ecC/ass(o(T)). At=1 p 0 idvi = trS (expr, [vijT])
• p I= 3■ ■ ■ [vn^], /\n=1 trS (expr,
• p |= trE (expr->size() >= n)
(7a) For t(expri) = t(expr2) = T for some class T,
1 [expri = expr2](o, ft) • 1 [expri](o, ft) = 1 [expr2](o, ft)
• 3v e Oaass(T).v = 1[expri](O, ft) A v = 1 [expr2](o, ft)
• 3^T] e cClass(OClass(T)).p 0 idv = trN(expri, [v?T]) A p 0 idv |= trN(expr2, [v?T])
• p =3([xTt], trN(expri, [v?T]) A trN(expr2,[vrT]))
• p = trE (expri = expr2)
(7b) For t(expri) = t(expr2) = Set(T) for some class T,
1 [expri = expr2](o, ft) • 1 [expri](o, ft) = 1 [expr2](o, ft)
• Vv e OClass(T).v e 1 [expri](o, ft) iff v e 1 [expr2](o, ft)
• V^S e cClass(o(T)). p 0 idv = trS (expri, [vTxb iff p 0 idv = trS (expr2, [v^
• p =V(£3, trS(expri, [v:Th iff trS(expr2, [vS]))
• p = trE (expri = expr2)
1 [v.attr op x] • 1 (op)(S, ft)(1 [v.attr] (S, ft), 1(x)(S, ft))
• 1 (op)(S, ft)(OAtt(attr)(ft(v)), x)
') = trE (v.attr op x)
(9) Let T=t(expri), T'=t(expr2), att(v, att)=OAtt(att)(1 [v] (o, ft)), pv = p 0 idv, pv'=p 0 idv 1 [exi.ai op ex2. a2](o, ft) • att(exi, ai) op att(ex2, a2)
](o, ft) A att(v, ai) op att(v', a2)
• 3v, v'.v = 1 [exi](o, ft) A v' = 1 [ex2]
• 3([vTx], [ v':T'|.pv = (trN(exi, [vTT]) a 3(
a1 op x
trN (exi, v=v':T
a1 op x ) A pv
pv |= trN(exi, a1 op x )
v=v':T
))) A pv' = trN(ex2, [v:^ A3( ))
a2 = x
(set axioms) (Ind. hyp.) (Def. |=) (Definition 14.4)
(set axioms) (Ind. hyp.) (Def. =) (Definition 14.5)
(set axioms) (Ind. hyp.)
(Def. =)
(Definition 14.6)
(use variable) (Ind. hyp.) (Def. |=) (Definition 14.7a)
(set axioms) (Ind. hyp.) (Def. |=) (Definition 14.7b)
(Ind. hyp.) (Def. =, Definition 14.9)
(Definition 16) (Ind. hyp.)
(Equiv. 2)
a2 = x
• p =3 (^, trN (exi,
v:T ) A trN (ex2, v:T
a1 op x a2 = x
A pv |= trN (ex2
V3(^TP1T71, trN (exi,
v:T ) A trN(ex2, v':T'
a1 op x a2 = x
• p = trE(exi.ai op ex2.a2) (10) Let t(expr) = T' and T e clan(T').
1 [expr.oclIsTypeOf(T) ](o, ft) • 1 [expr](a, ft) e (1 (T) - (JT''=MT 1 (T''))
• 3v = 1[expr](o, ft).v e 1(T) A Ai''=Mt .v e 1 (T'')
• 3v = 1[expr](o, ft).v e O^ss(T) A^MT''=Mt .v eO^JV)
• 3(1 v: 1' |.3(l v:
• p = 3 d^r]
■IvT) a A T''=T
v-T, AT''ec/an(T) • p = trE(expr.oclIsTypeOf(T))
t"<mt . ^
t''=t " —3([viT
v?T"1) A trN(expr, WT^)
(Def. |=)
(Definition 14.9)
(set axioms) (Definitions 3, 2) (Ind. hyp.) (Def. |=) (Definition 14.10)
The proof is analogous to the one for ocsIsTypeOf (without the (J-part). (11) Let t(expr) = T'.
v = i [expr.oclAsType(T)] (a. 5) — v = i [expr] (a. 5) A i [expr] (a. 5) e i(T)
— v = i[expr](a. 5) A v e aaass(J)
— 3EH e cdass(a(T)). A p e idv = trN(expr. [v?r]) a 3([v:T] ^ [v?f])
— p = 3(EH ^ [vrT]. trN(expr. EZ]))
— p = trN(expr.oclAsType(T) . EH) (12a) Let t(v) = t(v') = T.
v' = i[v](a. 5) — 3v' e a(T)5(v) = v'
— jv^l e cqass(a(T))
— p = 3(Iv=v':TI) — p |= trN(v. E]l])
(12b) First, assume T £clan(T') and let t(expr) = T'. t(expr.role) = T. v = i[expr.role](a. 5) — (i[expr](a. 5). v) e aAsSoc(role)
— 3v' = i[expr] (a. 5) A t(v') = T' A[vjlPMiS e cAsSoc(aAsSoc(role))
— 3(v']T] e cGass(a(T)).p e idv' = trN(expr. [vYF]) A p e idv' eidv |= iv7?T^lalefv?T1)
— p = 3 (EjTP1^. trN (expr. [V^)
— p = trN (expr.role. [VD
Now assume T e clan(T') and let t(expr) = T'. t(expr.role) = T.
v = i [expr.role] (a. 5) — (i [expr] (a. 5). v) e aAssoc(role)_
— 3v' = i[expr] (a. 5).[V?I:}I^leEЗ e cAssoc(aAssoc(role)) V lv=v':T'K>ole_
— 3(1 v':T'I.p e idv' = trN(expr. I v':T') a (p e idv'e idv = |v':T'F2lefy?T v |v=v':TQroie))
— p = 3(Iv'^'F^vT. trN(expr. I v':T'I)) V 3(E^ole. trN(expr. [v?T1))
— p = trN (expr.role. [VD
The proof of the trs cases is analogous to the trN cases.
(13) Let t(expr1) = Set(T).
ve i[expr1->select(v:T|expr2)](a. 5)
— v e{v' | v'e i[expr1] (a. 5)} A i[expr2] (a. 5{v/v'})}
— 3v e a(T).v e i[expr1] (a. 5) A i[expr2] (a. 5{v/v'})
— p e idv = trs(expr1.1 v:T) A p e idv = trE(expr2)
— p = trs(expr1->select(v:T | expr2) . es) The proof for reject is analogous.
(14) Let t(expr1) = Set(T).
v e i[expr1->collect(v:T |expr2) ](a. 5) — v e {i[expr2](a. 5{v/v'})|v' e i[expr1](a. 5)}
— 3v' e i[expr1](a. 5).v e i[expr](a. 5{v/v;})
— 3(E3. I v':T'|.p e idv' = trs (expr1. [VTt7^ a p e idv = trs (expr2. [vT]))
— 3([viX]. p =3(Iv':T'I. trs(expr1.1 v':T') A p e idv e idv' = trs(expr2. [v^T^))
— p =3(E3. trs (expr1. [vTl) a trs (expr2. [ v':T'))
— p = trs(expr1->collect(v:T | expr2) . i v':T'|) The proof for expr2 yielding an object is analogous.
(15) Let t(expr1) = Set(T).
v e i[expr1->union(expr2) ] (a. 5) — v e{v'|v' e i[expr1](a. ^^{v' |v' e i[expr2] (a. 5)}
— v e i[expr1] (a. 5) V v e i[expr2] (a. 5)
— p e idv = trs (expr1. ET) V p e idv = trs (expr2. ET)
— p = trs (expr1. [vTl) V trs (expr2. [ v:T)
— p = trs(expr1->union(expr2) . [ v:TI) The proofs for intersect, - and symmetricDifference are analogous.
(16) v e i[T.allInstances](a. 55) = aaass(T) — v e aaass(T) —t(v) = T
— p = 3(eH) — p |= trs(T .allInstances() . [vTT)
(17) Let t(expr1) = ... = t(exprN) = T. v e i [Set{expr1,...,exprN}](a. 5) — v e {i [expr1](a. 5)..... i [exprN](a. 5)}
— v = i[expr1](a. 5) V---V v = i[exprN](a. 5)
— p e idv = trN(expr1. [ v:TI) V---V p e idv = trN(exprN. ET)
— p = trN (expr1. E3) V---V trN(exprN. E3)
— p = trs (Set{expr1, ..., exprN}. [ v:T |) This completes the induction proof. □
(Definitions 3, 2) (Ind. hyp.)
(Def. |=) (Definition 14.11)
(cClass)
(Def. =, trN)
( c Assoc )
(Ind. hyp.) (Def. |=) (Definition 14.12)
( c Assoc )
(Ind. hyp.) (Def. |=) (Definition 14.12)
(set axioms) (Ind. hyp.) (Definition 14.13)
(set axioms) (Ind. hyp.) (Def. |=) (Def. |=) (Definition 14.14)
(set axioms) (Ind. hyp.) (Def. |=) (Definition 14.15)
(corrClass) (Def. =, trs)
(set axioms) (Ind. hyp.) (Def. |=) (Def. trs)
The completeness of the translation follows directly from the definitions.
Lemma 1 (Completeness). Translation tr is complete, i.e. for all Essential OCL invariants inv e Dom(tr), there is a graph condition tr(inv).
Proof. Since every OCL expression in Definition 4 is translated into a graph condition in Definition 14, tr is necessarily complete. □
7. From graph constraints to application conditions
In Section 5, Essential OCL invariants are translated into graph constraints. In this section, we informally recall the translation of graph constraints into right and left application conditions of rules as presented in [7]. Chaining both translations and combining them with the translation of meta-model structures to sets of edit rules, we obtain a graph grammar (with left application conditions) for instance generation.
71. Direct graph transformation
In the following, we reconsider graph transformation rules and direct graph transformations and restrict ourselves to rules with injective morphisms, left application conditions, and injective matches.
A rule q = (p, acL) consists of a plain rule p = (L ^ K ^ R) with two injective, type-strict morphisms and an application condition acL over L. The application of the rule q to a graph G means to select an occurrence of L in G, (i.e., an injective morphism g: L ^ G), check the dangling condition "No edge in G — g(L) is incident to a node in g(L — K)" and the left application condition acL, delete g(L—K) from G and to add a fresh copy of R—K. Several examples of direct graph transformations have been shown in Section 2.6 above.
7.2. From graph constraints to right application conditions
In this subsection, we sketch how constraints are shifted to right application conditions. The corresponding transformation is denoted by Shift.
A constraint holds over the empty graph, i.e., does not need any premise to hold. Shifting a constraint from the empty graph to the right-hand side of a rule adjusts the constraint to the right-hand side by adding items (nodes and edges) to every graph in the constraint, such that the resulting condition is a right application condition for the considered rule.
C .....> c'
Shifting a constraint 3(P -— C, c) over an injective morphism b : P — P' means to calculate all possible overlappings C' of P' and C, and to shift the subcondition c over the induced injective morphism b' yielding a condition c'. Hence, shifting the constraint 3(P -— C, c), the resulting right application condition is formed from the conditions \/iel 3(a'i, c'i) being equivalent to f\iel V(a'i, c'i).
Example 9 (From graph constraints to right application conditions). Consider the rule p = createPN(n: String) which creates a Petri net with name n and the graph constraint c1 stating that every Petri net has at least one token.
c1 = yd 1:PN 1, 3dTTPNpiaceiTpn-take»RTk ))
Shifting the constraint c1 over the morphism a from the empty graph to the right-hand side of the rule p yields the right application condition Shift(a, c1) = rc11 A rc12 with the subconditions
rcii =y( p:PN 1,p:PN , 3( 1,p:PN place
name=n name=n name=n J
p:PN place
name=n J
H-PÏÏ^e^-Tkl)
rci2 =y(
name=n
name=n 11:PNh
] place
OlO^HITk]))
While rcn requires that the newly created Petri net has at least one token, rci2 requires this for all other Petri nets in the result graph of the considered transformation. [13] presents this translation in more details.
—»■
—>■
7.3. From right to left application conditions
In this subsection, we sketch how right application conditions can be shifted over rules to left application conditions. The corresponding transformation is denoted by Left. The transformation Left is based on rule application, more precisely, the application of the inverse rule.
The application of Left to the right application condition 3(a, ac) yields a left application condition 3(a', ac') where the graph L' is obtained from the graph R' by applying the inverse rule (R — K ^ L) to R' according to the injective morphism R ^ R' provided that the dangling condition is met. The left application condition ac' is obtained by shifting the subcondition ac over the induced rule (L' — K' ^ R'). If the inverse rule is not applicable to a right condition, the resulting left condition is false.
Example 10 (From right to left application conditions). Consider the rule p = createPN(n:String) and right application condition rci = rcn Arci2 constructed in Example 9. The construction Left yields the left application condition Left(p, rci) = lcn A lc12 with
lc\\ = Left(p, rcn) = false
lci2 = Left(p, rci2) = V(0 ^ [Hi, 3(HN£!2£iniDMs*niE))
Since the inverse rule of p, p-1, cannot be applied to rc11 due to the dangling condition, lc11 is equal to false. But rule p-1 can be applied to rc12 yielding lc12, a left application condition which is equivalent to the original constraint, since the left-hand side of p is empty.
7.4. Constraints on rule parameters
We illustrate the effect that constraints may have on rule parameters such as names of created elements at the following example.
Example 11 (From constraints on attribute values to conditions on rule parameters). Consider the rule createPN(n:String) and the constraint
K—>R
a'l (2) | m [a
c2 =-3(
stating that a Petri net must not have an empty name. Translating the constraint by Shift and Left shows a special case: The PN-node is removed from the constraint, but the parameter n (used to refer to the Petri net name) remains. Hence, the corresponding right application condition states that n must not be the empty string.
In more detail, performing Shift over the morphism a from the empty graph to the right-hand side of the rule leads to rc2 = Shift(a, c2) = rc21 A rc22 with
Transforming rc21 to a left application condition results in the original constraint c2, whereas transforming rc22 leads to n =''.
As a result of this section, the translation of OCL invariants to graph constraints together with the Shift and Left constructions can be used to equip a set of rules with suitable (left) application conditions. In Section 2.4, we have introduced generation rules for Petri nets. Their application conditions are shown in Section 2.5. They ensure that after each transformation step all OCL invariants are satisfied. The generation of an example Petri net from the empty start graph using these extended rules is presented in Section 2.6.
8. Related work
In the literature, there are several approaches to translate OCL to formal frameworks. Most of them are logic-oriented; they translate class models with OCL invariants into logical facts and formulas. The motivations for translating OCL to formal frameworks are manifold and include defining a clear semantics, generating model instances, and performing formal verification of UML/OCL models. In the following, we sketch logic-oriented approaches using the Key prover, the Alloy project, and Constraint Logic Programming, respectively, and compare them roughly with graph-based approaches.
In [33], Beckert et al. present a translation of UML class diagrams with OCL constraints into first-order logic; the goal is logical reasoning about UML models. The translation has been implemented based on the KeY system.
Formal methods such as Alloy [4] can be used for instance generation: After translating a class diagram to Alloy, an instance can be generated or it can be shown that no instances exist. This generation relies on the use of SAT solvers and can also enumerate possible instances. In [34], UML models are automatically transformed to corresponding Alloy representations. Alloy models can then be analyzed automatically, with the help of the Alloy Analyzer. Defining a finite scope, i.e., an upper bound for the number of elements, the Alloy Analyzer can check if there exists an instance within that scope which fulfills all constraints. If the answer is "no", the user cannot infer that there does not exist an instance fulfilling all constraints. A recent work translating OCL to relational logic is presented in [3] covering more features than UML2Alloy. Comparing our instance-generation approach to Alloy-based ones, we can state that we do not establish scopes for instance generation but provide a rule set which guarantees the generation of valid instances. In an extreme case, however, our translation may lead to application condition false for certain rules which may lead to an inapplicable rule set while Alloy would not find instances in given scopes. These are two different ways to deal with the undecidability of the problem. It is up to future work to develop ideas how instance-generating rules can be adapted to rules that do not become inapplicable by our constraint translation. Although this will not always be possible, it would be interesting to push the limit.
In [2], Cabot et al. present UMLtoCSP, a tool that is able to automatically check correctness properties of UML class model with OCL constraints based on Constraint Logic Programming. UMLtoCSP translates a UML diagram and a set of OCL invariants into a Constraint Satisfaction Problem (CSP) that is solved by the constraint solver ECLiPSe. As for the Alloy-based instances, the system searches within user-defined upper bounds for an instance satisfying all constraints. In contrast to UML2Alloy and [3], Constraint Programming does not restrict the expressive power of OCL.
The USE tool [19,35] can be used for generating snapshots that conform to the model or for checking the conformity of a specific instance. Gogolla et al. follow a more imperative approach than the CSP- and SAT-based tools: The user provides a sequence of commands to sequentially generate snapshots, allowing backtracking. Inside the command sequence, OCL expressions are used to guide the snapshot generation. Additionally a set of OCL invariants can be loaded to further restrict the search results or to check the implication problem for OCL invariants on the generated snapshots. In contrast to our approach and the ones presented above, the USE tool uses OCL directly instead of translating invariants to other representations. Opposed to solver-based approaches, the user has a more fine-grained control over the instance generation.
In contrast to logic-oriented approaches, graph-based approaches translate OCL constraints to graph patterns or graph constraints. Pennemann has shown in [36] that a theorem prover for graph conditions works more efficiently than theorem provers for logical formulas being applied to graph conditions. The key idea is here that graph axioms are always satisfied by default when using a theorem prover for graph conditions. Lambers and Orejas [37] have shown that this theorem prover is not only correct but also complete, i.e., whenever an implication holds, it can be shown by the theorem prover.
Bergmann [9] has translated OCL constraints to graph patterns. He considers a pretty similar subset of OCL as we do (extended to some kind of OCL expressions not being first-order), and in fact, the way of translation shows a lot of similarities. The focus of that work, however, is not a formal translation showing correctness and completeness but an efficient implementation of constraint checking which is tested at example constraints. Since the implementation uses incremental pattern matching, it outperforms other implementations such as a naive Java implementation, the OCL interpreter of Eclipse, etc. for large model graphs. It has not yet been compared with the theorem prover by Pennemann.
In [38], an interesting extension of our OCL translation is considered: Special "trace" edges are used to represent ordered sets. Another extension of our OCL translation is presented in [39], where HR* conditions, an extension of nested conditions, are used to translate a subset of OCL expressions using iterate as operation.
9. Conclusion
This article presents a translation of Essential OCL to nested graph constraints. While navigation expressions in OCL are translated to graph patterns, the main idea for translating constraints with set operations is to use the characteristic function of sets which assigns each set operation its corresponding Boolean operation. For this translation, we introduce a compact notion of nested graph conditions. They permit a comparable complexity of OCL constraints and translated graph constraints. Hence, they present a new graphical representation of OCL invariants being slightly more abstract since several navigation paths can be combined in graphs and set operations are reduced to Boolean operations. Compact conditions are extensively used in our OCL translation. As the central contribution of this article we show that the translation of Essential OCL invariants to nested graph constraints is correct, i.e., a model satisfies an Essential OCL invariant iff its corresponding instance graph satisfies the corresponding nested graph constraint. Moreover, we show that our translation is complete for the chosen set of OCL invariants.
Translating Essential OCL invariants to nested graph constraints and further to application conditions of rules provides the missing link between meta-modeling and transformation systems which may be advantageously used by MDE activities. Applications of our results include but are not limited to the following: The generation of meta-model instances for, e.g., testing of model transformations and other kinds of algorithms on models. In addition, the generation of edit operations as well as model repair actions from meta-models may be interesting: For example, model change recognition as well as model patching may be lifted to recognizing and packaging edit operations to patches [40]. To adapt such a general approach to domain-specific needs, complete sets of edit operations have to be specified being able to build up and destroy all models of a DSML. The automatic generation of edit operations from a given meta-model would be of great help. A generation approach for meta-models without OCL constraints is presented in [41]; the incorporation of OCL constraints is left for
future work. Another kind of application of the presented translation is the following: Algebraic graph transformation (AGT) may be used as a formal foundation for model transformation languages: In [42], Richa et al. translate core concepts of ATL (including OCL constraints) to AGT to produce weakest preconditions of model transformations. To ensure that ATL developers will understand them, the backward translation of graph conditions to OCL is also of interest.
For an application in practice, we plan to implement the presented translation of OCL to application conditions in the context of the Eclipse Modeling Framework and Henshin [27], a model transformation environment based on graph transformation concepts. In this context, we will also reconsider the OCL translation by Bergmann [9] to EMF-lncQuery. Our ultimate goal is a well-defined approach to the translation of meta-models to language-specific model transformation systems for generating, completing or repairing models such that they are valid w.r.t. their meta-models afterwards.
Acknowledgements
We are grateful to Jens Kosiol, Nebras Nassar, Christian Sandmann, Tillmann Teusch, and the anonymous reviewers for their helpful comments on previous versions of this paper.
Appendix A. Syntax and semantics of operation expressions in Essential OCL
Table 1
OCL operations on pre-deflned and custom types.
Syntax and type e, ei, e2 e Expr Semantics 1[e](T) with т = (S,в) e Env
ei:T = e2:T ^ Boolean Ilei](T) =1[е2](т)
e-f.T <> e2:T ^ Boolean I[е,](т)=1MM
ei + e2 ^ Int 1[е,](т)+1Je2](T)
ei < e2 ^ Boolean VI
ei and e2 ^ Boolean I[ei](r)AI [e2](r)
'a string' ^ String 'a string'
e:C.allInstances() ^ Set(C) vClass(C )
e-.C.attr ^ T with attr eaatt(C) aatt (attr)(I[ec ](r))
e :C. nav ^ C' with (e, nav) e aassoc nav with (I[e](T),nav) e aassoc
e :C. nav ^ Set(C') with (e, nav) e aassoc {nav | (I[e](t), nav) e a Assoc)}
e:T.oclIsKindOf(T') Ile](r) e I(T')
e:T.oclIsTypeOf(T') I[e](T) e I(T') -Ut"<mt' I(T'')
e:T.oclAsType(T') I |]e](r) if I[e](T) e I (T') and 0 otherwise.
Table 2
OCL operations on sets.
Syntax and type e, e' e Expr, S = Set(T) Semantics I [e] (t) with t = (s,p) e Env
Set(ei ,...,en) ^ S with ei,...,en of type T {I[e,](r),...,I[en](r)}
e :S->union(e' :S) ^ S I[e](T)UI[e'](t)
e :S->intersection(e' :S) ^ S I[e](T)nI[e'](t)
e :S - e' :S ^ S I[e](T) - I[e' ](t)
e :S->symmetricDifference(e' :S) ^ S (I [e] (t) U I [e' ] (t)) - (I [e] (t) n I [e' ] C
e :S->select(v:T|e' :Boolean) ^ S {x | x e I[e](t) AI[e'](T{v/x})}
e:S->collect(v:T|e':T') ^ Set(T') {I[e'](T{v/x}) | x e I[e](T)}
e:S->size() ^ Int 1I[e](t) |
e:S->notEmpty() ^ Boolean I[e](T)= 0
e :S->exists(v:T|e' :Boolean) ^ Boolean V I [e'](T{v/x,})
if I[e](T) = {x1,..., xn}, else false
e :S->forAll(v:T| e' :Boolean) ^ Boolean A I [e'](T{v/xi})
if I[e](T) = {x1,..., xn}, else true
e :S->includesAll(e' :S) ^ Boolean I[e'](t) cI[e](T)
e :S->excludesAll(e' :S) ^ Boolean I[e](T) n I [e' ] (t) = 0
References
[1] OMG, Object constraint language, http://www.omg.org/spec/OCL/.
[2] J. Cabot, R. Clarisô, D. Riera, UMLtoCSP: a tool for the formal verification of UML/OCL models using constraint programming, in: Book 22nd IEEE/ACM International Conference on Automated Software Engineering, ASE, 2007, pp. 547-548.
[3] M. Kuhlmann, M. Gogolla, From UML and OCL to relational logic and back, in: Model Driven Engineering Languages and Systems - 15th Int. Conference, MODELS 2012, Proceedings, in: LNCS, vol. 7590, Springer, 2012, pp. 415-431.
[4] D. Jackson, Alloy analyzer website, http://alloy.mit.edu/, 2012.
[5] R. Bardohl, M. Minas, A. Schürr, G. Taentzer, Application of graph transformation to visual languages, in: Handbook of Graph Grammars and Computing by Graph Transformation, vol. 2, World Scientific, 1999, pp. 105-180.
[6] T. Arendt, A. Habel, H. Radke, G. Taentzer, From core OCL invariants to nested graph constraints, in: Graph Transformations, ICGT 2014, in: LNCS, vol. 8571, 2014, pp. 97-112.
[7] A. Habel, K.H. Pennemann, Correctness of high-level transformation systems relative to nested conditions, Math. Struct. Comput. Sci. 19 (2009) 245-296.
[8] H. Radke, T. Arendt, J.S. Becker, A. Habel, G. Taentzer, Translating essential OCL invariants to nested graph constraints focusing on set operations, in: Graph Transformation, ICGT 2015, in: LNCS, vol. 9151, 2015, pp. 155-170.
[9] G. Bergmann, Translating OCL to graph patterns, in: J. Dingel, W. Schulte, I. Ramos, S. Abrahäo, E. Insfran (Eds.), Model-Driven Engineering Languages and Systems, MoDELS, in: LNCS, vol. 8767, Springer, 2014, pp. 670-686.
[10] K. Ehrig, J.M. Küster, G. Taentzer, Generating instance models from meta models, Softw. Syst. Model. 8 (4) (2009) 479-500.
[11] OMG, Meta object facility, http://www.omg.org/spec/MOF/.
[12] J.J. Cadavid, B. Combemale, B. Baudry, An analysis of metamodeling practices for MOF and OCL, Comput. Lang. Syst. Struct. 41 (C) (April 2015) 42-65.
[13] H. Radke, T. Arendt, J.S. Becker, A. Habel, G. Taentzer, Translating essential OCL invariants to nested graph constraints focusing on set operations: long version, Available at: http://www.uni-marburg.de/fb12/forschung/berichte/berichteinformtk/pdfbi/bi2016-01, 2016.
[14] W. Reisig, Petri Nets with individual tokens, Theor. Comput. Sci. 41 (1985) 185-213.
[15] G. Wachsmuth, Metamodel adaptation and model co-adaptation, in: E. Ernst (Ed.), Proceedings of the 21st European Conference on Object-Oriented Programming, ECOOP'07, in: LNCS, vol. 4609, Springer, 2007, pp. 600-624.
[16] J. de Lara, R. Bardohl, H. Ehrig, K. Ehrig, U. Prange, G. Taentzer, Attributed graph transformation with node type inheritance, Theor. Comput. Sci. 376 (3) (2007) 139-163.
[17] OMG, Unified modeling language, http://www.uml.org/.
[18] J. Cabot, M. Gogolla, Object constraint language (OCL): a definitive guide, in: Int. School on Formal Methods for the Design of Computer, Communication, and Software Systems, SFM 2012, in: LNCS, vol. 7320, 2012, pp. 58-90.
[19] M. Richters, A Precise Approach to Validating UML Models and OCL Constraints, PhD thesis Universität Bremen, Logos Verlag, Berlin, 2002.
[20] H. Ehrig, K. Ehrig, U. Prange, G. Taentzer, Fundamentals of Algebraic Graph Transformation, EATCS Monographs of Theoretical Computer Science, Springer, 2006.
[21] F. Orejas, Symbolic graphs for attributed graph constraints, J. Symb. Comput. 46 (3) (2011) 294-315.
[22] H. Ehrig, B. Mahr, Fundamentals of Algebraic Specification 1: Equations and Initial Semantics, EATCS Monographs on Theoretical Computer Science, vol. 6, Springer, 1985.
[23] A. Rensink, Representing first-order logic by graphs, in: Graph Transformations, ICGT'04, in: LNCS, vol. 3256, 2004, pp. 319-335.
[24] G. Taentzer, AGG: a graph transformation environment for modeling and validation of software, in: Proc. Application of Graph Transformations with Industrial Relevance, AGTIVE'03, in: LNCS, vol. 3062, 2004, pp. 446-453.
[25] H. Kastenberg, A. Rensink, Model checking dynamic states in GROOVE, in: Model Checking Software, SPIN, in: LNCS, vol. 3925, 2006, pp. 299-305.
[26] R. Geiß, G.V. Batz, D. Grund, S. Hack, A. Szalkowski, GrGen: a fast SPO-based graph rewriting tool, in: Graph Transformations, ICGT 2006, in: LNCS, vol. 4178, 2006, pp. 383-397.
[27] T. Arendt, E. Biermann, S. Jurack, C. Krause, G. Taentzer, Henshin: advanced concepts and tools for in-place EMF model transformation, in: MoDELS 2010. Proceedings, Oslo, Norway, in: LNCS, vol. 6394, Springer, 2010, pp. 121-135.
[28] M. Fowler, Refactoring: Improving the Design of Existing Code, Pearson Education, India, 1999.
[29] J. Reimann, C. Wilke, B. Demuth, M. Muck, U. Aßmann, Tool supported OCL refactoring catalogue, in: Proceedings of the 12th Workshop on OCL and Textual Modelling, ACM, 2012, pp. 7-12.
[30] A. Schürr, Adding graph transformation concepts to UML's constraint language OCL, Electron. Notes Theor. Comput. Sci. 44 (4) (2001) 93-106.
[31] K. Lano, Null considered harmful (for transformation verification), in: Verification of Model Transformations, VOLT 2014, in: CEUR Workshop Proceedings, vol. 1325, 2014, pp. 26-35.
[32] OMG, Object constraint language, http://www.omg.org/spec/OCL/2.2/.
[33] B. Beckert, U. Keller, P.H. Schmitt, Translating the object constraint language into first-order predicate logic, in: VERIFY, Workshop at Federated Logic Conferences, FLoC, in: DIKU Technical Reports, vol. 02-07, 2002, pp. 113-123.
[34] K. Anastasakis, B. Bordbar, G. Georg, I. Ray, On challenges of model transformation from UML to alloy, Softw. Syst. Model. 9 (1) (2010) 69-86.
[35] M. Gogolla, J. Bohling, M. Richters, Validating UML and OCL models in USE by automatic snapshot generation, SoSyM 4 (4) (2009) 386-398.
[36] K.H. Pennemann, Development of Correct Graph Transformation Systems, PhD thesis, Universität, Oldenburg, 2009.
[37] L. Lambers, F. Orejas, Tableau-based reasoning for graph properties, in: Graph Transformation, ICGT 2014, in: LNCS, vol. 8571, 2014, pp. 17-32.
[38] E. Richa, E. Borde, L. Pautet, Translating ATL model transformations to algebraic graph transformations, in: ICMT 2015: Theory and Practice of Model Transformations, Proceedings, Springer, 2015, pp. 183-198.
[39] H. Radke, A Theory of HR* Graph Conditions and Their Application to Meta-Modeling, PhD thesis, Carl Von Ossietzky-Universität Oldenburg, 06 2016.
[40] T. Kehrer, U. Kelter, G. Taentzer, Consistency-preserving edit scripts in model versioning, in: E. Denney, T. Bultan, A. Zeller (Eds.), 2013 28th IEEE/ACM International Conference on Automated Software Engineering, ASE 2013, Silicon, Valley, CA, USA, November 11-15, 2013, IEEE, 2013, pp. 191-201.
[41] T. Kehrer, G. Taentzer, M. Rindt, U. Kelter, Automatically deriving the specification of model editing operations from meta-models, in: ICMT 2016, Springer, 2016.
[42] E. Richa, E. Borde, L. Pautet, M. Bordin, J.F. Ruiz, Towards testing model transformation chains using precondition construction in algebraic graph transformation, in: AMT 2014 - Analysis of Model Transformations Workshop Proceedings, 2014, pp. 34-43.