Commit c2875b9e authored by Sebastian Vollbrecht's avatar Sebastian Vollbrecht

Added JavaDoc to the new classes.

Also moved some code around, renamed some things here and there, fixed some tests, ... Many little changes. You know how it is.
parent f102241f
...@@ -29,12 +29,18 @@ import java.util.Map.Entry; ...@@ -29,12 +29,18 @@ import java.util.Map.Entry;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
/**
* This class contains some utility methods related to inspecting nodes and layer structure regarding possible
* infeasible node arrangements.
*
* @author Sebastian Vollbrecht
*/
public class InfeasibilityInspector { public class InfeasibilityInspector {
/** /**
* Computes possible problematic resources whose limit could be exceeded in a cycle, using the provided set of * Computes possible problematic resources whose limit could be exceeded in a cycle, using the provided set of
* nodes. The maximum inner delay is taken into account to discard resources whose delay exceeds the maximum inner * nodes. The maximum inner delay is taken into account to discard resources whose delay exceeds the maximum inner
* delay already. A cycle consisting of these resources would automatically exceed the specified MinII. * delay already. A cycle consisting of these resources would automatically exceed corresponding MinIIs.
* *
* @param nodes the set of nodes * @param nodes the set of nodes
* @param maxInnerDelay the cycle's maximum inner delay * @param maxInnerDelay the cycle's maximum inner delay
...@@ -81,6 +87,16 @@ public class InfeasibilityInspector { ...@@ -81,6 +87,16 @@ public class InfeasibilityInspector {
} }
/**
* Computes all destination nodes that could potentially be placed in the specified layer and serve as the
* destination node for the backedges of an infeasible cycle. The infeasible cycle's parameters (i.e. problematic
* resource, layer structure, node table and the maximum inner delay) are extracted from the provided start
* configuration.
*
* @param dstNodeLayer the layer for which possible possible destination nodes are needed
* @param startCfg the start configuration containing the cycle's parameters
* @return a set containing all potential destination node candidates
*/
public static Set<ResourceNode> getPossibleDstNodes(int dstNodeLayer, StartConfiguration startCfg) { public static Set<ResourceNode> getPossibleDstNodes(int dstNodeLayer, StartConfiguration startCfg) {
Set<ResourceNode> possibleDstNodes = new HashSet<>(); Set<ResourceNode> possibleDstNodes = new HashSet<>();
...@@ -166,8 +182,9 @@ public class InfeasibilityInspector { ...@@ -166,8 +182,9 @@ public class InfeasibilityInspector {
* If the current destination node's delay makes it impossible to ensure the * If the current destination node's delay makes it impossible to ensure the
* RecMinII, the delay is not valid. * RecMinII, the delay is not valid.
*/ */
if (dstNodeDelay + problematicResource.delay > startCfg.getMaxInnerDelay()) if (dstNodeDelay + problematicResource.delay > startCfg.getMaxInnerDelay()) {
return false; return false;
}
/* /*
* If only the problematic nodes have the current delay, we cannot use it if * If only the problematic nodes have the current delay, we cannot use it if
...@@ -227,7 +244,8 @@ public class InfeasibilityInspector { ...@@ -227,7 +244,8 @@ public class InfeasibilityInspector {
* problematic node if the resource's delay is zero). * problematic node if the resource's delay is zero).
* *
* If no additional end node can be used, the maximum inner delay will be * If no additional end node can be used, the maximum inner delay will be
* impossible to ensure and the destination node's delay/layer are invalid. * impossible to ensure (as there wouldn't be any edges available to distribute
* the remaining delay over) and the destination node's delay/layer are invalid.
*/ */
if (isProblematicDelayZero && isSameDelay && 0 < startCfg.getMaxInnerDelay()) { if (isProblematicDelayZero && isSameDelay && 0 < startCfg.getMaxInnerDelay()) {
if (lastProblematicLayer < lastPossibleLayer) { if (lastProblematicLayer < lastPossibleLayer) {
...@@ -240,8 +258,9 @@ public class InfeasibilityInspector { ...@@ -240,8 +258,9 @@ public class InfeasibilityInspector {
for (int remainingDelay : remainingDelays.keySet()) { for (int remainingDelay : remainingDelays.keySet()) {
if (zeroNodesRemaining == 0 && remainingDelay == 0) if (zeroNodesRemaining == 0 && remainingDelay == 0) {
continue; continue;
}
if (remainingDelay <= startCfg.getMaxInnerDelay()) { if (remainingDelay <= startCfg.getMaxInnerDelay()) {
candidateFound = true; candidateFound = true;
...@@ -264,10 +283,11 @@ public class InfeasibilityInspector { ...@@ -264,10 +283,11 @@ public class InfeasibilityInspector {
/* /*
* If there are no nodes left with a delay of zero and if not all problematic * If there are no nodes left with a delay of zero and if not all problematic
* nodes have yet been placed, the delay is impossible: we cannot use the next * nodes have yet been placed, the delay is impossible: we cannot use the next
* layer without increasing its minimal ASAP time. * layer without automatically pushing its nodes in different timeslots.
*/ */
if (zeroNodesRemaining == 0) if (zeroNodesRemaining == 0) {
return false; return false;
}
/* /*
* Otherwise, place as many problematic nodes as possible in the current layer. * Otherwise, place as many problematic nodes as possible in the current layer.
...@@ -293,7 +313,7 @@ public class InfeasibilityInspector { ...@@ -293,7 +313,7 @@ public class InfeasibilityInspector {
Map<Integer, Integer> remainingDelays = new HashMap<>(); Map<Integer, Integer> remainingDelays = new HashMap<>();
/* /*
* Skip an amount of nodes equal to (the resource's limit + 1) in order to compute the * Skip an amount of nodes equal to [the resource's limit + 1] in order to compute the
* remaining delays if the resource were to be deemed the problematic resource. * remaining delays if the resource were to be deemed the problematic resource.
*/ */
int skipsRequired = Objects.requireNonNull(problematicResource).limit + 1; int skipsRequired = Objects.requireNonNull(problematicResource).limit + 1;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
package graphgen.generator.components.properties.infeasibleMinII; package graphgen.generator.components.properties.infeasibleMinII;
import graphgen.datastructures.Pair;
import graphgen.generator.components.properties.Property; import graphgen.generator.components.properties.Property;
import graphgen.generator.components.properties.infeasibleMinII.configuration.InfeasibleConfiguration; import graphgen.generator.components.properties.infeasibleMinII.configuration.InfeasibleConfiguration;
import graphgen.generator.components.properties.infeasibleMinII.configuration.StartConfiguration; import graphgen.generator.components.properties.infeasibleMinII.configuration.StartConfiguration;
...@@ -282,14 +283,7 @@ public class InfeasibleMinIIProperty extends Property { ...@@ -282,14 +283,7 @@ public class InfeasibleMinIIProperty extends Property {
InfeasibleNodePlacer placer = new InfeasibleNodePlacer(startCfg, infeasibleCfg, rng); InfeasibleNodePlacer placer = new InfeasibleNodePlacer(startCfg, infeasibleCfg, rng);
/* placer.placeNode(startCfg.getDestinationNode(), JavaUtils.asSet(startCfg.getDestinationNodeLayer()));
* If the destination node's layer is currently not the chosen layer, we'll have
* to move the node to the destined layer by swapping it with any of the destined
* layer's nodes.
*/
if (layers.getDepth(startCfg.getDestinationNode().getId()) != startCfg.getDestinationNodeLayer()) {
placer.placeNode(startCfg.getDestinationNode(), JavaUtils.asSet(startCfg.getDestinationNodeLayer()));
}
/* /*
* Gather all remaining nodes which use the problematic resource and randomly * Gather all remaining nodes which use the problematic resource and randomly
...@@ -394,7 +388,10 @@ public class InfeasibleMinIIProperty extends Property { ...@@ -394,7 +388,10 @@ public class InfeasibleMinIIProperty extends Property {
*/ */
InfeasibleEdgePlanner edgePlanner = new InfeasibleEdgePlanner(startCfg, infeasibleCfg, suffixCfg, rng); InfeasibleEdgePlanner edgePlanner = new InfeasibleEdgePlanner(startCfg, infeasibleCfg, suffixCfg, rng);
Set<PlannedEdge> plannedEdges = edgePlanner.getIncomingEdges(); /* Stores pairs of source and destination nodes which need to be connected with an edge. */
Set<Pair<ResourceNode, ResourceNode>> edgePairs = edgePlanner.getIncomingEdgePairs();
Set<PlannedEdge> plannedEdges = new HashSet<>();
edgePairs.forEach(p -> plannedEdges.add(new PlannedEdge(p.first, p.second, 0, 0)));
/* Choose the timeslot of the problematic nodes (relative to the destination node). */ /* Choose the timeslot of the problematic nodes (relative to the destination node). */
Set<Integer> possibleTimeslots = edgePlanner.getProblematicTimeslots(); Set<Integer> possibleTimeslots = edgePlanner.getProblematicTimeslots();
...@@ -405,25 +402,26 @@ public class InfeasibleMinIIProperty extends Property { ...@@ -405,25 +402,26 @@ public class InfeasibleMinIIProperty extends Property {
* the chosen timeslot. The remaining inner delay will also be distributed over the * the chosen timeslot. The remaining inner delay will also be distributed over the
* non-problematic edges (e.g. the suffix edges). * non-problematic edges (e.g. the suffix edges).
*/ */
Optional<PlannedEdge> lastEdgeRepresentative = edgePlanner.distributeDelay(problematicTimeslot, plannedEdges); Optional<Integer> lowestEdgesDelay = edgePlanner.distributeDelay(problematicTimeslot, plannedEdges);
/* /*
* Adjust the suffix nodes' offsets (i.e. ASAP-wise from the destination node) * Adjust the suffix nodes' offsets (i.e. ASAP-wise from the destination node)
* based on the freshly distributed delay of the edges among them. These are * based on the freshly distributed delay of the edges among them. These are
* useful for the creation of the cycle's required outgoing edges below. * useful for the creation of the cycle's required outgoing edges below.
*/ */
if (lastEdgeRepresentative.isPresent()) { if (lowestEdgesDelay.isPresent()) {
int lowestEdgeDelay = lowestEdgesDelay.get();
Map<ResourceNode, PlannedEdge> outgoingEdgesByNode = InfeasibleEdgePlanner Map<ResourceNode, PlannedEdge> outgoingEdgesByNode = InfeasibleEdgePlanner
.getOutgoingEdgesMap(plannedEdges, suffixCfg.getSuffixNodes()); .getOutgoingEdgesMap(plannedEdges, suffixCfg.getSuffixNodes());
int firstSuffixSlot = problematicTimeslot + infeasibleCfg.getProblematicResource().delay + lowestEdgeDelay;
int firstSuffixSlot = problematicTimeslot + infeasibleCfg
.getProblematicResource().delay + lastEdgeRepresentative.get().delay;
suffixCfg.setInitialOffset(firstSuffixSlot); suffixCfg.setInitialOffset(firstSuffixSlot);
for (int i = 0; i < suffixCfg.getSuffixNodes().size() - 1; i++) { for (int i = 0; i < suffixCfg.getSuffixNodes().size() - 1; i++) {
ResourceNode src = suffixCfg.getSuffixNodes().get(i); ResourceNode src = suffixCfg.getSuffixNodes().get(i);
suffixCfg.addPlannedEdge(outgoingEdgesByNode.get(src)); suffixCfg.updateSuffixOffsets(outgoingEdgesByNode.get(src));
} }
} }
......
...@@ -30,18 +30,41 @@ import java.util.Objects; ...@@ -30,18 +30,41 @@ import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
/**
* This class is responsible for arranging nodes in an infeasible fashion. It provides methods for determining possible
* layers a problematic node could be placed in and offers a method for placing them there as well.
*
* @author Sebastian Vollbrecht
*/
public class InfeasibleNodePlacer { public class InfeasibleNodePlacer {
private final StartConfiguration startCfg; private final StartConfiguration startCfg;
private final InfeasibleConfiguration infeasibleCfg; private final InfeasibleConfiguration infeasibleCfg;
private final SeededRandom rng; private final SeededRandom rng;
/**
* Creates a new node placer, based on the provided configurations.
*
* @param startCfg the start configuration of the infeasible cycle
* @param infeasibleCfg the infeasible configuration of the cycle
* @param rng the random instance to use to when needed
*/
public InfeasibleNodePlacer(StartConfiguration startCfg, InfeasibleConfiguration infeasibleCfg, SeededRandom rng) { public InfeasibleNodePlacer(StartConfiguration startCfg, InfeasibleConfiguration infeasibleCfg, SeededRandom rng) {
this.startCfg = startCfg; this.startCfg = Objects.requireNonNull(startCfg);
this.infeasibleCfg = infeasibleCfg; this.infeasibleCfg = Objects.requireNonNull(infeasibleCfg);
this.rng = rng; this.rng = Objects.requireNonNull(rng);
} }
/**
* Computes all layers where the given problematic node could be placed without making it impossible for the
* remaining problematic nodes to be placed in the same timeslot. The calculation takes into account the non-fixed
* zero nodes to find out which layers are reachable and would remain reachable if the node were placed somewhere.
*
* @param problematicNode the problematic node to determine possible layers for
* @return a set of layers where the node could be placed
* @throws IllegalArgumentException if the node is not contained in the set of problematic nodes or if it has been
* fixed already
*/
public Set<Integer> getPossibleLayers(ResourceNode problematicNode) { public Set<Integer> getPossibleLayers(ResourceNode problematicNode) {
if (!infeasibleCfg.getProblematicNodes().contains(Objects.requireNonNull(problematicNode))) { if (!infeasibleCfg.getProblematicNodes().contains(Objects.requireNonNull(problematicNode))) {
...@@ -150,20 +173,31 @@ public class InfeasibleNodePlacer { ...@@ -150,20 +173,31 @@ public class InfeasibleNodePlacer {
} }
public void placeNode(ResourceNode problematicNode, Set<Integer> possibleLayers) { /**
* Places a node in a certain layer, using the given set of target layers and automatically pads the preceding
* layers of the node's target layers with zero nodes if needed. The node must either be a problematic node or the
* destination node, as all other nodes don't need to be moved manually at all. If the node's current layer is
* contained in the set of target layers, it will always be chosen so as to minimize changes to the generated graph.
* Otherwise, the target layer will be picked randomly.
*
* @param problematicNode the node to place
* @param targetLayers the set of possible layers the node could be placed in
* @throws IllegalArgumentException if the set of possible layers is empty, if the node is neither problematic nor
* the destination node or if any of the possible layers are invalid
*/
public void placeNode(ResourceNode problematicNode, Set<Integer> targetLayers) {
if (possibleLayers.isEmpty()) { if (targetLayers.isEmpty()) {
throw new IllegalArgumentException("Possible layers must be non-empty."); throw new IllegalArgumentException("Target layers must be non-empty.");
} else if (problematicNode != startCfg.getDestinationNode()) { } else if (problematicNode != startCfg.getDestinationNode()) {
if (possibleLayers.stream().anyMatch(l -> l <= startCfg.getDestinationNodeLayer())) { if (targetLayers.stream().anyMatch(l -> l <= startCfg.getDestinationNodeLayer())) {
throw new IllegalArgumentException( throw new IllegalArgumentException("Target layers must be greater than the destination node's layer.");
"Possible layers must be greater than the destination node's layer.");
} else if (!infeasibleCfg.getProblematicNodes().contains(problematicNode)) { } else if (!infeasibleCfg.getProblematicNodes().contains(problematicNode)) {
throw new IllegalArgumentException("Only problematic nodes must be placed in problematic spots."); throw new IllegalArgumentException("Only problematic nodes must be placed in problematic spots.");
} }
} }
boolean useCurrentLayer = possibleLayers.contains(infeasibleCfg.getLayers().getDepth(problematicNode.getId())); boolean useCurrentLayer = targetLayers.contains(infeasibleCfg.getLayers().getDepth(problematicNode.getId()));
/* /*
* Determine the problematic node's target layer, based on our previous * Determine the problematic node's target layer, based on our previous
...@@ -171,7 +205,7 @@ public class InfeasibleNodePlacer { ...@@ -171,7 +205,7 @@ public class InfeasibleNodePlacer {
*/ */
int targetLayer; int targetLayer;
if (!useCurrentLayer) { if (!useCurrentLayer) {
targetLayer = JavaUtils.pickRandomElement(possibleLayers, rng); targetLayer = JavaUtils.pickRandomElement(targetLayers, rng);
} else { } else {
targetLayer = infeasibleCfg.getLayers().getDepth(problematicNode.getId()); targetLayer = infeasibleCfg.getLayers().getDepth(problematicNode.getId());
} }
...@@ -183,7 +217,7 @@ public class InfeasibleNodePlacer { ...@@ -183,7 +217,7 @@ public class InfeasibleNodePlacer {
infeasibleCfg.fixateNode(problematicNode); infeasibleCfg.fixateNode(problematicNode);
/* /*
* Now we have to pave the previous layers with zero nodes, so that our * Now we have to pad the previous layers with zero nodes, so that our
* problematic node is guaranteed the possibility to end up in the same * problematic node is guaranteed the possibility to end up in the same
* ASAP slot as the other problematic nodes. * ASAP slot as the other problematic nodes.
*/ */
...@@ -259,7 +293,7 @@ public class InfeasibleNodePlacer { ...@@ -259,7 +293,7 @@ public class InfeasibleNodePlacer {
*/ */
private Optional<Integer> getLastLayerNeeded(ResourceNode nodeToPlace, int targetLayer) { private Optional<Integer> getLastLayerNeeded(ResourceNode nodeToPlace, int targetLayer) {
if (Objects.requireNonNull(infeasibleCfg).getFixedNodes().contains(Objects.requireNonNull(nodeToPlace))) { if (infeasibleCfg.getFixedNodes().contains(Objects.requireNonNull(nodeToPlace))) {
throw new IllegalArgumentException("Node " + nodeToPlace + " has been fixed already."); throw new IllegalArgumentException("Node " + nodeToPlace + " has been fixed already.");
} }
......
...@@ -28,19 +28,30 @@ import java.util.Map; ...@@ -28,19 +28,30 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
public class InfeasibleConfiguration extends Configuration { /**
* The infeasible configuration represents the infeasible part of an infeasible cycle. It contains methods related to
* the problematic nodes (which are responsible for the infeasibility by exceeding their shared resource's limit) and
* for the zero nodes needed to cross layer boundaries when arranging the problematic nodes.
*
* @author Sebastian Vollbrecht
*/
public class InfeasibleConfiguration extends MinIICycleConfiguration {
/**
* This set stores the nodes which need to be arranged in a single timeslot in order to make the graph infeasible at
* its MinII.
*/
private final Set<ResourceNode> problematicNodes; private final Set<ResourceNode> problematicNodes;
/** /**
* This set stores all nodes which must not be moved and must remain in place throughout the entire infeasible node * This set stores all nodes which must not be moved and must remain in place throughout the entire infeasible node
* arrangement phase (i.e. the node depth must not change). * arrangement phase (i.e. the nodes' depth must not change).
*/ */
private final Set<ResourceNode> fixedNodes; private final Set<ResourceNode> fixedNodes;
/** /**
* This map records for convenience purposes how many problematic nodes have already been placed in the individual * This map records (for convenience) how many problematic nodes have already been placed in the individual layers
* layers (useful when determining potential layers to place another problematic node in). * (useful when determining potential layers to place another problematic node in).
*/ */
private final Map<Integer, Integer> problematicNodesAtLayer; private final Map<Integer, Integer> problematicNodesAtLayer;
...@@ -53,6 +64,11 @@ public class InfeasibleConfiguration extends Configuration { ...@@ -53,6 +64,11 @@ public class InfeasibleConfiguration extends Configuration {
private final StartConfiguration startCfg; private final StartConfiguration startCfg;
/**
* Creates a new infeasible configuration based on the provided start configuration.
*
* @param startCfg the existing start configuration
*/
public InfeasibleConfiguration(StartConfiguration startCfg) { public InfeasibleConfiguration(StartConfiguration startCfg) {
super(Objects.requireNonNull(startCfg)); super(Objects.requireNonNull(startCfg));
this.startCfg = startCfg; this.startCfg = startCfg;
...@@ -62,6 +78,16 @@ public class InfeasibleConfiguration extends Configuration { ...@@ -62,6 +78,16 @@ public class InfeasibleConfiguration extends Configuration {
this.zeroNodesByLayer = new HashMap<>(); this.zeroNodesByLayer = new HashMap<>();
} }
/**
* Fixates a node in the infeasible cycle. A <i>fixed</i> node is locked in place from then on and cannot be
* displaced anymore (i.e. they must remain in the layer they were fixated in). Also updates the internal map
* keeping track of how many problematic nodes have been placed already and the map storing the layers and their
* zero nodes.
*
* @param node the node to fixate
* @throws IllegalArgumentException if the node has been fixated already or if it is a zero node located in a layer
* which contains a zero node already
*/
public void fixateNode(ResourceNode node) { public void fixateNode(ResourceNode node) {
if (!fixedNodes.add(Objects.requireNonNull(node))) { if (!fixedNodes.add(Objects.requireNonNull(node))) {
...@@ -84,6 +110,14 @@ public class InfeasibleConfiguration extends Configuration { ...@@ -84,6 +110,14 @@ public class InfeasibleConfiguration extends Configuration {
} }
} }
/**
* Adds a problematic node to the internal set of problematic nodes.
*
* @param problematicNode the new problematic node
* @throws IllegalArgumentException if the set of problematic nodes contains enough nodes already (i.e.
* <i>problematic resource's limit + 1</i>), if the set contains the node already
* or if the node is the destination node with a delay greater than zero
*/
public void addProblematicNode(ResourceNode problematicNode) { public void addProblematicNode(ResourceNode problematicNode) {
if (problematicNodes.size() == problematicResource.limit + 1) { if (problematicNodes.size() == problematicResource.limit + 1) {
...@@ -100,22 +134,51 @@ public class InfeasibleConfiguration extends Configuration { ...@@ -100,22 +134,51 @@ public class InfeasibleConfiguration extends Configuration {
} }
/**
* Returns an unmodifiable view of the set of problematic nodes.
*
* @return the set of problematic nodes
*/
public Set<ResourceNode> getProblematicNodes() { public Set<ResourceNode> getProblematicNodes() {
return Collections.unmodifiableSet(problematicNodes); return Collections.unmodifiableSet(problematicNodes);
} }
/**
* Returns an unmodifiable view of the set of fixed nodes. This includes both the fixed problematic nodes and the
* fixed zero nodes.
*
* @return the set of fixed nodes
*/
public Set<ResourceNode> getFixedNodes() { public Set<ResourceNode> getFixedNodes() {
return Collections.unmodifiableSet(fixedNodes); return Collections.unmodifiableSet(fixedNodes);
} }
/**
* Returns an unmodifiable view of the mapping of layers to the amount of <i>fixed</i> problematic nodes they
* contain.
*
* @return the mapping of layers to problematic node counts
*/
public Map<Integer, Integer> getProblematicNodesAtLayer() { public Map<Integer, Integer> getProblematicNodesAtLayer() {
return Collections.unmodifiableMap(problematicNodesAtLayer); return Collections.unmodifiableMap(problematicNodesAtLayer);
} }
/**
* Returns an unmodifiable view of the mapping of layers to the sets of <i>fixed</i> zero nodes they contain. A
* layer can only contain more than one zero node if the problematic resource's delay is zero as well, as the
* problematic nodes are then considered zero nodes as well.
*
* @return the mapping of layers to the sets of zero nodes they contain
*/
public Map<Integer, Set<ResourceNode>> getZeroNodesByLayer() { public Map<Integer, Set<ResourceNode>> getZeroNodesByLayer() {
return Collections.unmodifiableMap(zeroNodesByLayer); return Collections.unmodifiableMap(zeroNodesByLayer);
} }
/**
* Computes the amount of problematic nodes which still need to be placed in order to guarantee the infeasibility.
*
* @return the amount of problematic nodes which still need to be placed
*/
public int howManyLeftToPlace() { public int howManyLeftToPlace() {
return problematicResource.limit + 1 - MathUtils.sumInteger(problematicNodesAtLayer.values()); return problematicResource.limit + 1 - MathUtils.sumInteger(problematicNodesAtLayer.values());
} }
...@@ -137,6 +200,13 @@ public class InfeasibleConfiguration extends Configuration { ...@@ -137,6 +200,13 @@ public class InfeasibleConfiguration extends Configuration {
return remainingZeroNodes; return remainingZeroNodes;
} }
/**
* Computes all <i>loose</i> nodes at the provided layer, i.e. the nodes which have not been fixated yet. These can
* still be swapped with other nodes without destroying the infeasibility.
*
* @param layer the layer whose loose nodes are needed
* @return a set containing the loose nodes at the specified layer
*/
public Set<ResourceNode> getLooseNodesAtLayer(int layer) { public Set<ResourceNode> getLooseNodesAtLayer(int layer) {
Set<ResourceNode> looseNodes = new HashSet<>(); Set<ResourceNode> looseNodes = new HashSet<>();
for (int id : layers.getLayer(layer)) { for (int id : layers.getLayer(layer)) {
...@@ -147,12 +217,14 @@ public class InfeasibleConfiguration extends Configuration { ...@@ -147,12 +217,14 @@ public class InfeasibleConfiguration extends Configuration {
return looseNodes; return looseNodes;
} }
/**
* Returns the lowest problematic nodes, depth-wise (i.e. the nodes furthest from the graph's source node).
*
* @return the lowest problematic nodes
*/
public Set<ResourceNode> getLowestProblematicNodes() { public Set<ResourceNode> getLowestProblematicNodes() {
int maxDepth = Collections.max(problematicNodesAtLayer.keySet());
final int maxDepth = Collections.max(problematicNodesAtLayer.keySet());
return JavaUtils.asSet(problematicNodes.stream().filter(n -> layers.getDepth(n.getId()) == maxDepth)); return JavaUtils.asSet(problematicNodes.stream().filter(n -> layers.getDepth(n.getId()) == maxDepth));
} }
} }
...@@ -24,15 +24,30 @@ import graphgen.graph.ResourceNode; ...@@ -24,15 +24,30 @@ import graphgen.graph.ResourceNode;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
public abstract class Configuration { /**
* The abstract base class of the {@link StartConfiguration}, {@link InfeasibleConfiguration} and {@link
* SuffixConfiguration} classes. It stores the graph's layer structure, the node table, the infeasible cycle's
* problematic resource and its maximum inner delay.
*
* @author Sebastian Vollbrecht
*/
public abstract class MinIICycleConfiguration {
protected final LayerStructure layers; protected final LayerStructure layers;
protected final Map<Integer, ResourceNode> nodeTable; protected final Map<Integer, ResourceNode> nodeTable;
protected final Resource problematicResource; protected final Resource problematicResource;
protected final int maxInnerDelay; protected final int maxInnerDelay;
protected Configuration(LayerStructure layers, Map<Integer, ResourceNode> nodeTable, Resource problematicResource, /**
int maxInnerDelay) { * Creates a new configuration based on the provided arguments..
*
* @param layers the graph's layer structure
* @param nodeTable the graph's node table
* @param problematicResource the infeasible cycle's problematic resource
* @param maxInnerDelay the infeasible cycle's maximum inner delay
*/
protected MinIICycleConfiguration(LayerStructure layers, Map<Integer, ResourceNode> nodeTable,
Resource problematicResource, int maxInnerDelay) {
this.layers = Objects.requireNonNull(layers); this.layers = Objects.requireNonNull(layers);
this.nodeTable = Objects.requireNonNull(nodeTable); this.nodeTable = Objects.requireNonNull(nodeTable);
this.problematicResource = Objects.requireNonNull(problematicResource); this.problematicResource = Objects.requireNonNull(problematicResource);
...@@ -43,7 +58,7 @@ public abstract class Configuration { ...@@ -43,7 +58,7 @@ public abstract class Configuration {
this.maxInnerDelay = maxInnerDelay; this.maxInnerDelay = maxInnerDelay;
} }
protected Configuration(Configuration other) { protected MinIICycleConfiguration(MinIICycleConfiguration other) {
this(other.layers, other.nodeTable, other.problematicResource, other.maxInnerDelay); this(other.layers, other.nodeTable, other.problematicResource, other.maxInnerDelay);
} }
...@@ -69,7 +84,7 @@ public abstract class Configuration { ...@@ -69,7 +84,7 @@ public abstract class Configuration {
return true; return true;
if (o == null || getClass() != o.getClass()) if (o == null || getClass() != o.getClass())
return false; return false;
Configuration that = (Configuration) o; MinIICycleConfiguration that = (MinIICycleConfiguration) o;
return maxInnerDelay == that.maxInnerDelay && Objects.equals(layers, that.layers) && Objects return maxInnerDelay == that.maxInnerDelay && Objects.equals(layers, that.layers) && Objects
.equals(nodeTable, that.nodeTable) && Objects.equals(problematicResource, that.problematicResource); .equals(nodeTable, that.nodeTable) && Objects.equals(problematicResource, that.problematicResource);
} }
......
...@@ -24,20 +24,57 @@ import graphgen.graph.ResourceNode; ...@@ -24,20 +24,57 @@ import graphgen.graph.ResourceNode;
import java.util.Map; import java.util.Map;