1use crate::prelude::*;
2use crate::verify::{compare_normalized_number_str_to_zero, NumberCompareResult};
3
4impl Runtime {
5 pub fn infer_numeric_order_sign_from_order_atomic(
14 &mut self,
15 atomic_fact: &AtomicFact,
16 ) -> Result<InferResult, RuntimeError> {
17 let mut acc = match atomic_fact {
18 AtomicFact::GreaterEqualFact(f) => self.infer_numeric_order_sign_greater_equal(f),
19 AtomicFact::GreaterFact(f) => self.infer_numeric_order_sign_greater(f),
20 AtomicFact::LessEqualFact(f) => self.infer_numeric_order_sign_less_equal(f),
21 AtomicFact::LessFact(f) => self.infer_numeric_order_sign_less(f),
22 _ => Ok(InferResult::new()),
23 }?;
24 let flip = self.infer_flip_mul_minus_one_order_vs_zero(atomic_fact)?;
25 acc.new_infer_result_inside(flip);
26 Ok(acc)
27 }
28
29 fn order_flip_infer_operand_ok(&self, x: &Obj) -> bool {
30 self.peel_mul_by_literal_neg_one(x).is_none()
31 }
32
33 fn obj_mul_literal_neg_one(&self, x: Obj) -> Obj {
34 Mul::new(Number::new("-1".to_string()).into(), x).into()
35 }
36
37 fn atomic_fact_infer_opposite_mul_minus_one_target(
38 &self,
39 atomic_fact: &AtomicFact,
40 ) -> Option<AtomicFact> {
41 let z = Number::new("0".to_string()).into();
42 match atomic_fact {
43 AtomicFact::LessFact(f) if self.obj_is_resolved_zero(&f.right) => {
44 if !self.order_flip_infer_operand_ok(&f.left) {
45 return None;
46 }
47 Some(
48 GreaterEqualFact::new(
49 self.obj_mul_literal_neg_one(f.left.clone()),
50 z,
51 f.line_file.clone(),
52 )
53 .into(),
54 )
55 }
56 AtomicFact::LessEqualFact(f) if self.obj_is_resolved_zero(&f.right) => {
57 if !self.order_flip_infer_operand_ok(&f.left) {
58 return None;
59 }
60 Some(
61 GreaterEqualFact::new(
62 self.obj_mul_literal_neg_one(f.left.clone()),
63 z,
64 f.line_file.clone(),
65 )
66 .into(),
67 )
68 }
69 AtomicFact::GreaterFact(f) if self.obj_is_resolved_zero(&f.right) => {
70 if !self.order_flip_infer_operand_ok(&f.left) {
71 return None;
72 }
73 Some(
74 LessFact::new(
75 self.obj_mul_literal_neg_one(f.left.clone()),
76 z,
77 f.line_file.clone(),
78 )
79 .into(),
80 )
81 }
82 AtomicFact::GreaterEqualFact(f) if self.obj_is_resolved_zero(&f.right) => {
83 if !self.order_flip_infer_operand_ok(&f.left) {
84 return None;
85 }
86 Some(
87 LessEqualFact::new(
88 self.obj_mul_literal_neg_one(f.left.clone()),
89 z,
90 f.line_file.clone(),
91 )
92 .into(),
93 )
94 }
95 _ => None,
99 }
100 }
101
102 fn infer_flip_mul_minus_one_order_vs_zero(
103 &mut self,
104 atomic_fact: &AtomicFact,
105 ) -> Result<InferResult, RuntimeError> {
106 let Some(inferred_atomic) =
107 self.atomic_fact_infer_opposite_mul_minus_one_target(atomic_fact)
108 else {
109 return Ok(InferResult::new());
110 };
111 let fact_to_store: Fact = inferred_atomic.clone().into();
112 let mut infer_result = InferResult::new();
113 infer_result.new_fact(&fact_to_store);
114 let inner = self
118 .store_atomic_fact_without_well_defined_verified_and_infer(inferred_atomic)
119 .map_err(|previous_error| {
120 RuntimeError::from(InferRuntimeError(RuntimeErrorStruct::new(
121 None,
122 "infer opposite sign mul (-1): failed to store inferred order fact".to_string(),
123 atomic_fact.line_file(),
124 Some(previous_error),
125 vec![],
126 )))
127 })?;
128 infer_result.new_infer_result_inside(inner);
129 Ok(infer_result)
130 }
131
132 fn infer_numeric_order_sign_greater_equal(
133 &mut self,
134 f: &GreaterEqualFact,
135 ) -> Result<InferResult, RuntimeError> {
136 let left_num = self.resolve_obj_to_number(&f.left);
137 let right_num = self.resolve_obj_to_number(&f.right);
138 match (left_num, right_num) {
139 (Some(_), Some(_)) | (None, None) => Ok(InferResult::new()),
140 (None, Some(k)) => {
141 if matches!(
143 compare_normalized_number_str_to_zero(&k.normalized_value),
144 NumberCompareResult::Greater
145 ) {
146 self.infer_store_gt_zero(f.left.clone(), f.line_file.clone())
147 } else {
148 Ok(InferResult::new())
149 }
150 }
151 (Some(k), None) => {
152 if matches!(
154 compare_normalized_number_str_to_zero(&k.normalized_value),
155 NumberCompareResult::Less
156 ) {
157 self.infer_store_le_zero(f.right.clone(), f.line_file.clone())
158 } else {
159 Ok(InferResult::new())
160 }
161 }
162 }
163 }
164
165 fn infer_numeric_order_sign_greater(
166 &mut self,
167 f: &GreaterFact,
168 ) -> Result<InferResult, RuntimeError> {
169 let left_num = self.resolve_obj_to_number(&f.left);
170 let right_num = self.resolve_obj_to_number(&f.right);
171 match (left_num, right_num) {
172 (Some(_), Some(_)) | (None, None) => Ok(InferResult::new()),
173 (None, Some(k)) => {
174 if matches!(
176 compare_normalized_number_str_to_zero(&k.normalized_value),
177 NumberCompareResult::Greater
178 ) {
179 self.infer_store_gt_zero(f.left.clone(), f.line_file.clone())
180 } else {
181 Ok(InferResult::new())
182 }
183 }
184 (Some(k), None) => {
185 if matches!(
187 compare_normalized_number_str_to_zero(&k.normalized_value),
188 NumberCompareResult::Less | NumberCompareResult::Equal
189 ) {
190 self.infer_store_le_zero(f.right.clone(), f.line_file.clone())
191 } else {
192 Ok(InferResult::new())
193 }
194 }
195 }
196 }
197
198 fn infer_numeric_order_sign_less_equal(
199 &mut self,
200 f: &LessEqualFact,
201 ) -> Result<InferResult, RuntimeError> {
202 let left_num = self.resolve_obj_to_number(&f.left);
203 let right_num = self.resolve_obj_to_number(&f.right);
204 match (left_num, right_num) {
205 (Some(_), Some(_)) | (None, None) => Ok(InferResult::new()),
206 (None, Some(k)) => {
207 if matches!(
209 compare_normalized_number_str_to_zero(&k.normalized_value),
210 NumberCompareResult::Less
211 ) {
212 self.infer_store_le_zero(f.left.clone(), f.line_file.clone())
213 } else {
214 Ok(InferResult::new())
215 }
216 }
217 (Some(k), None) => {
218 if matches!(
220 compare_normalized_number_str_to_zero(&k.normalized_value),
221 NumberCompareResult::Greater
222 ) {
223 self.infer_store_gt_zero(f.right.clone(), f.line_file.clone())
224 } else {
225 Ok(InferResult::new())
226 }
227 }
228 }
229 }
230
231 fn infer_numeric_order_sign_less(&mut self, f: &LessFact) -> Result<InferResult, RuntimeError> {
232 let left_num = self.resolve_obj_to_number(&f.left);
233 let right_num = self.resolve_obj_to_number(&f.right);
234 match (left_num, right_num) {
235 (Some(_), Some(_)) | (None, None) => Ok(InferResult::new()),
236 (None, Some(k)) => {
237 if matches!(
239 compare_normalized_number_str_to_zero(&k.normalized_value),
240 NumberCompareResult::Less | NumberCompareResult::Equal
241 ) {
242 self.infer_store_le_zero(f.left.clone(), f.line_file.clone())
243 } else {
244 Ok(InferResult::new())
245 }
246 }
247 (Some(k), None) => {
248 if matches!(
250 compare_normalized_number_str_to_zero(&k.normalized_value),
251 NumberCompareResult::Greater
252 ) {
253 self.infer_store_gt_zero(f.right.clone(), f.line_file.clone())
254 } else {
255 Ok(InferResult::new())
256 }
257 }
258 }
259 }
260
261 fn infer_store_gt_zero(
262 &mut self,
263 x: Obj,
264 line_file: LineFile,
265 ) -> Result<InferResult, RuntimeError> {
266 let fact_to_store =
267 LessFact::new(Number::new("0".to_string()).into(), x, line_file.clone()).into();
268 let mut infer_result = InferResult::new();
269 infer_result.new_fact(&fact_to_store);
270 self.verify_well_defined_and_store_and_infer_with_default_verify_state(fact_to_store)
271 .map_err(|previous_error| {
272 RuntimeError::from(InferRuntimeError(RuntimeErrorStruct::new(
273 None,
274 "infer numeric order sign: failed to store inferred (0 < x) bound".to_string(),
275 line_file,
276 Some(previous_error),
277 vec![],
278 )))
279 })?;
280 Ok(infer_result)
281 }
282
283 fn infer_store_le_zero(
284 &mut self,
285 x: Obj,
286 line_file: LineFile,
287 ) -> Result<InferResult, RuntimeError> {
288 let fact_to_store =
289 LessEqualFact::new(x, Number::new("0".to_string()).into(), line_file.clone()).into();
290 let mut infer_result = InferResult::new();
291 infer_result.new_fact(&fact_to_store);
292 self.verify_well_defined_and_store_and_infer_with_default_verify_state(fact_to_store)
293 .map_err(|previous_error| {
294 RuntimeError::from(InferRuntimeError(RuntimeErrorStruct::new(
295 None,
296 "infer numeric order sign: failed to store inferred <= 0 bound".to_string(),
297 line_file,
298 Some(previous_error),
299 vec![],
300 )))
301 })?;
302 Ok(infer_result)
303 }
304}
305
306#[cfg(test)]
307mod tests {
308 use crate::verify::{compare_normalized_number_str_to_zero, NumberCompareResult};
309
310 #[test]
311 fn compare_to_zero_matches_expectations() {
312 assert!(matches!(
313 compare_normalized_number_str_to_zero("1"),
314 NumberCompareResult::Greater
315 ));
316 assert!(matches!(
317 compare_normalized_number_str_to_zero("0"),
318 NumberCompareResult::Equal
319 ));
320 assert!(matches!(
321 compare_normalized_number_str_to_zero("-2"),
322 NumberCompareResult::Less
323 ));
324 }
325}