This commit is contained in:
Gregory Travis 2024-07-17 16:12:47 -04:00
parent 2bbb32034b
commit baeea8989f
3 changed files with 155 additions and 24 deletions

View File

@ -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

View File

@ -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<T extends Number, I extends Storage<? su
BigIntegerArrayAdapter.fromStorage(s), bigInteger, problemAggregator);
case BigIntegerStorage s -> 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<T extends Number, I extends Storage<? su
case AbstractLongStorage s -> 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<T extends Number, I extends Storage<? su
return new BoolStorage(comparisonResults, isNothing, n, false);
}
protected BoolStorage runBigDecimalMap(
BigDecimalArrayAdapter lhs, BigDecimal rhs, MapOperationProblemAggregator problemAggregator) {
int n = lhs.size();
BitSet comparisonResults = new BitSet();
BitSet isNothing = new BitSet();
Context context = Context.getCurrent();
for (int i = 0; i < n; ++i) {
BigDecimal item = lhs.getItem(i);
if (item == null) {
isNothing.set(i);
} else {
boolean r = doBigDecimal(item, rhs);
if (r) {
comparisonResults.set(i);
}
}
context.safepoint();
}
return new BoolStorage(comparisonResults, isNothing, n, false);
}
@Override
public BoolStorage runZip(
I storage, Storage<?> 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<T extends Number, I extends Storage<? su
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);
};
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<T extends Number, I extends Storage<? su
return new BoolStorage(comparisonResults, isNothing, n, false);
}
protected BoolStorage runBigDecimalZip(
BigDecimalArrayAdapter lhs,
BigDecimalArrayAdapter rhs,
MapOperationProblemAggregator problemAggregator) {
int n = lhs.size();
int m = Math.min(lhs.size(), rhs.size());
BitSet comparisonResults = new BitSet();
BitSet isNothing = new BitSet();
Context context = Context.getCurrent();
for (int i = 0; i < m; ++i) {
BigDecimal x = lhs.getItem(i);
BigDecimal y = rhs.getItem(i);
if (x == null || y == null) {
isNothing.set(i);
} else {
boolean r = doBigDecimal(x, y);
if (r) {
comparisonResults.set(i);
}
}
context.safepoint();
}
if (m < n) {
isNothing.set(m, n);
}
return new BoolStorage(comparisonResults, isNothing, n, false);
}
protected BoolStorage runMixedZip(
Storage<?> lhs, Storage<?> rhs, MapOperationProblemAggregator problemAggregator) {
int n = lhs.size();

View File

@ -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"]]]