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