/** * {@inheritDoc} * * @see kodkod.engine.satlab.ReductionStrategy#next(kodkod.engine.satlab.ResolutionTrace) */ public IntSet next(ResolutionTrace trace) { if (hits.isEmpty()) return Ints.EMPTY_SET; // tried everything final IntSet relevantVars = StrategyUtils.coreTailUnits(trace); final long[] byRelevance = sortByRelevance(trace, relevantVars); if (DBG) printRelevant(byRelevance); for (int i = byRelevance.length - 1; i >= 0; i--) { final int var = (int) byRelevance[i]; if (hits.remove(var) != null) { // remove maxVar from the set of relevant variables relevantVars.remove(var); if (relevantVars.isEmpty()) break; // there was only one root formula left // get all axioms and resolvents corresponding to the clauses that // form the translations of formulas identified by relevant vars final IntSet relevantClauses = clausesFor(trace, relevantVars); assert !relevantClauses.isEmpty() && !relevantClauses.contains(trace.size() - 1); if (DBG) System.out.println("relevant clauses: " + relevantClauses.size() + ", removed " + var); return relevantClauses; } } hits.clear(); return Ints.EMPTY_SET; }
/** * Minimizes the current core using the trivial strategy that does one of the following: (1) if * there is a root that simplified to FALSE, sets the minimal core to that root; or (2) if not, * there must be two roots that translated to x and -x, where x is a boolean literal, so we pick * those two as the minimal core. The strategy argument is ignored (it can be null). * * @see Proof#minimize(ReductionStrategy) */ @Override public void minimize(ReductionStrategy strategy) { final Map<Formula, int[]> rootLits = new LinkedHashMap<Formula, int[]>(); final Map<Formula, Node> rootNodes = new LinkedHashMap<Formula, Node>(); final Set<Formula> roots = log().roots(); for (Iterator<TranslationRecord> itr = core(); itr.hasNext(); ) { final TranslationRecord rec = itr.next(); if (roots.contains(rec.translated())) { // simply record the most recent output value for each formula: // this is guaranteed to be the final output value for that // formula because of the translation log guarantee that the // log is replayed in the order of translation: i.e. a child's // output value is always recorded before the parent's int[] val = rootLits.get(rec.translated()); if (val == null) { val = new int[1]; rootLits.put(rec.translated(), val); } val[0] = rec.literal(); rootNodes.put(rec.translated(), rec.node()); } } final SparseSequence<Formula> lits = new TreeSequence<Formula>(); for (Map.Entry<Formula, int[]> entry : rootLits.entrySet()) { final int lit = entry.getValue()[0]; if (lit == -Integer.MAX_VALUE) { coreRoots = Collections.singletonMap(entry.getKey(), rootNodes.get(entry.getKey())); break; } else if (lits.containsIndex(-lit)) { final Formula f0 = lits.get(-lit); final Formula f1 = entry.getKey(); coreRoots = new LinkedHashMap<Formula, Node>(3); coreRoots.put(f0, rootNodes.get(f0)); coreRoots.put(f1, rootNodes.get(f1)); coreRoots = Collections.unmodifiableMap(coreRoots); break; } else { lits.put(lit, entry.getKey()); } } coreFilter = null; assert coreRoots.size() == 1 && rootLits.get(coreRoots.keySet().iterator().next())[0] == -Integer.MAX_VALUE || coreRoots.size() == 2; }
/** * Returns a deep (modifiable) copy of this Bounds object. * * @return a deep (modifiable) copy of this Bounds object. */ public Bounds clone() { try { return new Bounds( factory, new LinkedHashMap<Relation, TupleSet>(lowers), new LinkedHashMap<Relation, TupleSet>(uppers), intbounds.clone()); } catch (CloneNotSupportedException cnse) { throw new InternalError(); // should not be reached } }
/** * Returns an array R of longs such that for each i, j in [0..R.length) i < j implies that the * formula identified by (int)R[i] in this.hits contributes fewer clauses to the core of the given * trace than the formula identified by (int)R[j]. * * @return an array as described above */ private long[] sortByRelevance(ResolutionTrace trace, IntSet relevantVars) { hits.indices().retainAll(relevantVars); if (hits.get(hits.indices().min()) == null) { // first call, initialize the hits for (IntIterator varItr = relevantVars.iterator(); varItr.hasNext(); ) { final int var = varItr.next(); final IntSet varReachable = new IntBitSet(var + 1); varReachable.add(var); hits.put(var, varReachable); } for (Iterator<Clause> clauseItr = trace.reverseIterator(trace.axioms()); clauseItr.hasNext(); ) { final Clause clause = clauseItr.next(); final int maxVar = clause.maxVariable(); for (IntSet reachableVars : hits.values()) { if (reachableVars.contains(maxVar)) { for (IntIterator lits = clause.literals(); lits.hasNext(); ) { reachableVars.add(StrictMath.abs(lits.next())); } } } } } final long[] counts = new long[hits.size()]; for (Iterator<Clause> clauseItr = trace.iterator(trace.core()); clauseItr.hasNext(); ) { final Clause clause = clauseItr.next(); final int maxVar = clause.maxVariable(); int i = 0; for (IntSet reachableVars : hits.values()) { if (reachableVars.contains(maxVar)) { counts[i]++; } i++; } } int i = 0; for (IntIterator varItr = hits.indices().iterator(); varItr.hasNext(); ) { final int var = varItr.next(); counts[i] = (counts[i] << 32) | var; i++; } Arrays.sort(counts); return counts; }
/** * Constructs an ARCE strategy that will use the given translation log to relate the cnf clauses * back to the logic constraints from which they were generated. * * @ensures this.hardnessCutOff' = hardnessCutOff and this.recycleLimit' = recycleLimit and * this.noRecycleRatio' = noRecycleRatio */ public DynamicRCEStrategy( final TranslationLog log, double noRecycleRatio, double hardnessCutOff, double recycleLimit) { if (noRecycleRatio < 0 || noRecycleRatio > 1) throw new IllegalArgumentException("noRecycleRatio must be in [0..1]: " + noRecycleRatio); if (hardnessCutOff < 1) throw new IllegalArgumentException("hardnessCutOff must be >=1: " + hardnessCutOff); if (recycleLimit < 1) throw new IllegalArgumentException("recycleLimit must be >=1: " + recycleLimit); this.noRecycleRatio = noRecycleRatio; this.hardnessCutOff = hardnessCutOff; this.recycleLimit = recycleLimit; this.hits = new TreeSequence<IntSet>(); for (IntIterator itr = StrategyUtils.rootVars(log).iterator(); itr.hasNext(); ) { hits.put(itr.next(), null); } }
/** * Makes the specified tupleset an exact bound on the relational value that corresponds to the * given integer. * * @requires ibound.arity = 1 && i.bound.size() = 1 * @ensures this.intBound' = this.intBound' ++ i -> ibound * @throws NullPointerException ibound = null * @throws IllegalArgumentException ibound.arity != 1 || ibound.size() != 1 * @throws IllegalArgumentException ibound.universe != this.universe */ public void boundExactly(int i, TupleSet ibound) { checkBound(1, ibound); if (ibound.size() != 1) throw new IllegalArgumentException("ibound.size != 1: " + ibound); intbounds.put(i, ibound.clone().unmodifiableView()); }
/** * Returns the set of tuples representing the given integer. If i is not mapped by this, null is * returned. * * @return this.intBound[i] */ public TupleSet exactBound(int i) { return intbounds.get(i); }
/** * Returns the set of all integers bound by this Bounds. The returned set does not support the add * operation. It supports removal iff this is not an unmodifiable Bounds. * * @return this.intBounds.TupleSet */ public IntSet ints() { return intbounds.indices(); }