using System; using System.Collections.Generic; using System.Linq; using Microsoft.Msagl.Core.DataStructures; using Microsoft.Msagl.Core.GraphAlgorithms; using Microsoft.Msagl.Core.Layout; namespace Microsoft.Msagl.Layout.Layered { /// /// vertical constraints for Suquiyama scheme /// public class VerticalConstraintsForSugiyama { readonly Set _maxLayerOfGeomGraph = new Set(); /// /// nodes that are pinned to the max layer /// internal Set MaxLayerOfGeomGraph { get { return _maxLayerOfGeomGraph; } } readonly Set _minLayerOfGeomGraph = new Set(); /// /// nodes that are pinned to the min layer /// internal Set MinLayerOfGeomGraph { get { return _minLayerOfGeomGraph; } } Set> sameLayerConstraints = new Set>(); /// /// set of couple of nodes belonging to the same layer /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] public Set> SameLayerConstraints { get { return sameLayerConstraints; } } Set> upDownConstraints = new Set>(); /// /// set of node couples such that the first node of the couple is above the second one /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] internal Set> UpDownConstraints { get { return upDownConstraints; } } /// /// pins a node to max layer /// /// internal void PinNodeToMaxLayer(Node node) { MaxLayerOfGeomGraph.Insert(node); } /// /// pins a node to min layer /// /// internal void PinNodeToMinLayer(Node node) { System.Diagnostics.Debug.Assert(node != null); MinLayerOfGeomGraph.Insert(node); } internal bool IsEmpty { get { return MaxLayerOfGeomGraph.Count == 0 && MinLayerOfGeomGraph.Count == 0 && SameLayerConstraints.Count == 0 && this.UpDownConstraints.Count == 0; } } internal void Clear() { this.MaxLayerOfGeomGraph.Clear(); this.MinLayerOfGeomGraph.Clear(); this.SameLayerConstraints.Clear(); this.UpDownConstraints.Clear(); } Set gluedUpDownIntConstraints = new Set(); internal Set GluedUpDownIntConstraints { get { return gluedUpDownIntConstraints; } set { gluedUpDownIntConstraints = value; } } Dictionary nodeIdToIndex; BasicGraph intGraph; /// /// this graph is obtained from intGraph by glueing together same layer vertices /// BasicGraph gluedIntGraph; int maxRepresentative; int minRepresentative; /// /// Maps each node participating in same layer relation its representative on the layer. /// Dictionary sameLayerDictionaryOfRepresentatives = new Dictionary(); Dictionary> representativeToItsLayer = new Dictionary>(); internal IEnumerable GetFeedbackSet(BasicGraph intGraphPar, Dictionary nodeIdToIndexPar) { this.nodeIdToIndex = nodeIdToIndexPar; this.intGraph = intGraphPar; this.maxRepresentative = -1; this.minRepresentative = -1; CreateIntegerConstraints(); GlueTogetherSameConstraintsMaxAndMin(); AddMaxMinConstraintsToGluedConstraints(); RemoveCyclesFromGluedConstraints(); return GetFeedbackSet(); } private void RemoveCyclesFromGluedConstraints() { var feedbackSet= CycleRemoval. GetFeedbackSetWithConstraints(new BasicGraph(GluedUpDownIntConstraints, this.intGraph.NodeCount), null); //feedbackSet contains all glued constraints making constraints cyclic foreach (IntPair p in feedbackSet) GluedUpDownIntConstraints.Remove(p); } private void AddMaxMinConstraintsToGluedConstraints() { if (this.maxRepresentative != -1) for (int i = 0; i < this.intGraph.NodeCount; i++) { int j = NodeToRepr(i); if (j != maxRepresentative) GluedUpDownIntConstraints.Insert(new IntPair(maxRepresentative, j)); } if (this.minRepresentative != -1) for (int i = 0; i < this.intGraph.NodeCount; i++) { int j = NodeToRepr(i); if (j != minRepresentative) GluedUpDownIntConstraints.Insert(new IntPair(j, minRepresentative)); } } private void GlueTogetherSameConstraintsMaxAndMin() { CreateDictionaryOfSameLayerRepresentatives(); GluedUpDownIntConstraints = new Set(from p in UpDownInts select GluedIntPair(p)); } internal IntPair GluedIntPair(Tuple p) { return new IntPair(NodeToRepr(p.Item1), NodeToRepr(p.Item2)); } private IntPair GluedIntPair(IntEdge p) { return new IntPair(NodeToRepr(p.Source), NodeToRepr(p.Target)); } internal IntPair GluedIntPair(IntPair p) { return new IntPair(NodeToRepr(p.First), NodeToRepr(p.Second)); } internal IntEdge GluedIntEdge(IntEdge intEdge) { int sourceRepr = NodeToRepr(intEdge.Source); int targetRepr = NodeToRepr(intEdge.Target); IntEdge ie = new IntEdge(sourceRepr, targetRepr); ie.Separation = intEdge.Separation; ie.Weight = 0; ie.Edge = intEdge.Edge; return ie; } internal int NodeToRepr(int node) { int repr; if (this.sameLayerDictionaryOfRepresentatives.TryGetValue(node, out repr)) return repr; return node; } private void CreateDictionaryOfSameLayerRepresentatives() { BasicGraph graphOfSameLayers = CreateGraphOfSameLayers(); foreach (var comp in ConnectedComponentCalculator.GetComponents(graphOfSameLayers)) GlueSameLayerNodesOfALayer(comp); } private BasicGraph CreateGraphOfSameLayers() { return new BasicGraph(CreateEdgesOfSameLayers(), this.intGraph.NodeCount); } private IEnumerable CreateEdgesOfSameLayers() { List ret = new List(); if (maxRepresentative != -1) ret.AddRange(from v in maxLayerInt where v != maxRepresentative select new IntPair(maxRepresentative, v)); if (minRepresentative != -1) ret.AddRange(from v in minLayerInt where v != minRepresentative select new IntPair(minRepresentative, v)); ret.AddRange(from couple in SameLayerInts select new IntPair(couple.Item1, couple.Item2)); return ret; } /// /// maps all nodes of the component to one random representative /// /// private void GlueSameLayerNodesOfALayer(IEnumerable sameLayerNodes) { if (sameLayerNodes.Count() > 1) { int representative = -1; if (ComponentsIsMaxLayer(sameLayerNodes)) foreach (int v in sameLayerNodes) this.sameLayerDictionaryOfRepresentatives[v] = representative = maxRepresentative; else if (ComponentIsMinLayer(sameLayerNodes)) foreach (int v in sameLayerNodes) sameLayerDictionaryOfRepresentatives[v] = representative = minRepresentative; else { foreach (int v in sameLayerNodes) { if (representative == -1) representative = v; sameLayerDictionaryOfRepresentatives[v] = representative; } } this.representativeToItsLayer[representative] = sameLayerNodes; } } private bool ComponentIsMinLayer(IEnumerable component) { return component.Contains(this.minRepresentative); } private bool ComponentsIsMaxLayer(IEnumerable component) { return component.Contains(this.maxRepresentative); } List maxLayerInt = new List(); List minLayerInt = new List(); List> sameLayerInts = new List>(); /// /// contains also pinned max and min pairs /// internal List> SameLayerInts { get { return sameLayerInts; } set { sameLayerInts = value; } } List> upDownInts = new List>(); internal List> UpDownInts { get { return upDownInts; } set { upDownInts = value; } } private void CreateIntegerConstraints() { CreateMaxIntConstraints(); CreateMinIntConstraints(); CreateUpDownConstraints(); CreateSameLayerConstraints(); } private void CreateSameLayerConstraints() { this.SameLayerInts = CreateIntConstraintsFromStringCouples(this.SameLayerConstraints); } private void CreateUpDownConstraints() { this.UpDownInts = CreateIntConstraintsFromStringCouples(this.UpDownConstraints); } private List> CreateIntConstraintsFromStringCouples(Set> set) { return new List>(from couple in set let t = new Tuple(NodeIndex(couple.Item1), NodeIndex(couple.Item2)) where t.Item1 != -1 && t.Item2 != -1 select t); } private void CreateMinIntConstraints() { this.minLayerInt = CreateIntConstraintsFromExtremeLayer(this.MinLayerOfGeomGraph); if (minLayerInt.Count > 0) this.minRepresentative = minLayerInt[0]; } private void CreateMaxIntConstraints() { this.maxLayerInt = CreateIntConstraintsFromExtremeLayer(this.MaxLayerOfGeomGraph); if (maxLayerInt.Count > 0) this.maxRepresentative = maxLayerInt[0]; } private List CreateIntConstraintsFromExtremeLayer(Set setOfNodes) { return new List(from node in setOfNodes let index = NodeIndex(node) where index != -1 select index); } int NodeIndex(Node node) { int index; if (this.nodeIdToIndex.TryGetValue(node, out index)) return index; return -1; } private IEnumerable GetFeedbackSet() { this.gluedIntGraph = CreateGluedGraph(); return UnglueIntPairs(CycleRemoval.GetFeedbackSetWithConstraints(gluedIntGraph, this.GluedUpDownIntConstraints));//avoiding lazy evaluation } private IEnumerable UnglueIntPairs(IEnumerable gluedEdges) { foreach (IEdge gluedEdge in gluedEdges) foreach (IEdge ungluedEdge in UnglueEdge(gluedEdge)) yield return ungluedEdge; } private IEnumerable UnglueEdge(IEdge gluedEdge) { foreach (int source in UnglueNode(gluedEdge.Source)) foreach (IntEdge edge in intGraph.OutEdges(source)) if (NodeToRepr(edge.Target) == gluedEdge.Target) yield return edge; } private BasicGraph CreateGluedGraph() { return new BasicGraph(new Set(from edge in this.intGraph.Edges select GluedIntPair(edge)), this.intGraph.NodeCount); } IEnumerable UnglueNode(int node) { IEnumerable layer; if (this.representativeToItsLayer.TryGetValue(node, out layer)) return layer; return new int[] { node }; } internal int[] GetGluedNodeCounts() { int[] ret = new int[this.nodeIdToIndex.Count]; for (int node = 0; node < ret.Length; node++) ret[NodeToRepr(node)]++; return ret; } } }