1use crate::math::monotonicity::*;
21use datafusion_common::{Result, exec_err};
22use datafusion_expr::ScalarUDF;
23use std::sync::Arc;
24
25pub mod abs;
26pub mod bounds;
27pub mod ceil;
28mod common;
29pub mod cot;
30mod decimal;
31pub mod factorial;
32pub mod floor;
33pub mod gcd;
34pub mod iszero;
35pub mod lcm;
36pub mod log;
37pub mod monotonicity;
38pub mod nans;
39pub mod nanvl;
40pub mod pi;
41pub mod power;
42pub mod random;
43pub mod round;
44pub mod signum;
45pub mod trunc;
46
47fn validate_sqrt_input(value: f64) -> Result<()> {
48 if value < 0.0 {
49 exec_err!("cannot take square root of a negative number")
50 } else {
51 Ok(())
52 }
53}
54
55make_udf_function!(abs::AbsFunc, abs);
57make_math_unary_udf!(
58 AcosFunc,
59 acos,
60 acos,
61 super::acos_order,
62 super::bounds::acos_bounds,
63 true,
64 super::get_acos_doc
65);
66make_math_unary_udf!(
67 AcoshFunc,
68 acosh,
69 acosh,
70 super::acosh_order,
71 super::bounds::acosh_bounds,
72 true,
73 super::get_acosh_doc
74);
75make_math_unary_udf!(
76 AsinFunc,
77 asin,
78 asin,
79 super::asin_order,
80 super::bounds::asin_bounds,
81 true,
82 super::get_asin_doc
83);
84make_math_unary_udf!(
85 AsinhFunc,
86 asinh,
87 asinh,
88 super::asinh_order,
89 super::bounds::unbounded_bounds,
90 true,
91 super::get_asinh_doc
92);
93make_math_unary_udf!(
94 AtanFunc,
95 atan,
96 atan,
97 super::atan_order,
98 super::bounds::atan_bounds,
99 true,
100 super::get_atan_doc
101);
102make_math_unary_udf!(
103 AtanhFunc,
104 atanh,
105 atanh,
106 super::atanh_order,
107 super::bounds::unbounded_bounds,
108 true,
109 super::get_atanh_doc
110);
111make_math_binary_udf!(
112 Atan2,
113 atan2,
114 atan2,
115 super::atan2_order,
116 true,
117 super::get_atan2_doc
118);
119make_math_unary_udf!(
120 CbrtFunc,
121 cbrt,
122 cbrt,
123 super::cbrt_order,
124 super::bounds::unbounded_bounds,
125 true,
126 super::get_cbrt_doc
127);
128make_udf_function!(ceil::CeilFunc, ceil);
129make_math_unary_udf!(
130 CosFunc,
131 cos,
132 cos,
133 super::cos_order,
134 super::bounds::cos_bounds,
135 true,
136 super::get_cos_doc
137);
138make_math_unary_udf!(
139 CoshFunc,
140 cosh,
141 cosh,
142 super::cosh_order,
143 super::bounds::cosh_bounds,
144 true,
145 super::get_cosh_doc
146);
147make_udf_function!(cot::CotFunc, cot);
148make_math_unary_udf!(
149 DegreesFunc,
150 degrees,
151 to_degrees,
152 super::degrees_order,
153 super::bounds::unbounded_bounds,
154 true,
155 super::get_degrees_doc
156);
157make_math_unary_udf!(
158 ExpFunc,
159 exp,
160 exp,
161 super::exp_order,
162 super::bounds::exp_bounds,
163 true,
164 super::get_exp_doc
165);
166make_udf_function!(factorial::FactorialFunc, factorial);
167make_udf_function!(floor::FloorFunc, floor);
168make_udf_function!(log::LogFunc, log);
169make_udf_function!(gcd::GcdFunc, gcd);
170make_udf_function!(nans::IsNanFunc, isnan);
171make_udf_function!(iszero::IsZeroFunc, iszero);
172make_udf_function!(lcm::LcmFunc, lcm);
173make_math_unary_udf!(
174 LnFunc,
175 ln,
176 ln,
177 super::ln_order,
178 super::bounds::unbounded_bounds,
179 true,
180 super::get_ln_doc
181);
182make_math_unary_udf!(
183 Log2Func,
184 log2,
185 log2,
186 super::log2_order,
187 super::bounds::unbounded_bounds,
188 true,
189 super::get_log2_doc
190);
191make_math_unary_udf!(
192 Log10Func,
193 log10,
194 log10,
195 super::log10_order,
196 super::bounds::unbounded_bounds,
197 true,
198 super::get_log10_doc
199);
200make_udf_function!(nanvl::NanvlFunc, nanvl);
201make_udf_function!(pi::PiFunc, pi);
202make_udf_function!(power::PowerFunc, power);
203make_math_unary_udf!(
204 RadiansFunc,
205 radians,
206 to_radians,
207 super::radians_order,
208 super::bounds::radians_bounds,
209 true,
210 super::get_radians_doc
211);
212make_udf_function!(random::RandomFunc, random);
213make_udf_function!(round::RoundFunc, round);
214make_udf_function!(signum::SignumFunc, signum);
215make_math_unary_udf!(
216 SinFunc,
217 sin,
218 sin,
219 super::sin_order,
220 super::bounds::sin_bounds,
221 true,
222 super::get_sin_doc
223);
224make_math_unary_udf!(
225 SinhFunc,
226 sinh,
227 sinh,
228 super::sinh_order,
229 super::bounds::unbounded_bounds,
230 true,
231 super::get_sinh_doc
232);
233make_math_unary_udf!(
234 SqrtFunc,
235 sqrt,
236 sqrt,
237 super::sqrt_order,
238 super::bounds::sqrt_bounds,
239 true,
240 super::get_sqrt_doc,
241 Some(super::validate_sqrt_input)
242);
243make_math_unary_udf!(
244 TanFunc,
245 tan,
246 tan,
247 super::tan_order,
248 super::bounds::unbounded_bounds,
249 true,
250 super::get_tan_doc
251);
252make_math_unary_udf!(
253 TanhFunc,
254 tanh,
255 tanh,
256 super::tanh_order,
257 super::bounds::tanh_bounds,
258 true,
259 super::get_tanh_doc
260);
261make_udf_function!(trunc::TruncFunc, trunc);
262
263#[cfg(test)]
264mod strict_tests {
265 use super::*;
266 use arrow::datatypes::Field;
267 use datafusion_common::ScalarValue;
268 use datafusion_expr::{
269 ColumnarValue, ReturnFieldArgs, ScalarFunctionArgs, ScalarUDF,
270 };
271 use std::sync::Arc;
272
273 #[test]
274 fn strict_math_functions_propagate_nulls() {
275 let cases = vec![
276 (abs(), vec![ScalarValue::from(1.0)]),
277 (acos(), vec![ScalarValue::from(0.5)]),
278 (acosh(), vec![ScalarValue::from(1.5)]),
279 (asin(), vec![ScalarValue::from(0.5)]),
280 (asinh(), vec![ScalarValue::from(0.5)]),
281 (atan(), vec![ScalarValue::from(0.5)]),
282 (
283 atan2(),
284 vec![ScalarValue::from(0.5), ScalarValue::from(1.0)],
285 ),
286 (atanh(), vec![ScalarValue::from(0.5)]),
287 (cbrt(), vec![ScalarValue::from(8.0)]),
288 (ceil(), vec![ScalarValue::from(1.5)]),
289 (cos(), vec![ScalarValue::from(0.5)]),
290 (cosh(), vec![ScalarValue::from(0.5)]),
291 (cot(), vec![ScalarValue::from(0.5)]),
292 (degrees(), vec![ScalarValue::from(0.5)]),
293 (exp(), vec![ScalarValue::from(0.5)]),
294 (factorial(), vec![ScalarValue::from(5_i64)]),
295 (floor(), vec![ScalarValue::from(1.5)]),
296 (
297 gcd(),
298 vec![ScalarValue::from(48_i64), ScalarValue::from(18_i64)],
299 ),
300 (isnan(), vec![ScalarValue::from(1.0)]),
301 (iszero(), vec![ScalarValue::from(1.0)]),
302 (
303 lcm(),
304 vec![ScalarValue::from(4_i64), ScalarValue::from(5_i64)],
305 ),
306 (ln(), vec![ScalarValue::from(2.0)]),
307 (log(), vec![ScalarValue::from(10.0)]),
308 (
309 log(),
310 vec![ScalarValue::from(10.0), ScalarValue::from(100.0)],
311 ),
312 (log2(), vec![ScalarValue::from(2.0)]),
313 (log10(), vec![ScalarValue::from(10.0)]),
314 (
315 power(),
316 vec![ScalarValue::from(2.0), ScalarValue::from(3.0)],
317 ),
318 (radians(), vec![ScalarValue::from(90.0)]),
319 (round(), vec![ScalarValue::from(1.5)]),
320 (
321 round(),
322 vec![ScalarValue::from(1.5), ScalarValue::from(1_i32)],
323 ),
324 (signum(), vec![ScalarValue::from(-1.0)]),
325 (sin(), vec![ScalarValue::from(0.5)]),
326 (sinh(), vec![ScalarValue::from(0.5)]),
327 (sqrt(), vec![ScalarValue::from(4.0)]),
328 (tan(), vec![ScalarValue::from(0.5)]),
329 (tanh(), vec![ScalarValue::from(0.5)]),
330 (trunc(), vec![ScalarValue::from(1.5)]),
331 (
332 trunc(),
333 vec![ScalarValue::from(1.5), ScalarValue::from(1_i64)],
334 ),
335 ];
336
337 for (func, valid_args) in cases {
338 assert!(func.is_strict(), "{} should be marked strict", func.name());
339
340 for null_mask in 0..(1 << valid_args.len()) {
341 let mut args = valid_args.clone();
342 for (arg_idx, arg) in args.iter_mut().enumerate() {
343 if null_mask & (1 << arg_idx) != 0 {
344 *arg = ScalarValue::try_new_null(&arg.data_type()).unwrap();
345 }
346 }
347
348 let result =
349 invoke_with_scalar_args(&func, args).unwrap_or_else(|error| {
350 panic!(
351 "{} failed for NULL mask {null_mask:b}: {error}",
352 func.name()
353 )
354 });
355 let expected_null = null_mask != 0;
356 let result = result.into_array(1).unwrap();
357 assert_eq!(
358 result.null_count() == result.len(),
359 expected_null,
360 "{} returned {result:?} for NULL mask {null_mask:0width$b}",
361 func.name(),
362 width = valid_args.len(),
363 );
364 }
365 }
366 }
367
368 fn invoke_with_scalar_args(
369 func: &ScalarUDF,
370 args: Vec<ScalarValue>,
371 ) -> Result<ColumnarValue> {
372 let arg_fields = args
373 .iter()
374 .enumerate()
375 .map(|(idx, arg)| {
376 Arc::new(Field::new(
377 format!("arg_{idx}"),
378 arg.data_type(),
379 arg.is_null(),
380 ))
381 })
382 .collect::<Vec<_>>();
383 let scalar_arguments = args.iter().map(Some).collect::<Vec<_>>();
384 let return_field = func.return_field_from_args(ReturnFieldArgs {
385 arg_fields: &arg_fields,
386 scalar_arguments: &scalar_arguments,
387 })?;
388 func.invoke_with_args(ScalarFunctionArgs {
389 args: args.into_iter().map(ColumnarValue::Scalar).collect(),
390 arg_fields,
391 number_rows: 1,
392 return_field,
393 config_options: Arc::new(Default::default()),
394 })
395 }
396}
397
398pub mod expr_fn {
399 export_functions!(
400 (abs, "returns the absolute value of a given number", num),
401 (acos, "returns the arc cosine or inverse cosine of a number", num),
402 (acosh, "returns inverse hyperbolic cosine", num),
403 (asin, "returns the arc sine or inverse sine of a number", num),
404 (asinh, "returns inverse hyperbolic sine", num),
405 (atan, "returns inverse tangent", num),
406 (atan2, "returns inverse tangent of a division given in the argument", y x),
407 (atanh, "returns inverse hyperbolic tangent", num),
408 (cbrt, "cube root of a number", num),
409 (ceil, "nearest integer greater than or equal to argument", num),
410 (cos, "cosine", num),
411 (cosh, "hyperbolic cosine", num),
412 (cot, "cotangent of a number", num),
413 (degrees, "converts radians to degrees", num),
414 (exp, "exponential", num),
415 (factorial, "factorial", num),
416 (floor, "nearest integer less than or equal to argument", num),
417 (gcd, "greatest common divisor", x y),
418 (isnan, "returns true if a given number is +NaN or -NaN otherwise returns false", num),
419 (iszero, "returns true if a given number is +0.0 or -0.0 otherwise returns false", num),
420 (lcm, "least common multiple", x y),
421 (ln, "natural logarithm (base e) of a number", num),
422 (log, "logarithm of a number for a particular `base`", base num),
423 (log2, "base 2 logarithm of a number", num),
424 (log10, "base 10 logarithm of a number", num),
425 (nanvl, "returns x if x is not NaN otherwise returns y", x y),
426 (pi, "Returns an approximate value of π",),
427 (power, "`base` raised to the power of `exponent`", base exponent),
428 (radians, "converts degrees to radians", num),
429 (random, "Returns a random value in the range 0.0 <= x < 1.0",),
430 (signum, "sign of the argument (-1, 0, +1)", num),
431 (sin, "sine", num),
432 (sinh, "hyperbolic sine", num),
433 (sqrt, "square root of a number", num),
434 (tan, "returns the tangent of a number", num),
435 (tanh, "returns the hyperbolic tangent of a number", num),
436 (round, "round to nearest integer", args,),
437 (trunc, "truncate toward zero, with optional precision", args,)
438 );
439}
440
441pub fn functions() -> Vec<Arc<ScalarUDF>> {
443 vec![
444 abs(),
445 acos(),
446 acosh(),
447 asin(),
448 asinh(),
449 atan(),
450 atan2(),
451 atanh(),
452 cbrt(),
453 ceil(),
454 cos(),
455 cosh(),
456 cot(),
457 degrees(),
458 exp(),
459 factorial(),
460 floor(),
461 gcd(),
462 isnan(),
463 iszero(),
464 lcm(),
465 ln(),
466 log(),
467 log2(),
468 log10(),
469 nanvl(),
470 pi(),
471 power(),
472 radians(),
473 random(),
474 signum(),
475 sin(),
476 sinh(),
477 sqrt(),
478 tan(),
479 tanh(),
480 round(),
481 trunc(),
482 ]
483}
484
485#[cfg(test)]
486mod tests {
487 use arrow::datatypes::DataType;
488 use datafusion_common::ScalarValue;
489 use datafusion_expr::interval_arithmetic::Interval;
490
491 fn unbounded_interval(data_type: &DataType) -> Interval {
492 Interval::make_unbounded(data_type).unwrap()
493 }
494
495 fn one_to_inf_interval(data_type: &DataType) -> Interval {
496 Interval::try_new(
497 ScalarValue::new_one(data_type).unwrap(),
498 ScalarValue::try_from(data_type).unwrap(),
499 )
500 .unwrap()
501 }
502
503 fn zero_to_pi_interval(data_type: &DataType) -> Interval {
504 Interval::try_new(
505 ScalarValue::new_zero(data_type).unwrap(),
506 ScalarValue::new_pi_upper(data_type).unwrap(),
507 )
508 .unwrap()
509 }
510
511 fn assert_udf_evaluates_to_bounds(
512 udf: &datafusion_expr::ScalarUDF,
513 interval: Interval,
514 expected: Interval,
515 ) {
516 let input = vec![&interval];
517 let result = udf.evaluate_bounds(&input).unwrap();
518 assert_eq!(
519 result,
520 expected,
521 "Bounds check failed on UDF: {:?}",
522 udf.name()
523 );
524 }
525
526 #[test]
527 fn test_cases() -> crate::Result<()> {
528 let datatypes = [DataType::Float32, DataType::Float64];
529 let cases = datatypes
530 .iter()
531 .flat_map(|data_type| {
532 vec![
533 (
534 super::acos(),
535 unbounded_interval(data_type),
536 zero_to_pi_interval(data_type),
537 ),
538 (
539 super::acosh(),
540 unbounded_interval(data_type),
541 Interval::make_non_negative_infinity_interval(data_type).unwrap(),
542 ),
543 (
544 super::asin(),
545 unbounded_interval(data_type),
546 Interval::make_symmetric_half_pi_interval(data_type).unwrap(),
547 ),
548 (
549 super::atan(),
550 unbounded_interval(data_type),
551 Interval::make_symmetric_half_pi_interval(data_type).unwrap(),
552 ),
553 (
554 super::cos(),
555 unbounded_interval(data_type),
556 Interval::make_symmetric_unit_interval(data_type).unwrap(),
557 ),
558 (
559 super::cosh(),
560 unbounded_interval(data_type),
561 one_to_inf_interval(data_type),
562 ),
563 (
564 super::sin(),
565 unbounded_interval(data_type),
566 Interval::make_symmetric_unit_interval(data_type).unwrap(),
567 ),
568 (
569 super::exp(),
570 unbounded_interval(data_type),
571 Interval::make_non_negative_infinity_interval(data_type).unwrap(),
572 ),
573 (
574 super::sqrt(),
575 unbounded_interval(data_type),
576 Interval::make_non_negative_infinity_interval(data_type).unwrap(),
577 ),
578 (
579 super::radians(),
580 unbounded_interval(data_type),
581 Interval::make_symmetric_pi_interval(data_type).unwrap(),
582 ),
583 (
584 super::sqrt(),
585 unbounded_interval(data_type),
586 Interval::make_non_negative_infinity_interval(data_type).unwrap(),
587 ),
588 ]
589 })
590 .collect::<Vec<_>>();
591
592 for (udf, interval, expected) in cases {
593 assert_udf_evaluates_to_bounds(&udf, interval, expected);
594 }
595
596 Ok(())
597 }
598}