datafusion_functions/math/
mod.rs

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//! "math" DataFusion functions
19
20use crate::math::monotonicity::*;
21use datafusion_expr::ScalarUDF;
22use std::sync::Arc;
23
24pub mod abs;
25pub mod bounds;
26pub mod cot;
27pub mod factorial;
28pub mod gcd;
29pub mod iszero;
30pub mod lcm;
31pub mod log;
32pub mod monotonicity;
33pub mod nans;
34pub mod nanvl;
35pub mod pi;
36pub mod power;
37pub mod random;
38pub mod round;
39pub mod signum;
40pub mod trunc;
41
42// Create UDFs
43make_udf_function!(abs::AbsFunc, abs);
44make_math_unary_udf!(
45    AcosFunc,
46    acos,
47    acos,
48    super::acos_order,
49    super::bounds::acos_bounds,
50    super::get_acos_doc
51);
52make_math_unary_udf!(
53    AcoshFunc,
54    acosh,
55    acosh,
56    super::acosh_order,
57    super::bounds::acosh_bounds,
58    super::get_acosh_doc
59);
60make_math_unary_udf!(
61    AsinFunc,
62    asin,
63    asin,
64    super::asin_order,
65    super::bounds::asin_bounds,
66    super::get_asin_doc
67);
68make_math_unary_udf!(
69    AsinhFunc,
70    asinh,
71    asinh,
72    super::asinh_order,
73    super::bounds::unbounded_bounds,
74    super::get_asinh_doc
75);
76make_math_unary_udf!(
77    AtanFunc,
78    atan,
79    atan,
80    super::atan_order,
81    super::bounds::atan_bounds,
82    super::get_atan_doc
83);
84make_math_unary_udf!(
85    AtanhFunc,
86    atanh,
87    atanh,
88    super::atanh_order,
89    super::bounds::unbounded_bounds,
90    super::get_atanh_doc
91);
92make_math_binary_udf!(
93    Atan2,
94    atan2,
95    atan2,
96    super::atan2_order,
97    super::get_atan2_doc
98);
99make_math_unary_udf!(
100    CbrtFunc,
101    cbrt,
102    cbrt,
103    super::cbrt_order,
104    super::bounds::unbounded_bounds,
105    super::get_cbrt_doc
106);
107make_math_unary_udf!(
108    CeilFunc,
109    ceil,
110    ceil,
111    super::ceil_order,
112    super::bounds::unbounded_bounds,
113    super::get_ceil_doc
114);
115make_math_unary_udf!(
116    CosFunc,
117    cos,
118    cos,
119    super::cos_order,
120    super::bounds::cos_bounds,
121    super::get_cos_doc
122);
123make_math_unary_udf!(
124    CoshFunc,
125    cosh,
126    cosh,
127    super::cosh_order,
128    super::bounds::cosh_bounds,
129    super::get_cosh_doc
130);
131make_udf_function!(cot::CotFunc, cot);
132make_math_unary_udf!(
133    DegreesFunc,
134    degrees,
135    to_degrees,
136    super::degrees_order,
137    super::bounds::unbounded_bounds,
138    super::get_degrees_doc
139);
140make_math_unary_udf!(
141    ExpFunc,
142    exp,
143    exp,
144    super::exp_order,
145    super::bounds::exp_bounds,
146    super::get_exp_doc
147);
148make_udf_function!(factorial::FactorialFunc, factorial);
149make_math_unary_udf!(
150    FloorFunc,
151    floor,
152    floor,
153    super::floor_order,
154    super::bounds::unbounded_bounds,
155    super::get_floor_doc
156);
157make_udf_function!(log::LogFunc, log);
158make_udf_function!(gcd::GcdFunc, gcd);
159make_udf_function!(nans::IsNanFunc, isnan);
160make_udf_function!(iszero::IsZeroFunc, iszero);
161make_udf_function!(lcm::LcmFunc, lcm);
162make_math_unary_udf!(
163    LnFunc,
164    ln,
165    ln,
166    super::ln_order,
167    super::bounds::unbounded_bounds,
168    super::get_ln_doc
169);
170make_math_unary_udf!(
171    Log2Func,
172    log2,
173    log2,
174    super::log2_order,
175    super::bounds::unbounded_bounds,
176    super::get_log2_doc
177);
178make_math_unary_udf!(
179    Log10Func,
180    log10,
181    log10,
182    super::log10_order,
183    super::bounds::unbounded_bounds,
184    super::get_log10_doc
185);
186make_udf_function!(nanvl::NanvlFunc, nanvl);
187make_udf_function!(pi::PiFunc, pi);
188make_udf_function!(power::PowerFunc, power);
189make_math_unary_udf!(
190    RadiansFunc,
191    radians,
192    to_radians,
193    super::radians_order,
194    super::bounds::radians_bounds,
195    super::get_radians_doc
196);
197make_udf_function!(random::RandomFunc, random);
198make_udf_function!(round::RoundFunc, round);
199make_udf_function!(signum::SignumFunc, signum);
200make_math_unary_udf!(
201    SinFunc,
202    sin,
203    sin,
204    super::sin_order,
205    super::bounds::sin_bounds,
206    super::get_sin_doc
207);
208make_math_unary_udf!(
209    SinhFunc,
210    sinh,
211    sinh,
212    super::sinh_order,
213    super::bounds::unbounded_bounds,
214    super::get_sinh_doc
215);
216make_math_unary_udf!(
217    SqrtFunc,
218    sqrt,
219    sqrt,
220    super::sqrt_order,
221    super::bounds::sqrt_bounds,
222    super::get_sqrt_doc
223);
224make_math_unary_udf!(
225    TanFunc,
226    tan,
227    tan,
228    super::tan_order,
229    super::bounds::unbounded_bounds,
230    super::get_tan_doc
231);
232make_math_unary_udf!(
233    TanhFunc,
234    tanh,
235    tanh,
236    super::tanh_order,
237    super::bounds::tanh_bounds,
238    super::get_tanh_doc
239);
240make_udf_function!(trunc::TruncFunc, trunc);
241
242pub mod expr_fn {
243    export_functions!(
244        (abs, "returns the absolute value of a given number", num),
245        (acos, "returns the arc cosine or inverse cosine of a number", num),
246        (acosh, "returns inverse hyperbolic cosine", num),
247        (asin, "returns the arc sine or inverse sine of a number", num),
248        (asinh, "returns inverse hyperbolic sine", num),
249        (atan, "returns inverse tangent", num),
250        (atan2, "returns inverse tangent of a division given in the argument", y x),
251        (atanh, "returns inverse hyperbolic tangent", num),
252        (cbrt, "cube root of a number", num),
253        (ceil, "nearest integer greater than or equal to argument", num),
254        (cos, "cosine", num),
255        (cosh, "hyperbolic cosine", num),
256        (cot, "cotangent of a number", num),
257        (degrees, "converts radians to degrees", num),
258        (exp, "exponential", num),
259        (factorial, "factorial", num),
260        (floor, "nearest integer less than or equal to argument", num),
261        (gcd, "greatest common divisor", x y),
262        (isnan, "returns true if a given number is +NaN or -NaN otherwise returns false", num),
263        (iszero, "returns true if a given number is +0.0 or -0.0 otherwise returns false", num),
264        (lcm, "least common multiple", x y),
265        (ln, "natural logarithm (base e) of a number", num),
266        (log, "logarithm of a number for a particular `base`", base num),
267        (log2, "base 2 logarithm of a number", num),
268        (log10, "base 10 logarithm of a number", num),
269        (nanvl, "returns x if x is not NaN otherwise returns y", x y),
270        (pi, "Returns an approximate value of π",),
271        (power, "`base` raised to the power of `exponent`", base exponent),
272        (radians, "converts degrees to radians", num),
273        (random, "Returns a random value in the range 0.0 <= x < 1.0",),
274        (signum, "sign of the argument (-1, 0, +1)", num),
275        (sin, "sine", num),
276        (sinh, "hyperbolic sine", num),
277        (sqrt, "square root of a number", num),
278        (tan, "returns the tangent of a number", num),
279        (tanh, "returns the hyperbolic tangent of a number", num),
280        (round, "round to nearest integer", args,),
281        (trunc, "truncate toward zero, with optional precision", args,)
282    );
283}
284
285/// Returns all DataFusion functions defined in this package
286pub fn functions() -> Vec<Arc<ScalarUDF>> {
287    vec![
288        abs(),
289        acos(),
290        acosh(),
291        asin(),
292        asinh(),
293        atan(),
294        atan2(),
295        atanh(),
296        cbrt(),
297        ceil(),
298        cos(),
299        cosh(),
300        cot(),
301        degrees(),
302        exp(),
303        factorial(),
304        floor(),
305        gcd(),
306        isnan(),
307        iszero(),
308        lcm(),
309        ln(),
310        log(),
311        log2(),
312        log10(),
313        nanvl(),
314        pi(),
315        power(),
316        radians(),
317        random(),
318        signum(),
319        sin(),
320        sinh(),
321        sqrt(),
322        tan(),
323        tanh(),
324        round(),
325        trunc(),
326    ]
327}
328
329#[cfg(test)]
330mod tests {
331    use arrow::datatypes::DataType;
332    use datafusion_common::ScalarValue;
333    use datafusion_expr::interval_arithmetic::Interval;
334
335    fn unbounded_interval(data_type: &DataType) -> Interval {
336        Interval::make_unbounded(data_type).unwrap()
337    }
338
339    fn one_to_inf_interval(data_type: &DataType) -> Interval {
340        Interval::try_new(
341            ScalarValue::new_one(data_type).unwrap(),
342            ScalarValue::try_from(data_type).unwrap(),
343        )
344        .unwrap()
345    }
346
347    fn zero_to_pi_interval(data_type: &DataType) -> Interval {
348        Interval::try_new(
349            ScalarValue::new_zero(data_type).unwrap(),
350            ScalarValue::new_pi_upper(data_type).unwrap(),
351        )
352        .unwrap()
353    }
354
355    fn assert_udf_evaluates_to_bounds(
356        udf: &datafusion_expr::ScalarUDF,
357        interval: Interval,
358        expected: Interval,
359    ) {
360        let input = vec![&interval];
361        let result = udf.evaluate_bounds(&input).unwrap();
362        assert_eq!(
363            result,
364            expected,
365            "Bounds check failed on UDF: {:?}",
366            udf.name()
367        );
368    }
369
370    #[test]
371    fn test_cases() -> crate::Result<()> {
372        let datatypes = [DataType::Float32, DataType::Float64];
373        let cases = datatypes
374            .iter()
375            .flat_map(|data_type| {
376                vec![
377                    (
378                        super::acos(),
379                        unbounded_interval(data_type),
380                        zero_to_pi_interval(data_type),
381                    ),
382                    (
383                        super::acosh(),
384                        unbounded_interval(data_type),
385                        Interval::make_non_negative_infinity_interval(data_type).unwrap(),
386                    ),
387                    (
388                        super::asin(),
389                        unbounded_interval(data_type),
390                        Interval::make_symmetric_half_pi_interval(data_type).unwrap(),
391                    ),
392                    (
393                        super::atan(),
394                        unbounded_interval(data_type),
395                        Interval::make_symmetric_half_pi_interval(data_type).unwrap(),
396                    ),
397                    (
398                        super::cos(),
399                        unbounded_interval(data_type),
400                        Interval::make_symmetric_unit_interval(data_type).unwrap(),
401                    ),
402                    (
403                        super::cosh(),
404                        unbounded_interval(data_type),
405                        one_to_inf_interval(data_type),
406                    ),
407                    (
408                        super::sin(),
409                        unbounded_interval(data_type),
410                        Interval::make_symmetric_unit_interval(data_type).unwrap(),
411                    ),
412                    (
413                        super::exp(),
414                        unbounded_interval(data_type),
415                        Interval::make_non_negative_infinity_interval(data_type).unwrap(),
416                    ),
417                    (
418                        super::sqrt(),
419                        unbounded_interval(data_type),
420                        Interval::make_non_negative_infinity_interval(data_type).unwrap(),
421                    ),
422                    (
423                        super::radians(),
424                        unbounded_interval(data_type),
425                        Interval::make_symmetric_pi_interval(data_type).unwrap(),
426                    ),
427                    (
428                        super::sqrt(),
429                        unbounded_interval(data_type),
430                        Interval::make_non_negative_infinity_interval(data_type).unwrap(),
431                    ),
432                ]
433            })
434            .collect::<Vec<_>>();
435
436        for (udf, interval, expected) in cases {
437            assert_udf_evaluates_to_bounds(&udf, interval, expected);
438        }
439
440        Ok(())
441    }
442}