problemreductions/models/formula/
qbf.rs1use crate::models::formula::CNFClause;
12use crate::registry::{FieldInfo, ProblemSchemaEntry};
13use crate::traits::Problem;
14use serde::{Deserialize, Serialize};
15
16inventory::submit! {
17 ProblemSchemaEntry {
18 name: "QuantifiedBooleanFormulas",
19 display_name: "Quantified Boolean Formulas",
20 aliases: &["QBF"],
21 dimensions: &[],
22 module_path: module_path!(),
23 description: "Determine if a quantified Boolean formula is true",
24 fields: &[
25 FieldInfo { name: "num_vars", type_name: "usize", description: "Number of Boolean variables" },
26 FieldInfo { name: "quantifiers", type_name: "Vec<Quantifier>", description: "Quantifier for each variable (Exists or ForAll)" },
27 FieldInfo { name: "clauses", type_name: "Vec<CNFClause>", description: "CNF clauses of the Boolean expression E" },
28 ],
29 }
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
34pub enum Quantifier {
35 Exists,
37 ForAll,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct QuantifiedBooleanFormulas {
67 num_vars: usize,
69 quantifiers: Vec<Quantifier>,
71 clauses: Vec<CNFClause>,
73}
74
75impl QuantifiedBooleanFormulas {
76 pub fn new(num_vars: usize, quantifiers: Vec<Quantifier>, clauses: Vec<CNFClause>) -> Self {
82 assert_eq!(
83 quantifiers.len(),
84 num_vars,
85 "quantifiers length ({}) must equal num_vars ({})",
86 quantifiers.len(),
87 num_vars
88 );
89 Self {
90 num_vars,
91 quantifiers,
92 clauses,
93 }
94 }
95
96 pub fn num_vars(&self) -> usize {
98 self.num_vars
99 }
100
101 pub fn num_clauses(&self) -> usize {
103 self.clauses.len()
104 }
105
106 pub fn quantifiers(&self) -> &[Quantifier] {
108 &self.quantifiers
109 }
110
111 pub fn clauses(&self) -> &[CNFClause] {
113 &self.clauses
114 }
115
116 pub fn is_true(&self) -> bool {
124 let mut assignment = vec![false; self.num_vars];
125 self.evaluate_recursive(&mut assignment, 0)
126 }
127
128 fn evaluate_recursive(&self, assignment: &mut Vec<bool>, var_idx: usize) -> bool {
130 if var_idx == self.num_vars {
131 return self.clauses.iter().all(|c| c.is_satisfied(assignment));
133 }
134
135 match self.quantifiers[var_idx] {
136 Quantifier::Exists => {
137 assignment[var_idx] = false;
139 if self.evaluate_recursive(assignment, var_idx + 1) {
140 return true;
141 }
142 assignment[var_idx] = true;
143 self.evaluate_recursive(assignment, var_idx + 1)
144 }
145 Quantifier::ForAll => {
146 assignment[var_idx] = false;
148 if !self.evaluate_recursive(assignment, var_idx + 1) {
149 return false;
150 }
151 assignment[var_idx] = true;
152 self.evaluate_recursive(assignment, var_idx + 1)
153 }
154 }
155 }
156}
157
158impl Problem for QuantifiedBooleanFormulas {
159 const NAME: &'static str = "QuantifiedBooleanFormulas";
160 type Value = crate::types::Or;
161
162 fn dims(&self) -> Vec<usize> {
163 vec![]
164 }
165
166 fn evaluate(&self, config: &[usize]) -> crate::types::Or {
167 crate::types::Or({
168 if !config.is_empty() {
169 return crate::types::Or(false);
170 }
171 self.is_true()
172 })
173 }
174
175 fn variant() -> Vec<(&'static str, &'static str)> {
176 crate::variant_params![]
177 }
178}
179
180crate::declare_variants! {
181 default QuantifiedBooleanFormulas => "2^num_vars",
182}
183
184#[cfg(feature = "example-db")]
185pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
186 vec![crate::example_db::specs::ModelExampleSpec {
187 id: "quantified_boolean_formulas",
188 instance: Box::new(QuantifiedBooleanFormulas::new(
189 2,
190 vec![Quantifier::Exists, Quantifier::ForAll],
191 vec![
192 CNFClause::new(vec![1, 2]), CNFClause::new(vec![1, -2]), ],
195 )),
196 optimal_config: vec![],
197 optimal_value: serde_json::json!(true),
198 }]
199}
200
201#[cfg(test)]
202#[path = "../../unit_tests/models/formula/qbf.rs"]
203mod tests;