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