Skip to content

Commit 8fb005a

Browse files
committedJul 30, 2024·
WIP configure optimization in algorithms
1 parent 5ba79db commit 8fb005a

File tree

7 files changed

+446
-110
lines changed

7 files changed

+446
-110
lines changed
 

‎src/main/java/org/logicng/explanations/smus/SmusComputation.java

+198-33
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,28 @@
3131
import static org.logicng.handlers.Handler.aborted;
3232
import static org.logicng.handlers.Handler.start;
3333
import static org.logicng.handlers.OptimizationHandler.satHandler;
34+
import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.SAT_OPTIMIZATION;
3435

3536
import org.logicng.datastructures.Assignment;
3637
import org.logicng.datastructures.Tristate;
3738
import org.logicng.formulas.Formula;
3839
import org.logicng.formulas.FormulaFactory;
3940
import org.logicng.formulas.Variable;
41+
import org.logicng.handlers.MaxSATHandler;
4042
import org.logicng.handlers.OptimizationHandler;
43+
import org.logicng.handlers.SATHandler;
4144
import org.logicng.propositions.Proposition;
4245
import org.logicng.propositions.StandardProposition;
46+
import org.logicng.solvers.MaxSATSolver;
4347
import org.logicng.solvers.MiniSat;
4448
import org.logicng.solvers.SATSolver;
4549
import org.logicng.solvers.SolverState;
4650
import org.logicng.solvers.functions.OptimizationFunction;
51+
import org.logicng.solvers.maxsat.OptimizationConfig;
52+
import org.logicng.solvers.maxsat.algorithms.MaxSAT;
4753

