aboutsummaryrefslogtreecommitdiffstats
path: root/eval/src/tests
diff options
context:
space:
mode:
Diffstat (limited to 'eval/src/tests')
-rw-r--r--eval/src/tests/eval/gen_spec/gen_spec_test.cpp56
-rw-r--r--eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp2
-rw-r--r--eval/src/tests/eval/value_type/value_type_test.cpp37
-rw-r--r--eval/src/tests/instruction/mapped_lookup/CMakeLists.txt9
-rw-r--r--eval/src/tests/instruction/mapped_lookup/mapped_lookup_test.cpp126
5 files changed, 183 insertions, 47 deletions
diff --git a/eval/src/tests/eval/gen_spec/gen_spec_test.cpp b/eval/src/tests/eval/gen_spec/gen_spec_test.cpp
index 855b298f295..a52ece90e6a 100644
--- a/eval/src/tests/eval/gen_spec/gen_spec_test.cpp
+++ b/eval/src/tests/eval/gen_spec/gen_spec_test.cpp
@@ -31,13 +31,13 @@ TEST(DimSpecTest, mapped_dimension) {
TEST(DimSpecTest, simple_dictionary_creation) {
auto dict = DimSpec::make_dict(5, 1, "");
- std::vector<vespalib::string> expect = {"0", "1", "2", "3", "4"};
+ std::vector<vespalib::string> expect = {"1", "2", "3", "4", "5"};
EXPECT_EQ(dict, expect);
}
TEST(DimSpecTest, advanced_dictionary_creation) {
auto dict = DimSpec::make_dict(5, 3, "str_");
- std::vector<vespalib::string> expect = {"str_0", "str_3", "str_6", "str_9", "str_12"};
+ std::vector<vespalib::string> expect = {"str_3", "str_6", "str_9", "str_12", "str_15"};
EXPECT_EQ(dict, expect);
}
@@ -176,50 +176,50 @@ TEST(GenSpecTest, generating_custom_vector) {
//-----------------------------------------------------------------------------
TensorSpec basic_map = TensorSpec("tensor(a{})")
- .add({{"a", "0"}}, 1.0)
- .add({{"a", "1"}}, 2.0)
- .add({{"a", "2"}}, 3.0);
+ .add({{"a", "1"}}, 1.0)
+ .add({{"a", "2"}}, 2.0)
+ .add({{"a", "3"}}, 3.0);
TensorSpec custom_map = TensorSpec("tensor(a{})")
- .add({{"a", "s0"}}, 1.0)
- .add({{"a", "s5"}}, 2.0)
- .add({{"a", "s10"}}, 3.0);
+ .add({{"a", "s5"}}, 1.0)
+ .add({{"a", "s10"}}, 2.0)
+ .add({{"a", "s15"}}, 3.0);
TEST(GenSpecTest, generating_basic_map) {
EXPECT_EQ(GenSpec().map("a", 3).gen(), basic_map);
EXPECT_EQ(GenSpec().map("a", 3, 1).gen(), basic_map);
EXPECT_EQ(GenSpec().map("a", 3, 1, "").gen(), basic_map);
- EXPECT_EQ(GenSpec().map("a", {"0", "1", "2"}).gen(), basic_map);
+ EXPECT_EQ(GenSpec().map("a", {"1", "2", "3"}).gen(), basic_map);
}
TEST(GenSpecTest, generating_custom_map) {
EXPECT_EQ(GenSpec().map("a", 3, 5, "s").gen(), custom_map);
- EXPECT_EQ(GenSpec().map("a", {"s0", "s5", "s10"}).gen(), custom_map);
+ EXPECT_EQ(GenSpec().map("a", {"s5", "s10", "s15"}).gen(), custom_map);
}
//-----------------------------------------------------------------------------
TensorSpec basic_mixed = TensorSpec("tensor(a{},b[1],c{},d[3])")
- .add({{"a", "0"},{"b", 0},{"c", "0"},{"d", 0}}, 1.0)
- .add({{"a", "0"},{"b", 0},{"c", "0"},{"d", 1}}, 2.0)
- .add({{"a", "0"},{"b", 0},{"c", "0"},{"d", 2}}, 3.0)
- .add({{"a", "1"},{"b", 0},{"c", "0"},{"d", 0}}, 4.0)
- .add({{"a", "1"},{"b", 0},{"c", "0"},{"d", 1}}, 5.0)
- .add({{"a", "1"},{"b", 0},{"c", "0"},{"d", 2}}, 6.0)
- .add({{"a", "2"},{"b", 0},{"c", "0"},{"d", 0}}, 7.0)
- .add({{"a", "2"},{"b", 0},{"c", "0"},{"d", 1}}, 8.0)
- .add({{"a", "2"},{"b", 0},{"c", "0"},{"d", 2}}, 9.0);
+ .add({{"a", "1"},{"b", 0},{"c", "1"},{"d", 0}}, 1.0)
+ .add({{"a", "1"},{"b", 0},{"c", "1"},{"d", 1}}, 2.0)
+ .add({{"a", "1"},{"b", 0},{"c", "1"},{"d", 2}}, 3.0)
+ .add({{"a", "2"},{"b", 0},{"c", "1"},{"d", 0}}, 4.0)
+ .add({{"a", "2"},{"b", 0},{"c", "1"},{"d", 1}}, 5.0)
+ .add({{"a", "2"},{"b", 0},{"c", "1"},{"d", 2}}, 6.0)
+ .add({{"a", "3"},{"b", 0},{"c", "1"},{"d", 0}}, 7.0)
+ .add({{"a", "3"},{"b", 0},{"c", "1"},{"d", 1}}, 8.0)
+ .add({{"a", "3"},{"b", 0},{"c", "1"},{"d", 2}}, 9.0);
TensorSpec inverted_mixed = TensorSpec("tensor(a{},b[1],c{},d[3])")
- .add({{"a", "0"},{"b", 0},{"c", "0"},{"d", 0}}, 1.0)
- .add({{"a", "1"},{"b", 0},{"c", "0"},{"d", 0}}, 2.0)
- .add({{"a", "2"},{"b", 0},{"c", "0"},{"d", 0}}, 3.0)
- .add({{"a", "0"},{"b", 0},{"c", "0"},{"d", 1}}, 4.0)
- .add({{"a", "1"},{"b", 0},{"c", "0"},{"d", 1}}, 5.0)
- .add({{"a", "2"},{"b", 0},{"c", "0"},{"d", 1}}, 6.0)
- .add({{"a", "0"},{"b", 0},{"c", "0"},{"d", 2}}, 7.0)
- .add({{"a", "1"},{"b", 0},{"c", "0"},{"d", 2}}, 8.0)
- .add({{"a", "2"},{"b", 0},{"c", "0"},{"d", 2}}, 9.0);
+ .add({{"a", "1"},{"b", 0},{"c", "1"},{"d", 0}}, 1.0)
+ .add({{"a", "2"},{"b", 0},{"c", "1"},{"d", 0}}, 2.0)
+ .add({{"a", "3"},{"b", 0},{"c", "1"},{"d", 0}}, 3.0)
+ .add({{"a", "1"},{"b", 0},{"c", "1"},{"d", 1}}, 4.0)
+ .add({{"a", "2"},{"b", 0},{"c", "1"},{"d", 1}}, 5.0)
+ .add({{"a", "3"},{"b", 0},{"c", "1"},{"d", 1}}, 6.0)
+ .add({{"a", "1"},{"b", 0},{"c", "1"},{"d", 2}}, 7.0)
+ .add({{"a", "2"},{"b", 0},{"c", "1"},{"d", 2}}, 8.0)
+ .add({{"a", "3"},{"b", 0},{"c", "1"},{"d", 2}}, 9.0);
TEST(GenSpecTest, generating_basic_mixed) {
EXPECT_EQ(GenSpec().map("a", 3).idx("b", 1).map("c", 1).idx("d", 3).gen(), basic_mixed);
diff --git a/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp b/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp
index 657a6ca8d0e..a455e5522b3 100644
--- a/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp
+++ b/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp
@@ -31,7 +31,7 @@ EvalFixture::ParamRepo make_params() {
.add("x3_float", GenSpec().idx("x", 3).cells(CellType::FLOAT))
.add("x3_bfloat16", GenSpec().idx("x", 3).cells(CellType::BFLOAT16))
.add("x3_int8", GenSpec().idx("x", 3).cells(CellType::INT8))
- .add("x3m", GenSpec().map("x", 3))
+ .add("x3m", GenSpec().map("x", {"0", "1", "2"}))
.add("x3y5", GenSpec().idx("x", 3).idx("y", 5))
.add("x3y5_float", GenSpec().idx("x", 3).idx("y", 5).cells(CellType::FLOAT))
.add("x3y5_bfloat16", GenSpec().idx("x", 3).idx("y", 5).cells(CellType::BFLOAT16))
diff --git a/eval/src/tests/eval/value_type/value_type_test.cpp b/eval/src/tests/eval/value_type/value_type_test.cpp
index 3d4872c2ab3..245c9c30242 100644
--- a/eval/src/tests/eval/value_type/value_type_test.cpp
+++ b/eval/src/tests/eval/value_type/value_type_test.cpp
@@ -353,33 +353,34 @@ TEST("require that dimension index can be obtained") {
void verify_predicates(const ValueType &type,
bool expect_error, bool expect_double, bool expect_tensor,
- bool expect_sparse, bool expect_dense)
+ bool expect_sparse, bool expect_dense, bool expect_mixed)
{
EXPECT_EQUAL(type.is_error(), expect_error);
EXPECT_EQUAL(type.is_double(), expect_double);
EXPECT_EQUAL(type.has_dimensions(), expect_tensor);
EXPECT_EQUAL(type.is_sparse(), expect_sparse);
EXPECT_EQUAL(type.is_dense(), expect_dense);
+ EXPECT_EQUAL(type.is_mixed(), expect_mixed);
}
TEST("require that type-related predicate functions work as expected") {
- TEST_DO(verify_predicates(type("error"), true, false, false, false, false));
- TEST_DO(verify_predicates(type("double"), false, true, false, false, false));
- TEST_DO(verify_predicates(type("tensor()"), false, true, false, false, false));
- TEST_DO(verify_predicates(type("tensor(x{})"), false, false, true, true, false));
- TEST_DO(verify_predicates(type("tensor(x{},y{})"), false, false, true, true, false));
- TEST_DO(verify_predicates(type("tensor(x[5])"), false, false, true, false, true));
- TEST_DO(verify_predicates(type("tensor(x[5],y[10])"), false, false, true, false, true));
- TEST_DO(verify_predicates(type("tensor(x[5],y{})"), false, false, true, false, false));
- TEST_DO(verify_predicates(type("tensor<float>(x{})"), false, false, true, true, false));
- TEST_DO(verify_predicates(type("tensor<float>(x[5])"), false, false, true, false, true));
- TEST_DO(verify_predicates(type("tensor<float>(x[5],y{})"), false, false, true, false, false));
- TEST_DO(verify_predicates(type("tensor<bfloat16>(x{})"), false, false, true, true, false));
- TEST_DO(verify_predicates(type("tensor<bfloat16>(x[5])"), false, false, true, false, true));
- TEST_DO(verify_predicates(type("tensor<bfloat16>(x[5],y{})"), false, false, true, false, false));
- TEST_DO(verify_predicates(type("tensor<int8>(x{})"), false, false, true, true, false));
- TEST_DO(verify_predicates(type("tensor<int8>(x[5])"), false, false, true, false, true));
- TEST_DO(verify_predicates(type("tensor<int8>(x[5],y{})"), false, false, true, false, false));
+ TEST_DO(verify_predicates(type("error"), true, false, false, false, false, false));
+ TEST_DO(verify_predicates(type("double"), false, true, false, false, false, false));
+ TEST_DO(verify_predicates(type("tensor()"), false, true, false, false, false, false));
+ TEST_DO(verify_predicates(type("tensor(x{})"), false, false, true, true, false, false));
+ TEST_DO(verify_predicates(type("tensor(x{},y{})"), false, false, true, true, false, false));
+ TEST_DO(verify_predicates(type("tensor(x[5])"), false, false, true, false, true, false));
+ TEST_DO(verify_predicates(type("tensor(x[5],y[10])"), false, false, true, false, true, false));
+ TEST_DO(verify_predicates(type("tensor(x[5],y{})"), false, false, true, false, false, true));
+ TEST_DO(verify_predicates(type("tensor<float>(x{})"), false, false, true, true, false, false));
+ TEST_DO(verify_predicates(type("tensor<float>(x[5])"), false, false, true, false, true, false));
+ TEST_DO(verify_predicates(type("tensor<float>(x[5],y{})"), false, false, true, false, false, true));
+ TEST_DO(verify_predicates(type("tensor<bfloat16>(x{})"), false, false, true, true, false, false));
+ TEST_DO(verify_predicates(type("tensor<bfloat16>(x[5])"), false, false, true, false, true, false));
+ TEST_DO(verify_predicates(type("tensor<bfloat16>(x[5],y{})"), false, false, true, false, false, true));
+ TEST_DO(verify_predicates(type("tensor<int8>(x{})"), false, false, true, true, false, false));
+ TEST_DO(verify_predicates(type("tensor<int8>(x[5])"), false, false, true, false, true, false));
+ TEST_DO(verify_predicates(type("tensor<int8>(x[5],y{})"), false, false, true, false, false, true));
}
TEST("require that mapped and indexed dimensions can be counted") {
diff --git a/eval/src/tests/instruction/mapped_lookup/CMakeLists.txt b/eval/src/tests/instruction/mapped_lookup/CMakeLists.txt
new file mode 100644
index 00000000000..6bc598235ea
--- /dev/null
+++ b/eval/src/tests/instruction/mapped_lookup/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(eval_mapped_lookup_test_app TEST
+ SOURCES
+ mapped_lookup_test.cpp
+ DEPENDS
+ vespaeval
+ GTest::GTest
+)
+vespa_add_test(NAME eval_mapped_lookup_test_app COMMAND eval_mapped_lookup_test_app)
diff --git a/eval/src/tests/instruction/mapped_lookup/mapped_lookup_test.cpp b/eval/src/tests/instruction/mapped_lookup/mapped_lookup_test.cpp
new file mode 100644
index 00000000000..1ffc6b04f4b
--- /dev/null
+++ b/eval/src/tests/instruction/mapped_lookup/mapped_lookup_test.cpp
@@ -0,0 +1,126 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/eval/eval/fast_value.h>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/instruction/mapped_lookup.h>
+#include <vespa/eval/eval/test/eval_fixture.h>
+#include <vespa/eval/eval/test/gen_spec.h>
+#include <vespa/vespalib/gtest/gtest.h>
+
+using namespace vespalib::eval;
+using namespace vespalib::eval::test;
+
+//-----------------------------------------------------------------------------
+
+struct FunInfo {
+ using LookFor = MappedLookup;
+ bool expect_mutable;
+ FunInfo(bool expect_mutable_in)
+ : expect_mutable(expect_mutable_in) {}
+ void verify(const LookFor &fun) const {
+ EXPECT_EQ(fun.result_is_mutable(), expect_mutable);
+ }
+};
+
+void verify_optimized_cell_types(const vespalib::string &expr) {
+ auto same_stable_types = CellTypeSpace(CellTypeUtils::list_stable_types(), 2).same();
+ auto same_unstable_types = CellTypeSpace(CellTypeUtils::list_unstable_types(), 2).same();
+ auto different_types = CellTypeSpace(CellTypeUtils::list_types(), 2).different();
+ EvalFixture::verify<FunInfo>(expr, {FunInfo(false)}, same_stable_types);
+ EvalFixture::verify<FunInfo>(expr, {}, same_unstable_types);
+ EvalFixture::verify<FunInfo>(expr, {}, different_types);
+}
+
+void verify_optimized(const vespalib::string &expr, bool expect_mutable = false) {
+ CellTypeSpace just_float({CellType::FLOAT}, 2);
+ EvalFixture::verify<FunInfo>(expr, {FunInfo(expect_mutable)}, just_float);
+}
+
+void verify_not_optimized(const vespalib::string &expr) {
+ CellTypeSpace just_float({CellType::FLOAT}, 2);
+ EvalFixture::verify<FunInfo>(expr, {}, just_float);
+}
+
+//-----------------------------------------------------------------------------
+
+TEST(MappedLookup, expression_can_be_optimized) {
+ verify_optimized_cell_types("reduce(x1_1*x5_1y5,sum,x)");
+}
+
+TEST(MappedLookup, key_and_map_can_be_swapped) {
+ verify_optimized("reduce(x5_1y5*x1_1,sum,x)");
+}
+
+TEST(MappedLookup, trivial_indexed_dimensions_are_ignored) {
+ verify_optimized("reduce(c1d1x1_1*a1b1x5_1y5,sum,x,c,d,a,b)");
+ verify_optimized("reduce(c1d1x1_1*a1b1x5_1y5,sum,x,c,a)");
+ verify_optimized("reduce(c1d1x1_1*a1b1x5_1y5,sum,x)");
+}
+
+TEST(MappedLookup, mutable_map_gives_mutable_result) {
+ verify_optimized("reduce(@x1_1*x5_1y5,sum,x)", false);
+ verify_optimized("reduce(x1_1*@x5_1y5,sum,x)", true);
+ verify_optimized("reduce(@x5_1y5*x1_1,sum,x)", true);
+ verify_optimized("reduce(x5_1y5*@x1_1,sum,x)", false);
+ verify_optimized("reduce(@x5_1y5*@x1_1,sum,x)", true);
+}
+
+TEST(MappedLookup, similar_expressions_are_not_optimized) {
+ verify_not_optimized("reduce(x1_1*x5_1,sum,x)");
+ verify_not_optimized("reduce(x1_1*x5_1y5,sum,y)");
+ verify_not_optimized("reduce(x1_1*x5_1y5,sum)");
+ verify_not_optimized("reduce(x1_1*x5_1y5z8,sum,x,y)");
+ verify_not_optimized("reduce(x1_1*x5_1y5,prod,x)");
+ verify_not_optimized("reduce(x1_1y3_3*x5_1y3_2z5,sum,x)");
+ verify_not_optimized("reduce(x1_1y3_3*x5_1y3_2z5,sum,x,y)");
+ verify_not_optimized("reduce(x1_1y5*x5_1z5,sum,x)");
+}
+
+enum class KeyType { EMPTY, UNIT, SCALING, MULTI };
+GenSpec make_key(KeyType type) {
+ switch (type) {
+ case KeyType::EMPTY: return GenSpec().cells_float().map("x", {});
+ case KeyType::UNIT: return GenSpec().cells_float().map("x", {"1"}).seq({1.0});
+ case KeyType::SCALING: return GenSpec().cells_float().map("x", {"1"}).seq({5.0});
+ case KeyType::MULTI: return GenSpec().cells_float().map("x", {"1", "2", "3"}).seq({1.0});
+ }
+ abort();
+}
+
+enum class MapType { EMPTY, SMALL, MEDIUM, LARGE1, LARGE2, LARGE3 };
+GenSpec make_map(MapType type) {
+ switch (type) {
+ case MapType::EMPTY: return GenSpec().cells_float().idx("y", 5).map("x", {});
+ case MapType::SMALL: return GenSpec().cells_float().idx("y", 5).map("x", {"1"}).seq(N(10));
+ case MapType::MEDIUM: return GenSpec().cells_float().idx("y", 5).map("x", {"1", "2"}).seq(N(10));
+ case MapType::LARGE1: return GenSpec().cells_float().idx("y", 5).map("x", 5, 100).seq(N(10));
+ case MapType::LARGE2: return GenSpec().cells_float().idx("y", 5).map("x", 5, 2).seq(N(10));
+ case MapType::LARGE3: return GenSpec().cells_float().idx("y", 5).map("x", 5, 1).seq(N(10));
+ }
+ abort();
+}
+
+std::vector<MapType> map_types_for(KeyType key_type) {
+ if (key_type == KeyType::MULTI) {
+ return {MapType::EMPTY, MapType::SMALL, MapType::MEDIUM, MapType::LARGE1, MapType::LARGE2, MapType::LARGE3};
+ } else {
+ return {MapType::EMPTY, MapType::SMALL, MapType::MEDIUM};
+ }
+}
+
+TEST(MappedLookup, test_case_interactions) {
+ for (bool mutable_map: {false, true}) {
+ vespalib::string expr = mutable_map ? "reduce(a*@b,sum,x)" : "reduce(a*b,sum,x)";
+ for (KeyType key_type: {KeyType::EMPTY, KeyType::UNIT, KeyType::SCALING, KeyType::MULTI}) {
+ auto key = make_key(key_type);
+ for (MapType map_type: map_types_for(key_type)) {
+ auto map = make_map(map_type);
+ EvalFixture::verify<FunInfo>(expr, {FunInfo(mutable_map)}, {key,map});
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+GTEST_MAIN_RUN_ALL_TESTS()