Commit 624d1609 authored by Sebastian Vollbrecht's avatar Sebastian Vollbrecht

Overhauled property creation & strict mode.

Boni:
- the FeasibleMinIIProperty is now able to generate feasible cycles with inner delays != max inner delay
- the LayerStructure class does not include swap checkers/strict mode related things anymore
parent b8aa2d58
......@@ -19,8 +19,10 @@ package graphgen.generator;
import graphgen.datastructures.Pair;
import graphgen.datastructures.SeededRandom;
import graphgen.generator.components.StrictComponent;
import graphgen.generator.components.edges.EdgeCreator;
import graphgen.generator.components.edges.includers.EdgeIncluder;
import graphgen.generator.components.layers.GeneratedLayerStructure;
import graphgen.generator.components.layers.LayerCreator;
import graphgen.generator.components.nodes.NodeCreator;
import graphgen.generator.components.properties.Property;
......@@ -70,7 +72,7 @@ import java.util.Set;
* @see Property
* @see SeededRandom
*/
public final class GraphGenerator {
public final class GraphGenerator implements StrictComponent {
private final LayerCreator layerCreator;
private final NodeCreator nodeCreator;
......@@ -83,7 +85,6 @@ public final class GraphGenerator {
private final EdgeInclusionDuplicateChecker edgeChecker;
private boolean verbose = false;
private boolean strict = false;
private PrintStream out = System.out;
/**
......@@ -165,7 +166,7 @@ public final class GraphGenerator {
public Graph<ResourceNode> createGraph(long seed) {
if (verbose) {
out.println("Creating " + (strict ? "strict " : "") + "graph with seed " + seed);
out.println("Creating graph with seed " + seed);
}
// Reset and clear generation objects.
......@@ -183,22 +184,17 @@ public final class GraphGenerator {
// Start generating a new graph.
rng.setSeed(seed);
LayerStructure layers = layerCreator.createLayerStructure();
GeneratedLayerStructure layers = layerCreator.createLayerStructure();
layers.setStrict(strict);
edgeCreator.setStrict(strict);
edgeIncluder.setStrict(strict);
backedgeIncluder.setStrict(strict);
if (verbose) {
out.println("\tGenerated layer structure: " + layers.toString());
}
edgeCreator.addObserver(layers);
edgeCreator.addObserver(property);
edgeCreator.addObserver(edgeIncluder);
edgeCreator.addObserver(backedgeIncluder);
if (verbose) {
out.println("\tGenerated layer structure: " + layers.toString());
}
edgeCreator.setLayerStructure(layers);
edgeIncluder.setLayerStructure(layers);
backedgeIncluder.setLayerStructure(layers);
......@@ -233,7 +229,7 @@ public final class GraphGenerator {
nodes.forEach(n -> asapTimes.put(n, -1));
generateIncomingEdges(layers, nodes, nodeTable, asapTimes, seed);
generateIncomingEdges(layers, nodes, nodeTable, asapTimes);
if (verbose) {
out.println("\tGenerating outgoing edges.");
......@@ -347,24 +343,19 @@ public final class GraphGenerator {
}
/**
* Makes the generator <b>strict</b>, i.e. that all components are <b>not</b> allowed to deviate from their
* specified parameters. Note that this way the generation process might lead to exceptions more often.
*/
public void setStrict() {
strict = true;
}
/**
* Sets the generator to non-strict mode, i.e. that the components are allowed to deviate from their specified
* parameters (e.g. the properties are allowed to swap nodes around, to generate edges with specific delays, ...).
* Toggles the strictness of the generator. In strict mode, all components are <b>not</b> allowed to deviate from
* their specified parameters. Note that this way the generation process might lead to exceptions more often.
*/
public void setNonStrict() {
strict = false;
@Override
public void setStrictness(boolean strictness) {
layerCreator.setStrictness(strictness);
edgeCreator.setStrictness(strictness);
edgeIncluder.setStrictness(strictness);
backedgeIncluder.setStrictness(strictness);
}
private void generateIncomingEdges(LayerStructure layers, Set<ResourceNode> nodes,
Map<Integer, ResourceNode> nodeTable, Map<ResourceNode, Integer> asapTimes,
long seed) {
Map<Integer, ResourceNode> nodeTable, Map<ResourceNode, Integer> asapTimes) {
for (ResourceNode dst : JavaUtils.asShuffledList(nodes, rng)) {
......
......@@ -20,12 +20,12 @@ package graphgen.generator.components;
import graphgen.datastructures.SeededRandom;
/**
* An interface which all components participating in the creation of graphs can implement. It provides initialization
* An interface which all components participating in the creation of graphs implement. It provides initialization
* methods.
*
* @author Sebastian Vollbrecht
*/
public interface Initializable {
public interface GeneratorComponent {
/**
* Grants the implementing class access to the graph generator's random number generator. This method is called
......@@ -41,4 +41,5 @@ public interface Initializable {
* before the generator begins generating a new graph.
*/
void reset();
}
......@@ -15,39 +15,20 @@
* limitations under the License.
*/
package graphgen.generator.exceptions;
package graphgen.generator.components;
public final class InfeasibilityImpossibleException extends RuntimeException {
/**
* An interface which all components which can be set to strict mode implement. In strict mode, certain things might not
* be allowed (e.g. swapping nodes, creating custom edges, ...).
*
* @author Sebastian Vollbrecht
*/
public interface StrictComponent {
/**
* Sets the strictness of the component.
*
* @param strictness true to enable the component's strict mode, otherwise false
*/
private static final long serialVersionUID = 4162988113957743877L;
public enum InfeasibilityImpossibleCause {
NO_PROBLEMATIC_RESOURCE, NO_INFEASIBLE_ARRANGEMENT;
public String message() {
switch (this) {
case NO_PROBLEMATIC_RESOURCE:
return "No resource allows for an infeasible arrangement of nodes.";
case NO_INFEASIBLE_ARRANGEMENT:
return "The layer structure does not allow for an infeasible arrangement of problematic nodes.";
}
throw new UnsupportedOperationException(this.toString());
}
}
public final InfeasibilityImpossibleCause cause;
public InfeasibilityImpossibleException(InfeasibilityImpossibleCause cause) {
super(cause.message());
this.cause = cause;
}
void setStrictness(boolean strictness);
}
......@@ -17,7 +17,7 @@
package graphgen.generator.components.edges;
import graphgen.generator.components.Initializable;
import graphgen.generator.components.GeneratorComponent;
import graphgen.graph.LayerStructure;
import graphgen.graph.ResourceNode;
......@@ -29,7 +29,7 @@ import java.util.Map;
*
* @author Sebastian Vollbrecht
*/
public interface EdgeCreationComponent extends Initializable {
public interface EdgeCreationComponent extends GeneratorComponent {
/**
* Sets the layer structure of the implementing class, which can be used optionally for different purposes, such as
......
......@@ -18,12 +18,13 @@
package graphgen.generator.components.edges;
import graphgen.datastructures.SeededRandom;
import graphgen.enums.EdgeValue;
import graphgen.generator.GraphGenerator;
import graphgen.generator.components.StrictComponent;
import graphgen.generator.components.edges.computers.ValueComputer;
import graphgen.generator.components.edges.includers.EdgeIncluder;
import graphgen.generator.components.properties.Property;
import graphgen.generator.exceptions.IllegalEdgeException;
import graphgen.generator.exceptions.StrictModeException;
import graphgen.graph.LayerStructure;
import graphgen.graph.ResourceNode;
import graphgen.observer.Observable;
......@@ -46,7 +47,7 @@ import java.util.Set;
* @author Sebastian Vollbrecht
* @see ValueComputer
*/
public class EdgeCreator extends Observable<Edge<ResourceNode>> implements EdgeCreationComponent {
public class EdgeCreator extends Observable<Edge<ResourceNode>> implements EdgeCreationComponent, StrictComponent {
private final ValueComputer edgeDelayComputer;
private final ValueComputer backedgeDelayComputer;
......@@ -62,7 +63,6 @@ public class EdgeCreator extends Observable<Edge<ResourceNode>> implements EdgeC
private LayerStructure layers;
private Map<ResourceNode, Integer> asapTimes;
private boolean strict;
/**
* Constructs a new edge creator from the given value computers and the given edge includer.
......@@ -86,6 +86,10 @@ public class EdgeCreator extends Observable<Edge<ResourceNode>> implements EdgeC
this.incomingEdges = new HashMap<>();
this.incomingBackedges = new HashMap<>();
this.edgeDelayComputer.setEdgeValue(EdgeValue.EDGE_DELAY);
this.backedgeDelayComputer.setEdgeValue(EdgeValue.BACKEDGE_DELAY);
this.backedgeDistanceComputer.setEdgeValue(EdgeValue.BACKEDGE_DISTANCE);
}
/**
......@@ -98,8 +102,6 @@ public class EdgeCreator extends Observable<Edge<ResourceNode>> implements EdgeC
* @return the created edge
* @throws IllegalEdgeException if the delay is less than 0 or if the edge is {@link #isEdgeValid(ResourceNode,
* ResourceNode) invalid}
* @throws StrictModeException if the edge creator is in strict mode and any of the preventive measures specified
* in the {@link #setStrict(boolean)}-method isn't met
*/
public Edge<ResourceNode> createEdge(ResourceNode src, ResourceNode dst, int delay) {
......@@ -109,26 +111,16 @@ public class EdgeCreator extends Observable<Edge<ResourceNode>> implements EdgeC
if (!isEdgeValid(src, dst))
throw new IllegalEdgeException(src, dst, false);
if (strict) {
int previouslyComputedDelay = computeEdgeDelay(src, dst);
Edge<ResourceNode> edge = new Edge<>(src, dst, delay, 0);
if (previouslyComputedDelay != delay) {
throw new StrictModeException(
"The edge's delay must not deviate from the previously computed delay of " + previouslyComputedDelay + ".");
}
if (src != GraphGenerator.SOURCE && dst != GraphGenerator.SINK) {
notifyObservers(edge);
}
Edge<ResourceNode> edge = new Edge<>(src, dst, delay, 0);
edges.add(edge);
outgoingEdges.get(src).add(edge);
incomingEdges.get(dst).add(edge);
if (src != GraphGenerator.SOURCE && dst != GraphGenerator.SINK) {
notifyObservers(edge);
}
return edge;
}
......@@ -143,8 +135,6 @@ public class EdgeCreator extends Observable<Edge<ResourceNode>> implements EdgeC
* @return the created backedge
* @throws IllegalEdgeException if the delay is less than 0, if the distance is not greater than 0 or if it is
* {@link #isBackedgeValid(ResourceNode, ResourceNode) invalid}
* @throws StrictModeException if the edge creator is in strict mode and any of the preventive measures specified
* in the {@link #setStrict(boolean)}-method isn't met
*/
public Edge<ResourceNode> createBackedge(ResourceNode src, ResourceNode dst, int delay, int distance) {
......@@ -157,33 +147,16 @@ public class EdgeCreator extends Observable<Edge<ResourceNode>> implements EdgeC
if (!isBackedgeValid(src, dst))
throw new IllegalEdgeException(src, dst, true);
if (strict) {
int previouslyComputedDelay = computeBackedgeDelay(src, dst);
if (previouslyComputedDelay != delay) {
throw new StrictModeException(
"The backedge's delay must not deviate from the previously computed delay of " + previouslyComputedDelay + ".");
}
int previouslyComputedDistance = computeBackedgeDistance(src, dst);
Edge<ResourceNode> edge = new Edge<>(src, dst, delay, distance);
if (previouslyComputedDistance != distance) {
throw new StrictModeException(
"The backedge's distance must not deviate from the previously computed distance of " + previouslyComputedDistance + ".");
}
if (src != GraphGenerator.SOURCE && dst != GraphGenerator.SINK) {
notifyObservers(edge);
}
Edge<ResourceNode> edge = new Edge<>(src, dst, delay, distance);
edges.add(edge);
outgoingBackedges.get(src).add(edge);
incomingBackedges.get(dst).add(edge);
if (src != GraphGenerator.SOURCE && dst != GraphGenerator.SINK) {
notifyObservers(edge);
}
return edge;
}
......@@ -347,18 +320,11 @@ public class EdgeCreator extends Observable<Edge<ResourceNode>> implements EdgeC
}
/**
* Toggles strict mode, allowing or disallowing deviations of specified parameters.
* <p>
* In strict mode, an edge can only be created if its delay matches a previously computed delay (via {@link
* #computeEdgeDelay(ResourceNode, ResourceNode)}). If this hasn't been done, the method will be called to obtain a
* 'previously' computed delay. If the delays differ, the edge creation will be disallowed, resulting in a {@link
* StrictModeException} being thrown. (analogously: distances and backedges).
*
* @param strict true to disallow deviations, false to allow deviations
*/
public void setStrict(boolean strict) {
this.strict = strict;
@Override
public void setStrictness(boolean strictness) {
edgeDelayComputer.setStrictness(strictness);
backedgeDelayComputer.setStrictness(strictness);
backedgeDistanceComputer.setStrictness(strictness);
}
/**
......
......@@ -17,8 +17,13 @@
package graphgen.generator.components.edges.computers;
import graphgen.enums.EdgeValue;
import graphgen.generator.components.StrictComponent;
import graphgen.generator.components.edges.EdgeCreationComponent;
import graphgen.generator.exceptions.StrictModeException;
import graphgen.graph.ResourceNode;
import graphgen.observer.Observer;
import modsched.Edge;
import java.util.HashMap;
import java.util.Map;
......@@ -29,7 +34,7 @@ import java.util.Map;
*
* @author Sebastian Vollbrecht
*/
public abstract class ValueComputer implements EdgeCreationComponent {
public abstract class ValueComputer implements EdgeCreationComponent, StrictComponent, Observer<Edge<ResourceNode>> {
/*
* Maps source nodes to destination nodes and their computed edge values, since
......@@ -38,6 +43,8 @@ public abstract class ValueComputer implements EdgeCreationComponent {
* differ later on during the edge creation phase.
*/
private final Map<ResourceNode, Map<ResourceNode, Integer>> computedEdgeValues;
private boolean isStrict;
private EdgeValue edgeValue;
protected ValueComputer() {
this.computedEdgeValues = new HashMap<>();
......@@ -50,7 +57,7 @@ public abstract class ValueComputer implements EdgeCreationComponent {
* @param dst the edge's destination node
* @return the value of the edge
*/
public int getValue(ResourceNode src, ResourceNode dst) {
public final int getValue(ResourceNode src, ResourceNode dst) {
if (computedEdgeValues.containsKey(src) && computedEdgeValues.get(src).containsKey(dst))
return computedEdgeValues.get(src).get(dst);
......@@ -70,6 +77,39 @@ public abstract class ValueComputer implements EdgeCreationComponent {
implementedReset();
}
/**
* In strict mode, an edge can only be created if its value matches a previously computed value (via {@link
* #getValue(ResourceNode, ResourceNode)}). If the value of a created edge differs from the computed value, the edge
* creation will be disallowed, resulting in a {@link StrictModeException} being thrown.
*
* @param strictness true to disallow deviations, false to allow deviations
*/
@Override
public final void setStrictness(boolean strictness) {
this.isStrict = strictness;
}
@Override
public final void notify(Edge<ResourceNode> edge) {
if (isStrict) {
int previouslyComputedValue = getValue(edge.getSrc(), edge.getDst());
if (previouslyComputedValue != edgeValue.getEdgeValue(edge)) {
throw new StrictModeException(
"The edge's value must not deviate from the previously computed delay of " + previouslyComputedValue + ".");
}
}
}
/**
* Tells the value computer which value it is actually computing. This edge value is then used used to determine (in
* strict mode) whether or not a created edge is illegal.
*/
public final void setEdgeValue(EdgeValue edgeValue) {
this.edgeValue = edgeValue;
}
/**
* Computes the edge value of the edge connecting the source node to the destination node.
*
......
......@@ -17,6 +17,7 @@
package graphgen.generator.components.edges.includers;
import graphgen.generator.components.StrictComponent;
import graphgen.generator.components.edges.EdgeCreationComponent;
import graphgen.generator.exceptions.StrictModeException;
import graphgen.graph.ResourceNode;
......@@ -31,15 +32,14 @@ import java.util.Map;
*
* @author Sebastian Vollbrecht
*/
public abstract class EdgeIncluder implements EdgeCreationComponent, Observer<Edge<ResourceNode>> {
public abstract class EdgeIncluder implements EdgeCreationComponent, StrictComponent, Observer<Edge<ResourceNode>> {
private final Map<Edge<ResourceNode>, Boolean> decidedEdgeInclusions;
private boolean strict;
private boolean isStrict;
protected EdgeIncluder() {
this.decidedEdgeInclusions = new HashMap<>();
this.strict = false;
}
/**
......@@ -69,27 +69,21 @@ public abstract class EdgeIncluder implements EdgeCreationComponent, Observer<Ed
}
/**
* Toggles strict mode, allowing or disallowing deviations of specified parameters.
* <p>
* In strict mode, an edge can only be created if the includer allows so. If an edge is included although the
* In strict mode, an edge can only be created if the includer allows so. If an edge is created although the
* includer disallowed doing it, a {@link StrictModeException} will be thrown.
*
* @param strict true to disallow deviations, false to allow deviations
* @param strictness true to disallow deviations, false to allow deviations
*/
public void setStrict(boolean strict) {
this.strict = strict;
@Override
public final void setStrictness(boolean strictness) {
this.isStrict = strictness;
}
@Override
public void notify(Edge<ResourceNode> edge) {
if (strict) {
boolean decision;
if (!decidedEdgeInclusions.containsKey(edge)) {
decision = includeEdge(edge);
} else {
decision = decidedEdgeInclusions.get(edge);
}
public final void notify(Edge<ResourceNode> edge) {
if (isStrict) {
boolean decision = decidedEdgeInclusions.getOrDefault(edge, includeEdge(edge));
if (!decision) {
throw new StrictModeException(
......
......@@ -17,7 +17,7 @@
package graphgen.generator.components.edges.util.folding;
import graphgen.generator.components.Initializable;
import graphgen.generator.components.GeneratorComponent;
import java.util.List;
......@@ -26,7 +26,7 @@ import java.util.List;
*
* @author Sebastian Vollbrecht
*/
public interface FoldingStrategy<T> extends Initializable {
public interface FoldingStrategy<T> extends GeneratorComponent {
/**
* Folds a list of values into one single value.
......
/*
* 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.layers;
import graphgen.generator.components.StrictComponent;
import graphgen.generator.exceptions.IllegalSwapException;
import graphgen.generator.exceptions.StrictModeException;
import graphgen.graph.LayerStructure;
import graphgen.observer.Observer;
import modsched.Edge;
import modsched.Node;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* A layer structure which takes into account additional checks when swapping nodes around.<p>If any IDs of the created
* layer structure are swapped which are connected by an edge already and if the structure's state post-swap would
* violate the topological order implied by the edges, a corresponding exception will be thrown.<p>Furthermore, if
* strict mode is enabled, all swaps will be disallowed.
*
* @author Sebastian Vollbrecht
*/
public class GeneratedLayerStructure extends LayerStructure implements StrictComponent, Observer<Edge<? extends Node>> {
private boolean isStrict;
private final Map<Integer, Set<Integer>> outgoingEdges;
private final Map<Integer, Set<Integer>> incomingEdges;
/**
* Constructs a new layer structure based on the provided list of layers and the ID depths map.
*
* @param depthsByID the depths of the IDs contained in the given list of layers
* @throws IllegalArgumentException if any depth is negative
*/
GeneratedLayerStructure(Map<Integer, Integer> depthsByID) {
super(depthsByID);
this.outgoingEdges = new HashMap<>();
this.incomingEdges = new HashMap<>();
}
/**
* Swaps the two IDs with each other (see {@link LayerStructure#swapIDs(int, int)}).
*
* @throws IllegalSwapException if an illegal swap is detected, i.e. if the IDs are connected with an edge during a
* graph creation phase and if the swap would violate the layer structure implied by
* the edges
* @throws StrictModeException if strict mode is enabled
*/
@Override
public final void swapIDs(int firstID, int secondID) {
if (isStrict) {
throw new StrictModeException("Swap of nodes " + firstID + " and " + secondID + " not allowed.");
}
if (!isSwapValid(firstID, secondID)) {
throw new IllegalSwapException(firstID, secondID);
}
super.swapIDs(firstID, secondID);
}
/**
* Sets the layer creator to strict mode, disallowing node swaps.
*
* @param strictness true to disallow node swaps, false to allow them
*/
@Override
public final void setStrictness(boolean strictness) {
this.isStrict = strictness;
}
@Override
public final void notify(Edge<? extends Node> edge) {
if (edge.isBackedge()) {
return;
}
int srcID = edge.getSrc().getId();
int dstID = edge.getDst().getId();
outgoingEdges.putIfAbsent(srcID, new HashSet<>());
outgoingEdges.get(srcID).add(dstID);
incomingEdges.putIfAbsent(dstID, new HashSet<>());
incomingEdges.get(dstID).add(srcID);
}
private boolean isSwapValid(int firstID, int secondID) {
int firstDepth = getDepth(firstID);
int secondDepth = getDepth(secondID);
if (firstDepth == secondDepth) {
return true;
}
if (firstDepth > secondDepth) {
int tmp = firstID;
firstID = secondID;
secondID = tmp;
tmp = firstDepth;
firstDepth = secondDepth;
secondDepth = tmp;
}
if (incomingEdges.containsKey(secondID)) {
Set<Integer> preds = incomingEdges.get(secondID);
int maxPredDepth = preds.stream().mapToInt(this::getDepth).max().orElse(0);
if (maxPredDepth >= firstDepth) {
return false;
}
}
if (outgoingEdges.containsKey(firstID)) {
Set<Integer> succs = outgoingEdges.get(firstID);
int minSuccDepth = succs.stream().mapToInt(this::getDepth).min().orElse(0);
return minSuccDepth > secondDepth;
}
return true;
}
}
......@@ -17,7 +17,8 @@
package graphgen.generator.components.layers;
import graphgen.generator.components.Initializable;
import graphgen.generator.components.GeneratorComponent;
import graphgen.generator.components.StrictComponent;
import graphgen.graph.LayerStructure;
/**
......@@ -26,36 +27,49 @@ import graphgen.graph.LayerStructure;
*
* @author Sebastian Vollbrecht
*/
public abstract class LayerCreator implements Initializable {
public abstract class LayerCreator implements GeneratorComponent, StrictComponent {
private boolean isStrict;
/**
* Creates a new layer structure. The height <b>l</b> of the layer structure is determined through the {@link
* #getTargetHeight()} method, the node ID count
* <b>n</b> through the {@link #getTargetNodeCount()} method.