|
@@ -121,8 +121,6 @@ class CandidatesGenerator {
|
|
|
println()
|
|
|
}
|
|
|
|
|
|
- // TODO: Break this method into multiple methods: generation of constraints, propagation of constraints, etc...
|
|
|
- // Leave the recursive calls here!
|
|
|
def private int recGenerateVariants(Deque<VariantDiagram> ns,
|
|
|
HintConfiguration cs,
|
|
|
ConstraintsStack constraints, int maxVariants, boolean optimizeAlgebraicLoops) {
|
|
@@ -138,8 +136,57 @@ class CandidatesGenerator {
|
|
|
val n = ns.peek() // Head of the queue is the current element being visited.
|
|
|
|
|
|
try {
|
|
|
- val alternative = n.alternative
|
|
|
- switch alternative {
|
|
|
+ addConstraintsBasedOnAlternative(n.alternative, constraints, n, cs)
|
|
|
+
|
|
|
+ // Check invariant on localConstraints
|
|
|
+ localConstraints.forEach[k, v|
|
|
|
+ Assert.isTrue(k.precedes.containsAll(v))
|
|
|
+ ]
|
|
|
+
|
|
|
+ if (n.children.empty){
|
|
|
+ // Base case
|
|
|
+ if (numGenVariants < maxVariants){
|
|
|
+ // Propagate precedence constraints from inner scenarios to their parents.
|
|
|
+ // If two nodes are indirectly (via a path in the children nodes) connected, then they should be connected directly.
|
|
|
+ // This will ensure that the topological sort can safely ignore child nodes.
|
|
|
+ propagateConstraints(n, ns, constraints, cs)
|
|
|
+
|
|
|
+ val variantID = ns.map[n1 | n1.identifier].reduce[n1, n2| n2 + "_" + n1]
|
|
|
+ // mark alternatives as selected, so the processor knows which alternatives have been selected.
|
|
|
+ // Exclude root because it has no alternative
|
|
|
+ markSelected(ns, true)
|
|
|
+ processor.process(ns, variantID, constraints, cs)
|
|
|
+ markSelected(ns, false)
|
|
|
+ numGenVariants++
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // Recurse
|
|
|
+ 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, optimizeAlgebraicLoops)
|
|
|
+ numGenVariants = numGenVariants + childGenVariants
|
|
|
+ ns.pop()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (InfeasibleConstraintException e) {
|
|
|
+ // Do nothing.
|
|
|
+ logger.debug("The last added constraint is infeasible. Trying other alternatives.")
|
|
|
+ }
|
|
|
+
|
|
|
+ // Revert changes in model
|
|
|
+ localConstraints.forEach[k, v|
|
|
|
+ Assert.isTrue(k.precedes.removeAll(v))
|
|
|
+ ]
|
|
|
+ constraints.pop()
|
|
|
+
|
|
|
+ Assert.isTrue(callDepth == constraints.size)
|
|
|
+ return numGenVariants
|
|
|
+ }
|
|
|
+
|
|
|
+ def addConstraintsBasedOnAlternative(Alternative alternative, ConstraintsStack constraints, VariantDiagram n, HintConfiguration cs) {
|
|
|
+ switch alternative {
|
|
|
RootCandidateScenario: {
|
|
|
/*
|
|
|
* Recursively create I/O and DoStep constraints.
|
|
@@ -264,52 +311,6 @@ class CandidatesGenerator {
|
|
|
throw new UnsupportedOperationException()
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- // Check invariant on localConstraints
|
|
|
- localConstraints.forEach[k, v|
|
|
|
- Assert.isTrue(k.precedes.containsAll(v))
|
|
|
- ]
|
|
|
-
|
|
|
- if (n.children.empty){
|
|
|
- // Base case
|
|
|
- if (numGenVariants < maxVariants){
|
|
|
- // Propagate precedence constraints from inner scenarios to their parents.
|
|
|
- // If two nodes are indirectly (via a path in the children nodes) connected, then they should be connected directly.
|
|
|
- // This will ensure that the topological sort can safely ignore child nodes.
|
|
|
- propagateConstraints(n, ns, constraints, cs)
|
|
|
-
|
|
|
- val variantID = ns.map[n1 | n1.identifier].reduce[n1, n2| n2 + "_" + n1]
|
|
|
- // mark alternatives as selected, so the processor knows which alternatives have been selected.
|
|
|
- // Exclude root because it has no alternative
|
|
|
- markSelected(ns, true)
|
|
|
- processor.process(ns, variantID, constraints, cs)
|
|
|
- markSelected(ns, false)
|
|
|
- numGenVariants++
|
|
|
- }
|
|
|
- } else {
|
|
|
- // Recurse
|
|
|
- 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, optimizeAlgebraicLoops)
|
|
|
- numGenVariants = numGenVariants + childGenVariants
|
|
|
- ns.pop()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- } catch (InfeasibleConstraintException e) {
|
|
|
- // Do nothing.
|
|
|
- logger.debug("The last added constraint is infeasible. Trying other alternatives.")
|
|
|
- }
|
|
|
-
|
|
|
- // Revert changes in model
|
|
|
- localConstraints.forEach[k, v|
|
|
|
- Assert.isTrue(k.precedes.removeAll(v))
|
|
|
- ]
|
|
|
- constraints.pop()
|
|
|
-
|
|
|
- Assert.isTrue(callDepth == constraints.size)
|
|
|
- return numGenVariants
|
|
|
}
|
|
|
|
|
|
def propagateConstraints(VariantDiagram n, Deque<VariantDiagram> ns, ConstraintsStack constraints, HintConfiguration cs) {
|