54+
import java.util.ArrayList;
55+
import java.util.Collection;
4856
import java.util.Collections;
4957
import java.util.List;
5058
import java.util.Map;
@@ -60,7 +68,7 @@
6068
* Implementation is based on "Smallest MUS extraction with minimal
6169
* hitting set dualization" (Ignatiev, Previti, Liffiton, &
6270
* Marques-Silva, 2015).
63-
* @version 2.1.0
71+
* @version 2.6.0
6472
* @since 2.0.0
6573
*/
6674
public final class SmusComputation {
@@ -82,24 +90,114 @@ private SmusComputation() {
8290
* @param f the formula factory
8391
* @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation
8492
*/
85-
public static <P extends Proposition> List<P> computeSmus(final List<P> propositions, final List<Formula> additionalConstraints, final FormulaFactory f) {
86-
return computeSmus(propositions, additionalConstraints, f, null);
93+
public static <P extends Proposition> List<P> computeSmus(
94+
final List<P> propositions, final List<Formula> additionalConstraints, final FormulaFactory f) {
95+
final OptimizationConfig cfg = new OptimizationConfig(SAT_OPTIMIZATION, null, null, null);
96+
return computeSmus(propositions, additionalConstraints, f, cfg);
8797
}
8898

8999
/**
90100
* Computes the SMUS for the given list of propositions modulo some additional constraint.
91101
* <p>
92-
* The SMUS computation can be called with an {@link OptimizationHandler}. The given handler instance will be used for every subsequent
93-
* * {@link org.logicng.solvers.functions.OptimizationFunction} call and the handler's SAT handler is used for every subsequent SAT call.
102+
* The SMUS computation can be called with an {@link OptimizationHandler}. The given handler instance will be
103+
* used for every subsequent * {@link org.logicng.solvers.functions.OptimizationFunction} call and the handler's
104+
* SAT handler is used for every subsequent SAT call.
94105
* @param <P> the subtype of the propositions
95106
* @param propositions the propositions
96107
* @param additionalConstraints the additional constraints
97108
* @param f the formula factory
98109
* @param handler the handler, can be {@code null}
99110
* @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation
100111
*/
101-
public static <P extends Proposition> List<P> computeSmus(final List<P> propositions, final List<Formula> additionalConstraints, final FormulaFactory f,
102-
final OptimizationHandler handler) {
112+
public static <P extends Proposition> List<P> computeSmus(
113+
final List<P> propositions,
114+
final List<Formula> additionalConstraints,
115+
final FormulaFactory f,
116+
final OptimizationHandler handler) {
117+
final OptimizationConfig cfg = new OptimizationConfig(SAT_OPTIMIZATION, null, handler, null);
118+
return computeSmus(propositions, additionalConstraints, f, cfg);
119+
}
120+
121+
/**
122+
* Computes the SMUS for the given list of propositions modulo some additional constraint.
123+
* <p>
124+
* The SMUS computation can be called with an {@link OptimizationHandler}. The given handler instance will be used
125+
* for every subsequent {@link org.logicng.solvers.functions.OptimizationFunction} call and the handler's SAT
126+
* handler is used for every subsequent SAT call.
127+
* @param <P> the subtype of the propositions
128+
* @param propositions the propositions
129+
* @param additionalConstraints the additional constraints
130+
* @param f the formula factory
131+
* @param config the optimization configuration
132+
* @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation
133+
*/
134+
public static <P extends Proposition> List<P> computeSmus(
135+
final List<P> propositions,
136+
final List<Formula> additionalConstraints,
137+
final FormulaFactory f,
138+
final OptimizationConfig config) {
139+
if (config.getOptimizationType() == SAT_OPTIMIZATION) {
140+
return computeSmusSat(propositions, additionalConstraints, f, config.getOptimizationHandler());
141+
} else {
142+
return computeSmusMaxSAT(propositions, additionalConstraints, f, config);
143+
}
144+
}
145+
146+
/**
147+
* Computes the SMUS for the given list of formulas and some additional constraints.
148+
* @param formulas the formulas
149+
* @param additionalConstraints the additional constraints
150+
* @param f the formula factory
151+
* @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation
152+
*/
153+
public static List<Formula> computeSmusForFormulas(
154+
final List<Formula> formulas,
155+
final List<Formula> additionalConstraints,
156+
final FormulaFactory f) {
157+
final OptimizationConfig cfg = new OptimizationConfig(SAT_OPTIMIZATION, null, null, null);
158+
return computeSmusForFormulas(formulas, additionalConstraints, f, cfg);
159+
}
160+
161+
/**
162+
* Computes the SMUS for the given list of formulas and some additional constraints.
163+
* @param formulas the formulas
164+
* @param additionalConstraints the additional constraints
165+
* @param f the formula factory
166+
* @param handler the SMUS handler, can be {@code null}
167+
* @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation
168+
*/
169+
public static List<Formula> computeSmusForFormulas(
170+
final List<Formula> formulas,
171+
final List<Formula> additionalConstraints,
172+
final FormulaFactory f,
173+
final OptimizationHandler handler) {
174+
final OptimizationConfig cfg = new OptimizationConfig(SAT_OPTIMIZATION, null, handler, null);
175+
return computeSmusForFormulas(formulas, additionalConstraints, f, cfg);
176+
}
177+
178+
/**
179+
* Computes the SMUS for the given list of formulas and some additional constraints.
180+
* @param formulas the formulas
181+
* @param additionalConstraints the additional constraints
182+
* @param f the formula factory
183+
* @param config the optimization configuration
184+
* @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation
185+
*/
186+
public static List<Formula> computeSmusForFormulas(
187+
final List<Formula> formulas,
188+
final List<Formula> additionalConstraints,
189+
final FormulaFactory f,
190+
final OptimizationConfig config) {
191+
final List<Proposition> props = formulas.stream().map(StandardProposition::new).collect(Collectors.toList());
192+
final List<Proposition> smus = computeSmus(props, additionalConstraints, f, config);
193+
return smus == null ? null : smus.stream().map(Proposition::formula).collect(Collectors.toList());
194+
}
195+
196+
private static <P extends Proposition> List<P> computeSmusSat(
197+
final List<P> propositions,
198+
final List<Formula> additionalConstraints,
199+
final FormulaFactory f,
200+
final OptimizationHandler handler) {
103201
start(handler);
104202
final SATSolver growSolver = MiniSat.miniSat(f);
105203
growSolver.add(additionalConstraints == null ? Collections.singletonList(f.verum()) : additionalConstraints);
@@ -130,41 +228,81 @@ public static <P extends Proposition> List<P> computeSmus(final List<P> proposit
130228
}
131229
}
132230

133-
/**
134-
* Computes the SMUS for the given list of formulas and some additional constraints.
135-
* @param formulas the formulas
136-
* @param additionalConstraints the additional constraints
137-
* @param f the formula factory
138-
* @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation
139-
*/
140-
public static List<Formula> computeSmusForFormulas(final List<Formula> formulas, final List<Formula> additionalConstraints, final FormulaFactory f) {
141-
return computeSmusForFormulas(formulas, additionalConstraints, f, null);
142-
}
143-
144-
/**
145-
* Computes the SMUS for the given list of formulas and some additional constraints.
146-
* @param formulas the formulas
147-
* @param additionalConstraints the additional constraints
148-
* @param f the formula factory
149-
* @param handler the SMUS handler, can be {@code null}
150-
* @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation
151-
*/
152-
public static List<Formula> computeSmusForFormulas(final List<Formula> formulas, final List<Formula> additionalConstraints, final FormulaFactory f,
153-
final OptimizationHandler handler) {
154-
final List<Proposition> props = formulas.stream().map(StandardProposition::new).collect(Collectors.toList());
155-
final List<Proposition> smus = computeSmus(props, additionalConstraints, f, handler);
156-
return smus == null ? null : smus.stream().map(Proposition::formula).collect(Collectors.toList());
231+
private static <P extends Proposition> List<P> computeSmusMaxSAT(
232+
final List<P> propositions,
233+
final List<Formula> addConstraints,
234+
final FormulaFactory f,
235+
final OptimizationConfig config) {
236+
final MaxSATHandler handler = config.getMaxSATHandler();
237+
start(handler);
238+
final Collection<? extends Formula> additionalConstraints = addConstraints == null
239+
? Collections.singletonList(f.verum())
240+
: addConstraints;
241+
final List<Formula> growSolverConstraints = new ArrayList<>(additionalConstraints);
242+
final Map<Variable, P> propositionMapping = new TreeMap<>();
243+
for (final P proposition : propositions) {
244+
final Variable selector = f.variable(PROPOSITION_SELECTOR + propositionMapping.size());
245+
propositionMapping.put(selector, proposition);
246+
growSolverConstraints.add(f.equivalence(selector, proposition.formula()));
247+
}
248+
final SATSolver satSolver = MiniSat.miniSat(f);
249+
satSolver.add(growSolverConstraints);
250+
final SATHandler satHandler = handler == null ? null : handler.satHandler();
251+
final boolean sat = satSolver.sat(satHandler, propositionMapping.keySet()) == Tristate.TRUE;
252+
if (sat || aborted(satHandler)) {
253+
return null;
254+
}
255+
final List<Formula> hSolverConstraints = new ArrayList<>();
256+
while (true) {
257+
final SortedSet<Variable> h = minimumHs(hSolverConstraints, propositionMapping.keySet(), config, f);
258+
if (h == null || aborted(handler)) {
259+
return null;
260+
}
261+
final SortedSet<Variable> c = grow(growSolverConstraints, h, propositionMapping.keySet(), config, f);
262+
if (aborted(handler)) {
263+
return null;
264+
}
265+
if (c == null) {
266+
return h.stream().map(propositionMapping::get).collect(Collectors.toList());
267+
}
268+
hSolverConstraints.add(f.or(c));
269+
}
157270
}
158271

159-
private static SortedSet<Variable> minimumHs(final SATSolver hSolver, final Set<Variable> variables, final OptimizationHandler handler) {
272+
private static SortedSet<Variable> minimumHs(
273+
final SATSolver hSolver, final Set<Variable> variables, final OptimizationHandler handler) {
160274
final Assignment minimumHsModel = hSolver.execute(OptimizationFunction.builder()
161275
.handler(handler)
162276
.literals(variables)
163277
.minimize().build());
164278
return aborted(handler) ? null : new TreeSet<>(minimumHsModel.positiveVariables());
165279
}
166280

167-
private static SortedSet<Variable> grow(final SATSolver growSolver, final SortedSet<Variable> h, final Set<Variable> variables, final OptimizationHandler handler) {
281+
private static SortedSet<Variable> minimumHs(
282+
final List<Formula> constraints,
283+
final Set<Variable> variables,
284+
final OptimizationConfig config,
285+
final FormulaFactory f) {
286+
if (variables.isEmpty()) {
287+
return new TreeSet<>(); // TODO workaround: MaxSAT assertion fails for corner case
288+
}
289+
final MaxSATSolver maxSatSolver = config.genMaxSATSolver(f);
290+
constraints.forEach(maxSatSolver::addHardFormula);
291+
for (final Variable v : variables) {
292+
maxSatSolver.addSoftFormula(v.negate(), 1);
293+
}
294+
final MaxSAT.MaxSATResult result = maxSatSolver.solve(config.getMaxSATHandler());
295+
if (result == MaxSAT.MaxSATResult.UNDEF) {
296+
return null;
297+
}
298+
return new TreeSet<>(maxSatSolver.model().positiveVariables());
299+
}
300+
301+
private static SortedSet<Variable> grow(
302+
final SATSolver growSolver,
303+
final SortedSet<Variable> h,
304+
final Set<Variable> variables,
305+
final OptimizationHandler handler) {
168306
final SolverState solverState = growSolver.saveState();
169307
growSolver.add(h);
170308
final Assignment maxModel = growSolver.execute(OptimizationFunction.builder()
@@ -181,4 +319,31 @@ private static SortedSet<Variable> grow(final SATSolver growSolver, final Sorted
181319
return minimumCorrectionSet;
182320
}
183321
}
322+
323+
private static SortedSet<Variable> grow(
324+
final List<Formula> constraints,
325+
final SortedSet<Variable> h,
326+
final Set<Variable> variables,
327+
final OptimizationConfig config,
328+
final FormulaFactory f) {
329+
final MaxSATSolver maxSatSolver = config.genMaxSATSolver(f);
330+
constraints.forEach(maxSatSolver::addHardFormula);
331+
h.forEach(maxSatSolver::addHardFormula);
332+
for (final Variable v : variables) {
333+
maxSatSolver.addSoftFormula(v, 1);
334+
}
335+
final MaxSAT.MaxSATResult result = maxSatSolver.solve(config.getMaxSATHandler());
336+
if (result == MaxSAT.MaxSATResult.UNDEF) {
337+
return null;
338+
}
339+
final Assignment maxModel = maxSatSolver.model();
340+
if (maxModel == null) {
341+
return null;
342+
} else {
343+
final List<Variable> maximumSatisfiableSet = maxModel.positiveVariables();
344+
final SortedSet<Variable> minimumCorrectionSet = new TreeSet<>(variables);
345+
maximumSatisfiableSet.forEach(minimumCorrectionSet::remove);
346+
return minimumCorrectionSet;
347+
}
348+
}
184349
}

‎src/main/java/org/logicng/primecomputation/PrimeCompiler.java

+28-4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
import org.logicng.solvers.MiniSat;
4343
import org.logicng.solvers.SATSolver;
4444
import org.logicng.solvers.functions.OptimizationFunction;
45+
import org.logicng.solvers.maxsat.OptimizationConfig;
46+
import org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType;
4547
import org.logicng.solvers.sat.MiniSatConfig;
4648
import org.logicng.transformations.LiteralSubstitution;
4749
import org.logicng.util.FormulaHelper;
@@ -76,13 +78,17 @@ public final class PrimeCompiler {
7678

7779
private static final String POS = "_POS";
7880
private static final String NEG = "_NEG";
79-
private static final PrimeCompiler INSTANCE_MIN = new PrimeCompiler(false);
80-
private static final PrimeCompiler INSTANCE_MAX = new PrimeCompiler(true);
81+
private static final OptimizationConfig DEFAULT_CFG =
82+
new OptimizationConfig(OptimizationType.SAT_OPTIMIZATION, null, null, null);
83+
private static final PrimeCompiler INSTANCE_MIN = new PrimeCompiler(false, DEFAULT_CFG);
84+
private static final PrimeCompiler INSTANCE_MAX = new PrimeCompiler(true, DEFAULT_CFG);
8185

8286
private final boolean computeWithMaximization;
87+
private final OptimizationConfig config;
8388

84-
private PrimeCompiler(final boolean computeWithMaximization) {
89+
private PrimeCompiler(final boolean computeWithMaximization, final OptimizationConfig config) {
8590
this.computeWithMaximization = computeWithMaximization;
91+
this.config = config;
8692
}
8793

8894
/**
@@ -101,6 +107,22 @@ public static PrimeCompiler getWithMaximization() {
101107
return INSTANCE_MAX;
102108
}
103109

110+
/**
111+
* Returns a compiler which uses minimum models to compute the primes.
112+
* @return a compiler which uses minimum models to compute the primes
113+
*/
114+
public static PrimeCompiler getWithMinimization(final OptimizationConfig config) {
115+
return new PrimeCompiler(false, config);
116+
}
117+
118+
/**
119+
* Returns a compiler which uses maximum models to compute the primes.
120+
* @return a compiler which uses maximum models to compute the primes
121+
*/
122+
public static PrimeCompiler getWithMaximization(final OptimizationConfig config) {
123+
return new PrimeCompiler(false, config);
124+
}
125+
104126
/**
105127
* Computes prime implicants and prime implicates for a given formula.
106128
* The coverage type specifies if the implicants or the implicates will
@@ -167,7 +189,9 @@ private Pair<List<SortedSet<Literal>>, List<SortedSet<Literal>>> computeGeneric(
167189
return null;
168190
}
169191
if (fSat == Tristate.FALSE) {
170-
final SortedSet<Literal> primeImplicant = this.computeWithMaximization ? primeReduction.reduceImplicant(fModel.literals(), satHandler(handler)) : fModel.literals();
192+
final SortedSet<Literal> primeImplicant = this.computeWithMaximization
193+
? primeReduction.reduceImplicant(fModel.literals(), satHandler(handler))
194+
: fModel.literals();
171195
if (primeImplicant == null || aborted(handler)) {
172196
return null;
173197
}

0 commit comments

Comments
 (0)
Please sign in to comment.