summaryrefslogtreecommitdiffstats
path: root/eval
diff options
context:
space:
mode:
authorArne Juul <arnej@verizonmedia.com>2020-09-23 13:57:05 +0000
committerArne Juul <arnej@verizonmedia.com>2020-09-23 13:57:19 +0000
commit05442b391e2feedae7cbea9dd53a01caf26da5f1 (patch)
treea3a80b7ced332dc20146306133435979d6fa117d /eval
parent10169943144990208e11529109d30febccb49756 (diff)
add unit test for value_codec.h functions
Diffstat (limited to 'eval')
-rw-r--r--eval/CMakeLists.txt1
-rw-r--r--eval/src/tests/eval/value_codec/CMakeLists.txt10
-rw-r--r--eval/src/tests/eval/value_codec/value_codec_test.cpp281
3 files changed, 292 insertions, 0 deletions
diff --git a/eval/CMakeLists.txt b/eval/CMakeLists.txt
index d4189fb3256..c69425d5387 100644
--- a/eval/CMakeLists.txt
+++ b/eval/CMakeLists.txt
@@ -29,6 +29,7 @@ vespa_define_module(
src/tests/eval/tensor_lambda
src/tests/eval/tensor_spec
src/tests/eval/value_cache
+ src/tests/eval/value_codec
src/tests/eval/value_type
src/tests/gp/ponder_nov2017
src/tests/tensor/dense_add_dimension_optimizer
diff --git a/eval/src/tests/eval/value_codec/CMakeLists.txt b/eval/src/tests/eval/value_codec/CMakeLists.txt
new file mode 100644
index 00000000000..aa1adf10136
--- /dev/null
+++ b/eval/src/tests/eval/value_codec/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+vespa_add_executable(eval_value_codec_test_app TEST
+ SOURCES
+ value_codec_test.cpp
+ DEPENDS
+ vespaeval
+ GTest::GTest
+)
+vespa_add_test(NAME eval_value_codec_test_app COMMAND eval_value_codec_test_app)
diff --git a/eval/src/tests/eval/value_codec/value_codec_test.cpp b/eval/src/tests/eval/value_codec/value_codec_test.cpp
new file mode 100644
index 00000000000..43bbebfc094
--- /dev/null
+++ b/eval/src/tests/eval/value_codec/value_codec_test.cpp
@@ -0,0 +1,281 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <iostream>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/test/tensor_model.hpp>
+#include <vespa/eval/eval/value_codec.h>
+#include <vespa/vespalib/data/memory.h>
+#include <vespa/vespalib/gtest/gtest.h>
+#include <vespa/vespalib/objects/nbostream.h>
+
+using namespace vespalib;
+using namespace vespalib::eval;
+using namespace vespalib::eval::test;
+
+using vespalib::make_string_short::fmt;
+
+std::vector<Layout> layouts = {
+ {},
+ {x(3)},
+ {x(3),y(5)},
+ {x(3),y(5),z(7)},
+ float_cells({x(3),y(5),z(7)}),
+ {x({"a","b","c"})},
+ {x({"a","b","c"}),y({"foo","bar"})},
+ {x({"a","b","c"}),y({"foo","bar"}),z({"i","j","k","l"})},
+ float_cells({x({"a","b","c"}),y({"foo","bar"}),z({"i","j","k","l"})}),
+ {x(3),y({"foo", "bar"}),z(7)},
+ {x({"a","b","c"}),y(5),z({"i","j","k","l"})},
+ float_cells({x({"a","b","c"}),y(5),z({"i","j","k","l"})})
+};
+
+struct Factory {
+ SimpleValueBuilderFactory simple;
+ std::unique_ptr<Value> from_spec(const TensorSpec &spec) {
+ return value_from_spec(spec, simple);
+ }
+ std::unique_ptr<Value> decode(nbostream &input) {
+ return new_decode(input, simple);
+ }
+} simple_factory;
+
+TEST(ValueCodecTest, simple_values_can_be_converted_from_and_to_tensor_spec) {
+ for (const auto &layout: layouts) {
+ TensorSpec expect = spec(layout, N());
+ std::unique_ptr<Value> value = simple_factory.from_spec(expect);
+ TensorSpec actual = spec_from_value(*value);
+ EXPECT_EQ(actual, expect);
+ }
+}
+
+
+TEST(ValueCodecTest, require_that_simple_tensors_can_be_built_using_tensor_spec) {
+ TensorSpec spec("tensor(w{},x[2],y{},z[2])");
+ spec.add({{"w", "xxx"}, {"x", 0}, {"y", "xxx"}, {"z", 0}}, 1.0)
+ .add({{"w", "xxx"}, {"x", 0}, {"y", "yyy"}, {"z", 1}}, 2.0)
+ .add({{"w", "yyy"}, {"x", 1}, {"y", "xxx"}, {"z", 0}}, 3.0)
+ .add({{"w", "yyy"}, {"x", 1}, {"y", "yyy"}, {"z", 1}}, 4.0);
+ Value::UP tensor = simple_factory.from_spec(spec);
+ TensorSpec full_spec("tensor(w{},x[2],y{},z[2])");
+ full_spec
+ .add({{"w", "xxx"}, {"x", 0}, {"y", "xxx"}, {"z", 0}}, 1.0)
+ .add({{"w", "xxx"}, {"x", 0}, {"y", "xxx"}, {"z", 1}}, 0.0)
+ .add({{"w", "xxx"}, {"x", 0}, {"y", "yyy"}, {"z", 0}}, 0.0)
+ .add({{"w", "xxx"}, {"x", 0}, {"y", "yyy"}, {"z", 1}}, 2.0)
+ .add({{"w", "xxx"}, {"x", 1}, {"y", "xxx"}, {"z", 0}}, 0.0)
+ .add({{"w", "xxx"}, {"x", 1}, {"y", "xxx"}, {"z", 1}}, 0.0)
+ .add({{"w", "xxx"}, {"x", 1}, {"y", "yyy"}, {"z", 0}}, 0.0)
+ .add({{"w", "xxx"}, {"x", 1}, {"y", "yyy"}, {"z", 1}}, 0.0)
+ .add({{"w", "yyy"}, {"x", 0}, {"y", "xxx"}, {"z", 0}}, 0.0)
+ .add({{"w", "yyy"}, {"x", 0}, {"y", "xxx"}, {"z", 1}}, 0.0)
+ .add({{"w", "yyy"}, {"x", 0}, {"y", "yyy"}, {"z", 0}}, 0.0)
+ .add({{"w", "yyy"}, {"x", 0}, {"y", "yyy"}, {"z", 1}}, 0.0)
+ .add({{"w", "yyy"}, {"x", 1}, {"y", "xxx"}, {"z", 0}}, 3.0)
+ .add({{"w", "yyy"}, {"x", 1}, {"y", "xxx"}, {"z", 1}}, 0.0)
+ .add({{"w", "yyy"}, {"x", 1}, {"y", "yyy"}, {"z", 0}}, 0.0)
+ .add({{"w", "yyy"}, {"x", 1}, {"y", "yyy"}, {"z", 1}}, 4.0);
+ Value::UP full_tensor = simple_factory.from_spec(full_spec);
+ EXPECT_EQUAL(full_spec, spec_from_value(*tensor));
+ EXPECT_EQUAL(full_spec, spec_from_value(*full_tensor));
+};
+
+//-----------------------------------------------------------------------------
+
+vespalib::string make_type_spec(bool use_float, const vespalib::string &dims) {
+ vespalib::string type_spec = "tensor";
+ if (use_float) {
+ type_spec.append("<float>");
+ }
+ type_spec.append(dims);
+ return type_spec;
+}
+
+struct TensorExample {
+ virtual ~TensorExample();
+ virtual TensorSpec make_spec(bool use_float) const = 0;
+ virtual std::unique_ptr<Value> make_tensor(bool use_float) const = 0;
+ virtual void encode_default(nbostream &dst) const = 0;
+ virtual void encode_with_double(nbostream &dst) const = 0;
+ virtual void encode_with_float(nbostream &dst) const = 0;
+ void verify_encode_decode() const {
+ nbostream expect_default;
+ nbostream expect_double;
+ nbostream expect_float;
+ encode_default(expect_default);
+ encode_with_double(expect_double);
+ encode_with_float(expect_float);
+ nbostream data_double;
+ nbostream data_float;
+ new_encode(*make_tensor(false), data_double);
+ new_encode(*make_tensor(true), data_float);
+ EXPECT_EQ(Memory(data_double.peek(), data_double.size()),
+ Memory(expect_default.peek(), expect_default.size()));
+ EXPECT_EQ(Memory(data_float.peek(), data_float.size()),
+ Memory(expect_float.peek(), expect_float.size()));
+ EXPECT_EQ(spec_from_value(*simple_factory.decode(expect_default)), make_spec(false));
+ EXPECT_EQ(spec_from_value(*simple_factory.decode(expect_double)), make_spec(false));
+ EXPECT_EQ(spec_from_value(*simple_factory.decode(expect_float)), make_spec(true));
+ }
+};
+TensorExample::~TensorExample() = default;
+
+//-----------------------------------------------------------------------------
+
+struct SparseTensorExample : TensorExample {
+ TensorSpec make_spec(bool use_float) const override {
+ return TensorSpec(make_type_spec(use_float, "(x{},y{})"))
+ .add({{"x","a"},{"y","a"}}, 1)
+ .add({{"x","a"},{"y","b"}}, 2)
+ .add({{"x","b"},{"y","a"}}, 3);
+ }
+ std::unique_ptr<Value> make_tensor(bool use_float) const override {
+ return simple_factory.from_spec(make_spec(use_float));
+ }
+ template <typename T>
+ void encode_inner(nbostream &dst) const {
+ dst.putInt1_4Bytes(2);
+ dst.writeSmallString("x");
+ dst.writeSmallString("y");
+ dst.putInt1_4Bytes(3);
+ dst.writeSmallString("a");
+ dst.writeSmallString("a");
+ dst << (T) 1;
+ dst.writeSmallString("a");
+ dst.writeSmallString("b");
+ dst << (T) 2;
+ dst.writeSmallString("b");
+ dst.writeSmallString("a");
+ dst << (T) 3;
+ }
+ void encode_default(nbostream &dst) const override {
+ dst.putInt1_4Bytes(1);
+ encode_inner<double>(dst);
+ }
+ void encode_with_double(nbostream &dst) const override {
+ dst.putInt1_4Bytes(5);
+ dst.putInt1_4Bytes(0);
+ encode_inner<double>(dst);
+ }
+ void encode_with_float(nbostream &dst) const override {
+ dst.putInt1_4Bytes(5);
+ dst.putInt1_4Bytes(1);
+ encode_inner<float>(dst);
+ }
+};
+
+TEST(ValueCodecTest, require_that_sparse_tensors_can_be_encoded_and_decoded) {
+ SparseTensorExample f1;
+ f1.verify_encode_decode();
+}
+
+//-----------------------------------------------------------------------------
+
+struct DenseTensorExample : TensorExample {
+ TensorSpec make_spec(bool use_float) const override {
+ return TensorSpec(make_type_spec(use_float, "(x[3],y[2])"))
+ .add({{"x",0},{"y",0}}, 1)
+ .add({{"x",0},{"y",1}}, 2)
+ .add({{"x",1},{"y",0}}, 3)
+ .add({{"x",1},{"y",1}}, 4)
+ .add({{"x",2},{"y",0}}, 5)
+ .add({{"x",2},{"y",1}}, 6);
+ }
+ std::unique_ptr<Value> make_tensor(bool use_float) const override {
+ return simple_factory.from_spec(make_spec(use_float));
+ }
+ template <typename T>
+ void encode_inner(nbostream &dst) const {
+ dst.putInt1_4Bytes(2);
+ dst.writeSmallString("x");
+ dst.putInt1_4Bytes(3);
+ dst.writeSmallString("y");
+ dst.putInt1_4Bytes(2);
+ dst << (T) 1;
+ dst << (T) 2;
+ dst << (T) 3;
+ dst << (T) 4;
+ dst << (T) 5;
+ dst << (T) 6;
+ }
+ void encode_default(nbostream &dst) const override {
+ dst.putInt1_4Bytes(2);
+ encode_inner<double>(dst);
+ }
+ void encode_with_double(nbostream &dst) const override {
+ dst.putInt1_4Bytes(6);
+ dst.putInt1_4Bytes(0);
+ encode_inner<double>(dst);
+ }
+ void encode_with_float(nbostream &dst) const override {
+ dst.putInt1_4Bytes(6);
+ dst.putInt1_4Bytes(1);
+ encode_inner<float>(dst);
+ }
+};
+
+TEST(ValueCodecTest, require_that_dense_tensors_can_be_encoded_and_decoded) {
+ DenseTensorExample f1;
+ f1.verify_encode_decode();
+}
+
+//-----------------------------------------------------------------------------
+
+struct MixedTensorExample : TensorExample {
+ TensorSpec make_spec(bool use_float) const override {
+ return TensorSpec(make_type_spec(use_float, "(x{},y{},z[2])"))
+ .add({{"x","a"},{"y","a"},{"z",0}}, 1)
+ .add({{"x","a"},{"y","a"},{"z",1}}, 2)
+ .add({{"x","a"},{"y","b"},{"z",0}}, 3)
+ .add({{"x","a"},{"y","b"},{"z",1}}, 4)
+ .add({{"x","b"},{"y","a"},{"z",0}}, 5)
+ .add({{"x","b"},{"y","a"},{"z",1}}, 6);
+ }
+ std::unique_ptr<Value> make_tensor(bool use_float) const override {
+ return simple_factory.from_spec(make_spec(use_float));
+ }
+ template <typename T>
+ void encode_inner(nbostream &dst) const {
+ dst.putInt1_4Bytes(2);
+ dst.writeSmallString("x");
+ dst.writeSmallString("y");
+ dst.putInt1_4Bytes(1);
+ dst.writeSmallString("z");
+ dst.putInt1_4Bytes(2);
+ dst.putInt1_4Bytes(3);
+ dst.writeSmallString("a");
+ dst.writeSmallString("a");
+ dst << (T) 1;
+ dst << (T) 2;
+ dst.writeSmallString("a");
+ dst.writeSmallString("b");
+ dst << (T) 3;
+ dst << (T) 4;
+ dst.writeSmallString("b");
+ dst.writeSmallString("a");
+ dst << (T) 5;
+ dst << (T) 6;
+ }
+ void encode_default(nbostream &dst) const override {
+ dst.putInt1_4Bytes(3);
+ encode_inner<double>(dst);
+ }
+ void encode_with_double(nbostream &dst) const override {
+ dst.putInt1_4Bytes(7);
+ dst.putInt1_4Bytes(0);
+ encode_inner<double>(dst);
+ }
+ void encode_with_float(nbostream &dst) const override {
+ dst.putInt1_4Bytes(7);
+ dst.putInt1_4Bytes(1);
+ encode_inner<float>(dst);
+ }
+};
+
+TEST(ValueCodecTest, require_that_mixed_tensors_can_be_encoded_and_decoded) {
+ MixedTensorExample f1;
+ f1.verify_encode_decode();
+}
+
+//-----------------------------------------------------------------------------
+
+GTEST_MAIN_RUN_ALL_TESTS()