Commit 41146d31 authored by Sebastian Vollbrecht's avatar Sebastian Vollbrecht

Added a FeasibleCycleInspector and corresponding tests.

Also relocated minInnerDelay/maxInnerDelay methods for better clarity.
parent 9149cd22
/*
* 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;
import graphgen.graph.LayerStructure;
import graphgen.graph.ResourceNode;
import java.util.Objects;
import java.util.Set;
/**
* An abstract base class for analyzing created graphs regarding MinII-specific cycles.
*
* @author Sebastian Vollbrecht
*/
public abstract class MinIICycleInspector {
protected final LayerStructure layers;
protected final Set<ResourceNode> nodes;
protected MinIICycleInspector(LayerStructure layers, Set<ResourceNode> nodes) {
this.layers = Objects.requireNonNull(layers);
this.nodes = Objects.requireNonNull(nodes);
}
/**
* Returns the minimum inner delay which a cycle induced by the given arguments can have. The implementing classes
* are required to return a minimum inner delay such that a delay which is less than the returned delay would lead
* to one of the following problems:<ul><li>it would result in a MinII smaller than specified</li><li>it would not
* meet the implementing class's purpose (e.g. it would be impossible to ensure an infeasibility, ...)
*
* @param minII the MinII to ensure
* @param backedgeDelay the delay of the backedge(s) which will <i>close</i> the cycle
* @param backedgeDistance the distance of the backedge(s) which will <i>close</i> the cycle
* @return the cycle's minimum inner delay adhering to the above-mentioned requirements
*/
public abstract int getMinInnerDelay(int minII, int backedgeDelay, int backedgeDistance);
/**
* Returns the maximum inner delay which a cycle induced by the given arguments can have. The implementing classes
* are required to return a maximum inner delay such that a delay which is greater than the returned delay would
* lead to one of the following problems:<ul><li>it would result in a MinII greater than specified</li><li>it would
* not meet the implementing class's purpose.
*
* @param minII the MinII to ensure
* @param backedgeDelay the delay of the backedge(s) which will <i>close</i> the cycle
* @param backedgeDistance the distance of the backedge(s) which will <i>close</i> the cycle
* @return the cycle's maximum inner delay adhering to the above-mentioned requirements
*/
public abstract int getMaxInnerDelay(int minII, int backedgeDelay, int backedgeDistance);
/**
* Returns the minimum inner delay which a cycle containing backedges with the specified parameters can have without
* falling below the given MinII.
* <p>
* It is the lower bound of the RecMinII formula's ceiling function and can be retrieved like so:
* <pre>RecMinII = ceil((minInnerDelay + backedgeDelay) / backedgeDistance)</pre>
* It follows that
* <pre>(minInnerDelay + backedgeDelay) / backedgeDistance > RecMinII - 1</pre>
* and
* <pre>minInnerDelay > backedgeDistance * (RecMinII - 1) - backedgeDelay</pre><p>
* Because the inner delay is an integer value, the smallest possible value which still fulfills the inequality is
* the result of adding 1 to the right-hand side.
*
* @throws IllegalArgumentException if the MinII is not positive, if the delay is negative or if the distance is not
* positive
*/
public static int minInnerDelay(int minII, int backedgeDelay, int backedgeDistance) {
if (minII <= 0) {
throw new IllegalArgumentException("MinII must be positive.");
} else if (backedgeDelay < 0) {
throw new IllegalArgumentException("Backedge delay cannot be negative.");
} else if (backedgeDistance <= 0) {
throw new IllegalArgumentException("Backedge distance must be positive.");
}
return Math.max(0, backedgeDistance * (minII - 1) - backedgeDelay + 1);
}
/**
* Returns the maximum inner delay which a cycle containing backedges with the specified parameters can have without
* exceeding the given MinII.
* <p>
* It can be derived from the RecMinII formula:
* <pre>RecMinII = ceil((maxInnerDelay + backedgeDelay) / backedgeDistance)</pre>
* It follows that
* <pre>RecMinII * backedgeDistance = maxInnerDelay + backedgeDelay</pre>
* and
* <pre>RecMinII * backedgeDistance - backedgeDelay = maxInnerDelay</pre>
*
* @throws IllegalArgumentException if the MinII is not positive, if the delay is negative or if the distance is not
* positive
*/
public static int maxInnerDelay(int minII, int backedgeDelay, int backedgeDistance) {
if (minII <= 0) {
throw new IllegalArgumentException("MinII must be positive.");
} else if (backedgeDelay < 0) {
throw new IllegalArgumentException("Backedge delay cannot be negative.");
} else if (backedgeDistance <= 0) {
throw new IllegalArgumentException("Backedge distance must be positive.");
}
return backedgeDistance * minII - backedgeDelay;
}
}
/*
* 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.feasible;
import graphgen.generator.components.properties.minII.MinIICycleInspector;
import graphgen.graph.LayerStructure;
import graphgen.graph.ResourceNode;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* This class contains some utility methods related to inspecting a given set of nodes regarding possible feasible
* cycles.
*
* @author Sebastian Vollbrecht
*/
public class FeasibleCycleInspector extends MinIICycleInspector {
public FeasibleCycleInspector(LayerStructure layers, Set<ResourceNode> nodes) {
super(layers, nodes);
}
@Override
public int getMinInnerDelay(int minII, int backedgeDelay, int backedgeDistance) {
return minInnerDelay(minII, backedgeDelay, backedgeDistance);
}
@Override
public int getMaxInnerDelay(int minII, int backedgeDelay, int backedgeDistance) {
return maxInnerDelay(minII, backedgeDelay, backedgeDistance);
}
/**
* Computes all destination nodes that could potentially be the destination node for the backedges of a feasible
* cycle.<p>A node can only be considered destination node if at least one other node exists which can be appended
* to the destination node without exceeding the specified inner delay.<p>In case of a two-element cycle consisting
* of these two nodes only, it is furthermore important to filter out nodes which might result in an
* <i>infeasible</i> cycle if connected to the destination node. For example, if both nodes shared the same
* resource with delay 0 and a limit of 1, an edge with delay 0 would render their induced cycle infeasible.
*
* @param innerDelay the feasible cycle's inner delay
* @return a set containing all potential destination node candidates
*/
public Set<ResourceNode> getPossibleDstNodes(int innerDelay) {
Set<ResourceNode> possibleDstNodes = new HashSet<>();
Map<Integer, Set<ResourceNode>> nodesByDelay = new HashMap<>();
for (ResourceNode node : nodes) {
nodesByDelay.putIfAbsent(node.getDelay(), new HashSet<>());
nodesByDelay.get(node.getDelay()).add(node);
}
for (Entry<Integer, Set<ResourceNode>> firstEntry : nodesByDelay.entrySet()) {
int firstNodeDelay = firstEntry.getKey();
if (firstNodeDelay > innerDelay) {
continue;
}
for (ResourceNode dstNode : firstEntry.getValue()) {
if (possibleDstNodes.contains(dstNode)) {
continue;
}
for (Entry<Integer, Set<ResourceNode>> secondEntry : nodesByDelay.entrySet()) {
int secondNodeDelay = secondEntry.getKey();
/*
* RecMinII check.
*/
if (firstNodeDelay + secondNodeDelay > innerDelay) {
continue;
}
for (ResourceNode otherNode : secondEntry.getValue()) {
if (dstNode == otherNode) {
continue;
}
/*
* Infeasibility check.
*/
if (dstNode.resource == otherNode.resource) {
if (dstNode.resource.delay == 0 && dstNode.resource.limit == 1) {
/*
* If there is no inner delay remaining if these two nodes were used,
* they would need to be connected with an edge with delay 0, thus
* rendering the cycle infeasible.
*/
if (innerDelay - (2 * dstNode.resource.delay) == 0) {
continue;
}
}
}
/*
* If the first node can be the destination node, the second one can automatically
* be the destination node as well (skipping them in the next iteration speeds up
* the calculation).
*/
possibleDstNodes.add(dstNode);
possibleDstNodes.add(otherNode);
break;
}
}
}
}
return possibleDstNodes;
}
}
......@@ -21,6 +21,7 @@ import graphgen.datastructures.Pair;
import graphgen.enums.ModuloSchedulingFormulation;
import graphgen.generator.GraphGenerator;
import graphgen.generator.components.properties.Property;
import graphgen.generator.components.properties.minII.MinIICycleInspector;
import graphgen.generator.components.properties.util.PlannedEdge;
import graphgen.generator.components.properties.util.SCC;
import graphgen.generator.exceptions.MinIIImpossibleException;
......@@ -108,7 +109,7 @@ public class FeasibleMinIIProperty extends Property {
this.backedgeDistance = backedgeDistance;
// TODO: allow inner delays >= minInnerDelay and <= maxInnerDelay
this.maxInnerDelay = SchedulingUtils.getMaxInnerDelay(minII, backedgeDelay, backedgeDistance);
this.maxInnerDelay = MinIICycleInspector.maxInnerDelay(minII, backedgeDelay, backedgeDistance);
this.enclosedNodes = new HashSet<>();
this.formulation = formulation;
......
......@@ -17,6 +17,7 @@
package graphgen.generator.components.properties.minII.infeasible;
import graphgen.generator.components.properties.minII.MinIICycleInspector;
import graphgen.graph.LayerStructure;
import graphgen.graph.Resource;
import graphgen.graph.ResourceNode;
......@@ -27,25 +28,34 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* This class contains some utility methods related to inspecting nodes and layer structure regarding possible
* infeasible cycles.
* infeasible MinII cycles.
*
* @author Sebastian Vollbrecht
*/
public class InfeasibleCycleInspector {
private final LayerStructure layers;
private final Set<ResourceNode> nodes;
public class InfeasibleCycleInspector extends MinIICycleInspector {
public InfeasibleCycleInspector(LayerStructure layers, Set<ResourceNode> nodes) {
this.layers = Objects.requireNonNull(layers);
this.nodes = Objects.requireNonNull(nodes);
super(layers, nodes);
}
@Override
public int getMinInnerDelay(int minII, int backedgeDelay, int backedgeDistance) {
/*
* 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
public int getMaxInnerDelay(int minII, int backedgeDelay, int backedgeDistance) {
return maxInnerDelay(minII, backedgeDelay, backedgeDistance);
}
/**
......@@ -102,7 +112,7 @@ public class InfeasibleCycleInspector {
* destination node for the backedges of an infeasible cycle. This method assumes that the infeasibility is created
* by nodes using the given problematic resource.
*
* @param dstNodeLayer the layer for which possible possible destination nodes are needed
* @param dstNodeLayer the layer for which possible destination nodes are needed
* @param problematicResource the chosen problematic resource
* @return a set containing all potential destination node candidates
*/
......
......@@ -159,7 +159,7 @@ public class InfeasibleMinIIProperty extends Property {
InfeasibleCycleInspector inspector = new InfeasibleCycleInspector(layers, nodes);
int maxInnerDelay = SchedulingUtils.getMaxInnerDelay(minII, backedgeDelay, backedgeDistance);
int maxInnerDelay = inspector.getMaxInnerDelay(minII, backedgeDelay, backedgeDistance);
/* Determine possible problematic resources from the given set of nodes. */
Set<Resource> problematicResources = inspector.getProblematicResources(maxInnerDelay);
......
......@@ -405,59 +405,6 @@ public class SchedulingUtils {
nodeTimes.put(node, nodeSlot);
}
/**
* Returns the minimum inner delay which a cycle containing backedges with the specified parameters can have without
* falling below the given MinII.
* <p>
* It is the lower bound of the RecMinII formula's ceiling function and can be retrieved like so:
* <pre>RecMinII = ceil((minInnerDelay + backedgeDelay) / backedgeDistance)</pre>
* It follows that
* <pre>(minInnerDelay + backedgeDelay) / backedgeDistance > RecMinII - 1</pre>
* and
* <pre>minInnerDelay > backedgeDistance * (RecMinII - 1) - backedgeDelay</pre><p>
* Because the inner delay is an integer value, the smallest possible value which still fulfills the inequality is
* the result of adding 1 to the right-hand side.
*
* @throws IllegalArgumentException if the MinII is not positive, if the delay is negative or if the distance is not
* positive
*/
public static int getMinInnerDelay(int minII, int backedgeDelay, int backedgeDistance) {
if (minII <= 0) {
throw new IllegalArgumentException("MinII must be positive.");
} else if (backedgeDelay < 0) {
throw new IllegalArgumentException("Backedge delay cannot be negative.");
} else if (backedgeDistance <= 0) {
throw new IllegalArgumentException("Backedge distance must be positive.");
}
return Math.max(0, backedgeDistance * (minII - 1) - backedgeDelay + 1);
}
/**
* Returns the maximum inner delay which a cycle containing backedges with the specified parameters can have without
* exceeding the given MinII.
* <p>
* It can be derived from the RecMinII formula:
* <pre>RecMinII = ceil((maxInnerDelay + backedgeDelay) / backedgeDistance)</pre>
* It follows that
* <pre>RecMinII * backedgeDistance = maxInnerDelay + backedgeDelay</pre>
* and
* <pre>RecMinII * backedgeDistance - backedgeDelay = maxInnerDelay</pre>
*
* @throws IllegalArgumentException if the MinII is not positive, if the delay is negative or if the distance is not
* positive
*/
public static int getMaxInnerDelay(int minII, int backedgeDelay, int backedgeDistance) {
if (minII <= 0) {
throw new IllegalArgumentException("MinII must be positive.");
} else if (backedgeDelay < 0) {
throw new IllegalArgumentException("Backedge delay cannot be negative.");
} else if (backedgeDistance <= 0) {
throw new IllegalArgumentException("Backedge distance must be positive.");
}
return backedgeDistance * minII - backedgeDelay;
}
/**
* Transforms the provided graph into the given formulation.
*
......
/*
* 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;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class MinIICycleInspectorTest {
@Test
public void testInnerDelays() {
int minII = 5;
int backedgeDelay = 1;
int backedgeDistance = 1;
int minInnerDelay = MinIICycleInspector.minInnerDelay(minII, backedgeDelay, backedgeDistance);
int maxInnerDelay = MinIICycleInspector.maxInnerDelay(minII, backedgeDelay, backedgeDistance);
assertEquals(4, minInnerDelay);
assertEquals(4, maxInnerDelay);
backedgeDistance = 2;
minInnerDelay = MinIICycleInspector.minInnerDelay(minII, backedgeDelay, backedgeDistance);
maxInnerDelay = MinIICycleInspector.maxInnerDelay(minII, backedgeDelay, backedgeDistance);
assertEquals(8, minInnerDelay);
assertEquals(9, maxInnerDelay);
minII = 50;
backedgeDelay = 10;
backedgeDistance = 5;
minInnerDelay = MinIICycleInspector.minInnerDelay(minII, backedgeDelay, backedgeDistance);
maxInnerDelay = MinIICycleInspector.maxInnerDelay(minII, backedgeDelay, backedgeDistance);
assertEquals(236, minInnerDelay);
assertEquals(240, maxInnerDelay);
minII = 2;
backedgeDelay = 4;
backedgeDistance = 2;
minInnerDelay = MinIICycleInspector.minInnerDelay(minII, backedgeDelay, backedgeDistance);
maxInnerDelay = MinIICycleInspector.maxInnerDelay(minII, backedgeDelay, backedgeDistance);
// Verify that the minimum delay is not negative.
assertEquals(0, minInnerDelay);
assertEquals(0, maxInnerDelay);
}
}
\ No newline at end of file
/*
* 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.feasible;
import graphgen.graph.LayerStructure;
import graphgen.graph.Resource;
import graphgen.graph.ResourceNode;
import graphgen.util.JavaUtils;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class FeasibleCycleInspectorTest {
@Test
public void getPossibleInnerDelays() {
Resource problematic = new Resource("limited", 1, 2);
Resource unlimited = new Resource("unlimited", 0);
Map<Integer, Integer> depthsByID = new HashMap<>();
depthsByID.put(2, 0);
depthsByID.put(3, 1);
depthsByID.put(4, 2);
depthsByID.put(5, 2);
depthsByID.put(6, 3);
depthsByID.put(7, 3);
depthsByID.put(8, 4);
depthsByID.put(9, 5);
LayerStructure layers = new LayerStructure(depthsByID);
ResourceNode node2 = new ResourceNode(2, unlimited);
ResourceNode node3 = new ResourceNode(3, unlimited);
ResourceNode node4 = new ResourceNode(4, problematic);
ResourceNode node5 = new ResourceNode(5, unlimited);
ResourceNode node6 = new ResourceNode(6, problematic);
ResourceNode node7 = new ResourceNode(7, unlimited);
ResourceNode node8 = new ResourceNode(8, problematic);
ResourceNode node9 = new ResourceNode(9, problematic);
Set<ResourceNode> nodes = JavaUtils.asSet(node2, node3, node4, node5, node6, node7, node8, node9);
FeasibleCycleInspector inspector = new FeasibleCycleInspector(layers, nodes);
assertEquals(0, inspector.getMinInnerDelay(5, 5, 1));
assertEquals(1, inspector.getMinInnerDelay(5, 4, 1));
assertEquals(2, inspector.getMinInnerDelay(5, 3, 1));
assertEquals(3, inspector.getMinInnerDelay(5, 2, 1));
assertEquals(4, inspector.getMinInnerDelay(5, 1, 1));
assertEquals(5, inspector.getMinInnerDelay(5, 0, 1));
assertEquals(0, inspector.getMaxInnerDelay(5, 5, 1));
assertEquals(1, inspector.getMaxInnerDelay(5, 4, 1));
assertEquals(2, inspector.getMaxInnerDelay(5, 3, 1));
assertEquals(3, inspector.getMaxInnerDelay(5, 2, 1));
assertEquals(4, inspector.getMaxInnerDelay(5, 1, 1));
assertEquals(5, inspector.getMaxInnerDelay(5, 0, 1));
assertEquals(14, inspector.getMinInnerDelay(10, 5, 2));
assertEquals(15, inspector.getMinInnerDelay(10, 4, 2));
assertEquals(16, inspector.getMinInnerDelay(10, 3, 2));
assertEquals(15, inspector.getMaxInnerDelay(10, 5, 2));
assertEquals(16, inspector.getMaxInnerDelay(10, 4, 2));
assertEquals(17, inspector.getMaxInnerDelay(10, 3, 2));
assertEquals(11, inspector.getMinInnerDelay(5, 2, 3));
assertEquals(12, inspector.getMinInnerDelay(5, 1, 3));
assertEquals(13, inspector.getMinInnerDelay(5, 0, 3));
assertEquals(13, inspector.getMaxInnerDelay(5, 2, 3));
assertEquals(14, inspector.getMaxInnerDelay(5, 1, 3));
assertEquals(15, inspector.getMaxInnerDelay(5, 0, 3));
}
@Test
public void getPossibleDstNodes_ZeroDelay() {
Resource limited = new Resource("limited", 0, 1);
Map<Integer, Integer> depthsByID = new HashMap<>();
depthsByID.put(2, 0);
depthsByID.put(3, 1);
depthsByID.put(4, 2);
depthsByID.put(5, 2);
depthsByID.put(6, 3);
depthsByID.put(7, 3);
depthsByID.put(8, 4);
depthsByID.put(9, 5);
LayerStructure layers = new LayerStructure(depthsByID);
ResourceNode node2 = new ResourceNode(2, limited);
ResourceNode node3 = new ResourceNode(3, limited);
ResourceNode node4 = new ResourceNode(4, limited);
ResourceNode node5 = new ResourceNode(5, limited);
ResourceNode node6 = new ResourceNode(6, limited);
ResourceNode node7 = new ResourceNode(7, limited);
ResourceNode node8 = new ResourceNode(8, limited);
ResourceNode node9 = new ResourceNode(9, limited);
Set<ResourceNode> nodes = JavaUtils.asSet(node2, node3, node4, node5, node6, node7, node8, node9);
FeasibleCycleInspector inspector = new FeasibleCycleInspector(layers, nodes);
// We cannot create a feasible cycle with an inner delay of 0 without introducing an infeasibility.
assertTrue(inspector.getPossibleDstNodes(0).isEmpty());
assertEquals(nodes, inspector.getPossibleDstNodes(1));
assertEquals(nodes, inspector.getPossibleDstNodes(2));
// ...
}
@Test
public void getPossibleDstNodes_ZeroDelay2() {
Resource limited = new Resource("limited", 0, 1);
Resource other = new Resource("other", 0, 1);
Map<Integer, Integer> depthsByID = new HashMap<>();
depthsByID.put(2, 0);
depthsByID.put(3, 1);
depthsByID.put(4, 2);
depthsByID.put(5, 2);
depthsByID.put(6, 3);
depthsByID.put(7, 3);
depthsByID.put(8, 4);
depthsByID.put(9, 5);
LayerStructure layers = new LayerStructure(depthsByID);
ResourceNode node2 = new ResourceNode(2, other);
ResourceNode node3 = new ResourceNode(3, limited);
ResourceNode node4 = new ResourceNode(4, limited);
ResourceNode node5 = new ResourceNode(5, limited);
ResourceNode node6 = new ResourceNode(6, limited);
ResourceNode node7 = new ResourceNode(7, limited);
ResourceNode node8 = new ResourceNode(8, limited);
ResourceNode node9 = new ResourceNode(9, limited);
Set<ResourceNode> nodes = JavaUtils.asSet(node2, node3, node4, node5, node6, node7, node8, node9);
FeasibleCycleInspector inspector = new FeasibleCycleInspector(layers, nodes);
// Since we have at least one node with a non-problematic resource, we can easily create a feasible cycle.
assertEquals(nodes, inspector.getPossibleDstNodes(0));
assertEquals(nodes, inspector.getPossibleDstNodes(1));
// ...
}
@Test
public void getPossibleDstNodes_NonZeroDelay() {
Resource limited = new Resource("limited", 3, 1);
Resource other = new Resource("other", 5, 1);
Map<Integer, Integer> depthsByID = new HashMap<>();
depthsByID.put(2, 0);
depthsByID.put(3, 1);
depthsByID.put(4, 2);
depthsByID.put(5, 2);
depthsByID.put(6, 3);
depthsByID.put(7, 3);
depthsByID.put(8, 4);
depthsByID.put(9, 5);
LayerStructure layers = new LayerStructure(depthsByID);
ResourceNode node2 = new ResourceNode(2, other);
ResourceNode node3 = new ResourceNode(3, other);
ResourceNode node4 = new ResourceNode(4, other);
ResourceNode node5 = new ResourceNode(5, other);
ResourceNode node6 = new ResourceNode(6, limited);