blob: f90e3b45ef0cca50bfd95dcc3581d4726272b6cd [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004-2008 Akos Horvath, Gergely Varro and Daniel Varro
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Akos Horvath, Gergely Varro - initial API and implementation
*******************************************************************************/
package org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal;
import org.eclipse.viatra2.gtasm.interpreter.exception.ViatraTransformationException;
import org.eclipse.viatra2.gtasm.patternmatcher.ExecutionMode;
import org.eclipse.viatra2.gtasm.patternmatcher.IMatching;
import org.eclipse.viatra2.gtasm.patternmatcher.ParameterMode;
import org.eclipse.viatra2.gtasm.patternmatcher.PatternCallSignature;
import org.eclipse.viatra2.gtasm.patternmatcher.Scope;
import org.eclipse.viatra2.gtasm.patternmatcher.exceptions.PatternMatcherCompileTimeException;
import org.eclipse.viatra2.gtasm.patternmatcher.exceptions.PatternMatcherRuntimeException;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.callgraph.PatternNode;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.rgg.MagicSet;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.rgg.RemoteGoal;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.term.ITermHandler;
import org.eclipse.viatra2.gtasm.patternmatcher.patterns.IPatternMatcher;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.enums.ContainmentMode;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.enums.ValueKind;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.gt.GTPattern;
import org.eclipse.viatra2.core.IEntity;
import org.eclipse.viatra2.core.IModelElement;
import org.eclipse.viatra2.core.IModelManager;
import org.eclipse.viatra2.logger.Logger;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
/**
* PatternMatcher is the (executable) run-time equivalent
* of a GTPattern.
*
* The whole pattern matching engine is not represented as a single object, but
* the container ASM interpreter module should consist of a set of
* PatternMatcher objects.
*
* PatternMatcher objects (including all its subordinate data structures)
* are generated by PatternBuilders.
*
* @author Gergely Varro, Akos Horvath
*/
public class PatternMatcher implements IPatternMatcher {
protected Logger logger;
protected IModelManager manager;
protected ITermHandler termHandler;
protected PatternNode root;
protected Map<String,Map<String,RemoteGoal>> rggMapping;
public PatternMatcher( Logger logger, IModelManager manager, ITermHandler termHandler)
throws PatternMatcherCompileTimeException {
this.logger = logger;
this.manager = manager;
this.termHandler = termHandler;
}
public PatternMatcher(GTPattern pattern, Logger logger, IModelManager manager, ITermHandler termHandler)
throws PatternMatcherCompileTimeException {
this.logger = logger;
this.manager = manager;
this.termHandler = termHandler;
this.root = new PatternNode(this, pattern);
this.rggMapping = new HashMap<String, Map<String,RemoteGoal>>();
}
public boolean match(Object[] inputMapping) throws ViatraTransformationException {
PatternCallSignature[] signature =
new PatternCallSignature[inputMapping.length];
for (int i = 0; i < inputMapping.length; i++) {
signature[i] = new PatternCallSignature();
signature[i].setExecutionMode(ExecutionMode.SINGLE_RESULT);
if (inputMapping[i] == null || inputMapping[i].equals(ValueKind.UNDEF_LITERAL)) {
signature[i].setParameterMode(ParameterMode.OUTPUT);
} else {
signature[i].setParameterMode(ParameterMode.INPUT);
}
Scope scope = new Scope(Scope.DEFAULT_MODE, manager.getRoot());
signature[i].setParameterScope(scope);
}
return (match(inputMapping, signature) != null);
}
public IMatching match(Object[] inputMapping,
PatternCallSignature[] signature) throws ViatraTransformationException {
for (int i = 0; i < signature.length; i++) {
if (signature[i].getExecutionMode() == ExecutionMode.MULTIPLE_RESULTS) {
String[] context = {root.getPattern().getName()};
throw new PatternMatcherRuntimeException(
PatternMatcherErrorStrings.INTERNAL_PATTERNCALL_CHOOSE_WITH_MULTIPLERESULT
,context
,root.getPattern());
//logger.warning("The method match(Object[], PatternCallSignature[] has been invoked in MULTIPLE_RESULTS execution mode.");
//return null;
}
}
Integer[] quantificationOrder = new Integer[signature.length];
for (int i = 0; i < quantificationOrder.length; i++) {
quantificationOrder[i] = i;
}
Collection<IMatching> solutions =
matchAll(inputMapping, signature, quantificationOrder);
for (IMatching matching : solutions) {
return (MatchingFrame) matching;
}
return null;
}
/* public MatchingFrame matchFuture(Object[] inputMapping,
PatternCallSignature[] signature) {
try {
// Initialization (IN/BELOW constraint processing)
final Boolean[] adornment = new Boolean[signature.length];
Vector<Object> vec = new Vector<Object>();
Vector<Integer> freeVariables = new Vector<Integer>();
int strongestConstraint = 0;
int smallestWeight = 0;
Scope s = signature[0].getParameterScope();
if (s.getContainmentMode() == ContainmentMode.IN) {
smallestWeight = ((IEntity) s.getParent()).getContents().size();
} else if (s.getContainmentMode() == ContainmentMode.BELOW) {
smallestWeight = ((IEntity) s.getParent()).getAllComponents().size();
}
for (int i = 0; i < signature.length; i++) {
s = signature[i].getParameterScope();
if (signature[i].getParameterMode() == ParameterMode.INPUT) {
adornment[i] = true;
vec.add(inputMapping[i]);
if (s.getContainmentMode() == ContainmentMode.IN &&
!((IEntity) s.getParent()).getContents().contains(inputMapping[i]) ||
s.getContainmentMode() == ContainmentMode.BELOW &&
!((IEntity) s.getParent()).getAllComponents().contains(inputMapping[i])) {
logger.warning(FAILING_CONTAINMENT_CONSTRAINT);
return null;
}
} else {
adornment[i] = false;
freeVariables.add(i);
}
if (s.getContainmentMode() == ContainmentMode.IN) {
if (smallestWeight > ((IEntity) s.getParent()).getContents().size()) {
smallestWeight = ((IEntity) s.getParent()).getContents().size();
strongestConstraint = i;
}
} else if (s.getContainmentMode() == ContainmentMode.BELOW) {
if (smallestWeight > ((IEntity) s.getParent()).getAllComponents().size()) {
smallestWeight = ((IEntity) s.getParent()).getAllComponents().size();
strongestConstraint = i;
}
}
}
adornment[strongestConstraint] = (freeVariables.size() == signature.length
? true : adornment[strongestConstraint]);
// Preparing rule/goal graphs
Map<String, RemoteGoal> rggRoots = new HashMap<String, RemoteGoal>();
RemoteGoal main = root.buildRuleGoalGraph(adornment,rggRoots);
// Magic set initialization
if (freeVariables.size() == signature.length) {
s = signature[strongestConstraint].getParameterScope();
Iterator<IModelElement> i = (s.getContainmentMode() == ContainmentMode.IN
? ((IEntity) s.getParent()).getContents().iterator()
: ((IEntity) s.getParent()).getAllComponents().iterator());
for (; i.hasNext();) {
Object[] input = new Object[1];
input[0] = i.next();
main.getMagicSet().addArray(new MatchingKey(input));
}
} else {
Object[] input = new Object[vec.size()];
vec.toArray(input);
main.getMagicSet().addArray(new MatchingKey(input));
}
// Initial rule/goal graph synchronization
boolean isModified = false;
for (RemoteGoal goal : rggRoots.values()) {
isModified = isModified || goal.synchronize();
}
// Pattern matching
/*
while (isModified) {
isModified = false;
// Calculation phase
for (MatchingFrame frame = null; (frame = main.match(signature, freeVariables)) != null; ) {
return frame;
}
for (RemoteGoal goal : rggRoots.values()) {
if (!goal.equals(main)) {
goal.matchAll();
}
}
// Synchronization phase
for (RemoteGoal goal : rggRoots.values()) {
isModified = (goal.synchronize() ? true : isModified);
}
}
} catch (PatternMatcherRuntimeException e) {}
return null;
}*/
public Collection<IMatching> matchAll(Object[] inputMapping,
PatternCallSignature[] signature,
Integer[] quantificationOrder) throws ViatraTransformationException {
try {
// Key generator preparation based on the variables with forall quantifier
if (signature.length != quantificationOrder.length)
{
String[] context = {root.getPattern().getName()};
throw new PatternMatcherRuntimeException(
PatternMatcherErrorStrings.INTERNAL_QUANTIFICATION_AND_SIGNATURES_PARAMETER_MISMATCH
,context
,root.getPattern());
}
int multipleUpperBound = 0;
Vector<Integer> vector = new Vector<Integer>();
for (int i = 0; i < quantificationOrder.length; i++) {
Integer index = quantificationOrder[i];
if (index < signature.length) {
if (signature[index].getExecutionMode() == ExecutionMode.MULTIPLE_RESULTS) {
if (i <= multipleUpperBound) {
vector.add(index);
multipleUpperBound++;
} else {
String[] context = {root.getPattern().getName()};
throw new PatternMatcherRuntimeException(
PatternMatcherErrorStrings.INTERNAL_QUANTIFICATION_ORDER
,context
,root.getPattern());
}
}
} else {
String[] context = {root.getPattern().getName()};
throw new PatternMatcherRuntimeException(
PatternMatcherErrorStrings.INTERNAL_QUANTIFICATION_ORDER
,context
,root.getPattern());
}
}
final Integer[] keys = new Integer[vector.size()];
vector.toArray(keys);
IKeyGenerator<MatchingKey, MatchingFrame> resultKeyGenerator =
new IKeyGenerator<MatchingKey, MatchingFrame>() {
public MatchingKey calculateKey(MatchingFrame value) {
Object[] matchingKey = new Object[keys.length];
for (int i = 0; i < keys.length; i++) {
matchingKey[i] = value.getValue(keys[i]);
}
return new MatchingKey(matchingKey);
}
public int size() {
return keys.length;
}
};
// Matching table initalization
MatchingTable result = new MatchingTable();
if (signature.length == 0) {
return result;
}
// Initialization (IN/BELOW constraint processing)
final Boolean[] adornment = new Boolean[signature.length];
Vector<Object> vec = new Vector<Object>();
for (int i = 0; i < signature.length; i++) {
if (signature[i].getParameterMode() == ParameterMode.INPUT) {
adornment[i] = true;
vec.add(inputMapping[i]);
} else {
adornment[i] = false;
}
}
int strongestConstraint = 0;
if (vec.size() == 0) {
int largestDistance = 0;
boolean hasInConstraint = false;
for (int i = 0; i < signature.length; i++) {
Scope s = signature[i].getParameterScope();
int distance = 0;
IEntity parent = (IEntity) s.getParent();
for (distance = 0; !parent.equals(manager.getRoot()); distance++) {
parent = parent.getParent();
}
if (s.getContainmentMode() == ContainmentMode.IN) {
if (hasInConstraint && distance > largestDistance) {
largestDistance = distance;
strongestConstraint = i;
} else if (!hasInConstraint) {
hasInConstraint = true;
largestDistance = distance;
strongestConstraint = i;
}
} else if (s.getContainmentMode() == ContainmentMode.BELOW) {
if (!hasInConstraint && distance > largestDistance) {
largestDistance = distance;
strongestConstraint = i;
}
}
}
adornment[strongestConstraint] = true;
}
// Preparing rule/goal graphs
String adornmentString = Arrays.deepToString(adornment);
Map<String, RemoteGoal> rggRoots = rggMapping.get(adornmentString);
if (rggRoots == null) {
rggRoots = new HashMap<String, RemoteGoal>();
root.buildRuleGoalGraph(adornment,rggRoots);
rggMapping.put(adornmentString, rggRoots);
}
RemoteGoal main = rggRoots.get(RemoteGoal.generateID(root, adornment));
// Magic set initialization
if (vec.size() == 0) {
MagicSet ms = main.getMagicSet();
Scope s = signature[strongestConstraint].getParameterScope();
IEntity parent = (IEntity) s.getParent();
Iterator<IModelElement> i = (s.getContainmentMode() == ContainmentMode.IN
? parent.getElementsInNamespace().iterator()
: parent.getAllElementsInNamespace().iterator());
for (; i.hasNext();) {
Object[] input = new Object[1];
input[0] = i.next();
ms.addArray(new MatchingKey(input));
}
} else {
Object[] input = new Object[vec.size()];
vec.toArray(input);
main.getMagicSet().addArray(new MatchingKey(input));
}
// Initial rule/goal graph synchronization
boolean isModified = false;
for (RemoteGoal goal : rggRoots.values()) {
isModified = (goal.synchronize() ? true : isModified);
}
// Pattern matching
while (isModified) {
isModified = false;
// Calculation phase
for (RemoteGoal goal : rggRoots.values()) {
goal.matchAll();
}
// Synchronization phase
for (RemoteGoal goal : rggRoots.values()) {
isModified = (goal.synchronize() ? true : isModified);
}
}
//for debug purposes
//System.out.println("**********Final DEBUG*********");
//for (RemoteGoal goal : rggRoots.values()) {
// goal.debug();
//}
// Postprocessing (filling the matching table)
for (MatchingFrame frame : main) {
boolean constraintsFulfilled = true;
// Checking IN/BELOW constraints on the result
for (int i = 0; constraintsFulfilled && i < signature.length; i++) {
if (signature[i].getParameterMode() == ParameterMode.OUTPUT) {
Scope s = signature[i].getParameterScope();
IEntity container = (IEntity) s.getParent();
Object obj = frame.getValue(i);
if (obj instanceof IModelElement) {
IModelElement me = (IModelElement) obj;
if (s.getContainmentMode() == ContainmentMode.IN) {
constraintsFulfilled = me.getNamespace().compareTo(container) == 0;
} else if (s.getContainmentMode() == ContainmentMode.BELOW) {
constraintsFulfilled = me.isBelowNamespace(container);
}
} else {
// TODO gervarro: what happens, if a formal parameter is a String, integer and it has a container constraint?
}
}
}
if (constraintsFulfilled) {
// If all constraints are fulfilled, add the frame to the matching table
result.put(resultKeyGenerator.calculateKey(frame), frame);
}
}
// Clean up for all runtime data structures (except for the result)
for (RemoteGoal rg : rggRoots.values()) {
rg.init();
}
return result;
} catch (PatternMatcherRuntimeException e) {
throw e.addNewStackElement(root.getPattern());
}
}
public IMatching matchRandomly(Object[] inputMapping,
PatternCallSignature[] signature) throws ViatraTransformationException {
Integer[] quantificationOrder = new Integer[inputMapping.length];
for (int i=0; i<quantificationOrder.length; i++) quantificationOrder[i] = i;
Collection<IMatching> allMatches = matchAll(inputMapping, signature, quantificationOrder);
if (allMatches == null || allMatches.isEmpty()) return null;
else return (IMatching) allMatches.toArray()[(int)(Math.random() * allMatches.size())];
// TODO suboptimal
}
/**
*
* @return the logger
*/
public Logger getLogger() {
return logger;
}
/**
* @return the termHandler
*/
public ITermHandler getTermHandler() {
return termHandler;
}
public IModelManager getModelManager() {
return manager;
}
}