De-/Re-constructing Model Transformation Languages
Eugene Syriani and Hans Vangheluwe
Abstract
The diversity of today’s model transformation languages makes it hard to compare their expressiveness and provide
a framework for interoperability. De-constructing and then re-constructing model transformation languages by means
of a unique set of most primitive constructs facilitates both. We thus introduce T-Core, a collection of primitives for
model transformation. Combining T-Core with a (programming or modelling) language enables the design of model
transformation formalisms. We show how basic and more advanced features from existing model transformation
languages can be re-constructed using T-Core primitives. Finally, we design a new primitive language for model
transformation by combining T-Core with an existing asynchronous and timed modelling language.
1 Introduction
A plethora of different rule-based model transformation languages and supporting tools exist today. They cover all (or
a subset of) the well-known essential features of model transformation [1]: atomicity, sequencing, branching, looping,
non-determinism, recursion, parallelism, back-tracking, hierarchy, and time. For such languages, the semantics (and
hence implementation) of a transformation rule consists of the appropriate combination of building blocks implementing primitive operations such as matching, rewriting, and often a validation of consistent application of the rule.
The abovementioned essential features of transformation languages are achieved by implicitly or explicitly specifying
“rule scheduling”. Languages such as ATL [2], FUJABA [3], GReAT [4], MoTif [5], and VIATRA [6] include constructs
to specify the order in which rules are applied. This often takes the form of a control flow language. Without loss of
generality, we consider transformation languages where models are encoded as typed, attributed graphs.
The diversity of transformation languages makes it hard, on the one hand, to compare their expressiveness and, on
the other hand, to provide a framework for interoperability (i.e., meaningfully combining transformation units specified in different transformation languages). One approach is to express model transformation at the level of primitive
building blocks. De-constructing and then re-constructing model transformation languages by means of a small set of
most primitive constructs offers a common basis to compare the expressiveness transformation languages. It may also
help in the discovery of novel, possibly in domain-specific, model transformation constructs by combining the building blocks in new ways. Furthermore, it allows implementers to focus on maximizing the efficiency of the primitives
in isolation, leading to more efficient transformations overall. Lastly, once re-constructed, different transformation
languages can seamlessly interoperate as they are built on the same primitives. This use of common primitives in turn
allows for global as well as inter-rule optimization
We introduce T-Core, a collection of transformation language primitives for model transformation and motivate the
choice of its primitives in Section 2. Section 3 shows how transformation entities, common as well as more esoteric,
can be re-constructed. Section 4 explains how, in particular, timed and asynchronous model transformation languages
can be built. Section 5 describes related work and section 6 draws conclusions and presents directions for future work.
2 De-constructing Transformation Languages
We propose here a collection of model transformation primitives. The class diagram in Figure 1 presents the module TCore encapsulating model transformation primitives. T-Core consists of eight primitive constructs (Primitive objects):
1
Figure 1: The T-Core module
2
a Matcher, Iterator, Rewriter, Resolver, Rollbacker, Composer, Selector, and Synchronizer. The first five are RulePrimitive elements and represent the building blocks of a single transformation unit. T-Core is not restricted to any form of
specification of a transformation unit. In fact, we consider only PreConditionPatterns and PostConditionPatterns. For
example, in rule-based model transformation, the transformation unit is a rule. The PreConditionPattern determines its
applicability: it is usually described with a left-hand side (LHS) and optional negative application conditions (NACs).
It also consists of a PostConditionPattern which imposes a pattern to be found after the rule was applied: it is usually
described with a right-hand side (RHS).
RulePrimitives are to be distinguished from the ControlPrimitives, which are used in the design of the rule scheduling part of the transformation language. A meaningful composition of these different constructs in a Composer object
allows modular encapsulation of and communication between Primitive objects.
Primitives exchange three different types of messages: Packet, Cancel, and Exception. A packet π represents the
host model together with sufficient information for inter- and intra-rule processing of the matches. π thus holds the
current model (graph in our case) graph, the matchSet, and a reference to the current PreConditionPattern identifying a MatchSet. A MatchSet refers to a condition pattern and contains the actual matches as well as a reference
to the matchToRewrite. Note that each MatchSet of a packet have a unique condition, used identifying the set of
matches. A Match consists of a sub-graph of the graph in π where each element is bound to an element in graph.
Some elements (Nodes) of the match may be labelled as pivots, which allows certain elements of the model to be
identified and passed between rules. A cancel message ϕ is meant to cancel the activity of an active primitive element
(especially used in the presence of a Selector). Finally, specific exceptions χ can be explicitly thrown, carrying along
the currently processed packet π1 .
All the primitive constructs can receive packets by invoking either their packetIn, nextIn, successIn, or failIn
methods. The result of calling one of these methods sets the primitive in success or failure mode as recorded by
the isSuccess attribute. Cancel messages are received from the cancelIn method. Next, we describe in detail the
behaviour of the different methods supported by each of the eight primitive elements.
2.1 Matcher
The Matcher finds all possible matches of the condition pattern c on the graph embedded in the packet it receives
from its packetIn method. The transformation modeller may optimize the matching by setting the findAll attribute
to false when he a priori knows that at most one match of this matcher will be processed in the overall transformation.
The matching also considers the pivot mapping (if present) of the current match of π. Some implementations may,
for example, parametrize the Matcher by the condition or embed it directly in the Matcher. The transformation units
(e.g., rules) may be compiled in pre/post-condition patterns or interpreted, but this is a tool implementation issue
which we do not discuss here. After matching the graph, the Matcher stores the different matches in the packet as
described in Algorithm 1.
2.2 Rewriter
As described in Algorithm 2, the Rewriter applies the required transformation for its condition on the match specified
in the packet it receives from its packetIn method. That match is consumed by the Rewriter: no other operation can
be further applied on it. Some validations are made in the Rewriter to verify, for example, that π.current.condition
= condition.pre or that no error occurred during the transformation. In our approach, a modification (update or
delete) of an element in {M| hc, Mi ∈ π.matchSets} is automatically propagated to the other matches, if applicable.
1π
φ
is used to represent the empty packet.
3
Algorithm 1 Matcher.packetIn(π)
M ← (all) matches of condition found in
π.graph
if ∃ hcondition, M ′ i ∈ π.matchSets then
M′ ← M′ ∪ M
else
add hcondition, Mi to π.matchSets
end if
π.current ← condition
isSuccess ← M 6= 0/
return π
Algorithm 2 Rewriter.packetIn(π)
if π is invalid then
isSuccess ← false
exception ← χ(π)
return π
end if
apply transformation on M.matchToRewrite
for
which
hcondition.pre, Mi ∈
π.matchSets
if transformation failed then
isSuccess ← false
exception ← χ(π)
return π
end if
set all modified nodes in M to dirty
remove hcondition, Mi from π.matchSets
isSuccess ← true
return π
2.3 Iterator
The Iterator chooses a match among the set of matches of the current condition of the packet it receives from its
packetIn method, as described in Algorithm 3. The match is chosen randomly in a Monte-Carlo sense, repeatable
using sampling from a uniform distribution to provide a reproducible, fair sampling. When its nextIn method is
called, the Iterator chooses another match as long as the maximum number of iterations maxIterations (possibly
infinite) is not yet reached, as described in Algorithm 4.
Algorithm 3 Iterator.packetIn(π)
if hπ.current, Mi ∈ π.matchSets then
choose m ∈ M
M.matchToRewrite ← m
remIterations ← maxIterations − 1
isSuccess ← true
return π
else
isSuccess ← false
return π
end if
Algorithm 4 Iterator.nextIn(π)
if hπ.current, Mi ∈ π.matchSets and
remIterations > 0 then
choose m ∈ M
M.matchToRewrite ← m
remIterations ← remIterations − 1
isSuccess ← true
return π
else
isSuccess ← false
return π
end if
2.4 Rollbacker
The Rollbacker is only used to provide back-tracking capabilities to its transformation rule r. Consequently, it keeps
a stack of packets packetStack Π, as described in Algorithms 5 and 6. The packetIn method stores the received
4
packet and the nextIn method ensures the roll-back of the packet to its previous state. Again, a maximum number of
iterations can be specified.
Algorithm 5 Rollbacker.packetIn(π)
push π onto Π
remIterations ← maxIterations − 1
isSuccess ← true
return π
Algorithm 6 Rollbacker.nextIn(π)
if hπ.current, Mi ∈ π.matchSets and
remIterations > 0 then
remIterations ← maxIterations − 1
isSuccess ← true
return π
else if remIterations > 0 and Π 6= 0/ then
π̂ ← pop Π
remIterations ← maxIterations − 1
isSuccess ← true
return π̂
else
isSuccess ← false
return π
end if
2.5 Resolver
The Resolver resolves a potential conflict between matches and rewritings as described in Algorithm 7. For the moment, the Resolver detects conflicts in a simple conservative way: it prohibits any change to other matches in the
packet (check for dirty nodes). However, it does not verify if a modified match is still valid with respect to its precondition pattern. The externalMatchesOnly attribute specifies whether the conflict detection should also consider
matches from its identified by π.current or not. In the case of conflict, a default resolution function is provided but
the user may also override it.
5
Algorithm 7 Resolver.packetIn(π)
for all condition c ∈ {c| hc, Mi ∈
π.matchSets} do
if
externalMatchesOnly
and
c = π.current then
continue
end if
for all match m ∈ M do
if m has a dirty node then
if customResolution(π) then
isSuccess ← true
return π
else if defaultResolution(π) then
isSuccess ← true
return π
else
isSuccess ← false
exception ← χ(π)
return π
end if
end if
end for
end for
isSuccess ← false
exception ← χ(π)
return π
2.6 Selector
The Selector is used when a choice needs to be made between multiple packets processed concurrently by different
constructs. It allows exactly one of them to be processed further. When its successIn (or failIn) method is called,
the received packet is stored in its success (or fail) collection, respectively. Note that, unlike the previous described
methods, it is only when the select method in Algorithm 8 is called that a packet is returned, chosen from success.
The selection is random in the same way as in the Iterator. When the cancel method is invoked, the two collections are
cleared and a cancel message ϕ is returned where the exclusions set consists of the singleton π.current (meaning
that operations of the chosen condition should not be cancelled).
2.7 Synchronizer
The Synchronizer is used when multiple packets processed in parallel need to be synchronized. It is parametrized by
the number of threads to synchronize. This number is known at design-time. Its successIn and failIn methods
behave exactly like those of the Selector. The Synchronizer is in success mode only if all threads have terminated by
never invoking failIn. The merge method “merges” the packets in success, as described in Algorithm 9. A trivial
default merge function is provided by unifying and “gluing” the set of packets. Nevertheless, it first conservatively
verifies the validity of the received packets by prohibiting overlapping matches between them. If it fails, the user can
specify a custom merge function. This avoids the need for static parallel independence detection. Instead it is done at
6
run-time and the transformation modeller must explicitly describe the handler. One pragmatic use of that solution is,
for instance, to let the transformation run once to detect the possible conflicts and then the modeller may handle these
cases by modifying the transformation model.
Algorithm 8 Selector.select()
if success 6= 0/ then
π̂ ← choose from success
isSuccess ← true
else if fail 6= 0/ then
π̂ ← choose from fail
isSuccess ← false
else
π̂ ← πφ
isSuccess ← false
exception ← χ(πφ )
end if
success ← 0/
fail ← 0/
return π̂
Algorithm 9 Synchronizer.merge()
if |success| = threads then
if defaultMerge() then
π̂ ← the merged packet in success
isSuccess ← true
success ← 0/
fail ← 0/
return π̂
else if customMerge() then
π̂ ← the merged packet in success
isSuccess ← true
success ← 0/
fail ← 0/
return π̂
else
isSuccess ← false
exception ← χ(πφ )
return πφ
end if
else if |success| + |fail| = threads then
π̂ ← choose from fail
isSuccess ← false
return π̂
else
isSuccess ← false
exception ← χ(πφ )
return πφ
end if
2.8 Composer
The Composer serves as a modular encapsulation interface of the elements in its primitives list. When one of
its packetIn or nextIn methods is invoked, it is up to the user to manage subsequent method invocations to its
primitives. Nevertheless, when the cancelIn method is called, the Composer invokes the cancelIn method of all
its primitives. Whenever the cancelIn method is called on a RulePrimitive object, its current action is cancelled only
if it is actively processing a packet π such that the current condition of π is not in ϕ.exclusions, where ϕ is the
received cancel message. In the case of a Matcher, since the current condition of the packet may not already be set, the
cancelIn also verifies that the condition of the the Matcher is not in the exclusions list. The interruption of activity
can, for instance, be implemented as pre-emptive asynchronous method call of cancelIn.
7
2.9 T-Core: a minimal collection of transformation primitives
In the de-construction process of transformation languages into a collection of primitives, questions like “up to what
level?” or “what to include and what to exclude?” arise. The proposed T-Core module answers these questions in the
following way.
In a model transformation language, the smallest transformation unit is traditionally the rule. A rule is a complex
structure with a declarative part and an operational part. The declarative part of a rule consists of the specification of the
rule (e.g., LHS/RHS and optionally NAC in graph transformation rules). However, T-Core is not restricted to any form
of specification let it be rule-based, constraint-based, or function-based. In fact, some languages require units with
only a pre-condition to satisfy, while other with a pre- and a post-condition. Some even allow arbitrary permutations
of repetitions of the two. In T-Core, either a PreConditionPattern or both a Pre- and a PostConditionPattern must be
specified. For example, a graph transformation rule can be represented in T-Core as a couple of a pre- and a postcondition pattern, where the latter has a reference to the former to satisfy the semantics of the interface K (in the
L ← K → R algebraic graph transformation rules) and be able to perform the transformation. Transformation
languages where rules are expressed bidirectionally or as functions are supported in T-Core as long as they can be
represented as pre- and post-condition patterns.
The operational part of a rule describes how it executes. This operation is often encapsulated in the form of
an algorithm (with possibly local optimizations). Nevertheless, it always consists of a matching phase, i.e., finding
instances of the model that satisfy the pre-condition and of a transformation phase, i.e., applying the rule such that
the resulting model satisfies the post-condition. T-Core distinguishes these two phases by offering a Matcher and a
Rewriter as primitives. Consequently, the Matcher’s condition only consists of a pre-condition pattern and the Rewriter
then needs a post-condition pattern that can access the pre-condition pattern to perform the rewrite. Combinations
of Matchers and Rewriters in sequence can then represent a sequence of simple graph transformation rule: matchrewrite-match-rewrite. Moreover, because of the separation of these two phases, more complex constructs may be
built, such as: match-match-match or match-match-rewrite-rewrite. The former is a query where each Matcher filters
the conditions of the query. The latter is a nesting of transformation rules. In this case, however, overlapping matches
between different Matchers and then rewrites on the overlapping elements may lead to inconsistent transformations or
even non-sense. This is why a Resolver can be used from T-Core to safely allow match-rewrite combinations.
The data structure exchanged between T-Core RulePrimitives in the form of packets contains sufficient information
for each primitive to process it as described in the various algorithms in Section 2. The Match allows to refer to all
model elements that satisfy a pre-condition pattern. The pivot mappings allow elements of certain matches to be bound
to elements of previously matched elements. The pivot mapping is equivalent to passing parameters between rules as
will be shown in the example in Section 3.1. The MatchSet allows to delay the rewriting phase instead of having to
rewrite directly after matching.
Packets conceptually carry the complete model (optimized implementation may relax this) which allows concurrent execution of transformations. The Selector and the Synchronizer both permit to join branches or threads of
concurrent transformations. Also, having separated the matching from the rewriting enables to manage the matches
and the results of a rewrite by further operators. Advanced features such as iteration over multiple matches or backtracking to a previous state in the transformation are also supported in T-Core.
Since T-Core is a low-level collection of model transformation primitives, combining its primitives to achieve
relevant and useful transformations may involve a large number of these primitive operators. Therefore, it is necessary
to provide a “grouping” mechanism. The Composer allows to modularly organize T-Core primitives. It serves as an
interface to the primitives it encapsulates. This then enables scaling of transformations built on T-Core to large and
complex model transformations designs.
T-Core is presented here as an open module which can be extended, through inheritance for example. One could
add other primitive model transformation building blocks. For instance, a conformance check operator may be useful
to verify if the resulting transformed model still conforms to its meta-model. It can be interleaved between sequences
of rewrites or used at the end of the overall transformation as suggested in [SLE]. We believe however that such new
constructs should either be part of the (programming or modelling) language or the tool in which T-Core is integrated,
8
to keep T-Core as primitive as possible.
3 Re-constructing Transformation Languages
(a)
(b)
(c)
(d)
Figure 2: Combining T-Core with other languages allows to re-construct existing and new languages
Having de-constructed model transformation languages in a collection of model transformation primitives makes
it easier to reason about transformation languages. In fact, properly combining T-Core primitives with an existing
well-formed programming or modelling language allows us to re-construct some already existing transformation languages and even construct new ones. Figure 2 shows some examples of combinations of T-Core with other languages.
Figure 2(a) and Figure 2(b) combine a subset of T-Core with a simple (programming) language which offers sequencing, branching, and looping mechanisms (as proposed in Jocapini’s structured program theorem). We will refer to
such a language as an SBL language. The first combination only involves the Matcher and its PreConditionPattern,
Packet messages to exchange, and the Composer to organize the primitives. These T-Core primitives integrated in
an SBL language leads to a query language. Since only matching operations can be performed on the model, they
represent queries where the resulting packet holds the set of all elements (sub-graph) of the model (graph) that satisfy
the desired pre-conditions. Including other T-Core primitives such as the Rewriter promote the query language to a
transformation language. Figure 2(b) enumerates the necessary T-Core primitives combined with an SBL language to
design a complete sequential model transformation language. Replacing the SBL language by another one, such as
UML Activity Diagrams [7] in Figure 2(c), allows us to re-construct Story Diagrams [3], for example, since Story Diagrams are defined as a combination of UML Activity and Collaboration Diagrams with graph transformation features.
Other combinations involving the whole T-Core module may lead to novel transformation language with exception
handling and the notion of timed model transformations when combined with a discrete-event modelling language.
9
We now present the re-construction of two transformation features using the combination of an SBL language with
T-Core as in Figure 2(b).
3.1 Re-constructing Story Diagrams
Figure 3: The FUJABA doSubDemo transformation showing a for-all Pattern and two statement activities
In the context of object-oriented reverse-engineering, the FUJABA tool allows the user to specify the content of a
class method by means of Story Diagrams, an extension of UML Activity Diagrams. A Story Diagram organizes the
behaviour of a method with activities and transitions. An activity can be a Story Pattern or a statement activity. The
former consists of a graph transformation rule and the latter is Java code. Figure 3 shows such a story diagram taken
from the doDemo method example in [3]. This snippet represents an elevator loading people on a given floor of a house
who wish to go to another level. The rule in the pattern is specified in a UML Collaboration Diagram-like notation
[7] with objects and associations. Objects with implicit types (e.g., this, l2, and e1) are bound objects from previous
patterns or variables in the context of the current method. The Story Pattern 6 is a for-all Pattern. Its rule is applied on
all matches found looping over the unbound objects (e.g., p4, and l4). The outgoing transition labelled each time
applies statement 7 after each iteration of the for-all Pattern. This activity allows the pattern to simulate random choices
of levels for different people. When all iterations have been completed, the flow proceeds with statement 8 reached by
the transition labelled end. The latter activity simulates the elevator going one level up.
We now show how to re-construct this non-trivial story diagram transformation from an SLB language combined
with T-Core. An instance of that combination is called a T-Core model. First, we design the rules needed for the
conditions of rule primitives. Figure 4 describes the three necessary rules corresponding to the three Story Diagram
activities. We use the visual concrete syntax of MoTif [5] where the central compartment is the LHS, the compartment
on the right of the arrow head is the RHS and the compartment(s) on the left of dashed lines are the NAC(s). The
concrete syntax for representing the pattern was chosen to be intuitively close enough to the FUJABA graphical
representation. Numeric labels are used to uniquely identify different elements across compartments. Elements with
an alpha-numeric label between parentheses denote pivots. A right-directed arrow on top of the label depicts that the
model element matched for this pattern element is assigned to a pivot (e.g., p4 and l4). A left-directed arrow on top
of the label depicts that the model element matched for this pattern element is bound to the specified pivot (e.g., this
and e1).
The T-Core model equivalent to the original doSubDemo transformation consists of a Composer doSubDemoC.
The hierarchy of its sub-primitives is illustrated in the Collaboration Diagram in Figure 5. It is composed of two Composers loadC and nextStepC each containing a Matcher, an Iterator, a Rewriter, and a Resolver. The packetIn method
of doSubDemoC first calls the corresponding method of loadC and then feeds the returned packet to the packetIn
method of nextStepC. This ensures that the output packet of the overall transformation is the result of first loading all
the Person objects and then moving the elevator by one step. makeChoiceC and nextStepC behave as simple transformation rules. Their packetIn method behaves as specified in Algorithm 12. First, the matcher is tried on the input
packet. Note that the conditions of the matchers makeChoiceM and nextStepM are the LHSs of rules makeChoice
and nextStep, respectively. If it fails, the composer goes into failure mode and the packet is returned. Then, the
10
Figure 4: The three MoTif rules for the doSubDemo transformation
Figure 5: The object hierarchy of the doSubDemo composer
11
iterator chooses a match. Subsequently, the rewriter attempts to transform this match. Note that the conditions of the
rewriters makeChoiceW and nextStepW are the RHSs of rules makeChoice and nextStep, respectively. If it fails,
an exception is thrown and the transformation stops. Otherwise, the resolver verifies the application of this pattern
with respect to other matches in the transformed packet. The behaviour of the resolution function will be elaborated
on later. Finally, on a successful resolution, the resulting packet is output and the composer is put in success mode.
loadC is the composer that emulates the for-all Pattern of the example. Algorithm 11 specifies that behaviour. After
finding all matches with loadM (whose condition is the LHS and the NAC of rule load), the packet is forwarded to
the iterator loadI to choose a match. The iteration is emulated by a loop with the failure mode of loadI as the breaking
condition. Inside the loop, loadW rewrites the chosen match and loadR resolves possible conflicts. Then, the resulting
packet is sent to makeChoiceC to fulfil the each time transition of the story digram. After that, the nextIn method of
loadI is invoked with the new packet to choose a new match and proceed in the loop.
Algorithm 10 doSubDemoC.packetIn(π)
π ← loadC.packetIn(π)
π ← nextStepC.packetIn(π)
isSuccess ← true
return π
Having seen the overall T-Core transformation model, let us inspect how the different Resolvers should behave in
order to provide a correct and complete transformation. The first rewriter called is loadR and the first time it receives
a packet is when a transformation is applied on one of the matches of loadM. Therefore each match consists of the
same House (since it is a bound node), two Levels, an Elevator, and the associations between them. On the other
hand, loadW only adds a Person and links it to a Level. Therefore the default resolution function of loadR applies
successfully, since no matched element is modified nor is the NAC violated in any other match. The next resolver is
makeChoiceR which is in the same loop as loadR. There, the House is conflicting with all the matches in the packet
according to the conservative default resolution function. Note that makeChoiceM finds at most one match (the bound
House element). However, makeChoiceW does not really conflict with matches found in loadM. We therefore specify
a custom resolution function for makeChoiceR that always succeeds. The same applies for nextStepR.
12
Algorithm 11 loadC.packetIn(π)
π ← loadM.packetIn(π)
if not loadM.isSuccess then
isSuccess ← false
return π
end if
π ← loadI.packetIn(π)
while true do
if not loadI.isSuccess then
isSuccess ← true
return π
end if
π ← loadW.packetIn(π)
if not loadW.isSuccess then
isSuccess ← false
return π
end if
π ← loadR.packetIn(π)
if not loadR.isSuccess then
isSuccess ← false
return π
end if
π ← makeChoiceC.packetIn(π)
π ← loadI.nextIn(π)
end while
Algorithm 12 makeChoiceC.packetIn(π)
π ← makeChoiceM.packetIn(π)
if not makeChoiceM.isSuccess then
isSuccess ← false
return π
end if
π ← makeChoiceI.packetIn(π)
if not makeChoiceI.isSuccess then
isSuccess ← true
return π
end if
π ← makeChoiceW.packetIn(π)
if not makeChoiceW.isSuccess then
isSuccess ← false
return π
end if
π ← makeChoiceR.packetIn(π)
if not makeChoiceW.isSuccess then
isSuccess ← false
return π
end if
isSuccess ← true
return π
3.2 Re-constructing amalgamated rules
In a recent paper, Rensink et al. claim that the Repotting the Geraniums example is inexpressible in most transformation formalisms [8]. The authors propose a transformation language that uses an amalgamation scheme for nested
graph transformation rules. As we have seen in the previous example, nesting transformation rules is possible in TCore and will be used to solve the problem. It consists of repotting all flowering geraniums whose pots have cracked.
Figure 6 illustrates the two nested graph transformation rules involved and Algorithm 13 demonstrates the composition of primitive T-Core elements encoding these rules. baseM (with, as condition, the LHS of rule base) finds all
broken pots containing a flowering geranium, given the input packet containing the input graph. The set of matches
resulting in the packet are the combination of all flowering geraniums and their pot container. From then on starts the
loop. First, baseI chooses a match. If one is chosen, baseW transforms this match and baseR resolves any conflicts. In
this case, baseW only creates a new unbroken pot and assigns pivots. Therefore, baseR’s resolution function always
succeeds. In fact, the resolver is not needed here, but we include it for consistency. The innerC composer encodes the
inner rule which finds the two bound pots and moves a flourishing flower in the broken pot to the unbroken one.
In order to iterate over all the flowers in the broken pot, the innerC.packetIn method has the exact same behaviour
as loadC.packetIn in Algorithm 11, with the exception of not calling a sub-composer (like makeChoiceC). Note
that an always successful custom resolution function for innerR is required. After the Resolver successfully outputs
the packet, the inner rule is applied. Then (and also if baseI had failed) baseM.packetIn is called again with the
resulting packet. The loop ends when the baseM.packetIn method call inside the loop fails, which entails baseC to
return the final packet in success mode.
13
Algorithm 13 baseC.packetIn(π)
π ← baseM.packetIn(π)
if not baseM.isSuccess then
isSuccess ← false
return π
end if
while true do
π ← baseI.packetIn(π)
if baseI.isSuccess then
π ← baseW.packetIn(π)
if not baseW.isSuccess then
isSuccess ← false
return π
end if
π ← baseR.packetIn(π)
Figure 6: The transformation rules for the Repotting Geraif
not baseR.isSuccess then
niums example
isSuccess ← false
return π
end if
π ← innerC.packetIn(π)
end if
π ← baseM.packetIn(π)
if not baseM.isSuccess then
isSuccess ← false
return π
end if
end while
4 Re-constructing Asynchronous & Timed Transformation Languages
In the context of rule-based graph transformation, the Discrete Event System Specification (DEVS) formalism [9]
can be used as an underlying basis for rule scheduling in transformation languages [10]. DEVS is a compositional,
timed discrete-event language and is thus an attractive framework for generalize primitive model transformation language.
4.1 The MoTif-Core Language
MoTif-Core is a primitive transformation language which combines DEVS and T-Core (see Figure 2(d)). Its metamodel in Figure 7 shows how MoTif-Core is an extension of DEVS integrating all T-Core contructs. The so-called
T-Core primitives can be found encapsulated in the state of different AtomicDEVS elements, (except for the Composer). Those classes are prefixed by “TC”, depicting that they are semantically identical to their T-Core counterparts
(e.g., TCMatcher from MoTif-Core and Matcher from TCore). However, the messages sent through their method calls
use Event objects from MoTif-Core instead of T-Core.
All the RulePrimitive elements have two inports (PacketIn and CancelIn) from which packets and cancel events
are respectively received and two outports (SuccessOut and FailOut) from which packets are sent. Both the Iterator
and the Rollbacker have an extra NextIn inport. For compositionality and transparency reasons, the Composer has the
14
Figure 7: The meta-model of MoTif-Core
15
same ports, as well as an extra ExceptionOut outport. On the other hand, the ControlPrimitive elements have SuccessIn
and FailIn as inports and SuccessOut and FailOut as outports. When a MoTif-Core primitive (any sub-class RulePrimitive, ControlPrimitive, or CompositePrimitive from Figure 7) receives an event from an inport, its external transition
function invokes the appropriate method of its state (T-Core primitive) corresponding to this inport as illustrated in Algorithm 14. In the ControlPrimitive elements, the Selector’s select method is no longer used. It is the select function
of the Composer that takes care of the selection of the appropriate primitive to output. In MoTif-Core, the Composer
inherently composes other DEVSBlock elements (MoTif-Core primitives as well as pure DEVSBlocks) as it is a CoupledDEVS and hence stateless. Different types of Composers can be specified for re-using recurring composers in
different transformation models. This CompositePrimitive specifies the connection between the different in/outports to
ensure a proper flow of the transformation.
Algorithm 14 primitive.externalTransition(e)
// Some pre-processing...
if e received from ACancelIn then
state.cancelIn(e)
end if
if e received from APacketIn then
state.packetIn(e)
else if e received from ANextIn then
// if defined
state.nextIn(e)
end if
// ... some post-processing
MoTif-Core is a completely meta-modelled primitive language for model transformation. A MoTif-Core model is
a DEVS model specialized for transformation purposes. It can therefore be combined with AtomicDEVS and CoupledDEVS models. The implementation of a virtual machine makes use of this advantage to specify the interface for the
input of the host model in a similar way as in [10]. The interface for outputting the result of the transformation is also
modelled. Hence, MoTif-Core is a closed system.
MoTif-Core is inherently a timed event-based language. This allows transformation languages to specify the time
duration for the matching phase (Matcher) and for the rewriting phase (Rewriter) separately, which gives the opportunity to express real-time transformations. Note that the remaining AtomicDEVS elements do not consume time
(their time advance is 0). It also offers the possibility to add an orthogonal dimension to the causality of the flow of
a transformation. An example of such a transformation language can be found in [11]. Being discrete-event based,
MoTif-Core allows to specify asynchronous transformation languages and can provide a data flow of execution.
MoTif-Core models can be executed by a DEVS simulator. Looking more closely at the behaviour of the different
RulePrimitive elements, only packets or exception events are exchanged among them. Consequently, when an exception is thrown by a RulePrimitive, it can be propagated up in the coupling hierarchy of CRules and be presented to the
user. It is then possible to trace back the complete path where the exception arose as well as the exact time. Therefore,
one can extrapolate that the result of the execution of a MoTif-Core model is either the new model or an exception,
if the elements are combined accordingly. This may be a lead towards model transformation debugging. FUJABA’s
maybe statement is used for exceptions, but it is only available for statement activities (i.e., Java code).
MoTif-Core primitives are independent from one another as they do not share any information in common. Furthermore, the packets they exchange contain enough information for each primitive to process it. The ControlPrimitive
provide join points to parallel execution of other MoTif-Core primitives. Therefore, a distributed execution of MoTifCore models is possible with an appropriate distributed DEVS simulator.
16
Figure 8: A basic MoTif ARule re-constructed with MoTif-Core primitives
4.2 Applications of MoTif-Core
The simplest rule-based model transformation entity is the rule itself. Figure 8 shows how an ARule in the MoTif
transformation language is mapped onto a MoTif-Core model. The original semantics of an ARule can be found in
[5]. The pattern on the right-hand side of the figure preserves its semantics expressed in terms of MoTif-Core. The
graphical syntax of MoTif-Core primitives is a rounded rectangle labelled on the top right by its type (M for Matcher,
I for Iterator, W for Rewriter, R for Resolver, B for Rollbacker, S for Selector, and Y for Synchronizer). Inside it,
the optional alias followed by a column and then a name identify the primitive. The Composer is represented by
a double-lined rounded rectangle labelled with the composer’s type. In this figure, the composition of the different
primitive MoTif-Core elements are encapsulated in a Composer of type ARule. First, when a packet is received by the
Matcher, all matches in the graph of the graph transformation rule it encodes are found and stored in the packet. If
none were found, the Composer outputs the unchanged packet from the failure outport CFailOut. Otherwise, the Iterator
receives the modified packet output from the Matcher and selects one match. Then, the rewriter receives this packet
and transforms the graph according to the selected match (specified in the packet). If the rewriting fails, an exception
is sent outside the Composer through CExceptionOut. Otherwise, the selected match is removed and the packet is sent
to the Resolver. It validates the consistency of the transformation that just occurred with respect to possibly other
pending matches in the packet from other rules. In the case of a failure, an exception is again sent whereas in case of
a successful application, the newly modified packet is sent through the success outport CSuccessOut. The channels
between the CCancelIn inport and all the ACancelIn inports were omitted for clarity in the figure. The time of the
Matcher and Rewriter are those specified in the original ARule since MoTif supports timed transformations. Although
the concept of exceptions was not originally present in MoTif, the process of de-constructing and re-constructing its
elements allowed us to enhance the transformation language.
MoTif-Core is not only a timed language, but also allows parallel composition of models. Since the different
primitive models are designed such that they wait for an input event to arrive at an inport, they can inherently run in
parallel inside a Composer. GReAT [4] is a well-known graph transformation language with asynchronous behaviour.
For example, Figure 9(a)2 presents a Test block where two Cases (atomic or composite rules) can be applied. When
a Test block receives a packet in GReAT, the packet is tested on all the Cases. If multiple Cases succeed, only one
will be applied non-deterministically. Figure 9(a) shows how a Test block can be re-constructed using MoTif-Core
primitives. The MoTif-Core model consists of a Composer composing two ARules (one for each Case, assuming
they each consists of an atomic rule). However, a Selector (Cut) ensures that at most one of them will get applied
2 The
figure is taken from [4].
17
(a)
(b)
Figure 9: A Test block in GReAT showing two cases in (a) and its de-construction in MoTif-Core in (b)
by sending the appropriate cancel event to the ARules as soon as a packet is received. Since GReAT is not a timed
model transformation language, we assume that the Matcher and the Rewriter of both ARules consume the same time.
First, the two Matchers each receive a clone of the packet that the Composer received. Then, assuming both are in
success mode, the select function of the Composer will choose one of them to output. Without loss of generality,
suppose Case1 is chosen. Consequently the Selector receives the packet from ASuccessIn and instantaneously sends
it through ASuccessOut. However, both Iterators receive it. To solve this problem, the Selector also sends a cancel
event through ACancelOut which both Iterators receive and only the one mentioned in the exclusion list (in this case
Case1) does not cancel its activity. The same behaviour as previously described for the ARule follows from there. For
the case where one of Matchers fails, the same scenario applies since the Composer will still select the successful
one. Finally, in the case where both Matchers fail the Composer selects one of them and the Selector sends the packet
it receives through AFailOut. Therefore the MoTif-Core model is indeed semantically equivalent to the asynchronous
Test block in GReAT. Again, a side-effect of this re-construction is that it allows one to extend the GReAT language
with exception handling.
5 Related work
The closer work to our knowledge is [12]. In the context of global model management, the authors define type system
offering a set of primitives for model transformation. Their approach, however, does not deal with exceptions nor with
concept of time. Nevertheless, their framework is able to achieve higher-order transformations. This is in fact realized
in our approach by transforming a MoTif transformation entities into MoTif-Core models, the transformation itself
being expressed in MoTif-Core.
The GP graph transformation language [13] consists of transformation primitives at a higher-level of abstraction
then MoTif-Core. Although it is performs very efficiently, it is a small language that does not scale for multi-paradigm
modelling in the domain of transformations.
Other graph transformation tools, such as VIATRA [6] and GReAT [4], have their own virtual machine used as an
API. In our approach, since the primitive operations are modelled, they are completely compatible with other existing
18
model transformation frameworks.
6 Conclusion
In this report, we have motivated the need for providing a collection of primitives for model transformation languages.
We have defined T-Core which describes precisely each of these primitive constructs. The de-construction process of
model transformation languages enabled us to re-construct existing model transformation features by combining TCore with, for example, an SBL language. This allowed us to compare different model transformation languages using
a common basis. Finally, we have shown how the combination of T-Core with certain existing modelling languages,
such as DEVS, can lead to novel transformation languages. An example is MoTif-Core, which allowed us to enhance
and introduce new model transformation features, such as exception handling and the dimension of time.
Now that these primitives are well-defined, efficiently implementing each of them might lead to more efficient
model transformation languages. Also, for future work, we would like to closely compare MoTif-Core with QVT-Core
as they seem to express transformations at the same level of abstraction. We would also like to investigate further on
the notion of exceptions and error handling in the context of model transformation.
References
[1] Syriani, E. and Vangheluwe, H. (2009) Matters of model transformation. Technical Report SOCS-TR-2009.2.
McGill University, School of Computer Science.
[2] Jouault, F. and Kurtev, I. (2006) Transforming models with ATL. MTiP’05, January, LNCS, 3844, pp. 128–138.
Springer-Verlag.
[3] Fischer, T., Niere, J., Turunski, L., and Zündorf, A. (2000) Story diagrams: A new graph rewrite language based
on the Unified Modelling Language and Java. In Ehrig, H., Engels, G., Kreowski, H.-J., and Rozenberg, G.
(eds.), Theory and Application of Graph Transformations, Paderborn (Germany), November, LNCS, 1764, pp.
296–309. Springer-Verlag.
[4] Agrawal, A., Karsai, G., Kalmar, Z., Neema, S., Shi, F., and Vizhanyo, A. (2006) The design of a language for
model transformations. SoSym, 5, 261–288.
[5] Syriani, E. and Vangheluwe, H. (2009) Discrete-Event Modeling and Simulation: Theory and Applications. CRC
Press, Boca Raton (USA).
[6] Varró, D. and Balogh, A. (2007) The model transformation language of the VIATRA2 framework. Science of
Computer Programming, 68, 214–234.
[7] Object Management Group (2009) Unified Modeling Language Superstructure.
[8] Rensink, A. and Kuperus, J.-H. (2009) Repotting the geraniums: On nested graph transformation rules. In
Margaria, T., Padberg, J., and Taentzer, G. (eds.), GT-VMT’09, York (UK), March EASST.
[9] Zeigler, B. P. (1984) Multifacetted Modelling and Discrete Event Simulation. Academic Press.
[10] Syriani, E. and Vangheluwe, H. (2007) Programmed graph rewriting with DEVS. In Nagl, M. and Schürr, A.
(eds.), AGTIVE 2007, Kassel (Germany), LNCS, 5088, pp. 136–152. Springer-Verlag.
[11] Syriani, E. and Vangheluwe, H. (2008) Programmed graph rewriting with time for simulation-based design. In
Pierantonio, A., Vallecillo, A., Bézivin, J., and Gray, J. (eds.), ICMT 2008, Zürich (Switzerland), July, LNCS,
5063, pp. 91–106. Springer-Verlag.
[12] Vignaga, A., Jouault, F., Bastarrica, M. C., and Brunelière, H. (2009) Typing in model management. In Paige,
R. (ed.), Theory and Practice of Model Transformations (ICMT’09), Zürich (Switzerland), June, LNCS, 5563,
pp. 197–212. Springer-Verlag.
19
[13] Manning, G. and Plump, D. (2008) The GP programming system. GT-VMT’08, Budapest (Hungary), March
ECEASST, pp. 235–247.
20