1use crate::prelude::*;
2use crate::verify::verify_equality_by_builtin_rules::objs_equal_by_display_string;
3use std::result::Result;
4
5fn order_split_or_is_exhaustive_pair(a: &AtomicFact, b: &AtomicFact) -> bool {
8 use AtomicFact::*;
9 match (a, b) {
10 (GreaterFact(g), LessEqualFact(le)) => {
11 objs_equal_by_display_string(&g.left, &le.left)
12 && objs_equal_by_display_string(&g.right, &le.right)
13 }
14 (LessFact(l), GreaterEqualFact(ge)) => {
15 objs_equal_by_display_string(&l.left, &ge.left)
16 && objs_equal_by_display_string(&l.right, &ge.right)
17 }
18 (LessEqualFact(le), GreaterFact(g)) => {
19 objs_equal_by_display_string(&le.left, &g.left)
20 && objs_equal_by_display_string(&le.right, &g.right)
21 }
22 (GreaterEqualFact(ge), LessFact(l)) => {
23 objs_equal_by_display_string(&ge.left, &l.left)
24 && objs_equal_by_display_string(&ge.right, &l.right)
25 }
26 _ => false,
27 }
28}
29
30fn obj_is_literal_neg_one_for_abs_or_builtin(obj: &Obj) -> bool {
31 match obj {
32 Obj::Number(n) => n.normalized_value == "-1",
33 _ => false,
34 }
35}
36
37fn obj_is_negation_of_for_abs_or_builtin(obj: &Obj, expected_arg: &Obj) -> bool {
38 match obj {
39 Obj::Mul(m) => {
40 (obj_is_literal_neg_one_for_abs_or_builtin(m.left.as_ref())
41 && objs_equal_by_display_string(m.right.as_ref(), expected_arg))
42 || (obj_is_literal_neg_one_for_abs_or_builtin(m.right.as_ref())
43 && objs_equal_by_display_string(m.left.as_ref(), expected_arg))
44 }
45 _ => false,
46 }
47}
48
49fn abs_sign_split_or_is_exhaustive_pair(a: &AtomicFact, b: &AtomicFact) -> bool {
50 let (AtomicFact::EqualFact(first), AtomicFact::EqualFact(second)) = (a, b) else {
51 return false;
52 };
53 let (arg, first_other) = match (&first.left, &first.right) {
54 (Obj::Abs(abs), other) => (abs.arg.as_ref(), other),
55 (other, Obj::Abs(abs)) => (abs.arg.as_ref(), other),
56 _ => return false,
57 };
58 if !objs_equal_by_display_string(arg, first_other) {
59 return false;
60 }
61 let (second_arg, second_other) = match (&second.left, &second.right) {
62 (Obj::Abs(abs), other) => (abs.arg.as_ref(), other),
63 (other, Obj::Abs(abs)) => (abs.arg.as_ref(), other),
64 _ => return false,
65 };
66 objs_equal_by_display_string(arg, second_arg)
67 && obj_is_negation_of_for_abs_or_builtin(second_other, arg)
68}
69
70fn positive_integer_number_to_usize_for_mod_or_builtin(number: &Number) -> Option<usize> {
71 let value = normalized_nonnegative_integer_number_to_usize_for_mod_or_builtin(number)?;
72 if value == 0 {
73 return None;
74 }
75 Some(value)
76}
77
78fn nonnegative_integer_number_to_usize_for_mod_or_builtin(number: &Number) -> Option<usize> {
79 normalized_nonnegative_integer_number_to_usize_for_mod_or_builtin(number)
80}
81
82fn normalized_nonnegative_integer_number_to_usize_for_mod_or_builtin(
83 number: &Number,
84) -> Option<usize> {
85 let value = number.normalized_value.trim();
86 if value.starts_with('-') {
87 return None;
88 }
89 let unsigned = value.trim_start_matches('+');
90 let integer_part = match unsigned.find('.') {
91 Some(index) => {
92 let fractional_part = &unsigned[index + 1..];
93 if !fractional_part.chars().all(|c| c == '0') {
94 return None;
95 }
96 &unsigned[..index]
97 }
98 None => unsigned,
99 };
100 integer_part.parse::<usize>().ok()
101}
102
103fn mod_obj_and_residue_from_atomic_equal_for_mod_or_builtin(
104 atomic_fact: &AtomicFact,
105) -> Option<(&Obj, &Number, &Number)> {
106 let AtomicFact::EqualFact(eq) = atomic_fact else {
107 return None;
108 };
109 match (&eq.left, &eq.right) {
110 (Obj::Mod(m), Obj::Number(residue)) => match m.right.as_ref() {
111 Obj::Number(modulus) => Some((m.left.as_ref(), modulus, residue)),
112 _ => None,
113 },
114 (Obj::Number(residue), Obj::Mod(m)) => match m.right.as_ref() {
115 Obj::Number(modulus) => Some((m.left.as_ref(), modulus, residue)),
116 _ => None,
117 },
118 _ => None,
119 }
120}
121
122fn mod_positive_integer_residue_or_is_exhaustive(or_fact: &OrFact) -> bool {
126 if or_fact.facts.is_empty() {
127 return false;
128 }
129
130 let first_atomic = match &or_fact.facts[0] {
131 AndChainAtomicFact::AtomicFact(atomic) => atomic,
132 _ => return false,
133 };
134 let Some((first_obj, first_modulus, first_residue)) =
135 mod_obj_and_residue_from_atomic_equal_for_mod_or_builtin(first_atomic)
136 else {
137 return false;
138 };
139 let Some(modulus_value) = positive_integer_number_to_usize_for_mod_or_builtin(first_modulus)
140 else {
141 return false;
142 };
143 if modulus_value <= 1 || modulus_value != or_fact.facts.len() {
144 return false;
145 }
146
147 let mut seen_residues = vec![false; modulus_value];
148 let Some(first_residue_value) =
149 nonnegative_integer_number_to_usize_for_mod_or_builtin(first_residue)
150 else {
151 return false;
152 };
153 if first_residue_value >= modulus_value {
154 return false;
155 }
156 seen_residues[first_residue_value] = true;
157
158 for fact in or_fact.facts.iter().skip(1) {
159 let AndChainAtomicFact::AtomicFact(atomic) = fact else {
160 return false;
161 };
162 let Some((obj, modulus, residue)) =
163 mod_obj_and_residue_from_atomic_equal_for_mod_or_builtin(atomic)
164 else {
165 return false;
166 };
167 if !objs_equal_by_display_string(obj, first_obj)
168 || !objs_equal_by_display_string(
169 &Obj::Number(modulus.clone()),
170 &Obj::Number(first_modulus.clone()),
171 )
172 {
173 return false;
174 }
175 let Some(residue_value) = nonnegative_integer_number_to_usize_for_mod_or_builtin(residue)
176 else {
177 return false;
178 };
179 if residue_value >= modulus_value || seen_residues[residue_value] {
180 return false;
181 }
182 seen_residues[residue_value] = true;
183 }
184
185 seen_residues.iter().all(|seen| *seen)
186}
187
188impl Runtime {
189 pub fn verify_or_fact(
190 &mut self,
191 or_fact: &OrFact,
192 verify_state: &VerifyState,
193 ) -> Result<StmtResult, RuntimeError> {
194 if let Some(cached_result) =
195 self.verify_fact_from_cache_using_display_string(&or_fact.clone().into())
196 {
197 return Ok(cached_result);
198 }
199
200 if !verify_state.well_defined_already_verified {
201 if let Err(e) = self.verify_or_fact_well_defined(or_fact, verify_state) {
202 return Err({
203 VerifyRuntimeError(RuntimeErrorStruct::new(
204 Some(Fact::from(or_fact.clone()).into_stmt()),
205 String::new(),
206 or_fact.line_file.clone(),
207 Some(e),
208 vec![],
209 ))
210 .into()
211 });
212 }
213 }
214
215 let verify_state_for_children = verify_state.make_state_with_req_ok_set_to_true();
216
217 if or_fact.facts.len() == 2 {
218 if let (
219 AndChainAtomicFact::AtomicFact(first_atomic),
220 AndChainAtomicFact::AtomicFact(second_atomic),
221 ) = (&or_fact.facts[0], &or_fact.facts[1])
222 {
223 if first_atomic.make_reversed().to_string() == second_atomic.to_string() {
224 return Ok(
225 (FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
226 or_fact.clone().into(),
227 "or: complementary atomic facts (make_reversed first equals second)"
228 .to_string(),
229 Vec::new(),
230 ))
231 .into(),
232 );
233 }
234 if order_split_or_is_exhaustive_pair(first_atomic, second_atomic)
235 || order_split_or_is_exhaustive_pair(second_atomic, first_atomic)
236 {
237 return Ok(
238 (FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
239 or_fact.clone().into(),
240 "or: complementary order relations (strict vs non-strict) on the same terms"
241 .to_string(),
242 Vec::new(),
243 ))
244 .into(),
245 );
246 }
247 if abs_sign_split_or_is_exhaustive_pair(first_atomic, second_atomic)
248 || abs_sign_split_or_is_exhaustive_pair(second_atomic, first_atomic)
249 {
250 return Ok(
251 (FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
252 or_fact.clone().into(),
253 "or: abs(x) is x or -x".to_string(),
254 Vec::new(),
255 ))
256 .into(),
257 );
258 }
259 }
260 }
261
262 if mod_positive_integer_residue_or_is_exhaustive(or_fact) {
263 return Ok(
264 (FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
265 or_fact.clone().into(),
266 "or: complete residue classes modulo a positive integer".to_string(),
267 Vec::new(),
268 ))
269 .into(),
270 );
271 }
272
273 for fact in or_fact.facts.iter() {
274 let result = self.verify_and_chain_atomic_fact(fact, &verify_state_for_children)?;
275 if result.is_true() {
276 return Ok((FactualStmtSuccess::new_with_verified_by_known_fact(
277 or_fact.clone().into(),
278 VerifiedByResult::wrap_bys(vec![VerifiedByResult::Fact(
279 fact.clone().into(),
280 fact.to_string(),
281 )]),
282 Vec::new(),
283 ))
284 .into());
285 }
286 }
287
288 let result = self.verify_or_fact_with_known_or_facts(or_fact)?;
289 if result.is_true() {
290 return Ok(result);
291 }
292
293 let result = self.verify_or_fact_with_known_forall(or_fact, verify_state)?;
294 if result.is_true() {
295 return Ok(result);
296 }
297
298 Ok((StmtUnknown::new()).into())
299 }
300
301 pub fn verify_or_fact_with_known_or_facts(
302 &mut self,
303 or_fact: &OrFact,
304 ) -> Result<StmtResult, RuntimeError> {
305 let args_in_or_fact = or_fact.get_args_from_fact();
306 let mut all_objs_equal_to_each_arg: Vec<Vec<String>> = Vec::new();
307 for arg in args_in_or_fact.iter() {
308 let mut all_objs_equal_to_current_arg =
309 self.get_all_objs_equal_to_given(&arg.to_string());
310 if all_objs_equal_to_current_arg.is_empty() {
311 all_objs_equal_to_current_arg.push(arg.to_string());
312 }
313 all_objs_equal_to_each_arg.push(all_objs_equal_to_current_arg);
314 }
315
316 for environment in self.iter_environments_from_top() {
317 let result = Self::verify_or_fact_with_known_or_facts_with_facts_in_environment(
318 environment,
319 or_fact,
320 &all_objs_equal_to_each_arg,
321 )?;
322 if result.is_true() {
323 return Ok(result);
324 }
325 }
326
327 Ok((StmtUnknown::new()).into())
328 }
329
330 pub fn verify_or_fact_with_known_or_facts_with_facts_in_environment(
331 environment: &Environment,
332 or_fact: &OrFact,
333 all_objs_equal_to_each_arg: &Vec<Vec<String>>,
334 ) -> Result<StmtResult, RuntimeError> {
335 if let Some(known_or_facts) = environment.known_or_facts.get(&or_fact.key()) {
336 for known_or_fact in known_or_facts.iter() {
337 let result = Self::_verify_or_fact_the_same_type_and_return_matched_args(
338 known_or_fact,
339 or_fact,
340 )?;
341 let mut all_args_match = true;
342 if let Some(matched_args) = result {
343 for (index, matched_arg) in matched_args.iter().enumerate() {
344 let known_arg_string = matched_arg.0.to_string();
345
346 if known_arg_string != matched_arg.1.to_string()
347 && !all_objs_equal_to_each_arg[index].contains(&known_arg_string)
348 {
349 all_args_match = false;
350 break;
351 }
352 }
353 }
354
355 if all_args_match {
356 return Ok((FactualStmtSuccess::new_with_verified_by_known_fact(
357 or_fact.clone().into(),
358 VerifiedByResult::wrap_bys(vec![VerifiedByResult::Fact(
359 known_or_fact.clone().into(),
360 known_or_fact.to_string(),
361 )]),
362 Vec::new(),
363 ))
364 .into());
365 }
366 }
367 }
368
369 return Ok((StmtUnknown::new()).into());
370 }
371}