diff options
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.cpp | 216 |
1 files changed, 189 insertions, 27 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 index bfcb3a09a52..8895bd4bcbd 100644 --- a/eval/src/tests/eval/inline_operation/inline_operation_test.cpp +++ b/eval/src/tests/eval/inline_operation/inline_operation_test.cpp @@ -3,27 +3,29 @@ #include <vespa/eval/eval/operation.h> #include <vespa/eval/eval/inline_operation.h> #include <vespa/eval/eval/function.h> +#include <vespa/vespalib/util/typify.h> #include <vespa/vespalib/gtest/gtest.h> +using vespalib::typify_invoke; 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; }; +const int my_value = 42; +struct AsValue { template <typename T> static int invoke() { return my_value; } }; +struct AsRef { template <typename T> static const int &invoke() { return my_value; } }; -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> void test_op1(op1_t ref, double a, double expect) { + bool need_ref = std::is_same_v<T,CallOp1>; + T op = need_ref ? T(ref) : T(nullptr); + EXPECT_DOUBLE_EQ(ref(a), expect); + EXPECT_DOUBLE_EQ(op(a), expect); }; -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); +template <typename T> void test_op2(op2_t ref, double a, double b, double expect) { + bool need_ref = std::is_same_v<T,CallOp2>; + T op = need_ref ? T(ref) : T(nullptr); + EXPECT_DOUBLE_EQ(ref(a, b), expect); + EXPECT_DOUBLE_EQ(op(a, b), expect); }; op1_t as_op1(const vespalib::string &str) { @@ -63,6 +65,9 @@ TEST(InlineOperationTest, op1_lambdas_are_recognized) { EXPECT_EQ(as_op1("relu(a)"), &Relu::f); EXPECT_EQ(as_op1("sigmoid(a)"), &Sigmoid::f); EXPECT_EQ(as_op1("elu(a)"), &Elu::f); + //------------------------------------------- + EXPECT_EQ(as_op1("1/a"), &Inv::f); + EXPECT_EQ(as_op1("1.0/a"), &Inv::f); } TEST(InlineOperationTest, op1_lambdas_are_recognized_with_different_parameter_names) { @@ -121,11 +126,37 @@ TEST(InlineOperationTest, generic_op2_wrapper_works) { EXPECT_EQ(op(3,7), 10); } +TEST(InlineOperationTest, op1_typifier_forwards_return_value_correctly) { + auto a = typify_invoke<1,TypifyOp1,AsValue>(Neg::f); + auto b = typify_invoke<1,TypifyOp1,AsRef>(Neg::f); + EXPECT_EQ(a, my_value); + EXPECT_EQ(b, my_value); + bool same_memory = (&(typify_invoke<1,TypifyOp1,AsRef>(Neg::f)) == &my_value); + EXPECT_EQ(same_memory, true); +} + +TEST(InlineOperationTest, op2_typifier_forwards_return_value_correctly) { + auto a = typify_invoke<1,TypifyOp2,AsValue>(Add::f); + auto b = typify_invoke<1,TypifyOp2,AsRef>(Add::f); + EXPECT_EQ(a, my_value); + EXPECT_EQ(b, my_value); + bool same_memory = (&(typify_invoke<1,TypifyOp2,AsRef>(Add::f)) == &my_value); + EXPECT_EQ(same_memory, true); +} + +TEST(InlineOperationTest, inline_op1_example_works) { + op1_t ignored = nullptr; + InlineOp1<Inv> op(ignored); + EXPECT_EQ(op(2.0), 0.5); + EXPECT_EQ(op(4.0f), 0.25f); + EXPECT_EQ(op(8.0), 0.125); +} + 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); + EXPECT_EQ(op(2.0, 3.0), 5.0); + EXPECT_EQ(op(3.0, 7.0), 10.0); } TEST(InlineOperationTest, parameter_swap_wrapper_works) { @@ -137,20 +168,151 @@ TEST(InlineOperationTest, parameter_swap_wrapper_works) { 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, op1_exp_is_inlined) { + TypifyOp1::resolve(Exp::f, [](auto t) + { + using T = typename decltype(t)::type; + bool type_ok = std::is_same_v<T,InlineOp1<Exp>>; + op1_t ref = Exp::f; + EXPECT_TRUE(type_ok); + test_op1<T>(ref, 2.0, std::exp(2.0)); + test_op1<T>(ref, 3.0, std::exp(3.0)); + test_op1<T>(ref, 7.0, std::exp(7.0)); + }); +} + +TEST(InlineOperationTest, op1_inv_is_inlined) { + TypifyOp1::resolve(Inv::f, [](auto t) + { + using T = typename decltype(t)::type; + bool type_ok = std::is_same_v<T,InlineOp1<Inv>>; + op1_t ref = Inv::f; + EXPECT_TRUE(type_ok); + test_op1<T>(ref, 2.0, 1.0/2.0); + test_op1<T>(ref, 4.0, 1.0/4.0); + test_op1<T>(ref, 8.0, 1.0/8.0); + }); +} + +TEST(InlineOperationTest, op1_sqrt_is_inlined) { + TypifyOp1::resolve(Sqrt::f, [](auto t) + { + using T = typename decltype(t)::type; + bool type_ok = std::is_same_v<T,InlineOp1<Sqrt>>; + op1_t ref = Sqrt::f; + EXPECT_TRUE(type_ok); + test_op1<T>(ref, 2.0, sqrt(2.0)); + test_op1<T>(ref, 4.0, sqrt(4.0)); + test_op1<T>(ref, 64.0, sqrt(64.0)); + }); +} + +TEST(InlineOperationTest, op1_tanh_is_inlined) { + TypifyOp1::resolve(Tanh::f, [](auto t) + { + using T = typename decltype(t)::type; + bool type_ok = std::is_same_v<T,InlineOp1<Tanh>>; + op1_t ref = Tanh::f; + EXPECT_TRUE(type_ok); + test_op1<T>(ref, 0.1, std::tanh(0.1)); + test_op1<T>(ref, 0.3, std::tanh(0.3)); + test_op1<T>(ref, 0.7, std::tanh(0.7)); + }); +} + +TEST(InlineOperationTest, op1_neg_is_not_inlined) { + TypifyOp1::resolve(Neg::f, [](auto t) + { + using T = typename decltype(t)::type; + bool type_ok = std::is_same_v<T,CallOp1>; + op1_t ref = Neg::f; + EXPECT_TRUE(type_ok); + test_op1<T>(ref, 3.0, -3.0); + test_op1<T>(ref, 5.0, -5.0); + test_op1<T>(ref, -2.0, 2.0); + }); +} + +//----------------------------------------------------------------------------- + +TEST(InlineOperationTest, op2_add_is_inlined) { + TypifyOp2::resolve(Add::f, [](auto t) + { + using T = typename decltype(t)::type; + bool type_ok = std::is_same_v<T,InlineOp2<Add>>; + op2_t ref = Add::f; + EXPECT_TRUE(type_ok); + test_op2<T>(ref, 2.0, 2.0, 4.0); + test_op2<T>(ref, 3.0, 8.0, 11.0); + test_op2<T>(ref, 7.0, 1.0, 8.0); + }); +} + +TEST(InlineOperationTest, op2_div_is_inlined) { + TypifyOp2::resolve(Div::f, [](auto t) + { + using T = typename decltype(t)::type; + bool type_ok = std::is_same_v<T,InlineOp2<Div>>; + op2_t ref = Div::f; + EXPECT_TRUE(type_ok); + test_op2<T>(ref, 2.0, 2.0, 1.0); + test_op2<T>(ref, 3.0, 8.0, 3.0 / 8.0); + test_op2<T>(ref, 7.0, 5.0, 7.0 / 5.0); + }); +} + +TEST(InlineOperationTest, op2_mul_is_inlined) { + TypifyOp2::resolve(Mul::f, [](auto t) + { + using T = typename decltype(t)::type; + bool type_ok = std::is_same_v<T,InlineOp2<Mul>>; + op2_t ref = Mul::f; + EXPECT_TRUE(type_ok); + test_op2<T>(ref, 2.0, 2.0, 4.0); + test_op2<T>(ref, 3.0, 8.0, 24.0); + test_op2<T>(ref, 7.0, 5.0, 35.0); + }); +} + +TEST(InlineOperationTest, op2_pow_is_inlined) { + TypifyOp2::resolve(Pow::f, [](auto t) + { + using T = typename decltype(t)::type; + bool type_ok = std::is_same_v<T,InlineOp2<Pow>>; + op2_t ref = Pow::f; + EXPECT_TRUE(type_ok); + test_op2<T>(ref, 2.0, 2.0, std::pow(2.0, 2.0)); + test_op2<T>(ref, 3.0, 8.0, std::pow(3.0, 8.0)); + test_op2<T>(ref, 7.0, 5.0, std::pow(7.0, 5.0)); + }); +} + +TEST(InlineOperationTest, op2_sub_is_inlined) { + TypifyOp2::resolve(Sub::f, [](auto t) + { + using T = typename decltype(t)::type; + bool type_ok = std::is_same_v<T,InlineOp2<Sub>>; + op2_t ref = Sub::f; + EXPECT_TRUE(type_ok); + test_op2<T>(ref, 3.0, 2.0, 1.0); + test_op2<T>(ref, 3.0, 8.0, -5.0); + test_op2<T>(ref, 7.0, 5.0, 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); +TEST(InlineOperationTest, op2_mod_is_not_inlined) { + TypifyOp2::resolve(Mod::f, [](auto t) + { + using T = typename decltype(t)::type; + bool type_ok = std::is_same_v<T,CallOp2>; + op2_t ref = Mod::f; + EXPECT_TRUE(type_ok); + test_op2<T>(ref, 3.0, 2.0, std::fmod(3.0, 2.0)); + test_op2<T>(ref, 3.0, 8.0, std::fmod(3.0, 8.0)); + test_op2<T>(ref, 7.0, 5.0, std::fmod(7.0, 5.0)); + }); } GTEST_MAIN_RUN_ALL_TESTS() |