ICL-Beispielprogramm zur Constrainterzeugung

Aus Eclipse
Wechseln zu: Navigation, Suche

Erstellen eines neuen Xtext-Projektes in Eclipse

  • File → New → Project → Xtext → Xtext → Project
  • Bestätigen Sie alle Vorgaben durch Klick auf Finish
  • Erzeugen Sie das Projekt mittels Ausführung von org.xtext.example.mydsl/GenerateMyDsl.mwe2 als MWE2-Workflow
  • Legen Sie im src-Verzeichnis ein neues Paket mit der Bezeichnung org.xtext.example.mydsl.use an
  • Fügen Sie diesem Pakelt die Datei SampleProgram.mydsl mit dem folgenden Inhalt hinzu:
Hello Ben!
Hello Ken!

Hinweis: Diese Datei können Sie natürlich auch mit einer Eclipse-Runtime-Instanz inkl. Editorunterstützung für unsere einfache DSL erstellen.

  • Erzeugen Sie danach eine neue Java-Klasse SolveConstraints.java mit folgendem Inhalt:
package org.xtext.example.mydsl.use;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.xtext.example.mydsl.MyDslStandaloneSetup;
import org.xtext.example.mydsl.myDsl.Greeting;
import org.xtext.example.mydsl.myDsl.Model;

import com.google.inject.Injector;

import de.feu.ps.ocl2.csp.v3.dsl.icl.Artefact;
import de.feu.ps.ocl2.csp.v3.dsl.icl.Element;
import de.feu.ps.ocl2.csp.v3.dsl.icl.Property;
import de.feu.ps.ocl2csp.v3.dsl.baseIcl.ComparisonExpression;
import de.feu.ps.ocl2csp.v3.dsl.baseIcl.Expression;
import de.feu.ps.ocl2csp.v3.dsl.baseIcl.PropertyReferenceLiteral;
import de.feu.ps.ocl2csp.v3.dsl.icl.util.IclExpressionFactory;
import de.feu.ps.ocl2csp.v3.dsl.icl.util.Printer;
import de.feu.ps.ocl2csp.v3.icl.IclConstructor;
import de.feu.ps.ocl2csp.v3.solver.AbstractSolverFacade;
import de.feu.ps.ocl2csp.v3.solver.Solution;
import de.feu.ps.ocl2csp.v3.solver.SolutionEnvironment;
import de.feu.ps.ocl2csp.v3.solver.Solver;
import de.feu.ps.ocl2csp.v3.solver.SolverFactory;

public class SolveConstraints {
	private Artefact artefactFromResource;
	
	public static void main(String[] args) {
		new SolveConstraints().solve();
	}

