Skip to content

Commit e990201

Browse files
Updated EXPM1() and Tests to New Engine (#215) (#1334)
* Updated EXPM1() and tests to new engine Signed-off-by: Matthew Wells <[email protected]>
1 parent 4df8ed7 commit e990201

File tree

8 files changed

+169
-68
lines changed

8 files changed

+169
-68
lines changed

core/src/main/java/org/opensearch/sql/expression/DSL.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,10 @@ public static FunctionExpression exp(Expression... expressions) {
174174
return compile(FunctionProperties.None, BuiltinFunctionName.EXP, expressions);
175175
}
176176

177+
public static FunctionExpression expm1(Expression... expressions) {
178+
return compile(FunctionProperties.None, BuiltinFunctionName.EXPM1, expressions);
179+
}
180+
177181
public static FunctionExpression floor(Expression... expressions) {
178182
return compile(FunctionProperties.None, BuiltinFunctionName.FLOOR, expressions);
179183
}

core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public enum BuiltinFunctionName {
2828
CRC32(FunctionName.of("crc32")),
2929
E(FunctionName.of("e")),
3030
EXP(FunctionName.of("exp")),
31+
EXPM1(FunctionName.of("expm1")),
3132
FLOOR(FunctionName.of("floor")),
3233
LN(FunctionName.of("ln")),
3334
LOG(FunctionName.of("log")),

core/src/main/java/org/opensearch/sql/expression/operator/arthmetic/MathematicalFunction.java

Lines changed: 55 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.opensearch.sql.data.model.ExprNullValue;
3333
import org.opensearch.sql.data.model.ExprShortValue;
3434
import org.opensearch.sql.data.model.ExprStringValue;
35+
import org.opensearch.sql.data.model.ExprValue;
3536
import org.opensearch.sql.data.type.ExprCoreType;
3637
import org.opensearch.sql.data.type.ExprType;
3738
import org.opensearch.sql.expression.function.BuiltinFunctionName;
@@ -59,6 +60,7 @@ public static void register(BuiltinFunctionRepository repository) {
5960
repository.register(crc32());
6061
repository.register(euler());
6162
repository.register(exp());
63+
repository.register(expm1());
6264
repository.register(floor());
6365
repository.register(ln());
6466
repository.register(log());
@@ -85,6 +87,23 @@ public static void register(BuiltinFunctionRepository repository) {
8587
repository.register(tan());
8688
}
8789

90+
/**
91+
* Base function for math functions with similar formats that return DOUBLE.
92+
*
93+
* @param functionName BuiltinFunctionName of math function.
94+
* @param formula lambda function of math formula.
95+
* @param returnType data type return type of the calling function
96+
* @return DefaultFunctionResolver for math functions.
97+
*/
98+
private static DefaultFunctionResolver baseMathFunction(
99+
FunctionName functionName, SerializableFunction<ExprValue,
100+
ExprValue> formula, ExprCoreType returnType) {
101+
return FunctionDSL.define(functionName,
102+
ExprCoreType.numberTypes().stream().map(type -> FunctionDSL.impl(
103+
FunctionDSL.nullMissingHandling(formula),
104+
returnType, type)).collect(Collectors.toList()));
105+
}
106+
88107
/**
89108
* Definition of abs() function. The supported signature of abs() function are INT -> INT LONG ->
90109
* LONG FLOAT -> FLOAT DOUBLE -> DOUBLE
@@ -186,15 +205,21 @@ private static DefaultFunctionResolver euler() {
186205
}
187206

188207
/**
189-
* Definition of exp(x) function. Calculate exponent function e to the x The supported signature
190-
* of exp function is INTEGER/LONG/FLOAT/DOUBLE -> DOUBLE
208+
* Definition of exp(x) function. Calculate exponent function e to the x
209+
* The supported signature of exp function is INTEGER/LONG/FLOAT/DOUBLE -> DOUBLE
191210
*/
192211
private static DefaultFunctionResolver exp() {
193-
return FunctionDSL.define(BuiltinFunctionName.EXP.getName(),
194-
ExprCoreType.numberTypes().stream()
195-
.map(type -> FunctionDSL.impl(FunctionDSL.nullMissingHandling(
196-
v -> new ExprDoubleValue(Math.exp(v.doubleValue()))),
197-
type, DOUBLE)).collect(Collectors.toList()));
212+
return baseMathFunction(BuiltinFunctionName.EXP.getName(),
213+
v -> new ExprDoubleValue(Math.exp(v.doubleValue())), DOUBLE);
214+
}
215+
216+
/**
217+
* Definition of expm1(x) function. Calculate exponent function e to the x, minus 1
218+
* The supported signature of exp function is INTEGER/LONG/FLOAT/DOUBLE -> DOUBLE
219+
*/
220+
private static DefaultFunctionResolver expm1() {
221+
return baseMathFunction(BuiltinFunctionName.EXPM1.getName(),
222+
v -> new ExprDoubleValue(Math.expm1(v.doubleValue())), DOUBLE);
198223
}
199224

200225
/**
@@ -214,11 +239,8 @@ private static DefaultFunctionResolver floor() {
214239
* ln function is INTEGER/LONG/FLOAT/DOUBLE -> DOUBLE
215240
*/
216241
private static DefaultFunctionResolver ln() {
217-
return FunctionDSL.define(BuiltinFunctionName.LN.getName(),
218-
ExprCoreType.numberTypes().stream()
219-
.map(type -> FunctionDSL.impl(FunctionDSL.nullMissingHandling(
220-
v -> new ExprDoubleValue(Math.log(v.doubleValue()))),
221-
type, DOUBLE)).collect(Collectors.toList()));
242+
return baseMathFunction(BuiltinFunctionName.LN.getName(),
243+
v -> new ExprDoubleValue(Math.log(v.doubleValue())), DOUBLE);
222244
}
223245

224246
/**
@@ -255,23 +277,17 @@ private static DefaultFunctionResolver log() {
255277
* log function is SHORT/INTEGER/LONG/FLOAT/DOUBLE -> DOUBLE
256278
*/
257279
private static DefaultFunctionResolver log10() {
258-
return FunctionDSL.define(BuiltinFunctionName.LOG10.getName(),
259-
ExprCoreType.numberTypes().stream()
260-
.map(type -> FunctionDSL.impl(FunctionDSL.nullMissingHandling(
261-
v -> new ExprDoubleValue(Math.log10(v.doubleValue()))),
262-
type, DOUBLE)).collect(Collectors.toList()));
280+
return baseMathFunction(BuiltinFunctionName.LOG10.getName(),
281+
v -> new ExprDoubleValue(Math.log10(v.doubleValue())), DOUBLE);
263282
}
264283

265284
/**
266285
* Definition of log2(x) function. Calculate base-2 logarithm of x The supported signature of log
267286
* function is SHORT/INTEGER/LONG/FLOAT/DOUBLE -> DOUBLE
268287
*/
269288
private static DefaultFunctionResolver log2() {
270-
return FunctionDSL.define(BuiltinFunctionName.LOG2.getName(),
271-
ExprCoreType.numberTypes().stream()
272-
.map(type -> FunctionDSL.impl(FunctionDSL.nullMissingHandling(
273-
v -> new ExprDoubleValue(Math.log(v.doubleValue()) / Math.log(2))), DOUBLE, type))
274-
.collect(Collectors.toList()));
289+
return baseMathFunction(BuiltinFunctionName.LOG2.getName(),
290+
v -> new ExprDoubleValue(Math.log(v.doubleValue()) / Math.log(2)), DOUBLE);
275291
}
276292

277293
/**
@@ -450,11 +466,8 @@ private static DefaultFunctionResolver round() {
450466
* SHORT/INTEGER/LONG/FLOAT/DOUBLE -> INTEGER
451467
*/
452468
private static DefaultFunctionResolver sign() {
453-
return FunctionDSL.define(BuiltinFunctionName.SIGN.getName(),
454-
ExprCoreType.numberTypes().stream()
455-
.map(type -> FunctionDSL.impl(FunctionDSL.nullMissingHandling(
456-
v -> new ExprIntegerValue(Math.signum(v.doubleValue()))),
457-
INTEGER, type)).collect(Collectors.toList()));
469+
return baseMathFunction(BuiltinFunctionName.SIGN.getName(),
470+
v -> new ExprIntegerValue(Math.signum(v.doubleValue())), INTEGER);
458471
}
459472

460473
/**
@@ -464,12 +477,9 @@ private static DefaultFunctionResolver sign() {
464477
* INTEGER/LONG/FLOAT/DOUBLE -> DOUBLE
465478
*/
466479
private static DefaultFunctionResolver sqrt() {
467-
return FunctionDSL.define(BuiltinFunctionName.SQRT.getName(),
468-
ExprCoreType.numberTypes().stream()
469-
.map(type -> FunctionDSL.impl(FunctionDSL.nullMissingHandling(
470-
v -> v.doubleValue() < 0 ? ExprNullValue.of() :
471-
new ExprDoubleValue(Math.sqrt(v.doubleValue()))),
472-
DOUBLE, type)).collect(Collectors.toList()));
480+
return baseMathFunction(BuiltinFunctionName.SQRT.getName(),
481+
v -> v.doubleValue() < 0 ? ExprNullValue.of() :
482+
new ExprDoubleValue(Math.sqrt(v.doubleValue())), DOUBLE);
473483
}
474484

475485
/**
@@ -479,11 +489,8 @@ private static DefaultFunctionResolver sqrt() {
479489
* INTEGER/LONG/FLOAT/DOUBLE -> DOUBLE
480490
*/
481491
private static DefaultFunctionResolver cbrt() {
482-
return FunctionDSL.define(BuiltinFunctionName.CBRT.getName(),
483-
ExprCoreType.numberTypes().stream()
484-
.map(type -> FunctionDSL.impl(FunctionDSL.nullMissingHandling(
485-
v -> new ExprDoubleValue(Math.cbrt(v.doubleValue()))),
486-
DOUBLE, type)).collect(Collectors.toList()));
492+
return baseMathFunction(BuiltinFunctionName.CBRT.getName(),
493+
v -> new ExprDoubleValue(Math.cbrt(v.doubleValue())), DOUBLE);
487494
}
488495

489496
/**
@@ -606,11 +613,8 @@ private static DefaultFunctionResolver atan2() {
606613
* INTEGER/LONG/FLOAT/DOUBLE -> DOUBLE
607614
*/
608615
private static DefaultFunctionResolver cos() {
609-
return FunctionDSL.define(BuiltinFunctionName.COS.getName(),
610-
ExprCoreType.numberTypes().stream()
611-
.map(type -> FunctionDSL.impl(FunctionDSL.nullMissingHandling(
612-
v -> new ExprDoubleValue(Math.cos(v.doubleValue()))),
613-
DOUBLE, type)).collect(Collectors.toList()));
616+
return baseMathFunction(BuiltinFunctionName.COS.getName(),
617+
v -> new ExprDoubleValue(Math.cos(v.doubleValue())), DOUBLE);
614618
}
615619

616620
/**
@@ -641,11 +645,8 @@ private static DefaultFunctionResolver cot() {
641645
* INTEGER/LONG/FLOAT/DOUBLE -> DOUBLE
642646
*/
643647
private static DefaultFunctionResolver degrees() {
644-
return FunctionDSL.define(BuiltinFunctionName.DEGREES.getName(),
645-
ExprCoreType.numberTypes().stream()
646-
.map(type -> FunctionDSL.impl(FunctionDSL.nullMissingHandling(
647-
v -> new ExprDoubleValue(Math.toDegrees(v.doubleValue()))),
648-
type, DOUBLE)).collect(Collectors.toList()));
648+
return baseMathFunction(BuiltinFunctionName.DEGREES.getName(),
649+
v -> new ExprDoubleValue(Math.toDegrees(v.doubleValue())), DOUBLE);
649650
}
650651

651652
/**
@@ -655,11 +656,8 @@ private static DefaultFunctionResolver degrees() {
655656
* INTEGER/LONG/FLOAT/DOUBLE -> DOUBLE
656657
*/
657658
private static DefaultFunctionResolver radians() {
658-
return FunctionDSL.define(BuiltinFunctionName.RADIANS.getName(),
659-
ExprCoreType.numberTypes().stream()
660-
.map(type -> FunctionDSL.impl(FunctionDSL.nullMissingHandling(
661-
v -> new ExprDoubleValue(Math.toRadians(v.doubleValue()))),
662-
DOUBLE, type)).collect(Collectors.toList()));
659+
return baseMathFunction(BuiltinFunctionName.RADIANS.getName(),
660+
v -> new ExprDoubleValue(Math.toRadians(v.doubleValue())), DOUBLE);
663661
}
664662

665663
/**
@@ -669,11 +667,8 @@ private static DefaultFunctionResolver radians() {
669667
* INTEGER/LONG/FLOAT/DOUBLE -> DOUBLE
670668
*/
671669
private static DefaultFunctionResolver sin() {
672-
return FunctionDSL.define(BuiltinFunctionName.SIN.getName(),
673-
ExprCoreType.numberTypes().stream()
674-
.map(type -> FunctionDSL.impl(FunctionDSL.nullMissingHandling(
675-
v -> new ExprDoubleValue(Math.sin(v.doubleValue()))),
676-
DOUBLE, type)).collect(Collectors.toList()));
670+
return baseMathFunction(BuiltinFunctionName.SIN.getName(),
671+
v -> new ExprDoubleValue(Math.sin(v.doubleValue())), DOUBLE);
677672
}
678673

679674
/**
@@ -683,10 +678,7 @@ private static DefaultFunctionResolver sin() {
683678
* INTEGER/LONG/FLOAT/DOUBLE -> DOUBLE
684679
*/
685680
private static DefaultFunctionResolver tan() {
686-
return FunctionDSL.define(BuiltinFunctionName.TAN.getName(),
687-
ExprCoreType.numberTypes().stream()
688-
.map(type -> FunctionDSL.impl(FunctionDSL.nullMissingHandling(
689-
v -> new ExprDoubleValue(Math.tan(v.doubleValue()))),
690-
DOUBLE, type)).collect(Collectors.toList()));
681+
return baseMathFunction(BuiltinFunctionName.TAN.getName(),
682+
v -> new ExprDoubleValue(Math.tan(v.doubleValue())), DOUBLE);
691683
}
692684
}

core/src/test/java/org/opensearch/sql/expression/operator/arthmetic/MathematicalFunctionTest.java

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,90 @@ public void exp_missing_value() {
565565
assertTrue(exp.valueOf(valueEnv()).isMissing());
566566
}
567567

568+
/**
569+
* Test expm1 with integer value.
570+
*/
571+
@ParameterizedTest(name = "expm1({0})")
572+
@ValueSource(ints = {
573+
-1, 0, 1, Integer.MAX_VALUE, Integer.MIN_VALUE})
574+
public void expm1_int_value(Integer value) {
575+
FunctionExpression expm1 = DSL.expm1(DSL.literal(value));
576+
assertThat(
577+
expm1.valueOf(valueEnv()),
578+
allOf(hasType(DOUBLE), hasValue(Math.expm1(value))));
579+
assertEquals(String.format("expm1(%s)", value), expm1.toString());
580+
}
581+
582+
/**
583+
* Test expm1 with long value.
584+
*/
585+
@ParameterizedTest(name = "expm1({0})")
586+
@ValueSource(longs = {
587+
-1L, 0L, 1L, Long.MAX_VALUE, Long.MIN_VALUE})
588+
public void expm1_long_value(Long value) {
589+
FunctionExpression expm1 = DSL.expm1(DSL.literal(value));
590+
assertThat(
591+
expm1.valueOf(valueEnv()),
592+
allOf(hasType(DOUBLE), hasValue(Math.expm1(value))));
593+
assertEquals(String.format("expm1(%s)", value), expm1.toString());
594+
}
595+
596+
/**
597+
* Test expm1 with float value.
598+
*/
599+
@ParameterizedTest(name = "expm1({0})")
600+
@ValueSource(floats = {
601+
-1.5F, -1F, 0F, 1F, 1.5F, Float.MAX_VALUE, Float.MIN_VALUE})
602+
public void expm1_float_value(Float value) {
603+
FunctionExpression expm1 = DSL.expm1(DSL.literal(value));
604+
assertThat(
605+
expm1.valueOf(valueEnv()),
606+
allOf(hasType(DOUBLE), hasValue(Math.expm1(value))));
607+
assertEquals(String.format("expm1(%s)", value), expm1.toString());
608+
}
609+
610+
/**
611+
* Test expm1 with double value.
612+
*/
613+
@ParameterizedTest(name = "expm1({0})")
614+
@ValueSource(doubles = {
615+
-1.5D, -1D, 0D, 1D, 1.5D, Double.MAX_VALUE, Double.MIN_VALUE})
616+
public void expm1_double_value(Double value) {
617+
FunctionExpression expm1 = DSL.expm1(DSL.literal(value));
618+
assertThat(
619+
expm1.valueOf(valueEnv()),
620+
allOf(hasType(DOUBLE), hasValue(Math.expm1(value))));
621+
assertEquals(String.format("expm1(%s)", value), expm1.toString());
622+
}
623+
624+
/**
625+
* Test expm1 with short value.
626+
*/
627+
@ParameterizedTest(name = "expm1({0})")
628+
@ValueSource(shorts = {
629+
-1, 0, 1, Short.MAX_VALUE, Short.MIN_VALUE})
630+
public void expm1_short_value(Short value) {
631+
FunctionExpression expm1 = DSL.expm1(DSL.literal(value));
632+
assertThat(
633+
expm1.valueOf(valueEnv()),
634+
allOf(hasType(DOUBLE), hasValue(Math.expm1(value))));
635+
assertEquals(String.format("expm1(%s)", value), expm1.toString());
636+
}
637+
638+
/**
639+
* Test expm1 with short value.
640+
*/
641+
@ParameterizedTest(name = "expm1({0})")
642+
@ValueSource(bytes = {
643+
-1, 0, 1, Byte.MAX_VALUE, Byte.MIN_VALUE})
644+
public void expm1_byte_value(Byte value) {
645+
FunctionExpression expm1 = DSL.expm1(DSL.literal(value));
646+
assertThat(
647+
expm1.valueOf(valueEnv()),
648+
allOf(hasType(DOUBLE), hasValue(Math.expm1(value))));
649+
assertEquals(String.format("expm1(%s)", value), expm1.toString());
650+
}
651+
568652
/**
569653
* Test floor with integer value.
570654
*/
@@ -575,7 +659,7 @@ public void floor_int_value(Integer value) {
575659
assertThat(
576660
floor.valueOf(valueEnv()),
577661
allOf(hasType(LONG), hasValue((long) Math.floor(value))));
578-
assertEquals(String.format("floor(%s)", value.toString()), floor.toString());
662+
assertEquals(String.format("floor(%s)", value), floor.toString());
579663
}
580664

581665
/**

docs/user/dql/functions.rst

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -443,10 +443,21 @@ EXPM1
443443
Description
444444
>>>>>>>>>>>
445445

446-
Specifications:
446+
Usage: EXPM1(NUMBER T) returns the exponential of T, minus 1.
447+
448+
Argument type: INTEGER/LONG/FLOAT/DOUBLE
447449

448-
1. EXPM1(NUMBER T) -> T
450+
Return type: DOUBLE
449451

452+
Example::
453+
454+
os> SELECT EXPM1(-1), EXPM1(0), EXPM1(1), EXPM1(1.5)
455+
fetched rows / total rows = 1/1
456+
+---------------------+------------+-------------------+-------------------+
457+
| EXPM1(-1) | EXPM1(0) | EXPM1(1) | EXPM1(1.5) |
458+
|---------------------+------------+-------------------+-------------------|
459+
| -0.6321205588285577 | 0.0 | 1.718281828459045 | 3.481689070338065 |
460+
+---------------------+------------+-------------------+-------------------+
450461

451462
FLOOR
452463
-----

docs/user/ppl/functions/math.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ Example::
187187
| c | 44 | 1100 | 15 |
188188
+----------------------+----------------------+-------------------+---------------------+
189189

190+
190191
COS
191192
---
192193

@@ -278,6 +279,7 @@ Example::
278279
| 89.95437383553924 |
279280
+-------------------+
280281

282+
281283
E
282284
-
283285

@@ -309,7 +311,7 @@ Usage: exp(x) return e raised to the power of x.
309311

310312
Argument type: INTEGER/LONG/FLOAT/DOUBLE
311313

312-
Return type: INTEGER
314+
Return type: DOUBLE
313315

314316
Example::
315317

0 commit comments

Comments
 (0)