summaryrefslogtreecommitdiffstats
path: root/eval/src/tests/eval/inline_operation/inline_operation_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'eval/src/tests/eval/inline_operation/inline_operation_test.cpp')
-rw-r--r--eval/src/tests/eval/inline_operation/inline_operation_test.cpp156
1 files changed, 156 insertions, 0 deletions
diff --git a/eval/src/tests/eval/inline_operation/inline_operation_test.cpp b/eval/src/tests/eval/inline_operation/inline_operation_test.cpp
new file mode 100644
index 00000000000..4520176e276
--- /dev/null
+++ b/eval/src/tests/eval/inline_operation/inline_operation_test.cpp
@@ -0,0 +1,156 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/eval/eval/operation.h>
+#include <vespa/eval/eval/inline_operation.h>
+#include <vespa/eval/eval/function.h>
+#include <vespa/vespalib/gtest/gtest.h>
+
+using namespace vespalib::eval;
+using namespace vespalib::eval::operation;
+
+template <typename T> struct IsInlined { constexpr static bool value = true; };
+template <> struct IsInlined<CallOp1> { constexpr static bool value = false; };
+template <> struct IsInlined<CallOp2> { constexpr static bool value = false; };
+
+template <typename T> double test_op1(op1_t ref, double a, bool inlined) {
+ T op(ref);
+ EXPECT_EQ(IsInlined<T>::value, inlined);
+ EXPECT_EQ(op(a), ref(a));
+ return op(a);
+};
+
+template <typename T> double test_op2(op2_t ref, double a, double b, bool inlined) {
+ T op(ref);
+ EXPECT_EQ(IsInlined<T>::value, inlined);
+ EXPECT_EQ(op(a,b), ref(a,b));
+ return op(a,b);
+};
+
+op1_t as_op1(const vespalib::string &str) {
+ auto fun = Function::parse({"a"}, str);
+ auto res = lookup_op1(*fun);
+ EXPECT_TRUE(res.has_value());
+ return res.value();
+}
+
+op2_t as_op2(const vespalib::string &str) {
+ auto fun = Function::parse({"a", "b"}, str);
+ auto res = lookup_op2(*fun);
+ EXPECT_TRUE(res.has_value());
+ return res.value();
+}
+
+TEST(InlineOperationTest, op1_lambdas_are_recognized) {
+ EXPECT_EQ(as_op1("-a"), Neg::f);
+ EXPECT_EQ(as_op1("!a"), Not::f);
+ EXPECT_EQ(as_op1("cos(a)"), Cos::f);
+ EXPECT_EQ(as_op1("sin(a)"), Sin::f);
+ EXPECT_EQ(as_op1("tan(a)"), Tan::f);
+ EXPECT_EQ(as_op1("cosh(a)"), Cosh::f);
+ EXPECT_EQ(as_op1("sinh(a)"), Sinh::f);
+ EXPECT_EQ(as_op1("tanh(a)"), Tanh::f);
+ EXPECT_EQ(as_op1("acos(a)"), Acos::f);
+ EXPECT_EQ(as_op1("asin(a)"), Asin::f);
+ EXPECT_EQ(as_op1("atan(a)"), Atan::f);
+ EXPECT_EQ(as_op1("exp(a)"), Exp::f);
+ EXPECT_EQ(as_op1("log10(a)"), Log10::f);
+ EXPECT_EQ(as_op1("log(a)"), Log::f);
+ EXPECT_EQ(as_op1("sqrt(a)"), Sqrt::f);
+ EXPECT_EQ(as_op1("ceil(a)"), Ceil::f);
+ EXPECT_EQ(as_op1("fabs(a)"), Fabs::f);
+ EXPECT_EQ(as_op1("floor(a)"), Floor::f);
+ EXPECT_EQ(as_op1("isNan(a)"), IsNan::f);
+ EXPECT_EQ(as_op1("relu(a)"), Relu::f);
+ EXPECT_EQ(as_op1("sigmoid(a)"), Sigmoid::f);
+ EXPECT_EQ(as_op1("elu(a)"), Elu::f);
+}
+
+TEST(InlineOperationTest, op1_lambdas_are_recognized_with_different_parameter_names) {
+ EXPECT_EQ(lookup_op1(*Function::parse({"x"}, "-x")).value(), Neg::f);
+ EXPECT_EQ(lookup_op1(*Function::parse({"x"}, "!x")).value(), Not::f);
+}
+
+TEST(InlineOperationTest, non_op1_lambdas_are_not_recognized) {
+ EXPECT_FALSE(lookup_op1(*Function::parse({"a"}, "a*a")).has_value());
+ EXPECT_FALSE(lookup_op1(*Function::parse({"a", "b"}, "a+b")).has_value());
+}
+
+TEST(InlineOperationTest, op2_lambdas_are_recognized) {
+ EXPECT_EQ(as_op2("a+b"), Add::f);
+ EXPECT_EQ(as_op2("a-b"), Sub::f);
+ EXPECT_EQ(as_op2("a*b"), Mul::f);
+ EXPECT_EQ(as_op2("a/b"), Div::f);
+ EXPECT_EQ(as_op2("a%b"), Mod::f);
+ EXPECT_EQ(as_op2("a^b"), Pow::f);
+ EXPECT_EQ(as_op2("a==b"), Equal::f);
+ EXPECT_EQ(as_op2("a!=b"), NotEqual::f);
+ EXPECT_EQ(as_op2("a~=b"), Approx::f);
+ EXPECT_EQ(as_op2("a<b"), Less::f);
+ EXPECT_EQ(as_op2("a<=b"), LessEqual::f);
+ EXPECT_EQ(as_op2("a>b"), Greater::f);
+ EXPECT_EQ(as_op2("a>=b"), GreaterEqual::f);
+ EXPECT_EQ(as_op2("a&&b"), And::f);
+ EXPECT_EQ(as_op2("a||b"), Or::f);
+ EXPECT_EQ(as_op2("atan2(a,b)"), Atan2::f);
+ EXPECT_EQ(as_op2("ldexp(a,b)"), Ldexp::f);
+ EXPECT_EQ(as_op2("pow(a,b)"), Pow::f);
+ EXPECT_EQ(as_op2("fmod(a,b)"), Mod::f);
+ EXPECT_EQ(as_op2("min(a,b)"), Min::f);
+ EXPECT_EQ(as_op2("max(a,b)"), Max::f);
+}
+
+TEST(InlineOperationTest, op2_lambdas_are_recognized_with_different_parameter_names) {
+ EXPECT_EQ(lookup_op2(*Function::parse({"x", "y"}, "x+y")).value(), Add::f);
+ EXPECT_EQ(lookup_op2(*Function::parse({"x", "y"}, "x-y")).value(), Sub::f);
+}
+
+TEST(InlineOperationTest, non_op2_lambdas_are_not_recognized) {
+ EXPECT_FALSE(lookup_op2(*Function::parse({"a"}, "-a")).has_value());
+ EXPECT_FALSE(lookup_op2(*Function::parse({"a", "b"}, "b+a")).has_value());
+}
+
+TEST(InlineOperationTest, generic_op1_wrapper_works) {
+ CallOp1 op(Neg::f);
+ EXPECT_EQ(op(3), -3);
+ EXPECT_EQ(op(-5), 5);
+}
+
+TEST(InlineOperationTest, generic_op2_wrapper_works) {
+ CallOp2 op(Add::f);
+ EXPECT_EQ(op(2,3), 5);
+ EXPECT_EQ(op(3,7), 10);
+}
+
+TEST(InlineOperationTest, inline_op2_example_works) {
+ op2_t ignored = nullptr;
+ InlineOp2<Add> op(ignored);
+ EXPECT_EQ(op(2,3), 5);
+ EXPECT_EQ(op(3,7), 10);
+}
+
+TEST(InlineOperationTest, parameter_swap_wrapper_works) {
+ CallOp2 op(Sub::f);
+ SwapArgs2<CallOp2> swap_op(Sub::f);
+ EXPECT_EQ(op(2,3), -1);
+ EXPECT_EQ(swap_op(2,3), 1);
+ EXPECT_EQ(op(3,7), -4);
+ EXPECT_EQ(swap_op(3,7), 4);
+}
+
+TEST(InlineOperationTest, resolved_op1_works) {
+ auto a = TypifyOp1::resolve(Neg::f, [](auto t){ return test_op1<typename decltype(t)::type>(Neg::f, 2.0, false); });
+ // putting the lambda inside the EXPECT does not work
+ EXPECT_EQ(a, -2.0);
+}
+
+TEST(InlineOperationTest, resolved_op2_works) {
+ auto a = TypifyOp2::resolve(Add::f, [](auto t){ return test_op2<typename decltype(t)::type>(Add::f, 2.0, 5.0, true); });
+ auto b = TypifyOp2::resolve(Mul::f, [](auto t){ return test_op2<typename decltype(t)::type>(Mul::f, 5.0, 3.0, true); });
+ auto c = TypifyOp2::resolve(Sub::f, [](auto t){ return test_op2<typename decltype(t)::type>(Sub::f, 8.0, 5.0, false); });
+ // putting the lambda inside the EXPECT does not work
+ EXPECT_EQ(a, 7.0);
+ EXPECT_EQ(b, 15.0);
+ EXPECT_EQ(c, 3.0);
+}
+
+GTEST_MAIN_RUN_ALL_TESTS()