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