problemreductions/models/misc/
minimum_axiom_set.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
9use crate::traits::Problem;
10use crate::types::Min;
11use serde::{Deserialize, Serialize};
12
13inventory::submit! {
14 ProblemSchemaEntry {
15 name: "MinimumAxiomSet",
16 display_name: "Minimum Axiom Set",
17 aliases: &[],
18 dimensions: &[],
19 module_path: module_path!(),
20 description: "Find smallest axiom subset whose deductive closure equals the true sentences",
21 fields: &[
22 FieldInfo { name: "num_sentences", type_name: "usize", description: "Total number of sentences |S|" },
23 FieldInfo { name: "true_sentences", type_name: "Vec<usize>", description: "Indices of true sentences T ⊆ S" },
24 FieldInfo { name: "implications", type_name: "Vec<(Vec<usize>, usize)>", description: "Implication rules (antecedents, consequent)" },
25 ],
26 }
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct MinimumAxiomSet {
66 num_sentences: usize,
68 true_sentences: Vec<usize>,
70 implications: Vec<(Vec<usize>, usize)>,
72}
73
74impl MinimumAxiomSet {
75 pub fn new(
83 num_sentences: usize,
84 true_sentences: Vec<usize>,
85 implications: Vec<(Vec<usize>, usize)>,
86 ) -> Self {
87 for &s in &true_sentences {
89 assert!(
90 s < num_sentences,
91 "True sentence index {s} out of range [0, {num_sentences})"
92 );
93 }
94 let mut seen = vec![false; num_sentences];
96 for &s in &true_sentences {
97 assert!(!seen[s], "Duplicate true sentence index {s}");
98 seen[s] = true;
99 }
100 for (antecedents, consequent) in &implications {
102 for &a in antecedents {
103 assert!(
104 a < num_sentences,
105 "Implication antecedent {a} out of range [0, {num_sentences})"
106 );
107 }
108 assert!(
109 *consequent < num_sentences,
110 "Implication consequent {consequent} out of range [0, {num_sentences})"
111 );
112 }
113 Self {
114 num_sentences,
115 true_sentences,
116 implications,
117 }
118 }
119
120 pub fn num_sentences(&self) -> usize {
122 self.num_sentences
123 }
124
125 pub fn num_true_sentences(&self) -> usize {
127 self.true_sentences.len()
128 }
129
130 pub fn num_implications(&self) -> usize {
132 self.implications.len()
133 }
134
135 pub fn true_sentences(&self) -> &[usize] {
137 &self.true_sentences
138 }
139
140 pub fn implications(&self) -> &[(Vec<usize>, usize)] {
142 &self.implications
143 }
144}
145
146fn deductive_closure(current: &mut [bool], implications: &[(Vec<usize>, usize)]) {
150 loop {
151 let mut changed = false;
152 for (antecedents, consequent) in implications {
153 if !current[*consequent] && antecedents.iter().all(|&a| current[a]) {
154 current[*consequent] = true;
155 changed = true;
156 }
157 }
158 if !changed {
159 break;
160 }
161 }
162}
163
164impl Problem for MinimumAxiomSet {
165 const NAME: &'static str = "MinimumAxiomSet";
166 type Value = Min<usize>;
167
168 fn variant() -> Vec<(&'static str, &'static str)> {
169 crate::variant_params![]
170 }
171
172 fn dims(&self) -> Vec<usize> {
173 vec![2; self.num_true_sentences()]
174 }
175
176 fn evaluate(&self, config: &[usize]) -> Min<usize> {
177 if config.len() != self.num_true_sentences() {
178 return Min(None);
179 }
180 if config.iter().any(|&v| v >= 2) {
181 return Min(None);
182 }
183
184 let mut current = vec![false; self.num_sentences];
186 let mut count = 0usize;
187 for (i, &v) in config.iter().enumerate() {
188 if v == 1 {
189 current[self.true_sentences[i]] = true;
190 count += 1;
191 }
192 }
193
194 deductive_closure(&mut current, &self.implications);
196
197 let closure_equals_t = self.true_sentences.iter().all(|&s| current[s]);
199
200 if closure_equals_t {
201 Min(Some(count))
202 } else {
203 Min(None)
204 }
205 }
206}
207
208crate::declare_variants! {
209 default MinimumAxiomSet => "2^num_true_sentences",
210}
211
212#[cfg(feature = "example-db")]
213pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
214 vec![crate::example_db::specs::ModelExampleSpec {
217 id: "minimum_axiom_set",
218 instance: Box::new(MinimumAxiomSet::new(
219 8,
220 vec![0, 1, 2, 3, 4, 5, 6, 7],
221 vec![
222 (vec![0], 2),
223 (vec![0], 3),
224 (vec![1], 4),
225 (vec![1], 5),
226 (vec![2, 4], 6),
227 (vec![3, 5], 7),
228 (vec![6, 7], 0),
229 (vec![6, 7], 1),
230 ],
231 )),
232 optimal_config: vec![1, 1, 0, 0, 0, 0, 0, 0],
233 optimal_value: serde_json::json!(2),
234 }]
235}
236
237#[cfg(test)]
238#[path = "../../unit_tests/models/misc/minimum_axiom_set.rs"]
239mod tests;