/// <summary> /// Perform a node contraction (also: node identification) on two nodes. /// The resulting node will have targetname as name. /// The attributes of the endpoints are merged and copied to the target node, /// with head attributes taking precedence over tail attributes. /// /// Both node1 and node2 will be removed from the graph. /// Then all the neighbours of both endpoints are attached to the target, /// preserving direction and attributes. /// The new edges will be added to the root graph. /// If the graph is strict, no multiple edges will be added between nodes. /// </summary> /// <returns>target</returns> public Node Contract(Node node1, Node node2, string targetname) { Node target = MyRootGraph.GetOrAddNode(targetname); node1.CopyAttributesTo(target); node2.CopyAttributesTo(target); Merge(node1, target); Merge(node2, target); return(target); }
/// <summary> /// An edge can define a cluster as logical head. /// This is used to fake edges to and from clusters by clipping the edge on the borders of the logical head. /// </summary> public void SetLogicalHead(SubGraph lhead) { if (!lhead.IsCluster()) { throw new InvalidOperationException("ltail must be a cluster"); } if (!MyRootGraph.IsCompound()) { throw new InvalidOperationException("rootgraph must be compound for lheads/ltails to be used"); } string lheadname = lhead.GetName(); SafeSetAttribute("lhead", lheadname, ""); }
/// <summary> /// An edge can define a cluster as logical head. /// This is used to fake edges to and from clusters by clipping the edge on the borders of the logical head. /// </summary> public SubGraph LogicalHead() { if (!MyRootGraph.IsCompound()) { throw new InvalidOperationException("rootgraph must be compound for lheads/ltails to be used"); } string lheadname = GetAttribute("lhead"); if (lheadname == null) { return(null); } return(MyRootGraph.GetSubgraph(lheadname)); }
/// <summary> /// Merge a node into a target node. /// Basically, add the neighborhood of the node to the neighborhood of the target. /// The merge node will be removed from the graph. /// The new edges will be added to the root graph. /// /// If the graph is strict, no multiple edges will be added between nodes. /// /// If add_self_loops is true, edges between the merge node and the target node will be /// added as self loops to the target node. Self loops that already exist as such are always added. /// </summary> public void Merge(Node merge, Node target, bool add_self_loops = false) { // .Edges() won't iterate twice over self loops foreach (var e in merge.Edges()) { if (!e.IsBetween(merge, target) || add_self_loops) // Only add self loops if we want that { Node newtail = e.Tail().Equals(merge) ? target : e.Tail(); Node newhead = e.Head().Equals(merge) ? target : e.Head(); Edge newedge = MyRootGraph.GetOrAddEdge(newtail, newhead, e.GetName()); int returncode = e.CopyAttributesTo(newedge); // For some reason this may fail, even when the copying seems to have succeeded. Debug.Assert(returncode == 0); } } // The following will delete all edges connected to merge. MyRootGraph.Delete(merge); }