From 8c34ebbdd4660e35b0dd5c0a05b88942d0bf9de1 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Tue, 23 May 2023 10:56:22 -0400 Subject: [PATCH 01/40] move each_propagate into Range --- .../Base/0.0.0-dev/src/Data/Range.enso | 19 +++++++++++++++++++ .../0.0.0-dev/src/Internal/Column_Format.enso | 17 ++--------------- .../0.0.0-dev/src/Internal/Column_Ops.java | 0 test/Tests/src/Data/Range_Spec.enso | 7 +++++++ 4 files changed, 28 insertions(+), 15 deletions(-) create mode 100644 distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.java diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso index df9b105f93b3..cd4dfe90af44 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso @@ -200,6 +200,25 @@ type Range @Tail_Call go current+self.step go self.start + ## PRIVATE + ADVANCED + + Applies a function for each element in the range. Exits early if the body + produces an `Error`. + each_propagate : (Integer -> Any) -> Nothing ! Error + each_propagate self function = + if self.step == 0 then throw_zero_step_error else + end_condition = if self.step > 0 then (>=) else (<=) + go current = + if end_condition current self.end then Nothing else + result = function current + IO.println "RES" + IO.println current + IO.println result + result.if_not_error <| + @Tail_Call go current+self.step + go self.start + ## PRIVATE ADVANCED Applies a function to each element of the range. diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Format.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Format.enso index 48625a8dcc8c..e447b2e81f9d 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Format.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Format.enso @@ -57,19 +57,6 @@ handle_illegal_argument_exception format_string ~action = Panic.catch IllegalArgumentException handler=handler <| Panic.catch UnsupportedTemporalTypeException handler=handler action -## PRIVATE - Iterate over a range, exiting early if the body produces an `Error`. -each_propagate : Range -> (Number -> Any) -> Nothing ! Error -each_propagate range function = - if range.step == 0 then Error.throw (Illegal_State.Error "A range with step = 0 is ill-formed.") else - end_condition = if range.step > 0 then (>=) else (<=) - go current = - if end_condition current range.end then Nothing else - result = function current - result.if_not_error <| - @Tail_Call go current+range.step - go range.start - ## PRIVATE Map a text-returning function over the column values, using Storage directly. The output column has the same name as the input. @@ -78,7 +65,7 @@ map_over_storage input_column function builder skip_nothing=True = input_storage = input_column.java_column.getStorage num_input_rows = input_storage.size output_storage_builder = builder num_input_rows - ok = each_propagate (0.up_to num_input_rows) i-> + ok = 0.up_to num_input_rows.each_propagate i-> input_value = input_storage.getItemBoxed i if skip_nothing && input_value.is_nothing then output_storage_builder.append Nothing else output_value = function input_value @@ -103,7 +90,7 @@ map_2_over_storage input_column_0 input_column_1 function builder skip_nothing=T False -> num_input_rows = input_storage_0.size output_storage_builder = builder num_input_rows - ok = each_propagate (0.up_to num_input_rows) i-> + ok = 0.up_to num_input_rows.each_propagate i-> input_value_0 = input_storage_0.getItemBoxed i input_value_1 = input_storage_1.getItemBoxed i if skip_nothing && input_value_0.is_nothing then output_storage_builder.append Nothing else diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.java b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.java new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test/Tests/src/Data/Range_Spec.enso b/test/Tests/src/Data/Range_Spec.enso index 64766a5052f3..a875a2700f88 100644 --- a/test/Tests/src/Data/Range_Spec.enso +++ b/test/Tests/src/Data/Range_Spec.enso @@ -164,6 +164,13 @@ spec = Test.group "Range" <| vec_mut = Vector.new_builder 1.up_to 6 . each (i -> vec_mut.append i) vec_mut.to_vector . should_equal [1, 2, 3, 4, 5] + Test.specify "should allow iteration, with error propagation and early exit" <| + vec_mut = Vector.new_builder + result = 1.up_to 6 . each_propagate i-> + if i >= 3 then Error.throw (Illegal_Argument.Error "dummy") else + vec_mut.append i + result . should_fail_with Illegal_Argument + vec_mut.to_vector . should_equal [1, 2] Test.specify "should allow efficient iteration" <| cell = Ref.new 0 n = 100000000 From 3d8b55cd550770f54143890b9d0a80129a62cd29 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Tue, 23 May 2023 11:06:05 -0400 Subject: [PATCH 02/40] Column_Ops --- .../Base/0.0.0-dev/src/Data/Range.enso | 3 -- .../Table/0.0.0-dev/src/Data/Column.enso | 9 ++-- .../0.0.0-dev/src/Internal/Column_Format.enso | 43 ---------------- .../0.0.0-dev/src/Internal/Column_Ops.enso | 49 +++++++++++++++++++ .../0.0.0-dev/src/Internal/Column_Ops.java | 0 5 files changed, 54 insertions(+), 50 deletions(-) create mode 100644 distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso delete mode 100644 distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.java diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso index cd4dfe90af44..c5ed392529ef 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso @@ -212,9 +212,6 @@ type Range go current = if end_condition current self.end then Nothing else result = function current - IO.println "RES" - IO.println current - IO.println result result.if_not_error <| @Tail_Call go current+self.step go self.start diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index 37c2dcfc3407..e99bbb9e4ee3 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -13,6 +13,7 @@ import project.Data.Type.Storage import project.Data.Type.Value_Type_Helpers import project.Data.Table.Table import project.Internal.Cast_Helpers +import project.Internal.Column_Ops import project.Internal.Java_Problems import project.Internal.Naming_Helpers.Naming_Helpers import project.Internal.Parse_Values_Helper @@ -1278,18 +1279,18 @@ type Column new_column = case format of "" -> formatter = .to_text - map_over_storage self formatter make_string_builder + Column_Ops.map_over_storage self formatter make_string_builder Nothing -> formatter = .to_text - map_over_storage self formatter make_string_builder + Column_Ops.map_over_storage self formatter make_string_builder _ : Text -> formatter = create_formatter formatter.if_not_error <| - map_over_storage self (formatter format=format) make_string_builder + Column_Ops.map_over_storage self (formatter format=format) make_string_builder format_column : Column -> Value_Type.expect_text format_column <| formatter = create_formatter formatter.if_not_error <| - map_2_over_storage self format_column formatter make_string_builder + Column_Ops.map_2_over_storage self format_column formatter make_string_builder _ -> Error.throw <| Illegal_Argument.Error <| "Unsupported format type: " + format.to_text new_column diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Format.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Format.enso index e447b2e81f9d..08a5be12231f 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Format.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Format.enso @@ -56,46 +56,3 @@ handle_illegal_argument_exception format_string ~action = Error.throw (Illegal_Argument.Error msg) Panic.catch IllegalArgumentException handler=handler <| Panic.catch UnsupportedTemporalTypeException handler=handler action - -## PRIVATE - Map a text-returning function over the column values, using Storage directly. - The output column has the same name as the input. -map_over_storage : Column -> (Any -> Text) -> (Integer -> Any) -> Boolean -> Column -map_over_storage input_column function builder skip_nothing=True = - input_storage = input_column.java_column.getStorage - num_input_rows = input_storage.size - output_storage_builder = builder num_input_rows - ok = 0.up_to num_input_rows.each_propagate i-> - input_value = input_storage.getItemBoxed i - if skip_nothing && input_value.is_nothing then output_storage_builder.append Nothing else - output_value = function input_value - output_value.if_not_error - output_storage_builder.append output_value - ok.if_not_error <| - output_storage = output_storage_builder.seal - Column.from_storage input_column.name output_storage - -## PRIVATE - Map a text-returning function over the values of two columns, using Storage - directly. The output column has the same name as the first input column. - `skip_nothing` applies to the first input to the function, not both inputs. -map_2_over_storage : Column -> Column -> (Any -> Any -> Text) -> (Integer -> Any) -> Boolean -> Column -map_2_over_storage input_column_0 input_column_1 function builder skip_nothing=True = - input_storage_0 = input_column_0.java_column.getStorage - input_storage_1 = input_column_1.java_column.getStorage - case input_storage_0.size != input_storage_1.size of - True -> - msg = "Column lengths differ: " + input_storage_0.size.to_text + " != " + input_storage_1.size.to_text - Error.throw (Illegal_Argument.Error msg) - False -> - num_input_rows = input_storage_0.size - output_storage_builder = builder num_input_rows - ok = 0.up_to num_input_rows.each_propagate i-> - input_value_0 = input_storage_0.getItemBoxed i - input_value_1 = input_storage_1.getItemBoxed i - if skip_nothing && input_value_0.is_nothing then output_storage_builder.append Nothing else - output_value = function input_value_0 input_value_1 - output_storage_builder.append output_value - ok.if_not_error <| - output_storage = output_storage_builder.seal - Column.from_storage input_column_0.name output_storage diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso new file mode 100644 index 000000000000..845169ad0cdc --- /dev/null +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso @@ -0,0 +1,49 @@ +from Standard.Base import all + +import Standard.Base.Errors.Illegal_Argument.Illegal_Argument +import project.Data.Column.Column + +from project.Internal.Java_Exports import make_string_builder + +## PRIVATE + Map a text-returning function over the column values, using Storage directly. + The output column has the same name as the input. +map_over_storage : Column -> (Any -> Text) -> (Integer -> Any) -> Boolean -> Column +map_over_storage input_column function builder skip_nothing=True = + input_storage = input_column.java_column.getStorage + num_input_rows = input_storage.size + output_storage_builder = builder num_input_rows + ok = 0.up_to num_input_rows . each_propagate i-> + input_value = input_storage.getItemBoxed i + if skip_nothing && input_value.is_nothing then output_storage_builder.append Nothing else + output_value = function input_value + output_value.if_not_error + output_storage_builder.append output_value + ok.if_not_error <| + output_storage = output_storage_builder.seal + Column.from_storage input_column.name output_storage + +## PRIVATE + Map a text-returning function over the values of two columns, using Storage + directly. The output column has the same name as the first input column. + `skip_nothing` applies to the first input to the function, not both inputs. +map_2_over_storage : Column -> Column -> (Any -> Any -> Text) -> (Integer -> Any) -> Boolean -> Column +map_2_over_storage input_column_0 input_column_1 function builder skip_nothing=True = + input_storage_0 = input_column_0.java_column.getStorage + input_storage_1 = input_column_1.java_column.getStorage + case input_storage_0.size != input_storage_1.size of + True -> + msg = "Column lengths differ: " + input_storage_0.size.to_text + " != " + input_storage_1.size.to_text + Error.throw (Illegal_Argument.Error msg) + False -> + num_input_rows = input_storage_0.size + output_storage_builder = builder num_input_rows + ok = 0.up_to num_input_rows . each_propagate i-> + input_value_0 = input_storage_0.getItemBoxed i + input_value_1 = input_storage_1.getItemBoxed i + if skip_nothing && input_value_0.is_nothing then output_storage_builder.append Nothing else + output_value = function input_value_0 input_value_1 + output_storage_builder.append output_value + ok.if_not_error <| + output_storage = output_storage_builder.seal + Column.from_storage input_column_0.name output_storage diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.java b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.java deleted file mode 100644 index e69de29bb2d1..000000000000 From 2aa2302e1aa30111fe3d4a3e6b8be19c05b06deb Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Tue, 23 May 2023 12:23:22 -0400 Subject: [PATCH 03/40] round --- .../Base/0.0.0-dev/src/Data/Numbers.enso | 8 +- .../Table/0.0.0-dev/src/Data/Column.enso | 41 +++- .../0.0.0-dev/src/Internal/Column_Ops.enso | 26 ++- .../src/In_Memory/Column_Spec.enso | 201 +++++++++++------- 4 files changed, 178 insertions(+), 98 deletions(-) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso index dd91fa1987f1..b5e9eedbf174 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso @@ -601,7 +601,7 @@ type Decimal Use Banker's Rounding. 2.5 . round use_bankers=True == 2 - round : Integer -> Integer | Decimal ! Illegal_Argument + round : Integer -> Boolean -> Integer | Decimal ! Illegal_Argument round self decimal_places=0 use_bankers=False = check_decimal_places decimal_places <| case self.is_nan || self.is_infinite of @@ -923,12 +923,12 @@ type Integer Round to the nearest hundred, using Banker's Rounding. 12250 . round -2 use_bankers=True == 12200 - round : Integer -> Integer ! Illegal_Argument + round : Integer -> Boolean -> Integer ! Illegal_Argument round self decimal_places=0 use_bankers=False = check_decimal_places decimal_places <| case self < round_min_long || self > round_max_long of True -> - msg = "Error: Integer.round can only accept values between " + round_min_long.to_text + " and " + round_max_long.to_text + "(inclusive), but was " + self.to_text + msg = "Error: Integer.round can only accept values between " + round_min_long.to_text + " and " + round_max_long.to_text + " (inclusive), but was " + self.to_text Error.throw (Illegal_Argument.Error msg) False -> ## It's already an integer so unless decimal_places is @@ -1135,5 +1135,5 @@ round_min_long = -99999999999999 check_decimal_places : Integer -> Function check_decimal_places decimal_places ~action = if decimal_places >= round_min_decimal_places && decimal_places <= round_max_decimal_places then action else - msg = "round: decimal_places must be between " + round_min_decimal_places.to_text + " and " + round_max_decimal_places.to_text + "(inclusive), but was " + decimal_places.to_text + msg = "round: decimal_places must be between " + round_min_decimal_places.to_text + " and " + round_max_decimal_places.to_text + " (inclusive), but was " + decimal_places.to_text Error.throw (Illegal_Argument.Error msg) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index e99bbb9e4ee3..986e2e99c633 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -24,7 +24,7 @@ from project.Internal.Column_Format import all from project.Data.Table import print_table from project.Data.Type.Value_Type import Value_Type, Auto from project.Errors import No_Index_Set_Error, Floating_Point_Equality, Invalid_Value_Type, Inexact_Type_Coercion, Conversion_Failure -from project.Internal.Java_Exports import make_string_builder +from project.Internal.Java_Exports import make_string_builder, make_double_builder, make_long_builder polyglot java import org.enso.table.data.column.operation.map.MapOperationProblemBuilder polyglot java import org.enso.table.data.column.storage.Storage as Java_Storage @@ -657,6 +657,45 @@ type Column rs = s.iif true_val false_val storage_type Column.Value (Java_Column.new new_name rs) + ## Round the values in a numeric column to a specified number of decimal + places. + + For integers, rounding to 0 or more decimal places simply returns the + argument. For negative decimal places, see below. + + By default, rounding uses "asymmetric round-half-up", also known as + "round towards positive infinity." If use_bankers=True, then it uses + "round-half-even", also known as "banker's rounding". + + Arguments: + - decimal_places: The number of decimal places to round to. Can be + negative, which results in rounding to positive integer powers of 10. + Must be between -15 and 15 (inclusive). + - use_bankers: Rounds mid-point to nearest even number. + - on_problems: Specifies how to handle if a problem occurs, raising as a + warning by default. + + ! Error Conditions + Reports `Illegal_Argument` if the number is 15 or more decimal places. + Above 14 digits, it is possible that the underlying long, converted to + double in the rounding process, would lose precision in the least + significant bits. + (See https://en.wikipedia.org/wiki/Double-precision_floating-point_format.) + + If `decimal_places` is outside the range -15..15 (inclusive), an + `Illegal_Argument` error is thrown. + + ? Negative decimal place counts + Rounding to `n` digits can be thought of as "rounding to the nearest + multiple of 10^(-n)". For negative decimal counts, this results in + rounding to the nearest positive integer power of 10. + round : Integer -> Boolean -> Problem_Behavior -> Column | Illegal_Argument + round self decimal_places=0 use_bankers=False on_problems=Report_Warning = + returns_double = decimal_places > 0 + builder = if returns_double then make_double_builder else make_long_builder + fun = _.round decimal_places use_bankers + Column_Ops.map_over_storage self fun builder skip_nothing=True on_problems=on_problems + ## Returns a column of first non-`Nothing` value on each row of `self` and `values` list. diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso index 845169ad0cdc..468c12649417 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso @@ -1,34 +1,38 @@ from Standard.Base import all import Standard.Base.Errors.Illegal_Argument.Illegal_Argument + import project.Data.Column.Column +import project.Internal.Problem_Builder.Problem_Builder from project.Internal.Java_Exports import make_string_builder ## PRIVATE Map a text-returning function over the column values, using Storage directly. The output column has the same name as the input. -map_over_storage : Column -> (Any -> Text) -> (Integer -> Any) -> Boolean -> Column -map_over_storage input_column function builder skip_nothing=True = +map_over_storage : Column -> (Any -> Text) -> (Integer -> Any) -> Boolean -> Problem_Behavior -> Column +map_over_storage input_column function builder skip_nothing=True on_problems=Report_Warning = + problem_builder = Problem_Builder.new input_storage = input_column.java_column.getStorage num_input_rows = input_storage.size output_storage_builder = builder num_input_rows - ok = 0.up_to num_input_rows . each_propagate i-> + 0.up_to num_input_rows . each_propagate i-> input_value = input_storage.getItemBoxed i if skip_nothing && input_value.is_nothing then output_storage_builder.append Nothing else - output_value = function input_value - output_value.if_not_error - output_storage_builder.append output_value - ok.if_not_error <| - output_storage = output_storage_builder.seal - Column.from_storage input_column.name output_storage + output_value = function input_value . catch Any err-> + problem_builder.report_other_warning err + Nothing + output_storage_builder.append output_value + output_storage = output_storage_builder.seal + new_column = Column.from_storage input_column.name output_storage + problem_builder.attach_problems_after on_problems new_column ## PRIVATE Map a text-returning function over the values of two columns, using Storage directly. The output column has the same name as the first input column. `skip_nothing` applies to the first input to the function, not both inputs. -map_2_over_storage : Column -> Column -> (Any -> Any -> Text) -> (Integer -> Any) -> Boolean -> Column -map_2_over_storage input_column_0 input_column_1 function builder skip_nothing=True = +map_2_over_storage : Column -> Column -> (Any -> Any -> Text) -> (Integer -> Any) -> Boolean -> Problem_Behavior -> Column +map_2_over_storage input_column_0 input_column_1 function builder skip_nothing=True on_problems=Report_Warning = input_storage_0 = input_column_0.java_column.getStorage input_storage_1 = input_column_1.java_column.getStorage case input_storage_0.size != input_storage_1.size of diff --git a/test/Table_Tests/src/In_Memory/Column_Spec.enso b/test/Table_Tests/src/In_Memory/Column_Spec.enso index 6318ad66d212..487f4c27cccf 100644 --- a/test/Table_Tests/src/In_Memory/Column_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Column_Spec.enso @@ -1,4 +1,7 @@ from Standard.Base import all + +import project.Util + import Standard.Base.Errors.Common.Index_Out_Of_Bounds import Standard.Base.Errors.Illegal_Argument.Illegal_Argument @@ -6,89 +9,123 @@ from Standard.Table import Column, Value_Type import Standard.Examples -from Standard.Test import Test, Test_Suite +from Standard.Test import Test, Test_Suite, Problems import Standard.Test.Extensions main = Test_Suite.run_main spec -spec = Test.group "Columns" <| - test_column = Column.from_vector "Test" [1, 3, 5, 2, 4, 6] - empty_column = Column.from_vector "Test" [] - - Test.specify "should allow getting specific elements" <| - test_column.at 0 . should_equal 1 - test_column.at 2 . should_equal 5 - test_column.at 5 . should_equal 6 - test_column.at 6 . should_fail_with Index_Out_Of_Bounds - empty_column.at 0 . should_fail_with Index_Out_Of_Bounds - - Test.specify "should be able to take the first n elements" <| - expected_1 = Column.from_vector "Test" [1, 3, 5] - expected_2 = Column.from_vector "Test" [1, 3, 5, 2, 4, 6] - expected_3 = Column.from_vector "Test" [] - test_column.take (First 3) . to_vector . should_equal expected_1.to_vector - test_column.take (First 7) . to_vector . should_equal expected_2.to_vector - test_column.take (First 0) . to_vector . should_equal expected_3.to_vector - - Test.specify "should be able to take the first n elements by Integer" <| - expected_1 = Column.from_vector "Test" [1, 3, 5] - expected_2 = Column.from_vector "Test" [1, 3, 5, 2, 4, 6] - expected_3 = Column.from_vector "Test" [] - test_column.take 3 . to_vector . should_equal expected_1.to_vector - test_column.take 7 . to_vector . should_equal expected_2.to_vector - test_column.take 0 . to_vector . should_equal expected_3.to_vector - - Test.specify "should be able to take the last n elements" <| - expected_1 = Column.from_vector "Test" [2, 4, 6] - expected_2 = Column.from_vector "Test" [1, 3, 5, 2, 4, 6] - expected_3 = Column.from_vector "Test" [] - test_column.take (Last 3) . to_vector . should_equal expected_1.to_vector - test_column.take (Last 7) . to_vector . should_equal expected_2.to_vector - test_column.take (Last 0) . to_vector . should_equal expected_3.to_vector - - Test.specify "should be able to get the first element" <| - test_column.first . should_equal 1 - empty_column.first.should_fail_with Index_Out_Of_Bounds - - Test.specify "should be able to get the last element" <| - test_column.last . should_equal 6 - empty_column.last.should_fail_with Index_Out_Of_Bounds - - Test.specify "should be able to be reversed" <| - expected_1 = Column.from_vector "Test" [6, 4, 2, 5, 3, 1] - test_column.reverse.to_vector . should_equal expected_1.to_vector - empty_column.reverse.to_vector . should_equal empty_column.to_vector - - Test.specify "should allow to fill missing values from another column" <| - nulled = Column.from_vector "col" [0, Nothing, 4, 5, Nothing, Nothing] - defaults = Column.from_vector "def" [1, 2, 10, 20, Nothing, 30] - r = nulled.fill_nothing defaults - r.to_vector . should_equal [0, 2, 4, 5, Nothing, 30] - - Test.specify "should allow to count duplicate value occurences" <| - c_1 = Column.from_vector "c 1" [0, 1, 2, 2, 1, 0, 2] - c_1.duplicate_count.to_vector.should_equal [0, 0, 0, 1, 1, 1, 2] - - c_2 = Column.from_vector "c 2" ["foo", "bar", "foo", "baz", "bar"] - c_2.duplicate_count.to_vector.should_equal [0, 0, 1, 0, 1] - - Test.specify "should result in correct Storage if operation allows it" <| - another = Column.from_vector "Test" [10, 20, 30, 40, 50, 60] - (test_column + 1).value_type . should_equal Value_Type.Integer - (test_column - 1).value_type . should_equal Value_Type.Integer - (test_column * 2).value_type . should_equal Value_Type.Integer - (test_column * 1.5).value_type . should_equal Value_Type.Float - (test_column + another).value_type . should_equal Value_Type.Integer - - Test.specify "should not allow invalid column names" <| - c1 = Column.from_vector "" [1, 2, 3] - c1.should_fail_with Illegal_Argument - - c2 = Column.from_vector Nothing [1, 2, 3] - c2.should_fail_with Illegal_Argument - - c3 = Column.from_vector '\0' [1, 2, 3] - c3.should_fail_with Illegal_Argument - - c4 = Column.from_vector 'foo\0bar' [1, 2, 3] - c4.should_fail_with Illegal_Argument +spec = + Test.group "gmt" <| + Test.specify "should report out-of-range values as problems" <| + 1 . should_equal 1 + + Test.group "Columns" <| + test_column = Column.from_vector "Test" [1, 3, 5, 2, 4, 6] + empty_column = Column.from_vector "Test" [] + + Test.specify "should allow getting specific elements" <| + test_column.at 0 . should_equal 1 + test_column.at 2 . should_equal 5 + test_column.at 5 . should_equal 6 + test_column.at 6 . should_fail_with Index_Out_Of_Bounds + empty_column.at 0 . should_fail_with Index_Out_Of_Bounds + + Test.specify "should be able to take the first n elements" <| + expected_1 = Column.from_vector "Test" [1, 3, 5] + expected_2 = Column.from_vector "Test" [1, 3, 5, 2, 4, 6] + expected_3 = Column.from_vector "Test" [] + test_column.take (First 3) . to_vector . should_equal expected_1.to_vector + test_column.take (First 7) . to_vector . should_equal expected_2.to_vector + test_column.take (First 0) . to_vector . should_equal expected_3.to_vector + + Test.specify "should be able to take the first n elements by Integer" <| + expected_1 = Column.from_vector "Test" [1, 3, 5] + expected_2 = Column.from_vector "Test" [1, 3, 5, 2, 4, 6] + expected_3 = Column.from_vector "Test" [] + test_column.take 3 . to_vector . should_equal expected_1.to_vector + test_column.take 7 . to_vector . should_equal expected_2.to_vector + test_column.take 0 . to_vector . should_equal expected_3.to_vector + + Test.specify "should be able to take the last n elements" <| + expected_1 = Column.from_vector "Test" [2, 4, 6] + expected_2 = Column.from_vector "Test" [1, 3, 5, 2, 4, 6] + expected_3 = Column.from_vector "Test" [] + test_column.take (Last 3) . to_vector . should_equal expected_1.to_vector + test_column.take (Last 7) . to_vector . should_equal expected_2.to_vector + test_column.take (Last 0) . to_vector . should_equal expected_3.to_vector + + Test.specify "should be able to get the first element" <| + test_column.first . should_equal 1 + empty_column.first.should_fail_with Index_Out_Of_Bounds + + Test.specify "should be able to get the last element" <| + test_column.last . should_equal 6 + empty_column.last.should_fail_with Index_Out_Of_Bounds + + Test.specify "should be able to be reversed" <| + expected_1 = Column.from_vector "Test" [6, 4, 2, 5, 3, 1] + test_column.reverse.to_vector . should_equal expected_1.to_vector + empty_column.reverse.to_vector . should_equal empty_column.to_vector + + Test.specify "should allow to fill missing values from another column" <| + nulled = Column.from_vector "col" [0, Nothing, 4, 5, Nothing, Nothing] + defaults = Column.from_vector "def" [1, 2, 10, 20, Nothing, 30] + r = nulled.fill_nothing defaults + r.to_vector . should_equal [0, 2, 4, 5, Nothing, 30] + + Test.specify "should allow to count duplicate value occurences" <| + c_1 = Column.from_vector "c 1" [0, 1, 2, 2, 1, 0, 2] + c_1.duplicate_count.to_vector.should_equal [0, 0, 0, 1, 1, 1, 2] + + c_2 = Column.from_vector "c 2" ["foo", "bar", "foo", "baz", "bar"] + c_2.duplicate_count.to_vector.should_equal [0, 0, 1, 0, 1] + + Test.specify "should result in correct Storage if operation allows it" <| + another = Column.from_vector "Test" [10, 20, 30, 40, 50, 60] + (test_column + 1).value_type . should_equal Value_Type.Integer + (test_column - 1).value_type . should_equal Value_Type.Integer + (test_column * 2).value_type . should_equal Value_Type.Integer + (test_column * 1.5).value_type . should_equal Value_Type.Float + (test_column + another).value_type . should_equal Value_Type.Integer + + Test.specify "should not allow invalid column names" <| + c1 = Column.from_vector "" [1, 2, 3] + c1.should_fail_with Illegal_Argument + + c2 = Column.from_vector Nothing [1, 2, 3] + c2.should_fail_with Illegal_Argument + + c3 = Column.from_vector '\0' [1, 2, 3] + c3.should_fail_with Illegal_Argument + + c4 = Column.from_vector 'foo\0bar' [1, 2, 3] + c4.should_fail_with Illegal_Argument + + Test.group "Rounding" <| + Test.specify "should be able to round a column of decimals" <| + Column.from_vector "foo" [1.2, 2.3, 3.6] . round + Column.from_vector "foo" [1.2, 2.3, 3.6] . round . should_equal (Column.from_vector "foo" [1, 2, 4]) + Column.from_vector "foo" [1.25, 2.33, 3.57] . round 1 . should_equal <| Column.from_vector "foo" [1.3, 2.3, 3.6] + Column.from_vector "foo" [12.0, 24.0, 25.0, 29.0] . round -1 . should_equal <| Column.from_vector "foo" [10, 20, 30, 30] + Column.from_vector "foo" [1.5, 2.5, 3.5] . round use_bankers=True . should_equal <| Column.from_vector "foo" [2, 2, 4] + + Test.specify "should be able to round a column of integers" <| + Column.from_vector "foo" [12, 24, 25, 29] . round . should_equal <| Column.from_vector "foo" [12, 24, 25, 29] + Column.from_vector "foo" [12, 24, 25, 29] . round -1 . should_equal <| Column.from_vector "foo" [10, 20, 30, 30] + Column.from_vector "foo" [15, 25, 35] . round -1 use_bankers=True . should_equal <| Column.from_vector "foo" [20, 20, 40] + + Test.specify "should report out-of-range values as problems" <| + col = Column.from_vector "foo" [12, 23, 99999999999999999] + expected = Column.from_vector "foo" [10, 20, Nothing] + action = col.round -1 on_problems=_ + problems = [Illegal_Argument.Error "Error: Integer.round can only accept values between -99999999999999 and 99999999999999 (inclusive), but was 99999999999999999"] + tester = _.should_equal expected + Problems.test_problem_handling action problems tester + + Test.specify "should throw an error on decimal places out of range" <| + col = Column.from_vector "foo" [12, 23, 99999999999999999] + expected = Column.from_vector "foo" [Nothing, Nothing, Nothing] + action = col.round decimal_places=1200 on_problems=_ + problems = [Illegal_Argument.Error "round: decimal_places must be between -15 and 15 (inclusive), but was 1200"] + tester = _.should_equal expected + Problems.test_problem_handling action problems tester From 5f0d00f7b8f331af3a6d485819f701004928b775 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Tue, 23 May 2023 13:38:03 -0400 Subject: [PATCH 04/40] truncate ceil floor --- .../Table/0.0.0-dev/src/Data/Column.enso | 34 ++++++++++++++++++- .../src/In_Memory/Column_Spec.enso | 13 ++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index 986e2e99c633..c79979e1df3b 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -667,6 +667,9 @@ type Column "round towards positive infinity." If use_bankers=True, then it uses "round-half-even", also known as "banker's rounding". + If `decimal_places` > 0, `round` returns a column of `Decimal`; + otherwise, it returns a column of `Integer`. + Arguments: - decimal_places: The number of decimal places to round to. Can be negative, which results in rounding to positive integer powers of 10. @@ -690,12 +693,41 @@ type Column multiple of 10^(-n)". For negative decimal counts, this results in rounding to the nearest positive integer power of 10. round : Integer -> Boolean -> Problem_Behavior -> Column | Illegal_Argument - round self decimal_places=0 use_bankers=False on_problems=Report_Warning = + round self decimal_places=0 use_bankers=False on_problems=Report_Warning = Value_Type.expect_numeric self <| returns_double = decimal_places > 0 builder = if returns_double then make_double_builder else make_long_builder fun = _.round decimal_places use_bankers Column_Ops.map_over_storage self fun builder skip_nothing=True on_problems=on_problems + ## ALIAS int + + Truncate the floating-point values in a column to an integer by dropping + the fractional part. This is equivalent to "round-toward-zero". + + Returns a column of `Integer`. + truncate : Column + truncate self = Value_Type.expect_numeric self <| + fun = _.truncate + Column_Ops.map_over_storage self fun make_long_builder skip_nothing=True + + ## Computes the nearest integer above this number for values in numeric + column. + + Returns a column of `Integer`. + ceil : Column + ceil self = Value_Type.expect_numeric self <| + fun = _.ceil + Column_Ops.map_over_storage self fun make_long_builder skip_nothing=True + + ## Computes the nearest integer below this number for values in numeric + column. + + Returns a column of `Integer`. + floor : Column + floor self = Value_Type.expect_numeric self <| + fun = _.floor + Column_Ops.map_over_storage self fun make_long_builder skip_nothing=True + ## Returns a column of first non-`Nothing` value on each row of `self` and `values` list. diff --git a/test/Table_Tests/src/In_Memory/Column_Spec.enso b/test/Table_Tests/src/In_Memory/Column_Spec.enso index 487f4c27cccf..8ef25619fed1 100644 --- a/test/Table_Tests/src/In_Memory/Column_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Column_Spec.enso @@ -103,7 +103,6 @@ spec = Test.group "Rounding" <| Test.specify "should be able to round a column of decimals" <| - Column.from_vector "foo" [1.2, 2.3, 3.6] . round Column.from_vector "foo" [1.2, 2.3, 3.6] . round . should_equal (Column.from_vector "foo" [1, 2, 4]) Column.from_vector "foo" [1.25, 2.33, 3.57] . round 1 . should_equal <| Column.from_vector "foo" [1.3, 2.3, 3.6] Column.from_vector "foo" [12.0, 24.0, 25.0, 29.0] . round -1 . should_equal <| Column.from_vector "foo" [10, 20, 30, 30] @@ -129,3 +128,15 @@ spec = problems = [Illegal_Argument.Error "round: decimal_places must be between -15 and 15 (inclusive), but was 1200"] tester = _.should_equal expected Problems.test_problem_handling action problems tester + + Test.group "Rounding" <| + Test.specify "should be able to truncate a column of decimals" <| + Column.from_vector "foo" [1.25, 2.33, 3.57] . truncate . should_equal <| Column.from_vector "foo" [1, 2, 3] + + Test.group "ceil" <| + Test.specify "should be able to take the ceil of a column of decimals" <| + Column.from_vector "foo" [1.25, 2.33, 3.57] . ceil . should_equal <| Column.from_vector "foo" [2, 3, 4] + + Test.group "floor" <| + Test.specify "should be able to take the floor of a column of decimals" <| + Column.from_vector "foo" [1.25, 2.33, 3.57] . floor . should_equal <| Column.from_vector "foo" [1, 2, 3] From b8e528271c75a282b8ec34e1c4c4101ee7eb8126 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Tue, 23 May 2023 13:39:33 -0400 Subject: [PATCH 05/40] unused --- .../lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso index 468c12649417..757cacd787b0 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso @@ -31,8 +31,8 @@ map_over_storage input_column function builder skip_nothing=True on_problems=Rep Map a text-returning function over the values of two columns, using Storage directly. The output column has the same name as the first input column. `skip_nothing` applies to the first input to the function, not both inputs. -map_2_over_storage : Column -> Column -> (Any -> Any -> Text) -> (Integer -> Any) -> Boolean -> Problem_Behavior -> Column -map_2_over_storage input_column_0 input_column_1 function builder skip_nothing=True on_problems=Report_Warning = +map_2_over_storage : Column -> Column -> (Any -> Any -> Text) -> (Integer -> Any) -> Boolean -> Column +map_2_over_storage input_column_0 input_column_1 function builder skip_nothing=True = input_storage_0 = input_column_0.java_column.getStorage input_storage_1 = input_column_1.java_column.getStorage case input_storage_0.size != input_storage_1.size of From 97ab8ecd35ce4251e6a20a7624002d0c13451073 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Tue, 23 May 2023 14:32:26 -0400 Subject: [PATCH 06/40] all but date --- .../Table/0.0.0-dev/src/Data/Column.enso | 23 ++++++++++++------- .../0.0.0-dev/src/Internal/Java_Exports.enso | 5 ++++ .../src/In_Memory/Column_Spec.enso | 6 ++++- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index c79979e1df3b..5dead83b2fef 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -24,7 +24,7 @@ from project.Internal.Column_Format import all from project.Data.Table import print_table from project.Data.Type.Value_Type import Value_Type, Auto from project.Errors import No_Index_Set_Error, Floating_Point_Equality, Invalid_Value_Type, Inexact_Type_Coercion, Conversion_Failure -from project.Internal.Java_Exports import make_string_builder, make_double_builder, make_long_builder +from project.Internal.Java_Exports import make_string_builder, make_double_builder, make_long_builder, make_date_builder polyglot java import org.enso.table.data.column.operation.map.MapOperationProblemBuilder polyglot java import org.enso.table.data.column.storage.Storage as Java_Storage @@ -692,7 +692,7 @@ type Column Rounding to `n` digits can be thought of as "rounding to the nearest multiple of 10^(-n)". For negative decimal counts, this results in rounding to the nearest positive integer power of 10. - round : Integer -> Boolean -> Problem_Behavior -> Column | Illegal_Argument + round : Integer -> Boolean -> Problem_Behavior -> Column | Illegal_Argument | Invalid_Value_Type round self decimal_places=0 use_bankers=False on_problems=Report_Warning = Value_Type.expect_numeric self <| returns_double = decimal_places > 0 builder = if returns_double then make_double_builder else make_long_builder @@ -705,16 +705,23 @@ type Column the fractional part. This is equivalent to "round-toward-zero". Returns a column of `Integer`. - truncate : Column - truncate self = Value_Type.expect_numeric self <| - fun = _.truncate - Column_Ops.map_over_storage self fun make_long_builder skip_nothing=True + truncate : Column ! Invalid_Value_Type + truncate self = + case self.value_type.is_numeric of + True -> + fun = _.truncate + Column_Ops.map_over_storage self fun make_long_builder skip_nothing=True + False -> case self.value_type == Value_Type.Date_Time of + True -> + fun = _.date + Column_Ops.map_over_storage self fun make_date_builder skip_nothing=True + False -> Invalid_Value_Type.Column "Numeric or Date_Time" self.value_type ## Computes the nearest integer above this number for values in numeric column. Returns a column of `Integer`. - ceil : Column + ceil : Column ! Invalid_Value_Type ceil self = Value_Type.expect_numeric self <| fun = _.ceil Column_Ops.map_over_storage self fun make_long_builder skip_nothing=True @@ -723,7 +730,7 @@ type Column column. Returns a column of `Integer`. - floor : Column + floor : Column ! Invalid_Value_Type floor self = Value_Type.expect_numeric self <| fun = _.floor Column_Ops.map_over_storage self fun make_long_builder skip_nothing=True diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Java_Exports.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Java_Exports.enso index 76808aeb9b6f..7c8d925978d7 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Java_Exports.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Java_Exports.enso @@ -9,6 +9,7 @@ polyglot java import org.enso.table.data.table.Table as Java_Table polyglot java import org.enso.table.data.index.DefaultIndex polyglot java import org.enso.table.data.column.storage.Storage polyglot java import org.enso.table.data.column.builder.object.BoolBuilder +polyglot java import org.enso.table.data.column.builder.object.DateBuilder polyglot java import org.enso.table.data.column.builder.object.DateTimeBuilder polyglot java import org.enso.table.data.column.builder.object.InferredBuilder polyglot java import org.enso.table.data.column.builder.object.NumericBuilder @@ -39,6 +40,10 @@ make_time_of_day_builder initial_size = TimeOfDayBuilder.new initial_size make_date_time_builder : Integer -> DateTimeBuilder make_date_time_builder initial_size = DateTimeBuilder.new initial_size +## PRIVATE +make_date_builder : Integer -> DateBuilder +make_date_builder initial_size = DateBuilder.new initial_size + ## PRIVATE make_inferred_builder : Integer -> InferredBuilder make_inferred_builder initial_size = InferredBuilder.new initial_size diff --git a/test/Table_Tests/src/In_Memory/Column_Spec.enso b/test/Table_Tests/src/In_Memory/Column_Spec.enso index 8ef25619fed1..7466e390c379 100644 --- a/test/Table_Tests/src/In_Memory/Column_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Column_Spec.enso @@ -129,7 +129,7 @@ spec = tester = _.should_equal expected Problems.test_problem_handling action problems tester - Test.group "Rounding" <| + Test.group "truncate" <| Test.specify "should be able to truncate a column of decimals" <| Column.from_vector "foo" [1.25, 2.33, 3.57] . truncate . should_equal <| Column.from_vector "foo" [1, 2, 3] @@ -140,3 +140,7 @@ spec = Test.group "floor" <| Test.specify "should be able to take the floor of a column of decimals" <| Column.from_vector "foo" [1.25, 2.33, 3.57] . floor . should_equal <| Column.from_vector "foo" [1, 2, 3] + + Test.group "Date_Time truncate" pending="cannot construct a date column" <| + Test.specify "should be able to truncate a column of Date_Times" <| + Column.from_vector "foo" [Date_Time.new 2020 10 24 1 2 3, Date_Time.new 2020 10 24 1 2 3] . truncate . should_equal <| Column.from_vector "foo" [Date.new 2020 10 24, Date.new 2020 10 24] From 07527b637bf1d76a38994de530b1e0e29b43593b Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Tue, 23 May 2023 14:39:03 -0400 Subject: [PATCH 07/40] examples --- .../Table/0.0.0-dev/src/Data/Column.enso | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index 5dead83b2fef..7abdb3bb50e2 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -692,6 +692,11 @@ type Column Rounding to `n` digits can be thought of as "rounding to the nearest multiple of 10^(-n)". For negative decimal counts, this results in rounding to the nearest positive integer power of 10. + + > Example + Round a column of `Decimal` values`. + + Column.from_vector "foo" [1.2, 2.3, 3.6] . round == (Column.from_vector "foo" [1, 2, 4]) round : Integer -> Boolean -> Problem_Behavior -> Column | Illegal_Argument | Invalid_Value_Type round self decimal_places=0 use_bankers=False on_problems=Report_Warning = Value_Type.expect_numeric self <| returns_double = decimal_places > 0 @@ -704,7 +709,20 @@ type Column Truncate the floating-point values in a column to an integer by dropping the fractional part. This is equivalent to "round-toward-zero". + Truncate the `Date_Time` values in a column to `Date`. + Returns a column of `Integer`. + + > Example + Truncate a column of `Decimal` values. + + Column.from_vector "foo" [1.25, 2.33, 3.57] . truncate == (Column.from_vector "foo" [1, 2, 3]) + + > Example + Truncate a column of `Date_Time` values. + date_times = Column.from_vector "foo" [Date_Time.new 2020 10 24 1 2 3, Date_Time.new 2020 10 24 1 2 3] + dates = Column.from_vector "foo" [Date.new 2020 10 24, Date.new 2020 10 24] + col.truncate == dates truncate : Column ! Invalid_Value_Type truncate self = case self.value_type.is_numeric of @@ -721,6 +739,11 @@ type Column column. Returns a column of `Integer`. + + > Example + Take the ceiling of a column of `Decimal` values. + + Column.from_vector "foo" [1.25, 2.33, 3.57] . ceil == (Column.from_vector "foo" [2, 3, 4]) ceil : Column ! Invalid_Value_Type ceil self = Value_Type.expect_numeric self <| fun = _.ceil @@ -730,6 +753,11 @@ type Column column. Returns a column of `Integer`. + + > Example + Take the floor of a column of `Decimal` values. + + Column.from_vector "foo" [1.25, 2.33, 3.57] . floor == (Column.from_vector "foo" [1, 2, 3]) floor : Column ! Invalid_Value_Type floor self = Value_Type.expect_numeric self <| fun = _.floor From b0ed569094ba89d9eeca90c0f647c94e34b6507c Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Tue, 23 May 2023 14:39:37 -0400 Subject: [PATCH 08/40] cleanup --- test/Table_Tests/src/In_Memory/Column_Spec.enso | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/Table_Tests/src/In_Memory/Column_Spec.enso b/test/Table_Tests/src/In_Memory/Column_Spec.enso index 7466e390c379..5831bc8ca664 100644 --- a/test/Table_Tests/src/In_Memory/Column_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Column_Spec.enso @@ -15,10 +15,6 @@ import Standard.Test.Extensions main = Test_Suite.run_main spec spec = - Test.group "gmt" <| - Test.specify "should report out-of-range values as problems" <| - 1 . should_equal 1 - Test.group "Columns" <| test_column = Column.from_vector "Test" [1, 3, 5, 2, 4, 6] empty_column = Column.from_vector "Test" [] From c3818dc0a57bd98dc1e866688e754ed41cbbc03a Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Tue, 23 May 2023 14:49:47 -0400 Subject: [PATCH 09/40] cleanup --- .../Table/0.0.0-dev/src/Data/Column.enso | 19 +++++++++---------- .../src/In_Memory/Column_Spec.enso | 6 ++---- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index 7abdb3bb50e2..66de435c8b90 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -667,8 +667,9 @@ type Column "round towards positive infinity." If use_bankers=True, then it uses "round-half-even", also known as "banker's rounding". - If `decimal_places` > 0, `round` returns a column of `Decimal`; - otherwise, it returns a column of `Integer`. + If the column is of type `Decimal` and `decimal_places` > 0, `round` + returns a column of `Decimal`; otherwise, it returns a column of + `Integer`. Arguments: - decimal_places: The number of decimal places to round to. Can be @@ -706,12 +707,10 @@ type Column ## ALIAS int - Truncate the floating-point values in a column to an integer by dropping - the fractional part. This is equivalent to "round-toward-zero". - - Truncate the `Date_Time` values in a column to `Date`. - - Returns a column of `Integer`. + If the column is numeric, truncate the floating-point values to an + integer by dropping the fractional part. This is equivalent to + "round-toward-zero". If the column is of type `Date_Time`, truncates the + values to `Date`. > Example Truncate a column of `Decimal` values. @@ -735,7 +734,7 @@ type Column Column_Ops.map_over_storage self fun make_date_builder skip_nothing=True False -> Invalid_Value_Type.Column "Numeric or Date_Time" self.value_type - ## Computes the nearest integer above this number for values in numeric + ## Computes the nearest integer above this number for values in a numeric column. Returns a column of `Integer`. @@ -749,7 +748,7 @@ type Column fun = _.ceil Column_Ops.map_over_storage self fun make_long_builder skip_nothing=True - ## Computes the nearest integer below this number for values in numeric + ## Computes the nearest integer below this number for values in a numeric column. Returns a column of `Integer`. diff --git a/test/Table_Tests/src/In_Memory/Column_Spec.enso b/test/Table_Tests/src/In_Memory/Column_Spec.enso index 5831bc8ca664..c619fa6319b8 100644 --- a/test/Table_Tests/src/In_Memory/Column_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Column_Spec.enso @@ -4,13 +4,11 @@ import project.Util import Standard.Base.Errors.Common.Index_Out_Of_Bounds import Standard.Base.Errors.Illegal_Argument.Illegal_Argument - -from Standard.Table import Column, Value_Type - import Standard.Examples +import Standard.Test.Extensions +from Standard.Table import Column, Value_Type from Standard.Test import Test, Test_Suite, Problems -import Standard.Test.Extensions main = Test_Suite.run_main spec From 35d83a135aeb20ff26ed4e602e3bdca0c862d764 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Wed, 24 May 2023 13:58:41 -0400 Subject: [PATCH 10/40] date_time truncate --- .../Table/0.0.0-dev/src/Data/Column.enso | 24 ++++++++++++++++++- .../0.0.0-dev/src/Internal/Column_Ops.enso | 5 ++-- .../column/builder/object/DateBuilder.java | 2 ++ .../src/In_Memory/Column_Spec.enso | 2 +- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index 66de435c8b90..7ebc577637ec 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -26,6 +26,7 @@ from project.Data.Type.Value_Type import Value_Type, Auto from project.Errors import No_Index_Set_Error, Floating_Point_Equality, Invalid_Value_Type, Inexact_Type_Coercion, Conversion_Failure from project.Internal.Java_Exports import make_string_builder, make_double_builder, make_long_builder, make_date_builder +polyglot java import org.enso.table.data.column.builder.object.DateBuilder polyglot java import org.enso.table.data.column.operation.map.MapOperationProblemBuilder polyglot java import org.enso.table.data.column.storage.Storage as Java_Storage polyglot java import org.enso.table.data.table.Column as Java_Column @@ -731,7 +732,7 @@ type Column False -> case self.value_type == Value_Type.Date_Time of True -> fun = _.date - Column_Ops.map_over_storage self fun make_date_builder skip_nothing=True + Column_Ops.map_over_storage self fun make_date_builder_adapter skip_nothing=True False -> Invalid_Value_Type.Column "Numeric or Date_Time" self.value_type ## Computes the nearest integer above this number for values in a numeric @@ -2014,3 +2015,24 @@ wrap_text_argument_as_value_provider val = col : Column -> storage = col.java_column.getStorage i-> storage.getItemBoxed i + +## PRIVATE + Wrapper around a DateBuilder that uses DateBuilder.appendDate() to append a + value (instead of builder.append()) +type DateBuilderAdapter + Value (date_builder : DateBuilder) + + append : Date -> Nothing + append self date = + IO.println "HII" + IO.println date + self.date_builder.appendDate date + + seal : Java_Storage + seal self = self.date_builder.seal + +## PRIVATE + DateBuilderAdapter constructor that behaves like the builder adapters in + Java_Exports. +make_date_builder_adapter : Integer -> DateBuilderAdapter +make_date_builder_adapter n = DateBuilderAdapter.Value (make_date_builder n) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso index 757cacd787b0..f667ef6d23ed 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso @@ -5,8 +5,6 @@ import Standard.Base.Errors.Illegal_Argument.Illegal_Argument import project.Data.Column.Column import project.Internal.Problem_Builder.Problem_Builder -from project.Internal.Java_Exports import make_string_builder - ## PRIVATE Map a text-returning function over the column values, using Storage directly. The output column has the same name as the input. @@ -22,6 +20,9 @@ map_over_storage input_column function builder skip_nothing=True on_problems=Rep output_value = function input_value . catch Any err-> problem_builder.report_other_warning err Nothing + IO.println "USING" + IO.println output_storage_builder + IO.println output_value output_storage_builder.append output_value output_storage = output_storage_builder.seal new_column = Column.from_storage input_column.name output_storage diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/builder/object/DateBuilder.java b/std-bits/table/src/main/java/org/enso/table/data/column/builder/object/DateBuilder.java index 3c939d908f13..a769af48a97c 100644 --- a/std-bits/table/src/main/java/org/enso/table/data/column/builder/object/DateBuilder.java +++ b/std-bits/table/src/main/java/org/enso/table/data/column/builder/object/DateBuilder.java @@ -28,6 +28,8 @@ public void appendNoGrow(Object o) { data[currentSize++] = (LocalDate) o; } + public void appendDate(LocalDate date) { append(date); } + @Override public boolean accepts(Object o) { return o instanceof LocalDate; diff --git a/test/Table_Tests/src/In_Memory/Column_Spec.enso b/test/Table_Tests/src/In_Memory/Column_Spec.enso index c619fa6319b8..9aab1428b3d8 100644 --- a/test/Table_Tests/src/In_Memory/Column_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Column_Spec.enso @@ -135,6 +135,6 @@ spec = Test.specify "should be able to take the floor of a column of decimals" <| Column.from_vector "foo" [1.25, 2.33, 3.57] . floor . should_equal <| Column.from_vector "foo" [1, 2, 3] - Test.group "Date_Time truncate" pending="cannot construct a date column" <| + Test.group "Date_Time truncate" <| Test.specify "should be able to truncate a column of Date_Times" <| Column.from_vector "foo" [Date_Time.new 2020 10 24 1 2 3, Date_Time.new 2020 10 24 1 2 3] . truncate . should_equal <| Column.from_vector "foo" [Date.new 2020 10 24, Date.new 2020 10 24] From 430090f416a6d344b40002d0c04e64f83e1207a3 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Wed, 24 May 2023 14:03:55 -0400 Subject: [PATCH 11/40] cleanup --- distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso | 2 -- .../lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso | 3 --- 2 files changed, 5 deletions(-) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index 7ebc577637ec..ac0a05c470e4 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -2024,8 +2024,6 @@ type DateBuilderAdapter append : Date -> Nothing append self date = - IO.println "HII" - IO.println date self.date_builder.appendDate date seal : Java_Storage diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso index f667ef6d23ed..43547f7dc8c7 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso @@ -20,9 +20,6 @@ map_over_storage input_column function builder skip_nothing=True on_problems=Rep output_value = function input_value . catch Any err-> problem_builder.report_other_warning err Nothing - IO.println "USING" - IO.println output_storage_builder - IO.println output_value output_storage_builder.append output_value output_storage = output_storage_builder.seal new_column = Column.from_storage input_column.name output_storage From 2db1924b7256206a12e405f212bb690bb7d4341f Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Wed, 24 May 2023 14:40:16 -0400 Subject: [PATCH 12/40] fix format tests --- .../lib/Standard/Table/0.0.0-dev/src/Data/Column.enso | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index ac0a05c470e4..42fae30ac38d 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -1385,14 +1385,14 @@ type Column new_column = case format of "" -> formatter = .to_text - Column_Ops.map_over_storage self formatter make_string_builder + Column_Ops.map_over_storage self formatter make_string_builder on_problems=Problem_Behavior.Report_Error Nothing -> formatter = .to_text - Column_Ops.map_over_storage self formatter make_string_builder + Column_Ops.map_over_storage self formatter make_string_builder on_problems=Problem_Behavior.Report_Error _ : Text -> formatter = create_formatter formatter.if_not_error <| - Column_Ops.map_over_storage self (formatter format=format) make_string_builder + Column_Ops.map_over_storage self (formatter format=format) make_string_builder on_problems=Problem_Behavior.Report_Error format_column : Column -> Value_Type.expect_text format_column <| formatter = create_formatter formatter.if_not_error <| From 8a62af21116da73bd5244a64ee63ee66e62f1313 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Wed, 24 May 2023 14:47:23 -0400 Subject: [PATCH 13/40] check column types --- test/Table_Tests/src/In_Memory/Column_Spec.enso | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/Table_Tests/src/In_Memory/Column_Spec.enso b/test/Table_Tests/src/In_Memory/Column_Spec.enso index 9aab1428b3d8..14aa76477cfc 100644 --- a/test/Table_Tests/src/In_Memory/Column_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Column_Spec.enso @@ -102,11 +102,18 @@ spec = Column.from_vector "foo" [12.0, 24.0, 25.0, 29.0] . round -1 . should_equal <| Column.from_vector "foo" [10, 20, 30, 30] Column.from_vector "foo" [1.5, 2.5, 3.5] . round use_bankers=True . should_equal <| Column.from_vector "foo" [2, 2, 4] + Test.specify "decimal rounding should return the correct column type" <| + Column.from_vector "foo" [1.2, 2.3, 3.6] . round . value_type . should_equal Value_Type.Integer + Column.from_vector "foo" [1.2, 2.3, 3.6] . round 1 . value_type . should_equal Value_Type.Float + Test.specify "should be able to round a column of integers" <| Column.from_vector "foo" [12, 24, 25, 29] . round . should_equal <| Column.from_vector "foo" [12, 24, 25, 29] Column.from_vector "foo" [12, 24, 25, 29] . round -1 . should_equal <| Column.from_vector "foo" [10, 20, 30, 30] Column.from_vector "foo" [15, 25, 35] . round -1 use_bankers=True . should_equal <| Column.from_vector "foo" [20, 20, 40] + Test.specify "integer rounding should return the correct column type" <| + Column.from_vector "foo" [12, 24, 25, 29] . round -1 . value_type . should_equal Value_Type.Integer + Test.specify "should report out-of-range values as problems" <| col = Column.from_vector "foo" [12, 23, 99999999999999999] expected = Column.from_vector "foo" [10, 20, Nothing] @@ -126,15 +133,19 @@ spec = Test.group "truncate" <| Test.specify "should be able to truncate a column of decimals" <| Column.from_vector "foo" [1.25, 2.33, 3.57] . truncate . should_equal <| Column.from_vector "foo" [1, 2, 3] + Column.from_vector "foo" [1.25, 2.33, 3.57] . truncate . value_type . should_equal Value_Type.Integer Test.group "ceil" <| Test.specify "should be able to take the ceil of a column of decimals" <| Column.from_vector "foo" [1.25, 2.33, 3.57] . ceil . should_equal <| Column.from_vector "foo" [2, 3, 4] + Column.from_vector "foo" [1.25, 2.33, 3.57] . ceil . value_type . should_equal Value_Type.Integer Test.group "floor" <| Test.specify "should be able to take the floor of a column of decimals" <| Column.from_vector "foo" [1.25, 2.33, 3.57] . floor . should_equal <| Column.from_vector "foo" [1, 2, 3] + Column.from_vector "foo" [1.25, 2.33, 3.57] . floor . value_type . should_equal Value_Type.Integer Test.group "Date_Time truncate" <| Test.specify "should be able to truncate a column of Date_Times" <| Column.from_vector "foo" [Date_Time.new 2020 10 24 1 2 3, Date_Time.new 2020 10 24 1 2 3] . truncate . should_equal <| Column.from_vector "foo" [Date.new 2020 10 24, Date.new 2020 10 24] + Column.from_vector "foo" [Date_Time.new 2020 10 24 1 2 3, Date_Time.new 2020 10 24 1 2 3] . truncate . value_type . should_equal Value_Type.Date From 759de4df2544f18e260604bea078b4cbfdd4b377 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Wed, 24 May 2023 15:06:16 -0400 Subject: [PATCH 14/40] each_p no --- .../lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso index 43547f7dc8c7..304b2e9c3b33 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Column_Ops.enso @@ -14,7 +14,7 @@ map_over_storage input_column function builder skip_nothing=True on_problems=Rep input_storage = input_column.java_column.getStorage num_input_rows = input_storage.size output_storage_builder = builder num_input_rows - 0.up_to num_input_rows . each_propagate i-> + 0.up_to num_input_rows . each i-> input_value = input_storage.getItemBoxed i if skip_nothing && input_value.is_nothing then output_storage_builder.append Nothing else output_value = function input_value . catch Any err-> From d616cea2a8354c2c521fe5264224e7c73df85ff6 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Wed, 24 May 2023 15:15:07 -0400 Subject: [PATCH 15/40] noop --- .../lib/Standard/Table/0.0.0-dev/src/Data/Column.enso | 10 ++++++---- test/Table_Tests/src/In_Memory/Column_Spec.enso | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index 42fae30ac38d..d88351da430a 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -701,10 +701,12 @@ type Column Column.from_vector "foo" [1.2, 2.3, 3.6] . round == (Column.from_vector "foo" [1, 2, 4]) round : Integer -> Boolean -> Problem_Behavior -> Column | Illegal_Argument | Invalid_Value_Type round self decimal_places=0 use_bankers=False on_problems=Report_Warning = Value_Type.expect_numeric self <| - returns_double = decimal_places > 0 - builder = if returns_double then make_double_builder else make_long_builder - fun = _.round decimal_places use_bankers - Column_Ops.map_over_storage self fun builder skip_nothing=True on_problems=on_problems + # If it's an integer column and decimal_places >=0 then it's a no-op. + if self.value_type.is_integer && decimal_places >= 0 then self else + returns_double = decimal_places > 0 + builder = if returns_double then make_double_builder else make_long_builder + fun = _.round decimal_places use_bankers + Column_Ops.map_over_storage self fun builder skip_nothing=True on_problems=on_problems ## ALIAS int diff --git a/test/Table_Tests/src/In_Memory/Column_Spec.enso b/test/Table_Tests/src/In_Memory/Column_Spec.enso index 14aa76477cfc..c17a2943cfe8 100644 --- a/test/Table_Tests/src/In_Memory/Column_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Column_Spec.enso @@ -125,8 +125,8 @@ spec = Test.specify "should throw an error on decimal places out of range" <| col = Column.from_vector "foo" [12, 23, 99999999999999999] expected = Column.from_vector "foo" [Nothing, Nothing, Nothing] - action = col.round decimal_places=1200 on_problems=_ - problems = [Illegal_Argument.Error "round: decimal_places must be between -15 and 15 (inclusive), but was 1200"] + action = col.round decimal_places=-1200 on_problems=_ + problems = [Illegal_Argument.Error "round: decimal_places must be between -15 and 15 (inclusive), but was -1200"] tester = _.should_equal expected Problems.test_problem_handling action problems tester From b85f5588f3e80402aea935e266c01c01c6b441e7 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Wed, 24 May 2023 15:23:28 -0400 Subject: [PATCH 16/40] changelog, test fix --- CHANGELOG.md | 2 ++ test/Table_Tests/src/In_Memory/Column_Spec.enso | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e8cfe412233..7a4b4db40fc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -460,6 +460,7 @@ - [Added `Date_Range`.][6621] - [Implemented the `cast` operation for `Table` and `Column`.][6711] - [Added `.round` and `.int` to `Integer` and `Decimal`.][6743] +- [Added `.round`, `.truncate`, `.ceil`, and `.floor` to `Column`.][6817] [debug-shortcuts]: https://github.com/enso-org/enso/blob/develop/app/gui/docs/product/shortcuts.md#debug @@ -672,6 +673,7 @@ [6621]: https://github.com/enso-org/enso/pull/6621 [6711]: https://github.com/enso-org/enso/pull/6711 [6743]: https://github.com/enso-org/enso/pull/6743 +[6817]: https://github.com/enso-org/enso/pull/6817 #### Enso Compiler diff --git a/test/Table_Tests/src/In_Memory/Column_Spec.enso b/test/Table_Tests/src/In_Memory/Column_Spec.enso index c17a2943cfe8..5f1994d1a9fc 100644 --- a/test/Table_Tests/src/In_Memory/Column_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Column_Spec.enso @@ -126,7 +126,7 @@ spec = col = Column.from_vector "foo" [12, 23, 99999999999999999] expected = Column.from_vector "foo" [Nothing, Nothing, Nothing] action = col.round decimal_places=-1200 on_problems=_ - problems = [Illegal_Argument.Error "round: decimal_places must be between -15 and 15 (inclusive), but was -1200"] + problems = [Illegal_Argument.Error "round: decimal_places must be between -15 and 15 (inclusive), but was 1200"] tester = _.should_equal expected Problems.test_problem_handling action problems tester From 82ed44372827a10e04c8e7b339419c0d5143983a Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Wed, 24 May 2023 15:27:37 -0400 Subject: [PATCH 17/40] java fmt --- .../enso/table/data/column/builder/object/DateBuilder.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/builder/object/DateBuilder.java b/std-bits/table/src/main/java/org/enso/table/data/column/builder/object/DateBuilder.java index a769af48a97c..3a83f3d47de8 100644 --- a/std-bits/table/src/main/java/org/enso/table/data/column/builder/object/DateBuilder.java +++ b/std-bits/table/src/main/java/org/enso/table/data/column/builder/object/DateBuilder.java @@ -28,7 +28,9 @@ public void appendNoGrow(Object o) { data[currentSize++] = (LocalDate) o; } - public void appendDate(LocalDate date) { append(date); } + public void appendDate(LocalDate date) { + append(date); + } @Override public boolean accepts(Object o) { From 0eeb10eed712e37dd506a35be2b822c819a0df15 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Thu, 25 May 2023 14:53:31 -0400 Subject: [PATCH 18/40] review, throw --- .../lib/Standard/Base/0.0.0-dev/src/Data/Range.enso | 4 ++-- .../lib/Standard/Table/0.0.0-dev/src/Data/Column.enso | 6 +++--- test/Table_Tests/src/In_Memory/Column_Spec.enso | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso index c5ed392529ef..1a7374d37885 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso @@ -203,9 +203,9 @@ type Range ## PRIVATE ADVANCED - Applies a function for each element in the range. Exits early if the body + Executes a function for each element in the range. Exits early if the body produces an `Error`. - each_propagate : (Integer -> Any) -> Nothing ! Error + each_propagate : (Integer -> Nothing) -> Nothing ! Error each_propagate self function = if self.step == 0 then throw_zero_step_error else end_condition = if self.step > 0 then (>=) else (<=) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index d88351da430a..a6e3d23b03bc 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -668,8 +668,8 @@ type Column "round towards positive infinity." If use_bankers=True, then it uses "round-half-even", also known as "banker's rounding". - If the column is of type `Decimal` and `decimal_places` > 0, `round` - returns a column of `Decimal`; otherwise, it returns a column of + If the column is of type `Float` and `decimal_places` > 0, `round` + returns a column of `Float`; otherwise, it returns a column of `Integer`. Arguments: @@ -735,7 +735,7 @@ type Column True -> fun = _.date Column_Ops.map_over_storage self fun make_date_builder_adapter skip_nothing=True - False -> Invalid_Value_Type.Column "Numeric or Date_Time" self.value_type + False -> Error.throw <| Invalid_Value_Type.Column "Numeric or Date_Time" self.value_type ## Computes the nearest integer above this number for values in a numeric column. diff --git a/test/Table_Tests/src/In_Memory/Column_Spec.enso b/test/Table_Tests/src/In_Memory/Column_Spec.enso index 5f1994d1a9fc..c17a2943cfe8 100644 --- a/test/Table_Tests/src/In_Memory/Column_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Column_Spec.enso @@ -126,7 +126,7 @@ spec = col = Column.from_vector "foo" [12, 23, 99999999999999999] expected = Column.from_vector "foo" [Nothing, Nothing, Nothing] action = col.round decimal_places=-1200 on_problems=_ - problems = [Illegal_Argument.Error "round: decimal_places must be between -15 and 15 (inclusive), but was 1200"] + problems = [Illegal_Argument.Error "round: decimal_places must be between -15 and 15 (inclusive), but was -1200"] tester = _.should_equal expected Problems.test_problem_handling action problems tester From e9be9d5c7f2272476b6231d63939942e0f4aeb6c Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Thu, 25 May 2023 14:59:56 -0400 Subject: [PATCH 19/40] move adapter --- .../Table/0.0.0-dev/src/Data/Column.enso | 21 +------------------ .../0.0.0-dev/src/Internal/Java_Exports.enso | 20 ++++++++++++++++++ 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index a6e3d23b03bc..90f761318938 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -24,7 +24,7 @@ from project.Internal.Column_Format import all from project.Data.Table import print_table from project.Data.Type.Value_Type import Value_Type, Auto from project.Errors import No_Index_Set_Error, Floating_Point_Equality, Invalid_Value_Type, Inexact_Type_Coercion, Conversion_Failure -from project.Internal.Java_Exports import make_string_builder, make_double_builder, make_long_builder, make_date_builder +from project.Internal.Java_Exports import make_string_builder, make_double_builder, make_long_builder, make_date_builder_adapter polyglot java import org.enso.table.data.column.builder.object.DateBuilder polyglot java import org.enso.table.data.column.operation.map.MapOperationProblemBuilder @@ -2017,22 +2017,3 @@ wrap_text_argument_as_value_provider val = col : Column -> storage = col.java_column.getStorage i-> storage.getItemBoxed i - -## PRIVATE - Wrapper around a DateBuilder that uses DateBuilder.appendDate() to append a - value (instead of builder.append()) -type DateBuilderAdapter - Value (date_builder : DateBuilder) - - append : Date -> Nothing - append self date = - self.date_builder.appendDate date - - seal : Java_Storage - seal self = self.date_builder.seal - -## PRIVATE - DateBuilderAdapter constructor that behaves like the builder adapters in - Java_Exports. -make_date_builder_adapter : Integer -> DateBuilderAdapter -make_date_builder_adapter n = DateBuilderAdapter.Value (make_date_builder n) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Java_Exports.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Java_Exports.enso index 7c8d925978d7..11ee667008f8 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Java_Exports.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Java_Exports.enso @@ -15,6 +15,7 @@ polyglot java import org.enso.table.data.column.builder.object.InferredBuilder polyglot java import org.enso.table.data.column.builder.object.NumericBuilder polyglot java import org.enso.table.data.column.builder.object.StringBuilder polyglot java import org.enso.table.data.column.builder.object.TimeOfDayBuilder +polyglot java import org.enso.table.data.column.storage.Storage as Java_Storage ## PRIVATE make_bool_builder : BoolBuilder @@ -51,3 +52,22 @@ make_inferred_builder initial_size = InferredBuilder.new initial_size ## PRIVATE make_column : Text -> Storage -> Column make_column name storage = Column.Value (Java_Column.new name storage) + +## PRIVATE + Wrapper around a DateBuilder that uses DateBuilder.appendDate() to append a + value (instead of builder.append()) +type DateBuilderAdapter + Value (date_builder : DateBuilder) + + append : Date -> Nothing + append self date = + self.date_builder.appendDate date + + seal : Java_Storage + seal self = self.date_builder.seal + +## PRIVATE + DateBuilderAdapter constructor that matches the interface of the other + make_*_builder functions. +make_date_builder_adapter : Integer -> DateBuilderAdapter +make_date_builder_adapter n = DateBuilderAdapter.Value (make_date_builder n) From 01f0f65477e4bd35ce253f478e874a46c2aae6f0 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Fri, 26 May 2023 14:31:08 -0400 Subject: [PATCH 20/40] limit round input for float too --- .../Base/0.0.0-dev/src/Data/Numbers.enso | 27 +++++++++++-------- test/Tests/src/Data/Numbers_Spec.enso | 12 +++++++-- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso index b5e9eedbf174..e250d33a7eeb 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso @@ -608,7 +608,7 @@ type Decimal True -> msg = "round cannot accept " + self.to_text Error.throw (Arithmetic_Error.Error msg) - False -> + False -> check_round_input self <| decimal_result = case use_bankers of False -> scale = 10 ^ decimal_places @@ -925,16 +925,11 @@ type Integer 12250 . round -2 use_bankers=True == 12200 round : Integer -> Boolean -> Integer ! Illegal_Argument round self decimal_places=0 use_bankers=False = - check_decimal_places decimal_places <| - case self < round_min_long || self > round_max_long of - True -> - msg = "Error: Integer.round can only accept values between " + round_min_long.to_text + " and " + round_max_long.to_text + " (inclusive), but was " + self.to_text - Error.throw (Illegal_Argument.Error msg) - False -> - ## It's already an integer so unless decimal_places is - negative, the value is unchanged. - if decimal_places >= 0 then self else - self.to_decimal.round decimal_places use_bankers . truncate + check_decimal_places decimal_places <| check_round_input self <| + ## It's already an integer so unless decimal_places is + negative, the value is unchanged. + if decimal_places >= 0 then self else + self.to_decimal.round decimal_places use_bankers . truncate ## Compute the negation of this. @@ -1132,8 +1127,18 @@ round_max_long = 99999999999999 round_min_long : Integer round_min_long = -99999999999999 +## PRIVATE + Restrict rounding decimal_places parameter. check_decimal_places : Integer -> Function check_decimal_places decimal_places ~action = if decimal_places >= round_min_decimal_places && decimal_places <= round_max_decimal_places then action else msg = "round: decimal_places must be between " + round_min_decimal_places.to_text + " and " + round_max_decimal_places.to_text + " (inclusive), but was " + decimal_places.to_text Error.throw (Illegal_Argument.Error msg) + +## PRIVATE + Restrict allowed range of input to rounding methods. +check_round_input : Number -> Function +check_round_input n ~action = + if n >= round_min_long && n <= round_max_long then action else + msg = "Error: Integer.round can only accept values between " + round_min_long.to_text + " and " + round_max_long.to_text + " (inclusive), but was " + n.to_text + Error.throw (Illegal_Argument.Error msg) diff --git a/test/Tests/src/Data/Numbers_Spec.enso b/test/Tests/src/Data/Numbers_Spec.enso index c03cd64f83bd..1ac4c34a1452 100644 --- a/test/Tests/src/Data/Numbers_Spec.enso +++ b/test/Tests/src/Data/Numbers_Spec.enso @@ -585,7 +585,7 @@ spec = 231.2 . round . should_be_a Integer 231.2 . round -1 . should_be_a Integer - Test.specify "Edge cases" <| + Test.specify "Edge cases" pending="Re-enable this if the 15-digit restriction is removed" <| max_double = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0 max_double . should_equal max_double max_double_minus_point_five = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858367.5 @@ -602,6 +602,14 @@ spec = neg_max_double_minus_point_four . round . should_equal neg_max_double neg_max_double_minus_point_five . round . should_equal neg_max_double_minus_one + Test.specify "Input out of range" <| + 100000000000000.0 . round . should_fail_with Illegal_Argument + -100000000000000.0 . round . should_fail_with Illegal_Argument + 100000000000000.0 . round -2 . should_fail_with Illegal_Argument + -100000000000000.0 . round -2 . should_fail_with Illegal_Argument + 99999999999999.0 . round -2 . should_equal 100000000000000 + -99999999999999.0 . round -2 . should_equal -100000000000000 + Test.specify "Decimal places out of range" <| 3.1 . round 16 . should_fail_with Illegal_Argument 3.1 . round -16 . should_fail_with Illegal_Argument @@ -685,7 +693,7 @@ spec = 3 . round 16 . should_fail_with Illegal_Argument 3 . round -16 . should_fail_with Illegal_Argument - Test.specify "Number out of range" <| + Test.specify "Input out of range" <| 100000000000000 . round . should_fail_with Illegal_Argument -100000000000000 . round . should_fail_with Illegal_Argument 100000000000000 . round -2 . should_fail_with Illegal_Argument From 4a4e886138650e993506c0ebac3330b656e87748 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Fri, 26 May 2023 14:42:26 -0400 Subject: [PATCH 21/40] unimplemented stubs --- .../Database/0.0.0-dev/src/Data/Column.enso | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Column.enso index d75e14bd8224..4a32520127d6 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Column.enso @@ -557,6 +557,27 @@ type Column op_result = self.make_op "IIF" [when_true, when_false] new_name adapt_unified_column op_result common_type + ## Rounding values is not supported in database columns. + round : Integer -> Boolean -> Problem_Behavior -> Column | Illegal_Argument | Invalid_Value_Type + round self decimal_places=0 use_bankers=False on_problems=Report_Warning = + _ = [decimal_places, use_bankers, on_problems] + Error.throw <| Unsupported_Database_Operation.Error "`Column.round` is not implemented yet for the Database backends." + + ## Truncating values is not supported in database columns. + truncate : Column ! Invalid_Value_Type + truncate self = + Error.throw <| Unsupported_Database_Operation.Error "`Column.truncate` is not implemented yet for the Database backends." + + ## Taking the ceiling of values is not supported in database columns. + ceil : Column ! Invalid_Value_Type + ceil self = + Error.throw <| Unsupported_Database_Operation.Error "`Column.ceil` is not implemented yet for the Database backends." + + ## Taking the floor of values is not supported in database columns. + floor : Column ! Invalid_Value_Type + floor self = + Error.throw <| Unsupported_Database_Operation.Error "`Column.floor` is not implemented yet for the Database backends." + ## Returns a column of first non-`Nothing` value on each row of `self` and `values` list. From ac93d31958396feba888d3ae31f082ef3d2375ae Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Tue, 30 May 2023 14:08:08 -0400 Subject: [PATCH 22/40] generalize error --- distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso index e250d33a7eeb..f9e60b11a194 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso @@ -1140,5 +1140,5 @@ check_decimal_places decimal_places ~action = check_round_input : Number -> Function check_round_input n ~action = if n >= round_min_long && n <= round_max_long then action else - msg = "Error: Integer.round can only accept values between " + round_min_long.to_text + " and " + round_max_long.to_text + " (inclusive), but was " + n.to_text + msg = "Error: `round` can only accept values between " + round_min_long.to_text + " and " + round_max_long.to_text + " (inclusive), but was " + n.to_text Error.throw (Illegal_Argument.Error msg) From ea1fd0b50f147d0ea9a617e16ccaf29b225e8a59 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Wed, 31 May 2023 12:23:37 -0400 Subject: [PATCH 23/40] remove big num test --- test/Tests/src/Data/Numbers_Spec.enso | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/test/Tests/src/Data/Numbers_Spec.enso b/test/Tests/src/Data/Numbers_Spec.enso index 1ac4c34a1452..09eac34a8d7e 100644 --- a/test/Tests/src/Data/Numbers_Spec.enso +++ b/test/Tests/src/Data/Numbers_Spec.enso @@ -585,23 +585,6 @@ spec = 231.2 . round . should_be_a Integer 231.2 . round -1 . should_be_a Integer - Test.specify "Edge cases" pending="Re-enable this if the 15-digit restriction is removed" <| - max_double = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0 - max_double . should_equal max_double - max_double_minus_point_five = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858367.5 - max_double_minus_point_six = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858367.4 - max_double_minus_one = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858367.0 - max_double_minus_point_five . round . should_equal max_double - max_double_minus_point_six . round . should_equal max_double_minus_one - - neg_max_double = -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0 - neg_max_double . should_equal neg_max_double - neg_max_double_minus_point_four = -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858367.6 - neg_max_double_minus_point_five = -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858367.5 - neg_max_double_minus_one = -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858367.0 - neg_max_double_minus_point_four . round . should_equal neg_max_double - neg_max_double_minus_point_five . round . should_equal neg_max_double_minus_one - Test.specify "Input out of range" <| 100000000000000.0 . round . should_fail_with Illegal_Argument -100000000000000.0 . round . should_fail_with Illegal_Argument From 2fab69b45588e1443b1741a1f84afeab029cbb32 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Thu, 1 Jun 2023 12:04:09 -0400 Subject: [PATCH 24/40] fix test --- test/Table_Tests/src/In_Memory/Column_Spec.enso | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Table_Tests/src/In_Memory/Column_Spec.enso b/test/Table_Tests/src/In_Memory/Column_Spec.enso index c17a2943cfe8..66624dda10ca 100644 --- a/test/Table_Tests/src/In_Memory/Column_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Column_Spec.enso @@ -118,7 +118,7 @@ spec = col = Column.from_vector "foo" [12, 23, 99999999999999999] expected = Column.from_vector "foo" [10, 20, Nothing] action = col.round -1 on_problems=_ - problems = [Illegal_Argument.Error "Error: Integer.round can only accept values between -99999999999999 and 99999999999999 (inclusive), but was 99999999999999999"] + problems = [Illegal_Argument.Error "Error: `round` can only accept values between -99999999999999 and 99999999999999 (inclusive), but was 99999999999999999"] tester = _.should_equal expected Problems.test_problem_handling action problems tester From 7d2380c3d89013fd9b639f8ab591c528893f7ef6 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Thu, 1 Jun 2023 14:35:40 -0400 Subject: [PATCH 25/40] 1 test --- .../lib/Standard/Table/0.0.0-dev/src/Data/Column.enso | 3 +-- .../org/enso/table/data/column/storage/DoubleStorage.java | 8 ++++++++ .../java/org/enso/table/data/column/storage/Storage.java | 1 + test/Table_Tests/src/In_Memory/Column_Spec.enso | 5 +++++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index a214e821e733..142c92f60ad7 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -729,8 +729,7 @@ type Column truncate self = case self.value_type.is_numeric of True -> - fun = _.truncate - Column_Ops.map_over_storage self fun make_long_builder skip_nothing=True + simple_unary_op self "truncate" False -> case self.value_type == Value_Type.Date_Time of True -> fun = _.date diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/storage/DoubleStorage.java b/std-bits/table/src/main/java/org/enso/table/data/column/storage/DoubleStorage.java index 1e25446f7e76..e3bf071afeb8 100644 --- a/std-bits/table/src/main/java/org/enso/table/data/column/storage/DoubleStorage.java +++ b/std-bits/table/src/main/java/org/enso/table/data/column/storage/DoubleStorage.java @@ -8,6 +8,7 @@ import org.enso.table.data.column.operation.map.numeric.DoubleBooleanOp; import org.enso.table.data.column.operation.map.numeric.DoubleIsInOp; import org.enso.table.data.column.operation.map.numeric.DoubleNumericOp; +import org.enso.table.data.column.operation.map.UnaryIntegerOp; import org.enso.table.data.column.storage.type.FloatType; import org.enso.table.data.column.storage.type.StorageType; import org.enso.table.data.index.Index; @@ -242,6 +243,13 @@ protected double doDouble( return Math.pow(a, b); } }) + .add( + new UnaryIntegerOp<>(Maps.TRUNCATE) { + @Override + protected long doOperation(Double a) { + return (long) a.doubleValue(); + } + }) .add( new DoubleBooleanOp(Maps.LT) { @Override diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/storage/Storage.java b/std-bits/table/src/main/java/org/enso/table/data/column/storage/Storage.java index 1e173a1528ad..beeeab590c64 100644 --- a/std-bits/table/src/main/java/org/enso/table/data/column/storage/Storage.java +++ b/std-bits/table/src/main/java/org/enso/table/data/column/storage/Storage.java @@ -58,6 +58,7 @@ public static final class Maps { public static final String DIV = "/"; public static final String MOD = "%"; public static final String POWER = "^"; + public static final String TRUNCATE = "truncate"; public static final String NOT = "not"; public static final String AND = "&&"; public static final String OR = "||"; diff --git a/test/Table_Tests/src/In_Memory/Column_Spec.enso b/test/Table_Tests/src/In_Memory/Column_Spec.enso index 66624dda10ca..38f431aa259b 100644 --- a/test/Table_Tests/src/In_Memory/Column_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Column_Spec.enso @@ -13,6 +13,11 @@ from Standard.Test import Test, Test_Suite, Problems main = Test_Suite.run_main spec spec = + Test.group "gmt" <| + Test.specify "should be able to truncate a column of decimals" <| + Column.from_vector "foo" [1.25, 2.33, 3.57] . truncate . should_equal <| Column.from_vector "truncate([foo])" [1, 2, 3] + Column.from_vector "foo" [1.25, 2.33, 3.57] . truncate . value_type . should_equal Value_Type.Integer + Test.group "Columns" <| test_column = Column.from_vector "Test" [1, 3, 5, 2, 4, 6] empty_column = Column.from_vector "Test" [] From af6c6cf7e41ac7ee7b99a02a698d6d4b88e63f9e Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Thu, 1 Jun 2023 16:58:58 -0400 Subject: [PATCH 26/40] int tests --- .../src/In_Memory/Column_Spec.enso | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/test/Table_Tests/src/In_Memory/Column_Spec.enso b/test/Table_Tests/src/In_Memory/Column_Spec.enso index 38f431aa259b..2265c9e9d297 100644 --- a/test/Table_Tests/src/In_Memory/Column_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Column_Spec.enso @@ -136,20 +136,32 @@ spec = Problems.test_problem_handling action problems tester Test.group "truncate" <| - Test.specify "should be able to truncate a column of decimals" <| - Column.from_vector "foo" [1.25, 2.33, 3.57] . truncate . should_equal <| Column.from_vector "foo" [1, 2, 3] + Test.specify "should be able to truncate a column of floats" <| + Column.from_vector "foo" [1.25, 2.33, 3.57] . truncate . should_equal <| Column.from_vector "truncate([foo])" [1, 2, 3] Column.from_vector "foo" [1.25, 2.33, 3.57] . truncate . value_type . should_equal Value_Type.Integer + Test.specify "should also work on ints" <| + Column.from_vector "foo" [1, 2, 3] . truncate . should_equal <| Column.from_vector "truncate([foo])" [1, 2, 3] + Column.from_vector "foo" [1, 2, 3] . truncate . value_type . should_equal Value_Type.Integer + Test.group "ceil" <| - Test.specify "should be able to take the ceil of a column of decimals" <| + Test.specify "should be able to take the ceil of a column of floats" <| Column.from_vector "foo" [1.25, 2.33, 3.57] . ceil . should_equal <| Column.from_vector "foo" [2, 3, 4] Column.from_vector "foo" [1.25, 2.33, 3.57] . ceil . value_type . should_equal Value_Type.Integer + Test.specify "should also work on ints" <| + Column.from_vector "foo" [1, 2, 3] . ceil . should_equal <| Column.from_vector "foo" [1, 2, 3] + Column.from_vector "foo" [1, 2, 3] . ceil . value_type . should_equal Value_Type.Integer + Test.group "floor" <| - Test.specify "should be able to take the floor of a column of decimals" <| + Test.specify "should be able to take the floor of a column of floats" <| Column.from_vector "foo" [1.25, 2.33, 3.57] . floor . should_equal <| Column.from_vector "foo" [1, 2, 3] Column.from_vector "foo" [1.25, 2.33, 3.57] . floor . value_type . should_equal Value_Type.Integer + Test.specify "should also work on ints" <| + Column.from_vector "foo" [1, 2, 3] . floor . should_equal <| Column.from_vector "foo" [1, 2, 3] + Column.from_vector "foo" [1, 2, 3] . floor . value_type . should_equal Value_Type.Integer + Test.group "Date_Time truncate" <| Test.specify "should be able to truncate a column of Date_Times" <| Column.from_vector "foo" [Date_Time.new 2020 10 24 1 2 3, Date_Time.new 2020 10 24 1 2 3] . truncate . should_equal <| Column.from_vector "foo" [Date.new 2020 10 24, Date.new 2020 10 24] From 1a2afbce95660805e5ef3cdf3329b418c9555922 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Thu, 1 Jun 2023 17:03:45 -0400 Subject: [PATCH 27/40] int.trunc --- .../org/enso/table/data/column/storage/LongStorage.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/storage/LongStorage.java b/std-bits/table/src/main/java/org/enso/table/data/column/storage/LongStorage.java index 9b99e4a78ba5..2ffc011c85b7 100644 --- a/std-bits/table/src/main/java/org/enso/table/data/column/storage/LongStorage.java +++ b/std-bits/table/src/main/java/org/enso/table/data/column/storage/LongStorage.java @@ -9,6 +9,7 @@ import org.enso.table.data.column.operation.map.numeric.LongBooleanOp; import org.enso.table.data.column.operation.map.numeric.LongIsInOp; import org.enso.table.data.column.operation.map.numeric.LongNumericOp; +import org.enso.table.data.column.operation.map.UnaryIntegerOp; import org.enso.table.data.column.storage.type.IntegerType; import org.enso.table.data.column.storage.type.StorageType; import org.enso.table.data.index.Index; @@ -289,6 +290,13 @@ public Long doLong( "Internal error: Power operation should cast to double."); } }) + .add( + new UnaryIntegerOp<>(Maps.TRUNCATE) { + @Override + protected long doOperation(Long a) { + return a.longValue(); + } + }) .add( new LongNumericOp(Maps.DIV, true) { @Override From 49b17196b8621577bf0f8ba67b31d765d4e3c12b Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Thu, 1 Jun 2023 17:11:45 -0400 Subject: [PATCH 28/40] ceil and floor --- .../Table/0.0.0-dev/src/Data/Column.enso | 6 ++--- .../data/column/storage/DoubleStorage.java | 14 ++++++++++ .../data/column/storage/LongStorage.java | 26 ++++++++++++++----- .../table/data/column/storage/Storage.java | 2 ++ .../src/In_Memory/Column_Spec.enso | 8 +++--- 5 files changed, 42 insertions(+), 14 deletions(-) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index 142c92f60ad7..f7bcd69b0987 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -747,8 +747,7 @@ type Column Column.from_vector "foo" [1.25, 2.33, 3.57] . ceil == (Column.from_vector "foo" [2, 3, 4]) ceil : Column ! Invalid_Value_Type ceil self = Value_Type.expect_numeric self <| - fun = _.ceil - Column_Ops.map_over_storage self fun make_long_builder skip_nothing=True + simple_unary_op self "ceil" ## Computes the nearest integer below this number for values in a numeric column. @@ -761,8 +760,7 @@ type Column Column.from_vector "foo" [1.25, 2.33, 3.57] . floor == (Column.from_vector "foo" [1, 2, 3]) floor : Column ! Invalid_Value_Type floor self = Value_Type.expect_numeric self <| - fun = _.floor - Column_Ops.map_over_storage self fun make_long_builder skip_nothing=True + simple_unary_op self "floor" ## Returns a column of first non-`Nothing` value on each row of `self` and `values` list. diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/storage/DoubleStorage.java b/std-bits/table/src/main/java/org/enso/table/data/column/storage/DoubleStorage.java index e3bf071afeb8..ef2820817b84 100644 --- a/std-bits/table/src/main/java/org/enso/table/data/column/storage/DoubleStorage.java +++ b/std-bits/table/src/main/java/org/enso/table/data/column/storage/DoubleStorage.java @@ -250,6 +250,20 @@ protected long doOperation(Double a) { return (long) a.doubleValue(); } }) + .add( + new UnaryIntegerOp<>(Maps.CEIL) { + @Override + protected long doOperation(Double a) { + return (long) Math.ceil(a); + } + }) + .add( + new UnaryIntegerOp<>(Maps.FLOOR) { + @Override + protected long doOperation(Double a) { + return (long) Math.floor(a); + } + }) .add( new DoubleBooleanOp(Maps.LT) { @Override diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/storage/LongStorage.java b/std-bits/table/src/main/java/org/enso/table/data/column/storage/LongStorage.java index 2ffc011c85b7..d40227643474 100644 --- a/std-bits/table/src/main/java/org/enso/table/data/column/storage/LongStorage.java +++ b/std-bits/table/src/main/java/org/enso/table/data/column/storage/LongStorage.java @@ -291,12 +291,26 @@ public Long doLong( } }) .add( - new UnaryIntegerOp<>(Maps.TRUNCATE) { - @Override - protected long doOperation(Long a) { - return a.longValue(); - } - }) + new UnaryIntegerOp<>(Maps.TRUNCATE) { + @Override + protected long doOperation(Long a) { + return a.longValue(); + } + }) + .add( + new UnaryIntegerOp<>(Maps.CEIL) { + @Override + protected long doOperation(Long a) { + return a.longValue(); + } + }) + .add( + new UnaryIntegerOp<>(Maps.FLOOR) { + @Override + protected long doOperation(Long a) { + return a.longValue(); + } + }) .add( new LongNumericOp(Maps.DIV, true) { @Override diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/storage/Storage.java b/std-bits/table/src/main/java/org/enso/table/data/column/storage/Storage.java index beeeab590c64..2804091ca1bf 100644 --- a/std-bits/table/src/main/java/org/enso/table/data/column/storage/Storage.java +++ b/std-bits/table/src/main/java/org/enso/table/data/column/storage/Storage.java @@ -59,6 +59,8 @@ public static final class Maps { public static final String MOD = "%"; public static final String POWER = "^"; public static final String TRUNCATE = "truncate"; + public static final String CEIL = "ceil"; + public static final String FLOOR = "floor"; public static final String NOT = "not"; public static final String AND = "&&"; public static final String OR = "||"; diff --git a/test/Table_Tests/src/In_Memory/Column_Spec.enso b/test/Table_Tests/src/In_Memory/Column_Spec.enso index 2265c9e9d297..23ea4a0a8c9e 100644 --- a/test/Table_Tests/src/In_Memory/Column_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Column_Spec.enso @@ -146,20 +146,20 @@ spec = Test.group "ceil" <| Test.specify "should be able to take the ceil of a column of floats" <| - Column.from_vector "foo" [1.25, 2.33, 3.57] . ceil . should_equal <| Column.from_vector "foo" [2, 3, 4] + Column.from_vector "foo" [1.25, 2.33, 3.57] . ceil . should_equal <| Column.from_vector "ceil([foo])" [2, 3, 4] Column.from_vector "foo" [1.25, 2.33, 3.57] . ceil . value_type . should_equal Value_Type.Integer Test.specify "should also work on ints" <| - Column.from_vector "foo" [1, 2, 3] . ceil . should_equal <| Column.from_vector "foo" [1, 2, 3] + Column.from_vector "foo" [1, 2, 3] . ceil . should_equal <| Column.from_vector "ceil([foo])" [1, 2, 3] Column.from_vector "foo" [1, 2, 3] . ceil . value_type . should_equal Value_Type.Integer Test.group "floor" <| Test.specify "should be able to take the floor of a column of floats" <| - Column.from_vector "foo" [1.25, 2.33, 3.57] . floor . should_equal <| Column.from_vector "foo" [1, 2, 3] + Column.from_vector "foo" [1.25, 2.33, 3.57] . floor . should_equal <| Column.from_vector "floor([foo])" [1, 2, 3] Column.from_vector "foo" [1.25, 2.33, 3.57] . floor . value_type . should_equal Value_Type.Integer Test.specify "should also work on ints" <| - Column.from_vector "foo" [1, 2, 3] . floor . should_equal <| Column.from_vector "foo" [1, 2, 3] + Column.from_vector "foo" [1, 2, 3] . floor . should_equal <| Column.from_vector "floor([foo])" [1, 2, 3] Column.from_vector "foo" [1, 2, 3] . floor . value_type . should_equal Value_Type.Integer Test.group "Date_Time truncate" <| From e5545bfc6ad30070a01a9054e429f4ed23d46caf Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Thu, 1 Jun 2023 17:22:05 -0400 Subject: [PATCH 29/40] err tests, but failing --- test/Table_Tests/src/In_Memory/Column_Spec.enso | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/Table_Tests/src/In_Memory/Column_Spec.enso b/test/Table_Tests/src/In_Memory/Column_Spec.enso index 23ea4a0a8c9e..713187e0f0c9 100644 --- a/test/Table_Tests/src/In_Memory/Column_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Column_Spec.enso @@ -8,6 +8,7 @@ import Standard.Examples import Standard.Test.Extensions from Standard.Table import Column, Value_Type +from Standard.Table.Errors import Invalid_Value_Type from Standard.Test import Test, Test_Suite, Problems main = Test_Suite.run_main spec @@ -144,6 +145,9 @@ spec = Column.from_vector "foo" [1, 2, 3] . truncate . should_equal <| Column.from_vector "truncate([foo])" [1, 2, 3] Column.from_vector "foo" [1, 2, 3] . truncate . value_type . should_equal Value_Type.Integer + Test.specify "Should error on input of the wrong type" <| + Column.from_vector "foo" ["asdf", "zxcv", "qwer"] . truncate . should_fail_with Invalid_Value_Type + Test.group "ceil" <| Test.specify "should be able to take the ceil of a column of floats" <| Column.from_vector "foo" [1.25, 2.33, 3.57] . ceil . should_equal <| Column.from_vector "ceil([foo])" [2, 3, 4] @@ -153,6 +157,9 @@ spec = Column.from_vector "foo" [1, 2, 3] . ceil . should_equal <| Column.from_vector "ceil([foo])" [1, 2, 3] Column.from_vector "foo" [1, 2, 3] . ceil . value_type . should_equal Value_Type.Integer + Test.specify "Should error on input of the wrong type" <| + Column.from_vector "foo" ["asdf", "zxcv", "qwer"] . ceil . should_fail_with Invalid_Value_Type + Test.group "floor" <| Test.specify "should be able to take the floor of a column of floats" <| Column.from_vector "foo" [1.25, 2.33, 3.57] . floor . should_equal <| Column.from_vector "floor([foo])" [1, 2, 3] @@ -162,6 +169,9 @@ spec = Column.from_vector "foo" [1, 2, 3] . floor . should_equal <| Column.from_vector "floor([foo])" [1, 2, 3] Column.from_vector "foo" [1, 2, 3] . floor . value_type . should_equal Value_Type.Integer + Test.specify "Should error on input of the wrong type" <| + Column.from_vector "foo" ["asdf", "zxcv", "qwer"] . floor . should_fail_with Invalid_Value_Type + Test.group "Date_Time truncate" <| Test.specify "should be able to truncate a column of Date_Times" <| Column.from_vector "foo" [Date_Time.new 2020 10 24 1 2 3, Date_Time.new 2020 10 24 1 2 3] . truncate . should_equal <| Column.from_vector "foo" [Date.new 2020 10 24, Date.new 2020 10 24] From 6b7ecff672a1d446cb39dee762bd05f9e852390c Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Fri, 2 Jun 2023 12:35:23 -0400 Subject: [PATCH 30/40] fix type error test --- distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index f7bcd69b0987..c905db1ba1a7 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -734,7 +734,7 @@ type Column True -> fun = _.date Column_Ops.map_over_storage self fun make_date_builder_adapter skip_nothing=True - False -> Error.throw <| Invalid_Value_Type.Column "Numeric or Date_Time" self.value_type + False -> Error.throw <| Invalid_Value_Type.Column "Numeric or Date_Time" self.value_type self.name ## Computes the nearest integer above this number for values in a numeric column. From da57912cefce1fbd3d1adbcce2894e963b7f528f Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Fri, 2 Jun 2023 14:32:26 -0400 Subject: [PATCH 31/40] one --- .../Standard/Test/0.0.0-dev/src/Bench.enso | 4 +- test/Benchmarks/src/Column_Numeric.enso | 37 +++++++++++++++++++ test/Benchmarks/src/Main.enso | 1 + 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 test/Benchmarks/src/Column_Numeric.enso diff --git a/distribution/lib/Standard/Test/0.0.0-dev/src/Bench.enso b/distribution/lib/Standard/Test/0.0.0-dev/src/Bench.enso index 880e85573796..63b078898e56 100644 --- a/distribution/lib/Standard/Test/0.0.0-dev/src/Bench.enso +++ b/distribution/lib/Standard/Test/0.0.0-dev/src/Bench.enso @@ -32,7 +32,7 @@ type Bench act_it_num = num_iters - it_num res = times it_size single_call avg = avg_list res - fmt = (avg / 1000000).format "%.2f" + fmt = (avg / 1000000).format "#.##" result.put (result.get + avg) case dry_run of False -> @@ -41,7 +41,7 @@ type Bench IO.println (label + "/dry-run: " + fmt) if dry_run then times 1 (iteration 1) else times num_iters (iteration iter_size) - fmt_avg = (result.get / (1000000*num_iters)).format "%.2f" + fmt_avg = (result.get / (1000000*num_iters)).format "#.##" IO.println (label + " average: " + fmt_avg + "ms") ## PRIVATE diff --git a/test/Benchmarks/src/Column_Numeric.enso b/test/Benchmarks/src/Column_Numeric.enso new file mode 100644 index 000000000000..eeedee554149 --- /dev/null +++ b/test/Benchmarks/src/Column_Numeric.enso @@ -0,0 +1,37 @@ +from Standard.Base import all + +from Standard.Table import Column +from Standard.Test import Bench, Faker + +## Bench Utilities ============================================================ + +vector_size = 1000000 +iter_size = 100 +num_iterations = 10 + +# The Benchmarks ============================================================== + +bench = + ## No specific significance to this constant, just fixed to make generated set deterministic + fixed_random_seed = 1644575867 + faker = Faker.new fixed_random_seed + + IO.println <| "Creating floats" + floats_vec = Vector.new vector_size _->(faker.decimal -1000000000 1000000000) + floats = Column.from_vector "floats" floats_vec + + IO.println <| "Truncating floats" + Bench.measure floats.truncate "Column.truncate floats" iter_size num_iterations + + ## + IO.println <| "Creating decimal strings" + decimal_strings = Vector.new vector_size _->(faker.decimal -1000000000 1000000000).to_text + IO.println <| "Benchmarking Decimal.parse" + Bench.measure (decimal_strings.map Decimal.parse) "Decimal.parse" iter_size num_iterations + + IO.println <| "Creating integer strings" + int_strings = Vector.new vector_size _->(faker.integer -1000000000 1000000000).to_text + IO.println <| "Benchmarking Integer.parse" + Bench.measure (int_strings.map Integer.parse) "Integer.parse" iter_size num_iterations + +main = bench diff --git a/test/Benchmarks/src/Main.enso b/test/Benchmarks/src/Main.enso index 6f622cdc19e8..401d2d08b2cb 100644 --- a/test/Benchmarks/src/Main.enso +++ b/test/Benchmarks/src/Main.enso @@ -16,6 +16,7 @@ import project.Vector not breaking them. main = Collections.bench + Column_Numeric.bench Equality.bench Json_Bench.bench Natural_Order_Sort.bench From 52a542163c45b5e7bc076877774a05776d24e279 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Fri, 2 Jun 2023 14:35:31 -0400 Subject: [PATCH 32/40] all --- test/Benchmarks/src/Column_Numeric.enso | 28 ++++++++++++++----------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/test/Benchmarks/src/Column_Numeric.enso b/test/Benchmarks/src/Column_Numeric.enso index eeedee554149..d1c4ce6ff2a2 100644 --- a/test/Benchmarks/src/Column_Numeric.enso +++ b/test/Benchmarks/src/Column_Numeric.enso @@ -20,18 +20,22 @@ bench = floats_vec = Vector.new vector_size _->(faker.decimal -1000000000 1000000000) floats = Column.from_vector "floats" floats_vec - IO.println <| "Truncating floats" - Bench.measure floats.truncate "Column.truncate floats" iter_size num_iterations - - ## - IO.println <| "Creating decimal strings" - decimal_strings = Vector.new vector_size _->(faker.decimal -1000000000 1000000000).to_text - IO.println <| "Benchmarking Decimal.parse" - Bench.measure (decimal_strings.map Decimal.parse) "Decimal.parse" iter_size num_iterations + IO.println <| "Creating integers" + ints_vec = Vector.new vector_size _->(faker.integer -1000000000 1000000000) + ints = Column.from_vector "ints" ints_vec - IO.println <| "Creating integer strings" - int_strings = Vector.new vector_size _->(faker.integer -1000000000 1000000000).to_text - IO.println <| "Benchmarking Integer.parse" - Bench.measure (int_strings.map Integer.parse) "Integer.parse" iter_size num_iterations + IO.println <| ".truncate floats" + Bench.measure floats.truncate "Column.truncate floats" iter_size num_iterations + IO.println <| ".ceil floats" + Bench.measure floats.ceil "Column.ceil floats" iter_size num_iterations + IO.println <| ".floor floats" + Bench.measure floats.floor "Column.floor floats" iter_size num_iterations + + IO.println <| ".truncate ints" + Bench.measure ints.truncate "Column.truncate ints" iter_size num_iterations + IO.println <| ".ceil ints" + Bench.measure ints.ceil "Column.ceil ints" iter_size num_iterations + IO.println <| ".floor ints" + Bench.measure ints.floor "Column.floor ints" iter_size num_iterations main = bench From 29631cbf719e30b57f814382692a7f0f40dc0957 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Fri, 2 Jun 2023 14:50:05 -0400 Subject: [PATCH 33/40] fmt --- .../data/column/storage/DoubleStorage.java | 36 +++++++++---------- .../data/column/storage/LongStorage.java | 36 +++++++++---------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/storage/DoubleStorage.java b/std-bits/table/src/main/java/org/enso/table/data/column/storage/DoubleStorage.java index ef2820817b84..5943d2ec4713 100644 --- a/std-bits/table/src/main/java/org/enso/table/data/column/storage/DoubleStorage.java +++ b/std-bits/table/src/main/java/org/enso/table/data/column/storage/DoubleStorage.java @@ -244,26 +244,26 @@ protected double doDouble( } }) .add( - new UnaryIntegerOp<>(Maps.TRUNCATE) { - @Override - protected long doOperation(Double a) { - return (long) a.doubleValue(); - } - }) + new UnaryIntegerOp<>(Maps.TRUNCATE) { + @Override + protected long doOperation(Double a) { + return (long) a.doubleValue(); + } + }) .add( - new UnaryIntegerOp<>(Maps.CEIL) { - @Override - protected long doOperation(Double a) { - return (long) Math.ceil(a); - } - }) + new UnaryIntegerOp<>(Maps.CEIL) { + @Override + protected long doOperation(Double a) { + return (long) Math.ceil(a); + } + }) .add( - new UnaryIntegerOp<>(Maps.FLOOR) { - @Override - protected long doOperation(Double a) { - return (long) Math.floor(a); - } - }) + new UnaryIntegerOp<>(Maps.FLOOR) { + @Override + protected long doOperation(Double a) { + return (long) Math.floor(a); + } + }) .add( new DoubleBooleanOp(Maps.LT) { @Override diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/storage/LongStorage.java b/std-bits/table/src/main/java/org/enso/table/data/column/storage/LongStorage.java index d40227643474..2bb4f211a933 100644 --- a/std-bits/table/src/main/java/org/enso/table/data/column/storage/LongStorage.java +++ b/std-bits/table/src/main/java/org/enso/table/data/column/storage/LongStorage.java @@ -291,26 +291,26 @@ public Long doLong( } }) .add( - new UnaryIntegerOp<>(Maps.TRUNCATE) { - @Override - protected long doOperation(Long a) { - return a.longValue(); - } - }) + new UnaryIntegerOp<>(Maps.TRUNCATE) { + @Override + protected long doOperation(Long a) { + return a.longValue(); + } + }) .add( - new UnaryIntegerOp<>(Maps.CEIL) { - @Override - protected long doOperation(Long a) { - return a.longValue(); - } - }) + new UnaryIntegerOp<>(Maps.CEIL) { + @Override + protected long doOperation(Long a) { + return a.longValue(); + } + }) .add( - new UnaryIntegerOp<>(Maps.FLOOR) { - @Override - protected long doOperation(Long a) { - return a.longValue(); - } - }) + new UnaryIntegerOp<>(Maps.FLOOR) { + @Override + protected long doOperation(Long a) { + return a.longValue(); + } + }) .add( new LongNumericOp(Maps.DIV, true) { @Override From 0e858abc78c00ab2e7207dff8515e7255ce9cbea Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Fri, 2 Jun 2023 14:50:44 -0400 Subject: [PATCH 34/40] cleanup --- test/Table_Tests/src/In_Memory/Column_Spec.enso | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/Table_Tests/src/In_Memory/Column_Spec.enso b/test/Table_Tests/src/In_Memory/Column_Spec.enso index 713187e0f0c9..f2b2eeeeba94 100644 --- a/test/Table_Tests/src/In_Memory/Column_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Column_Spec.enso @@ -14,11 +14,6 @@ from Standard.Test import Test, Test_Suite, Problems main = Test_Suite.run_main spec spec = - Test.group "gmt" <| - Test.specify "should be able to truncate a column of decimals" <| - Column.from_vector "foo" [1.25, 2.33, 3.57] . truncate . should_equal <| Column.from_vector "truncate([foo])" [1, 2, 3] - Column.from_vector "foo" [1.25, 2.33, 3.57] . truncate . value_type . should_equal Value_Type.Integer - Test.group "Columns" <| test_column = Column.from_vector "Test" [1, 3, 5, 2, 4, 6] empty_column = Column.from_vector "Test" [] From bf21ddcdba8200a5c565ecfd5c6c2d0bb37d3623 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Fri, 2 Jun 2023 14:55:20 -0400 Subject: [PATCH 35/40] changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 862d1a96c44a..2d8b485ad0e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -471,6 +471,7 @@ - [Implemented the `cast` operation for `Table` and `Column`.][6711] - [Added `.round` and `.int` to `Integer` and `Decimal`.][6743] - [Added `.round`, `.truncate`, `.ceil`, and `.floor` to `Column`.][6817] +- [Speed improvements to `Column` `.truncate`, `.ceil`, and `.floor`.][6941] [debug-shortcuts]: https://github.com/enso-org/enso/blob/develop/app/gui/docs/product/shortcuts.md#debug @@ -684,6 +685,7 @@ [6711]: https://github.com/enso-org/enso/pull/6711 [6743]: https://github.com/enso-org/enso/pull/6743 [6817]: https://github.com/enso-org/enso/pull/6817 +[6941]: https://github.com/enso-org/enso/pull/6941 #### Enso Compiler From 6399b572e279d062948895d6c85c691d38405ffa Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Fri, 2 Jun 2023 15:08:48 -0400 Subject: [PATCH 36/40] benchmark round too --- test/Benchmarks/src/Column_Numeric.enso | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/Benchmarks/src/Column_Numeric.enso b/test/Benchmarks/src/Column_Numeric.enso index d1c4ce6ff2a2..04a477ef12a6 100644 --- a/test/Benchmarks/src/Column_Numeric.enso +++ b/test/Benchmarks/src/Column_Numeric.enso @@ -24,6 +24,11 @@ bench = ints_vec = Vector.new vector_size _->(faker.integer -1000000000 1000000000) ints = Column.from_vector "ints" ints_vec + IO.println <| ".round floats" + Bench.measure floats.round "Column.round floats" iter_size num_iterations + IO.println <| ".round ints" + Bench.measure ints.round "Column.round ints" iter_size num_iterations + IO.println <| ".truncate floats" Bench.measure floats.truncate "Column.truncate floats" iter_size num_iterations IO.println <| ".ceil floats" From 09c0d6234ea925bedf49b26c915722b9633afc66 Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Fri, 2 Jun 2023 15:35:50 -0400 Subject: [PATCH 37/40] order --- test/Benchmarks/src/Column_Numeric.enso | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Benchmarks/src/Column_Numeric.enso b/test/Benchmarks/src/Column_Numeric.enso index 04a477ef12a6..ea94b069d3d7 100644 --- a/test/Benchmarks/src/Column_Numeric.enso +++ b/test/Benchmarks/src/Column_Numeric.enso @@ -26,8 +26,6 @@ bench = IO.println <| ".round floats" Bench.measure floats.round "Column.round floats" iter_size num_iterations - IO.println <| ".round ints" - Bench.measure ints.round "Column.round ints" iter_size num_iterations IO.println <| ".truncate floats" Bench.measure floats.truncate "Column.truncate floats" iter_size num_iterations @@ -36,6 +34,8 @@ bench = IO.println <| ".floor floats" Bench.measure floats.floor "Column.floor floats" iter_size num_iterations + IO.println <| ".round ints" + Bench.measure ints.round "Column.round ints" iter_size num_iterations IO.println <| ".truncate ints" Bench.measure ints.truncate "Column.truncate ints" iter_size num_iterations IO.println <| ".ceil ints" From 38e6812949ab4a3ddfa096ba131041d56eb72a7d Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Mon, 5 Jun 2023 11:06:14 -0400 Subject: [PATCH 38/40] specialize ops --- .../operation/map/UnaryDoubleToLongOp.java | 31 +++++++++++++++++++ .../operation/map/UnaryLongToLongOp.java | 31 +++++++++++++++++++ .../storage/numeric/AbstractLongStorage.java | 20 +++++------- .../column/storage/numeric/DoubleStorage.java | 16 +++++----- 4 files changed, 77 insertions(+), 21 deletions(-) create mode 100644 std-bits/table/src/main/java/org/enso/table/data/column/operation/map/UnaryDoubleToLongOp.java create mode 100644 std-bits/table/src/main/java/org/enso/table/data/column/operation/map/UnaryLongToLongOp.java diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/operation/map/UnaryDoubleToLongOp.java b/std-bits/table/src/main/java/org/enso/table/data/column/operation/map/UnaryDoubleToLongOp.java new file mode 100644 index 000000000000..5a076f2976e5 --- /dev/null +++ b/std-bits/table/src/main/java/org/enso/table/data/column/operation/map/UnaryDoubleToLongOp.java @@ -0,0 +1,31 @@ +package org.enso.table.data.column.operation.map; + +import org.enso.table.data.column.storage.numeric.DoubleStorage; +import org.enso.table.data.column.storage.numeric.LongStorage; + +import java.util.BitSet; + +/** An operation that takes a single double argumebnt and returns a long. */ +public abstract class UnaryDoubleToLongOp extends UnaryMapOperation { + + public UnaryDoubleToLongOp(String name) { + super(name); + } + + protected abstract long doOperation(double value); + + @Override + protected LongStorage run(DoubleStorage storage) { + BitSet newMissing = new BitSet(); + long[] newVals = new long[storage.size()]; + for (int i = 0; i < storage.size(); i++) { + if (!storage.isNa(i)) { + newVals[i] = doOperation(storage.getItem(i)); + } else { + newMissing.set(i); + } + } + + return new LongStorage(newVals, newVals.length, newMissing); + } +} diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/operation/map/UnaryLongToLongOp.java b/std-bits/table/src/main/java/org/enso/table/data/column/operation/map/UnaryLongToLongOp.java new file mode 100644 index 000000000000..f11d4d2e641a --- /dev/null +++ b/std-bits/table/src/main/java/org/enso/table/data/column/operation/map/UnaryLongToLongOp.java @@ -0,0 +1,31 @@ +package org.enso.table.data.column.operation.map; + +import org.enso.table.data.column.storage.numeric.AbstractLongStorage; +import org.enso.table.data.column.storage.numeric.LongStorage; + +import java.util.BitSet; + +/** An operation that takes a single double argumebnt and returns a long. */ +public abstract class UnaryLongToLongOp extends UnaryMapOperation { + + public UnaryLongToLongOp(String name) { + super(name); + } + + protected abstract long doOperation(long value); + + @Override + protected LongStorage run(AbstractLongStorage storage) { + BitSet newMissing = new BitSet(); + long[] newVals = new long[storage.size()]; + for (int i = 0; i < storage.size(); i++) { + if (!storage.isNa(i)) { + newVals[i] = doOperation(storage.getItem(i)); + } else { + newMissing.set(i); + } + } + + return new LongStorage(newVals, newVals.length, newMissing); + } +} diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/storage/numeric/AbstractLongStorage.java b/std-bits/table/src/main/java/org/enso/table/data/column/storage/numeric/AbstractLongStorage.java index b6df5bc97acf..ce805e17ee36 100644 --- a/std-bits/table/src/main/java/org/enso/table/data/column/storage/numeric/AbstractLongStorage.java +++ b/std-bits/table/src/main/java/org/enso/table/data/column/storage/numeric/AbstractLongStorage.java @@ -8,7 +8,7 @@ import org.enso.table.data.column.operation.map.numeric.LongBooleanOp; import org.enso.table.data.column.operation.map.numeric.LongIsInOp; import org.enso.table.data.column.operation.map.numeric.LongNumericOp; -import org.enso.table.data.column.operation.map.UnaryIntegerOp; +import org.enso.table.data.column.operation.map.UnaryLongToLongOp; import org.enso.table.data.column.storage.BoolStorage; import org.enso.table.data.column.storage.Storage; @@ -130,25 +130,19 @@ public Long doLong( } }) .add( - new UnaryIntegerOp<>(Maps.TRUNCATE) { + new UnaryLongToLongOp(Maps.TRUNCATE) { @Override - protected long doOperation(Long a) { - return a.longValue(); - } + protected long doOperation(long a) { return a; } }) .add( - new UnaryIntegerOp<>(Maps.CEIL) { + new UnaryLongToLongOp(Maps.CEIL) { @Override - protected long doOperation(Long a) { - return a.longValue(); - } + protected long doOperation(long a) { return a; } }) .add( - new UnaryIntegerOp<>(Maps.FLOOR) { + new UnaryLongToLongOp(Maps.FLOOR) { @Override - protected long doOperation(Long a) { - return a.longValue(); - } + protected long doOperation(long a) { return a; } }) .add( new LongNumericOp(Storage.Maps.DIV, true) { diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/storage/numeric/DoubleStorage.java b/std-bits/table/src/main/java/org/enso/table/data/column/storage/numeric/DoubleStorage.java index 8f988f085b24..37968bc18ae4 100644 --- a/std-bits/table/src/main/java/org/enso/table/data/column/storage/numeric/DoubleStorage.java +++ b/std-bits/table/src/main/java/org/enso/table/data/column/storage/numeric/DoubleStorage.java @@ -8,7 +8,7 @@ import org.enso.table.data.column.operation.map.numeric.DoubleBooleanOp; import org.enso.table.data.column.operation.map.numeric.DoubleIsInOp; import org.enso.table.data.column.operation.map.numeric.DoubleNumericOp; -import org.enso.table.data.column.operation.map.UnaryIntegerOp; +import org.enso.table.data.column.operation.map.UnaryDoubleToLongOp; import org.enso.table.data.column.storage.BoolStorage; import org.enso.table.data.column.storage.Storage; import org.enso.table.data.column.storage.type.FloatType; @@ -246,23 +246,23 @@ protected double doDouble( } }) .add( - new UnaryIntegerOp<>(Maps.TRUNCATE) { + new UnaryDoubleToLongOp(Maps.TRUNCATE) { @Override - protected long doOperation(Double a) { - return (long) a.doubleValue(); + protected long doOperation(double a) { + return (long) a; } }) .add( - new UnaryIntegerOp<>(Maps.CEIL) { + new UnaryDoubleToLongOp(Maps.CEIL) { @Override - protected long doOperation(Double a) { + protected long doOperation(double a) { return (long) Math.ceil(a); } }) .add( - new UnaryIntegerOp<>(Maps.FLOOR) { + new UnaryDoubleToLongOp(Maps.FLOOR) { @Override - protected long doOperation(Double a) { + protected long doOperation(double a) { return (long) Math.floor(a); } }) From 9a615eaf944009cca091c0e426525baae6e40dae Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Mon, 5 Jun 2023 11:06:54 -0400 Subject: [PATCH 39/40] specialize ops --- .../operation/map/UnaryDoubleToLongOp.java | 34 +++++++++---------- .../operation/map/UnaryLongToLongOp.java | 34 +++++++++---------- .../storage/numeric/AbstractLongStorage.java | 12 +++++-- 3 files changed, 43 insertions(+), 37 deletions(-) diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/operation/map/UnaryDoubleToLongOp.java b/std-bits/table/src/main/java/org/enso/table/data/column/operation/map/UnaryDoubleToLongOp.java index 5a076f2976e5..ea13de40c0e1 100644 --- a/std-bits/table/src/main/java/org/enso/table/data/column/operation/map/UnaryDoubleToLongOp.java +++ b/std-bits/table/src/main/java/org/enso/table/data/column/operation/map/UnaryDoubleToLongOp.java @@ -8,24 +8,24 @@ /** An operation that takes a single double argumebnt and returns a long. */ public abstract class UnaryDoubleToLongOp extends UnaryMapOperation { - public UnaryDoubleToLongOp(String name) { - super(name); - } - - protected abstract long doOperation(double value); + public UnaryDoubleToLongOp(String name) { + super(name); + } - @Override - protected LongStorage run(DoubleStorage storage) { - BitSet newMissing = new BitSet(); - long[] newVals = new long[storage.size()]; - for (int i = 0; i < storage.size(); i++) { - if (!storage.isNa(i)) { - newVals[i] = doOperation(storage.getItem(i)); - } else { - newMissing.set(i); - } - } + protected abstract long doOperation(double value); - return new LongStorage(newVals, newVals.length, newMissing); + @Override + protected LongStorage run(DoubleStorage storage) { + BitSet newMissing = new BitSet(); + long[] newVals = new long[storage.size()]; + for (int i = 0; i < storage.size(); i++) { + if (!storage.isNa(i)) { + newVals[i] = doOperation(storage.getItem(i)); + } else { + newMissing.set(i); + } } + + return new LongStorage(newVals, newVals.length, newMissing); + } } diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/operation/map/UnaryLongToLongOp.java b/std-bits/table/src/main/java/org/enso/table/data/column/operation/map/UnaryLongToLongOp.java index f11d4d2e641a..d530f603809a 100644 --- a/std-bits/table/src/main/java/org/enso/table/data/column/operation/map/UnaryLongToLongOp.java +++ b/std-bits/table/src/main/java/org/enso/table/data/column/operation/map/UnaryLongToLongOp.java @@ -8,24 +8,24 @@ /** An operation that takes a single double argumebnt and returns a long. */ public abstract class UnaryLongToLongOp extends UnaryMapOperation { - public UnaryLongToLongOp(String name) { - super(name); - } - - protected abstract long doOperation(long value); + public UnaryLongToLongOp(String name) { + super(name); + } - @Override - protected LongStorage run(AbstractLongStorage storage) { - BitSet newMissing = new BitSet(); - long[] newVals = new long[storage.size()]; - for (int i = 0; i < storage.size(); i++) { - if (!storage.isNa(i)) { - newVals[i] = doOperation(storage.getItem(i)); - } else { - newMissing.set(i); - } - } + protected abstract long doOperation(long value); - return new LongStorage(newVals, newVals.length, newMissing); + @Override + protected LongStorage run(AbstractLongStorage storage) { + BitSet newMissing = new BitSet(); + long[] newVals = new long[storage.size()]; + for (int i = 0; i < storage.size(); i++) { + if (!storage.isNa(i)) { + newVals[i] = doOperation(storage.getItem(i)); + } else { + newMissing.set(i); + } } + + return new LongStorage(newVals, newVals.length, newMissing); + } } diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/storage/numeric/AbstractLongStorage.java b/std-bits/table/src/main/java/org/enso/table/data/column/storage/numeric/AbstractLongStorage.java index ce805e17ee36..8846a900ee45 100644 --- a/std-bits/table/src/main/java/org/enso/table/data/column/storage/numeric/AbstractLongStorage.java +++ b/std-bits/table/src/main/java/org/enso/table/data/column/storage/numeric/AbstractLongStorage.java @@ -132,17 +132,23 @@ public Long doLong( .add( new UnaryLongToLongOp(Maps.TRUNCATE) { @Override - protected long doOperation(long a) { return a; } + protected long doOperation(long a) { + return a; + } }) .add( new UnaryLongToLongOp(Maps.CEIL) { @Override - protected long doOperation(long a) { return a; } + protected long doOperation(long a) { + return a; + } }) .add( new UnaryLongToLongOp(Maps.FLOOR) { @Override - protected long doOperation(long a) { return a; } + protected long doOperation(long a) { + return a; + } }) .add( new LongNumericOp(Storage.Maps.DIV, true) { From 3e7250decb9dc6803cd1f03f8ed994433fe085ee Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Mon, 5 Jun 2023 11:36:52 -0400 Subject: [PATCH 40/40] fix benchmark main --- test/Benchmarks/src/Main.enso | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Benchmarks/src/Main.enso b/test/Benchmarks/src/Main.enso index 401d2d08b2cb..65afdb6e4a20 100644 --- a/test/Benchmarks/src/Main.enso +++ b/test/Benchmarks/src/Main.enso @@ -1,4 +1,5 @@ import project.Collections +import project.Column_Numeric import project.Equality import project.Json_Bench import project.Natural_Order_Sort