=Paper=
{{Paper
|id=Vol-2026/paper13
|storemode=property
|title=Solving the TTC Families to Persons Case with FunnyQT
|pdfUrl=https://ceur-ws.org/Vol-2026/paper13.pdf
|volume=Vol-2026
|authors=Tassilo Horn
|dblpUrl=https://dblp.org/rec/conf/staf/Horn17
}}
==Solving the TTC Families to Persons Case with FunnyQT==
Solving the TTC Families to Persons Case with FunnyQT Tassilo Horn tsdh@gnu.org The GNU Project Abstract This paper describes the FunnyQT solution to the bidirectional Fami- lies to Persons transformation case of TTC 2017. The solution is simple and concise and passes all batch transformations and some incremental tests. 1 Introduction This paper describes the FunnyQT1 [Hor16, Hor15] solution of the Families to Persons case [ABW17] of TTC 2017. With only 52 lines of declarative code, the solution is able to pass all batch transformation tests and some incremental tests. The solution project is available on Github2 and it is integrated into the benchmarx 3 framework. FunnyQT is a model querying and transformation library for the functional Lisp dialect Clojure4 . Queries and transformations are Clojure functions using the features provided by the FunnyQT API. Clojure provides strong metaprogramming capabilities that are used by FunnyQT in order to define several embedded domain-specific languages (embedded DSL [Fow10]) for different querying and transformation tasks. FunnyQT is designed to be extensible. By default, it supports EMF [SBPM08] and JGraLab5 TGraph models. Support for other modeling frameworks can be added without having to touch FunnyQT’s internals. The FunnyQT API is structured into several namespaces, each namespace providing constructs supporting concrete querying and transformation use-cases, e.g., model management, functional querying, polymorphic func- tions, relational querying, pattern matching, in-place transformations, out-place transformations, bidirectional transformations, and some more. For solving the Families to Persons case, its bidirectional transformation and relational model querying DSLs have been used. 2 Solution Description This section explains the FunnyQT solution. First, Section 2.1 explains the actual transformation solving the case. Then, Section 2.2 explains how the solution is integrated into the benchmarx framework. 2.1 The Families to Persons Transformation As a first step, relational querying APIs for the two metamodels are generated. 1 (rel/generate-metamodel-relations "metamodels/Families.ecore" f) 2 (rel/generate-metamodel-relations "metamodels/Persons.ecore" p) This makes the relations for the families metamodel available with the namespace alias f and those of the persons metamodel with alias p. Relations are generated for every metamodel element. For example, there is a Copyright c by the paper’s authors. Copying permitted for private and academic purposes. In: A. Garcia-Dominguez, G. Hinkel and F. Krikava (eds.): Proceedings of the 10th Transformation Tool Contest, Marburg, Germany, 21-07-2017, published at http://ceur-ws.org 1 http://funnyqt.org 2 https://github.com/tsdh/ttc17-families2persons-bx 3 https://github.com/eMoflon/benchmarx/ 4 http://clojure.org 5 https://github.com/jgralab/jgralab relation (f/Family f family) which succeeds for every family in the given family model f. There is a relation (f/name f el n) which succeeds if el is a member or family of the family model f whose name is n. And there are reference relations like (f/->sons f parent child) which succeed if child is a son of parent. Before the transformation itself, we define a helper relation which defines the possible kinds of relationships between a family and a family member depending on if we prefer to create parents over creating children (parameter pref-parent). This is a higher-order relation in that the two remaining parameters are a parent relation prel (either f/->father or f/->mother) and a child relation (either f/->daughters or f/->sons). 3 (defn relationshipo [pref-parent f family member prel crel] 4 (ccl/conda 5 [(bx/target-directiono :right) ;; (1) 6 (ccl/conde 7 [(prel f family member)] 8 [(crel f family member)])] 9 [(bx/existing-elemento? member)] ;; (2) 10 [(ccl/== pref-parent false) ;; (3) 11 (crel f family member)] 12 [(bx/unseto? f family prel member) ;; (4) 13 (prel f family member)] 14 [(crel f family member)])) ;; (5) ccl/conda is like a short-cutting logical disjunction. The n-th clause is only tried if all preceeding clauses fail. The first clause succeeds when we are transforming into the direction of the right model, i.e., the person register. In this case, member may be in a parental role of family (prel), or it might be in a child role (crel). We don’t really care but want to ensure that all members of the given family are reachable, thus we use a non-short-cutting ccl/conde which gives both clauses a chance to succeed. All other clauses deal with transforming a person model to a family model, i.e., the backward transformation. The second clause deals with the case where member is an already existing element, i.e., not created by the current execution of the transformation. Here, we assume that this member is already properly assigned to a family, so we simply succeed without doing anything. In the third clause, if we do not prefer assigning to parental roles, then the child relation crel must succeed between the family and the member. The child relations can always succeed because a family can have an arbitrary number of daughters and sons. Thus, in the remaining clauses we have to deal only with the case where assigning to parental roles is preferred. In the fourth clause, if the family’s parental role is still unset or already assigned to member, then the parental relation must succeed between the family and the member. Lastly, if no clause has succeeded until now, then the child relation has to succeed. As said, this goal6 can always succeed. In the following, the actual transformation definition is explained. It is defined using the deftransformation macro provided by FunnyQT. 15 (bx/deftransformation families2persons [f p prefer-parent prefer-ex-family] 16 :delete-unmatched-target-elements true 17 :id-init-fn bx/number-all-source-model-elements The name of the transformation is families2persons and it declares four parameters. The parameter f is the family model (the left model), p is the persons model (the right model), prefer-parent is a Boolean flag determining if we prefer creating parents to creating children, and prefer-ex-family is a Boolean flag, too, determining if we prefer re-using existing families over creating new families for new family members. By default, bidirectional FunnyQT transformations will never delete elements from the current target model, i.e., the model being created or modified by the synchronization. The reason for that behavior is that it allows to run the transformation in one direction first and then in the other direction in order to perform a full synchroniza- tion where missing elements are created in each of the two models. Thus, after running a transformation, e.g., in the direction of the right model, it is only ensured that for each element (considered by the transformation’s rules) in the left model, there is a corresponding counterpart in the right model. However, the right model might still contain elements which have no counterpart in the left model. With option :delete-unmatched-target-elements set to true, this behavior is changed. Elements in the current target model which are not required by the current source model and the transformation relations are deleted. 6 The application of a relation is called a goal. The next option, :id-init-fn, has the following purpose. In this transformation case, family members and persons do not have some kind of unique identity. For example, it is allowed to have two members named Jim with the same name in the very same family Smith. However, FunnyQT BX transformations have forall-there-exists semantics where it would suffice to create just one person in the right model with the name set to “Smith, Jim”. But the case description mandates that we create one person for every member and vice versa, no matter if they can be distinguished based on their attribute values. For such scenarios, FunnyQT’s bidirectional transformation DSL provides a concept of synthetic ID attributes. The value of :id-init-fn has to be a function which returns a map from elements to their synthetic IDs. The built-in function bx/number-all-source-model-elements returns a map where every element in the source model gets assigned a unique integer number. These synthetic IDs are then used in a transformation relation which is discussed further below. The first transformation relation, family-register2person-register, transforms between family and person registers. 18 (^:top family-register2person-register 19 :left [(f/FamilyRegister f ?family-register)] 20 :right [(p/PersonRegister p ?person-register)] 21 :where [(member2female :?family-register ?family-register :?person-register ?person-register) 22 (member2male :?family-register ?family-register :?person-register ?person-register)]) It is defined as a top-level rule meaning that it will be executed as the entry point of the transformation. Its :left and :right clauses describe that for every ?family-register there has to be a ?person-register and vice versa. We assume that there is always just one register in each model. The :where clause defines that after this relation has been enforced (or checked in checkonly mode), then the two transformation relations member2female and member2male have to be enforced (or tested) between the current ?family-register and ?person-register7 . The next transformation relation, member2person, describes how family members of a family contained in a family register in the left model correspond to persons contained in a person register in the right model. As it can be seen, there is no goal describing how the ?family and the ?member are connected in the :left clause and in the :right clause we are dealing with just a ?person of type Person which is an abstract class. As such, this relation is not sufficient for the complete synchronization between members in the different roles of a family to females and males. Instead, it only captures the aspects that are common in the cases where mothers and daughters are synchronized with females and fathers and sons are synchronized with males. Therefore, this relation is declared abstract. 23 (^:abstract member2person 24 :left [(f/->families f ?family-register ?family) 25 (f/Family f ?family) 26 (f/name f ?family ?last-name) 27 (f/FamilyMember f ?member) 28 (f/name f ?member ?first-name) 29 (id ?member ?id) 30 (ccl/conda 31 [(ccl/== prefer-ex-family true)] 32 [(bx/existing-elemento? ?member) 33 (id ?family ?last-name)] 34 [(id ?family ?id)])] 35 :right [(p/->persons p ?person-register ?person) 36 (p/Person p ?person) 37 (p/name p ?person ?full-name) 38 (id ?person ?id)] 39 :when [(rel/stro ?last-name ", " ?first-name ?full-name)]) So what are these common aspects? Well, a ?member of a ?family (where we have not determined the role, yet) contained in the ?family-register passed in as parameter from family-register2person-register corresponds to a ?person (where we have not determined the gender, yet) contained in the ?person-register passed in as the other parameter from family-register2person-register. The :when clause defines that the concatenation of the ?family’s ?last-name, the string ", " and the ?member’s ?first-name gives the ?full-name of the ?person. What has not been described so far are the id goals in lines 29, and 34 and the ccl/conda goal starting in line 30. The first two define that the ?member and the corresponding ?person must have the same synthetic ID. Remember the :id-init-fn in line 17 which assigned a unique number to every element in the respective source 7 Transformation relations are called with keyword parameters. The two calls in the :where clause state that the current ?family-register will be bound to the logic variable with the same name in the called relation and the same is true for the ?person-register. model of the transformation. With these synthetic IDs, the transformation is able to create one person for every member and vice versa even in the case where two elements are equal based on their attribute values. Lastly, the ccl/conda goal starting in line 30 of the :left clause handles the preference of re-using existing families, i.e., assigning new members to existing families, over creating new families for new members. By default, FunnyQT would always try to re-use an existing family. Thus, if the prefer-ex-family parameter is true, nothing needs to be done. Likewise, if ?member is an existing element for which we assume she is already assigned to some family, we can also just stick to the default behavior but define the ID of the ?family to be its name (although it is probably not unique). If the first two ccl/conda clauses fail, i.e., prefer-ex-family is false and ?member is a new member which is just going to be created by the enforcement of this relation, then we define that the ID of the ?family must equal to the IDs of the ?member and ?person. Thus, in this case and only in this case, new members force the creation of a new family even when there is already a family with the right name. The last two transformation relations extend the member2person relation for synchronizing between members in the role of a family mother or daughter and female persons and between family fathers or sons and male persons. 40 (member2female 41 :extends [(member2person)] 42 :left [(relationshipo prefer-parent f ?family ?member f/->mother f/->daughters)] 43 :right [(p/Female p ?person)]) 44 (member2male 45 :extends [(member2person)] 46 :left [(relationshipo prefer-parent f ?family ?member f/->father f/->sons)] 47 :right [(p/Male p ?person)])) In the :left clauses we use the relationshipo helper relation described in the beginning of this section which chooses the right female or male role based on the preference parameter prefer-parent and the current state of the family, i.e., by checking if the respective parental role is still unset. In the two :right clauses, we only need to specify that the Person ?person is actually a Female or Male. These 33 lines of transformation specification plus the 12 lines for the relationshipo helper, and two lines for the generation of the metamodel-specific relational querying APIs form the complete functional parts of the solution. The only thing omitted from the paper are the namespace declarations8 consisting of 5 lines of code. 2.2 Gluing the Solution with the Framework Typically, open-source Clojure libraries and programs are distributed as JAR files that contain the source files rather than byte-compiled class files. This solution does almost the same except that the JAR contains the solution source code, FunnyQT itself (also as sources) and every dependency of FunnyQT (like Clojure) except for EMF which the benchmarx project already provides. Calling Clojure functions from Java is really easy and FunnyQT transformations are no exception because they are plain Clojure functions, too. The BXTool implementation FunnyQTFamiliesToPerson extends the BXToolForEMF class. Essentially, it has just a static member T which is set to the transformation. public class FunnyQTFamiliesToPerson extends BXToolForEMF{ private final static Keyword LEFT = (Keyword) Clojure.read(":left"); private final static Keyword RIGHT = (Keyword) Clojure.read(":right"); private final static IFn T; // <-- The FunnyQT Transformation static { final String transformationNamespace = "ttc17-families2persons-bx.core"; // Clojure’s require is similar to Java’s import. However, it also loads the required // namespace from a source code file and immediately compiles it. final IFn require = Clojure.var("clojure.core", "require"); require.invoke(Clojure.read(transformationNamespace)); T = Clojure.var(transformationNamespace, "families2persons"); } All Clojure functions implement the IFn interface and can be called using invoke(). And exactly this is done to call the transformation. private void transform(Keyword direction) { T.invoke(srcModel, trgModel, direction, configurator.decide(Decisions.PREFER_CREATING_PARENT_TO_CHILD), configurator.decide(Decisions.PREFER_EXISTING_FAMILY_TO_NEW)); } This corresponds to a direct Clojure call (families2persons src trg dir prefer-parent prefer-ex-family). 8 The Clojure equivalent of Java’s package statement and imports. 3 Evaluation and Conclusion In this section, the test results of the FunnyQT solution are presented and classified as requested by the case description [ABW17]. Since the bidirectional transformation DSL of FunnyQT is state-based and not incremental at all (and by design), many of the incremental tests are mostly out of scope. However, in its core use case, non-incremental bidirectional transformations, the solution passes all tests. BatchForward.* All tests result in an expected pass. BatchBwdEandP.* All tests result in an expected pass. BatchBwdEnotP.* All tests result in an expected pass. BatchBwdNotEandP.* All tests result in an expected pass. BatchBwdNotEnotP.* All tests result in an expected pass. IncrementalForward.* The solution expectedly passes the tests testStability, testHippocraticness, and testIncrementalInserts. All remaining tests fail expectedly because those tests require incremental abil- ities. For example, in some tests the birthdates are set manually in the persons model. The re-execution of the transformation causes deletion and re-creation of those persons, however then they get assigned default birthdates and not the manually edited ones as the transformation does not consider this attribute at all. IncrementalBackward.* The solution expectedly passes the tests testStability, testIncrementalInsertsFixedConfig, testIncrementalOperational, and testHippocraticness. The test testIncrementalInsertsDynamicConfig fails unexpectedly. When we neither prefer existing families nor assigning to parental roles, the transformation still adds the new Seymore to an existing family in a parental role. All other tests are expected fails due to the fact that they require incremental capabilities. In summary, the correctness is satisfying. There is only one test which fails unexpectedly. All other fails are expected and can hardly be solved by a non-incremental approach. A very weak point of the solution is its performance. It is at least an order of magnitude slower than the other solutions already integrated in the benchmarx project (BiGUL, eMoflon, BXtend, MediniQVT). Where their runtimes are in the tenth of seconds or below, the FunnyQT solution takes seconds. With models in the size of thousands of elements, you might have to wait a bit for the transformation to finish. One reason is that the FunnyQT BX implementation is state-based and thus needs to recompute the correspondences between all elements in the source and target models on every invocation instead of just propagating small deltas like incre- mental approaches do. Furthermore, FunnyQT’s bidirectional transformation DSL is built upon the relational programming library core.logic 9 which is not tuned for performance but for simplicity and extensibility of its implementation and FunnyQT probably does not use it in the best possible way. Other good points of the solution are its conciseness and simplicity. With only 52 lines of code, it is by far the most concise solution currently integrated in the benchmarx project. And it is quite simple to understand. The only complexities it has arose from the different alternatives depending on external parameters. References [ABW17] Anthony Anjorin, Thomas Buchmann, and Bernhard Westfechtel. The Families to Persons Case. In Antonio Garcia-Dominguez, Georg Hinkel, and Filip Krikava, editors, Proceedings of the 10th Transformation Tool Contest, a part of the Software Technologies: Applications and Foundations (STAF 2017) federation of conferences, CEUR Workshop Proceedings. CEUR-WS.org, July 2017. [Fow10] Martin Fowler. Domain-Specific Languages. Addison-Wesley Professional, 2010. [Hor15] Tassilo Horn. Graph Pattern Matching as an Embedded Clojure DSL. In International Conference on Graph Transformation - 8th International Conference, ICGT 2015, L’Aquila, Italy, July 2015, 2015. [Hor16] Tassilo Horn. A Functional, Comprehensive and Extensible Multi-Platform Querying and Transfor- mation Approach. PhD thesis, University Koblenz-Landau, Germany, 2016. [SBPM08] Dave Steinberg, Frank Budinsky, Marcelo Paternostro, and Ed Merks. EMF: Eclipse Modeling Frame- work. Addison-Wesley Professional, 2 edition, 2008. 9 https://github.com/clojure/core.logic