From baeea8989fdd7f49b6a2b8cb5563731854325cbf Mon Sep 17 00:00:00 2001 From: Gregory Travis Date: Wed, 17 Jul 2024 16:12:47 -0400 Subject: [PATCH] impl --- .../Standard/Table/0.0.0-dev/src/Column.enso | 2 + .../comparisons/NumericComparison.java | 96 +++++++++++++++++-- .../Column_Operations_Spec.enso | 81 ++++++++++++---- 3 files changed, 155 insertions(+), 24 deletions(-) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Column.enso index 0398030aa61..34be1f8df7c 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Column.enso @@ -411,6 +411,8 @@ type Column example_lt = Examples.integer_column < 1 < : Column | Any -> Column < self other = Value_Type.expect_comparable self other <| + if other.is_a Column then + IO.println "AAA "+self.value_type.to_text+" :: "+other.value_type.to_text Incomparable_Values.handle_errors <| run_vectorized_binary_op self Java_Storage.Maps.LT fallback_fn=(<) other expected_result_type=Value_Type.Boolean diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/operation/map/numeric/comparisons/NumericComparison.java b/std-bits/table/src/main/java/org/enso/table/data/column/operation/map/numeric/comparisons/NumericComparison.java index fcef5f95557..e070d589b8d 100644 --- a/std-bits/table/src/main/java/org/enso/table/data/column/operation/map/numeric/comparisons/NumericComparison.java +++ b/std-bits/table/src/main/java/org/enso/table/data/column/operation/map/numeric/comparisons/NumericComparison.java @@ -4,10 +4,12 @@ import static org.enso.table.data.column.operation.map.numeric.helpers.DoubleArr import java.math.BigInteger; import java.util.BitSet; + import org.enso.base.CompareException; import org.enso.base.polyglot.NumericConverter; import org.enso.table.data.column.operation.map.BinaryMapOperation; import org.enso.table.data.column.operation.map.MapOperationProblemAggregator; +import org.enso.table.data.column.operation.map.numeric.helpers.BigDecimalArrayAdapter; import org.enso.table.data.column.operation.map.numeric.helpers.BigIntegerArrayAdapter; import org.enso.table.data.column.operation.map.numeric.helpers.DoubleArrayAdapter; import org.enso.table.data.column.storage.BoolStorage; @@ -47,6 +49,8 @@ public abstract class NumericComparison runBigIntegerMap( BigIntegerArrayAdapter.fromStorage(s), bigInteger, problemAggregator); + case BigDecimalStorage s -> runBigDecimalMap( + BigIntegerArrayAdapter.fromStorage(s), new BigDecimal(bigInteger), problemAggregator); case DoubleStorage s -> runDoubleMap(s, bigInteger.doubleValue(), problemAggregator); default -> throw new IllegalStateException( "Unsupported lhs storage: " + storage.getClass().getCanonicalName()); @@ -57,14 +61,21 @@ public abstract class NumericComparison runLongMap(s, rhs, problemAggregator); case BigIntegerStorage s -> runBigIntegerMap( BigIntegerArrayAdapter.fromStorage(s), BigInteger.valueOf(rhs), problemAggregator); + case BigDecimalStorage s -> runBigDecimalMap( + BigDecimalArrayAdapter.fromStorage(s), BigDecimal.valueOf(rhs), problemAggregator); case DoubleStorage s -> runDoubleMap(s, (double) rhs, problemAggregator); default -> throw new IllegalStateException( "Unsupported lhs storage: " + storage.getClass().getCanonicalName()); }; } else if (NumericConverter.isCoercibleToDouble(arg)) { - DoubleArrayAdapter lhs = DoubleArrayAdapter.fromAnyStorage(storage); - double rhs = NumericConverter.coerceToDouble(arg); - return runDoubleMap(lhs, rhs, problemAggregator); + return switch (storage) { + case BigDecimalStorage s -> runBigDecimalMap( + BigDecimalArrayAdapter.fromStorage(s), BigDecimal.valueOf(arg), problemAggregator); + default -> { + DoubleArrayAdapter lhs = DoubleArrayAdapter.fromAnyStorage(storage); + double rhs = NumericConverter.coerceToDouble(arg); + yield runDoubleMap(lhs, rhs, problemAggregator); + } } else { int n = storage.size(); BitSet isNothing = new BitSet(); @@ -155,15 +166,44 @@ public abstract class NumericComparison arg, MapOperationProblemAggregator problemAggregator) { return switch (storage) { case DoubleStorage lhs -> { - if (arg.getType() instanceof AnyObjectType) { - yield runMixedZip(lhs, arg, problemAggregator); - } else { - yield runDoubleZip(lhs, fromAnyStorage(arg), problemAggregator); + case BigDecimalStorage rhs -> runBigDecimalZip( + new BigDecimalArrayAdapter(lhs), + new BigDecimalArrayAdapter(rhs), + problemAggregator); + default -> { + if (arg.getType() instanceof AnyObjectType) { + yield runMixedZip(lhs, arg, problemAggregator); + } else { + yield runDoubleZip(lhs, fromAnyStorage(arg), problemAggregator); + } } } @@ -174,22 +214,31 @@ public abstract class NumericComparison runBigDecimalZip( + new BigDecimalArrayAdapter(lhs), + new BigDecimalArrayAdapter(rhs), + problemAggregator); case DoubleStorage rhs -> runDoubleZip( DoubleArrayAdapter.fromStorage(lhs), rhs, problemAggregator); default -> runMixedZip(lhs, arg, problemAggregator); }; case BigIntegerStorage lhs -> { - BigIntegerArrayAdapter left = BigIntegerArrayAdapter.fromStorage(lhs); yield switch (arg) { case AbstractLongStorage rhs -> { + BigIntegerArrayAdapter left = BigIntegerArrayAdapter.fromStorage(lhs); BigIntegerArrayAdapter right = BigIntegerArrayAdapter.fromStorage(rhs); yield runBigIntegerZip(left, right, problemAggregator); } case BigIntegerStorage rhs -> { + BigIntegerArrayAdapter left = BigIntegerArrayAdapter.fromStorage(lhs); BigIntegerArrayAdapter right = BigIntegerArrayAdapter.fromStorage(rhs); yield runBigIntegerZip(left, right, problemAggregator); } + case BigDecimalStorage rhs -> runBigDecimalZip( + new BigDecimalArrayAdapter(lhs), + new BigDecimalArrayAdapter(rhs), + problemAggregator); case DoubleStorage rhs -> runDoubleZip( DoubleArrayAdapter.fromStorage(lhs), rhs, problemAggregator); default -> runMixedZip(lhs, arg, problemAggregator); @@ -294,6 +343,37 @@ public abstract class NumericComparison lhs, Storage rhs, MapOperationProblemAggregator problemAggregator) { int n = lhs.size(); diff --git a/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso b/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso index 19063902bd8..59773504a19 100644 --- a/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso +++ b/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso @@ -649,26 +649,75 @@ add_specs suite_builder setup = suite_builder.group prefix+"(Column_Operations_Spec) Column Comparisons" group_builder-> table_builder = build_sorted_table table_builder=setup.light_table_builder + + group_builder.specify "should infer the correct precise value type for mixed columns" <| + with_mixed_columns_if_supported [["i", [1, 4, 5, Nothing]], ["f", [2.0, 3.25, 5.0, Nothing]], ["d", [dec "2.0", dec "3.25", dec "5.0", Nothing]]] t-> + setup.is_integer_type (t.at "i").inferred_precise_value_type . should_be_true + (t.at "f").inferred_precise_value_type . should_be_a (Value_Type.Float ...) + (t.at "d").inferred_precise_value_type . should_be_a (Value_Type.Decimal ...) + group_builder.specify "should allow to compare numbers" <| - with_mixed_columns_if_supported [["x", [1, 4, 5, Nothing]], ["y", [2.0, 3.25, 5.0, Nothing]]] t2-> - x = t2.at "x" - y = t2.at "y" - setup.is_integer_type x.inferred_precise_value_type . should_be_true - y.inferred_precise_value_type . should_be_a (Value_Type.Float ...) + x_values = [1.25, 4.5, 5.0] + y_values = [2.0, 3.25, 5.0] - (x < y).to_vector . should_equal [True, False, False, Nothing] - (x <= y).to_vector . should_equal [True, False, True, Nothing] - (x > y).to_vector . should_equal (x <= y).not.to_vector - (x >= y).to_vector . should_equal (x < y).not.to_vector + converters = [.truncate, x->x, dec] + converters.map x_converter -> converters.map y_converter -> + x_values_converted = x_values.map x_converter + y_values_converted = y_values.map y_converter + with_mixed_columns_if_supported [['x', x_values_converted + [Nothing]], ['y', y_values_converted + [Nothing]] + clue = x.value_type.to_text+', '+y.value_type.to_text + #IO.println "CLUE "+clue + Test.with_clue clue <| + (x < y).to_vector . should_equal [True, False, False, Nothing] + (x <= y).to_vector . should_equal [True, False, True, Nothing] + (x > y).to_vector . should_equal (x <= y).not.to_vector + (x >= y).to_vector . should_equal (x < y).not.to_vector - (x < 1000).to_vector . should_equal [True, True, True, Nothing] + [6.5, 1000.5].map const_float-> + converters.map converter-> + constant = converter const_float + (x < -constant).to_vector . should_equal [False, False, False, Nothing] + (x < constant).to_vector . should_equal [True, True, True, Nothing] + (x < -constant).to_vector . should_equal [False, False, False, Nothing] + (x < constant).to_vector . should_equal [True, True, True, Nothing] + + [(<), (<=), (>), (>=)].each op-> + op x y . value_type . should_equal Value_Type.Boolean + op x y . to_vector . should_succeed + op x 23 . to_vector . should_succeed + op y 23 . to_vector . should_succeed + op x 1.5 . to_vector . should_succeed + op x (dec 1.5) . to_vector . should_succeed + + ## + with_mixed_columns_if_supported [["x", [1, 4, 5, Nothing]], ["yf", [2.0, 3.25, 5.0, Nothing]], ["yd", [Decimal.new "2.0", Decimal.new "3.25", Decimal.new "5.0", Nothing]]] t-> + setup.is_integer_type (t.at "x").inferred_precise_value_type . should_be_true + (t.at "yf").inferred_precise_value_type . should_be_a (Value_Type.Float ...) + (t.at "yd").inferred_precise_value_type . should_be_a (Value_Type.Decimal ...) + + x = t.at "x" + #q0 = (x < (t.at "yf")).to_vector + #q1 = (x < (t.at "yd")).to_vector + + [t.at "yf", t.at "yd"].map y-> + clue = x.value_type.to_text+', '+y.value_type.to_text + IO.println "CLUE "+clue + Test.with_clue clue <| + + (x < y).to_vector . should_equal [True, False, False, Nothing] + (x <= y).to_vector . should_equal [True, False, True, Nothing] + (x > y).to_vector . should_equal (x <= y).not.to_vector + (x >= y).to_vector . should_equal (x < y).not.to_vector + + (x < 1000).to_vector . should_equal [True, True, True, Nothing] + + [(<), (<=), (>), (>=)].each op-> + op x y . value_type . should_equal Value_Type.Boolean + op x y . to_vector . should_succeed + op x 23 . to_vector . should_succeed + op y 23 . to_vector . should_succeed + op x 1.5 . to_vector . should_succeed - [(<), (<=), (>), (>=)].each op-> - op x y . value_type . should_equal Value_Type.Boolean - op x y . to_vector . should_succeed - op x 23 . to_vector . should_succeed - op y 23 . to_vector . should_succeed - op x 1.5 . to_vector . should_succeed group_builder.specify "should allow to compare texts" <| t0 = table_builder [["X", ["a", "b", "c"]], ["Y", ["a", "b", "d"]]]