private void checkNodeAvoidNegatives(option location, ruleNode LNode, node hostNode) { if (!nodeMatches(LNode, hostNode, location) && !nodeMatchRelaxed(LNode, hostNode, location)) { return; } location.nodes[L.nodes.IndexOf(LNode)] = hostNode; var newLArc = LNode.arcs.FirstOrDefault(a => (((a is ruleHyperarc) && ((ruleHyperarc)a).MustExist) || ((a is ruleArc) && ((ruleArc)a).MustExist)) && (location.findLMappedElement(a) == null)); if (newLArc == null) { FindPositiveStartElementAvoidNegatives(location); } else if (newLArc is ruleHyperarc) { checkHyperArcAvoidNegatives(location, LNode, hostNode, (ruleHyperarc)newLArc); } else if (newLArc is ruleArc) { checkArcAvoidNegatives(location, LNode, hostNode, (ruleArc)newLArc); } }
private void checkForNegativeNode(option location, ruleNode LNode, node hostNode) { if (!nodeMatches(LNode, hostNode, location)) { return; } location.nodes[L.nodes.IndexOf(LNode)] = hostNode; var newLArc = LNode.arcs.FirstOrDefault(a => (location.findLMappedElement(a) == null)); if (newLArc == null) { findNegativeStartElement(location); } else if (newLArc is ruleHyperarc) { checkForNegativeHyperArc(location, LNode, hostNode, (ruleHyperarc)newLArc); } else if (newLArc is ruleArc) { checkForNegativeArc(location, LNode, hostNode, (ruleArc)newLArc); } }
/* 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 Boolean InvalidateWithRelaxation(option location) { if (negativeRelaxation.NumberAllowable == 0) { return(false); } var ruleNegElts = new List <graphElement>(); ruleNegElts.AddRange(L.nodes.FindAll(n => ((ruleNode)n).NotExist)); ruleNegElts.AddRange(L.arcs.FindAll(a => ((ruleArc)a).NotExist)); ruleNegElts.AddRange(L.hyperarcs.FindAll(h => ((ruleHyperarc)h).NotExist)); foreach (var ruleElt in ruleNegElts) { var hostElt = location.findLMappedElement(ruleElt); if (ruleElt.localLabels.Count < hostElt.localLabels.Count) { var rContainsAll = negativeRelaxation.FirstOrDefault( r => r.Matches(Relaxations.Contains_All_Local_Labels_Imposed, ruleElt)); if (rContainsAll != null) { negativeRelaxation.NumberAllowable--; rContainsAll.NumberAllowed--; negativeRelaxation.FulfilledItems.Add( new RelaxItem(Relaxations.Contains_All_Local_Labels_Imposed, 1, ruleElt, hostElt.localLabels.Count.ToString(CultureInfo.InvariantCulture))); return(true); } } if ((ruleElt is ruleNode) && (!((ruleNode)ruleElt).strictDegreeMatch) && ((node)ruleElt).degree != ((node)hostElt).degree) { var rStrictDegree = negativeRelaxation.FirstOrDefault(r => r.Matches(Relaxations.Strict_Degree_Match_Imposed, ruleElt)); if (rStrictDegree != null) { negativeRelaxation.NumberAllowable--; rStrictDegree.NumberAllowed--; negativeRelaxation.FulfilledItems.Add(new RelaxItem(Relaxations.Strict_Degree_Match_Imposed, 1, ruleElt, ((node)hostElt).degree.ToString( CultureInfo.InvariantCulture))); return(true); } } if ((ruleElt is ruleHyperarc) && (!((ruleHyperarc)ruleElt).strictNodeCountMatch) && ((hyperarc)ruleElt).degree != ((hyperarc)hostElt).degree) { var rStrictDegree = negativeRelaxation.FirstOrDefault(r => r.Matches(Relaxations.Strict_Node_Count_Imposed, ruleElt)); if (rStrictDegree != null) { negativeRelaxation.NumberAllowable--; rStrictDegree.NumberAllowed--; negativeRelaxation.FulfilledItems.Add(new RelaxItem(Relaxations.Strict_Node_Count_Imposed, 1, ruleElt, ((hyperarc)hostElt).degree.ToString( CultureInfo.InvariantCulture))); return(true); } } if (ruleElt is arc) { var rulearc = (ruleArc)ruleElt; var hostarc = (arc)hostElt; if (!rulearc.nullMeansNull && ((rulearc.To == null && hostarc.To != null) || (rulearc.From == null && hostarc.From != null))) { var rNullMeansNull = negativeRelaxation.FirstOrDefault(r => r.Matches(Relaxations.Null_Means_Null_Imposed, ruleElt)); if (rNullMeansNull != null) { negativeRelaxation.NumberAllowable--; rNullMeansNull.NumberAllowed--; negativeRelaxation.FulfilledItems.Add(new RelaxItem(Relaxations.Null_Means_Null_Imposed, 1, ruleElt, (rulearc.To == null) ? hostarc.To.name : hostarc.From.name)); return(true); } } if (!rulearc.directionIsEqual && ((rulearc.doublyDirected != hostarc.doublyDirected) || (rulearc.directed != hostarc.directed))) { var rDir = negativeRelaxation.FirstOrDefault( r => r.Matches(Relaxations.Direction_Is_Equal_Imposed, ruleElt)); if (rDir != null) { negativeRelaxation.NumberAllowable--; rDir.NumberAllowed--; negativeRelaxation.FulfilledItems.Add(new RelaxItem(Relaxations.Direction_Is_Equal_Imposed, 1, ruleElt)); return(true); } } } var ruleNegLabels = (ruleElt is ruleNode) ? ((ruleNode)ruleElt).negateLabels : (ruleElt is ruleArc) ? ((ruleArc)ruleElt).negateLabels : ((ruleHyperarc)ruleElt).negateLabels; foreach (var negLabel in ruleNegLabels) { var rLabel = negativeRelaxation.FirstOrDefault( r => r.Matches(Relaxations.Label_Imposed, ruleElt, negLabel)); if (rLabel != null) { negativeRelaxation.NumberAllowable--; rLabel.NumberAllowed--; negativeRelaxation.FulfilledItems.Add(new RelaxItem(Relaxations.Label_Imposed, 1, ruleElt, negLabel)); return(true); } } foreach (var lab in ruleElt.localLabels) { var rNegLabel = negativeRelaxation.FirstOrDefault( r => r.Matches(Relaxations.Negate_Label_Imposed, ruleElt, lab)); if (rNegLabel != null) { negativeRelaxation.NumberAllowable--; rNegLabel.NumberAllowed--; negativeRelaxation.FulfilledItems.Add(new RelaxItem(Relaxations.Negate_Label_Imposed, 1, ruleElt, lab)); return(true); } } } var localNumAllowable = negativeRelaxation.NumberAllowable; var usedRelaxItems = new List <RelaxItem>(); var usedFulfilledRelaxItems = new List <RelaxItem>(); foreach (var elt in ruleNegElts) { var rNotExist = negativeRelaxation.FirstOrDefault(r => r.Matches(Relaxations.Element_Made_Positive, elt) && usedRelaxItems.Count(ur => ur == r) < r.NumberAllowed); if (rNotExist == null) { break; } localNumAllowable--; usedRelaxItems.Add(rNotExist); usedFulfilledRelaxItems.Add(new RelaxItem(Relaxations.Element_Made_Positive, 1, elt)); } if ((localNumAllowable >= 0) && usedFulfilledRelaxItems.Count == ruleNegElts.Count) { negativeRelaxation.NumberAllowable = localNumAllowable; foreach (var r in usedRelaxItems) { r.NumberAllowed--; } negativeRelaxation.FulfilledItems.AddRange(usedFulfilledRelaxItems); return(true); } return(false); }
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 }