
org.logicng.explanations.smus.SmusComputation 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. //
// //
///////////////////////////////////////////////////////////////////////////
package org.logicng.explanations.smus;
import static org.logicng.handlers.Handler.aborted;
import static org.logicng.handlers.Handler.start;
import static org.logicng.handlers.OptimizationHandler.satHandler;
import org.logicng.datastructures.Assignment;
import org.logicng.datastructures.Tristate;
import org.logicng.formulas.Formula;
import org.logicng.formulas.FormulaFactory;
import org.logicng.formulas.Variable;
import org.logicng.handlers.OptimizationHandler;
import org.logicng.propositions.Proposition;
import org.logicng.propositions.StandardProposition;
import org.logicng.solvers.MiniSat;
import org.logicng.solvers.SATSolver;
import org.logicng.solvers.SolverState;
import org.logicng.solvers.functions.OptimizationFunction;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;
/**
* Computation of a SMUS (smallest MUS, smallest minimal unsatisfiable set).
*
* Implementation is based on "Smallest MUS extraction with minimal
* hitting set dualization" (Ignatiev, Previti, Liffiton, &
* Marques-Silva, 2015).
* @version 2.1.0
* @since 2.0.0
*/
public final class SmusComputation {
private static final String PROPOSITION_SELECTOR = "@PROPOSITION_SEL_";
/**
* Private empty constructor. Class only contains static utility methods.
*/
private SmusComputation() {
// Intentionally left empty
}
/**
* Computes the SMUS for the given list of propositions modulo some additional constraint.
* @param
the subtype of the propositions
* @param propositions the propositions
* @param additionalConstraints the additional constraints
* @param f the formula factory
* @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation
*/
public static
List
computeSmus(final List
propositions, final List additionalConstraints, final FormulaFactory f) {
return computeSmus(propositions, additionalConstraints, f, null);
}
/**
* Computes the SMUS for the given list of propositions modulo some additional constraint.
*
* The SMUS computation can be called with an {@link OptimizationHandler}. The given handler instance will be used for every subsequent
* * {@link org.logicng.solvers.functions.OptimizationFunction} call and the handler's SAT handler is used for every subsequent SAT call.
* @param
the subtype of the propositions
* @param propositions the propositions
* @param additionalConstraints the additional constraints
* @param f the formula factory
* @param handler the handler, can be {@code null}
* @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation
*/
public static
List
computeSmus(final List
propositions, final List additionalConstraints, final FormulaFactory f,
final OptimizationHandler handler) {
start(handler);
final SATSolver growSolver = MiniSat.miniSat(f);
growSolver.add(additionalConstraints == null ? Collections.singletonList(f.verum()) : additionalConstraints);
final Map propositionMapping = new TreeMap<>();
for (final P proposition : propositions) {
final Variable selector = f.variable(PROPOSITION_SELECTOR + propositionMapping.size());
propositionMapping.put(selector, proposition);
growSolver.add(f.equivalence(selector, proposition.formula()));
}
final boolean sat = growSolver.sat(satHandler(handler), propositionMapping.keySet()) == Tristate.TRUE;
if (sat || aborted(handler)) {
return null;
}
final SATSolver hSolver = MiniSat.miniSat(f);
while (true) {
final SortedSet h = minimumHs(hSolver, propositionMapping.keySet(), handler);
if (h == null || aborted(handler)) {
return null;
}
final SortedSet c = grow(growSolver, h, propositionMapping.keySet(), handler);
if (aborted(handler)) {
return null;
}
if (c == null) {
return h.stream().map(propositionMapping::get).collect(Collectors.toList());
}
hSolver.add(f.or(c));
}
}
/**
* Computes the SMUS for the given list of formulas and some additional constraints.
* @param formulas the formulas
* @param additionalConstraints the additional constraints
* @param f the formula factory
* @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation
*/
public static List computeSmusForFormulas(final List formulas, final List additionalConstraints, final FormulaFactory f) {
return computeSmusForFormulas(formulas, additionalConstraints, f, null);
}
/**
* Computes the SMUS for the given list of formulas and some additional constraints.
* @param formulas the formulas
* @param additionalConstraints the additional constraints
* @param f the formula factory
* @param handler the SMUS handler, can be {@code null}
* @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation
*/
public static List computeSmusForFormulas(final List formulas, final List additionalConstraints, final FormulaFactory f,
final OptimizationHandler handler) {
final List props = formulas.stream().map(StandardProposition::new).collect(Collectors.toList());
final List smus = computeSmus(props, additionalConstraints, f, handler);
return smus == null ? null : smus.stream().map(Proposition::formula).collect(Collectors.toList());
}
private static SortedSet minimumHs(final SATSolver hSolver, final Set variables, final OptimizationHandler handler) {
final Assignment minimumHsModel = hSolver.execute(OptimizationFunction.builder()
.handler(handler)
.literals(variables)
.minimize().build());
return aborted(handler) ? null : new TreeSet<>(minimumHsModel.positiveVariables());
}
private static SortedSet grow(final SATSolver growSolver, final SortedSet h, final Set variables, final OptimizationHandler handler) {
final SolverState solverState = growSolver.saveState();
growSolver.add(h);
final Assignment maxModel = growSolver.execute(OptimizationFunction.builder()
.handler(handler)
.literals(variables)
.maximize().build());
if (maxModel == null || aborted(handler)) {
return null;
} else {
final List maximumSatisfiableSet = maxModel.positiveVariables();
growSolver.loadState(solverState);
final SortedSet minimumCorrectionSet = new TreeSet<>(variables);
maximumSatisfiableSet.forEach(minimumCorrectionSet::remove);
return minimumCorrectionSet;
}
}
}