// Copyright (c) 2020 Kiel University and others.
//
// SPDX-License-Identifier: EPL-2.0

// Package preserveorder ports ELK Layered's stateful model-order comparators. // Their comparison history is observable and is retained across every call // made by a sort.
package preserveorder import ( basegraph ) type LongEdgeOrderingStrategy uint8 const ( DummyNodeOver LongEdgeOrderingStrategy = iota DummyNodeUnder LongEdgeEqual ) func ( LongEdgeOrderingStrategy) () int { switch { case DummyNodeOver: return math.MaxInt case DummyNodeUnder: return math.MinInt default: return 0 } } // NodeComparator is ELK 0.12.0's ModelOrderNodeComparator for ordinary D2 // model orders. BiggerThan and SmallerThan encode the transitive associations // accumulated while the sort calls Compare. type NodeComparator struct { Arena *layered.LGraphArena PreviousLayer []layered.LNodeID Ordering layered.OrderingStrategy LongEdgeOrder LongEdgeOrderingStrategy BeforePorts bool BiggerThan map[layered.LNodeID]map[layered.LNodeID]struct{} SmallerThan map[layered.LNodeID]map[layered.LNodeID]struct{} } func ( *layered.LGraphArena, []layered.LNodeID, layered.OrderingStrategy, LongEdgeOrderingStrategy, bool, ) *NodeComparator { return &NodeComparator{ Arena: , PreviousLayer: append([]layered.LNodeID(nil), ...), Ordering: , LongEdgeOrder: , BeforePorts: , BiggerThan: make(map[layered.LNodeID]map[layered.LNodeID]struct{}), SmallerThan: make(map[layered.LNodeID]map[layered.LNodeID]struct{}), } } func ( *NodeComparator) (, layered.LNodeID) int { if := .initializeAndRecall(, ); != 0 { return } := .Arena.Node() := .Arena.Node() := basegraph.Has(&.Properties, layered.ModelOrder) := basegraph.Has(&.Properties, layered.ModelOrder) if .Ordering == layered.OrderingPreferEdges || ! || ! { , := .incomingSourcePortFromPreviousLayer() , := .incomingSourcePortFromPreviousLayer() if && { := *.Arena.Port().Node := *.Arena.Port().Node if == { for , := range .Arena.Node().Ports { if == { .update(, ) return -1 } if == { .update(, ) return 1 } } := .connectedEdgeModelOrder() := .connectedEdgeModelOrder() if > { .update(, ) return 1 } .update(, ) return -1 } for , := range .PreviousLayer { if == { .update(, ) return -1 } if == { .update(, ) return 1 } } } if != { if := .handleHelperDummyNodes(, ); != 0 { .recordResult(, , ) return } if ! || ! { := .connectedEdgeModelOrder() := .connectedEdgeModelOrder() if > { .update(, ) return 1 } .update(, ) return -1 } } if ! && ! { if := .handleHelperDummyNodes(, ); != 0 { .recordResult(, , ) return } } } if && { := .Arena.Graph(.Arena.NodeGraph()) := basegraph.Get(&.Properties, layered.MaximumModelOrderNodes) := CalculateModelOrderOrGroupModelOrder( , &.Properties, &.Properties, ) := CalculateModelOrderOrGroupModelOrder( , &.Properties, &.Properties, ) if > { .update(, ) return 1 } .update(, ) return -1 } .update(, ) return -1 } func ( *NodeComparator) ( , layered.LNodeID, ) int { if , := .BiggerThan[]; ! { .BiggerThan[] = make(map[layered.LNodeID]struct{}) } else if containsNode(.BiggerThan[], ) { return 1 } if , := .BiggerThan[]; ! { .BiggerThan[] = make(map[layered.LNodeID]struct{}) } else if containsNode(.BiggerThan[], ) { return -1 } if , := .SmallerThan[]; ! { .SmallerThan[] = make(map[layered.LNodeID]struct{}) } else if containsNode(.SmallerThan[], ) { return -1 } if , := .SmallerThan[]; ! { .SmallerThan[] = make(map[layered.LNodeID]struct{}) } else if containsNode(.BiggerThan[], ) { // Preserve the source comparator's second biggerThan lookup. return 1 } return 0 } func ( *NodeComparator) ( layered.LNodeID, ) (layered.LPortID, bool) { := .Arena.Node() if .Layer == nil { return 0, false } := .Arena.Layer(*.Layer).ID - 1 for , := range .Ports { := .Arena.Port().IncomingEdges if len() == 0 { continue } := .Arena.Edge([0]) if .Source == nil || .Arena.Port(*.Source).Node == nil { continue } := .Arena.Node(*.Arena.Port(*.Source).Node) if .Layer != nil && .Arena.Layer(*.Layer).ID == { return *.Source, true } } return 0, false } func ( *NodeComparator) ( layered.LNodeID) int { for , := range .Arena.Node().Ports { := .Arena.Port().IncomingEdges if len() != 0 { return basegraph.Get( &.Arena.Edge([0]).Properties, layered.ModelOrder) } } return .LongEdgeOrder.ReturnValue() } func ( *NodeComparator) ( , layered.LNodeID, ) int { := .Arena.Node() := .Arena.Node() switch { case .Type == layered.LongEdgeNode && .Type == layered.NormalNode: , , := .dummyEndpoints() if ! { return 0 } := .nodeLayerID() if .nodeLayerID() != && .nodeLayerID() != { return 0 } if == || == { .update(, ) return 1 } return .Compare(, ) case .Type == layered.NormalNode && .Type == layered.LongEdgeNode: , , := .dummyEndpoints() if ! { return 0 } := .nodeLayerID() if .nodeLayerID() != && .nodeLayerID() != { return 0 } if == || == { .update(, ) return -1 } return .Compare(, ) case .Type == layered.LongEdgeNode && .Type == layered.LongEdgeNode: , , , , := .dummyEndpointPorts() , , , , := .dummyEndpointPorts() if ! || ! { return 0 } := .nodeLayerID() := .nodeLayerID() := .nodeLayerID() == := .nodeLayerID() == := .nodeLayerID() == := .nodeLayerID() == , := , if { = } else if { = } if { = } else if { = } if == { if .BeforePorts { switch { case && : := NewPortComparator( .Arena, .PreviousLayer, .Ordering, nil, , ) if .Compare(, ) > 0 { .update(, ) return 1 } .update(, ) return -1 case && : .update(, ) return 1 case && : .update(, ) return -1 case && : return 0 } } else { for , := range .Arena.Node().Ports { if == { .update(, ) return -1 } if == { .update(, ) return 1 } } } } _ = return .Compare(, ) } return 0 } func ( *NodeComparator) ( layered.LNodeID, ) (layered.LNodeID, layered.LNodeID, bool) { , , , , := .dummyEndpointPorts() return , , } func ( *NodeComparator) ( layered.LNodeID, ) (layered.LPortID, layered.LPortID, layered.LNodeID, layered.LNodeID, bool) { var , layered.LPortID , := false, false for , := range .Arena.Node().Ports { := .Arena.Port() if ! && len(.IncomingEdges) != 0 { := .Arena.Edge(.IncomingEdges[0]) if .Source != nil && .Arena.Port(*.Source).Node != nil { , = *.Source, true } } if ! && len(.OutgoingEdges) != 0 { := .Arena.Edge(.OutgoingEdges[0]) if .Target != nil && .Arena.Port(*.Target).Node != nil { , = *.Target, true } } } if ! || ! { return 0, 0, 0, 0, false } return , , *.Arena.Port().Node, *.Arena.Port().Node, true } func ( *NodeComparator) ( layered.LNodeID) int { := .Arena.Node().Layer if == nil { return math.MinInt } return .Arena.Layer(*).ID } func ( *NodeComparator) ( , layered.LNodeID, int, ) { if > 0 { .update(, ) } else { .update(, ) } } func ( *NodeComparator) (, layered.LNodeID) { .ensureOrderingEntry() .ensureOrderingEntry() := .BiggerThan[] := .BiggerThan[] := .SmallerThan[] := .SmallerThan[] [] = struct{}{} [] = struct{}{} for := range { .ensureOrderingEntry() [] = struct{}{} .SmallerThan[][] = struct{}{} for := range { .SmallerThan[][] = struct{}{} } } for := range { .ensureOrderingEntry() [] = struct{}{} .BiggerThan[][] = struct{}{} for := range { .BiggerThan[][] = struct{}{} } } } func ( *NodeComparator) ( layered.LNodeID) { if .BiggerThan[] == nil { .BiggerThan[] = make(map[layered.LNodeID]struct{}) } if .SmallerThan[] == nil { .SmallerThan[] = make(map[layered.LNodeID]struct{}) } } func ( *NodeComparator) () { .BiggerThan = make(map[layered.LNodeID]map[layered.LNodeID]struct{}) .SmallerThan = make(map[layered.LNodeID]map[layered.LNodeID]struct{}) } func containsNode( map[layered.LNodeID]struct{}, layered.LNodeID) bool { , := [] return } func compareInt(, int) int { if < { return -1 } if > { return 1 } return 0 }