Skip to main content

Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "VIATRA/DSE/UserGuide/API"

< VIATRA‎ | DSE
(Usage of the VIATRA-DSE API)
m (Usage of the VIATRA-DSE API)
Line 1: Line 1:
 
= Usage of the VIATRA-DSE API =
 
= Usage of the VIATRA-DSE API =
  
This page presents the basic API of the VIATRA-DSE framework. After reading this you will be able to define a DSE problem including transformation rules and goals, run it with different built in strategies and use the solutions the exploration found.
+
This page presents the basic API of the VIATRA-DSE framework. After reading this you will be able to define a DSE problem including transformation rules and objectives, run it with different built in strategies and use the solutions the exploration found.
  
 
It is highly recommended to get familiar with the [[EMF|EMF]] and [[EMFIncQuery|EMF-IncQuery]] frameworks first as they are essential for using VIATRA-DSE.
 
It is highly recommended to get familiar with the [[EMF|EMF]] and [[EMFIncQuery|EMF-IncQuery]] frameworks first as they are essential for using VIATRA-DSE.
Line 27: Line 27:
  
  
The initial model must be set as the root EObject of the model (i.e.: it contains all other objects of the model via the containment hierarchy). In the future Resource and ResourceSet may be supported as well.
+
The initial model must be set as the root <code>EObject</code> of the model (i.e.: it contains all other objects of the model via the containment hierarchy). In the future <code>Resource</code> and <code>ResourceSet</code> may be supported as well.
  
 
== Transformation rules ==
 
== Transformation rules ==
  
Rules tell the engine how the initial model can be modified and treated as atomic steps. They consist of a left hand side (LHS or condition) and a right hand side (RHS) . The LHS is always an IncQuery pattern (or a model query) while the RHS is simple Java code. To define such a rule an instance of the TransformationRule class must be created.
+
Rules tell the engine how the initial model can be modified and treated as atomic steps. They consist of a left hand side (LHS or condition) and a right hand side (RHS). The LHS is always an IncQuery pattern (i.e. a model query) while the RHS is simple Java code. To define such a rule an instance of the TransformationRule class must be created.
  
 
Let's say a pattern named myPattern with two parameters is already available and can be used as a LHS.
 
Let's say a pattern named myPattern with two parameters is already available and can be used as a LHS.
Line 37: Line 37:
 
<source lang="java">
 
<source lang="java">
 
     TransformationRule<MyPatternMatch> rule =  
 
     TransformationRule<MyPatternMatch> rule =  
    new TransformationRule<MyPatternMatch>(MyPatternQuerySpecification.instance(), new MyPatternMatchProcessor() {
+
        new TransformationRule<MyPatternMatch>(MyPatternQuerySpecification.instance(), new MyPatternMatchProcessor() {
        @Override
+
            @Override
        public void process(ExampleEObject p1, ExampleEObject p2) {
+
            public void process(ExampleEObject p1, ExampleEObject p2) {
            // RHS manipulates the EMF model
+
                // RHS manipulates the EMF model
            p1.setFriend(p2);
+
                p1.setFriend(p2);
        }
+
            }
    });
+
        });
  
dse.addTransformation(rule);
+
    dse.addTransformation(rule);
 
</source>
 
</source>
  
Line 51: Line 51:
 
Note 1: A rule can also have a name via the "setName(String)" method.
 
Note 1: A rule can also have a name via the "setName(String)" method.
  
Note 2: It's forbidden to apply two rules with same LHS to be able to distinguish them based on the pattern. Using the IncQuery keyword ''find'' can avoid code duplication.
+
Note 2: It's forbidden to apply two rules with the same LHS to be able to distinguish them based on the pattern. If two rules would use the same LHS, creating a new pattern and using the IncQuery keyword ''find'' can avoid code duplication.
  
Note 3:  It's a good practice to use static factory methods in a separate class for creating rules.
+
Note 3:  It's a good practice to use static factory methods in a separate class for creating rules, as the above code can worsen the readability.
  
 
== Objectives ==
 
== Objectives ==
  
Objectives determine the quality of a solution represented in a double value. The goal can be a single objective with a binary check (valid or invalid model) or it can consist of multiple numerical objectives giving a multi-objective optimization problem. There are two type of objectives: hard and soft. Hard objectives are used to decide whether the solution is valid and can be considered as a usable solution, while soft objectives determine the quality and enables the ordering of the solutions. It is possible to use both types or only one of them.
+
Objectives determine the quality of a solution represented in double values. The goal can be a single objective with a binary check (valid or invalid model) or it can consist of multiple numerical objectives giving a multi-objective optimization problem. There are two types of objective: hard and soft. Hard objectives are used to decide whether the solution is valid and can be considered as a usable solution, while soft objectives determine the quality and enables the ordering of the solutions. It is possible to use both types or only one of them.
  
