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
741 use super::*;
742
743 #[derive(Debug)]
744 struct MonotonicityTestCase {
745 name: &'static str,
746 func: fn(&[ExprProperties]) -> Result<SortProperties>,
747 lower: f64,
748 upper: f64,
749 input_sort: SortProperties,
750 expected: Result<SortProperties>,
751 }
752
753 #[test]
754 fn test_monotonicity_table() {
755 fn create_ep(lower: f64, upper: f64, sp: SortProperties) -> ExprProperties {
756 ExprProperties {
757 range: Interval::try_new(
758 ScalarValue::from(lower),
759 ScalarValue::from(upper),
760 )
761 .unwrap(),
762 sort_properties: sp,
763 preserves_lex_ordering: false,
764 }
765 }
766
767 let test_cases = vec![
768 MonotonicityTestCase {
769 name: "acos_order within domain",
770 func: acos_order,
771 lower: -0.5,
772 upper: 0.5,
773 input_sort: SortProperties::Ordered(SortOptions {
774 descending: false,
775 nulls_first: false,
776 }),
777 expected: Ok(SortProperties::Ordered(SortOptions {
778 descending: true,
779 nulls_first: false,
780 })),
781 },
782 MonotonicityTestCase {
783 name: "acos_order out of domain",
784 func: acos_order,
785 lower: -2.0,
786 upper: 1.0,
787 input_sort: SortProperties::Ordered(SortOptions {
788 descending: false,
789 nulls_first: false,
790 }),
791 expected: exec_err!("Input range of ACOS contains out-of-domain values"),
792 },
793 MonotonicityTestCase {
794 name: "acosh_order within domain",
795 func: acosh_order,
796 lower: 2.0,
797 upper: 100.0,
798 input_sort: SortProperties::Ordered(SortOptions {
799 descending: false,
800 nulls_first: true,
801 }),
802 expected: Ok(SortProperties::Ordered(SortOptions {
803 descending: false,
804 nulls_first: true,
805 })),
806 },
807 MonotonicityTestCase {
808 name: "acosh_order out of domain",
809 func: acosh_order,
810 lower: 0.5,
811 upper: 1.0,
812 input_sort: SortProperties::Ordered(SortOptions {
813 descending: true,
814 nulls_first: false,
815 }),
816 expected: exec_err!("Input range of ACOSH contains out-of-domain values"),
817 },
818 MonotonicityTestCase {
819 name: "asin_order within domain",
820 func: asin_order,
821 lower: -0.5,
822 upper: 0.5,
823 input_sort: SortProperties::Ordered(SortOptions {
824 descending: false,
825 nulls_first: false,
826 }),
827 expected: Ok(SortProperties::Ordered(SortOptions {
828 descending: false,
829 nulls_first: false,
830 })),
831 },
832 MonotonicityTestCase {
833 name: "asin_order out of domain",
834 func: asin_order,
835 lower: -2.0,
836 upper: 1.0,
837 input_sort: SortProperties::Ordered(SortOptions {
838 descending: false,
839 nulls_first: false,
840 }),
841 expected: exec_err!("Input range of ASIN contains out-of-domain values"),
842 },
843 MonotonicityTestCase {
844 name: "asinh_order within domain",
845 func: asinh_order,
846 lower: -1.0,
847 upper: 1.0,
848 input_sort: SortProperties::Ordered(SortOptions {
849 descending: false,
850 nulls_first: false,
851 }),
852 expected: Ok(SortProperties::Ordered(SortOptions {
853 descending: false,
854 nulls_first: false,
855 })),
856 },
857 MonotonicityTestCase {
858 name: "asinh_order out of domain",
859 func: asinh_order,
860 lower: -2.0,
861 upper: 1.0,
862 input_sort: SortProperties::Ordered(SortOptions {
863 descending: false,
864 nulls_first: false,
865 }),
866 expected: Ok(SortProperties::Ordered(SortOptions {
867 descending: false,
868 nulls_first: false,
869 })),
870 },
871 MonotonicityTestCase {
872 name: "atan_order within domain",
873 func: atan_order,
874 lower: -1.0,
875 upper: 1.0,
876 input_sort: SortProperties::Ordered(SortOptions {
877 descending: false,
878 nulls_first: false,
879 }),
880 expected: Ok(SortProperties::Ordered(SortOptions {
881 descending: false,
882 nulls_first: false,
883 })),
884 },
885 MonotonicityTestCase {
886 name: "atan_order out of domain",
887 func: atan_order,
888 lower: -2.0,
889 upper: 1.0,
890 input_sort: SortProperties::Ordered(SortOptions {
891 descending: false,
892 nulls_first: false,
893 }),
894 expected: Ok(SortProperties::Ordered(SortOptions {
895 descending: false,
896 nulls_first: false,
897 })),
898 },
899 MonotonicityTestCase {
900 name: "atanh_order within domain",
901 func: atanh_order,
902 lower: -0.6,
903 upper: 0.6,
904 input_sort: SortProperties::Ordered(SortOptions {
905 descending: false,
906 nulls_first: false,
907 }),
908 expected: Ok(SortProperties::Ordered(SortOptions {
909 descending: false,
910 nulls_first: false,
911 })),
912 },
913 MonotonicityTestCase {
914 name: "atanh_order out of domain",
915 func: atanh_order,
916 lower: -2.0,
917 upper: 1.0,
918 input_sort: SortProperties::Ordered(SortOptions {
919 descending: false,
920 nulls_first: false,
921 }),
922 expected: exec_err!("Input range of ATANH contains out-of-domain values"),
923 },
924 MonotonicityTestCase {
925 name: "cbrt_order within domain",
926 func: cbrt_order,
927 lower: -1.0,
928 upper: 1.0,
929 input_sort: SortProperties::Ordered(SortOptions {
930 descending: false,
931 nulls_first: false,
932 }),
933 expected: Ok(SortProperties::Ordered(SortOptions {
934 descending: false,
935 nulls_first: false,
936 })),
937 },
938 MonotonicityTestCase {
939 name: "cbrt_order out of domain",
940 func: cbrt_order,
941 lower: -2.0,
942 upper: 1.0,
943 input_sort: SortProperties::Ordered(SortOptions {
944 descending: false,
945 nulls_first: false,
946 }),
947 expected: Ok(SortProperties::Ordered(SortOptions {
948 descending: false,
949 nulls_first: false,
950 })),
951 },
952 MonotonicityTestCase {
953 name: "ceil_order within domain",
954 func: ceil_order,
955 lower: -1.0,
956 upper: 1.0,
957 input_sort: SortProperties::Ordered(SortOptions {
958 descending: false,
959 nulls_first: false,
960 }),
961 expected: Ok(SortProperties::Ordered(SortOptions {
962 descending: false,
963 nulls_first: false,
964 })),
965 },
966 MonotonicityTestCase {
967 name: "ceil_order out of domain",
968 func: ceil_order,
969 lower: -2.0,
970 upper: 1.0,
971 input_sort: SortProperties::Ordered(SortOptions {
972 descending: false,
973 nulls_first: false,
974 }),
975 expected: Ok(SortProperties::Ordered(SortOptions {
976 descending: false,
977 nulls_first: false,
978 })),
979 },
980 MonotonicityTestCase {
981 name: "cos_order within domain",
982 func: cos_order,
983 lower: 0.0,
984 upper: 2.0 * std::f64::consts::PI,
985 input_sort: SortProperties::Ordered(SortOptions {
986 descending: false,
987 nulls_first: false,
988 }),
989 expected: Ok(SortProperties::Unordered),
990 },
991 MonotonicityTestCase {
992 name: "cos_order out of domain",
993 func: cos_order,
994 lower: -2.0,
995 upper: 1.0,
996 input_sort: SortProperties::Ordered(SortOptions {
997 descending: false,
998 nulls_first: false,
999 }),
1000 expected: Ok(SortProperties::Unordered),
1001 },
1002 MonotonicityTestCase {
1003 name: "cosh_order within domain positive",
1004 func: cosh_order,
1005 lower: 5.0,
1006 upper: 100.0,
1007 input_sort: SortProperties::Ordered(SortOptions {
1008 descending: false,
1009 nulls_first: false,
1010 }),
1011 expected: Ok(SortProperties::Ordered(SortOptions {
1012 descending: false,
1013 nulls_first: false,
1014 })),
1015 },
1016 MonotonicityTestCase {
1017 name: "cosh_order within domain negative",
1018 func: cosh_order,
1019 lower: -100.0,
1020 upper: -5.0,
1021 input_sort: SortProperties::Ordered(SortOptions {
1022 descending: false,
1023 nulls_first: false,
1024 }),
1025 expected: Ok(SortProperties::Ordered(SortOptions {
1026 descending: true,
1027 nulls_first: false,
1028 })),
1029 },
1030 MonotonicityTestCase {
1031 name: "cosh_order out of domain so unordered",
1032 func: cosh_order,
1033 lower: -1.0,
1034 upper: 1.0,
1035 input_sort: SortProperties::Ordered(SortOptions {
1036 descending: false,
1037 nulls_first: false,
1038 }),
1039 expected: Ok(SortProperties::Unordered),
1040 },
1041 MonotonicityTestCase {
1042 name: "degrees_order",
1043 func: degrees_order,
1044 lower: -1.0,
1045 upper: 1.0,
1046 input_sort: SortProperties::Ordered(SortOptions {
1047 descending: true,
1048 nulls_first: true,
1049 }),
1050 expected: Ok(SortProperties::Ordered(SortOptions {
1051 descending: true,
1052 nulls_first: true,
1053 })),
1054 },
1055 MonotonicityTestCase {
1056 name: "exp_order",
1057 func: exp_order,
1058 lower: -1000.0,
1059 upper: 1000.0,
1060 input_sort: SortProperties::Ordered(SortOptions {
1061 descending: false,
1062 nulls_first: false,
1063 }),
1064 expected: Ok(SortProperties::Ordered(SortOptions {
1065 descending: false,
1066 nulls_first: false,
1067 })),
1068 },
1069 MonotonicityTestCase {
1070 name: "floor_order",
1071 func: floor_order,
1072 lower: -1.0,
1073 upper: 1.0,
1074 input_sort: SortProperties::Ordered(SortOptions {
1075 descending: true,
1076 nulls_first: true,
1077 }),
1078 expected: Ok(SortProperties::Ordered(SortOptions {
1079 descending: true,
1080 nulls_first: true,
1081 })),
1082 },
1083 MonotonicityTestCase {
1084 name: "ln_order within domain",
1085 func: ln_order,
1086 lower: 1.0,
1087 upper: 2.0,
1088 input_sort: SortProperties::Ordered(SortOptions {
1089 descending: false,
1090 nulls_first: false,
1091 }),
1092 expected: Ok(SortProperties::Ordered(SortOptions {
1093 descending: false,
1094 nulls_first: false,
1095 })),
1096 },
1097 MonotonicityTestCase {
1098 name: "ln_order out of domain",
1099 func: ln_order,
1100 lower: -5.0,
1101 upper: -4.0,
1102 input_sort: SortProperties::Ordered(SortOptions {
1103 descending: false,
1104 nulls_first: false,
1105 }),
1106 expected: exec_err!("Input range of LN contains out-of-domain values"),
1107 },
1108 ];
1109
1110 for tcase in test_cases {
1111 let input = vec![create_ep(tcase.lower, tcase.upper, tcase.input_sort)];
1112 let actual = (tcase.func)(&input);
1113 match (&actual, &tcase.expected) {
1114 (Ok(a), Ok(e)) => assert_eq!(
1115 a, e,
1116 "Test '{}' failed: got {:?}, expected {:?}",
1117 tcase.name, a, e
1118 ),
1119 (Err(e1), Err(e2)) => {
1120 assert_eq!(
1121 e1.strip_backtrace().to_string(),
1122 e2.strip_backtrace().to_string(),
1123 "Test '{}' failed: got {:?}, expected {:?}",
1124 tcase.name,
1125 e1,
1126 e2
1127 )
1128 } _ => panic!(
1130 "Test '{}' failed: got {:?}, expected {:?}",
1131 tcase.name, actual, tcase.expected
1132 ),
1133 }
1134 }
1135 }
1136}