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_pow_from_base_nonzero(not_equal_fact, verify_state)?
92 {
93 return Ok(verified_result);
94 }
95
96 match self
97 .try_verify_not_equal_fact_when_zero_and_binary_arithmetic_reduces_by_operand_facts(
98 not_equal_fact,
99 verify_state,
100 )? {
101 Some(verified_result) => return Ok(verified_result),
102 None => {}
103 }
104
105 Ok((StmtUnknown::new()).into())
106 }
107
108 fn try_verify_not_equal_from_known_strict_order(
110 &mut self,
111 not_equal_fact: &NotEqualFact,
112 ) -> Result<Option<StmtResult>, RuntimeError> {
113 let line_file = not_equal_fact.line_file.clone();
114 let x = not_equal_fact.left.clone();
115 let y = not_equal_fact.right.clone();
116 let candidates: [AtomicFact; 4] = [
117 LessFact::new(x.clone(), y.clone(), line_file.clone()).into(),
118 GreaterFact::new(x.clone(), y.clone(), line_file.clone()).into(),
119 LessFact::new(y.clone(), x.clone(), line_file.clone()).into(),
120 GreaterFact::new(y.clone(), x.clone(), line_file.clone()).into(),
121 ];
122 for order_atomic in candidates {
123 let sub =
124 self.verify_non_equational_atomic_fact_with_known_atomic_facts(&order_atomic)?;
125 if sub.is_true() {
126 return Ok(Some(
127 FactualStmtSuccess::new_with_verified_by_builtin_rules(
128 not_equal_fact.clone().into(),
129 InferResult::new(),
130 "not_equal_from_known_strict_order".to_string(),
131 vec![sub],
132 )
133 .into(),
134 ));
135 }
136 }
137 Ok(None)
138 }
139
140 fn try_verify_not_equal_pow_from_base_nonzero(
142 &mut self,
143 not_equal_fact: &NotEqualFact,
144 verify_state: &VerifyState,
145 ) -> Result<Option<StmtResult>, RuntimeError> {
146 let line_file = not_equal_fact.line_file.clone();
147 let zero_obj: Obj = Number::new("0".to_string()).into();
148 let pow = match (¬_equal_fact.left, ¬_equal_fact.right) {
149 (Obj::Pow(p), r) if self.obj_represents_zero_for_not_equal_builtin_rules(r) => p,
150 (l, Obj::Pow(p)) if self.obj_represents_zero_for_not_equal_builtin_rules(l) => p,
151 _ => return Ok(None),
152 };
153 let Obj::Number(exp_num) = pow.exponent.as_ref() else {
154 return Ok(None);
155 };
156 if !is_integer_after_simplification(exp_num) {
157 return Ok(None);
158 }
159
160 let base = pow.base.as_ref().clone();
161 let base_neq_zero: AtomicFact = NotEqualFact::new(base, zero_obj, line_file.clone()).into();
162 let mut result =
163 self.verify_non_equational_atomic_fact_with_known_atomic_facts(&base_neq_zero)?;
164 if !result.is_true() {
165 result = self.verify_non_equational_atomic_fact(&base_neq_zero, verify_state, true)?;
166 }
167 if result.is_true() {
168 return Ok(Some(
169 FactualStmtSuccess::new_with_verified_by_builtin_rules(
170 not_equal_fact.clone().into(),
171 InferResult::new(),
172 "not_equal_pow_from_base_nonzero".to_string(),
173 vec![result],
174 )
175 .into(),
176 ));
177 }
178 Ok(None)
179 }
180
181 fn obj_represents_zero_for_not_equal_builtin_rules(self: &Self, obj: &Obj) -> bool {
182 match self.resolve_obj_to_number(obj) {
183 Some(number) => number.normalized_value == "0",
184 None => false,
185 }
186 }
187
188 fn operand_is_not_equal_to_zero_by_known_non_equational_facts(
189 &mut self,
190 operand: &Obj,
191 line_file: LineFile,
192 ) -> Result<bool, RuntimeError> {
193 let zero_obj: Obj = Number::new("0".to_string()).into();
194 let operand_not_equal_zero_fact =
195 NotEqualFact::new(operand.clone(), zero_obj, line_file).into();
196 let verify_result = self.verify_non_equational_atomic_fact_with_known_atomic_facts(
197 &operand_not_equal_zero_fact,
198 )?;
199 Ok(verify_result.is_true())
200 }
201
202 fn both_operands_nonzero_by_known_non_equational_facts(
203 &mut self,
204 left_operand: &Obj,
205 right_operand: &Obj,
206 line_file: LineFile,
207 ) -> Result<bool, RuntimeError> {
208 let left_nonzero = self.operand_is_not_equal_to_zero_by_known_non_equational_facts(
209 left_operand,
210 line_file.clone(),
211 )?;
212 if !left_nonzero {
213 return Ok(false);
214 }
215 self.operand_is_not_equal_to_zero_by_known_non_equational_facts(right_operand, line_file)
216 }
217
218 fn both_operands_strictly_positive_by_non_equational_verify(
219 &mut self,
220 left_operand: &Obj,
221 right_operand: &Obj,
222 line_file: LineFile,
223 verify_state: &VerifyState,
224 ) -> Result<bool, RuntimeError> {
225 let zero_obj: Obj = Number::new("0".to_string()).into();
226 let zero_less_than_left =
227 LessFact::new(zero_obj.clone(), left_operand.clone(), line_file.clone()).into();
228 if !self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
229 &zero_less_than_left,
230 verify_state,
231 )? {
232 return Ok(false);
233 }
234 let zero_less_than_right = LessFact::new(zero_obj, right_operand.clone(), line_file).into();
235 self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
236 &zero_less_than_right,
237 verify_state,
238 )
239 }
240
241 fn both_operands_strictly_negative_by_non_equational_verify(
242 &mut self,
243 left_operand: &Obj,
244 right_operand: &Obj,
245 line_file: LineFile,
246 verify_state: &VerifyState,
247 ) -> Result<bool, RuntimeError> {
248 let zero_obj: Obj = Number::new("0".to_string()).into();
249 let left_less_than_zero =
250 LessFact::new(left_operand.clone(), zero_obj.clone(), line_file.clone()).into();
251 if !self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
252 &left_less_than_zero,
253 verify_state,
254 )? {
255 return Ok(false);
256 }
257 let right_less_than_zero = LessFact::new(right_operand.clone(), zero_obj, line_file).into();
258 self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
259 &right_less_than_zero,
260 verify_state,
261 )
262 }
263
264 pub fn mul_product_negative_when_factors_have_strict_opposite_sign_by_non_equational_verify(
265 &mut self,
266 left_factor: &Obj,
267 right_factor: &Obj,
268 line_file: LineFile,
269 verify_state: &VerifyState,
270 ) -> Result<bool, RuntimeError> {
271 let zero_obj: Obj = Number::new("0".to_string()).into();
272 let left_less_than_zero =
273 LessFact::new(left_factor.clone(), zero_obj.clone(), line_file.clone()).into();
274 let zero_less_than_right =
275 LessFact::new(zero_obj.clone(), right_factor.clone(), line_file.clone()).into();
276 if self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
277 &left_less_than_zero,
278 verify_state,
279 )? && self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
280 &zero_less_than_right,
281 verify_state,
282 )? {
283 return Ok(true);
284 }
285 let zero_less_than_left =
286 LessFact::new(zero_obj.clone(), left_factor.clone(), line_file.clone()).into();
287 let right_less_than_zero = LessFact::new(right_factor.clone(), zero_obj, line_file).into();
288 Ok(
289 self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
290 &zero_less_than_left,
291 verify_state,
292 )? && self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
293 &right_less_than_zero,
294 verify_state,
295 )?,
296 )
297 }
298
299 fn sub_difference_nonzero_when_operands_have_strict_opposite_sign_by_non_equational_verify(
300 &mut self,
301 minuend: &Obj,
302 subtrahend: &Obj,
303 line_file: LineFile,
304 verify_state: &VerifyState,
305 ) -> Result<bool, RuntimeError> {
306 let zero_obj: Obj = Number::new("0".to_string()).into();
307 let zero_less_than_minuend =
308 LessFact::new(zero_obj.clone(), minuend.clone(), line_file.clone()).into();
309 let subtrahend_less_than_zero =
310 LessFact::new(subtrahend.clone(), zero_obj.clone(), line_file.clone()).into();
311 if self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
312 &zero_less_than_minuend,
313 verify_state,
314 )? && self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
315 &subtrahend_less_than_zero,
316 verify_state,
317 )? {
318 return Ok(true);
319 }
320 let minuend_less_than_zero =
321 LessFact::new(minuend.clone(), zero_obj.clone(), line_file.clone()).into();
322 let zero_less_than_subtrahend =
323 LessFact::new(zero_obj, subtrahend.clone(), line_file).into();
324 Ok(
325 self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
326 &minuend_less_than_zero,
327 verify_state,
328 )? && self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
329 &zero_less_than_subtrahend,
330 verify_state,
331 )?,
332 )
333 }
334
335 fn try_verify_not_equal_fact_when_zero_and_binary_arithmetic_reduces_by_operand_facts(
336 &mut self,
337 not_equal_fact: &NotEqualFact,
338 verify_state: &VerifyState,
339 ) -> Result<Option<StmtResult>, RuntimeError> {
340 let line_file = not_equal_fact.line_file.clone();
341 let expression_obj =
342 if self.obj_represents_zero_for_not_equal_builtin_rules(¬_equal_fact.right) {
343 ¬_equal_fact.left
344 } else if self.obj_represents_zero_for_not_equal_builtin_rules(¬_equal_fact.left) {
345 ¬_equal_fact.right
346 } else {
347 return Ok(None);
348 };
349
350 let builtin_rule_label = match expression_obj {
351 Obj::Add(add) => {
352 if self.both_operands_strictly_positive_by_non_equational_verify(
353 &add.left,
354 &add.right,
355 line_file.clone(),
356 verify_state,
357 )? {
358 Some("add_not_equal_zero_both_operands_strictly_positive")
359 } else if self.both_operands_strictly_negative_by_non_equational_verify(
360 &add.left,
361 &add.right,
362 line_file.clone(),
363 verify_state,
364 )? {
365 Some("add_not_equal_zero_both_operands_strictly_negative")
366 } else {
367 None
368 }
369 }
370 Obj::Mul(mul) => {
371 if self.both_operands_nonzero_by_known_non_equational_facts(
372 &mul.left,
373 &mul.right,
374 line_file.clone(),
375 )? {
376 Some("mul_not_equal_zero_both_factors_nonzero_by_known_facts")
377 } else if self.both_operands_strictly_positive_by_non_equational_verify(
378 &mul.left,
379 &mul.right,
380 line_file.clone(),
381 verify_state,
382 )? {
383 Some("mul_not_equal_zero_both_factors_strictly_positive")
384 } else if self.both_operands_strictly_negative_by_non_equational_verify(
385 &mul.left,
386 &mul.right,
387 line_file.clone(),
388 verify_state,
389 )? {
390 Some("mul_not_equal_zero_both_factors_strictly_negative")
391 } else {
392 None
393 }
394 }
395 Obj::Sub(sub) => {
396 if self.sub_difference_nonzero_when_operands_have_strict_opposite_sign_by_non_equational_verify(
397 &sub.left,
398 &sub.right,
399 line_file,
400 verify_state,
401 )? {
402 Some("sub_not_equal_zero_operands_strict_opposite_sign")
403 } else {
404 None
405 }
406 }
407 other => {
408 let zero_obj: Obj = Number::new("0".to_string()).into();
409 let zero_lt_a = LessFact::new(
410 zero_obj.clone(),
411 other.clone(),
412 line_file.clone(),
413 ).into();
414
415 let final_round_verify_state = verify_state.make_final_round_state();
416
417 if self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
418 &zero_lt_a,
419 &final_round_verify_state,
420 )? {
421 Some("not_equal_zero_operand_strictly_positive")
422 } else {
423 let a_lt_0 = LessFact::new(
424 other.clone(),
425 zero_obj,
426 line_file.clone(),
427 ).into();
428 if self.non_equational_atomic_fact_holds_by_full_verify_pipeline(
429 &a_lt_0,
430 &final_round_verify_state,
431 )? {
432 Some("not_equal_zero_operand_strictly_negative")
433 } else {
434 None
435 }
436 }
437 }
438 };
439
440 match builtin_rule_label {
441 Some(rule_label) => Ok(Some(
442 (FactualStmtSuccess::new_with_verified_by_builtin_rules_recording_stmt(
443 not_equal_fact.clone().into(),
444 rule_label.to_string(),
445 Vec::new(),
446 ))
447 .into(),
448 )),
449 None => Ok(None),
450 }
451 }
452}