/* this is similar for rules with nonexistence graph elements*/ private void FindPositiveStartElementAvoidNegatives(option location) { #region Case #1: Location found! No empty slots left in the location /* this is the only way to properly exist the recursive loop. */ if (!L.nodes.Any(n => ((ruleNode)n).MustExist && location.findLMappedNode(n) == null) && !L.arcs.Any(a => ((ruleArc)a).MustExist && location.findLMappedArc(a) == null) && !L.hyperarcs.Any(n => ((ruleHyperarc)n).MustExist && location.findLMappedHyperarc(n) == null)) { /* as a recursive function, we first check how the recognition process terminates. If all nodes, * hyperarcs and arcs within location have been filled with references to elements in the host, * then we've found a location...well maybe. More details are described in the LocationFound function. */ if (!FinalRuleChecks(location) && !FinalRuleCheckRelaxed(location)) { return; } Boolean resultNegativeNotFulfilled; lock (AllNegativeElementsFound) { AllNegativeElementsFound = false; negativeRelaxation = location.Relaxations.copy(); findNegativeStartElement(location); resultNegativeNotFulfilled = !(bool)AllNegativeElementsFound; } if (resultNegativeNotFulfilled) { var locCopy = location.copy(); locCopy.Relaxations = negativeRelaxation; lock (options) { options.Add(locCopy); } } return; } #endregion #region Case #2: build off of a hyperarc found so far - by looking for unfulfilled nodes /* the quickest approach to finding a new element in the LHS to host subgraph matching is to build * directly off of elements found so far. This is because we don't need to check amongst ALL elements in the * host (as is the case in the last three cases below). In this case we start with any hyperarcs * that have already been matched to one in the host, and see if it connects to any nodes that * have yet to be matched. */ var startHyperArc = (ruleHyperarc)L.hyperarcs.FirstOrDefault(ha => ((ruleHyperarc)ha).MustExist && ((location.findLMappedHyperarc(ha) != null) && (ha.nodes.Any(n => ((ruleNode)n).MustExist && (location.findLMappedNode(n) == null))))); if (startHyperArc != null) { var hostHyperArc = location.findLMappedHyperarc(startHyperArc); var newLNode = (ruleNode)startHyperArc.nodes.FirstOrDefault(n => ((ruleNode)n).MustExist && (location.findLMappedNode(n) == null)); foreach (var n in hostHyperArc.nodes.Where(n => !location.nodes.Contains(n))) { checkNodeAvoidNegatives(location.copy(), newLNode, n); } return; } #endregion #region Case #3: build off of a node found so far - by looking for unfulfilled arcs /* as stated above, the quickest approach is to build from elements that have already been found. * Therefore, we see if there are any nodes already matched to a node in L that has an arc in L * that has yet to be matched with a host arc. This is more efficient than the last 3 cases * because they look through the entire host, which is potentially large. */ var startNode = (ruleNode)L.nodes.FirstOrDefault(n => ((ruleNode)n).MustExist && ((location.findLMappedNode(n) != null) && (n.arcs.Any(a => (((a is ruleHyperarc) && ((ruleHyperarc)a).MustExist) || ((a is ruleArc) && ((ruleArc)a).MustExist)) && (location.findLMappedElement(a) == null))))); /* is there a node already matched (which would only occur if your recursed to get here) that has an * unrecognized arc attaced to it. If yes, try all possible arcs in the host with the one that needs * to be fulfilled in L. */ if (startNode != null) { var newLArc = startNode.arcs.FirstOrDefault(a => (((a is ruleHyperarc) && ((ruleHyperarc)a).MustExist) || ((a is ruleArc) && ((ruleArc)a).MustExist)) && (location.findLMappedElement(a) == null)); if (newLArc is ruleHyperarc) { checkHyperArcAvoidNegatives(location, startNode, location.findLMappedNode(startNode), (ruleHyperarc)newLArc); } else if (newLArc is ruleArc) { checkArcAvoidNegatives(location, startNode, location.findLMappedNode(startNode), (ruleArc)newLArc); } return; } #endregion #region Case 4: Check entire host for a matching hyperarc /* if the above cases didn't match we try to match a hyperarc in the L to any in the host. Since the * prior three cases have conditions which require some non-nulls in the location, this is likely where the * process will start when invoked from line 79 of recognize above. Hyperarcs are most efficient to start from * since there are likely fewer hyperarcs in the host than nodes, or arcs. */ startHyperArc = (ruleHyperarc)L.hyperarcs.FirstOrDefault(ha => ((ruleHyperarc)ha).MustExist && (location.findLMappedHyperarc(ha) == null)); if (startHyperArc != null) { if (_in_parallel_) { Parallel.ForEach(host.hyperarcs, hostHyperArc => { if (!location.hyperarcs.Contains(hostHyperArc)) { checkHyperArcAvoidNegatives(location.copy(), startHyperArc, hostHyperArc); } }); } else { foreach (var hostHyperArc in host.hyperarcs.Where(hostHyperArc => !location.hyperarcs.Contains(hostHyperArc))) { checkHyperArcAvoidNegatives(location.copy(), startHyperArc, hostHyperArc); } } return; } #endregion #region Case 5: Check entire host for a matching node /* If no other hyperarcs to recognize look to a unlocated node. If one gets here then none of the above * three conditions were met (obviously) but this also implies that there are multiple components in the * LHS, and we are now jumping to a new one with this. This is potentially time intensive if there are * a lot of nodes in the host. We allow for the possibility that this recognition can be done in parallel. */ startNode = (ruleNode)L.nodes.FirstOrDefault(n => ((ruleNode)n).MustExist && (location.findLMappedNode(n) == null)); if (startNode != null) { if (_in_parallel_) { Parallel.ForEach(host.nodes, hostNode => { if (!location.nodes.Contains(hostNode)) { checkNodeAvoidNegatives(location.copy(), startNode, hostNode); } }); } else { foreach (var hostNode in host.nodes .Where(hostNode => !location.nodes.Contains(hostNode))) { checkNodeAvoidNegatives(location.copy(), startNode, hostNode); } } return; } #endregion #region Case 6: Check entire host for a matching arc var looseArc = (ruleArc)L.arcs.FirstOrDefault(a => ((ruleArc)a).MustExist && (location.findLMappedArc(a) == null)); /* the only way one can get here is if there are one or more arcs NOT connected to any nodes * in L - a floating arc, dangling on both sides, like an eyelash. */ if (looseArc != null) { if (_in_parallel_) { Parallel.ForEach(host.arcs, hostArc => { if ((!location.arcs.Contains(hostArc)) && (!location.nodes.Contains(hostArc.From)) && (!location.nodes.Contains(hostArc.To)) && (arcMatches(looseArc, hostArc) || arcMatchRelaxed(looseArc, hostArc, location))) { var newLocation = location.copy(); newLocation.arcs[L.arcs.IndexOf(looseArc)] = hostArc; FindPositiveStartElementAvoidNegatives(newLocation); } }); } else { foreach (var hostArc in host.arcs) { if ((!location.arcs.Contains(hostArc)) && (!location.nodes.Contains(hostArc.From)) && (!location.nodes.Contains(hostArc.To)) && (arcMatches(looseArc, hostArc) || arcMatchRelaxed(looseArc, hostArc, location))) { var newLocation = location.copy(); newLocation.arcs[L.arcs.IndexOf(looseArc)] = hostArc; FindPositiveStartElementAvoidNegatives(newLocation); } } } } #endregion }
private void findNegativeStartElement(option location) { if ((bool)AllNegativeElementsFound) { return; /* another sub-branch found a match to the negative elements. * There's no point in finding more than one, so this statement * aborts the search down this branch. */ } #region Case #1: Location found! No empty slots left in the location /* this is the only way to properly exit the recursive loop. */ if (!location.nodes.Contains(null) && !location.arcs.Contains(null) && !location.hyperarcs.Contains(null)) { if (FinalRuleChecks(location)) { if (!InvalidateWithRelaxation(location)) { AllNegativeElementsFound = true; } } return; } #endregion #region Case #2: build off of a hyperarc found so far - by looking for unfulfilled nodes /* the quickest approach to finding a new element in the LHS to host subgraph matching is to build * directly off of elements found so far. This is because we don't need to check amongst ALL elements in the * host (as is the case in the last three cases below). In this case we start with any hyperarcs * that have already been matched to one in the host, and see if it connects to any nodes that * have yet to be matched. */ var startHyperArc = (ruleHyperarc)L.hyperarcs.FirstOrDefault(ha => ((location.findLMappedHyperarc(ha) != null) && (ha.nodes.Any(n => (location.findLMappedNode(n) == null))))); if (startHyperArc != null) { var hostHyperArc = location.findLMappedHyperarc(startHyperArc); var newLNode = (ruleNode)startHyperArc.nodes.FirstOrDefault(n => (location.findLMappedNode(n) == null)); foreach (var n in hostHyperArc.nodes.Where(n => !location.nodes.Contains(n))) { checkForNegativeNode(location.copy(), newLNode, n); if ((bool)AllNegativeElementsFound) { return; } } return; } #endregion #region Case #2.5: build off of a partially matched arc /* unlike the other renditions of this function (findNewStartElement, * findPositiveStartElementAvoidNegatives) this has a situation in which an arc has only been * partially matched but the connected nodes were not touched because they were negative elements.*/ var startArc = (ruleArc)L.arcs.FirstOrDefault(a => (location.findLMappedArc(a) != null) && a.To != null && location.findLMappedNode(a.To) == null); if (startArc != null) { var hostArc = location.findLMappedArc(startArc); if ((hostArc.To != null) && !location.nodes.Contains(hostArc.To)) { checkForNegativeNode(location.copy(), (ruleNode)startArc.To, hostArc.To); } else if (!startArc.directionIsEqual && hostArc.From != null && !location.nodes.Contains(hostArc.From)) { checkForNegativeNode(location.copy(), (ruleNode)startArc.To, hostArc.From); } return; } startArc = (ruleArc)L.arcs.FirstOrDefault(a => (location.findLMappedArc(a) != null) && a.From != null && location.findLMappedNode(a.From) == null); if (startArc != null) { var hostArc = location.findLMappedArc(startArc); if ((hostArc.From != null) && !location.nodes.Contains(hostArc.From)) { checkForNegativeNode(location.copy(), (ruleNode)startArc.From, hostArc.From); } else if (!startArc.directionIsEqual && hostArc.To != null && !location.nodes.Contains(hostArc.To)) { checkForNegativeNode(location.copy(), (ruleNode)startArc.From, hostArc.To); } return; } #endregion #region Case #3: build off of a node found so far - by looking for unfulfilled arcs /* as stated above, the quickest approach is to build from elements that have already been found. * Therefore, we see if there are any nodes already matched to a node in L that has an arc in L * that has yet to be matched with a host arc. This is more efficient than the last 3 cases * because they look through the entire host, which is potentially large. */ var startNode = (ruleNode)L.nodes.FirstOrDefault(n => ((location.findLMappedNode(n) != null) && (n.arcs.Any(a => (location.findLMappedElement(a) == null))))); /* is there a node already matched (which would only occur if your recursed to get here) that has an * unrecognized arc attaced to it. If yes, try all possible arcs in the host with the one that needs * to be fulfilled in L. */ if (startNode != null) { var newLArc = startNode.arcs.FirstOrDefault(a => (location.findLMappedElement(a) == null)); if (newLArc is ruleHyperarc) { checkForNegativeHyperArc(location, startNode, location.findLMappedNode(startNode), (ruleHyperarc)newLArc); } else if (newLArc is ruleArc) { checkForNegativeArc(location, startNode, location.findLMappedNode(startNode), (ruleArc)newLArc); } return; } #endregion #region Case 4: Check entire host for a matching hyperarc /* if the above cases didn't match we try to match a hyperarc in the L to any in the host. Since the * prior three cases have conditions which require some non-nulls in the location, this is likely where the * process will start when invoked from line 87 of recognize above. Hyperarcs are most efficient to start from * since there are likely fewer hyperarcs in the host than nodes, or arcs. */ startHyperArc = (ruleHyperarc)L.hyperarcs.FirstOrDefault(ha => (location.findLMappedHyperarc(ha) == null)); if (startHyperArc != null) { foreach (var hostHyperArc in host.hyperarcs.Where(hostHyperArc => !location.hyperarcs.Contains(hostHyperArc))) { checkForNegativeHyperArc(location.copy(), startHyperArc, hostHyperArc); if ((bool)AllNegativeElementsFound) { return; } } return; } #endregion #region Case 5: Check entire host for a matching node /* If no other hyperarcs can be recognized, then look to a unlocated node. If one gets here then none of the above * three conditions were met (obviously) but this also implies that there are multiple components in the * LHS, and we are now jumping to a new one with this. This is potentially time intensive if there are * a lot of nodes in the host. We allow for the possibility that this recognition can be done in parallel. */ startNode = (ruleNode)L.nodes.FirstOrDefault(n => (location.findLMappedNode(n) == null)); if (startNode != null) { foreach (var hostNode in host.nodes.Where(hostNode => !location.nodes.Contains(hostNode))) { checkForNegativeNode(location.copy(), startNode, hostNode); if ((bool)AllNegativeElementsFound) { return; } } return; } #endregion #region Case 6: Check entire host for a matching arc var looseArc = (ruleArc)L.arcs.FirstOrDefault(a => (location.findLMappedArc(a) == null)); /* the only way one can get here is if there are one or more arcs NOT connected to any nodes * in L - a floating arc, dangling on both sides, like an eyelash. */ if (looseArc != null) { foreach (var hostArc in host.arcs) { if (!location.arcs.Contains(hostArc) && !location.nodes.Contains(hostArc.From) && !location.nodes.Contains(hostArc.To) && arcMatches(looseArc, hostArc)) { var newLocation = location.copy(); newLocation.arcs[L.arcs.IndexOf(looseArc)] = hostArc; findNegativeStartElement(newLocation); } if ((bool)AllNegativeElementsFound) { return; } } } #endregion }