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