To use an objective one must implement the IObjective interface or use one of the built in implementations. As objectives are mainly defined by IncQuery patterns, hence the built in implementations are focused on them. <code>AllMustHaveMatchHardObjective</code> is a hard objective implementation, which can be configured with IncQuery patterns. It checks if all of the given patterns have a match in the actual model, and considers it a valid solution only if they have (returning a fitness value 1 and returning 0 if it is invalid). See the following example:
+
To use an objective one must implement the IObjective interface or use one of the built in implementations. Objectives are mainly defined by IncQuery patterns, hence the built in implementations are focused on them. <code>AllMustHaveMatchHardObjective</code> is a hard objective implementation, which can be configured with IncQuery patterns. It checks if all of the given patterns have a match in the actual model, and considers it a valid solution only if they have (returning a fitness value 1 and returning 0 if it is invalid). See the following example:
  
 
<source lang="java">
 
<source lang="java">
Line 74: Line 74:
 
* CompositSoftObjective - can be configured with a set of soft objectives. Returns the sum of the calculated fitness by the the sub objectives.
 
* CompositSoftObjective - can be configured with a set of soft objectives. Returns the sum of the calculated fitness by the the sub objectives.
  
Objectives also have a comparator, which decides the relation between two solutions (which one is better) corresponding to the particular objective. For example, an objective could be a value to maximize, or a value to minimize a difference from a given number. This is dependent of the objective comparator.
+
Objectives also have a comparator, which decides the relation between two solutions (which one is better) corresponding to the particular objective. For example, an objective could be a value to maximize, or a value to minimize a difference from a given number. This is dependent of the objective's comparator.
  
 
== State coding ==
 
== State coding ==
Line 117: Line 117:
 
=== Global constraints ===
 
=== Global constraints ===
  
If there are any global constraints added they must be satisfied in all of the intermediate model state of trajectory. If a global constraint is not satisfied the engine won't allow the exploration to go further from that state. It can be useful to reduce the state space, but it can also be a goal of the problem. Defining a global constraint is very similar to defining a goal patter.
+
If there are any global constraints added they must be satisfied in all of the intermediate model state of trajectory. If a global constraint is not satisfied the engine won't allow the exploration to go further from that state. It can be useful to reduce the state space, but it can also be a criteria for a usable solution.
  
 
<source lang="java">
 
<source lang="java">

Revision as of 11:37, 8 January 2015

Usage of the VIATRA-DSE API

This page presents the basic API of the VIATRA-DSE framework. After reading this you will be able to define a DSE problem including transformation rules and objectives, run it with different built in strategies and use the solutions the exploration found.

It is highly recommended to get familiar with the EMF and EMF-IncQuery frameworks first as they are essential for using VIATRA-DSE.

API

VIATRA-DSE depends on the Eclipse platform thus using it one should create a plug-in project and add the org.eclipse.viatra.dse.base plug-in as a dependency for the plug-in project. To start using the framework type this line of code:

    DesignSpaceExplorer dse = new DesignSpaceExplorer();

Defining the domain

The first thing required is a metamodel or ecore model created with EMF and an initial model. See the code below.

    EObject root = createInitialModel();
    dse.setStartingModel(root);
 
    // You can also define the metamodel however it is not obligatory
    dse.addMetaModel(MetamodelEPackage.eINSTANCE);


The initial model must be set as the root EObject of the model (i.e.: it contains all other objects of the model via the containment hierarchy). In the future Resource and ResourceSet may be supported as well.

Transformation rules

Rules tell the engine how the initial model can be modified and treated as atomic steps. They consist of a left hand side (LHS or condition) and a right hand side (RHS). The LHS is always an IncQuery pattern (i.e. a model query) while the RHS is simple Java code. To define such a rule an instance of the TransformationRule class must be created.

Let's say a pattern named myPattern with two parameters is already available and can be used as a LHS.

    TransformationRule<MyPatternMatch> rule = 
        new TransformationRule<MyPatternMatch>(MyPatternQuerySpecification.instance(), new MyPatternMatchProcessor() {
            @Override
            public void process(ExampleEObject p1, ExampleEObject p2) {
                // RHS manipulates the EMF model
                p1.setFriend(p2);
            }
        });
 
    dse.addTransformation(rule);


Note 1: A rule can also have a name via the "setName(String)" method.

Note 2: It's forbidden to apply two rules with the same LHS to be able to distinguish them based on the pattern. If two rules would use the same LHS, creating a new pattern and using the IncQuery keyword find can avoid code duplication.

Note 3: It's a good practice to use static factory methods in a separate class for creating rules, as the above code can worsen the readability.

Objectives

