| /******************************************************************************* |
| * 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.algorithms;
|
|
|
| import java.util.Vector;
|
|
|
| import org.eclipse.viatra2.core.IModelElement;
|
| import org.eclipse.viatra2.core.IModelManager;
|
| 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.EdgeType; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.MatchingFrame; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.PatternMatcherErrorStrings; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.AllEntitiesOperation; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.AllRelationsOperation; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.BoundToBoundCheckOperation; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.BoundToConstantCheckOperation; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.ConstantToBoundCheckOperation; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.ConstantToConstantCheckOperation; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.CopyValueOperation; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.ExtendBoundNodeOperation; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.ExtendConstantNodeOperation; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.IsEntityorRelationCheckOperation; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.PatternCallOperation; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.SearchPlanOperation; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.VariableAssignmentCheckOperation; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.ConstantSearchGraphNode; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.PatternCallSearchGraphNode; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.SearchGraphEdge; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.SearchGraphNode; |
| import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.VariableSearchGraphNode; |
|
|
|
|
| /**Generates the operations base on the search plan.
|
| * @author Akos Horvath
|
| *
|
| */
|
| public class VPMPatternOperationGenerator {
|
|
|
| public static Vector<SearchPlanOperation> evaluateVPMOperationPlan(SearchGraphNode[] searchPlan, |
| MatchingFrame template, |
| IModelManager manager) throws PatternMatcherRuntimeException{
|
| Vector<SearchPlanOperation> searchOperations = new Vector<SearchPlanOperation>();
|
| SearchPlanOperation operation = null;
|
|
|
| for(SearchGraphNode node : searchPlan){
|
| if(node instanceof ConstantSearchGraphNode)
|
| node.setChecked(true);
|
|
|
| //tree edge evaluation
|
| if(node.getTreeEdge() != null && (!node.isChecked()))
|
| {operation = VPMPatternOperationGenerator.treeEdgeSearchOperation(node.getTreeEdge(), template,manager);
|
| if(operation!= null)
|
| { //operation.debug();
|
| searchOperations.add(operation);
|
| }
|
| }
|
| //check operation evaluation
|
| for(SearchGraphEdge edge : node.getSources()){
|
| if(edge.getSourceNode().isChecked() && edge.getTargetNode().isChecked())
|
| {operation = VPMPatternOperationGenerator.evaluateEdgeSearchPlanOperation(edge, template,manager);
|
| if(operation != null)
|
| {//operation.debug();
|
| searchOperations.add(operation);
|
| }
|
| }
|
| }
|
| }
|
| // have to check if there are any edges left
|
| for(SearchGraphNode node : searchPlan)
|
| for(SearchGraphEdge edge : node.getSources())
|
| if(!edge.isChecked())
|
| {
|
| //oldVersion operation = checkSearchOperation(edge, template);
|
| operation= VPMPatternOperationGenerator.evaluateEdgeSearchPlanOperation(edge,template,manager);
|
| //operation.debug();
|
| if(operation != null)
|
| searchOperations.add(operation);
|
| //searchOperations.add(checkSearchOperation(edge));
|
| }
|
|
|
|
|
| return searchOperations;
|
| }
|
|
|
|
|
|
|
| /** Returns the corresponding search plan operation equivalent to the input search graph edge
|
| * @param edge The edge to process
|
| * @param template the Matching frame with the bound variables
|
| * @param manager Model manager of the actual model space
|
| * @return the generated operation
|
| */
|
| public static SearchPlanOperation evaluateEdgeSearchPlanOperation( |
| SearchGraphEdge edge, |
| MatchingFrame template, |
| IModelManager manager) throws PatternMatcherRuntimeException
|
| {SearchPlanOperation operation = null;
|
| if(edge.isChecked()) return null;
|
|
|
| //checking the type of the edge, for debugging
|
| if(edge.getVPMEdgeType() == EdgeType.BELOW
|
| || edge.getVPMEdgeType() == EdgeType.IN
|
| || edge.getVPMEdgeType() == EdgeType.INSTANCEOF
|
| || edge.getVPMEdgeType() == EdgeType.SOURCE
|
| || edge.getVPMEdgeType() == EdgeType.TARGET
|
| || edge.getVPMEdgeType() == EdgeType.SUPERTYPEOF
|
| || edge.getVPMEdgeType() == EdgeType.PATTERN_CALL_PARAMETER
|
| || edge.getVPMEdgeType() == EdgeType.VARIABLE_ASSIGNMENT) //TODO: new edge types has to be added to this check
|
| {
|
| operation = checkSearchOperation(edge, template,manager);
|
| }
|
| else
|
| { |
| String[] context = {edge.getVPMEdgeType().toString(), edge.getName()}; |
| throw new PatternMatcherRuntimeException(PatternMatcherErrorStrings.INTERNAL_EDGETYPE_NOT_SUPPORTED |
| ,context |
| ,template.getPattern().getGTASMRepresentation(edge)); |
| }
|
| return operation;
|
| }
|
|
|
|
|
| /** Returns the corresponding search plan operation equivalent of the input search graph edge (CHECK OPERATIONS)
|
| * @param edge The edge whose operation is generated
|
| * @param template template the Matching frame with the bound variables
|
| * @param manager model manager
|
| * @return the operation itself
|
| */
|
| private static SearchPlanOperation checkSearchOperation( |
| SearchGraphEdge edge, |
| MatchingFrame template, |
| IModelManager manager)
|
| throws PatternMatcherRuntimeException{
|
| SearchPlanOperation operation = null;
|
|
|
| //some of the check operations have to be skipped as they does not represent any additional constraints
|
| if( edge.getSourceNode() instanceof VariableSearchGraphNode
|
| && edge.getVPMEdgeType().equals(EdgeType.BELOW) //default Scope value
|
| && (template.getValue(((VariableSearchGraphNode)edge.getSourceNode()).getId()) != null) //default Scope value
|
| && ((IModelElement)template.getValue(((VariableSearchGraphNode)edge.getSourceNode()).getId())).equals(manager.getRoot()))
|
| {
|
| edge.setChecked(true);
|
| return null;
|
| }
|
|
|
| // in case the source is an entity or a relation a special check operation is required
|
| if( edge.getSourceNode() instanceof ConstantSearchGraphNode
|
| && edge.getVPMEdgeType().equals(EdgeType.INSTANCEOF)
|
| && ( ((ConstantSearchGraphNode)edge.getSourceNode()).getElement().equals(ISearchGraph.VPM_RELATION_FQN)
|
| || ((ConstantSearchGraphNode)edge.getSourceNode()).getElement().equals(ISearchGraph.VPM_ENTITY_FQN) ))
|
| {
|
| //TODO: Can an entity have an instance relation to an entity? |
| //If yes, then can be tricked out as an entity can have an instance relation to a relation and it is not checked
|
| operation = new IsEntityorRelationCheckOperation(((VariableSearchGraphNode)edge.getTargetNode()).getId()
|
| ,edge,
|
| ((ConstantSearchGraphNode)edge.getSourceNode()).getElement());
|
| edge.setChecked(true);
|
| return operation;
|
| }
|
| /************complex operations******************/
|
| //pattern call operation
|
| if(edge.getTargetNode() instanceof PatternCallSearchGraphNode)
|
| { |
| String[] context = {edge.getTargetNode().getName()};
|
| throw new PatternMatcherRuntimeException( |
| PatternMatcherErrorStrings.INTERNAL_PATTERNCALLNODE_EXCEPTION |
| ,context |
| ,template.getPattern().getGTASMRepresentation(edge));
|
| }
|
|
|
|
|
| /**************simple operations*******************/
|
| if(edge.getVPMEdgeType().equals(EdgeType.VARIABLE_ASSIGNMENT))
|
| operation = new VariableAssignmentCheckOperation(((VariableSearchGraphNode)edge.getSourceNode()).getId(),
|
| ((VariableSearchGraphNode)edge.getTargetNode()).getId() |
| ,edge); //TODO: does the direction counts? (inverse or not)
|
| else
|
| if(edge.getSourceNode() instanceof VariableSearchGraphNode && edge.getTargetNode() instanceof VariableSearchGraphNode)
|
| operation = new BoundToBoundCheckOperation(((VariableSearchGraphNode)edge.getSourceNode()).getId()
|
| ,((VariableSearchGraphNode)edge.getTargetNode()).getId()
|
| ,edge);
|
| else
|
| if(edge.getSourceNode() instanceof VariableSearchGraphNode && edge.getTargetNode() instanceof ConstantSearchGraphNode )
|
| operation = new BoundToConstantCheckOperation(((VariableSearchGraphNode)edge.getSourceNode()).getId()
|
| ,manager.getElementByName(((ConstantSearchGraphNode)edge.getTargetNode()).getElement())
|
| ,edge);
|
| else
|
| if(edge.getSourceNode() instanceof ConstantSearchGraphNode && edge.getTargetNode() instanceof VariableSearchGraphNode)
|
| operation = new ConstantToBoundCheckOperation(manager.getElementByName(((ConstantSearchGraphNode)edge.getSourceNode()).getElement())
|
| ,((VariableSearchGraphNode)edge.getTargetNode()).getId()
|
| ,edge);
|
| else
|
| if(edge.getSourceNode() instanceof ConstantSearchGraphNode && edge.getTargetNode() instanceof ConstantSearchGraphNode)
|
| operation = new ConstantToConstantCheckOperation(manager.getElementByName(((ConstantSearchGraphNode)edge.getSourceNode()).getElement())
|
| ,manager.getElementByName(((ConstantSearchGraphNode)edge.getTargetNode()).getElement())
|
| ,edge);
|
|
|
| if(operation != null)
|
| edge.setChecked(true);
|
|
|
| return operation;
|
|
|
| }
|
|
|
| private static int getPatternCallParameterId(Integer id, |
| PatternCallSearchGraphNode callNode, MatchingFrame frame |
| ) throws PatternMatcherRuntimeException {
|
| Integer[] inputParameterMapping = callNode.getInputParameterMapping(); |
| |
| for(int i =0; i< inputParameterMapping.length; i++)
|
| if(id == inputParameterMapping[i])
|
| return i;
|
| |
| String[] context = {callNode.getName()};
|
| throw new PatternMatcherRuntimeException( |
| PatternMatcherErrorStrings.INTERNAL_PATTERNCALLNODE_WRONGPARAMETER_ORDER |
| ,context |
| ,frame.getPattern().getGTASMRepresentation(callNode));
|
| }
|
|
|
| /** Returns the corresponding search plan operation equivalent of the input search graph TREE edge (EXTEND OPERATIONS)
|
| * @param edge
|
| * @param Matchingframe containing the bound variables
|
| * @param manager model manager
|
| * @return
|
| */
|
| public static SearchPlanOperation treeEdgeSearchOperation(SearchGraphEdge edge, MatchingFrame template, IModelManager manager) throws PatternMatcherRuntimeException{
|
| SearchPlanOperation operation = null;
|
| if(edge.getSourceNode().isChecked() && edge.getTargetNode().isChecked())
|
| //the source and the target are already checked, simple checks the edge
|
| operation = checkSearchOperation(edge, template,manager);
|
| else//not a check type operation
|
|
|
| /**********complex operations**********/
|
| if(edge.getVPMEdgeType().equals(EdgeType.PATTERN_CALL_PARAMETER) |
| || edge.getVPMEdgeType().equals(EdgeType.PATTERN_CALL_STORAGE))
|
| {
|
| if(edge.isSource()) //the edge is the tree edge of the pattern call node
|
| {
|
| PatternCallSearchGraphNode callNode = (PatternCallSearchGraphNode) edge.getTargetNode();
|
| Boolean[] boundParameters = new Boolean[callNode.getPatternNode().getPattern().getSymParameters().size()];
|
|
|
| for (SearchGraphEdge callEdge:callNode.getSources()) |
| {
|
| //[DEBUG] error in the algorithm, one edge of the PatternCall node is already checked
|
| //if(!callEdge.isChecked())
|
| // System.out.println("[ERROR] One edge of a PatternCallNode is already traversed before the PatternNode was traversed");
|
|
|
| //if it is a bound input parameter
|
| if(callEdge.getVPMEdgeType().equals(EdgeType.PATTERN_CALL_PARAMETER)) |
| { if(callEdge.getSourceNode().isChecked())
|
| {
|
| boundParameters[getPatternCallParameterId(((VariableSearchGraphNode)callEdge.getSourceNode()).getId()
|
| ,callNode,template)] = true;
|
| }
|
| else//the pattern call will bound the variable
|
| { if(callEdge.getSourceNode().getTreeEdge().getSourceNode().equals(callNode))
|
| {
|
| boundParameters[getPatternCallParameterId(((VariableSearchGraphNode)callEdge.getSourceNode()).getId()
|
| ,callNode,template)] = false;
|
| callEdge.getSourceNode().setChecked(true);
|
| }
|
| else//Error the recursive call is not the tree edge for an unbound parameter
|
| { |
| String[] context = {callEdge.getSourceNode().getName(),callNode.getName()};
|
| throw new PatternMatcherRuntimeException( |
| PatternMatcherErrorStrings.INTERNAL_PATTERNCALLNODE_EDGE_EXCEPTION |
| ,context
|
| ,template.getPattern().getGTASMRepresentation(callNode));
|
| }
|
| } |
| } |
| //else // it is an incrementally matched pattern call -> not part of the invocation context |
| |
| callEdge.setChecked(true);
|
| }
|
| return //PatternCallOperation patternOperation =
|
| new PatternCallOperation(callNode.getPatternNode()
|
| ,callNode.getInputParameterMapping(),boundParameters);
|
|
|
| }
|
| else//the edge is an outgoing edge from a pattern call node
|
| {
|
| //edge.getTargetNode().setChecked(true);
|
| PatternCallSearchGraphNode callNode = (PatternCallSearchGraphNode) edge.getSourceNode(); |
| String[] context = {edge.getName(),callNode.getName()}; |
| throw new PatternMatcherRuntimeException( |
| PatternMatcherErrorStrings.INTERNAL_PATTERNCALLNODE_EDGE_TRAVERSAL_EXCEPTION |
| ,context |
| ,template.getPattern().getGTASMRepresentation(callNode)); |
| }
|
| }
|
| /**************simple operations ******************/
|
| else
|
| if(edge.getSourceNode().isChecked())
|
| {
|
| //simple operation
|
| if(edge.getVPMEdgeType().equals(EdgeType.VARIABLE_ASSIGNMENT))
|
| {operation = new CopyValueOperation(((VariableSearchGraphNode)edge.getSourceNode()).getId()
|
| ,((VariableSearchGraphNode)edge.getTargetNode()).getId() |
| ,edge);
|
| }
|
| else
|
| if(edge.getSourceNode() instanceof ConstantSearchGraphNode &&
|
| ((ConstantSearchGraphNode)edge.getSourceNode()).getElement().equals(ISearchGraph.VPM_ENTITY_FQN))
|
| {
|
| operation = new AllEntitiesOperation(((VariableSearchGraphNode)edge.getTargetNode()).getId()
|
| ,edge, manager);
|
| }
|
| else
|
| if(edge.getSourceNode() instanceof ConstantSearchGraphNode &&
|
| ((ConstantSearchGraphNode)edge.getSourceNode()).getElement().equals(ISearchGraph.VPM_RELATION_FQN))
|
| {
|
| operation = new AllRelationsOperation(((VariableSearchGraphNode)edge.getTargetNode()).getId()
|
| ,edge, manager);
|
| }
|
| else
|
| if(edge.getSourceNode() instanceof VariableSearchGraphNode && edge.getTargetNode() instanceof VariableSearchGraphNode)
|
| {operation = new ExtendBoundNodeOperation(((VariableSearchGraphNode)edge.getSourceNode()).getId()
|
| ,((VariableSearchGraphNode)edge.getTargetNode()).getId()
|
| ,edge);
|
| }
|
| else
|
| if(edge.getSourceNode() instanceof ConstantSearchGraphNode && edge.getTargetNode() instanceof VariableSearchGraphNode)
|
| {operation = new ExtendConstantNodeOperation(manager.getElementByName(((ConstantSearchGraphNode)edge.getSourceNode()).getElement())
|
| ,((VariableSearchGraphNode)edge.getTargetNode()).getId()
|
| ,edge);
|
| }
|
| }
|
| else
|
| if(edge.getTargetNode().isChecked())
|
| {
|
| //simple operation
|
| if(edge.getVPMEdgeType().equals(EdgeType.VARIABLE_ASSIGNMENT))
|
| {operation = new CopyValueOperation(((VariableSearchGraphNode)edge.getTargetNode()).getId()
|
| ,((VariableSearchGraphNode)edge.getSourceNode()).getId() |
| ,edge);
|
| }
|
| if(edge.getTargetNode() instanceof ConstantSearchGraphNode &&
|
| ((ConstantSearchGraphNode)edge.getTargetNode()).getElement().equals(ISearchGraph.VPM_ENTITY_FQN))
|
| {
|
| operation = new AllEntitiesOperation(((VariableSearchGraphNode)edge.getSourceNode()).getId()
|
| ,edge, manager);
|
| }
|
| else
|
| if(edge.getTargetNode() instanceof ConstantSearchGraphNode &&
|
| ((ConstantSearchGraphNode)edge.getTargetNode()).getElement().equals(ISearchGraph.VPM_RELATION_FQN))
|
| {
|
| operation = new AllRelationsOperation(((VariableSearchGraphNode)edge.getSourceNode()).getId()
|
| ,edge, manager);
|
| }
|
| else
|
| if(edge.getSourceNode() instanceof VariableSearchGraphNode && edge.getTargetNode() instanceof VariableSearchGraphNode)
|
| {operation = new ExtendBoundNodeOperation(((VariableSearchGraphNode)edge.getTargetNode()).getId()
|
| ,((VariableSearchGraphNode)edge.getSourceNode()).getId()
|
| ,edge);
|
| }
|
| else
|
| if(edge.getSourceNode() instanceof ConstantSearchGraphNode && edge.getTargetNode() instanceof VariableSearchGraphNode)
|
| {operation = new ExtendConstantNodeOperation(manager.getElementByName(((ConstantSearchGraphNode)edge.getTargetNode()).getElement())
|
| ,((VariableSearchGraphNode)edge.getSourceNode()).getId()
|
| ,edge);
|
| }
|
| }
|
|
|
| if(operation != null)
|
| {
|
| edge.getSourceNode().setChecked(true);
|
| edge.getTargetNode().setChecked(true);
|
| edge.setChecked(true);
|
| }
|
|
|
| return operation;
|
|
|
| }
|
|
|
| }
|