1use crate::prelude::*;
2use crate::verify::verify_number_in_standard_set::is_integer_after_simplification;
3
4impl Runtime {
5 pub fn _verify_not_equal_fact_with_builtin_rules(
6 &mut self,
7 not_equal_fact: &NotEqualFact,
8 verify_state: &VerifyState,
9 ) -> Result<StmtResult, RuntimeError> {
10 let left_obj = ¬_equal_fact.left;
11 let right_obj = ¬_equal_fact.right;
12
13 match (
14 self.resolve_obj_to_number_for_not_equal_builtin_rule(left_obj),
15 self.resolve_obj_to_number_for_not_equal_builtin_rule(right_obj),
16 ) {
17 (Some(left_number), Some(right_number)) => {
18 if left_number.normalized_value != right_number.normalized_value {
19 return Ok(
20 (FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
21 not_equal_fact.clone().into(),
22 "not_equal_numeric_resolved_or_equal_class_calculation".to_string(),
23 Vec::new(),
24 ))
25 .into(),
26 );
27 }
28 }
29 _ => {}
30 }
31
32 if let (Obj::ListSet(left_ls), Obj::ListSet(right_ls)) = (left_obj, right_obj) {
33 if left_ls.list.len() != right_ls.list.len() {
34 return Ok(
35 (FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
36 not_equal_fact.clone().into(),
37 "list_set_different_length".to_string(),
38 Vec::new(),
39 ))
40 .into(),
41 );
42 }
43 }
44
45 if let Some(verified_result) =
46 self.try_verify_not_equal_from_known_strict_order(not_equal_fact)?
47 {
48 return Ok(verified_result);
49 }
50
51 if let Some(verified_result) =
52 self.try_verify_not_equal_zero_from_n_and_one_le(not_equal_fact, verify_state)?
53 {
54 return Ok(verified_result);
55 }
56
57 if let Some(verified_result) =
58 self.try_verify_not_equal_pow_from_base_nonzero(not_equal_fact, verify_state)?
59 {
60 return Ok(verified_result);
61 }
62
63 if let Some(verified_result) = self
64 .try_verify_square_sum_not_equal_zero_from_nonzero_component(
65 not_equal_fact,
66 verify_state,
67 )?
68 {
69 return Ok(verified_result);
70 }
71
72 match self
73 .try_verify_not_equal_fact_when_zero_and_binary_arithmetic_reduces_by_operand_facts(
74 not_equal_fact,
75 verify_state,
76 )? {
77 Some(verified_result) => return Ok(verified_result),
78 None => {}
79 }
80
81 Ok((StmtUnknown::new()).into())
82 }
83}
84
85impl Runtime {
86 fn try_parse_number_literal_obj_string_for_not_equal_builtin_rule(
87 &self,
88 obj_string: &str,
89 ) -> Option<Number> {
90 let trimmed = obj_string.trim();
91 if trimmed.is_empty() {
92 return None;
93 }
94 let parsed = Number::new(trimmed.to_string());
95 if parsed.to_string() == trimmed {
96 return Some(parsed);
97 }
98 None
99 }
100
101 fn resolve_obj_to_number_for_not_equal_builtin_rule(&self, obj: &Obj) -> Option<Number> {
102 if let Some(number) = self.resolve_obj_to_number_resolved(obj) {
103 return Some(number);
104 }
105 let obj_key = obj.to_string();
106 if let Some(number) = self.get_object_equal_to_normalized_decimal_number(&obj_key) {
107 return Some(number);
108 }
109 let all_equal_obj_strings = self.get_all_objs_equal_to_given(&obj_key);
110 for equal_obj_string in all_equal_obj_strings {
111 if let Some(number) =
112 self.get_object_equal_to_normalized_decimal_number(&equal_obj_string)
113 {
114 return Some(number);
115 }
116 if let Some(number) = self
117 .try_parse_number_literal_obj_string_for_not_equal_builtin_rule(&equal_obj_string)
118 {
119 return Some(number);
120 }
121 }
122 None
123 }
124
125 fn try_verify_not_equal_from_known_strict_order(
127 &mut self,
128 not_equal_fact: &NotEqualFact,
129 ) -> Result<Option<StmtResult>, RuntimeError> {
130 let line_file = not_equal_fact.line_file.clone();
131 let x = not_equal_fact.left.clone();
132 let y = not_equal_fact.right.clone();
133 let candidates: [AtomicFact; 4] = [
134 LessFact::new(x.clone(), y.clone(), line_file.clone()).into(),
135 GreaterFact::new(x.clone(), y.clone(), line_file.clone()).into(),
136 LessFact::new(y.clone(), x.clone(), line_file.clone()).into(),
137 GreaterFact::new(y.clone(), x.clone(), line_file.clone()).into(),
138 ];
139 for order_atomic in candidates {
140 let sub =
141 self.verify_non_equational_atomic_fact_with_known_atomic_facts(&order_atomic)?;
142 if sub.is_true() {
143 return Ok(Some(
144 FactualStmtSuccess::new_with_verified_by_builtin_rules_label_and_steps(
145 not_equal_fact.clone().into(),
146 InferResult::new(),
147 "not_equal_from_known_strict_order".to_string(),
148 vec![sub],
149 )
150 .into(),
151 ));
152 }
153 }
154 Ok(None)
155 }
156
157 fn try_verify_not_equal_zero_from_n_and_one_le(
159 &mut self,
160 not_equal_fact: &NotEqualFact,
161 verify_state: &VerifyState,
162 ) -> Result<Option<StmtResult>, RuntimeError> {
163 let line_file = not_equal_fact.line_file.clone();
164 let one_obj: Obj = Number::new("1".to_string()).into();
165 let x = match (¬_equal_fact.left, ¬_equal_fact.right) {
166 (l, r) if self.obj_represents_zero_for_not_equal_builtin_rules(r) => l.clone(),
167 (l, r) if self.obj_represents_zero_for_not_equal_builtin_rules(l) => r.clone(),
168 _ => return Ok(None),
169 };
170 let in_n: AtomicFact =
171 InFact::new(x.clone(), StandardSet::N.into(), line_file.clone()).into();
172 if !self
173 .verify_non_equational_known_then_builtin_rules_only(&in_n, verify_state)?
174 .is_true()
175 {
176 return Ok(None);
177 }
178 let ge: AtomicFact =
179 GreaterEqualFact::new(x.clone(), one_obj.clone(), line_file.clone()).into();
180 if self
181 .verify_non_equational_atomic_fact_with_known_atomic_facts(&ge)?
182 .is_true()
183 {
184 return Ok(Some(
185 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
186 not_equal_fact.clone().into(),
187 "n != 0 from n $in N and 1 <= n".to_string(),
188 Vec::new(),
189 )
190 .into(),
191 ));
192 }
193 let one_le: AtomicFact = LessEqualFact::new(one_obj, x, line_file.clone()).into();
194 if self
195 .verify_non_equational_atomic_fact_with_known_atomic_facts(&one_le)?
196 .is_true()
197 {
198 return Ok(Some(
199 FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
200 not_equal_fact.clone().into(),
201 "n != 0 from n $in N and 1 <= n".to_string(),
202 Vec::new(),
203 )
204 .into(),
205 ));
206 }
207 Ok(None)
208 }
209
210 fn try_verify_not_equal_pow_from_base_nonzero(
212 &mut self,
213 not_equal_fact: &NotEqualFact,
214 verify_state: &VerifyState,
215 ) -> Result<Option<StmtResult>, RuntimeError> {
216 let line_file = not_equal_fact.line_file.clone();
217 let zero_obj: Obj = Number::new("0".to_string()).into();
218 let pow = match (¬_equal_fact.left, ¬_equal_fact.right) {
219 (Obj::Pow(p), r) if self.obj_represents_zero_for_not_equal_builtin_rules(r) => p,
220 (l, Obj::Pow(p)) if self.obj_represents_zero_for_not_equal_builtin_rules(l) => p,
221 _ => return Ok(None),
222 };
223 let Obj::Number(exp_num) = pow.exponent.as_ref() else {
224 return Ok(None);
225 };
226 if !is_integer_after_simplification(exp_num) {
227 return Ok(None);
228 }
229
230 let base = pow.base.as_ref().clone();
231 let base_neq_zero: AtomicFact = NotEqualFact::new(base, zero_obj, line_file.clone()).into();
232 let mut result =
233 self.verify_non_equational_atomic_fact_with_known_atomic_facts(&base_neq_zero)?;
234 if !result.is_true() {
235 result = self.verify_non_equational_atomic_fact(&base_neq_zero, verify_state, true)?;
236 }
237 if result.is_true() {
238 return Ok(Some(
239 FactualStmtSuccess::new_with_verified_by_builtin_rules_label_and_steps(
240 not_equal_fact.clone().into(),
241 InferResult::new(),
242 "not_equal_pow_from_base_nonzero".to_string(),
243 vec![result],
244 )
245 .into(),
246 ));
247 }
248 Ok(None)
249 }
250
251 fn try_verify_square_sum_not_equal_zero_from_nonzero_component(
256 &mut self,
257 not_equal_fact: &NotEqualFact,
258 verify_state: &VerifyState,
259 ) -> Result<Option<StmtResult>, RuntimeError> {
260 let line_file = not_equal_fact.line_file.clone();
261 let expression_obj =
262 if self.obj_represents_zero_for_not_equal_builtin_rules(¬_equal_fact.right) {
263 ¬_equal_fact.left
264 } else if self.obj_represents_zero_for_not_equal_builtin_rules(¬_equal_fact.left) {
265 ¬_equal_fact.right
266 } else {
267 return Ok(None);
268 };
269
270 let Some((left_base, right_base)) =
271 self.square_sum_bases_for_not_equal_zero(expression_obj)
272 else {
273 return Ok(None);
274 };
275
276 let zero_obj: Obj = Number::new("0".to_string()).into();
277 let left_nonzero: AtomicFact =
278 NotEqualFact::new(left_base.clone(), zero_obj.clone(), line_file.clone()).into();
279 let right_nonzero: AtomicFact =
280 NotEqualFact::new(right_base.clone(), zero_obj, line_file.clone()).into();
281 let known_or = OrFact::new(
282 vec![
283 AndChainAtomicFact::AtomicFact(left_nonzero.clone()),
284 AndChainAtomicFact::AtomicFact(right_nonzero.clone()),
285 ],
286 line_file.clone(),
287 );
288
289 let mut steps = Vec::new();
290 let known_or_result = self.verify_or_fact(&known_or, verify_state)?;
291 if known_or_result.is_true() {
292 steps.push(known_or_result);
293 return Ok(Some(
294 FactualStmtSuccess::new_with_verified_by_builtin_rules_label_and_steps(
295 not_equal_fact.clone().into(),
296 InferResult::new(),
297 "square_sum_not_equal_zero_from_nonzero_component_or".to_string(),
298 steps,
299 )
300 .into(),
301 ));
302 }
303
304 let left_result =
305 self.verify_non_equational_atomic_fact(&left_nonzero, verify_state, true)?;
306 if left_result.is_true() {
307 steps.push(left_result);
308 return Ok(Some(
309 FactualStmtSuccess::new_with_verified_by_builtin_rules_label_and_steps(
310 not_equal_fact.clone().into(),
311 InferResult::new(),
312 "square_sum_not_equal_zero_from_left_nonzero".to_string(),
313 steps,
314 )
315 .into(),
316 ));
317 }
318
319 let right_result =
320 self.verify_non_equational_atomic_fact(&right_nonzero, verify_state, true)?;
321 if right_result.is_true() {
322 steps.push(right_result);
323 return Ok(Some(
324 FactualStmtSuccess::new_with_verified_by_builtin_rules_label_and_steps(
325 not_equal_fact.clone().into(),
326 InferResult::new(),
327 "square_sum_not_equal_zero_from_right_nonzero".to_string(),
328 steps,
329 )
330 .into(),
331 ));
332 }
333
334 Ok(None)
335 }
336
337 fn square_sum_bases_for_not_equal_zero(&self, obj: &Obj) -> Option<(Obj, Obj)> {
338 let Obj::Add(add) = obj else {
339 return None;
340 };
341 let left_base = self.square_base_for_not_equal_zero(add.left.as_ref())?;
342 let right_base = self.square_base_for_not_equal_zero(add.right.as_ref())?;
343 Some((left_base, right_base))
344 }
345
346 fn square_base_for_not_equal_zero(&self, obj: &Obj) -> Option<Obj> {
347 match obj {
348 Obj::Pow(pow) => {
349 let Obj::Number(exp_number) = pow.exponent.as_ref() else {
350 return None;
351 };
352 if exp_number.to_string() == "2" {
353 Some(pow.base.as_ref().clone())
354 } else {
355 None
356 }
357 }
358 Obj::Mul(mul) if mul.left.as_ref().to_string() == mul.right.as_ref().to_string() => {
359 Some(mul.left.as_ref().clone())
360 }
361 _ => None,
362 }
363 }
364
365 fn obj_represents_zero_for_not_equal_builtin_rules(self: &Self, obj: &Obj) -> bool {
366 match self.resolve_obj_to_number(obj) {
367 Some(number) => number.normalized_value == "0",
368 None => false,
369 }
370 }
371
372 fn operand_is_not_equal_to_zero_by_known_non_equational_facts(
373 &mut self,
374 operand: &Obj,
375 line_file: LineFile,
376 ) -> Result<bool, RuntimeError> {
377 let zero_obj: Obj = Number::new("0".to_string()).into();
378 let operand_not_equal_zero_fact =
379 NotEqualFact::new(operand.clone(), zero_obj, line_file).into();
380 let verify_result = self.verify_non_equational_atomic_fact_with_known_atomic_facts(
381 &operand_not_equal_zero_fact,
382 )?;
383 Ok(verify_result.is_true())
384 }
385
386 fn both_operands_nonzero_by_known_non_equational_facts(
387 &mut self,
388 left_operand: &Obj,
389 right_operand: &Obj,
390 line_file: LineFile,
391 ) -> Result<bool, RuntimeError> {
392 let left_nonzero = self.operand_is_not_equal_to_zero_by_known_non_equational_facts(
393 left_operand,
394 line_file.clone(),
395 )?;
396 if !left_nonzero {
397 return Ok(false);
398 }
399 self.operand_is_not_equal_to_zero_by_known_non_equational_facts(right_operand, line_file)
400 }
401
402 fn both_operands_strictly_positive_by_non_equational_verify(
403 &mut self,
404 left_operand: &Obj,
405 right_operand: &Obj,
406 line_file: LineFile,
407 verify_state: &VerifyState,
408 ) -> Result<bool, RuntimeError> {
409 let zero_obj: Obj = Number::new("0".to_string()).into();
410 let zero_less_than_left =
411 LessFact::new(zero_obj.clone(), left_operand.clone(), line_file.clone()).into();
412 if !self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
413 &zero_less_than_left,
414 verify_state,
415 )? {
416 return Ok(false);
417 }
418 let zero_less_than_right = LessFact::new(zero_obj, right_operand.clone(), line_file).into();
419 self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
420 &zero_less_than_right,
421 verify_state,
422 )
423 }
424
425 fn both_operands_strictly_negative_by_non_equational_verify(
426 &mut self,
427 left_operand: &Obj,
428 right_operand: &Obj,
429 line_file: LineFile,
430 verify_state: &VerifyState,
431 ) -> Result<bool, RuntimeError> {
432 let zero_obj: Obj = Number::new("0".to_string()).into();
433 let left_less_than_zero =
434 LessFact::new(left_operand.clone(), zero_obj.clone(), line_file.clone()).into();
435 if !self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
436 &left_less_than_zero,
437 verify_state,
438 )? {
439 return Ok(false);
440 }
441 let right_less_than_zero = LessFact::new(right_operand.clone(), zero_obj, line_file).into();
442 self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
443 &right_less_than_zero,
444 verify_state,
445 )
446 }
447
448 pub fn mul_product_negative_when_factors_have_strict_opposite_sign_by_non_equational_verify(
449 &mut self,
450 left_factor: &Obj,
451 right_factor: &Obj,
452 line_file: LineFile,
453 verify_state: &VerifyState,
454 ) -> Result<bool, RuntimeError> {
455 let zero_obj: Obj = Number::new("0".to_string()).into();
456 let left_less_than_zero =
457 LessFact::new(left_factor.clone(), zero_obj.clone(), line_file.clone()).into();
458 let zero_less_than_right =
459 LessFact::new(zero_obj.clone(), right_factor.clone(), line_file.clone()).into();
460 if self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
461 &left_less_than_zero,
462 verify_state,
463 )? && self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
464 &zero_less_than_right,
465 verify_state,
466 )? {
467 return Ok(true);
468 }
469 let zero_less_than_left =
470 LessFact::new(zero_obj.clone(), left_factor.clone(), line_file.clone()).into();
471 let right_less_than_zero = LessFact::new(right_factor.clone(), zero_obj, line_file).into();
472 Ok(
473 self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
474 &zero_less_than_left,
475 verify_state,
476 )? && self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
477 &right_less_than_zero,
478 verify_state,
479 )?,
480 )
481 }
482
483 fn sub_difference_nonzero_when_operands_have_strict_opposite_sign_by_non_equational_verify(
484 &mut self,
485 minuend: &Obj,
486 subtrahend: &Obj,
487 line_file: LineFile,
488 verify_state: &VerifyState,
489 ) -> Result<bool, RuntimeError> {
490 let zero_obj: Obj = Number::new("0".to_string()).into();
491 let zero_less_than_minuend =
492 LessFact::new(zero_obj.clone(), minuend.clone(), line_file.clone()).into();
493 let subtrahend_less_than_zero =
494 LessFact::new(subtrahend.clone(), zero_obj.clone(), line_file.clone()).into();
495 if self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
496 &zero_less_than_minuend,
497 verify_state,
498 )? && self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
499 &subtrahend_less_than_zero,
500 verify_state,
501 )? {
502 return Ok(true);
503 }
504 let minuend_less_than_zero =
505 LessFact::new(minuend.clone(), zero_obj.clone(), line_file.clone()).into();
506 let zero_less_than_subtrahend =
507 LessFact::new(zero_obj, subtrahend.clone(), line_file).into();
508 Ok(
509 self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
510 &minuend_less_than_zero,
511 verify_state,
512 )? && self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
513 &zero_less_than_subtrahend,
514 verify_state,
515 )?,
516 )
517 }
518
519 fn try_verify_not_equal_fact_when_zero_and_binary_arithmetic_reduces_by_operand_facts(
520 &mut self,
521 not_equal_fact: &NotEqualFact,
522 verify_state: &VerifyState,
523 ) -> Result<Option<StmtResult>, RuntimeError> {
524 let line_file = not_equal_fact.line_file.clone();
525 let expression_obj =
526 if self.obj_represents_zero_for_not_equal_builtin_rules(¬_equal_fact.right) {
527 ¬_equal_fact.left
528 } else if self.obj_represents_zero_for_not_equal_builtin_rules(¬_equal_fact.left) {
529 ¬_equal_fact.right
530 } else {
531 return Ok(None);
532 };
533
534 let builtin_rule_label = match expression_obj {
535 Obj::Add(add) => {
536 if self.both_operands_strictly_positive_by_non_equational_verify(
537 &add.left,
538 &add.right,
539 line_file.clone(),
540 verify_state,
541 )? {
542 Some("add_not_equal_zero_both_operands_strictly_positive")
543 } else if self.both_operands_strictly_negative_by_non_equational_verify(
544 &add.left,
545 &add.right,
546 line_file.clone(),
547 verify_state,
548 )? {
549 Some("add_not_equal_zero_both_operands_strictly_negative")
550 } else {
551 None
552 }
553 }
554 Obj::Mul(mul) => {
555 if self.both_operands_nonzero_by_known_non_equational_facts(
556 &mul.left,
557 &mul.right,
558 line_file.clone(),
559 )? {
560 Some("mul_not_equal_zero_both_factors_nonzero_by_known_facts")
561 } else if self.both_operands_strictly_positive_by_non_equational_verify(
562 &mul.left,
563 &mul.right,
564 line_file.clone(),
565 verify_state,
566 )? {
567 Some("mul_not_equal_zero_both_factors_strictly_positive")
568 } else if self.both_operands_strictly_negative_by_non_equational_verify(
569 &mul.left,
570 &mul.right,
571 line_file.clone(),
572 verify_state,
573 )? {
574 Some("mul_not_equal_zero_both_factors_strictly_negative")
575 } else {
576 None
577 }
578 }
579 Obj::Sub(sub) => {
580 if self.sub_difference_nonzero_when_operands_have_strict_opposite_sign_by_non_equational_verify(
581 &sub.left,
582 &sub.right,
583 line_file,
584 verify_state,
585 )? {
586 Some("sub_not_equal_zero_operands_strict_opposite_sign")
587 } else {
588 None
589 }
590 }
591 other => {
592 let zero_obj: Obj = Number::new("0".to_string()).into();
593 let zero_lt_a = LessFact::new(
594 zero_obj.clone(),
595 other.clone(),
596 line_file.clone(),
597 ).into();
598
599 let final_round_verify_state = verify_state.make_final_round_state();
600
601 if self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
602 &zero_lt_a,
603 &final_round_verify_state,
604 )? {
605 Some("not_equal_zero_operand_strictly_positive")
606 } else {
607 let a_lt_0 = LessFact::new(
608 other.clone(),
609 zero_obj,
610 line_file.clone(),
611 ).into();
612 if self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
613 &a_lt_0,
614 &final_round_verify_state,
615 )? {
616 Some("not_equal_zero_operand_strictly_negative")
617 } else {
618 None
619 }
620 }
621 }
622 };
623
624 match builtin_rule_label {
625 Some(rule_label) => Ok(Some(
626 (FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
627 not_equal_fact.clone().into(),
628 rule_label.to_string(),
629 Vec::new(),
630 ))
631 .into(),
632 )),
633 None => Ok(None),
634 }
635 }
636}