/// <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); }
/// <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 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 } }