/*
* Kodkod -- Copyright (c) 2005-2007, Emina Torlak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package kodkod.engine.fol2sat;
import java.util.Map;
import kodkod.ast.Relation;
import kodkod.engine.satlab.SATSolver;
import kodkod.instance.Bounds;
import kodkod.instance.Instance;
import kodkod.instance.TupleFactory;
import kodkod.instance.TupleSet;
import kodkod.util.ints.IntIterator;
import kodkod.util.ints.IntSet;
import kodkod.util.ints.Ints;
/**
* Stores the translation of a {@link kodkod.ast.Formula kodkod formula}
* to CNF.
*
* @specfield formula: Formula // the formula that was translated
* @specfield bounds: Bounds // the bounds used to obtain the CNF from the formula
* @specfield solver: SATSolver // a SATSolver containing the CNF representation of the formula
* @specfield options: Options // the options object used to control translation parameters
* @author Emina Torlak
*/
public final class Translation {
private final Bounds bounds;
private final SATSolver solver;
/* maps relations to the literals that comprise their translations */
private final Map<Relation, IntSet> primaryVarUsage;
private final TranslationLog log;
private final int maxPrimaryLit;
/**
* Constructs a new Translation object for the given solver, bounds, mapping
* from Relations to literals, and TranslationLog.
* @requires maxPrimaryLit = max(varUsage[Relation].max)
* @requires bounds.relations = varUsage.IntSet
* @effects this.solver' = solver && this.bounds' = bounds
*/
Translation(SATSolver solver, Bounds bounds, Map<Relation, IntSet> varUsage, int maxPrimaryLit, TranslationLog log) {
this.solver = solver;
this.bounds = bounds;
this.primaryVarUsage = varUsage;
this.maxPrimaryLit = maxPrimaryLit;
this.log = log;
}
/**
* Returns a SATSolver object initialized with the CNF encoding of this.formula
* and the timeout and random seed values specified by this.options. Satisfiability
* of the formula can be checked by calling {@link kodkod.engine.satlab.SATSolver#solve()}.
* @return {s: SATSolver | [[s.clauses]] = [[this.formula]] && s.timeout() = this.options.timeout() &&
* s.seed() = this.options.seed() }
*/
public SATSolver cnf() {
return solver;
}
/**
* If this.solver.solve() is true, returns
* an interpretation of the cnf solution as a
* mapping from Relations to sets of Tuples. The Relations
* mapped by the returned instance are either leaves
* of this.formula with different lower and upper
* bounds (i.e. {r: this.formula.*children & Relation |
* this.bounds.upperBound[r] != this.bounds.lowerBound[r]}),
* or skolem constants.
* @return an interpretation of the cnf solution as
* a mapping from (this.variableUsage().keySet() & Relation) to sets of Tuples.
* @throws IllegalStateException - this.solver.solve() has not been called or the
* outcome of the last call was not <code>true</code>.
*/
public Instance interpret() {
final TupleFactory f = bounds.universe().factory();
final Instance instance = new Instance(bounds.universe());
// System.out.println(varUsage);
for(Relation r : bounds.relations()) {
TupleSet lower = bounds.lowerBound(r);
IntSet indeces = Ints.bestSet(lower.capacity());
indeces.addAll(lower.indexView());
IntSet vars = primaryVarUsage.get(r);
if (vars!=null) {
int lit = vars.min();
for(IntIterator iter = bounds.upperBound(r).indexView().iterator(); iter.hasNext();) {
final int index = iter.next();
if (!indeces.contains(index) && solver.valueOf(lit++))
indeces.add(index);
}
}
instance.add(r, f.setOf(r.arity(), indeces));
}
return instance;
}
/**
* Returns the set of primary variable literals that represent
* the tuples in the given relation. If no literals were allocated
* to the given relation, null is returned.
* @return the set of primary variable literals that represent
* the tuples in the given relation.
*/
public IntSet primaryVariables(Relation relation) {
return primaryVarUsage.get(relation);
}
/**
* Returns the number of primary variables allocated
* during translation. Primary variables represent
* the tuples of Relations that are either leaves
* of this.formula with different lower and upper
* bounds (i.e. {r: this.formula.*children & Relation |
* this.bounds.upperBound[r] != this.bounds.lowerBound[r]}),
* or skolem constants.
* @return the number of primary variables allocated
* during translation.
*/
public int numPrimaryVariables() {
return maxPrimaryLit;
}
/**
* If this.options.logTranslation was set to true, returns the log of the
* translation that produced this Translation object. Otherwise returns null.
* @return the log of the translation that produced this Translation
* object, if this.options.logTranslation was enabled during translation, or null if not.
*/
public TranslationLog log() {
return log;
}
}