use of org.eclipse.elk.alg.common.networksimplex.NGraph in project elk by eclipse.
the class NetworkSimplexLayerer method initialize.
/**
* Helper method for the network simplex layerer. It instantiates all necessary attributes for
* the execution of the network simplex layerer and initializes them with their default values.
* All edges in the connected component given by the input argument will be determined, as well
* as the number of incoming and outgoing edges of each node ( {@code inDegree}, respectively
* {@code outDegree}). All sinks and source nodes in the connected component identified in this
* step will be added to {@code sinks}, respectively {@code sources}.
*
* @param theNodes
* a {@code Collection} containing all nodes of the graph
*/
private NGraph initialize(final List<LNode> theNodes) {
final Map<LNode, NNode> nodeMap = Maps.newHashMap();
// transform nodes
NGraph graph = new NGraph();
for (LNode lNode : theNodes) {
NNode nNode = NNode.of().origin(lNode).create(graph);
nodeMap.put(lNode, nNode);
}
// transform edges
for (LNode lNode : theNodes) {
for (LEdge lEdge : lNode.getOutgoingEdges()) {
// ignore self-loops
if (lEdge.isSelfLoop()) {
continue;
}
NEdge.of(lEdge).weight(1 * Math.max(1, lEdge.getProperty(LayeredOptions.PRIORITY_SHORTNESS))).delta(1).source(nodeMap.get(lEdge.getSource().getNode())).target(nodeMap.get(lEdge.getTarget().getNode())).create();
}
}
return graph;
}
use of org.eclipse.elk.alg.common.networksimplex.NGraph in project elk by eclipse.
the class NetworkSimplexLayerer method process.
/**
* The main method of the network simplex layerer. It determines an optimal layering of all
* nodes in the graph concerning a minimal length of all edges by using the network simplex
* algorithm described in {@literal Emden R. Gansner, Eleftherios Koutsofios, Stephen
* C. North, Kiem-Phong Vo: "A Technique for Drawing Directed Graphs", AT&T Bell Laboratories.
* Note that the execution time of this implemented algorithm has not been proven quadratic yet.
*
* @param theLayeredGraph
* a layered graph which initially only contains layerless nodes and is
* then filled with layers
* @param monitor
* the progress monitor
*/
public void process(final LGraph theLayeredGraph, final IElkProgressMonitor monitor) {
monitor.begin("Network simplex layering", 1);
layeredGraph = theLayeredGraph;
int thoroughness = theLayeredGraph.getProperty(LayeredOptions.THOROUGHNESS) * ITER_LIMIT_FACTOR;
List<LNode> theNodes = layeredGraph.getLayerlessNodes();
if (theNodes.size() < 1) {
monitor.done();
return;
}
// layer graph, each connected component separately
List<List<LNode>> connectedComponents = connectedComponents(theNodes);
int[] previousLayeringNodeCounts = null;
for (List<LNode> connComp : connectedComponents) {
// determine a limit on the number of iterations
int iterLimit = thoroughness * (int) Math.sqrt(connComp.size());
NGraph graph = initialize(connComp);
// execute the network simplex algorithm on the (sub-)graph
NetworkSimplex.forGraph(graph).withIterationLimit(iterLimit).withPreviousLayering(previousLayeringNodeCounts).withBalancing(true).execute(monitor.subTask(1));
// the layers are store in the NNode's layer field.
List<Layer> layers = layeredGraph.getLayers();
for (NNode nNode : graph.nodes) {
// add additional layers to match required number
while (layers.size() <= nNode.layer) {
layers.add(layers.size(), new Layer(layeredGraph));
}
LNode lNode = (LNode) nNode.origin;
lNode.setLayer(layers.get(nNode.layer));
}
if (connectedComponents.size() > 1) {
previousLayeringNodeCounts = new int[layeredGraph.getLayers().size()];
int layerIdx = 0;
for (Layer l : layeredGraph) {
previousLayeringNodeCounts[layerIdx++] = l.getNodes().size();
}
}
}
// empty the list of unlayered nodes
theNodes.clear();
// release the created resources
dispose();
monitor.done();
}
use of org.eclipse.elk.alg.common.networksimplex.NGraph in project elk by eclipse.
the class NetworkSimplexPlacer method prepare.
// ------------------------------------------------------------------------------------------------
// Preparation
// ------------------------------------------------------------------------------------------------
private void prepare() {
this.nGraph = new NGraph();
// "integerify" port anchor and port positions
// note that margin.top and margin.bottom are not required to be integral
// since they do not influence the offset calculation for the edges
// ... while we're at it, we assign ids to the nodes and edges
int nodeIdx = 0;
int edgeIdx = 0;
for (Layer l : lGraph) {
for (LNode lNode : l) {
lNode.id = nodeIdx++;
for (LEdge e : lNode.getOutgoingEdges()) {
e.id = edgeIdx++;
}
// if a node is flexible, an edge attaches to the port itself within
// the auxiliary graph, thus the anchor must be integer
// otherwise the port position can be altered such that it accounts for the anchor's position as well
boolean anchorMustBeInteger = isFlexibleNode(lNode);
for (LPort p : lNode.getPorts()) {
if (anchorMustBeInteger) {
// anchor
double y = p.getAnchor().y;
if (y != Math.floor(y)) {
double offset = y - Math.round(y);
p.getAnchor().y -= offset;
}
}
// port + anchor
double y = p.getPosition().y + p.getAnchor().y;
if (y != Math.floor(y)) {
double offset = y - Math.round(y);
p.getPosition().y -= offset;
}
}
}
}
this.nodeCount = nodeIdx;
this.edgeCount = edgeIdx;
this.nodeReps = new NodeRep[nodeIdx];
this.edgeReps = new EdgeRep[edgeIdx];
this.flexibleWhereSpacePermitsEdges.clear();
}
use of org.eclipse.elk.alg.common.networksimplex.NGraph in project elk by eclipse.
the class NetworkSimplexPlacer method insertFlexibleWhereSpaceAuxiliaryEdges.
/**
* Inserts auxiliary edges for the case that {@link NodeFlexibility#NODE_SIZE_WHERE_SPACE_PERMITS} node exist.
*/
private void insertFlexibleWhereSpaceAuxiliaryEdges() {
int minLayer = nGraph.nodes.stream().map(n -> n.layer).min(Integer::compare).get();
int maxLayer = nGraph.nodes.stream().map(n -> n.layer).max(Integer::compare).get();
int usedLayers = maxLayer - minLayer;
NNode globalSource = NNode.of().create(nGraph);
NNode globalSink = NNode.of().create(nGraph);
// make sure the distance between source and sink is preserved
NEdge.of().weight(NODE_SIZE_WEIGHT_STATIC * 2).delta(usedLayers).source(globalSource).target(globalSink).create();
// fix the position of most non-flexible nodes and make sure the flexible nodes
// can only increase in size
Arrays.stream(nodeReps).filter(nr -> nr.origin.getType() == NodeType.NORMAL).filter(// allow leaves to move
nr -> nr.origin.getPorts().size() > 1).forEach(nr -> {
NEdge.of().weight(0).delta(nr.tail.layer - minLayer).source(globalSource).target(nr.tail).create();
NEdge.of().weight(0).delta(usedLayers - nr.head.layer).source(nr.head).target(globalSink).create();
});
}
use of org.eclipse.elk.alg.common.networksimplex.NGraph in project elk by eclipse.
the class NetworkSimplexPlacer method transformFixedPosNode.
/**
* @return a {@link NodeRep} instance that basically contains two references to {@link LNode}.
*/
private NodeRep transformFixedPosNode(final LNode lNode) {
NNode singleNode = NNode.of().origin(lNode).type("non-flexible").create(nGraph);
// register the ports with the node
lNode.getPorts().stream().filter(p -> PortSide.SIDES_EAST_WEST.contains(p.getSide())).forEach(p -> portMap.put(p, singleNode));
return new NodeRep(lNode, false, singleNode, singleNode);
}
Aggregations