	private void solve() {
		try {
			
			String dslSourceFileName = "org/xtext/example/mydsl/use/SampleProgram.mydsl";
			String sourceFilePath = this.getClass().getClassLoader().getResource(dslSourceFileName).getPath();
			
			Injector injector = new MyDslStandaloneSetup().createInjectorAndDoEMFRegistration();
			ResourceSet rs = injector.getInstance(ResourceSet.class);
			Resource r1 = rs.getResource(URI.createFileURI(sourceFilePath), true);
			r1.load(null);
			EList<Greeting> allGreetings = ((Model)r1.getContents().get(0)).getGreetings();
			System.out.println(allGreetings.get(0));
			IclConstructor iclConstructor = new IclConstructor();
			artefactFromResource = iclConstructor.getArtefactFromResource(r1);
			
			System.out.println(Printer.INSTANCE.dumpArtefact(artefactFromResource));
			
			IclExpressionFactory f = IclExpressionFactory.INSTANCE;
			
			ArrayList<Expression> expressions = new ArrayList<Expression>();
			int greetingsSize = allGreetings.size();
			for( int i = 0; i < greetingsSize; i++) {
				Greeting greeting01 = allGreetings.get(i);
				for(int j = 0; j < greetingsSize; j++) {
					if(j <= i) continue;
					Greeting greeting02 = allGreetings.get(j);
					
					Property nameProp01 = artefactFromResource.searchElement(greeting01).getProperty("name");
					Property nameProp02 = artefactFromResource.searchElement(greeting02).getProperty("name");
					
					this.initializeVariable(nameProp01);
					this.initializeVariable(nameProp02);
					
					PropertyReferenceLiteral propertyReferenceLiteral01 = f.propRef(nameProp01);
					PropertyReferenceLiteral propertyReferenceLiteral02 = f.propRef(nameProp02);
					
					ComparisonExpression eq = f.eq(propertyReferenceLiteral01, propertyReferenceLiteral02);
					expressions.add(f.not(eq));
				}
				
			}
			
			SolverFactory<? extends SolutionEnvironment<?, ?, ?>, ? extends AbstractSolverFacade<?, ? extends SolutionEnvironment<?, ?, ?>>> factory = SolverFactory
					.createConstantAcceptingSolverFactory(Solver.CHOCO_V3);
			
			SolutionEnvironment<?, ?, ?> solutionEnvironment = factory
					.solveOnArtefactWithVariabilityFromExpressions(artefactFromResource, expressions, true);
			List<Solution> solutions = solutionEnvironment.getSolutions();
			System.out.println(Solution.dumpSolutionsToArrayNotation(solutions));
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void initializeVariable(Property p) {
		if (p.isVariable())
			throw new RuntimeException("Property " + p.toString()
					+ " has alrady been declared as variable.");
		p.initializeVariable();
		if (p.isReadOnly())
			p.getVariable().getDomain().addAll(p.getValues());
		else {
			if (EcorePackage.eINSTANCE.getEClass().isInstance(
					p.getFeature().getEType())) {
				@SuppressWarnings("unchecked")
				EList<Object> domain = (EList<Object>) ((EList<?>) getVariableDomain(p));
				p.getVariable().setDomain(domain);
			} else if (EcorePackage.eINSTANCE.getEEnum().isInstance(
					p.getFeature().getEType())) {
				EEnum enumDecl = (EEnum) p.getFeature().getEType();
				for (EEnumLiteral eEnumLiteral : enumDecl.getELiterals())
					p.getVariable().getDomain()
							.add(artefactFromResource.searchEnumLiteral(eEnumLiteral));
			} else if (EcorePackage.eINSTANCE.getEString().equals(p.getType())) {
				BasicEList<Object> domain = new BasicEList<Object>(artefactFromResource.getStringMap().values());
				p.getVariable().setDomain(domain);
			} else if (EcorePackage.eINSTANCE.getEBoolean().equals(p.getType())) {
				p.getVariable().getDomain().add(Boolean.TRUE);
				p.getVariable().getDomain().add(Boolean.FALSE);
			}
		}
	}
	
	private EList<Element> getVariableDomain(Property p) {
		EClass type = (EClass) p.getFeature().getEType();
		EList<Element> retVal = artefactFromResource.searchElements(type);
		return retVal;
	}
}

Hierbei müssen Sie die entsprechenden Abhängigkeiten auflösen, wobei Ihnen Eclipse behilflich ist.

Ausführen von SolveConstraints.java

  • Rechtsklick auf SolveConstraints.java im Project-Explorer Run As → Java Application

Interpretation des Ergebnisses

Wenn bis hierher alles glatt gelaufen ist, sollte in der Programmausgabe folgendes Ergebnis zu finden sein:

Found a total of 2 solutions:
new String[][][] {
{
},
{
	{"Greeting<2>.name", "['Ken']"},
	{"Greeting<3>.name", "['Ben']"}
}}

In den for-Schleifen der Methode solve werden Constraints erzeugt, die bewirken, dass die Namen in den Hello ...! Zeilen alle unterschiedlich sein sollen:

...
PropertyReferenceLiteral propertyReferenceLiteral01 = f.propRef(nameProp01);
PropertyReferenceLiteral propertyReferenceLiteral02 = f.propRef(nameProp02);
ComparisonExpression eq = f.eq(propertyReferenceLiteral01, propertyReferenceLiteral02);
expressions.add(f.not(eq));
...

Die so erzeugten Constraints werden nachfolgend einer Instanz des Choco-Solvers zum Ermitteln von Lösungen übergeben, :

SolutionEnvironment<?, ?, ?> solutionEnvironment = factory
      .solveOnArtefactWithVariabilityFromExpressions(artefactFromResource, expressions, true);
List<Solution> solutions = solutionEnvironment.getSolutions();
System.out.println(Solution.dumpSolutionsToArrayNotation(solutions));

Die zwei Ergebnisse sind nun dahingehend zu interpretieren, dass die Constraints dann erfüllt sind, wenn

  1. das Programm unverändert bleibt oder
  2. die beiden Zeilen vertauscht werden:
Hello Ken!
Hello Ben!