Commit 5ccf5525 authored by Sebastian Vollbrecht's avatar Sebastian Vollbrecht

Began working on an InfeasibleMinII-FeasibleII property (for fixed numbers of...

Began working on an InfeasibleMinII-FeasibleII property (for fixed numbers of infeasible II candidates).
parent 89e2b3ee
/*
* 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.minII.combined;
import graphgen.enums.ModuloSchedulingFormulation;
import graphgen.generator.components.properties.minII.infeasible.InfeasibleMinIICycleProperty;
import graphgen.graph.ResourceNode;
import graphgen.util.SchedulingUtils;
import modsched.Edge;
import java.util.HashSet;
import java.util.Set;
/**
* This property can be used to define the distance of the first <i>feasible</i> II to a defined MinII.
*
* @author Sebastian Vollbrecht
*/
public class InfeasibleMinIIFeasibleIIProperty extends InfeasibleMinIICycleProperty {
private final ModuloSchedulingFormulation formulation;
/**
* Creates a new infeasible MinII & feasible II property which ensures that the specified MinII and the number of
* subsequent given timesteps will be (and remain) infeasible during graph creation. The delay and distance
* parameters will be used for the RecMinII-ensuring backedges. The backedge parameters are set to 1 in this
* constructor. The infeasible timesteps parameter denotes how many timesteps should be infeasible, starting at the
* MinII's timestep (inclusive).
*
* @param minII the MinII to ensure
* @param infeasibleTimesteps the number of infeasible timesteps
* @param formulation the ILP formulation to use to determine edge and backedge validity for the (MinII +
* infeasible timesteps)-th timestep
* @throws IllegalArgumentException if the MinII is not greater than zero, if the backedge delay is less than zero
* or if the backedge distance is not greater than zero
*/
public InfeasibleMinIIFeasibleIIProperty(int minII, int infeasibleTimesteps,
ModuloSchedulingFormulation formulation) {
this(minII, 1, 1, infeasibleTimesteps, formulation);
}
/**
* Creates a new infeasible MinII & feasible II property which ensures that the specified MinII and the number of
* given timesteps will be (and remain) infeasible during graph creation. The delay and distance parameters will be
* used for the RecMinII-ensuring backedges. The infeasible timesteps parameter denotes how many timesteps should be
* infeasible, starting at the MinII's timestep (inclusive).
*
* @param minII the MinII to ensure
* @param backedgeDelay the delay of the RecMinII-ensuring backedges
* @param backedgeDistance the distance of the RecMinII-ensuring backedges
* @param infeasibleTimesteps the number of infeasible timesteps
* @param formulation the ILP formulation to use to determine edge and backedge validity for the (MinII +
* infeasible timesteps)-th timestep
* @throws IllegalArgumentException if the MinII is not greater than zero, if the backedge delay is less than zero
* or if the backedge distance is not greater than zero
*/
public InfeasibleMinIIFeasibleIIProperty(int minII, int backedgeDelay, int backedgeDistance,
int infeasibleTimesteps, ModuloSchedulingFormulation formulation) {
super(minII, backedgeDelay, backedgeDistance, infeasibleTimesteps);
this.formulation = formulation;
}
@Override
public boolean isEdgeValid(ResourceNode src, ResourceNode dst, int delay) {
return isBackedgeValid(src, dst, delay, 0);
}
@Override
public boolean isBackedgeValid(ResourceNode src, ResourceNode dst, int delay, int distance) {
Set<Edge<ResourceNode>> tmpEdges = new HashSet<>(edgeCreator.edgeView());
tmpEdges.add(new Edge<>(src, dst, delay, distance));
if (SchedulingUtils.getRecMinII(nodes, tmpEdges) > minII) {
return false;
}
int firstFeasibleII = minII + infeasibleIIs;
for (int II = minII; II < firstFeasibleII; II++) {
assert !SchedulingUtils.isFeasible(nodes, tmpEdges, formulation, II, II);
}
return SchedulingUtils.schedule(nodes, tmpEdges, "", formulation, 1, minII, firstFeasibleII)
.getII() == firstFeasibleII;
}
}
/*
* 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.minII.infeasible;
import graphgen.datastructures.Pair;
import graphgen.generator.components.properties.minII.MinIIProperty;
import graphgen.generator.components.properties.minII.util.PlannedEdge;
import graphgen.graph.Resource;
import graphgen.graph.ResourceNode;
import graphgen.util.JavaUtils;
import modsched.Edge;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Predicate;
/**
* TODO: place your javadoc here
*
* @author Sebastian Vollbrecht
*/
public abstract class InfeasibleMinIICycleProperty extends MinIIProperty<InfeasibleConfiguration> {
/**
* Stores how many IIs should be infeasible in total, starting at the cycle's MinII (inclusive).
*/
protected final int infeasibleIIs;
protected InfeasibleMinIICycleProperty(int minII, int backedgeDelay, int backedgeDistance, int infeasibleIIs) {
super(minII, backedgeDelay, backedgeDistance);
this.infeasibleIIs = JavaUtils.requireGreater(infeasibleIIs, 0);
}
@Override
protected boolean isResMinIISufficient(int resMinII) {
/*
* We *have* to create an infeasible sub graph - even if the ResMinII equals the MinII -
* as the generated graph itself might not be infeasible in all cases.
*/
return false;
}
@Override
protected int getMinInnerDelay() {
/*
* We must use the absolute maximum inner delay for infeasible cycles.
* Otherwise we might introduce slack, resulting in potentially feasible cycles.
*/
return maxInnerDelay(minII, backedgeDelay, backedgeDistance);
}
@Override
protected int getMaxInnerDelay() {
return maxInnerDelay(minII, backedgeDelay, backedgeDistance);
}
@Override
protected Set<InfeasibleConfiguration> getInitialConfigurations(int maxInnerDelay) {
/* Determine possible problematic resources from the given set of nodes. */
Set<Resource> problematicResources = getProblematicResources(maxInnerDelay);
/*
* Possible infeasible configurations can be computed for every potential resource.
*/
Map<Resource, Set<InfeasibleConfiguration>> configurationsByResource = new HashMap<>();
for (Resource problematicResource : problematicResources) {
Set<InfeasibleConfiguration> infeasibleConfigurations = new HashSet<>();
for (int dstNodeLayer = 0; dstNodeLayer < layers.getHeight() - 1; dstNodeLayer++) {
InfeasibleCycleInspector inspector = new InfeasibleCycleInspector(layers, nodes, problematicResource,
infeasibleIIs, dstNodeLayer
);
Set<ResourceNode> possibleDstNodes = inspector.getInitialNodes(maxInnerDelay);
/*
* Continue with the next destination node layer if there are no valid
* destination nodes for the current destination node layer.
*/
if (possibleDstNodes.isEmpty()) {
continue;
}
/*
* If any of the currently possible destination nodes is already contained in
* the current layer, we prefer choosing one of them. Otherwise, randomly choose
* a possible destination node.
*/
Set<Integer> currentLayer = layers.getLayer(dstNodeLayer);
Set<ResourceNode> nodesInCurrentLayer = new HashSet<>();
possibleDstNodes.stream().filter(n -> currentLayer.contains(n.getId()))
.forEach(nodesInCurrentLayer::add);
ResourceNode dstNode;
if (!nodesInCurrentLayer.isEmpty()) {
dstNode = JavaUtils.pickRandomElement(nodesInCurrentLayer, rng);
} else {
dstNode = JavaUtils.pickRandomElement(possibleDstNodes, rng);
}
infeasibleConfigurations
.add(new InfeasibleConfiguration(layers, nodeTable, maxInnerDelay, problematicResource,
infeasibleIIs, dstNode, dstNodeLayer
));
}
if (!infeasibleConfigurations.isEmpty()) {
configurationsByResource.put(problematicResource, infeasibleConfigurations);
}
}
if (configurationsByResource.isEmpty()) {
return Collections.emptySet();
}
/*
* Randomly choose from the remaining resources a potential resource and return the
* set of corresponding infeasible configurations.
*/
Resource problematicResource = JavaUtils.pickRandomElement(problematicResources, rng);
return configurationsByResource.get(problematicResource);
}
/**
* Computes possible problematic resources whose limit could be exceeded in a cycle. 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 corresponding MinIIs.
*
* @param maxInnerDelay the cycle's maximum inner delay
* @return a set containing problematic resource candidates
*/
private Set<Resource> getProblematicResources(int maxInnerDelay) {
Set<Resource> potentialResources = new HashSet<>();
/*
* Maps limited resources to the amount of nodes using them.
*/
Map<Resource, Integer> limitedResourceUsages = new HashMap<>();
for (ResourceNode node : nodes) {
if (node.isUnlimited()) {
continue;
}
JavaUtils.insertOrIncValue(limitedResourceUsages, node.resource);
}
/*
* A resource is only a valid problematic resource if it is used more than its
* limit allows for throughout the graph and if its delay does not exceed the
* maximum possible inner delay.
*/
for (Map.Entry<Resource, Integer> resourceUsage : limitedResourceUsages.entrySet()) {
Resource resource = resourceUsage.getKey();
if (resourceUsage.getValue() > (resource.limit * infeasibleIIs) && resource.delay <= maxInnerDelay) {
potentialResources.add(resource);
}
}
return potentialResources;
}
@Override
protected void arrangeNodes(int innerDelay, InfeasibleConfiguration infeasibleCfg) {
Resource problematicResource = infeasibleCfg.getProblematicResource();
/*
* If and only if the following conditions are met, the destination node can be
* counted as a problematic node, since it then won't shift the subsequent
* layers' time slots (where other problematic nodes might need to be placed).
*/
if (infeasibleCfg.getDestinationNode().resource.equals(problematicResource) && problematicResource.delay == 0) {
infeasibleCfg.addProblematicNode(infeasibleCfg.getDestinationNode());
}
InfeasibleNodePlacer placer = new InfeasibleNodePlacer(infeasibleCfg, rng);
placer.placeNode(infeasibleCfg.getDestinationNode(), JavaUtils.asSet(infeasibleCfg.getDestinationNodeLayer()));
/*
* Gather all remaining nodes which use the problematic resource and randomly
* choose the required amount of nodes to create the infeasible cycle.
*/
Set<ResourceNode> problematicCandidates = new HashSet<>();
for (ResourceNode node : nodes) {
if (node.resource.equals(problematicResource) && !node.equals(infeasibleCfg.getDestinationNode())) {
problematicCandidates.add(node);
}
}
for (int i = 0; i < infeasibleCfg.howManyLeftToPlace(); i++) {
ResourceNode problematicNode = JavaUtils.removeRandomElement(problematicCandidates, rng);
infeasibleCfg.addProblematicNode(problematicNode);
}
/*
* Now we place the remaining problematic nodes. By sorting them first
* using their layer depths we can achieve that most of the problematic nodes
* will be placed in the layers they are currently residing in. Otherwise they
* 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(layers::getDepth))) {
/*
* If a problematic node has been fixed already, we don't need to place it
* anymore. This can only occur if the problematic resource's delay is zero and
* a problematic node has been chosen as a zero node while moving across layer
* boundaries.
*/
if (!infeasibleCfg.getFixedNodes().contains(problematicNode)) {
Set<Integer> possibleLayers = placer.getPossibleLayers(problematicNode);
placer.placeNode(problematicNode, possibleLayers);
}
}
/*
* Now try to append a suffix to the infeasible part of the cycle.
*/
int remainingInnerDelay = infeasibleCfg.getRemainingInnerDelay();
/*
* Append suffix nodes to the cycle as long as possible. The suffix layers begin
* after the last problematic layer.
*
* Also pick a random double value which defines the probability to append a
* node with delay zero if the remaining inner delay is zero already.
*/
double pToAppendMoreZeroNodes = rng.nextDouble();
int maxDepth = Collections.max(infeasibleCfg.getProblematicNodeCountsByLayer().keySet());
for (int layer = maxDepth + 1; layer < layers.getHeight(); layer++) {
Set<ResourceNode> candidates = new HashSet<>();
if (remainingInnerDelay == 0 && rng.nextDouble() > pToAppendMoreZeroNodes) {
break;
}
for (int nodeID : layers.getLayer(layer)) {
ResourceNode candidate = nodeTable.get(nodeID);
if (candidate.getDelay() <= remainingInnerDelay) {
candidates.add(candidate);
}
}
if (candidates.isEmpty())
break;
/*
* Append a randomly picked candidate to the suffix and update the remaining
* inner delay accordingly.
*/
ResourceNode candidate = JavaUtils.pickRandomElement(candidates, rng);
infeasibleCfg.appendSuffixNode(candidate);
remainingInnerDelay -= candidate.getDelay();
}
}
@Override
public void reset() {
// Do nothing.
}
@Override
public void notify(Edge<ResourceNode> edge) {
// Do nothing.
}
@Override
protected Set<PlannedEdge> getNeededEdges(InfeasibleConfiguration infeasibleCfg,
BiFunction<ResourceNode, ResourceNode, Integer> delayComputer) {
Set<PlannedEdge> plannedEdges = new HashSet<>();
/* Choose the timeslot of the problematic nodes (relative to the destination node). */
Set<Integer> possibleTimeslots = InfeasibleEdgePlanner.getProblematicTimeslots(infeasibleCfg);
int problematicTimeslot = JavaUtils.pickRandomElement(possibleTimeslots, rng);
/*
* 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.
*/
InfeasibleEdgePlanner edgePlanner = new InfeasibleEdgePlanner(infeasibleCfg, problematicTimeslot, rng);
/* Stores pairs of source and destination nodes which need to be connected with an edge. */
Set<Pair<ResourceNode, ResourceNode>> edgePairs = edgePlanner.getNeededEdgePairs();
edgePairs.forEach(p -> plannedEdges.add(new PlannedEdge(p.first, p.second, 0)));
/*
* 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).
*/
edgePlanner.distributeDelay(plannedEdges, delayComputer);
/*
* 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).
*/
Predicate<ResourceNode> needsOutgoingEdge = n -> plannedEdges.stream().noneMatch(e -> e.src.equals(n));
Set<PlannedEdge> outgoingEdges = edgePlanner
.getOutgoingEdges(problematicTimeslot, needsOutgoingEdge, delayComputer);
plannedEdges.addAll(outgoingEdges);
/*
* Finally, add the backedges going to the destination node. The backedge
* source selection depends on whether or not a suffix exists.
*/
ResourceNode dst = infeasibleCfg.getDestinationNode();
if (infeasibleCfg.getSuffixNodes().isEmpty()) {
for (ResourceNode src : infeasibleCfg.getBackedgeSources()) {
plannedEdges.add(new PlannedEdge(src, dst, backedgeDelay, backedgeDistance));
}
} else {
ResourceNode src = infeasibleCfg.getSuffixNodes().get(infeasibleCfg.getSuffixNodes().size() - 1);
plannedEdges.add(new PlannedEdge(src, dst, backedgeDelay, backedgeDistance));
}
return plannedEdges;
}
}
\ No newline at end of file
......@@ -62,6 +62,7 @@ public class Main {
// CaseStudyCASES2018.generate();
// RandomGraphs.generate();
}
/**
......
......@@ -40,6 +40,7 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.Callable;
......@@ -294,8 +295,9 @@ public class SchedulingUtils {
for (Edge<ResourceNode> edge : incoming.get(node)) {
if (edge.isBackedge())
if (edge.isBackedge()) {
continue;
}
ResourceNode src = edge.getSrc();
......@@ -319,16 +321,46 @@ public class SchedulingUtils {
}
int maxII = 0;
for (Entry<ResourceNode, Integer> timeEntry : earliestPossibleTimes.entrySet()) {
/*
* The additional call to Math.max(...) makes sure that 'end' nodes with delay
* 0 don't lead to the next iteration beginning in the end node's timeslot.
*/
maxII = Math.max(timeEntry.getValue() + Math.max(timeEntry.getKey().getDelay(), 1), maxII);
}
/*
* Because the computation of the MaxII does not take into account the
* inter-iteration-dependencies imposed by the backedges, it might be smaller
* than the RecMinII of the graph. Therefore, the greater value of both II
* bounds should be returned.
* Check whether the current MaxII fulfills every single backedge dependency by
* calculating how far away the backedge's source and destination nodes would be
* placed in the non-modulo schedule. If they are too close together, the MaxII
* needs to be increased accordingly.
*/
int maxII = layers.getLastLayer().stream().map(graph::getNode)
.mapToInt(n -> earliestPossibleTimes.get(n) + n.getDelay()).max().orElse(0);
for (Edge<ResourceNode> backedge : JavaUtils
.asSet(graph.edges.stream().filter(EdgeType.BACKWARD::matchesEdge))) {
ResourceNode src = backedge.getSrc();
ResourceNode dst = backedge.getDst();
int srcTime = earliestPossibleTimes.get(src);
int dstTime = earliestPossibleTimes.get(dst);
/*
* The resulting time denotes the time of the destination node in the next
* iteration.
*/
int resultingTimeDelta = (dstTime + maxII) - srcTime;
int neededTimeDelta = (src.getDelay() + backedge.getDelay()) / backedge.getDistance();
int delta = neededTimeDelta - resultingTimeDelta;
if (delta > 0) {
maxII += delta;
}
}
return Math.max(maxII, getMinII(graph));
return maxII;
}
......@@ -369,7 +401,7 @@ public class SchedulingUtils {
}
}
resourceUsagePerSlot.get(nodeSlot).put(res, resourceUsagePerSlot.get(nodeSlot).get(res) + 1);
JavaUtils.insertOrIncValue(resourceUsagePerSlot.get(nodeSlot), res);
nodeTimes.put(node, nodeSlot);
}
......
......@@ -554,6 +554,45 @@ public class SchedulingUtilsTest {
assertEquals(13, SchedulingUtils.getMaxII(graph));
}
@Test
public void testMaxII2() {
Resource limited = new Resource("adder", 1, 1);
Resource unlimited = new Resource("unlimited", 0);
ResourceNode n0 = new ResourceNode(0, unlimited);
ResourceNode n1 = new ResourceNode(1, unlimited);
ResourceNode n2 = new ResourceNode(2, limited);
ResourceNode n3 = new ResourceNode(3, limited);
ResourceNode n4 = new ResourceNode(4, limited);
ResourceNode n5 = new ResourceNode(5, unlimited);
Set<ResourceNode> nodes = JavaUtils.asSet(n0, n1, n2, n3, n4, n5);
Set<Edge<ResourceNode>> edges = new HashSet<>();
edges.add(new Edge<>(n0, n1, 0, 0));
edges.add(new Edge<>(n0, n2, 0, 0));
edges.add(new Edge<>(n0, n3, 0, 0));
edges.add(new Edge<>(n1, n4, 0, 0));
edges.add(new Edge<>(n2, n5, 1, 0));
edges.add(new Edge<>(n3, n5, 1, 0));
edges.add(new Edge<>(n4, n5, 1, 0));
Edge<ResourceNode> edge = new Edge<>(n5, n0, 1, 1);
edges.add(edge);
//assertEquals(5, SchedulingUtils.getMaxII(new Graph<>(nodes, edges)));
edges.remove(edge);
edge = new Edge<>(n5, n0, 50, 1);
edges.add(edge);
assertEquals(54, SchedulingUtils.getMaxII(new Graph<>(nodes, edges)));
edges.remove(edge);
edge = new Edge<>(n5, n0, 50, 2);
edges.add(edge);
assertEquals(29, SchedulingUtils.getMaxII(new Graph<>(nodes, edges)));
}
@Test
public void minIIGreaterMaxIIProblematicOne1() {
......
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