/Users/andrewlamb/Software/datafusion/datafusion/expr-common/src/interval_arithmetic.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | //! Interval arithmetic library |
19 | | |
20 | | use crate::operator::Operator; |
21 | | use crate::type_coercion::binary::get_result_type; |
22 | | use std::borrow::Borrow; |
23 | | use std::fmt::{self, Display, Formatter}; |
24 | | use std::ops::{AddAssign, SubAssign}; |
25 | | |
26 | | use arrow::compute::{cast_with_options, CastOptions}; |
27 | | use arrow::datatypes::{ |
28 | | DataType, IntervalDayTime, IntervalMonthDayNano, IntervalUnit, TimeUnit, |
29 | | }; |
30 | | use datafusion_common::rounding::{alter_fp_rounding_mode, next_down, next_up}; |
31 | | use datafusion_common::{internal_err, Result, ScalarValue}; |
32 | | |
33 | | macro_rules! get_extreme_value { |
34 | | ($extreme:ident, $value:expr) => { |
35 | | match $value { |
36 | | DataType::UInt8 => ScalarValue::UInt8(Some(u8::$extreme)), |
37 | | DataType::UInt16 => ScalarValue::UInt16(Some(u16::$extreme)), |
38 | | DataType::UInt32 => ScalarValue::UInt32(Some(u32::$extreme)), |
39 | | DataType::UInt64 => ScalarValue::UInt64(Some(u64::$extreme)), |
40 | | DataType::Int8 => ScalarValue::Int8(Some(i8::$extreme)), |
41 | | DataType::Int16 => ScalarValue::Int16(Some(i16::$extreme)), |
42 | | DataType::Int32 => ScalarValue::Int32(Some(i32::$extreme)), |
43 | | DataType::Int64 => ScalarValue::Int64(Some(i64::$extreme)), |
44 | | DataType::Float32 => ScalarValue::Float32(Some(f32::$extreme)), |
45 | | DataType::Float64 => ScalarValue::Float64(Some(f64::$extreme)), |
46 | | DataType::Duration(TimeUnit::Second) => { |
47 | | ScalarValue::DurationSecond(Some(i64::$extreme)) |
48 | | } |
49 | | DataType::Duration(TimeUnit::Millisecond) => { |
50 | | ScalarValue::DurationMillisecond(Some(i64::$extreme)) |
51 | | } |
52 | | DataType::Duration(TimeUnit::Microsecond) => { |
53 | | ScalarValue::DurationMicrosecond(Some(i64::$extreme)) |
54 | | } |
55 | | DataType::Duration(TimeUnit::Nanosecond) => { |
56 | | ScalarValue::DurationNanosecond(Some(i64::$extreme)) |
57 | | } |
58 | | DataType::Timestamp(TimeUnit::Second, _) => { |
59 | | ScalarValue::TimestampSecond(Some(i64::$extreme), None) |
60 | | } |
61 | | DataType::Timestamp(TimeUnit::Millisecond, _) => { |
62 | | ScalarValue::TimestampMillisecond(Some(i64::$extreme), None) |
63 | | } |
64 | | DataType::Timestamp(TimeUnit::Microsecond, _) => { |
65 | | ScalarValue::TimestampMicrosecond(Some(i64::$extreme), None) |
66 | | } |
67 | | DataType::Timestamp(TimeUnit::Nanosecond, _) => { |
68 | | ScalarValue::TimestampNanosecond(Some(i64::$extreme), None) |
69 | | } |
70 | | DataType::Interval(IntervalUnit::YearMonth) => { |
71 | | ScalarValue::IntervalYearMonth(Some(i32::$extreme)) |
72 | | } |
73 | | DataType::Interval(IntervalUnit::DayTime) => { |
74 | | ScalarValue::IntervalDayTime(Some(IntervalDayTime::$extreme)) |
75 | | } |
76 | | DataType::Interval(IntervalUnit::MonthDayNano) => { |
77 | | ScalarValue::IntervalMonthDayNano(Some(IntervalMonthDayNano::$extreme)) |
78 | | } |
79 | | _ => unreachable!(), |
80 | | } |
81 | | }; |
82 | | } |
83 | | |
84 | | macro_rules! value_transition { |
85 | | ($bound:ident, $direction:expr, $value:expr) => { |
86 | | match $value { |
87 | | UInt8(Some(value)) if value == u8::$bound => UInt8(None), |
88 | | UInt16(Some(value)) if value == u16::$bound => UInt16(None), |
89 | | UInt32(Some(value)) if value == u32::$bound => UInt32(None), |
90 | | UInt64(Some(value)) if value == u64::$bound => UInt64(None), |
91 | | Int8(Some(value)) if value == i8::$bound => Int8(None), |
92 | | Int16(Some(value)) if value == i16::$bound => Int16(None), |
93 | | Int32(Some(value)) if value == i32::$bound => Int32(None), |
94 | | Int64(Some(value)) if value == i64::$bound => Int64(None), |
95 | | Float32(Some(value)) if value == f32::$bound => Float32(None), |
96 | | Float64(Some(value)) if value == f64::$bound => Float64(None), |
97 | | DurationSecond(Some(value)) if value == i64::$bound => DurationSecond(None), |
98 | | DurationMillisecond(Some(value)) if value == i64::$bound => { |
99 | | DurationMillisecond(None) |
100 | | } |
101 | | DurationMicrosecond(Some(value)) if value == i64::$bound => { |
102 | | DurationMicrosecond(None) |
103 | | } |
104 | | DurationNanosecond(Some(value)) if value == i64::$bound => { |
105 | | DurationNanosecond(None) |
106 | | } |
107 | | TimestampSecond(Some(value), tz) if value == i64::$bound => { |
108 | | TimestampSecond(None, tz) |
109 | | } |
110 | | TimestampMillisecond(Some(value), tz) if value == i64::$bound => { |
111 | | TimestampMillisecond(None, tz) |
112 | | } |
113 | | TimestampMicrosecond(Some(value), tz) if value == i64::$bound => { |
114 | | TimestampMicrosecond(None, tz) |
115 | | } |
116 | | TimestampNanosecond(Some(value), tz) if value == i64::$bound => { |
117 | | TimestampNanosecond(None, tz) |
118 | | } |
119 | | IntervalYearMonth(Some(value)) if value == i32::$bound => { |
120 | | IntervalYearMonth(None) |
121 | | } |
122 | | IntervalDayTime(Some(value)) |
123 | | if value == arrow::datatypes::IntervalDayTime::$bound => |
124 | | { |
125 | | IntervalDayTime(None) |
126 | | } |
127 | | IntervalMonthDayNano(Some(value)) |
128 | | if value == arrow::datatypes::IntervalMonthDayNano::$bound => |
129 | | { |
130 | | IntervalMonthDayNano(None) |
131 | | } |
132 | | _ => next_value_helper::<$direction>($value), |
133 | | } |
134 | | }; |
135 | | } |
136 | | |
137 | | /// The `Interval` type represents a closed interval used for computing |
138 | | /// reliable bounds for mathematical expressions. |
139 | | /// |
140 | | /// Conventions: |
141 | | /// |
142 | | /// 1. **Closed bounds**: The interval always encompasses its endpoints. We |
143 | | /// accommodate operations resulting in open intervals by incrementing or |
144 | | /// decrementing the interval endpoint value to its successor/predecessor. |
145 | | /// |
146 | | /// 2. **Unbounded endpoints**: If the `lower` or `upper` bounds are indeterminate, |
147 | | /// they are labeled as *unbounded*. This is represented using a `NULL`. |
148 | | /// |
149 | | /// 3. **Overflow handling**: If the `lower` or `upper` endpoints exceed their |
150 | | /// limits after any operation, they either become unbounded or they are fixed |
151 | | /// to the maximum/minimum value of the datatype, depending on the direction |
152 | | /// of the overflowing endpoint, opting for the safer choice. |
153 | | /// |
154 | | /// 4. **Floating-point special cases**: |
155 | | /// - `INF` values are converted to `NULL`s while constructing an interval to |
156 | | /// ensure consistency, with other data types. |
157 | | /// - `NaN` (Not a Number) results are conservatively result in unbounded |
158 | | /// endpoints. |
159 | | #[derive(Debug, Clone, PartialEq, Eq)] |
160 | | pub struct Interval { |
161 | | lower: ScalarValue, |
162 | | upper: ScalarValue, |
163 | | } |
164 | | |
165 | | /// This macro handles the `NaN` and `INF` floating point values. |
166 | | /// |
167 | | /// - `NaN` values are always converted to unbounded i.e. `NULL` values. |
168 | | /// - For lower bounds: |
169 | | /// - A `NEG_INF` value is converted to a `NULL`. |
170 | | /// - An `INF` value is conservatively converted to the maximum representable |
171 | | /// number for the floating-point type in question. In this case, converting |
172 | | /// to `NULL` doesn't make sense as it would be interpreted as a `NEG_INF`. |
173 | | /// - For upper bounds: |
174 | | /// - An `INF` value is converted to a `NULL`. |
175 | | /// - An `NEG_INF` value is conservatively converted to the minimum representable |
176 | | /// number for the floating-point type in question. In this case, converting |
177 | | /// to `NULL` doesn't make sense as it would be interpreted as an `INF`. |
178 | | macro_rules! handle_float_intervals { |
179 | | ($scalar_type:ident, $primitive_type:ident, $lower:expr, $upper:expr) => {{ |
180 | | let lower = match $lower { |
181 | | ScalarValue::$scalar_type(Some(l_val)) |
182 | | if l_val == $primitive_type::NEG_INFINITY || l_val.is_nan() => |
183 | | { |
184 | | ScalarValue::$scalar_type(None) |
185 | | } |
186 | | ScalarValue::$scalar_type(Some(l_val)) |
187 | | if l_val == $primitive_type::INFINITY => |
188 | | { |
189 | | ScalarValue::$scalar_type(Some($primitive_type::MAX)) |
190 | | } |
191 | | value @ ScalarValue::$scalar_type(Some(_)) => value, |
192 | | _ => ScalarValue::$scalar_type(None), |
193 | | }; |
194 | | |
195 | | let upper = match $upper { |
196 | | ScalarValue::$scalar_type(Some(r_val)) |
197 | | if r_val == $primitive_type::INFINITY || r_val.is_nan() => |
198 | | { |
199 | | ScalarValue::$scalar_type(None) |
200 | | } |
201 | | ScalarValue::$scalar_type(Some(r_val)) |
202 | | if r_val == $primitive_type::NEG_INFINITY => |
203 | | { |
204 | | ScalarValue::$scalar_type(Some($primitive_type::MIN)) |
205 | | } |
206 | | value @ ScalarValue::$scalar_type(Some(_)) => value, |
207 | | _ => ScalarValue::$scalar_type(None), |
208 | | }; |
209 | | |
210 | | Interval { lower, upper } |
211 | | }}; |
212 | | } |
213 | | |
214 | | /// Ordering floating-point numbers according to their binary representations |
215 | | /// contradicts with their natural ordering. Floating-point number ordering |
216 | | /// after unsigned integer transmutation looks like: |
217 | | /// |
218 | | /// ```text |
219 | | /// 0, 1, 2, 3, ..., MAX, -0, -1, -2, ..., -MAX |
220 | | /// ``` |
221 | | /// |
222 | | /// This macro applies a one-to-one map that fixes the ordering above. |
223 | | macro_rules! map_floating_point_order { |
224 | | ($value:expr, $ty:ty) => {{ |
225 | | let num_bits = std::mem::size_of::<$ty>() * 8; |
226 | | let sign_bit = 1 << (num_bits - 1); |
227 | | if $value & sign_bit == sign_bit { |
228 | | // Negative numbers: |
229 | | !$value |
230 | | } else { |
231 | | // Positive numbers: |
232 | | $value | sign_bit |
233 | | } |
234 | | }}; |
235 | | } |
236 | | |
237 | | impl Interval { |
238 | | /// Attempts to create a new `Interval` from the given lower and upper bounds. |
239 | | /// |
240 | | /// # Notes |
241 | | /// |
242 | | /// This constructor creates intervals in a "canonical" form where: |
243 | | /// - **Boolean intervals**: |
244 | | /// - Unboundedness (`NULL`) for boolean endpoints is converted to `false` |
245 | | /// for lower and `true` for upper bounds. |
246 | | /// - **Floating-point intervals**: |
247 | | /// - Floating-point endpoints with `NaN`, `INF`, or `NEG_INF` are converted |
248 | | /// to `NULL`s. |
249 | 19.9k | pub fn try_new(lower: ScalarValue, upper: ScalarValue) -> Result<Self> { |
250 | 19.9k | if lower.data_type() != upper.data_type() { |
251 | 0 | return internal_err!("Endpoints of an Interval should have the same type"); |
252 | 19.9k | } |
253 | 19.9k | |
254 | 19.9k | let interval = Self::new(lower, upper); |
255 | 19.9k | |
256 | 19.9k | if interval.lower.is_null() |
257 | 18.0k | || interval.upper.is_null() |
258 | 6.97k | || interval.lower <= interval.upper |
259 | | { |
260 | 19.9k | Ok(interval) |
261 | | } else { |
262 | 0 | internal_err!( |
263 | 0 | "Interval's lower bound {} is greater than the upper bound {}", |
264 | 0 | interval.lower, |
265 | 0 | interval.upper |
266 | 0 | ) |
267 | | } |
268 | 19.9k | } |
269 | | |
270 | | /// Only for internal usage. Responsible for standardizing booleans and |
271 | | /// floating-point values, as well as fixing NaNs. It doesn't validate |
272 | | /// the given bounds for ordering, or verify that they have the same data |
273 | | /// type. For its user-facing counterpart and more details, see |
274 | | /// [`Interval::try_new`]. |
275 | 123k | fn new(lower: ScalarValue, upper: ScalarValue) -> Self { |
276 | 123k | if let ScalarValue::Boolean(lower_bool3.38k ) = lower { |
277 | 3.38k | let ScalarValue::Boolean(upper_bool) = upper else { |
278 | | // We are sure that upper and lower bounds have the same type. |
279 | 0 | unreachable!(); |
280 | | }; |
281 | | // Standardize boolean interval endpoints: |
282 | 3.38k | return Self { |
283 | 3.38k | lower: ScalarValue::Boolean(Some(lower_bool.unwrap_or(false))), |
284 | 3.38k | upper: ScalarValue::Boolean(Some(upper_bool.unwrap_or(true))), |
285 | 3.38k | }; |
286 | 119k | } |
287 | 119k | match lower.data_type() { |
288 | | // Standardize floating-point endpoints: |
289 | 20 | DataType::Float32 => handle_float_intervals!(Float32, f32, lower8 , upper8 ), |
290 | 29.6k | DataType::Float64 => handle_float_intervals!11.1k (Float64, f64, lower, upper1.47k ), |
291 | | // Unsigned null values for lower bounds are set to zero: |
292 | 0 | DataType::UInt8 if lower.is_null() => Self { |
293 | 0 | lower: ScalarValue::UInt8(Some(0)), |
294 | 0 | upper, |
295 | 0 | }, |
296 | 0 | DataType::UInt16 if lower.is_null() => Self { |
297 | 0 | lower: ScalarValue::UInt16(Some(0)), |
298 | 0 | upper, |
299 | 0 | }, |
300 | 133 | DataType::UInt32 if lower.is_null() => Self { |
301 | 133 | lower: ScalarValue::UInt32(Some(0)), |
302 | 133 | upper, |
303 | 133 | }, |
304 | 5 | DataType::UInt64 if lower.is_null() => Self { |
305 | 5 | lower: ScalarValue::UInt64(Some(0)), |
306 | 5 | upper, |
307 | 5 | }, |
308 | | // Other data types do not require standardization: |
309 | 78.9k | _ => Self { lower, upper }, |
310 | | } |
311 | 123k | } |
312 | | |
313 | | /// Convenience function to create a new `Interval` from the given (optional) |
314 | | /// bounds, for use in tests only. Absence of either endpoint indicates |
315 | | /// unboundedness on that side. See [`Interval::try_new`] for more information. |
316 | | pub fn make<T>(lower: Option<T>, upper: Option<T>) -> Result<Self> |
317 | | where |
318 | | ScalarValue: From<Option<T>>, |
319 | | { |
320 | | Self::try_new(ScalarValue::from(lower), ScalarValue::from(upper)) |
321 | | } |
322 | | |
323 | | /// Creates a singleton zero interval if the datatype supported. |
324 | 0 | pub fn make_zero(data_type: &DataType) -> Result<Self> { |
325 | 0 | let zero_endpoint = ScalarValue::new_zero(data_type)?; |
326 | 0 | Ok(Self::new(zero_endpoint.clone(), zero_endpoint)) |
327 | 0 | } |
328 | | |
329 | | /// Creates an unbounded interval from both sides if the datatype supported. |
330 | 13.9k | pub fn make_unbounded(data_type: &DataType) -> Result<Self> { |
331 | 13.9k | let unbounded_endpoint = ScalarValue::try_from(data_type)?0 ; |
332 | 13.9k | Ok(Self::new(unbounded_endpoint.clone(), unbounded_endpoint)) |
333 | 13.9k | } |
334 | | |
335 | | /// Creates an interval between -1 to 1. |
336 | 0 | pub fn make_symmetric_unit_interval(data_type: &DataType) -> Result<Self> { |
337 | 0 | Self::try_new( |
338 | 0 | ScalarValue::new_negative_one(data_type)?, |
339 | 0 | ScalarValue::new_one(data_type)?, |
340 | | ) |
341 | 0 | } |
342 | | |
343 | | /// Create an interval from -π to π. |
344 | 0 | pub fn make_symmetric_pi_interval(data_type: &DataType) -> Result<Self> { |
345 | 0 | Self::try_new( |
346 | 0 | ScalarValue::new_negative_pi_lower(data_type)?, |
347 | 0 | ScalarValue::new_pi_upper(data_type)?, |
348 | | ) |
349 | 0 | } |
350 | | |
351 | | /// Create an interval from -π/2 to π/2. |
352 | 0 | pub fn make_symmetric_half_pi_interval(data_type: &DataType) -> Result<Self> { |
353 | 0 | Self::try_new( |
354 | 0 | ScalarValue::new_neg_frac_pi_2_lower(data_type)?, |
355 | 0 | ScalarValue::new_frac_pi_2_upper(data_type)?, |
356 | | ) |
357 | 0 | } |
358 | | |
359 | | /// Create an interval from 0 to infinity. |
360 | 0 | pub fn make_non_negative_infinity_interval(data_type: &DataType) -> Result<Self> { |
361 | 0 | Self::try_new( |
362 | 0 | ScalarValue::new_zero(data_type)?, |
363 | 0 | ScalarValue::try_from(data_type)?, |
364 | | ) |
365 | 0 | } |
366 | | |
367 | | /// Returns a reference to the lower bound. |
368 | 5.51k | pub fn lower(&self) -> &ScalarValue { |
369 | 5.51k | &self.lower |
370 | 5.51k | } |
371 | | |
372 | | /// Returns a reference to the upper bound. |
373 | 3.52k | pub fn upper(&self) -> &ScalarValue { |
374 | 3.52k | &self.upper |
375 | 3.52k | } |
376 | | |
377 | | /// Converts this `Interval` into its boundary scalar values. It's useful |
378 | | /// when you need to work with the individual bounds directly. |
379 | 54 | pub fn into_bounds(self) -> (ScalarValue, ScalarValue) { |
380 | 54 | (self.lower, self.upper) |
381 | 54 | } |
382 | | |
383 | | /// This function returns the data type of this interval. |
384 | 370k | pub fn data_type(&self) -> DataType { |
385 | 370k | let lower_type = self.lower.data_type(); |
386 | 370k | let upper_type = self.upper.data_type(); |
387 | 370k | |
388 | 370k | // There must be no way to create an interval whose endpoints have |
389 | 370k | // different types. |
390 | 370k | assert!( |
391 | 370k | lower_type == upper_type, |
392 | 0 | "Interval bounds have different types: {lower_type} != {upper_type}" |
393 | | ); |
394 | 370k | lower_type |
395 | 370k | } |
396 | | |
397 | | /// Casts this interval to `data_type` using `cast_options`. |
398 | 1.55k | pub fn cast_to( |
399 | 1.55k | &self, |
400 | 1.55k | data_type: &DataType, |
401 | 1.55k | cast_options: &CastOptions, |
402 | 1.55k | ) -> Result<Self> { |
403 | 1.55k | Self::try_new( |
404 | 1.55k | cast_scalar_value(&self.lower, data_type, cast_options)?0 , |
405 | 1.55k | cast_scalar_value(&self.upper, data_type, cast_options)?0 , |
406 | | ) |
407 | 1.55k | } |
408 | | |
409 | | pub const CERTAINLY_FALSE: Self = Self { |
410 | | lower: ScalarValue::Boolean(Some(false)), |
411 | | upper: ScalarValue::Boolean(Some(false)), |
412 | | }; |
413 | | |
414 | | pub const UNCERTAIN: Self = Self { |
415 | | lower: ScalarValue::Boolean(Some(false)), |
416 | | upper: ScalarValue::Boolean(Some(true)), |
417 | | }; |
418 | | |
419 | | pub const CERTAINLY_TRUE: Self = Self { |
420 | | lower: ScalarValue::Boolean(Some(true)), |
421 | | upper: ScalarValue::Boolean(Some(true)), |
422 | | }; |
423 | | |
424 | | /// Decide if this interval is certainly greater than, possibly greater than, |
425 | | /// or can't be greater than `other` by returning `[true, true]`, |
426 | | /// `[false, true]` or `[false, false]` respectively. |
427 | | /// |
428 | | /// NOTE: This function only works with intervals of the same data type. |
429 | | /// Attempting to compare intervals of different data types will lead |
430 | | /// to an error. |
431 | 10.1k | pub fn gt<T: Borrow<Self>>(&self, other: T) -> Result<Self> { |
432 | 10.1k | let rhs = other.borrow(); |
433 | 10.1k | if self.data_type().ne(&rhs.data_type()) { |
434 | 0 | internal_err!( |
435 | 0 | "Only intervals with the same data type are comparable, lhs:{}, rhs:{}", |
436 | 0 | self.data_type(), |
437 | 0 | rhs.data_type() |
438 | 0 | ) |
439 | 10.1k | } else if !(self.upper.is_null() || rhs.lower.is_null()1.55k ) |
440 | 11 | && self.upper <= rhs.lower |
441 | | { |
442 | | // Values in this interval are certainly less than or equal to |
443 | | // those in the given interval. |
444 | 2 | Ok(Self::CERTAINLY_FALSE) |
445 | 10.1k | } else if !(self.lower.is_null() || rhs.upper.is_null()8.53k ) |
446 | 9 | && (self.lower > rhs.upper) |
447 | | { |
448 | | // Values in this interval are certainly greater than those in the |
449 | | // given interval. |
450 | 2 | Ok(Self::CERTAINLY_TRUE) |
451 | | } else { |
452 | | // All outcomes are possible. |
453 | 10.1k | Ok(Self::UNCERTAIN) |
454 | | } |
455 | 10.1k | } |
456 | | |
457 | | /// Decide if this interval is certainly greater than or equal to, possibly |
458 | | /// greater than or equal to, or can't be greater than or equal to `other` |
459 | | /// by returning `[true, true]`, `[false, true]` or `[false, false]` respectively. |
460 | | /// |
461 | | /// NOTE: This function only works with intervals of the same data type. |
462 | | /// Attempting to compare intervals of different data types will lead |
463 | | /// to an error. |
464 | 1.34k | pub fn gt_eq<T: Borrow<Self>>(&self, other: T) -> Result<Self> { |
465 | 1.34k | let rhs = other.borrow(); |
466 | 1.34k | if self.data_type().ne(&rhs.data_type()) { |
467 | 0 | internal_err!( |
468 | 0 | "Only intervals with the same data type are comparable, lhs:{}, rhs:{}", |
469 | 0 | self.data_type(), |
470 | 0 | rhs.data_type() |
471 | 0 | ) |
472 | 1.34k | } else if !(self.lower.is_null() || rhs.upper.is_null()1.03k ) |
473 | 21 | && self.lower >= rhs.upper |
474 | | { |
475 | | // Values in this interval are certainly greater than or equal to |
476 | | // those in the given interval. |
477 | 4 | Ok(Self::CERTAINLY_TRUE) |
478 | 1.33k | } else if !(self.upper.is_null() || rhs.lower.is_null()327 ) |
479 | 17 | && (self.upper < rhs.lower) |
480 | | { |
481 | | // Values in this interval are certainly less than those in the |
482 | | // given interval. |
483 | 0 | Ok(Self::CERTAINLY_FALSE) |
484 | | } else { |
485 | | // All outcomes are possible. |
486 | 1.33k | Ok(Self::UNCERTAIN) |
487 | | } |
488 | 1.34k | } |
489 | | |
490 | | /// Decide if this interval is certainly less than, possibly less than, or |
491 | | /// can't be less than `other` by returning `[true, true]`, `[false, true]` |
492 | | /// or `[false, false]` respectively. |
493 | | /// |
494 | | /// NOTE: This function only works with intervals of the same data type. |
495 | | /// Attempting to compare intervals of different data types will lead |
496 | | /// to an error. |
497 | 5.07k | pub fn lt<T: Borrow<Self>>(&self, other: T) -> Result<Self> { |
498 | 5.07k | other.borrow().gt(self) |
499 | 5.07k | } |
500 | | |
501 | | /// Decide if this interval is certainly less than or equal to, possibly |
502 | | /// less than or equal to, or can't be less than or equal to `other` by |
503 | | /// returning `[true, true]`, `[false, true]` or `[false, false]` respectively. |
504 | | /// |
505 | | /// NOTE: This function only works with intervals of the same data type. |
506 | | /// Attempting to compare intervals of different data types will lead |
507 | | /// to an error. |
508 | 681 | pub fn lt_eq<T: Borrow<Self>>(&self, other: T) -> Result<Self> { |
509 | 681 | other.borrow().gt_eq(self) |
510 | 681 | } |
511 | | |
512 | | /// Decide if this interval is certainly equal to, possibly equal to, or |
513 | | /// can't be equal to `other` by returning `[true, true]`, `[false, true]` |
514 | | /// or `[false, false]` respectively. |
515 | | /// |
516 | | /// NOTE: This function only works with intervals of the same data type. |
517 | | /// Attempting to compare intervals of different data types will lead |
518 | | /// to an error. |
519 | 5 | pub fn equal<T: Borrow<Self>>(&self, other: T) -> Result<Self> { |
520 | 5 | let rhs = other.borrow(); |
521 | 5 | if get_result_type(&self.data_type(), &Operator::Eq, &rhs.data_type()).is_err() { |
522 | 0 | internal_err!( |
523 | 0 | "Interval data types must be compatible for equality checks, lhs:{}, rhs:{}", |
524 | 0 | self.data_type(), |
525 | 0 | rhs.data_type() |
526 | 0 | ) |
527 | 5 | } else if !self.lower.is_null() |
528 | 2 | && (self.lower == self.upper) |
529 | 0 | && (rhs.lower == rhs.upper) |
530 | 0 | && (self.lower == rhs.lower) |
531 | | { |
532 | 0 | Ok(Self::CERTAINLY_TRUE) |
533 | 5 | } else if self.intersect(rhs)?0 .is_none() { |
534 | 0 | Ok(Self::CERTAINLY_FALSE) |
535 | | } else { |
536 | 5 | Ok(Self::UNCERTAIN) |
537 | | } |
538 | 5 | } |
539 | | |
540 | | /// Compute the logical conjunction of this (boolean) interval with the |
541 | | /// given boolean interval. |
542 | 5.74k | pub fn and<T: Borrow<Self>>(&self, other: T) -> Result<Self> { |
543 | 5.74k | let rhs = other.borrow(); |
544 | 5.74k | match (&self.lower, &self.upper, &rhs.lower, &rhs.upper) { |
545 | | ( |
546 | 5.74k | &ScalarValue::Boolean(Some(self_lower)), |
547 | 5.74k | &ScalarValue::Boolean(Some(self_upper)), |
548 | 5.74k | &ScalarValue::Boolean(Some(other_lower)), |
549 | 5.74k | &ScalarValue::Boolean(Some(other_upper)), |
550 | | ) => { |
551 | 5.74k | let lower = self_lower && other_lower2 ; |
552 | 5.74k | let upper = self_upper && other_upper5.73k ; |
553 | | |
554 | 5.74k | Ok(Self { |
555 | 5.74k | lower: ScalarValue::Boolean(Some(lower)), |
556 | 5.74k | upper: ScalarValue::Boolean(Some(upper)), |
557 | 5.74k | }) |
558 | | } |
559 | 0 | _ => internal_err!("Incompatible data types for logical conjunction"), |
560 | | } |
561 | 5.74k | } |
562 | | |
563 | | /// Compute the logical disjunction of this boolean interval with the |
564 | | /// given boolean interval. |
565 | 0 | pub fn or<T: Borrow<Self>>(&self, other: T) -> Result<Self> { |
566 | 0 | let rhs = other.borrow(); |
567 | 0 | match (&self.lower, &self.upper, &rhs.lower, &rhs.upper) { |
568 | | ( |
569 | 0 | &ScalarValue::Boolean(Some(self_lower)), |
570 | 0 | &ScalarValue::Boolean(Some(self_upper)), |
571 | 0 | &ScalarValue::Boolean(Some(other_lower)), |
572 | 0 | &ScalarValue::Boolean(Some(other_upper)), |
573 | | ) => { |
574 | 0 | let lower = self_lower || other_lower; |
575 | 0 | let upper = self_upper || other_upper; |
576 | | |
577 | 0 | Ok(Self { |
578 | 0 | lower: ScalarValue::Boolean(Some(lower)), |
579 | 0 | upper: ScalarValue::Boolean(Some(upper)), |
580 | 0 | }) |
581 | | } |
582 | 0 | _ => internal_err!("Incompatible data types for logical conjunction"), |
583 | | } |
584 | 0 | } |
585 | | |
586 | | /// Compute the logical negation of this (boolean) interval. |
587 | 0 | pub fn not(&self) -> Result<Self> { |
588 | 0 | if self.data_type().ne(&DataType::Boolean) { |
589 | 0 | internal_err!("Cannot apply logical negation to a non-boolean interval") |
590 | 0 | } else if self == &Self::CERTAINLY_TRUE { |
591 | 0 | Ok(Self::CERTAINLY_FALSE) |
592 | 0 | } else if self == &Self::CERTAINLY_FALSE { |
593 | 0 | Ok(Self::CERTAINLY_TRUE) |
594 | | } else { |
595 | 0 | Ok(Self::UNCERTAIN) |
596 | | } |
597 | 0 | } |
598 | | |
599 | | /// Compute the intersection of this interval with the given interval. |
600 | | /// If the intersection is empty, return `None`. |
601 | | /// |
602 | | /// NOTE: This function only works with intervals of the same data type. |
603 | | /// Attempting to compare intervals of different data types will lead |
604 | | /// to an error. |
605 | 61.6k | pub fn intersect<T: Borrow<Self>>(&self, other: T) -> Result<Option<Self>> { |
606 | 61.6k | let rhs = other.borrow(); |
607 | 61.6k | if self.data_type().ne(&rhs.data_type()) { |
608 | 0 | return internal_err!( |
609 | 0 | "Only intervals with the same data type are intersectable, lhs:{}, rhs:{}", |
610 | 0 | self.data_type(), |
611 | 0 | rhs.data_type() |
612 | 0 | ); |
613 | 61.6k | }; |
614 | 61.6k | |
615 | 61.6k | // If it is evident that the result is an empty interval, short-circuit |
616 | 61.6k | // and directly return `None`. |
617 | 61.6k | if (!(self.lower.is_null() || rhs.upper.is_null()35.6k ) && self.lower > rhs.upper17.2k ) |
618 | 61.6k | || (!(self.upper.is_null() || rhs.lower.is_null()20.9k ) && self.upper < rhs.lower17.2k ) |
619 | | { |
620 | 4 | return Ok(None); |
621 | 61.6k | } |
622 | 61.6k | |
623 | 61.6k | let lower = max_of_bounds(&self.lower, &rhs.lower); |
624 | 61.6k | let upper = min_of_bounds(&self.upper, &rhs.upper); |
625 | 61.6k | |
626 | 61.6k | // New lower and upper bounds must always construct a valid interval. |
627 | 61.6k | assert!( |
628 | 61.6k | (lower.is_null() || upper.is_null()57.8k || (lower <= upper)39.4k ), |
629 | 0 | "The intersection of two intervals can not be an invalid interval" |
630 | | ); |
631 | | |
632 | 61.6k | Ok(Some(Self { lower, upper })) |
633 | 61.6k | } |
634 | | |
635 | | /// Decide if this interval certainly contains, possibly contains, or can't |
636 | | /// contain a [`ScalarValue`] (`other`) by returning `[true, true]`, |
637 | | /// `[false, true]` or `[false, false]` respectively. |
638 | | /// |
639 | | /// NOTE: This function only works with intervals of the same data type. |
640 | | /// Attempting to compare intervals of different data types will lead |
641 | | /// to an error. |
642 | 0 | pub fn contains_value<T: Borrow<ScalarValue>>(&self, other: T) -> Result<bool> { |
643 | 0 | let rhs = other.borrow(); |
644 | 0 | if self.data_type().ne(&rhs.data_type()) { |
645 | 0 | return internal_err!( |
646 | 0 | "Data types must be compatible for containment checks, lhs:{}, rhs:{}", |
647 | 0 | self.data_type(), |
648 | 0 | rhs.data_type() |
649 | 0 | ); |
650 | 0 | } |
651 | 0 |
|
652 | 0 | // We only check the upper bound for a `None` value because `None` |
653 | 0 | // values are less than `Some` values according to Rust. |
654 | 0 | Ok(&self.lower <= rhs && (self.upper.is_null() || rhs <= &self.upper)) |
655 | 0 | } |
656 | | |
657 | | /// Decide if this interval is a superset of, overlaps with, or |
658 | | /// disjoint with `other` by returning `[true, true]`, `[false, true]` or |
659 | | /// `[false, false]` respectively. |
660 | | /// |
661 | | /// NOTE: This function only works with intervals of the same data type. |
662 | | /// Attempting to compare intervals of different data types will lead |
663 | | /// to an error. |
664 | 11.5k | pub fn contains<T: Borrow<Self>>(&self, other: T) -> Result<Self> { |
665 | 11.5k | let rhs = other.borrow(); |
666 | 11.5k | if self.data_type().ne(&rhs.data_type()) { |
667 | 0 | return internal_err!( |
668 | 0 | "Interval data types must match for containment checks, lhs:{}, rhs:{}", |
669 | 0 | self.data_type(), |
670 | 0 | rhs.data_type() |
671 | 0 | ); |
672 | 11.5k | }; |
673 | 11.5k | |
674 | 11.5k | match self.intersect(rhs)?0 { |
675 | 11.5k | Some(intersection) => { |
676 | 11.5k | if &intersection == rhs { |
677 | 5.75k | Ok(Self::CERTAINLY_TRUE) |
678 | | } else { |
679 | 5.75k | Ok(Self::UNCERTAIN) |
680 | | } |
681 | | } |
682 | 4 | None => Ok(Self::CERTAINLY_FALSE), |
683 | | } |
684 | 11.5k | } |
685 | | |
686 | | /// Add the given interval (`other`) to this interval. Say we have intervals |
687 | | /// `[a1, b1]` and `[a2, b2]`, then their sum is `[a1 + a2, b1 + b2]`. Note |
688 | | /// that this represents all possible values the sum can take if one can |
689 | | /// choose single values arbitrarily from each of the operands. |
690 | 22.1k | pub fn add<T: Borrow<Self>>(&self, other: T) -> Result<Self> { |
691 | 22.1k | let rhs = other.borrow(); |
692 | 22.1k | let dt = get_result_type(&self.data_type(), &Operator::Plus, &rhs.data_type())?0 ; |
693 | | |
694 | 22.1k | Ok(Self::new( |
695 | 22.1k | add_bounds::<false>(&dt, &self.lower, &rhs.lower), |
696 | 22.1k | add_bounds::<true>(&dt, &self.upper, &rhs.upper), |
697 | 22.1k | )) |
698 | 22.1k | } |
699 | | |
700 | | /// Subtract the given interval (`other`) from this interval. Say we have |
701 | | /// intervals `[a1, b1]` and `[a2, b2]`, then their difference is |
702 | | /// `[a1 - b2, b1 - a2]`. Note that this represents all possible values the |
703 | | /// difference can take if one can choose single values arbitrarily from |
704 | | /// each of the operands. |
705 | 44.3k | pub fn sub<T: Borrow<Interval>>(&self, other: T) -> Result<Self> { |
706 | 44.3k | let rhs = other.borrow(); |
707 | 44.3k | let dt = get_result_type(&self.data_type(), &Operator::Minus, &rhs.data_type())?0 ; |
708 | | |
709 | 44.3k | Ok(Self::new( |
710 | 44.3k | sub_bounds::<false>(&dt, &self.lower, &rhs.upper), |
711 | 44.3k | sub_bounds::<true>(&dt, &self.upper, &rhs.lower), |
712 | 44.3k | )) |
713 | 44.3k | } |
714 | | |
715 | | /// Multiply the given interval (`other`) with this interval. Say we have |
716 | | /// intervals `[a1, b1]` and `[a2, b2]`, then their product is `[min(a1 * a2, |
717 | | /// a1 * b2, b1 * a2, b1 * b2), max(a1 * a2, a1 * b2, b1 * a2, b1 * b2)]`. |
718 | | /// Note that this represents all possible values the product can take if |
719 | | /// one can choose single values arbitrarily from each of the operands. |
720 | | /// |
721 | | /// NOTE: This function only works with intervals of the same data type. |
722 | | /// Attempting to compare intervals of different data types will lead |
723 | | /// to an error. |
724 | 0 | pub fn mul<T: Borrow<Self>>(&self, other: T) -> Result<Self> { |
725 | 0 | let rhs = other.borrow(); |
726 | 0 | let dt = if self.data_type().eq(&rhs.data_type()) { |
727 | 0 | self.data_type() |
728 | | } else { |
729 | 0 | return internal_err!( |
730 | 0 | "Intervals must have the same data type for multiplication, lhs:{}, rhs:{}", |
731 | 0 | self.data_type(), |
732 | 0 | rhs.data_type() |
733 | 0 | ); |
734 | | }; |
735 | | |
736 | 0 | let zero = ScalarValue::new_zero(&dt)?; |
737 | | |
738 | 0 | let result = match ( |
739 | 0 | self.contains_value(&zero)?, |
740 | 0 | rhs.contains_value(&zero)?, |
741 | 0 | dt.is_unsigned_integer(), |
742 | | ) { |
743 | 0 | (true, true, false) => mul_helper_multi_zero_inclusive(&dt, self, rhs), |
744 | | (true, false, false) => { |
745 | 0 | mul_helper_single_zero_inclusive(&dt, self, rhs, zero) |
746 | | } |
747 | | (false, true, false) => { |
748 | 0 | mul_helper_single_zero_inclusive(&dt, rhs, self, zero) |
749 | | } |
750 | 0 | _ => mul_helper_zero_exclusive(&dt, self, rhs, zero), |
751 | | }; |
752 | 0 | Ok(result) |
753 | 0 | } |
754 | | |
755 | | /// Divide this interval by the given interval (`other`). Say we have intervals |
756 | | /// `[a1, b1]` and `[a2, b2]`, then their division is `[a1, b1] * [1 / b2, 1 / a2]` |
757 | | /// if `0 ∉ [a2, b2]` and `[NEG_INF, INF]` otherwise. Note that this represents |
758 | | /// all possible values the quotient can take if one can choose single values |
759 | | /// arbitrarily from each of the operands. |
760 | | /// |
761 | | /// NOTE: This function only works with intervals of the same data type. |
762 | | /// Attempting to compare intervals of different data types will lead |
763 | | /// to an error. |
764 | | /// |
765 | | /// **TODO**: Once interval sets are supported, cases where the divisor contains |
766 | | /// zero should result in an interval set, not the universal set. |
767 | 0 | pub fn div<T: Borrow<Self>>(&self, other: T) -> Result<Self> { |
768 | 0 | let rhs = other.borrow(); |
769 | 0 | let dt = if self.data_type().eq(&rhs.data_type()) { |
770 | 0 | self.data_type() |
771 | | } else { |
772 | 0 | return internal_err!( |
773 | 0 | "Intervals must have the same data type for division, lhs:{}, rhs:{}", |
774 | 0 | self.data_type(), |
775 | 0 | rhs.data_type() |
776 | 0 | ); |
777 | | }; |
778 | | |
779 | 0 | let zero = ScalarValue::new_zero(&dt)?; |
780 | | // We want 0 to be approachable from both negative and positive sides. |
781 | 0 | let zero_point = match &dt { |
782 | 0 | DataType::Float32 | DataType::Float64 => Self::new(zero.clone(), zero), |
783 | 0 | _ => Self::new(prev_value(zero.clone()), next_value(zero)), |
784 | | }; |
785 | | |
786 | | // Exit early with an unbounded interval if zero is strictly inside the |
787 | | // right hand side: |
788 | 0 | if rhs.contains(&zero_point)? == Self::CERTAINLY_TRUE && !dt.is_unsigned_integer() |
789 | | { |
790 | 0 | Self::make_unbounded(&dt) |
791 | | } |
792 | | // At this point, we know that only one endpoint of the right hand side |
793 | | // can be zero. |
794 | 0 | else if self.contains(&zero_point)? == Self::CERTAINLY_TRUE |
795 | 0 | && !dt.is_unsigned_integer() |
796 | | { |
797 | 0 | Ok(div_helper_lhs_zero_inclusive(&dt, self, rhs, &zero_point)) |
798 | | } else { |
799 | 0 | Ok(div_helper_zero_exclusive(&dt, self, rhs, &zero_point)) |
800 | | } |
801 | 0 | } |
802 | | |
803 | | /// Returns the cardinality of this interval, which is the number of all |
804 | | /// distinct points inside it. This function returns `None` if: |
805 | | /// - The interval is unbounded from either side, or |
806 | | /// - Cardinality calculations for the datatype in question is not |
807 | | /// implemented yet, or |
808 | | /// - An overflow occurs during the calculation: This case can only arise |
809 | | /// when the calculated cardinality does not fit in an `u64`. |
810 | 128 | pub fn cardinality(&self) -> Option<u64> { |
811 | 128 | let data_type = self.data_type(); |
812 | 128 | if data_type.is_integer() { |
813 | 118 | self.upper.distance(&self.lower).map(|diff| diff as u64107 ) |
814 | 10 | } else if data_type.is_floating() { |
815 | | // Negative numbers are sorted in the reverse order. To |
816 | | // always have a positive difference after the subtraction, |
817 | | // we perform following transformation: |
818 | 4 | match (&self.lower, &self.upper) { |
819 | | // Exploit IEEE 754 ordering properties to calculate the correct |
820 | | // cardinality in all cases (including subnormals). |
821 | | ( |
822 | 4 | ScalarValue::Float32(Some(lower)), |
823 | 4 | ScalarValue::Float32(Some(upper)), |
824 | | ) => { |
825 | 4 | let lower_bits = map_floating_point_order!(lower.to_bits(), u32); |
826 | 4 | let upper_bits = map_floating_point_order!(upper.to_bits(), u32); |
827 | 4 | Some((upper_bits - lower_bits) as u64) |
828 | | } |
829 | | ( |
830 | 0 | ScalarValue::Float64(Some(lower)), |
831 | 0 | ScalarValue::Float64(Some(upper)), |
832 | | ) => { |
833 | 0 | let lower_bits = map_floating_point_order!(lower.to_bits(), u64); |
834 | 0 | let upper_bits = map_floating_point_order!(upper.to_bits(), u64); |
835 | 0 | let count = upper_bits - lower_bits; |
836 | 0 | (count != u64::MAX).then_some(count) |
837 | | } |
838 | 0 | _ => None, |
839 | | } |
840 | | } else { |
841 | | // Cardinality calculations are not implemented for this data type yet: |
842 | 6 | None |
843 | | } |
844 | 128 | .map(|result| result + 1111 ) |
845 | 128 | } |
846 | | |
847 | | /// Reflects an [`Interval`] around the point zero. |
848 | | /// |
849 | | /// This method computes the arithmetic negation of the interval, reflecting |
850 | | /// it about the origin of the number line. This operation swaps and negates |
851 | | /// the lower and upper bounds of the interval. |
852 | 0 | pub fn arithmetic_negate(self) -> Result<Self> { |
853 | 0 | Ok(Self { |
854 | 0 | lower: self.upper().clone().arithmetic_negate()?, |
855 | 0 | upper: self.lower().clone().arithmetic_negate()?, |
856 | | }) |
857 | 0 | } |
858 | | } |
859 | | |
860 | | impl Display for Interval { |
861 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
862 | 0 | write!(f, "[{}, {}]", self.lower, self.upper) |
863 | 0 | } |
864 | | } |
865 | | |
866 | | /// Applies the given binary operator the `lhs` and `rhs` arguments. |
867 | 83.7k | pub fn apply_operator(op: &Operator, lhs: &Interval, rhs: &Interval) -> Result<Interval> { |
868 | 83.7k | match *op { |
869 | 5 | Operator::Eq => lhs.equal(rhs), |
870 | 0 | Operator::NotEq => lhs.equal(rhs)?.not(), |
871 | 5.07k | Operator::Gt => lhs.gt(rhs), |
872 | 662 | Operator::GtEq => lhs.gt_eq(rhs), |
873 | 5.07k | Operator::Lt => lhs.lt(rhs), |
874 | 681 | Operator::LtEq => lhs.lt_eq(rhs), |
875 | 5.74k | Operator::And => lhs.and(rhs), |
876 | 22.1k | Operator::Plus => lhs.add(rhs), |
877 | 44.3k | Operator::Minus => lhs.sub(rhs), |
878 | 0 | Operator::Multiply => lhs.mul(rhs), |
879 | 0 | Operator::Divide => lhs.div(rhs), |
880 | 0 | _ => internal_err!("Interval arithmetic does not support the operator {op}"), |
881 | | } |
882 | 83.7k | } |
883 | | |
884 | | /// Helper function used for adding the end-point values of intervals. |
885 | | /// |
886 | | /// **Caution:** This function contains multiple calls to `unwrap()`, and may |
887 | | /// return non-standardized interval bounds. Therefore, it should be used |
888 | | /// with caution. Currently, it is used in contexts where the `DataType` |
889 | | /// (`dt`) is validated prior to calling this function, and the following |
890 | | /// interval creation is standardized with `Interval::new`. |
891 | 44.3k | fn add_bounds<const UPPER: bool>( |
892 | 44.3k | dt: &DataType, |
893 | 44.3k | lhs: &ScalarValue, |
894 | 44.3k | rhs: &ScalarValue, |
895 | 44.3k | ) -> ScalarValue { |
896 | 44.3k | if lhs.is_null() || rhs.is_null()22.0k { |
897 | 22.2k | return ScalarValue::try_from(dt).unwrap(); |
898 | 22.0k | } |
899 | 22.0k | |
900 | 22.0k | match dt { |
901 | | DataType::Float64 | DataType::Float32 => { |
902 | 8.06k | alter_fp_rounding_mode::<UPPER, _>(lhs, rhs, |lhs, rhs| lhs.add_checked(rhs)) |
903 | | } |
904 | 13.9k | _ => lhs.add_checked(rhs), |
905 | | } |
906 | 22.0k | .unwrap_or_else(|_| handle_overflow::<UPPER>(dt, Operator::Plus, lhs, rhs)0 ) |
907 | 44.3k | } |
908 | | |
909 | | /// Helper function used for subtracting the end-point values of intervals. |
910 | | /// |
911 | | /// **Caution:** This function contains multiple calls to `unwrap()`, and may |
912 | | /// return non-standardized interval bounds. Therefore, it should be used |
913 | | /// with caution. Currently, it is used in contexts where the `DataType` |
914 | | /// (`dt`) is validated prior to calling this function, and the following |
915 | | /// interval creation is standardized with `Interval::new`. |
916 | 88.6k | fn sub_bounds<const UPPER: bool>( |
917 | 88.6k | dt: &DataType, |
918 | 88.6k | lhs: &ScalarValue, |
919 | 88.6k | rhs: &ScalarValue, |
920 | 88.6k | ) -> ScalarValue { |
921 | 88.6k | if lhs.is_null() || rhs.is_null()44.2k { |
922 | 66.5k | return ScalarValue::try_from(dt).unwrap(); |
923 | 22.0k | } |
924 | 22.0k | |
925 | 22.0k | match dt { |
926 | | DataType::Float64 | DataType::Float32 => { |
927 | 8.06k | alter_fp_rounding_mode::<UPPER, _>(lhs, rhs, |lhs, rhs| lhs.sub_checked(rhs)) |
928 | | } |
929 | 14.0k | _ => lhs.sub_checked(rhs), |
930 | | } |
931 | 22.0k | .unwrap_or_else(|_| handle_overflow::<UPPER>(dt, Operator::Minus, lhs, rhs)0 ) |
932 | 88.6k | } |
933 | | |
934 | | /// Helper function used for multiplying the end-point values of intervals. |
935 | | /// |
936 | | /// **Caution:** This function contains multiple calls to `unwrap()`, and may |
937 | | /// return non-standardized interval bounds. Therefore, it should be used |
938 | | /// with caution. Currently, it is used in contexts where the `DataType` |
939 | | /// (`dt`) is validated prior to calling this function, and the following |
940 | | /// interval creation is standardized with `Interval::new`. |
941 | 0 | fn mul_bounds<const UPPER: bool>( |
942 | 0 | dt: &DataType, |
943 | 0 | lhs: &ScalarValue, |
944 | 0 | rhs: &ScalarValue, |
945 | 0 | ) -> ScalarValue { |
946 | 0 | if lhs.is_null() || rhs.is_null() { |
947 | 0 | return ScalarValue::try_from(dt).unwrap(); |
948 | 0 | } |
949 | 0 |
|
950 | 0 | match dt { |
951 | | DataType::Float64 | DataType::Float32 => { |
952 | 0 | alter_fp_rounding_mode::<UPPER, _>(lhs, rhs, |lhs, rhs| lhs.mul_checked(rhs)) |
953 | | } |
954 | 0 | _ => lhs.mul_checked(rhs), |
955 | | } |
956 | 0 | .unwrap_or_else(|_| handle_overflow::<UPPER>(dt, Operator::Multiply, lhs, rhs)) |
957 | 0 | } |
958 | | |
959 | | /// Helper function used for dividing the end-point values of intervals. |
960 | | /// |
961 | | /// **Caution:** This function contains multiple calls to `unwrap()`, and may |
962 | | /// return non-standardized interval bounds. Therefore, it should be used |
963 | | /// with caution. Currently, it is used in contexts where the `DataType` |
964 | | /// (`dt`) is validated prior to calling this function, and the following |
965 | | /// interval creation is standardized with `Interval::new`. |
966 | 0 | fn div_bounds<const UPPER: bool>( |
967 | 0 | dt: &DataType, |
968 | 0 | lhs: &ScalarValue, |
969 | 0 | rhs: &ScalarValue, |
970 | 0 | ) -> ScalarValue { |
971 | 0 | let zero = ScalarValue::new_zero(dt).unwrap(); |
972 | 0 |
|
973 | 0 | if (lhs.is_null() || rhs.eq(&zero)) || (dt.is_unsigned_integer() && rhs.is_null()) { |
974 | 0 | return ScalarValue::try_from(dt).unwrap(); |
975 | 0 | } else if rhs.is_null() { |
976 | 0 | return zero; |
977 | 0 | } |
978 | 0 |
|
979 | 0 | match dt { |
980 | | DataType::Float64 | DataType::Float32 => { |
981 | 0 | alter_fp_rounding_mode::<UPPER, _>(lhs, rhs, |lhs, rhs| lhs.div(rhs)) |
982 | | } |
983 | 0 | _ => lhs.div(rhs), |
984 | | } |
985 | 0 | .unwrap_or_else(|_| handle_overflow::<UPPER>(dt, Operator::Divide, lhs, rhs)) |
986 | 0 | } |
987 | | |
988 | | /// This function handles cases where an operation results in an overflow. Such |
989 | | /// results are converted to an *unbounded endpoint* if: |
990 | | /// - We are calculating an upper bound and we have a positive overflow. |
991 | | /// - We are calculating a lower bound and we have a negative overflow. |
992 | | /// |
993 | | /// Otherwise, the function sets the endpoint as: |
994 | | /// - The minimum representable number with the given datatype (`dt`) if |
995 | | /// we are calculating an upper bound and we have a negative overflow. |
996 | | /// - The maximum representable number with the given datatype (`dt`) if |
997 | | /// we are calculating a lower bound and we have a positive overflow. |
998 | | /// |
999 | | /// **Caution:** This function contains multiple calls to `unwrap()`, and may |
1000 | | /// return non-standardized interval bounds. Therefore, it should be used |
1001 | | /// with caution. Currently, it is used in contexts where the `DataType` |
1002 | | /// (`dt`) is validated prior to calling this function, `op` is supported by |
1003 | | /// interval library, and the following interval creation is standardized with |
1004 | | /// `Interval::new`. |
1005 | 0 | fn handle_overflow<const UPPER: bool>( |
1006 | 0 | dt: &DataType, |
1007 | 0 | op: Operator, |
1008 | 0 | lhs: &ScalarValue, |
1009 | 0 | rhs: &ScalarValue, |
1010 | 0 | ) -> ScalarValue { |
1011 | 0 | let zero = ScalarValue::new_zero(dt).unwrap(); |
1012 | 0 | let positive_sign = match op { |
1013 | | Operator::Multiply | Operator::Divide => { |
1014 | 0 | lhs.lt(&zero) && rhs.lt(&zero) || lhs.gt(&zero) && rhs.gt(&zero) |
1015 | | } |
1016 | 0 | Operator::Plus => lhs.ge(&zero), |
1017 | 0 | Operator::Minus => lhs.ge(rhs), |
1018 | | _ => { |
1019 | 0 | unreachable!() |
1020 | | } |
1021 | | }; |
1022 | 0 | match (UPPER, positive_sign) { |
1023 | 0 | (true, true) | (false, false) => ScalarValue::try_from(dt).unwrap(), |
1024 | | (true, false) => { |
1025 | 0 | get_extreme_value!(MIN, dt) |
1026 | | } |
1027 | | (false, true) => { |
1028 | 0 | get_extreme_value!(MAX, dt) |
1029 | | } |
1030 | | } |
1031 | 0 | } |
1032 | | |
1033 | | // This function should remain private since it may corrupt the an interval if |
1034 | | // used without caution. |
1035 | 5.24k | fn next_value(value: ScalarValue) -> ScalarValue { |
1036 | | use ScalarValue::*; |
1037 | 5.24k | value_transition!0 (MAX, true, value) |
1038 | 5.24k | } |
1039 | | |
1040 | | // This function should remain private since it may corrupt the an interval if |
1041 | | // used without caution. |
1042 | 9.28k | fn prev_value(value: ScalarValue) -> ScalarValue { |
1043 | | use ScalarValue::*; |
1044 | 9.28k | value_transition!0 (MIN, false, value) |
1045 | 9.28k | } |
1046 | | |
1047 | | trait OneTrait: Sized + std::ops::Add + std::ops::Sub { |
1048 | | fn one() -> Self; |
1049 | | } |
1050 | | macro_rules! impl_OneTrait{ |
1051 | 2.67k | ($($m:ty),*) => {$( impl OneTrait for $m { fn one() -> Self { 1 as $m } })*} |
1052 | | } |
1053 | | impl_OneTrait! {u8, u16, u32, u64, i8, i16, i32, i64, i128} |
1054 | | |
1055 | | impl OneTrait for IntervalDayTime { |
1056 | 328 | fn one() -> Self { |
1057 | 328 | IntervalDayTime { |
1058 | 328 | days: 0, |
1059 | 328 | milliseconds: 1, |
1060 | 328 | } |
1061 | 328 | } |
1062 | | } |
1063 | | |
1064 | | impl OneTrait for IntervalMonthDayNano { |
1065 | 0 | fn one() -> Self { |
1066 | 0 | IntervalMonthDayNano { |
1067 | 0 | months: 0, |
1068 | 0 | days: 0, |
1069 | 0 | nanoseconds: 1, |
1070 | 0 | } |
1071 | 0 | } |
1072 | | } |
1073 | | |
1074 | | /// This function either increments or decrements its argument, depending on |
1075 | | /// the `INC` value (where a `true` value corresponds to the increment). |
1076 | 3.00k | fn increment_decrement<const INC: bool, T: OneTrait + SubAssign + AddAssign>( |
1077 | 3.00k | mut value: T, |
1078 | 3.00k | ) -> T { |
1079 | 3.00k | if INC { |
1080 | 2.31k | value.add_assign(T::one()); |
1081 | 2.31k | } else { |
1082 | 689 | value.sub_assign(T::one()); |
1083 | 689 | } |
1084 | 3.00k | value |
1085 | 3.00k | } |
1086 | | |
1087 | | /// This function returns the next/previous value depending on the `INC` value. |
1088 | | /// If `true`, it returns the next value; otherwise it returns the previous value. |
1089 | 14.5k | fn next_value_helper<const INC: bool>(value: ScalarValue) -> ScalarValue { |
1090 | | use ScalarValue::*; |
1091 | 0 | match value { |
1092 | | // f32/f64::NEG_INF/INF and f32/f64::NaN values should not emerge at this point. |
1093 | 0 | Float32(Some(val)) => { |
1094 | 0 | assert!(val.is_finite(), "Non-standardized floating point usage"); |
1095 | 0 | Float32(Some(if INC { next_up(val) } else { next_down(val) })) |
1096 | | } |
1097 | 1.36k | Float64(Some(val)) => { |
1098 | 1.36k | assert!(val.is_finite(), "Non-standardized floating point usage"0 ); |
1099 | 1.36k | Float64(Some(if INC { next_up(val) } else { next_down(val)0 })) |
1100 | | } |
1101 | 0 | Int8(Some(val)) => Int8(Some(increment_decrement::<INC, i8>(val))), |
1102 | 0 | Int16(Some(val)) => Int16(Some(increment_decrement::<INC, i16>(val))), |
1103 | 1.45k | Int32(Some(val)) => Int32(Some(increment_decrement::<INC, i32>(val))), |
1104 | 212 | Int64(Some(val)) => Int64(Some(increment_decrement::<INC, i64>(val))), |
1105 | 0 | UInt8(Some(val)) => UInt8(Some(increment_decrement::<INC, u8>(val))), |
1106 | 0 | UInt16(Some(val)) => UInt16(Some(increment_decrement::<INC, u16>(val))), |
1107 | 0 | UInt32(Some(val)) => UInt32(Some(increment_decrement::<INC, u32>(val))), |
1108 | 0 | UInt64(Some(val)) => UInt64(Some(increment_decrement::<INC, u64>(val))), |
1109 | 0 | DurationSecond(Some(val)) => { |
1110 | 0 | DurationSecond(Some(increment_decrement::<INC, i64>(val))) |
1111 | | } |
1112 | 672 | DurationMillisecond(Some(val)) => { |
1113 | 672 | DurationMillisecond(Some(increment_decrement::<INC, i64>(val))) |
1114 | | } |
1115 | 0 | DurationMicrosecond(Some(val)) => { |
1116 | 0 | DurationMicrosecond(Some(increment_decrement::<INC, i64>(val))) |
1117 | | } |
1118 | 0 | DurationNanosecond(Some(val)) => { |
1119 | 0 | DurationNanosecond(Some(increment_decrement::<INC, i64>(val))) |
1120 | | } |
1121 | 0 | TimestampSecond(Some(val), tz) => { |
1122 | 0 | TimestampSecond(Some(increment_decrement::<INC, i64>(val)), tz) |
1123 | | } |
1124 | 336 | TimestampMillisecond(Some(val), tz) => { |
1125 | 336 | TimestampMillisecond(Some(increment_decrement::<INC, i64>(val)), tz) |
1126 | | } |
1127 | 0 | TimestampMicrosecond(Some(val), tz) => { |
1128 | 0 | TimestampMicrosecond(Some(increment_decrement::<INC, i64>(val)), tz) |
1129 | | } |
1130 | 0 | TimestampNanosecond(Some(val), tz) => { |
1131 | 0 | TimestampNanosecond(Some(increment_decrement::<INC, i64>(val)), tz) |
1132 | | } |
1133 | 0 | IntervalYearMonth(Some(val)) => { |
1134 | 0 | IntervalYearMonth(Some(increment_decrement::<INC, i32>(val))) |
1135 | | } |
1136 | 328 | IntervalDayTime(Some(val)) => IntervalDayTime(Some(increment_decrement::< |
1137 | 328 | INC, |
1138 | 328 | arrow::datatypes::IntervalDayTime, |
1139 | 328 | >(val))), |
1140 | 0 | IntervalMonthDayNano(Some(val)) => { |
1141 | 0 | IntervalMonthDayNano(Some(increment_decrement::< |
1142 | 0 | INC, |
1143 | 0 | arrow::datatypes::IntervalMonthDayNano, |
1144 | 0 | >(val))) |
1145 | | } |
1146 | 10.1k | _ => value, // Unbounded values return without change. |
1147 | | } |
1148 | 14.5k | } |
1149 | | |
1150 | | /// Returns the greater of the given interval bounds. Assumes that a `NULL` |
1151 | | /// value represents `NEG_INF`. |
1152 | 61.6k | fn max_of_bounds(first: &ScalarValue, second: &ScalarValue) -> ScalarValue { |
1153 | 61.6k | if !first.is_null() && (second.is_null()35.6k || first >= second35.6k ) { |
1154 | 20.4k | first.clone() |
1155 | | } else { |
1156 | 41.1k | second.clone() |
1157 | | } |
1158 | 61.6k | } |
1159 | | |
1160 | | /// Returns the lesser of the given interval bounds. Assumes that a `NULL` |
1161 | | /// value represents `INF`. |
1162 | 61.6k | fn min_of_bounds(first: &ScalarValue, second: &ScalarValue) -> ScalarValue { |
1163 | 61.6k | if !first.is_null() && (second.is_null()20.9k || first <= second20.9k ) { |
1164 | 20.5k | first.clone() |
1165 | | } else { |
1166 | 41.0k | second.clone() |
1167 | | } |
1168 | 61.6k | } |
1169 | | |
1170 | | /// This function updates the given intervals by enforcing (i.e. propagating) |
1171 | | /// the inequality `left > right` (or the `left >= right` inequality, if `strict` |
1172 | | /// is `true`). |
1173 | | /// |
1174 | | /// Returns a `Result` wrapping an `Option` containing the tuple of resulting |
1175 | | /// intervals. If the comparison is infeasible, returns `None`. |
1176 | | /// |
1177 | | /// Example usage: |
1178 | | /// ``` |
1179 | | /// use datafusion_common::DataFusionError; |
1180 | | /// use datafusion_expr_common::interval_arithmetic::{satisfy_greater, Interval}; |
1181 | | /// |
1182 | | /// let left = Interval::make(Some(-1000.0_f32), Some(1000.0_f32))?; |
1183 | | /// let right = Interval::make(Some(500.0_f32), Some(2000.0_f32))?; |
1184 | | /// let strict = false; |
1185 | | /// assert_eq!( |
1186 | | /// satisfy_greater(&left, &right, strict)?, |
1187 | | /// Some(( |
1188 | | /// Interval::make(Some(500.0_f32), Some(1000.0_f32))?, |
1189 | | /// Interval::make(Some(500.0_f32), Some(1000.0_f32))? |
1190 | | /// )) |
1191 | | /// ); |
1192 | | /// Ok::<(), DataFusionError>(()) |
1193 | | /// ``` |
1194 | | /// |
1195 | | /// NOTE: This function only works with intervals of the same data type. |
1196 | | /// Attempting to compare intervals of different data types will lead |
1197 | | /// to an error. |
1198 | 11.4k | pub fn satisfy_greater( |
1199 | 11.4k | left: &Interval, |
1200 | 11.4k | right: &Interval, |
1201 | 11.4k | strict: bool, |
1202 | 11.4k | ) -> Result<Option<(Interval, Interval)>> { |
1203 | 11.4k | if left.data_type().ne(&right.data_type()) { |
1204 | 0 | return internal_err!( |
1205 | 0 | "Intervals must have the same data type, lhs:{}, rhs:{}", |
1206 | 0 | left.data_type(), |
1207 | 0 | right.data_type() |
1208 | 0 | ); |
1209 | 11.4k | } |
1210 | 11.4k | |
1211 | 11.4k | if !left.upper.is_null() && left.upper <= right.lower1.87k { |
1212 | 0 | if !strict && left.upper == right.lower { |
1213 | | // Singleton intervals: |
1214 | 0 | return Ok(Some(( |
1215 | 0 | Interval::new(left.upper.clone(), left.upper.clone()), |
1216 | 0 | Interval::new(left.upper.clone(), left.upper.clone()), |
1217 | 0 | ))); |
1218 | | } else { |
1219 | | // Left-hand side: <--======----0------------> |
1220 | | // Right-hand side: <------------0--======----> |
1221 | | // No intersection, infeasible to propagate: |
1222 | 0 | return Ok(None); |
1223 | | } |
1224 | 11.4k | } |
1225 | | |
1226 | | // Only the lower bound of left hand side and the upper bound of the right |
1227 | | // hand side can change after propagating the greater-than operation. |
1228 | 11.4k | let new_left_lower = if left.lower.is_null() || left.lower <= right.lower9.56k { |
1229 | 6.52k | if strict { |
1230 | 5.24k | next_value(right.lower.clone()) |
1231 | | } else { |
1232 | 1.28k | right.lower.clone() |
1233 | | } |
1234 | | } else { |
1235 | 4.96k | left.lower.clone() |
1236 | | }; |
1237 | | // Below code is asymmetric relative to the above if statement, because |
1238 | | // `None` compares less than `Some` in Rust. |
1239 | 11.4k | let new_right_upper = if right.upper.is_null() |
1240 | 1.87k | || (!left.upper.is_null() && left.upper <= right.upper1.86k ) |
1241 | | { |
1242 | 10.5k | if strict { |
1243 | 9.28k | prev_value(left.upper.clone()) |
1244 | | } else { |
1245 | 1.27k | left.upper.clone() |
1246 | | } |
1247 | | } else { |
1248 | 932 | right.upper.clone() |
1249 | | }; |
1250 | | |
1251 | 11.4k | Ok(Some(( |
1252 | 11.4k | Interval::new(new_left_lower, left.upper.clone()), |
1253 | 11.4k | Interval::new(right.lower.clone(), new_right_upper), |
1254 | 11.4k | ))) |
1255 | 11.4k | } |
1256 | | |
1257 | | /// Multiplies two intervals that both contain zero. |
1258 | | /// |
1259 | | /// This function takes in two intervals (`lhs` and `rhs`) as arguments and |
1260 | | /// returns their product (whose data type is known to be `dt`). It is |
1261 | | /// specifically designed to handle intervals that contain zero within their |
1262 | | /// ranges. Returns an error if the multiplication of bounds fails. |
1263 | | /// |
1264 | | /// ```text |
1265 | | /// Left-hand side: <-------=====0=====-------> |
1266 | | /// Right-hand side: <-------=====0=====-------> |
1267 | | /// ``` |
1268 | | /// |
1269 | | /// **Caution:** This function contains multiple calls to `unwrap()`. Therefore, |
1270 | | /// it should be used with caution. Currently, it is used in contexts where the |
1271 | | /// `DataType` (`dt`) is validated prior to calling this function. |
1272 | 0 | fn mul_helper_multi_zero_inclusive( |
1273 | 0 | dt: &DataType, |
1274 | 0 | lhs: &Interval, |
1275 | 0 | rhs: &Interval, |
1276 | 0 | ) -> Interval { |
1277 | 0 | if lhs.lower.is_null() |
1278 | 0 | || lhs.upper.is_null() |
1279 | 0 | || rhs.lower.is_null() |
1280 | 0 | || rhs.upper.is_null() |
1281 | | { |
1282 | 0 | return Interval::make_unbounded(dt).unwrap(); |
1283 | 0 | } |
1284 | 0 | // Since unbounded cases are handled above, we can safely |
1285 | 0 | // use the utility functions here to eliminate code duplication. |
1286 | 0 | let lower = min_of_bounds( |
1287 | 0 | &mul_bounds::<false>(dt, &lhs.lower, &rhs.upper), |
1288 | 0 | &mul_bounds::<false>(dt, &rhs.lower, &lhs.upper), |
1289 | 0 | ); |
1290 | 0 | let upper = max_of_bounds( |
1291 | 0 | &mul_bounds::<true>(dt, &lhs.upper, &rhs.upper), |
1292 | 0 | &mul_bounds::<true>(dt, &lhs.lower, &rhs.lower), |
1293 | 0 | ); |
1294 | 0 | // There is no possibility to create an invalid interval. |
1295 | 0 | Interval::new(lower, upper) |
1296 | 0 | } |
1297 | | |
1298 | | /// Multiplies two intervals when only left-hand side interval contains zero. |
1299 | | /// |
1300 | | /// This function takes in two intervals (`lhs` and `rhs`) as arguments and |
1301 | | /// returns their product (whose data type is known to be `dt`). This function |
1302 | | /// serves as a subroutine that handles the specific case when only `lhs` contains |
1303 | | /// zero within its range. The interval not containing zero, i.e. rhs, can lie |
1304 | | /// on either side of zero. Returns an error if the multiplication of bounds fails. |
1305 | | /// |
1306 | | /// ``` text |
1307 | | /// Left-hand side: <-------=====0=====-------> |
1308 | | /// Right-hand side: <--======----0------------> |
1309 | | /// |
1310 | | /// or |
1311 | | /// |
1312 | | /// Left-hand side: <-------=====0=====-------> |
1313 | | /// Right-hand side: <------------0--======----> |
1314 | | /// ``` |
1315 | | /// |
1316 | | /// **Caution:** This function contains multiple calls to `unwrap()`. Therefore, |
1317 | | /// it should be used with caution. Currently, it is used in contexts where the |
1318 | | /// `DataType` (`dt`) is validated prior to calling this function. |
1319 | 0 | fn mul_helper_single_zero_inclusive( |
1320 | 0 | dt: &DataType, |
1321 | 0 | lhs: &Interval, |
1322 | 0 | rhs: &Interval, |
1323 | 0 | zero: ScalarValue, |
1324 | 0 | ) -> Interval { |
1325 | 0 | // With the following interval bounds, there is no possibility to create an invalid interval. |
1326 | 0 | if rhs.upper <= zero && !rhs.upper.is_null() { |
1327 | | // <-------=====0=====-------> |
1328 | | // <--======----0------------> |
1329 | 0 | let lower = mul_bounds::<false>(dt, &lhs.upper, &rhs.lower); |
1330 | 0 | let upper = mul_bounds::<true>(dt, &lhs.lower, &rhs.lower); |
1331 | 0 | Interval::new(lower, upper) |
1332 | | } else { |
1333 | | // <-------=====0=====-------> |
1334 | | // <------------0--======----> |
1335 | 0 | let lower = mul_bounds::<false>(dt, &lhs.lower, &rhs.upper); |
1336 | 0 | let upper = mul_bounds::<true>(dt, &lhs.upper, &rhs.upper); |
1337 | 0 | Interval::new(lower, upper) |
1338 | | } |
1339 | 0 | } |
1340 | | |
1341 | | /// Multiplies two intervals when neither of them contains zero. |
1342 | | /// |
1343 | | /// This function takes in two intervals (`lhs` and `rhs`) as arguments and |
1344 | | /// returns their product (whose data type is known to be `dt`). It is |
1345 | | /// specifically designed to handle intervals that do not contain zero within |
1346 | | /// their ranges. Returns an error if the multiplication of bounds fails. |
1347 | | /// |
1348 | | /// ``` text |
1349 | | /// Left-hand side: <--======----0------------> |
1350 | | /// Right-hand side: <--======----0------------> |
1351 | | /// |
1352 | | /// or |
1353 | | /// |
1354 | | /// Left-hand side: <--======----0------------> |
1355 | | /// Right-hand side: <------------0--======----> |
1356 | | /// |
1357 | | /// or |
1358 | | /// |
1359 | | /// Left-hand side: <------------0--======----> |
1360 | | /// Right-hand side: <--======----0------------> |
1361 | | /// |
1362 | | /// or |
1363 | | /// |
1364 | | /// Left-hand side: <------------0--======----> |
1365 | | /// Right-hand side: <------------0--======----> |
1366 | | /// ``` |
1367 | | /// |
1368 | | /// **Caution:** This function contains multiple calls to `unwrap()`. Therefore, |
1369 | | /// it should be used with caution. Currently, it is used in contexts where the |
1370 | | /// `DataType` (`dt`) is validated prior to calling this function. |
1371 | 0 | fn mul_helper_zero_exclusive( |
1372 | 0 | dt: &DataType, |
1373 | 0 | lhs: &Interval, |
1374 | 0 | rhs: &Interval, |
1375 | 0 | zero: ScalarValue, |
1376 | 0 | ) -> Interval { |
1377 | 0 | let (lower, upper) = match ( |
1378 | 0 | lhs.upper <= zero && !lhs.upper.is_null(), |
1379 | 0 | rhs.upper <= zero && !rhs.upper.is_null(), |
1380 | | ) { |
1381 | | // With the following interval bounds, there is no possibility to create an invalid interval. |
1382 | 0 | (true, true) => ( |
1383 | 0 | // <--======----0------------> |
1384 | 0 | // <--======----0------------> |
1385 | 0 | mul_bounds::<false>(dt, &lhs.upper, &rhs.upper), |
1386 | 0 | mul_bounds::<true>(dt, &lhs.lower, &rhs.lower), |
1387 | 0 | ), |
1388 | 0 | (true, false) => ( |
1389 | 0 | // <--======----0------------> |
1390 | 0 | // <------------0--======----> |
1391 | 0 | mul_bounds::<false>(dt, &lhs.lower, &rhs.upper), |
1392 | 0 | mul_bounds::<true>(dt, &lhs.upper, &rhs.lower), |
1393 | 0 | ), |
1394 | 0 | (false, true) => ( |
1395 | 0 | // <------------0--======----> |
1396 | 0 | // <--======----0------------> |
1397 | 0 | mul_bounds::<false>(dt, &rhs.lower, &lhs.upper), |
1398 | 0 | mul_bounds::<true>(dt, &rhs.upper, &lhs.lower), |
1399 | 0 | ), |
1400 | 0 | (false, false) => ( |
1401 | 0 | // <------------0--======----> |
1402 | 0 | // <------------0--======----> |
1403 | 0 | mul_bounds::<false>(dt, &lhs.lower, &rhs.lower), |
1404 | 0 | mul_bounds::<true>(dt, &lhs.upper, &rhs.upper), |
1405 | 0 | ), |
1406 | | }; |
1407 | 0 | Interval::new(lower, upper) |
1408 | 0 | } |
1409 | | |
1410 | | /// Divides the left-hand side interval by the right-hand side interval when |
1411 | | /// the former contains zero. |
1412 | | /// |
1413 | | /// This function takes in two intervals (`lhs` and `rhs`) as arguments and |
1414 | | /// returns their quotient (whose data type is known to be `dt`). This function |
1415 | | /// serves as a subroutine that handles the specific case when only `lhs` contains |
1416 | | /// zero within its range. Returns an error if the division of bounds fails. |
1417 | | /// |
1418 | | /// ``` text |
1419 | | /// Left-hand side: <-------=====0=====-------> |
1420 | | /// Right-hand side: <--======----0------------> |
1421 | | /// |
1422 | | /// or |
1423 | | /// |
1424 | | /// Left-hand side: <-------=====0=====-------> |
1425 | | /// Right-hand side: <------------0--======----> |
1426 | | /// ``` |
1427 | | /// |
1428 | | /// **Caution:** This function contains multiple calls to `unwrap()`. Therefore, |
1429 | | /// it should be used with caution. Currently, it is used in contexts where the |
1430 | | /// `DataType` (`dt`) is validated prior to calling this function. |
1431 | 0 | fn div_helper_lhs_zero_inclusive( |
1432 | 0 | dt: &DataType, |
1433 | 0 | lhs: &Interval, |
1434 | 0 | rhs: &Interval, |
1435 | 0 | zero_point: &Interval, |
1436 | 0 | ) -> Interval { |
1437 | 0 | // With the following interval bounds, there is no possibility to create an invalid interval. |
1438 | 0 | if rhs.upper <= zero_point.lower && !rhs.upper.is_null() { |
1439 | | // <-------=====0=====-------> |
1440 | | // <--======----0------------> |
1441 | 0 | let lower = div_bounds::<false>(dt, &lhs.upper, &rhs.upper); |
1442 | 0 | let upper = div_bounds::<true>(dt, &lhs.lower, &rhs.upper); |
1443 | 0 | Interval::new(lower, upper) |
1444 | | } else { |
1445 | | // <-------=====0=====-------> |
1446 | | // <------------0--======----> |
1447 | 0 | let lower = div_bounds::<false>(dt, &lhs.lower, &rhs.lower); |
1448 | 0 | let upper = div_bounds::<true>(dt, &lhs.upper, &rhs.lower); |
1449 | 0 | Interval::new(lower, upper) |
1450 | | } |
1451 | 0 | } |
1452 | | |
1453 | | /// Divides the left-hand side interval by the right-hand side interval when |
1454 | | /// neither interval contains zero. |
1455 | | /// |
1456 | | /// This function takes in two intervals (`lhs` and `rhs`) as arguments and |
1457 | | /// returns their quotient (whose data type is known to be `dt`). It is |
1458 | | /// specifically designed to handle intervals that do not contain zero within |
1459 | | /// their ranges. Returns an error if the division of bounds fails. |
1460 | | /// |
1461 | | /// ``` text |
1462 | | /// Left-hand side: <--======----0------------> |
1463 | | /// Right-hand side: <--======----0------------> |
1464 | | /// |
1465 | | /// or |
1466 | | /// |
1467 | | /// Left-hand side: <--======----0------------> |
1468 | | /// Right-hand side: <------------0--======----> |
1469 | | /// |
1470 | | /// or |
1471 | | /// |
1472 | | /// Left-hand side: <------------0--======----> |
1473 | | /// Right-hand side: <--======----0------------> |
1474 | | /// |
1475 | | /// or |
1476 | | /// |
1477 | | /// Left-hand side: <------------0--======----> |
1478 | | /// Right-hand side: <------------0--======----> |
1479 | | /// ``` |
1480 | | /// |
1481 | | /// **Caution:** This function contains multiple calls to `unwrap()`. Therefore, |
1482 | | /// it should be used with caution. Currently, it is used in contexts where the |
1483 | | /// `DataType` (`dt`) is validated prior to calling this function. |
1484 | 0 | fn div_helper_zero_exclusive( |
1485 | 0 | dt: &DataType, |
1486 | 0 | lhs: &Interval, |
1487 | 0 | rhs: &Interval, |
1488 | 0 | zero_point: &Interval, |
1489 | 0 | ) -> Interval { |
1490 | 0 | let (lower, upper) = match ( |
1491 | 0 | lhs.upper <= zero_point.lower && !lhs.upper.is_null(), |
1492 | 0 | rhs.upper <= zero_point.lower && !rhs.upper.is_null(), |
1493 | | ) { |
1494 | | // With the following interval bounds, there is no possibility to create an invalid interval. |
1495 | 0 | (true, true) => ( |
1496 | 0 | // <--======----0------------> |
1497 | 0 | // <--======----0------------> |
1498 | 0 | div_bounds::<false>(dt, &lhs.upper, &rhs.lower), |
1499 | 0 | div_bounds::<true>(dt, &lhs.lower, &rhs.upper), |
1500 | 0 | ), |
1501 | 0 | (true, false) => ( |
1502 | 0 | // <--======----0------------> |
1503 | 0 | // <------------0--======----> |
1504 | 0 | div_bounds::<false>(dt, &lhs.lower, &rhs.lower), |
1505 | 0 | div_bounds::<true>(dt, &lhs.upper, &rhs.upper), |
1506 | 0 | ), |
1507 | 0 | (false, true) => ( |
1508 | 0 | // <------------0--======----> |
1509 | 0 | // <--======----0------------> |
1510 | 0 | div_bounds::<false>(dt, &lhs.upper, &rhs.upper), |
1511 | 0 | div_bounds::<true>(dt, &lhs.lower, &rhs.lower), |
1512 | 0 | ), |
1513 | 0 | (false, false) => ( |
1514 | 0 | // <------------0--======----> |
1515 | 0 | // <------------0--======----> |
1516 | 0 | div_bounds::<false>(dt, &lhs.lower, &rhs.upper), |
1517 | 0 | div_bounds::<true>(dt, &lhs.upper, &rhs.lower), |
1518 | 0 | ), |
1519 | | }; |
1520 | 0 | Interval::new(lower, upper) |
1521 | 0 | } |
1522 | | |
1523 | | /// This function computes the selectivity of an operation by computing the |
1524 | | /// cardinality ratio of the given input/output intervals. If this can not be |
1525 | | /// calculated for some reason, it returns `1.0` meaning fully selective (no |
1526 | | /// filtering). |
1527 | 46 | pub fn cardinality_ratio(initial_interval: &Interval, final_interval: &Interval) -> f64 { |
1528 | 46 | match (final_interval.cardinality(), initial_interval.cardinality()) { |
1529 | 35 | (Some(final_interval), Some(initial_interval)) => { |
1530 | 35 | (final_interval as f64) / (initial_interval as f64) |
1531 | | } |
1532 | 11 | _ => 1.0, |
1533 | | } |
1534 | 46 | } |
1535 | | |
1536 | | /// Cast scalar value to the given data type using an arrow kernel. |
1537 | 3.10k | fn cast_scalar_value( |
1538 | 3.10k | value: &ScalarValue, |
1539 | 3.10k | data_type: &DataType, |
1540 | 3.10k | cast_options: &CastOptions, |
1541 | 3.10k | ) -> Result<ScalarValue> { |
1542 | 3.10k | let cast_array = cast_with_options(&value.to_array()?0 , data_type, cast_options)?0 ; |
1543 | 3.10k | ScalarValue::try_from_array(&cast_array, 0) |
1544 | 3.10k | } |
1545 | | |
1546 | | /// An [Interval] that also tracks null status using a boolean interval. |
1547 | | /// |
1548 | | /// This represents values that may be in a particular range or be null. |
1549 | | /// |
1550 | | /// # Examples |
1551 | | /// |
1552 | | /// ``` |
1553 | | /// use arrow::datatypes::DataType; |
1554 | | /// use datafusion_common::ScalarValue; |
1555 | | /// use datafusion_expr_common::interval_arithmetic::Interval; |
1556 | | /// use datafusion_expr_common::interval_arithmetic::NullableInterval; |
1557 | | /// |
1558 | | /// // [1, 2) U {NULL} |
1559 | | /// let maybe_null = NullableInterval::MaybeNull { |
1560 | | /// values: Interval::try_new( |
1561 | | /// ScalarValue::Int32(Some(1)), |
1562 | | /// ScalarValue::Int32(Some(2)), |
1563 | | /// ).unwrap(), |
1564 | | /// }; |
1565 | | /// |
1566 | | /// // (0, ∞) |
1567 | | /// let not_null = NullableInterval::NotNull { |
1568 | | /// values: Interval::try_new( |
1569 | | /// ScalarValue::Int32(Some(0)), |
1570 | | /// ScalarValue::Int32(None), |
1571 | | /// ).unwrap(), |
1572 | | /// }; |
1573 | | /// |
1574 | | /// // {NULL} |
1575 | | /// let null_interval = NullableInterval::Null { datatype: DataType::Int32 }; |
1576 | | /// |
1577 | | /// // {4} |
1578 | | /// let single_value = NullableInterval::from(ScalarValue::Int32(Some(4))); |
1579 | | /// ``` |
1580 | | #[derive(Debug, Clone, PartialEq, Eq)] |
1581 | | pub enum NullableInterval { |
1582 | | /// The value is always null. This is typed so it can be used in physical |
1583 | | /// expressions, which don't do type coercion. |
1584 | | Null { datatype: DataType }, |
1585 | | /// The value may or may not be null. If it is non-null, its is within the |
1586 | | /// specified range. |
1587 | | MaybeNull { values: Interval }, |
1588 | | /// The value is definitely not null, and is within the specified range. |
1589 | | NotNull { values: Interval }, |
1590 | | } |
1591 | | |
1592 | | impl Display for NullableInterval { |
1593 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
1594 | 0 | match self { |
1595 | 0 | Self::Null { .. } => write!(f, "NullableInterval: {{NULL}}"), |
1596 | 0 | Self::MaybeNull { values } => { |
1597 | 0 | write!(f, "NullableInterval: {} U {{NULL}}", values) |
1598 | | } |
1599 | 0 | Self::NotNull { values } => write!(f, "NullableInterval: {}", values), |
1600 | | } |
1601 | 0 | } |
1602 | | } |
1603 | | |
1604 | | impl From<ScalarValue> for NullableInterval { |
1605 | | /// Create an interval that represents a single value. |
1606 | 0 | fn from(value: ScalarValue) -> Self { |
1607 | 0 | if value.is_null() { |
1608 | 0 | Self::Null { |
1609 | 0 | datatype: value.data_type(), |
1610 | 0 | } |
1611 | | } else { |
1612 | 0 | Self::NotNull { |
1613 | 0 | values: Interval { |
1614 | 0 | lower: value.clone(), |
1615 | 0 | upper: value, |
1616 | 0 | }, |
1617 | 0 | } |
1618 | | } |
1619 | 0 | } |
1620 | | } |
1621 | | |
1622 | | impl NullableInterval { |
1623 | | /// Get the values interval, or None if this interval is definitely null. |
1624 | 0 | pub fn values(&self) -> Option<&Interval> { |
1625 | 0 | match self { |
1626 | 0 | Self::Null { .. } => None, |
1627 | 0 | Self::MaybeNull { values } | Self::NotNull { values } => Some(values), |
1628 | | } |
1629 | 0 | } |
1630 | | |
1631 | | /// Get the data type |
1632 | 0 | pub fn data_type(&self) -> DataType { |
1633 | 0 | match self { |
1634 | 0 | Self::Null { datatype } => datatype.clone(), |
1635 | 0 | Self::MaybeNull { values } | Self::NotNull { values } => values.data_type(), |
1636 | | } |
1637 | 0 | } |
1638 | | |
1639 | | /// Return true if the value is definitely true (and not null). |
1640 | 0 | pub fn is_certainly_true(&self) -> bool { |
1641 | 0 | match self { |
1642 | 0 | Self::Null { .. } | Self::MaybeNull { .. } => false, |
1643 | 0 | Self::NotNull { values } => values == &Interval::CERTAINLY_TRUE, |
1644 | | } |
1645 | 0 | } |
1646 | | |
1647 | | /// Return true if the value is definitely false (and not null). |
1648 | 0 | pub fn is_certainly_false(&self) -> bool { |
1649 | 0 | match self { |
1650 | 0 | Self::Null { .. } => false, |
1651 | 0 | Self::MaybeNull { .. } => false, |
1652 | 0 | Self::NotNull { values } => values == &Interval::CERTAINLY_FALSE, |
1653 | | } |
1654 | 0 | } |
1655 | | |
1656 | | /// Perform logical negation on a boolean nullable interval. |
1657 | 0 | fn not(&self) -> Result<Self> { |
1658 | 0 | match self { |
1659 | 0 | Self::Null { datatype } => Ok(Self::Null { |
1660 | 0 | datatype: datatype.clone(), |
1661 | 0 | }), |
1662 | 0 | Self::MaybeNull { values } => Ok(Self::MaybeNull { |
1663 | 0 | values: values.not()?, |
1664 | | }), |
1665 | 0 | Self::NotNull { values } => Ok(Self::NotNull { |
1666 | 0 | values: values.not()?, |
1667 | | }), |
1668 | | } |
1669 | 0 | } |
1670 | | |
1671 | | /// Apply the given operator to this interval and the given interval. |
1672 | | /// |
1673 | | /// # Examples |
1674 | | /// |
1675 | | /// ``` |
1676 | | /// use datafusion_common::ScalarValue; |
1677 | | /// use datafusion_expr_common::operator::Operator; |
1678 | | /// use datafusion_expr_common::interval_arithmetic::Interval; |
1679 | | /// use datafusion_expr_common::interval_arithmetic::NullableInterval; |
1680 | | /// |
1681 | | /// // 4 > 3 -> true |
1682 | | /// let lhs = NullableInterval::from(ScalarValue::Int32(Some(4))); |
1683 | | /// let rhs = NullableInterval::from(ScalarValue::Int32(Some(3))); |
1684 | | /// let result = lhs.apply_operator(&Operator::Gt, &rhs).unwrap(); |
1685 | | /// assert_eq!(result, NullableInterval::from(ScalarValue::Boolean(Some(true)))); |
1686 | | /// |
1687 | | /// // [1, 3) > NULL -> NULL |
1688 | | /// let lhs = NullableInterval::NotNull { |
1689 | | /// values: Interval::try_new( |
1690 | | /// ScalarValue::Int32(Some(1)), |
1691 | | /// ScalarValue::Int32(Some(3)), |
1692 | | /// ).unwrap(), |
1693 | | /// }; |
1694 | | /// let rhs = NullableInterval::from(ScalarValue::Int32(None)); |
1695 | | /// let result = lhs.apply_operator(&Operator::Gt, &rhs).unwrap(); |
1696 | | /// assert_eq!(result.single_value(), Some(ScalarValue::Boolean(None))); |
1697 | | /// |
1698 | | /// // [1, 3] > [2, 4] -> [false, true] |
1699 | | /// let lhs = NullableInterval::NotNull { |
1700 | | /// values: Interval::try_new( |
1701 | | /// ScalarValue::Int32(Some(1)), |
1702 | | /// ScalarValue::Int32(Some(3)), |
1703 | | /// ).unwrap(), |
1704 | | /// }; |
1705 | | /// let rhs = NullableInterval::NotNull { |
1706 | | /// values: Interval::try_new( |
1707 | | /// ScalarValue::Int32(Some(2)), |
1708 | | /// ScalarValue::Int32(Some(4)), |
1709 | | /// ).unwrap(), |
1710 | | /// }; |
1711 | | /// let result = lhs.apply_operator(&Operator::Gt, &rhs).unwrap(); |
1712 | | /// // Both inputs are valid (non-null), so result must be non-null |
1713 | | /// assert_eq!(result, NullableInterval::NotNull { |
1714 | | /// // Uncertain whether inequality is true or false |
1715 | | /// values: Interval::UNCERTAIN, |
1716 | | /// }); |
1717 | | /// ``` |
1718 | 0 | pub fn apply_operator(&self, op: &Operator, rhs: &Self) -> Result<Self> { |
1719 | 0 | match op { |
1720 | | Operator::IsDistinctFrom => { |
1721 | 0 | let values = match (self, rhs) { |
1722 | | // NULL is distinct from NULL -> False |
1723 | 0 | (Self::Null { .. }, Self::Null { .. }) => Interval::CERTAINLY_FALSE, |
1724 | | // x is distinct from y -> x != y, |
1725 | | // if at least one of them is never null. |
1726 | | (Self::NotNull { .. }, _) | (_, Self::NotNull { .. }) => { |
1727 | 0 | let lhs_values = self.values(); |
1728 | 0 | let rhs_values = rhs.values(); |
1729 | 0 | match (lhs_values, rhs_values) { |
1730 | 0 | (Some(lhs_values), Some(rhs_values)) => { |
1731 | 0 | lhs_values.equal(rhs_values)?.not()? |
1732 | | } |
1733 | 0 | (Some(_), None) | (None, Some(_)) => Interval::CERTAINLY_TRUE, |
1734 | 0 | (None, None) => unreachable!("Null case handled above"), |
1735 | | } |
1736 | | } |
1737 | 0 | _ => Interval::UNCERTAIN, |
1738 | | }; |
1739 | | // IsDistinctFrom never returns null. |
1740 | 0 | Ok(Self::NotNull { values }) |
1741 | | } |
1742 | 0 | Operator::IsNotDistinctFrom => self |
1743 | 0 | .apply_operator(&Operator::IsDistinctFrom, rhs) |
1744 | 0 | .map(|i| i.not())?, |
1745 | | _ => { |
1746 | 0 | if let (Some(left_values), Some(right_values)) = |
1747 | 0 | (self.values(), rhs.values()) |
1748 | | { |
1749 | 0 | let values = apply_operator(op, left_values, right_values)?; |
1750 | 0 | match (self, rhs) { |
1751 | | (Self::NotNull { .. }, Self::NotNull { .. }) => { |
1752 | 0 | Ok(Self::NotNull { values }) |
1753 | | } |
1754 | 0 | _ => Ok(Self::MaybeNull { values }), |
1755 | | } |
1756 | 0 | } else if op.is_comparison_operator() { |
1757 | 0 | Ok(Self::Null { |
1758 | 0 | datatype: DataType::Boolean, |
1759 | 0 | }) |
1760 | | } else { |
1761 | 0 | Ok(Self::Null { |
1762 | 0 | datatype: self.data_type(), |
1763 | 0 | }) |
1764 | | } |
1765 | | } |
1766 | | } |
1767 | 0 | } |
1768 | | |
1769 | | /// Decide if this interval is a superset of, overlaps with, or |
1770 | | /// disjoint with `other` by returning `[true, true]`, `[false, true]` or |
1771 | | /// `[false, false]` respectively. |
1772 | | /// |
1773 | | /// NOTE: This function only works with intervals of the same data type. |
1774 | | /// Attempting to compare intervals of different data types will lead |
1775 | | /// to an error. |
1776 | | pub fn contains<T: Borrow<Self>>(&self, other: T) -> Result<Self> { |
1777 | | let rhs = other.borrow(); |
1778 | | if let (Some(left_values), Some(right_values)) = (self.values(), rhs.values()) { |
1779 | | left_values |
1780 | | .contains(right_values) |
1781 | | .map(|values| match (self, rhs) { |
1782 | | (Self::NotNull { .. }, Self::NotNull { .. }) => { |
1783 | | Self::NotNull { values } |
1784 | | } |
1785 | | _ => Self::MaybeNull { values }, |
1786 | | }) |
1787 | | } else { |
1788 | | Ok(Self::Null { |
1789 | | datatype: DataType::Boolean, |
1790 | | }) |
1791 | | } |
1792 | | } |
1793 | | |
1794 | | /// If the interval has collapsed to a single value, return that value. |
1795 | | /// Otherwise, returns `None`. |
1796 | | /// |
1797 | | /// # Examples |
1798 | | /// |
1799 | | /// ``` |
1800 | | /// use datafusion_common::ScalarValue; |
1801 | | /// use datafusion_expr_common::interval_arithmetic::Interval; |
1802 | | /// use datafusion_expr_common::interval_arithmetic::NullableInterval; |
1803 | | /// |
1804 | | /// let interval = NullableInterval::from(ScalarValue::Int32(Some(4))); |
1805 | | /// assert_eq!(interval.single_value(), Some(ScalarValue::Int32(Some(4)))); |
1806 | | /// |
1807 | | /// let interval = NullableInterval::from(ScalarValue::Int32(None)); |
1808 | | /// assert_eq!(interval.single_value(), Some(ScalarValue::Int32(None))); |
1809 | | /// |
1810 | | /// let interval = NullableInterval::MaybeNull { |
1811 | | /// values: Interval::try_new( |
1812 | | /// ScalarValue::Int32(Some(1)), |
1813 | | /// ScalarValue::Int32(Some(4)), |
1814 | | /// ).unwrap(), |
1815 | | /// }; |
1816 | | /// assert_eq!(interval.single_value(), None); |
1817 | | /// ``` |
1818 | 0 | pub fn single_value(&self) -> Option<ScalarValue> { |
1819 | 0 | match self { |
1820 | 0 | Self::Null { datatype } => { |
1821 | 0 | Some(ScalarValue::try_from(datatype).unwrap_or(ScalarValue::Null)) |
1822 | | } |
1823 | 0 | Self::MaybeNull { values } | Self::NotNull { values } |
1824 | 0 | if values.lower == values.upper && !values.lower.is_null() => |
1825 | | { |
1826 | 0 | Some(values.lower.clone()) |
1827 | | } |
1828 | 0 | _ => None, |
1829 | | } |
1830 | 0 | } |
1831 | | } |
1832 | | |
1833 | | #[cfg(test)] |
1834 | | mod tests { |
1835 | | use crate::interval_arithmetic::{next_value, prev_value, satisfy_greater, Interval}; |
1836 | | |
1837 | | use arrow::datatypes::DataType; |
1838 | | use datafusion_common::{Result, ScalarValue}; |
1839 | | |
1840 | | #[test] |
1841 | | fn test_next_prev_value() -> Result<()> { |
1842 | | let zeros = vec![ |
1843 | | ScalarValue::new_zero(&DataType::UInt8)?, |
1844 | | ScalarValue::new_zero(&DataType::UInt16)?, |
1845 | | ScalarValue::new_zero(&DataType::UInt32)?, |
1846 | | ScalarValue::new_zero(&DataType::UInt64)?, |
1847 | | ScalarValue::new_zero(&DataType::Int8)?, |
1848 | | ScalarValue::new_zero(&DataType::Int16)?, |
1849 | | ScalarValue::new_zero(&DataType::Int32)?, |
1850 | | ScalarValue::new_zero(&DataType::Int64)?, |
1851 | | ]; |
1852 | | let ones = vec![ |
1853 | | ScalarValue::new_one(&DataType::UInt8)?, |
1854 | | ScalarValue::new_one(&DataType::UInt16)?, |
1855 | | ScalarValue::new_one(&DataType::UInt32)?, |
1856 | | ScalarValue::new_one(&DataType::UInt64)?, |
1857 | | ScalarValue::new_one(&DataType::Int8)?, |
1858 | | ScalarValue::new_one(&DataType::Int16)?, |
1859 | | ScalarValue::new_one(&DataType::Int32)?, |
1860 | | ScalarValue::new_one(&DataType::Int64)?, |
1861 | | ]; |
1862 | | zeros.into_iter().zip(ones).for_each(|(z, o)| { |
1863 | | assert_eq!(next_value(z.clone()), o); |
1864 | | assert_eq!(prev_value(o), z); |
1865 | | }); |
1866 | | |
1867 | | let values = vec![ |
1868 | | ScalarValue::new_zero(&DataType::Float32)?, |
1869 | | ScalarValue::new_zero(&DataType::Float64)?, |
1870 | | ]; |
1871 | | let eps = vec![ |
1872 | | ScalarValue::Float32(Some(1e-6)), |
1873 | | ScalarValue::Float64(Some(1e-6)), |
1874 | | ]; |
1875 | | values.into_iter().zip(eps).for_each(|(value, eps)| { |
1876 | | assert!(next_value(value.clone()) |
1877 | | .sub(value.clone()) |
1878 | | .unwrap() |
1879 | | .lt(&eps)); |
1880 | | assert!(value.sub(prev_value(value.clone())).unwrap().lt(&eps)); |
1881 | | assert_ne!(next_value(value.clone()), value); |
1882 | | assert_ne!(prev_value(value.clone()), value); |
1883 | | }); |
1884 | | |
1885 | | let min_max = vec![ |
1886 | | ( |
1887 | | ScalarValue::UInt64(Some(u64::MIN)), |
1888 | | ScalarValue::UInt64(Some(u64::MAX)), |
1889 | | ), |
1890 | | ( |
1891 | | ScalarValue::Int8(Some(i8::MIN)), |
1892 | | ScalarValue::Int8(Some(i8::MAX)), |
1893 | | ), |
1894 | | ( |
1895 | | ScalarValue::Float32(Some(f32::MIN)), |
1896 | | ScalarValue::Float32(Some(f32::MAX)), |
1897 | | ), |
1898 | | ( |
1899 | | ScalarValue::Float64(Some(f64::MIN)), |
1900 | | ScalarValue::Float64(Some(f64::MAX)), |
1901 | | ), |
1902 | | ]; |
1903 | | let inf = vec![ |
1904 | | ScalarValue::UInt64(None), |
1905 | | ScalarValue::Int8(None), |
1906 | | ScalarValue::Float32(None), |
1907 | | ScalarValue::Float64(None), |
1908 | | ]; |
1909 | | min_max.into_iter().zip(inf).for_each(|((min, max), inf)| { |
1910 | | assert_eq!(next_value(max.clone()), inf); |
1911 | | assert_ne!(prev_value(max.clone()), max); |
1912 | | assert_ne!(prev_value(max), inf); |
1913 | | |
1914 | | assert_eq!(prev_value(min.clone()), inf); |
1915 | | assert_ne!(next_value(min.clone()), min); |
1916 | | assert_ne!(next_value(min), inf); |
1917 | | |
1918 | | assert_eq!(next_value(inf.clone()), inf); |
1919 | | assert_eq!(prev_value(inf.clone()), inf); |
1920 | | }); |
1921 | | |
1922 | | Ok(()) |
1923 | | } |
1924 | | |
1925 | | #[test] |
1926 | | fn test_new_interval() -> Result<()> { |
1927 | | use ScalarValue::*; |
1928 | | |
1929 | | let cases = vec![ |
1930 | | ( |
1931 | | (Boolean(None), Boolean(Some(false))), |
1932 | | Boolean(Some(false)), |
1933 | | Boolean(Some(false)), |
1934 | | ), |
1935 | | ( |
1936 | | (Boolean(Some(false)), Boolean(None)), |
1937 | | Boolean(Some(false)), |
1938 | | Boolean(Some(true)), |
1939 | | ), |
1940 | | ( |
1941 | | (Boolean(Some(false)), Boolean(Some(true))), |
1942 | | Boolean(Some(false)), |
1943 | | Boolean(Some(true)), |
1944 | | ), |
1945 | | ( |
1946 | | (UInt16(Some(u16::MAX)), UInt16(None)), |
1947 | | UInt16(Some(u16::MAX)), |
1948 | | UInt16(None), |
1949 | | ), |
1950 | | ( |
1951 | | (Int16(None), Int16(Some(-1000))), |
1952 | | Int16(None), |
1953 | | Int16(Some(-1000)), |
1954 | | ), |
1955 | | ( |
1956 | | (Float32(Some(f32::MAX)), Float32(Some(f32::MAX))), |
1957 | | Float32(Some(f32::MAX)), |
1958 | | Float32(Some(f32::MAX)), |
1959 | | ), |
1960 | | ( |
1961 | | (Float32(Some(f32::NAN)), Float32(Some(f32::MIN))), |
1962 | | Float32(None), |
1963 | | Float32(Some(f32::MIN)), |
1964 | | ), |
1965 | | ( |
1966 | | ( |
1967 | | Float64(Some(f64::NEG_INFINITY)), |
1968 | | Float64(Some(f64::INFINITY)), |
1969 | | ), |
1970 | | Float64(None), |
1971 | | Float64(None), |
1972 | | ), |
1973 | | ]; |
1974 | | for (inputs, lower, upper) in cases { |
1975 | | let result = Interval::try_new(inputs.0, inputs.1)?; |
1976 | | assert_eq!(result.clone().lower(), &lower); |
1977 | | assert_eq!(result.upper(), &upper); |
1978 | | } |
1979 | | |
1980 | | let invalid_intervals = vec![ |
1981 | | (Float32(Some(f32::INFINITY)), Float32(Some(100_f32))), |
1982 | | (Float64(Some(0_f64)), Float64(Some(f64::NEG_INFINITY))), |
1983 | | (Boolean(Some(true)), Boolean(Some(false))), |
1984 | | (Int32(Some(1000)), Int32(Some(-2000))), |
1985 | | (UInt64(Some(1)), UInt64(Some(0))), |
1986 | | ]; |
1987 | | for (lower, upper) in invalid_intervals { |
1988 | | Interval::try_new(lower, upper).expect_err( |
1989 | | "Given parameters should have given an invalid interval error", |
1990 | | ); |
1991 | | } |
1992 | | |
1993 | | Ok(()) |
1994 | | } |
1995 | | |
1996 | | #[test] |
1997 | | fn test_make_unbounded() -> Result<()> { |
1998 | | use ScalarValue::*; |
1999 | | |
2000 | | let unbounded_cases = vec![ |
2001 | | (DataType::Boolean, Boolean(Some(false)), Boolean(Some(true))), |
2002 | | (DataType::UInt8, UInt8(Some(0)), UInt8(None)), |
2003 | | (DataType::UInt16, UInt16(Some(0)), UInt16(None)), |
2004 | | (DataType::UInt32, UInt32(Some(0)), UInt32(None)), |
2005 | | (DataType::UInt64, UInt64(Some(0)), UInt64(None)), |
2006 | | (DataType::Int8, Int8(None), Int8(None)), |
2007 | | (DataType::Int16, Int16(None), Int16(None)), |
2008 | | (DataType::Int32, Int32(None), Int32(None)), |
2009 | | (DataType::Int64, Int64(None), Int64(None)), |
2010 | | (DataType::Float32, Float32(None), Float32(None)), |
2011 | | (DataType::Float64, Float64(None), Float64(None)), |
2012 | | ]; |
2013 | | for (dt, lower, upper) in unbounded_cases { |
2014 | | let inf = Interval::make_unbounded(&dt)?; |
2015 | | assert_eq!(inf.clone().lower(), &lower); |
2016 | | assert_eq!(inf.upper(), &upper); |
2017 | | } |
2018 | | |
2019 | | Ok(()) |
2020 | | } |
2021 | | |
2022 | | #[test] |
2023 | | fn gt_lt_test() -> Result<()> { |
2024 | | let exactly_gt_cases = vec![ |
2025 | | ( |
2026 | | Interval::make(Some(1000_i64), None)?, |
2027 | | Interval::make(None, Some(999_i64))?, |
2028 | | ), |
2029 | | ( |
2030 | | Interval::make(Some(1000_i64), Some(1000_i64))?, |
2031 | | Interval::make(None, Some(999_i64))?, |
2032 | | ), |
2033 | | ( |
2034 | | Interval::make(Some(501_i64), Some(1000_i64))?, |
2035 | | Interval::make(Some(500_i64), Some(500_i64))?, |
2036 | | ), |
2037 | | ( |
2038 | | Interval::make(Some(-1000_i64), Some(1000_i64))?, |
2039 | | Interval::make(None, Some(-1500_i64))?, |
2040 | | ), |
2041 | | ( |
2042 | | Interval::try_new( |
2043 | | next_value(ScalarValue::Float32(Some(0.0))), |
2044 | | next_value(ScalarValue::Float32(Some(0.0))), |
2045 | | )?, |
2046 | | Interval::make(Some(0.0_f32), Some(0.0_f32))?, |
2047 | | ), |
2048 | | ( |
2049 | | Interval::make(Some(-1.0_f32), Some(-1.0_f32))?, |
2050 | | Interval::try_new( |
2051 | | prev_value(ScalarValue::Float32(Some(-1.0))), |
2052 | | prev_value(ScalarValue::Float32(Some(-1.0))), |
2053 | | )?, |
2054 | | ), |
2055 | | ]; |
2056 | | for (first, second) in exactly_gt_cases { |
2057 | | assert_eq!(first.gt(second.clone())?, Interval::CERTAINLY_TRUE); |
2058 | | assert_eq!(second.lt(first)?, Interval::CERTAINLY_TRUE); |
2059 | | } |
2060 | | |
2061 | | let possibly_gt_cases = vec![ |
2062 | | ( |
2063 | | Interval::make(Some(1000_i64), Some(2000_i64))?, |
2064 | | Interval::make(Some(1000_i64), Some(1000_i64))?, |
2065 | | ), |
2066 | | ( |
2067 | | Interval::make(Some(500_i64), Some(1000_i64))?, |
2068 | | Interval::make(Some(500_i64), Some(1000_i64))?, |
2069 | | ), |
2070 | | ( |
2071 | | Interval::make(Some(1000_i64), None)?, |
2072 | | Interval::make(Some(1000_i64), None)?, |
2073 | | ), |
2074 | | ( |
2075 | | Interval::make::<i64>(None, None)?, |
2076 | | Interval::make::<i64>(None, None)?, |
2077 | | ), |
2078 | | ( |
2079 | | Interval::try_new( |
2080 | | ScalarValue::Float32(Some(0.0_f32)), |
2081 | | next_value(ScalarValue::Float32(Some(0.0_f32))), |
2082 | | )?, |
2083 | | Interval::make(Some(0.0_f32), Some(0.0_f32))?, |
2084 | | ), |
2085 | | ( |
2086 | | Interval::make(Some(-1.0_f32), Some(-1.0_f32))?, |
2087 | | Interval::try_new( |
2088 | | prev_value(ScalarValue::Float32(Some(-1.0_f32))), |
2089 | | ScalarValue::Float32(Some(-1.0_f32)), |
2090 | | )?, |
2091 | | ), |
2092 | | ]; |
2093 | | for (first, second) in possibly_gt_cases { |
2094 | | assert_eq!(first.gt(second.clone())?, Interval::UNCERTAIN); |
2095 | | assert_eq!(second.lt(first)?, Interval::UNCERTAIN); |
2096 | | } |
2097 | | |
2098 | | let not_gt_cases = vec![ |
2099 | | ( |
2100 | | Interval::make(Some(1000_i64), Some(1000_i64))?, |
2101 | | Interval::make(Some(1000_i64), Some(1000_i64))?, |
2102 | | ), |
2103 | | ( |
2104 | | Interval::make(Some(500_i64), Some(1000_i64))?, |
2105 | | Interval::make(Some(1000_i64), None)?, |
2106 | | ), |
2107 | | ( |
2108 | | Interval::make(None, Some(1000_i64))?, |
2109 | | Interval::make(Some(1000_i64), Some(1500_i64))?, |
2110 | | ), |
2111 | | ( |
2112 | | Interval::make(Some(0_u8), Some(0_u8))?, |
2113 | | Interval::make::<u8>(None, None)?, |
2114 | | ), |
2115 | | ( |
2116 | | Interval::try_new( |
2117 | | prev_value(ScalarValue::Float32(Some(0.0_f32))), |
2118 | | ScalarValue::Float32(Some(0.0_f32)), |
2119 | | )?, |
2120 | | Interval::make(Some(0.0_f32), Some(0.0_f32))?, |
2121 | | ), |
2122 | | ( |
2123 | | Interval::make(Some(-1.0_f32), Some(-1.0_f32))?, |
2124 | | Interval::try_new( |
2125 | | ScalarValue::Float32(Some(-1.0_f32)), |
2126 | | next_value(ScalarValue::Float32(Some(-1.0_f32))), |
2127 | | )?, |
2128 | | ), |
2129 | | ]; |
2130 | | for (first, second) in not_gt_cases { |
2131 | | assert_eq!(first.gt(second.clone())?, Interval::CERTAINLY_FALSE); |
2132 | | assert_eq!(second.lt(first)?, Interval::CERTAINLY_FALSE); |
2133 | | } |
2134 | | |
2135 | | Ok(()) |
2136 | | } |
2137 | | |
2138 | | #[test] |
2139 | | fn gteq_lteq_test() -> Result<()> { |
2140 | | let exactly_gteq_cases = vec![ |
2141 | | ( |
2142 | | Interval::make(Some(1000_i64), None)?, |
2143 | | Interval::make(None, Some(1000_i64))?, |
2144 | | ), |
2145 | | ( |
2146 | | Interval::make(Some(1000_i64), Some(1000_i64))?, |
2147 | | Interval::make(None, Some(1000_i64))?, |
2148 | | ), |
2149 | | ( |
2150 | | Interval::make(Some(500_i64), Some(1000_i64))?, |
2151 | | Interval::make(Some(500_i64), Some(500_i64))?, |
2152 | | ), |
2153 | | ( |
2154 | | Interval::make(Some(-1000_i64), Some(1000_i64))?, |
2155 | | Interval::make(None, Some(-1500_i64))?, |
2156 | | ), |
2157 | | ( |
2158 | | Interval::make::<u64>(None, None)?, |
2159 | | Interval::make(Some(0_u64), Some(0_u64))?, |
2160 | | ), |
2161 | | ( |
2162 | | Interval::make(Some(0.0_f32), Some(0.0_f32))?, |
2163 | | Interval::make(Some(0.0_f32), Some(0.0_f32))?, |
2164 | | ), |
2165 | | ( |
2166 | | Interval::try_new( |
2167 | | ScalarValue::Float32(Some(-1.0)), |
2168 | | next_value(ScalarValue::Float32(Some(-1.0))), |
2169 | | )?, |
2170 | | Interval::try_new( |
2171 | | prev_value(ScalarValue::Float32(Some(-1.0))), |
2172 | | ScalarValue::Float32(Some(-1.0)), |
2173 | | )?, |
2174 | | ), |
2175 | | ]; |
2176 | | for (first, second) in exactly_gteq_cases { |
2177 | | assert_eq!(first.gt_eq(second.clone())?, Interval::CERTAINLY_TRUE); |
2178 | | assert_eq!(second.lt_eq(first)?, Interval::CERTAINLY_TRUE); |
2179 | | } |
2180 | | |
2181 | | let possibly_gteq_cases = vec![ |
2182 | | ( |
2183 | | Interval::make(Some(999_i64), Some(2000_i64))?, |
2184 | | Interval::make(Some(1000_i64), Some(1000_i64))?, |
2185 | | ), |
2186 | | ( |
2187 | | Interval::make(Some(500_i64), Some(1000_i64))?, |
2188 | | Interval::make(Some(500_i64), Some(1001_i64))?, |
2189 | | ), |
2190 | | ( |
2191 | | Interval::make(Some(0_i64), None)?, |
2192 | | Interval::make(Some(1000_i64), None)?, |
2193 | | ), |
2194 | | ( |
2195 | | Interval::make::<i64>(None, None)?, |
2196 | | Interval::make::<i64>(None, None)?, |
2197 | | ), |
2198 | | ( |
2199 | | Interval::try_new( |
2200 | | prev_value(ScalarValue::Float32(Some(0.0))), |
2201 | | ScalarValue::Float32(Some(0.0)), |
2202 | | )?, |
2203 | | Interval::make(Some(0.0_f32), Some(0.0_f32))?, |
2204 | | ), |
2205 | | ( |
2206 | | Interval::make(Some(-1.0_f32), Some(-1.0_f32))?, |
2207 | | Interval::try_new( |
2208 | | prev_value(ScalarValue::Float32(Some(-1.0_f32))), |
2209 | | next_value(ScalarValue::Float32(Some(-1.0_f32))), |
2210 | | )?, |
2211 | | ), |
2212 | | ]; |
2213 | | for (first, second) in possibly_gteq_cases { |
2214 | | assert_eq!(first.gt_eq(second.clone())?, Interval::UNCERTAIN); |
2215 | | assert_eq!(second.lt_eq(first)?, Interval::UNCERTAIN); |
2216 | | } |
2217 | | |
2218 | | let not_gteq_cases = vec![ |
2219 | | ( |
2220 | | Interval::make(Some(1000_i64), Some(1000_i64))?, |
2221 | | Interval::make(Some(2000_i64), Some(2000_i64))?, |
2222 | | ), |
2223 | | ( |
2224 | | Interval::make(Some(500_i64), Some(999_i64))?, |
2225 | | Interval::make(Some(1000_i64), None)?, |
2226 | | ), |
2227 | | ( |
2228 | | Interval::make(None, Some(1000_i64))?, |
2229 | | Interval::make(Some(1001_i64), Some(1500_i64))?, |
2230 | | ), |
2231 | | ( |
2232 | | Interval::try_new( |
2233 | | prev_value(ScalarValue::Float32(Some(0.0_f32))), |
2234 | | prev_value(ScalarValue::Float32(Some(0.0_f32))), |
2235 | | )?, |
2236 | | Interval::make(Some(0.0_f32), Some(0.0_f32))?, |
2237 | | ), |
2238 | | ( |
2239 | | Interval::make(Some(-1.0_f32), Some(-1.0_f32))?, |
2240 | | Interval::try_new( |
2241 | | next_value(ScalarValue::Float32(Some(-1.0))), |
2242 | | next_value(ScalarValue::Float32(Some(-1.0))), |
2243 | | )?, |
2244 | | ), |
2245 | | ]; |
2246 | | for (first, second) in not_gteq_cases { |
2247 | | assert_eq!(first.gt_eq(second.clone())?, Interval::CERTAINLY_FALSE); |
2248 | | assert_eq!(second.lt_eq(first)?, Interval::CERTAINLY_FALSE); |
2249 | | } |
2250 | | |
2251 | | Ok(()) |
2252 | | } |
2253 | | |
2254 | | #[test] |
2255 | | fn equal_test() -> Result<()> { |
2256 | | let exactly_eq_cases = vec![ |
2257 | | ( |
2258 | | Interval::make(Some(1000_i64), Some(1000_i64))?, |
2259 | | Interval::make(Some(1000_i64), Some(1000_i64))?, |
2260 | | ), |
2261 | | ( |
2262 | | Interval::make(Some(0_u64), Some(0_u64))?, |
2263 | | Interval::make(Some(0_u64), Some(0_u64))?, |
2264 | | ), |
2265 | | ( |
2266 | | Interval::make(Some(f32::MAX), Some(f32::MAX))?, |
2267 | | Interval::make(Some(f32::MAX), Some(f32::MAX))?, |
2268 | | ), |
2269 | | ( |
2270 | | Interval::make(Some(f64::MIN), Some(f64::MIN))?, |
2271 | | Interval::make(Some(f64::MIN), Some(f64::MIN))?, |
2272 | | ), |
2273 | | ]; |
2274 | | for (first, second) in exactly_eq_cases { |
2275 | | assert_eq!(first.equal(second.clone())?, Interval::CERTAINLY_TRUE); |
2276 | | assert_eq!(second.equal(first)?, Interval::CERTAINLY_TRUE); |
2277 | | } |
2278 | | |
2279 | | let possibly_eq_cases = vec![ |
2280 | | ( |
2281 | | Interval::make::<i64>(None, None)?, |
2282 | | Interval::make::<i64>(None, None)?, |
2283 | | ), |
2284 | | ( |
2285 | | Interval::make(Some(0_i64), Some(0_i64))?, |
2286 | | Interval::make(Some(0_i64), Some(1000_i64))?, |
2287 | | ), |
2288 | | ( |
2289 | | Interval::make(Some(0_i64), Some(0_i64))?, |
2290 | | Interval::make(Some(0_i64), Some(1000_i64))?, |
2291 | | ), |
2292 | | ( |
2293 | | Interval::make(Some(100.0_f32), Some(200.0_f32))?, |
2294 | | Interval::make(Some(0.0_f32), Some(1000.0_f32))?, |
2295 | | ), |
2296 | | ( |
2297 | | Interval::try_new( |
2298 | | prev_value(ScalarValue::Float32(Some(0.0))), |
2299 | | ScalarValue::Float32(Some(0.0)), |
2300 | | )?, |
2301 | | Interval::make(Some(0.0_f32), Some(0.0_f32))?, |
2302 | | ), |
2303 | | ( |
2304 | | Interval::make(Some(-1.0_f32), Some(-1.0_f32))?, |
2305 | | Interval::try_new( |
2306 | | prev_value(ScalarValue::Float32(Some(-1.0))), |
2307 | | next_value(ScalarValue::Float32(Some(-1.0))), |
2308 | | )?, |
2309 | | ), |
2310 | | ]; |
2311 | | for (first, second) in possibly_eq_cases { |
2312 | | assert_eq!(first.equal(second.clone())?, Interval::UNCERTAIN); |
2313 | | assert_eq!(second.equal(first)?, Interval::UNCERTAIN); |
2314 | | } |
2315 | | |
2316 | | let not_eq_cases = vec![ |
2317 | | ( |
2318 | | Interval::make(Some(1000_i64), Some(1000_i64))?, |
2319 | | Interval::make(Some(2000_i64), Some(2000_i64))?, |
2320 | | ), |
2321 | | ( |
2322 | | Interval::make(Some(500_i64), Some(999_i64))?, |
2323 | | Interval::make(Some(1000_i64), None)?, |
2324 | | ), |
2325 | | ( |
2326 | | Interval::make(None, Some(1000_i64))?, |
2327 | | Interval::make(Some(1001_i64), Some(1500_i64))?, |
2328 | | ), |
2329 | | ( |
2330 | | Interval::try_new( |
2331 | | prev_value(ScalarValue::Float32(Some(0.0))), |
2332 | | prev_value(ScalarValue::Float32(Some(0.0))), |
2333 | | )?, |
2334 | | Interval::make(Some(0.0_f32), Some(0.0_f32))?, |
2335 | | ), |
2336 | | ( |
2337 | | Interval::make(Some(-1.0_f32), Some(-1.0_f32))?, |
2338 | | Interval::try_new( |
2339 | | next_value(ScalarValue::Float32(Some(-1.0))), |
2340 | | next_value(ScalarValue::Float32(Some(-1.0))), |
2341 | | )?, |
2342 | | ), |
2343 | | ]; |
2344 | | for (first, second) in not_eq_cases { |
2345 | | assert_eq!(first.equal(second.clone())?, Interval::CERTAINLY_FALSE); |
2346 | | assert_eq!(second.equal(first)?, Interval::CERTAINLY_FALSE); |
2347 | | } |
2348 | | |
2349 | | Ok(()) |
2350 | | } |
2351 | | |
2352 | | #[test] |
2353 | | fn and_test() -> Result<()> { |
2354 | | let cases = vec![ |
2355 | | (false, true, false, false, false, false), |
2356 | | (false, false, false, true, false, false), |
2357 | | (false, true, false, true, false, true), |
2358 | | (false, true, true, true, false, true), |
2359 | | (false, false, false, false, false, false), |
2360 | | (true, true, true, true, true, true), |
2361 | | ]; |
2362 | | |
2363 | | for case in cases { |
2364 | | assert_eq!( |
2365 | | Interval::make(Some(case.0), Some(case.1))? |
2366 | | .and(Interval::make(Some(case.2), Some(case.3))?)?, |
2367 | | Interval::make(Some(case.4), Some(case.5))? |
2368 | | ); |
2369 | | } |
2370 | | Ok(()) |
2371 | | } |
2372 | | |
2373 | | #[test] |
2374 | | fn not_test() -> Result<()> { |
2375 | | let cases = vec![ |
2376 | | (false, true, false, true), |
2377 | | (false, false, true, true), |
2378 | | (true, true, false, false), |
2379 | | ]; |
2380 | | |
2381 | | for case in cases { |
2382 | | assert_eq!( |
2383 | | Interval::make(Some(case.0), Some(case.1))?.not()?, |
2384 | | Interval::make(Some(case.2), Some(case.3))? |
2385 | | ); |
2386 | | } |
2387 | | Ok(()) |
2388 | | } |
2389 | | |
2390 | | #[test] |
2391 | | fn intersect_test() -> Result<()> { |
2392 | | let possible_cases = vec![ |
2393 | | ( |
2394 | | Interval::make(Some(1000_i64), None)?, |
2395 | | Interval::make::<i64>(None, None)?, |
2396 | | Interval::make(Some(1000_i64), None)?, |
2397 | | ), |
2398 | | ( |
2399 | | Interval::make(Some(1000_i64), None)?, |
2400 | | Interval::make(None, Some(1000_i64))?, |
2401 | | Interval::make(Some(1000_i64), Some(1000_i64))?, |
2402 | | ), |
2403 | | ( |
2404 | | Interval::make(Some(1000_i64), None)?, |
2405 | | Interval::make(None, Some(2000_i64))?, |
2406 | | Interval::make(Some(1000_i64), Some(2000_i64))?, |
2407 | | ), |
2408 | | ( |
2409 | | Interval::make(Some(1000_i64), Some(2000_i64))?, |
2410 | | Interval::make(Some(1000_i64), None)?, |
2411 | | Interval::make(Some(1000_i64), Some(2000_i64))?, |
2412 | | ), |
2413 | | ( |
2414 | | Interval::make(Some(1000_i64), Some(2000_i64))?, |
2415 | | Interval::make(Some(1000_i64), Some(1500_i64))?, |
2416 | | Interval::make(Some(1000_i64), Some(1500_i64))?, |
2417 | | ), |
2418 | | ( |
2419 | | Interval::make(Some(1000_i64), Some(2000_i64))?, |
2420 | | Interval::make(Some(500_i64), Some(1500_i64))?, |
2421 | | Interval::make(Some(1000_i64), Some(1500_i64))?, |
2422 | | ), |
2423 | | ( |
2424 | | Interval::make::<i64>(None, None)?, |
2425 | | Interval::make::<i64>(None, None)?, |
2426 | | Interval::make::<i64>(None, None)?, |
2427 | | ), |
2428 | | ( |
2429 | | Interval::make(None, Some(2000_u64))?, |
2430 | | Interval::make(Some(500_u64), None)?, |
2431 | | Interval::make(Some(500_u64), Some(2000_u64))?, |
2432 | | ), |
2433 | | ( |
2434 | | Interval::make(Some(0_u64), Some(0_u64))?, |
2435 | | Interval::make(Some(0_u64), None)?, |
2436 | | Interval::make(Some(0_u64), Some(0_u64))?, |
2437 | | ), |
2438 | | ( |
2439 | | Interval::make(Some(1000.0_f32), None)?, |
2440 | | Interval::make(None, Some(1000.0_f32))?, |
2441 | | Interval::make(Some(1000.0_f32), Some(1000.0_f32))?, |
2442 | | ), |
2443 | | ( |
2444 | | Interval::make(Some(1000.0_f32), Some(1500.0_f32))?, |
2445 | | Interval::make(Some(0.0_f32), Some(1500.0_f32))?, |
2446 | | Interval::make(Some(1000.0_f32), Some(1500.0_f32))?, |
2447 | | ), |
2448 | | ( |
2449 | | Interval::make(Some(-1000.0_f64), Some(1500.0_f64))?, |
2450 | | Interval::make(Some(-1500.0_f64), Some(2000.0_f64))?, |
2451 | | Interval::make(Some(-1000.0_f64), Some(1500.0_f64))?, |
2452 | | ), |
2453 | | ( |
2454 | | Interval::make(Some(16.0_f64), Some(32.0_f64))?, |
2455 | | Interval::make(Some(32.0_f64), Some(64.0_f64))?, |
2456 | | Interval::make(Some(32.0_f64), Some(32.0_f64))?, |
2457 | | ), |
2458 | | ]; |
2459 | | for (first, second, expected) in possible_cases { |
2460 | | assert_eq!(first.intersect(second)?.unwrap(), expected) |
2461 | | } |
2462 | | |
2463 | | let empty_cases = vec![ |
2464 | | ( |
2465 | | Interval::make(Some(1000_i64), None)?, |
2466 | | Interval::make(None, Some(0_i64))?, |
2467 | | ), |
2468 | | ( |
2469 | | Interval::make(Some(1000_i64), None)?, |
2470 | | Interval::make(None, Some(999_i64))?, |
2471 | | ), |
2472 | | ( |
2473 | | Interval::make(Some(1500_i64), Some(2000_i64))?, |
2474 | | Interval::make(Some(1000_i64), Some(1499_i64))?, |
2475 | | ), |
2476 | | ( |
2477 | | Interval::make(Some(0_i64), Some(1000_i64))?, |
2478 | | Interval::make(Some(2000_i64), Some(3000_i64))?, |
2479 | | ), |
2480 | | ( |
2481 | | Interval::try_new( |
2482 | | prev_value(ScalarValue::Float32(Some(1.0))), |
2483 | | prev_value(ScalarValue::Float32(Some(1.0))), |
2484 | | )?, |
2485 | | Interval::make(Some(1.0_f32), Some(1.0_f32))?, |
2486 | | ), |
2487 | | ( |
2488 | | Interval::try_new( |
2489 | | next_value(ScalarValue::Float32(Some(1.0))), |
2490 | | next_value(ScalarValue::Float32(Some(1.0))), |
2491 | | )?, |
2492 | | Interval::make(Some(1.0_f32), Some(1.0_f32))?, |
2493 | | ), |
2494 | | ]; |
2495 | | for (first, second) in empty_cases { |
2496 | | assert_eq!(first.intersect(second)?, None) |
2497 | | } |
2498 | | |
2499 | | Ok(()) |
2500 | | } |
2501 | | |
2502 | | #[test] |
2503 | | fn test_contains() -> Result<()> { |
2504 | | let possible_cases = vec![ |
2505 | | ( |
2506 | | Interval::make::<i64>(None, None)?, |
2507 | | Interval::make::<i64>(None, None)?, |
2508 | | Interval::CERTAINLY_TRUE, |
2509 | | ), |
2510 | | ( |
2511 | | Interval::make(Some(1500_i64), Some(2000_i64))?, |
2512 | | Interval::make(Some(1501_i64), Some(1999_i64))?, |
2513 | | Interval::CERTAINLY_TRUE, |
2514 | | ), |
2515 | | ( |
2516 | | Interval::make(Some(1000_i64), None)?, |
2517 | | Interval::make::<i64>(None, None)?, |
2518 | | Interval::UNCERTAIN, |
2519 | | ), |
2520 | | ( |
2521 | | Interval::make(Some(1000_i64), Some(2000_i64))?, |
2522 | | Interval::make(Some(500), Some(1500_i64))?, |
2523 | | Interval::UNCERTAIN, |
2524 | | ), |
2525 | | ( |
2526 | | Interval::make(Some(16.0), Some(32.0))?, |
2527 | | Interval::make(Some(32.0), Some(64.0))?, |
2528 | | Interval::UNCERTAIN, |
2529 | | ), |
2530 | | ( |
2531 | | Interval::make(Some(1000_i64), None)?, |
2532 | | Interval::make(None, Some(0_i64))?, |
2533 | | Interval::CERTAINLY_FALSE, |
2534 | | ), |
2535 | | ( |
2536 | | Interval::make(Some(1500_i64), Some(2000_i64))?, |
2537 | | Interval::make(Some(1000_i64), Some(1499_i64))?, |
2538 | | Interval::CERTAINLY_FALSE, |
2539 | | ), |
2540 | | ( |
2541 | | Interval::try_new( |
2542 | | prev_value(ScalarValue::Float32(Some(1.0))), |
2543 | | prev_value(ScalarValue::Float32(Some(1.0))), |
2544 | | )?, |
2545 | | Interval::make(Some(1.0_f32), Some(1.0_f32))?, |
2546 | | Interval::CERTAINLY_FALSE, |
2547 | | ), |
2548 | | ( |
2549 | | Interval::try_new( |
2550 | | next_value(ScalarValue::Float32(Some(1.0))), |
2551 | | next_value(ScalarValue::Float32(Some(1.0))), |
2552 | | )?, |
2553 | | Interval::make(Some(1.0_f32), Some(1.0_f32))?, |
2554 | | Interval::CERTAINLY_FALSE, |
2555 | | ), |
2556 | | ]; |
2557 | | for (first, second, expected) in possible_cases { |
2558 | | assert_eq!(first.contains(second)?, expected) |
2559 | | } |
2560 | | |
2561 | | Ok(()) |
2562 | | } |
2563 | | |
2564 | | #[test] |
2565 | | fn test_add() -> Result<()> { |
2566 | | let cases = vec![ |
2567 | | ( |
2568 | | Interval::make(Some(100_i64), Some(200_i64))?, |
2569 | | Interval::make(None, Some(200_i64))?, |
2570 | | Interval::make(None, Some(400_i64))?, |
2571 | | ), |
2572 | | ( |
2573 | | Interval::make(Some(100_i64), Some(200_i64))?, |
2574 | | Interval::make(Some(200_i64), None)?, |
2575 | | Interval::make(Some(300_i64), None)?, |
2576 | | ), |
2577 | | ( |
2578 | | Interval::make(None, Some(200_i64))?, |
2579 | | Interval::make(Some(100_i64), Some(200_i64))?, |
2580 | | Interval::make(None, Some(400_i64))?, |
2581 | | ), |
2582 | | ( |
2583 | | Interval::make(Some(200_i64), None)?, |
2584 | | Interval::make(Some(100_i64), Some(200_i64))?, |
2585 | | Interval::make(Some(300_i64), None)?, |
2586 | | ), |
2587 | | ( |
2588 | | Interval::make(Some(100_i64), Some(200_i64))?, |
2589 | | Interval::make(Some(-300_i64), Some(150_i64))?, |
2590 | | Interval::make(Some(-200_i64), Some(350_i64))?, |
2591 | | ), |
2592 | | ( |
2593 | | Interval::make(Some(f32::MAX), Some(f32::MAX))?, |
2594 | | Interval::make(Some(11_f32), Some(11_f32))?, |
2595 | | Interval::make(Some(f32::MAX), None)?, |
2596 | | ), |
2597 | | ( |
2598 | | Interval::make(Some(f32::MIN), Some(f32::MIN))?, |
2599 | | Interval::make(Some(-10_f32), Some(10_f32))?, |
2600 | | // Since rounding mode is up, the result would be much greater than f32::MIN |
2601 | | // (f32::MIN = -3.4_028_235e38, the result is -3.4_028_233e38) |
2602 | | Interval::make( |
2603 | | None, |
2604 | | Some(-340282330000000000000000000000000000000.0_f32), |
2605 | | )?, |
2606 | | ), |
2607 | | ( |
2608 | | Interval::make(Some(f32::MIN), Some(f32::MIN))?, |
2609 | | Interval::make(Some(-10_f32), Some(-10_f32))?, |
2610 | | Interval::make(None, Some(f32::MIN))?, |
2611 | | ), |
2612 | | ( |
2613 | | Interval::make(Some(1.0), Some(f32::MAX))?, |
2614 | | Interval::make(Some(f32::MAX), Some(f32::MAX))?, |
2615 | | Interval::make(Some(f32::MAX), None)?, |
2616 | | ), |
2617 | | ( |
2618 | | Interval::make(Some(f32::MIN), Some(f32::MIN))?, |
2619 | | Interval::make(Some(f32::MAX), Some(f32::MAX))?, |
2620 | | Interval::make(Some(-0.0_f32), Some(0.0_f32))?, |
2621 | | ), |
2622 | | ( |
2623 | | Interval::make(Some(100_f64), None)?, |
2624 | | Interval::make(None, Some(200_f64))?, |
2625 | | Interval::make::<i64>(None, None)?, |
2626 | | ), |
2627 | | ( |
2628 | | Interval::make(None, Some(100_f64))?, |
2629 | | Interval::make(None, Some(200_f64))?, |
2630 | | Interval::make(None, Some(300_f64))?, |
2631 | | ), |
2632 | | ]; |
2633 | | for case in cases { |
2634 | | let result = case.0.add(case.1)?; |
2635 | | if case.0.data_type().is_floating() { |
2636 | | assert!( |
2637 | | result.lower().is_null() && case.2.lower().is_null() |
2638 | | || result.lower().le(case.2.lower()) |
2639 | | ); |
2640 | | assert!( |
2641 | | result.upper().is_null() && case.2.upper().is_null() |
2642 | | || result.upper().ge(case.2.upper()) |
2643 | | ); |
2644 | | } else { |
2645 | | assert_eq!(result, case.2); |
2646 | | } |
2647 | | } |
2648 | | |
2649 | | Ok(()) |
2650 | | } |
2651 | | |
2652 | | #[test] |
2653 | | fn test_sub() -> Result<()> { |
2654 | | let cases = vec![ |
2655 | | ( |
2656 | | Interval::make(Some(i32::MAX), Some(i32::MAX))?, |
2657 | | Interval::make(Some(11_i32), Some(11_i32))?, |
2658 | | Interval::make(Some(i32::MAX - 11), Some(i32::MAX - 11))?, |
2659 | | ), |
2660 | | ( |
2661 | | Interval::make(Some(100_i64), Some(200_i64))?, |
2662 | | Interval::make(None, Some(200_i64))?, |
2663 | | Interval::make(Some(-100_i64), None)?, |
2664 | | ), |
2665 | | ( |
2666 | | Interval::make(Some(100_i64), Some(200_i64))?, |
2667 | | Interval::make(Some(200_i64), None)?, |
2668 | | Interval::make(None, Some(0_i64))?, |
2669 | | ), |
2670 | | ( |
2671 | | Interval::make(None, Some(200_i64))?, |
2672 | | Interval::make(Some(100_i64), Some(200_i64))?, |
2673 | | Interval::make(None, Some(100_i64))?, |
2674 | | ), |
2675 | | ( |
2676 | | Interval::make(Some(200_i64), None)?, |
2677 | | Interval::make(Some(100_i64), Some(200_i64))?, |
2678 | | Interval::make(Some(0_i64), None)?, |
2679 | | ), |
2680 | | ( |
2681 | | Interval::make(Some(100_i64), Some(200_i64))?, |
2682 | | Interval::make(Some(-300_i64), Some(150_i64))?, |
2683 | | Interval::make(Some(-50_i64), Some(500_i64))?, |
2684 | | ), |
2685 | | ( |
2686 | | Interval::make(Some(i64::MIN), Some(i64::MIN))?, |
2687 | | Interval::make(Some(-10_i64), Some(-10_i64))?, |
2688 | | Interval::make(Some(i64::MIN + 10), Some(i64::MIN + 10))?, |
2689 | | ), |
2690 | | ( |
2691 | | Interval::make(Some(1), Some(i64::MAX))?, |
2692 | | Interval::make(Some(i64::MAX), Some(i64::MAX))?, |
2693 | | Interval::make(Some(1 - i64::MAX), Some(0))?, |
2694 | | ), |
2695 | | ( |
2696 | | Interval::make(Some(i64::MIN), Some(i64::MIN))?, |
2697 | | Interval::make(Some(i64::MAX), Some(i64::MAX))?, |
2698 | | Interval::make(None, Some(i64::MIN))?, |
2699 | | ), |
2700 | | ( |
2701 | | Interval::make(Some(2_u32), Some(10_u32))?, |
2702 | | Interval::make(Some(4_u32), Some(6_u32))?, |
2703 | | Interval::make(None, Some(6_u32))?, |
2704 | | ), |
2705 | | ( |
2706 | | Interval::make(Some(2_u32), Some(10_u32))?, |
2707 | | Interval::make(Some(20_u32), Some(30_u32))?, |
2708 | | Interval::make(None, Some(0_u32))?, |
2709 | | ), |
2710 | | ( |
2711 | | Interval::make(Some(f32::MIN), Some(f32::MIN))?, |
2712 | | Interval::make(Some(-10_f32), Some(10_f32))?, |
2713 | | // Since rounding mode is up, the result would be much larger than f32::MIN |
2714 | | // (f32::MIN = -3.4_028_235e38, the result is -3.4_028_233e38) |
2715 | | Interval::make( |
2716 | | None, |
2717 | | Some(-340282330000000000000000000000000000000.0_f32), |
2718 | | )?, |
2719 | | ), |
2720 | | ( |
2721 | | Interval::make(Some(100_f64), None)?, |
2722 | | Interval::make(None, Some(200_f64))?, |
2723 | | Interval::make(Some(-100_f64), None)?, |
2724 | | ), |
2725 | | ( |
2726 | | Interval::make(None, Some(100_f64))?, |
2727 | | Interval::make(None, Some(200_f64))?, |
2728 | | Interval::make::<i64>(None, None)?, |
2729 | | ), |
2730 | | ]; |
2731 | | for case in cases { |
2732 | | let result = case.0.sub(case.1)?; |
2733 | | if case.0.data_type().is_floating() { |
2734 | | assert!( |
2735 | | result.lower().is_null() && case.2.lower().is_null() |
2736 | | || result.lower().le(case.2.lower()) |
2737 | | ); |
2738 | | assert!( |
2739 | | result.upper().is_null() && case.2.upper().is_null() |
2740 | | || result.upper().ge(case.2.upper(),) |
2741 | | ); |
2742 | | } else { |
2743 | | assert_eq!(result, case.2); |
2744 | | } |
2745 | | } |
2746 | | |
2747 | | Ok(()) |
2748 | | } |
2749 | | |
2750 | | #[test] |
2751 | | fn test_mul() -> Result<()> { |
2752 | | let cases = vec![ |
2753 | | ( |
2754 | | Interval::make(Some(1_i64), Some(2_i64))?, |
2755 | | Interval::make(None, Some(2_i64))?, |
2756 | | Interval::make(None, Some(4_i64))?, |
2757 | | ), |
2758 | | ( |
2759 | | Interval::make(Some(1_i64), Some(2_i64))?, |
2760 | | Interval::make(Some(2_i64), None)?, |
2761 | | Interval::make(Some(2_i64), None)?, |
2762 | | ), |
2763 | | ( |
2764 | | Interval::make(None, Some(2_i64))?, |
2765 | | Interval::make(Some(1_i64), Some(2_i64))?, |
2766 | | Interval::make(None, Some(4_i64))?, |
2767 | | ), |
2768 | | ( |
2769 | | Interval::make(Some(2_i64), None)?, |
2770 | | Interval::make(Some(1_i64), Some(2_i64))?, |
2771 | | Interval::make(Some(2_i64), None)?, |
2772 | | ), |
2773 | | ( |
2774 | | Interval::make(Some(1_i64), Some(2_i64))?, |
2775 | | Interval::make(Some(-3_i64), Some(15_i64))?, |
2776 | | Interval::make(Some(-6_i64), Some(30_i64))?, |
2777 | | ), |
2778 | | ( |
2779 | | Interval::make(Some(-0.0), Some(0.0))?, |
2780 | | Interval::make(None, Some(0.0))?, |
2781 | | Interval::make::<i64>(None, None)?, |
2782 | | ), |
2783 | | ( |
2784 | | Interval::make(Some(f32::MIN), Some(f32::MIN))?, |
2785 | | Interval::make(Some(-10_f32), Some(10_f32))?, |
2786 | | Interval::make::<i64>(None, None)?, |
2787 | | ), |
2788 | | ( |
2789 | | Interval::make(Some(1_u32), Some(2_u32))?, |
2790 | | Interval::make(Some(0_u32), Some(1_u32))?, |
2791 | | Interval::make(Some(0_u32), Some(2_u32))?, |
2792 | | ), |
2793 | | ( |
2794 | | Interval::make(None, Some(2_u32))?, |
2795 | | Interval::make(Some(0_u32), Some(1_u32))?, |
2796 | | Interval::make(None, Some(2_u32))?, |
2797 | | ), |
2798 | | ( |
2799 | | Interval::make(None, Some(2_u32))?, |
2800 | | Interval::make(Some(1_u32), Some(2_u32))?, |
2801 | | Interval::make(None, Some(4_u32))?, |
2802 | | ), |
2803 | | ( |
2804 | | Interval::make(None, Some(2_u32))?, |
2805 | | Interval::make(Some(1_u32), None)?, |
2806 | | Interval::make::<u32>(None, None)?, |
2807 | | ), |
2808 | | ( |
2809 | | Interval::make::<u32>(None, None)?, |
2810 | | Interval::make(Some(0_u32), None)?, |
2811 | | Interval::make::<u32>(None, None)?, |
2812 | | ), |
2813 | | ( |
2814 | | Interval::make(Some(f32::MAX), Some(f32::MAX))?, |
2815 | | Interval::make(Some(11_f32), Some(11_f32))?, |
2816 | | Interval::make(Some(f32::MAX), None)?, |
2817 | | ), |
2818 | | ( |
2819 | | Interval::make(Some(f32::MIN), Some(f32::MIN))?, |
2820 | | Interval::make(Some(-10_f32), Some(-10_f32))?, |
2821 | | Interval::make(Some(f32::MAX), None)?, |
2822 | | ), |
2823 | | ( |
2824 | | Interval::make(Some(1.0), Some(f32::MAX))?, |
2825 | | Interval::make(Some(f32::MAX), Some(f32::MAX))?, |
2826 | | Interval::make(Some(f32::MAX), None)?, |
2827 | | ), |
2828 | | ( |
2829 | | Interval::make(Some(f32::MIN), Some(f32::MIN))?, |
2830 | | Interval::make(Some(f32::MAX), Some(f32::MAX))?, |
2831 | | Interval::make(None, Some(f32::MIN))?, |
2832 | | ), |
2833 | | ( |
2834 | | Interval::make(Some(-0.0_f32), Some(0.0_f32))?, |
2835 | | Interval::make(Some(f32::MAX), None)?, |
2836 | | Interval::make::<f32>(None, None)?, |
2837 | | ), |
2838 | | ( |
2839 | | Interval::make(Some(0.0_f32), Some(0.0_f32))?, |
2840 | | Interval::make(Some(f32::MAX), None)?, |
2841 | | Interval::make(Some(0.0_f32), None)?, |
2842 | | ), |
2843 | | ( |
2844 | | Interval::make(Some(1_f64), None)?, |
2845 | | Interval::make(None, Some(2_f64))?, |
2846 | | Interval::make::<f64>(None, None)?, |
2847 | | ), |
2848 | | ( |
2849 | | Interval::make(None, Some(1_f64))?, |
2850 | | Interval::make(None, Some(2_f64))?, |
2851 | | Interval::make::<f64>(None, None)?, |
2852 | | ), |
2853 | | ( |
2854 | | Interval::make(Some(-0.0_f64), Some(-0.0_f64))?, |
2855 | | Interval::make(Some(1_f64), Some(2_f64))?, |
2856 | | Interval::make(Some(-0.0_f64), Some(-0.0_f64))?, |
2857 | | ), |
2858 | | ( |
2859 | | Interval::make(Some(0.0_f64), Some(0.0_f64))?, |
2860 | | Interval::make(Some(1_f64), Some(2_f64))?, |
2861 | | Interval::make(Some(0.0_f64), Some(0.0_f64))?, |
2862 | | ), |
2863 | | ( |
2864 | | Interval::make(Some(-0.0_f64), Some(0.0_f64))?, |
2865 | | Interval::make(Some(1_f64), Some(2_f64))?, |
2866 | | Interval::make(Some(-0.0_f64), Some(0.0_f64))?, |
2867 | | ), |
2868 | | ( |
2869 | | Interval::make(Some(-0.0_f64), Some(1.0_f64))?, |
2870 | | Interval::make(Some(1_f64), Some(2_f64))?, |
2871 | | Interval::make(Some(-0.0_f64), Some(2.0_f64))?, |
2872 | | ), |
2873 | | ( |
2874 | | Interval::make(Some(0.0_f64), Some(1.0_f64))?, |
2875 | | Interval::make(Some(1_f64), Some(2_f64))?, |
2876 | | Interval::make(Some(0.0_f64), Some(2.0_f64))?, |
2877 | | ), |
2878 | | ( |
2879 | | Interval::make(Some(-0.0_f64), Some(1.0_f64))?, |
2880 | | Interval::make(Some(-1_f64), Some(2_f64))?, |
2881 | | Interval::make(Some(-1.0_f64), Some(2.0_f64))?, |
2882 | | ), |
2883 | | ( |
2884 | | Interval::make::<f64>(None, None)?, |
2885 | | Interval::make(Some(-0.0_f64), Some(0.0_f64))?, |
2886 | | Interval::make::<f64>(None, None)?, |
2887 | | ), |
2888 | | ( |
2889 | | Interval::make::<f64>(None, Some(10.0_f64))?, |
2890 | | Interval::make(Some(-0.0_f64), Some(0.0_f64))?, |
2891 | | Interval::make::<f64>(None, None)?, |
2892 | | ), |
2893 | | ]; |
2894 | | for case in cases { |
2895 | | let result = case.0.mul(case.1)?; |
2896 | | if case.0.data_type().is_floating() { |
2897 | | assert!( |
2898 | | result.lower().is_null() && case.2.lower().is_null() |
2899 | | || result.lower().le(case.2.lower()) |
2900 | | ); |
2901 | | assert!( |
2902 | | result.upper().is_null() && case.2.upper().is_null() |
2903 | | || result.upper().ge(case.2.upper()) |
2904 | | ); |
2905 | | } else { |
2906 | | assert_eq!(result, case.2); |
2907 | | } |
2908 | | } |
2909 | | |
2910 | | Ok(()) |
2911 | | } |
2912 | | |
2913 | | #[test] |
2914 | | fn test_div() -> Result<()> { |
2915 | | let cases = vec![ |
2916 | | ( |
2917 | | Interval::make(Some(100_i64), Some(200_i64))?, |
2918 | | Interval::make(Some(1_i64), Some(2_i64))?, |
2919 | | Interval::make(Some(50_i64), Some(200_i64))?, |
2920 | | ), |
2921 | | ( |
2922 | | Interval::make(Some(-200_i64), Some(-100_i64))?, |
2923 | | Interval::make(Some(-2_i64), Some(-1_i64))?, |
2924 | | Interval::make(Some(50_i64), Some(200_i64))?, |
2925 | | ), |
2926 | | ( |
2927 | | Interval::make(Some(100_i64), Some(200_i64))?, |
2928 | | Interval::make(Some(-2_i64), Some(-1_i64))?, |
2929 | | Interval::make(Some(-200_i64), Some(-50_i64))?, |
2930 | | ), |
2931 | | ( |
2932 | | Interval::make(Some(-200_i64), Some(-100_i64))?, |
2933 | | Interval::make(Some(1_i64), Some(2_i64))?, |
2934 | | Interval::make(Some(-200_i64), Some(-50_i64))?, |
2935 | | ), |
2936 | | ( |
2937 | | Interval::make(Some(-200_i64), Some(100_i64))?, |
2938 | | Interval::make(Some(1_i64), Some(2_i64))?, |
2939 | | Interval::make(Some(-200_i64), Some(100_i64))?, |
2940 | | ), |
2941 | | ( |
2942 | | Interval::make(Some(-100_i64), Some(200_i64))?, |
2943 | | Interval::make(Some(1_i64), Some(2_i64))?, |
2944 | | Interval::make(Some(-100_i64), Some(200_i64))?, |
2945 | | ), |
2946 | | ( |
2947 | | Interval::make(Some(10_i64), Some(20_i64))?, |
2948 | | Interval::make::<i64>(None, None)?, |
2949 | | Interval::make::<i64>(None, None)?, |
2950 | | ), |
2951 | | ( |
2952 | | Interval::make(Some(-100_i64), Some(200_i64))?, |
2953 | | Interval::make(Some(-1_i64), Some(2_i64))?, |
2954 | | Interval::make::<i64>(None, None)?, |
2955 | | ), |
2956 | | ( |
2957 | | Interval::make(Some(-100_i64), Some(200_i64))?, |
2958 | | Interval::make(Some(-2_i64), Some(1_i64))?, |
2959 | | Interval::make::<i64>(None, None)?, |
2960 | | ), |
2961 | | ( |
2962 | | Interval::make(Some(100_i64), Some(200_i64))?, |
2963 | | Interval::make(Some(0_i64), Some(1_i64))?, |
2964 | | Interval::make(Some(100_i64), None)?, |
2965 | | ), |
2966 | | ( |
2967 | | Interval::make(Some(100_i64), Some(200_i64))?, |
2968 | | Interval::make(None, Some(0_i64))?, |
2969 | | Interval::make(None, Some(0_i64))?, |
2970 | | ), |
2971 | | ( |
2972 | | Interval::make(Some(100_i64), Some(200_i64))?, |
2973 | | Interval::make(Some(0_i64), Some(0_i64))?, |
2974 | | Interval::make::<i64>(None, None)?, |
2975 | | ), |
2976 | | ( |
2977 | | Interval::make(Some(0_i64), Some(1_i64))?, |
2978 | | Interval::make(Some(100_i64), Some(200_i64))?, |
2979 | | Interval::make(Some(0_i64), Some(0_i64))?, |
2980 | | ), |
2981 | | ( |
2982 | | Interval::make(Some(0_i64), Some(1_i64))?, |
2983 | | Interval::make(Some(100_i64), Some(200_i64))?, |
2984 | | Interval::make(Some(0_i64), Some(0_i64))?, |
2985 | | ), |
2986 | | ( |
2987 | | Interval::make(Some(1_u32), Some(2_u32))?, |
2988 | | Interval::make(Some(0_u32), Some(0_u32))?, |
2989 | | Interval::make::<u32>(None, None)?, |
2990 | | ), |
2991 | | ( |
2992 | | Interval::make(Some(10_u32), Some(20_u32))?, |
2993 | | Interval::make(None, Some(2_u32))?, |
2994 | | Interval::make(Some(5_u32), None)?, |
2995 | | ), |
2996 | | ( |
2997 | | Interval::make(Some(10_u32), Some(20_u32))?, |
2998 | | Interval::make(Some(0_u32), Some(2_u32))?, |
2999 | | Interval::make(Some(5_u32), None)?, |
3000 | | ), |
3001 | | ( |
3002 | | Interval::make(Some(10_u32), Some(20_u32))?, |
3003 | | Interval::make(Some(0_u32), Some(0_u32))?, |
3004 | | Interval::make::<u32>(None, None)?, |
3005 | | ), |
3006 | | ( |
3007 | | Interval::make(Some(12_u64), Some(48_u64))?, |
3008 | | Interval::make(Some(10_u64), Some(20_u64))?, |
3009 | | Interval::make(Some(0_u64), Some(4_u64))?, |
3010 | | ), |
3011 | | ( |
3012 | | Interval::make(Some(12_u64), Some(48_u64))?, |
3013 | | Interval::make(None, Some(2_u64))?, |
3014 | | Interval::make(Some(6_u64), None)?, |
3015 | | ), |
3016 | | ( |
3017 | | Interval::make(Some(12_u64), Some(48_u64))?, |
3018 | | Interval::make(Some(0_u64), Some(2_u64))?, |
3019 | | Interval::make(Some(6_u64), None)?, |
3020 | | ), |
3021 | | ( |
3022 | | Interval::make(None, Some(48_u64))?, |
3023 | | Interval::make(Some(0_u64), Some(2_u64))?, |
3024 | | Interval::make::<u64>(None, None)?, |
3025 | | ), |
3026 | | ( |
3027 | | Interval::make(Some(f32::MAX), Some(f32::MAX))?, |
3028 | | Interval::make(Some(-0.1_f32), Some(0.1_f32))?, |
3029 | | Interval::make::<f32>(None, None)?, |
3030 | | ), |
3031 | | ( |
3032 | | Interval::make(Some(f32::MIN), None)?, |
3033 | | Interval::make(Some(0.1_f32), Some(0.1_f32))?, |
3034 | | Interval::make::<f32>(None, None)?, |
3035 | | ), |
3036 | | ( |
3037 | | Interval::make(Some(-10.0_f32), Some(10.0_f32))?, |
3038 | | Interval::make(Some(-0.1_f32), Some(-0.1_f32))?, |
3039 | | Interval::make(Some(-100.0_f32), Some(100.0_f32))?, |
3040 | | ), |
3041 | | ( |
3042 | | Interval::make(Some(-10.0_f32), Some(f32::MAX))?, |
3043 | | Interval::make::<f32>(None, None)?, |
3044 | | Interval::make::<f32>(None, None)?, |
3045 | | ), |
3046 | | ( |
3047 | | Interval::make(Some(f32::MIN), Some(10.0_f32))?, |
3048 | | Interval::make(Some(1.0_f32), None)?, |
3049 | | Interval::make(Some(f32::MIN), Some(10.0_f32))?, |
3050 | | ), |
3051 | | ( |
3052 | | Interval::make(Some(-0.0_f32), Some(0.0_f32))?, |
3053 | | Interval::make(Some(f32::MAX), None)?, |
3054 | | Interval::make(Some(-0.0_f32), Some(0.0_f32))?, |
3055 | | ), |
3056 | | ( |
3057 | | Interval::make(Some(-0.0_f32), Some(0.0_f32))?, |
3058 | | Interval::make(None, Some(-0.0_f32))?, |
3059 | | Interval::make::<f32>(None, None)?, |
3060 | | ), |
3061 | | ( |
3062 | | Interval::make(Some(0.0_f32), Some(0.0_f32))?, |
3063 | | Interval::make(Some(f32::MAX), None)?, |
3064 | | Interval::make(Some(0.0_f32), Some(0.0_f32))?, |
3065 | | ), |
3066 | | ( |
3067 | | Interval::make(Some(1.0_f32), Some(2.0_f32))?, |
3068 | | Interval::make(Some(0.0_f32), Some(4.0_f32))?, |
3069 | | Interval::make(Some(0.25_f32), None)?, |
3070 | | ), |
3071 | | ( |
3072 | | Interval::make(Some(1.0_f32), Some(2.0_f32))?, |
3073 | | Interval::make(Some(-4.0_f32), Some(-0.0_f32))?, |
3074 | | Interval::make(None, Some(-0.25_f32))?, |
3075 | | ), |
3076 | | ( |
3077 | | Interval::make(Some(-4.0_f64), Some(2.0_f64))?, |
3078 | | Interval::make(Some(10.0_f64), Some(20.0_f64))?, |
3079 | | Interval::make(Some(-0.4_f64), Some(0.2_f64))?, |
3080 | | ), |
3081 | | ( |
3082 | | Interval::make(Some(-0.0_f64), Some(-0.0_f64))?, |
3083 | | Interval::make(None, Some(-0.0_f64))?, |
3084 | | Interval::make(Some(0.0_f64), None)?, |
3085 | | ), |
3086 | | ( |
3087 | | Interval::make(Some(1.0_f64), Some(2.0_f64))?, |
3088 | | Interval::make::<f64>(None, None)?, |
3089 | | Interval::make(Some(0.0_f64), None)?, |
3090 | | ), |
3091 | | ]; |
3092 | | for case in cases { |
3093 | | let result = case.0.div(case.1)?; |
3094 | | if case.0.data_type().is_floating() { |
3095 | | assert!( |
3096 | | result.lower().is_null() && case.2.lower().is_null() |
3097 | | || result.lower().le(case.2.lower()) |
3098 | | ); |
3099 | | assert!( |
3100 | | result.upper().is_null() && case.2.upper().is_null() |
3101 | | || result.upper().ge(case.2.upper()) |
3102 | | ); |
3103 | | } else { |
3104 | | assert_eq!(result, case.2); |
3105 | | } |
3106 | | } |
3107 | | |
3108 | | Ok(()) |
3109 | | } |
3110 | | |
3111 | | #[test] |
3112 | | fn test_cardinality_of_intervals() -> Result<()> { |
3113 | | // In IEEE 754 standard for floating-point arithmetic, if we keep the sign and exponent fields same, |
3114 | | // we can represent 4503599627370496+1 different numbers by changing the mantissa |
3115 | | // (4503599627370496 = 2^52, since there are 52 bits in mantissa, and 2^23 = 8388608 for f32). |
3116 | | // TODO: Add tests for non-exponential boundary aligned intervals too. |
3117 | | let distinct_f64 = 4503599627370497; |
3118 | | let distinct_f32 = 8388609; |
3119 | | let intervals = [ |
3120 | | Interval::make(Some(0.25_f64), Some(0.50_f64))?, |
3121 | | Interval::make(Some(0.5_f64), Some(1.0_f64))?, |
3122 | | Interval::make(Some(1.0_f64), Some(2.0_f64))?, |
3123 | | Interval::make(Some(32.0_f64), Some(64.0_f64))?, |
3124 | | Interval::make(Some(-0.50_f64), Some(-0.25_f64))?, |
3125 | | Interval::make(Some(-32.0_f64), Some(-16.0_f64))?, |
3126 | | ]; |
3127 | | for interval in intervals { |
3128 | | assert_eq!(interval.cardinality().unwrap(), distinct_f64); |
3129 | | } |
3130 | | |
3131 | | let intervals = [ |
3132 | | Interval::make(Some(0.25_f32), Some(0.50_f32))?, |
3133 | | Interval::make(Some(-1_f32), Some(-0.5_f32))?, |
3134 | | ]; |
3135 | | for interval in intervals { |
3136 | | assert_eq!(interval.cardinality().unwrap(), distinct_f32); |
3137 | | } |
3138 | | |
3139 | | // The regular logarithmic distribution of floating-point numbers are |
3140 | | // only applicable outside of the `(-phi, phi)` interval where `phi` |
3141 | | // denotes the largest positive subnormal floating-point number. Since |
3142 | | // the following intervals include such subnormal points, we cannot use |
3143 | | // a simple powers-of-two type formula for our expectations. Therefore, |
3144 | | // we manually supply the actual expected cardinality. |
3145 | | let interval = Interval::make(Some(-0.0625), Some(0.0625))?; |
3146 | | assert_eq!(interval.cardinality().unwrap(), 9178336040581070850); |
3147 | | |
3148 | | let interval = Interval::try_new( |
3149 | | ScalarValue::UInt64(Some(u64::MIN + 1)), |
3150 | | ScalarValue::UInt64(Some(u64::MAX)), |
3151 | | )?; |
3152 | | assert_eq!(interval.cardinality().unwrap(), u64::MAX); |
3153 | | |
3154 | | let interval = Interval::try_new( |
3155 | | ScalarValue::Int64(Some(i64::MIN + 1)), |
3156 | | ScalarValue::Int64(Some(i64::MAX)), |
3157 | | )?; |
3158 | | assert_eq!(interval.cardinality().unwrap(), u64::MAX); |
3159 | | |
3160 | | let interval = Interval::try_new( |
3161 | | ScalarValue::Float32(Some(-0.0_f32)), |
3162 | | ScalarValue::Float32(Some(0.0_f32)), |
3163 | | )?; |
3164 | | assert_eq!(interval.cardinality().unwrap(), 2); |
3165 | | |
3166 | | Ok(()) |
3167 | | } |
3168 | | |
3169 | | #[test] |
3170 | | fn test_satisfy_comparison() -> Result<()> { |
3171 | | let cases = vec![ |
3172 | | ( |
3173 | | Interval::make(Some(1000_i64), None)?, |
3174 | | Interval::make(None, Some(1000_i64))?, |
3175 | | true, |
3176 | | Interval::make(Some(1000_i64), None)?, |
3177 | | Interval::make(None, Some(1000_i64))?, |
3178 | | ), |
3179 | | ( |
3180 | | Interval::make(None, Some(1000_i64))?, |
3181 | | Interval::make(Some(1000_i64), None)?, |
3182 | | true, |
3183 | | Interval::make(Some(1000_i64), Some(1000_i64))?, |
3184 | | Interval::make(Some(1000_i64), Some(1000_i64))?, |
3185 | | ), |
3186 | | ( |
3187 | | Interval::make(Some(1000_i64), None)?, |
3188 | | Interval::make(None, Some(1000_i64))?, |
3189 | | false, |
3190 | | Interval::make(Some(1000_i64), None)?, |
3191 | | Interval::make(None, Some(1000_i64))?, |
3192 | | ), |
3193 | | ( |
3194 | | Interval::make(Some(0_i64), Some(1000_i64))?, |
3195 | | Interval::make(Some(500_i64), Some(1500_i64))?, |
3196 | | true, |
3197 | | Interval::make(Some(500_i64), Some(1000_i64))?, |
3198 | | Interval::make(Some(500_i64), Some(1000_i64))?, |
3199 | | ), |
3200 | | ( |
3201 | | Interval::make(Some(500_i64), Some(1500_i64))?, |
3202 | | Interval::make(Some(0_i64), Some(1000_i64))?, |
3203 | | true, |
3204 | | Interval::make(Some(500_i64), Some(1500_i64))?, |
3205 | | Interval::make(Some(0_i64), Some(1000_i64))?, |
3206 | | ), |
3207 | | ( |
3208 | | Interval::make(Some(0_i64), Some(1000_i64))?, |
3209 | | Interval::make(Some(500_i64), Some(1500_i64))?, |
3210 | | false, |
3211 | | Interval::make(Some(501_i64), Some(1000_i64))?, |
3212 | | Interval::make(Some(500_i64), Some(999_i64))?, |
3213 | | ), |
3214 | | ( |
3215 | | Interval::make(Some(500_i64), Some(1500_i64))?, |
3216 | | Interval::make(Some(0_i64), Some(1000_i64))?, |
3217 | | false, |
3218 | | Interval::make(Some(500_i64), Some(1500_i64))?, |
3219 | | Interval::make(Some(0_i64), Some(1000_i64))?, |
3220 | | ), |
3221 | | ( |
3222 | | Interval::make::<i64>(None, None)?, |
3223 | | Interval::make(Some(1_i64), Some(1_i64))?, |
3224 | | false, |
3225 | | Interval::make(Some(2_i64), None)?, |
3226 | | Interval::make(Some(1_i64), Some(1_i64))?, |
3227 | | ), |
3228 | | ( |
3229 | | Interval::make::<i64>(None, None)?, |
3230 | | Interval::make(Some(1_i64), Some(1_i64))?, |
3231 | | true, |
3232 | | Interval::make(Some(1_i64), None)?, |
3233 | | Interval::make(Some(1_i64), Some(1_i64))?, |
3234 | | ), |
3235 | | ( |
3236 | | Interval::make(Some(1_i64), Some(1_i64))?, |
3237 | | Interval::make::<i64>(None, None)?, |
3238 | | false, |
3239 | | Interval::make(Some(1_i64), Some(1_i64))?, |
3240 | | Interval::make(None, Some(0_i64))?, |
3241 | | ), |
3242 | | ( |
3243 | | Interval::make(Some(1_i64), Some(1_i64))?, |
3244 | | Interval::make::<i64>(None, None)?, |
3245 | | true, |
3246 | | Interval::make(Some(1_i64), Some(1_i64))?, |
3247 | | Interval::make(None, Some(1_i64))?, |
3248 | | ), |
3249 | | ( |
3250 | | Interval::make(Some(1_i64), Some(1_i64))?, |
3251 | | Interval::make::<i64>(None, None)?, |
3252 | | false, |
3253 | | Interval::make(Some(1_i64), Some(1_i64))?, |
3254 | | Interval::make(None, Some(0_i64))?, |
3255 | | ), |
3256 | | ( |
3257 | | Interval::make(Some(1_i64), Some(1_i64))?, |
3258 | | Interval::make::<i64>(None, None)?, |
3259 | | true, |
3260 | | Interval::make(Some(1_i64), Some(1_i64))?, |
3261 | | Interval::make(None, Some(1_i64))?, |
3262 | | ), |
3263 | | ( |
3264 | | Interval::make::<i64>(None, None)?, |
3265 | | Interval::make(Some(1_i64), Some(1_i64))?, |
3266 | | false, |
3267 | | Interval::make(Some(2_i64), None)?, |
3268 | | Interval::make(Some(1_i64), Some(1_i64))?, |
3269 | | ), |
3270 | | ( |
3271 | | Interval::make::<i64>(None, None)?, |
3272 | | Interval::make(Some(1_i64), Some(1_i64))?, |
3273 | | true, |
3274 | | Interval::make(Some(1_i64), None)?, |
3275 | | Interval::make(Some(1_i64), Some(1_i64))?, |
3276 | | ), |
3277 | | ( |
3278 | | Interval::make(Some(-1000.0_f32), Some(1000.0_f32))?, |
3279 | | Interval::make(Some(-500.0_f32), Some(500.0_f32))?, |
3280 | | false, |
3281 | | Interval::try_new( |
3282 | | next_value(ScalarValue::Float32(Some(-500.0))), |
3283 | | ScalarValue::Float32(Some(1000.0)), |
3284 | | )?, |
3285 | | Interval::make(Some(-500_f32), Some(500.0_f32))?, |
3286 | | ), |
3287 | | ( |
3288 | | Interval::make(Some(-500.0_f32), Some(500.0_f32))?, |
3289 | | Interval::make(Some(-1000.0_f32), Some(1000.0_f32))?, |
3290 | | true, |
3291 | | Interval::make(Some(-500.0_f32), Some(500.0_f32))?, |
3292 | | Interval::make(Some(-1000.0_f32), Some(500.0_f32))?, |
3293 | | ), |
3294 | | ( |
3295 | | Interval::make(Some(-500.0_f32), Some(500.0_f32))?, |
3296 | | Interval::make(Some(-1000.0_f32), Some(1000.0_f32))?, |
3297 | | false, |
3298 | | Interval::make(Some(-500.0_f32), Some(500.0_f32))?, |
3299 | | Interval::try_new( |
3300 | | ScalarValue::Float32(Some(-1000.0_f32)), |
3301 | | prev_value(ScalarValue::Float32(Some(500.0_f32))), |
3302 | | )?, |
3303 | | ), |
3304 | | ( |
3305 | | Interval::make(Some(-1000.0_f64), Some(1000.0_f64))?, |
3306 | | Interval::make(Some(-500.0_f64), Some(500.0_f64))?, |
3307 | | true, |
3308 | | Interval::make(Some(-500.0_f64), Some(1000.0_f64))?, |
3309 | | Interval::make(Some(-500.0_f64), Some(500.0_f64))?, |
3310 | | ), |
3311 | | ]; |
3312 | | for (first, second, includes_endpoints, left_modified, right_modified) in cases { |
3313 | | assert_eq!( |
3314 | | satisfy_greater(&first, &second, !includes_endpoints)?.unwrap(), |
3315 | | (left_modified, right_modified) |
3316 | | ); |
3317 | | } |
3318 | | |
3319 | | let infeasible_cases = vec![ |
3320 | | ( |
3321 | | Interval::make(None, Some(1000_i64))?, |
3322 | | Interval::make(Some(1000_i64), None)?, |
3323 | | false, |
3324 | | ), |
3325 | | ( |
3326 | | Interval::make(Some(-1000.0_f32), Some(1000.0_f32))?, |
3327 | | Interval::make(Some(1500.0_f32), Some(2000.0_f32))?, |
3328 | | false, |
3329 | | ), |
3330 | | ]; |
3331 | | for (first, second, includes_endpoints) in infeasible_cases { |
3332 | | assert_eq!(satisfy_greater(&first, &second, !includes_endpoints)?, None); |
3333 | | } |
3334 | | |
3335 | | Ok(()) |
3336 | | } |
3337 | | |
3338 | | #[test] |
3339 | | fn test_interval_display() { |
3340 | | let interval = Interval::make(Some(0.25_f32), Some(0.50_f32)).unwrap(); |
3341 | | assert_eq!(format!("{}", interval), "[0.25, 0.5]"); |
3342 | | |
3343 | | let interval = Interval::try_new( |
3344 | | ScalarValue::Float32(Some(f32::NEG_INFINITY)), |
3345 | | ScalarValue::Float32(Some(f32::INFINITY)), |
3346 | | ) |
3347 | | .unwrap(); |
3348 | | assert_eq!(format!("{}", interval), "[NULL, NULL]"); |
3349 | | } |
3350 | | |
3351 | | macro_rules! capture_mode_change { |
3352 | | ($TYPE:ty) => { |
3353 | | paste::item! { |
3354 | | capture_mode_change_helper!([<capture_mode_change_ $TYPE>], |
3355 | | [<create_interval_ $TYPE>], |
3356 | | $TYPE); |
3357 | | } |
3358 | | }; |
3359 | | } |
3360 | | |
3361 | | macro_rules! capture_mode_change_helper { |
3362 | | ($TEST_FN_NAME:ident, $CREATE_FN_NAME:ident, $TYPE:ty) => { |
3363 | | fn $CREATE_FN_NAME(lower: $TYPE, upper: $TYPE) -> Interval { |
3364 | | Interval::try_new( |
3365 | | ScalarValue::try_from(Some(lower as $TYPE)).unwrap(), |
3366 | | ScalarValue::try_from(Some(upper as $TYPE)).unwrap(), |
3367 | | ) |
3368 | | .unwrap() |
3369 | | } |
3370 | | |
3371 | | fn $TEST_FN_NAME(input: ($TYPE, $TYPE), expect_low: bool, expect_high: bool) { |
3372 | | assert!(expect_low || expect_high); |
3373 | | let interval1 = $CREATE_FN_NAME(input.0, input.0); |
3374 | | let interval2 = $CREATE_FN_NAME(input.1, input.1); |
3375 | | let result = interval1.add(&interval2).unwrap(); |
3376 | | let without_fe = $CREATE_FN_NAME(input.0 + input.1, input.0 + input.1); |
3377 | | assert!( |
3378 | | (!expect_low || result.lower < without_fe.lower) |
3379 | | && (!expect_high || result.upper > without_fe.upper) |
3380 | | ); |
3381 | | } |
3382 | | }; |
3383 | | } |
3384 | | |
3385 | | capture_mode_change!(f32); |
3386 | | capture_mode_change!(f64); |
3387 | | |
3388 | | #[cfg(all( |
3389 | | any(target_arch = "x86_64", target_arch = "aarch64"), |
3390 | | not(target_os = "windows") |
3391 | | ))] |
3392 | | #[test] |
3393 | | fn test_add_intervals_lower_affected_f32() { |
3394 | | // Lower is affected |
3395 | | let lower = f32::from_bits(1073741887); //1000000000000000000000000111111 |
3396 | | let upper = f32::from_bits(1098907651); //1000001100000000000000000000011 |
3397 | | capture_mode_change_f32((lower, upper), true, false); |
3398 | | |
3399 | | // Upper is affected |
3400 | | let lower = f32::from_bits(1072693248); //111111111100000000000000000000 |
3401 | | let upper = f32::from_bits(715827883); //101010101010101010101010101011 |
3402 | | capture_mode_change_f32((lower, upper), false, true); |
3403 | | |
3404 | | // Lower is affected |
3405 | | let lower = 1.0; // 0x3FF0000000000000 |
3406 | | let upper = 0.3; // 0x3FD3333333333333 |
3407 | | capture_mode_change_f64((lower, upper), true, false); |
3408 | | |
3409 | | // Upper is affected |
3410 | | let lower = 1.4999999999999998; // 0x3FF7FFFFFFFFFFFF |
3411 | | let upper = 0.000_000_000_000_000_022_044_604_925_031_31; // 0x3C796A6B413BB21F |
3412 | | capture_mode_change_f64((lower, upper), false, true); |
3413 | | } |
3414 | | |
3415 | | #[cfg(any( |
3416 | | not(any(target_arch = "x86_64", target_arch = "aarch64")), |
3417 | | target_os = "windows" |
3418 | | ))] |
3419 | | #[test] |
3420 | | fn test_next_impl_add_intervals_f64() { |
3421 | | let lower = 1.5; |
3422 | | let upper = 1.5; |
3423 | | capture_mode_change_f64((lower, upper), true, true); |
3424 | | |
3425 | | let lower = 1.5; |
3426 | | let upper = 1.5; |
3427 | | capture_mode_change_f32((lower, upper), true, true); |
3428 | | } |
3429 | | } |