Commit 78672061 authored by Sebastian Vollbrecht's avatar Sebastian Vollbrecht

Adapted FeasibleMinIIProperty to the recent changes.

Also removed SCC-related classes as they have become obsolete.
parent 9354d739
/*
* 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.util;
import graphgen.enums.EdgeType;
import graphgen.generator.components.edges.EdgeCreator;
import graphgen.generator.exceptions.SCCException;
import graphgen.graph.LayerStructure;
import graphgen.graph.ResourceNode;
import graphgen.util.GraphUtils;
import graphgen.util.JavaUtils;
import modsched.Edge;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.IntStream;
/**
* This class represents strongly connected components, which can be constructed through arbitrary amounts of backedges.
* The provided methods are very useful to determine slacks end enclosed nodes.
*
* @author Sebastian Vollbrecht
*/
public final class SCC {
private final List<Edge<ResourceNode>> backedges;
private final LayerStructure layers;
private final Map<ResourceNode, Set<Edge<ResourceNode>>> outgoingEdges;
private final Map<ResourceNode, Set<Edge<ResourceNode>>> incomingEdges;
private final Map<ResourceNode, Set<Integer>> possibleSlotsByNode;
private final Map<ResourceNode, Integer> delaysFromPreviousDstNode;
private final Map<ResourceNode, Integer> delaysToNextSrcNode;
private final Set<ResourceNode> enclosedNodes;
private final int accumulatedBackedgeDelays;
private final int accumulatedBackedgeDistances;
private final Map<ResourceNode, ResourceNode> nodesToNextSrcs;
private final Map<ResourceNode, ResourceNode> nodesToPreviousDsts;
public SCC(List<Edge<ResourceNode>> backedges, LayerStructure layers,
Map<ResourceNode, Set<Edge<ResourceNode>>> outgoingEdges,
Map<ResourceNode, Set<Edge<ResourceNode>>> incomingEdges) {
this.backedges = Collections.unmodifiableList(backedges);
this.layers = layers;
this.outgoingEdges = outgoingEdges;
this.incomingEdges = incomingEdges;
this.possibleSlotsByNode = new HashMap<>();
this.delaysFromPreviousDstNode = new HashMap<>();
this.delaysToNextSrcNode = new HashMap<>();
this.enclosedNodes = new HashSet<>();
this.nodesToNextSrcs = new HashMap<>();
this.nodesToPreviousDsts = new HashMap<>();
this.accumulatedBackedgeDelays = backedges.stream().mapToInt(Edge::getDelay).sum();
this.accumulatedBackedgeDistances = backedges.stream().mapToInt(Edge::getDistance).sum();
checkIfCyclic(backedges, layers, outgoingEdges);
}
public SCC(List<Edge<ResourceNode>> backedges, LayerStructure layers, EdgeCreator edgeCreator) {
this(backedges, layers, edgeCreator.outgoingEdgesView(), edgeCreator.incomingEdgesView());
}
/**
* Computes the SCC's data regarding the specified minII. The minII is used to compute the maximum inner delay and
* corresponding node slacks.
*
* @param minII the minII
* @return the set of nodes enclosed in this SCC
*/
// TODO: update only if changes have been made
public Set<ResourceNode> update(int minII) {
int remainingDelay = (minII * accumulatedBackedgeDistances) - accumulatedBackedgeDelays;
for (int i = 0; i < backedges.size(); i++) {
ResourceNode previousDst = backedges.get(i).getDst();
ResourceNode nextSrc = backedges.get((i + 1) % backedges.size()).getSrc();
Map<ResourceNode, Integer> delaysFromPreviousDstNode = GraphUtils
.getMaxDelayToNodesInBetweenMap(previousDst, nextSrc, layers, outgoingEdges);
for (ResourceNode reachableNode : delaysFromPreviousDstNode.keySet()) {
this.delaysFromPreviousDstNode.put(reachableNode, delaysFromPreviousDstNode.get(reachableNode));
nodesToPreviousDsts.put(reachableNode, previousDst);
}
Map<ResourceNode, Integer> delaysToNextSrcNode = GraphUtils
.getMaxDelayFromNodesInBetweenMap(previousDst, nextSrc, layers, incomingEdges);
for (ResourceNode connectedNode : delaysToNextSrcNode.keySet()) {
this.delaysToNextSrcNode.put(connectedNode, delaysToNextSrcNode.get(connectedNode));
nodesToNextSrcs.put(connectedNode, nextSrc);
}
int innerDelay = delaysToNextSrcNode.get(previousDst) + nextSrc.getDelay();
remainingDelay -= innerDelay;
if (remainingDelay < 0)
throw new SCCException(this, minII);
Set<ResourceNode> enclosedNodes = JavaUtils
.setIntersection(delaysFromPreviousDstNode.keySet(), delaysToNextSrcNode.keySet());
for (ResourceNode enclosedNode : enclosedNodes) {
if (enclosedNode.isUnlimited() && enclosedNode != nextSrc && enclosedNode != previousDst)
continue;
computeDeltas(enclosedNode, nextSrc, innerDelay);
}
this.enclosedNodes.addAll(enclosedNodes);
}
if (remainingDelay > 0) {
for (Entry<ResourceNode, Set<Integer>> entry : possibleSlotsByNode.entrySet()) {
Set<Integer> possibleDeltas = entry.getValue();
int maxDelta = Collections.max(possibleDeltas);
IntStream.rangeClosed(maxDelta + 1, maxDelta + remainingDelay).forEach(possibleDeltas::add);
}
}
return getEnclosedNodes();
}
/**
* A node's set of time slots contains all possible time slots relative to its preceding destination node in which
* it can be placed without affecting the RecMinII.
*
* @return the mapping of nodes to the all possible deltas
* @see #getPreviousDst(ResourceNode)
*/
public Map<ResourceNode, Set<Integer>> getPossibleSlotsByNode() {
return Collections.unmodifiableMap(possibleSlotsByNode);
}
/**
* @return the mapping of nodes to their delays to the preceding backedge destination nodes
* @see #getPreviousDst(ResourceNode)
*/
public Map<ResourceNode, Integer> getDelaysFromPreviousDstNode() {
return Collections.unmodifiableMap(delaysFromPreviousDstNode);
}
/**
* @return the mapping of nodes to their delays to the subsequent backedge source nodes
* @see #getNextSrc(ResourceNode)
*/
public Map<ResourceNode, Integer> getDelaysToNextSrcNode() {
return Collections.unmodifiableMap(delaysToNextSrcNode);
}
/**
* @return the nodes enclosed in this SCC
*/
public Set<ResourceNode> getEnclosedNodes() {
return Collections.unmodifiableSet(enclosedNodes);
}
/**
* Returns the node's subsequent backedge source node. The subsequent node is defined as the backedge source node
* which 'closes' the enclosed interval which the provided node resides in.
*
* @param node the node
* @return the subsequent backedge source node
*/
public ResourceNode getNextSrc(ResourceNode node) {
return nodesToNextSrcs.get(node);
}
/**
* Returns the node's preceding backedge destination node. The preceding node is defined as the backedge destination
* node which 'opens' the enclosed interval which the provided node resides in.
*
* @param node the node
* @return the preceding backedge destination node
*/
public ResourceNode getPreviousDst(ResourceNode node) {
return nodesToPreviousDsts.get(node);
}
public List<Edge<ResourceNode>> getBackedges() {
return Collections.unmodifiableList(backedges);
}
@Override
public String toString() {
return backedges.toString();
}
private void computeDeltas(ResourceNode node, ResourceNode backedgeSrc, int innerDelay) {
int delayFromDstNode = delaysFromPreviousDstNode.get(node);
int delayToSrcNode = delaysToNextSrcNode.get(node);
int slack = innerDelay - delayFromDstNode - delayToSrcNode - backedgeSrc.getDelay();
Set<Integer> possibleDeltas = new HashSet<>();
int maxDelta = delayFromDstNode + slack;
/*if (!possibleDeltas.isEmpty())
maxDelta = Math.min(maxDelta, Collections.max(possibleDeltas));*/
IntStream.rangeClosed(delayFromDstNode, maxDelta).forEach(possibleDeltas::add);
possibleSlotsByNode.put(node, possibleDeltas);
nodesToNextSrcs.put(node, backedgeSrc);
}
private void checkIfCyclic(List<Edge<ResourceNode>> backedges, LayerStructure layers,
Map<ResourceNode, Set<Edge<ResourceNode>>> outgoingEdges) {
Set<Edge<ResourceNode>> edges = new HashSet<>();
outgoingEdges.values().forEach(edges::addAll);
for (int i = 0; i < backedges.size(); i++) {
ResourceNode dst = backedges.get(i).getDst();
ResourceNode src = backedges.get((i + 1) % backedges.size()).getSrc();
if (!GraphUtils.pathExistsTo(dst, src, edges, EdgeType.FORWARD))
throw new SCCException(this);
}
}
}
\ 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.exceptions;
import graphgen.generator.components.properties.util.SCC;
public final class SCCException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 6044788422273569435L;
public SCCException(SCC scc) {
super("The given backedges do not form a cycle.\n" + scc);
}
public SCCException(SCC scc, int minII) {
super("The SCC's RecMinII is greater than the specified minII of " + minII + ".\n" + scc);
}
}
/*
* 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.util;
import graphgen.enums.EdgeType;
import graphgen.generator.GraphGenerator;
import graphgen.generator.exceptions.SCCException;
import graphgen.graph.LayerStructure;
import graphgen.graph.Resource;
import graphgen.graph.ResourceNode;
import graphgen.util.GraphUtils;
import graphgen.util.JavaUtils;
import modsched.Edge;
import org.junit.Test;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
public class SCCTest {
@Test
public void testCycleUpdate() {
Resource unl = new Resource("unlimited", 0);
Resource mul = new Resource("multiplier", 2, 1);
Resource add = new Resource("adder", 1, 2);
int id = GraphGenerator.SINK.getId() + 1;
ResourceNode n_0 = new ResourceNode(id++, unl);
ResourceNode n_1 = new ResourceNode(id++, unl);
ResourceNode n_2 = new ResourceNode(id++, mul);
ResourceNode n_3 = new ResourceNode(id++, mul);
ResourceNode n_4 = new ResourceNode(id++, unl);
ResourceNode n_5 = new ResourceNode(id++, add);
ResourceNode n_6 = new ResourceNode(id++, unl);
ResourceNode n_7 = new ResourceNode(id++, mul);
ResourceNode n_8 = new ResourceNode(id++, mul);
ResourceNode n_9 = new ResourceNode(id++, add);
ResourceNode n_10 = new ResourceNode(id, unl);
Set<Edge<ResourceNode>> edges = new HashSet<>();
edges.add(new Edge<>(n_6, n_8, 1, 0));
edges.add(new Edge<>(n_3, n_0, 1, 0));
edges.add(new Edge<>(n_8, n_7, 1, 0));
edges.add(new Edge<>(n_6, n_3, 5, 0));
edges.add(new Edge<>(n_6, n_10, 2, 0));
edges.add(new Edge<>(n_10, n_3, 0, 0));
edges.add(new Edge<>(n_5, n_4, 1, 0));
edges.add(new Edge<>(n_0, n_1, 0, 0));
edges.add(new Edge<>(n_6, n_9, 0, 0));
edges.add(new Edge<>(n_6, n_2, 4, 0));
edges.add(new Edge<>(n_9, n_5, 1, 0));
edges.add(new Edge<>(n_4, n_1, 3, 0));
edges.add(new Edge<>(n_7, n_3, 1, 0));
edges.add(new Edge<>(n_6, n_3, 5, 0));
edges.add(new Edge<>(n_2, n_4, 1, 0));
Edge<ResourceNode> n4_n6 = new Edge<>(n_4, n_6, 1, 1);
edges.add(n4_n6);
Edge<ResourceNode> n0_n9 = new Edge<>(n_0, n_9, 1, 1);
edges.add(n0_n9);
Map<ResourceNode, Set<Edge<ResourceNode>>> outgoingEdges = GraphUtils
.getOutgoingEdgesMap(edges, EdgeType.FORWARD);
Map<ResourceNode, Set<Edge<ResourceNode>>> incomingEdges = GraphUtils
.getIncomingEdgesMap(edges, EdgeType.FORWARD);
LayerStructure layers = GraphUtils.getLayerStructure(edges, true);
SCC cycle = new SCC(Arrays.asList(n4_n6), layers, outgoingEdges, incomingEdges);
cycle.update(8);
Map<ResourceNode, Set<Integer>> deltasByNode = new HashMap<>(cycle.getPossibleSlotsByNode());
assertEquals(JavaUtils.asSet(7), deltasByNode.remove(n_4));
assertEquals(JavaUtils.asSet(2, 3, 4, 5), deltasByNode.remove(n_5));
assertEquals(JavaUtils.asSet(0, 1, 2, 3), deltasByNode.remove(n_9));
assertEquals(JavaUtils.asSet(4), deltasByNode.remove(n_2));
assertEquals(JavaUtils.asSet(0), deltasByNode.remove(n_6));
assertEquals(0, deltasByNode.size());
try {
new SCC(Arrays.asList(n0_n9), layers, outgoingEdges, incomingEdges);
fail("This call should have thrown an exception.");
} catch (SCCException expected) {
}
/*
* Provide a MinII which is less than the cycle's RecMinII.
*/
try {
cycle = new SCC(Arrays.asList(n4_n6), layers, outgoingEdges, incomingEdges);
cycle.update(7);
fail("This call should have thrown an exception.");
} catch (SCCException expected) {
}
cycle = new SCC(Arrays.asList(n4_n6, n0_n9), layers, outgoingEdges, incomingEdges);
cycle.update(8);
deltasByNode = new HashMap<>(cycle.getPossibleSlotsByNode());
assertEquals(JavaUtils.asSet(4), deltasByNode.remove(n_4));
assertEquals(JavaUtils.asSet(2), deltasByNode.remove(n_5));
assertEquals(JavaUtils.asSet(0), deltasByNode.remove(n_9));
assertEquals(JavaUtils.asSet(1), deltasByNode.remove(n_8));
assertEquals(JavaUtils.asSet(4), deltasByNode.remove(n_7));
assertEquals(JavaUtils.asSet(7), deltasByNode.remove(n_3));
assertEquals(JavaUtils.asSet(10), deltasByNode.remove(n_0));
assertEquals(JavaUtils.asSet(0), deltasByNode.remove(n_6));
/*
* Because 10 is unlimited, it does not appear in the deltas map. These would be
* its possible deltas, though:
*
* assertEquals(JavaUtils.asSet(2, 3, 4, 5, 6, 7), deltasByNode.remove(n_10));
*/
assertEquals(0, deltasByNode.size());
/*
* Swap the backedge order.
*/
cycle = new SCC(Arrays.asList(n0_n9, n4_n6), layers, outgoingEdges, incomingEdges);
cycle.update(8);
deltasByNode = new HashMap<>(cycle.getPossibleSlotsByNode());
assertEquals(JavaUtils.asSet(4), deltasByNode.remove(n_4));
assertEquals(JavaUtils.asSet(2), deltasByNode.remove(n_5));
assertEquals(JavaUtils.asSet(0), deltasByNode.remove(n_9));
assertEquals(JavaUtils.asSet(1), deltasByNode.remove(n_8));
assertEquals(JavaUtils.asSet(4), deltasByNode.remove(n_7));
assertEquals(JavaUtils.asSet(7), deltasByNode.remove(n_3));
assertEquals(JavaUtils.asSet(10), deltasByNode.remove(n_0));
assertEquals(JavaUtils.asSet(0), deltasByNode.remove(n_6));
assertEquals(0, deltasByNode.size());
/*
* Introduce a slack of 2 by increasing the minII from 8 to 9.
*/
cycle = new SCC(Arrays.asList(n4_n6, n0_n9), layers, outgoingEdges, incomingEdges);
cycle.update(9);
deltasByNode = new HashMap<>(cycle.getPossibleSlotsByNode());
assertEquals(JavaUtils.asSet(4, 5, 6), deltasByNode.remove(n_4));
assertEquals(JavaUtils.asSet(2, 3, 4), deltasByNode.remove(n_5));
assertEquals(JavaUtils.asSet(0, 1, 2), deltasByNode.remove(n_9));
assertEquals(JavaUtils.asSet(1, 2, 3), deltasByNode.remove(n_8));
assertEquals(JavaUtils.asSet(4, 5, 6), deltasByNode.remove(n_7));
assertEquals(JavaUtils.asSet(7, 8, 9), deltasByNode.remove(n_3));
assertEquals(JavaUtils.asSet(10, 11, 12), deltasByNode.remove(n_0));
assertEquals(JavaUtils.asSet(0, 1, 2), deltasByNode.remove(n_6));
assertEquals(0, deltasByNode.size());
/*
* Add an invalid 'forward backedge' cycle.
*/
Edge<ResourceNode> n2_n5 = new Edge<>(n_2, n_5, 1, 1);
try {
new SCC(Arrays.asList(n2_n5), layers, outgoingEdges, incomingEdges);
fail("This call should have thrown an exception.");
} catch (SCCException expected) {
}
/*
* Create a cycle with a forward backedge.
*/
cycle = new SCC(Arrays.asList(n2_n5, n4_n6), layers, outgoingEdges, incomingEdges);
cycle.update(5);
deltasByNode = new HashMap<>(cycle.getPossibleSlotsByNode());
assertEquals(JavaUtils.asSet(0), deltasByNode.remove(n_5));
assertEquals(JavaUtils.asSet(2), deltasByNode.remove(n_4));
assertEquals(JavaUtils.asSet(0), deltasByNode.remove(n_6));
assertEquals(JavaUtils.asSet(4), deltasByNode.remove(n_2));
assertEquals(0, deltasByNode.size());
}
}
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