private void initialize(final LGraph graph) { layeredGraph = graph; int layerCount = graph.getLayers().size(); bestNodeOrder = new LNode[layerCount][]; currentNodeOrder = new LNode[layerCount][]; originalNodeOrder = new LNode[layerCount][]; ListIterator<Layer> layerIter = graph.getLayers().listIterator(); while (layerIter.hasNext()) { Layer layer = layerIter.next(); int layerNodeCount = layer.getNodes().size(); assert layerNodeCount > 0; int layerIndex = layerIter.previousIndex(); bestNodeOrder[layerIndex] = new LNode[layerNodeCount]; currentNodeOrder[layerIndex] = new LNode[layerNodeCount]; originalNodeOrder[layerIndex] = new LNode[layerNodeCount]; ListIterator<LNode> nodeIter = layer.getNodes().listIterator(); int id = 0; while (nodeIter.hasNext()) { LNode node = nodeIter.next(); node.id = id++; currentNodeOrder[layerIndex][nodeIter.previousIndex()] = node; bestNodeOrder[layerIndex][nodeIter.previousIndex()] = node; originalNodeOrder[layerIndex][nodeIter.previousIndex()] = node; } } crossingCounter = new AllCrossingsCounter(currentNodeOrder); if (greedySwitchType.useHyperedgeCounter()) { crossingCounter.useHyperedgeCounter(); } }
/** * Splits this linear segment before the given node. The returned segment contains all nodes * from the given node onward, with their ID set to the new segment's ID. Those nodes are * removed from this segment. * * @param node the node to split the segment at. * @param newId the new segment's id. * @return new linear segment with ID {@code -1} and all nodes from {@code node} onward. */ LinearSegment split(final LNode node, final int newId) { int nodeIndex = nodes.indexOf(node); // Prepare the new segment LinearSegment newSegment = new LinearSegment(); newSegment.id = newId; // Move nodes to the new segment ListIterator<LNode> iterator = nodes.listIterator(nodeIndex); while (iterator.hasNext()) { LNode movedNode = iterator.next(); movedNode.id = newId; newSegment.nodes.add(movedNode); iterator.remove(); } return newSegment; }
/** * Put a node into the given linear segment and check for following parts of a long edge. * * @param node the node to put into the linear segment * @param segment a linear segment * @return {@code true} if the given node was not already part of another segment and was thus * added to the given segment. */ private boolean fillSegment(final LNode node, final LinearSegment segment) { NodeType nodeType = node.getType(); // handle initial big nodes as big node type if (node.getProperty(InternalProperties.BIG_NODE_INITIAL)) { nodeType = NodeType.BIG_NODE; } if (node.id >= 0) { // The node is already part of another linear segment return false; } else if (segment.nodeType != null && (nodeType == NodeType.BIG_NODE && nodeType != segment.nodeType)) { // Big nodes are not allowed to share a linear segment with other dummy nodes return false; } else { // Add the node to the given linear segment node.id = segment.id; segment.nodes.add(node); } segment.nodeType = nodeType; if (nodeType == NodeType.LONG_EDGE || nodeType == NodeType.NORTH_SOUTH_PORT || nodeType == NodeType.BIG_NODE) { // This is a LONG_EDGE, NORTH_SOUTH_PORT or BIG_NODE dummy; check if any of its // successors are of one of these types too. If so, we can form a linear segment // with one of them. (not with more than one, though) // Note 1: LONG_EDGES and NORTH_SOUTH_PORTs can share a common linear segment // Note 2: we must take care not to make a segment out of nodes that are in the same layer // Note 3: for BIG_NODEs also the first BIG_NODE_INITIAL which is no actual dummy node has // to be considered here for (LPort sourcePort : node.getPorts()) { for (LPort targetPort : sourcePort.getSuccessorPorts()) { LNode targetNode = targetPort.getNode(); NodeType targetNodeType = targetNode.getType(); if (node.getLayer() != targetNode.getLayer()) { if (nodeType == NodeType.BIG_NODE) { // current AND the next node are BIG_NODE dummies if (targetNodeType == NodeType.BIG_NODE) { if (fillSegment(targetNode, segment)) { // We just added another node to this node's linear segment. // That's quite enough. return true; } } } else { // current no bignode and next node is LONG_EDGE and NORTH_SOUTH_PORT if (targetNodeType == NodeType.LONG_EDGE || targetNodeType == NodeType.NORTH_SOUTH_PORT) { if (fillSegment(targetNode, segment)) { // We just added another node to this node's linear segment. // That's quite enough. return true; } } } } } } } return true; }
/** * Sorts the linear segments of the given layered graph by finding a topological ordering in the * corresponding segment ordering graph. * * @param layeredGraph layered graph to process * @return a sorted array of linear segments */ private LinearSegment[] sortLinearSegments(final LGraph layeredGraph) { // set the identifier and input / output priority for all nodes List<LinearSegment> segmentList = Lists.newArrayList(); for (Layer layer : layeredGraph) { for (LNode node : layer) { node.id = -1; int inprio = Integer.MIN_VALUE, outprio = Integer.MIN_VALUE; for (LPort port : node.getPorts()) { for (LEdge edge : port.getIncomingEdges()) { int prio = edge.getProperty(InternalProperties.PRIORITY); inprio = Math.max(inprio, prio); } for (LEdge edge : port.getOutgoingEdges()) { int prio = edge.getProperty(InternalProperties.PRIORITY); outprio = Math.max(outprio, prio); } } node.setProperty(INPUT_PRIO, inprio); node.setProperty(OUTPUT_PRIO, outprio); } } // create linear segments for the layered graph, ignoring odd port side dummies int nextLinearSegmentID = 0; for (Layer layer : layeredGraph) { for (LNode node : layer) { // Test for the node ID; calls to fillSegment(...) may have caused the node ID // to be != -1. if (node.id < 0) { LinearSegment segment = new LinearSegment(); segment.id = nextLinearSegmentID++; fillSegment(node, segment); segmentList.add(segment); } } } // create and initialize segment ordering graph List<List<LinearSegment>> outgoingList = Lists.newArrayListWithCapacity(segmentList.size()); List<Integer> incomingCountList = Lists.newArrayListWithCapacity(segmentList.size()); for (int i = 0; i < segmentList.size(); i++) { outgoingList.add(new ArrayList<LinearSegment>()); incomingCountList.add(0); } // create edges for the segment ordering graph createDependencyGraphEdges(layeredGraph, segmentList, outgoingList, incomingCountList); // turn lists into arrays LinearSegment[] segments = segmentList.toArray(new LinearSegment[segmentList.size()]); @SuppressWarnings("unchecked") List<LinearSegment>[] outgoing = outgoingList.toArray(new List[outgoingList.size()]); int[] incomingCount = new int[incomingCountList.size()]; for (int i = 0; i < incomingCount.length; i++) { incomingCount[i] = incomingCountList.get(i); } // gather the sources of the segment ordering graph int nextRank = 0; List<LinearSegment> noIncoming = Lists.newArrayList(); for (int i = 0; i < segments.length; i++) { if (incomingCount[i] == 0) { noIncoming.add(segments[i]); } } // find a topological ordering of the segment ordering graph int[] newRanks = new int[segments.length]; while (!noIncoming.isEmpty()) { LinearSegment segment = noIncoming.remove(0); newRanks[segment.id] = nextRank++; while (!outgoing[segment.id].isEmpty()) { LinearSegment target = outgoing[segment.id].remove(0); incomingCount[target.id]--; if (incomingCount[target.id] == 0) { noIncoming.add(target); } } } // apply the new ordering to the array of linear segments linearSegments = new LinearSegment[segments.length]; for (int i = 0; i < segments.length; i++) { assert outgoing[i].isEmpty(); LinearSegment ls = segments[i]; int rank = newRanks[i]; linearSegments[rank] = ls; ls.id = rank; for (LNode node : ls.nodes) { node.id = rank; } } return linearSegments; }