/*
* Copyright (C) 2009-2012 University of Freiburg
*
* This file is part of SMTInterpol.
*
* SMTInterpol is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SMTInterpol is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SMTInterpol. If not, see <http://www.gnu.org/licenses/>.
*/
package de.uni_freiburg.informatik.ultimate.smtinterpol.dpll;
import java.util.Arrays;
import de.uni_freiburg.informatik.ultimate.logic.Term;
import de.uni_freiburg.informatik.ultimate.logic.Theory;
import de.uni_freiburg.informatik.ultimate.smtinterpol.proof.ProofNode;
import de.uni_freiburg.informatik.ultimate.smtinterpol.proof.ResolutionNode;
import de.uni_freiburg.informatik.ultimate.util.HashUtils;
/**
* This class represents a clause. It basically consists of an array
* of literals. There is also some additional informations like activity,
* literal watchers, proof information and stacklevel for push/pop mechanism.
*
* @author Jochen Hoenicke
*
*/
public class Clause extends SimpleListable<Clause> {
Literal[] mLiterals;
/**
* The next watched clause on the watcher list.
* Each clause has two watchers. The first watching lit 0, the next lit1.
* Their watchers form a linked list. For memory efficiency reasons there
* is no real data structure for watchers, but a clause and a bit is used
* to represent a watcher.
*/
Clause mNextFirstWatch, mNextSecondWatch;
/**
* A bitset telling if the next watcher for nextFirstWatch/nextSecondWatch
* is the first or second watcher in that clause. Bit0 is 1, iff the
* next watcher on the first list, which watches nextFirstWatch, is the
* second watcher of that clause. Likewise Bit1 is 1, iff the next watcher
* on the second list is the second watcher of the clause nextSecondWatch.
*/
int mNextIsSecond;
/**
* A WatchList is a list of watchers.
* Each clause has two watchers. The first watching lit 0, the next lit1.
* Their watchers form a linked list. For memory efficiency reasons there
* is no real data structure for watchers, but a clause and a bit is used
* to represent a watcher.
*/
final static class WatchList {
Clause mHead;
int mHeadIndex;
Clause mTail;
int mTailIndex;
int mSize;
public WatchList() {
mHead = mTail = null;
}
public boolean isEmpty() {
return mHead == null;
}
public int size() {
return mSize;
}
public void prepend(Clause c, int index) {
if (mHead == null) {
mTail = c;
mTailIndex = index;
} else {
if (index == 0) {
assert c.mNextFirstWatch == null;
c.mNextFirstWatch = mHead;
c.mNextIsSecond |= mHeadIndex;
} else {
assert c.mNextSecondWatch == null;
c.mNextSecondWatch = mHead;
c.mNextIsSecond |= mHeadIndex << 1;
}
}
mHead = c;
mHeadIndex = index;
mSize++;
}
public void append(Clause c, int index) {
if (mHead == null) {
mHead = c;
mHeadIndex = index;
} else {
final Clause t = mTail;
if (mTailIndex == 0) {
assert t.mNextFirstWatch == null;
t.mNextFirstWatch = c;
t.mNextIsSecond |= index;
} else {
assert t.mNextSecondWatch == null;
t.mNextSecondWatch = c;
t.mNextIsSecond |= index << 1;
}
}
mTail = c;
mTailIndex = index;
mSize++;
}
public int getIndex() {
return mHeadIndex;
}
public Clause removeFirst() {
final Clause c = mHead;
if (mHeadIndex == 0) {
mHead = c.mNextFirstWatch;
mHeadIndex = c.mNextIsSecond & 1;
c.mNextFirstWatch = null;
c.mNextIsSecond &= 2;
} else {
mHead = c.mNextSecondWatch;
mHeadIndex = (c.mNextIsSecond & 2) >> 1;
c.mNextSecondWatch = null;
c.mNextIsSecond &= 1;
}
if (mHead == null) {
mTail = null;
mTailIndex = 0;
}
mSize--;
return c;
}
public void moveAll(WatchList src) {
if (src.mHead == null) {
return;
}
append(src.mHead, src.mHeadIndex);
mSize += src.mSize - 1;
mTail = src.mTail;
mTailIndex = src.mTailIndex;
src.mHead = null;
src.mHeadIndex = 0;
src.mTail = null;
src.mTailIndex = 0;
src.mSize = 0;
}
}
/**
* The activity of a clause. Infinity for clauses that are not inferred. If
* the activity drops below some point the clause is removed.
*/
double mActivity;
// int usedTimes;
/**
* The stacklevel this clause was introduced.
*/
final int mStacklevel;
/**
* Proof annotation
*/
ProofNode mProof;
ClauseDeletionHook mCleanupHook;
private int mHash = 0;
public int getSize() {
return mLiterals.length;
}
public Literal getLiteral(int i) {
return mLiterals[i];
}
public Clause(Literal[] literals) {
mLiterals = literals;
mStacklevel = computeStackLevel();
}
public Clause(Literal[] literals, ProofNode proof) {
mLiterals = literals;
mProof = proof;
mStacklevel = computeStackLevel();
}
public Clause(Literal[] literals, int stacklevel) {
mLiterals = literals;
mStacklevel = Math.max(stacklevel, computeStackLevel());
}
public Clause(Literal[] literals, ResolutionNode proof, int stacklevel) {
mLiterals = literals;
mProof = proof;
mStacklevel = Math.max(stacklevel, computeStackLevel());
}
private final int computeStackLevel() {
int sl = 0;
for (final Literal lit : mLiterals) {
if (lit.getAtom().mAssertionstacklevel > sl) {
sl = lit.getAtom().mAssertionstacklevel;
}
}
return sl;
}
@Override
public String toString() {
return Arrays.toString(mLiterals);
}
public String toSMTLIB(Theory smtTheory) {
if (mLiterals.length == 0) {
return "false";
}
if (mLiterals.length == 1) {
return mLiterals[0].getSMTFormula(smtTheory, true).toString();
}
final StringBuilder sb = new StringBuilder("(or");
for (final Literal l : mLiterals) {
sb.append(' ').append(l.getSMTFormula(smtTheory, true));
}
sb.append(')');
return sb.toString();
}
public void setActivityInfinite() {
mActivity = Double.POSITIVE_INFINITY;
}
@Override
public boolean equals(Object o) {
if (o instanceof Clause) {
return Arrays.equals(mLiterals, ((Clause) o).mLiterals);
}
return false;
}
public void setProof(ProofNode proof) {
mProof = proof;
}
public ProofNode getProof() {
return mProof;
}
public void setDeletionHook(ClauseDeletionHook hook) {
mCleanupHook = hook;
}
public boolean doCleanup(DPLLEngine engine) {
return mCleanupHook == null
? true : mCleanupHook.clauseDeleted(this, engine);
}
/**
* Returns true, if the clause contains the literal with the same polarity.
* @param lit the literal it should contain.
* @return true, if the clause contains the literal with the same polarity.
*/
public boolean contains(Literal lit) {
for (final Literal l : mLiterals) {
if (l == lit) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
if (mHash == 0) {
mHash = HashUtils.hashJenkins(0, (Object[]) mLiterals);
if (mHash == 0) {
mHash = 0xbadc0ded;
}
}
return mHash;
}
public Term toTerm(Theory theory) {
if (mLiterals.length == 0) {
return theory.mFalse;
}
if (mLiterals.length == 1) {
return mLiterals[0].getSMTFormula(theory, true);
}
final Term[] args = new Term[mLiterals.length];
for (int i = 0; i < mLiterals.length; ++i) {
args[i] = mLiterals[i].getSMTFormula(theory, true);
}
return theory.term("or", args);
}
}