1use std::sync::LazyLock;
19
20use datafusion_common::{Result, ScalarValue, exec_err};
21use datafusion_doc::scalar_doc_sections::DOC_SECTION_MATH;
22use datafusion_expr::Documentation;
23use datafusion_expr::interval_arithmetic::Interval;
24use datafusion_expr::sort_properties::{ExprProperties, SortProperties};
25
26pub fn acos_order(input: &[ExprProperties]) -> Result<SortProperties> {
28 let arg = &input[0];
29 let range = &arg.range;
30
31 let valid_domain =
32 Interval::make_symmetric_unit_interval(&range.lower().data_type())?;
33
34 if valid_domain.contains(range)? == Interval::TRUE {
35 Ok(-arg.sort_properties)
36 } else {
37 exec_err!("Input range of ACOS contains out-of-domain values")
38 }
39}
40
41static DOCUMENTATION_ACOS: LazyLock<Documentation> = LazyLock::new(|| {
42 Documentation::builder(
43 DOC_SECTION_MATH,
44 "Returns the arc cosine or inverse cosine of a number.",
45 "acos(numeric_expression)",
46 )
47 .with_standard_argument("numeric_expression", Some("Numeric"))
48 .with_sql_example(
49 r#"```sql
50> SELECT acos(1);
51+----------+
52| acos(1) |
53+----------+
54| 0.0 |
55+----------+
56```"#,
57 )
58 .build()
59});
60
61pub fn get_acos_doc() -> &'static Documentation {
62 &DOCUMENTATION_ACOS
63}
64
65pub fn acosh_order(input: &[ExprProperties]) -> Result<SortProperties> {
67 let arg = &input[0];
68 let range = &arg.range;
69
70 let valid_domain = Interval::try_new(
71 ScalarValue::new_one(&range.lower().data_type())?,
72 ScalarValue::try_from(&range.upper().data_type())?,
73 )?;
74
75 if valid_domain.contains(range)? == Interval::TRUE {
76 Ok(arg.sort_properties)
77 } else {
78 exec_err!("Input range of ACOSH contains out-of-domain values")
79 }
80}
81
82static DOCUMENTATION_ACOSH: LazyLock<Documentation> =
83 LazyLock::new(|| {
84 Documentation::builder(
85 DOC_SECTION_MATH,
86 "Returns the area hyperbolic cosine or inverse hyperbolic cosine of a number.",
87 "acosh(numeric_expression)",
88 )
89 .with_standard_argument("numeric_expression", Some("Numeric"))
90 .with_sql_example(r#"```sql
91> SELECT acosh(2);
92+------------+
93| acosh(2) |
94+------------+
95| 1.31696 |
96+------------+
97```"#)
98 .build()
99 });
100
101pub fn get_acosh_doc() -> &'static Documentation {
102 &DOCUMENTATION_ACOSH
103}
104
105pub fn asin_order(input: &[ExprProperties]) -> Result<SortProperties> {
107 let arg = &input[0];
108 let range = &arg.range;
109
110 let valid_domain =
111 Interval::make_symmetric_unit_interval(&range.lower().data_type())?;
112
113 if valid_domain.contains(range)? == Interval::TRUE {
114 Ok(arg.sort_properties)
115 } else {
116 exec_err!("Input range of ASIN contains out-of-domain values")
117 }
118}
119
120static DOCUMENTATION_ASIN: LazyLock<Documentation> = LazyLock::new(|| {
121 Documentation::builder(
122 DOC_SECTION_MATH,
123 "Returns the arc sine or inverse sine of a number.",
124 "asin(numeric_expression)",
125 )
126 .with_standard_argument("numeric_expression", Some("Numeric"))
127 .with_sql_example(
128 r#"```sql
129> SELECT asin(0.5);
130+------------+
131| asin(0.5) |
132+------------+
133| 0.5235988 |
134+------------+
135```"#,
136 )
137 .build()
138});
139
140pub fn get_asin_doc() -> &'static Documentation {
141 &DOCUMENTATION_ASIN
142}
143
144pub fn asinh_order(input: &[ExprProperties]) -> Result<SortProperties> {
146 Ok(input[0].sort_properties)
147}
148
149static DOCUMENTATION_ASINH: LazyLock<Documentation> = LazyLock::new(|| {
150 Documentation::builder(
151 DOC_SECTION_MATH,
152 "Returns the area hyperbolic sine or inverse hyperbolic sine of a number.",
153 "asinh(numeric_expression)",
154 )
155 .with_standard_argument("numeric_expression", Some("Numeric"))
156 .with_sql_example(
157 r#" ```sql
158> SELECT asinh(1);
159+------------+
160| asinh(1) |
161+------------+
162| 0.8813736 |
163+------------+
164```"#,
165 )
166 .build()
167});
168
169pub fn get_asinh_doc() -> &'static Documentation {
170 &DOCUMENTATION_ASINH
171}
172
173pub fn atan_order(input: &[ExprProperties]) -> Result<SortProperties> {
175 Ok(input[0].sort_properties)
176}
177
178static DOCUMENTATION_ATAN: LazyLock<Documentation> = LazyLock::new(|| {
179 Documentation::builder(
180 DOC_SECTION_MATH,
181 "Returns the arc tangent or inverse tangent of a number.",
182 "atan(numeric_expression)",
183 )
184 .with_standard_argument("numeric_expression", Some("Numeric"))
185 .with_sql_example(
186 r#"```sql
187 > SELECT atan(1);
188+-----------+
189| atan(1) |
190+-----------+
191| 0.7853982 |
192+-----------+
193```"#,
194 )
195 .build()
196});
197
198pub fn get_atan_doc() -> &'static Documentation {
199 &DOCUMENTATION_ATAN
200}
201
202pub fn atanh_order(input: &[ExprProperties]) -> Result<SortProperties> {
204 let arg = &input[0];
205 let range = &arg.range;
206
207 let valid_domain =
208 Interval::make_symmetric_unit_interval(&range.lower().data_type())?;
209
210 if valid_domain.contains(range)? == Interval::TRUE {
211 Ok(arg.sort_properties)
212 } else {
213 exec_err!("Input range of ATANH contains out-of-domain values")
214 }
215}
216
217static DOCUMENTATION_ATANH: LazyLock<Documentation> =
218 LazyLock::new(|| {
219 Documentation::builder(
220 DOC_SECTION_MATH,
221 "Returns the area hyperbolic tangent or inverse hyperbolic tangent of a number.",
222 "atanh(numeric_expression)",
223 )
224 .with_standard_argument("numeric_expression", Some("Numeric"))
225 .with_sql_example(r#"```sql
226 > SELECT atanh(0.5);
227+-------------+
228| atanh(0.5) |
229+-------------+
230| 0.5493061 |
231+-------------+
232```"#)
233 .build()
234 });
235
236pub fn get_atanh_doc() -> &'static Documentation {
237 &DOCUMENTATION_ATANH
238}
239
240pub fn atan2_order(_input: &[ExprProperties]) -> Result<SortProperties> {
243 Ok(SortProperties::Unordered)
244}
245
246static DOCUMENTATION_ATANH2: LazyLock<Documentation> =
247 LazyLock::new(|| {
248 Documentation::builder(
249 DOC_SECTION_MATH,
250 "Returns the arc tangent or inverse tangent of `expression_y / expression_x`.",
251 "atan2(expression_y, expression_x)",
252 )
253 .with_argument(
254 "expression_y",
255 r#"First numeric expression to operate on.
256Can be a constant, column, or function, and any combination of arithmetic operators."#,
257 )
258 .with_argument(
259 "expression_x",
260 r#"Second numeric expression to operate on.
261Can be a constant, column, or function, and any combination of arithmetic operators."#,
262 )
263 .with_sql_example(r#"```sql
264> SELECT atan2(1, 1);
265+------------+
266| atan2(1,1) |
267+------------+
268| 0.7853982 |
269+------------+
270```"#)
271 .build()
272 });
273
274pub fn get_atan2_doc() -> &'static Documentation {
275 &DOCUMENTATION_ATANH2
276}
277
278pub fn cbrt_order(input: &[ExprProperties]) -> Result<SortProperties> {
280 Ok(input[0].sort_properties)
281}
282
283static DOCUMENTATION_CBRT: LazyLock<Documentation> = LazyLock::new(|| {
284 Documentation::builder(
285 DOC_SECTION_MATH,
286 "Returns the cube root of a number.",
287 "cbrt(numeric_expression)",
288 )
289 .with_standard_argument("numeric_expression", Some("Numeric"))
290 .with_sql_example(
291 r#"```sql
292> SELECT cbrt(27);
293+-----------+
294| cbrt(27) |
295+-----------+
296| 3.0 |
297+-----------+
298```"#,
299 )
300 .build()
301});
302
303pub fn get_cbrt_doc() -> &'static Documentation {
304 &DOCUMENTATION_CBRT
305}
306
307pub fn ceil_order(input: &[ExprProperties]) -> Result<SortProperties> {
309 Ok(input[0].sort_properties)
310}
311
312pub fn cos_order(_input: &[ExprProperties]) -> Result<SortProperties> {
316 Ok(SortProperties::Unordered)
317}
318
319static DOCUMENTATION_COS: LazyLock<Documentation> = LazyLock::new(|| {
320 Documentation::builder(
321 DOC_SECTION_MATH,
322 "Returns the cosine of a number.",
323 "cos(numeric_expression)",
324 )
325 .with_standard_argument("numeric_expression", Some("Numeric"))
326 .with_sql_example(
327 r#"```sql
328> SELECT cos(0);
329+--------+
330| cos(0) |
331+--------+
332| 1.0 |
333+--------+
334```"#,
335 )
336 .build()
337});
338
339pub fn get_cos_doc() -> &'static Documentation {
340 &DOCUMENTATION_COS
341}
342
343pub fn cosh_order(input: &[ExprProperties]) -> Result<SortProperties> {
345 let arg = &input[0];
346 let range = &arg.range;
347
348 let zero_point = Interval::make_zero(&range.lower().data_type())?;
349
350 if range.gt_eq(&zero_point)? == Interval::TRUE {
351 Ok(arg.sort_properties)
352 } else if range.lt_eq(&zero_point)? == Interval::TRUE {
353 Ok(-arg.sort_properties)
354 } else {
355 Ok(SortProperties::Unordered)
356 }
357}
358
359static DOCUMENTATION_COSH: LazyLock<Documentation> = LazyLock::new(|| {
360 Documentation::builder(
361 DOC_SECTION_MATH,
362 "Returns the hyperbolic cosine of a number.",
363 "cosh(numeric_expression)",
364 )
365 .with_standard_argument("numeric_expression", Some("Numeric"))
366 .with_sql_example(
367 r#"```sql
368> SELECT cosh(1);
369+-----------+
370| cosh(1) |
371+-----------+
372| 1.5430806 |
373+-----------+
374```"#,
375 )
376 .build()
377});
378
379pub fn get_cosh_doc() -> &'static Documentation {
380 &DOCUMENTATION_COSH
381}
382
383pub fn degrees_order(input: &[ExprProperties]) -> Result<SortProperties> {
385 Ok(input[0].sort_properties)
386}
387
388static DOCUMENTATION_DEGREES: LazyLock<Documentation> = LazyLock::new(|| {
389 Documentation::builder(
390 DOC_SECTION_MATH,
391 "Converts radians to degrees.",
392 "degrees(numeric_expression)",
393 )
394 .with_standard_argument("numeric_expression", Some("Numeric"))
395 .with_sql_example(
396 r#"```sql
397 > SELECT degrees(pi());
398+------------+
399| degrees(0) |
400+------------+
401| 180.0 |
402+------------+
403```"#,
404 )
405 .build()
406});
407
408pub fn get_degrees_doc() -> &'static Documentation {
409 &DOCUMENTATION_DEGREES
410}
411
412pub fn exp_order(input: &[ExprProperties]) -> Result<SortProperties> {
414 Ok(input[0].sort_properties)
415}
416
417static DOCUMENTATION_EXP: LazyLock<Documentation> = LazyLock::new(|| {
418 Documentation::builder(
419 DOC_SECTION_MATH,
420 "Returns the base-e exponential of a number.",
421 "exp(numeric_expression)",
422 )
423 .with_standard_argument("numeric_expression", Some("Numeric"))
424 .with_sql_example(
425 r#"```sql
426> SELECT exp(1);
427+---------+
428| exp(1) |
429+---------+
430| 2.71828 |
431+---------+
432```"#,
433 )
434 .build()
435});
436
437pub fn get_exp_doc() -> &'static Documentation {
438 &DOCUMENTATION_EXP
439}
440
441pub fn floor_order(input: &[ExprProperties]) -> Result<SortProperties> {
443 Ok(input[0].sort_properties)
444}
445
446pub fn ln_order(input: &[ExprProperties]) -> Result<SortProperties> {
448 let arg = &input[0];
449 let range = &arg.range;
450
451 let zero_point = Interval::make_zero(&range.lower().data_type())?;
452
453 if range.gt_eq(&zero_point)? == Interval::TRUE {
454 Ok(arg.sort_properties)
455 } else {
456 exec_err!("Input range of LN contains out-of-domain values")
457 }
458}
459
460static DOCUMENTATION_LN: LazyLock<Documentation> = LazyLock::new(|| {
461 Documentation::builder(
462 DOC_SECTION_MATH,
463 "Returns the natural logarithm of a number.",
464 "ln(numeric_expression)",
465 )
466 .with_standard_argument("numeric_expression", Some("Numeric"))
467 .with_sql_example(
468 r#"```sql
469> SELECT ln(2.71828);
470+-------------+
471| ln(2.71828) |
472+-------------+
473| 1.0 |
474+-------------+
475```"#,
476 )
477 .build()
478});
479
480pub fn get_ln_doc() -> &'static Documentation {
481 &DOCUMENTATION_LN
482}
483
484pub fn log2_order(input: &[ExprProperties]) -> Result<SortProperties> {
486 let arg = &input[0];
487 let range = &arg.range;
488
489 let zero_point = Interval::make_zero(&range.lower().data_type())?;
490
491 if range.gt_eq(&zero_point)? == Interval::TRUE {
492 Ok(arg.sort_properties)
493 } else {
494 exec_err!("Input range of LOG2 contains out-of-domain values")
495 }
496}
497
498static DOCUMENTATION_LOG2: LazyLock<Documentation> = LazyLock::new(|| {
499 Documentation::builder(
500 DOC_SECTION_MATH,
501 "Returns the base-2 logarithm of a number.",
502 "log2(numeric_expression)",
503 )
504 .with_standard_argument("numeric_expression", Some("Numeric"))
505 .with_sql_example(
506 r#"```sql
507> SELECT log2(8);
508+-----------+
509| log2(8) |
510+-----------+
511| 3.0 |
512+-----------+
513```"#,
514 )
515 .build()
516});
517
518pub fn get_log2_doc() -> &'static Documentation {
519 &DOCUMENTATION_LOG2
520}
521
522pub fn log10_order(input: &[ExprProperties]) -> Result<SortProperties> {
524 let arg = &input[0];
525 let range = &arg.range;
526
527 let zero_point = Interval::make_zero(&range.lower().data_type())?;
528
529 if range.gt_eq(&zero_point)? == Interval::TRUE {
530 Ok(arg.sort_properties)
531 } else {
532 exec_err!("Input range of LOG10 contains out-of-domain values")
533 }
534}
535
536static DOCUMENTATION_LOG10: LazyLock<Documentation> = LazyLock::new(|| {
537 Documentation::builder(
538 DOC_SECTION_MATH,
539 "Returns the base-10 logarithm of a number.",
540 "log10(numeric_expression)",
541 )
542 .with_standard_argument("numeric_expression", Some("Numeric"))
543 .with_sql_example(
544 r#"```sql
545> SELECT log10(100);
546+-------------+
547| log10(100) |
548+-------------+
549| 2.0 |
550+-------------+
551```"#,
552 )
553 .build()
554});
555
556pub fn get_log10_doc() -> &'static Documentation {
557 &DOCUMENTATION_LOG10
558}
559
560pub fn radians_order(input: &[ExprProperties]) -> Result<SortProperties> {
562 Ok(input[0].sort_properties)
563}
564
565static DOCUMENTATION_RADIANS: LazyLock<Documentation> = LazyLock::new(|| {
566 Documentation::builder(
567 DOC_SECTION_MATH,
568 "Converts degrees to radians.",
569 "radians(numeric_expression)",
570 )
571 .with_standard_argument("numeric_expression", Some("Numeric"))
572 .with_sql_example(
573 r#"```sql
574> SELECT radians(180);
575+----------------+
576| radians(180) |
577+----------------+
578| 3.14159265359 |
579+----------------+
580```"#,
581 )
582 .build()
583});
584
585pub fn get_radians_doc() -> &'static Documentation {
586 &DOCUMENTATION_RADIANS
587}
588
589pub fn sin_order(_input: &[ExprProperties]) -> Result<SortProperties> {
593 Ok(SortProperties::Unordered)
594}
595
596static DOCUMENTATION_SIN: LazyLock<Documentation> = LazyLock::new(|| {
597 Documentation::builder(
598 DOC_SECTION_MATH,
599 "Returns the sine of a number.",
600 "sin(numeric_expression)",
601 )
602 .with_standard_argument("numeric_expression", Some("Numeric"))
603 .with_sql_example(
604 r#"```sql
605> SELECT sin(0);
606+----------+
607| sin(0) |
608+----------+
609| 0.0 |
610+----------+
611```"#,
612 )
613 .build()
614});
615
616pub fn get_sin_doc() -> &'static Documentation {
617 &DOCUMENTATION_SIN
618}
619
620pub fn sinh_order(input: &[ExprProperties]) -> Result<SortProperties> {
622 Ok(input[0].sort_properties)
623}
624
625static DOCUMENTATION_SINH: LazyLock<Documentation> = LazyLock::new(|| {
626 Documentation::builder(
627 DOC_SECTION_MATH,
628 "Returns the hyperbolic sine of a number.",
629 "sinh(numeric_expression)",
630 )
631 .with_standard_argument("numeric_expression", Some("Numeric"))
632 .with_sql_example(
633 r#"```sql
634> SELECT sinh(1);
635+-----------+
636| sinh(1) |
637+-----------+
638| 1.1752012 |
639+-----------+
640```"#,
641 )
642 .build()
643});
644
645pub fn get_sinh_doc() -> &'static Documentation {
646 &DOCUMENTATION_SINH
647}
648
649pub fn sqrt_order(input: &[ExprProperties]) -> Result<SortProperties> {
651 let arg = &input[0];
652 let range = &arg.range;
653
654 let zero_point = Interval::make_zero(&range.lower().data_type())?;
655
656 if range.gt_eq(&zero_point)? == Interval::TRUE {
657 Ok(arg.sort_properties)
658 } else {
659 exec_err!("Input range of SQRT contains out-of-domain values")
660 }
661}
662
663static DOCUMENTATION_SQRT: LazyLock<Documentation> = LazyLock::new(|| {
664 Documentation::builder(
665 DOC_SECTION_MATH,
666 "Returns the square root of a number.",
667 "sqrt(numeric_expression)",
668 )
669 .with_standard_argument("numeric_expression", Some("Numeric"))
670 .build()
671});
672
673pub fn get_sqrt_doc() -> &'static Documentation {
674 &DOCUMENTATION_SQRT
675}
676
677pub fn tan_order(_input: &[ExprProperties]) -> Result<SortProperties> {
681 Ok(SortProperties::Unordered)
682}
683
684static DOCUMENTATION_TAN: LazyLock<Documentation> = LazyLock::new(|| {
685 Documentation::builder(
686 DOC_SECTION_MATH,
687 "Returns the tangent of a number.",
688 "tan(numeric_expression)",
689 )
690 .with_standard_argument("numeric_expression", Some("Numeric"))
691 .with_sql_example(
692 r#"```sql
693> SELECT tan(pi()/4);
694+--------------+
695| tan(PI()/4) |
696+--------------+
697| 1.0 |
698+--------------+
699```"#,
700 )
701 .build()
702});
703
704pub fn get_tan_doc() -> &'static Documentation {
705 &DOCUMENTATION_TAN
706}
707
708pub fn tanh_order(input: &[ExprProperties]) -> Result<SortProperties> {
710 Ok(input[0].sort_properties)
711}
712
713static DOCUMENTATION_TANH: LazyLock<Documentation> = LazyLock::new(|| {
714 Documentation::builder(
715 DOC_SECTION_MATH,
716 "Returns the hyperbolic tangent of a number.",
717 "tanh(numeric_expression)",
718 )
719 .with_standard_argument("numeric_expression", Some("Numeric"))
720 .with_sql_example(
721 r#"```sql
722 > SELECT tanh(20);
723 +----------+
724 | tanh(20) |
725 +----------+
726 | 1.0 |
727 +----------+
728 ```"#,
729 )
730 .build()
731});
732
733pub fn get_tanh_doc() -> &'static Documentation {
734 &DOCUMENTATION_TANH
735}
736
737#[cfg(test)]
738mod tests {
739 use arrow::compute::SortOptions;
740 use datafusion_common::Result;
741
742 use super::*;
743
744 #[derive(Debug)]
745 struct MonotonicityTestCase {
746 name: &'static str,
747 func: fn(&[ExprProperties]) -> Result<SortProperties>,
748 lower: f64,
749 upper: f64,
750 input_sort: SortProperties,
751 expected: Result<SortProperties>,
752 }
753
754 #[test]
755 fn test_monotonicity_table() {
756 fn create_ep(lower: f64, upper: f64, sp: SortProperties) -> ExprProperties {
757 ExprProperties {
758 range: Interval::try_new(
759 ScalarValue::from(lower),
760 ScalarValue::from(upper),
761 )
762 .unwrap(),
763 sort_properties: sp,
764 preserves_lex_ordering: false,
765 }
766 }
767
768 let test_cases = vec![
769 MonotonicityTestCase {
770 name: "acos_order within domain",
771 func: acos_order,
772 lower: -0.5,
773 upper: 0.5,
774 input_sort: SortProperties::Ordered(SortOptions {
775 descending: false,
776 nulls_first: false,
777 }),
778 expected: Ok(SortProperties::Ordered(SortOptions {
779 descending: true,
780 nulls_first: false,
781 })),
782 },
783 MonotonicityTestCase {
784 name: "acos_order out of domain",
785 func: acos_order,
786 lower: -2.0,
787 upper: 1.0,
788 input_sort: SortProperties::Ordered(SortOptions {
789 descending: false,
790 nulls_first: false,
791 }),
792 expected: exec_err!("Input range of ACOS contains out-of-domain values"),
793 },
794 MonotonicityTestCase {
795 name: "acosh_order within domain",
796 func: acosh_order,
797 lower: 2.0,
798 upper: 100.0,
799 input_sort: SortProperties::Ordered(SortOptions {
800 descending: false,
801 nulls_first: true,
802 }),
803 expected: Ok(SortProperties::Ordered(SortOptions {
804 descending: false,
805 nulls_first: true,
806 })),
807 },
808 MonotonicityTestCase {
809 name: "acosh_order out of domain",
810 func: acosh_order,
811 lower: 0.5,
812 upper: 1.0,
813 input_sort: SortProperties::Ordered(SortOptions {
814 descending: true,
815 nulls_first: false,
816 }),
817 expected: exec_err!("Input range of ACOSH contains out-of-domain values"),
818 },
819 MonotonicityTestCase {
820 name: "asin_order within domain",
821 func: asin_order,
822 lower: -0.5,
823 upper: 0.5,
824 input_sort: SortProperties::Ordered(SortOptions {
825 descending: false,
826 nulls_first: false,
827 }),
828 expected: Ok(SortProperties::Ordered(SortOptions {
829 descending: false,
830 nulls_first: false,
831 })),
832 },
833 MonotonicityTestCase {
834 name: "asin_order out of domain",
835 func: asin_order,
836 lower: -2.0,
837 upper: 1.0,
838 input_sort: SortProperties::Ordered(SortOptions {
839 descending: false,
840 nulls_first: false,
841 }),
842 expected: exec_err!("Input range of ASIN contains out-of-domain values"),
843 },
844 MonotonicityTestCase {
845 name: "asinh_order within domain",
846 func: asinh_order,
847 lower: -1.0,
848 upper: 1.0,
849 input_sort: SortProperties::Ordered(SortOptions {
850 descending: false,
851 nulls_first: false,
852 }),
853 expected: Ok(SortProperties::Ordered(SortOptions {
854 descending: false,
855 nulls_first: false,
856 })),
857 },
858 MonotonicityTestCase {
859 name: "asinh_order out of domain",
860 func: asinh_order,
861 lower: -2.0,
862 upper: 1.0,
863 input_sort: SortProperties::Ordered(SortOptions {
864 descending: false,
865 nulls_first: false,
866 }),
867 expected: Ok(SortProperties::Ordered(SortOptions {
868 descending: false,
869 nulls_first: false,
870 })),
871 },
872 MonotonicityTestCase {
873 name: "atan_order within domain",
874 func: atan_order,
875 lower: -1.0,
876 upper: 1.0,
877 input_sort: SortProperties::Ordered(SortOptions {
878 descending: false,
879 nulls_first: false,
880 }),
881 expected: Ok(SortProperties::Ordered(SortOptions {
882 descending: false,
883 nulls_first: false,
884 })),
885 },
886 MonotonicityTestCase {
887 name: "atan_order out of domain",
888 func: atan_order,
889 lower: -2.0,
890 upper: 1.0,
891 input_sort: SortProperties::Ordered(SortOptions {
892 descending: false,
893 nulls_first: false,
894 }),
895 expected: Ok(SortProperties::Ordered(SortOptions {
896 descending: false,
897 nulls_first: false,
898 })),
899 },
900 MonotonicityTestCase {
901 name: "atanh_order within domain",
902 func: atanh_order,
903 lower: -0.6,
904 upper: 0.6,
905 input_sort: SortProperties::Ordered(SortOptions {
906 descending: false,
907 nulls_first: false,
908 }),
909 expected: Ok(SortProperties::Ordered(SortOptions {
910 descending: false,
911 nulls_first: false,
912 })),
913 },
914 MonotonicityTestCase {
915 name: "atanh_order out of domain",
916 func: atanh_order,
917 lower: -2.0,
918 upper: 1.0,
919 input_sort: SortProperties::Ordered(SortOptions {
920 descending: false,
921 nulls_first: false,
922 }),
923 expected: exec_err!("Input range of ATANH contains out-of-domain values"),
924 },
925 MonotonicityTestCase {
926 name: "cbrt_order within domain",
927 func: cbrt_order,
928 lower: -1.0,
929 upper: 1.0,
930 input_sort: SortProperties::Ordered(SortOptions {
931 descending: false,
932 nulls_first: false,
933 }),
934 expected: Ok(SortProperties::Ordered(SortOptions {
935 descending: false,
936 nulls_first: false,
937 })),
938 },
939 MonotonicityTestCase {
940 name: "cbrt_order out of domain",
941 func: cbrt_order,
942 lower: -2.0,
943 upper: 1.0,
944 input_sort: SortProperties::Ordered(SortOptions {
945 descending: false,
946 nulls_first: false,
947 }),
948 expected: Ok(SortProperties::Ordered(SortOptions {
949 descending: false,
950 nulls_first: false,
951 })),
952 },
953 MonotonicityTestCase {
954 name: "ceil_order within domain",
955 func: ceil_order,
956 lower: -1.0,
957 upper: 1.0,
958 input_sort: SortProperties::Ordered(SortOptions {
959 descending: false,
960 nulls_first: false,
961 }),
962 expected: Ok(SortProperties::Ordered(SortOptions {
963 descending: false,
964 nulls_first: false,
965 })),
966 },
967 MonotonicityTestCase {
968 name: "ceil_order out of domain",
969 func: ceil_order,
970 lower: -2.0,
971 upper: 1.0,
972 input_sort: SortProperties::Ordered(SortOptions {
973 descending: false,
974 nulls_first: false,
975 }),
976 expected: Ok(SortProperties::Ordered(SortOptions {
977 descending: false,
978 nulls_first: false,
979 })),
980 },
981 MonotonicityTestCase {
982 name: "cos_order within domain",
983 func: cos_order,
984 lower: 0.0,
985 upper: 2.0 * std::f64::consts::PI,
986 input_sort: SortProperties::Ordered(SortOptions {
987 descending: false,
988 nulls_first: false,
989 }),
990 expected: Ok(SortProperties::Unordered),
991 },
992 MonotonicityTestCase {
993 name: "cos_order out of domain",
994 func: cos_order,
995 lower: -2.0,
996 upper: 1.0,
997 input_sort: SortProperties::Ordered(SortOptions {
998 descending: false,
999 nulls_first: false,
1000 }),
1001 expected: Ok(SortProperties::Unordered),
1002 },
1003 MonotonicityTestCase {
1004 name: "cosh_order within domain positive",
1005 func: cosh_order,
1006 lower: 5.0,
1007 upper: 100.0,
1008 input_sort: SortProperties::Ordered(SortOptions {
1009 descending: false,
1010 nulls_first: false,
1011 }),
1012 expected: Ok(SortProperties::Ordered(SortOptions {
1013 descending: false,
1014 nulls_first: false,
1015 })),
1016 },
1017 MonotonicityTestCase {
1018 name: "cosh_order within domain negative",
1019 func: cosh_order,
1020 lower: -100.0,
1021 upper: -5.0,
1022 input_sort: SortProperties::Ordered(SortOptions {
1023 descending: false,
1024 nulls_first: false,
1025 }),
1026 expected: Ok(SortProperties::Ordered(SortOptions {
1027 descending: true,
1028 nulls_first: false,
1029 })),
1030 },
1031 MonotonicityTestCase {
1032 name: "cosh_order out of domain so unordered",
1033 func: cosh_order,
1034 lower: -1.0,
1035 upper: 1.0,
1036 input_sort: SortProperties::Ordered(SortOptions {
1037 descending: false,
1038 nulls_first: false,
1039 }),
1040 expected: Ok(SortProperties::Unordered),
1041 },
1042 MonotonicityTestCase {
1043 name: "degrees_order",
1044 func: degrees_order,
1045 lower: -1.0,
1046 upper: 1.0,
1047 input_sort: SortProperties::Ordered(SortOptions {
1048 descending: true,
1049 nulls_first: true,
1050 }),
1051 expected: Ok(SortProperties::Ordered(SortOptions {
1052 descending: true,
1053 nulls_first: true,
1054 })),
1055 },
1056 MonotonicityTestCase {
1057 name: "exp_order",
1058 func: exp_order,
1059 lower: -1000.0,
1060 upper: 1000.0,
1061 input_sort: SortProperties::Ordered(SortOptions {
1062 descending: false,
1063 nulls_first: false,
1064 }),
1065 expected: Ok(SortProperties::Ordered(SortOptions {
1066 descending: false,
1067 nulls_first: false,
1068 })),
1069 },
1070 MonotonicityTestCase {
1071 name: "floor_order",
1072 func: floor_order,
1073 lower: -1.0,
1074 upper: 1.0,
1075 input_sort: SortProperties::Ordered(SortOptions {
1076 descending: true,
1077 nulls_first: true,
1078 }),
1079 expected: Ok(SortProperties::Ordered(SortOptions {
1080 descending: true,
1081 nulls_first: true,
1082 })),
1083 },
1084 MonotonicityTestCase {
1085 name: "ln_order within domain",
1086 func: ln_order,
1087 lower: 1.0,
1088 upper: 2.0,
1089 input_sort: SortProperties::Ordered(SortOptions {
1090 descending: false,
1091 nulls_first: false,
1092 }),
1093 expected: Ok(SortProperties::Ordered(SortOptions {
1094 descending: false,
1095 nulls_first: false,
1096 })),
1097 },
1098 MonotonicityTestCase {
1099 name: "ln_order out of domain",
1100 func: ln_order,
1101 lower: -5.0,
1102 upper: -4.0,
1103 input_sort: SortProperties::Ordered(SortOptions {
1104 descending: false,
1105 nulls_first: false,
1106 }),
1107 expected: exec_err!("Input range of LN contains out-of-domain values"),
1108 },
1109 ];
1110
1111 for tcase in test_cases {
1112 let input = vec![create_ep(tcase.lower, tcase.upper, tcase.input_sort)];
1113 let actual = (tcase.func)(&input);
1114 match (&actual, &tcase.expected) {
1115 (Ok(a), Ok(e)) => assert_eq!(
1116 a, e,
1117 "Test '{}' failed: got {:?}, expected {:?}",
1118 tcase.name, a, e
1119 ),
1120 (Err(e1), Err(e2)) => {
1121 assert_eq!(
1122 e1.strip_backtrace().to_string(),
1123 e2.strip_backtrace().to_string(),
1124 "Test '{}' failed: got {:?}, expected {:?}",
1125 tcase.name,
1126 e1,
1127 e2
1128 )
1129 } _ => panic!(
1131 "Test '{}' failed: got {:?}, expected {:?}",
1132 tcase.name, actual, tcase.expected
1133 ),
1134 }
1135 }
1136 }
1137}