7#include "TseitinCnfizer.h"
16#include "dlinear/util/Stats.h"
17#include "dlinear/util/Timer.h"
18#include "dlinear/util/exception.h"
26void Cnfize(
const Variable &b,
const Formula &f, std::vector<Formula> *clauses);
27void CnfizeNegation(
const Variable &b,
const Formula &f, std::vector<Formula> *clauses);
28void CnfizeConjunction(
const Variable &b,
const Formula &f, std::vector<Formula> *clauses);
29void CnfizeDisjunction(
const Variable &b,
const Formula &f, std::vector<Formula> *clauses);
40 std::map<Variable, Formula>
map;
41 std::vector<Formula> ret;
46 for (
auto const &p :
map) {
47 if (get_variable(head).
equal_to(p.first)) {
48 if (is_conjunction(p.second)) {
49 const std::set<Formula> &conjuncts(get_operands(p.second));
50 copy(conjuncts.begin(), conjuncts.end(), back_inserter(ret));
52 ret.push_back(p.second);
55 Cnfize(p.first, p.second, &ret);
60std::vector<Formula> TseitinCnfizer::operator()(
const Formula &f)
const {
return Process(f); }
62Formula TseitinCnfizer::VisitForall(
const Formula &f, std::map<Variable, Formula> &
map)
const {
68 const Variables &quantified_variables{get_quantified_variables(f)};
69 const Formula &quantified_formula{get_quantified_formula(f)};
72 const std::set<Formula> new_clauses{
::dlinear::map(clauses, [&quantified_variables](
const Formula &clause) {
73 DLINEAR_ASSERT(
is_clause(clause),
"Must be a clause");
75 return forall(quantified_variables, clause);
81 DLINEAR_ASSERT(!new_clauses.empty(),
"Clause must not be empty");
82 if (new_clauses.size() == 1) {
83 return *(new_clauses.begin());
85 static std::size_t
id{0};
92Formula TseitinCnfizer::VisitConjunction(
const Formula &f, std::map<Variable, Formula> &
map)
const {
95 static std::size_t
id{0};
97 get_operands(f), [
this, &
map](
const Formula &formula) {
return this->VisitFormula(formula,
map); })};
100 return Formula{bvar};
103Formula TseitinCnfizer::VisitDisjunction(
const Formula &f, std::map<Variable, Formula> &
map)
const {
104 static std::size_t
id{0};
106 get_operands(f), [
this, &
map](
const Formula &formula) {
return this->VisitFormula(formula,
map); })};
109 return Formula{bvar};
112Formula TseitinCnfizer::VisitNegation(
const Formula &f, std::map<Variable, Formula> &
map)
const {
113 const Formula &operand{get_operand(f)};
118 const Formula transformed_operand{VisitFormula(operand,
map)};
119 map.emplace(bvar, !transformed_operand);
120 return Formula{bvar};
127void Cnfize(
const Variable &b,
const Formula &f, std::vector<Formula> *clauses) {
128 switch (f.get_kind()) {
129 case FormulaKind::False:
130 DLINEAR_UNREACHABLE();
131 case FormulaKind::True:
132 DLINEAR_UNREACHABLE();
133 case FormulaKind::Var:
134 DLINEAR_UNREACHABLE();
135 case FormulaKind::Eq:
136 DLINEAR_UNREACHABLE();
137 case FormulaKind::Neq:
138 DLINEAR_UNREACHABLE();
139 case FormulaKind::Gt:
140 DLINEAR_UNREACHABLE();
141 case FormulaKind::Geq:
142 DLINEAR_UNREACHABLE();
143 case FormulaKind::Lt:
144 DLINEAR_UNREACHABLE();
145 case FormulaKind::Leq:
146 DLINEAR_UNREACHABLE();
147 case FormulaKind::Forall:
148 DLINEAR_UNREACHABLE();
149 case FormulaKind::And:
150 return CnfizeConjunction(b, f, clauses);
151 case FormulaKind::Or:
152 return CnfizeDisjunction(b, f, clauses);
153 case FormulaKind::Not:
154 return CnfizeNegation(b, f, clauses);
156 DLINEAR_UNREACHABLE();
160void Add(
const Formula &f, std::vector<Formula> *clauses) {
162 clauses->push_back(f);
167void AddIff(
const Formula &f1,
const Formula &f2, std::vector<Formula> *clauses) {
176void CnfizeNegation(
const Variable &b,
const Formula &f, std::vector<Formula> *clauses) {
177 AddIff(Formula{b}, f, clauses);
186void CnfizeConjunction(
const Variable &b,
const Formula &f, std::vector<Formula> *clauses) {
188 const std::set<Formula> &operands{get_operands(f)};
190 const std::set<Formula> &negated_operands{
map(operands, [](
const Formula &formula) {
return !formula; })};
191 Formula ret{Formula::True()};
192 for (
const Formula &b_i : operands) {
193 Add(!b || b_i, clauses);
204void CnfizeDisjunction(
const Variable &b,
const Formula &f, std::vector<Formula> *clauses) {
206 const std::set<Formula> &negated_operands{
map(get_operands(f), [](
const Formula &formula) {
return !formula; })};
207 Add(!b || f, clauses);
208 for (
const Formula &neg_b_i : negated_operands) {
209 Add(neg_b_i || b, clauses);
void Increase()
Increase the iteration counter by one.
Formula Process(const Formula &f) const
Convert a f into an equivalent formula f' in CNF.
Timer & m_timer()
Get read-write access to the timer of the stats.
bool enabled() const
Check whether the stats is enabled.
The TimeGuard wraps a timer object and pauses it when the guard object is destructed.
const NaiveCnfizer naive_cnfizer_
Naive CNFizer. Transforms nested formulas inside universal quantification.
std::vector< Formula > Process(const Formula &f) const
Convert f into an equi-satisfiable formula in CNF.
@ BOOLEAN
A BOOLEAN variable takes a bool value.
bool equal_to(const Variable &v) const
Checks the equality of two variables based on their ID values.
Global namespace for the dlinear library.
Formula make_conjunction(const std::vector< Formula > &formulas)
Make conjunction of formulas.
std::set< Formula > map(const std::set< Formula > &formulas, const std::function< Formula(const Formula &)> &func)
Given formulas = {f₁, ..., fₙ} and a func : Formula → Formula, map(formulas, func) returns a set {fun...
std::set< Formula > get_clauses(const Formula &f)
Returns the set of clauses in f.
Formula imply(const Formula &f1, const Formula &f2)
Return a formula f1 ⇒ f2.
Formula make_disjunction(const std::vector< Formula > &formulas)
Make disjunction of formulas.
bool is_clause(const Formula &f)
Check if f is a clause.
bool HaveIntersection(const Variables &variables1, const Variables &variables2)
Check if the intersection of variables1 and variables2 is non-empty.
bool is_atomic(const Formula &f)
Check if f is atomic.