
org.logicng.solvers.sat.MiniCard Maven / Gradle / Ivy
///////////////////////////////////////////////////////////////////////////
// __ _ _ ________ //
// / / ____ ____ _(_)____/ | / / ____/ //
// / / / __ \/ __ `/ / ___/ |/ / / __ //
// / /___/ /_/ / /_/ / / /__/ /| / /_/ / //
// /_____/\____/\__, /_/\___/_/ |_/\____/ //
// /____/ //
// //
// The Next Generation Logic Library //
// //
///////////////////////////////////////////////////////////////////////////
// //
// Copyright 2015-20xx Christoph Zengler //
// //
// Licensed under the Apache License, Version 2.0 (the "License"); //
// you may not use this file except in compliance with the License. //
// You may obtain a copy of the License at //
// //
// http://www.apache.org/licenses/LICENSE-2.0 //
// //
// Unless required by applicable law or agreed to in writing, software //
// distributed under the License is distributed on an "AS IS" BASIS, //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or //
// implied. See the License for the specific language governing //
// permissions and limitations under the License. //
// //
///////////////////////////////////////////////////////////////////////////
/*
* MiniCARD Copyright (c) 2012, Mark Liffiton, Jordyn Maglalang
*
* MiniCARD is based on MiniSAT, whose original copyright notice is maintained below,
* and it is released under the same license.
* ---
*
* MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
* 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 org.logicng.solvers.sat;
import static org.logicng.handlers.Handler.start;
import static org.logicng.handlers.SATHandler.finishSolving;
import org.logicng.collections.LNGBooleanVector;
import org.logicng.collections.LNGIntVector;
import org.logicng.collections.LNGVector;
import org.logicng.datastructures.Tristate;
import org.logicng.handlers.SATHandler;
import org.logicng.propositions.Proposition;
import org.logicng.solvers.datastructures.MSClause;
import org.logicng.solvers.datastructures.MSVariable;
import org.logicng.solvers.datastructures.MSWatcher;
/**
* A cardinality solver based on MiniCard.
* @version 2.1.0
* @since 1.0
*/
public class MiniCard extends MiniSatStyleSolver {
protected static final int LIT_ERROR = -2;
protected LNGIntVector unitClauses;
/**
* Constructs a new MiniSAT 2 solver with the default values for solver configuration. By default, incremental mode
* is activated.
*/
public MiniCard() {
this(MiniSatConfig.builder().build());
}
/**
* Constructs a new MiniSAT 2 solver with a given solver configuration.
* @param config the solver configuration
*/
public MiniCard(final MiniSatConfig config) {
super(config);
this.initializeMiniSAT();
}
/**
* Initializes the additional parameters.
*/
protected void initializeMiniSAT() {
this.unitClauses = new LNGIntVector();
this.learntsizeAdjustConfl = 0;
this.learntsizeAdjustCnt = 0;
this.learntsizeAdjustStartConfl = 100;
this.learntsizeAdjustInc = 1.5;
this.maxLearnts = 0;
}
@Override
public int newVar(final boolean sign, final boolean dvar) {
final int v = this.vars.size();
final MSVariable newVar = new MSVariable(sign);
this.vars.push(newVar);
this.watches.push(new LNGVector<>());
this.watches.push(new LNGVector<>());
this.seen.push(false);
newVar.setDecision(dvar);
insertVarOrder(v);
return v;
}
@Override
public boolean addClause(final LNGIntVector ps, final Proposition proposition) {
assert decisionLevel() == 0;
if (!this.ok) {
return false;
}
ps.sort();
int p;
int i;
int j;
for (i = 0, j = 0, p = LIT_UNDEF; i < ps.size(); i++) {
if (value(ps.get(i)) == Tristate.TRUE || ps.get(i) == not(p)) {
return true;
} else if (value(ps.get(i)) != Tristate.FALSE && ps.get(i) != p) {
p = ps.get(i);
ps.set(j++, p);
}
}
ps.removeElements(i - j);
if (ps.empty()) {
this.ok = false;
return false;
} else if (ps.size() == 1) {
uncheckedEnqueue(ps.get(0), null);
this.ok = propagate() == null;
if (this.incremental) {
this.unitClauses.push(ps.get(0));
}
return this.ok;
} else {
final MSClause c = new MSClause(ps, false);
this.clauses.push(c);
attachClause(c);
}
return true;
}
@Override
public Tristate solve(final SATHandler handler) {
this.handler = handler;
start(handler);
this.model.clear();
this.conflict.clear();
if (!this.ok) {
return Tristate.FALSE;
}
this.learntsizeAdjustConfl = this.learntsizeAdjustStartConfl;
this.learntsizeAdjustCnt = (int) this.learntsizeAdjustConfl;
this.maxLearnts = this.clauses.size() * this.learntsizeFactor;
Tristate status = Tristate.UNDEF;
int currRestarts = 0;
while (status == Tristate.UNDEF && !this.canceledByHandler) {
final double restBase = luby(this.restartInc, currRestarts);
status = search((int) (restBase * this.restartFirst));
currRestarts++;
}
if (status == Tristate.TRUE) {
this.model = new LNGBooleanVector(this.vars.size());
for (final MSVariable v : this.vars) {
this.model.push(v.assignment() == Tristate.TRUE);
}
} else if (status == Tristate.FALSE && this.conflict.empty()) {
this.ok = false;
}
finishSolving(handler);
cancelUntil(0);
this.handler = null;
this.canceledByHandler = false;
return status;
}
@Override
public void reset() {
super.initialize();
this.initializeMiniSAT();
}
/**
* Saves and returns the solver state expressed as an integer array which stores the length of the internal data
* structures. The array has length 5 and has the following layout:
*
* {@code | current solver state | #vars | #clauses | #learnt clauses | #unit clauses |}
* @return the current solver state
*/
@Override
public int[] saveState() {
if (!this.incremental) {
throw new IllegalStateException("Cannot save a state when the incremental mode is deactivated");
}
final int[] state;
state = new int[5];
state[0] = this.ok ? 1 : 0;
state[1] = this.vars.size();
state[2] = this.clauses.size();
state[3] = this.learnts.size();
state[4] = this.unitClauses.size();
return state;
}
@Override
public void loadState(final int[] state) {
if (!this.incremental) {
throw new IllegalStateException("Cannot save a state when the incremental mode is deactivated");
}
int i;
completeBacktrack();
this.ok = state[0] == 1;
final int newVarsSize = Math.min(state[1], this.vars.size());
for (i = this.vars.size() - 1; i >= newVarsSize; i--) {
this.orderHeap.remove(this.name2idx.remove(this.idx2name.remove(i)));
}
this.vars.shrinkTo(newVarsSize);
final int newClausesSize = Math.min(state[2], this.clauses.size());
for (i = this.clauses.size() - 1; i >= newClausesSize; i--) {
simpleRemoveClause(this.clauses.get(i));
}
this.clauses.shrinkTo(newClausesSize);
final int newLearntsSize = Math.min(state[3], this.learnts.size());
for (i = this.learnts.size() - 1; i >= newLearntsSize; i--) {
simpleRemoveClause(this.learnts.get(i));
}
this.learnts.shrinkTo(newLearntsSize);
this.watches.shrinkTo(newVarsSize * 2);
this.unitClauses.shrinkTo(state[4]);
for (i = 0; this.ok && i < this.unitClauses.size(); i++) {
uncheckedEnqueue(this.unitClauses.get(i), null);
this.ok = propagate() == null;
}
}
@Override
protected void uncheckedEnqueue(final int lit, final MSClause reason) {
assert value(lit) == Tristate.UNDEF;
final MSVariable var = v(lit);
var.assign(Tristate.fromBool(!sign(lit)));
var.setReason(reason);
var.setLevel(decisionLevel());
this.trail.push(lit);
}
@Override
protected void attachClause(final MSClause c) {
if (c.isAtMost()) {
for (int i = 0; i < c.atMostWatchers(); i++) {
final int l = c.get(i);
this.watches.get(l).push(new MSWatcher(c, LIT_UNDEF));
}
this.clausesLiterals += c.size();
} else {
assert c.size() > 1;
this.watches.get(not(c.get(0))).push(new MSWatcher(c, c.get(1)));
this.watches.get(not(c.get(1))).push(new MSWatcher(c, c.get(0)));
if (c.learnt()) {
this.learntsLiterals += c.size();
} else {
this.clausesLiterals += c.size();
}
}
}
@Override
protected void detachClause(final MSClause c) {
assert !c.isAtMost();
assert c.size() > 1;
this.watches.get(not(c.get(0))).remove(new MSWatcher(c, c.get(1)));
this.watches.get(not(c.get(1))).remove(new MSWatcher(c, c.get(0)));
if (c.learnt()) {
this.learntsLiterals -= c.size();
} else {
this.clausesLiterals -= c.size();
}
}
@Override
protected void removeClause(final MSClause c) {
if (c.isAtMost()) {
detachAtMost(c);
for (int i = 0; i < c.atMostWatchers(); i++) {
if (value(c.get(i)) == Tristate.FALSE && v(c.get(i)).reason() != null && v(c.get(i)).reason() == c) {
v(c.get(i)).setReason(null);
}
}
} else {
detachClause(c);
if (locked(c)) {
v(c.get(0)).setReason(null);
}
}
}
@Override
protected MSClause propagate() {
MSClause confl = null;
int numProps = 0;
while (this.qhead < this.trail.size()) {
final int p = this.trail.get(this.qhead++);
final LNGVector ws = this.watches.get(p);
int iInd = 0;
int jInd = 0;
numProps++;
while (iInd < ws.size()) {
final MSWatcher i = ws.get(iInd);
final int blocker = i.blocker();
if (blocker != LIT_UNDEF && value(blocker) == Tristate.TRUE) {
ws.set(jInd++, i);
iInd++;
continue;
}
final MSClause c = i.clause();
if (c.isAtMost()) {
final int newWatch = findNewWatch(c, p);
if (newWatch == LIT_UNDEF) {
for (int k = 0; k < c.atMostWatchers(); k++) {
if (c.get(k) != p && value(c.get(k)) != Tristate.FALSE) {
assert value(c.get(k)) == Tristate.UNDEF || value(c.get(k)) == Tristate.FALSE;
uncheckedEnqueue(not(c.get(k)), c);
}
}
ws.set(jInd++, ws.get(iInd++));
} else if (newWatch == LIT_ERROR) {
confl = c;
this.qhead = this.trail.size();
while (iInd < ws.size()) {
ws.set(jInd++, ws.get(iInd++));
}
} else if (newWatch == p) {
ws.set(jInd++, ws.get(iInd++));
} else {
iInd++;
final MSWatcher w = new MSWatcher(c, LIT_UNDEF);
this.watches.get(newWatch).push(w);
}
} else {
final int falseLit = not(p);
if (c.get(0) == falseLit) {
c.set(0, c.get(1));
c.set(1, falseLit);
}
assert c.get(1) == falseLit;
iInd++;
final int first = c.get(0);
final MSWatcher w = new MSWatcher(c, first);
if (first != blocker && value(first) == Tristate.TRUE) {
ws.set(jInd++, w);
continue;
}
boolean foundWatch = false;
for (int k = 2; k < c.size() && !foundWatch; k++) {
if (value(c.get(k)) != Tristate.FALSE) {
c.set(1, c.get(k));
c.set(k, falseLit);
this.watches.get(not(c.get(1))).push(w);
foundWatch = true;
}
}
if (!foundWatch) {
ws.set(jInd++, w);
if (value(first) == Tristate.FALSE) {
confl = c;
this.qhead = this.trail.size();
while (iInd < ws.size()) {
ws.set(jInd++, ws.get(iInd++));
}
} else {
uncheckedEnqueue(first, c);
}
}
}
}
ws.removeElements(iInd - jInd);
}
this.simpDBProps -= numProps;
return confl;
}
@Override
protected boolean litRedundant(final int p, final int abstractLevels) {
this.analyzeStack.clear();
this.analyzeStack.push(p);
final int top = this.analyzeToClear.size();
while (this.analyzeStack.size() > 0) {
assert v(this.analyzeStack.back()).reason() != null;
final MSClause c = v(this.analyzeStack.back()).reason();
this.analyzeStack.pop();
if (c.isAtMost()) {
for (int i = 0; i < c.size(); i++) {
if (value(c.get(i)) != Tristate.TRUE) {
continue;
}
final int q = not(c.get(i));
if (!this.seen.get(var(q)) && v(q).level() > 0) {
if (v(q).reason() != null && (abstractLevel(var(q)) & abstractLevels) != 0) {
this.seen.set(var(q), true);
this.analyzeStack.push(q);
this.analyzeToClear.push(q);
} else {
for (int j = top; j < this.analyzeToClear.size(); j++) {
this.seen.set(var(this.analyzeToClear.get(j)), false);
}
this.analyzeToClear.removeElements(this.analyzeToClear.size() - top);
return false;
}
}
}
} else {
for (int i = 1; i < c.size(); i++) {
final int q = c.get(i);
if (!this.seen.get(var(q)) && v(q).level() > 0) {
if (v(q).reason() != null && (abstractLevel(var(q)) & abstractLevels) != 0) {
this.seen.set(var(q), true);
this.analyzeStack.push(q);
this.analyzeToClear.push(q);
} else {
for (int j = top; j < this.analyzeToClear.size(); j++) {
this.seen.set(var(this.analyzeToClear.get(j)), false);
}
this.analyzeToClear.removeElements(this.analyzeToClear.size() - top);
return false;
}
}
}
}
}
return true;
}
@Override
protected void analyzeFinal(final int p, final LNGIntVector outConflict) {
outConflict.clear();
outConflict.push(p);
if (decisionLevel() == 0) {
return;
}
this.seen.set(var(p), true);
int x;
MSVariable v;
for (int i = this.trail.size() - 1; i >= this.trailLim.get(0); i--) {
x = var(this.trail.get(i));
if (this.seen.get(x)) {
v = this.vars.get(x);
if (v.reason() == null) {
assert v.level() > 0;
outConflict.push(not(this.trail.get(i)));
} else {
final MSClause c = v.reason();
if (!c.isAtMost()) {
for (int j = 1; j < c.size(); j++) {
if (v(c.get(j)).level() > 0) {
this.seen.set(var(c.get(j)), true);
}
}
} else {
for (int j = 0; j < c.size(); j++) {
if (value(c.get(j)) == Tristate.TRUE && v(c.get(j)).level() > 0) {
this.seen.set(var(c.get(j)), true);
}
}
}
}
this.seen.set(x, false);
}
}
this.seen.set(var(p), false);
}
@Override
protected void reduceDB() {
int i;
int j;
final double extraLim = this.claInc / this.learnts.size();
this.learnts.manualSort(MSClause.minisatComparator);
for (i = j = 0; i < this.learnts.size(); i++) {
final MSClause c = this.learnts.get(i);
assert !c.isAtMost();
if (c.size() > 2 && !locked(c) && (i < this.learnts.size() / 2 || c.activity() < extraLim)) {
removeClause(this.learnts.get(i));
} else {
this.learnts.set(j++, this.learnts.get(i));
}
}
this.learnts.removeElements(i - j);
}
@Override
protected void removeSatisfied(final LNGVector cs) {
int i;
int j;
for (i = j = 0; i < cs.size(); i++) {
final MSClause c = cs.get(i);
if (satisfied(c)) {
removeClause(cs.get(i));
} else {
cs.set(j++, cs.get(i));
}
}
cs.removeElements(i - j);
}
@Override
protected boolean satisfied(final MSClause c) {
if (c.isAtMost()) {
int numFalse = 0;
for (int i = 0; i < c.size(); i++) {
if (value(c.get(i)) == Tristate.FALSE) {
numFalse++;
if (numFalse >= c.atMostWatchers() - 1) {
return true;
}
}
}
} else {
for (int i = 0; i < c.size(); i++) {
if (value(c.get(i)) == Tristate.TRUE) {
return true;
}
}
}
return false;
}
@Override
protected boolean simplify() {
assert decisionLevel() == 0;
if (!this.ok || propagate() != null) {
this.ok = false;
return false;
}
if (nAssigns() == this.simpDBAssigns || (this.simpDBProps > 0)) {
return true;
}
removeSatisfied(this.learnts);
if (this.shouldRemoveSatsisfied) {
removeSatisfied(this.clauses);
}
rebuildOrderHeap();
this.simpDBAssigns = nAssigns();
this.simpDBProps = this.clausesLiterals + this.learntsLiterals;
return true;
}
/**
* Adds an at-most k constraint.
* @param ps the literals of the constraint
* @param rhs the right-hand side of the constraint
* @return {@code true} if the constraint was added, {@code false} otherwise
*/
public boolean addAtMost(final LNGIntVector ps, final int rhs) {
int k = rhs;
assert decisionLevel() == 0;
if (!this.ok) {
return false;
}
ps.sort();
int p;
int i;
int j;
for (i = j = 0, p = LIT_UNDEF; i < ps.size(); i++) {
if (value(ps.get(i)) == Tristate.TRUE) {
k--;
} else if (ps.get(i) == not(p)) {
p = ps.get(i);
j--;
k--;
} else if (value(ps.get(i)) != Tristate.FALSE && ps.get(i) != p) {
p = ps.get(i);
ps.set(j++, p);
}
}
ps.removeElements(i - j);
if (k >= ps.size()) {
return true;
}
if (k < 0) {
this.ok = false;
return false;
}
if (k == 0) {
for (i = 0; i < ps.size(); i++) {
uncheckedEnqueue(not(ps.get(i)), null);
if (this.incremental) {
this.unitClauses.push(not(ps.get(i)));
}
}
this.ok = propagate() == null;
return this.ok;
}
final MSClause cr = new MSClause(ps, false, true);
cr.setAtMostWatchers(ps.size() - k + 1);
this.clauses.push(cr);
attachClause(cr);
return true;
}
/**
* Detaches a given at-most clause.
* @param c the at-most clause.
*/
protected void detachAtMost(final MSClause c) {
for (int i = 0; i < c.atMostWatchers(); i++) {
this.watches.get(c.get(i)).remove(new MSWatcher(c, c.get(i)));
}
this.clausesLiterals -= c.size();
}
/**
* The main search procedure of the CDCL algorithm.
* @param nofConflicts the number of conflicts till the next restart
* @return a {@link Tristate} representing the result. {@code FALSE} if the formula is UNSAT, {@code TRUE} if the
* formula is SAT, and {@code UNKNOWN} if the state is not known yet (restart)
*/
protected Tristate search(final int nofConflicts) {
if (!this.ok) {
return Tristate.FALSE;
}
int conflictC = 0;
this.selectionOrderIdx = 0;
while (true) {
final MSClause confl = propagate();
if (confl != null) {
if (this.handler != null && !this.handler.detectedConflict()) {
this.canceledByHandler = true;
return Tristate.UNDEF;
}
conflictC++;
if (decisionLevel() == 0) {
return Tristate.FALSE;
}
final LNGIntVector learntClause = new LNGIntVector();
analyze(confl, learntClause);
cancelUntil(this.analyzeBtLevel);
if (this.analyzeBtLevel < this.selectionOrder.size()) {
this.selectionOrderIdx = this.analyzeBtLevel;
}
if (learntClause.size() == 1) {
uncheckedEnqueue(learntClause.get(0), null);
this.unitClauses.push(learntClause.get(0));
} else {
final MSClause cr = new MSClause(learntClause, true);
this.learnts.push(cr);
attachClause(cr);
if (!this.incremental) {
claBumpActivity(cr);
}
uncheckedEnqueue(learntClause.get(0), cr);
}
decayActivities();
} else {
if (nofConflicts >= 0 && conflictC >= nofConflicts) {
cancelUntil(0);
return Tristate.UNDEF;
}
if (!this.incremental) {
if (decisionLevel() == 0 && !simplify()) {
return Tristate.FALSE;
}
if (this.learnts.size() - nAssigns() >= this.maxLearnts) {
reduceDB();
}
}
int next = LIT_UNDEF;
while (decisionLevel() < this.assumptions.size()) {
final int p = this.assumptions.get(decisionLevel());
if (value(p) == Tristate.TRUE) {
this.trailLim.push(this.trail.size());
} else if (value(p) == Tristate.FALSE) {
analyzeFinal(not(p), this.conflict);
return Tristate.FALSE;
} else {
next = p;
break;
}
}
if (next == LIT_UNDEF) {
next = pickBranchLit();
if (next == LIT_UNDEF) {
return Tristate.TRUE;
}
}
this.trailLim.push(this.trail.size());
uncheckedEnqueue(next, null);
}
}
}
protected int findNewWatch(final MSClause c, final int p) {
assert c.isAtMost();
int newWatch = LIT_ERROR;
int numFalse = 0;
int numTrue = 0;
final int maxTrue = c.size() - c.atMostWatchers() + 1;
for (int q = 0; q < c.atMostWatchers(); q++) {
final Tristate val = value(c.get(q));
if (val == Tristate.UNDEF) {
continue;
} else if (val == Tristate.FALSE) {
numFalse++;
if (numFalse >= c.atMostWatchers() - 1) {
return p;
}
continue;
}
assert val == Tristate.TRUE;
numTrue++;
if (numTrue > maxTrue) {
return LIT_ERROR;
}
if (c.get(q) == p) {
assert newWatch == LIT_ERROR;
for (int next = c.atMostWatchers(); next < c.size(); next++) {
if (value(c.get(next)) != Tristate.TRUE) {
newWatch = c.get(next);
c.set(next, c.get(q));
c.set(q, newWatch);
return newWatch;
}
}
newWatch = LIT_UNDEF;
}
}
assert newWatch == LIT_UNDEF;
if (numTrue > 1) {
return LIT_ERROR;
} else {
return LIT_UNDEF;
}
}
/**
* Analyzes a given conflict clause wrt. the current solver state. A 1-UIP clause is created during this procedure
* and the new backtracking level is stored in the solver state.
* @param conflictClause the conflict clause to start the resolution analysis with
* @param outLearnt the vector where the new learnt 1-UIP clause is stored
*/
protected void analyze(final MSClause conflictClause, final LNGIntVector outLearnt) {
MSClause c = conflictClause;
int pathC = 0;
int p = LIT_UNDEF;
outLearnt.push(-1);
int index = this.trail.size() - 1;
do {
assert c != null;
if (c.isAtMost()) {
for (int j = 0; j < c.size(); j++) {
if (value(c.get(j)) != Tristate.TRUE) {
continue;
}
final int q = not(c.get(j));
if (!this.seen.get(var(q)) && v(q).level() > 0) {
varBumpActivity(var(q));
this.seen.set(var(q), true);
if (v(q).level() >= decisionLevel()) {
pathC++;
} else {
outLearnt.push(q);
}
}
}
} else {
if (!this.incremental && c.learnt()) {
claBumpActivity(c);
}
for (int j = (p == LIT_UNDEF) ? 0 : 1; j < c.size(); j++) {
final int q = c.get(j);
if (!this.seen.get(var(q)) && v(q).level() > 0) {
varBumpActivity(var(q));
this.seen.set(var(q), true);
if (v(q).level() >= decisionLevel()) {
pathC++;
} else {
outLearnt.push(q);
}
}
}
}
while (!this.seen.get(var(this.trail.get(index--)))) {
}
p = this.trail.get(index + 1);
c = v(p).reason();
this.seen.set(var(p), false);
pathC--;
} while (pathC > 0);
outLearnt.set(0, not(p));
simplifyClause(outLearnt);
}
/**
* Minimizes a given learnt clause depending on the minimization method of the solver configuration.
* @param outLearnt the learnt clause which should be minimized
*/
protected void simplifyClause(final LNGIntVector outLearnt) {
int i;
int j;
this.analyzeToClear = new LNGIntVector(outLearnt);
if (this.ccminMode == MiniSatConfig.ClauseMinimization.DEEP) {
int abstractLevel = 0;
for (i = 1; i < outLearnt.size(); i++) {
abstractLevel |= abstractLevel(var(outLearnt.get(i)));
}
for (i = j = 1; i < outLearnt.size(); i++) {
if (v(outLearnt.get(i)).reason() == null || !litRedundant(outLearnt.get(i), abstractLevel)) {
outLearnt.set(j++, outLearnt.get(i));
}
}
} else if (this.ccminMode == MiniSatConfig.ClauseMinimization.BASIC) {
for (i = j = 1; i < outLearnt.size(); i++) {
if (v(outLearnt.get(i)).reason() == null) {
outLearnt.set(j++, outLearnt.get(i));
} else {
final MSClause c = v(outLearnt.get(i)).reason();
for (int k = 1; k < c.size(); k++) {
if (!this.seen.get(var(c.get(k))) && v(c.get(k)).level() > 0) {
outLearnt.set(j++, outLearnt.get(i));
break;
}
}
}
}
} else {
i = j = outLearnt.size();
}
outLearnt.removeElements(i - j);
this.analyzeBtLevel = 0;
if (outLearnt.size() > 1) {
int max = 1;
for (int k = 2; k < outLearnt.size(); k++) {
if (v(outLearnt.get(k)).level() > v(outLearnt.get(max)).level()) {
max = k;
}
}
final int p = outLearnt.get(max);
outLearnt.set(max, outLearnt.get(1));
outLearnt.set(1, p);
this.analyzeBtLevel = v(p).level();
}
for (int l = 0; l < this.analyzeToClear.size(); l++) {
this.seen.set(var(this.analyzeToClear.get(l)), false);
}
}
/**
* Performs an unconditional backtrack to level zero.
*/
protected void completeBacktrack() {
for (int v = 0; v < this.vars.size(); v++) {
final MSVariable var = this.vars.get(v);
var.assign(Tristate.UNDEF);
var.setReason(null);
if (!this.orderHeap.inHeap(v) && var.decision()) {
this.orderHeap.insert(v);
}
}
this.trail.clear();
this.trailLim.clear();
this.qhead = 0;
}
/**
* Performs a simple removal of clauses used during the loading of an older state.
* @param c the clause to remove
*/
protected void simpleRemoveClause(final MSClause c) {
if (c.isAtMost()) {
for (int i = 0; i < c.atMostWatchers(); i++) {
this.watches.get(c.get(i)).remove(new MSWatcher(c, c.get(i)));
}
} else {
this.watches.get(not(c.get(0))).remove(new MSWatcher(c, c.get(1)));
this.watches.get(not(c.get(1))).remove(new MSWatcher(c, c.get(0)));
}
}
}