|
|
@@ -23,19 +23,25 @@ class CandidatesGenerator {
|
|
|
processor = p
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * Recursively goes through every path on the variant diagram and creates the necessary precedence constraints, cleaning up after the function call (that's why we use a stack to keep groups of constraints together).
|
|
|
+ * Optimization: when optimizeAlgebraicLoops==false, check if there is a cycle every time there are a new edge is created. Then abort that function call, as any children of the variant tree will not be valid. Possible paper that addresses this: https://dl.acm.org/citation.cfm?id=1033207
|
|
|
+ * The simple solution to find a cycle is to check if there already is a path connecting those two ports being connected.
|
|
|
+ * (Not done) A better way is to compute transitive closure for quicker reachable computation after adding multiple edges. This result is passed down function calls, and cleaned up as well.
|
|
|
+ * For now, we just check whether there is a single path passing through all nodes, in a DFS, and return the first such path (mark it on the model, and call semantic adaptation code generation).
|
|
|
+ *
|
|
|
+ * When optimizeAlgebraicLoops==true, we have to continue the recursion, and add constraints as needed. When a variant is fully specified, we launch the algebraic loop optimizer in order to find a schedule for the cosim scenario.
|
|
|
+ */
|
|
|
def generateVariants(HintConfiguration cs, int maxVariants, boolean optimizeAlgebraicLoops){
|
|
|
- /*
|
|
|
- * Recursively goes through every path on the variant diagram and creates the necessary precedence constraints, cleaning up after the function call.
|
|
|
- Optimizations: check if there is a cycle every time there are a new edge is created. Then abort that function call, as any children of the variant tree will not be valid. Possible paper that addresses this: https://dl.acm.org/citation.cfm?id=1033207
|
|
|
- Simple solution is to check if there already is a path connecting those two ports being connected.
|
|
|
- (Not done) Compute transitive closure for quicker reachable computation after adding multiple edges. This result is passed down function calls, and cleaned up as well.
|
|
|
- The base case, for now, is to check whether there is a single path passing through all nodes, in a DFS, and return the first such path (mark it on the model, and call semantic adaptation code generation).
|
|
|
- */
|
|
|
|
|
|
// Assumes that there is a variant diagram created.
|
|
|
Assert.isTrue(cs.root !== null)
|
|
|
|
|
|
- val genVariants = recGenerateVariants(newLinkedList(cs.root), cs, new ConstraintsStack(), maxVariants)
|
|
|
+ if (optimizeAlgebraicLoops && maxVariants > 1) {
|
|
|
+ logger.warn("Multiple variants chosen with algebraic loop optimizer enabled. This will cause the optimizer to be used for every variant, and might be slow.")
|
|
|
+ }
|
|
|
+
|
|
|
+ val genVariants = recGenerateVariants(newLinkedList(cs.root), cs, new ConstraintsStack(), maxVariants, optimizeAlgebraicLoops)
|
|
|
return genVariants
|
|
|
}
|
|
|
|
|
|
@@ -119,7 +125,7 @@ class CandidatesGenerator {
|
|
|
// Leave the recursive calls here!
|
|
|
def private int recGenerateVariants(Deque<VariantDiagram> ns,
|
|
|
HintConfiguration cs,
|
|
|
- ConstraintsStack constraints, int maxVariants) {
|
|
|
+ ConstraintsStack constraints, int maxVariants, boolean optimizeAlgebraicLoops) {
|
|
|
// Store size of stack for assertion
|
|
|
val callDepth = constraints.size
|
|
|
|
|
|
@@ -285,7 +291,7 @@ class CandidatesGenerator {
|
|
|
for (c : n.children) {
|
|
|
if (numGenVariants < maxVariants && variantValidator.validVariant(c, n.children.filter[a | a!==c], ns)){
|
|
|
ns.push(c)
|
|
|
- val childGenVariants = recGenerateVariants(ns, cs, constraints, maxVariants-numGenVariants)
|
|
|
+ val childGenVariants = recGenerateVariants(ns, cs, constraints, maxVariants-numGenVariants, optimizeAlgebraicLoops)
|
|
|
numGenVariants = numGenVariants + childGenVariants
|
|
|
ns.pop()
|
|
|
}
|