Skip to content

Commit f4581d5

Browse files
authored
Lets start on some missing Maths functions (#14433)
- Fix for issue with `text_mid` on Snowflake (when is an integer not an integer). - Adds `sin`, `cos`, `tan`, `asin`, `acos` and `atan` to `Numeric_Column` in both in memory and in database. - Adds `sinh`, `cosh` and `tanh` to `Numeric_Column` in both in memory and in database. - Adds `degrees` and `radians` to `Numeric_Column` in both in memory and in database. - Adds `sqrt`, `pow`, `ln`, `log10` and `log` to `Numeric_Column` in both in memory and in database. - Added new base class `NumericUnaryTypedOperation<T>` to help make in-memory unary numeric operations. - Refactors `SignumOperation` to have a base class of `NumericUnaryTypedOperation<Long>`. - New `DoubleUnaryOperation` to handle unary maths operations in memory.
1 parent 34d69ee commit f4581d5

File tree

17 files changed

+697
-128
lines changed

17 files changed

+697
-128
lines changed

CHANGELOG.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,16 +74,17 @@
7474
- [Add error_on_missing_columns to more methods.][14236]
7575
- [Add `OneDrive_File` to Microsoft 365 implementation.][14237]
7676
- [Progress of `Runtime.sleep` visualized.][14275]
77-
- [Add Email.send][14258]
77+
- [Add `Email.send`][14258]
7878
- [Full DuckDB Dialect.][14298]
79-
- [Initial Spatial support within DuckDB][14331]
80-
- [Add email SMTP support][14350]
79+
- [Initial Spatial support within DuckDB.][14331]
80+
- [Add email SMTP support.][14350]
8181
- [Read files into DuckDB both spatial and not.][14367]
8282
- [Implement Text_Column to_case for DB backends.][14386]
8383
- [Implement bulk loading to DuckDB.][14402]
8484
- [Implement `Text_Column.text_mid` for in-memory and database backends.][14420]
8585
- [Initial file writing from DuckDB.][14421]
8686
- [Parquet file reading and writing, DuckDB formats.][14427]
87+
- [Trigonometry and other maths function on Column.][14433]
8788

8889
[13769]: https://github.com/enso-org/enso/pull/13769
8990
[14026]: https://github.com/enso-org/enso/pull/14026
@@ -111,6 +112,7 @@
111112
[14420]: https://github.com/enso-org/enso/pull/14420
112113
[14421]: https://github.com/enso-org/enso/pull/14421
113114
[14427]: https://github.com/enso-org/enso/pull/14427
115+
[14433]: https://github.com/enso-org/enso/pull/14433
114116

115117
#### Enso Language & Runtime
116118

distribution/lib/Standard/Database/0.0.0-dev/src/Connection/Database.enso

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ from project.Errors import SQL_Error
1616
- sqlite: details=SQLite.From_File
1717
- sql_server: details=..SQLServer
1818
- snowflake: details=..Snowflake
19+
- duckdb: details=DuckDB.From_File
1920
group: Standard.Base.Database
2021
icon: drive
2122
suggested: 5

distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Base_Generator.enso

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ base_dialect_operations =
486486
unary = name -> [name, make_unary_op name]
487487
fun = name -> [name, make_function name]
488488

489-
arith = [["ADD_NUMBER", make_binary_op "+"], ["ADD_TEXT", make_binary_op "||"], bin "-", bin "*", bin "/", bin "%", ["MOD", make_function "MOD"], ["^", make_function "POWER"], ["ROUND", make_function "ROUND"], ["TRUNCATE", make_function "TRUNC"], ["CEIL", make_function "CEIL"], ["FLOOR", make_function "FLOOR"], ["ABS", make_function "ABS"], ["SIGNUM", make_function "SIGN"]]
489+
arith = [["ADD_NUMBER", make_binary_op "+"], ["ADD_TEXT", make_binary_op "||"], bin "-", bin "*", bin "/", bin "%", ["MOD", make_function "MOD"], ["^", make_function "POWER"], ["ROUND", make_function "ROUND"], ["TRUNCATE", make_function "TRUNC"], ["CEIL", make_function "CEIL"], ["FLOOR", make_function "FLOOR"], ["ABS", make_function "ABS"], ["SIGNUM", make_function "SIGN"], ["EXP", make_function "EXP"], ["LN", make_function "LN"], ["LOG10", make_function "LOG10"], ["SQRT", make_function "SQRT"]]
490490
logic = [bin "AND", bin "OR", unary "NOT", ["IIF", make_iif], ["CASE", case_when]]
491491
eq = lift_binary_op "==" make_equals
492492
neq = lift_binary_op "!=" make_not_equals
@@ -500,7 +500,8 @@ base_dialect_operations =
500500
types = [simple_cast]
501501
windows = [["ROW_NUMBER", make_row_number], ["ROW_NUMBER_IN_GROUP", make_row_number_in_group], ["GROUP_NUMBER", make_group_number], ["GROUP_NUMBER_EQUAL_COUNT", make_group_number_equal_count]]
502502
leadlag = [["LEAD", _make_lead_lag "LEAD"], ["LAG", _make_lead_lag "LAG"], ["LEAD_CLOSEST", _make_lead_lag_closest_value "LEAD"], ["LAG_CLOSEST", _make_lead_lag_closest_value "LAG"]]
503-
base_dict = Dictionary.from_vector (arith + logic + compare + functions + agg + counts + text + nulls + contains + types + windows + leadlag)
503+
trig = [["SIN", make_function "SIN"], ["ASIN", make_function "ASIN"], ["COS", make_function "COS"], ["ACOS", make_function "ACOS"], ["TAN", make_function "TAN"], ["ATAN", make_function "ATAN"], ["SINH", make_function "SINH"], ["COSH", make_function "COSH"], ["TANH", make_function "TANH"]]
504+
base_dict = Dictionary.from_vector (arith + logic + compare + functions + agg + counts + text + nulls + contains + types + windows + leadlag + trig)
504505
Dialect_Operations.Value base_dict
505506

506507
## ---

distribution/lib/Standard/Database/0.0.0-dev/src/Internal/DB_Column_Implementation.enso

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,13 +344,13 @@ type DB_Column_Implementation
344344
make_binary_op this_column "RIGHT" n2 new_name
345345

346346
text_mid (this_column : Column & DB_Column) (start : Column | Any) (length : Column | Any) =
347-
Value_Type.expect_integer start <|
347+
Helpers.expect_specific_integer_type this_column start <|
348348
case length of
349349
_ : Rest_Of_String ->
350350
new_name = (naming_helper this_column).function_name "text_mid" [this_column, start]
351351
make_op this_column "SUBSTR" [start + 1] new_name
352352
_ ->
353-
Value_Type.expect_integer length <|
353+
Helpers.expect_specific_integer_type this_column length <|
354354
new_name = (naming_helper this_column).function_name "text_mid" [this_column, start, length]
355355
make_op this_column "SUBSTR" [start + 1, length] new_name
356356

distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Dialect.enso

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ make_dialect_operations =
441441
cases = [["LOWER", Base_Generator.make_function "LOWER"], ["UPPER", Base_Generator.make_function "UPPER"], ["PROPER", Base_Generator.make_function "INITCAP"]]
442442
text = [starts_with, contains, ends_with, agg_shortest, agg_longest, make_case_sensitive, ["REPLACE", replace], left, right, ["SUBSTR", _make_mid], regex_match]+concat_ops+cases+trim_ops
443443
counts = [agg_count_is_null, agg_count_empty, agg_count_not_empty, ["COUNT_DISTINCT", agg_count_distinct], ["COUNT_DISTINCT_INCLUDE_NULL", agg_count_distinct_include_null]]
444-
arith_extensions = [is_nan, is_inf, is_finite, floating_point_div, mod_op, decimal_div, decimal_mod, ["ROW_MIN", Base_Generator.make_function "LEAST"], ["ROW_MAX", Base_Generator.make_function "GREATEST"]]
444+
arith_extensions = [power, sqrt, exp, ln, log10, is_nan, is_inf, is_finite, floating_point_div, mod_op, decimal_div, decimal_mod, ["ROW_MIN", Base_Generator.make_function "LEAST"], ["ROW_MAX", Base_Generator.make_function "GREATEST"]]
445445
bool = [bool_or]
446446

447447
stddev_pop = ["STDDEV_POP", Base_Generator.make_function "stddev_pop"]
@@ -737,6 +737,36 @@ make_order_descriptor internal_column:Internal_Column sort_direction text_orderi
737737
folded_expression = SQL_IR_Expression.Operation "LOWER" [upper]
738738
Order_Descriptor.Value folded_expression sort_direction nulls_order=nulls collation=Nothing
739739

740+
## ---
741+
private: true
742+
---
743+
sqrt = Base_Generator.lift_unary_op "SQRT" arg->
744+
(SQL_Builder.code "CASE WHEN " ++ arg ++ "< 0 THEN (double precision 'NaN') ELSE SQRT(" ++ arg ++ ") END").paren
745+
746+
## ---
747+
private: true
748+
---
749+
ln = Base_Generator.lift_unary_op "LN" arg->
750+
(SQL_Builder.code "CASE WHEN " ++ arg ++ " < 0 THEN (double precision 'NaN') WHEN " ++ arg ++ " = 0 THEN (double precision '-Infinity') ELSE LN(" ++ arg ++ ") END").paren
751+
752+
## ---
753+
private: true
754+
---
755+
log10 = Base_Generator.lift_unary_op "LOG10" arg->
756+
(SQL_Builder.code "CASE WHEN " ++ arg ++ " < 0 THEN (double precision 'NaN') WHEN " ++ arg ++ " = 0 THEN (double precision '-Infinity') ELSE LOG10(" ++ arg ++ ") END").paren
757+
758+
## ---
759+
private: true
760+
---
761+
power = Base_Generator.lift_binary_op "^" x-> y->
762+
(SQL_Builder.code "CASE WHEN " ++ x ++ " < 0 AND " ++ y ++ " != FLOOR(" ++ y ++ ") THEN (double precision 'NaN') WHEN " ++ x ++ " = 0 AND " ++ y ++ " < 0 THEN (double precision 'Infinity') ELSE POWER(" ++ x ++ ", " ++ y ++ ") END").paren
763+
764+
## ---
765+
private: true
766+
---
767+
exp = Base_Generator.lift_unary_op "EXP" arg->
768+
SQL_Builder.code "EXP(CAST(" ++ arg ++ " AS double precision))"
769+
740770
## ---
741771
private: true
742772
---

distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Type_Mapping.enso

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ operations_dict =
251251
Panic.throw (Illegal_State.Error "RUNTIME_ERROR should not be part of direct type inference, so this code should never be reached. This is a bug in the Database library.")
252252

253253
always_boolean_ops = ["==", "!=", "EQUALS_IGNORE_CASE", ">=", "<=", "<", ">", "BETWEEN", "AND", "OR", "NOT", "IS_NULL", "IS_EMPTY", "LIKE", "IS_IN", "IS_IN_COLUMN", "STARTS_WITH", "ENDS_WITH", "CONTAINS", "BOOL_OR", "IS_INF", "IS_FINITE"]
254-
always_floating_ops = ["/", "MOD", "AVG", "STDDEV_POP", "STDDEV_SAMP", "ROUND"]
254+
always_floating_ops = ["/", "MOD", "AVG", "STDDEV_POP", "STDDEV_SAMP", "ROUND", "SIN", "ASIN", "COS", "ACOS", "TAN", "ATAN", "SINH", "COSH", "TANH", "EXP", "LN", "LOG10", "SQRT"]
255255
always_text_ops = ["ADD_TEXT", "CONCAT", "CONCAT_QUOTE_IF_NEEDED", "MAKE_CASE_SENSITIVE", "FOLD_CASE", "TRIM", "LTRIM", "RTRIM", "REPLACE", "LEFT", "RIGHT", "SUBSTR", "UPPER", "LOWER"]
256256
always_integer_ops = ["COUNT", "COUNT_IS_NULL", "COUNT_DISTINCT", "COUNT_DISTINCT_INCLUDE_NULL", "COUNT_EMPTY", "COUNT_NOT_EMPTY", "COUNT_ROWS", "COUNT_OVER_PARTITION", "ROW_NUMBER", "ROW_NUMBER_IN_GROUP", "GROUP_NUMBER", "GROUP_NUMBER_EQUAL_COUNT", "LENGTH", "SIGNUM"]
257257
same_as_first = ["TRUNCATE", "CEIL", "FLOOR", "FIRST", "LAST", "ABS"]

distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Type_Refinements/Typed_DB_Column_Implementations.enso

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,91 @@ private
33
from Standard.Base import all
44
import Standard.Base.Errors.Unimplemented.Unimplemented
55

6-
from Standard.Table import Value_Type
6+
from Standard.Table import Column, Value_Type
77

8+
import project.DB_Column.DB_Column
89
from project.Internal.DB_Column_Implementation import make_unary_op, naming_helper
910

1011
type DB_Numeric_Column_Implementation
11-
abs column =
12+
abs (column : Column & DB_Column) =
1213
Value_Type.expect_numeric column <|
1314
new_name = (naming_helper column).function_name "abs" [column]
1415
make_unary_op column "ABS" new_name
1516

16-
signum column =
17+
signum (column : Column & DB_Column) =
1718
Value_Type.expect_numeric column <|
1819
new_name = (naming_helper column).function_name "signum" [column]
1920
make_unary_op column "SIGNUM" new_name
2021

21-
randbetween column limit seed =
22+
randbetween (column : Column & DB_Column) limit seed =
2223
_ = [column, limit, seed]
2324
Unimplemented.throw "randbetween is not implemented for database backends."
2425

26+
sin (column : Column & DB_Column) =
27+
Value_Type.expect_numeric column <|
28+
new_name = (naming_helper column).function_name "sin" [column]
29+
make_unary_op column "SIN" new_name
30+
31+
asin (column : Column & DB_Column) =
32+
Value_Type.expect_numeric column <|
33+
new_name = (naming_helper column).function_name "asin" [column]
34+
make_unary_op column "ASIN" new_name
35+
36+
cos (column : Column & DB_Column) =
37+
Value_Type.expect_numeric column <|
38+
new_name = (naming_helper column).function_name "cos" [column]
39+
make_unary_op column "COS" new_name
40+
41+
acos (column : Column & DB_Column) =
42+
Value_Type.expect_numeric column <|
43+
new_name = (naming_helper column).function_name "acos" [column]
44+
make_unary_op column "ACOS" new_name
45+
46+
tan (column : Column & DB_Column) =
47+
Value_Type.expect_numeric column <|
48+
new_name = (naming_helper column).function_name "tan" [column]
49+
make_unary_op column "TAN" new_name
50+
51+
atan (column : Column & DB_Column) =
52+
Value_Type.expect_numeric column <|
53+
new_name = (naming_helper column).function_name "atan" [column]
54+
make_unary_op column "ATAN" new_name
55+
56+
sinh (column : Column & DB_Column) =
57+
Value_Type.expect_numeric column <|
58+
new_name = (naming_helper column).function_name "sinh" [column]
59+
make_unary_op column "SINH" new_name
60+
61+
cosh (column : Column & DB_Column) =
62+
Value_Type.expect_numeric column <|
63+
new_name = (naming_helper column).function_name "cosh" [column]
64+
make_unary_op column "COSH" new_name
65+
66+
tanh (column : Column & DB_Column) =
67+
Value_Type.expect_numeric column <|
68+
new_name = (naming_helper column).function_name "tanh" [column]
69+
make_unary_op column "TANH" new_name
70+
71+
sqrt (column : Column & DB_Column) =
72+
Value_Type.expect_numeric column <|
73+
new_name = (naming_helper column).function_name "sqrt" [column]
74+
make_unary_op column "SQRT" new_name
75+
76+
ln (column : Column & DB_Column) =
77+
Value_Type.expect_numeric column <|
78+
new_name = (naming_helper column).function_name "ln" [column]
79+
make_unary_op column "LN" new_name
80+
81+
exp (column : Column & DB_Column) =
82+
Value_Type.expect_numeric column <|
83+
new_name = (naming_helper column).function_name "exp" [column]
84+
make_unary_op column "EXP" new_name
85+
86+
log10 (column : Column & DB_Column) =
87+
Value_Type.expect_numeric column <|
88+
new_name = (naming_helper column).function_name "log10" [column]
89+
make_unary_op column "LOG10" new_name
90+
2591
type DB_Text_Column_Implementation
2692
to_case column case_option:Case=..Lower locale:Locale=Locale.default =
2793
if locale != Locale.default then

distribution/lib/Standard/Snowflake/0.0.0-dev/src/Internal/Snowflake_Dialect.enso

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ type Snowflake_Dialect
452452
private: true
453453
---
454454
make_dialect_operations =
455-
arith = [round_bankers]
455+
arith = [sqrt, ln, log10, power, round_bankers]
456456
cases = [["LOWER", Base_Generator.make_function "LOWER"], ["UPPER", Base_Generator.make_function "UPPER"], ["PROPER", Base_Generator.make_function "INITCAP"]]
457457
text = [starts_with, contains, ends_with, agg_shortest, agg_longest, make_case_sensitive, ["REPLACE", replace], left, right, regex_match]+concat_ops+cases+trim_ops
458458
counts = [agg_count_is_null, agg_count_empty, agg_count_not_empty, ["COUNT_DISTINCT", agg_count_distinct], ["COUNT_DISTINCT_INCLUDE_NULL", agg_count_distinct_include_null]]
@@ -725,6 +725,30 @@ make_order_descriptor internal_column sort_direction text_ordering =
725725
True ->
726726
Order_Descriptor.Value (Internals_Access.column_expression internal_column) sort_direction nulls_order=nulls collation="en-ci"
727727

728+
## ---
729+
private: true
730+
---
731+
sqrt = Base_Generator.lift_unary_op "SQRT" arg->
732+
(SQL_Builder.code "CASE WHEN " ++ arg ++ "< 0 THEN ('NaN'::float) ELSE SQRT(" ++ arg ++ ") END").paren
733+
734+
## ---
735+
private: true
736+
---
737+
ln = Base_Generator.lift_unary_op "LN" arg->
738+
(SQL_Builder.code "CASE WHEN " ++ arg ++ " < 0 THEN ('NaN'::float) WHEN " ++ arg ++ " = 0 THEN ('-Infinity'::float) ELSE LN(" ++ arg ++ ") END").paren
739+
740+
## ---
741+
private: true
742+
---
743+
log10 = Base_Generator.lift_unary_op "LOG10" arg->
744+
(SQL_Builder.code "CASE WHEN " ++ arg ++ " < 0 THEN ('NaN'::float) WHEN " ++ arg ++ " = 0 THEN ('-Infinity'::float) ELSE LOG(10, " ++ arg ++ ") END").paren
745+
746+
## ---
747+
private: true
748+
---
749+
power = Base_Generator.lift_binary_op "^" x-> y->
750+
(SQL_Builder.code "CASE WHEN " ++ x ++ " < 0 AND " ++ y ++ " != FLOOR(" ++ y ++ ") THEN ('NaN'::float) WHEN " ++ x ++ " = 0 AND " ++ y ++ " < 0 THEN ('Infinity'::float) ELSE POWER(" ++ x ++ ", " ++ y ++ ") END").paren
751+
728752
## ---
729753
private: true
730754
---

distribution/lib/Standard/Table/0.0.0-dev/docs/api/Refined_Types/Numeric_Column.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,22 @@
22
## module Standard.Table.Refined_Types.Numeric_Column
33
- type Numeric_Column
44
- abs self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
5+
- acos self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
6+
- asin self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
7+
- atan self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
8+
- cos self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
9+
- cosh self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
10+
- degrees self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
11+
- exp self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
12+
- ln self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
13+
- log self base:Standard.Base.Any.Any= -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
14+
- log10 self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
15+
- power self power:Standard.Base.Any.Any -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
16+
- radians self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
517
- randbetween self limit:Standard.Base.Any.Any seed:Standard.Base.Data.Numbers.Integer= -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
618
- signum self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
19+
- sin self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
20+
- sinh self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
21+
- sqrt self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
22+
- tan self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)
23+
- tanh self -> (Standard.Table.Column.Column&Standard.Table.Refined_Types.Numeric_Column.Numeric_Column)

0 commit comments

Comments
 (0)