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