Commit 4a46bdea authored by Sebastian Vollbrecht's avatar Sebastian Vollbrecht

Further refactoring of the edge creation phase.

parent c98932fd
......@@ -290,8 +290,9 @@ public class FeasibleMinIIProperty extends Property {
Set<Pair<ResourceNode, ResourceNode>> initialPairs = getPossibleInitialPairs(nodesByDelay);
if (initialPairs.isEmpty())
throw new MinIIImpossibleException(nodes);
if (initialPairs.isEmpty()) {
throw new MinIIImpossibleException();
}
Edge<ResourceNode> theBackedge = createMaxInnerDelayPath(initialPairs, nodesByDelay);
......@@ -507,7 +508,7 @@ public class FeasibleMinIIProperty extends Property {
remainingPathDelay = appendNodeToPath(remainingPathDelay, nodesByDelay, path);
}
PlannedEdge.distributeRemainingDelay(path.path, remainingPathDelay, rng);
PlannedEdge.distributeDelay(path.path, remainingPathDelay, rng);
path.path.forEach(e -> edgeCreator.createEdge(e.src, e.dst, e.delay));
......
......@@ -32,13 +32,16 @@ import graphgen.util.SchedulingUtils;
import modsched.Edge;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
/**
* This property creates graphs which are infeasible regarding a specified MinII. The infeasibility is ensured through
......@@ -133,6 +136,7 @@ public class InfeasibleMinIIProperty extends Property {
Set<Edge<ResourceNode>> tmpEdges = new HashSet<>(edgeCreator.edgeView());
tmpEdges.add(new Edge<>(src, dst, delay, distance));
// TODO: test == instead of <=
return SchedulingUtils.getRecMinII(nodes, tmpEdges) <= minII;
}
......@@ -146,9 +150,7 @@ public class InfeasibleMinIIProperty extends Property {
throw new MinIIImpossibleException(resMinII, minII);
}
Set<Resource> problematicResources = getProblematicResources();
StartConfiguration startCfg = chooseStartConfiguration(problematicResources);
StartConfiguration startCfg = chooseStartConfiguration(getProblematicResources());
/* 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. */
......@@ -157,25 +159,66 @@ public class InfeasibleMinIIProperty extends Property {
layers.swapIDs(startCfg.getDestinationNode().getId(), nodeToSwapWith);
}
InfeasibleConfiguration infeasibleCfg = new InfeasibleConfiguration(startCfg);
arrangeProblematicNodes(startCfg, infeasibleCfg);
InfeasibleConfiguration infeasibleCfg = chooseInfeasibleConfiguration(startCfg);
SuffixConfiguration suffixCfg = chooseSuffixConfiguration(startCfg, infeasibleCfg);
// TODO: refactor edge creation
InfeasibleEdgeInspector edgeInspector = new InfeasibleEdgeInspector(startCfg, infeasibleCfg, suffixCfg);
/*
* We need to create an incoming edge for all fixed nodes. The source node can
* either be the destination node or a zero node of the previous layer.
* Also create an incoming edge for every suffix node.
*/
Set<PlannedEdge> plannedEdges = edgeInspector.getIncomingEdges();
/* Choose the timeslot of the problematic nodes (relative to the destination node). */
Set<Integer> possibleTimeslots = InfeasibilityInspector
.getProblematicTimeslots(startCfg, infeasibleCfg, suffixCfg);
int problematicTimeslot = JavaUtils.pickRandomElement(possibleTimeslots, rng);
/*
* Create the minimally needed edges among the suffix nodes (if present) and
* among the problematic nodes/zero nodes.
* Update the delay of the created incoming edges so that the problematic nodes will share
* the chosen timeslot. The remaining inner delay will also be distributed over the
* non-problematic edges (e.g. the suffix edges).
*/
Optional<PlannedEdge> lastEdgeRepresentative = edgeInspector.distributeDelay(problematicTimeslot, plannedEdges);
Set<PlannedEdge> edges = InfeasibilityInspector.getNeededEdges(startCfg, infeasibleCfg, suffixCfg, rng);
if (lastEdgeRepresentative.isPresent()) {
InfeasibilityInspector
.getOutgoingProblematicEdges(startCfg, infeasibleCfg, suffixCfg, rng, edgeCreator::computeEdgeDelay);
Map<ResourceNode, PlannedEdge> outgoingEdgesByNode = InfeasibleEdgeInspector
.getOutgoingEdgesMap(plannedEdges, suffixCfg.getSuffixNodes());
edges.forEach(e -> edgeCreator.createEdge(e.src, e.dst, e.delay));
/*
* Adjust the suffix nodes' offsets (i.e. ASAP-wise from the destination node)
* based on the freshly distributed delay of the edges among them.
*/
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));
}
}
/*
* Create the required outgoing edges.
* Note that there is no need to create edges for problematic nodes which have
* been connected to other nodes already (this can happen if they are zero
* nodes themselves) or which will be used as backedge sources.
*/
Predicate<ResourceNode> nodeNeedsOutgoingEdge = n -> plannedEdges.stream()
.noneMatch(e -> e.src == n && e.distance == 0) && !suffixCfg.getBackedgeSources().contains(n);
Set<PlannedEdge> outgoingEdges = edgeInspector
.getOutgoingEdges(problematicTimeslot, nodeNeedsOutgoingEdge, edgeCreator::computeEdgeDelay);
plannedEdges.addAll(outgoingEdges);
/*
* Finalize the edges.
*/
plannedEdges.forEach(e -> edgeCreator.createEdge(e.src, e.dst, e.delay));
/*
* Finally, create the backedges going to the destination node, depending on
......@@ -301,7 +344,9 @@ public class InfeasibleMinIIProperty extends Property {
}
private void arrangeProblematicNodes(StartConfiguration startCfg, InfeasibleConfiguration infeasibleCfg) {
private InfeasibleConfiguration chooseInfeasibleConfiguration(StartConfiguration startCfg) {
InfeasibleConfiguration infeasibleCfg = new InfeasibleConfiguration(startCfg);
Resource problematicResource = startCfg.getProblematicResource();
......@@ -347,8 +392,11 @@ public class InfeasibleMinIIProperty extends Property {
* could be replaced by zero nodes if a lower problematic node required one to
* be placed in the respective layer.
*/
for (ResourceNode problematicNode : JavaUtils.asSortedList(infeasibleCfg.getProblematicNodes(), Comparator
.comparingInt(n -> layers.getDepth(n.getId())))) {
InfeasibleNodePlacer placer = new InfeasibleNodePlacer(startCfg, infeasibleCfg);
placer.init(rng);
for (ResourceNode problematicNode : JavaUtils
.asSortedList(infeasibleCfg.getProblematicNodes(), Comparator.comparingInt(layers::getDepth))) {
/*
* If a problematic node has been fixed already, we don't need to place it
......@@ -357,16 +405,20 @@ public class InfeasibleMinIIProperty extends Property {
* boundaries.
*/
if (!infeasibleCfg.getFixedNodes().contains(problematicNode)) {
int chosenLayer = InfeasibilityInspector.placeNode(problematicNode, infeasibleCfg, rng);
Set<Integer> possibleLayers = placer.getPossibleLayers(problematicNode);
int chosenLayer = placer.placeNode(problematicNode, possibleLayers);
/*
* Now we have to pave the previous layers with zero nodes, so that our
* problematic node is going to end up in the same ASAP slot as the other
* problematic nodes.
*/
InfeasibilityInspector.placeZeroNodesInBetween(chosenLayer, infeasibleCfg, rng);
placer.placeZeroNodesInBetween(chosenLayer);
}
}
return infeasibleCfg;
}
private SuffixConfiguration chooseSuffixConfiguration(StartConfiguration startCfg,
......@@ -374,27 +426,6 @@ public class InfeasibleMinIIProperty extends Property {
List<ResourceNode> suffixNodes = new ArrayList<>();
/*
* Determine the lowest problematic nodes to check whether the RecMinII-ensuring
* backedge(s) must extend from them themselves or whether additional suffix
* nodes can be appended.
*/
Set<ResourceNode> lowestNodes = new HashSet<>();
int maxDepth = Integer.MIN_VALUE;
for (ResourceNode problematicNode : infeasibleCfg.getProblematicNodes()) {
int nodeDepth = layers.getDepth(problematicNode.getId());
if (nodeDepth > maxDepth) {
maxDepth = nodeDepth;
lowestNodes.clear();
lowestNodes.add(problematicNode);
} else if (nodeDepth == maxDepth) {
lowestNodes.add(problematicNode);
}
}
int remainingInnerDelay = maxInnerDelay - startCfg.getProblematicResource().delay - startCfg
.getDestinationNode().getDelay();
......@@ -406,6 +437,7 @@ public class InfeasibleMinIIProperty extends Property {
* node with delay zero if the remaining inner delay is zero already.
*/
double pToAppendMoreZeroNodes = rng.nextDouble();
int maxDepth = Collections.max(infeasibleCfg.getProblematicNodesAtLayer().keySet());
for (int layer = maxDepth + 1; layer < layers.getHeight(); layer++) {
......@@ -452,7 +484,7 @@ public class InfeasibleMinIIProperty extends Property {
if (suffixNodes.isEmpty()) {
if (infeasibleCfg.getProblematicResource().delay == 0) {
backedgeSources.addAll(lowestNodes);
backedgeSources.addAll(infeasibleCfg.getLowestProblematicNodes());
} else {
backedgeSources.addAll(infeasibleCfg.getProblematicNodes());
}
......@@ -460,7 +492,7 @@ public class InfeasibleMinIIProperty extends Property {
backedgeSources.add(suffixNodes.get(suffixNodes.size() - 1));
}
return new SuffixConfiguration(suffixNodes, backedgeSources, infeasibleCfg);
return new SuffixConfiguration(suffixNodes, backedgeSources, startCfg);
}
}
}
\ No newline at end of file
......@@ -43,10 +43,8 @@ public abstract class Configuration {
this.maxInnerDelay = maxInnerDelay;
}
protected Configuration(StartConfiguration startConfiguration) {
this(startConfiguration.layers, startConfiguration.nodeTable, startConfiguration.problematicResource,
startConfiguration.maxInnerDelay
);
protected Configuration(Configuration other) {
this(other.layers, other.nodeTable, other.problematicResource, other.maxInnerDelay);
}
public LayerStructure getLayers() {
......
......@@ -30,8 +30,6 @@ import java.util.Set;
public class InfeasibleConfiguration extends Configuration {
private final StartConfiguration startCfg;
private final Set<ResourceNode> problematicNodes;
/**
......@@ -53,8 +51,10 @@ public class InfeasibleConfiguration extends Configuration {
*/
private final Map<Integer, Set<ResourceNode>> zeroNodesByLayer;
private final StartConfiguration startCfg;
public InfeasibleConfiguration(StartConfiguration startCfg) {
super(startCfg);
super(Objects.requireNonNull(startCfg));
this.startCfg = startCfg;
this.problematicNodes = new HashSet<>();
this.fixedNodes = new HashSet<>();
......@@ -75,7 +75,11 @@ public class InfeasibleConfiguration extends Configuration {
}
if (node.getDelay() == 0) {
zeroNodesByLayer.put(layer, new HashSet<>());
if (!problematicNodes.contains(node) && zeroNodesByLayer.containsKey(layer)) {
throw new IllegalArgumentException("Layer " + layer + " already contains a zero node.");
}
zeroNodesByLayer.putIfAbsent(layer, new HashSet<>());
zeroNodesByLayer.get(layer).add(node);
}
}
......@@ -96,10 +100,6 @@ public class InfeasibleConfiguration extends Configuration {
}
public StartConfiguration getStartConfiguration() {
return startCfg;
}
public Set<ResourceNode> getProblematicNodes() {
return Collections.unmodifiableSet(problematicNodes);
}
......@@ -121,9 +121,11 @@ public class InfeasibleConfiguration extends Configuration {
}
/**
* Returns all nodes with a delay of zero which have not been fixed yet. These nodes are important whenever the
* problematic nodes must be placed across layer boundaries, as only zero nodes do not increase the ASAP times when
* crossing the boundaries.
* Computes all remaining nodes with a delay of zero which have not been fixed yet. These nodes are important
* whenever the problematic nodes must be placed across layer boundaries, as only zero nodes do not necessarily
* increase their successors' ASAP times when crossing the boundaries.
*
* @return the computed set of zero nodes
*/
public Set<ResourceNode> getRemainingZeroNodes() {
Set<ResourceNode> remainingZeroNodes = new HashSet<>();
......@@ -136,13 +138,21 @@ public class InfeasibleConfiguration extends Configuration {
}
public Set<ResourceNode> getLooseNodesAtLayer(int layer) {
Set<ResourceNode> freeNodes = new HashSet<>();
Set<ResourceNode> looseNodes = new HashSet<>();
for (int id : layers.getLayer(layer)) {
if (!fixedNodes.contains(nodeTable.get(id))) {
freeNodes.add(nodeTable.get(id));
looseNodes.add(nodeTable.get(id));
}
}
return freeNodes;
return looseNodes;
}
public Set<ResourceNode> getLowestProblematicNodes() {
final int maxDepth = Collections.max(problematicNodesAtLayer.keySet());
return JavaUtils.asSet(problematicNodes.stream().filter(n -> layers.getDepth(n.getId()) == maxDepth));
}
}
......@@ -25,13 +25,13 @@ import java.util.Map;
import java.util.Objects;
public class StartConfiguration extends Configuration {
private ResourceNode destinationNode;
private int destinationNodeLayer;
protected ResourceNode destinationNode;
private Integer destinationNodeLayer;
public StartConfiguration(LayerStructure layers, Map<Integer, ResourceNode> nodeTable, Resource problematicResource,
int maxInnerDelay) {
super(layers, nodeTable, problematicResource, maxInnerDelay);
}
public void setDestinationNode(ResourceNode destinationNode) {
......@@ -46,29 +46,16 @@ public class StartConfiguration extends Configuration {
}
public ResourceNode getDestinationNode() {
if (destinationNode == null) {
throw new UnsupportedOperationException("Destination node must be set first.");
}
return destinationNode;
}
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 destinationNodeLayer == that.destinationNodeLayer && Objects
.equals(destinationNode, that.destinationNode);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), destinationNode, destinationNodeLayer);
}
}
......@@ -31,6 +31,7 @@ import java.util.Set;
public class SuffixConfiguration extends Configuration {
private final List<ResourceNode> suffixNodes;
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
......@@ -38,27 +39,29 @@ public class SuffixConfiguration extends Configuration {
* infeasibility wouldn't be guaranteed anymore.
*/
private final Map<ResourceNode, Integer> suffixOffsets;
private final Set<ResourceNode> backedgeSources;
private final InfeasibleConfiguration infeasibleCfg;
private final StartConfiguration startCfg;
public SuffixConfiguration(List<ResourceNode> suffixNodes, Set<ResourceNode> backedgeSources,
InfeasibleConfiguration infeasibleCfg) {
super(Objects.requireNonNull(infeasibleCfg).getStartConfiguration());
StartConfiguration startCfg) {
super(Objects.requireNonNull(startCfg));
this.suffixNodes = Objects.requireNonNull(suffixNodes);
this.backedgeSources = Objects.requireNonNull(backedgeSources);
this.suffixOffsets = new HashMap<>();
this.infeasibleCfg = infeasibleCfg;
this.startCfg = startCfg;
}
public int getRemainingInnerDelay() {
return maxInnerDelay - problematicResource.delay - infeasibleCfg.getStartConfiguration().getDestinationNode()
.getDelay() - suffixNodes.stream().mapToInt(Node::getDelay).sum();
return maxInnerDelay - problematicResource.delay - startCfg.getDestinationNode().getDelay() - suffixNodes
.stream().mapToInt(Node::getDelay).sum();
}
public void setInitialOffset(int offset) {
suffixOffsets.put(suffixNodes.get(0), offset);
}
public void addPlannedEdge(PlannedEdge edge) {
if (!suffixNodes.contains(edge.src) && !suffixNodes.contains(edge.dst)) {
if (!suffixNodes.contains(Objects.requireNonNull(edge).src) || !suffixNodes.contains(edge.dst)) {
throw new IllegalArgumentException("The edge does not affect any suffix node.");
} else if (!suffixOffsets.containsKey(edge.src)) {
throw new IllegalArgumentException(
......
......@@ -24,6 +24,11 @@ import graphgen.util.JavaUtils;
import java.util.Collection;
import java.util.Objects;
/**
* A utility class for non-final edges where edge delays and distances can be freely modified.
*
* @author Sebastian Vollbrecht
*/
public final class PlannedEdge {
public final ResourceNode src;
......@@ -34,15 +39,7 @@ public final class PlannedEdge {
public PlannedEdge(ResourceNode src, ResourceNode dst, int delay, int distance) {
this.src = Objects.requireNonNull(src);
this.dst = Objects.requireNonNull(dst);
if (delay < 0) {
throw new IllegalArgumentException("Delay cannot be negative.\nGiven delay: " + delay);
}
this.delay = delay;
if (distance < 0) {
throw new IllegalArgumentException("Delay cannot be negative.\nGiven delay: " + delay);
}
this.distance = distance;
}
......@@ -55,11 +52,10 @@ public final class PlannedEdge {
* @throws NullPointerException if the set of edges is null
* @throws IllegalArgumentException if the set of edges is empty and the delay to distribute is non-zero
*/
public static void distributeRemainingDelay(Collection<PlannedEdge> plannedEdges, int delay, SeededRandom rng) {
public static void distributeDelay(Collection<PlannedEdge> plannedEdges, int delay, SeededRandom rng) {
if (Objects.requireNonNull(plannedEdges).isEmpty() && delay > 0) {
throw new IllegalArgumentException(
"Cannot distribute remaining delay of " + delay + " over non-existent edges.");
throw new IllegalArgumentException("Cannot distribute delay of " + delay + " over non-existent edges.");
} else if (delay < 0) {
throw new IllegalArgumentException("The delay cannot be negative.");
}
......@@ -102,10 +98,11 @@ public final class PlannedEdge {
@Override
public String toString() {
if (distance > 0)
if (distance > 0) {
return src + "--(" + delay + ", " + distance + ")-->" + dst;
else
} else {
return src + "--" + delay + "-->" + dst;
}
}
}
\ No newline at end of file
......@@ -17,10 +17,6 @@
package graphgen.generator.exceptions;
import modsched.Node;
import java.util.Set;
public class MinIIImpossibleException extends RuntimeException {
/**
......@@ -32,7 +28,7 @@ public class MinIIImpossibleException extends RuntimeException {
super("The ResMinII " + resMinII + " of the nodes is greater than the specified MinII of " + minII + ".");
}
public MinIIImpossibleException(Set<? extends Node> nodes) {
public MinIIImpossibleException() {
super("The nodes' delays do not allow for a RecMinII-ensuring cycle to be laid among them.");
}
......
......@@ -109,15 +109,15 @@ public class JavaUtils {
}
/**
* Constructs a set containing the provided elements. Changes to the returned set do not write through to the array,
* in contrast to {@link Arrays#asList(Object...)}.
* Constructs a hash set containing the provided elements. Changes to the returned set do not write through to the
* array, in contrast to {@link Arrays#asList(Object[])}.
*
* @param <T> the element type
* @param ts the elements
* @return the set containing the elements
*/
@SafeVarargs
public static <T> Set<T> asSet(T... ts) {
public static <T> HashSet<T> asSet(T... ts) {
return new HashSet<>(Arrays.asList(ts));
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment