1use super::order_normalize::normalize_positive_order_atomic_fact;
2use crate::prelude::*;
3
4impl Runtime {
5 pub fn verify_order_atomic_fact_numeric_builtin_only(
20 &mut self,
21 atomic_fact: &AtomicFact,
22 ) -> Result<StmtResult, RuntimeError> {
23 let vs = VerifyState::new(0, true);
24 if let Some(result) =
25 self.try_verify_order_nonnegative_from_membership_in_n(atomic_fact, &vs)?
26 {
27 return Ok(result);
28 }
29 if let Some(result) =
30 self.try_verify_order_one_le_from_membership_in_n_pos(atomic_fact, &vs)?
31 {
32 return Ok(result);
33 }
34 if let Some(result) =
35 self.try_verify_order_one_le_from_membership_in_n_and_nonzero(atomic_fact, &vs)?
36 {
37 return Ok(result);
38 }
39 if let Some(result) =
40 self.try_verify_order_one_le_from_membership_in_z_and_positive(atomic_fact, &vs)?
41 {
42 return Ok(result);
43 }
44 if let Some(result) = self.try_verify_order_opposite_sign_mul_minus_one(atomic_fact, &vs)? {
45 return Ok(result);
46 }
47 if let Some(result) = self.verify_order_from_known_negated_complement(atomic_fact)? {
48 return Ok(result);
49 }
50 if let Some(result) = self.verify_negated_order_from_known_equivalent_order(atomic_fact)? {
51 return Ok(result);
52 }
53 if let Some(result) = self.verify_order_algebra_structural_builtin_rule(atomic_fact)? {
54 return Ok(result);
55 }
56 if let Some(result) = self.verify_zero_le_abs_builtin_rule(atomic_fact)? {
57 return Ok(result);
58 }
59 if let Some(result) = self.verify_abs_order_builtin_rule(atomic_fact)? {
60 return Ok(result);
61 }
62 if let Some(result) = self.verify_abs_order_strict_builtin_rule(atomic_fact)? {
63 return Ok(result);
64 }
65 if let Some(result) =
66 self.verify_zero_order_on_sub_from_two_sided_order_builtin_rule(atomic_fact)?
67 {
68 return Ok(result);
69 }
70 if let Some(result) =
71 self.verify_zero_le_add_from_known_atomic_facts_builtin_rule(atomic_fact)?
72 {
73 return Ok(result);
74 }
75 if let Some(result) =
76 self.verify_zero_lt_add_from_known_atomic_facts_builtin_rule(atomic_fact)?
77 {
78 return Ok(result);
79 }
80 if let Some(result) = self.verify_zero_le_even_integer_pow_builtin_rule(atomic_fact)? {
81 return Ok(result);
82 }
83 if let Some(result) =
84 self.verify_zero_lt_even_integer_pow_from_base_nonzero_builtin_rule(atomic_fact)?
85 {
86 return Ok(result);
87 }
88 if let Some(result) =
89 self.verify_zero_lt_pow_from_positive_base_real_exp_builtin_rule(atomic_fact)?
90 {
91 return Ok(result);
92 }
93 if let Some(result) =
94 self.verify_zero_le_pow_from_positive_base_real_exp_builtin_rule(atomic_fact)?
95 {
96 return Ok(result);
97 }
98 if let Some(result) =
99 self.verify_zero_le_pow_integer_exponent_from_nonneg_base_builtin_rule(atomic_fact)?
100 {
101 return Ok(result);
102 }
103 if let Some(result) =
104 self.verify_zero_le_mul_from_known_atomic_facts_builtin_rule(atomic_fact)?
105 {
106 return Ok(result);
107 }
108 if let Some(result) =
109 self.verify_zero_lt_mul_from_known_atomic_facts_builtin_rule(atomic_fact)?
110 {
111 return Ok(result);
112 }
113 if let Some(result) =
114 self.verify_zero_le_div_from_known_atomic_facts_builtin_rule(atomic_fact)?
115 {
116 return Ok(result);
117 }
118 if let Some(result) =
119 self.verify_zero_lt_div_from_known_atomic_facts_builtin_rule(atomic_fact)?
120 {
121 return Ok(result);
122 }
123
124 if let AtomicFact::LessEqualFact(less_equal_fact) = atomic_fact {
125 if less_equal_fact.left.to_string() == less_equal_fact.right.to_string() {
126 return Ok(StmtResult::FactualStmtSuccess(
127 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
128 less_equal_fact.clone().into(),
129 "less_equal_fact_equal".to_string(),
130 Vec::new(),
131 ),
132 ));
133 }
134 let equal_result = self.verify_objs_are_equal_known_only(
135 &less_equal_fact.left,
136 &less_equal_fact.right,
137 less_equal_fact.line_file.clone(),
138 );
139 if equal_result.is_true() {
140 return Ok(StmtResult::FactualStmtSuccess(
141 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
142 less_equal_fact.clone().into(),
143 "less_equal_fact_from_known_equality".to_string(),
144 vec![equal_result],
145 ),
146 ));
147 }
148 let strict_fact: Fact = LessFact::new(
149 less_equal_fact.left.clone(),
150 less_equal_fact.right.clone(),
151 less_equal_fact.line_file.clone(),
152 )
153 .into();
154 let strict_key = strict_fact.to_string();
155 let (cache_ok, _) = self.cache_known_facts_contains(&strict_key);
156 if cache_ok {
157 return Ok(StmtResult::FactualStmtSuccess(
158 FactualStmtSuccess::new_with_verified_by_known_fact(
159 less_equal_fact.clone().into(),
160 VerifiedByResult::cited_fact(
161 less_equal_fact.clone().into(),
162 strict_fact,
163 None,
164 ),
165 Vec::new(),
166 ),
167 ));
168 }
169 }
170 if let AtomicFact::GreaterEqualFact(greater_equal_fact) = atomic_fact {
171 if greater_equal_fact.left.to_string() == greater_equal_fact.right.to_string() {
172 return Ok(StmtResult::FactualStmtSuccess(
173 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
174 greater_equal_fact.clone().into(),
175 "greater_equal_fact_equal".to_string(),
176 Vec::new(),
177 ),
178 ));
179 }
180 let equal_result = self.verify_objs_are_equal_known_only(
181 &greater_equal_fact.left,
182 &greater_equal_fact.right,
183 greater_equal_fact.line_file.clone(),
184 );
185 if equal_result.is_true() {
186 return Ok(StmtResult::FactualStmtSuccess(
187 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
188 greater_equal_fact.clone().into(),
189 "greater_equal_fact_from_known_equality".to_string(),
190 vec![equal_result],
191 ),
192 ));
193 }
194 }
195 if let Some(true) = self.verify_number_comparison_builtin_rule(atomic_fact) {
196 Ok(StmtResult::FactualStmtSuccess(
197 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
198 atomic_fact.clone().into(),
199 "number comparison".to_string(),
200 Vec::new(),
201 ),
202 ))
203 } else {
204 Ok(StmtResult::StmtUnknown(StmtUnknown::new()))
205 }
206 }
207
208 pub fn verify_number_comparison_builtin_rule(&self, atomic_fact: &AtomicFact) -> Option<bool> {
209 let normalized = normalize_positive_order_atomic_fact(atomic_fact)?;
210 match normalized {
211 AtomicFact::LessFact(less_fact) => {
212 if let Some(calculated_number_string_pair) =
213 self.calculate_obj_pair_to_number_strings(&less_fact.left, &less_fact.right)
214 {
215 return Some(matches!(
216 compare_number_strings(
217 &calculated_number_string_pair.0,
218 &calculated_number_string_pair.1
219 ),
220 NumberCompareResult::Less
221 ));
222 }
223 self.try_verify_numeric_order_via_div_elimination(
224 &less_fact.left,
225 &less_fact.right,
226 false,
227 )
228 }
229 AtomicFact::LessEqualFact(less_equal_fact) => {
230 if let Some(calculated_number_string_pair) = self
231 .calculate_obj_pair_to_number_strings(
232 &less_equal_fact.left,
233 &less_equal_fact.right,
234 )
235 {
236 let compare_result = compare_number_strings(
237 &calculated_number_string_pair.0,
238 &calculated_number_string_pair.1,
239 );
240 return Some(matches!(
241 compare_result,
242 NumberCompareResult::Less | NumberCompareResult::Equal
243 ));
244 }
245 self.try_verify_numeric_order_via_div_elimination(
246 &less_equal_fact.left,
247 &less_equal_fact.right,
248 true,
249 )
250 }
251 _ => None,
252 }
253 }
254}
255
256pub enum NumberCompareResult {
257 Less,
258 Equal,
259 Greater,
260}
261
262pub fn compare_normalized_number_str_to_zero(number_value: &str) -> NumberCompareResult {
264 compare_number_strings(number_value.trim(), "0")
265}
266
267fn parse_number_parts_for_comparison(number_value: &str) -> (bool, Vec<u8>, Vec<u8>) {
268 let trimmed_number_value = number_value.trim();
269 let (is_negative, magnitude_string) = if trimmed_number_value.starts_with('-') {
270 (true, trimmed_number_value[1..].trim())
271 } else {
272 (false, trimmed_number_value)
273 };
274
275 let (integer_part_string, fractional_part_string) = match magnitude_string.find('.') {
276 Some(dot_index) => (
277 &magnitude_string[..dot_index],
278 &magnitude_string[dot_index + 1..],
279 ),
280 None => (magnitude_string, ""),
281 };
282
283 let mut integer_digits: Vec<u8> = Vec::new();
284 if integer_part_string.is_empty() {
285 integer_digits.push(0);
286 } else {
287 for current_char in integer_part_string.chars() {
288 if current_char.is_ascii_digit() {
289 integer_digits.push(current_char as u8 - b'0');
290 }
291 }
292 if integer_digits.is_empty() {
293 integer_digits.push(0);
294 }
295 }
296
297 let mut fractional_digits: Vec<u8> = Vec::new();
298 for current_char in fractional_part_string.chars() {
299 if current_char.is_ascii_digit() {
300 fractional_digits.push(current_char as u8 - b'0');
301 }
302 }
303
304 (is_negative, integer_digits, fractional_digits)
305}
306
307fn digits_are_all_zero(digits: &[u8]) -> bool {
308 for digit in digits {
309 if *digit != 0 {
310 return false;
311 }
312 }
313 true
314}
315
316fn normalized_decimal_string_is_integer(number_value: &str) -> bool {
317 let (_, _integer_digits, fractional_digits) = parse_number_parts_for_comparison(number_value);
318 digits_are_all_zero(&fractional_digits)
319}
320
321pub(crate) fn normalized_decimal_string_is_even_integer(number_value: &str) -> bool {
322 if !normalized_decimal_string_is_integer(number_value) {
323 return false;
324 }
325 let (_is_negative, integer_digits, _fractional_digits) =
326 parse_number_parts_for_comparison(number_value);
327 let last_digit = integer_digits.last().copied().unwrap_or(0);
328 last_digit % 2 == 0
329}
330
331fn first_non_zero_integer_digit_index(integer_digits: &[u8]) -> usize {
332 let mut current_index = 0;
333 while current_index + 1 < integer_digits.len() && integer_digits[current_index] == 0 {
334 current_index += 1;
335 }
336 current_index
337}
338
339fn compare_non_negative_decimal_parts(
340 left_integer_digits: &[u8],
341 left_fractional_digits: &[u8],
342 right_integer_digits: &[u8],
343 right_fractional_digits: &[u8],
344) -> NumberCompareResult {
345 let left_integer_start_index = first_non_zero_integer_digit_index(left_integer_digits);
346 let right_integer_start_index = first_non_zero_integer_digit_index(right_integer_digits);
347
348 let left_effective_integer_len = left_integer_digits.len() - left_integer_start_index;
349 let right_effective_integer_len = right_integer_digits.len() - right_integer_start_index;
350 if left_effective_integer_len < right_effective_integer_len {
351 return NumberCompareResult::Less;
352 }
353 if left_effective_integer_len > right_effective_integer_len {
354 return NumberCompareResult::Greater;
355 }
356
357 let mut integer_index = 0;
358 while integer_index < left_effective_integer_len {
359 let left_digit = left_integer_digits[left_integer_start_index + integer_index];
360 let right_digit = right_integer_digits[right_integer_start_index + integer_index];
361 if left_digit < right_digit {
362 return NumberCompareResult::Less;
363 }
364 if left_digit > right_digit {
365 return NumberCompareResult::Greater;
366 }
367 integer_index += 1;
368 }
369
370 let fractional_compare_len = if left_fractional_digits.len() > right_fractional_digits.len() {
371 left_fractional_digits.len()
372 } else {
373 right_fractional_digits.len()
374 };
375 let mut fractional_index = 0;
376 while fractional_index < fractional_compare_len {
377 let left_digit = match left_fractional_digits.get(fractional_index) {
378 Some(digit) => *digit,
379 None => 0,
380 };
381 let right_digit = match right_fractional_digits.get(fractional_index) {
382 Some(digit) => *digit,
383 None => 0,
384 };
385 if left_digit < right_digit {
386 return NumberCompareResult::Less;
387 }
388 if left_digit > right_digit {
389 return NumberCompareResult::Greater;
390 }
391 fractional_index += 1;
392 }
393
394 NumberCompareResult::Equal
395}
396
397pub fn compare_number_strings(
398 left_number_value: &str,
399 right_number_value: &str,
400) -> NumberCompareResult {
401 let (left_is_negative, left_integer_digits, left_fractional_digits) =
402 parse_number_parts_for_comparison(left_number_value);
403 let (right_is_negative, right_integer_digits, right_fractional_digits) =
404 parse_number_parts_for_comparison(right_number_value);
405
406 let left_is_zero =
407 digits_are_all_zero(&left_integer_digits) && digits_are_all_zero(&left_fractional_digits);
408 let right_is_zero =
409 digits_are_all_zero(&right_integer_digits) && digits_are_all_zero(&right_fractional_digits);
410 if left_is_zero && right_is_zero {
411 return NumberCompareResult::Equal;
412 }
413
414 if left_is_negative && !left_is_zero && !right_is_negative {
415 return NumberCompareResult::Less;
416 }
417 if right_is_negative && !right_is_zero && !left_is_negative {
418 return NumberCompareResult::Greater;
419 }
420
421 let non_negative_compare_result = compare_non_negative_decimal_parts(
422 &left_integer_digits,
423 &left_fractional_digits,
424 &right_integer_digits,
425 &right_fractional_digits,
426 );
427 if left_is_negative && !left_is_zero && right_is_negative && !right_is_zero {
428 return match non_negative_compare_result {
429 NumberCompareResult::Less => NumberCompareResult::Greater,
430 NumberCompareResult::Equal => NumberCompareResult::Equal,
431 NumberCompareResult::Greater => NumberCompareResult::Less,
432 };
433 }
434
435 non_negative_compare_result
436}
437
438impl Runtime {
439 pub(crate) fn verify_non_equational_known_then_builtin_rules_only(
443 &mut self,
444 atomic_fact: &AtomicFact,
445 verify_state: &VerifyState,
446 ) -> Result<StmtResult, RuntimeError> {
447 let r = self.verify_non_equational_atomic_fact_with_known_atomic_facts(atomic_fact)?;
448 if r.is_true() {
449 return Ok(r);
450 }
451 self.verify_non_equational_atomic_fact_with_builtin_rules(atomic_fact, verify_state)
452 }
453
454 fn verify_zero_order_on_sub_expr(
455 &mut self,
456 zero: &Obj,
457 sub_expr: &Obj,
458 weak: bool,
459 line_file: &LineFile,
460 ) -> Result<StmtResult, RuntimeError> {
461 let fact: AtomicFact = if weak {
462 LessEqualFact::new(zero.clone(), sub_expr.clone(), line_file.clone()).into()
463 } else {
464 LessFact::new(zero.clone(), sub_expr.clone(), line_file.clone()).into()
465 };
466 let mut result = self.verify_non_equational_atomic_fact_with_known_atomic_facts(&fact)?;
467 if !result.is_true() {
468 result = self.verify_order_atomic_fact_numeric_builtin_only(&fact)?;
469 }
470 Ok(result)
471 }
472
473 fn try_verify_order_nonnegative_from_membership_in_n(
475 &mut self,
476 atomic_fact: &AtomicFact,
477 verify_state: &VerifyState,
478 ) -> Result<Option<StmtResult>, RuntimeError> {
479 let (n, line_file) = match atomic_fact {
480 AtomicFact::GreaterEqualFact(f) => {
481 let Some(z) = self.resolve_obj_to_number(&f.right) else {
482 return Ok(None);
483 };
484 if !matches!(
485 compare_normalized_number_str_to_zero(&z.normalized_value),
486 NumberCompareResult::Equal
487 ) {
488 return Ok(None);
489 }
490 (f.left.clone(), f.line_file.clone())
491 }
492 AtomicFact::LessEqualFact(f) => {
493 let Some(z) = self.resolve_obj_to_number(&f.left) else {
494 return Ok(None);
495 };
496 if !matches!(
497 compare_normalized_number_str_to_zero(&z.normalized_value),
498 NumberCompareResult::Equal
499 ) {
500 return Ok(None);
501 }
502 (f.right.clone(), f.line_file.clone())
503 }
504 _ => return Ok(None),
505 };
506 let in_n: AtomicFact = InFact::new(n, StandardSet::N.into(), line_file.clone()).into();
507 if self
508 .verify_non_equational_known_then_builtin_rules_only(&in_n, verify_state)?
509 .is_true()
510 {
511 return Ok(Some(StmtResult::FactualStmtSuccess(
512 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
513 atomic_fact.clone().into(),
514 "n >= 0 from n $in N".to_string(),
515 Vec::new(),
516 ),
517 )));
518 }
519 Ok(None)
520 }
521
522 fn try_verify_order_one_le_from_membership_in_n_pos(
524 &mut self,
525 atomic_fact: &AtomicFact,
526 verify_state: &VerifyState,
527 ) -> Result<Option<StmtResult>, RuntimeError> {
528 let (n, line_file) = match atomic_fact {
529 AtomicFact::GreaterEqualFact(f) => {
530 let Some(one) = self.resolve_obj_to_number(&f.right) else {
531 return Ok(None);
532 };
533 if !matches!(
534 compare_number_strings(&one.normalized_value, "1"),
535 NumberCompareResult::Equal
536 ) {
537 return Ok(None);
538 }
539 (f.left.clone(), f.line_file.clone())
540 }
541 AtomicFact::LessEqualFact(f) => {
542 let Some(one) = self.resolve_obj_to_number(&f.left) else {
543 return Ok(None);
544 };
545 if !matches!(
546 compare_number_strings(&one.normalized_value, "1"),
547 NumberCompareResult::Equal
548 ) {
549 return Ok(None);
550 }
551 (f.right.clone(), f.line_file.clone())
552 }
553 _ => return Ok(None),
554 };
555 let in_n_pos: AtomicFact =
556 InFact::new(n, StandardSet::NPos.into(), line_file.clone()).into();
557 if self
558 .verify_non_equational_known_then_builtin_rules_only(&in_n_pos, verify_state)?
559 .is_true()
560 {
561 return Ok(Some(StmtResult::FactualStmtSuccess(
562 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
563 atomic_fact.clone().into(),
564 "n >= 1 from n $in N_pos".to_string(),
565 Vec::new(),
566 ),
567 )));
568 }
569 Ok(None)
570 }
571
572 fn try_verify_order_one_le_from_membership_in_n_and_nonzero(
575 &mut self,
576 atomic_fact: &AtomicFact,
577 verify_state: &VerifyState,
578 ) -> Result<Option<StmtResult>, RuntimeError> {
579 let (n, line_file) = match atomic_fact {
580 AtomicFact::GreaterEqualFact(f) => {
581 let Some(one) = self.resolve_obj_to_number(&f.right) else {
582 return Ok(None);
583 };
584 if !matches!(
585 compare_number_strings(&one.normalized_value, "1"),
586 NumberCompareResult::Equal
587 ) {
588 return Ok(None);
589 }
590 (f.left.clone(), f.line_file.clone())
591 }
592 AtomicFact::LessEqualFact(f) => {
593 let Some(one) = self.resolve_obj_to_number(&f.left) else {
594 return Ok(None);
595 };
596 if !matches!(
597 compare_number_strings(&one.normalized_value, "1"),
598 NumberCompareResult::Equal
599 ) {
600 return Ok(None);
601 }
602 (f.right.clone(), f.line_file.clone())
603 }
604 _ => return Ok(None),
605 };
606 let zero_obj: Obj = Number::new("0".to_string()).into();
607 let in_n: AtomicFact =
608 InFact::new(n.clone(), StandardSet::N.into(), line_file.clone()).into();
609 let nonzero: AtomicFact = NotEqualFact::new(n, zero_obj, line_file.clone()).into();
610 if !self
611 .verify_non_equational_known_then_builtin_rules_only(&in_n, verify_state)?
612 .is_true()
613 {
614 return Ok(None);
615 }
616 if !self
617 .verify_non_equational_atomic_fact_with_known_atomic_facts(&nonzero)?
618 .is_true()
619 {
620 return Ok(None);
621 }
622 Ok(Some(StmtResult::FactualStmtSuccess(
623 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
624 atomic_fact.clone().into(),
625 "1 <= n from n $in N and n != 0".to_string(),
626 Vec::new(),
627 ),
628 )))
629 }
630
631 fn try_verify_order_one_le_from_membership_in_z_and_positive(
633 &mut self,
634 atomic_fact: &AtomicFact,
635 verify_state: &VerifyState,
636 ) -> Result<Option<StmtResult>, RuntimeError> {
637 let (n, line_file) = match atomic_fact {
638 AtomicFact::GreaterEqualFact(f) => {
639 let Some(one) = self.resolve_obj_to_number(&f.right) else {
640 return Ok(None);
641 };
642 if !matches!(
643 compare_number_strings(&one.normalized_value, "1"),
644 NumberCompareResult::Equal
645 ) {
646 return Ok(None);
647 }
648 (f.left.clone(), f.line_file.clone())
649 }
650 AtomicFact::LessEqualFact(f) => {
651 let Some(one) = self.resolve_obj_to_number(&f.left) else {
652 return Ok(None);
653 };
654 if !matches!(
655 compare_number_strings(&one.normalized_value, "1"),
656 NumberCompareResult::Equal
657 ) {
658 return Ok(None);
659 }
660 (f.right.clone(), f.line_file.clone())
661 }
662 _ => return Ok(None),
663 };
664 let zero_obj: Obj = Number::new("0".to_string()).into();
665 let in_z: AtomicFact =
666 InFact::new(n.clone(), StandardSet::Z.into(), line_file.clone()).into();
667 let positive: AtomicFact = LessFact::new(zero_obj, n, line_file.clone()).into();
668 if !self
669 .verify_non_equational_known_then_builtin_rules_only(&in_z, verify_state)?
670 .is_true()
671 {
672 return Ok(None);
673 }
674 if !self
675 .verify_non_equational_known_then_builtin_rules_only(&positive, verify_state)?
676 .is_true()
677 {
678 return Ok(None);
679 }
680 Ok(Some(StmtResult::FactualStmtSuccess(
681 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
682 atomic_fact.clone().into(),
683 "1 <= n from n $in Z and 0 < n".to_string(),
684 Vec::new(),
685 ),
686 )))
687 }
688
689 fn verify_zero_le_abs_builtin_rule(
690 &mut self,
691 atomic_fact: &AtomicFact,
692 ) -> Result<Option<StmtResult>, RuntimeError> {
693 let Some(norm) = normalize_positive_order_atomic_fact(atomic_fact) else {
694 return Ok(None);
695 };
696 let AtomicFact::LessEqualFact(f) = &norm else {
697 return Ok(None);
698 };
699 if f.left.to_string() != "0" {
700 return Ok(None);
701 }
702 if !matches!(&f.right, Obj::Abs(_)) {
703 return Ok(None);
704 }
705 Ok(Some(StmtResult::FactualStmtSuccess(
706 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
707 atomic_fact.clone().into(),
708 "0 <= abs(x) for x in R".to_string(),
709 Vec::new(),
710 ),
711 )))
712 }
713
714 fn try_verify_order_opposite_sign_mul_minus_one(
717 &mut self,
718 atomic_fact: &AtomicFact,
719 verify_state: &VerifyState,
720 ) -> Result<Option<StmtResult>, RuntimeError> {
721 let z: Obj = Number::new("0".to_string()).into();
722 let success = |msg: &'static str| {
723 Ok(Some(StmtResult::FactualStmtSuccess(
724 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
725 atomic_fact.clone().into(),
726 msg.to_string(),
727 Vec::new(),
728 ),
729 )))
730 };
731 match atomic_fact {
732 AtomicFact::GreaterEqualFact(f) if self.obj_is_resolved_zero(&f.right) => {
733 if let Some(x) = self.peel_mul_by_literal_neg_one(&f.left) {
734 let le: AtomicFact =
735 LessEqualFact::new(x.clone(), z.clone(), f.line_file.clone()).into();
736 if self
737 .verify_non_equational_known_then_builtin_rules_only(&le, verify_state)?
738 .is_true()
739 {
740 return success("order: (-1)*x >= 0 from x <= 0");
741 }
742 let lt: AtomicFact = LessFact::new(x, z.clone(), f.line_file.clone()).into();
743 if self
744 .verify_non_equational_known_then_builtin_rules_only(<, verify_state)?
745 .is_true()
746 {
747 return success("order: (-1)*x >= 0 from x < 0");
748 }
749 }
750 Ok(None)
751 }
752 AtomicFact::GreaterFact(f) if self.obj_is_resolved_zero(&f.right) => {
753 if let Some(x) = self.peel_mul_by_literal_neg_one(&f.left) {
754 let lt: AtomicFact = LessFact::new(x, z.clone(), f.line_file.clone()).into();
755 if self
756 .verify_non_equational_known_then_builtin_rules_only(<, verify_state)?
757 .is_true()
758 {
759 return success("order: (-1)*x > 0 from x < 0");
760 }
761 }
762 Ok(None)
763 }
764 AtomicFact::LessEqualFact(f) if self.obj_is_resolved_zero(&f.right) => {
765 if let Some(x) = self.peel_mul_by_literal_neg_one(&f.left) {
766 let ge: AtomicFact =
767 GreaterEqualFact::new(x.clone(), z.clone(), f.line_file.clone()).into();
768 if self
769 .verify_non_equational_known_then_builtin_rules_only(&ge, verify_state)?
770 .is_true()
771 {
772 return success("order: (-1)*x <= 0 from x >= 0");
773 }
774 let gt: AtomicFact = GreaterFact::new(x, z.clone(), f.line_file.clone()).into();
775 if self
776 .verify_non_equational_known_then_builtin_rules_only(>, verify_state)?
777 .is_true()
778 {
779 return success("order: (-1)*x <= 0 from x > 0");
780 }
781 }
782 Ok(None)
783 }
784 AtomicFact::LessFact(f) if self.obj_is_resolved_zero(&f.right) => {
785 if let Some(x) = self.peel_mul_by_literal_neg_one(&f.left) {
786 let gt: AtomicFact = GreaterFact::new(x, z.clone(), f.line_file.clone()).into();
787 if self
788 .verify_non_equational_known_then_builtin_rules_only(>, verify_state)?
789 .is_true()
790 {
791 return success("order: (-1)*x < 0 from x > 0");
792 }
793 }
794 Ok(None)
795 }
796 AtomicFact::LessEqualFact(f) if self.obj_is_resolved_zero(&f.left) => {
797 if let Some(x) = self.peel_mul_by_literal_neg_one(&f.right) {
798 let le: AtomicFact =
799 LessEqualFact::new(x.clone(), z.clone(), f.line_file.clone()).into();
800 if self
801 .verify_non_equational_known_then_builtin_rules_only(&le, verify_state)?
802 .is_true()
803 {
804 return success("order: 0 <= (-1)*x from x <= 0");
805 }
806 let lt: AtomicFact = LessFact::new(x, z.clone(), f.line_file.clone()).into();
807 if self
808 .verify_non_equational_known_then_builtin_rules_only(<, verify_state)?
809 .is_true()
810 {
811 return success("order: 0 <= (-1)*x from x < 0");
812 }
813 }
814 Ok(None)
815 }
816 AtomicFact::LessFact(f) if self.obj_is_resolved_zero(&f.left) => {
817 if let Some(x) = self.peel_mul_by_literal_neg_one(&f.right) {
818 let lt: AtomicFact = LessFact::new(x, z.clone(), f.line_file.clone()).into();
819 if self
820 .verify_non_equational_known_then_builtin_rules_only(<, verify_state)?
821 .is_true()
822 {
823 return success("order: 0 < (-1)*x from x < 0");
824 }
825 }
826 Ok(None)
827 }
828 AtomicFact::GreaterEqualFact(f) if self.obj_is_resolved_zero(&f.left) => {
829 if let Some(x) = self.peel_mul_by_literal_neg_one(&f.right) {
830 let ge: AtomicFact =
831 GreaterEqualFact::new(x.clone(), z.clone(), f.line_file.clone()).into();
832 if self
833 .verify_non_equational_known_then_builtin_rules_only(&ge, verify_state)?
834 .is_true()
835 {
836 return success("order: 0 >= (-1)*x from x >= 0");
837 }
838 let gt: AtomicFact = GreaterFact::new(x, z.clone(), f.line_file.clone()).into();
839 if self
840 .verify_non_equational_known_then_builtin_rules_only(>, verify_state)?
841 .is_true()
842 {
843 return success("order: 0 >= (-1)*x from x > 0");
844 }
845 }
846 Ok(None)
847 }
848 AtomicFact::GreaterFact(f) if self.obj_is_resolved_zero(&f.left) => {
849 if let Some(x) = self.peel_mul_by_literal_neg_one(&f.right) {
850 let gt: AtomicFact = GreaterFact::new(x, z.clone(), f.line_file.clone()).into();
851 if self
852 .verify_non_equational_known_then_builtin_rules_only(>, verify_state)?
853 .is_true()
854 {
855 return success("order: 0 > (-1)*x from x > 0");
856 }
857 }
858 Ok(None)
859 }
860 _ => Ok(None),
861 }
862 }
863
864 fn verify_order_from_known_negated_complement(
866 &mut self,
867 atomic_fact: &AtomicFact,
868 ) -> Result<Option<StmtResult>, RuntimeError> {
869 let negated: Option<AtomicFact> = match atomic_fact {
870 AtomicFact::GreaterFact(f) => Some(
871 NotLessEqualFact::new(f.left.clone(), f.right.clone(), f.line_file.clone()).into(),
872 ),
873 AtomicFact::LessFact(f) => Some(
874 NotGreaterEqualFact::new(f.left.clone(), f.right.clone(), f.line_file.clone())
875 .into(),
876 ),
877 AtomicFact::GreaterEqualFact(f) => {
878 Some(NotLessFact::new(f.left.clone(), f.right.clone(), f.line_file.clone()).into())
879 }
880 AtomicFact::LessEqualFact(f) => Some(
881 NotGreaterFact::new(f.left.clone(), f.right.clone(), f.line_file.clone()).into(),
882 ),
883 _ => None,
884 };
885 let Some(neg) = negated else {
886 return Ok(None);
887 };
888 let sub = self.verify_non_equational_atomic_fact_with_known_atomic_facts(&neg)?;
889 if sub.is_true() {
890 return Ok(Some(
891 FactualStmtSuccess::new_with_verified_by_builtin_rules_label_and_steps(
892 atomic_fact.clone().into(),
893 InferResult::new(),
894 "order_from_known_negated_complement".to_string(),
895 vec![sub],
896 )
897 .into(),
898 ));
899 }
900 Ok(None)
901 }
902
903 fn verify_negated_order_from_known_equivalent_order(
905 &mut self,
906 atomic_fact: &AtomicFact,
907 ) -> Result<Option<StmtResult>, RuntimeError> {
908 let candidates: Vec<AtomicFact> = match atomic_fact {
909 AtomicFact::NotLessFact(f) => {
910 let lf = f.line_file.clone();
911 vec![
912 LessEqualFact::new(f.right.clone(), f.left.clone(), lf.clone()).into(),
913 GreaterEqualFact::new(f.left.clone(), f.right.clone(), lf).into(),
914 ]
915 }
916 AtomicFact::NotGreaterFact(f) => {
917 let lf = f.line_file.clone();
918 vec![
919 LessEqualFact::new(f.left.clone(), f.right.clone(), lf.clone()).into(),
920 GreaterEqualFact::new(f.right.clone(), f.left.clone(), lf).into(),
921 ]
922 }
923 AtomicFact::NotLessEqualFact(f) => {
924 let lf = f.line_file.clone();
925 vec![
926 LessFact::new(f.right.clone(), f.left.clone(), lf.clone()).into(),
927 GreaterFact::new(f.left.clone(), f.right.clone(), lf).into(),
928 ]
929 }
930 AtomicFact::NotGreaterEqualFact(f) => {
931 let lf = f.line_file.clone();
932 vec![
933 LessFact::new(f.left.clone(), f.right.clone(), lf.clone()).into(),
934 GreaterFact::new(f.right.clone(), f.left.clone(), lf).into(),
935 ]
936 }
937 _ => return Ok(None),
938 };
939 for candidate in candidates {
940 let sub = self.verify_non_equational_atomic_fact_with_known_atomic_facts(&candidate)?;
941 if sub.is_true() {
942 return Ok(Some(
943 FactualStmtSuccess::new_with_verified_by_builtin_rules_label_and_steps(
944 atomic_fact.clone().into(),
945 InferResult::new(),
946 "negated_order_from_known_equivalent_order".to_string(),
947 vec![sub],
948 )
949 .into(),
950 ));
951 }
952 }
953 Ok(None)
954 }
955
956 fn verify_zero_order_on_sub_from_two_sided_order_builtin_rule(
958 &mut self,
959 atomic_fact: &AtomicFact,
960 ) -> Result<Option<StmtResult>, RuntimeError> {
961 let Some(norm) = normalize_positive_order_atomic_fact(atomic_fact) else {
962 return Ok(None);
963 };
964 match &norm {
965 AtomicFact::LessEqualFact(f) if f.left.to_string() == "0" => {
966 let Obj::Sub(sub) = &f.right else {
967 return Ok(None);
968 };
969 let derived: AtomicFact = LessEqualFact::new(
970 sub.right.as_ref().clone(),
971 sub.left.as_ref().clone(),
972 f.line_file.clone(),
973 )
974 .into();
975 let mut result =
976 self.verify_non_equational_atomic_fact_with_known_atomic_facts(&derived)?;
977 if !result.is_true() {
978 result = self.verify_order_atomic_fact_numeric_builtin_only(&derived)?;
979 }
980 if result.is_true() {
981 Ok(Some(StmtResult::FactualStmtSuccess(
982 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
983 atomic_fact.clone().into(),
984 "0 <= u - v from v <= u".to_string(),
985 vec![result],
986 ),
987 )))
988 } else {
989 Ok(None)
990 }
991 }
992 AtomicFact::LessFact(f) if f.left.to_string() == "0" => {
993 let Obj::Sub(sub) = &f.right else {
994 return Ok(None);
995 };
996 let derived: AtomicFact = LessFact::new(
997 sub.right.as_ref().clone(),
998 sub.left.as_ref().clone(),
999 f.line_file.clone(),
1000 )
1001 .into();
1002 let mut result =
1003 self.verify_non_equational_atomic_fact_with_known_atomic_facts(&derived)?;
1004 if !result.is_true() {
1005 result = self.verify_order_atomic_fact_numeric_builtin_only(&derived)?;
1006 }
1007 if result.is_true() {
1008 Ok(Some(StmtResult::FactualStmtSuccess(
1009 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
1010 atomic_fact.clone().into(),
1011 "0 < u - v from v < u".to_string(),
1012 vec![result],
1013 ),
1014 )))
1015 } else {
1016 Ok(None)
1017 }
1018 }
1019 _ => Ok(None),
1020 }
1021 }
1022
1023 fn verify_zero_le_add_from_known_atomic_facts_builtin_rule(
1024 &mut self,
1025 atomic_fact: &AtomicFact,
1026 ) -> Result<Option<StmtResult>, RuntimeError> {
1027 let Some(normalized_fact) = normalize_positive_order_atomic_fact(atomic_fact) else {
1028 return Ok(None);
1029 };
1030 let AtomicFact::LessEqualFact(less_equal_fact) = normalized_fact else {
1031 return Ok(None);
1032 };
1033 if less_equal_fact.left.to_string() != "0" {
1034 return Ok(None);
1035 }
1036 let Obj::Add(add_obj) = &less_equal_fact.right else {
1037 return Ok(None);
1038 };
1039
1040 let zero = &less_equal_fact.left;
1041 let line_file = &less_equal_fact.line_file;
1042 let left_verify_result =
1043 self.verify_zero_order_on_sub_expr(zero, add_obj.left.as_ref(), true, line_file)?;
1044 if !left_verify_result.is_true() {
1045 return Ok(None);
1046 }
1047 let right_verify_result =
1048 self.verify_zero_order_on_sub_expr(zero, add_obj.right.as_ref(), true, line_file)?;
1049 if !right_verify_result.is_true() {
1050 return Ok(None);
1051 }
1052
1053 Ok(Some(StmtResult::FactualStmtSuccess(
1054 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
1055 atomic_fact.clone().into(),
1056 "0 <= a + b from known atomic facts 0 <= a and 0 <= b".to_string(),
1057 vec![left_verify_result, right_verify_result],
1058 ),
1059 )))
1060 }
1061
1062 fn verify_zero_lt_add_from_known_atomic_facts_builtin_rule(
1063 &mut self,
1064 atomic_fact: &AtomicFact,
1065 ) -> Result<Option<StmtResult>, RuntimeError> {
1066 let Some(normalized_fact) = normalize_positive_order_atomic_fact(atomic_fact) else {
1067 return Ok(None);
1068 };
1069 let AtomicFact::LessFact(less_fact) = normalized_fact else {
1070 return Ok(None);
1071 };
1072 if less_fact.left.to_string() != "0" {
1073 return Ok(None);
1074 }
1075 let Obj::Add(add_obj) = &less_fact.right else {
1076 return Ok(None);
1077 };
1078
1079 let zero = &less_fact.left;
1080 let line_file = &less_fact.line_file;
1081
1082 let strict_then_weak = |this: &mut Self| -> Result<Option<StmtResult>, RuntimeError> {
1083 let left_result =
1084 this.verify_zero_order_on_sub_expr(zero, add_obj.left.as_ref(), false, line_file)?;
1085 if !left_result.is_true() {
1086 return Ok(None);
1087 }
1088 let right_result =
1089 this.verify_zero_order_on_sub_expr(zero, add_obj.right.as_ref(), true, line_file)?;
1090 if !right_result.is_true() {
1091 return Ok(None);
1092 }
1093 Ok(Some(StmtResult::FactualStmtSuccess(
1094 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
1095 atomic_fact.clone().into(),
1096 "0 < a + b from (0 < a and 0 <= b)".to_string(),
1097 vec![left_result, right_result],
1098 ),
1099 )))
1100 };
1101 let weak_then_strict = |this: &mut Self| -> Result<Option<StmtResult>, RuntimeError> {
1102 let left_result =
1103 this.verify_zero_order_on_sub_expr(zero, add_obj.left.as_ref(), true, line_file)?;
1104 if !left_result.is_true() {
1105 return Ok(None);
1106 }
1107 let right_result =
1108 this.verify_zero_order_on_sub_expr(zero, add_obj.right.as_ref(), false, line_file)?;
1109 if !right_result.is_true() {
1110 return Ok(None);
1111 }
1112 Ok(Some(StmtResult::FactualStmtSuccess(
1113 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
1114 atomic_fact.clone().into(),
1115 "0 < a + b from (0 <= a and 0 < b)".to_string(),
1116 vec![left_result, right_result],
1117 ),
1118 )))
1119 };
1120
1121 if let Some(success) = strict_then_weak(self)? {
1122 return Ok(Some(success));
1123 }
1124 weak_then_strict(self)
1125 }
1126
1127 fn verify_zero_le_even_integer_pow_builtin_rule(
1128 &mut self,
1129 atomic_fact: &AtomicFact,
1130 ) -> Result<Option<StmtResult>, RuntimeError> {
1131 let Some(normalized_fact) = normalize_positive_order_atomic_fact(atomic_fact) else {
1132 return Ok(None);
1133 };
1134 let AtomicFact::LessEqualFact(less_equal_fact) = normalized_fact else {
1135 return Ok(None);
1136 };
1137 if less_equal_fact.left.to_string() != "0" {
1138 return Ok(None);
1139 }
1140 let right = &less_equal_fact.right;
1141 let is_equal_factors_mul = match right {
1142 Obj::Mul(mul_obj) => mul_obj.left.to_string() == mul_obj.right.to_string(),
1143 _ => false,
1144 };
1145 let is_even_pow = match right {
1146 Obj::Pow(pow_obj) => match pow_obj.exponent.as_ref() {
1147 Obj::Number(n) => normalized_decimal_string_is_even_integer(&n.normalized_value),
1148 _ => false,
1149 },
1150 _ => false,
1151 };
1152 if !is_equal_factors_mul && !is_even_pow {
1153 return Ok(None);
1154 }
1155 let msg = if is_equal_factors_mul {
1156 "0 <= a * a from even integer exponent (here 2) (forall a R)".to_string()
1157 } else {
1158 "0 <= a^n for even integer n (forall a R)".to_string()
1159 };
1160 Ok(Some(StmtResult::FactualStmtSuccess(
1161 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
1162 atomic_fact.clone().into(),
1163 msg,
1164 Vec::new(),
1165 ),
1166 )))
1167 }
1168
1169 fn verify_zero_lt_even_integer_pow_from_base_nonzero_builtin_rule(
1170 &mut self,
1171 atomic_fact: &AtomicFact,
1172 ) -> Result<Option<StmtResult>, RuntimeError> {
1173 let Some(normalized_fact) = normalize_positive_order_atomic_fact(atomic_fact) else {
1174 return Ok(None);
1175 };
1176 let AtomicFact::LessFact(less_fact) = normalized_fact else {
1177 return Ok(None);
1178 };
1179 if less_fact.left.to_string() != "0" {
1180 return Ok(None);
1181 }
1182 let Obj::Pow(pow_obj) = &less_fact.right else {
1183 return Ok(None);
1184 };
1185 let Obj::Number(exp_num) = pow_obj.exponent.as_ref() else {
1186 return Ok(None);
1187 };
1188 if !normalized_decimal_string_is_even_integer(&exp_num.normalized_value) {
1189 return Ok(None);
1190 }
1191
1192 let line_file = less_fact.line_file.clone();
1193 let base = pow_obj.base.as_ref().clone();
1194 let zero_obj: Obj = Number::new("0".to_string()).into();
1195 let base_neq_zero: AtomicFact = NotEqualFact::new(base, zero_obj, line_file.clone()).into();
1196
1197 let neq_result = self.verify_non_equational_known_then_builtin_rules_only(
1198 &base_neq_zero,
1199 &VerifyState::new(0, true),
1200 )?;
1201 if !neq_result.is_true() {
1202 return Ok(None);
1203 }
1204
1205 Ok(Some(StmtResult::FactualStmtSuccess(
1206 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
1207 atomic_fact.clone().into(),
1208 "0 < a^n for even integer n from a != 0".to_string(),
1209 vec![neq_result],
1210 ),
1211 )))
1212 }
1213
1214 fn verify_zero_lt_pow_from_positive_base_real_exp_builtin_rule(
1216 &mut self,
1217 atomic_fact: &AtomicFact,
1218 ) -> Result<Option<StmtResult>, RuntimeError> {
1219 let Some(normalized_fact) = normalize_positive_order_atomic_fact(atomic_fact) else {
1220 return Ok(None);
1221 };
1222 let AtomicFact::LessFact(less_fact) = normalized_fact else {
1223 return Ok(None);
1224 };
1225 if less_fact.left.to_string() != "0" {
1226 return Ok(None);
1227 }
1228 let Obj::Pow(pow_obj) = &less_fact.right else {
1229 return Ok(None);
1230 };
1231 let zero = &less_fact.left;
1232 let line_file = &less_fact.line_file;
1233 let base = pow_obj.base.as_ref();
1234 let base_result = self.verify_zero_order_on_sub_expr(zero, base, false, line_file)?;
1235 if !base_result.is_true() {
1236 return Ok(None);
1237 }
1238 let in_r: AtomicFact = InFact::new(
1239 (*pow_obj.exponent).clone(),
1240 StandardSet::R.into(),
1241 line_file.clone(),
1242 )
1243 .into();
1244 let in_r_result = self.verify_non_equational_known_then_builtin_rules_only(
1245 &in_r,
1246 &VerifyState::new(0, true),
1247 )?;
1248 if !in_r_result.is_true() {
1249 return Ok(None);
1250 }
1251 Ok(Some(StmtResult::FactualStmtSuccess(
1252 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
1253 atomic_fact.clone().into(),
1254 "0 < a^b from 0 < a and b in R".to_string(),
1255 vec![base_result, in_r_result],
1256 ),
1257 )))
1258 }
1259
1260 fn verify_zero_le_pow_from_positive_base_real_exp_builtin_rule(
1263 &mut self,
1264 atomic_fact: &AtomicFact,
1265 ) -> Result<Option<StmtResult>, RuntimeError> {
1266 let Some(normalized_fact) = normalize_positive_order_atomic_fact(atomic_fact) else {
1267 return Ok(None);
1268 };
1269 let AtomicFact::LessEqualFact(less_equal_fact) = normalized_fact else {
1270 return Ok(None);
1271 };
1272 if less_equal_fact.left.to_string() != "0" {
1273 return Ok(None);
1274 }
1275 let Obj::Pow(pow_obj) = &less_equal_fact.right else {
1276 return Ok(None);
1277 };
1278 let zero = &less_equal_fact.left;
1279 let line_file = &less_equal_fact.line_file;
1280 let base = pow_obj.base.as_ref();
1281 let base_result = self.verify_zero_order_on_sub_expr(zero, base, false, line_file)?;
1282 if !base_result.is_true() {
1283 return Ok(None);
1284 }
1285 let in_r: AtomicFact = InFact::new(
1286 (*pow_obj.exponent).clone(),
1287 StandardSet::R.into(),
1288 line_file.clone(),
1289 )
1290 .into();
1291 let in_r_result = self.verify_non_equational_known_then_builtin_rules_only(
1292 &in_r,
1293 &VerifyState::new(0, true),
1294 )?;
1295 if !in_r_result.is_true() {
1296 return Ok(None);
1297 }
1298 Ok(Some(StmtResult::FactualStmtSuccess(
1299 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
1300 atomic_fact.clone().into(),
1301 "0 <= a^b from 0 < a and b in R".to_string(),
1302 vec![base_result, in_r_result],
1303 ),
1304 )))
1305 }
1306
1307 fn verify_zero_le_pow_integer_exponent_from_nonneg_base_builtin_rule(
1308 &mut self,
1309 atomic_fact: &AtomicFact,
1310 ) -> Result<Option<StmtResult>, RuntimeError> {
1311 let Some(normalized_fact) = normalize_positive_order_atomic_fact(atomic_fact) else {
1312 return Ok(None);
1313 };
1314 let AtomicFact::LessEqualFact(less_equal_fact) = normalized_fact else {
1315 return Ok(None);
1316 };
1317 if less_equal_fact.left.to_string() != "0" {
1318 return Ok(None);
1319 }
1320 let Obj::Pow(pow_obj) = &less_equal_fact.right else {
1321 return Ok(None);
1322 };
1323 let Obj::Number(exp_num) = pow_obj.exponent.as_ref() else {
1324 return Ok(None);
1325 };
1326 if !normalized_decimal_string_is_integer(&exp_num.normalized_value) {
1327 return Ok(None);
1328 }
1329
1330 let zero = &less_equal_fact.left;
1331 let line_file = &less_equal_fact.line_file;
1332 let base = pow_obj.base.as_ref();
1333
1334 let exponent_vs_zero = compare_normalized_number_str_to_zero(&exp_num.normalized_value);
1335 let base_result = match exponent_vs_zero {
1336 NumberCompareResult::Less => {
1337 self.verify_zero_order_on_sub_expr(zero, base, false, line_file)?
1338 }
1339 NumberCompareResult::Equal | NumberCompareResult::Greater => {
1340 self.verify_zero_order_on_sub_expr(zero, base, true, line_file)?
1341 }
1342 };
1343 if !base_result.is_true() {
1344 return Ok(None);
1345 }
1346
1347 let msg = match exponent_vs_zero {
1348 NumberCompareResult::Less => "0 <= a^n from 0 < a and integer n < 0".to_string(),
1349 _ => "0 <= a^n from 0 <= a and integer n".to_string(),
1350 };
1351
1352 Ok(Some(StmtResult::FactualStmtSuccess(
1353 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
1354 atomic_fact.clone().into(),
1355 msg,
1356 vec![base_result],
1357 ),
1358 )))
1359 }
1360
1361 fn verify_zero_le_mul_from_known_atomic_facts_builtin_rule(
1362 &mut self,
1363 atomic_fact: &AtomicFact,
1364 ) -> Result<Option<StmtResult>, RuntimeError> {
1365 let Some(normalized_fact) = normalize_positive_order_atomic_fact(atomic_fact) else {
1366 return Ok(None);
1367 };
1368 let AtomicFact::LessEqualFact(less_equal_fact) = normalized_fact else {
1369 return Ok(None);
1370 };
1371 if less_equal_fact.left.to_string() != "0" {
1372 return Ok(None);
1373 }
1374 let Obj::Mul(mul_obj) = &less_equal_fact.right else {
1375 return Ok(None);
1376 };
1377
1378 let zero = &less_equal_fact.left;
1379 let line_file = &less_equal_fact.line_file;
1380 let left_verify_result =
1381 self.verify_zero_order_on_sub_expr(zero, mul_obj.left.as_ref(), true, line_file)?;
1382 if !left_verify_result.is_true() {
1383 return Ok(None);
1384 }
1385 let right_verify_result =
1386 self.verify_zero_order_on_sub_expr(zero, mul_obj.right.as_ref(), true, line_file)?;
1387 if !right_verify_result.is_true() {
1388 return Ok(None);
1389 }
1390
1391 Ok(Some(StmtResult::FactualStmtSuccess(
1392 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
1393 atomic_fact.clone().into(),
1394 "0 <= a * b from 0 <= a and 0 <= b".to_string(),
1395 vec![left_verify_result, right_verify_result],
1396 ),
1397 )))
1398 }
1399
1400 fn verify_zero_lt_mul_from_known_atomic_facts_builtin_rule(
1401 &mut self,
1402 atomic_fact: &AtomicFact,
1403 ) -> Result<Option<StmtResult>, RuntimeError> {
1404 let Some(normalized_fact) = normalize_positive_order_atomic_fact(atomic_fact) else {
1405 return Ok(None);
1406 };
1407 let AtomicFact::LessFact(less_fact) = normalized_fact else {
1408 return Ok(None);
1409 };
1410 if less_fact.left.to_string() != "0" {
1411 return Ok(None);
1412 }
1413 let Obj::Mul(mul_obj) = &less_fact.right else {
1414 return Ok(None);
1415 };
1416
1417 let zero = &less_fact.left;
1418 let line_file = &less_fact.line_file;
1419 let left_verify_result =
1420 self.verify_zero_order_on_sub_expr(zero, mul_obj.left.as_ref(), false, line_file)?;
1421 if !left_verify_result.is_true() {
1422 return Ok(None);
1423 }
1424 let right_verify_result =
1425 self.verify_zero_order_on_sub_expr(zero, mul_obj.right.as_ref(), false, line_file)?;
1426 if !right_verify_result.is_true() {
1427 return Ok(None);
1428 }
1429
1430 Ok(Some(StmtResult::FactualStmtSuccess(
1431 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
1432 atomic_fact.clone().into(),
1433 "0 < a * b from 0 < a and 0 < b".to_string(),
1434 vec![left_verify_result, right_verify_result],
1435 ),
1436 )))
1437 }
1438
1439 fn verify_zero_le_div_from_known_atomic_facts_builtin_rule(
1440 &mut self,
1441 atomic_fact: &AtomicFact,
1442 ) -> Result<Option<StmtResult>, RuntimeError> {
1443 let Some(normalized_fact) = normalize_positive_order_atomic_fact(atomic_fact) else {
1444 return Ok(None);
1445 };
1446 let AtomicFact::LessEqualFact(less_equal_fact) = normalized_fact else {
1447 return Ok(None);
1448 };
1449 if less_equal_fact.left.to_string() != "0" {
1450 return Ok(None);
1451 }
1452 let Obj::Div(div_obj) = &less_equal_fact.right else {
1453 return Ok(None);
1454 };
1455
1456 let zero = &less_equal_fact.left;
1457 let line_file = &less_equal_fact.line_file;
1458 let numer_result =
1459 self.verify_zero_order_on_sub_expr(zero, div_obj.left.as_ref(), true, line_file)?;
1460 if !numer_result.is_true() {
1461 return Ok(None);
1462 }
1463 let denom_result =
1464 self.verify_zero_order_on_sub_expr(zero, div_obj.right.as_ref(), false, line_file)?;
1465 if !denom_result.is_true() {
1466 return Ok(None);
1467 }
1468
1469 Ok(Some(StmtResult::FactualStmtSuccess(
1470 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
1471 atomic_fact.clone().into(),
1472 "0 <= a / b from 0 <= a and 0 < b".to_string(),
1473 vec![numer_result, denom_result],
1474 ),
1475 )))
1476 }
1477
1478 fn verify_zero_lt_div_from_known_atomic_facts_builtin_rule(
1479 &mut self,
1480 atomic_fact: &AtomicFact,
1481 ) -> Result<Option<StmtResult>, RuntimeError> {
1482 let Some(normalized_fact) = normalize_positive_order_atomic_fact(atomic_fact) else {
1483 return Ok(None);
1484 };
1485 let AtomicFact::LessFact(less_fact) = normalized_fact else {
1486 return Ok(None);
1487 };
1488 if less_fact.left.to_string() != "0" {
1489 return Ok(None);
1490 }
1491 let Obj::Div(div_obj) = &less_fact.right else {
1492 return Ok(None);
1493 };
1494
1495 let zero = &less_fact.left;
1496 let line_file = &less_fact.line_file;
1497 let numer_result =
1498 self.verify_zero_order_on_sub_expr(zero, div_obj.left.as_ref(), false, line_file)?;
1499 if !numer_result.is_true() {
1500 return Ok(None);
1501 }
1502 let denom_result =
1503 self.verify_zero_order_on_sub_expr(zero, div_obj.right.as_ref(), false, line_file)?;
1504 if !denom_result.is_true() {
1505 return Ok(None);
1506 }
1507
1508 Ok(Some(StmtResult::FactualStmtSuccess(
1509 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
1510 atomic_fact.clone().into(),
1511 "0 < a / b from 0 < a and 0 < b".to_string(),
1512 vec![numer_result, denom_result],
1513 ),
1514 )))
1515 }
1516
1517 fn calculate_obj_pair_to_number_strings(
1518 &self,
1519 left_obj: &Obj,
1520 right_obj: &Obj,
1521 ) -> Option<(String, String)> {
1522 let left_number = self.resolve_obj_to_number_resolved(left_obj)?;
1523 let right_number = self.resolve_obj_to_number_resolved(right_obj)?;
1524 Some((left_number.normalized_value, right_number.normalized_value))
1525 }
1526}