/// <summary> /// Copies this instance of an arc and returns the copy. /// </summary> /// <returns>the copy of the arc.</returns> public virtual hyperarc copy() { var copyOfArc = new hyperarc(); copy(copyOfArc); return(copyOfArc); }
/// <summary> /// Replaces the type of the arc with inherited. /// </summary> /// <param name="origArc">The orig arc.</param> /// <param name="newType">The new type.</param> public void replaceHyperArcWithInheritedType(hyperarc origArc, Type newType) { addHyperArc(origArc.nodes, origArc.name, newType); origArc.copy(hyperarcs.Last()); hyperarcs.Last().DisplayShape = origArc.DisplayShape; removeHyperArc(origArc); }
internal Boolean ruleIsRecognized(hyperarc dangleHyperArc, List<node> neighborNodes, node nodeRemoved) { IEnumerable<string> neighborlabels = null ; neighborlabels = neighborNodes.Aggregate(neighborlabels, (current, n) => current.Union(n.localLabels)); return ((labelsMatch(dangleHyperArc.localLabels, neighborlabels.ToList())) && ((nodeRemoved == null) || (dangleHyperArc.nodes.Contains(nodeRemoved)))); }
/// <summary> /// Replaces the type of the arc with inherited. /// </summary> /// <param name="origArc">The orig arc.</param> /// <param name="newType">The new type.</param> public void replaceHyperArcWithInheritedType(hyperarc origArc, Type newType) { var newHa = addHyperArc(origArc.nodes, origArc.name, newType); origArc.copy(newHa); newHa.DisplayShape = origArc.DisplayShape; removeHyperArc(origArc); }
/// <summary> /// Removes the hyper arc. /// </summary> /// <param name="arcToRemove">The arc to remove.</param> public void removeHyperArc(hyperarc arcToRemove) { for (var i = arcToRemove.nodes.Count - 1; i >= 0; i--) { arcToRemove.DisconnectFrom(arcToRemove.nodes[i]); } hyperarcs.Remove(arcToRemove); }
/// <summary> /// Initializes a new instance of the <see cref="ruleHyperarc"/> class. /// Converts a hyperarc to a ruleHyperArc and returns it with default Booleans. /// The original hyperarc is unaffected. /// </summary> /// <param name="ha">The hyperarc, ha.</param> /// <returns></returns> public ruleHyperarc(hyperarc ha) : this(ha.name) { DisplayShape = ha.DisplayShape; TargetType = ha.GetType().ToString(); localLabels.AddRange(ha.localLabels); localVariables.AddRange(ha.localVariables); nodes.AddRange(ha.nodes); }
/// <summary> /// Adds the arc to the graph and connects it between these nodes. /// </summary> /// <param name="newArc">The new arc.</param> /// <param name="attachedNodes">The nodes.</param> public void addHyperArc(hyperarc newArc, List <node> attachedNodes = null) { if (attachedNodes != null) { foreach (var n in attachedNodes) { newArc.ConnectTo(n); } } hyperarcs.Add(newArc); }
/// <summary> /// Copies this instance into the (already intialized) copyOfHyperArc. /// </summary> /// <param name = "copyOfHyperArc">The copy of node.</param> public override void copy(hyperarc copyOfHyperArc) { base.copy(copyOfHyperArc); if (copyOfHyperArc is ruleHyperarc) { var rcopy = (ruleHyperarc)copyOfHyperArc; rcopy.containsAllLocalLabels = containsAllLocalLabels; rcopy.strictNodeCountMatch = strictNodeCountMatch; foreach (var label in negateLabels) { rcopy.negateLabels.Add(label); } } }
/// <summary> /// Creates and Adds a new hyperarc to the graph, and connects it /// to the stated nodes. /// </summary> /// <param name="attachedNodes">The nodes.</param> /// <param name="newName">The new name.</param> /// <param name="hyperarcType">The t.</param> public void addHyperArc(List <node> attachedNodes, string newName = "", Type hyperarcType = null) { hyperarc newArc; if (string.IsNullOrWhiteSpace(newName)) { newName = makeUniqueHyperArcName(); } if (hyperarcType == null || hyperarcType == typeof(hyperarc)) { newArc = new hyperarc(newName); } else { var types = new[] { typeof(string), typeof(node), typeof(node) }; var arcConstructor = hyperarcType.GetConstructor(types); var inputs = new object[] { newName, attachedNodes }; newArc = (hyperarc)arcConstructor.Invoke(inputs); } addHyperArc(newArc, attachedNodes); }
/// <summary> /// Predicts whether the option p invalidates option q. /// This invalidation is a tricky thing. For the most part, this function /// has been carefully coded to handle all cases. The only exceptions /// are from what the additional recognize and apply functions require or modify. /// This is handled by actually testing to see if this is true. /// </summary> /// <param name="p">The p.</param> /// <param name="q">The q.</param> /// <param name="cand">The cand.</param> /// <param name="confluenceAnalysis">The confluence analysis.</param> /// <returns></returns> private static int doesPInvalidateQ(option p, option q, candidate cand, ConfluenceAnalysis confluenceAnalysis) { #region Global Labels var pIntersectLabels = p.rule.L.globalLabels.Intersect(p.rule.R.globalLabels); var pRemovedLabels = new List <string>(p.rule.L.globalLabels); pRemovedLabels.RemoveAll(s => pIntersectLabels.Contains(s)); var pAddedLabels = new List <string>(p.rule.R.globalLabels); pAddedLabels.RemoveAll(s => pIntersectLabels.Contains(s)); if ( /* first check that there are no labels deleted that the other depeonds on*/ (q.rule.L.globalLabels.Intersect(pRemovedLabels).Any()) || /* adding labels is problematic if the other rule was recognized under * the condition of containsAllLocalLabels. */ ((q.rule.containsAllGlobalLabels) && (pAddedLabels.Any())) || /* adding labels is also problematic if you add a label that negates the * other rule. */ (pAddedLabels.Intersect(q.rule.negateLabels).Any())) { return(1); } #endregion #region Nodes /* first we check the nodes. If two options do not share any nodes, then * the whole block of code is skipped. q is to save time if comparing many * options on a large graph. However, since there is some need to understand what * nodes are saved in rule execution, the following two lists are defined outside * of q condition and are used in the Arcs section below. */ /* why are the following three parameters declared here and not in scope with the * other node parameters below? This is because they are used in the induced and * shape restriction calculations below - why calculate twice? */ int Num_pKNodes = 0; string[] pNodesKNames = null; node[] pKNodes = null; var commonNodes = q.nodes.Intersect(p.nodes); if (commonNodes.Any()) /* if there are no common nodes, then no need to check the details. */ { /* the following arrays of nodes are within the rule not the host. */ #region Check whether there are nodes that p will delete that q depends upon. var pNodesLNames = from n in p.rule.L.nodes where ((ruleNode)n).MustExist select n.name; var pNodesRNames = from n in p.rule.R.nodes select n.name; pNodesKNames = pNodesRNames.Intersect(pNodesLNames).ToArray(); Num_pKNodes = pNodesKNames.GetLength(0); pKNodes = new node[Num_pKNodes]; for (var i = 0; i < p.rule.L.nodes.Count; i++) { var index = Array.IndexOf(pNodesKNames, p.rule.L.nodes[i].name); if (index >= 0) { pKNodes[index] = p.nodes[i]; } else if (commonNodes.Contains(p.nodes[i])) { return(1); } } #endregion #region NodesModified /* in the above regions where deletions are checked, we also create lists for potentially * modified nodes, nodes common to both L and R. We will now check these. There are several * ways that a node can be modified: * 1. labels are removed * 2. labels are added (and potentially in the negabels of the other rule). * 3. number of arcs connected, which affect strictDegreeMatch * 4. variables are added/removed/changed * * There first 3 conditions are check all at once below. For the last one, it is impossible * to tell without executing extra functions that the user may have created for rule * recognition. Therefore, additional functions are not check in q confluence check. */ foreach (var commonNode in commonNodes) { var qNodeL = (ruleNode)q.rule.L.nodes[q.nodes.IndexOf(commonNode)]; var pNodeL = (ruleNode)p.rule.L.nodes[p.nodes.IndexOf(commonNode)]; var pNodeR = (ruleNode)p.rule.R[pNodeL.name]; pIntersectLabels = pNodeL.localLabels.Intersect(pNodeR.localLabels); pRemovedLabels = new List <string>(pNodeL.localLabels); pRemovedLabels.RemoveAll(s => pIntersectLabels.Contains(s)); pAddedLabels = new List <string>(pNodeR.localLabels); pAddedLabels.RemoveAll(s => pIntersectLabels.Contains(s)); if ( /* first check that there are no labels deleted that the other depeonds on*/ (qNodeL.localLabels.Intersect(pRemovedLabels).Any()) || /* adding labels is problematic if the other rule was recognized under * the condition of containsAllLocalLabels. */ ((qNodeL.containsAllLocalLabels) && (pAddedLabels.Any())) || /* adding labels is also problematic if you add a label that negates the * other rule. */ (pAddedLabels.Intersect(qNodeL.negateLabels).Any()) || /* if one rule uses strictDegreeMatch, we need to make sure the other rule * doesn't change the degree. */ (qNodeL.strictDegreeMatch && (pNodeL.degree != pNodeR.degree)) || /* actually, the degree can also change from free-arc embedding rules. These * are checked below. */ (qNodeL.strictDegreeMatch && (p.rule.embeddingRules.FindAll(e => (e.RNodeName.Equals(pNodeR.name))).Count > 0))) { return(1); } } #endregion } #endregion #region Arcs var commonArcs = q.arcs.Intersect(p.arcs); if (commonArcs.Any()) /* if there are no common arcs, then no need to check the details. */ { /* the following arrays of arcs are within the rule not the host. */ #region Check whether there are arcs that p will delete that q depends upon. var pArcsLNames = from n in p.rule.L.arcs where ((ruleArc)n).MustExist select n.name; var pArcsRNames = from n in p.rule.R.arcs select n.name; var pArcsKNames = new List <string>(pArcsRNames.Intersect(pArcsLNames)); var pKArcs = new arc[pArcsKNames.Count()]; for (var i = 0; i < p.rule.L.arcs.Count; i++) { if (pArcsKNames.Contains(p.rule.L.arcs[i].name)) { pKArcs[pArcsKNames.IndexOf(p.rule.L.arcs[i].name)] = p.arcs[i]; } else if (commonArcs.Contains(p.arcs[i])) { return(1); } } #endregion #region ArcsModified foreach (var commonArc in commonArcs) { var qArcL = (ruleArc)q.rule.L.arcs[q.arcs.IndexOf(commonArc)]; var pArcL = (ruleArc)p.rule.L.arcs[p.arcs.IndexOf(commonArc)]; var pArcR = (ruleArc)p.rule.R[pArcL.name]; pIntersectLabels = pArcL.localLabels.Intersect(pArcR.localLabels); pRemovedLabels = new List <string>(pArcL.localLabels); pRemovedLabels.RemoveAll(s => pIntersectLabels.Contains(s)); pAddedLabels = new List <string>(pArcR.localLabels); pAddedLabels.RemoveAll(s => pIntersectLabels.Contains(s)); if ( /* first check that there are no labels deleted that the other depeonds on*/ (qArcL.localLabels.Intersect(pRemovedLabels).Any()) || /* adding labels is problematic if the other rule was recognized under * the condition of containsAllLocalLabels. */ ((qArcL.containsAllLocalLabels) && (pAddedLabels.Any())) || /* adding labels is also problematic if you add a label that negates the * other rule. */ (pAddedLabels.Intersect(qArcL.negateLabels).Any()) || /* if one rule uses strictDegreeMatch, we need to make sure the other rule * doesn't change the degree. */ /* if one rule requires that an arc be dangling for correct recognition (nullMeansNull) * then we check to make sure that the other rule doesn't add a node to it. */ ((qArcL.nullMeansNull) && (((qArcL.From == null) && (pArcR.From != null)) || ((qArcL.To == null) && (pArcR.To != null)))) || /* well, even if the dangling isn't required, we still need to ensure that p * doesn't put a node on an empty end that q is expecting to belong * to some other node. */ ((pArcL.From == null) && (pArcR.From != null) && (qArcL.From != null)) || /* check the To direction as well */ ((pArcL.To == null) && (pArcR.To != null) && (qArcL.To != null)) || /* in q, the rule is not matching with a dangling arc, but we need to ensure that * the rule doesn't remove or re-connect the arc to something else in the K of the rule * such that the recogniation of the second rule is invalidated. q may be a tad strong * (or conservative) as there could still be confluence despite the change in connectivity. * How? I have yet to imagine. But clearly the assumption here is that change in * connectivity prevent confluence. */ ((pArcL.From != null) && (pNodesKNames != null && pNodesKNames.Contains(pArcL.From.name)) && ((pArcR.From == null) || (pArcL.From.name != pArcR.From.name))) || ((pArcL.To != null) && (pNodesKNames != null && pNodesKNames.Contains(pArcL.To.name)) && ((pArcR.To == null) || (pArcL.To.name != pArcR.To.name))) || /* Changes in Arc Direction * * /* finally we check that the changes in arc directionality (e.g. making * directed, making doubly-directed, making undirected) do not affect * the other rule. */ /* Here, the directionIsEqual restriction is easier to check than the * default case where directed match with doubly-directed and undirected * match with directed. */ ((qArcL.directionIsEqual) && ((!qArcL.directed.Equals(pArcR.directed)) || (!qArcL.doublyDirected.Equals(pArcR.doublyDirected)))) || ((qArcL.directed && !pArcR.directed) || (qArcL.doublyDirected && !pArcR.doublyDirected)) ) { return(1); } } #endregion } #endregion #region HyperArcs /* Onto hyperarcs! q is similiar to nodes - more so than arcs. */ var commonHyperArcs = q.hyperarcs.Intersect(p.hyperarcs); if (commonHyperArcs.Any()) { #region Check whether there are hyperarcs that p will delete that q.option depends upon. var pHyperArcsLNames = from n in p.rule.L.hyperarcs where ((ruleHyperarc)n).MustExist select n.name; var pHyperArcsRNames = from n in p.rule.R.hyperarcs select n.name; var pHyperArcsKNames = new List <string>(pHyperArcsRNames.Intersect(pHyperArcsLNames)); var pKHyperarcs = new hyperarc[pHyperArcsKNames.Count()]; for (var i = 0; i < p.rule.L.hyperarcs.Count; i++) { if (pHyperArcsKNames.Contains(p.rule.L.hyperarcs[i].name)) { pKHyperarcs[pHyperArcsKNames.IndexOf(p.rule.L.hyperarcs[i].name)] = p.hyperarcs[i]; } else if (commonHyperArcs.Contains(p.hyperarcs[i])) { return(1); } } #endregion #region HyperArcsModified foreach (var commonHyperArc in commonHyperArcs) { var qHyperArcL = (ruleHyperarc)q.rule.L.hyperarcs[q.hyperarcs.IndexOf(commonHyperArc)]; var pHyperArcL = (ruleHyperarc)p.rule.L.hyperarcs[p.hyperarcs.IndexOf(commonHyperArc)]; var pHyperArcR = (ruleHyperarc)p.rule.R[pHyperArcL.name]; pIntersectLabels = pHyperArcL.localLabels.Intersect(pHyperArcR.localLabels); pRemovedLabels = new List <string>(pHyperArcL.localLabels); pRemovedLabels.RemoveAll(s => pIntersectLabels.Contains(s)); pAddedLabels = new List <string>(pHyperArcR.localLabels); pAddedLabels.RemoveAll(s => pIntersectLabels.Contains(s)); if ( /* first check that there are no labels deleted that the other depends on*/ (qHyperArcL.localLabels.Intersect(pRemovedLabels).Any()) || /* adding labels is problematic if the other rule was recognized under * the condition of containsAllLocalLabels. */ ((qHyperArcL.containsAllLocalLabels) && (pAddedLabels.Any())) || /* adding labels is also problematic if you add a label that negates the * other rule. */ (pAddedLabels.Intersect(qHyperArcL.negateLabels).Any()) || /* if one rule uses strictDegreeMatch, we need to make sure the other rule * doesn't change the degree. */ (qHyperArcL.strictNodeCountMatch && (pHyperArcL.degree != pHyperArcR.degree))) { /* actually, the degree can also change from free-arc embedding rules. These * are checked below. */ return(1); } } #endregion } #endregion #region now we're left with some tricky checks... if (commonNodes.Any()) { #region if q is induced /* if q is induced then p will invalidate it, if it adds arcs between the * common nodes. */ if (q.rule.induced) { var pArcsLNames = from a in p.rule.L.arcs select a.name; if ((from newArc in p.rule.R.arcs.Where(a => !pArcsLNames.Contains(a.name)) where newArc.To != null && newArc.From != null let toName = newArc.To.name let fromName = newArc.To.name where pNodesKNames.Contains(toName) && pNodesKNames.Contains(fromName) where commonNodes.Contains(pKNodes[Array.IndexOf(pNodesKNames, toName)]) && commonNodes.Contains(pKNodes[Array.IndexOf(pNodesKNames, fromName)]) select toName).Any()) { return(1); } /* is there another situation in which an embedding rule in p may work against * q being an induced rule? It doesn't seem like it would seem embedding rules * reattach free-arcs. oh, what about arc duplication in embedding rules? nah. */ } #endregion #region shape restrictions for (int i = 0; i < Num_pKNodes; i++) { var pNode = pKNodes[i]; if (commonNodes.Contains(pNode)) { continue; } var pname = pNodesKNames[i]; var lNode = (node)p.rule.L[pname]; var rNode = (node)p.rule.R[pname]; if (q.rule.UseShapeRestrictions && p.rule.TransformNodePositions && !(MatrixMath.sameCloseZero(lNode.X, rNode.X) && MatrixMath.sameCloseZero(lNode.Y, rNode.Y) && MatrixMath.sameCloseZero(lNode.Z, rNode.Z))) { return(1); } if ((q.rule.RestrictToNodeShapeMatch && p.rule.TransformNodeShapes && lNode.DisplayShape != null && rNode.DisplayShape != null) && !(MatrixMath.sameCloseZero(lNode.DisplayShape.Height, rNode.DisplayShape.Height) && MatrixMath.sameCloseZero(lNode.DisplayShape.Width, rNode.DisplayShape.Width) && MatrixMath.sameCloseZero(p.positionTransform[0, 0], 1) && MatrixMath.sameCloseZero(p.positionTransform[1, 1], 1) && MatrixMath.sameCloseZero(p.positionTransform[1, 0]) && MatrixMath.sameCloseZero(p.positionTransform[0, 1]))) { return(1); } } #endregion } /* you've run the gauntlet of easy checks, now need to check * (1) if there is something caught by additional recognition functions, * or (2) NOTExist elements now exist. These can only be solving by an empirical * test, which will be expensive. * So, now we switch from conditions that return true (or a 1; p does invalidate q) to conditions that return false. */ if (q.rule.ContainsNegativeElements || q.rule.recognizeFuncs.Any() || p.rule.applyFuncs.Any()) { if (confluenceAnalysis == ConfluenceAnalysis.Full) { return(fullInvalidationCheck(p, q, cand)); } else { return(0); //return 0 is like "I don't know" } } return(-1); //like false, there is no invalidating - in otherwords confluence (maybe)! #endregion }
/// <summary> /// Finds the L mapped hyperarc. /// </summary> /// <param name="x">The x.</param> /// <returns></returns> public hyperarc findLMappedHyperarc(hyperarc x) { return(hyperarcs[rule.L.hyperarcs.IndexOf(x)]); }
/* if allowArcDuplication is true then for each rule that matches with the arc the arc will be * duplicated. */ #endregion #region Methods internal static Boolean hyperArcIsFree(hyperarc dangleHyperArc, designGraph host, out List <node> neighborNodes) { neighborNodes = dangleHyperArc.nodes.Where(n => !host.nodes.Contains(n)).ToList(); return(neighborNodes.Count > 0); }
/// <summary> /// Copies this.arc into the argument copyOfArc. /// </summary> /// <param name = "copyOfArc">The copy of arc.</param> public virtual void copy(hyperarc copyOfArc) { base.copy(copyOfArc); }
private void checkForNegativeHyperArc(option location, ruleHyperarc LHyperArc, hyperarc hostHyperArc) { if (!hyperArcMatches(LHyperArc, hostHyperArc)) { return; } location.hyperarcs[L.hyperarcs.IndexOf(LHyperArc)] = hostHyperArc; var newLNode = (ruleNode)LHyperArc.nodes.FirstOrDefault(n => (location.findLMappedNode(n) == null)); if (newLNode == null) { findNegativeStartElement(location); } else { foreach (var n in hostHyperArc.nodes.Where(n => !location.nodes.Contains(n))) { checkForNegativeNode(location.copy(), newLNode, n); 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. */ } } } }
private void checkHyperArcAvoidNegatives(option location, ruleHyperarc LHyperArc, hyperarc hostHyperArc) { if (!hyperArcMatches(LHyperArc, hostHyperArc) && !hyperArcMatchRelaxed(LHyperArc, hostHyperArc, location)) { return; } location.hyperarcs[L.hyperarcs.IndexOf(LHyperArc)] = hostHyperArc; var newLNode = (ruleNode)LHyperArc.nodes.FirstOrDefault(n => ((ruleNode)n).MustExist && (location.findLMappedNode(n) == null)); if (newLNode == null) { FindPositiveStartElementAvoidNegatives(location); } else { foreach (var n in hostHyperArc.nodes.Where(n => !location.nodes.Contains(n))) { checkNodeAvoidNegatives(location.copy(), newLNode, n); } } }