public static IDictionary <PatternElement, SetValueType> ExtractOwnElements(ScheduledSearchPlan nestingScheduledSearchPlan, PatternGraph patternGraph) { Dictionary <PatternElement, SetValueType> ownElements = new Dictionary <PatternElement, SetValueType>(); // elements contained in the schedule of the nesting pattern, that are declared in the current pattern graph // stem from inlining an indepent, extract them to treat them specially in search plan building (preset from nesting pattern) if (nestingScheduledSearchPlan != null) { for (int i = 0; i < nestingScheduledSearchPlan.Operations.Length; ++i) { if (nestingScheduledSearchPlan.Operations[i].Type == SearchOperationType.Condition || nestingScheduledSearchPlan.Operations[i].Type == SearchOperationType.AssignVar || nestingScheduledSearchPlan.Operations[i].Type == SearchOperationType.DefToBeYieldedTo) { continue; } SearchPlanNode spn = (SearchPlanNode)nestingScheduledSearchPlan.Operations[i].Element; if (spn.PatternElement.pointOfDefinition == patternGraph) { ownElements.Add(spn.PatternElement.OriginalIndependentElement, null); } } } return(ownElements); }
private static void DumpEdge(StreamWriter sw, SearchOperationType opType, SearchPlanNode source, SearchPlanNode target, float cost, bool markRed) { String typeStr = " #"; switch (opType) { case SearchOperationType.Outgoing: typeStr = "--"; break; case SearchOperationType.Incoming: typeStr = "->"; break; case SearchOperationType.Incident: typeStr = "<->"; break; case SearchOperationType.ImplicitSource: typeStr = "IS"; break; case SearchOperationType.ImplicitTarget: typeStr = "IT"; break; case SearchOperationType.Implicit: typeStr = "IM"; break; case SearchOperationType.Lookup: typeStr = " *"; break; case SearchOperationType.ActionPreset: typeStr = " p"; break; case SearchOperationType.NegIdptPreset: typeStr = "np"; break; case SearchOperationType.SubPreset: typeStr = "sp"; break; } sw.WriteLine("edge:{{sourcename:\"{0}\" targetname:\"{1}\" label:\"{2} / {3:0.00}\"{4}}}", GetDumpName(source), GetDumpName(target), typeStr, cost, markRed ? " color:red" : ""); }
public SearchPlanGraph(SearchPlanNode root, SearchPlanNode[] nodes, SearchPlanEdge[] edges) { Root = root; Nodes = nodes; Edges = edges; NumPresetElements = 0; foreach (SearchPlanNode node in nodes) { if (node.IsPreset) { ++NumPresetElements; } } foreach (SearchPlanEdge edge in edges) { if (edge.Type == SearchOperationType.PickFromStorage || edge.Type == SearchOperationType.MapWithStorage || edge.Type == SearchOperationType.PickFromIndex || edge.Type == SearchOperationType.PickByName || edge.Type == SearchOperationType.PickByUnique) { ++NumIndependentStorageIndexElements; } } }
public float LocalCost; // only used in benchmarking public SearchPlanEdge(SearchOperationType type, SearchPlanNode source, SearchPlanNode target, float cost) { Target = target; Cost = cost; Source = source; Type = type; }
public SearchOperation(SearchOperationType type, object elem, SearchPlanNode srcSPNode, float costToEnd) { Type = type; Element = elem; SourceSPNode = srcSPNode; CostToEnd = costToEnd; }
private static void DumpNode(StreamWriter sw, SearchPlanNode node) { if (node.NodeType == PlanNodeType.Edge) { sw.WriteLine("node:{{title:\"{0}\" label:\"{1} : {2}\" shape:ellipse}}", GetDumpName(node), node.PatternElement.TypeID, node.PatternElement.Name); } else { sw.WriteLine("node:{{title:\"{0}\" label:\"{1} : {2}\"}}", GetDumpName(node), node.PatternElement.TypeID, node.PatternElement.Name); } }
public static void DumpScheduledSearchPlanAsVcg(ScheduledSearchPlan ssp, IGraphModel model, String dumpname) { StreamWriter sw = new StreamWriter(dumpname + "-scheduledsp.vcg", false); sw.WriteLine("graph:{\ninfoname 1: \"Attributes\"\ndisplay_edge_labels: no\nport_sharing: no\nsplines: no\n" + "\nmanhattan_edges: no\nsmanhattan_edges: no\norientation: bottom_to_top\nedges: yes\nnodes: yes\nclassname 1: \"normal\""); sw.WriteLine("node:{title:\"root\" label:\"ROOT\"}\n"); SearchPlanNode root = new SearchPlanNode("root"); sw.WriteLine("graph:{{title:\"pattern\" label:\"{0}\" status:clustered color:lightgrey", dumpname); foreach (SearchOperation op in ssp.Operations) { switch (op.Type) { case SearchOperationType.Lookup: case SearchOperationType.Incoming: case SearchOperationType.Outgoing: case SearchOperationType.ImplicitSource: case SearchOperationType.ImplicitTarget: { SearchPlanNode spnode = (SearchPlanNode)op.Element; DumpNode(sw, spnode); SearchPlanNode src; switch (op.Type) { case SearchOperationType.Lookup: case SearchOperationType.ActionPreset: case SearchOperationType.NegIdptPreset: src = root; break; default: src = op.SourceSPNode; break; } DumpEdge(sw, op.Type, src, spnode, op.CostToEnd, false); break; } case SearchOperationType.Condition: sw.WriteLine("node:{title:\"Condition\" label:\"CONDITION\"}\n"); break; case SearchOperationType.NegativePattern: sw.WriteLine("node:{title:\"NAC\" label:\"NAC\"}\n"); break; } } }
private static String GetDumpName(SearchPlanNode node) { if (node.NodeType == PlanNodeType.Root) { return("root"); } else if (node.NodeType == PlanNodeType.Node) { return("node_" + node.PatternElement.Name); } else { return("edge_" + node.PatternElement.Name); } }
private static void InsertInlinedElementIdentityCheckIntoSchedule(PatternGraph patternGraph, List <SearchOperation> operations) { for (int i = 0; i < operations.Count; ++i) { PatternElement assignmentSource = null; if (operations[i].Element is SearchPlanNode) { assignmentSource = ((SearchPlanNode)operations[i].Element).PatternElement.AssignmentSource; } if (assignmentSource != null && operations[i].Type != SearchOperationType.Identity) { for (int j = 0; j < operations.Count; ++j) { SearchPlanNode binder = null; if (operations[j].Element is SearchPlanNode) { binder = (SearchPlanNode)operations[j].Element; } if (binder != null && binder.PatternElement == assignmentSource && operations[j].Type != SearchOperationType.Identity) { if (operations[i].Type != SearchOperationType.Assign && operations[j].Type != SearchOperationType.Assign) { int indexOfSecond = Math.Max(i, j); SearchOperation so = new SearchOperation(SearchOperationType.Identity, operations[i].Element, binder, operations[indexOfSecond].CostToEnd); operations.Insert(indexOfSecond + 1, so); break; } } } } } }
public static void Explain(SearchOperation so, SourceBuilder sb, IGraphModel model) { SearchPlanNode src = so.SourceSPNode as SearchPlanNode; SearchPlanNode tgt = so.Element as SearchPlanNode; String connectednessCheck = ""; if (so.ConnectednessCheck.PatternElementName != null) { connectednessCheck = " check " + so.ConnectednessCheck.PatternNodeName + (so.ConnectednessCheck.TheOtherPatternNodeName != null ? " or " + so.ConnectednessCheck.TheOtherPatternNodeName : "") + " connected to " + so.ConnectednessCheck.PatternEdgeName; } switch (so.Type) { case SearchOperationType.Outgoing: sb.AppendFront("from " + src.PatternElement.UnprefixedName + " outgoing -" + tgt.PatternElement.UnprefixedName + ":" + model.EdgeModel.Types[tgt.PatternElement.TypeID].Name + "->" + connectednessCheck + "\n"); break; case SearchOperationType.Incoming: sb.AppendFront("from " + src.PatternElement.UnprefixedName + " incoming <-" + tgt.PatternElement.UnprefixedName + ":" + model.EdgeModel.Types[tgt.PatternElement.TypeID].Name + "-" + connectednessCheck + "\n"); break; case SearchOperationType.Incident: sb.AppendFront("from " + src.PatternElement.UnprefixedName + " incident <-" + tgt.PatternElement.UnprefixedName + ":" + model.EdgeModel.Types[tgt.PatternElement.TypeID].Name + "->" + connectednessCheck + "\n"); break; case SearchOperationType.ImplicitSource: sb.AppendFront("from <-" + src.PatternElement.UnprefixedName + "- get source " + tgt.PatternElement.UnprefixedName + ":" + model.NodeModel.Types[tgt.PatternElement.TypeID].Name + connectednessCheck + "\n"); break; case SearchOperationType.ImplicitTarget: sb.AppendFront("from -" + src.PatternElement.UnprefixedName + "-> get target " + tgt.PatternElement.UnprefixedName + ":" + model.NodeModel.Types[tgt.PatternElement.TypeID].Name + connectednessCheck + "\n"); break; case SearchOperationType.Implicit: sb.AppendFront("from <-" + src.PatternElement.UnprefixedName + "-> get implicit " + tgt.PatternElement.UnprefixedName + ":" + model.NodeModel.Types[tgt.PatternElement.TypeID].Name + connectednessCheck + "\n"); break; case SearchOperationType.Lookup: if (tgt.PatternElement is PatternNode) { sb.AppendFront("lookup " + tgt.PatternElement.UnprefixedName + ":" + model.NodeModel.Types[tgt.PatternElement.TypeID].Name + " in graph" + connectednessCheck + "\n"); } else { sb.AppendFront("lookup -" + tgt.PatternElement.UnprefixedName + ":" + model.EdgeModel.Types[tgt.PatternElement.TypeID].Name + "-> in graph" + connectednessCheck + "\n"); } break; case SearchOperationType.ActionPreset: sb.AppendFront("(preset: " + tgt.PatternElement.UnprefixedName + connectednessCheck + ")\n"); break; case SearchOperationType.NegIdptPreset: sb.AppendFront("(preset: " + tgt.PatternElement.UnprefixedName + (tgt.PatternElement.PresetBecauseOfIndependentInlining ? " after independent inlining" : "") + connectednessCheck + ")\n"); break; case SearchOperationType.SubPreset: sb.AppendFront("(preset: " + tgt.PatternElement.UnprefixedName + connectednessCheck + ")\n"); break; case SearchOperationType.Condition: sb.AppendFront("if { depending on " + String.Join(",", ((PatternCondition)so.Element).NeededNodeNames) + (((PatternCondition)so.Element).NeededNodeNames.Length != 0 && ((PatternCondition)so.Element).NeededEdgeNames.Length != 0 ? "," : "") + String.Join(",", ((PatternCondition)so.Element).NeededEdgeNames) + " }\n"); break; case SearchOperationType.NegativePattern: sb.AppendFront("negative {\n"); sb.Indent(); Explain(((ScheduledSearchPlan)so.Element), sb, model); sb.Append("\n"); ((ScheduledSearchPlan)so.Element).PatternGraph.ExplainNested(sb, model); sb.Unindent(); sb.AppendFront("}\n"); break; case SearchOperationType.IndependentPattern: sb.AppendFront("independent {\n"); sb.Indent(); Explain(((ScheduledSearchPlan)so.Element), sb, model); sb.Append("\n"); ((ScheduledSearchPlan)so.Element).PatternGraph.ExplainNested(sb, model); sb.Unindent(); sb.AppendFront("}\n"); break; case SearchOperationType.PickFromStorage: case SearchOperationType.PickFromStorageDependent: sb.AppendFront(tgt.PatternElement.UnprefixedName + "{" + so.Storage.ToString() + "}" + connectednessCheck + "\n"); break; case SearchOperationType.MapWithStorage: case SearchOperationType.MapWithStorageDependent: sb.AppendFront(tgt.PatternElement.UnprefixedName + "{" + so.Storage.ToString() + "[" + so.StorageIndex.ToString() + "]}" + connectednessCheck + "\n"); break; case SearchOperationType.PickFromIndex: case SearchOperationType.PickFromIndexDependent: sb.AppendFront(tgt.PatternElement.UnprefixedName + "{" + so.IndexAccess.ToString() + "}" + connectednessCheck + "\n"); break; case SearchOperationType.PickByName: case SearchOperationType.PickByNameDependent: sb.AppendFront(tgt.PatternElement.UnprefixedName + "{" + so.NameLookup.ToString() + "}" + connectednessCheck + "\n"); break; case SearchOperationType.PickByUnique: case SearchOperationType.PickByUniqueDependent: sb.AppendFront(tgt.PatternElement.UnprefixedName + "{" + so.UniqueLookup.ToString() + "}" + connectednessCheck + "\n"); break; case SearchOperationType.Cast: sb.AppendFront(tgt.PatternElement.UnprefixedName + "<" + src.PatternElement.UnprefixedName + ">" + connectednessCheck + "\n"); break; case SearchOperationType.Assign: sb.AppendFront("(" + tgt.PatternElement.UnprefixedName + " = " + src.PatternElement.UnprefixedName + ")\n"); break; case SearchOperationType.Identity: sb.AppendFront("(" + tgt.PatternElement.UnprefixedName + " == " + src.PatternElement.UnprefixedName + ")\n"); break; case SearchOperationType.AssignVar: sb.AppendFront("(" + tgt.PatternElement.UnprefixedName + " = expr" + ")\n"); break; case SearchOperationType.LockLocalElementsForPatternpath: sb.AppendFront("lock for patternpath\n"); break; case SearchOperationType.DefToBeYieldedTo: if (so.Element is PatternVariable) { sb.AppendFront("def " + ((PatternVariable)so.Element).Name + "\n"); } else { sb.AppendFront("def " + ((SearchPlanNode)so.Element).PatternElement.Name + "\n"); } break; case SearchOperationType.ParallelLookup: if (tgt.PatternElement is PatternNode) { sb.AppendFront("parallelized lookup " + tgt.PatternElement.UnprefixedName + ":" + model.NodeModel.Types[tgt.PatternElement.TypeID].Name + " in graph\n"); } else { sb.AppendFront("parallelized lookup -" + tgt.PatternElement.UnprefixedName + ":" + model.EdgeModel.Types[tgt.PatternElement.TypeID].Name + "-> in graph\n"); } break; case SearchOperationType.ParallelPickFromStorage: case SearchOperationType.ParallelPickFromStorageDependent: sb.AppendFront("parallelized " + tgt.PatternElement.UnprefixedName + "{" + so.Storage.ToString() + "}\n"); break; case SearchOperationType.ParallelOutgoing: sb.AppendFront("parallelized from " + src.PatternElement.UnprefixedName + " outgoing -" + tgt.PatternElement.UnprefixedName + ":" + model.EdgeModel.Types[tgt.PatternElement.TypeID].Name + "->\n"); break; case SearchOperationType.ParallelIncoming: sb.AppendFront("parallelized from " + src.PatternElement.UnprefixedName + " incoming <-" + tgt.PatternElement.UnprefixedName + ":" + model.EdgeModel.Types[tgt.PatternElement.TypeID].Name + "-\n"); break; case SearchOperationType.ParallelIncident: sb.AppendFront("parallelized from " + src.PatternElement.UnprefixedName + " incident <-" + tgt.PatternElement.UnprefixedName + ":" + model.EdgeModel.Types[tgt.PatternElement.TypeID].Name + "->\n"); break; case SearchOperationType.WriteParallelPreset: case SearchOperationType.ParallelPreset: case SearchOperationType.WriteParallelPresetVar: case SearchOperationType.ParallelPresetVar: case SearchOperationType.SetupParallelLookup: case SearchOperationType.SetupParallelPickFromStorage: case SearchOperationType.SetupParallelPickFromStorageDependent: case SearchOperationType.SetupParallelOutgoing: case SearchOperationType.SetupParallelIncoming: case SearchOperationType.SetupParallelIncident: break; // uninteresting to the user } }
/// <summary> /// Generates a scheduled search plan for a given search plan graph /// </summary> public static ScheduledSearchPlan ScheduleSearchPlan(SearchPlanGraph spGraph, PatternGraph patternGraph, bool isNegativeOrIndependent, bool lazyNegativeIndependentConditionEvaluation) { // the schedule List <SearchOperation> operations = new List <SearchOperation>(); // a set of search plan edges representing the currently reachable not yet visited elements PriorityQueue <SearchPlanEdge> activeEdges = new PriorityQueue <SearchPlanEdge>(); // first schedule all preset elements foreach (SearchPlanEdge edge in spGraph.Root.OutgoingEdges) { if (edge.Target.IsPreset && edge.Type != SearchOperationType.DefToBeYieldedTo) { foreach (SearchPlanEdge edgeOutgoingFromPresetElement in edge.Target.OutgoingEdges) { activeEdges.Add(edgeOutgoingFromPresetElement); } // note: here a normal preset is converted into a neg/idpt preset operation if in negative/independent pattern SearchOperation newOp = new SearchOperation( isNegativeOrIndependent ? SearchOperationType.NegIdptPreset : edge.Type, edge.Target, spGraph.Root, 0); operations.Add(newOp); } } // then schedule all map with storage / pick from index / pick from storage / pick from name index elements not depending on other elements foreach (SearchPlanEdge edge in spGraph.Root.OutgoingEdges) { if (edge.Type == SearchOperationType.MapWithStorage) { foreach (SearchPlanEdge edgeOutgoingFromPickedElement in edge.Target.OutgoingEdges) { activeEdges.Add(edgeOutgoingFromPickedElement); } SearchOperation newOp = new SearchOperation(edge.Type, edge.Target, spGraph.Root, 0); newOp.Storage = edge.Target.PatternElement.Storage; newOp.StorageIndex = edge.Target.PatternElement.StorageIndex; operations.Add(newOp); } } foreach (SearchPlanEdge edge in spGraph.Root.OutgoingEdges) { if (edge.Type == SearchOperationType.PickFromStorage) { foreach (SearchPlanEdge edgeOutgoingFromPickedElement in edge.Target.OutgoingEdges) { activeEdges.Add(edgeOutgoingFromPickedElement); } SearchOperation newOp = new SearchOperation(edge.Type, edge.Target, spGraph.Root, 0); newOp.Storage = edge.Target.PatternElement.Storage; operations.Add(newOp); } } foreach (SearchPlanEdge edge in spGraph.Root.OutgoingEdges) { if (edge.Type == SearchOperationType.PickFromIndex) { foreach (SearchPlanEdge edgeOutgoingFromPickedElement in edge.Target.OutgoingEdges) { activeEdges.Add(edgeOutgoingFromPickedElement); } SearchOperation newOp = new SearchOperation(edge.Type, edge.Target, spGraph.Root, 0); newOp.IndexAccess = edge.Target.PatternElement.IndexAccess; operations.Add(newOp); } } foreach (SearchPlanEdge edge in spGraph.Root.OutgoingEdges) { if (edge.Type == SearchOperationType.PickByName) { foreach (SearchPlanEdge edgeOutgoingFromPickedElement in edge.Target.OutgoingEdges) { activeEdges.Add(edgeOutgoingFromPickedElement); } SearchOperation newOp = new SearchOperation(edge.Type, edge.Target, spGraph.Root, 0); newOp.NameLookup = edge.Target.PatternElement.NameLookup; operations.Add(newOp); } } foreach (SearchPlanEdge edge in spGraph.Root.OutgoingEdges) { if (edge.Type == SearchOperationType.PickByUnique) { foreach (SearchPlanEdge edgeOutgoingFromPickedElement in edge.Target.OutgoingEdges) { activeEdges.Add(edgeOutgoingFromPickedElement); } SearchOperation newOp = new SearchOperation(edge.Type, edge.Target, spGraph.Root, 0); newOp.UniqueLookup = edge.Target.PatternElement.UniqueLookup; operations.Add(newOp); } } // iterate over all reachable elements until the whole graph has been scheduled(/visited), // choose next cheapest operation, update the reachable elements and the search plan costs SearchPlanNode lastNode = spGraph.Root; for (int i = 0; i < spGraph.Nodes.Length - spGraph.NumPresetElements - spGraph.NumIndependentStorageIndexElements; ++i) { foreach (SearchPlanEdge edge in lastNode.OutgoingEdges) { if (edge.Target.IsPreset) { continue; } if (edge.Target.PatternElement.Storage != null && edge.Target.PatternElement.GetPatternElementThisElementDependsOnOutsideOfGraphConnectedness() == null) { continue; } if (edge.Target.PatternElement.IndexAccess != null && edge.Target.PatternElement.GetPatternElementThisElementDependsOnOutsideOfGraphConnectedness() == null) { continue; } if (edge.Target.PatternElement.NameLookup != null && edge.Target.PatternElement.GetPatternElementThisElementDependsOnOutsideOfGraphConnectedness() == null) { continue; } if (edge.Target.PatternElement.UniqueLookup != null && edge.Target.PatternElement.GetPatternElementThisElementDependsOnOutsideOfGraphConnectedness() == null) { continue; } CostDecreaseForLeavingInlinedIndependent(edge); activeEdges.Add(edge); } SearchPlanEdge minEdge = activeEdges.DequeueFirst(); lastNode = minEdge.Target; SearchOperation newOp = new SearchOperation(minEdge.Type, lastNode, minEdge.Source, minEdge.Cost); newOp.Storage = minEdge.Target.PatternElement.Storage; newOp.StorageIndex = minEdge.Target.PatternElement.StorageIndex; newOp.IndexAccess = minEdge.Target.PatternElement.IndexAccess; newOp.NameLookup = minEdge.Target.PatternElement.NameLookup; newOp.UniqueLookup = minEdge.Target.PatternElement.UniqueLookup; foreach (SearchOperation op in operations) { op.CostToEnd += minEdge.Cost; } operations.Add(newOp); } // remove the elements stemming from inlined independents // they were added in the hope that they might help in matching this pattern, // they don't if they are matched after the elements of this pattern (in fact they only increase the costs then) RemoveInlinedIndependentElementsAtEnd(operations); // insert inlined element identity check into the schedule in case neither of the possible assignments was scheduled InsertInlinedElementIdentityCheckIntoSchedule(patternGraph, operations); // insert inlined variable assignments into the schedule InsertInlinedVariableAssignmentsIntoSchedule(patternGraph, operations); // insert conditions into the schedule InsertConditionsIntoSchedule(patternGraph.ConditionsPlusInlined, operations, lazyNegativeIndependentConditionEvaluation); // schedule the initialization of all def to be yielded to elements and variables at the end, // must come after the pattern elements (and preset elements), as they may be used in the def initialization foreach (SearchPlanEdge edge in spGraph.Root.OutgoingEdges) { if (edge.Type == SearchOperationType.DefToBeYieldedTo && (!isNegativeOrIndependent || (edge.Target.PatternElement.pointOfDefinition == patternGraph && edge.Target.PatternElement.originalElement == null))) { SearchOperation newOp = new SearchOperation( SearchOperationType.DefToBeYieldedTo, edge.Target, spGraph.Root, 0); newOp.Expression = edge.Target.PatternElement.Initialization; operations.Add(newOp); } } foreach (PatternVariable var in patternGraph.variablesPlusInlined) { if (var.defToBeYieldedTo && (!isNegativeOrIndependent || var.pointOfDefinition == patternGraph && var.originalVariable == null)) { SearchOperation newOp = new SearchOperation( SearchOperationType.DefToBeYieldedTo, var, spGraph.Root, 0); newOp.Expression = var.initialization; operations.Add(newOp); } } float cost = operations.Count > 0 ? operations[0].CostToEnd : 0; return(new ScheduledSearchPlan(patternGraph, operations.ToArray(), cost)); }
/// <summary> /// Generate search plan graph out of the plan graph, /// search plan graph only contains edges chosen by the MSA algorithm. /// Edges in search plan graph are given in the nodes by outgoing list, as needed for scheduling, /// in contrast to incoming list in plan graph, as needed for MSA computation. /// </summary> /// <param name="planGraph">The source plan graph</param> /// <returns>A new search plan graph</returns> public static SearchPlanGraph GenerateSearchPlanGraph(PlanGraph planGraph) { SearchPlanNode searchPlanRoot = new SearchPlanNode("search plan root"); SearchPlanNode[] searchPlanNodes = new SearchPlanNode[planGraph.Nodes.Length]; SearchPlanEdge[] searchPlanEdges = new SearchPlanEdge[planGraph.Nodes.Length - 1 + 1]; // +1 for root Dictionary <PlanNode, SearchPlanNode> planToSearchPlanNode = // for generating edges new Dictionary <PlanNode, SearchPlanNode>(planGraph.Nodes.Length); planToSearchPlanNode.Add(planGraph.Root, searchPlanRoot); // generate the search plan graph nodes, same as plan graph nodes, // representing pattern graph nodes and edges int i = 0; foreach (PlanNode planNode in planGraph.Nodes) { if (planNode.NodeType == PlanNodeType.Edge) { searchPlanNodes[i] = new SearchPlanEdgeNode(planNode, null, null); } else { searchPlanNodes[i] = new SearchPlanNodeNode(planNode); } planToSearchPlanNode.Add(planNode, searchPlanNodes[i]); ++i; } // generate the search plan graph edges, // that are the plan graph edges chosen by the MSA algorithm, in reversed direction // and add references to originating pattern elements i = 0; foreach (PlanNode planNode in planGraph.Nodes) { PlanEdge planEdge = planNode.IncomingMSAEdge; searchPlanEdges[i] = new SearchPlanEdge(planEdge.Type, planToSearchPlanNode[planEdge.Source], planToSearchPlanNode[planEdge.Target], planEdge.Cost); planToSearchPlanNode[planEdge.Source].OutgoingEdges.Add(searchPlanEdges[i]); if (planNode.NodeType == PlanNodeType.Edge) { SearchPlanEdgeNode searchPlanEdgeNode = (SearchPlanEdgeNode)planToSearchPlanNode[planNode]; SearchPlanNode patElem; if (planEdge.Target.PatternEdgeSource != null && planToSearchPlanNode.TryGetValue(planEdge.Target.PatternEdgeSource, out patElem)) { searchPlanEdgeNode.PatternEdgeSource = (SearchPlanNodeNode)patElem; searchPlanEdgeNode.PatternEdgeSource.OutgoingPatternEdges.Add(searchPlanEdgeNode); } if (planEdge.Target.PatternEdgeTarget != null && planToSearchPlanNode.TryGetValue(planEdge.Target.PatternEdgeTarget, out patElem)) { searchPlanEdgeNode.PatternEdgeTarget = (SearchPlanNodeNode)patElem; searchPlanEdgeNode.PatternEdgeTarget.IncomingPatternEdges.Add(searchPlanEdgeNode); } } ++i; } return(new SearchPlanGraph(searchPlanRoot, searchPlanNodes, searchPlanEdges)); }
/// <summary> /// Determines which homomorphy check operations are necessary /// at the operation of the given position within the scheduled search plan /// and appends them. /// </summary> private static void DetermineAndAppendHomomorphyChecks(IGraphModel model, ScheduledSearchPlan ssp, int j) { // take care of global homomorphy FillInGlobalHomomorphyPatternElements(ssp, j); /////////////////////////////////////////////////////////////////////////// // first handle special case pure homomorphy SearchPlanNode spn_j = (SearchPlanNode)ssp.Operations[j].Element; if (spn_j.ElementID == -1) { // inlined from independent for better matching, independent from the rest return; } bool homToAll = true; if (spn_j.NodeType == PlanNodeType.Node) { for (int i = 0; i < ssp.PatternGraph.nodesPlusInlined.Length; ++i) { if (!ssp.PatternGraph.homomorphicNodes[spn_j.ElementID - 1, i]) { homToAll = false; break; } } } else //(spn_j.NodeType == PlanNodeType.Edge) { for (int i = 0; i < ssp.PatternGraph.edgesPlusInlined.Length; ++i) { if (!ssp.PatternGraph.homomorphicEdges[spn_j.ElementID - 1, i]) { homToAll = false; break; } } } if (homToAll) { // operation is allowed to be homomorph with everything // no checks for isomorphy or restricted homomorphy needed at all return; } /////////////////////////////////////////////////////////////////////////// // no pure homomorphy, so we have restricted homomorphy or isomorphy // and need to inspect the operations before, together with the homomorphy matrix // for determining the necessary homomorphy checks GraphElementType[] types; bool[,] hom; if (spn_j.NodeType == PlanNodeType.Node) { types = model.NodeModel.Types; hom = ssp.PatternGraph.homomorphicNodes; } else // (spn_j.NodeType == PlanNodeType.Edge) { types = model.EdgeModel.Types; hom = ssp.PatternGraph.homomorphicEdges; } // order operation to check against all elements it's not allowed to be homomorph to // iterate through the operations before our position bool homomorphyPossibleAndAllowed = false; for (int i = 0; i < j; ++i) { // only check operations computing nodes or edges if (ssp.Operations[i].Type == SearchOperationType.Condition || ssp.Operations[i].Type == SearchOperationType.NegativePattern || ssp.Operations[i].Type == SearchOperationType.IndependentPattern || ssp.Operations[i].Type == SearchOperationType.Assign || ssp.Operations[i].Type == SearchOperationType.AssignVar || ssp.Operations[i].Type == SearchOperationType.DefToBeYieldedTo || ssp.Operations[i].Type == SearchOperationType.InlinedIndependentCheckForDuplicateMatch) { continue; } SearchPlanNode spn_i = (SearchPlanNode)ssp.Operations[i].Element; if (spn_i.NodeType != spn_j.NodeType) { // don't compare nodes with edges continue; } if (spn_i.ElementID == -1) { // inlined from independent for better matching, independent from the rest continue; } // find out whether element types are disjoint GraphElementType type_i = types[spn_i.PatternElement.TypeID]; GraphElementType type_j = types[spn_j.PatternElement.TypeID]; bool disjoint = true; foreach (GraphElementType subtype_i in type_i.SubOrSameTypes) { if (type_j.IsA(subtype_i) || subtype_i.IsA(type_j)) // IsA==IsSuperTypeOrSameType { disjoint = false; break; } } if (disjoint) { // don't check elements if their types are disjoint continue; } // at this position we found out that spn_i and spn_j // might get matched to the same host graph element, i.e. homomorphy is possible // if that's ok we don't need to insert checks to prevent this from happening if (hom[spn_i.ElementID - 1, spn_j.ElementID - 1]) { homomorphyPossibleAndAllowed = true; continue; } // otherwise the generated matcher code has to check // that pattern element j doesn't get bound to the same graph element // the pattern element i is already bound to if (ssp.Operations[j].Isomorphy.PatternElementsToCheckAgainst == null) { ssp.Operations[j].Isomorphy.PatternElementsToCheckAgainst = new List <SearchPlanNode>(); } ssp.Operations[j].Isomorphy.PatternElementsToCheckAgainst.Add(spn_i); // if spn_j might get matched to the same host graph element as spn_i and this is not allowed // make spn_i set the is-matched-bit so that spn_j can detect this situation ssp.Operations[i].Isomorphy.SetIsMatchedBit = true; } // only if elements, the operation must be isomorph to, were matched before // (otherwise there were only elements, the operation is allowed to be homomorph to, // matched before, so no check needed here) if (ssp.Operations[j].Isomorphy.PatternElementsToCheckAgainst != null && ssp.Operations[j].Isomorphy.PatternElementsToCheckAgainst.Count > 0) { // order operation to check whether the is-matched-bit is set ssp.Operations[j].Isomorphy.CheckIsMatchedBit = true; } // if no check for isomorphy was skipped due to homomorphy being allowed // pure isomorphy is to be guaranteed - simply check the is-matched-bit and be done // the pattern elements to check against are only needed // if spn_j is allowed to be homomorph to some elements but must be isomorph to some others if (ssp.Operations[j].Isomorphy.CheckIsMatchedBit && !homomorphyPossibleAndAllowed) { ssp.Operations[j].Isomorphy.PatternElementsToCheckAgainst = null; } }
/// <summary> /// fill in globally homomorphic elements as exception to global isomorphy check /// </summary> private static void FillInGlobalHomomorphyPatternElements(ScheduledSearchPlan ssp, int j) { SearchPlanNode spn_j = (SearchPlanNode)ssp.Operations[j].Element; if (spn_j.NodeType == PlanNodeType.Node) { if (spn_j.ElementID == -1 || // inlined from independent for better matching, independent from the rest ssp.PatternGraph.totallyHomomorphicNodes[spn_j.ElementID - 1]) { ssp.Operations[j].Isomorphy.TotallyHomomorph = true; return; // iso-exceptions to totally hom are handled with non-global iso checks } } else { if (spn_j.ElementID == -1 || // inlined from independent for better matching, independent from the rest ssp.PatternGraph.totallyHomomorphicEdges[spn_j.ElementID - 1]) { ssp.Operations[j].Isomorphy.TotallyHomomorph = true; return; // iso-exceptions to totally hom are handled with non-global iso checks } } bool[,] homGlobal; if (spn_j.NodeType == PlanNodeType.Node) { homGlobal = ssp.PatternGraph.homomorphicNodesGlobal; } else // (spn_j.NodeType == PlanNodeType.Edge) { homGlobal = ssp.PatternGraph.homomorphicEdgesGlobal; } // iterate through the operations before our position for (int i = 0; i < j; ++i) { // only check operations computing nodes or edges if (ssp.Operations[i].Type == SearchOperationType.Condition || ssp.Operations[i].Type == SearchOperationType.NegativePattern || ssp.Operations[i].Type == SearchOperationType.IndependentPattern || ssp.Operations[i].Type == SearchOperationType.Assign || ssp.Operations[i].Type == SearchOperationType.AssignVar || ssp.Operations[i].Type == SearchOperationType.DefToBeYieldedTo || ssp.Operations[i].Type == SearchOperationType.InlinedIndependentCheckForDuplicateMatch) { continue; } SearchPlanNode spn_i = (SearchPlanNode)ssp.Operations[i].Element; if (spn_i.NodeType != spn_j.NodeType) { // don't compare nodes with edges continue; } if (spn_i.ElementID == -1) { // inlined from independent for better matching, independent from the rest continue; } // in global isomorphy check at current position // allow globally homomorphic elements as exception // if they were already defined(preset) if (homGlobal[spn_j.ElementID - 1, spn_i.ElementID - 1]) { if (ssp.Operations[j].Isomorphy.GloballyHomomorphPatternElements == null) { ssp.Operations[j].Isomorphy.GloballyHomomorphPatternElements = new List <SearchPlanNode>(); } ssp.Operations[j].Isomorphy.GloballyHomomorphPatternElements.Add(spn_i); } } }