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