blob: b2c87a5a712348a1598f1632d6fdf5d986b8a724 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004-2009 Gabor Bergmann 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:
* Gabor Bergmann - initial API and implementation
*******************************************************************************/
package org.eclipse.viatra2.gtasm.patternmatcher.incremental;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import org.eclipse.viatra2.core.IEntity;
import org.eclipse.viatra2.core.IModelElement;
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.incremental.rete.matcher.RetePatternMatcher;
import org.eclipse.viatra2.gtasm.patternmatcher.incremental.rete.tuple.Tuple;
import org.eclipse.viatra2.gtasm.patternmatcher.incremental.rete.tuple.TupleMask;
import org.eclipse.viatra2.gtasm.patternmatcher.patterns.IPatternMatcher;
/**
* @author Bergmann Gábor
*
*/
public class ReteGTASMPatternMatcher implements IPatternMatcher {
RetePatternMatcher matcher;
Random random = null;
/**
* @param matcher the GTASM-ignorant RetePatternMatcher to wrap
*/
public ReteGTASMPatternMatcher(RetePatternMatcher matcher) {
super();
this.matcher = matcher;
}
/**
* @param inputMapping quantification indicated by org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.enums.ValueKind.UNDEF_LITERAL
*/
public boolean match(Object[] inputMapping) {
boolean[] fixed = new boolean[inputMapping.length];
for (int i = 0; i < inputMapping.length; ++i) {
fixed[i] = !org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.enums.ValueKind.UNDEF_LITERAL
.equals(inputMapping[i]);
}
return matcher.count(inputMapping, fixed) != 0;
}
public IMatching match(Object[] inputMapping, PatternCallSignature[] signature) {
boolean ignoreScope = isScopeIgnorable(signature);
if (!ignoreScope) // there needs to be scope checking, which is deadlock-prone to do in a matchfetcher!
{
ArrayList<IMatching> result = matchAll(inputMapping, signature, null);
return result.isEmpty() ? null : result.iterator().next();
} else
{
boolean[] fixed = new boolean[inputMapping.length];
for (int i = 0; i < inputMapping.length; ++i) {
fixed[i] = (signature[i].getParameterMode() == ParameterMode.INPUT);
}
// retrieving the projection
Tuple match = matcher.matchOne(inputMapping, fixed);
return match==null? null : new ReteMatching(match, matcher.getPosMapping());
}
}
public ArrayList<IMatching> matchAll(Object[] inputMapping, PatternCallSignature[] signature, Integer[] quantificationOrder) {
// analyzing the execution mode (quantification, bound variables)
boolean[] fixed = new boolean[inputMapping.length];
boolean[] quantified = new boolean[inputMapping.length];
boolean hasExistential = false; // there are variables neither universally quantified not bound
boolean hasUniversal = false;
for (int i = 0; i < inputMapping.length; ++i) {
fixed[i] = (signature[i].getParameterMode() == ParameterMode.INPUT);
quantified[i] = (signature[i].getParameterMode() == ParameterMode.OUTPUT
&& signature[i].getExecutionMode() == ExecutionMode.MULTIPLE_RESULTS);
if (!fixed[i]) {
hasUniversal = hasUniversal || quantified[i];
hasExistential = hasExistential || !quantified[i];
}
}
boolean ignoreScope = isScopeIgnorable(signature);
// default to single matching
if (!hasUniversal && ignoreScope) {
Tuple match = matcher.matchOne(inputMapping, fixed);
return match==null? new ArrayList<IMatching>() :
new ArrayList<IMatching>(Collections.singleton(new ReteMatching(match, matcher.getPosMapping())));
}
// retrieving the projection
Collection<Tuple> unscopedMatches = matcher.matchAll(inputMapping, fixed);
// processing matches, checking scopes
if (unscopedMatches == null) return new ArrayList<IMatching>();
ArrayList<IMatching> matchings = new ArrayList<IMatching>(unscopedMatches.size());
TupleMask quantifiedMask = null;
Set<Tuple> quantifiedProjections = null;
if (hasExistential) {
quantifiedMask = new TupleMask(quantified);
quantifiedProjections = new LinkedHashSet<Tuple>();
}
for (Tuple ps : /* productionNode */unscopedMatches) {
//Tuple ps = boundary.unwrapTuple(um);
Tuple quantifiedPart = null;
if (hasExistential) {
quantifiedPart = quantifiedMask.transform(ps);
if (quantifiedProjections.contains(quantifiedPart)) continue; // not the first occurrence
}
boolean ok = true;
if (!ignoreScope) for (int k = 0; (k < ps.getSize()) && ok; k++) {
if (signature[k].getParameterMode() == ParameterMode.INPUT) {
// ok = ok && (inputMapping[k]==ps.elements[k]);
// should now be true
} else // ParameterMode.OUTPUT
{
IEntity scopeParent = (IEntity) signature[k]
.getParameterScope().getParent();
Integer containmentMode = signature[k]
.getParameterScope().getContainmentMode();
if (containmentMode == Scope.BELOW) {
// ok = ok &&
// scopeParent.getAllComponents().contains
// (ps.elements[k]);
ok = ok
&& ((IModelElement) ps.get(k))
.isBelowNamespace(scopeParent);
} else /* case Scope.IN: */
{
ok = ok
&& scopeParent.equals(((IModelElement) ps
.get(k)).getNamespace());
// note: getNamespace returns null instead of the
// (imaginary) modelspace root entity for top level
// elements;
// this is not a problem here as Scope.IN implies
// scopeParent != root.
}
}
}
if (ok) {
if (hasExistential) quantifiedProjections.add(quantifiedPart);
matchings.add(new ReteMatching(ps, matcher.getPosMapping()));
}
}
return matchings;
}
public IMatching matchRandomly(Object[] inputMapping, PatternCallSignature[] signature) {
if(random == null){
random = new Random();
}
// all unbounded parameters are set to return multiple results
for(int j = 0; j < signature.length; j++)
{
// output parameters are in the front of the array
if(signature[j].getParameterMode() == ParameterMode.OUTPUT)
signature[j].setExecutionMode(ExecutionMode.MULTIPLE_RESULTS);
}
ArrayList<IMatching> allMatches = matchAll(inputMapping, signature, null);
if (allMatches == null || allMatches.isEmpty()) return null;
else return allMatches.get(random.nextInt(allMatches.size()));
}
boolean isScopeIgnorable(PatternCallSignature[] signature) {
for (PatternCallSignature sig : signature) {
if (sig.getParameterMode() == ParameterMode.OUTPUT) {
Scope scope = sig.getParameterScope();
if (scope.getContainmentMode() != Scope.BELOW || scope.getParent() != Scope.DEFAULT_PARENT)
return false;
}
}
return true;
}
/**
* Builds a mapping between parameter indices and scopes.
* @param signatures PatternCallSignature array, as present in an IPatternMatcher query
* @return a scope map suitable for ReteEngine.accessMatcherScoped()
*/
public static Map<Integer, Scope> buildAdditionalScopeMap(PatternCallSignature[] signatures) {
Map<Integer, Scope> scopeMap = new HashMap<Integer, Scope>();
for (int i=0; i<signatures.length; ++i) {
PatternCallSignature signature = signatures[i];
if (signature.getParameterMode().equals(ParameterMode.OUTPUT) &&
! signature.getParameterScope().getParent().equals(Scope.DEFAULT_PARENT))
{
scopeMap.put(i, signature.getParameterScope());
}
}
return scopeMap;
}
}