Commit 1fc1c0dd authored by Anne Parrain's avatar Anne Parrain
Browse files

Add a solver with the "Divide by 2" feature. Correctthe previous version

and remove it from the standard process.
parent c5a99b7a
Pipeline #138 failed with stage
......@@ -68,6 +68,7 @@ import org.sat4j.pb.core.PBSolverCP;
import org.sat4j.pb.core.PBSolverCPCardLearning;
import org.sat4j.pb.core.PBSolverCPClauseLearning;
import org.sat4j.pb.core.PBSolverCPLong;
import org.sat4j.pb.core.PBSolverCPLongDivideBy2;
import org.sat4j.pb.core.PBSolverCPLongReduceToCard;
import org.sat4j.pb.core.PBSolverCPLongRounding;
//import org.sat4j.pb.core.PBSolverCard;
......@@ -632,6 +633,18 @@ public final class SolverFactory extends ASolverFactory<IPBSolver> {
return solver;
}
private static PBSolverCP newPBCPStarDivideBy2(PBDataStructureFactory dsf,
IOrder order, boolean noRemove) {
MiniSATLearning<PBDataStructureFactory> learning = new MiniSATLearning<PBDataStructureFactory>();
PBSolverCP solver = new PBSolverCPLongDivideBy2(learning, dsf, order,
noRemove);
learning.setDataStructureFactory(solver.getDSFactory());
learning.setVarActivityListener(solver);
solver.setRestartStrategy(new ArminRestarts());
solver.setLearnedConstraintsDeletionStrategy(solver.lbd_based);
return solver;
}
private static PBSolverCP newPBCPStarRounding(PBDataStructureFactory dsf,
IOrder order, boolean noRemove) {
MiniSATLearning<PBDataStructureFactory> learning = new MiniSATLearning<PBDataStructureFactory>();
......@@ -704,6 +717,11 @@ public final class SolverFactory extends ASolverFactory<IPBSolver> {
new VarOrderHeapObjective(), true);
}
public static IPBSolver newCuttingPlanesStarDivideBy2() {
return newPBCPStarDivideBy2(new PBMaxClauseCardConstrDataStructure(),
new VarOrderHeapObjective(), true);
}
/**
* Cutting Planes based solver. The inference during conflict analysis is
* based on cutting planes instead of resolution as in a SAT solver.
......
......@@ -35,6 +35,7 @@ import org.sat4j.core.VecInt;
import org.sat4j.minisat.constraints.cnf.Lits;
import org.sat4j.minisat.core.ILits;
import org.sat4j.minisat.core.VarActivityListener;
import org.sat4j.pb.core.PBSolverStats;
import org.sat4j.specs.IVecInt;
import org.sat4j.specs.IteratorInt;
......@@ -49,6 +50,9 @@ public class ConflictMap extends MapPb implements IConflict {
public static final int NOPOSTPROCESS = 0;
public static final int POSTPROCESSTOCLAUSE = 1;
public static final int POSTPROCESSTOCARD = 2;
public static final int POSTPROCESSDIVIDEBY2 = 3;
private static final int NOTCOMPUTED = -2;
protected boolean hasBeenReduced = false;
protected long numberOfReductions = 0;
......@@ -59,6 +63,9 @@ public class ConflictMap extends MapPb implements IConflict {
protected BigInteger currentSlack;
protected int currentLevel;
private int backtrackLevel = NOTCOMPUTED;
private final PBSolverStats stats;
/**
* allows to access directly to all variables belonging to a particular
......@@ -82,24 +89,31 @@ public class ConflictMap extends MapPb implements IConflict {
public static IConflict createConflict(PBConstr cpb, int level,
boolean noRemove) {
return new ConflictMap(cpb, level, noRemove, NOPOSTPROCESS);
return new ConflictMap(cpb, level, noRemove, NOPOSTPROCESS, null);
}
public static IConflict createConflict(PBConstr cpb, int level,
boolean noRemove, int postProcessing) {
return new ConflictMap(cpb, level, noRemove, postProcessing);
return new ConflictMap(cpb, level, noRemove, postProcessing, null);
}
public static IConflict createConflict(PBConstr cpb, int level,
boolean noRemove, int postProcessing, PBSolverStats stats) {
return new ConflictMap(cpb, level, noRemove, postProcessing, stats);
}
ConflictMap(PBConstr cpb, int level) {
this(cpb, level, false, NOPOSTPROCESS);
this(cpb, level, false, NOPOSTPROCESS, null);
}
ConflictMap(PBConstr cpb, int level, boolean noRemove) {
this(cpb, level, noRemove, NOPOSTPROCESS);
this(cpb, level, noRemove, NOPOSTPROCESS, null);
}
ConflictMap(PBConstr cpb, int level, boolean noRemove, int postProcessing) {
ConflictMap(PBConstr cpb, int level, boolean noRemove, int postProcessing,
PBSolverStats stats) {
super(cpb, level, noRemove);
this.stats = stats;
this.voc = cpb.getVocabulary();
this.currentLevel = level;
initStructures();
......@@ -110,10 +124,14 @@ public class ConflictMap extends MapPb implements IConflict {
case POSTPROCESSTOCARD:
this.postProcess = new PostProcessToCard();
break;
case POSTPROCESSDIVIDEBY2:
this.postProcess = new PostProcessDivideBy2();
break;
default:
this.postProcess = new NoPostProcess();
break;
}
if (noRemove)
this.rmSatLit = new NoRemoveSatisfied();
else
......@@ -224,18 +242,6 @@ public class ConflictMap extends MapPb implements IConflict {
*/
private interface IPostProcess {
void postProcess(int dl);
/**
* retourne le niveau de backtrack : c'est-?-dire le niveau le plus haut
* pour lequel la contrainte est assertive
*
* @param maxLevel
* le plus bas niveau pour lequel la contrainte est assertive
* @return the highest level (smaller int) for which the constraint is
* assertive.
*/
int getBacktrackLevel(int maxLevel);
}
private final IPostProcess postProcess;
......@@ -245,56 +251,6 @@ public class ConflictMap extends MapPb implements IConflict {
}
/**
* computes the level for the backtrack : the highest decision level for
* which the conflict is assertive.
*
* @param maxLevel
* the lowest level for which the conflict is assertive
* @return the highest level (smaller int) for which the constraint is
* assertive.
*/
public int getBacktrackLevel(int maxLevel) {
// we are looking for a level higher than maxLevel
// where the constraint is still assertive
VecInt lits;
int level;
int indStop = levelToIndex(maxLevel) - 1;
int indStart = levelToIndex(0);
BigInteger slack = computeSlack(0)
.subtract(ConflictMap.this.degree);
int previous = 0;
for (int indLevel = indStart; indLevel <= indStop; indLevel++) {
if (ConflictMap.this.byLevel[indLevel] != null) {
level = indexToLevel(indLevel);
assert ConflictMap.this.computeSlack(level)
.subtract(ConflictMap.this.degree).equals(slack);
if (ConflictMap.this.isImplyingLiteralOrdered(level,
slack)) {
break;
}
// updating the new slack
lits = ConflictMap.this.byLevel[indLevel];
int lit;
for (IteratorInt iterator = lits.iterator(); iterator
.hasNext();) {
lit = iterator.next();
if (ConflictMap.this.voc.isFalsified(lit)
&& ConflictMap.this.voc.getLevel(
lit) == indexToLevel(indLevel)) {
slack = slack.subtract(
ConflictMap.this.weightedLits.get(lit));
}
}
if (!lits.isEmpty()) {
previous = level;
}
}
}
assert previous == oldGetBacktrackLevel(maxLevel);
return previous;
}
}
private class PostProcessToClause implements IPostProcess {
......@@ -303,7 +259,8 @@ public class ConflictMap extends MapPb implements IConflict {
&& (!ConflictMap.this.degree.equals(BigInteger.ONE))) {
int litLevel, ilit;
if (ConflictMap.this.assertiveLiteral != -1) {
this.chooseAssertiveLiteral(dl);
ConflictMap.this.assertiveLiteral = this
.chooseAssertiveLiteral(dl);
int lit = ConflictMap.this.weightedLits
.getLit(ConflictMap.this.assertiveLiteral);
......@@ -330,23 +287,21 @@ public class ConflictMap extends MapPb implements IConflict {
ConflictMap.this.degree = BigInteger.ONE;
ConflictMap.this.assertiveLiteral = ConflictMap.this.weightedLits
.getFromAllLits(lit);
// ConflictMap.this.currentSlack = ConflictMap.this
// .computeSlack(this.assertiveLevel);
// assert ConflictMap.this.isAssertive(this.backtrackLevel);
assert this.backtrackLevel == oldGetBacktrackLevel(dl);
assert ConflictMap.this.backtrackLevel == oldGetBacktrackLevel(
dl);
}
}
}
private int assertiveLevel;
private int backtrackLevel;
public void chooseAssertiveLiteral(int maxLevel) {
public int chooseAssertiveLiteral(int maxLevel) {
// we are looking for a level higher than maxLevel
// where the constraint is still assertive
// update ConflictMap.this.assertiveLiteral
VecInt lits;
int level;
int indStop = levelToIndex(maxLevel); // ou maxLevel - 1 ???
int indStart = levelToIndex(0);
BigInteger slack = ConflictMap.this.computeSlack(0)
......@@ -359,8 +314,8 @@ public class ConflictMap extends MapPb implements IConflict {
.subtract(ConflictMap.this.degree).equals(slack);
if (ConflictMap.this.isImplyingLiteralOrdered(level,
slack)) {
this.backtrackLevel = previous;
this.assertiveLevel = level;
ConflictMap.this.backtrackLevel = previous;
assertiveLevel = level;
break;
}
// updating the new slack
......@@ -382,11 +337,9 @@ public class ConflictMap extends MapPb implements IConflict {
}
}
assert this.backtrackLevel == oldGetBacktrackLevel(maxLevel);
}
public int getBacktrackLevel(int maxLevel) {
return this.backtrackLevel;
assert ConflictMap.this.backtrackLevel == oldGetBacktrackLevel(
maxLevel);
return assertiveLiteral;
}
}
......@@ -469,13 +422,13 @@ public class ConflictMap extends MapPb implements IConflict {
ConflictMap.this.assertiveLiteral = ConflictMap.this.weightedLits
.getFromAllLits(lit);
assert this.backtrackLevel == oldGetBacktrackLevel(dl);
assert ConflictMap.this.backtrackLevel == oldGetBacktrackLevel(
dl);
}
}
}
private int assertiveLevel;
private int backtrackLevel;
public int chooseAssertiveLiteral(int maxLevel) {
// we are looking for a level higher than maxLevel
......@@ -493,10 +446,10 @@ public class ConflictMap extends MapPb implements IConflict {
level = indexToLevel(indLevel);
assert ConflictMap.this.computeSlack(level)
.subtract(ConflictMap.this.degree).equals(slack);
if (ConflictMap.this.isImplyingLiteralOrderedIndexes(level,
slack, literals)) {
if (ConflictMap.this.isImplyingLiteralOrdered(level, slack,
literals)) {
this.assertiveLevel = level;
this.backtrackLevel = previous;
ConflictMap.this.backtrackLevel = previous;
break;
}
// updating the new slack
......@@ -530,13 +483,23 @@ public class ConflictMap extends MapPb implements IConflict {
}
}
assert this.backtrackLevel == oldGetBacktrackLevel(maxLevel);
assert ConflictMap.this.backtrackLevel == oldGetBacktrackLevel(
maxLevel);
assert literals.size() > 0;
return maxLit;
}
public int getBacktrackLevel(int maxLevel) {
return this.backtrackLevel;
}
private class PostProcessDivideBy2 implements IPostProcess {
public void postProcess(int dl) {
int nbBits = ConflictMap.this.reduceCoeffsByPower2();
if (nbBits > 0) {
stats.numberOfReductionsByPower2++;
stats.numberOfRightShiftsForCoeffs = stats.numberOfRightShiftsForCoeffs
+ nbBits;
}
}
}
......@@ -905,21 +868,6 @@ public class ConflictMap extends MapPb implements IConflict {
// a particular level
// uses the coefs data structure (where coefficients are decreasing ordered)
// to parse each literal
private boolean isImplyingLiteralOrderedIndexes(int dl, BigInteger slack,
IVecInt literals) {
assert literals.size() == 0;
int ilit, litLevel;
for (int i = 0; i < size(); i++) {
ilit = this.weightedLits.getLit(i);
litLevel = this.voc.getLevel(ilit);
if ((litLevel >= dl || this.voc.isUnassigned(ilit))
&& slack.compareTo(this.weightedLits.getCoef(i)) < 0) {
literals.push(i);
}
}
return literals.size() > 0;
}
private boolean isImplyingLiteralOrdered(int dl, BigInteger slack,
IVecInt literals) {
assert literals.size() == 0;
......@@ -929,7 +877,7 @@ public class ConflictMap extends MapPb implements IConflict {
litLevel = this.voc.getLevel(ilit);
if ((litLevel >= dl || this.voc.isUnassigned(ilit))
&& slack.compareTo(this.weightedLits.getCoef(i)) < 0) {
literals.push(ilit);
literals.push(i);
}
}
return literals.size() > 0;
......@@ -1068,7 +1016,46 @@ public class ConflictMap extends MapPb implements IConflict {
* assertive.
*/
public int getBacktrackLevel(int maxLevel) {
return this.postProcess.getBacktrackLevel(maxLevel);
if (this.backtrackLevel == NOTCOMPUTED) {
// we are looking for a level higher than maxLevel
// where the constraint is still assertive
VecInt lits;
int level;
int indStop = levelToIndex(maxLevel) - 1;
int indStart = levelToIndex(0);
BigInteger slack = computeSlack(0)
.subtract(ConflictMap.this.degree);
int previous = 0;
for (int indLevel = indStart; indLevel <= indStop; indLevel++) {
if (ConflictMap.this.byLevel[indLevel] != null) {
level = indexToLevel(indLevel);
assert ConflictMap.this.computeSlack(level)
.subtract(ConflictMap.this.degree).equals(slack);
if (ConflictMap.this.isImplyingLiteralOrdered(level, slack))
break;
// updating the new slack
lits = ConflictMap.this.byLevel[indLevel];
int lit;
for (IteratorInt iterator = lits.iterator(); iterator
.hasNext();) {
lit = iterator.next();
if (ConflictMap.this.voc.isFalsified(lit)
&& ConflictMap.this.voc.getLevel(
lit) == indexToLevel(indLevel))
slack = slack.subtract(
ConflictMap.this.weightedLits.get(lit));
}
if (!lits.isEmpty())
previous = level;
}
}
assert previous == oldGetBacktrackLevel(maxLevel);
return previous;
} else
return this.backtrackLevel;
}
public int oldGetBacktrackLevel(int maxLevel) {
......
......@@ -75,10 +75,14 @@ public class MapPb implements IDataStructurePB {
}
public int reduceCoeffsByPower2() {
int nbBits = 1;
for (int i = 0; i < this.weightedLits.size() && nbBits > 0; i++)
assert this.weightedLits.size() > 0;
int nbBits = this.weightedLits.getCoef(0).bitLength();
for (int i = 0; i < this.weightedLits.size() && nbBits > 0; i++) {
nbBits = Math.min(nbBits,
this.weightedLits.getCoef(i).getLowestSetBit());
if (nbBits == 0)
break;
}
if (nbBits > 0) {
for (int i = 0; i < this.weightedLits.size(); i++) {
this.weightedLits.changeCoef(i,
......
......@@ -164,12 +164,6 @@ public class PBSolverCP extends PBSolver {
}
// assertive PB-constraint is build and referenced
int nbBits = confl.reduceCoeffsByPower2();
if (nbBits > 0) {
stats.numberOfReductionsByPower2++;
stats.numberOfRightShiftsForCoeffs = stats.numberOfRightShiftsForCoeffs
+ nbBits;
}
confl.postProcess(currentLevel);
PBConstr resConstr = (PBConstr) this.dsfactory
.createUnregisteredPseudoBooleanConstraint(confl);
......
package org.sat4j.pb.core;
import org.sat4j.minisat.core.IOrder;
import org.sat4j.minisat.core.LearningStrategy;
import org.sat4j.minisat.core.RestartStrategy;
import org.sat4j.minisat.core.SearchParams;
import org.sat4j.pb.constraints.pb.ConflictMap;
import org.sat4j.pb.constraints.pb.ConflictMapReduceToClause;
import org.sat4j.pb.constraints.pb.IConflict;
import org.sat4j.pb.constraints.pb.PBConstr;
public class PBSolverCPLongDivideBy2 extends PBSolverCPLong {
public PBSolverCPLongDivideBy2(
LearningStrategy<PBDataStructureFactory> learner,
PBDataStructureFactory dsf, IOrder order) {
super(learner, dsf, order);
// TODO Auto-generated constructor stub
}
public PBSolverCPLongDivideBy2(
LearningStrategy<PBDataStructureFactory> learner,
PBDataStructureFactory dsf, SearchParams params, IOrder order,
RestartStrategy restarter) {
super(learner, dsf, params, order, restarter);
// TODO Auto-generated constructor stub
}
public PBSolverCPLongDivideBy2(
LearningStrategy<PBDataStructureFactory> learner,
PBDataStructureFactory dsf, SearchParams params, IOrder order) {
super(learner, dsf, params, order);
// TODO Auto-generated constructor stub
}
public PBSolverCPLongDivideBy2(
LearningStrategy<PBDataStructureFactory> learner,
PBDataStructureFactory dsf, IOrder order, boolean noRemove) {
super(learner, dsf, order, noRemove);
// TODO Auto-generated constructor stub
}
public PBSolverCPLongDivideBy2(
LearningStrategy<PBDataStructureFactory> learner,
PBDataStructureFactory dsf, SearchParams params, IOrder order,
RestartStrategy restarter, boolean noRemove) {
super(learner, dsf, params, order, restarter, noRemove);
// TODO Auto-generated constructor stub
}
public PBSolverCPLongDivideBy2(
LearningStrategy<PBDataStructureFactory> learner,
PBDataStructureFactory dsf, SearchParams params, IOrder order,
boolean noRemove) {
super(learner, dsf, params, order, noRemove);
// TODO Auto-generated constructor stub
}
@Override
protected IConflict chooseConflict(PBConstr myconfl, int level) {
return ConflictMapReduceToClause.createConflict(myconfl, level,
noRemove, ConflictMap.POSTPROCESSDIVIDEBY2, stats);
}
@Override
public String toString(String prefix) {
return super.toString(prefix) + "\n" + prefix
+ "Performs a post-processing after conflict analysis in order to divide by 2 as much as possible coefficients of learned constraints";
}
}
package org.sat4j.pb.constraints;
import org.sat4j.pb.IPBSolver;
import org.sat4j.pb.SolverFactory;
public class PBCPMaxClauseCardConstrLearningDivideBy2Test
extends AbstractPseudoBooleanAndPigeonHoleTest {
public PBCPMaxClauseCardConstrLearningDivideBy2Test(String arg) {
super(arg);
// TODO Auto-generated constructor stub
}
@Override
protected IPBSolver createSolver() {
return SolverFactory.newCuttingPlanesStarDivideBy2();
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment