use of kodkod.ast.Relation in project org.alloytools.alloy by AlloyTools.
the class SymmetryBreaker method breakAcyclic.
/**
* If possible, breaks symmetry on the given acyclic predicate and returns a
* formula f such that the meaning of acyclic with respect to this.bounds is
* equivalent to the meaning of f with respect to this.bounds'. If symmetry
* cannot be broken on the given predicate, returns null.
* <p>
* We break symmetry on the relation constrained by the given predicate iff
* this.bounds.upperBound[acyclic.relation] is the cross product of some
* partition in this.symmetries with itself. Assuming that this is the case, we
* then break symmetry on acyclic.relation using one of the methods described in
* {@linkplain #breakMatrixSymmetries(Map, boolean)}; the method used depends on
* the value of the "agressive" flag. The partition that formed the upper bound
* of acylic.relation is removed from this.symmetries.
* </p>
*
* @return null if symmetry cannot be broken on acyclic; otherwise returns a
* formula f such that the meaning of acyclic with respect to
* this.bounds is equivalent to the meaning of f with respect to
* this.bounds'
* @ensures this.symmetries and this.bounds are modified as described in
* {@linkplain #breakMatrixSymmetries(Map, boolean)} iff
* this.bounds.upperBound[acyclic.relation] is the cross product of
* some partition in this.symmetries with itself
* @see #breakMatrixSymmetries(Map,boolean)
*/
private final Formula breakAcyclic(RelationPredicate.Acyclic acyclic, boolean aggressive) {
final IntSet[] colParts = symmetricColumnPartitions(acyclic.relation());
if (colParts != null) {
final Relation relation = acyclic.relation();
final IntSet upper = bounds.upperBound(relation).indexView();
final IntSet reduced = Ints.bestSet(usize * usize);
for (IntIterator tuples = upper.iterator(); tuples.hasNext(); ) {
int tuple = tuples.next();
int mirror = (tuple / usize) + (tuple % usize) * usize;
if (tuple != mirror) {
if (!upper.contains(mirror))
return null;
if (!reduced.contains(mirror))
reduced.add(tuple);
}
}
// remove the partition from the set of symmetric partitions
removePartition(colParts[0].min());
if (aggressive) {
bounds.bound(relation, bounds.universe().factory().setOf(2, reduced));
return Formula.TRUE;
} else {
final Relation acyclicConst = Relation.binary("SYM_BREAK_CONST_" + acyclic.relation().name());
bounds.boundExactly(acyclicConst, bounds.universe().factory().setOf(2, reduced));
return relation.in(acyclicConst);
}
}
return null;
}
use of kodkod.ast.Relation in project org.alloytools.alloy by AlloyTools.
the class Translator method toCNF.
/**
* Translates the given circuit to CNF, adds the clauses to a SATSolver returned
* by options.solver(), and returns a Translation object constructed from the
* solver and the provided arguments.
*
* @requires SAT(circuit) iff SAT(this.originalFormula, this.originalBounds,
* this.options)
* @requires circuit.factory = interpreter.factory
* @requires interpreter.universe = this.bounds.universe &&
* interpreter.relations = this.bounds.relations() && interpreter.ints
* = this.bounds.ints() && interpreter.lbounds =
* this.bounds.lowerBound && this.interpreter.ubounds =
* bounds.upperBound && interpreter.ibounds = bounds.intBound
* @requires log.originalFormula = this.originalFormula && log.bounds =
* this.bounds
* @ensures {@link #completeBounds()}
* @ensures this.options.reporter.translatingToCNF(circuit)
* @return some t: Translation | t.bounds = completeBounds() && t.originalBounds
* = this.originalBounds && t.vars = interpreter.vars &&
* t.vars[Relation].int in t.solver.variables && t.solver.solve() iff
* SAT(this.formula, this.bounds, this.options)
*/
private Translation toCNF(BooleanFormula circuit, LeafInterpreter interpreter, TranslationLog log) {
options.reporter().translatingToCNF(circuit);
final int maxPrimaryVar = interpreter.factory().maxVariable();
if (incremental) {
final Bool2CNFTranslator incrementer = Bool2CNFTranslator.translateIncremental(circuit, maxPrimaryVar, options.solver());
return new Translation.Incremental(completeBounds(), options, SymmetryDetector.partition(originalBounds), interpreter, incrementer);
} else {
final Map<Relation, IntSet> varUsage = interpreter.vars();
// enable gc
interpreter = null;
final SATSolver cnf = Bool2CNFTranslator.translate(circuit, maxPrimaryVar, options.solver());
return new Translation.Whole(completeBounds(), options, cnf, varUsage, maxPrimaryVar, log);
}
}
use of kodkod.ast.Relation in project org.alloytools.alloy by AlloyTools.
the class Translator method checkIncrementalBounds.
/**
* Checks that the given {@code inc} bounds are incremental with respect to the
* given {@code translation}.
*
* @requires translation.bounds.universe = inc.universe && no inc.intBound && no
* (translation.bounds.relations & inc.relations)
* @requires all s: translation.symmetries | some p:
* {@link SymmetryDetector#partition(Bounds) partition}(inc) |
* s.elements in p.elements
* @throws IllegalArgumentException any of the preconditions are violated
*/
public static void checkIncrementalBounds(Bounds inc, Translation.Incremental translation) {
final Bounds base = translation.bounds();
if (!base.universe().equals(inc.universe()))
incBoundErr(inc.universe(), "universe", "equal to", base.universe());
if (!inc.intBounds().isEmpty())
incBoundErr(inc.intBounds(), "intBound", "empty, with integer bounds fully specified by", base.intBounds());
if (inc.relations().isEmpty())
return;
final Set<Relation> baseRels = base.relations();
for (Relation r : inc.relations()) {
if (baseRels.contains(r)) {
incBoundErr(inc.relations(), "relations", "disjoint from", baseRels);
}
}
final Set<IntSet> symmetries = translation.symmetries();
final Set<IntSet> incSymmetries = SymmetryDetector.partition(inc);
EQUIV_CHECK: for (IntSet part : symmetries) {
for (IntSet incPart : incSymmetries) {
if (incPart.containsAll(part))
continue EQUIV_CHECK;
}
incBoundErr(incSymmetries, "partition", "coarser than", symmetries);
}
}
use of kodkod.ast.Relation in project org.alloytools.alloy by AlloyTools.
the class Translator method translateIncrementalNonTrivial.
/**
* @requires checkIncrementalBounds(bounds, transl)
* @requires checkIncrementalOptions(transl.options)
* @requires !transl.trivial()
* @return see {@link #translateIncremental(Formula, Bounds, Options)}
*/
private static Translation.Incremental translateIncrementalNonTrivial(Formula formula, Bounds bounds, Translation.Incremental transl) {
final Options tOptions = transl.options();
final Bounds tBounds = transl.bounds();
// save the set of relations bound in the pre-state
final Set<Relation> oldRelations = new LinkedHashSet<Relation>(tBounds.relations());
// skolemization (below) may also cause extra relations to be added.
for (Relation r : bounds.relations()) {
tBounds.bound(r, bounds.lowerBound(r), bounds.upperBound(r));
}
final AnnotatedNode<Formula> annotated = (transl.options().skolemDepth() < 0) ? annotate(formula) : skolemize(annotate(formula), tBounds, tOptions);
// extend the interpreter with variable allocations for new relations,
// either from given bounds
// or those introduced by skolemization
final LeafInterpreter interpreter = transl.interpreter();
interpreter.extend(setDifference(tBounds.relations(), oldRelations), tBounds.lowerBounds(), tBounds.upperBounds());
final BooleanValue circuit = FOL2BoolTranslator.translate(annotated, interpreter);
if (circuit == BooleanConstant.FALSE) {
// release the old solver and state, and return a fresh trivially
// false incremental translation.
transl.incrementer().solver().free();
return new Translation.Incremental(tBounds, tOptions, transl.symmetries(), LeafInterpreter.empty(tBounds.universe(), tOptions), Bool2CNFTranslator.translateIncremental(BooleanConstant.FALSE, tOptions.solver()));
} else if (circuit == BooleanConstant.TRUE) {
// must add any newly allocated primary variables to the solver for
// interpretation to work correctly
final int maxVar = interpreter.factory().maxVariable();
final int cnfVar = transl.cnf().numberOfVariables();
if (maxVar > cnfVar) {
transl.cnf().addVariables(maxVar - cnfVar);
}
} else {
// circuit is a formula; add its CNF representation to
// transl.incrementer.solver()
Bool2CNFTranslator.translateIncremental((BooleanFormula) circuit, interpreter.factory().maxVariable(), transl.incrementer());
}
return transl;
}
use of kodkod.ast.Relation in project org.alloytools.alloy by AlloyTools.
the class Proc method union.
public static Bounds union(Bounds b1, Bounds b2) {
if (b1 == null)
return b2;
if (b2 == null)
return b1;
if (b1 == b2)
return b1;
if (b1.relations().containsAll(b2.relations()))
return b1;
if (b2.relations().containsAll(b1.relations()))
return b2;
Bounds ans = b1.clone();
Set<Relation> diff = new HashSet<Relation>(b2.relations());
// diff.removeAll(bounds.relations());
for (Relation r : diff) ans.bound(r, b2.lowerBound(r), b2.upperBound(r));
return ans;
}
Aggregations