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

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));
......
/*
* Copyright 2018 Sebastian Vollbrecht, Julian Oppermann
* Embedded Systems and Applications Group, TU Darmstadt
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package graphgen.generator.components.properties.infeasibleMinII;
import graphgen.datastructures.SeededRandom;
import graphgen.generator.components.Initializable;
import graphgen.generator.components.properties.infeasibleMinII.configuration.InfeasibleConfiguration;
import graphgen.generator.components.properties.infeasibleMinII.configuration.StartConfiguration;
import graphgen.generator.components.properties.infeasibleMinII.configuration.SuffixConfiguration;
import graphgen.generator.components.properties.util.PlannedEdge;
import graphgen.graph.ResourceNode;
import graphgen.util.JavaUtils;
import java.util.ArrayList;
import java.util.Collection;
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.BiFunction;
import java.util.function.Predicate;
public class InfeasibleEdgeInspector implements Initializable {
private final StartConfiguration startCfg;
private final InfeasibleConfiguration infeasibleCfg;
private final SuffixConfiguration suffixCfg;
private SeededRandom rng;
public InfeasibleEdgeInspector(StartConfiguration startCfg, InfeasibleConfiguration infeasibleCfg,
SuffixConfiguration suffixCfg) {
this.startCfg = startCfg;
this.infeasibleCfg = infeasibleCfg;
this.suffixCfg = suffixCfg;
}
public Set<PlannedEdge> getIncomingEdges() {
Set<PlannedEdge> edges = new HashSet<>();
Map<ResourceNode, Set<PlannedEdge>> incomingEdgesByNode = new HashMap<>();
Map<ResourceNode, Set<PlannedEdge>> outgoingEdgesByNode = new HashMap<>();
/* Generate an incoming edge for every fixed node. */
for (ResourceNode fixedNode : infeasibleCfg.getFixedNodes()) {
if (incomingEdgesByNode.containsKey(fixedNode) || fixedNode == startCfg.getDestinationNode()) {
continue;
}
Set<ResourceNode> predecessors = getPossiblePredecessors(fixedNode, startCfg, infeasibleCfg);
ResourceNode predecessor = JavaUtils.pickRandomElement(predecessors, rng);
PlannedEdge edge = new PlannedEdge(predecessor, fixedNode, 0, 0);
incomingEdgesByNode.putIfAbsent(fixedNode, new HashSet<>());
incomingEdgesByNode.get(fixedNode).add(edge);
outgoingEdgesByNode.putIfAbsent(predecessor, new HashSet<>());
outgoingEdgesByNode.get(predecessor).add(edge);
edges.add(edge);
}
/* Generate an incoming edge for every suffix node. */
for (int i = 0; i < suffixCfg.getSuffixNodes().size(); i++) {
ResourceNode suffixNode = suffixCfg.getSuffixNodes().get(i);
if (i == 0) {
for (ResourceNode src : infeasibleCfg.getLowestProblematicNodes()) {
PlannedEdge edge = new PlannedEdge(src, suffixNode, 0, 0);
incomingEdgesByNode.putIfAbsent(src, new HashSet<>());
incomingEdgesByNode.get(src).add(edge);
outgoingEdgesByNode.putIfAbsent(src, new HashSet<>());
outgoingEdgesByNode.get(src).add(edge);
edges.add(edge);
}
} else {
ResourceNode src = suffixCfg.getSuffixNodes().get(i - 1);
PlannedEdge edge = new PlannedEdge(src, suffixNode, 0, 0);
incomingEdgesByNode.putIfAbsent(suffixNode, new HashSet<>());
incomingEdgesByNode.get(suffixNode).add(edge);
outgoingEdgesByNode.putIfAbsent(src, new HashSet<>());
outgoingEdgesByNode.get(src).add(edge);
edges.add(edge);
}
}
return edges;
}
public Set<PlannedEdge> getOutgoingEdges(int problematicTimeslot, Predicate<ResourceNode> nodeNeedsOutgoingEdge,
BiFunction<ResourceNode, ResourceNode, Integer> delayComputer) {
Set<PlannedEdge> problematicEdges = new HashSet<>();
/*
* Create an outgoing edge for every fixed node. This can either be an edge
* connecting to other fixed nodes/suffix nodes, or it can be a backedge
* connecting to the destination node, thereby reducing the fixed node's slack
* to zero as well.
*/
for (ResourceNode fixedNode : infeasibleCfg.getFixedNodes()) {
if (!nodeNeedsOutgoingEdge.test(fixedNode)) {
continue;
}
Map<ResourceNode, Integer> possibleDstsWithDelay = new HashMap<>();
/*
* A problematic node may only connect to other problematic nodes if both the
* edge's delay and the problematic resource's delay are zero. Otherwise, the
* target node's ASAP time would increase and it would no longer share the
* problematic slot with the other nodes.
*/
if (startCfg.getProblematicResource().delay == 0) {
int sourceNodeDepth = startCfg.getLayers().getDepth(fixedNode.getId());
for (ResourceNode dst : infeasibleCfg.getFixedNodes()) {
if (startCfg.getLayers().getDepth(dst.getId()) <= sourceNodeDepth) {
continue;
}
if (delayComputer.apply(fixedNode, dst) == 0) {
possibleDstsWithDelay.put(dst, 0);
}
}
}
/*
* A problematic node may only connect to suffix nodes if the edge delay of the
* resulting edge would reduce the problematic node's slack to zero.
*/
for (ResourceNode suffixNode : suffixCfg.getSuffixNodes()) {
int suffixNodeSlot = suffixCfg.getSuffixOffsets().get(suffixNode);
int edgeDelay = delayComputer.apply(fixedNode, suffixNode);
int neededEdgeDelay = suffixNodeSlot - fixedNode.getDelay() - problematicTimeslot;
if (edgeDelay == neededEdgeDelay) {
possibleDstsWithDelay.put(suffixNode, edgeDelay);
}
}
/*
* If no possible destination node could be found, connect the problematic
* node to the first suffix node (if present) to keep the edge delay
* minimal. If no suffix has been created, the node must become a backedge
* source.
*/
if (possibleDstsWithDelay.isEmpty()) {
if (!suffixCfg.getSuffixNodes().isEmpty()) {
ResourceNode firstSuffixNode = suffixCfg.getSuffixNodes().get(0);
int suffixNodeSlot = suffixCfg.getSuffixOffsets().get(firstSuffixNode);
int edgeDelay = suffixNodeSlot - fixedNode.getDelay() - problematicTimeslot;
problematicEdges.add(new PlannedEdge(fixedNode, firstSuffixNode, edgeDelay, 0));
} else {
suffixCfg.getBackedgeSources().add(fixedNode);
}
}
/*
* Otherwise, if possible destination nodes have been determined, pick one of
* them randomly and create the resulting edge.
*/
else {
ResourceNode dst = JavaUtils.pickRandomElement(possibleDstsWithDelay.keySet(), rng);
problematicEdges.add(new PlannedEdge(fixedNode, dst, possibleDstsWithDelay.get(dst), 0));
}
}
return problematicEdges;
}
public Optional<PlannedEdge> distributeDelay(int problematicTimeslot, Set<PlannedEdge> edges) {
if (problematicTimeslot < 0) {
throw new IllegalArgumentException("The problematic nodes' timeslot cannot be negative.");
}
Map<ResourceNode, PlannedEdge> incomingEdgesByNode = getIncomingEdgesMap(edges, infeasibleCfg.getFixedNodes());
for (ResourceNode dst : infeasibleCfg.getFixedNodes()) {
if (dst != startCfg.getDestinationNode() && !incomingEdgesByNode.containsKey(dst)) {
throw new IllegalArgumentException("Fixed node " + dst + " does not have any incoming edges.");
}
}
/*
* The delay we need to distribute over edges leading to the problematic nodes
* so that they all end up in the given problematic timeslot.
*/
int problematicEdgesDelay = problematicTimeslot - startCfg.getDestinationNode().getDelay();
/* The set of edges whose delay must not change anymore to not destroy the infeasibility. */
Set<PlannedEdge> fixedEdges = new HashSet<>();
for (ResourceNode node : infeasibleCfg.getProblematicNodes()) {
makeNodeSlotProblematic(node, problematicEdgesDelay, incomingEdgesByNode, fixedEdges);
}
List<ResourceNode> suffixNodes = suffixCfg.getSuffixNodes();
if (!suffixNodes.isEmpty()) {
/*
* Add an edge representing all edges connecting from the lowest problematic nodes
* to the first suffix node. These edges MUST have equal delays.
*/
Set<ResourceNode> lowestNodes = infeasibleCfg.getLowestProblematicNodes();
Set<ResourceNode> relevantNodes = new HashSet<>(lowestNodes);
relevantNodes.addAll(suffixNodes);
Map<ResourceNode, PlannedEdge> outgoingEdgesByNode = getOutgoingEdgesMap(edges, relevantNodes);
for (ResourceNode src : relevantNodes) {
if (!outgoingEdgesByNode.containsKey(src) && src != suffixNodes.get(suffixNodes.size() - 1)) {
throw new IllegalArgumentException("Node " + src + " does not have any outgoing edge.");
}
}
List<PlannedEdge> suffixChain = new ArrayList<>();
PlannedEdge representative = outgoingEdgesByNode.get(lowestNodes.iterator().next());
suffixChain.add(representative);
suffixChain.addAll(getSuffixEdgeChain(outgoingEdgesByNode));
int remainingDelay = suffixCfg.getRemainingInnerDelay() - problematicTimeslot;
PlannedEdge.distributeDelay(suffixChain, remainingDelay, rng);
for (ResourceNode lowestNode : lowestNodes) {
outgoingEdgesByNode.get(lowestNode).delay = representative.delay;
}
return Optional.of(representative);
}
return Optional.empty();
}
private List<PlannedEdge> getSuffixEdgeChain(Map<ResourceNode, PlannedEdge> outgoingEdgesByNode) {
List<PlannedEdge> chain = new ArrayList<>();
for (int i = 0; i < suffixCfg.getSuffixNodes().size() - 1; i++) {
ResourceNode suffixNode = suffixCfg.getSuffixNodes().get(i);
chain.add(outgoingEdgesByNode.get(suffixNode));
}
return chain;
}
private void makeNodeSlotProblematic(ResourceNode problematicNode, int problematicEdgesDelay,
Map<ResourceNode, PlannedEdge> incomingEdgesByNode,
Set<PlannedEdge> fixedEdges) {
List<PlannedEdge> chain = new ArrayList<>();
int delayToDistribute = problematicEdgesDelay;
ResourceNode dst = problematicNode;
while (dst != startCfg.getDestinationNode()) {
PlannedEdge edge = incomingEdgesByNode.get(dst);
delayToDistribute -= edge.delay;
if (!fixedEdges.contains(edge)) {
chain.add(edge);
}
dst = edge.src;
}
PlannedEdge.distributeDelay(chain, delayToDistribute, rng);
fixedEdges.addAll(chain);
}
@Override
public void init(SeededRandom rng) {
this.rng = rng;
}
@Override
public void reset() {
// Do nothing.
}
public static Set<ResourceNode> getPossiblePredecessors(ResourceNode node, StartConfiguration startCfg,
InfeasibleConfiguration infeasibleCfg) {
int nodeDepth = infeasibleCfg.getLayers().getDepth(node.getId());
if (nodeDepth == startCfg.getDestinationNodeLayer() + 1) {
return JavaUtils.asSet(startCfg.getDestinationNode());
} else {
return infeasibleCfg.getZeroNodesByLayer().get(nodeDepth - 1);
}
}
public static Map<ResourceNode, PlannedEdge> getIncomingEdgesMap(Set<PlannedEdge> edges,
Collection<ResourceNode> relevantNodes) {
Map<ResourceNode, PlannedEdge> incomingEdgesByNode = new HashMap<>();
for (PlannedEdge edge : Objects.requireNonNull(edges)) {
if (relevantNodes.contains(edge.src) && relevantNodes.contains(edge.dst)) {
if (incomingEdgesByNode.containsKey(edge.dst)) {
throw new IllegalArgumentException("Node " + edge.dst + " must have exactly one incoming edge.");
}
incomingEdgesByNode.put(edge.dst, edge);
}
}
return incomingEdgesByNode;
}
public static Map<ResourceNode, PlannedEdge> getOutgoingEdgesMap(Set<PlannedEdge> edges,
Collection<ResourceNode> relevantNodes) {
Map<ResourceNode, PlannedEdge> outgoingEdgesByNode = new HashMap<>();
for (PlannedEdge edge : Objects.requireNonNull(edges)) {
if (relevantNodes.contains(edge.src) && relevantNodes.contains(edge.dst)) {
if (outgoingEdgesByNode.containsKey(edge.src)) {
throw new IllegalArgumentException("Node " + edge.src + " must have exactly one outgoing edge.");
}
outgoingEdgesByNode.put(edge.src, edge);
}
}
return outgoingEdgesByNode;
}
}
......@@ -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;