• Nem Talált Eredményt

After calculating and initializing the previous data structures at compile time, the rest of the pattern matching process is carried out at run-time.

5.6.1 Search Plan Generation

Generating of a search plan for a specific flattened pattern body requires two input parameters; (i) its corresponding search graph itself and (ii) the binding of its input parameters (adornment on its

5.6. RUNTIME STEPS 55

pattern variables). The generation is realized as described in Section 5.3. We implemented a simple caching mechanism to prevent the generation of search plans that are already available with a specific adornment. Additionally, there is an option for the transformation designer to generate search plans for all graph patterns with all kinds of binding. However, it turned out that it resulted in a large overhead at compile time with a very moderate speed up at runtime and this advantage was only measurable in case of small instance models.

Example 17 One possible search plan for the#13flattened pattern body of themissingCircleLink graph pattern with all input parameters considered as unbound is depicted in Section 5.5(b). The interesting parts are that it starts from theCPrelation using itsCirclePathconstant node and from there extends the matching in both direction towards Field1 and Field2. Additionally, due to the iteration over allCirclePathtyped link in the instance model as the starting operation the algorithm came up with a search plan that tries to use the injectivity check between the edges as soon as possible in order to keep the search tree small.

5.6.2 Executing the Operations

Finally, the generated search plan is executed using a simple algorithm that tries to execute the operations of the search plan and backtracks if one fails (check) or could not provide additional matching candidate for the specific pattern variable (extend). In this way the execution of the search plan produces a match if the algorithm executes the last operation.

The skeleton of the actual Java implementation of the algorithm in the Viatra2 framework is depicted in Listing 5.2. The inputframeobject represents a container that stores all pattern variables and their matching candidate values. All operation is a subtype of theSearchPlanOperationclass and theoperationsarray contains the pattern matching operations of the search plan. The code first simply initializes the frame that sets the constant and bound pattern variables as required by the search plan and then starts executing the operations in the followingwhile-doconstruct. The while terminates if either the last operation is executed and thus theframeobject contains a valid match or the loop backtracked to the first operation. Within the loop the actual operation which is saved by thecurrentOperationvariables is executed. If its execution returns with a true the execution continues with the following operation in the next round if not, than the operation is backtracked using thepostprocessmethod of the operation. In some cases preprocessing is also required that is handled by calling thepreprocessmethod.

It is important to note that theextendoperations hold their actual state and contain information on the already tried candidates. For example, in case of an operation that iterates through the ele-ments of a specific type (see in Example 17 the first operation of the search plan that extends through the CirclePathtype as candidates for the CP pattern variable) it saves which CirclePathlinks were already tried as a candidate during its executions.

Finally, the match is filtered out of those elements of that do not correspond to a parameter of the pattern signature.

public class SearchPlan {

private SearchPlanOperation [] operations ; private int currentOperation ;

.../** Executes the Search Plan

* @param frame The container for the match . It holds the values of the

* pattern variables

* @return true if there is a match found and false if there is no match

* @throws PatternMatcherRuntimeException

*/

56 CHAPTER 5. SEARCH PLAN DRIVEN GRAPH PATTERN MATCHING

public boolean execute ( MatchingFrame frame ) throws PatternMatcherRuntimeException {

int upperBound = operations . length - 1; // inits the upper bound init ( frame ); // init the constant or bound values in the frame

// the execution stops if all operations are executed or backtracked to the beginning while ( currentOperation >= 0 and currentOperation < upperBound ) {

if ( operations [ currentOperation ]. execute ( frame )) { // executes the operation currentOperation ++;

operations [ currentOperation ]. preprocess ( frame );

// complex operations require preprocessing } else {

operations [ currentOperation ]. postprocess ( frame ); // backtracks the operation currentOperation --;

}}

return ( currentOperation == upperBound ); // true if it reached the last operation }...

}

Listing 5.2: Skeleton of the operation execution code

5.6.3 Performance

The performance of our implementation of the adorned search graph driven pattern matcher in the Viatra2 framework was assessed in many graph and model transformation tool contests either as a separate pattern matcher [27,17] or as part of the Viatra2 hybrid pattern matcher engine [16,24 2,21]. Its evaluation as a standalone pattern matcher on the Sierpinski case study introduced at the 2007 AGTIVE tool contest is discussed in Section 5.6.3.1, while as part of the hybrid engine on the AntWorld running example is discussed in Section 6.3.3.

5.6.3.1 Summary of the Sierpinski Graph Transformation Tool Contest Case Study

The task in the case study is to simulate the creation of a Sierpinski graph. Originally constructed as a mathematical curve, this is one of the basic examples of self-similar sets, i.e. it is a mathematically generated pattern that can be reproduced at any magnification or reduction. It is created by the following algorithm:

1. Start with any triangle in a plane (any closed, bounded region in the plane will actually work).

The canonical Sierpinski triangle uses an equilateral triangle with a base parallel to the hori-zontal axis.

2. Shrink the triangle by1/2, make two copies, and position the three shrunken triangles so that each triangle touches the two other triangles at a corner.

3. Repeat step 2 with each of the smaller triangles.

The Solution Our solution follows the simple structure that it first matches all triangles that are needed to be extended, then generates the required additional triangles. Figure 5.6 illustrates our simple metamodel.

Based on this metamodel, we used a very simple pattern (see in Listing 5.3) to match to the required triangles. It simply defines the triangle in a clockwise order that, due the definition of our metamodel, matches only on those triangles that are needed to be extended in the following round.

5.6. RUNTIME STEPS 57

Figure 5.6: Metamodel for capturing the Sierpinski triangles

pattern triangle (A,B,C,EAB ,EBC , ECA ) = { a(A); node .e(EAB ,A,B);

b(B); node .e(EBC ,B,C);

c(C); node .e(ECA ,C,A);

}

Listing 5.3: Pattern for finding the required triangles

Control Flow Listing 5.4 describes the main control flow of our Sierpinski generator transformation program. It uses thetrianglepattern in theforallto match to all required triangles and then in all iterations it first deletes the old edges, then creates the new triangle and connects it to the rest of the model.

The outer iteration makes sure that the Sierpinski generation is not executed more than its input maximum iteration number.

rule generate (in MaxRounds ) = let RoundCount = 0 in seq {

iterate if( RoundCount < MaxRounds ) seq { forall A,B,C,

EAB , EBC , ECA with find triangle (A,B,C,EAB ,EBC , ECA ) do seq { // The old edges are deleted :

delete( EAB );

delete( EBC );

delete( ECA );

// The new nodes are created : new(ab(AB) in models (" model "));

new(bc(BC) in models (" model "));

new(ac(AC) in models (" model "));

// The new edges are created :

new( node .e(EAAB ,A,AB )); new( node .e(EABB ,AB ,B )); new( node .e(EACBC ,AC ,BC ));

new( node .e(EABAC ,AB ,AC )); new( node .e(EBBC ,B,BC )); new( node .e(EBCC ,BC ,C ));

new( node .e(EACA ,AC ,A )); new( node .e(EBCAB ,BC ,AB )); new( node .e(ECAC ,C,AC ));}

update RoundCount = RoundCount +1;}

else fail ;}

Listing 5.4: The triangle generator transformation

Conclusion On an Intel T2400@1830 MHz notebook with 2 GByte memory, we managed to handle 10 iterations and received a JVM out of memory exception on the eleventh. It is roughly a little less than one million model elements (nodes and edges altogether). As for the runtime performance, due to some randomization in the matching process, we measured huge differences between different executions, but overall the generation took from a couple of minutes to more then 10 minutes for the 10. iteration. Detailed results for the different iterations are depicted in Figure 5.7.

58 CHAPTER 5. SEARCH PLAN DRIVEN GRAPH PATTERN MATCHING

Figure 5.7: Runtime results of the Sierpinski casesstudy

In overall, based on this case study and all of our other experiences [27,17, 2] the local search based pattern matcher is capable of handling problems within the few hundred thousand model elements with acceptable performance.