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