Objectives determine the quality of a solution represented in double values. The goal can be a single objective with a binary check (valid or invalid model) or it can consist of multiple numerical objectives giving a multi-objective optimization problem. There are two types of objective: hard and soft. Hard objectives are used to decide whether the solution is valid and can be considered as a usable solution, while soft objectives determine the quality and enables the ordering of the solutions. It is possible to use both types or only one of them.

To use an objective one must implement the IObjective interface or use one of the built in implementations. Objectives are mainly defined by IncQuery patterns, hence the built in implementations are focused on them. AllMustHaveMatchHardObjective is a hard objective implementation, which can be configured with IncQuery patterns. It checks if all of the given patterns have a match in the actual model, and considers it a valid solution only if they have (returning a fitness value 1 and returning 0 if it is invalid). See the following example:

    dse.addObjective(new AllMustHaveMatchHardObjective("MyHardObjective")
        .addConstraint(Pattern1QuerySpecification.instance()
        .addConstraint(Pattern2QuerySpecification.instance()));


Other built-in objective implementations are:

  • NoMatchHardObjective - which is similar to the previous one, but it considers a solution valid only if all the patterns have no matches.
  • WeightedPatternsSoftObjective - is a soft objective, which can be configured with a list of patterns and weights assigned to them. It calculates a fitness value in the following way: fitness = sum(pattern[i].countMatches() * weight[i])
  • CompositHardObjective - can be configured with a set of hard objectives. It considers a solution valid, if all the hard objectives assess it as a valid solution.
  • CompositSoftObjective - can be configured with a set of soft objectives. Returns the sum of the calculated fitness by the the sub objectives.

Objectives also have a comparator, which decides the relation between two solutions (which one is better) corresponding to the particular objective. For example, an objective could be a value to maximize, or a value to minimize a difference from a given number. This is dependent of the objective's comparator.

State coding

A state coder is also necessary for the engine to start the exploration. For any more detail about this please see the state coding section of this wiki.

    ArrayList<EPackage> metaModelPackages = new ArrayList<EPackage>();
    metaModelPackages.add(MetamodelEPackage.eINSTANCE);
    dse.setSerializerFactory(new IncrementalGraphHasherFactory(metaModelPackages));

Starting the exploration

To start the exploration a strategy must also be defined. Static methods of the Strategies class can be used to create a built in strategy like depth first search. The exploration runs in separate threads hence there is a boolean parameter whether to wait for the exploration process.

    boolean waitForTermination = true;
    dse.startExploration(Strategies.createDFSStrategy(), waitForTermination);


The second parameter can also be an integer for timeout, which if elapses the exploration will stop as soon as possible.

Using the results

A solution of the exploration is a trajectory, a sequence of rules which if applied to the initial model, it satisfies the goals. It's important that the same goal state can be reached by different trajectories and this is also represented by the results: an instance of Solution class can have multiple SolutionTrajectory instances. A solution has at least one solution trajectory, but nothing more can be expected, as it is heavily depend on the traversal strategy and the actual traversal of the state space. The SolutionTrajectory can be used to transform the given model (should be the initial model) based on the trajectory.

    Collection<Solution> solutions = dse.getAllSolutions();
    if (!solutions.isEmpty()) {
        Solution solution = dse.getAllSolutions().iterator().next();
        SolutionTrajectory solutionTrajectory = solution.getArbitraryTrajectory();
        // Transform the model
        solutionTrajectory.setModel(theInitialModel);
        solutionTrajectory.doTransformation();
    }

Other functions of the API

Global constraints

If there are any global constraints added they must be satisfied in all of the intermediate model state of trajectory. If a global constraint is not satisfied the engine won't allow the exploration to go further from that state. It can be useful to reduce the state space, but it can also be a criteria for a usable solution.

    dse.addConstraint(new PatternWithCardinality(MyGlobalConstraintQuerySpecifiaction.instance()));

Parallel execution

The engine allows the traversal strategy to explore the state space with multiple threads. By default it allows a number of threads equal to the number of logical cores in the processor. It can be overridden with the following code:

    dse.setMaxNumberOfThreads(1);

Run configuration

Running the DSE engine needs an Eclipse platform, thus it is recommended to use a JUnit plug-in test in headless mode. Here are some basic steps to configure it properly:

  • Add the org.junit as a dependency.
  • Annotate the method with @Test annotation
  • Create a JUnit plug-in test run configuration with the corresponding class
  • Locate the Run configuration / Main tab and change the selection at "Run an application" to "[No Application] – Headless Mode".
  • On the Plug-ins tab select "plug-ins selected below only" from the drop down list and select the plugin which contains the class with the annotated method.
  • Hit "Add Required Plug-ins" 2-3 times.

Examples

Coming soon.

Copyright © Eclipse Foundation, Inc. All Rights Reserved.