Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
layered: Added model order cycle breaker. (#759)
* layered: Added model order cycle breaker. Signed-off-by: Soeren Domroes <sdo@informatik.uni-kiel.de> * layered: Model order cycle breaker: Set cyclic property if needed. Throw correct exception, fixed copy-paste bug. Signed-off-by: Soeren Domroes <sdo@informatik.uni-kiel.de> * layered: ModelOrderCyclebreaker: Handle layer constraints. Also removes author tag and check for self loops. Signed-off-by: Soeren Domroes <sdo@informatik.uni-kiel.de> * layered.test: Add model order cycle breaker to test cases. Signed-off-by: Soeren Domroes <sdo@informatik.uni-kiel.de> * layered: Correctly not use port order if port constraints are set. Signed-off-by: Soeren Domroes <sdo@informatik.uni-kiel.de> * layered: Corrected model order offset between constraint classes. Signed-off-by: Soeren Domroes <sdo@informatik.uni-kiel.de> * layered.test: Added model order and model order cycle breaker tests. Signed-off-by: Soeren Domroes <sdo@informatik.uni-kiel.de> * layered: Make sure that model order ordering for dummy nodes is always transitive. Signed-off-by: Soeren Domroes <sdo@informatik.uni-kiel.de> * layered: Improved calculation of transitive comparator dependencies. Signed-off-by: Soeren Domroes <sdo@informatik.uni-kiel.de>
- Loading branch information
1 parent
ea98387
commit 5f4ffc1
Showing
8 changed files
with
367 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
135 changes: 135 additions & 0 deletions
135
...ipse.elk.alg.layered/src/org/eclipse/elk/alg/layered/p1cycles/ModelOrderCycleBreaker.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2021 Kiel University and others. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
*******************************************************************************/ | ||
package org.eclipse.elk.alg.layered.p1cycles; | ||
|
||
import java.util.List; | ||
|
||
import org.eclipse.elk.alg.layered.LayeredPhases; | ||
import org.eclipse.elk.alg.layered.graph.LEdge; | ||
import org.eclipse.elk.alg.layered.graph.LGraph; | ||
import org.eclipse.elk.alg.layered.graph.LNode; | ||
import org.eclipse.elk.alg.layered.graph.LPort; | ||
import org.eclipse.elk.alg.layered.intermediate.IntermediateProcessorStrategy; | ||
import org.eclipse.elk.alg.layered.options.InternalProperties; | ||
import org.eclipse.elk.alg.layered.options.LayeredOptions; | ||
import org.eclipse.elk.alg.layered.options.PortType; | ||
import org.eclipse.elk.core.alg.ILayoutPhase; | ||
import org.eclipse.elk.core.alg.LayoutProcessorConfiguration; | ||
import org.eclipse.elk.core.util.IElkProgressMonitor; | ||
|
||
import com.google.common.collect.Lists; | ||
|
||
/** | ||
* A cycle breaker that reverses all edges that go against the model order, | ||
* i.e. edges from high model order to low model order. | ||
* | ||
* <dl> | ||
* <dt>Precondition:</dt> | ||
* <dd>no self loops</dd> | ||
* <dt>Postcondition:</dt> | ||
* <dd>the graph has no cycles</dd> | ||
* </dl> | ||
*/ | ||
public final class ModelOrderCycleBreaker implements ILayoutPhase<LayeredPhases, LGraph> { | ||
|
||
private int firstSeparateModelOrder; | ||
private int lastSeparateModelOrder; | ||
|
||
/** intermediate processing configuration. */ | ||
private static final LayoutProcessorConfiguration<LayeredPhases, LGraph> INTERMEDIATE_PROCESSING_CONFIGURATION = | ||
LayoutProcessorConfiguration.<LayeredPhases, LGraph>create() | ||
.addAfter(LayeredPhases.P5_EDGE_ROUTING, IntermediateProcessorStrategy.REVERSED_EDGE_RESTORER); | ||
|
||
@Override | ||
public LayoutProcessorConfiguration<LayeredPhases, LGraph> getLayoutProcessorConfiguration(final LGraph graph) { | ||
return INTERMEDIATE_PROCESSING_CONFIGURATION; | ||
} | ||
|
||
@Override | ||
public void process(final LGraph layeredGraph, final IElkProgressMonitor monitor) { | ||
monitor.begin("Model order cycle breaking", 1); | ||
|
||
// Reset FIRST_SEPARATE and LAST_SEPARATE counters. | ||
firstSeparateModelOrder = 0; | ||
lastSeparateModelOrder = 0; | ||
|
||
// gather edges that point to the wrong direction | ||
List<LEdge> revEdges = Lists.newArrayList(); | ||
|
||
// One needs an offset to make sure that the model order of nodes with port constraints is | ||
// always lower/higher than that of other nodes. | ||
// E.g. A node with the LAST constraint needs to have a model order m = modelOrder + offset | ||
// such that m > m(n) with m(n) being the model order of a normal node n (without constraints). | ||
// Such that the highest model order has to be used as an offset | ||
int offset = layeredGraph.getLayerlessNodes().size(); | ||
for (LNode node : layeredGraph.getLayerlessNodes()) { | ||
if (node.hasProperty(InternalProperties.MODEL_ORDER)) { | ||
offset = Math.max(offset, node.getProperty(InternalProperties.MODEL_ORDER) + 1); | ||
} | ||
} | ||
|
||
for (LNode source : layeredGraph.getLayerlessNodes()) { | ||
int modelOrderSource = computeConstraintModelOrder(source, offset); | ||
|
||
for (LPort port : source.getPorts(PortType.OUTPUT)) { | ||
for (LEdge edge : port.getOutgoingEdges()) { | ||
LNode target = edge.getTarget().getNode(); | ||
int modelOrderTarget = computeConstraintModelOrder(target, offset); | ||
if (modelOrderTarget < modelOrderSource) { | ||
revEdges.add(edge); | ||
} | ||
} | ||
} | ||
} | ||
|
||
// reverse the gathered edges | ||
for (LEdge edge : revEdges) { | ||
edge.reverse(layeredGraph, true); | ||
layeredGraph.setProperty(InternalProperties.CYCLIC, true); | ||
} | ||
revEdges.clear(); | ||
monitor.done(); | ||
} | ||
|
||
/** | ||
* Set model order to a value such that the constraint is respected and the ordering between nodes with | ||
* the same constraint is preserved. | ||
* The order should be FIRST_SEPARATE < FIRST < NORMAL < LAST < LAST_SEPARATE. The offset is used to make sure the | ||
* all nodes have unique model orders. | ||
* @param node The LNode | ||
* @param offset The offset between FIRST, FIRST_SEPARATE, NORMAL, LAST_SEPARATE, and LAST nodes for unique order | ||
* @return A unique model order | ||
*/ | ||
private int computeConstraintModelOrder(final LNode node, final int offset) { | ||
int modelOrder = 0; | ||
switch (node.getProperty(LayeredOptions.LAYERING_LAYER_CONSTRAINT)) { | ||
case FIRST_SEPARATE: | ||
modelOrder = 2 * -offset + firstSeparateModelOrder; | ||
firstSeparateModelOrder++; | ||
break; | ||
case FIRST: | ||
modelOrder = -offset; | ||
break; | ||
case LAST: | ||
modelOrder = offset; | ||
break; | ||
case LAST_SEPARATE: | ||
modelOrder = 2 * offset + lastSeparateModelOrder; | ||
lastSeparateModelOrder++; | ||
break; | ||
default: | ||
break; | ||
} | ||
if (node.hasProperty(InternalProperties.MODEL_ORDER)) { | ||
modelOrder += node.getProperty(InternalProperties.MODEL_ORDER); | ||
} | ||
return modelOrder; | ||
} | ||
} |
Oops, something went wrong.