/// <summary> /// Recursively assembles interpretation plan from scheduled search plan, beginning at index 0. /// Decides which specialized build procedure is to be called. /// The specialized build procedure then calls this procedure again, /// in order to process the next search plan operation at the following index. /// The insertionPoint is the lastly built operation; /// the next operation built is inserted into the next link of it, /// then it becomes the current insertionPoint. /// </summary> private void BuildInterpretationPlan(InterpretationPlan insertionPoint, int index) { if (index >= ssp.Operations.Length) { // end of scheduled search plan reached, stop recursive iteration buildMatchComplete(insertionPoint); return; } SearchOperation op = ssp.Operations[index]; // for current scheduled search plan operation // insert corresponding interpretation plan operations into interpretation plan switch (op.Type) { case SearchOperationType.Lookup: if(((SearchPlanNode)op.Element).NodeType == PlanNodeType.Node) buildLookup(insertionPoint, index, (SearchPlanNodeNode)op.Element); else buildLookup(insertionPoint, index, (SearchPlanEdgeNode)op.Element); break; case SearchOperationType.ImplicitSource: buildImplicit(insertionPoint, index, (SearchPlanEdgeNode)op.SourceSPNode, (SearchPlanNodeNode)op.Element, ImplicitNodeType.Source); break; case SearchOperationType.ImplicitTarget: buildImplicit(insertionPoint, index, (SearchPlanEdgeNode)op.SourceSPNode, (SearchPlanNodeNode)op.Element, ImplicitNodeType.Target); break; case SearchOperationType.Implicit: buildImplicit(insertionPoint, index, (SearchPlanEdgeNode)op.SourceSPNode, (SearchPlanNodeNode)op.Element, ImplicitNodeType.SourceOrTarget); break; case SearchOperationType.Incoming: buildIncident(insertionPoint, index, (SearchPlanNodeNode)op.SourceSPNode, (SearchPlanEdgeNode)op.Element, IncidentEdgeType.Incoming); break; case SearchOperationType.Outgoing: buildIncident(insertionPoint, index, (SearchPlanNodeNode)op.SourceSPNode, (SearchPlanEdgeNode)op.Element, IncidentEdgeType.Outgoing); break; case SearchOperationType.Incident: buildIncident(insertionPoint, index, (SearchPlanNodeNode)op.SourceSPNode, (SearchPlanEdgeNode)op.Element, IncidentEdgeType.IncomingOrOutgoing); break; case SearchOperationType.Condition: buildCondition(insertionPoint, index, (PatternCondition)op.Element); break; default: throw new Exception("Unknown or unsupported search operation"); } }
/// <summary> /// Decides which check connectedness operations are needed for the given edge of fixed direction /// and inserts them into the interpretation plan /// receives insertion point, returns new insertion point /// </summary> private InterpretationPlan decideOnAndInsertCheckConnectednessOfEdgeFixedDirection( InterpretationPlan insertionPoint, SearchPlanEdgeNode edge, CheckCandidateForConnectednessType connectednessType) { Debug.Assert(connectednessType == CheckCandidateForConnectednessType.Source || connectednessType == CheckCandidateForConnectednessType.Target); // check whether source/target-nodes of the candidate edge // are the same as the already found nodes to which the edge must be incident // don't need to, if that node is not matched by now (signaled by visited) SearchPlanNodeNode nodeRequiringCheck = connectednessType == CheckCandidateForConnectednessType.Source ? edge.PatternEdgeSource : edge.PatternEdgeTarget; if (nodeRequiringCheck.Visited) { if(connectednessType == CheckCandidateForConnectednessType.Source) { insertionPoint.next = new InterpretationPlanCheckConnectednessSource( nodeRequiringCheck.nodeMatcher, edge.edgeMatcher); insertionPoint = insertionPoint.next; } else //if(connectednessType == CheckCandidateForConnectednessType.Target) { insertionPoint.next = new InterpretationPlanCheckConnectednessTarget( nodeRequiringCheck.nodeMatcher, edge.edgeMatcher); insertionPoint = insertionPoint.next; } } return insertionPoint; }
/// <summary> /// Decides which check connectedness operations are needed for the given edge in both directions /// and inserts them into the interpretation plan /// receives insertion point, returns new insertion point /// </summary> private InterpretationPlan decideOnAndInsertCheckConnectednessOfEdgeBothDirections( InterpretationPlan insertionPoint, SearchPlanEdgeNode edge, bool edgeDeterminationContainsFirstNodeLoop) { // check whether source/target-nodes of the candidate edge // are the same as the already found nodes to which the edge must be incident if (!edgeDeterminationContainsFirstNodeLoop && currentEdgeConnectsToFirstIncidentNode(edge)) { SearchPlanNodeNode nodeRequiringFirstNodeLoop = edge.PatternEdgeSource != null ? edge.PatternEdgeSource : edge.PatternEdgeTarget; // due to currentEdgeConnectsToFirstIncidentNode: at least on incident node available if (edge.PatternEdgeSource == edge.PatternEdgeTarget) { // reflexive edge without direction iteration as we don't want 2 matches insertionPoint.next = new InterpretationPlanCheckConnectednessSource( nodeRequiringFirstNodeLoop.nodeMatcher, edge.edgeMatcher); // might be Target as well insertionPoint = insertionPoint.next; } else { edge.directionVariable = new InterpretationPlanBothDirections(); insertionPoint.next = edge.directionVariable; insertionPoint = insertionPoint.next; insertionPoint.next = new InterpretationPlanCheckConnectednessSourceOrTarget( nodeRequiringFirstNodeLoop.nodeMatcher, edge.edgeMatcher, edge.directionVariable); insertionPoint = insertionPoint.next; } } if (currentEdgeConnectsToSecondIncidentNode(edge)) { // due to currentEdgeConnectsToSecondIncidentNode: both incident node available insertionPoint.next = new InterpretationPlanCheckConnectednessTheOther( edge.PatternEdgeTarget.nodeMatcher, edge.edgeMatcher, edge.PatternEdgeSource.nodeMatcher); insertionPoint = insertionPoint.next; } return insertionPoint; }
/// <summary> /// Decides which check connectedness operations are needed for the given edge determined by lookup /// and inserts them into the interpretation plan /// receives insertion point, returns new insertion point /// </summary> private InterpretationPlan decideOnAndInsertCheckConnectednessOfEdgeFromLookup( InterpretationPlan insertionPoint, SearchPlanEdgeNode edge) { if (((PatternEdge)edge.PatternElement).fixedDirection) { // don't need to check if the edge is not required by the pattern to be incident to some given node if (edge.PatternEdgeSource != null) { insertionPoint = decideOnAndInsertCheckConnectednessOfEdgeFixedDirection(insertionPoint, edge, CheckCandidateForConnectednessType.Source); } if (edge.PatternEdgeTarget != null) { insertionPoint = decideOnAndInsertCheckConnectednessOfEdgeFixedDirection(insertionPoint, edge, CheckCandidateForConnectednessType.Target); } } else { insertionPoint = decideOnAndInsertCheckConnectednessOfEdgeBothDirections(insertionPoint, edge, false); } return insertionPoint; }
/// <summary> /// Decides which check connectedness operations are needed for the given edge determined from incident node /// and inserts them into the interpretation plan /// receives insertion point, returns new insertions point /// </summary> private InterpretationPlan decideOnAndInsertCheckConnectednessOfIncidentEdgeFromNode( InterpretationPlan insertionPoint, SearchPlanEdgeNode edge, SearchPlanNodeNode originatingNode, bool edgeIncomingAtOriginatingNode) { if (((PatternEdge)edge.PatternElement).fixedDirection) { // don't need to check if the edge is not required by the pattern to be incident to some given node // or if the edge was taken from the given originating node if (edge.PatternEdgeSource != null) { if (!(!edgeIncomingAtOriginatingNode && edge.PatternEdgeSource == originatingNode)) { insertionPoint = decideOnAndInsertCheckConnectednessOfEdgeFixedDirection(insertionPoint, edge, CheckCandidateForConnectednessType.Source); } } if (edge.PatternEdgeTarget != null) { if (!(edgeIncomingAtOriginatingNode && edge.PatternEdgeTarget == originatingNode)) { insertionPoint = decideOnAndInsertCheckConnectednessOfEdgeFixedDirection(insertionPoint, edge, CheckCandidateForConnectednessType.Target); } } } else { insertionPoint = decideOnAndInsertCheckConnectednessOfEdgeBothDirections(insertionPoint, edge, true); } return insertionPoint; }
/// <summary> /// Decides which check connectedness operations are needed for the given node and edge of fixed direction /// and inserts them into the interpretation plan /// receives insertion point, returns new insertion point /// </summary> private InterpretationPlan decideOnAndInsertCheckConnectednessOfNodeFixedDirection( InterpretationPlan insertionPoint, SearchPlanNodeNode currentNode, SearchPlanEdgeNode edge, CheckCandidateForConnectednessType connectednessType) { Debug.Assert(connectednessType == CheckCandidateForConnectednessType.Source || connectednessType == CheckCandidateForConnectednessType.Target); // check whether the pattern edges which must be incident to the candidate node (according to the pattern) // are really incident to it // only if edge is already matched by now (signaled by visited) if (edge.Visited) { if(connectednessType == CheckCandidateForConnectednessType.Source) { insertionPoint.next = new InterpretationPlanCheckConnectednessSource( currentNode.nodeMatcher, edge.edgeMatcher); insertionPoint = insertionPoint.next; } else //if(connectednessType == CheckCandidateForConnectednessType.Target) { insertionPoint.next = new InterpretationPlanCheckConnectednessTarget( currentNode.nodeMatcher, edge.edgeMatcher); insertionPoint = insertionPoint.next; } } return insertionPoint; }
/// <summary> /// Decides which check connectedness operations are needed for the given node and edge in both directions /// and inserts them into the interpretation plan /// receives insertion point, returns new insertion point /// </summary> private InterpretationPlan decideOnAndInsertCheckConnectednessOfNodeBothDirections( InterpretationPlan insertionPoint, SearchPlanNodeNode currentNode, SearchPlanEdgeNode edge) { Debug.Assert(edge.PatternEdgeSource != edge.PatternEdgeTarget); // check whether the pattern edges which must be incident to the candidate node (according to the pattern) // are really incident to it if (currentNodeIsFirstIncidentNodeOfEdge(currentNode, edge)) { edge.directionVariable = new InterpretationPlanBothDirections(); insertionPoint.next = edge.directionVariable; insertionPoint = insertionPoint.next; insertionPoint.next = new InterpretationPlanCheckConnectednessSourceOrTarget( currentNode.nodeMatcher, edge.edgeMatcher, edge.directionVariable); insertionPoint = insertionPoint.next; } if (currentNodeIsSecondIncidentNodeOfEdge(currentNode, edge)) { insertionPoint.next = new InterpretationPlanCheckConnectednessTheOther( currentNode.nodeMatcher, edge.edgeMatcher, edge.PatternEdgeSource == currentNode ? edge.PatternEdgeTarget.nodeMatcher : edge.PatternEdgeSource.nodeMatcher); insertionPoint = insertionPoint.next; } return insertionPoint; }
/// <summary> /// Decides which check connectedness operations are needed for the given node just determined by lookup /// and inserts them into the interpretation plan /// receives insertion point, returns new insertion point /// </summary> private InterpretationPlan decideOnAndInsertCheckConnectednessOfNodeFromLookup( InterpretationPlan insertionPoint, SearchPlanNodeNode node) { // check for edges required by the pattern to be incident to the given node foreach (SearchPlanEdgeNode edge in node.OutgoingPatternEdges) { if (((PatternEdge)edge.PatternElement).fixedDirection || edge.PatternEdgeSource == edge.PatternEdgeTarget) { insertionPoint = decideOnAndInsertCheckConnectednessOfNodeFixedDirection(insertionPoint, node, edge, CheckCandidateForConnectednessType.Source); } else { insertionPoint = decideOnAndInsertCheckConnectednessOfNodeBothDirections(insertionPoint, node, edge); } } foreach (SearchPlanEdgeNode edge in node.IncomingPatternEdges) { if (((PatternEdge)edge.PatternElement).fixedDirection || edge.PatternEdgeSource == edge.PatternEdgeTarget) { insertionPoint = decideOnAndInsertCheckConnectednessOfNodeFixedDirection(insertionPoint, node, edge, CheckCandidateForConnectednessType.Target); } else { insertionPoint = decideOnAndInsertCheckConnectednessOfNodeBothDirections(insertionPoint, node, edge); } } return insertionPoint; }
/// <summary> /// Decides which check connectedness operations are needed for the given node just drawn from edge /// and inserts them into the interpretation plan /// receives insertion point, returns new insertion point /// </summary> private InterpretationPlan decideOnAndInsertCheckConnectednessOfImplicitNodeFromEdge( InterpretationPlan insertionPoint, SearchPlanNodeNode node, SearchPlanEdgeNode originatingEdge, SearchPlanNodeNode otherNodeOfOriginatingEdge) { // check for edges required by the pattern to be incident to the given node // only if the node was not taken from the given originating edge // with the exception of reflexive edges, as these won't get checked thereafter foreach (SearchPlanEdgeNode edge in node.OutgoingPatternEdges) { if (((PatternEdge)edge.PatternElement).fixedDirection || edge.PatternEdgeSource == edge.PatternEdgeTarget) { if (edge != originatingEdge || node == otherNodeOfOriginatingEdge) { insertionPoint = decideOnAndInsertCheckConnectednessOfNodeFixedDirection(insertionPoint, node, edge, CheckCandidateForConnectednessType.Source); } } else { if (edge != originatingEdge || node == otherNodeOfOriginatingEdge) { insertionPoint = decideOnAndInsertCheckConnectednessOfNodeBothDirections(insertionPoint, node, edge); } } } foreach (SearchPlanEdgeNode edge in node.IncomingPatternEdges) { if (((PatternEdge)edge.PatternElement).fixedDirection || edge.PatternEdgeSource == edge.PatternEdgeTarget) { if (edge != originatingEdge || node == otherNodeOfOriginatingEdge) { insertionPoint = decideOnAndInsertCheckConnectednessOfNodeFixedDirection(insertionPoint, node, edge, CheckCandidateForConnectednessType.Target); } } else { if (edge != originatingEdge || node == otherNodeOfOriginatingEdge) { insertionPoint = decideOnAndInsertCheckConnectednessOfNodeBothDirections(insertionPoint, node, edge); } } } return insertionPoint; }
/////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Inserts code to get an implicit node from an edge /// receives insertion point, returns new insertion point /// </summary> private InterpretationPlan insertImplicitNodeFromEdge( InterpretationPlan insertionPoint, SearchPlanEdgeNode edge, SearchPlanNodeNode currentNode, ImplicitNodeType nodeType) { int targetType = currentNode.PatternElement.TypeID; if (nodeType == ImplicitNodeType.Source) { currentNode.nodeMatcher = new InterpretationPlanImplicitSource(targetType, edge.edgeMatcher, currentNode); } else if(nodeType == ImplicitNodeType.Target) { currentNode.nodeMatcher = new InterpretationPlanImplicitTarget(targetType, edge.edgeMatcher, currentNode); } else { Debug.Assert(nodeType != ImplicitNodeType.TheOther); if (currentNodeIsSecondIncidentNodeOfEdge(currentNode, edge)) { currentNode.nodeMatcher = new InterpretationPlanImplicitTheOther(targetType, edge.edgeMatcher, edge.PatternEdgeSource == currentNode ? edge.PatternEdgeTarget.nodeMatcher : edge.PatternEdgeSource.nodeMatcher, currentNode); } else // edge connects to first incident node { if (edge.PatternEdgeSource == edge.PatternEdgeTarget) { // reflexive edge without direction iteration as we don't want 2 matches currentNode.nodeMatcher = new InterpretationPlanImplicitSource(targetType, edge.edgeMatcher, currentNode); } else { edge.directionVariable = new InterpretationPlanBothDirections(); insertionPoint.next = edge.directionVariable; insertionPoint = insertionPoint.next; currentNode.nodeMatcher = new InterpretationPlanImplicitSourceOrTarget(targetType, edge.edgeMatcher, edge.directionVariable, currentNode); } } } currentNode.nodeMatcher.prev = insertionPoint; insertionPoint.next = currentNode.nodeMatcher; insertionPoint = insertionPoint.next; return insertionPoint; }
/// <summary> /// Inserts code to get an incident edge from some node /// receives insertion point, returns new insertion point /// </summary> private InterpretationPlan insertIncidentEdgeFromNode( InterpretationPlan insertionPoint, SearchPlanNodeNode node, SearchPlanEdgeNode currentEdge, IncidentEdgeType incidentType) { int targetType = currentEdge.PatternElement.TypeID; if (incidentType == IncidentEdgeType.Incoming) { currentEdge.edgeMatcher = new InterpretationPlanIncoming(targetType, node.nodeMatcher, currentEdge); } else if(incidentType == IncidentEdgeType.Outgoing) { currentEdge.edgeMatcher = new InterpretationPlanOutgoing(targetType, node.nodeMatcher, currentEdge); } else // IncidentEdgeType.IncomingOrOutgoing { if (currentEdge.PatternEdgeSource == currentEdge.PatternEdgeTarget) { // reflexive edge without direction iteration as we don't want 2 matches currentEdge.edgeMatcher = new InterpretationPlanIncoming(targetType, node.nodeMatcher, currentEdge); } else { currentEdge.directionVariable = new InterpretationPlanBothDirections(); insertionPoint.next = currentEdge.directionVariable; insertionPoint = insertionPoint.next; currentEdge.edgeMatcher = new InterpretationPlanIncomingOrOutgoing(targetType, node.nodeMatcher, currentEdge.directionVariable, currentEdge); } } currentEdge.edgeMatcher.prev = insertionPoint; insertionPoint.next = currentEdge.edgeMatcher; insertionPoint = insertionPoint.next; return insertionPoint; }
/// <summary> /// The closing matching completed interpretation plan operation is added at the insertion point /// </summary> private void buildMatchComplete(InterpretationPlan insertionPoint) { insertionPoint.next = new InterpretationPlanMatchComplete( ssp.PatternGraph.nodesPlusInlined.Length, ssp.PatternGraph.edgesPlusInlined.Length); insertionPoint.next.prev = insertionPoint; }
/// <summary> /// Interpretation plan operations implementing the /// CheckCondition search plan operation /// are created and inserted into the interpretation plan at the insertion point /// </summary> private void buildCondition( InterpretationPlan insertionPoint, int index, PatternCondition condition) { // check condition expression.AreAttributesEqual aae = (expression.AreAttributesEqual)condition.ConditionExpression; foreach(SearchPlanNode spn in spg.Nodes) { if(spn.PatternElement == aae.thisInPattern) { InterpretationPlanCheckCondition checkCondition; if(spn is SearchPlanNodeNode) { SearchPlanNodeNode nodeNode = (SearchPlanNodeNode)spn; checkCondition = new InterpretationPlanCheckCondition( aae, nodeNode.nodeMatcher, Array.IndexOf(aae.thisInPattern.pointOfDefinition.nodes, aae.thisInPattern)); } else { SearchPlanEdgeNode edgeNode = (SearchPlanEdgeNode)spn; checkCondition = new InterpretationPlanCheckCondition( aae, edgeNode.edgeMatcher, Array.IndexOf(aae.thisInPattern.pointOfDefinition.edges, aae.thisInPattern)); } checkCondition.prev = insertionPoint; insertionPoint.next = checkCondition; insertionPoint = insertionPoint.next; // continue with next operation BuildInterpretationPlan(insertionPoint, index + 1); return; } } throw new Exception("Internal error constructing interpretation plan!"); }
/// <summary> /// Interpretation plan operations implementing the /// Extend Incoming|Outgoing|IncomingOrOutgoing search plan operation /// are created and inserted into the interpretation plan at the insertion point /// </summary> private void buildIncident( InterpretationPlan insertionPoint, int index, SearchPlanNodeNode source, SearchPlanEdgeNode target, IncidentEdgeType edgeType) { // get candidate = iterate available incident edges insertionPoint = insertIncidentEdgeFromNode(insertionPoint, source, target, edgeType); // check connectedness of candidate insertionPoint = decideOnAndInsertCheckConnectednessOfIncidentEdgeFromNode(insertionPoint, target, source, edgeType==IncidentEdgeType.Incoming); // continue with next operation target.Visited = true; BuildInterpretationPlan(insertionPoint, index + 1); target.Visited = false; }
/// <summary> /// Interpretation plan operations implementing the /// Implicit Source|Target|SourceOrTarget search plan operation /// are created and inserted into the interpretation plan at the insertion point /// </summary> private void buildImplicit( InterpretationPlan insertionPoint, int index, SearchPlanEdgeNode source, SearchPlanNodeNode target, ImplicitNodeType nodeType) { // get candidate = demanded node from edge insertionPoint = insertImplicitNodeFromEdge(insertionPoint, source, target, nodeType); // check connectedness of candidate SearchPlanNodeNode otherNodeOfOriginatingEdge = null; if (nodeType == ImplicitNodeType.Source) otherNodeOfOriginatingEdge = source.PatternEdgeTarget; if (nodeType == ImplicitNodeType.Target) otherNodeOfOriginatingEdge = source.PatternEdgeSource; if (source.PatternEdgeTarget == source.PatternEdgeSource) // reflexive sign needed in unfixed direction case, too otherNodeOfOriginatingEdge = source.PatternEdgeSource; insertionPoint = decideOnAndInsertCheckConnectednessOfImplicitNodeFromEdge(insertionPoint, target, source, otherNodeOfOriginatingEdge); // continue with next operation target.Visited = true; BuildInterpretationPlan(insertionPoint, index + 1); target.Visited = false; }
/// <summary> /// Interpretation plan operations implementing the /// Lookup edge search plan operation /// are created and inserted into the interpretation plan at the insertion point /// </summary> private void buildLookup( InterpretationPlan insertionPoint, int index, SearchPlanEdgeNode target) { // get candidate = iterate available edges target.edgeMatcher = new InterpretationPlanLookupEdge(target.PatternElement.TypeID, target); target.edgeMatcher.prev = insertionPoint; insertionPoint.next = target.edgeMatcher; insertionPoint = insertionPoint.next; // check connectedness of candidate insertionPoint = decideOnAndInsertCheckConnectednessOfEdgeFromLookup(insertionPoint, target); // continue with next operation target.Visited = true; BuildInterpretationPlan(insertionPoint, index + 1); target.Visited = false; }