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;
import java.util.Objects;
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 {
/**
* 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
* 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 maxInnerDelay the cycle's maximum inner delay
......@@ -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) {
Set<ResourceNode> possibleDstNodes = new HashSet<>();
......@@ -166,8 +182,9 @@ public class InfeasibilityInspector {
* If the current destination node's delay makes it impossible to ensure the
* RecMinII, the delay is not valid.
*/
if (dstNodeDelay + problematicResource.delay > startCfg.getMaxInnerDelay())
if (dstNodeDelay + problematicResource.delay > startCfg.getMaxInnerDelay()) {
return false;
}
/*
* If only the problematic nodes have the current delay, we cannot use it if
......@@ -227,7 +244,8 @@ public class InfeasibilityInspector {
* problematic node if the resource's delay is zero).
*
* 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 (lastProblematicLayer < lastPossibleLayer) {
......@@ -240,8 +258,9 @@ public class InfeasibilityInspector {
for (int remainingDelay : remainingDelays.keySet()) {
if (zeroNodesRemaining == 0 && remainingDelay == 0)
if (zeroNodesRemaining == 0 && remainingDelay == 0) {
continue;
}
if (remainingDelay <= startCfg.getMaxInnerDelay()) {
candidateFound = true;
......@@ -264,10 +283,11 @@ public class InfeasibilityInspector {
/*
* 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
* layer without increasing its minimal ASAP time.
* layer without automatically pushing its nodes in different timeslots.
*/
if (zeroNodesRemaining == 0)
if (zeroNodesRemaining == 0) {
return false;
}
/*
* Otherwise, place as many problematic nodes as possible in the current layer.
......@@ -293,7 +313,7 @@ public class InfeasibilityInspector {
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.
*/
int skipsRequired = Objects.requireNonNull(problematicResource).limit + 1;
......
......@@ -17,6 +17,7 @@
package graphgen.generator.components.properties.infeasibleMinII;
import graphgen.datastructures.Pair;
import graphgen.generator.components.properties.Property;
import graphgen.generator.components.properties.infeasibleMinII.configuration.InfeasibleConfiguration;
import graphgen.generator.components.properties.infeasibleMinII.configuration.StartConfiguration;
......@@ -282,14 +283,7 @@ public class InfeasibleMinIIProperty extends Property {
InfeasibleNodePlacer placer = new InfeasibleNodePlacer(startCfg, infeasibleCfg, rng);
/*
* 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()));
}
placer.placeNode(startCfg.getDestinationNode(), JavaUtils.asSet(startCfg.getDestinationNodeLayer()));
/*
* Gather all remaining nodes which use the problematic resource and randomly
......@@ -394,7 +388,10 @@ public class InfeasibleMinIIProperty extends Property {
*/
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). */
Set<Integer> possibleTimeslots = edgePlanner.getProblematicTimeslots();
......@@ -405,25 +402,26 @@ public class InfeasibleMinIIProperty extends Property {
* the chosen timeslot. The remaining inner delay will also be distributed over the
* 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)
* 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.
*/
if (lastEdgeRepresentative.isPresent()) {
if (lowestEdgesDelay.isPresent()) {
int lowestEdgeDelay = lowestEdgesDelay.get();
Map<ResourceNode, PlannedEdge> outgoingEdgesByNode = InfeasibleEdgePlanner
.getOutgoingEdgesMap(plannedEdges, suffixCfg.getSuffixNodes());
int firstSuffixSlot = problematicTimeslot + infeasibleCfg.getProblematicResource().delay + lowestEdgeDelay;
int firstSuffixSlot = problematicTimeslot + infeasibleCfg
.getProblematicResource().delay + lastEdgeRepresentative.get().delay;
suffixCfg.setInitialOffset(firstSuffixSlot);
for (int i = 0; i < suffixCfg.getSuffixNodes().size() - 1; 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;
import java.util.Optional;
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 {
private final StartConfiguration startCfg;
private final InfeasibleConfiguration infeasibleCfg;
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) {
this.startCfg = startCfg;
this.infeasibleCfg = infeasibleCfg;
this.rng = rng;
this.startCfg = Objects.requireNonNull(startCfg);
this.infeasibleCfg = Objects.requireNonNull(infeasibleCfg);
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) {
if (!infeasibleCfg.getProblematicNodes().contains(Objects.requireNonNull(problematicNode))) {
......@@ -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()) {
throw new IllegalArgumentException("Possible layers must be non-empty.");
if (targetLayers.isEmpty()) {
throw new IllegalArgumentException("Target layers must be non-empty.");
} else if (problematicNode != startCfg.getDestinationNode()) {
if (possibleLayers.stream().anyMatch(l -> l <= startCfg.getDestinationNodeLayer())) {
throw new IllegalArgumentException(
"Possible layers must be greater than the destination node's layer.");
if (targetLayers.stream().anyMatch(l -> l <= startCfg.getDestinationNodeLayer())) {
throw new IllegalArgumentException("Target layers must be greater than the destination node's layer.");
} else if (!infeasibleCfg.getProblematicNodes().contains(problematicNode)) {
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
......@@ -171,7 +205,7 @@ public class InfeasibleNodePlacer {
*/
int targetLayer;
if (!useCurrentLayer) {
targetLayer = JavaUtils.pickRandomElement(possibleLayers, rng);
targetLayer = JavaUtils.pickRandomElement(targetLayers, rng);
} else {
targetLayer = infeasibleCfg.getLayers().getDepth(problematicNode.getId());
}
......@@ -183,7 +217,7 @@ public class InfeasibleNodePlacer {
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
* ASAP slot as the other problematic nodes.
*/
......@@ -259,7 +293,7 @@ public class InfeasibleNodePlacer {
*/
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.");
}
......
......@@ -28,19 +28,30 @@ import java.util.Map;
import java.util.Objects;
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;
/**
* 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;
/**
* This map records for convenience purposes how many problematic nodes have already been placed in the individual
* layers (useful when determining potential layers to place another problematic node in).
* This map records (for convenience) how many problematic nodes have already been placed in the individual layers
* (useful when determining potential layers to place another problematic node in).
*/
private final Map<Integer, Integer> problematicNodesAtLayer;
......@@ -53,6 +64,11 @@ public class InfeasibleConfiguration extends Configuration {
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) {
super(Objects.requireNonNull(startCfg));
this.startCfg = startCfg;
......@@ -62,6 +78,16 @@ public class InfeasibleConfiguration extends Configuration {
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) {
if (!fixedNodes.add(Objects.requireNonNull(node))) {
......@@ -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) {
if (problematicNodes.size() == problematicResource.limit + 1) {
......@@ -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() {
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() {
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() {
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() {
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() {
return problematicResource.limit + 1 - MathUtils.sumInteger(problematicNodesAtLayer.values());
}
......@@ -137,6 +200,13 @@ public class InfeasibleConfiguration extends Configuration {
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) {
Set<ResourceNode> looseNodes = new HashSet<>();
for (int id : layers.getLayer(layer)) {
......@@ -147,12 +217,14 @@ public class InfeasibleConfiguration extends Configuration {
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() {
final int maxDepth = Collections.max(problematicNodesAtLayer.keySet());
int maxDepth = Collections.max(problematicNodesAtLayer.keySet());
return JavaUtils.asSet(problematicNodes.stream().filter(n -> layers.getDepth(n.getId()) == maxDepth));
}
}
......@@ -24,15 +24,30 @@ import graphgen.graph.ResourceNode;
import java.util.Map;
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 Map<Integer, ResourceNode> nodeTable;
protected final Resource problematicResource;
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.nodeTable = Objects.requireNonNull(nodeTable);
this.problematicResource = Objects.requireNonNull(problematicResource);
......@@ -43,7 +58,7 @@ public abstract class Configuration {
this.maxInnerDelay = maxInnerDelay;
}
protected Configuration(Configuration other) {
protected MinIICycleConfiguration(MinIICycleConfiguration other) {
this(other.layers, other.nodeTable, other.problematicResource, other.maxInnerDelay);
}
......@@ -69,7 +84,7 @@ public abstract class Configuration {
return true;
if (o == null || getClass() != o.getClass())
return false;
Configuration that = (Configuration) o;
MinIICycleConfiguration that = (MinIICycleConfiguration) o;
return maxInnerDelay == that.maxInnerDelay && Objects.equals(layers, that.layers) && Objects
.equals(nodeTable, that.nodeTable) && Objects.equals(problematicResource, that.problematicResource);
}
......
......@@ -24,20 +24,57 @@ import graphgen.graph.ResourceNode;
import java.util.Map;
import java.util.Objects;
public class StartConfiguration extends Configuration {
/**
* The start configuration represents the very start of an infeasible cycle. It contains the <i>destination node</i> and
* the layer it is located in. The destination node is the single node which all backedges of the infasible cycle must
* later connect to (hence the name <i>destination</i> node).
*
* @author Sebastian Vollbrecht
*/
public class StartConfiguration extends MinIICycleConfiguration {
/**
* The destination node is the node which the infeasible cycle's backedges will connect to later on (hence the name
* destination node).
*/
protected ResourceNode destinationNode;
/**
* The layer the destination node will reside in.
*/
private Integer destinationNodeLayer;
/**
* Creates a new start configuration based on the provided arguments. The destination node and the layer it is
* located in must be separately using {@link #setDestinationNode(ResourceNode)} and {@link
* #setDestinationNodeLayer(int)}.
*
* @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
*/
public StartConfiguration(LayerStructure layers, Map<Integer, ResourceNode> nodeTable, Resource problematicResource,
int maxInnerDelay) {
super(layers, nodeTable, problematicResource, maxInnerDelay);
}
/**
* Sets the destination node of the infeasible cycle.
*
* @param destinationNode the infeasible cycle's destination node
* @throws NullPointerException if the destination node is null
*/
public void setDestinationNode(ResourceNode destinationNode) {
this.destinationNode = Objects.requireNonNull(destinationNode);
}
/**
* Sets the layer of the infeasible cycle's destination node.
*
* @param destinationNodeLayer the destination node's layer
* @throws IllegalArgumentException if the destination node layer is less than zero
*/
public void setDestinationNodeLayer(int destinationNodeLayer) {
if (destinationNodeLayer < 0) {
throw new IllegalArgumentException("Destination node layer cannot be negative.");
......@@ -45,6 +82,12 @@ public class StartConfiguration extends Configuration {
this.destinationNodeLayer = destinationNodeLayer;
}
/**
* Returns the destination node of the infeasible cycle.
*
* @return the destination node
* @throws UnsupportedOperationException if the destination node is null
*/
public ResourceNode getDestinationNode() {
if (destinationNode == null) {
throw new UnsupportedOperationException("Destination node must be set first.");
......@@ -52,10 +95,34 @@ public class StartConfiguration extends Configuration {
return destinationNode;
}
/**
* Returns the layer of the destination node.
*
* @return the destination node's layer
* @throws UnsupportedOperationException if the layer is null
*/
public int getDestinationNodeLayer() {
if (destinationNodeLayer == null) {
throw new UnsupportedOperationException("Destination node layer must be set first.");
}
return destinationNodeLayer;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
if (!super.equals(o))
return false;
StartConfiguration that = (StartConfiguration) o;
return Objects.equals(destinationNode, that.destinationNode) && Objects
.equals(destinationNodeLayer, that.destinationNodeLayer);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), destinationNode, destinationNodeLayer);
}
}
......@@ -30,20 +30,44 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
public class SuffixConfiguration extends Configuration {
/**
* The suffix configuration represents the suffix an infeasible cycle. The idea behind the suffix is to minimize the
* infeasible cycle's edge delays by appending a single chain of nodes to the infeasible part (the <i>suffix nodes</i>).
* Whether or not a suffix can be appended depends heavily on the delays of the resources at play, the layer structure
* and the cycle's maximum inner delay.
*
* @author Sebastian Vollbrecht
*/
public class SuffixConfiguration extends MinIICycleConfiguration {
/**
* This list stores the suffix nodes which can be appended to the problematic nodes of an infeasible configuration.
*/
private final List<ResourceNode> suffixNodes;
/**
* This set stores all nodes from which the infeasibility-creating backedges must extend in order to create said
* infeasibility. These nodes can either be the very last suffix node or the problematic nodes themselves.
*/
private final Set<ResourceNode> backedgeSources;
/**
* The offset of the suffix nodes denotes their delay from the very first suffix node. It is useful to compute edge
* delays for edges connecting problematic nodes to suffix nodes. These must not introduce slack as otherwise the
* The offset of the suffix nodes denotes their delay from the destination node. It is useful to compute edge delays
* for edges connecting problematic nodes to suffix nodes. These must not introduce slack as otherwise the
* infeasibility wouldn't be guaranteed anymore.
*/
private final Map<ResourceNode, Integer> suffixOffsets;
private final StartConfiguration startCfg;
private final InfeasibleConfiguration infeasibleCfg;
/**
* Creates a new suffix configuration based on the provided start and infeasible configurations.
*
* @param startCfg the existing start configuration
* @param infeasibleCfg the existing infeasible configuration
*/
public SuffixConfiguration(StartConfiguration startCfg, InfeasibleConfiguration infeasibleCfg) {
super(Objects.requireNonNull(startCfg));
this.suffixNodes = new ArrayList<>();
......@@ -54,25 +78,55 @@ public class SuffixConfiguration extends Configuration {
}
/**
* Computes the infeasible cycle's remaining inner delay. The calculation takes into account the delay of the
* destination node, the problematic resource's delay and the delays of the suffix nodes (if present).
*
* @return the cycle's remaining inner delay
*/
public int getRemainingInnerDelay() {
return maxInnerDelay - problematicResource.delay - startCfg.getDestinationNode().getDelay() - suffixNodes
.stream().mapToInt(Node::getDelay).sum();
}
/**
* Sets the offset of the very first suffix node to the destination node (ASAP-wise).
*
* @param offset the first suffix node's offset
* @throws IllegalArgumentException if the offset has been set already
*/
public void setInitialOffset(int offset) {
if (suffixOffsets.containsKey(suffixNodes.get(0))) {
throw new IllegalArgumentException("Initial offset has been set already.");
}
suffixOffsets.put(suffixNodes.get(0), offset);
}
/**
* Appends a suffix node to the existing chain of suffix nodes.
*
* @param suffixNode the suffix node to append to the existing chain
* @throws NullPointerException if the node is null