/// <summary> /// Creates a random graph that takes two parameters: the number of nodes, /// and the average degree. Note: that there is no guarantee that the graph /// will be connected. /// </summary> /// <param name = "numNodes">The number of nodes.</param> /// <param name = "aveDegree">The average degree.</param> /// <returns></returns> public static designGraph CreateRandomGraph(int numNodes, int aveDegree) { var randomGraph = new designGraph { name = "RandomGraph_with_" + numNodes + "_nodes_and_degree_of_" + aveDegree }; var arcProb = (double)aveDegree / (numNodes + 1); var rnd = new Random(); for (var i = 0; i != numNodes; i++) { randomGraph.addNode(); } for (var i = 0; i != numNodes; i++) { for (var j = i + 1; j != numNodes; j++) { if ((double)rnd.Next(1000) / 1000 <= arcProb) { randomGraph.addArc(randomGraph.nodes[i], randomGraph.nodes[j]); } } } return(randomGraph); }
public designGraph copy() { /* at times we want to copy a graph and not refer to the same objects. This happens mainly * (rather initially what inspired this function) when the seed graph is copied into a candidate.*/ int toIndex, fromIndex; designGraph copyOfGraph = new designGraph(); copyOfGraph.name = name; foreach (string label in globalLabels) { copyOfGraph.globalLabels.Add(label.ToString()); } foreach (double v in globalVariables) { copyOfGraph.globalVariables.Add(v); } foreach (node origNode in nodes) { copyOfGraph.nodes.Add(origNode.copy()); } foreach (arc origArc in arcs) { arc copyOfArc = origArc.copy(); toIndex = nodes.FindIndex(delegate(node a) { return(a == origArc.To); }); fromIndex = nodes.FindIndex(delegate(node b) { return(b == origArc.From); }); copyOfGraph.addArc(copyOfArc, fromIndex, toIndex); } return(copyOfGraph); }
/// <summary> /// Creates a complete graph where every node is connected to every /// other node by an arc. /// </summary> /// <param name="numNodes">The number of nodes.</param> /// <returns></returns> public static designGraph CreateCompleteGraph(int numNodes) { var numArcs = numNodes * (numNodes - 1) / 2; var completeGraph = new designGraph { name = "CompleteGraph_with_" + numNodes + "_nodes_and_" + numArcs + "_arcs" }; for (var i = 0; i != numNodes; i++) { completeGraph.addNode(); } for (var i = 0; i != numNodes; i++) { for (var j = i + 1; j != numNodes; j++) { completeGraph.addArc(completeGraph.nodes[i], completeGraph.nodes[j]); } } return(completeGraph); }
/// <summary> /// Copies the specified make deep copy. /// </summary> /// <param name = "MakeDeepCopy">if set to <c>true</c> [make deep copy].</param> /// <returns></returns> public designGraph copy(Boolean MakeDeepCopy = true) { /* at times we want to copy a graph and not refer to the same objects. This happens mainly * (rather initially what inspired this function) when the seed graph is copied into a candidate.*/ var copyOfGraph = new designGraph { name = name }; foreach (var label in globalLabels) { copyOfGraph.globalLabels.Add(label); } foreach (var v in globalVariables) { copyOfGraph.globalVariables.Add(v); } foreach (var origNode in nodes) { copyOfGraph.addNode(MakeDeepCopy ? origNode.copy() : origNode); } foreach (var origArc in arcs) { if (MakeDeepCopy) { var copyOfArc = origArc.copy(); var toIndex = nodes.FindIndex(a => (a == origArc.To)); var fromIndex = nodes.FindIndex(b => (b == origArc.From)); node fromNode = null; if (fromIndex > -1) { fromNode = copyOfGraph.nodes[fromIndex]; } node toNode = null; if (toIndex > -1) { toNode = copyOfGraph.nodes[toIndex]; } copyOfGraph.addArc(copyOfArc, fromNode, toNode); } else { copyOfGraph.arcs.Add(origArc); } } foreach (var origHyperArc in hyperarcs) { if (MakeDeepCopy) { var copyOfHyperArc = origHyperArc.copy(); var attachedNodes = new List <node>(); foreach (var n in origHyperArc.nodes) { var index = nodes.FindIndex(a => (a == n)); attachedNodes.Add(copyOfGraph.nodes[index]); } copyOfGraph.addHyperArc(copyOfHyperArc, attachedNodes); } else { copyOfGraph.hyperarcs.Add(origHyperArc); } } return(copyOfGraph); }
private void freeArcEmbedding(designGraph Lmapping, designGraph host, designGraph Rmapping) { /* There are nodes in host which may have been left dangling due to the fact that their * connected nodes were part of the L-R deletion. These now need to be either 1) connected * up to their new nodes, 2) their references to old nodes need to be changed to null if * intentionally left dangling, or 3) the arcs are to be removed. In the function * removeLdiffKfromHost we remove old nodes but leave their references intact on their * connected arcs. This allows us to quickly find the list of freeArcs that are candidates * for the embedding rules. Essentially, we are capturing the neighborhood within the host * for the rule application, that is the arcs that are affected by the deletion of the L-R * subgraph. Should one check non-dangling non-neighborhood arcs? No, this would seem to * cause a duplication of such an arc. Additionally, what node in host should the arc remain * attached to? There seems to be no rigor in applying these more global (non-neighborhood) * changes within the literature as well for the general edNCE method. */ sbyte freeEndIdentifier; node newNodeToConnect, nodeRemovedinLdiffRDeletion, toNode, fromNode; node neighborNode = null; int numOfArcs = host.arcs.Count; for (int i = 0; i != numOfArcs; i++) { /* first, check to see if the arc is really a freeArc that needs updating. */ if (embeddingRule.arcIsFree(host.arcs[i], host, out freeEndIdentifier, neighborNode)) { arc freeArc = host.arcs[i]; /* For each of the embedding rules, we see if it is applicable to the identified freeArc. * The rule then modifies the arc by simply pointing it to the new node in R as indicated * by the embedding Rule's RNodeName. NOTE: the order of the rules are important. If two * rules are 'recognized' with the same freeArc only the first one will modify it, as it * will then remove it from the freeArc list. This is useful in that rules may have precedence * to one another. There is an exception if the rule has allowArcDuplication set to true, * since this would simply create a copy of the arc. */ foreach (embeddingRule eRule in embeddingRules) { newNodeToConnect = eRule.findNewNodeToConnect(R, Rmapping); nodeRemovedinLdiffRDeletion = eRule.findDeletedNode(L, Lmapping); if (eRule.ruleIsRecognized(freeEndIdentifier, freeArc, neighborNode, nodeRemovedinLdiffRDeletion)) { #region set up new connection points if (freeEndIdentifier >= 0) { if (eRule.newDirection >= 0) { toNode = newNodeToConnect; fromNode = freeArc.From; } else { toNode = freeArc.From; fromNode = newNodeToConnect; } } else { if (eRule.newDirection <= 0) { fromNode = newNodeToConnect; toNode = freeArc.To; } else { fromNode = freeArc.To; toNode = newNodeToConnect; } } #endregion #region if making a copy of arc, duplicate it and all the characteristics if (eRule.allowArcDuplication) { /* under the allowArcDuplication section, we will be making a copy of the * freeArc. This seems a little error-prone at first, since if there is only * one rule that applies to freeArc then we will have good copy and the old * bad copy. However, at the end of this function, we go through the arcs again * and remove any arcs that still appear free. This also serves the purpose to * delete any dangling nodes that were not recognized in any rules. */ host.addArc(freeArc.copy(), fromNode, toNode); } #endregion #region else, just update the old freeArc else { freeArc.From = fromNode; freeArc.To = toNode; break; /* skip to the next arc */ /* this is done so that no more embedding rules will be checked with this freeArc.*/ } #endregion } } } } #region clean up (i.e. delete) any freeArcs that are still in host.arcs for (int i = host.arcs.Count - 1; i >= 0; i--) { /* this seems a little archaic to use this i-counter instead of foreach. * the issue is that since we are removing nodes from the list as we go * through it, we very well can't use foreach. The countdown allows us to * disregard problems with the deleting. */ if ((host.arcs[i].From != null && !host.nodes.Contains(host.arcs[i].From)) || (host.arcs[i].To != null && !host.nodes.Contains(host.arcs[i].To))) host.removeArc(host.arcs[i]); } #endregion }
private void addRdiffKtoD(designGraph Lmapping, designGraph D, designGraph Rmapping) { /* in this adding and gluing function, we are careful to distinguish * the Lmapping or recognized subgraph of L in the host - heretofore * known as Lmapping - from the mapping of new nodes and arcs of the * graph, which we call Rmapping. This is a complex function that goes * through 4 key steps: * 1. add the new nodes that are in R but not in L. * 2. update the remaining nodes common to L&R (aka K nodes) that might * have had some label changes. * 3. add the new arcs that are in R but not in L. These may connect to * either the newly connected nodes from step 1 or from the updated nodes * of step 2. * 4. update the arcs common to L&R (aka K arcs) which might now be connected * to new nodes created in step 1 (they are already connected to * nodes in K). Also make sure to update their labels just as K nodes were * updated in step 2. /* here are some placeholders used in this bookeeping. Many are used multiple times * so we might as well declare them just once at the start. */ int index1, index2; node from, to, KNode; arc KArc; for (int i = 0; i != R.nodes.Count; i++) { ruleNode rNode = (ruleNode)R.nodes[i]; #region Step 1. add new nodes to D if (!L.nodes.Exists(delegate(node b) { return (b.name == rNode.name); })) { D.addNode(rNode.nodeType); /* create a new node. */ Rmapping.nodes[i] = D.nodes[D.lastNode]; /* make sure it's referenced in Rmapping. */ /* labels cannot be set equal, since that merely sets the reference of this list * to the same value. So, we need to make a complete copy. */ rNode.copy(D.nodes[D.lastNode]); /* give that new node a name and labels to match with the R. */ } #endregion #region Step 2. update K nodes else { /* else, we may need to modify or update the node. In the pure graph * grammar sense this is merely changing the local labels. In a way, * this is a like a set grammar. We need to find the labels in L that * are no longer in R and delete them, and we need to add the new labels * that are in R but not already in L. The ones common to both are left * alone. */ index1 = L.nodes.FindIndex(delegate(node b) { return (rNode.name == b.name); }); /* find index of the common node in L...*/ KNode = Lmapping.nodes[index1]; /*...and then set Knode to the actual node in D.*/ Rmapping.nodes[i] = KNode; /*also, make sure that the Rmapping is to this same node.*/ foreach (string a in L.nodes[index1].localLabels) if (!rNode.localLabels.Contains(a)) KNode.localLabels.Remove(a); /* removing the labels in L but not in R...*/ foreach (string a in rNode.localLabels) if (!L.nodes[index1].localLabels.Contains(a)) KNode.localLabels.Add(a.ToString()); /*...and adding the label in R but not in L.*/ foreach (double a in L.nodes[index1].localVariables) /* do the same now, for the variables. */ if (!rNode.localVariables.Contains(a)) KNode.localVariables.Remove(a); /* removing the labels in L but not in R...*/ foreach (double a in rNode.localVariables) if (!L.nodes[index1].localVariables.Contains(a)) KNode.localVariables.Add(a); /*...and adding the label in R but not in L.*/ KNode.shapekey = rNode.shapekey; } } #endregion /* now moving onto the arcs (a little more challenging actually). */ for (int i = 0; i != R.arcs.Count; i++) { ruleArc rArc = (ruleArc)R.arcs[i]; #region Step 3. add new arcs to D if (!L.arcs.Exists(delegate(arc b) { return (b.name == rArc.name); })) { #region setting up where arc comes from if (rArc.From == null) from = null; else if (L.nodes.Exists(delegate(node b) { return (b.name == rArc.From.name); })) /* if the arc is coming from a node that is in K, then it must've been * part of the location (or Lmapping) that was originally recognized.*/ { index1 = L.nodes.FindIndex(delegate(node b) { return (rArc.From.name == b.name); }); /* therefore we need to find the position/index of that node in L. */ from = Lmapping.nodes[index1]; /* and that index1 will correspond to its image in Lmapping. Following, * the Lmapping reference, we get to the proper node reference in D. */ } else /* if not in K then the arc connects to one of the new nodes that were * created at the beginning of this function (see step 1) and is now * one of the references in Rmapping. */ { index1 = R.nodes.FindIndex(delegate(node b) { return (rArc.From.name == b.name); }); from = Rmapping.nodes[index1]; } #endregion #region setting up where arc goes to /* this code is the same of "setting up where arc comes from - except here * we do the same for the to connection of the arc. */ if (rArc.To == null) to = null; else if (L.nodes.Exists(delegate(node b) { return (b.name == rArc.To.name); })) { index1 = L.nodes.FindIndex(delegate(node b) { return (rArc.To.name == b.name); }); to = Lmapping.nodes[index1]; } else { index1 = R.nodes.FindIndex(delegate(node b) { return (rArc.To.name == b.name); }); to = Rmapping.nodes[index1]; } #endregion D.addArc(rArc.name, rArc.arcType, from, to); Rmapping.arcs[i] = D.arcs[D.lastArc]; rArc.copy(D.arcs[D.lastArc]); } #endregion #region Step 4. update K arcs else { index2 = L.arcs.FindIndex(delegate(arc b) { return (rArc.name == b.name); }); /* first find the position of the same arc in L. */ ruleArc currentLArc = (ruleArc)L.arcs[index2]; KArc = Lmapping.arcs[index2]; /* then find the actual arc in D that is to be changed.*/ /* one very subtle thing just happend here! (07/06/06) if the direction is reversed, then * you might mess-up this Karc. We need to establish a boolean so that references * incorrectly altered. */ Boolean KArcIsReversed = false; if ((Lmapping.nodes.IndexOf(KArc.From) != L.nodes.IndexOf(currentLArc.From)) && (Lmapping.nodes.IndexOf(KArc.To) != L.nodes.IndexOf(currentLArc.To))) KArcIsReversed = true; Rmapping.arcs[i] = KArc; /*similar to Step 3., we first find how to update the from and to. */ if ((currentLArc.From != null) && (rArc.From == null)) { /* this is a rare case in which you actually want to break an arc from its attached * node. If the corresponding L arc is not null only! if it is null then it may be * actually connected to something in the host, and we are in no place to remove it. */ if (KArcIsReversed) KArc.To = null; else KArc.From = null; } else if (rArc.From != null) { index1 = R.nodes.FindIndex(delegate(node b) { return (rArc.From.name == b.name); }); /* find the position of node that this arc is supposed to connect to in R */ if (KArcIsReversed) KArc.To = Rmapping.nodes[index1]; else KArc.From = Rmapping.nodes[index1]; } /* now do the same for the To connection. */ if ((currentLArc.To != null) && (rArc.To == null)) { if (KArcIsReversed) KArc.From = null; else KArc.To = null; } else if (rArc.To != null) { index1 = R.nodes.FindIndex(delegate(node b) { return (rArc.To.name == b.name); }); if (KArcIsReversed) KArc.From = Rmapping.nodes[index1]; else KArc.To = Rmapping.nodes[index1]; } /* just like in Step 2, we may need to update the labels of the arc. */ foreach (string a in currentLArc.localLabels) if (!rArc.localLabels.Contains(a)) KArc.localLabels.Remove(a); foreach (string a in rArc.localLabels) if (!currentLArc.localLabels.Contains(a)) KArc.localLabels.Add(a.ToString()); foreach (double a in currentLArc.localVariables) if (!rArc.localVariables.Contains(a)) KArc.localVariables.Remove(a); foreach (double a in rArc.localVariables) if (!currentLArc.localVariables.Contains(a)) KArc.localVariables.Add(a); KArc.curveStyle = rArc.curveStyle; if (!KArc.directed || (KArc.directed && currentLArc.directionIsEqual)) KArc.directed = rArc.directed; /* if the KArc is currently undirected or if it is and direction is equal * then the directed should be inherited from R. */ if (!KArc.doublyDirected || (KArc.doublyDirected && currentLArc.directionIsEqual)) KArc.doublyDirected = rArc.doublyDirected; KArc.fromConnector = rArc.fromConnector; KArc.toConnector = rArc.toConnector; } #endregion } }
public designGraph copy() { /* at times we want to copy a graph and not refer to the same objects. This happens mainly * (rather initially what inspired this function) when the seed graph is copied into a candidate.*/ int toIndex, fromIndex; designGraph copyOfGraph = new designGraph(); copyOfGraph.name = name; foreach (string label in globalLabels) copyOfGraph.globalLabels.Add(label.ToString()); foreach (double v in globalVariables) copyOfGraph.globalVariables.Add(v); foreach (node origNode in nodes) { copyOfGraph.nodes.Add(origNode.copy()); } foreach (arc origArc in arcs) { arc copyOfArc = origArc.copy(); toIndex = nodes.FindIndex(delegate(node a) { return (a == origArc.To); }); fromIndex = nodes.FindIndex(delegate(node b) { return (b == origArc.From); }); copyOfGraph.addArc(copyOfArc, fromIndex, toIndex); } return copyOfGraph; }