Loading src/main/java/graphgen/generator/components/properties/minII/combined/InfeasibleMinIIFeasibleIIProperty.java 0 → 100644 +103 −0 Original line number Diff line number Diff line /* * 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; } } src/main/java/graphgen/generator/components/properties/minII/infeasible/InfeasibleMinIICycleProperty.java 0 → 100644 +366 −0 Original line number Diff line number Diff line /* * 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 src/main/java/graphgen/main/Main.java +1 −0 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ public class Main { // CaseStudyCASES2018.generate(); // RandomGraphs.generate(); } /** Loading src/main/java/graphgen/util/SchedulingUtils.java +41 −9 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading @@ -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); } /* * 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. */ 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); /* * 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. * The resulting time denotes the time of the destination node in the next * iteration. */ int maxII = layers.getLastLayer().stream().map(graph::getNode) .mapToInt(n -> earliestPossibleTimes.get(n) + n.getDelay()).max().orElse(0); 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; } Loading Loading @@ -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); } Loading src/test/java/graphgen/util/SchedulingUtilsTest.java +39 −0 Original line number Diff line number Diff line Loading @@ -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() { Loading Loading
src/main/java/graphgen/generator/components/properties/minII/combined/InfeasibleMinIIFeasibleIIProperty.java 0 → 100644 +103 −0 Original line number Diff line number Diff line /* * 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; } }
src/main/java/graphgen/generator/components/properties/minII/infeasible/InfeasibleMinIICycleProperty.java 0 → 100644 +366 −0 Original line number Diff line number Diff line /* * 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
src/main/java/graphgen/main/Main.java +1 −0 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ public class Main { // CaseStudyCASES2018.generate(); // RandomGraphs.generate(); } /** Loading
src/main/java/graphgen/util/SchedulingUtils.java +41 −9 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading @@ -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); } /* * 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. */ 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); /* * 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. * The resulting time denotes the time of the destination node in the next * iteration. */ int maxII = layers.getLastLayer().stream().map(graph::getNode) .mapToInt(n -> earliestPossibleTimes.get(n) + n.getDelay()).max().orElse(0); 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; } Loading Loading @@ -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); } Loading
src/test/java/graphgen/util/SchedulingUtilsTest.java +39 −0 Original line number Diff line number Diff line Loading @@ -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() { Loading